Clear[x]
expr = Sum[x^i, {i, 15}]^30;
CoefficientList[expr, x]; // Timing
Coefficient[Expand@expr, x, 234]; // Timing
Coefficient[expr, x, 234]; // Timing
{0.047,空值}
{0.047,空值}
{4.93,空值}
帮助状态:
Coefficient
可以处理expr
是否以展开形式明确给出的情况。
Clear[x]
expr = Sum[x^i, {i, 15}]^30;
CoefficientList[expr, x]; // Timing
Coefficient[Expand@expr, x, 234]; // Timing
Coefficient[expr, x, 234]; // Timing
{0.047,空值}
{0.047,空值}
{4.93,空值}
帮助状态:
Coefficient
可以处理expr
是否以展开形式明确给出的情况。
Coefficient
需要如此缓慢?这里有一个可能让你的代码更快的技巧,但我不能保证它总是能正确运行:
ClearAll[withFastCoefficient];
SetAttributes[withFastCoefficient, HoldFirst];
withFastCoefficient[code_] :=
Block[{Binomial},
Binomial[x_, y_] := 10 /; ! FreeQ[Stack[_][[-6]], Coefficient];
code]
使用它,我们得到:
In[58]:= withFastCoefficient[Coefficient[expr,x,234]]//Timing
Out[58]= {0.172,3116518719381876183528738595379210}
这个想法是,Coefficient
在内部使用 Binomial
估计项数,如果项数小于 1000
,则扩展(调用 Expand
),您可以通过使用 Trace[..., TraceInternal->True]
进行检查。当它不扩展时,它会计算许多大量由零主导的系数列表的求和,这显然比扩展慢,适用于一系列表达式。我的做法是欺骗 Binomial
返回一个小数(10
),但我还尝试使其仅影响 Coefficient
内部调用的 Binomial
:
In[67]:= withFastCoefficient[f[Binomial[7,4]]Coefficient[expr,x,234]]
Out[67]= 3116518719381876183528738595379210 f[35]
我不能保证在代码的其他地方计算Binomial
时不会出现错误。
编辑
当然,一种更安全的替代方法是使用Villegas - Gayley技巧重新定义Coefficient
,展开其中的表达式并再次调用:
Unprotect[Coefficient];
Module[{inCoefficient},
Coefficient[expr_, args__] :=
Block[{inCoefficient = True},
Coefficient[Expand[expr], args]] /; ! TrueQ[inCoefficient]
];
Protect[Coefficient];
编辑2
我的第一个建议有一个优点,即我们定义了一个宏,可以在本地修改函数的属性,但缺点是不安全。我的第二个建议更加安全,但会在全局范围内修改Coefficient
,因此它将一直扩展,直到我们删除该定义。我们可以借助Internal`InheritedBlock
来实现两全其美,它可以创建给定函数的本地副本。以下是代码:
ClearAll[withExpandingCoefficient];
SetAttributes[withExpandingCoefficient, HoldFirst];
withExpandingCoefficient[code_] :=
Module[{inCoefficient},
Internal`InheritedBlock[{Coefficient},
Unprotect[Coefficient];
Coefficient[expr_, args__] :=
Block[{inCoefficient = True},
Coefficient[Expand[expr], args]] /; ! TrueQ[inCoefficient];
Protect[Coefficient];
code
]
];
使用方式与第一种情况类似:In[92]:= withExpandingCoefficient[Coefficient[expr,x,234]]//Timing
Out[92]= {0.156,3116518719381876183528738595379210}
然而,主要的Coefficient
函数保持不变:
In[93]:= DownValues[Coefficient]
Out[93]= {}
Coefficient
只有在认为有必要扩展时才会进行扩展,这确实避免了内存爆炸。我相信自从3版本以来就一直是这样的(我记得我大约在1995年左右开始使用它)。
避免扩展也可能更快。下面是一个简单的例子。
In[28]:= expr = Sum[x^i + y^j + z^k, {i, 15}, {j, 10}, {k, 20}]^20;
In[29]:= Coefficient[expr, x, 234]; // Timing
Out[29]= {0.81, Null}
但是这个在第8版中似乎会卡住,而且在开发版的Mathematica中至少需要半分钟(因为Expand
已经变了)。
Coefficient[Expand[expr], x, 234]; // Timing
可能需要添加一些启发式方法来查找不会爆炸的单变量。但似乎不是非常重要的事情。
Daniel Lichtblau
expr = Sum[x^i, {i, 15}]^30;
scoeff[ex_, var_, n_] /; PolynomialQ[ex, var] :=
ex + O[var]^(n + 1) /.
Verbatim[SeriesData][_, 0, c_List, nmin_, nmax_, 1] :>
If[nmax - nmin != Length[c], 0, c[[-1]]];
Timing[scoeff[expr, x, 234]]
看起来速度相当快。
ex + O[var]^(n + 1)
。 - Mr.Wizard在跟随Rolf Mertig的答案做出一些实验后,这似乎是处理像Sum[x^i, {i, 15}]^30
这样类型表达式的最快方法:
SeriesCoefficient[expr, {x, 0, 234}]
Coefficient
缓慢的原因(重点在于Coefficient
和“为什么缓慢”),而不是可能更快的替代方法。 - Leonid Shifrin
Coefficient
算法会以速度为代价来换取能够处理极长展开式的表达式的能力?顺便说一下,你的电脑比我的快4.5倍。 - Szabolcs(1 + x)^50000
上,Coefficient
更加节省内存。有没有什么合理的方法可以让一个调用Coefficient
的通用函数更快一些?是否有某种半展开形式或Method
选项可以在这些选项之间给我一个平衡点? - Mr.Wizardexpr = Sum[x ^ i,{i,30}] ^ 20;
时,它们之间有670的因素。 就内存使用而言,我没有注意到太大的区别,但系统监视器不是非常敏感。 - Sjoerd C. de VriesRadon[]
的更改。 - Szabolcs