(TLDR:当您将方程作为纯 Python 列表传递时,SymPy 的 linsolve 函数无法求解线性方程组,该方程组是通过将有限差分法应用于 ODE BVP 生成的,但能够将所述方程列表放入其中SymPy 的 Matrix 函数。这可能是一个需要修复的错误,特别是考虑到在 SymPy 文档中,他们给您的示例让他们将列表作为参数传递给 linsolve。)
我有一个边值问题常微分方程,我打算使用有限差分法求解。在 SymPy 表示中,我的 ODE 是x*y(x).diff(x,2) + y(x).diff(x) + 500 = 0
、y(1)=600
和y(3.5)=25
。整个代码如下:
import sympy as sp
from numpy import *
from matplotlib.pyplot import *
y = sp.Function('y')
ti = time.time()
steps = 10
ys = [ y(i) for i in range(steps+1) ]
ys[0], ys[-1] = 600, 25
xs = linspace(1, 3.5, steps+1)
dx = xs[1] - xs[0]
eqns = [ xs[i]*(ys[i-1] - 2*ys[i] + ys[i+1])/dx**2 +
( ys[i+1] - ys[i-1] )/2/dx + 500
for i in range(1, steps) ]
ys[1:-1] = sp.linsolve(eqns, ys[1:-1]).args[0]
scatter(xs, ys)
tf = time.time()
print(f'Time elapsed: {tf-ti}')
对于十个步骤,这工作得很好。但是,如果我立即超过 11 步,SymPy 将不再能够求解线性方程组。试图绘制结果会抛出TypeError: can't convert expression to float
. 检查 y 值列表 ys 发现其中一个变量,特别是倒数第二个变量,并没有被 sympy 的 linsolve 求解,而是根据这个未求解的变量来求解其他变量的解。例如,如果我有 50 步,则倒数第二个变量是y(49)
,并且这在其他未知数的解决方案中具有特色,而不是例如2.02061855670103*y(49) - 26.1340206185567
. 相比之下,在我解决的另一个 BVP ODE 中,y(x).diff(x,2) + y(x).diff(x) + y(x) - 1
使用y(0)=1.5
和y(3)=2.5
,我想要 10 步、50 步还是 200 步都没有任何问题。它很好地解决了所有变量,但这似乎是一个特殊的例外,因为我在许多其他 ODE 中遇到了上述问题。
SymPy 的不一致在这里非常令人沮丧。唯一的安慰是,在我遇到这个问题之前,我实际上已经用我想要的不同数量的步骤解决了几次。我将eqns
变量包含在 sympy 的 Matrix 函数中,ys[1:-1] = sp.linsolve(sp.Matrix(eqns), ys[1:-1]).args[0]
因为它在终端中以这种方式显示得更好。但是对于在脚本文件中解决,我认为将其包装在里面sp.Matrix
是不必要的,我自然将其删除以简化事情。