【发布时间】:2016-04-27 12:35:54
【问题描述】:
我在使用 python 的 complex_ode 求解器时遇到了一些问题。
我正在尝试解决以下等式:
dy/dt = -iAy - icos(Omegat)By
其中 A 和 B 是 NxN 数组,未知 y 是 Nx1 数组,i 是虚数单位,Omega 是参数。
这是我的代码:
import numpy as np
from scipy.integrate import ode,complex_ode
N = 3 #linear matrix dim
Omega = 1.0 #parameter
# define symmetric matrices A and B
A = np.random.ranf((N,N))
A = (A + A.T)/2.0
B = np.random.ranf((N,N))
B = (B + B.T)/2.0
# define RHS of ODE
def f(t,y,Omega,A,B):
return -1j*A.dot(y)-1j*np.cos(Omega*t)*B.dot(y)
# define list of parameter
params=[Omega,A,B]
# choose solver: need complex_ode for this ODE
#solver = ode(f)
solver = complex_ode(f)
solver.set_f_params(*params)
solver.set_integrator("dop853")
# set initial value
v0 = np.zeros((N,),dtype=np.float64)
v0[0] = 1.0
# check that the function f works properly
print f(0,v0,Omega,A,B)
# solve-check the ODE
solver.set_initial_value(v0)
solver.integrate(10.0)
print solver.successful()
运行此脚本会产生错误
capi_return is NULL
Call-back cb_fcn_in___user__routines failed.
Traceback (most recent call last):
File "ode_test.py", line 37, in <module>
solver.integrate(10.0)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 515, in integrate
y = ode.integrate(self, t, step, relax)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 388, in integrate
self.f_params, self.jac_params)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 946, in run
tuple(self.call_args) + (f_params,)))
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 472, in _wrap
f = self.cf(*((t, y[::2] + 1j * y[1::2]) + f_args))
TypeError: f() takes exactly 5 arguments (2 given)
如果我改为使用求解器 = ode(f),即。实值求解器,它运行良好。除了它不能解决我想要的复值 ODE :(
然后我尝试通过使矩阵 A 和 B 成为全局变量来减少参数的数量。这样,函数 f 接受的唯一参数是 Omega。错误变为
capi_return is NULL
Call-back cb_fcn_in___user__routines failed.
Traceback (most recent call last):
File "ode_test.py", line 37, in <module>
solver.integrate(10.0)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 515, in integrate
y = ode.integrate(self, t, step, relax)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 388, in integrate
self.f_params, self.jac_params)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 946, in run
tuple(self.call_args) + (f_params,)))
File "/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python/scipy/integrate/_ode.py", line 472, in _wrap
f = self.cf(*((t, y[::2] + 1j * y[1::2]) + f_args))
TypeError: 'float' object has no attribute '__getitem__'
我发现 float 指的是参数 Omega [通过尝试整数]。同样,“ode”也适用于这种情况。
最后,我尝试了相同的复值方程,但现在 A 和 B 只是数字。我尝试将它们都作为参数传递,即 params = [Omega,A,B],以及在这种情况下将它们设为全局变量 params=[Omega]。错误是
TypeError: 'float' object has no attribute '__getitem__'
error - 完整的错误与上面相同。再一次,对于实值“ode”,这个问题不会发生。
我知道 zvode 是一种替代方案,但对于大 N 来说它似乎变得相当慢。在我遇到的真正问题中,A 是对角矩阵,但 B 是非稀疏完整矩阵。
非常感谢任何见解!我对 (i) 使用数组值参数解决这个复值 ODE 的替代方法以及 (ii) 如何让 complex_ode 运行感兴趣:)
谢谢!
【问题讨论】:
-
你能告诉我们完整的追溯吗?
TypeError似乎与 here 相同。简而言之,不要将set_f_params()与complex_ode()一起使用。对于求解复杂 ODE,您还可以使用zvode()。这就解决了第 2 个问题。 -
我更新了帖子,显示了两种情况下的完整错误消息。我知道 zvode 但是当矩阵大小变大时它有点慢。或者你的意思是有一种方法可以结合 complex_ode() 和 zvode 只是为了传递参数?
-
这是错误,好吧。如果您打印在
_wrap()中传递的值,如果您使用了set_f_params(),或者您自己修改了solver.params(这是set_f_params()在内部所做的),您会看到它们都被弄乱了。所以你应该在_wrap()中对数组进行切片,你最终会得到浮点数,因此TypeError。不,这两个积分器没有结合,您只需从一开始就使用zvode。当矩阵变大时,为什么积分器不应该变慢?如果矩阵应该包含未知参数,则它们的数量会增加 N**2。 -
我似乎误解了你的部分问题(不是你自己的错,不用担心)。参数
Omega、A和B是否不变?如果是,您的 2 个问题归结为 “如何在 complex_ode 中传递参数”,答案在链接中。澄清一下,你不能在不破坏complex_ode()的情况下使用set_f_params()。唯一的解决方案是将函数创建为def f(t, y),并让Omega、A和B从全局变量中获取。链接中的解决方案几乎实现了这一点,但通过创建一个包装函数。此外,zvode比complex_ode()更快。
标签: python