使用sagemath或sympy将n阶微分方程简化为一阶方程组

使用sagemath或sympy将n阶微分方程简化为一阶方程组,math,numerical-methods,sympy,ode,sage,Math,Numerical Methods,Sympy,Ode,Sage,我想把一个n阶常微分方程化为一阶方程组。这是为数值分析做准备。我使用Symphy和Sagemath来计算计算机代数,但我还没有在它们中找到任何函数来进行这种类型的约简。我不确定是否有其他人可以指出Symphy或Sagemath中是否存在此功能 这方面的一个例子是减少等式: x''' - 2x'' + x' = 0 对于一阶方程组: [0 1 0 0 0 1 0 -1 2] 我不使用Sympy或Sagemath。但是在他们的API文档中寻找拉普拉斯或Z变换 如果找到了,那么你就

我想把一个n阶常微分方程化为一阶方程组。这是为数值分析做准备。我使用Symphy和Sagemath来计算计算机代数,但我还没有在它们中找到任何函数来进行这种类型的约简。我不确定是否有其他人可以指出Symphy或Sagemath中是否存在此功能

这方面的一个例子是减少等式:

x''' - 2x'' + x' = 0 
对于一阶方程组:

[0  1 0 
 0  0 1 
 0 -1 2]

我不使用Sympy或Sagemath。但是在他们的API文档中寻找拉普拉斯或Z变换

  • 如果找到了,那么你就没有那么多工作要做了
  • 如果没有,您必须自己找到lib或编写它
用拉普拉斯方法求解微分系统

  • 我有一段时间没用这个了,所以用一些数学书检查一下
  • 无论如何,如果我没记错的话
  • 拉普拉斯变换将积分函数转换为线性函数(时域到s域)
  • 微分函数必须有连续的导数/积分才能工作
  • 要解决您的问题,请执行以下操作:

  • 通过积分将所有微分转换为积分
  • 应用拉普拉斯变换
    • 这将把微分系统转换成多项式系统
  • 解多项式方程组
  • 应用拉普拉斯逆变换
    • 这将部分结果转换为解决方案的结果
  • 通过probem定义的边案例求解积分常数
  • 另外再找一个例子

  • 关于这个话题,谷歌有很多东西
用Z求微分系统

  • 从未这样做过,但如果与拉普拉斯变换的解不同,则应相似

问题是,首先,您如何将微分方程编码为字符串。因为编码已经比写下一阶系统更复杂了

一般手动程序是设置x1=x,x2=x',x3=x'',然后注意

x1'=x'=x2
x2'=x''=x3
x3'=x'''= 2*x'' - x' = 2*x3 - x2
然后将生成的系统转换为矩阵形式


另请参见多项式的伴随矩阵,这也是(直至换位)高阶线性微分方程系统矩阵的一般形式。

据我所知,Symphy没有直接执行此操作的函数,但手动执行此操作非常简单

我假设你总是希望你的两个附加方程的形式是
y=x'
z=y'

首先,让我们创建ODE(在SymPy中,表达式被自动假定为等于零,因此为了简化事情,我们不必担心
=0
部分)。我假设您的独立变量是
t

In [4]: t = symbols('t')

In [7]: x, y, z = symbols('x y z', cls=Function)

In [6]: ode = x(t).diff(t, t) - 2*x(t).diff(t) + x(t)

In [13]: ode = x(t).diff(t, 3) - 2*x(t).diff(t, t) + x(t).diff(t)

In [14]: ode
Out[14]:
               2           3
d             d           d
──(x(t)) - 2⋅───(x(t)) + ───(x(t))
dt             2           3
             dt          dt
现在,如果我们将
x'
替换为
y

In [15]: ode.subs(x(t).diff(t), y(t))
Out[15]:
                      2
         d           d
y(t) - 2⋅──(y(t)) + ───(y(t))
         dt           2
                    dt
我们看到它还将
x'
替换为
y'
。因此,让我们用
z
替换
y'

In [16]: ode = ode.subs(x(t).diff(t), y(t)).subs(y(t).diff(t), z(t))

In [17]: ode
Out[17]:
                d
y(t) - 2⋅z(t) + ──(z(t))
                dt
现在我们的系统是

In [20]: Matrix([y(t), z(t), solve(ode, z(t).diff(t))[0]])
Out[20]:
⎡     y(t)     ⎤
⎢              ⎥
⎢     z(t)     ⎥
⎢              ⎥
⎣-y(t) + 2⋅z(t)⎦
请注意,我们已经知道
x'=y
y'=z
,所以我们直接使用它们,但我们使用
solve()
来获得关于
z'
的替换ODE

如果需要系数,一个简单的技巧是采用雅可比矩阵:

In [23]: M = Matrix([y(t), z(t), solve(ode, z(t).diff(t))[0]]).jacobian([x(t), y(t), z(t)])

In [24]: M
Out[24]:
⎡0  1   0⎤
⎢        ⎥
⎢0  0   1⎥
⎢        ⎥
⎣0  -1  2⎦

我将把把它包装成单个函数
ode_to_系统(ode[x(t),y(t),z(t)])
留给读者作为练习

我写了一个实验库来处理常微分方程组:

[0  1 0 
 0  0 1 
 0 -1 2]

它是基于Symphy的,不幸的是,我没有写太多文档,但我提供了很多示例。我将按如下方式处理你的等式:

from sympy import *
from symodesys.odesys import AnyOrderODESystem

t = Symbol('t')
x = Function('x')(t)

D1x = x.diff(t)
D2x = x.diff(t, 2)
D3x = x.diff(t, 3)

expr = Eq(D3x, 2*D2x - D1x)

odesys = AnyOrderODESystem.from_list_of_eqs([expr])
print(odesys.all_depv)
redsys = odesys.reduce_to_sys_of_first_order()
print(redsys.all_depv)
print(redsys.f)
哪些产出:

[x(t)]
[x(t), x_h1(t), x_h2(t)]
OrderedDict([(x(t), x_h1(t)), (x_h1(t), x_h2(t)), (x_h2(t), -x_h1(t) + 2*x_h2(t))])
添加一些额外的行可以为您提供一个gui来试验初始值问题 (参见溶液曲线作为初始值的函数)

这给了你:


安装某些依赖项有点棘手,如果需要帮助,请添加注释

尝试搜索拉普拉斯变换或Z变换,这是常用的purpose@Spektre谢谢你的来信。我不确定拉普拉斯变换在这里是否正确。所以我想拿一个二阶或三阶微分方程,把它转换成一阶系统。实际上,我想使用计算机代数工具,如Sympy或Sage,这样我就可以检查自己的代数错误。使用拉普拉斯变换可以作为求解方程的一种方法,但我不确定它能否将三阶齐次微分方程转化为一阶微分方程组。也许你可以解释一下你的意思。补充答案(这确实是一个注释,但在注释中它是不可读的)@Spektre OP正在寻找将一个常微分方程转换为一阶常微分方程组的方法,该方法可以通过数值解算,例如使用特征值方法。有关一些示例,请参见。无需对字符串进行编码。这就是使用SymPy或Sage的全部意义,它可以直接表示符号对象。您需要将ODE编码为某种代码对象,作为输入,以CAS可以解析和解释的形式。也就是说,把方程从纸上转移到计算机上。即使这是微不足道的,根据方法的不同,所做的工作也将相当于手动建立一阶系统。