SymPy/SciPy:求解含不同变量的常微分方程组
我刚接触SymPy和Python,正在用Python 2.7和SymPy 0.7.5做一些事情,目标是:
a) 从文本文件中读取一个微分方程组
b) 解这个方程组
我已经看过这个问题和另一个问题,它们几乎是我想要的,但我还有一个额外的问题:我不知道方程组的具体形式,所以不能像这个例子那样在脚本里用def
创建相应的函数。所有的事情都必须在运行时处理。
所以,这里是我代码的一些片段。假设我有一个文本文件system.txt,里面包含以下内容:
dx/dt = 0.0387*x - 0.0005*x*y
dy/dt = 0.0036*x*y - 0.1898*y
我做的事情是:
# imports
import sympy
import scipy
import re as regex
# define all symbols I am going to use
x = sympy.Symbol('x')
y = sympy.Symbol('y')
t = sympy.Symbol('t')
# read the file
systemOfEquations = []
with open("system.txt", "r") as fp :
for line in fp :
pattern = regex.compile(r'.+?\s+=\s+(.+?)$')
expressionString = regex.search(pattern, line) # first match ends in group(1)
systemOfEquations.append( sympy.sympify( expressionString.group(1) ) )
到目前为止,我在systemOfEquation列表里的两个符号表达式上卡住了。假设我可以从另一个文件中读取微分方程组的初始条件,为了使用scipy.integrate.odeint
,我需要把这个方程组转换成Python能读的函数,像这样:
def dX_dt(X, t=0):
return array([ 0.0387*X[0] - 0.0005*X[0]*X[1] ,
-0.1898*X[1] + 0.0036*X[0]*X[1] ])
有没有什么好的方法在运行时创建这个?比如,把函数写到另一个文件里,然后把新创建的文件作为函数导入?(也许我在这里有点傻,但请记住我对Python还比较陌生 :-D)
我看到用sympy.utilities.lambdify.lambdify
可以把符号表达式转换成lambda函数,但我在想这能不能帮到我……lambdify似乎一次只能处理一个表达式,而不是处理整个系统。
提前谢谢任何建议 :-)
编辑:
经过最小的修改,Warren的回答完美地解决了我的问题。我在listOfSymbols里有了所有符号的列表;而且,它们的顺序和将被odeint使用的数据X的列顺序是一样的。所以,我用的函数是
def dX_dt(X, t):
vals = dict()
for index, s in enumerate(listOfSymbols) :
if s != time :
vals[s] = X[index]
vals[time] = t
return [eq.evalf(subs=vals) for eq in systemOfEquations]
我只是对我特定问题中的变量'time'做了个例外。再次感谢! :-)
1 个回答
如果你打算在读取文件的同一个脚本中解决这个系统(这样systemOfEquations
就可以作为全局变量使用),而且在systemOfEquations
中使用的变量只有x
、y
,可能还有t
,那么你可以在同一个文件中这样定义dX_dt
:
def dX_dt(X, t):
vals = dict(x=X[0], y=X[1], t=t)
return [eq.evalf(subs=vals) for eq in systemOfEquations]
dX_dt
可以在odeint
中使用。在下面的ipython会话中,我已经运行了创建systemOfEquations
并定义dX_dt
的脚本:
In [31]: odeint(dX_dt, [1,2], np.linspace(0, 1, 5))
Out[31]:
array([[ 1. , 2. ],
[ 1.00947534, 1.90904183],
[ 1.01905178, 1.82223595],
[ 1.02872997, 1.73939226],
[ 1.03851059, 1.66032942]]