在scipy的solve_ivp()中实现lambda函数会导致太多的值无法解包

wpcxdonn  于 2023-10-20  发布在  其他
关注(0)|答案(2)|浏览(171)
from scipy.integrate import solve_ivp

def myfunc(a,b,c,d,e,f,g,h):
  t=a+2
  d=b+3
  return t,d

a=1
b=2
c=3
d=4
e=5
f=6
g=7
e=8

solve_ivp(lambda t,s:myfunc(a,b,c,d,e,f,g,h),np.linspace(0,100),3)

这就是我面临的问题。Scipy的solve_ivp()使用语法solve_ivp(function,timerange,initial guess,**kwargs)求解函数。
我有一个函数(比如myfunc()),它接受大量的参数,对它们进行一些数学操作,并返回2个变量。我在这里提供了一个样本。我想把这个函数作为solve_ivp()的参考。我已经用lambda做过了,但我遇到了一个too many values to unpack (expected 2)错误。
我该如何解决这个问题?

vaqhlq81

vaqhlq811#

这是另一种情况,我应该只要求完整的追溯,而不是快速猜测问题(请参阅我的评论)。
运行代码:

...: integrate.solve_ivp(lambda t,s:myfunc(a,b,c,d,e,f,g,h),np.linspace(0,100),3)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[9], line 15
     12 g=7
     13 e=8
---> 15 integrate.solve_ivp(lambda t,s:myfunc(a,b,c,d,e,f,g,h),np.linspace(0,100),3)

File ~/.local/lib/python3.10/site-packages/scipy/integrate/_ivp/ivp.py:524, in solve_ivp(fun, t_span, y0, method, t_eval, dense_output, events, vectorized, args, **options)
    519 if method not in METHODS and not (
    520         inspect.isclass(method) and issubclass(method, OdeSolver)):
    521     raise ValueError("`method` must be one of {} or OdeSolver class."
    522                      .format(METHODS))
--> 524 t0, tf = map(float, t_span)
    526 if args is not None:
    527     # Wrap the user's fun (and jac, if given) in lambdas to hide the
    528     # additional parameters.  Pass in the original fun as a keyword
    529     # argument to keep it in the scope of the lambda.
    530     try:

ValueError: too many values to unpack (expected 2)

这是一个解包错误,在

t0, tf = map(float, t_span)

这试图得到2个浮点值的t_span参数,并在2个变量,t0,tf。相反,你提供了一个arange(100)
用(0,100)来运行它:

In [12]: integrate.solve_ivp(lambda t,s:myfunc(a,b,c,d,e,f,g,h),(0,100),3)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
Cell In[12], line 1
----> 1 integrate.solve_ivp(lambda t,s:myfunc(a,b,c,d,e,f,g,h),(0,100),3)

File ~/.local/lib/python3.10/site-packages/scipy/integrate/_ivp/ivp.py:568, in solve_ivp(fun, t_span, y0, method, t_eval, dense_output, events, vectorized, args, **options)
    565 if method in METHODS:
    566     method = METHODS[method]
--> 568 solver = method(fun, t0, y0, tf, vectorized=vectorized, **options)
    570 if t_eval is None:
    571     ts = [t0]

File ~/.local/lib/python3.10/site-packages/scipy/integrate/_ivp/rk.py:89, in RungeKutta.__init__(self, fun, t0, y0, t_bound, max_step, rtol, atol, vectorized, first_step, **extraneous)
     85 def __init__(self, fun, t0, y0, t_bound, max_step=np.inf,
     86              rtol=1e-3, atol=1e-6, vectorized=False,
     87              first_step=None, **extraneous):
     88     warn_extraneous(extraneous)
---> 89     super().__init__(fun, t0, y0, t_bound, vectorized,
     90                      support_complex=True)
     91     self.y_old = None
     92     self.max_step = validate_max_step(max_step)

File ~/.local/lib/python3.10/site-packages/scipy/integrate/_ivp/base.py:135, in OdeSolver.__init__(self, fun, t0, y0, t_bound, vectorized, support_complex)
    133 self.t_old = None
    134 self.t = t0
--> 135 self._fun, self.y = check_arguments(fun, y0, support_complex)
    136 self.t_bound = t_bound
    137 self.vectorized = vectorized

File ~/.local/lib/python3.10/site-packages/scipy/integrate/_ivp/base.py:17, in check_arguments(fun, y0, support_complex)
     14 y0 = y0.astype(dtype, copy=False)
     16 if y0.ndim != 1:
---> 17     raise ValueError("`y0` must be 1-dimensional.")
     19 if not np.isfinite(y0).all():
     20     raise ValueError("All components of the initial state `y0` must be finite.")

ValueError: `y0` must be 1-dimensional.

所以现在它不喜欢标量3y0。将其更改为列表[3](或等效数组):

In [13]: integrate.solve_ivp(lambda t,s:myfunc(a,b,c,d,e,f,g,h),(0,100),[3])
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In[13], line 1
----> 1 integrate.solve_ivp(lambda t,s:myfunc(a,b,c,d,e,f,g,h),(0,100),[3])

File ~/.local/lib/python3.10/site-packages/scipy/integrate/_ivp/ivp.py:568, in solve_ivp(fun, t_span, y0, method, t_eval, dense_output, events, vectorized, args, **options)
    565 if method in METHODS:
    566     method = METHODS[method]
--> 568 solver = method(fun, t0, y0, tf, vectorized=vectorized, **options)
    570 if t_eval is None:
    571     ts = [t0]

File ~/.local/lib/python3.10/site-packages/scipy/integrate/_ivp/rk.py:94, in RungeKutta.__init__(self, fun, t0, y0, t_bound, max_step, rtol, atol, vectorized, first_step, **extraneous)
     92 self.max_step = validate_max_step(max_step)
     93 self.rtol, self.atol = validate_tol(rtol, atol, self.n)
---> 94 self.f = self.fun(self.t, self.y)
     95 if first_step is None:
     96     self.h_abs = select_initial_step(
     97         self.fun, self.t, self.y, self.f, self.direction,
     98         self.error_estimator_order, self.rtol, self.atol)

File ~/.local/lib/python3.10/site-packages/scipy/integrate/_ivp/base.py:154, in OdeSolver.__init__.<locals>.fun(t, y)
    152 def fun(t, y):
    153     self.nfev += 1
--> 154     return self.fun_single(t, y)

File ~/.local/lib/python3.10/site-packages/scipy/integrate/_ivp/base.py:23, in check_arguments.<locals>.fun_wrapped(t, y)
     22 def fun_wrapped(t, y):
---> 23     return np.asarray(fun(t, y), dtype=dtype)

Cell In[13], line 1, in <lambda>(t, s)
----> 1 integrate.solve_ivp(lambda t,s:myfunc(a,b,c,d,e,f,g,h),(0,100),[3])

NameError: name 'h' is not defined

现在我们有一个缺失的变量h。这是从哪来的
更正全局变量赋值:

In [17]: e=5; h=8
In [18]: integrate.solve_ivp(lambda t,s:myfunc(a,b,c,d,e,f,g,h),(0,100),[3,3])
Out[18]: 
  message: The solver successfully reached the end of the integration interval.
  success: True
   status: 0
        t: [ 0.000e+00  9.384e-02  1.032e+00  1.042e+01  1.000e+02]
        y: [[ 3.000e+00  3.282e+00  6.097e+00  3.425e+01  3.030e+02]
            [ 3.000e+00  3.469e+00  8.161e+00  5.508e+01  5.030e+02]]
      sol: None
 t_events: None
 y_events: None
     nfev: 26
     njev: 0
      nlu: 0

现在它能跑了,虽然我不知道这有什么好处。函数总是返回(a+2,B+3),即(3,5)。你在范围(0,100)上积分,所以返回的y是初始值+ 100*(3,5),即。(303,503):

In [20]: 3+_18['t']*3
Out[20]: 
array([  3.        ,   3.28153316,   6.09686481,  34.25018124,
       303.        ])
In [21]: 3+_18['t']*5
Out[21]: 
array([  3.        ,   3.46922194,   8.16144135,  55.0836354 ,
       503.        ])

你的函数返回两个值,一个全局变量ab的函数。所以y0也需要是形状(2)。solve_ivp将是标量t和2个元素y的值,尽管lambda将它们丢弃。我尝试使用lambda t,s: my_func(t,s,a,b,...),但在尝试返回(t,[s+(2,3)])时总是遇到问题,这是一个“粗糙的数组”。
我可以用
integrate.solve_ivp(lambda t,s:myfunc(a,b,t,s,c,d,e,f),(0,100),[0,0])
t,s放在myfunc将忽略它们的插槽中。

ee7vknir

ee7vknir2#

这里有几个关于你的代码的问题。
1.微分方程函数的前两个参数应该是时间和因变量。你的lambda有两个参数,ts,但从来没有使用过它们。
1.为时间范围传递linspace,但应该是包含开始和停止时间的2个成员tuplelist。(如果您想要在特定时间的结果,请将所需时间传递到t_evalkwarg
1.当它应该是一个形状为(n,)的数组(或list)时,你传递一个整数作为初始猜测,其中n是方程的数量。n应该与微分方程返回值的大小相匹配,但是微分方程返回两个值,而你只提供了一个初始条件。
您需要解决所有这些问题,以使您的代码正常工作。

相关问题