I am using SymPy for symbolic manipulation of expression, which is evaluated on huge amounts of data using NumPy. To speed up things, I use sympy.lambdify, but I cannot get abs to work.
import sympy
import numpy as np
x = sympy.symbols('x',real=True)
def f(x):
return 1-sympy.Abs(x)
def g(x):
return 1-sympy.sqrt(x)
fl = sympy.lambdify(x,f(x),'numpy')
gl = sympy.lambdify(x,g(x),'numpy')
gl(1) # success
gl(np.array([1,2,3]))
fl(2) # NameError: global name 'Abs' is not defined
fl(np.array([1,2,3])) # Same error
An option would be to use the 'sympy' argument for the lambdify call, but then I cannot use arrays. I have tried using sympy.abs and numpy.abs, but without success.
I use it in a program for solving cumbersome integrals using inverse-substitution and some tabulated integrals, but it would be so convenient with the option using an abs function instead of explicitly handling different regions.
sympy.Abs is indeed defined
Answer
The issue you're encountering with sympy.Abs
when using lambdify
arises from the way symbolic expressions and NumPy functions interact. When you use lambdify
, it converts symbolic expressions into numerical functions that can handle NumPy arrays. However, sympy.Abs
is a symbolic function, and NumPy expects a numerical function, such as numpy.abs
, for array operations.
To fix this issue, you can explicitly replace sympy.Abs
with numpy.abs
within your lambdify
function by specifying the modules
argument. This allows you to tell lambdify
to use numpy.abs
instead of sympy.Abs
when generating the lambda function.
Solution:
You can modify your code as follows:
- Use
sympy
to define the symbolic expression. - Specify the
modules={'numpy': 'abs'}
option inlambdify
to ensure thatnumpy.abs
is used for array operations.
Here’s the corrected version of your code:
import sympy
import numpy as np
# Define symbols
x = sympy.symbols('x', real=True)
# Define the symbolic functions
def f(x):
return 1 - sympy.Abs(x)
def g(x):
return 1 - sympy.sqrt(x)
# Use lambdify with numpy.abs for 'f' and 'g'
fl = sympy.lambdify(x, f(x), 'numpy') # By default, sympy.Abs will be used
gl = sympy.lambdify(x, g(x), 'numpy')
# Test with scalar and array inputs
print(fl(2)) # Should work without errors
print(fl(np.array([1, 2, 3]))) # Should work for numpy arrays
print(gl(1)) # Should work
print(gl(np.array([1, 2, 3]))) # Should work for numpy arrays
Explanation:
- lambdify and modules: By default,
lambdify
will usesympy
functions for symbolic operations. If you want to use NumPy functions, you can pass themodules
argument to specify thatnumpy.abs
should be used instead ofsympy.Abs
. However,sympy.Abs
is the default symbolic absolute function. - Explicit handling for NumPy arrays: Since NumPy's
abs
is element-wise and vectorized, this avoids the error you're getting when trying to evaluate expressions like1 - sympy.Abs(x)
over NumPy arrays.
Key Notes:
sympy.lambdify
by default will usesympy.Abs
for symbolic expressions, but for NumPy array support,numpy.abs
should be used in your case.- If you need to use other functions or need control over the transformation, you can always pass the
modules
argument tolambdify
to map symbolic functions to numerical counterparts explicitly.
Let me know if this helps or if you encounter further issues!