使用Fold计算依赖于多个先前值的线性递归结果

时间:2011-03-14 03:19:19

标签: wolfram-mathematica

我有一个线性递归问题,其中下一个元素不仅依赖于前一个值,例如: Fibonacci序列。计算n th 元素的一种方法是通过函数调用来定义它,例如

Fibonacci[0] = 0; Fibonacci[1] = 1;
Fibonacci[n_Integer?Positive] := Fibonacci[n] + Fibonacci[n - 1]

对于我正在使用的序列,这正是我所做的。 (定义在Module内部,所以我不会污染Global`。)但是,我将使用2 10 - 2 13 点,所以当我只需要最后一个术语而没有任何先前的元素时,我担心额外的开销。我想使用Fold来执行此操作,但Fold仅传递前一个结果,这意味着它对一般线性递归问题不直接有用。

我想要一对函数来替换FoldFoldList,它们将指定数量的先前序列元素传递给函数,即

In[1] := MultiFoldList[f, {1,2}, {3,4,5}] (* for lack of a better name *)
Out[1]:= {1, 2, f[3,2,1], f[4,f[3,2,1],2], f[5,f[4,f[3,2,1],2],f[3,2,1]]}

我有一些东西可以做到这一点,但我在保存之前关闭了笔记本。所以,如果我自己重写它,我会发布它。

修改:为什么我没有使用RSolveMatrixPower来解决此问题。我的具体问题是我正在执行n-point Pade approximant以分析方式继续我只知道假想轴上的一定数量的点{z i }的函数。创建近似值的一部分是生成一组系数,一个 i ,这是另一个递归关系,然后被送入最终关系

A[n+1]== A[n] + (z - z[[n]]) a[[n+1]] A[n-1]

不适合RSolveMatrixPower,至少我能看到。

4 个答案:

答案 0 :(得分:5)

RecurrenceTable可以为您执行此任务吗?

根据之前的两个值找出重复的第1000个术语:

In[1]:= RecurrenceTable[{a[n] == a[n - 1] + a[n - 2], 
  a[1] == a[2] == 1}, a, 
   {n, {1000}}]

Out[1]= {4346655768693745643568852767504062580256466051737178040248172\
9089536555417949051890403879840079255169295922593080322634775209689623\
2398733224711616429964409065331879382989696499285160037044761377951668\
49228875}

修改:如果您的重复定义是由不希望评估非数字m和n的函数f[m, n]定义的,那么您可以使用Condition

In[2]:= f[m_, n_] /; IntegerQ[m] && IntegerQ[n] := m + n

f

表示的重复表
In[3]:= RecurrenceTable[{a[n] == f[a[n - 1], a[n - 2]], 
  a[1] == a[2] == 1}, a, {n, {1000}}]

Out[3]= {4346655768693745643568852767504062580256466051737178040248172\
9089536555417949051890403879840079255169295922593080322634775209689623\
2398733224711616429964409065331879382989696499285160037044761377951668\
49228875}

答案 1 :(得分:4)

多个折叠列表可能很有用,但它不是一种有效的方法来获得对大输入进行评估的线性重复。一些替代方案是使用RSolve或矩阵幂乘以初始值的向量。

如果第n个术语等于n-1个术语加上n-2个术语的两倍,这些方法适用于这个例子。

f[n_] =  f[n] /. RSolve[{f[n] == f[n - 1] + 2*f[n - 2], f[1] == 1, f[2] == 1},
  f[n], n][[1]]

Out [67] = 1/3( - ( - 1)^ n + 2 ^ n)

f2[n_Integer] := Last[MatrixPower[{{0, 1}, {2, 1}}, n - 2].{1, 1}]

{f[11], f2[11]}

出[79] = {683,683}

Daniel Lichtblau Wolfram Research

答案 2 :(得分:3)

几乎是一个令人费解的笑话,但你可以使用NestWhileList的副作用

fibo[n_] := 
  Module[{i = 1, s = 1}, 
   NestWhileList[ s &, 1, (s = Total[{##}]; ++i < n) &, 2]];  

性能不太好:

In[153]:= First@Timing@fibo[10000]
Out[153]= 0.235  

通过将任何整数更改为最后2,您可以将最后的k个结果传递给您的函数(在本例中为Total [])。

答案 3 :(得分:2)

LinearRecurrenceRecurrenceTable非常有用。

对于小内核,Daniel给出的MatrixPower方法是最快的。

对于某些问题,这些可能不适用,您可能需要自己动手。

我将使用Nest,因为我认为这适用于此问题,但类似的构造可以与Fold一起使用。

一个具体的例子,Fibonacci序列。这可能不是最干净的,但我相信你会继续看到效用。

fib[n_] :=
  First@Nest[{##2, # + #2} & @@ # &, {1, 1}, n - 1]

fib[15]

Fibonacci[15]

我在这里使用Apply@@),以便我可以使用##2等来处理元素,而不是#[[1]]等。使用SlotSequence删除旧列表中的第一个元素,同时Sequence将其放入新列表中。

如果您要一次操作整个列表,那么简单的Append[Rest@#, ...可能会更好。这两种方法都可以很容易地推广。例如,一个简单的线性重复实现是

 lr[a_, b_, n_Integer] := First@Nest[Append[Rest@#, a.#] &, b, n - 1]

 lr[{1,1}, {1,1}, 15]

(内核与内置的LinearRecurrence

的顺序相反