Python: SymPy lambdify abs for use with NumPy

ghz 3days ago ⋅ 7 views

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:

  1. Use sympy to define the symbolic expression.
  2. Specify the modules={'numpy': 'abs'} option in lambdify to ensure that numpy.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 use sympy functions for symbolic operations. If you want to use NumPy functions, you can pass the modules argument to specify that numpy.abs should be used instead of sympy.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 like 1 - sympy.Abs(x) over NumPy arrays.

Key Notes:

  • sympy.lambdify by default will use sympy.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 to lambdify to map symbolic functions to numerical counterparts explicitly.

Let me know if this helps or if you encounter further issues!