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

发布于 2024-10-21 22:24:30 字数 1390 浏览 2 评论 0原文

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

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

,对于我正在使用的序列,这正是我所做的。 (定义位于 Module 内部,因此我不会污染 Global`。)但是,我将将此与 210 - 213 点,因此当我只需要最后一项而不需要任何先前元素时,我担心额外的开销。我想使用 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 点 Pade 近似 分析地继续一个函数,我只知道虚轴上的一组点,{zi}。创建近似值的一部分是生成一组系数 ai,这是另一种递归关系,然后将其输入到最终关系中,

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

该关系不适合 RSolve 也不是 MatrixPower,至少我可以看到。

I have a linear recurrence problem where the next element relies on more than just the prior value, e.g. the Fibonacci sequence. One method calculating the nth element is to define it via a function call, e.g.

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

and for the sequence I'm working with, that is exactly what I do. (The definition is inside of a Module so I don't pollute Global`.) However, I am going to be using this with 210 - 213 points, so I'm concerned about the extra overhead when I just need the last term and none of the prior elements. I'd like to use Fold to do this, but Fold only passes the immediately prior result which means it is not directly useful for a general linear recurrence problem.

I'd like a pair of functions to replace Fold and FoldList that pass a specified number of prior sequence elements to the function, i.e.

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

I had something that did this, but I closed the notebook prior to saving it. So, if I rewrite it on my own, I'll post it.

Edit: as to why I am not using RSolve or MatrixPower to solve this. My specific problem is I'm performing an n-point Pade approximant to analytically continue a function I only know at a set number of points on the imaginary axis, {zi}. Part of creating the approximant is to generate a set of coefficients, ai, which is another recurrence relation, that are then fed into the final relationship

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

which is not amenable to either RSolve nor MatrixPower, at least that I can see.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

柏林苍穹下 2024-10-28 22:24:30

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}

编辑:如果您的循环是由函数 f[m, n] 定义的,而该函数不喜欢得到评估非数字 m 和 n,那么您可以使用条件

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}

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}
2024-10-28 22:24:30

多个折叠列表可能很有用,但它不是评估大型输入的线性递归的有效方法。有几种替代方法是使用 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]]

输出[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
沃尔夫勒姆研究公司

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

飘然心甜 2024-10-28 22:24:30

几乎是一个令人费解的笑话,但您可以使用 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[])。

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[]).

城歌 2024-10-28 22:24:30

LinearRecurrenceRecurrenceTable 非常有用。

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

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

我将使用 Nest,因为我相信这适合解决这个问题,但类似的构造也可以用于 Fold。

一个具体的例子,斐波那契数列。这可能不是最干净的,但我相信随着我的继续,你会看到这个实用程序。

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 的顺序相反)

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)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文