from itertools import product import math import inspect import linecache import gc import mpmath import cmath from sympy.testing.pytest import raises, warns_deprecated_sympy from sympy.concrete.summations import Sum from sympy.core.function import (Function, Lambda, diff) from sympy.core.numbers import (E, Float, I, Rational, all_close, oo, pi) from sympy.core.relational import Eq from sympy.core.singleton import S from sympy.core.symbol import (Dummy, symbols) from sympy.functions.combinatorial.factorials import (RisingFactorial, factorial) from sympy.functions.combinatorial.numbers import bernoulli, harmonic from sympy.functions.elementary.complexes import Abs, sign from sympy.functions.elementary.exponential import exp, log from sympy.functions.elementary.hyperbolic import asinh,acosh,atanh from sympy.functions.elementary.integers import floor from sympy.functions.elementary.miscellaneous import (Max, Min, sqrt) from sympy.functions.elementary.piecewise import Piecewise from sympy.functions.elementary.trigonometric import (asin, acos, atan, cos, cot, sin, sinc, tan) from sympy.functions import sinh,cosh,tanh from sympy.functions.special.bessel import (besseli, besselj, besselk, bessely, jn, yn) from sympy.functions.special.beta_functions import (beta, betainc, betainc_regularized) from sympy.functions.special.delta_functions import (Heaviside) from sympy.functions.special.error_functions import (Ei, erf, erfc, fresnelc, fresnels, Si, Ci) from sympy.functions.special.gamma_functions import (digamma, gamma, loggamma, polygamma) from sympy.functions.special.zeta_functions import zeta from sympy.integrals.integrals import Integral from sympy.logic.boolalg import (And, false, ITE, Not, Or, true) from sympy.matrices.expressions.dotproduct import DotProduct from sympy.simplify.cse_main import cse from sympy.tensor.array import derive_by_array, Array from sympy.tensor.array.expressions import ArraySymbol from sympy.tensor.indexed import IndexedBase, Idx from sympy.utilities.lambdify import lambdify from sympy.utilities.iterables import numbered_symbols from sympy.vector import CoordSys3D from sympy.core.expr import UnevaluatedExpr from sympy.codegen.cfunctions import expm1, log1p, exp2, log2, log10, hypot, isnan, isinf from sympy.codegen.numpy_nodes import logaddexp, logaddexp2, amin, amax, minimum, maximum from sympy.codegen.scipy_nodes import cosm1, powm1 from sympy.functions.elementary.complexes import re, im, arg from sympy.functions.special.polynomials import \ chebyshevt, chebyshevu, legendre, hermite, laguerre, gegenbauer, \ assoc_legendre, assoc_laguerre, jacobi from sympy.matrices import Matrix, MatrixSymbol, SparseMatrix from sympy.printing.codeprinter import PrintMethodNotImplementedError from sympy.printing.lambdarepr import LambdaPrinter from sympy.printing.numpy import NumPyPrinter from sympy.utilities.lambdify import implemented_function, lambdastr from sympy.testing.pytest import skip from sympy.utilities.decorator import conserve_mpmath_dps from sympy.utilities.exceptions import ignore_warnings from sympy.external import import_module from sympy.functions.special.gamma_functions import uppergamma, lowergamma import sympy MutableDenseMatrix = Matrix numpy = import_module('numpy') scipy = import_module('scipy', import_kwargs={'fromlist': ['sparse']}) numexpr = import_module('numexpr') tensorflow = import_module('tensorflow') cupy = import_module('cupy') jax = import_module('jax') numba = import_module('numba') if tensorflow: # Hide Tensorflow warnings import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' w, x, y, z = symbols('w,x,y,z') #================== Test different arguments ======================= def test_no_args(): f = lambdify([], 1) raises(TypeError, lambda: f(-1)) assert f() == 1 def test_single_arg(): f = lambdify(x, 2*x) assert f(1) == 2 def test_list_args(): f = lambdify([x, y], x + y) assert f(1, 2) == 3 def test_nested_args(): f1 = lambdify([[w, x]], [w, x]) assert f1([91, 2]) == [91, 2] raises(TypeError, lambda: f1(1, 2)) f2 = lambdify([(w, x), (y, z)], [w, x, y, z]) assert f2((18, 12), (73, 4)) == [18, 12, 73, 4] raises(TypeError, lambda: f2(3, 4)) f3 = lambdify([w, [[[x]], y], z], [w, x, y, z]) assert f3(10, [[[52]], 31], 44) == [10, 52, 31, 44] def test_str_args(): f = lambdify('x,y,z', 'z,y,x') assert f(3, 2, 1) == (1, 2, 3) assert f(1.0, 2.0, 3.0) == (3.0, 2.0, 1.0) # make sure correct number of args required raises(TypeError, lambda: f(0)) def test_own_namespace_1(): myfunc = lambda x: 1 f = lambdify(x, sin(x), {"sin": myfunc}) assert f(0.1) == 1 assert f(100) == 1 def test_own_namespace_2(): def myfunc(x): return 1 f = lambdify(x, sin(x), {'sin': myfunc}) assert f(0.1) == 1 assert f(100) == 1 def test_own_module(): f = lambdify(x, sin(x), math) assert f(0) == 0.0 p, q, r = symbols("p q r", real=True) ae = abs(exp(p+UnevaluatedExpr(q+r))) f = lambdify([p, q, r], [ae, ae], modules=math) results = f(1.0, 1e18, -1e18) refvals = [math.exp(1.0)]*2 for res, ref in zip(results, refvals): assert abs((res-ref)/ref) < 1e-15 def test_bad_args(): # no vargs given raises(TypeError, lambda: lambdify(1)) # same with vector exprs raises(TypeError, lambda: lambdify([1, 2])) def test_atoms(): # Non-Symbol atoms should not be pulled out from the expression namespace f = lambdify(x, pi + x, {"pi": 3.14}) assert f(0) == 3.14 f = lambdify(x, I + x, {"I": 1j}) assert f(1) == 1 + 1j #================== Test different modules ========================= # high precision output of sin(0.2*pi) is used to detect if precision is lost unwanted @conserve_mpmath_dps def test_sympy_lambda(): mpmath.mp.dps = 50 sin02 = mpmath.mpf("0.19866933079506121545941262711838975037020672954020") f = lambdify(x, sin(x), "sympy") assert f(x) == sin(x) prec = 1e-15 assert -prec < f(Rational(1, 5)).evalf() - Float(str(sin02)) < prec # arctan is in numpy module and should not be available # The arctan below gives NameError. What is this supposed to test? # raises(NameError, lambda: lambdify(x, arctan(x), "sympy")) @conserve_mpmath_dps def test_math_lambda(): mpmath.mp.dps = 50 sin02 = mpmath.mpf("0.19866933079506121545941262711838975037020672954020") f = lambdify(x, sin(x), "math") prec = 1e-15 assert -prec < f(0.2) - sin02 < prec raises(TypeError, lambda: f(x)) # if this succeeds, it can't be a Python math function @conserve_mpmath_dps def test_mpmath_lambda(): mpmath.mp.dps = 50 sin02 = mpmath.mpf("0.19866933079506121545941262711838975037020672954020") f = lambdify(x, sin(x), "mpmath") prec = 1e-49 # mpmath precision is around 50 decimal places assert -prec < f(mpmath.mpf("0.2")) - sin02 < prec raises(TypeError, lambda: f(x)) # if this succeeds, it can't be a mpmath function ref2 = (mpmath.mpf("1e-30") - mpmath.mpf("1e-45")/2 + 5*mpmath.mpf("1e-60")/6 - 3*mpmath.mpf("1e-75")/4 + 33*mpmath.mpf("1e-90")/40 ) f2a = lambdify((x, y), x**y - 1, "mpmath") f2b = lambdify((x, y), powm1(x, y), "mpmath") f2c = lambdify((x,), expm1(x*log1p(x)), "mpmath") ans2a = f2a(mpmath.mpf("1")+mpmath.mpf("1e-15"), mpmath.mpf("1e-15")) ans2b = f2b(mpmath.mpf("1")+mpmath.mpf("1e-15"), mpmath.mpf("1e-15")) ans2c = f2c(mpmath.mpf("1e-15")) assert abs(ans2a - ref2) < 1e-51 assert abs(ans2b - ref2) < 1e-67 assert abs(ans2c - ref2) < 1e-80 @conserve_mpmath_dps def test_number_precision(): mpmath.mp.dps = 50 sin02 = mpmath.mpf("0.19866933079506121545941262711838975037020672954020") f = lambdify(x, sin02, "mpmath") prec = 1e-49 # mpmath precision is around 50 decimal places assert -prec < f(0) - sin02 < prec @conserve_mpmath_dps def test_mpmath_precision(): mpmath.mp.dps = 100 assert str(lambdify((), pi.evalf(100), 'mpmath')()) == str(pi.evalf(100)) #================== Test Translations ============================== # We can only check if all translated functions are valid. It has to be checked # by hand if they are complete. def test_math_transl(): from sympy.utilities.lambdify import MATH_TRANSLATIONS for sym, mat in MATH_TRANSLATIONS.items(): assert sym in sympy.__dict__ assert mat in math.__dict__ def test_mpmath_transl(): from sympy.utilities.lambdify import MPMATH_TRANSLATIONS for sym, mat in MPMATH_TRANSLATIONS.items(): assert sym in sympy.__dict__ or sym == 'Matrix' assert mat in mpmath.__dict__ def test_numpy_transl(): if not numpy: skip("numpy not installed.") from sympy.utilities.lambdify import NUMPY_TRANSLATIONS for sym, nump in NUMPY_TRANSLATIONS.items(): assert sym in sympy.__dict__ assert nump in numpy.__dict__ def test_scipy_transl(): if not scipy: skip("scipy not installed.") from sympy.utilities.lambdify import SCIPY_TRANSLATIONS for sym, scip in SCIPY_TRANSLATIONS.items(): assert sym in sympy.__dict__ assert scip in scipy.__dict__ or scip in scipy.special.__dict__ def test_numpy_translation_abs(): if not numpy: skip("numpy not installed.") f = lambdify(x, Abs(x), "numpy") assert f(-1) == 1 assert f(1) == 1 def test_numexpr_printer(): if not numexpr: skip("numexpr not installed.") # if translation/printing is done incorrectly then evaluating # a lambdified numexpr expression will throw an exception from sympy.printing.lambdarepr import NumExprPrinter blacklist = ('where', 'complex', 'contains') arg_tuple = (x, y, z) # some functions take more than one argument for sym in NumExprPrinter._numexpr_functions.keys(): if sym in blacklist: continue ssym = S(sym) if hasattr(ssym, '_nargs'): nargs = ssym._nargs[0] else: nargs = 1 args = arg_tuple[:nargs] f = lambdify(args, ssym(*args), modules='numexpr') assert f(*(1, )*nargs) is not None def test_cmath_sqrt(): f = lambdify(x, sqrt(x), "cmath") assert f(0) == 0 assert f(1) == 1 assert f(4) == 2 assert abs(f(2) - 1.414) < 0.001 assert f(-1) == 1j assert f(-4) == 2j def test_cmath_log(): f = lambdify(x, log(x), "cmath") assert abs(f(1) - 0) < 1e-15 assert abs(f(cmath.e) - 1) < 1e-15 assert abs(f(-1) - cmath.log(-1)) < 1e-15 def test_cmath_sinh(): f = lambdify(x, sinh(x), "cmath") assert abs(f(0) - cmath.sinh(0)) < 1e-15 assert abs(f(pi) - cmath.sinh(pi)) < 1e-15 assert abs(f(-pi) - cmath.sinh(-pi)) < 1e-15 assert abs(f(1j) - cmath.sinh(1j)) < 1e-15 def test_cmath_cosh(): f = lambdify(x, cosh(x), "cmath") assert abs(f(0) - cmath.cosh(0)) < 1e-15 assert abs(f(pi) - cmath.cosh(pi)) < 1e-15 assert abs(f(-pi) - cmath.cosh(-pi)) < 1e-15 assert abs(f(1j) - cmath.cosh(1j)) < 1e-15 def test_cmath_tanh(): f = lambdify(x, tanh(x), "cmath") assert abs(f(0) - cmath.tanh(0)) < 1e-15 assert abs(f(pi) - cmath.tanh(pi)) < 1e-15 assert abs(f(-pi) - cmath.tanh(-pi)) < 1e-15 assert abs(f(1j) - cmath.tanh(1j)) < 1e-15 def test_cmath_sin(): f = lambdify(x, sin(x), "cmath") assert abs(f(0) - cmath.sin(0)) < 1e-15 assert abs(f(pi) - cmath.sin(pi)) < 1e-15 assert abs(f(-pi) - cmath.sin(-pi)) < 1e-15 assert abs(f(1j) - cmath.sin(1j)) < 1e-15 def test_cmath_cos(): f = lambdify(x, cos(x), "cmath") assert abs(f(0) - cmath.cos(0)) < 1e-15 assert abs(f(pi) - cmath.cos(pi)) < 1e-15 assert abs(f(-pi) - cmath.cos(-pi)) < 1e-15 assert abs(f(1j) - cmath.cos(1j)) < 1e-15 def test_cmath_tan(): f = lambdify(x, tan(x), "cmath") assert abs(f(0) - cmath.tan(0)) < 1e-15 assert abs(f(1j) - cmath.tan(1j)) < 1e-15 def test_cmath_asin(): f = lambdify(x, asin(x), "cmath") assert abs(f(0) - cmath.asin(0)) < 1e-15 assert abs(f(1) - cmath.asin(1)) < 1e-15 assert abs(f(-1) - cmath.asin(-1)) < 1e-15 assert abs(f(2) - cmath.asin(2)) < 1e-15 assert abs(f(1j) - cmath.asin(1j)) < 1e-15 def test_cmath_acos(): f = lambdify(x, acos(x), "cmath") assert abs(f(1) - cmath.acos(1)) < 1e-15 assert abs(f(-1) - cmath.acos(-1)) < 1e-15 assert abs(f(2) - cmath.acos(2)) < 1e-15 assert abs(f(1j) - cmath.acos(1j)) < 1e-15 def test_cmath_atan(): f = lambdify(x, atan(x), "cmath") assert abs(f(0) - cmath.atan(0)) < 1e-15 assert abs(f(1) - cmath.atan(1)) < 1e-15 assert abs(f(-1) - cmath.atan(-1)) < 1e-15 assert abs(f(2) - cmath.atan(2)) < 1e-15 assert abs(f(2j) - cmath.atan(2j)) < 1e-15 def test_cmath_asinh(): f = lambdify(x, asinh(x), "cmath") assert abs(f(0) - cmath.asinh(0)) < 1e-15 assert abs(f(1) - cmath.asinh(1)) < 1e-15 assert abs(f(-1) - cmath.asinh(-1)) < 1e-15 assert abs(f(2) - cmath.asinh(2)) < 1e-15 assert abs(f(2j) - cmath.asinh(2j)) < 1e-15 def test_cmath_acosh(): f = lambdify(x, acosh(x), "cmath") assert abs(f(1) - cmath.acosh(1)) < 1e-15 assert abs(f(2) - cmath.acosh(2)) < 1e-15 assert abs(f(-1) - cmath.acosh(-1)) < 1e-15 assert abs(f(2j) - cmath.acosh(2j)) < 1e-15 def test_cmath_atanh(): f = lambdify(x, atanh(x), "cmath") assert abs(f(0) - cmath.atanh(0)) < 1e-15 assert abs(f(0.5) - cmath.atanh(0.5)) < 1e-15 assert abs(f(-0.5) - cmath.atanh(-0.5)) < 1e-15 assert abs(f(2) - cmath.atanh(2)) < 1e-15 assert abs(f(-2) - cmath.atanh(-2)) < 1e-15 assert abs(f(2j) - cmath.atanh(2j)) < 1e-15 def test_cmath_complex_identities(): # Define symbol z = symbols('z') # Trigonometric identity using re(z) and im(z) expr = cos(z) - cos(re(z)) * cosh(im(z)) + I * sin(re(z)) * sinh(im(z)) func = lambdify([z], expr, modules=["cmath", "math"]) hpi = math.pi / 2 assert abs(func(hpi + 1j * hpi)) < 4e-16 # Euler's Formula: e^(i*z) = cos(z) + i*sin(z) func = lambdify([z], exp(I * z) - (cos(z) + I * sin(z)), modules=["cmath", "math"]) assert abs(func(hpi)) < 4e-16 # Exponential Identity: e^z = e^(Re(z)) * (cos(Im(z)) + i*sin(Im(z))) func_exp = lambdify([z], exp(z) - exp(re(z)) * (cos(im(z)) + I * sin(im(z))), modules=["cmath", "math"]) assert abs(func_exp(hpi + 1j * hpi)) < 4e-16 # Complex Cosine Identity: cos(z) = cos(Re(z)) * cosh(Im(z)) - i*sin(Re(z)) * sinh(Im(z)) func_cos = lambdify([z], cos(z) - (cos(re(z)) * cosh(im(z)) - I * sin(re(z)) * sinh(im(z))), modules=["cmath", "math"]) assert abs(func_cos(hpi + 1j * hpi)) < 4e-16 # Complex Sine Identity: sin(z) = sin(Re(z)) * cosh(Im(z)) + i*cos(Re(z)) * sinh(Im(z)) func_sin = lambdify([z], sin(z) - (sin(re(z)) * cosh(im(z)) + I * cos(re(z)) * sinh(im(z))), modules=["cmath", "math"]) assert abs(func_sin(hpi + 1j * hpi)) < 4e-16 # Complex Hyperbolic Cosine Identity: cosh(z) = cosh(Re(z)) * cos(Im(z)) + i*sinh(Re(z)) * sin(Im(z)) func_cosh_1 = lambdify([z], cosh(z) - (cosh(re(z)) * cos(im(z)) + I * sinh(re(z)) * sin(im(z))), modules=["cmath", "math"]) assert abs(func_cosh_1(hpi + 1j * hpi)) < 4e-16 # Complex Hyperbolic Sine Identity: sinh(z) = sinh(Re(z)) * cos(Im(z)) + i*cosh(Re(z)) * sin(Im(z)) func_sinh = lambdify([z], sinh(z) - (sinh(re(z)) * cos(im(z)) + I * cosh(re(z)) * sin(im(z))), modules=["cmath", "math"]) assert abs(func_sinh(hpi + 1j * hpi)) < 4e-16 # cosh(z) = (e^z + e^(-z)) / 2 func_cosh_2 = lambdify([z], cosh(z) - (exp(z) + exp(-z)) / 2, modules=["cmath", "math"]) assert abs(func_cosh_2(hpi)) < 4e-16 # Additional expressions testing log and exp with real and imaginary parts expr1 = log(re(z)) + log(im(z)) - log(re(z) * im(z)) expr2 = exp(re(z)) * exp(im(z) * I) - exp(z) expr3 = log(exp(re(z))) - re(z) expr4 = exp(log(re(z))) - re(z) expr5 = log(exp(re(z) + im(z))) - (re(z) + im(z)) expr6 = exp(log(re(z) + im(z))) - (re(z) + im(z)) func1 = lambdify([z], expr1, modules=["cmath", "math"]) func2 = lambdify([z], expr2, modules=["cmath", "math"]) func3 = lambdify([z], expr3, modules=["cmath", "math"]) func4 = lambdify([z], expr4, modules=["cmath", "math"]) func5 = lambdify([z], expr5, modules=["cmath", "math"]) func6 = lambdify([z], expr6, modules=["cmath", "math"]) test_value = 3 + 4j assert abs(func1(test_value)) < 4e-16 assert abs(func2(test_value)) < 4e-16 assert abs(func3(test_value)) < 4e-16 assert abs(func4(test_value)) < 4e-16 assert abs(func5(test_value)) < 4e-16 assert abs(func6(test_value)) < 4e-16 def test_issue_9334(): if not numexpr: skip("numexpr not installed.") if not numpy: skip("numpy not installed.") expr = S('b*a - sqrt(a**2)') a, b = sorted(expr.free_symbols, key=lambda s: s.name) func_numexpr = lambdify((a,b), expr, modules=[numexpr], dummify=False) foo, bar = numpy.random.random((2, 4)) func_numexpr(foo, bar) def test_issue_12984(): if not numexpr: skip("numexpr not installed.") func_numexpr = lambdify((x,y,z), Piecewise((y, x >= 0), (z, x > -1)), numexpr) with ignore_warnings(RuntimeWarning): assert func_numexpr(1, 24, 42) == 24 assert str(func_numexpr(-1, 24, 42)) == 'nan' def test_empty_modules(): x, y = symbols('x y') expr = -(x % y) no_modules = lambdify([x, y], expr) empty_modules = lambdify([x, y], expr, modules=[]) assert no_modules(3, 7) == empty_modules(3, 7) assert no_modules(3, 7) == -3 def test_exponentiation(): f = lambdify(x, x**2) assert f(-1) == 1 assert f(0) == 0 assert f(1) == 1 assert f(-2) == 4 assert f(2) == 4 assert f(2.5) == 6.25 def test_sqrt(): f = lambdify(x, sqrt(x)) assert f(0) == 0.0 assert f(1) == 1.0 assert f(4) == 2.0 assert abs(f(2) - 1.414) < 0.001 assert f(6.25) == 2.5 def test_trig(): f = lambdify([x], [cos(x), sin(x)], 'math') d = f(pi) prec = 1e-11 assert -prec < d[0] + 1 < prec assert -prec < d[1] < prec d = f(3.14159) prec = 1e-5 assert -prec < d[0] + 1 < prec assert -prec < d[1] < prec def test_integral(): if numpy and not scipy: skip("scipy not installed.") f = Lambda(x, exp(-x**2)) l = lambdify(y, Integral(f(x), (x, y, oo))) d = l(-oo) assert 1.77245385 < d < 1.772453851 def test_double_integral(): if numpy and not scipy: skip("scipy not installed.") # example from http://mpmath.org/doc/current/calculus/integration.html i = Integral(1/(1 - x**2*y**2), (x, 0, 1), (y, 0, z)) l = lambdify([z], i) d = l(1) assert 1.23370055 < d < 1.233700551 def test_spherical_bessel(): if numpy and not scipy: skip("scipy not installed.") test_point = 4.2 #randomly selected x = symbols("x") jtest = jn(2, x) assert abs(lambdify(x,jtest)(test_point) - jtest.subs(x,test_point).evalf()) < 1e-8 ytest = yn(2, x) assert abs(lambdify(x,ytest)(test_point) - ytest.subs(x,test_point).evalf()) < 1e-8 #================== Test vectors =================================== def test_vector_simple(): f = lambdify((x, y, z), (z, y, x)) assert f(3, 2, 1) == (1, 2, 3) assert f(1.0, 2.0, 3.0) == (3.0, 2.0, 1.0) # make sure correct number of args required raises(TypeError, lambda: f(0)) def test_vector_discontinuous(): f = lambdify(x, (-1/x, 1/x)) raises(ZeroDivisionError, lambda: f(0)) assert f(1) == (-1.0, 1.0) assert f(2) == (-0.5, 0.5) assert f(-2) == (0.5, -0.5) def test_trig_symbolic(): f = lambdify([x], [cos(x), sin(x)], 'math') d = f(pi) assert abs(d[0] + 1) < 0.0001 assert abs(d[1] - 0) < 0.0001 def test_trig_float(): f = lambdify([x], [cos(x), sin(x)]) d = f(3.14159) assert abs(d[0] + 1) < 0.0001 assert abs(d[1] - 0) < 0.0001 def test_docs(): f = lambdify(x, x**2) assert f(2) == 4 f = lambdify([x, y, z], [z, y, x]) assert f(1, 2, 3) == [3, 2, 1] f = lambdify(x, sqrt(x)) assert f(4) == 2.0 f = lambdify((x, y), sin(x*y)**2) assert f(0, 5) == 0 def test_math(): f = lambdify((x, y), sin(x), modules="math") assert f(0, 5) == 0 def test_sin(): f = lambdify(x, sin(x)**2) assert isinstance(f(2), float) f = lambdify(x, sin(x)**2, modules="math") assert isinstance(f(2), float) def test_matrix(): A = Matrix([[x, x*y], [sin(z) + 4, x**z]]) sol = Matrix([[1, 2], [sin(3) + 4, 1]]) f = lambdify((x, y, z), A, modules="sympy") assert f(1, 2, 3) == sol f = lambdify((x, y, z), (A, [A]), modules="sympy") assert f(1, 2, 3) == (sol, [sol]) J = Matrix((x, x + y)).jacobian((x, y)) v = Matrix((x, y)) sol = Matrix([[1, 0], [1, 1]]) assert lambdify(v, J, modules='sympy')(1, 2) == sol assert lambdify(v.T, J, modules='sympy')(1, 2) == sol def test_numpy_matrix(): if not numpy: skip("numpy not installed.") A = Matrix([[x, x*y], [sin(z) + 4, x**z]]) sol_arr = numpy.array([[1, 2], [numpy.sin(3) + 4, 1]]) #Lambdify array first, to ensure return to array as default f = lambdify((x, y, z), A, ['numpy']) numpy.testing.assert_allclose(f(1, 2, 3), sol_arr) #Check that the types are arrays and matrices assert isinstance(f(1, 2, 3), numpy.ndarray) # gh-15071 class dot(Function): pass x_dot_mtx = dot(x, Matrix([[2], [1], [0]])) f_dot1 = lambdify(x, x_dot_mtx) inp = numpy.zeros((17, 3)) assert numpy.all(f_dot1(inp) == 0) strict_kw = {"allow_unknown_functions": False, "inline": True, "fully_qualified_modules": False} p2 = NumPyPrinter(dict(user_functions={'dot': 'dot'}, **strict_kw)) f_dot2 = lambdify(x, x_dot_mtx, printer=p2) assert numpy.all(f_dot2(inp) == 0) p3 = NumPyPrinter(strict_kw) # The line below should probably fail upon construction (before calling with "(inp)"): raises(Exception, lambda: lambdify(x, x_dot_mtx, printer=p3)(inp)) def test_numpy_transpose(): if not numpy: skip("numpy not installed.") A = Matrix([[1, x], [0, 1]]) f = lambdify((x), A.T, modules="numpy") numpy.testing.assert_array_equal(f(2), numpy.array([[1, 0], [2, 1]])) def test_numpy_dotproduct(): if not numpy: skip("numpy not installed") A = Matrix([x, y, z]) f1 = lambdify([x, y, z], DotProduct(A, A), modules='numpy') f2 = lambdify([x, y, z], DotProduct(A, A.T), modules='numpy') f3 = lambdify([x, y, z], DotProduct(A.T, A), modules='numpy') f4 = lambdify([x, y, z], DotProduct(A, A.T), modules='numpy') assert f1(1, 2, 3) == \ f2(1, 2, 3) == \ f3(1, 2, 3) == \ f4(1, 2, 3) == \ numpy.array([14]) def test_numpy_inverse(): if not numpy: skip("numpy not installed.") A = Matrix([[1, x], [0, 1]]) f = lambdify((x), A**-1, modules="numpy") numpy.testing.assert_array_equal(f(2), numpy.array([[1, -2], [0, 1]])) def test_numpy_old_matrix(): if not numpy: skip("numpy not installed.") A = Matrix([[x, x*y], [sin(z) + 4, x**z]]) sol_arr = numpy.array([[1, 2], [numpy.sin(3) + 4, 1]]) f = lambdify((x, y, z), A, [{'ImmutableDenseMatrix': numpy.matrix}, 'numpy']) with ignore_warnings(PendingDeprecationWarning): numpy.testing.assert_allclose(f(1, 2, 3), sol_arr) assert isinstance(f(1, 2, 3), numpy.matrix) def test_scipy_sparse_matrix(): if not scipy: skip("scipy not installed.") A = SparseMatrix([[x, 0], [0, y]]) f = lambdify((x, y), A, modules="scipy") B = f(1, 2) assert isinstance(B, scipy.sparse.coo_matrix) def test_python_div_zero_issue_11306(): if not numpy: skip("numpy not installed.") p = Piecewise((1 / x, y < -1), (x, y < 1), (1 / x, True)) f = lambdify([x, y], p, modules='numpy') with numpy.errstate(divide='ignore'): assert float(f(numpy.array(0), numpy.array(0.5))) == 0 assert float(f(numpy.array(0), numpy.array(1))) == float('inf') def test_issue9474(): mods = [None, 'math'] if numpy: mods.append('numpy') if mpmath: mods.append('mpmath') for mod in mods: f = lambdify(x, S.One/x, modules=mod) assert f(2) == 0.5 f = lambdify(x, floor(S.One/x), modules=mod) assert f(2) == 0 for absfunc, modules in product([Abs, abs], mods): f = lambdify(x, absfunc(x), modules=modules) assert f(-1) == 1 assert f(1) == 1 assert f(3+4j) == 5 def test_issue_9871(): if not numexpr: skip("numexpr not installed.") if not numpy: skip("numpy not installed.") r = sqrt(x**2 + y**2) expr = diff(1/r, x) xn = yn = numpy.linspace(1, 10, 16) # expr(xn, xn) = -xn/(sqrt(2)*xn)^3 fv_exact = -numpy.sqrt(2.)**-3 * xn**-2 fv_numpy = lambdify((x, y), expr, modules='numpy')(xn, yn) fv_numexpr = lambdify((x, y), expr, modules='numexpr')(xn, yn) numpy.testing.assert_allclose(fv_numpy, fv_exact, rtol=1e-10) numpy.testing.assert_allclose(fv_numexpr, fv_exact, rtol=1e-10) def test_numpy_piecewise(): if not numpy: skip("numpy not installed.") pieces = Piecewise((x, x < 3), (x**2, x > 5), (0, True)) f = lambdify(x, pieces, modules="numpy") numpy.testing.assert_array_equal(f(numpy.arange(10)), numpy.array([0, 1, 2, 0, 0, 0, 36, 49, 64, 81])) # If we evaluate somewhere all conditions are False, we should get back NaN nodef_func = lambdify(x, Piecewise((x, x > 0), (-x, x < 0))) numpy.testing.assert_array_equal(nodef_func(numpy.array([-1, 0, 1])), numpy.array([1, numpy.nan, 1])) def test_numpy_logical_ops(): if not numpy: skip("numpy not installed.") and_func = lambdify((x, y), And(x, y), modules="numpy") and_func_3 = lambdify((x, y, z), And(x, y, z), modules="numpy") or_func = lambdify((x, y), Or(x, y), modules="numpy") or_func_3 = lambdify((x, y, z), Or(x, y, z), modules="numpy") not_func = lambdify((x), Not(x), modules="numpy") arr1 = numpy.array([True, True]) arr2 = numpy.array([False, True]) arr3 = numpy.array([True, False]) numpy.testing.assert_array_equal(and_func(arr1, arr2), numpy.array([False, True])) numpy.testing.assert_array_equal(and_func_3(arr1, arr2, arr3), numpy.array([False, False])) numpy.testing.assert_array_equal(or_func(arr1, arr2), numpy.array([True, True])) numpy.testing.assert_array_equal(or_func_3(arr1, arr2, arr3), numpy.array([True, True])) numpy.testing.assert_array_equal(not_func(arr2), numpy.array([True, False])) def test_numpy_matmul(): if not numpy: skip("numpy not installed.") xmat = Matrix([[x, y], [z, 1+z]]) ymat = Matrix([[x**2], [Abs(x)]]) mat_func = lambdify((x, y, z), xmat*ymat, modules="numpy") numpy.testing.assert_array_equal(mat_func(0.5, 3, 4), numpy.array([[1.625], [3.5]])) numpy.testing.assert_array_equal(mat_func(-0.5, 3, 4), numpy.array([[1.375], [3.5]])) # Multiple matrices chained together in multiplication f = lambdify((x, y, z), xmat*xmat*xmat, modules="numpy") numpy.testing.assert_array_equal(f(0.5, 3, 4), numpy.array([[72.125, 119.25], [159, 251]])) def test_numpy_numexpr(): if not numpy: skip("numpy not installed.") if not numexpr: skip("numexpr not installed.") a, b, c = numpy.random.randn(3, 128, 128) # ensure that numpy and numexpr return same value for complicated expression expr = sin(x) + cos(y) + tan(z)**2 + Abs(z-y)*acos(sin(y*z)) + \ Abs(y-z)*acosh(2+exp(y-x))- sqrt(x**2+I*y**2) npfunc = lambdify((x, y, z), expr, modules='numpy') nefunc = lambdify((x, y, z), expr, modules='numexpr') assert numpy.allclose(npfunc(a, b, c), nefunc(a, b, c)) def test_numexpr_userfunctions(): if not numpy: skip("numpy not installed.") if not numexpr: skip("numexpr not installed.") a, b = numpy.random.randn(2, 10) uf = type('uf', (Function, ), {'eval' : classmethod(lambda x, y : y**2+1)}) func = lambdify(x, 1-uf(x), modules='numexpr') assert numpy.allclose(func(a), -(a**2)) uf = implemented_function(Function('uf'), lambda x, y : 2*x*y+1) func = lambdify((x, y), uf(x, y), modules='numexpr') assert numpy.allclose(func(a, b), 2*a*b+1) def test_tensorflow_basic_math(): if not tensorflow: skip("tensorflow not installed.") expr = Max(sin(x), Abs(1/(x+2))) func = lambdify(x, expr, modules="tensorflow") with tensorflow.compat.v1.Session() as s: a = tensorflow.constant(0, dtype=tensorflow.float32) assert func(a).eval(session=s) == 0.5 def test_tensorflow_placeholders(): if not tensorflow: skip("tensorflow not installed.") expr = Max(sin(x), Abs(1/(x+2))) func = lambdify(x, expr, modules="tensorflow") with tensorflow.compat.v1.Session() as s: a = tensorflow.compat.v1.placeholder(dtype=tensorflow.float32) assert func(a).eval(session=s, feed_dict={a: 0}) == 0.5 def test_tensorflow_variables(): if not tensorflow: skip("tensorflow not installed.") expr = Max(sin(x), Abs(1/(x+2))) func = lambdify(x, expr, modules="tensorflow") with tensorflow.compat.v1.Session() as s: a = tensorflow.Variable(0, dtype=tensorflow.float32) s.run(a.initializer) assert func(a).eval(session=s, feed_dict={a: 0}) == 0.5 def test_tensorflow_logical_operations(): if not tensorflow: skip("tensorflow not installed.") expr = Not(And(Or(x, y), y)) func = lambdify([x, y], expr, modules="tensorflow") with tensorflow.compat.v1.Session() as s: assert func(False, True).eval(session=s) == False def test_tensorflow_piecewise(): if not tensorflow: skip("tensorflow not installed.") expr = Piecewise((0, Eq(x,0)), (-1, x < 0), (1, x > 0)) func = lambdify(x, expr, modules="tensorflow") with tensorflow.compat.v1.Session() as s: assert func(-1).eval(session=s) == -1 assert func(0).eval(session=s) == 0 assert func(1).eval(session=s) == 1 def test_tensorflow_multi_max(): if not tensorflow: skip("tensorflow not installed.") expr = Max(x, -x, x**2) func = lambdify(x, expr, modules="tensorflow") with tensorflow.compat.v1.Session() as s: assert func(-2).eval(session=s) == 4 def test_tensorflow_multi_min(): if not tensorflow: skip("tensorflow not installed.") expr = Min(x, -x, x**2) func = lambdify(x, expr, modules="tensorflow") with tensorflow.compat.v1.Session() as s: assert func(-2).eval(session=s) == -2 def test_tensorflow_relational(): if not tensorflow: skip("tensorflow not installed.") expr = x >= 0 func = lambdify(x, expr, modules="tensorflow") with tensorflow.compat.v1.Session() as s: assert func(1).eval(session=s) == True def test_tensorflow_complexes(): if not tensorflow: skip("tensorflow not installed") func1 = lambdify(x, re(x), modules="tensorflow") func2 = lambdify(x, im(x), modules="tensorflow") func3 = lambdify(x, Abs(x), modules="tensorflow") func4 = lambdify(x, arg(x), modules="tensorflow") with tensorflow.compat.v1.Session() as s: # For versions before # https://github.com/tensorflow/tensorflow/issues/30029 # resolved, using Python numeric types may not work a = tensorflow.constant(1+2j) assert func1(a).eval(session=s) == 1 assert func2(a).eval(session=s) == 2 tensorflow_result = func3(a).eval(session=s) sympy_result = Abs(1 + 2j).evalf() assert abs(tensorflow_result-sympy_result) < 10**-6 tensorflow_result = func4(a).eval(session=s) sympy_result = arg(1 + 2j).evalf() assert abs(tensorflow_result-sympy_result) < 10**-6 def test_tensorflow_array_arg(): # Test for issue 14655 (tensorflow part) if not tensorflow: skip("tensorflow not installed.") f = lambdify([[x, y]], x*x + y, 'tensorflow') with tensorflow.compat.v1.Session() as s: fcall = f(tensorflow.constant([2.0, 1.0])) assert fcall.eval(session=s) == 5.0 #================== Test symbolic ================================== def test_sym_single_arg(): f = lambdify(x, x * y) assert f(z) == z * y def test_sym_list_args(): f = lambdify([x, y], x + y + z) assert f(1, 2) == 3 + z def test_sym_integral(): f = Lambda(x, exp(-x**2)) l = lambdify(x, Integral(f(x), (x, -oo, oo)), modules="sympy") assert l(y) == Integral(exp(-y**2), (y, -oo, oo)) assert l(y).doit() == sqrt(pi) def test_namespace_order(): # lambdify had a bug, such that module dictionaries or cached module # dictionaries would pull earlier namespaces into themselves. # Because the module dictionaries form the namespace of the # generated lambda, this meant that the behavior of a previously # generated lambda function could change as a result of later calls # to lambdify. n1 = {'f': lambda x: 'first f'} n2 = {'f': lambda x: 'second f', 'g': lambda x: 'function g'} f = sympy.Function('f') g = sympy.Function('g') if1 = lambdify(x, f(x), modules=(n1, "sympy")) assert if1(1) == 'first f' if2 = lambdify(x, g(x), modules=(n2, "sympy")) # previously gave 'second f' assert if1(1) == 'first f' assert if2(1) == 'function g' def test_imps(): # Here we check if the default returned functions are anonymous - in # the sense that we can have more than one function with the same name f = implemented_function('f', lambda x: 2*x) g = implemented_function('f', lambda x: math.sqrt(x)) l1 = lambdify(x, f(x)) l2 = lambdify(x, g(x)) assert str(f(x)) == str(g(x)) assert l1(3) == 6 assert l2(3) == math.sqrt(3) # check that we can pass in a Function as input func = sympy.Function('myfunc') assert not hasattr(func, '_imp_') my_f = implemented_function(func, lambda x: 2*x) assert hasattr(my_f, '_imp_') # Error for functions with same name and different implementation f2 = implemented_function("f", lambda x: x + 101) raises(ValueError, lambda: lambdify(x, f(f2(x)))) def test_imps_errors(): # Test errors that implemented functions can return, and still be able to # form expressions. # See: https://github.com/sympy/sympy/issues/10810 # # XXX: Removed AttributeError here. This test was added due to issue 10810 # but that issue was about ValueError. It doesn't seem reasonable to # "support" catching AttributeError in the same context... for val, error_class in product((0, 0., 2, 2.0), (TypeError, ValueError)): def myfunc(a): if a == 0: raise error_class return 1 f = implemented_function('f', myfunc) expr = f(val) assert expr == f(val) def test_imps_wrong_args(): raises(ValueError, lambda: implemented_function(sin, lambda x: x)) def test_lambdify_imps(): # Test lambdify with implemented functions # first test basic (sympy) lambdify f = sympy.cos assert lambdify(x, f(x))(0) == 1 assert lambdify(x, 1 + f(x))(0) == 2 assert lambdify((x, y), y + f(x))(0, 1) == 2 # make an implemented function and test f = implemented_function("f", lambda x: x + 100) assert lambdify(x, f(x))(0) == 100 assert lambdify(x, 1 + f(x))(0) == 101 assert lambdify((x, y), y + f(x))(0, 1) == 101 # Can also handle tuples, lists, dicts as expressions lam = lambdify(x, (f(x), x)) assert lam(3) == (103, 3) lam = lambdify(x, [f(x), x]) assert lam(3) == [103, 3] lam = lambdify(x, [f(x), (f(x), x)]) assert lam(3) == [103, (103, 3)] lam = lambdify(x, {f(x): x}) assert lam(3) == {103: 3} lam = lambdify(x, {f(x): x}) assert lam(3) == {103: 3} lam = lambdify(x, {x: f(x)}) assert lam(3) == {3: 103} # Check that imp preferred to other namespaces by default d = {'f': lambda x: x + 99} lam = lambdify(x, f(x), d) assert lam(3) == 103 # Unless flag passed lam = lambdify(x, f(x), d, use_imps=False) assert lam(3) == 102 def test_dummification(): t = symbols('t') F = Function('F') G = Function('G') #"\alpha" is not a valid Python variable name #lambdify should sub in a dummy for it, and return #without a syntax error alpha = symbols(r'\alpha') some_expr = 2 * F(t)**2 / G(t) lam = lambdify((F(t), G(t)), some_expr) assert lam(3, 9) == 2 lam = lambdify(sin(t), 2 * sin(t)**2) assert lam(F(t)) == 2 * F(t)**2 #Test that \alpha was properly dummified lam = lambdify((alpha, t), 2*alpha + t) assert lam(2, 1) == 5 raises(SyntaxError, lambda: lambdify(F(t) * G(t), F(t) * G(t) + 5)) raises(SyntaxError, lambda: lambdify(2 * F(t), 2 * F(t) + 5)) raises(SyntaxError, lambda: lambdify(2 * F(t), 4 * F(t) + 5)) def test_lambdify__arguments_with_invalid_python_identifiers(): # see sympy/sympy#26690 N = CoordSys3D('N') xn, yn, zn = N.base_scalars() expr = xn + yn f = lambdify([xn, yn], expr) res = f(0.2, 0.3) ref = 0.2 + 0.3 assert abs(res-ref) < 1e-15 def test_curly_matrix_symbol(): # Issue #15009 curlyv = sympy.MatrixSymbol("{v}", 2, 1) lam = lambdify(curlyv, curlyv) assert lam(1)==1 lam = lambdify(curlyv, curlyv, dummify=True) assert lam(1)==1 def test_python_keywords(): # Test for issue 7452. The automatic dummification should ensure use of # Python reserved keywords as symbol names will create valid lambda # functions. This is an additional regression test. python_if = symbols('if') expr = python_if / 2 f = lambdify(python_if, expr) assert f(4.0) == 2.0 def test_lambdify_docstring(): func = lambdify((w, x, y, z), w + x + y + z) ref = ( "Created with lambdify. Signature:\n\n" "func(w, x, y, z)\n\n" "Expression:\n\n" "w + x + y + z" ).splitlines() assert func.__doc__.splitlines()[:len(ref)] == ref syms = symbols('a1:26') func = lambdify(syms, sum(syms)) ref = ( "Created with lambdify. Signature:\n\n" "func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,\n" " a16, a17, a18, a19, a20, a21, a22, a23, a24, a25)\n\n" "Expression:\n\n" "a1 + a10 + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + a19 + a2 + a20 +..." ).splitlines() assert func.__doc__.splitlines()[:len(ref)] == ref def test_lambdify_linecache(): func = lambdify(x, x + 1) source = 'def _lambdifygenerated(x):\n return x + 1\n' assert inspect.getsource(func) == source filename = inspect.getsourcefile(func) assert filename.startswith('= (1, 10) if have_scipy_1_10plus: cm2 = lambdify((x, y), powm1(x, y), modules='scipy') assert abs(cm2(1.2, 1e-9) - 1.82321557e-10) < 1e-17 def test_scipy_bernoulli(): if not scipy: skip("scipy not installed") bern = lambdify((x,), bernoulli(x), modules='scipy') assert bern(1) == 0.5 def test_scipy_harmonic(): if not scipy: skip("scipy not installed") hn = lambdify((x,), harmonic(x), modules='scipy') assert hn(2) == 1.5 hnm = lambdify((x, y), harmonic(x, y), modules='scipy') assert hnm(2, 2) == 1.25 def test_cupy_array_arg(): if not cupy: skip("CuPy not installed") f = lambdify([[x, y]], x*x + y, 'cupy') result = f(cupy.array([2.0, 1.0])) assert result == 5 assert "cupy" in str(type(result)) def test_cupy_array_arg_using_numpy(): # numpy functions can be run on cupy arrays # unclear if we can "officially" support this, # depends on numpy __array_function__ support if not cupy: skip("CuPy not installed") f = lambdify([[x, y]], x*x + y, 'numpy') result = f(cupy.array([2.0, 1.0])) assert result == 5 assert "cupy" in str(type(result)) def test_cupy_dotproduct(): if not cupy: skip("CuPy not installed") A = Matrix([x, y, z]) f1 = lambdify([x, y, z], DotProduct(A, A), modules='cupy') f2 = lambdify([x, y, z], DotProduct(A, A.T), modules='cupy') f3 = lambdify([x, y, z], DotProduct(A.T, A), modules='cupy') f4 = lambdify([x, y, z], DotProduct(A, A.T), modules='cupy') assert f1(1, 2, 3) == \ f2(1, 2, 3) == \ f3(1, 2, 3) == \ f4(1, 2, 3) == \ cupy.array([14]) def test_jax_array_arg(): if not jax: skip("JAX not installed") f = lambdify([[x, y]], x*x + y, 'jax') result = f(jax.numpy.array([2.0, 1.0])) assert result == 5 assert "jax" in str(type(result)) def test_jax_array_arg_using_numpy(): if not jax: skip("JAX not installed") f = lambdify([[x, y]], x*x + y, 'numpy') result = f(jax.numpy.array([2.0, 1.0])) assert result == 5 assert "jax" in str(type(result)) def test_jax_dotproduct(): if not jax: skip("JAX not installed") A = Matrix([x, y, z]) f1 = lambdify([x, y, z], DotProduct(A, A), modules='jax') f2 = lambdify([x, y, z], DotProduct(A, A.T), modules='jax') f3 = lambdify([x, y, z], DotProduct(A.T, A), modules='jax') f4 = lambdify([x, y, z], DotProduct(A, A.T), modules='jax') assert f1(1, 2, 3) == \ f2(1, 2, 3) == \ f3(1, 2, 3) == \ f4(1, 2, 3) == \ jax.numpy.array([14]) def test_lambdify_cse(): def no_op_cse(exprs): return (), exprs def dummy_cse(exprs): from sympy.simplify.cse_main import cse return cse(exprs, symbols=numbered_symbols(cls=Dummy)) def minmem(exprs): from sympy.simplify.cse_main import cse_release_variables, cse return cse(exprs, postprocess=cse_release_variables) class Case: def __init__(self, *, args, exprs, num_args, requires_numpy=False): self.args = args self.exprs = exprs self.num_args = num_args subs_dict = dict(zip(self.args, self.num_args)) self.ref = [e.subs(subs_dict).evalf() for e in exprs] self.requires_numpy = requires_numpy def lambdify(self, *, cse): return lambdify(self.args, self.exprs, cse=cse) def assertAllClose(self, result, *, abstol=1e-15, reltol=1e-15): if self.requires_numpy: assert all(numpy.allclose(result[i], numpy.asarray(r, dtype=float), rtol=reltol, atol=abstol) for i, r in enumerate(self.ref)) return for i, r in enumerate(self.ref): abs_err = abs(result[i] - r) if r == 0: assert abs_err < abstol else: assert abs_err/abs(r) < reltol cases = [ Case( args=(x, y, z), exprs=[ x + y + z, x + y - z, 2*x + 2*y - z, (x+y)**2 + (y+z)**2, ], num_args=(2., 3., 4.) ), Case( args=(x, y, z), exprs=[ x + sympy.Heaviside(x), y + sympy.Heaviside(x), z + sympy.Heaviside(x, 1), z/sympy.Heaviside(x, 1) ], num_args=(0., 3., 4.) ), Case( args=(x, y, z), exprs=[ x + sinc(y), y + sinc(y), z - sinc(y) ], num_args=(0.1, 0.2, 0.3) ), Case( args=(x, y, z), exprs=[ Matrix([[x, x*y], [sin(z) + 4, x**z]]), x*y+sin(z)-x**z, Matrix([x*x, sin(z), x**z]) ], num_args=(1.,2.,3.), requires_numpy=True ), Case( args=(x, y), exprs=[(x + y - 1)**2, x, x + y, (x + y)/(2*x + 1) + (x + y - 1)**2, (2*x + 1)**(x + y)], num_args=(1,2) ) ] for case in cases: if not numpy and case.requires_numpy: continue for _cse in [False, True, minmem, no_op_cse, dummy_cse]: f = case.lambdify(cse=_cse) result = f(*case.num_args) case.assertAllClose(result) def test_issue_25288(): syms = numbered_symbols(cls=Dummy) ok = lambdify(x, [x**2, sin(x**2)], cse=lambda e: cse(e, symbols=syms))(2) assert ok def test_deprecated_set(): with warns_deprecated_sympy(): lambdify({x, y}, x + y) def test_issue_13881(): if not numpy: skip("numpy not installed.") X = MatrixSymbol('X', 3, 1) f = lambdify(X, X.T*X, 'numpy') assert f(numpy.array([1, 2, 3])) == 14 assert f(numpy.array([3, 2, 1])) == 14 f = lambdify(X, X*X.T, 'numpy') assert f(numpy.array([1, 2, 3])) == 14 assert f(numpy.array([3, 2, 1])) == 14 f = lambdify(X, (X*X.T)*X, 'numpy') arr1 = numpy.array([[1], [2], [3]]) arr2 = numpy.array([[14],[28],[42]]) assert numpy.array_equal(f(arr1), arr2) def test_23536_lambdify_cse_dummy(): f = Function('x')(y) g = Function('w')(y) expr = z + (f**4 + g**5)*(f**3 + (g*f)**3) expr = expr.expand() eval_expr = lambdify(((f, g), z), expr, cse=True) ans = eval_expr((1.0, 2.0), 3.0) # shouldn't raise NameError assert ans == 300.0 # not a list and value is 300 class LambdifyDocstringTestCase: SIGNATURE = None EXPR = None SRC = None def __init__(self, docstring_limit, expected_redacted): self.docstring_limit = docstring_limit self.expected_redacted = expected_redacted @property def expected_expr(self): expr_redacted_msg = "EXPRESSION REDACTED DUE TO LENGTH, (see lambdify's `docstring_limit`)" return self.EXPR if not self.expected_redacted else expr_redacted_msg @property def expected_src(self): src_redacted_msg = "SOURCE CODE REDACTED DUE TO LENGTH, (see lambdify's `docstring_limit`)" return self.SRC if not self.expected_redacted else src_redacted_msg @property def expected_docstring(self): expected_docstring = ( f'Created with lambdify. Signature:\n\n' f'func({self.SIGNATURE})\n\n' f'Expression:\n\n' f'{self.expected_expr}\n\n' f'Source code:\n\n' f'{self.expected_src}\n\n' f'Imported modules:\n\n' ) return expected_docstring def __len__(self): return len(self.expected_docstring) def __repr__(self): return ( f'{self.__class__.__name__}(' f'docstring_limit={self.docstring_limit}, ' f'expected_redacted={self.expected_redacted})' ) def test_lambdify_docstring_size_limit_simple_symbol(): class SimpleSymbolTestCase(LambdifyDocstringTestCase): SIGNATURE = 'x' EXPR = 'x' SRC = ( 'def _lambdifygenerated(x):\n' ' return x\n' ) x = symbols('x') test_cases = ( SimpleSymbolTestCase(docstring_limit=None, expected_redacted=False), SimpleSymbolTestCase(docstring_limit=100, expected_redacted=False), SimpleSymbolTestCase(docstring_limit=1, expected_redacted=False), SimpleSymbolTestCase(docstring_limit=0, expected_redacted=True), SimpleSymbolTestCase(docstring_limit=-1, expected_redacted=True), ) for test_case in test_cases: lambdified_expr = lambdify( [x], x, 'sympy', docstring_limit=test_case.docstring_limit, ) assert lambdified_expr.__doc__ == test_case.expected_docstring def test_lambdify_docstring_size_limit_nested_expr(): class ExprListTestCase(LambdifyDocstringTestCase): SIGNATURE = 'x, y, z' EXPR = ( '[x, [y], z, x**3 + 3*x**2*y + 3*x**2*z + 3*x*y**2 + 6*x*y*z ' '+ 3*x*z**2 +...' ) SRC = ( 'def _lambdifygenerated(x, y, z):\n' ' return [x, [y], z, x**3 + 3*x**2*y + 3*x**2*z + 3*x*y**2 ' '+ 6*x*y*z + 3*x*z**2 + y**3 + 3*y**2*z + 3*y*z**2 + z**3]\n' ) x, y, z = symbols('x, y, z') expr = [x, [y], z, ((x + y + z)**3).expand()] test_cases = ( ExprListTestCase(docstring_limit=None, expected_redacted=False), ExprListTestCase(docstring_limit=200, expected_redacted=False), ExprListTestCase(docstring_limit=50, expected_redacted=True), ExprListTestCase(docstring_limit=0, expected_redacted=True), ExprListTestCase(docstring_limit=-1, expected_redacted=True), ) for test_case in test_cases: lambdified_expr = lambdify( [x, y, z], expr, 'sympy', docstring_limit=test_case.docstring_limit, ) assert lambdified_expr.__doc__ == test_case.expected_docstring def test_lambdify_docstring_size_limit_matrix(): class MatrixTestCase(LambdifyDocstringTestCase): SIGNATURE = 'x, y, z' EXPR = ( 'Matrix([[0, x], [x + y + z, x**3 + 3*x**2*y + 3*x**2*z + 3*x*y**2 ' '+ 6*x*y*z...' ) SRC = ( 'def _lambdifygenerated(x, y, z):\n' ' return ImmutableDenseMatrix([[0, x], [x + y + z, x**3 ' '+ 3*x**2*y + 3*x**2*z + 3*x*y**2 + 6*x*y*z + 3*x*z**2 + y**3 ' '+ 3*y**2*z + 3*y*z**2 + z**3]])\n' ) x, y, z = symbols('x, y, z') expr = Matrix([[S.Zero, x], [x + y + z, ((x + y + z)**3).expand()]]) test_cases = ( MatrixTestCase(docstring_limit=None, expected_redacted=False), MatrixTestCase(docstring_limit=200, expected_redacted=False), MatrixTestCase(docstring_limit=50, expected_redacted=True), MatrixTestCase(docstring_limit=0, expected_redacted=True), MatrixTestCase(docstring_limit=-1, expected_redacted=True), ) for test_case in test_cases: lambdified_expr = lambdify( [x, y, z], expr, 'sympy', docstring_limit=test_case.docstring_limit, ) assert lambdified_expr.__doc__ == test_case.expected_docstring def test_lambdify_empty_tuple(): a = symbols("a") expr = ((), (a,)) f = lambdify(a, expr) result = f(1) assert result == ((), (1,)), "Lambdify did not handle the empty tuple correctly." def test_assoc_legendre_numerical_evaluation(): tol = 1e-10 sympy_result_integer = assoc_legendre(1, 1/2, 0.1).evalf() sympy_result_complex = assoc_legendre(2, 1, 3).evalf() mpmath_result_integer = -0.474572528387641 mpmath_result_complex = -25.45584412271571*I assert all_close(sympy_result_integer, mpmath_result_integer, tol) assert all_close(sympy_result_complex, mpmath_result_complex, tol) def test_Piecewise(): modules = [math] if numpy: modules.append('numpy') for mod in modules: # test isinf f = lambdify(x, Piecewise((7.0, isinf(x)), (3.0, True)), mod) assert f(+float('inf')) == +7.0 assert f(-float('inf')) == +7.0 assert f(42.) == 3.0 f2 = lambdify(x, Piecewise((7.0*sign(x), isinf(x)), (3.0, True)), mod) assert f2(+float('inf')) == +7.0 assert f2(-float('inf')) == -7.0 assert f2(42.) == 3.0 # test isnan (gh-26784) g = lambdify(x, Piecewise((7.0, isnan(x)), (3.0, True)), mod) assert g(float('nan')) == 7.0 assert g(42.) == 3.0 def test_array_symbol(): if not numpy: skip("numpy not installed.") a = ArraySymbol('a', (3,)) f = lambdify((a), a) assert numpy.all(f(numpy.array([1,2,3])) == numpy.array([1,2,3]))