Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/gwt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 用辛表达式和SciPy解算器求解一阶常微分方程组_Python_Scipy_Sympy_Ode - Fatal编程技术网

Python 用辛表达式和SciPy解算器求解一阶常微分方程组

Python 用辛表达式和SciPy解算器求解一阶常微分方程组,python,scipy,sympy,ode,Python,Scipy,Sympy,Ode,我正在尝试学习如何将python SymPy与SciPy集成,以数值求解常微分方程。然而,我对如何将一阶颂歌系统的交响形式转换成我可以用scipy.integrate.odeint()处理的格式有点迷茫 注意,有些人认为这类似于另一篇文章,但事实并非如此。另一个帖子在这里。 因此,这篇文章是一个更复杂的案例,用户希望使用Theano或其他库加速ODE的计算。我只是想了解Symphy和SciPy之间的基本接口,所以这篇文章根本没有帮助 作为一个玩具示例,我使用Lotka-Volterra方程来测

我正在尝试学习如何将python SymPy与SciPy集成,以数值求解常微分方程。然而,我对如何将一阶颂歌系统的交响形式转换成我可以用
scipy.integrate.odeint()处理的格式有点迷茫

注意,有些人认为这类似于另一篇文章,但事实并非如此。另一个帖子在这里。

因此,这篇文章是一个更复杂的案例,用户希望使用Theano或其他库加速ODE的计算。我只是想了解Symphy和SciPy之间的基本接口,所以这篇文章根本没有帮助

作为一个玩具示例,我使用Lotka-Volterra方程来测试SymPy的使用。方程式如下:

我可以用Scipy的传统方法解决这个问题,而且它很有效。这是工作代码

import numpy as np
import scipy
from scipy.integrate import odeint, ode, solve_ivp
import sympy
import matplotlib.pyplot as plt
sympy.init_printing()

def F_direct(X, t, args):
    F = np.zeros(2)
    a, b, c, d = args
    x,y = X
    F[0] = a*x - b*x*y
    F[1] = c*x*y- d*y
    return F

argst = [0.4,0.002,0.001,0.7]
xy0 = [600, 400]
t = np.linspace(0, 50, 250)
xy_t, infodict = odeint(F_direct, xy0, t, args=(argst,), full_output=True)

plt.plot(t, xy_t[:,1], 'o', t, xy_t[:,0])
plt.grid(True)
plt.xlabel('x'); plt.ylabel('y')
plt.legend(('Numerical', 'Exact'), loc=0)
plt.show()
现在我有点不知所措,不知道如何和SymPy一起做这件事。我知道需要做什么,但不知道如何继续。我发现的唯一一个例子是太复杂而无法学习。这是我的

x, y, a, b, c, d = sympy.symbols('x y a b c d')
t = np.linspace(0, 50, 250)
ode1 = sympy.Eq(a*x - b*x*y)
ode2 = sympy.Eq(c*x*y - d*y)
我应该把这些方程转换成某种系统形式,然后使用
sympy.lambdify
函数返回一个新函数,我可以传递给
odeint


因此,任何人都可以在这里填写我如何设置此
ode1、ode2
系统以使用Symphy进行处理的空白。

在Symphy中很少需要使用Eq对象;方程最好用表达式表示,在解算器的上下文中,表达式被理解为等于零。因此,
ode1
ode2
应该只是ODE系统右侧的表达式。然后可以将它们一起lambdifed,如下所示:

ode1 = a*x - b*x*y
ode2 = c*x*y - d*y
F_sympy = sympy.lambdify((x, y, a, b, c, d), [ode1, ode2])
def F_from_sympy(X, t, args):
    a, b, c, d = args
    x, y = X    
    return F_sympy(x, y, a, b, c, d)
lambdification之后需要额外的步骤,因为SciPy的解算器传递一些数组,lambdified函数将不知道如何解包。例如:

F_from_sympy([1, 2], np.linspace(0, 1, 100), (3, 4, 5, 6))
返回
[-5,-2]
,这是一个Python列表而不是NumPy数组,但是ODE解算器应该处理这个问题。(或者您可以返回
np.array(F_sympy(x,y,a,b,c,d))

我写的,它从描述右侧的符号表达式(sympy或SymEngine)创建ODE integrator对象(处理方式类似于
scipy.integrate.ODE
)。在引擎盖下,它使用
scipy.integrate.ode
scipy.integrate.solve_ivp
进行集成

在您的例子中,唯一的缺点是动态变量和时间的符号是规定的,因此您可能必须进行符号替换——然而,这不应该是一个大问题。 下面是以Lotka–Volterra方程为例,使用
y(0)
代替
x
y(1)
代替
y

import numpy as np
from sympy.abc import a,b,c,d
from jitcode import y, jitcode

xy0 = [600,400]
argst = [0.4,0.002,0.001,0.7]

lotka_volterra = [
         a*y(0) - b*y(0)*y(1),
        -d*y(1) + c*y(0)*y(1)
    ]

ODE = jitcode( lotka_volterra, control_pars=[a,b,c,d] )
ODE.set_integrator("dopri5")
ODE.set_initial_value(xy0)
ODE.set_parameters(*argst)

times = np.linspace(0, 50, 250)
xy_t = np.vstack(ODE.integrate(time) for time in times)

请注意,此模块的主要功能是为了提高效率而编译右侧。取决于你需要做什么,这可能是过火了,但如果它起作用也不会有什么坏处(你也可以禁用它并使用lambdication,如中所述)。

是你的复制品吗?@Warren感谢你找到这个附加问题。我觉得你贴的问题比我现在做的要高级一点。我试图解决一个相对简单的ODE来学习API。在您发布的问题中,用户试图使用GPU或类似的工具来加速数值解的计算。所以我可以使用更复杂答案中的东西,直到我理解如何首先做这个更简单的答案。可能是优秀的复制品,我会给它一个机会。是的,也谢谢你的
scipy
提示。我还没有找到很多关于
sympy
scipy
连接的例子。我发现的很多例子都太复杂了,一开始很难从中学习——不过在我习惯了这些之后,它们会很有用。谢谢你的帮助。哦@Wrzlprmft非常感谢你的回答。这太棒了,我可以试试JiTCODE。实际上,我还需要做一些关于延迟微分方程的工作,所以你的JiTCDDE模块看起来也很棒。如果我能为标准常微分方程和延迟微分方程提供一个一致的接口,那将是一个巨大的帮助。再次感谢。嘿@Wrzlprmft只是一个我不清楚的问题。用户是否需要为集成例程指定雅可比矩阵,还是JiTCODE会自动生成雅可比矩阵?我看到类上有一个
wants\u jacobian
参数和
generate\u jac\u sym
方法。但我不清楚是否需要指定雅可比矩阵,或者是否自动处理。谢谢。@krishnab:如果积分器可以使用雅可比矩阵,它将自动计算。你提到的东西只是为了微调而存在的。你通常不需要为此烦恼。哇,太好了。非常感谢您的包裹:)。