【问题标题】:python complex_ode pass matrix-valued parameterspython complex_ode 传递矩阵值参数
【发布时间】: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。
  • 我似乎误解了你的部分问题(不是你自己的错,不用担心)。参数OmegaAB 是否不变?如果是,您的 2 个问题归结为 “如何在 complex_ode 中传递参数”,答案在链接中。澄清一下,你不能在不破坏complex_ode()的情况下使用set_f_params()。唯一的解决方案是将函数创建为def f(t, y),并让OmegaAB 从全局变量中获取。链接中的解决方案几乎实现了这一点,但通过创建一个包装函数。此外,zvodecomplex_ode() 更快。

标签: python


【解决方案1】:

Reti43 发布的链接似乎包含了答案,所以让我把它放在这里,以方便未来的用户:

from scipy.integrate import complex_ode
import numpy as np

N = 3
Omega = 1.0;

class myfuncs(object):
    def __init__(self, f, fargs=[]):
        self._f = f
        self.fargs=fargs

    def f(self, t, y):
        return self._f(t, y, *self.fargs)

def f(t, y, Omega,A,B):
    return -1j*(A+np.cos(Omega*t)*B).dot(y)    


A = np.random.ranf((N,N))
A = (A + A.T)/2.0

B = np.random.ranf((N,N))
B = (B + B.T)/2.0

v0 = np.zeros((N,),dtype=np.float64)
v0[0] = 1.0

t0 = 0

case = myfuncs(f, fargs=[Omega, A, B] )
solver = complex_ode(case.f)
solver.set_initial_value(v0, t0)

solver.integrate([10.0])

print solver.successful()

"""
t1 = 10
dt = 1
while solver.successful() and solver.t < t1:
    solver.integrate(solver.t+dt)
    print(solver.t, solver.y)

"""

也许有人可以评论一下为什么这个技巧能奏效吗?

【讨论】:

  • 请参阅我上面关于仅将 ty 的函数传递给 complex_ode() 的评论。如果您回答我的问题 OmegaAB 是否为常量参数,那么我们可以将其作为重复参数来解决。通过链接到另一个问题,未来的读者将能够看到解决方案,而无需在此处发布重复的问题。
  • 是的,Omega、A 和 B 独立于 t。我认为这是重复的,因此可以将其删除。
  • 不要删除问题。重复项很有用,因为它们有效地引入了更多关键字,人们可以在搜索中使用这些关键字来偶然发现原始问题/答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-11-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多