0

I have some issue using sympy.lambdify. I have a rather simple symbolic expression involving only square root, sine and cosine and some large numbers (which get generated by other parts of the program not shown here). Lambdify does work for single floats, but not for numpy arrays. However, these would be very helpful for plotting later.

The error I get is

AttributeError: 'float' object has no attribute 'sqrt'

Here is a mwe. Note that expr1 works just fine whereas expr2 does not. Any help to fix the issue would be well appreciated.

import sympy
import numpy

x = sympy.symbols('x', real=True)

expr1 = -sympy.sqrt(4*sympy.sin(3*x/4)**2 - 2*sympy.cos(3*x/83) + 5*sympy.cos(2*x/3)**2 + 2)
expr2 = -sympy.sqrt(2.14881349445107e+30*sympy.sin(209178661335919*x/10000000000000)**2 + 13456000000000000000000000000*sympy.cos(209178661335919*x/10000000000000)**2 - 1.40793126300373e+29*sympy.cos(209178661335919*x/10000000000000) + 4.73607234789273e+30)

func1 = sympy.lambdify(x, expr1, modules='numpy')
func2 = sympy.lambdify(x, expr2, modules='numpy')

array = numpy.arange(2)
print(func1(array))
print(func2(array[0]))
print(func2(array[1]))  #works fine until here
print(func2(array))     #fails

python 3.7.3
numpy 1.16.3
sympy 1.14

EDIT:
I cannot directly modify expr2. It just appears here in this form to provide a mwe. However, in the real code it get generated as eigenvalue of a matrix and takes rather long to calculate.

eigenvalues = Matrix.eigenvals()
expr2 = list(eigenvalues.keys())[0]
laolux
  • 1,445
  • 1
  • 17
  • 28
  • 3
    Explicitly changing the large integers to floating point constants (by appending `.0`) solves the error. Note that the results are not necessarily accurate due to rounding. – MB-F May 09 '19 at 09:20
  • Thanks @kazemakase. This does indeed work. However, in my real program `expr2` gets generated by sympy and I cannot modify it that easily. See edit. Any suggestions of how to handle that situation? Also, I am not very concerned about numerical accuracy. This is just intended to be plotted as guide to the eye, not for subsequent calculations. – laolux May 10 '19 at 01:24

1 Answers1

1

Try to apply nfloat to the expression before passing it to lambdify: expr2 = sympy.nfloat(expr1).

smichr
  • 16,948
  • 2
  • 27
  • 34
  • Thanks, this solves it for me. I had just started with `numpy.vectorize` and `numpy.frompyfunc`, but those are awefully slow compared to your solution. – laolux May 10 '19 at 06:44
  • I'm very limited wrt numpy and lambdify, but if you just need to make big ints floats, nfloat is one way to do it. If you need to retain all digits of precision of the integers then doing `(expr1.xreplace(dict([(i, Float(str(i))) for i in expr1.atoms(Rational)]))` would be better. – smichr May 10 '19 at 06:51
  • I will keep that in mind for the future. For now I could not spot any difference to `sympy.nfloat` for my given example, so I will use the easier one. – laolux May 10 '19 at 07:04