I have a system of equations expressed by sympy:
def test1a(A):
t, tt = sym.symbols('t tt')
return sym.cos(t+tt+A)*A
def test1b(B):
t, tt = sym.symbols('t tt')
return sym.sin(t-tt+B)*B
That I want to convert to a numpy expression before evaluating the result with fsolve()
:
def testprep(variables, A, B):
t, tt = sym.symbols('t tt')
fA = lambdify([(t, tt)], test1a(A))
fB = lambdify([(t, tt)], test1b(B))
t, tt = variables
return [fA,fB]
def testsolve(A, B):
print(so.fsolve(testprep, [-1, 1], args = (A, B)))
return
When ran, I get the following result:
import scipy.optimize as so
import sympy as sym
from sympy.utilities.lambdify import lambdify as lambdify
import numpy as np
def main():
A = 1
B = 2
testsolve(A,B)
return
if __name__ == '__main__':
main()
Output:
error: Result from function call is not a proper array of floats.
As a sanity check, I drafted the same system in terms of numpy expressions and solved it:
def standard(variables, A, B):
t, tt = variables
eq1 = np.cos(t+tt+A)*A
eq2 = np.sin(t-tt+B)*B
return [eq1, eq2]
def solvestandard(A, B):
print(so.fsolve(standard, np.array([-1, 1]), args = (A,B)))
return
With output:
[-0.71460184 1.28539816]
I'm new to lambdify( )
and am not too familiar with the process of converting from sympy to numpy. What would I need to change in order to make the test-case work?
You've presented your code in a very convoluted way for an SO question. You don't need so many functions just to show what is basically 5 lines of code!
Please reduce your examples to something as simple as possible that is a single block of code that can be copy-pasted complete with all imports. Then please test it by copy-pasting and running in a fresh python process.
The way to use lambdify
with fsolve
is something like:
import sympy as sym
import scipy.optimize as so
t, tt = sym.symbols('t tt')
A, B = 1, 2
eq1 = sym.cos(t+tt+A)*A
eq2 = sym.sin(t-tt+B)*B
f = lambdify([(t, tt)], [eq1, eq2])
print(so.fsolve(f, [-1, 1]))
The idea is that lambdify makes an efficient function that can be computed many times (e.g. fsolve
will call it iteratively). Then you pass that efficient function to fsolve
.
The function that you pass to fsolve
should not call lambdify
itself (as your testprep
does) because lambdify
is a lot slower than evaluating the function:
In [22]: %time f = lambdify([(t, tt)], [eq1, eq2])
CPU times: user 4.74 ms, sys: 77 µs, total: 4.82 ms
Wall time: 4.96 ms
In [23]: %time f([1, 2])
CPU times: user 36 µs, sys: 1e+03 ns, total: 37 µs
Wall time: 41 µs
Out[23]: [-0.6536436208636119, 1.682941969615793]
Maybe your real problem is more complicated but I would use sympy's nsolve
for something like this:
In [16]: nsolve([eq1, eq2], [t, tt], [-1, 1])
Out[16]:
⎡-0.714601836602552⎤
⎢ ⎥
⎣ 1.28539816339745 ⎦
In [17]: nsolve([eq1, eq2], [t, tt], [-1, 1], prec=100)
Out[17]:
⎡-0.714601836602551690384339154180124278950707650156223544756263851923045898428447750342991293664470733⎤
⎢ ⎥
⎣1.285398163397448309615660845819875721049292349843776455243736148076954101571552249657008706335529267 ⎦
SymPy's nsolve
takes care of calling lambdify
for you. It is somewhat slower than fsolve
because it works with arbitrary precision floating point but that means it can also compute more accurate results.