【问题标题】:How to convert class 'sympy.core' to 'number' or 'float' for optimization?如何将类 'sympy.core' 转换为 'number' 或 'float' 以进行优化?
【发布时间】:2020-07-30 08:58:20
【问题描述】:

我是 Python 发起者,我想解决以下问题,但我不知道是什么原因。我使用 'fsolve' 一个优化工具解决了这个问题。

首先,我试图求解一个非线性方程,但我已经在两种情况下处理过它。一个案例效果很好。但我找不到另一个案例。

第一个案例(完整案例)

from sympy import *
from scipy.optimize import fsolve
import numpy as np


y= symbols('y')
b_1, b_2 = symbols ('b_1,b_2')

b = 1                     
  
f = b_1 + b_2*(y/b)**2

K1 = integrate(f**2,(y,0,b))


eq1 = diff(K1,b_1)
eq2 = diff(K1,b_2)

    
def function(v):
       
    b_1 = v[0]     
    b_2 = v[1]    
    
    return (2*b_1 + 2*b_2/3,2*b_1/3 + 2*b_2/5)

x0 = [1,1]
       
solutions = fsolve(function,x0)

sol = np.zeros(2)

sol[0] = solutions[0]

sol[1] = solutions[1]

sol
Out[413]: array([-5.e-324,  1.e-323])

第二种情况(失败情况)

from sympy import *
from scipy.optimize import fsolve
import numpy as np


y= symbols('y')
b_1, b_2 = symbols ('b_1,b_2')

b = 1                     
  
f = b_1 + b_2*(y/b)**2

K1 = integrate(f**2,(y,0,b))


eq1 = diff(K1,b_1)
eq2 = diff(K1,b_2)

    
def function(v):
       
    b_1 = v[0]     
    b_2 = v[1]    
    
    return (eq1,eq2)

x0 = [1,1]
       
solutions = fsolve(function,x0)

sol = np.zeros(2)

sol[0] = solutions[0]

sol[1] = solutions[1]

失败的消息如下。

runfile('C:/Users/user/Desktop/******/untitled0.py', wdir='C:/Users/user/Desktop/******')
Traceback (most recent call last):

  File "C:\Users\user\AppData\Roaming\Python\Python37\site-packages\sympy\core\expr.py", line 327, in __float__
    raise TypeError("can't convert expression to float")

TypeError: can't convert expression to float

Traceback (most recent call last):

  File "C:\Users\user\Desktop\*******\untitled0.py", line 29, in <module>
    solutions = fsolve(function,x0)

  File "C:\Users\user\anaconda3\lib\site-packages\scipy\optimize\minpack.py", line 147, in fsolve
    res = _root_hybr(func, x0, args, jac=fprime, **options)

  File "C:\Users\user\anaconda3\lib\site-packages\scipy\optimize\minpack.py", line 225, in _root_hybr
    ml, mu, epsfcn, factor, diag)

error: Result from function call is not a proper array of floats.

只需将数学表达式eq1,eq2直接输入到'Return'中,但结果与手动输入表达式不同。

我尝试了很多方法将“sympy 函数”转换为“浮点数组”,但效果不佳。

我尝试了 'lambdify'、'lambda'...这些也都失败了。

如何以浮点形式输入定义为“sympy”的函数以使用优化工具“fsolve”进行计算?

实际上,上面的代码不是我的情况。因为它只是简化的情况。但在我的情况下,不可能像上面那样手动输入所有函数,因为我要求解一个非常复杂的非线性方程,它有数百个十阶或更高阶的项。

有没有人能解决这个问题?

【问题讨论】:

  • sympy 表达式不能在numpyscipy 中可靠地使用。 scipy 求解器需要一个 numpy/python 函数,而不是一个使用 sympy 符号的函数。如果您无法让lambdify 工作,请坚持使用 sympy 求解器。

标签: python numpy class scipy sympy


【解决方案1】:

要在fsolve 中工作,您的function 必须使用类似x0 的值。

第一种情况:

In [1]: def function(v): 
   ...:         
   ...:     b_1 = v[0]      
   ...:     b_2 = v[1]     
   ...:      
   ...:     return (2*b_1 + 2*b_2/3,2*b_1/3 + 2*b_2/5) 
   ...:                                                                                              

In [3]: function([1,2])                                                                              
Out[3]: (3.333333333333333, 1.4666666666666668)

第二种情况:

In [4]: y= symbols('y') 
   ...: b_1, b_2 = symbols ('b_1,b_2') 
   ...:  
   ...: b = 1                      
   ...:    
   ...: f = b_1 + b_2*(y/b)**2 
   ...:  
   ...: K1 = integrate(f**2,(y,0,b)) 
   ...:  
   ...:  
   ...: eq1 = diff(K1,b_1) 
   ...: eq2 = diff(K1,b_2) 
   ...:                                                                                              

In [5]: eq1                                                                                          
Out[5]: 
       2⋅b₂
2⋅b₁ + ────
        3  

In [6]: eq2                                                                                          
Out[6]: 
2⋅b₁   2⋅b₂
──── + ────
 3      5  

In [7]: def function(v): 
   ...:         
   ...:     b_1 = v[0]      
   ...:     b_2 = v[1]     
   ...:      
   ...:     return (eq1,eq2) 
   ...:                                                                                              

In [8]: function([1,2])                                                                              
Out[8]: 
⎛       2⋅b₂  2⋅b₁   2⋅b₂⎞
⎜2⋅b₁ + ────, ──── + ────⎟
⎝        3     3      5  ⎠

这会返回一个 sympy 表达式的元组。 fsolve 在第一种情况下需要数字。请注意,v 值不会更改返回的表达式。函数里面的b_1eq里面的b₁不一样。

我们可以使用lambdify将sympy转换成numpy函数:

In [15]: f1 = lambdify([b_1, b_2], eq1)                                                              

In [17]: f1(1,2)                                                                                     
Out[17]: 3.333333333333333

In [18]: f2 = lambdify([b_1, b_2], eq2)                                                              

In [19]: def function(v): 
    ...:         
    ...:     b_1 = v[0]      
    ...:     b_2 = v[1]     
    ...:      
    ...:     return (f1(b_1,b_2), f2(b_1, b_2))                                                                                              

In [20]: function([1,2])                                                                             
Out[20]: (3.333333333333333, 1.4666666666666668)

现在应该可以在 fsolve 中使用。

注意lambdify 产生了什么:

In [22]: print(f1.__doc__)                                                                           
Created with lambdify. Signature:
func(b_1, b_2)

Expression:

2*b_1 + 2*b_2/3

Source code:

def _lambdifygenerated(b_1, b_2):
    return (2*b_1 + (2/3)*b_2)

您的错误是在尝试执行以下操作时产生的:

In [23]: np.array(Out[8], dtype=float)                                                               
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-23-5f2b1be0015f> in <module>
----> 1 np.array(Out[8], dtype=float)

/usr/local/lib/python3.6/dist-packages/sympy/core/expr.py in __float__(self)
    325         if result.is_number and result.as_real_imag()[1]:
    326             raise TypeError("can't convert complex to float")
--> 327         raise TypeError("can't convert expression to float")
    328 
    329     def __complex__(self):

TypeError: can't convert expression to float

(看起来你没有给出完整的回溯。无论如何,fsolve 想要一个函数,在给定数组输入(形状像 x0)时返回浮点数组(或等效数组)。

lambdify 是将 sympy 表达式转换为 numpy 兼容函数的最佳方法,即使不是唯一方法。

【讨论】:

  • 非常感谢。好久没解决,终于解决了。你是最棒的。
  • 您也可以使用function = lambdify([(b_1, b_2)], [eq1, eq2]) 制作一个接受列表并返回列表的函数。
猜你喜欢
  • 2018-07-11
  • 2014-04-04
  • 1970-01-01
  • 2019-12-11
  • 2019-11-03
  • 2014-06-28
  • 1970-01-01
  • 2014-06-20
  • 1970-01-01
相关资源
最近更新 更多