ODE¶
备注
对于一个面向初学者的专注于解决常微分方程的指南,请参阅 代数求解常微分方程 (ODE)。
用户功能¶
这些是使用 from sympy import *
导入到全局命名空间的函数。这些函数(与下面的 提示函数 不同)旨在供 SymPy 的普通用户使用。
- sympy.solvers.ode.dsolve(
- eq,
- func=None,
- hint='default',
- simplify=True,
- ics=None,
- xi=None,
- eta=None,
- x0=0,
- n=6,
- **kwargs,
解决任何(支持的)类型的常微分方程和常微分方程组。
示例
>>> from sympy import Function, dsolve, Eq, Derivative, sin, cos, symbols >>> from sympy.abc import x >>> f = Function('f') >>> dsolve(Derivative(f(x), x, x) + 9*f(x), f(x)) Eq(f(x), C1*sin(3*x) + C2*cos(3*x))
>>> eq = sin(x)*cos(f(x)) + cos(x)*sin(f(x))*f(x).diff(x) >>> dsolve(eq, hint='1st_exact') [Eq(f(x), -acos(C1/cos(x)) + 2*pi), Eq(f(x), acos(C1/cos(x)))] >>> dsolve(eq, hint='almost_linear') [Eq(f(x), -acos(C1/cos(x)) + 2*pi), Eq(f(x), acos(C1/cos(x)))] >>> t = symbols('t') >>> x, y = symbols('x, y', cls=Function) >>> eq = (Eq(Derivative(x(t),t), 12*t*x(t) + 8*y(t)), Eq(Derivative(y(t),t), 21*x(t) + 7*t*y(t))) >>> dsolve(eq) [Eq(x(t), C1*x0(t) + C2*x0(t)*Integral(8*exp(Integral(7*t, t))*exp(Integral(12*t, t))/x0(t)**2, t)), Eq(y(t), C1*y0(t) + C2*(y0(t)*Integral(8*exp(Integral(7*t, t))*exp(Integral(12*t, t))/x0(t)**2, t) + exp(Integral(7*t, t))*exp(Integral(12*t, t))/x0(t)))] >>> eq = (Eq(Derivative(x(t),t),x(t)*y(t)*sin(t)), Eq(Derivative(y(t),t),y(t)**2*sin(t))) >>> dsolve(eq) {Eq(x(t), -exp(C1)/(C2*exp(C1) - cos(t))), Eq(y(t), -1/(C1 - cos(t)))}
- sympy.solvers.ode.systems.dsolve_system(
- eqs,
- funcs=None,
- t=None,
- ics=None,
- doit=False,
- simplify=True,
解决任何(支持的)常微分方程组
- 参数:
- eqs列表
待解的ODE系统
- 函数列表或无
构成ODE系统的因变量列表
- t符号或无
ODEs 系统中的自变量
- ics字典或无
ODEs 系统的初始边界/条件集
- 执行布尔值
如果为真,评估解决方案。默认值为 True。如果积分评估耗时过长和/或不需要,可以设置为 false。
- simplify: Boolean
简化系统的解决方案。默认值为 True。如果简化过程耗时过长和/或不需要,可以设置为 false。
- 返回:
- 方程列表的列表
- Raises:
- NotImplementedError
当常微分方程系统无法通过此函数求解时。
- ValueError
当传递的参数不符合所需的形式时。
示例
>>> from sympy import symbols, Eq, Function >>> from sympy.solvers.ode.systems import dsolve_system >>> f, g = symbols("f g", cls=Function) >>> x = symbols("x")
>>> eqs = [Eq(f(x).diff(x), g(x)), Eq(g(x).diff(x), f(x))] >>> dsolve_system(eqs) [[Eq(f(x), -C1*exp(-x) + C2*exp(x)), Eq(g(x), C1*exp(-x) + C2*exp(x))]]
你也可以传递常微分方程系统的初始条件:
>>> dsolve_system(eqs, ics={f(0): 1, g(0): 0}) [[Eq(f(x), exp(x)/2 + exp(-x)/2), Eq(g(x), exp(x)/2 - exp(-x)/2)]]
可选地,您可以传递系统要解的因变量和自变量:
>>> funcs = [f(x), g(x)] >>> dsolve_system(eqs, funcs=funcs, t=x) [[Eq(f(x), -C1*exp(-x) + C2*exp(x)), Eq(g(x), C1*exp(-x) + C2*exp(x))]]
让我们来看一个隐式常微分方程系统:
>>> eqs = [Eq(f(x).diff(x)**2, g(x)**2), Eq(g(x).diff(x), g(x))] >>> dsolve_system(eqs) [[Eq(f(x), C1 - C2*exp(x)), Eq(g(x), C2*exp(x))], [Eq(f(x), C1 + C2*exp(x)), Eq(g(x), C2*exp(x))]]
- sympy.solvers.ode.classify_ode(
- eq,
- func=None,
- dict=False,
- ics=None,
- *,
- prep=True,
- xi=None,
- eta=None,
- n=None,
- **kwargs,
返回一个可能的
dsolve()
分类元组用于一个常微分方程。元组是有序的,因此第一个项目是
dsolve()
默认用于求解ODE的分类。通常情况下,列表中靠前的分类会比靠后的分类更快地产生更好的解决方案,但总会有例外。要让dsolve()
使用不同的分类,请使用dsolve(ODE, func, hint=<classification>)
。另请参阅dsolve()
文档字符串,了解您可以使用的不同元提示。如果
dict
为真,classify_ode()
将返回一个hint:match
表达式项的字典。这是为dsolve()
的内部使用而设计的。请注意,由于字典的顺序是任意的,这很可能不会与元组的顺序相同。你可以通过执行
help(ode.ode_hintname)
来获取不同提示的帮助,其中hintname
是提示的名称,不包括_Integral
。参见
allhints
或ode
文档字符串,以获取所有支持的提示列表,这些提示可以从classify_ode()
返回。注释
这些是关于提示名称的备注。
_Integral
如果一个分类以
_Integral
结尾,它将返回一个包含未求值的Integral
类的表达式。请注意,如果integrate()
无法求积分,提示可能会这样做,尽管仅使用_Integral
会快得多。实际上,_Integral
提示总是比没有_Integral
的相应提示快,因为integrate()
是一个昂贵的例程。如果dsolve()
挂起,可能是因为integrate()
在一个困难或不可能的积分上挂起。尝试使用_Integral
提示或all_Integral
来让它返回一些内容。注意,有些提示没有对应的
_Integral
版本。这是因为integrate()
在解决这些方法的常微分方程时并未使用。例如,具有常系数的 \(n\) 阶线性齐次常微分方程不需要积分来求解,因此没有nth_linear_homogeneous_constant_coeff_Integrate
提示。你可以通过执行expr.doit()
轻松计算表达式中任何未计算的Integral
。序数
一些提示包含序数,例如
1st_linear
。这是为了帮助区分它们与其他提示,以及可能尚未实现的其他方法。如果一个提示中包含nth
,例如nth_linear
提示,这意味着所使用的方法适用于任何阶的常微分方程。indep
和dep
一些提示包含
indep
或dep
这样的词。它们分别引用自变量和因变函数。例如,如果一个ODE是关于 \(f(x)\) 的,那么indep
将引用 \(x\),而dep
将引用 \(f\)。subs
如果一个提示中包含单词
subs
,这意味着通过将单词subs
后面的表达式替换为一个单一的虚拟变量来求解ODE。这通常是根据上述的indep
和dep
来进行的。替换后的表达式将仅使用Python对象名称允许的字符书写,这意味着运算符将被拼写出来。例如,indep
/dep
将被写为indep_div_dep
。coeff
提示中的单词
coeff
指的是 ODE 中某物的系数,通常是导数项的系数。有关更多信息,请参阅各个方法的文档字符串(help(ode)
)。这与coefficients
形成对比,如undetermined_coefficients
中的coefficients
,它指的是一种方法的通用名称。_best
有多种基本解决方法的方法将为每种子方法提供一个提示,并有一个
_best
元分类。这将评估所有提示并返回最佳的,使用与普通best
元提示相同的考虑因素。示例
>>> from sympy import Function, classify_ode, Eq >>> from sympy.abc import x >>> f = Function('f') >>> classify_ode(Eq(f(x).diff(x), 0), f(x)) ('nth_algebraic', 'separable', '1st_exact', '1st_linear', 'Bernoulli', '1st_homogeneous_coeff_best', '1st_homogeneous_coeff_subs_indep_div_dep', '1st_homogeneous_coeff_subs_dep_div_indep', '1st_power_series', 'lie_group', 'nth_linear_constant_coeff_homogeneous', 'nth_linear_euler_eq_homogeneous', 'nth_algebraic_Integral', 'separable_Integral', '1st_exact_Integral', '1st_linear_Integral', 'Bernoulli_Integral', '1st_homogeneous_coeff_subs_indep_div_dep_Integral', '1st_homogeneous_coeff_subs_dep_div_indep_Integral') >>> classify_ode(f(x).diff(x, 2) + 3*f(x).diff(x) + 2*f(x) - 4) ('factorable', 'nth_linear_constant_coeff_undetermined_coefficients', 'nth_linear_constant_coeff_variation_of_parameters', 'nth_linear_constant_coeff_variation_of_parameters_Integral')
- sympy.solvers.ode.checkodesol(
- ode,
- sol,
- func=None,
- order='auto',
- solve_for_func=True,
将
sol
代入ode
并检查结果是否为0
。当
func
是一个函数时,例如 \(f(x)\),或者是一个函数列表,例如 \([f(x), g(x)]\),当 \(ode\) 是一个常微分方程系统时,这将会起作用。sol
可以是一个单一的解或一个解的列表。每个解可能是一个Equality
,即解满足的等式,例如Eq(f(x), C1), Eq(f(x) + C1, 0)
;或者仅仅是一个Expr
,例如f(x) - C1
。在大多数情况下,不需要显式地识别函数,但如果无法从原始方程推断出函数,则可以通过func
参数提供。如果传递了一个解决方案序列,将使用相同类型的容器来返回每个解决方案的结果。
它按顺序尝试以下方法,直到找到零等价为止:
将 \(f\) 的解代入原方程。这仅在
ode
已求解 \(f\) 时有效。除非solve_for_func == False
,否则它将首先尝试求解。取解的 \(n\) 阶导数,其中 \(n\) 是
ode
的阶数,并检查其是否等于解。这仅适用于精确的常微分方程。取解的第1、2、…、\(n`阶导数,每次求解该阶导数`f`(这总是可能的,因为`f`是一个线性算子)。然后按相反顺序将每个导数代入``ode`\)。
此函数返回一个元组。元组中的第一项在替换结果为
0
时为True
,否则为False
。元组中的第二项是替换的结果。如果第一项为True
,则第二项应始终为0
。有时,即使表达式恒等于0
,此函数也会返回False
。这种情况发生在simplify()
未能将表达式简化为0
时。如果此函数返回的表达式恒等于零,则sol
确实是ode
的解。如果这个函数看起来挂起,可能是因为进行了复杂的简化。
要使用此功能进行测试,请测试元组的第一个项目。
示例
>>> from sympy import (Eq, Function, checkodesol, symbols, ... Derivative, exp) >>> x, C1, C2 = symbols('x,C1,C2') >>> f, g = symbols('f g', cls=Function) >>> checkodesol(f(x).diff(x), Eq(f(x), C1)) (True, 0) >>> assert checkodesol(f(x).diff(x), C1)[0] >>> assert not checkodesol(f(x).diff(x), x)[0] >>> checkodesol(f(x).diff(x, 2), x**2) (False, 2)
>>> eqs = [Eq(Derivative(f(x), x), f(x)), Eq(Derivative(g(x), x), g(x))] >>> sol = [Eq(f(x), C1*exp(x)), Eq(g(x), C2*exp(x))] >>> checkodesol(eqs, sol) (True, [0, 0])
- sympy.solvers.ode.homogeneous_order(eq, *symbols)[源代码][源代码]¶
如果 \(g\) 是齐次的,则返回阶数 \(n\),如果不是齐次的,则返回
None
。确定一个函数是否是齐次的,如果是,确定其齐次阶数。函数 \(f(x, y, \cdots)\) 是 \(n\) 阶齐次的,如果 \(f(t x, t y, \cdots) = t^n f(x, y, \cdots)\)。
If the function is of two variables, \(F(x, y)\), then \(f\) being homogeneous of any order is equivalent to being able to rewrite \(F(x, y)\) as \(G(x/y)\) or \(H(y/x)\). This fact is used to solve 1st order ordinary differential equations whose coefficients are homogeneous of the same order (see the docstrings of
HomogeneousCoeffSubsDepDivIndep
andHomogeneousCoeffSubsIndepDivDep
).符号可以是函数,但函数的每个参数都必须是符号,并且表达式中出现的函数参数必须与符号列表中的参数匹配。如果声明的函数出现的参数与符号列表中的参数不同,则返回
None
。示例
>>> from sympy import Function, homogeneous_order, sqrt >>> from sympy.abc import x, y >>> f = Function('f') >>> homogeneous_order(f(x), f(x)) is None True >>> homogeneous_order(f(x,y), f(y, x), x, y) is None True >>> homogeneous_order(f(x), f(x), x) 1 >>> homogeneous_order(x**2*f(x)/sqrt(x**2+f(x)**2), x, f(x)) 2 >>> homogeneous_order(x**2+f(x), x, f(x)) is None True
- sympy.solvers.ode.infinitesimals(
- eq,
- func=None,
- order=None,
- hint='default',
- match=None,
常微分方程的无穷小函数,\(\xi(x,y)\) 和 \(\eta(x,y)\),是使得微分方程不变的点变换的李群的无穷小。因此,微分方程 \(y'=f(x,y)\) 将承认一个李群 \(x^*=X(x,y;\varepsilon)=x+\varepsilon\xi(x,y)\),\(y^*=Y(x,y;\varepsilon)=y+\varepsilon\eta(x,y)\) 使得 \((y^*)'=f(x^*, y^*)\)。可以通过坐标变换,变为 \(r(x,y)\) 和 \(s(x,y)\),使得这个李群成为平移群,\(r^*=r\) 和 \(s^*=s+\varepsilon\)。它们是新坐标系坐标曲线的切线。
考虑变换 \((x, y) \to (X, Y)\),使得微分方程保持不变。\(\xi\) 和 \(\eta\) 是变换后的坐标 \(X\) 和 \(Y\) 在 \(\varepsilon=0\) 处的切线。
\[\left(\frac{\partial X(x,y;\varepsilon)}{\partial\varepsilon}\right)|_{\varepsilon=0} = \xi,\left(\frac{\partial Y(x,y;\varepsilon)}{\partial\varepsilon}\right)|_{\varepsilon=0} = \eta,\]可以通过求解以下偏微分方程找到无穷小量:
>>> from sympy import Function, Eq, pprint >>> from sympy.abc import x, y >>> xi, eta, h = map(Function, ['xi', 'eta', 'h']) >>> h = h(x, y) # dy/dx = h >>> eta = eta(x, y) >>> xi = xi(x, y) >>> genform = Eq(eta.diff(x) + (eta.diff(y) - xi.diff(x))*h ... - (xi.diff(y))*h**2 - xi*(h.diff(x)) - eta*(h.diff(y)), 0) >>> pprint(genform) /d d \ d 2 d d d |--(eta(x, y)) - --(xi(x, y))|*h(x, y) - eta(x, y)*--(h(x, y)) - h (x, y)*--(xi(x, y)) - xi(x, y)*--(h(x, y)) + --(eta(x, y)) = 0 \dy dx / dy dy dx dx
解决上述提到的偏微分方程并非易事,只能通过为 \(\xi\) 和 \(\eta\) 做出智能假设(启发式方法)来解决。一旦找到一个无穷小量,寻找更多启发式方法的尝试就会停止。这样做是为了优化求解微分方程的速度。如果需要所有无穷小量的列表,应将
hint
标记为all
,这将给出所有无穷小量的完整列表。如果需要找到特定启发式的无穷小量,可以将其作为标志传递给hint
。参考文献
通过对称群求解微分方程,John Starrett,第1页 - 第14页
示例
>>> from sympy import Function >>> from sympy.solvers.ode.lie_group import infinitesimals >>> from sympy.abc import x >>> f = Function('f') >>> eq = f(x).diff(x) - x**2*f(x) >>> infinitesimals(eq) [{eta(x, f(x)): exp(x**3/3), xi(x, f(x)): 0}]
- sympy.solvers.ode.checkinfsol(
- eq,
- infinitesimals,
- func=None,
- order=None,
此函数用于检查给定的无穷小量是否是给定的一阶微分方程的实际无穷小量。此方法特定于常微分方程的李群求解器。
截至目前,它仅通过在偏微分方程中代入无穷小量来进行检查。
\[ \begin{align}\begin{aligned}\frac{\partial \eta}{\partial x} + \left(\frac{\partial \eta}{\partial y} - \frac{\partial \xi}{\partial x}\right)*h - \frac{\partial \xi}{\partial y}*h^{2} - \xi\frac{\partial h}{\partial x} - \eta\frac{\partial h}{\partial y} = 0\\\frac{\partial \eta}{\partial x} + \left(\frac{\partial \eta}{\partial y} - \frac{\partial \xi}{\partial x}\right)*h - \frac{\partial \xi}{\partial y}*h^{2} - \xi\frac{\partial h}{\partial x} - \eta\frac{\partial h}{\partial y} = 0\end{aligned}\end{align} \]其中 \(\eta\) 和 \(\xi\) 是无穷小量,且 \(h(x,y) = \frac{dy}{dx}\)
无穷小量应以字典列表的形式给出
[{xi(x, y): inf, eta(x, y): inf}]
,对应于函数 infinitesimals 的输出。它返回一个形式为[(True/False, sol)]
的值列表,其中sol
是在 PDE 中代入无穷小量后得到的值。如果为True
,则sol
应为 0。
- sympy.solvers.ode.constantsimp(expr, constants)[源代码][源代码]¶
简化包含任意常量的表达式。
此函数专门编写以与
dsolve()
一起工作,并不打算用于一般用途。简化是通过将任意常数“吸收”到其他任意常数、数字和符号中来完成的,这些常数、数字和符号与它们不是独立的。
这些符号必须全部具有相同的名字并在其后加上数字,例如,
C1
,C2
,C3
。这里的symbolname
将是 ‘C
’,startnumber
将是 1,而endnumber
将是 3。如果任意常数与变量x
无关,那么独立符号将是x
。不需要指定依赖函数,例如f(x)
,因为它已经包含了独立符号x
。因为术语被“吸收”到任意常数中,并且在简化后常数会被重新编号,所以 expr 中的任意常数不一定等于返回结果中同名的常数。
如果两个或多个任意常数相加、相乘或相互取幂,它们首先会被合并成一个单一的任意常数。然后,如有必要,这个新常数会与其他项合并。
常量的吸收是在有限的帮助下完成的:
Add
的项被收集起来,以尝试合并常数,因此 \(e^x (C_1 \cos(x) + C_2 \cos(x))\) 将简化为 \(e^x C_1 \cos(x)\);指数为
Add
的幂会被展开,因此 \(e^{C_1 + x}\) 将被简化为 \(C_1 e^x\)。
使用
constant_renumber()
在简化后重新编号常量,否则常量上可能会出现任意数字,例如 \(C_1 + C_3 x\)。在极少数情况下,一个常数可以被“简化”为两个常数。每个微分方程的解应该有与微分方程阶数相同数量的任意常数。这里的结果在技术上是正确的,但例如,在一个表达式中可能有 \(C_1\) 和 \(C_2\),而实际上 \(C_1\) 等于 \(C_2\)。在这种情况下请自行判断,并利用在
dsolve()
中使用提示的能力。示例
>>> from sympy import symbols >>> from sympy.solvers.ode.ode import constantsimp >>> C1, C2, C3, x, y = symbols('C1, C2, C3, x, y') >>> constantsimp(2*C1*x, {C1, C2, C3}) C1*x >>> constantsimp(C1 + 2 + x, {C1, C2, C3}) C1 + x >>> constantsimp(C1*C2 + 2 + C2 + C3*x, {C1, C2, C3}) C1 + C3*x
提示函数¶
这些函数旨在供 dsolve()
和其他内部使用。与上面的 User Functions 不同,这些函数并不打算供普通 SymPy 用户日常使用。相反,应该使用诸如 dsolve()
这样的函数。尽管如此,这些函数的文档字符串中包含了关于各种 ODE 求解方法的有用信息。因此,它们在这里被记录下来。
- sympy.solvers.ode.allhints = ('factorable', 'nth_algebraic', 'separable', '1st_exact', '1st_linear', 'Bernoulli', '1st_rational_riccati', 'Riccati_special_minus2', '1st_homogeneous_coeff_best', '1st_homogeneous_coeff_subs_indep_div_dep', '1st_homogeneous_coeff_subs_dep_div_indep', 'almost_linear', 'linear_coefficients', 'separable_reduced', '1st_power_series', 'lie_group', 'nth_linear_constant_coeff_homogeneous', 'nth_linear_euler_eq_homogeneous', 'nth_linear_constant_coeff_undetermined_coefficients', 'nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients', 'nth_linear_constant_coeff_variation_of_parameters', 'nth_linear_euler_eq_nonhomogeneous_variation_of_parameters', 'Liouville', '2nd_linear_airy', '2nd_linear_bessel', '2nd_hypergeometric', '2nd_hypergeometric_Integral', 'nth_order_reducible', '2nd_power_series_ordinary', '2nd_power_series_regular', 'nth_algebraic_Integral', 'separable_Integral', '1st_exact_Integral', '1st_linear_Integral', 'Bernoulli_Integral', '1st_homogeneous_coeff_subs_indep_div_dep_Integral', '1st_homogeneous_coeff_subs_dep_div_indep_Integral', 'almost_linear_Integral', 'linear_coefficients_Integral', 'separable_reduced_Integral', 'nth_linear_constant_coeff_variation_of_parameters_Integral', 'nth_linear_euler_eq_nonhomogeneous_variation_of_parameters_Integral', 'Liouville_Integral', '2nd_nonlinear_autonomous_conserved', '2nd_nonlinear_autonomous_conserved_Integral')¶
内置的不可变序列。
如果没有给出参数,构造函数将返回一个空元组。如果指定了可迭代对象,则元组将使用可迭代对象的项进行初始化。
如果参数是一个元组,返回值是同一个对象。
- sympy.solvers.ode.ode.odesimp(ode, eq, func, hint)[源代码][源代码]¶
简化常微分方程的解法,包括尝试求解
func
并运行constantsimp()
。它可能会利用提示返回的解决方案类型知识来应用额外的简化。
如果提示不是
_Integral
提示,它还会尝试整合表达式中的任何Integral
。此函数对由
dsolve()
返回的表达式不应产生影响,因为dsolve()
已经调用了odesimp()
,但各个提示函数并不调用dsolve()
包装器会调用)。因此,此函数主要设计用于内部使用。示例
>>> from sympy import sin, symbols, dsolve, pprint, Function >>> from sympy.solvers.ode.ode import odesimp >>> x, u2, C1= symbols('x,u2,C1') >>> f = Function('f')
>>> eq = dsolve(x*f(x).diff(x) - f(x) - x*sin(f(x)/x), f(x), ... hint='1st_homogeneous_coeff_subs_indep_div_dep_Integral', ... simplify=False) >>> pprint(eq, wrap_line=False) x ---- f(x) / | | / 1 \ | -|u1 + -------| | | /1 \| | | sin|--|| | \ \u1// log(f(x)) = log(C1) + | ---------------- d(u1) | 2 | u1 | /
>>> pprint(odesimp(eq, f(x), 1, {C1}, ... hint='1st_homogeneous_coeff_subs_indep_div_dep' ... )) x --------- = C1 /f(x)\ tan|----| \2*x /
- sympy.solvers.ode.ode.constant_renumber(
- expr,
- variables=None,
- newconstants=None,
在
expr
中重新编号任意常量,以使用newconstants
中给出的符号名称。在此过程中,这将按标准方式重新排序表达式项。如果未提供
newconstants
,则新常量名称将为C1
、C2
等。否则,newconstants
应为一个可迭代对象,按顺序提供用于常量的新符号。variables
参数是一个非常量符号的列表。在expr
中找到的所有其他自由符号都被假定为常量,并将被重新编号。如果未给出variables
,则任何以C
开头的编号符号(例如C1
)都被假定为常量。符号根据
.sort_key()
重新编号,因此它们的编号应大致按照它们在最终打印表达式中出现的顺序。请注意,此排序部分基于哈希值,因此在不同机器上可能会产生不同的结果。这个函数的结构与
constantsimp()
非常相似。示例
>>> from sympy import symbols >>> from sympy.solvers.ode.ode import constant_renumber >>> x, C1, C2, C3 = symbols('x,C1:4') >>> expr = C3 + C2*x + C1*x**2 >>> expr C1*x**2 + C2*x + C3 >>> constant_renumber(expr) C1 + C2*x + C3*x**2
variables
参数指定了哪些是常量,以便其他符号不会被重新编号:>>> constant_renumber(expr, [C1, x]) C1*x**2 + C2 + C3*x
newconstants
参数用于指定在替换常量时要使用的符号:>>> constant_renumber(expr, [x], newconstants=symbols('E1:4')) E1 + E2*x + E3*x**2
- sympy.solvers.ode.ode.ode_sol_simplicity(sol, func, trysolving=True)[源代码][源代码]¶
返回一个扩展的整数,表示一个常微分方程解的简单程度。
以下事项按从最简单到最复杂的顺序考虑:
sol
是为func
求解的。sol
没有为func
求解,但如果传递给 solve 则可以求解(例如,由dsolve(ode, func, simplify=False
返回的解)。如果
sol
没有为func
求解,则根据sol
的长度来确定结果,如len(str(sol))
计算的那样。如果
sol
包含任何未求值的Integral
,这将被自动视为比上述任何情况都更不简单。
此函数返回一个整数,使得如果解决方案A比解决方案B在该度量上更简单,那么
ode_sol_simplicity(sola, func) < ode_sol_simplicity(solb, func)
。目前,以下是返回的数字,但如果启发式方法得到改进,这可能会改变。只有顺序是保证的。
简单性
返回
sol
解决了func
-2
sol
未解决func
但可以解决-1
sol
对于func
既未解决也无法解决len(str(sol))
sol
contains anIntegral
oo
oo
这里指的是 SymPy 的无限大,它应该比任何整数都大。如果你已经知道
solve()
无法解决sol
,你可以使用trysolving=False
来跳过这一步,这是唯一可能较慢的步骤。例如,使用simplify=False
标志的dsolve()
应该这样做。如果
sol
是一个解决方案列表,如果列表中最差的解决方案返回oo
,则返回该值,否则返回len(str(sol))
,即整个列表的字符串表示的长度。示例
此函数设计为作为
key
参数传递给min
,例如min(listofsolutions, key=lambda i: ode_sol_simplicity(i, f(x)))
。>>> from sympy import symbols, Function, Eq, tan, Integral >>> from sympy.solvers.ode.ode import ode_sol_simplicity >>> x, C1, C2 = symbols('x, C1, C2') >>> f = Function('f')
>>> ode_sol_simplicity(Eq(f(x), C1*x**2), f(x)) -2 >>> ode_sol_simplicity(Eq(x**2 + f(x), C1), f(x)) -1 >>> ode_sol_simplicity(Eq(f(x), C1*Integral(2*x, x)), f(x)) oo >>> eq1 = Eq(f(x)/tan(f(x)/(2*x)), C1) >>> eq2 = Eq(f(x)/tan(f(x)/(2*x) + f(x)), C2) >>> [ode_sol_simplicity(eq, f(x)) for eq in [eq1, eq2]] [28, 35] >>> min([eq1, eq2], key=lambda i: ode_sol_simplicity(i, f(x))) Eq(f(x)/tan(f(x)/(2*x)), C1)
- class sympy.solvers.ode.single.Factorable(ode_problem)[源代码][源代码]¶
解决具有可解因子的方程。
此函数用于求解含有因子的方程。因子可以是代数类型或常微分方程类型。它将尝试独立求解每个因子。因子将通过调用 dsolve 来求解。我们将返回解的列表。
- 属性:
- ode_problem
- 顺序
方法
get_general_solution
匹配
示例
>>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x >>> f = Function('f') >>> eq = (f(x)**2-4)*(f(x).diff(x)+f(x)) >>> pprint(dsolve(eq, f(x))) -x [f(x) = 2, f(x) = -2, f(x) = C1*e ]
- class sympy.solvers.ode.single.FirstExact(ode_problem)[源代码][源代码]¶
求解一阶精确常微分方程。
一阶微分方程被称为恰当的,如果它是某个函数的总微分。也就是说,微分方程
\[P(x, y) \,\partial{}x + Q(x, y) \,\partial{}y = 0\]如果存在某个函数 \(F(x, y)\) 使得 \(P(x, y) = \partial{}F/\partial{}x\) 且 \(Q(x, y) = \partial{}F/\partial{}y\),则该方程是精确的。可以证明,一阶常微分方程为精确的充要条件是 \(\partial{}P/\partial{}y = \partial{}Q/\partial{}x\)。然后,解将如下所示:
>>> from sympy import Function, Eq, Integral, symbols, pprint >>> x, y, t, x0, y0, C1= symbols('x,y,t,x0,y0,C1') >>> P, Q, F= map(Function, ['P', 'Q', 'F']) >>> pprint(Eq(Eq(F(x, y), Integral(P(t, y), (t, x0, x)) + ... Integral(Q(x0, t), (t, y0, y))), C1)) x y / / | | F(x, y) = | P(t, y) dt + | Q(x0, t) dt = C1 | | / / x0 y0
在 \(P\) 和 \(Q\) 的前部分存在且在单连通区域中连续的地方。
注意:SymPy 目前无法表示表达式上的惰性替换,因此提示
1st_exact_Integral
将返回一个带有 \(dy\) 的积分。这应该表示您正在求解的函数。- 属性:
- ode_problem
方法
get_general_solution
匹配
wilds
wilds_match
参考文献
M. Tenenbaum & H. Pollard, “Ordinary Differential Equations”, Dover 1963, pp. 73
# 间接文档测试
示例
>>> from sympy import Function, dsolve, cos, sin >>> from sympy.abc import x >>> f = Function('f') >>> dsolve(cos(f(x)) - (x*sin(f(x)) - f(x)**2)*f(x).diff(x), ... f(x), hint='1st_exact') Eq(x*cos(f(x)) + f(x)**3/3, C1)
- class sympy.solvers.ode.single.HomogeneousCoeffBest(ode_problem)[源代码][源代码]¶
返回从两个提示
1st_homogeneous_coeff_subs_dep_div_indep
和1st_homogeneous_coeff_subs_indep_div_dep
中得到的 ODE 的最佳解。这是由
ode_sol_simplicity()
决定的。See the
HomogeneousCoeffSubsIndepDivDep
andHomogeneousCoeffSubsDepDivIndep
docstrings for more information on these hints. Note that there is noode_1st_homogeneous_coeff_best_Integral
hint.- 属性:
- ode_problem
方法
get_general_solution
匹配
wilds
wilds_match
参考文献
M. Tenenbaum & H. Pollard, “Ordinary Differential Equations”, Dover 1963, pp. 59
# 间接文档测试
示例
>>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(2*x*f(x) + (x**2 + f(x)**2)*f(x).diff(x), f(x), ... hint='1st_homogeneous_coeff_best', simplify=False)) / 2 \ |3*x | log|----- + 1| | 2 | \f (x) / log(f(x)) = log(C1) - -------------- 3
- class sympy.solvers.ode.single.HomogeneousCoeffSubsDepDivIndep(ode_problem)[源代码][源代码]¶
使用代换 \(u_1 = \frac{\text{<因变量>}}{\text{<自变量>}}\) 求解具有齐次系数的 1 阶微分方程。
这是一个微分方程
\[P(x, y) + Q(x, y) dy/dx = 0\]使得 \(P\) 和 \(Q\) 是齐次且同阶的。一个函数 \(F(x, y)\) 是 \(n\) 阶齐次的,如果 \(F(x t, y t) = t^n F(x, y)\)。等价地,\(F(x, y)\) 可以重写为 \(G(y/x)\) 或 \(H(x/y)\)。另见
homogeneous_order()
的文档字符串。如果在上述微分方程中的系数 \(P\) 和 \(Q\) 是同阶的齐次函数,那么可以证明,代换 \(y = u_1 x`(即 `u_1 = y/x\))将把微分方程转化为变量 \(x\) 和 \(u\) 可分离的方程。如果 \(h(u_1)\) 是通过代换 \(u_1 = f(x)/x\) 在 \(P(x, f(x))\) 上得到的结果函数,而 \(g(u_2)\) 是通过在微分方程 \(P(x, f(x)) + Q(x, f(x)) f'(x) = 0\) 中的 \(Q(x, f(x))\) 上进行代换得到的结果函数,那么通解为:
>>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x >>> f, g, h = map(Function, ['f', 'g', 'h']) >>> genform = g(f(x)/x) + h(f(x)/x)*f(x).diff(x) >>> pprint(genform) /f(x)\ /f(x)\ d g|----| + h|----|*--(f(x)) \ x / \ x / dx >>> pprint(dsolve(genform, f(x), ... hint='1st_homogeneous_coeff_subs_dep_div_indep_Integral')) f(x) ---- x / | | -h(u1) log(x) = C1 + | ---------------- d(u1) | u1*h(u1) + g(u1) | /
其中 \(u_1 h(u_1) + g(u_1) e 0\) 且 \(x e 0\)。
See also the docstrings of
HomogeneousCoeffBest
andHomogeneousCoeffSubsIndepDivDep
.- 属性:
- ode_problem
方法
get_general_solution
匹配
wilds
wilds_match
参考文献
M. Tenenbaum & H. Pollard, “Ordinary Differential Equations”, Dover 1963, pp. 59
# 间接文档测试
示例
>>> from sympy import Function, dsolve >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(2*x*f(x) + (x**2 + f(x)**2)*f(x).diff(x), f(x), ... hint='1st_homogeneous_coeff_subs_dep_div_indep', simplify=False)) / 3 \ |3*f(x) f (x)| log|------ + -----| | x 3 | \ x / log(x) = log(C1) - ------------------- 3
- class sympy.solvers.ode.single.HomogeneousCoeffSubsIndepDivDep(ode_problem)[源代码][源代码]¶
使用替换 \(u_2 = \frac{\text{<自变量>}}{\text{<因变量>}}\) 解决具有齐次系数的1阶微分方程。
这是一个微分方程
\[P(x, y) + Q(x, y) dy/dx = 0\]使得 \(P\) 和 \(Q\) 是齐次且同阶的。一个函数 \(F(x, y)\) 是 \(n\) 阶齐次的,如果 \(F(x t, y t) = t^n F(x, y)\)。等价地,\(F(x, y)\) 可以重写为 \(G(y/x)\) 或 \(H(x/y)\)。另见
homogeneous_order()
的文档字符串。如果在上述微分方程中的系数 \(P\) 和 \(Q\) 是同阶的齐次函数,那么可以证明代换 \(x = u_2 y\) (即 \(u_2 = x/y\)) 将把微分方程转化为变量 \(y\) 和 \(u_2\) 可分离的方程。如果 \(h(u_2)\) 是通过代换 \(u_2 = x/f(x)\) 在 \(P(x, f(x))\) 上得到的结果函数,而 \(g(u_2)\) 是通过在微分方程 \(P(x, f(x)) + Q(x, f(x)) f'(x) = 0\) 中代换 \(Q(x, f(x))\) 得到的结果函数,那么通解为:
>>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x >>> f, g, h = map(Function, ['f', 'g', 'h']) >>> genform = g(x/f(x)) + h(x/f(x))*f(x).diff(x) >>> pprint(genform) / x \ / x \ d g|----| + h|----|*--(f(x)) \f(x)/ \f(x)/ dx >>> pprint(dsolve(genform, f(x), ... hint='1st_homogeneous_coeff_subs_indep_div_dep_Integral')) x ---- f(x) / | | -g(u1) | ---------------- d(u1) | u1*g(u1) + h(u1) | / f(x) = C1*e
其中 \(u_1 g(u_1) + h(u_1) e 0\) 且 \(f(x) e 0\)。
See also the docstrings of
HomogeneousCoeffBest
andHomogeneousCoeffSubsDepDivIndep
.- 属性:
- ode_problem
方法
get_general_solution
匹配
wilds
wilds_match
参考文献
M. Tenenbaum & H. Pollard, “Ordinary Differential Equations”, Dover 1963, pp. 59
# 间接文档测试
示例
>>> from sympy import Function, pprint, dsolve >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(2*x*f(x) + (x**2 + f(x)**2)*f(x).diff(x), f(x), ... hint='1st_homogeneous_coeff_subs_indep_div_dep', ... simplify=False)) / 2 \ |3*x | log|----- + 1| | 2 | \f (x) / log(f(x)) = log(C1) - -------------- 3
- class sympy.solvers.ode.single.FirstLinear(ode_problem)[源代码][源代码]¶
求解一阶线性微分方程。
这些是形式为的微分方程
\[dy/dx + P(x) y = Q(x)\text{.}\]这类微分方程可以用一般方法求解。积分因子 \(e^{\int P(x) \,dx}\) 将把方程转化为可分离方程。通解为:
>>> from sympy import Function, dsolve, Eq, pprint, diff, sin >>> from sympy.abc import x >>> f, P, Q = map(Function, ['f', 'P', 'Q']) >>> genform = Eq(f(x).diff(x) + P(x)*f(x), Q(x)) >>> pprint(genform) d P(x)*f(x) + --(f(x)) = Q(x) dx >>> pprint(dsolve(genform, f(x), hint='1st_linear_Integral')) / / \ | | | | | / | / | | | | | | | | P(x) dx | - | P(x) dx | | | | | | | / | / f(x) = |C1 + | Q(x)*e dx|*e | | | \ / /
- 属性:
- ode_problem
方法
get_general_solution
匹配
wilds
wilds_match
参考文献
M. Tenenbaum & H. Pollard, “Ordinary Differential Equations”, Dover 1963, pp. 92
# 间接文档测试
示例
>>> f = Function('f') >>> pprint(dsolve(Eq(x*diff(f(x), x) - f(x), x**2*sin(x)), ... f(x), '1st_linear')) f(x) = x*(C1 - cos(x))
- class sympy.solvers.ode.single.RationalRiccati(ode_problem)[源代码][源代码]¶
给出了一阶Riccati微分方程的一般解法,这些方程至少有一个有理特解。
\[y' = b_0(x) + b_1(x) y + b_2(x) y^2\]其中 \(b_0\), \(b_1\) 和 \(b_2\) 是 \(x\) 的有理函数,且 \(b_2 e 0`(若 `b_2 = 0\),则变为伯努利方程)。
- 属性:
- ode_problem
方法
get_general_solution
匹配
wilds
wilds_match
参考文献
Riccati 常微分方程: https://en.wikipedia.org/wiki/Riccati_equation
N. Thieu Vo - Rational and Algebraic Solutions of First-Order Algebraic ODEs: Algorithm 11, pp. 78 - https://www3.risc.jku.at/publications/download/risc_5387/PhDThesisThieu.pdf
示例
>>> from sympy import Symbol, Function, dsolve, checkodesol >>> f = Function('f') >>> x = Symbol('x')
>>> eq = -x**4*f(x)**2 + x**3*f(x).diff(x) + x**2*f(x) + 20 >>> sol = dsolve(eq, hint="1st_rational_riccati") >>> sol Eq(f(x), (4*C1 - 5*x**9 - 4)/(x**2*(C1 + x**9 - 1))) >>> checkodesol(eq, sol) (True, 0)
- class sympy.solvers.ode.single.SecondLinearAiry(ode_problem)[源代码][源代码]¶
给出 Airy 微分方程的解
\[\frac{d^2y}{dx^2} + (a + b x) y(x) = 0\]就 Airy 特殊函数 airyai 和 airybi 而言。
- 属性:
- ode_problem
- 顺序
方法
get_general_solution
匹配
示例
>>> from sympy import dsolve, Function >>> from sympy.abc import x >>> f = Function("f") >>> eq = f(x).diff(x, 2) - x*f(x) >>> dsolve(eq) Eq(f(x), C1*airyai(x) + C2*airybi(x))
- class sympy.solvers.ode.single.SecondLinearBessel(ode_problem)[源代码][源代码]¶
给出贝塞尔微分方程的解
\[x^2 \frac{d^2y}{dx^2} + x \frac{dy}{dx} y(x) + (x^2-n^2) y(x)\]如果 \(n\) 是整数,那么解的形式为
Eq(f(x), C0 besselj(n,x) + C1 bessely(n,x))
,因为这两个解是线性独立的;否则,如果 \(n\) 是分数,那么解的形式为Eq(f(x), C0 besselj(n,x) + C1 besselj(-n,x))
,这也可以转换为Eq(f(x), C0 besselj(n,x) + C1 bessely(n,x))
。- 属性:
- ode_problem
- 顺序
方法
get_general_solution
匹配
参考文献
https://math24.net/bessel-differential-equation.html
示例
>>> from sympy.abc import x >>> from sympy import Symbol >>> v = Symbol('v', positive=True) >>> from sympy import dsolve, Function >>> f = Function('f') >>> y = f(x) >>> genform = x**2*y.diff(x, 2) + x*y.diff(x) + (x**2 - v**2)*y >>> dsolve(genform) Eq(f(x), C1*besselj(v, x) + C2*bessely(v, x))
- class sympy.solvers.ode.single.Bernoulli(ode_problem)[源代码][源代码]¶
求解伯努利微分方程。
这些是形式为
\[dy/dx + P(x) y = Q(x) y^n ext{, }n e 1` ext{.}\]The substitution \(w = 1/y^{1-n}\) will transform an equation of this form into one that is linear (see the docstring of
FirstLinear
). The general solution is:>>> from sympy import Function, dsolve, Eq, pprint >>> from sympy.abc import x, n >>> f, P, Q = map(Function, ['f', 'P', 'Q']) >>> genform = Eq(f(x).diff(x) + P(x)*f(x), Q(x)*f(x)**n) >>> pprint(genform) d n P(x)*f(x) + --(f(x)) = Q(x)*f (x) dx >>> pprint(dsolve(genform, f(x), hint='Bernoulli_Integral'), num_columns=110) -1 ----- n - 1 // / / \ \ || | | | | || | / | / | / | || | | | | | | | || | -(n - 1)* | P(x) dx | -(n - 1)* | P(x) dx | (n - 1)* | P(x) dx| || | | | | | | | || | / | / | / | f(x) = ||C1 - n* | Q(x)*e dx + | Q(x)*e dx|*e | || | | | | \\ / / / /
Note that the equation is separable when \(n = 1\) (see the docstring of
Separable
).>>> pprint(dsolve(Eq(f(x).diff(x) + P(x)*f(x), Q(x)*f(x)), f(x), ... hint='separable_Integral')) f(x) / | / | 1 | | - dy = C1 + | (-P(x) + Q(x)) dx | y | | / /
- 属性:
- ode_problem
方法
get_general_solution
匹配
wilds
wilds_match
参考文献
https://en.wikipedia.org/wiki/伯努利微分方程
M. Tenenbaum & H. Pollard, “Ordinary Differential Equations”, Dover 1963, pp. 95
# 间接文档测试
示例
>>> from sympy import Function, dsolve, Eq, pprint, log >>> from sympy.abc import x >>> f = Function('f')
>>> pprint(dsolve(Eq(x*f(x).diff(x) + f(x), log(x)*f(x)**2), ... f(x), hint='Bernoulli')) 1 f(x) = ----------------- C1*x + log(x) + 1
- class sympy.solvers.ode.single.Liouville(ode_problem)[源代码][源代码]¶
求解二阶李维尔微分方程。
Liouville ODE 的一般形式是
\[\begin{split}\frac{d^2 y}{dx^2} + g(y) \left(\!\frac{dy}{dx}\\!\right)^2 + h(x) \frac{dy}{dx}\text{.}\end{split}\]一般解决方案是:
>>> from sympy import Function, dsolve, Eq, pprint, diff >>> from sympy.abc import x >>> f, g, h = map(Function, ['f', 'g', 'h']) >>> genform = Eq(diff(f(x),x,x) + g(f(x))*diff(f(x),x)**2 + ... h(x)*diff(f(x),x), 0) >>> pprint(genform) 2 2 /d \ d d g(f(x))*|--(f(x))| + h(x)*--(f(x)) + ---(f(x)) = 0 \dx / dx 2 dx >>> pprint(dsolve(genform, f(x), hint='Liouville_Integral')) f(x) / / | | | / | / | | | | | - | h(x) dx | | g(y) dy | | | | | / | / C1 + C2* | e dx + | e dy = 0 | | / /
- 属性:
- ode_problem
方法
get_general_solution
匹配
wilds
wilds_match
参考文献
Goldstein 和 Braun, “微分方程求解的高级方法”, 第98页
https://www.maplesoft.com/support/help/Maple/view.aspx?path=odeadvisor/Liouville
# 间接文档测试
示例
>>> from sympy import Function, dsolve, Eq, pprint >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(diff(f(x), x, x) + diff(f(x), x)**2/f(x) + ... diff(f(x), x)/x, f(x), hint='Liouville')) ________________ ________________ [f(x) = -\/ C1 + C2*log(x) , f(x) = \/ C1 + C2*log(x) ]
- class sympy.solvers.ode.single.RiccatiSpecial(ode_problem)[源代码][源代码]¶
一般Riccati方程的形式为
\[dy/dx = f(x) y^2 + g(x) y + h(x)\text{.}\]虽然它没有通解 [1],但“特殊”形式 \(dy/dx = a y^2 - b x^c\) 在许多情况下确实有解 [2]。此程序返回 \(a(dy/dx) = b y^2 + c y/x + d/x^2\) 的解,该解是通过使用适当的变量替换将其简化为特殊形式得到的,并且在 \(a\) 和 \(b\) 都不为零且 \(c\) 或 \(d\) 为零时有效。
>>> from sympy.abc import x, a, b, c, d >>> from sympy import dsolve, checkodesol, pprint, Function >>> f = Function('f') >>> y = f(x) >>> genform = a*y.diff(x) - (b*y**2 + c*y/x + d/x**2) >>> sol = dsolve(genform, y, hint="Riccati_special_minus2") >>> pprint(sol, wrap_line=False) / / __________________ \\ | __________________ | / 2 || | / 2 | \/ 4*b*d - (a + c) *log(x)|| -|a + c - \/ 4*b*d - (a + c) *tan|C1 + ----------------------------|| \ \ 2*a // f(x) = ------------------------------------------------------------------------ 2*b*x
>>> checkodesol(genform, sol, order=1)[0] True
- 属性:
- ode_problem
方法
get_general_solution
匹配
wilds
wilds_match
参考文献
- class sympy.solvers.ode.single.NthLinearConstantCoeffHomogeneous(ode_problem)[源代码][源代码]¶
求解具有常系数的 \(n\) 阶线性齐次微分方程。
这是一个形式的方程
\[ \begin{align}\begin{aligned}a_n f^{(n)}(x) + a_{n-1} f^{(n-1)}(x) + \cdots + a_1 f'(x) + a_0 f(x) = 0\text{.}\\a_n f^{(n)}(x) + a_{n-1} f^{(n-1)}(x) + \cdots + a_1 f'(x) + a_0 f(x) = 0\text{.}\end{aligned}\end{align} \]这些方程可以通过求解特征方程 \(a_n m^n + a_{n-1} m^{n-1} + \cdots + a_1 m + a_0 = 0\) 的根来一般性地求解。解将是 \(C_n x^i e^{r x}\) 项的和,其中 \(C_n\) 是任意常数,\(r\) 是特征方程的根,\(i\) 是从 0 到根的重数减 1 的每一个值(例如,重数为 2 的根 3 将生成项 \(C_1 e^{3 x} + C_2 x e^{3 x}\))。对于复数根,指数通常使用欧拉公式 \(e^{I x} = \cos(x) + I \sin(x)\) 展开。在实系数多项式中,复数根总是成对出现,因此这两个根将表示为(简化常数后)`e^{a x} left(C_1 cos(b x) + C_2 sin(b x)right)`。
如果 SymPy 无法找到特征方程的精确根,将返回一个
ComplexRootOf
实例。>>> from sympy import Function, dsolve >>> from sympy.abc import x >>> f = Function('f') >>> dsolve(f(x).diff(x, 5) + 10*f(x).diff(x) - 2*f(x), f(x), ... hint='nth_linear_constant_coeff_homogeneous') ... Eq(f(x), C5*exp(x*CRootOf(_x**5 + 10*_x - 2, 0)) + (C1*sin(x*im(CRootOf(_x**5 + 10*_x - 2, 1))) + C2*cos(x*im(CRootOf(_x**5 + 10*_x - 2, 1))))*exp(x*re(CRootOf(_x**5 + 10*_x - 2, 1))) + (C3*sin(x*im(CRootOf(_x**5 + 10*_x - 2, 3))) + C4*cos(x*im(CRootOf(_x**5 + 10*_x - 2, 3))))*exp(x*re(CRootOf(_x**5 + 10*_x - 2, 3))))
请注意,由于此方法不涉及积分,因此没有
nth_linear_constant_coeff_homogeneous_Integral
提示。- 属性:
- ode_problem
- 顺序
方法
get_general_solution
匹配
参考文献
https://en.wikipedia.org/wiki/Linear_differential_equation 部分: 具有常系数的非齐次方程
M. Tenenbaum & H. Pollard, “Ordinary Differential Equations”, Dover 1963, pp. 211
# 间接文档测试
示例
>>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(f(x).diff(x, 4) + 2*f(x).diff(x, 3) - ... 2*f(x).diff(x, 2) - 6*f(x).diff(x) + 5*f(x), f(x), ... hint='nth_linear_constant_coeff_homogeneous')) x -2*x f(x) = (C1 + C2*x)*e + (C3*sin(x) + C4*cos(x))*e
- class sympy.solvers.ode.single.NthLinearConstantCoeffUndeterminedCoefficients(
- ode_problem,
使用待定系数法求解具有常系数的 \(n\) 阶线性微分方程。
此方法适用于以下形式的微分方程
\[ \begin{align}\begin{aligned}a_n f^{(n)}(x) + a_{n-1} f^{(n-1)}(x) + \cdots + a_1 f'(x) + a_0 f(x) = P(x)\text{,}\\a_n f^{(n)}(x) + a_{n-1} f^{(n-1)}(x) + \cdots + a_1 f'(x) + a_0 f(x) = P(x)\text{,}\end{aligned}\end{align} \]其中 \(P(x)\) 是一个具有有限个线性无关导数的函数。
满足此要求的函数是有限和形式的函数,如 \(a x^i e^{b x} \sin(c x + d)\) 或 \(a x^i e^{b x} \cos(c x + d)\),其中 \(i\) 是非负整数,\(a\), \(b\), \(c\), 和 \(d\) 是常数。例如,任何 \(x\) 的多项式,函数如 \(x^2 e^{2 x}\)、\(x \sin(x)\) 和 \(e^x \cos(x)\) 都可以使用。\(\sin\) 和 \(\cos\) 的乘积具有有限数量的导数,因为它们可以展开为 \(\sin(a x)\) 和 \(\cos(b x)\) 项。然而,SymPy 目前无法进行这种展开,因此您需要手动将表达式重写为上述形式以使用此方法。因此,例如,您需要手动将 \(\sin^2(x)\) 转换为 \((1 + \cos(2 x))/2\) 以正确应用待定系数法。
此方法通过从表达式及其所有线性无关的导数创建一个试探函数,并将它们代入原始常微分方程(ODE)中来工作。每个项的系数将形成一个线性方程组,这些方程将被求解并代入,从而得到解。如果任何试探函数与齐次方程的解线性相关,则将它们乘以足够的 \(x\) 以使其线性无关。
- 属性:
- ode_problem
- 顺序
方法
get_general_solution
匹配
参考文献
https://zh.wikipedia.org/wiki/%E6%9C%AA%E7%A1%AE%E5%AE%9A%E7%B3%BB%E6%95%B0%E6%B3%95
M. Tenenbaum & H. Pollard, “Ordinary Differential Equations”, Dover 1963, pp. 221
# 间接文档测试
示例
>>> from sympy import Function, dsolve, pprint, exp, cos >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(f(x).diff(x, 2) + 2*f(x).diff(x) + f(x) - ... 4*exp(-x)*x**2 + cos(2*x), f(x), ... hint='nth_linear_constant_coeff_undetermined_coefficients')) / / 3\\ | | x || -x 4*sin(2*x) 3*cos(2*x) f(x) = |C1 + x*|C2 + --||*e - ---------- + ---------- \ \ 3 // 25 25
- class sympy.solvers.ode.single.NthLinearConstantCoeffVariationOfParameters(
- ode_problem,
使用参数变分法求解具有常系数的 \(n\) 阶线性微分方程。
此方法适用于任何形式的微分方程
\[ \begin{align}\begin{aligned}f^{(n)}(x) + a_{n-1} f^{(n-1)}(x) + \cdots + a_1 f'(x) + a_0 f(x) = P(x)\text{.}\\f^{(n)}(x) + a_{n-1} f^{(n-1)}(x) + \cdots + a_1 f'(x) + a_0 f(x) = P(x)\text{.}\end{aligned}\end{align} \]此方法通过假设特解具有以下形式来工作
\[\sum_{x=1}^{n} c_i(x) y_i(x)\text{,}\]其中 \(y_i\) 是齐次方程的第 \(i\) 个解。然后使用 Wronskian 和 Cramer 法则求解。特解由以下公式给出:
\[\[\sum_{x=1}^n \left( \int \frac{W_i(x)}{W(x)} \,dx \right) y_i(x) \text{,}\]\]其中 \(W(x)\) 是基本系统的 Wronskian(齐次方程的 \(n\) 个线性独立解的系统),而 \(W_i(x)\) 是基本系统的 Wronskian,其中第 \(i\) 列被替换为 \([0, 0, \cdots, 0, P(x)]\)。
这个方法足够通用,可以解决任何具有常系数的`n`阶非齐次线性微分方程,但有时SymPy无法充分简化Wronskian以进行积分。如果此方法挂起,请尝试使用``nth_linear_constant_coeff_variation_of_parameters_Integral``提示,并手动简化积分。此外,当适用时,优先使用``nth_linear_constant_coeff_undetermined_coefficients``,因为它不使用积分,从而更快且更可靠。
警告,在
dsolve()
中使用 ‘nth_linear_constant_coeff_variation_of_parameters’ 时,如果设置 simplify=False,可能会导致程序挂起,因为它不会在积分前尝试简化Wronskian。建议你仅在使用 ‘nth_linear_constant_coeff_variation_of_parameters_Integral’ 时使用 simplify=False,特别是当齐次方程的解包含三角函数时。- 属性:
- ode_problem
- 顺序
方法
get_general_solution
匹配
参考文献
M. Tenenbaum & H. Pollard, “Ordinary Differential Equations”, Dover 1963, pp. 233
# 间接文档测试
示例
>>> from sympy import Function, dsolve, pprint, exp, log >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(f(x).diff(x, 3) - 3*f(x).diff(x, 2) + ... 3*f(x).diff(x) - f(x) - exp(x)*log(x), f(x), ... hint='nth_linear_constant_coeff_variation_of_parameters')) / / / x*log(x) 11*x\\\ x f(x) = |C1 + x*|C2 + x*|C3 + -------- - ----|||*e \ \ \ 6 36 ///
- class sympy.solvers.ode.single.NthLinearEulerEqHomogeneous(ode_problem)[源代码][源代码]¶
求解一个 \(n\) 阶线性齐次变系数 Cauchy-Euler 等维常微分方程。
这是一个带有形式的方程 \(0 = a_0 f(x) + a_1 x f'(x) + a_2 x^2 f''(x) \cdots\)。
These equations can be solved in a general manner, by substituting solutions of the form \(f(x) = x^r\), and deriving a characteristic equation for \(r\). When there are repeated roots, we include extra terms of the form \(C_{r k} \ln^k(x) x^r\), where \(C_{r k}\) is an arbitrary integration constant, \(r\) is a root of the characteristic equation, and \(k\) ranges over the multiplicity of \(r\). In the cases where the roots are complex, solutions of the form \(C_1 x^a \sin(b \log(x)) + C_2 x^a \cos(b \log(x))\) are returned, based on expansions with Euler’s formula. The general solution is the sum of the terms found. If SymPy cannot find exact roots to the characteristic equation, a
ComplexRootOf
instance will be returned instead.>>> from sympy import Function, dsolve >>> from sympy.abc import x >>> f = Function('f') >>> dsolve(4*x**2*f(x).diff(x, 2) + f(x), f(x), ... hint='nth_linear_euler_eq_homogeneous') ... Eq(f(x), sqrt(x)*(C1 + C2*log(x)))
请注意,由于此方法不涉及积分,因此没有
nth_linear_euler_eq_homogeneous_Integral
提示。以下内容供内部使用:
returns = 'sol'
返回 ODE 的解。returns = 'list'
返回一个线性无关解的列表,对应于基本解集,用于非齐次解法,如参数变异法和未定系数法。请注意,尽管解应该是线性无关的,但此函数不会显式检查这一点。你可以执行assert simplify(wronskian(sollist)) != 0
来检查线性无关性。此外,assert len(sollist) == order
也需要通过。returns = 'both'
,返回一个字典{'sol': <ODE的解>, 'list': <线性独立解的列表>}
。
- 属性:
- ode_problem
- 顺序
方法
get_general_solution
匹配
参考文献
https://en.wikipedia.org/wiki/柯西-欧拉方程
C. Bender & S. Orszag, “Advanced Mathematical Methods for Scientists and Engineers”, Springer 1999, pp. 12
# 间接文档测试
示例
>>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x >>> f = Function('f') >>> eq = f(x).diff(x, 2)*x**2 - 4*f(x).diff(x)*x + 6*f(x) >>> pprint(dsolve(eq, f(x), ... hint='nth_linear_euler_eq_homogeneous')) 2 f(x) = x *(C1 + C2*x)
- class sympy.solvers.ode.single.NthLinearEulerEqNonhomogeneousVariationOfParameters(
- ode_problem,
使用参数变分法求解 \(n\) 阶线性非齐次 Cauchy-Euler 等维常微分方程。
这是一个带有形式的方程 \(g(x) = a_0 f(x) + a_1 x f'(x) + a_2 x^2 f''(x) \cdots\)。
此方法通过假设特解具有以下形式来工作
\[\sum_{x=1}^{n} c_i(x) y_i(x) {a_n} {x^n} \text{, }\]其中 \(y_i\) 是齐次方程的第 \(i\) 个解。然后使用 Wronskian 和 Cramer 法则求解。特解由下面给出的方程乘以 \(a_n x^{n}\) 得到。
\[\[ \sum_{x=1}^n \left( \int \frac{W_i(x)}{W(x)} \, dx \right) y_i(x) \text{, } \]\]其中 \(W(x)\) 是基本系统的朗斯基行列式(该系统由齐次方程的 \(n\) 个线性独立解组成),而 \(W_i(x)\) 是基本系统的朗斯基行列式,其中第 \(i\) 列被替换为 \([0, 0, \cdots, 0, \frac{x^{- n}}{a_n} g{\left(x \right)}]\)。
这种方法足够通用,可以解决任何 \(n\) 阶非齐次线性微分方程,但有时 SymPy 无法充分简化 Wronskian 以进行积分。如果此方法挂起,请尝试使用
nth_linear_constant_coeff_variation_of_parameters_Integral
提示并手动简化积分。此外,在适用时,优先使用nth_linear_constant_coeff_undetermined_coefficients
,因为它不使用积分,从而更快且更可靠。警告,在
dsolve()
中使用 ‘nth_linear_constant_coeff_variation_of_parameters’ 时,如果设置 simplify=False,可能会导致程序挂起,因为它不会在积分前尝试简化Wronskian。建议你仅在使用 ‘nth_linear_constant_coeff_variation_of_parameters_Integral’ 时使用 simplify=False,特别是当齐次方程的解包含三角函数时。- 属性:
- ode_problem
- 顺序
方法
get_general_solution
匹配
示例
>>> from sympy import Function, dsolve, Derivative >>> from sympy.abc import x >>> f = Function('f') >>> eq = x**2*Derivative(f(x), x, x) - 2*x*Derivative(f(x), x) + 2*f(x) - x**4 >>> dsolve(eq, f(x), ... hint='nth_linear_euler_eq_nonhomogeneous_variation_of_parameters').expand() Eq(f(x), C1*x + C2*x**2 + x**4/6)
- class sympy.solvers.ode.single.NthLinearEulerEqNonhomogeneousUndeterminedCoefficients(
- ode_problem,
使用未定系数法求解 \(n\) 阶线性非齐次 Cauchy-Euler 等维常微分方程。
这是一个带有形式的方程 \(g(x) = a_0 f(x) + a_1 x f'(x) + a_2 x^2 f''(x) \cdots\)。
这些方程可以通过一般方式求解,通过代入形式为 \(x = exp(t)\) 的解,并推导出形式为 \(g(exp(t)) = b_0 f(t) + b_1 f'(t) + b_2 f''(t) \cdots\) 的特征方程,然后可以通过 nth_linear_constant_coeff_undetermined_coefficients 求解,如果 g(exp(t)) 具有有限数量的线性独立导数。
满足此要求的函数是有限和形式的函数,如 \(a x^i e^{b x} \sin(c x + d)\) 或 \(a x^i e^{b x} \cos(c x + d)\),其中 \(i\) 是非负整数,\(a\), \(b\), \(c\), 和 \(d\) 是常数。例如,任何 \(x\) 的多项式,函数如 \(x^2 e^{2 x}\)、\(x \sin(x)\) 和 \(e^x \cos(x)\) 都可以使用。\(\sin\) 和 \(\cos\) 的乘积具有有限数量的导数,因为它们可以展开为 \(\sin(a x)\) 和 \(\cos(b x)\) 项。然而,SymPy 目前无法进行这种展开,因此您需要手动将表达式重写为上述形式以使用此方法。因此,例如,您需要手动将 \(\sin^2(x)\) 转换为 \((1 + \cos(2 x))/2\) 以正确应用待定系数法。
在将 x 替换为 exp(t) 之后,此方法通过从表达式及其所有线性独立导数创建一个试探函数,并将它们代入原始常微分方程中。每个项的系数将形成一个线性方程组,求解并代入这些系数,即可得到解。如果任何试探函数与齐次方程的解线性相关,则将它们乘以足够的 \(x\) 以使其线性独立。
- 属性:
- ode_problem
- 顺序
方法
get_general_solution
匹配
示例
>>> from sympy import dsolve, Function, Derivative, log >>> from sympy.abc import x >>> f = Function('f') >>> eq = x**2*Derivative(f(x), x, x) - 2*x*Derivative(f(x), x) + 2*f(x) - log(x) >>> dsolve(eq, f(x), ... hint='nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients').expand() Eq(f(x), C1*x + C2*x**2 + log(x)/2 + 3/4)
- class sympy.solvers.ode.single.NthAlgebraic(ode_problem)[源代码][源代码]¶
使用代数和积分求解 \(n\) 阶常微分方程。
这种方程没有通用的形式。方程通过将微分视为可逆的代数函数,以代数方式求解。
- 属性:
- ode_problem
- 顺序
方法
get_general_solution
匹配
示例
>>> from sympy import Function, dsolve, Eq >>> from sympy.abc import x >>> f = Function('f') >>> eq = Eq(f(x) * (f(x).diff(x)**2 - 1), 0) >>> dsolve(eq, f(x), hint='nth_algebraic') [Eq(f(x), 0), Eq(f(x), C1 - x), Eq(f(x), C1 + x)]
请注意,此求解器可以返回不包含任何积分常数的代数解(如上例中的 f(x) = 0)。
- class sympy.solvers.ode.single.NthOrderReducible(ode_problem)[源代码][源代码]¶
解决仅涉及因变量导数的常微分方程,使用形式为 \(f^n(x) = g(x)\) 的代换。
例如,任何形式的二阶ODE \(f''(x) = h(f'(x), x)\) 都可以转化为一对一阶ODE \(g'(x) = h(g(x), x)\) 和 \(f'(x) = g(x)\)。通常,`g`的一阶ODE更容易求解。如果这给出了`g`的显式解,那么`f`可以通过积分简单地找到。
- 属性:
- ode_problem
- 顺序
方法
get_general_solution
匹配
示例
>>> from sympy import Function, dsolve, Eq >>> from sympy.abc import x >>> f = Function('f') >>> eq = Eq(x*f(x).diff(x)**2 + f(x).diff(x, 2), 0) >>> dsolve(eq, f(x), hint='nth_order_reducible') ... Eq(f(x), C1 - sqrt(-1/C2)*log(-C2*sqrt(-1/C2) + x) + sqrt(-1/C2)*log(C2*sqrt(-1/C2) + x))
- class sympy.solvers.ode.single.Separable(ode_problem)[源代码][源代码]¶
求解可分离的一阶微分方程。
这是一个可以写成 \(P(y) \tfrac{dy}{dx} = Q(x)\) 的微分方程。然后可以通过重新排列项并积分来求解:\(\int P(y) \,dy = \int Q(x) \,dx\)。此提示使用
sympy.simplify.simplify.separatevars()
作为其后端,因此如果可分离方程未被此求解器捕获,则很可能是该函数的问题。separatevars()
足够智能,可以完成大多数必要的展开和因式分解,以将可分离方程 \(F(x, y)\) 转换为适当的形式 \(P(x)\cdot{}Q(y)\)。一般解为:>>> from sympy import Function, dsolve, Eq, pprint >>> from sympy.abc import x >>> a, b, c, d, f = map(Function, ['a', 'b', 'c', 'd', 'f']) >>> genform = Eq(a(x)*b(f(x))*f(x).diff(x), c(x)*d(f(x))) >>> pprint(genform) d a(x)*b(f(x))*--(f(x)) = c(x)*d(f(x)) dx >>> pprint(dsolve(genform, f(x), hint='separable_Integral')) f(x) / / | | | b(y) | c(x) | ---- dy = C1 + | ---- dx | d(y) | a(x) | | / /
- 属性:
- ode_problem
方法
get_general_solution
匹配
wilds
wilds_match
参考文献
M. Tenenbaum & H. Pollard, “Ordinary Differential Equations”, Dover 1963, pp. 52
# 间接文档测试
示例
>>> from sympy import Function, dsolve, Eq >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(Eq(f(x)*f(x).diff(x) + x, 3*x*f(x)**2), f(x), ... hint='separable', simplify=False)) / 2 \ 2 log\3*f (x) - 1/ x ---------------- = C1 + -- 6 2
- class sympy.solvers.ode.single.AlmostLinear(ode_problem)[源代码][源代码]¶
解决一个近似线性的微分方程。
几乎线性微分方程的一般形式是
\[a(x) g'(f(x)) f'(x) + b(x) g(f(x)) + c(x)\]这里 \(f(x)\) 是待求解的函数(因变量)。代换 \(g(f(x)) = u(x)\) 导致 \(u(x)\) 的线性微分方程形式为 \(a(x) u' + b(x) u + c(x) = 0\)。这可以通过 \(first_linear\) 提示求解 \(u(x)\),然后通过解 \(g(f(x)) = u(x)\) 找到 \(f(x)\)。
- 属性:
- ode_problem
方法
get_general_solution
匹配
wilds
wilds_match
参考文献
Joel Moses, “符号积分 - 动荡的十年”, 《ACM通讯》, 第14卷, 第8期, 1971年8月, 第558页
示例
>>> from sympy import dsolve, Function, pprint, sin, cos >>> from sympy.abc import x >>> f = Function('f') >>> d = f(x).diff(x) >>> eq = x*d + x*f(x) + 1 >>> dsolve(eq, f(x), hint='almost_linear') Eq(f(x), (C1 - Ei(x))*exp(-x)) >>> pprint(dsolve(eq, f(x), hint='almost_linear')) -x f(x) = (C1 - Ei(x))*e >>> example = cos(f(x))*f(x).diff(x) + sin(f(x)) + 1 >>> pprint(example) d sin(f(x)) + cos(f(x))*--(f(x)) + 1 dx >>> pprint(dsolve(example, f(x), hint='almost_linear')) / -x \ / -x \ [f(x) = pi - asin\C1*e - 1/, f(x) = asin\C1*e - 1/]
- class sympy.solvers.ode.single.LinearCoefficients(ode_problem)[源代码][源代码]¶
求解具有线性系数的微分方程。
具有线性系数微分方程的一般形式是
\[y' + F\left(\!\frac{a_1 x + b_1 y + c_1}{a_2 x + b_2 y + c_2}\!\right) = 0\text{,}\]其中 \(a_1\), \(b_1\), \(c_1\), \(a_2\), \(b_2\), \(c_2\) 是常数,且 \(a_1 b_2 - a_2 b_1 e 0\)。
这可以通过替换来解决:
\[ \begin{align}\begin{aligned}x = x' + \frac{b_2 c_1 - b_1 c_2}{a_2 b_1 - a_1 b_2}\\y = y' + \frac{a_1 c_2 - a_2 c_1}{a_2 b_1 - a_1 b_2}\text{.}\end{aligned}\end{align} \]这种替换将方程简化为一个齐次微分方程。
- 属性:
- ode_problem
方法
get_general_solution
匹配
wilds
wilds_match
参见
参考文献
Joel Moses, “符号积分 - 动荡的十年”, 《ACM通讯》, 第14卷, 第8期, 1971年8月, 第558页
示例
>>> from sympy import dsolve, Function, pprint >>> from sympy.abc import x >>> f = Function('f') >>> df = f(x).diff(x) >>> eq = (x + f(x) + 1)*df + (f(x) - 6*x + 1) >>> dsolve(eq, hint='linear_coefficients') [Eq(f(x), -x - sqrt(C1 + 7*x**2) - 1), Eq(f(x), -x + sqrt(C1 + 7*x**2) - 1)] >>> pprint(dsolve(eq, hint='linear_coefficients')) ___________ ___________ / 2 / 2 [f(x) = -x - \/ C1 + 7*x - 1, f(x) = -x + \/ C1 + 7*x - 1]
- class sympy.solvers.ode.single.SeparableReduced(ode_problem)[源代码][源代码]¶
解决一个可以简化为可分离形式的微分方程。
这个方程的一般形式是
\[y' + (y/x) H(x^n y) = 0\text{}.\]这可以通过代入 \(u(y) = x^n y\) 来解决。 方程随后简化为可分离形式 \(\frac{u'}{u (\mathrm{power} - H(u))} - \frac{1}{x} = 0\)。
一般解决方案是:
>>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x, n >>> f, g = map(Function, ['f', 'g']) >>> genform = f(x).diff(x) + (f(x)/x)*g(x**n*f(x)) >>> pprint(genform) / n \ d f(x)*g\x *f(x)/ --(f(x)) + --------------- dx x >>> pprint(dsolve(genform, hint='separable_reduced')) n x *f(x) / | | 1 | ------------ dy = C1 + log(x) | y*(n - g(y)) | /
- 属性:
- ode_problem
方法
get_general_solution
匹配
wilds
wilds_match
参考文献
Joel Moses, “符号积分 - 动荡的十年”, 《ACM通讯》, 第14卷, 第8期, 1971年8月, 第558页
示例
>>> from sympy import dsolve, Function, pprint >>> from sympy.abc import x >>> f = Function('f') >>> d = f(x).diff(x) >>> eq = (x - x**2*f(x))*d - f(x) >>> dsolve(eq, hint='separable_reduced') [Eq(f(x), (1 - sqrt(C1*x**2 + 1))/x), Eq(f(x), (sqrt(C1*x**2 + 1) + 1)/x)] >>> pprint(dsolve(eq, hint='separable_reduced')) ___________ ___________ / 2 / 2 1 - \/ C1*x + 1 \/ C1*x + 1 + 1 [f(x) = ------------------, f(x) = ------------------] x x
- class sympy.solvers.ode.single.LieGroup(ode_problem)[源代码][源代码]¶
这个提示实现了求解一阶微分方程的李群方法。目的是将给定的微分方程从给定的坐标系转换到另一个坐标系,使其在单参数平移李群下不变。转换后的常微分方程可以通过求积容易地求解。它使用了
sympy.solvers.ode.infinitesimals()
函数,该函数返回变换的无穷小量。坐标 \(r\) 和 \(s\) 可以通过求解以下偏微分方程得到。
\[\xi\frac{\partial r}{\partial x} + \eta\frac{\partial r}{\partial y} = 0\]\[\xi\frac{\partial s}{\partial x} + \eta\frac{\partial s}{\partial y} = 1\]在新坐标系中,微分方程变为可分离的。
\[\frac{ds}{dr} = \frac{\frac{\partial s}{\partial x} + h(x, y)\frac{\partial s}{\partial y}}{\frac{\partial r}{\partial x} + h(x, y)\frac{\partial r}{\partial y}}\]通过积分找到解后,再通过将 \(r\) 和 \(s\) 用 \(x\) 和 \(y\) 表示代回去,转换回原来的坐标系。
- 属性:
- ode_problem
- 顺序
方法
get_general_solution
匹配
参考文献
通过对称群求解微分方程,John Starrett,第1页 - 第14页
示例
>>> from sympy import Function, dsolve, exp, pprint >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(f(x).diff(x) + 2*x*f(x) - x*exp(-x**2), f(x), ... hint='lie_group')) / 2\ 2 | x | -x f(x) = |C1 + --|*e \ 2 /
- class sympy.solvers.ode.single.SecondHypergeometric(ode_problem)[源代码][源代码]¶
求解二阶线性微分方程。
它计算可以用 2F1、1F1 或 0F1 超几何函数表示的特殊函数解。
\[y'' + A(x) y' + B(x) y = 0\text{,}\]其中 \(A\) 和 \(B\) 是有理函数。
这类微分方程的解具有非Liouvillian形式。
给定的线性常微分方程可以从由 2F1 给出的方程中获得
\[(x^2 - x) y'' + ((a + b + 1) x - c) y' + b a y = 0 ext{,}\]其中 {a, b, c} 是任意常数。
- 属性:
- ode_problem
- 顺序
方法
get_general_solution
匹配
注释
该算法应找到任何形式的解决方案
\[ \begin{align}\begin{aligned}y = P(x) _pF_q(..; ..;\frac{\alpha x^k + \beta}{\gamma x^k + \delta})\text{,}\\y = P(x) _pF_q(..; ..;\frac{\alpha x^k + \beta}{\gamma x^k + \delta})\text{,}\end{aligned}\end{align} \]其中 pFq 可以是 2F1、1F1 或 0F1,而 \(P\) 是一个“任意函数”。目前 SymPy 中仅实现了 2F1 的情况,但其他情况在论文中有描述,并可能在将来实现(欢迎贡献!)。
参考文献
“二阶线性常微分方程的非Liouvillian解” 作者:L. Chan, E.S. Cheb-Terrab
示例
>>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x >>> f = Function('f') >>> eq = (x*x - x)*f(x).diff(x,2) + (5*x - 1)*f(x).diff(x) + 4*f(x) >>> pprint(dsolve(eq, f(x), '2nd_hypergeometric')) _ / / 4 \\ |_ /-1, -1 | \ |C1 + C2*|log(x) + -----||* | | | x| \ \ x + 1// 2 1 \ 1 | / f(x) = -------------------------------------------- 3 (x - 1)
- sympy.solvers.ode.ode.ode_1st_power_series(eq, func, order, match)[源代码][源代码]¶
幂级数解法是一种给出微分方程解的泰勒级数展开的方法。
对于一阶微分方程 \(\frac{dy}{dx} = h(x, y)\),如果在 \(x = x_{0}\) 处 \(h(x, y)\) 是解析的,则存在幂级数解。该解由以下公式给出:
\[y(x) = y(x_{0}) + \sum_{n = 1}^{\infty} \frac{F_{n}(x_{0},b)(x - x_{0})^n}{n!},\]其中 \(y(x_{0}) = b\) 是 y 在初始值 \(x_{0}\) 处的值。为了计算 \(F_{n}(x_{0},b)\) 的值,遵循以下算法,直到生成所需数量的项。
\(F_1 = h(x_{0}, b)\)
\(F_{n+1} = \frac{\partial F_{n}}{\partial x} + \frac{\partial F_{n}}{\partial y}F_{1}\)
参考文献
Travis W. Walker, 解析幂级数技术用于求解一阶微分方程, p.p 17, 18
示例
>>> from sympy import Function, pprint, exp, dsolve >>> from sympy.abc import x >>> f = Function('f') >>> eq = exp(x)*(f(x).diff(x)) - f(x) >>> pprint(dsolve(eq, hint='1st_power_series')) 3 4 5 C1*x C1*x C1*x / 6\ f(x) = C1 + C1*x - ----- + ----- + ----- + O\x / 6 24 60
- sympy.solvers.ode.ode.ode_2nd_power_series_ordinary(
- eq,
- func,
- order,
- match,
给出一个在普通点处具有多项式系数的二阶齐次微分方程的幂级数解。齐次微分方程的形式为
\[P(x)\frac{d^2y}{dx^2} + Q(x)\frac{dy}{dx} + R(x) y(x) = 0\]为简单起见,假设 \(P(x)\)、\(Q(x)\) 和 \(R(x)\) 是多项式,只要 \(\frac{Q(x)}{P(x)}\) 和 \(\frac{R(x)}{P(x)}\) 在 \(x_{0}\) 处存在即可。通过将 \(y\) 替换为 \(\sum_{n=0}^\infty a_{n}x^{n}\),代入微分方程并使第 n 项相等,可以得到递推关系。利用此关系可以生成各种项。
参考文献
https://tutorial.math.lamar.edu/Classes/DE/SeriesSolutions.aspx
George E. Simmons, “微分方程:应用与历史笔记”, 第176 - 184页
示例
>>> from sympy import dsolve, Function, pprint >>> from sympy.abc import x >>> f = Function("f") >>> eq = f(x).diff(x, 2) + f(x) >>> pprint(dsolve(eq, hint='2nd_power_series_ordinary')) / 4 2 \ / 2\ |x x | | x | / 6\ f(x) = C2*|-- - -- + 1| + C1*x*|1 - --| + O\x / \24 2 / \ 6 /
- sympy.solvers.ode.ode.ode_2nd_power_series_regular(
- eq,
- func,
- order,
- match,
给出在正则点处具有多项式系数的二阶齐次微分方程的幂级数解。二阶齐次微分方程的形式为
\[P(x)\frac{d^2y}{dx^2} + Q(x)\frac{dy}{dx} + R(x) y(x) = 0\]如果 \(x - x0\frac{Q(x)}{P(x)}\) 和 \((x - x0)^{2}\frac{R(x)}{P(x)}\) 在 \(x0\) 处是解析的,则称点在 \(x0\) 处是规则奇异的。为简单起见,假设 \(P(x)\)、\(Q(x)\) 和 \(R(x)\) 是多项式。寻找幂级数解的算法是:
尝试将 \((x - x0)P(x)\) 和 \(((x - x0)^{2})Q(x)\) 表示为关于 x0 的幂级数解。找出 \(p0\) 和 \(q0\),它们是幂级数展开的常数项。
求解指标方程 \(f(m) = m(m - 1) + m*p0 + q0\),以获得指标方程的根 \(m1\) 和 \(m2\)。
如果 \(m1 - m2\) 是非整数,则存在两个级数解。如果 \(m1 = m2\),则只存在一个解。如果 \(m1 - m2\) 是整数,则确认存在一个解。另一个解可能存在也可能不存在。
幂级数解的形式为 \(x^{m}\sum_{n=0}^\infty a_{n}x^{n}\)。系数由以下递推关系确定。\(a_{n} = -\frac{\sum_{k=0}^{n-1} q_{n-k} + (m + k)p_{n-k}}{f(m + n)}\)。对于 \(m1 - m2\) 为整数的情况,从递推关系可以看出,对于较小的根 \(m\),当 \(n\) 等于两个根的差值时,分母变为零。因此,如果分子不等于零,则存在第二个级数解。
参考文献
George E. Simmons, “微分方程:应用与历史笔记”, 第176 - 184页
示例
>>> from sympy import dsolve, Function, pprint >>> from sympy.abc import x >>> f = Function("f") >>> eq = x*(f(x).diff(x, 2)) + 2*(f(x).diff(x)) + x*f(x) >>> pprint(dsolve(eq, hint='2nd_power_series_regular')) / 6 4 2 \ | x x x | / 4 2 \ C1*|- --- + -- - -- + 1| |x x | \ 720 24 2 / / 6\ f(x) = C2*|--- - -- + 1| + ------------------------ + O\x / \120 6 / x
Lie heuristics¶
这些函数旨在供李群求解器的内部使用。尽管如此,它们在其文档字符串中包含了关于为各种启发式算法所实现的算法的实用信息。
- sympy.solvers.ode.lie_group.lie_heuristic_abaco1_simple(match, comp=False)[源代码][源代码]¶
第一个启发式方法使用以下关于 \(\xi\) 和 \(\eta\) 的四组假设
\[\xi = 0, \eta = f(x)\]\[\xi = 0, \eta = f(y)\]\[\xi = f(x), \eta = 0\]\[\xi = f(y), \eta = 0\]这种启发式的成功取决于代数因式分解。对于第一个假设 \(\xi = 0\) 和 \(\eta\) 是 \(x\) 的函数,偏微分方程
\[\[\frac{\partial \eta}{\partial x} + \left(\frac{\partial \eta}{\partial y} - \frac{\partial \xi}{\partial x}\right)*h - \frac{\partial \xi}{\partial y}*h^{2} - \xi*\frac{\partial h}{\partial x} - \eta*\frac{\partial h}{\partial y} = 0\]\]简化为 \(f'(x) - f\frac{\partial h}{\partial y} = 0\) 如果 \(\frac{\partial h}{\partial y}\) 是 \(x\) 的函数,那么这通常可以很容易地积分。类似的思路也应用于其他3个假设中。
参考文献
E.S Cheb-Terrab, L.G.S Duarte 和 L.A,C.P da Mota,《使用对称方法的计算机代数求解一阶常微分方程》,第8页
- sympy.solvers.ode.lie_group.lie_heuristic_abaco1_product(match, comp=False)[源代码][源代码]¶
第二种启发式方法使用以下关于 \(\xi\) 和 \(\eta\) 的两个假设
\[\eta = 0, \xi = f(x)*g(y)\]\[\eta = f(x)*g(y), \xi = 0\]该启发式的第一个假设成立,如果 \(\frac{1}{h^{2}}\frac{\partial^2}{\partial x \partial y}\log(h)\) 在 \(x\) 和 \(y\) 中是可分离的,那么包含 \(x\) 的分离因子是 \(f(x)\),而 \(g(y)\) 是通过
\[e^{\int f\frac{\partial}{\partial x}\left(\frac{1}{f*h}\right)\,dy}\]假设 \(f\frac{\partial}{\partial x}\left(\frac{1}{f*h}\right)\) 仅是 \(y\) 的函数。
如果 \(\frac{dy}{dx} = h(x, y)\) 被重写为 \(\frac{dy}{dx} = \frac{1}{h(y, x)}\) 并且满足第一个假设的相同性质,那么第二个假设成立。在得到 \(f(x)\) 和 \(g(y)\) 之后,坐标再次互换,以得到 \(\eta\) 为 \(f(x)*g(y)\)
参考文献
E.S. Cheb-Terrab, A.D. Roche, 对称性与一阶ODE模式, 第7页 - 第8页
- sympy.solvers.ode.lie_group.lie_heuristic_bivariate(match, comp=False)[源代码][源代码]¶
第三个启发式假设无穷小量 \(\xi\) 和 \(\eta\) 是 \(x\) 和 \(y\) 中的二元多项式。下面逻辑的假设是 \(h\) 是 \(x\) 和 \(y\) 中的有理函数,尽管这可能不是无穷小量成为二元多项式的必要条件。通过将无穷小量代入偏微分方程并分组相似的多项式项来找出无穷小量的系数,因为它们形成了一个线性系统,解并检查非平凡解。假设的二元多项式的次数增加到某个最大值。
参考文献
李群与微分方程 第327页 - 第329页
- sympy.solvers.ode.lie_group.lie_heuristic_chi(match, comp=False)[源代码][源代码]¶
第四条启发式的目标是找到满足偏微分方程 \(\frac{d\chi}{dx} + h\frac{d\chi}{dx} - \frac{\partial h}{\partial y}\chi = 0\) 的函数 \(\chi(x, y)\)。
这里假设 \(\chi\) 是一个关于 \(x\) 和 \(y\) 的二元多项式。直觉上,\(h\) 应该是 \(x\) 和 \(y\) 的有理函数。这里使用的方法是用一个一般二项式替换 \(\chi\),直到达到某个最大次数。多项式的系数是通过收集 \(x\) 和 \(y\) 中相同次数的项来计算的。
在找到 \(\chi\) 之后,下一步是使用 \(\eta = \xi*h + \chi\) 来确定 \(\xi\) 和 \(\eta\)。这可以通过将 \(\chi\) 除以 \(h\) 来完成,这将给出 \(-\xi\) 作为商和 \(\eta\) 作为余数。
参考文献
E.S Cheb-Terrab, L.G.S Duarte 和 L.A,C.P da Mota,《使用对称方法的计算机代数求解一阶常微分方程》,第8页
- sympy.solvers.ode.lie_group.lie_heuristic_abaco2_similar(match, comp=False)[源代码][源代码]¶
该启发式算法基于对 \(\xi\) 和 \(\eta\) 的以下两个假设
\[\eta = g(x), \xi = f(x)\]\[\eta = f(y), \xi = g(y)\]对于第一个假设,
首先计算 \(\frac{\frac{\partial h}{\partial y}}{\frac{\partial^{2} h}{ \partial yy}}\)。假设这个值为 A
如果这是常数,那么 \(h\) 匹配为形式 \(A(x) + B(x)e^{ \frac{y}{C}}\),则 \(\frac{e^{\int \frac{A(x)}{C} \,dx}}{B(x)}\) 给出 \(f(x)\),而 \(A(x)*f(x)\) 给出 \(g(x)\)
否则 \(\frac{\frac{\partial A}{\partial X}}{\frac{\partial A}{ \partial Y}} = \gamma\) 将被计算。如果
a] \(\gamma\) 是 \(x\) 的函数
b] \(\frac{\gamma\frac{\partial h}{\partial y} - \gamma'(x) - \frac{ \partial h}{\partial x}}{h + \gamma} = G\) 是 \(x\) 的函数。那么,\(e^{\int G \,dx}\) 给出 \(f(x)\) 而 \(-\gamma*f(x)\) 给出 \(g(x)\)
第二个假设成立,如果 \(\frac{dy}{dx} = h(x, y)\) 被重写为 \(\frac{dy}{dx} = \frac{1}{h(y, x)}\) 并且满足第一个假设的相同性质。在得到 \(f(x)\) 和 \(g(x)\) 之后,坐标再次互换,以得到 \(\xi\) 为 \(f(x^*)\) 和 \(\eta\) 为 \(g(y^*)\)
参考文献
E.S. Cheb-Terrab, A.D. Roche, 对称性与一阶常微分方程模式, 第10页 - 第12页
- sympy.solvers.ode.lie_group.lie_heuristic_function_sum(match, comp=False)[源代码][源代码]¶
该启发式算法基于对 \(\xi\) 和 \(\eta\) 的以下两个假设
\[\eta = 0, \xi = f(x) + g(y)\]\[\eta = f(x) + g(y), \xi = 0\]如果这个启发式的第一个假设成立,那么
\[\frac{\partial}{\partial y}[(h\frac{\partial^{2}}{\partial x^{2}}(h^{-1}))^{-1}]\]在 \(x\) 和 \(y\) 中是可分离的,
包含 \(y\) 的分离因子是 \(\frac{\partial g}{\partial y}\)。由此可以确定 \(g(y)\)。
包含 \(x\) 的分离因子是 \(f''(x)\)。
\(h\frac{\partial^{2}}{\partial x^{2}}(h^{-1})\) 等于 \(\frac{f''(x)}{f(x) + g(y)}\)。由此可以确定 \(f(x)\)。
第二个假设成立,如果 \(\frac{dy}{dx} = h(x, y)\) 被改写为 \(\frac{dy}{dx} = \frac{1}{h(y, x)}\) 并且满足第一个假设的相同性质。在得到 \(f(x)\) 和 \(g(y)\) 之后,坐标再次互换,以得到 \(\eta\) 为 \(f(x) + g(y)\)。
对于这两种假设,常数因子分别分布在 \(g(y)\) 和 \(f''(x)\) 之间,使得从 [3] 中得到的 \(f''(x)\) 与从 [2] 中得到的相同。如果不可能,那么这个启发式方法失败。
参考文献
E.S. Cheb-Terrab, A.D. Roche, 对称性与一阶ODE模式, 第7页 - 第8页
- sympy.solvers.ode.lie_group.lie_heuristic_abaco2_unique_unknown(
- match,
- comp=False,
这种启发式方法假设存在未知函数或具有非整数幂的已知函数。
包含 x 和 y 的所有函数和非整数幂的列表
遍历列表中的每个元素 \(f\),找到 \(\frac{\frac{\partial f}{\partial x}}{ \frac{\partial f}{\partial x}} = R\)
如果它在 \(x\) 和 \(y\) 中是可分离的,设 \(X\) 为包含 \(x\) 的因子。然后
- a] 检查 \(\xi = X\) 和 \(\eta = -\frac{X}{R}\) 是否满足偏微分方程。如果是,则返回
\(\xi\) 和 \(\eta\)
- b] 检查 \(\xi = \frac{-R}{X}\) 和 \(\eta = -\frac{1}{X}\) 是否满足偏微分方程。
如果是,则返回 \(\xi\) 和 \(\eta\)
如果没有,那么检查是否
a] \(\xi = -R,\eta = 1\)
b] \(\xi = 1, \eta = -\frac{1}{R}\)
是解决方案。
参考文献
E.S. Cheb-Terrab, A.D. Roche, 对称性与一阶常微分方程模式, 第10页 - 第12页
- sympy.solvers.ode.lie_group.lie_heuristic_abaco2_unique_general(
- match,
- comp=False,
该启发式方法判断是否存在形如 \(\eta = f(x)\)、\(\xi = g(y)\) 的无穷小量,且不对 \(h\) 做任何假设。
完整的步骤序列在下面提到的论文中给出。
参考文献
E.S. Cheb-Terrab, A.D. Roche, 对称性与一阶常微分方程模式, 第10页 - 第12页
- sympy.solvers.ode.lie_group.lie_heuristic_linear(match, comp=False)[源代码][源代码]¶
这种启发式假设
\(\xi = ax + by + c\) 并且
\(\eta = fx + gy + h\)
在确定偏微分方程中代入以下假设后,它简化为
\[f + (g - a)h - bh^{2} - (ax + by + c)\frac{\partial h}{\partial x} - (fx + gy + c)\frac{\partial h}{\partial y}\]使用特征线法求解得到的简化偏微分方程变得不切实际。所采用的方法是将相似项分组并求解得到的线性方程组。与双变量启发式的区别在于,在这种情况下,\(h\) 不必是理性函数。
参考文献
E.S. Cheb-Terrab, A.D. Roche, 对称性与一阶常微分方程模式, 第10页 - 第12页
Rational Riccati 求解器¶
这些函数旨在用于内部使用,以解决至少具有一个有理特解的一阶Riccati微分方程。
- sympy.solvers.ode.riccati.riccati_normal(w, x, b1, b2)[源代码][源代码]¶
给定方程的解 \(w(x)\)
\[w'(x) = b_0(x) + b_1(x)*w(x) + b_2(x)*w(x)^2\]以及有理函数系数 \(b_1(x)\) 和 \(b_2(x)\),此函数转换解以给出其对应的标准 Riccati ODE 的解 \(y(x)\)。
\[y'(x) + y(x)^2 = a(x)\]使用转换
\[y(x) = -b_2(x)*w(x) - b'_2(x)/(2*b_2(x)) - b_1(x)/2\]
- sympy.solvers.ode.riccati.riccati_inverse_normal(y, x, b1, b2, bp=None)[源代码][源代码]¶
将解逆变换回标准Riccati常微分方程,以获得Riccati常微分方程的解。
- sympy.solvers.ode.riccati.riccati_reduced(eq, f, x)[源代码][源代码]¶
将一个 Riccati 常微分方程转换为其对应的正常 Riccati 常微分方程。
- sympy.solvers.ode.riccati.rational_laurent_series(num, den, x, r, m, n)[源代码][源代码]¶
该函数计算有理函数的Laurent级数系数。
- 参数:
- num: 一个 Poly 对象,是 `f(x)` 的分子。
- den: 一个 Poly 对象,是 `f(x)` 的分母。
- x: 级数展开的变量。
- r: 级数的展开点。
- m: 如果 r 是 `f(x)` 的极点,r 的重数。应该
- 否则为零。
- n: 展开级数的项的阶数。
- 返回:
- series: 一个以项的幂次为键的字典
- 并将该项的系数作为值。
- 以下是关于如何求解一个
- 关于 \(x_0\) 的 \(f(x)\) 的有理函数正在计算中 -
- 用 \(x + x_0\) 替换 \(x\)。如果 \(x_0\)
- 是 \(f(x)\) 的极点,将表达式乘以 \(x^m\)
- 其中 \(m\) 是 \(x_0\) 的重数。记为
- 将结果表达式记为 g(x)。我们进行这种替换。
- 以便我们现在可以找到 g(x) 关于的洛朗级数
- \(x = 0\).
- 我们可以假设 \(g(x)\) 的洛朗级数为
- 采用以下形式 -
\[g(x) = \frac{num(x)}{den(x)} = \sum_{m = 0}^{\infty} a_m x^m ..\]- 其中 \(a_m\) 表示洛朗级数的系数。
- 将分母乘以方程的右侧
- 并形成系数 \(a_m\) 的递推关系。
- sympy.solvers.ode.riccati.compute_m_ybar(x, poles, choice, N)[源代码][源代码]¶
用于计算的辅助函数 -
1. m - The degree bound for the polynomial solution that must be found for the auxiliary differential equation.
2. ybar - Part of the solution which can be computed using the poles, c and d vectors.
- sympy.solvers.ode.riccati.solve_aux_eq(numa, dena, numy, deny, x, m)[源代码][源代码]¶
用于找到辅助微分方程的m次多项式解的辅助函数。
ODE 系统¶
这些函数旨在供 dsolve()
在处理微分方程系统时内部使用。
- sympy.solvers.ode.ode._linear_2eq_order1_type6(x, y, t, r, eq)[源代码][源代码]¶
这种类型的常微分方程的方程是。
\[x' = f(t) x + g(t) y\]\[y' = a [f(t) + a h(t)] x + a [g(t) - h(t)] y\]这是通过首先将第一个方程乘以 \(-a\) 并将其加到第二个方程中来解决的
\[y' - a x' = -a h(t) (y - a x)\]设定 \(U = y - ax\) 并积分方程,我们得到
\[y - ax = C_1 e^{-a \int h(t) \,dt}\]并且在将 y 的值代入第一个方程后,会产生一阶常微分方程。在求解 \(x\) 之后,我们可以通过将 \(x\) 的值代入第二个方程来获得 \(y\)。
- sympy.solvers.ode.ode._linear_2eq_order1_type7(x, y, t, r, eq)[源代码][源代码]¶
这种类型的常微分方程的方程是。
\[x' = f(t) x + g(t) y\]\[y' = h(t) x + p(t) y\]对第一个方程求导并将第二个方程中的 \(y\) 值代入,将得到一个二阶线性方程
\[g x'' - (fg + gp + g') x' + (fgp - g^{2} h + f g' - f' g) x = 0\]如果满足以下条件,上述方程可以很容易地积分。
\(fgp - g^{2} h + f g' - f' g = 0\)
\(fg - g^{2} h + f g' - f' g = ag, fg + gp + g' = bg\)
如果满足第一个条件,则由当前的 dsolve 求解器解决,而在第二种情况下,它变成一个常系数微分方程,同样由当前的求解器解决。
否则,如果上述条件失败,则假设一个特定解为 \(x = x_0(t)\) 和 \(y = y_0(t)\)。然后,通解表示为
\[x = C_1 x_0(t) + C_2 x_0(t) \int \frac{g(t) F(t) P(t)}{x_0^{2}(t)} \,dt\]\[y = C_1 y_0(t) + C_2 [\frac{F(t) P(t)}{x_0(t)} + y_0(t) \int \frac{g(t) F(t) P(t)}{x_0^{2}(t)} \,dt]\]其中 C1 和 C2 是任意常数,并且
\[F(t) = e^{\int f(t) \,dt}, P(t) = e^{\int p(t) \,dt}\]
- sympy.solvers.ode.systems.linear_ode_to_matrix(eqs, funcs, t, order)[源代码][源代码]¶
将一个线性常微分方程组转换为矩阵形式
- 参数:
- eqsSymPy 表达式或等式的列表
作为表达式的方程(假设等于零)。
- 函数应用函数的列表
ODE 系统的因变量。
- t符号
自变量。
- 顺序整数
常微分方程系统的阶数。
- 返回:
- 元组
(As, b)
其中As
是一个矩阵元组,b
是 - 表示矩阵方程右侧的矩阵。
- 元组
- Raises:
- ODEOrderError
当常微分方程系统的阶数大于指定值时
- ODENonlinearError
当常微分方程组是非线性时
参见
linear_eq_to_matrix
用于线性代数方程组。
参考文献
[1]示例
>>> from sympy import Function, Symbol, Matrix, Eq >>> from sympy.solvers.ode.systems import linear_ode_to_matrix >>> t = Symbol('t') >>> x = Function('x') >>> y = Function('y')
我们可以创建一个线性常微分方程系统,例如
>>> eqs = [ ... Eq(x(t).diff(t), x(t) + y(t) + 1), ... Eq(y(t).diff(t), x(t) - y(t)), ... ] >>> funcs = [x(t), y(t)] >>> order = 1 # 1st order system
现在
linear_ode_to_matrix
可以将此表示为矩阵微分方程。>>> (A1, A0), b = linear_ode_to_matrix(eqs, funcs, t, order) >>> A1 Matrix([ [1, 0], [0, 1]]) >>> A0 Matrix([ [1, 1], [1, -1]]) >>> b Matrix([ [1], [0]])
可以从这些矩阵中恢复原始方程:
>>> eqs_mat = Matrix([eq.lhs - eq.rhs for eq in eqs]) >>> X = Matrix(funcs) >>> A1 * X.diff(t) - A0 * X - b == eqs_mat True
如果方程组的最高阶数大于指定的系统阶数,则会引发 ODEOrderError 异常。
>>> eqs = [Eq(x(t).diff(t, 2), x(t).diff(t) + x(t)), Eq(y(t).diff(t), y(t) + x(t))] >>> linear_ode_to_matrix(eqs, funcs, t, 1) Traceback (most recent call last): ... ODEOrderError: Cannot represent system in 1-order form
如果方程组是非线性的,则引发 ODENonlinearError。
>>> eqs = [Eq(x(t).diff(t), x(t) + y(t)), Eq(y(t).diff(t), y(t)**2 + x(t))] >>> linear_ode_to_matrix(eqs, funcs, t, 1) Traceback (most recent call last): ... ODENonlinearError: The system of ODEs is nonlinear.
- sympy.solvers.ode.systems.canonical_odes(eqs, funcs, t)[源代码][源代码]¶
求解系统中最高阶导数的函数
- 参数:
- eqs列表
ODEs 列表
- 函数列表
依赖变量列表
- t符号
自变量
- 返回:
- 列表
示例
>>> from sympy import symbols, Function, Eq, Derivative >>> from sympy.solvers.ode.systems import canonical_odes >>> f, g = symbols("f g", cls=Function) >>> x, y = symbols("x y") >>> funcs = [f(x), g(x)] >>> eqs = [Eq(f(x).diff(x) - 7*f(x), 12*g(x)), Eq(g(x).diff(x) + g(x), 20*f(x))]
>>> canonical_eqs = canonical_odes(eqs, funcs, x) >>> canonical_eqs [[Eq(Derivative(f(x), x), 7*f(x) + 12*g(x)), Eq(Derivative(g(x), x), 20*f(x) - g(x))]]
>>> system = [Eq(Derivative(f(x), x)**2 - 2*Derivative(f(x), x) + 1, 4), Eq(-y*f(x) + Derivative(g(x), x), 0)]
>>> canonical_system = canonical_odes(system, funcs, x) >>> canonical_system [[Eq(Derivative(f(x), x), -1), Eq(Derivative(g(x), x), y*f(x))], [Eq(Derivative(f(x), x), 3), Eq(Derivative(g(x), x), y*f(x))]]
- sympy.solvers.ode.systems.linodesolve_type(A, t, b=None)[源代码][源代码]¶
Helper function that determines the type of the system of ODEs for solving with
sympy.solvers.ode.systems.linodesolve()
- 参数:
- A矩阵
ODEs 系统的系数矩阵
- b矩阵或无
系统的非齐次项。默认值为 None。如果此参数为 None,则假定系统是齐次的。
- 返回:
- 字典
- Raises:
- NotImplementedError
当系数矩阵没有交换的反导数时
参见
linodesolve
获取信息的函数,其中 linodesolve_type 获取信息
示例
>>> from sympy import symbols, Matrix >>> from sympy.solvers.ode.systems import linodesolve_type >>> t = symbols("t") >>> A = Matrix([[1, 1], [2, 3]]) >>> b = Matrix([t, 1])
>>> linodesolve_type(A, t) {'antiderivative': None, 'type_of_equation': 'type1'}
>>> linodesolve_type(A, t, b=b) {'antiderivative': None, 'type_of_equation': 'type2'}
>>> A_t = Matrix([[1, t], [-t, 1]])
>>> linodesolve_type(A_t, t) {'antiderivative': Matrix([ [ t, t**2/2], [-t**2/2, t]]), 'type_of_equation': 'type3'}
>>> linodesolve_type(A_t, t, b=b) {'antiderivative': Matrix([ [ t, t**2/2], [-t**2/2, t]]), 'type_of_equation': 'type4'}
>>> A_non_commutative = Matrix([[1, t], [t, -1]]) >>> linodesolve_type(A_non_commutative, t) Traceback (most recent call last): ... NotImplementedError: The system does not have a commutative antiderivative, it cannot be solved by linodesolve.
- sympy.solvers.ode.systems.matrix_exp_jordan_form(A, t)[源代码][源代码]¶
矩阵指数 \(\exp(A*t)\) 对于矩阵 A 和标量 t。
- 参数:
- A矩阵
表达式 \(\exp(A*t)\) 中的矩阵 \(A\)
- t符号
自变量
参考文献
[3]https://en.wikipedia.org/wiki/Jordan_标准型
示例
>>> from sympy import Matrix, Symbol >>> from sympy.solvers.ode.systems import matrix_exp, matrix_exp_jordan_form >>> t = Symbol('t')
我们将考虑一个2x2的缺陷矩阵。这表明我们的方法即使对于缺陷矩阵也有效。
>>> A = Matrix([[1, 1], [0, 1]])
可以看出,这个函数为我们提供了Jordan标准型以及所需的逆矩阵P。
>>> P, expJ = matrix_exp_jordan_form(A, t)
这里,显示了该函数返回的 P 和 expJ 是正确的,因为它们满足公式:P * expJ * P_inverse = exp(A*t)。
>>> P * expJ * P.inv() == matrix_exp(A, t) True
- sympy.solvers.ode.systems.matrix_exp(A, t)[源代码][源代码]¶
矩阵指数 \(\exp(A*t)\) 对于矩阵
A
和标量t
。- 参数:
- A矩阵
表达式 \(\exp(A*t)\) 中的矩阵 \(A\)
- t符号
自变量
参见
matrix_exp_jordan_form
对于若尔当标准型的指数
参考文献
[1]https://en.wikipedia.org/wiki/Jordan_标准型
[2]示例
>>> from sympy import Symbol, Matrix, pprint >>> from sympy.solvers.ode.systems import matrix_exp >>> t = Symbol('t')
我们将考虑一个2x2矩阵来计算指数
>>> A = Matrix([[2, -5], [2, -4]]) >>> pprint(A) [2 -5] [ ] [2 -4]
现在,exp(A*t) 给出如下:
>>> pprint(matrix_exp(A, t)) [ -t -t -t ] [3*e *sin(t) + e *cos(t) -5*e *sin(t) ] [ ] [ -t -t -t ] [ 2*e *sin(t) - 3*e *sin(t) + e *cos(t)]
- sympy.solvers.ode.systems.linodesolve(
- A,
- t,
- b=None,
- B=None,
- type='auto',
- doit=False,
- tau=None,
n 个方程的线性一阶微分方程系统
- 参数:
- A矩阵
线性一阶常微分方程组的系数矩阵。
- t符号
ODEs 系统中的自变量。
- b矩阵或无
ODEs 系统中的非齐次项。如果传递 None,则假设为齐次 ODEs 系统。
- B矩阵或无
系数矩阵的反导数。如果未传递反导数且解需要该项,则求解器将在内部计算它。
- 类型字符串
传递的ODE系统的类型。根据类型,评估解决方案。允许的类型值及其对应的系统解决方法为:“type1”用于常系数齐次系统,“type2”用于常系数非齐次系统,“type3”用于非常系数齐次系统,“type4”用于非常系数非齐次系统,“type5”和“type6”分别用于非常系数齐次和非齐次系统,其中系数矩阵可以分解为常系数矩阵。默认值为“auto”,这将让求解器决定传递系统的正确类型。
- 执行布尔值
如果为真,则评估解决方案,默认值为假
- tau: 表达式
用于替代系统解得后 \(t\) 的值。
- 返回:
- 列表
- Raises:
- ValueError
当系数矩阵、非齐次项或传递的反导数不是矩阵或没有正确维度时,会引发此错误。
- NonSquareMatrixError
当系数矩阵或其反导数(如果传递的话)不是方阵时
- NotImplementedError
如果系数矩阵没有交换的反导数
参见
linear_ode_to_matrix
系数矩阵计算函数
canonical_odes
ODEs 系统表示的变化
linodesolve_type
获取关于 ODE 系统的信息以传递给此求解器
示例
要使用此函数直接求解常微分方程组,必须按正确的顺序完成几件事情。向函数输入错误的内容将导致错误的结果。
>>> from sympy import symbols, Function, Eq >>> from sympy.solvers.ode.systems import canonical_odes, linear_ode_to_matrix, linodesolve, linodesolve_type >>> from sympy.solvers.ode.subscheck import checkodesol >>> f, g = symbols("f, g", cls=Function) >>> x, a = symbols("x, a") >>> funcs = [f(x), g(x)] >>> eqs = [Eq(f(x).diff(x) - f(x), a*g(x) + 1), Eq(g(x).diff(x) + g(x), a*f(x))]
Here, it is important to note that before we derive the coefficient matrix, it is important to get the system of ODEs into the desired form. For that we will use
sympy.solvers.ode.systems.canonical_odes()
.>>> eqs = canonical_odes(eqs, funcs, x) >>> eqs [[Eq(Derivative(f(x), x), a*g(x) + f(x) + 1), Eq(Derivative(g(x), x), a*f(x) - g(x))]]
Now, we will use
sympy.solvers.ode.systems.linear_ode_to_matrix()
to get the coefficient matrix and the non-homogeneous term if it is there.>>> eqs = eqs[0] >>> (A1, A0), b = linear_ode_to_matrix(eqs, funcs, x, 1) >>> A = A0
We have the coefficient matrices and the non-homogeneous term ready. Now, we can use
sympy.solvers.ode.systems.linodesolve_type()
to get the information for the system of ODEs to finally pass it to the solver.>>> system_info = linodesolve_type(A, x, b=b) >>> sol_vector = linodesolve(A, x, b=b, B=system_info['antiderivative'], type=system_info['type_of_equation'])
Now, we can prove if the solution is correct or not by using
sympy.solvers.ode.checkodesol()
>>> sol = [Eq(f, s) for f, s in zip(funcs, sol_vector)] >>> checkodesol(eqs, sol) (True, [0, 0])
我们也可以使用 doit 方法来评估函数传递的解决方案。
>>> sol_vector_evaluated = linodesolve(A, x, b=b, type="type2", doit=True)
现在,我们将研究一个非定常的常微分方程组。
>>> eqs = [Eq(f(x).diff(x), f(x) + x*g(x)), Eq(g(x).diff(x), -x*f(x) + g(x))]
上述定义的系统已经处于所需的形式,因此我们不需要进行转换。
>>> (A1, A0), b = linear_ode_to_matrix(eqs, funcs, x, 1) >>> A = A0
A user can also pass the commutative antiderivative required for type3 and type4 system of ODEs. Passing an incorrect one will lead to incorrect results. If the coefficient matrix is not commutative with its antiderivative, then
sympy.solvers.ode.systems.linodesolve_type()
raises a NotImplementedError. If it does have a commutative antiderivative, then the function just returns the information about the system.>>> system_info = linodesolve_type(A, x, b=b)
现在,我们可以将反导数作为参数传递以获得解决方案。如果没有传递系统信息,那么求解器将在内部计算所需的参数。
>>> sol_vector = linodesolve(A, x, b=b)
再次,我们可以验证得到的解。
>>> sol = [Eq(f, s) for f, s in zip(funcs, sol_vector)] >>> checkodesol(eqs, sol) (True, [0, 0])
- sympy.solvers.ode.ode._nonlinear_2eq_order1_type1(x, y, t, eq)[源代码][源代码]¶
方程式:
\[x' = x^n F(x,y)\]\[y' = g(y) F(x,y)\]解决方案:
\[x = \varphi(y), \int \frac{1}{g(y) F(\varphi(y),y)} \,dy = t + C_2\]哪里
如果 \(n \neq 1\)
\[\varphi = [C_1 + (1-n) \int \frac{1}{g(y)} \,dy]^{\frac{1}{1-n}}\]如果 \(n = 1\)
\[\varphi = C_1 e^{\int \frac{1}{g(y)} \,dy}\]其中 \(C_1\) 和 \(C_2\) 是任意常数。
- sympy.solvers.ode.ode._nonlinear_2eq_order1_type2(x, y, t, eq)[源代码][源代码]¶
方程式:
\[x' = e^{\lambda x} F(x,y)\]\[y' = g(y) F(x,y)\]解决方案:
\[x = \varphi(y), \int \frac{1}{g(y) F(\varphi(y),y)} \,dy = t + C_2\]哪里
如果 \(\lambda \neq 0\)
\[\varphi = -\frac{1}{\lambda} log(C_1 - \lambda \int \frac{1}{g(y)} \,dy)\]如果 \(\lambda = 0\)
\[\varphi = C_1 + \int \frac{1}{g(y)} \,dy\]其中 \(C_1\) 和 \(C_2\) 是任意常数。
- sympy.solvers.ode.ode._nonlinear_2eq_order1_type3(x, y, t, eq)[源代码][源代码]¶
一般形式的自治系统
\[x' = F(x,y)\]\[y' = G(x,y)\]假设 \(y = y(x, C_1)\) 其中 \(C_1\) 是一个任意常数,是这个一阶方程的通解。
\[F(x,y) y'_x = G(x,y)\]那么原方程组的一般解具有以下形式
\[\int \frac{1}{F(x,y(x,C_1))} \,dx = t + C_1\]
- sympy.solvers.ode.ode._nonlinear_2eq_order1_type4(x, y, t, eq)[源代码][源代码]¶
方程式:
\[x' = f_1(x) g_1(y) \phi(x,y,t)\]\[y' = f_2(x) g_2(y) \phi(x,y,t)\]第一个积分:
\[\int \frac{f_2(x)}{f_1(x)} \,dx - \int \frac{g_1(y)}{g_2(y)} \,dy = C\]其中 \(C\) 是一个任意常数。
在求解 \(x`(或 `y\))的第一个积分并将所得表达式代入原始解的任一方程后,可以得到一个用于确定 \(y`(或 `x\))的一阶方程。
- sympy.solvers.ode.ode._nonlinear_2eq_order1_type5(func, t, eq)[源代码][源代码]¶
Clairaut 常微分方程组
\[x = t x' + F(x',y')\]\[y = t y' + G(x',y')\]以下是系统的解
\((i)\) 直线:
\[x = C_1 t + F(C_1, C_2), y = C_2 t + G(C_1, C_2)\]其中 \(C_1\) 和 \(C_2\) 是任意常数;
\((ii)\) 上述线条的包络;
\((iii)\) 由 \((i)\) 和 \((ii)\) 的线段组成的连续可微曲线。
- sympy.solvers.ode.ode._nonlinear_3eq_order1_type1(x, y, z, t, eq)[源代码][源代码]¶
方程式:
\[ \begin{align}\begin{aligned}a x' = (b - c) y z, \enspace b y' = (c - a) z x, \enspace c z' = (a - b) x y\\a x' = (b - c) y z, \enspace b y' = (c - a) z x, \enspace c z' = (a - b) x y\end{aligned}\end{align} \]首次积分:
\[a x^{2} + b y^{2} + c z^{2} = C_1\]\[a^{2} x^{2} + b^{2} y^{2} + c^{2} z^{2} = C_2\]其中 \(C_1\) 和 \(C_2\) 是任意常数。在求解 \(y\) 和 \(z\) 的积分并将结果表达式代入系统的第一个方程后,我们得到一个关于 \(x\) 的可分离的一阶方程。同样地,对其他两个方程进行类似操作,我们也将得到关于 \(y\) 和 \(z\) 的一阶方程。
参考文献
- sympy.solvers.ode.ode._nonlinear_3eq_order1_type2(x, y, z, t, eq)[源代码][源代码]¶
方程式:
\[a x' = (b - c) y z f(x, y, z, t)\]\[b y' = (c - a) z x f(x, y, z, t)\]\[c z' = (a - b) x y f(x, y, z, t)\]首次积分:
\[a x^{2} + b y^{2} + c z^{2} = C_1\]\[a^{2} x^{2} + b^{2} y^{2} + c^{2} z^{2} = C_2\]其中 \(C_1\) 和 \(C_2\) 是任意常数。在求解 \(y\) 和 \(z\) 的积分并将所得表达式代入系统的第一个方程后,我们得到了一个关于 \(x\) 的一阶微分方程。同样地,对其他两个方程进行类似操作,我们将得到关于 \(y\) 和 \(z\) 的一阶方程。
参考文献
- sympy.solvers.ode.ode._nonlinear_3eq_order1_type3(x, y, z, t, eq)[源代码][源代码]¶
方程式:
\[x' = c F_2 - b F_3, \enspace y' = a F_3 - c F_1, \enspace z' = b F_1 - a F_2\]其中 \(F_n = F_n(x, y, z, t)\)。
第一积分:
\[a x + b y + c z = C_1,\]其中 C 是任意常数。
2. If we assume function \(F_n\) to be independent of \(t\),i.e, \(F_n\) = \(F_n (x, y, z)\) Then, on eliminating \(t\) and \(z\) from the first two equation of the system, one arrives at the first-order equation
\[\[\frac{dy}{dx} = \frac{a F_3 (x, y, z) - c F_1 (x, y, z)}{c F_2 (x, y, z) - b F_3 (x, y, z)}\]\]其中 \(z = \frac{1}{c} (C_1 - a x - b y)\)
参考文献
- sympy.solvers.ode.ode._nonlinear_3eq_order1_type4(x, y, z, t, eq)[源代码][源代码]¶
方程式:
\[ \begin{align}\begin{aligned}x' = c z F_2 - b y F_3, \enspace y' = a x F_3 - c z F_1, \enspace z' = b y F_1 - a x F_2\\x' = c z F_2 - b y F_3, \enspace y' = a x F_3 - c z F_1, \enspace z' = b y F_1 - a x F_2\end{aligned}\end{align} \]其中 \(F_n = F_n (x, y, z, t)\)
第一个积分:
\[a x^{2} + b y^{2} + c z^{2} = C_1\]其中 \(C\) 是一个任意常数。
2. Assuming the function \(F_n\) is independent of \(t\): \(F_n = F_n (x, y, z)\). Then on eliminating \(t\) and \(z\) from the first two equations of the system, one arrives at the first-order equation
\[\frac{dy}{dx} = \frac{a x F_3 (x, y, z) - c z F_1 (x, y, z)} {c z F_2 (x, y, z) - b y F_3 (x, y, z)}\]其中 \(z = \pm \sqrt{\frac{1}{c} (C_1 - a x^{2} - b y^{2})}\)
参考文献
- sympy.solvers.ode.ode._nonlinear_3eq_order1_type5(x, y, z, t, eq)[源代码][源代码]¶
- \[x' = x (c F_2 - b F_3), \enspace y' = y (a F_3 - c F_1), \enspace z' = z (b F_1 - a F_2)\]
其中 \(F_n = F_n (x, y, z, t)\) 并且是任意函数。
第一积分:
\[\left|x\right|^{a} \left|y\right|^{b} \left|z\right|^{c} = C_1\]其中 \(C\) 是一个任意常数。如果函数 \(F_n\) 与 \(t\) 无关,那么通过消去系统前两个方程中的 \(t\) 和 \(z\),可以得到一个一阶方程。
参考文献
关于 ode 模块的信息¶
此模块包含 dsolve()
及其使用的不同辅助函数。
dsolve()
解决常微分方程。查看各个函数的文档字符串以了解其用途。请注意,偏微分方程的支持在 pde.py
中。请注意,提示函数有文档字符串描述它们的多种方法,但它们主要用于内部使用。使用 dsolve(ode, func, hint=hint)
来使用特定提示解决一个ODE。另请参阅 dsolve()
的文档字符串。
本模块中的函数
这些是本模块中的用户函数:
dsolve()
- 求解常微分方程。
classify_ode()
- 将常微分方程分类为可能的提示,用于dsolve()
。
checkodesol()
- 检查一个方程是否是某个ODE的解。
homogeneous_order()
- 返回表达式的齐次阶数。
infinitesimals()
- 返回常微分方程的点变换李群的无穷小,使得该方程不变。
checkinfsol()
- 检查给定的无穷小是否是一个一阶常微分方程的实际无穷小。这些是非求解器辅助函数,供内部使用。用户应使用
dsolve()
的各种选项来获取这些函数提供的功能:
odesimp()
- 执行所有形式的ODE简化。
ode_sol_simplicity()
- 一个用于通过简单性比较解的关键函数。
constantsimp()
- 简化任意常数。
constant_renumber()
- 重新编号任意常数。
_handle_Integral()
- 计算未计算的积分。另请参阅这些函数的文档字符串。
当前实现的求解器方法
以下方法用于求解常微分方程。有关每种方法的更多信息,请参阅各种提示函数的文档字符串(运行 help(ode)
):
本模块背后的哲学
这个模块旨在使添加新的常微分方程(ODE)求解方法变得容易,而无需处理其他方法的求解代码。其思路是有一个 classify_ode()
函数,它接收一个ODE并告诉你,如果有的话,哪些提示可以求解该ODE。它不尝试求解ODE,因此速度很快。每个求解方法都是一个提示,并且它有自己的函数,命名为 ode_<hint>
。该函数接收ODE和由 classify_ode()
收集的任何匹配表达式,并返回一个已求解的结果。如果这个结果包含任何积分,提示函数将返回一个未求值的 Integral
类。 dsolve()
是所有这些的用户包装函数,它将调用 odesimp()
处理结果,其中,除了其他事项外,还将尝试求解方程中的因变量(我们正在求解的函数),简化表达式中的任意常数,并在提示允许的情况下求值任何积分。
如何添加新的解决方案方法
如果你有一个希望 dsolve()
能够求解的常微分方程(ODE),尽量避免在这里添加特殊情况的代码。相反,尝试找到一种能够解决你的ODE以及其他ODE的通用方法。这样,ode
模块将变得更加健壮,并且不会被特殊情况的技巧所阻碍。WolphramAlpha 和 Maple 的 DETools[odeadvisor] 函数是你用来分类特定ODE的两个资源。如果可能的话,一个方法最好能够处理 \(n\) 阶ODE,而不仅仅限于特定的阶数。
To add a new method, there are a few things that you need to do. First, you
need a hint name for your method. Try to name your hint so that it is
unambiguous with all other methods, including ones that may not be implemented
yet. If your method uses integrals, also include a hint_Integral
hint.
If there is more than one way to solve ODEs with your method, include a hint
for each one, as well as a <hint>_best
hint. Your ode_<hint>_best()
function should choose the best using min with ode_sol_simplicity
as the
key argument. See
HomogeneousCoeffBest
, for example.
The function that uses your method will be called ode_<hint>()
, so the
hint must only use characters that are allowed in a Python function name
(alphanumeric characters and the underscore ‘_
’ character). Include a
function for every hint, except for _Integral
hints
(dsolve()
takes care of those automatically).
Hint names should be all lowercase, unless a word is commonly capitalized
(such as Integral or Bernoulli). If you have a hint that you do not want to
run with all_Integral
that does not have an _Integral
counterpart (such
as a best hint that would defeat the purpose of all_Integral
), you will
need to remove it manually in the dsolve()
code.
See also the classify_ode()
docstring for
guidelines on writing a hint name.
确定 一般而言 你的方法返回的解与其他可能解决相同常微分方程的方法相比如何。然后,将你的提示按它们应被调用的顺序放入 allhints
元组中。此元组的顺序决定了哪些提示是默认的。请注意,异常是可以接受的,因为用户很容易通过 dsolve()
选择个别提示。一般而言,_Integral
变体应放在列表的末尾,而 _best
变体应放在它们所适用的各种提示之前。例如,undetermined_coefficients
提示出现在 variation_of_parameters
提示之前,因为尽管变分参数比待定系数更通用,但待定系数通常对于它能解决的常微分方程返回更简洁的结果,并且它不需要积分,因此速度更快。
接下来,你需要有一个匹配表达式或函数来匹配ODE的类型,你应该将其放入 classify_ode()
中(如果匹配函数不仅仅是几行代码)。它应该尽可能在不求解ODE的情况下进行匹配,以确保 classify_ode()
保持快速并且不会被求解代码中的错误所阻碍。务必考虑边界情况。例如,如果你的求解方法涉及除以某个数,请确保排除该除数为0的情况。
在大多数情况下,ODE的匹配也会给你提供解决它所需的各种部分。你应该将这些部分放入一个字典中(.match()
会为你完成这个任务),并在 classify_ode()
的相关部分中将其添加为 matching_hints['hint'] = matchdict
。classify_ode()
随后会将此发送给 dsolve()
,后者会将其作为 match
参数发送给你的函数。你的函数应命名为 ode_<hint>(eq, func, order, match)`。如果你需要传递更多信息,请将其放入 ``match
字典中。例如,如果你在 classify_ode()
中必须替换一个虚拟变量以匹配ODE,你将需要使用 match
字典将其传递给你的函数以访问它。你可以使用 func.args[0]
访问自变量,使用 func.func
访问因变量(即你试图求解的函数)。如果在尝试求解ODE时发现无法求解,请引发 NotImplementedError
。dsolve()
会使用 all
元提示捕获此错误,而不是导致整个程序失败。
为你的函数添加一个描述所使用方法的文档字符串。与SymPy中的其他内容一样,你需要在文档字符串中添加一个doctest,此外还需要在``test_ode.py``中添加实际测试。尽量保持与其他提示函数文档字符串的一致性。将你的方法添加到此文档字符串顶部的列表中。同时,将你的方法添加到``docs/src``目录下的``ode.rst``文件中,以便Sphinx文档能够将它的文档字符串拉入SymPy主文档中。确保通过从doc目录中运行``make html``来生成Sphinx文档,以验证文档字符串格式是否正确。
If your solution method involves integrating, use Integral
instead of
integrate()
. This allows the user to bypass
hard/slow integration by using the _Integral
variant of your hint. In
most cases, calling sympy.core.basic.Basic.doit()
will integrate your
solution. If this is not the case, you will need to write special code in
_handle_Integral()
. Arbitrary constants should be
symbols named C1
, C2
, and so on. All solution methods should return
an equality instance. If you need an arbitrary number of arbitrary constants,
you can use constants = numbered_symbols(prefix='C', cls=Symbol, start=1)
.
If it is possible to solve for the dependent function in a general way, do so.
Otherwise, do as best as you can, but do not call solve in your
ode_<hint>()
function. odesimp()
will attempt
to solve the solution for you, so you do not need to do that. Lastly, if your
ODE has a common simplification that can be applied to your solutions, you can
add a special case in odesimp()
for it. For
example, solutions returned from the 1st_homogeneous_coeff
hints often
have many log
terms, so
odesimp()
calls
logcombine()
on them (it also helps to write
the arbitrary constant as log(C1)
instead of C1
in this case). Also
consider common ways that you can rearrange your solution to have
constantsimp()
take better advantage of it. It is
better to put simplification in odesimp()
than in
your method, because it can then be turned off with the simplify flag in
dsolve()
. If you have any extraneous
simplification in your function, be sure to only run it using if
match.get('simplify', True):
, especially if it can be slow or if it can
reduce the domain of the solution.
最后,与SymPy的每一次贡献一样,您的方法需要经过测试。在 test_ode.py
中为每个方法添加测试。遵循那里的惯例,即使用 dsolve(eq, f(x), hint=your_hint)
测试求解器,并使用 checkodesol()
测试解(您可以将这些测试放在单独的测试中,如果运行太慢或无法工作,可以跳过/XFAIL)。确保在 dsolve()
中明确调用您的提示,这样测试就不会仅仅因为引入另一个匹配的提示而中断。如果您的方程适用于高阶(>1)ODE,您需要为每个解运行 sol = constant_renumber(sol, 'C', 1, order)
,其中 order
是ODE的阶数。这是因为 constant_renumber
根据打印顺序对任意常数进行重新编号,而打印顺序是平台相关的。尽量测试求解器的每个角落情况,包括如果它是 \(n\)阶求解器,则测试一系列阶数,但如果您的求解器很慢,例如如果它涉及复杂的积分,请尽量减少测试运行时间。
随意重构现有的提示以避免代码重复或创建不一致性。如果你能证明你的方法完全复制了一个现有的方法,包括在获取解决方案的简单性和速度上,那么你可以移除旧的、通用性较差的方法。现有代码在 test_ode.py
中经过了广泛的测试,所以如果有任何问题,其中一个测试肯定会失败。
这些功能不是为最终用户使用的。