Unexpected behaviour of sympy.lambdify with trigonometric functions - python

Given an expression, we can convert it into a function using sympy.lambdify. Similarly, given a function, we can convert it into an expression by evaluating it at symbol x. We would naturally expect that these two operations are inverses of each other. And, this expected behaviour is displayed when I use polynomial expressions. For example,
import sympy as sym
x = sym.symbols('x')
expr = 5*x**2 + 2*x + 3
f = sym.lambdify([x],expr)
f_expr = f(x)
print(expr == f_expr)
gives True as its output.
On the other hand, the following code does not run
import sympy as sym
x = sym.symbols('x')
expr = sym.sin(x)
f = sym.lambdify([x],expr)
f_expr = f(x)
print(expr == f_expr)
and throws the error "TypeError: loop of ufunc does not support argument 0 of type Symbol which has no callable sin method". Could you please explain why this is happening? My guess would be that sym.sin(x) does not return an "expression" analogous to 5x**2 + 2x + 3. But, I would like to understand it a bit better. Thanks in advance.

For a non-numeric object the lambdify code tries to do x.sin()
with making sure the sin function is from library sympy not numpy to avoid confusions.
you can try :
import sympy as sym
from sympy import sin
x = sym.symbols('x')
expr = sin(x)
# f = sym.lambdify(x,expr)
f = lambda x:sin(x)
f_expr = f(x)
print(expr == f_expr)

Related

Sympy: turn python function into sympy expression

For example, I have the function, that accepts only floats:
def do_smth(a: float, b: float) -> float:
return a + b
This is not necessarily a summation, it can be any function (for example, a function after autowrap) - what matters is that it does not accept Symbol as arguments
How can I turn it into sympy expression, which only evaluated when the numbers are substituted?
Something like this:
from sympy.abc import x,y
wf = wrap2sympy(do_smth, args=(x,y))
wf.subs(x, 5).subs(y, 0.5).evalf() # returns 5.5

add two numpy arrays using lamdify - pass expression as function argument

I have this piece of code:
import numpy as np
import sympy
from sympy import symbols
from sympy.utilities.autowrap import ufuncify
from sympy.utilities.lambdify import lambdify
def test(expr,a,b):
a_var, b_var = symbols("a b")
#f = ufuncify((a_var, b_var), expr, backend='numpy')
f = lambdify( (a_var, b_var), expr, 'numpy')
return f(a_var, b_var)
a = np.array([2,3])
b = np.array([1,2])
expr = a + b
print(test(expr, a, b))
which give me:
../anaconda3/envs/python3/lib/python3.6/site-packages/sympy/core/sympify.py:282: VisibleDeprecationWarning: using a non-integer number instead of an integer will result in an error in the future
rational=rational) for x in a])
File "<string>", line 1
lambda _Dummy_52,_Dummy_53: ([3 5])
SyntaxError: invalid syntax
If I use the ufuncify :
...
TypeError: unhashable type: 'numpy.ndarray'
During handling of the above exception, another exception occurred:
...
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
====== UPDATE ================
One solution I found is to use expr like a string and then inside function use sympify:
data_a = np.array([2,3])
data_b = np.array([1,2])
expr = "data_a + data_b"
def test(expr,data_a, data_b):
a, b = symbols("data_a data_b")
expr = sympify(expr)
f = lambdify( (a, b), expr, 'numpy')
return f(data_a, data_b)
and I am taking:
[3 5]
But how can I avoid using the expression as a string?
lambdify converts SymPy expressions into NumPy functions. You are trying to convert a NumPy array into a NumPy function. The arguments to lambdify need to be SymPy objects.
You want something like
a_var, b_var = symbols("a b")
expr = a_var + b_var
f = lambdify((a_var, b_var), expr, 'numpy')
You'll then get
>>> a = np.array([2,3])
>>> b = np.array([1,2])
>>> f(a, b)
array([3, 5])
The basic code flow for lambdify is SymPy expression => NumPy function. To keep things clear in your head and in your code, you should start with just SymPy, and manipulate the expressions until you have a lambdified function. Then use it with your NumPy data. Start with defining symbol names. Then you can define an expression in terms of those symbols, without using a string (for instance, as I have done above). Once you have an expression and the symbols, you create a lambdified function. At that point, you pass NumPy arrays into the function. I recommend using different variable names for SymPy symbols/expressions and NumPy arrays, so that they don't get mixed up. I also recommend using the same variable name for symbols as the symbol names themselves, so that when you print the expression it will appear exactly as you would write it (e.g., below if you print(expr), you will get a + b, which is exactly what you would write to get expr).
In your updated example, you can use
a, b = symbols("a b")
expr = a + b
f = lambdify((a, b), expr, 'numpy')
data_a = np.array([2,3])
data_b = np.array([1,2])
f(data_a, data_b)
Note how I start with creating SymPy symbols and a SymPy expression from those symbols. Then I lambdify it. Once it's lambdified, I have the lambdified function (f). At this point, I'm not using SymPy at all anymore, just NumPy arrays (the data) and the lambdified function f.

Sympy: Get functions from expression

To get all variables from a sympy expression, one can call .free_symbols on the expression. I would like to retrieve all functions used in an expression. For example, from y in
from sympy import *
f = Function('f')
g = Function('g')
x = Symbol('x')
y = f(x) + 2*g(x)
I'd like to get f and g.
Any hints?
atoms does the trick:
for f in y.atoms(Function):
print(f.func)
For all functions, use atoms(Function).
In [40]: (f(x) + sin(x)).atoms(Function)
Out[40]: set([f(x), sin(x)])
For only undefined functions, use atoms(AppliedUndef).
In [41]: from sympy.core.function import AppliedUndef
In [42]: (f(x) + sin(x)).atoms(AppliedUndef)
Out[42]: set([f(x)])

Printing a whole equation (including variables) in Python

say I want to print the equation g(x) in the form g(x) = x^2 *........
how do I do it? This is my first time using python
import numpy as np
import matplotlib.pyplot as plt
import math
from sympy.mpmath import *
f = lambda x: ((x^2)*math.exp(-x))
dfdx = lambda x: diff(f,x)
d2fdx2 = lambda x: diff(dfdx,x)
g = lambda x: ((math.exp(x)/math.factorial(2))*d2fdx2)
print(g)
(edit) the output im getting is
function lambda at 0x0671C198
First of drop all the the unnecessary imports and stick to what you really need. Symbolic math is what sympy was made for so check out the documentation for that.
In sympy you have to define symbols first
import sympy
x = symbols('x')
Now you would use the symbol x to construct an expression using builtin operators and functions in the sympy module. Be aware that ** is exponentiation and ^ is logical xor.
f = x ** 2 * sympy.exp(-x)
dfdx = sympy.diff(f, x)
d2fdx2 = sympy.diff(f, x, x)
g = sympy.exp(x) / sympy.factorial(2) * d2fdx2
When you write g in the interactive interpreter it will write the expression the way you want it. Can't show that here but atleast I can do this:
>>> print(g)
x**2/2 - 2*x + 1
You cannot do what you want with the math, sympy.mpmath and numpy modules as they exist for numerical evalutions - they want numbers and give you number.
If you later want to evaluate your expression for a given value of x you could do
val_at_point = g.evalf(subs={x: 1.5})
where subs is a dictionary.
Or you could turn g into a python lambda function:
fun_g = sympy.lambdify(x, g)
val_at_point = fun_g(1.5)
If you're doing this for a math class you probably want to be working in the interpreter anyway in which case you can start by writing
>>> from sympy import *
so that you can skip all the sympy. stuff in the above code samples. I left them there just to show where symbols come from.

How to manipulate equation in Matlab or python?

I have a complicated equation which is function of several variables and I want to manipulate like this example:
y = (x + a) / z
x = y*z - a
Is it possible to do this kind of manipulation matlab or python?
If there is possibility then please point out method or function to do this operation.
I tried following code in Sympy Shell:
x,y,z,a = symbols ('x y z a')
solve ( y = (x-a)/z, x)
I am getting following error:
Traceback (most recent call last):
File "<string>", line 1
SyntaxError: non-keyword arg after keyword arg
In Matlab you'd need the symbolic math toolbox (which I don't have so I can't test) and then you should be able to do use the solve function:
syms y x a z
solve(y == (x+a)/z, x)
I have NO experince with sympy but pretty sure based on the docs this is how you do it:
from sympy import solve, Poly, Eq, Function, exp
from sympy.abc import x, y, z, a
solve(y - (x+a)/z, x)
SymPy is a Python library, so your SymPy code needs to be valid Python. In Python, = is the assignment operator, which is why solve ( y = (x-a)/z, x) gives a SyntaxError. See http://docs.sympy.org/latest/gotchas.html#equals-signs.
To create an equality in SymPy use Eq, like solve(Eq(y, (x - a)/z, x), or use the fact that expressions in SymPy are assumed to be equal to zero, like solve(y - (x - a)/z, x).

Categories