0
votes

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
A sympy expression cannot be used reliably in numpy or scipy. scipy solvers require a numpy/python function, not one that uses sympy symbols. If you can't get lambdify to work, stick with sympy solvers. - hpaulj

1 Answers

1
votes

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.