SymPy - 在dsolve中使用许多参数时出现问题

use*_*497 5 python sympy dsolve

我正在使用SymPy版本0.7.3,并在使用dsolve函数时遇到一些问题.当输入方程具有太多参数时,似乎dsolve有困难.

我试过解决以下等式:

from sympy import *
p = Function('p')
t, u1, u2, u3, u4, u5 = symbols('t u1 u2 u3 u4 u5')
eq = Eq(Derivative(p(t),t), -(u3 + u4)*p(t) + exp(-t*(u1 + u2)))
eq
     Out: Derivative(p(t), t) == (-u3 - u4)*p(t) + exp(-t*(u1 + u2))
%time dsolve(eq)
Run Code Online (Sandbox Code Playgroud)

得到了:

CPU times: user 213.11 s, sys: 0.00 s, total: 213.11 s
Wall time: 213.12 s
       p(t) == (C1 + Piecewise((t*u1/(u1 + u2) + t*u2/(u1 + u2), u3 == u1 + u2 - u4), (-exp(t*u3)*exp(t*u4)/(u1*exp(t*u1)*exp(t*u2) + u2*exp(t*u1)*exp(t*u2) - u3*exp(t*u1)*exp(t*u2) - u4*exp(t*u1)*ex
p(t*u2)), True)))*exp(-t*(u3 + u4))
Run Code Online (Sandbox Code Playgroud)

(花了213.12秒!)

然后我用u5替换了u1 + u2:

eq = Eq(Derivative(p(t),t), -(u3 + u4)*p(t) + exp(-t*(u1 + u2))).subs(u1+u2, u5)
eq
     Out:Derivative(p(t), t) == (-u3 - u4)*p(t) + exp(-t*u5)
%time dsolve(eq)
Run Code Online (Sandbox Code Playgroud)

得到了:

CPU times: user 1.62 s, sys: 0.00 s, total: 1.62 s
Wall time: 1.62 s
        p(t) == (C1 + Piecewise((t, u3 == -u4 + u5), (exp(t*u3)*exp(t*u4)/(u3*exp(t*u5) + u4*exp(t*u5) - u5*exp(t*u5)), True)))*exp(-t*(u3 + u4))
Run Code Online (Sandbox Code Playgroud)

(仅1.62秒!)

我尝试过使用不同的提示,但没有帮助......

我还注意到,在更复杂的函数中,dsolve会崩溃,但是当替换一些常量参数时,它会很快运行.

你知道这种现象的原因是什么吗?有没有办法自动解决这个问题?

Ste*_*fan 2

我注意到 Mathematica 也存在同样的问题,限制表达式中符号的数量非常有利。我认为原因是大多数符号计算工具的工作原理是首先机械地应用通用方法来解决问题,然后尽可能地简化结果。

在一般解决方案中,简化器可能很难恢复某些符号仅出现在给定组合中,因此可以将其视为单个符号。因此简化器不必要地处理更大的搜索空间。此外,它必须确保正确处理所有边界情况(u1可能是 < 0、> 0、= 0、复杂,...?)

我发现在将问题交给符号求解器之前尽可能多地手动进行简化是非常有利的。手动将变量分组在一起(就像在您的示例中一样)是一种有用的技术。另一种技术是计算归一化,或将一个参数设置为 1。例如,在处理多项式时a x^2 + b x + c,大多数时候问题x^2 + B x + C与我们等效。(因为我们实际上确定a != 0,但忘记告诉求解器,对吧?...)但是对于求解器来说,如果符号变量的数量减少 1,则会产生很大的差异。

在某些时候,这些符号求解器肯定会变得足够聪明,可以在尝试解决问题之前将变量分组在一起。不过目前看来,还是需要人为干预。

另一方面,很难想象符号求解器会自动识别更复杂的变换来简化问题,例如从笛卡尔坐标切换到极坐标,或者对 、 等变量进行更改l=x+iy,r=x-iy这些变化并不明显,但已知对某些问题有好处。

更新

看来我们对这个问题能做的最好的事情就是设置a = u3 + u4和a + b = u1 + u2。除了将参数数量从 4 个减少到 2 个之外,现在 时 出现特殊情况b == 0,因此我们可以轻松指示求解器忽略它:

from sympy import *
p = Function('p')
t, a = symbols('t a')
b = symbols('b', nonzero=True)
eq = Eq(Derivative(p(t),t), -a*p(t) + exp(-(a + b)*t))
dsolve(eq)
# -> p(t) == (C1 - exp(-b*t)/b)*exp(-a*t)
# (0.75 s)
Run Code Online (Sandbox Code Playgroud)

因此,通过避免特殊情况来帮助求解器将求解时间再次缩短一半(我的系统上的时间与您的系统相似)。如果特殊情况b == 0实际上是相关的,人们可以很容易地从 的泰勒级数展开中恢复它exp(-b*t) ~ 1 - b*t。

一般来说,指定变量为实数、非零、严格大于零等对于避免求解器在特殊情况下挂起也非常有用。有时,实际上更好地分别解决x < 0、x > 0和 的问题x == 0(避免出现臭名昭著的sqrt(x^2)表达式,即求解器在不知道 的符号的情况下无法进一步简化x)。