问题
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