How to convert class 'sympy.core' to 'number' or 'float' for optimization?

霸气de小男生 提交于 2021-02-11 14:13:13

问题


I'm a Python initiator and I'd like to solve the following problems, but I don't know what the cause is.I approached the problem using 'fsolve' an optimization tool.

First of all, I'm trying to solve a nonlinear equation, but I've approached it in two cases. One case worked out well. But I can't find another case.

First case (complete case)

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])

Second case (Fail case)

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]

The message that failed is as follows.

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.

Simply enter mathematical expressions eq1,eq2 directly into the 'Return', But the results is different from manually input the expressions.

I tried many things for converting 'sympy function' into 'float array', but it didn't go well.

I tried 'lambdify','lambda'... These were also failed.

How can i enter a function defined as 'sympy' in the form of float to calculate with the optimization tool 'fsolve'?

Actually, The codes above are not my cases. As it is Just simplified situation. But in my cases it's not possible to manually input all functions like above that because i am going to solve a very complex non-linear equation that has hundreds of terms in the tenth or higher order.

Is there anyone who can solve this problem?


回答1:


To work in in fsolve your function has to run with something like the x0 value.

In the first case:

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 the second case:

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  ⎠

This returns a tuple of sympy expressions. fsolve needs numbers as in the first case. Note that the v values don't change the returned expressions. The b_1 inside the function is not the same as the b₁ in the eq.

We can use lambdify to convert the sympy into numpy functions:

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)

This should now work in fsolve.

Note what lambdify has produced:

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)

Your error was produced when trying to do something like:

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

(It doesn't look like you gave the full traceback. In any case, fsolve wants a function that returns an array of floats (or equivalent) when given array input (shaped like x0).

lambdify is the best, if not the only, way to convert a sympy expression into a numpy compatible function.



来源:https://stackoverflow.com/questions/63160024/how-to-convert-class-sympy-core-to-number-or-float-for-optimization

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!