Using Fold to calculate the result of linear recurrence relying on multiple previous values

こ雲淡風輕ζ 提交于 2019-12-04 11:55:31

Can RecurrenceTable perform this task for you?

Find the 1000th term in a recurrence depending on two previous values:

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}

Edit: If your recurrence is defined by a function f[m, n] that doesn't like to get evaluated for non-numeric m and n, then you could use Condition:

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

The recurrence table in terms of 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}

A multiple foldlist can be useful but it would not be an efficient way to get linear recurrences evaluated for large inputs. A couple of alternatives are to use RSolve or matrix powers times a vector of initial values.

Here are these methods applied to example if nth term equal to n-1 term plus two times n-2 term.

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]}

Out[79]= {683, 683}

Daniel Lichtblau Wolfram Research

Almost a convoluted joke, but you could use a side-effect of NestWhileList

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

Not too bad performance:

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

By changing the last 2 by any integer you may pass the last k results to your function (in this case Total[]).

LinearRecurrence and RecurrenceTable are very useful.

For small kernels, the MatrixPower method that Daniel gave is the fastest.

For some problems these may not be applicable, and you may need to roll your own.

I will be using Nest because I believe that is appropriate for this problem, but a similar construct can be used with Fold.

A specific example, the Fibonacci sequence. This may not be the cleanest possible for that, but I believe you will see the utility as I continue.

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

fib[15]

Fibonacci[15]

Here I use Apply (@@) so that I can address elements with #, #2, etc., rathern than #[[1]] etc. I use SlotSequence to drop the first element from the old list, and Sequence it into the new list at the same time.

If you are going to operate on the entire list at once, then a simple Append[Rest@#, ... may be better. Either method can be easily generalized. For example, a simple linear recurrence implementation is

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

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

(the kernel is in reverse order from the built in LinearRecurrence)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!