rocksNwaves
rocksNwaves

Reputation: 6144

Passing a function formula using sympify and evaluating it

I have seen and attempted to implement the following answer to a similar question to no avail: https://stackoverflow.com/a/23687379/3696204

I have also reviewed the documentation for SymPy evalf, about halfway down on this article: http://docs.sympy.org/latest/tutorial/basic_operations.html

My code:

from sympy import sympify


def test_function(a, b, c, d, funct):

    f = sympify(funct)
    dx = 0.2
    J = int(2/dx)

    for i in range(J-1):
        x = -1 + (i * dx)
        print("f(", x, ") = ", f.evalf(x))

    print("Just for fun: ", a, b, c, d)

    return c + d


if __name__ == '__main__':

    print(test_function(1, 2, 3, 4, funct="pow(x, 4) - 2 * pow(x, 2) + 2"))

    print(test_function(1, 2, 3, 4, funct="x**4 - 2 * x**2 + 2"))

Results in:


    f( -1.0 ) =  -0.e+0*pow(x, 2) + pow(x, 4) + 0.e+0
    f( -0.8 ) =  -0.e+0*pow(x, 2) + pow(x, 4) + 0.e+0
    f( -0.6 ) =  -0.e+0*pow(x, 2) + pow(x, 4) + 0.e+0
    f( -0.3999999999999999 ) =  -0.e+0*pow(x, 2) + pow(x, 4) + 0.e+0
    f( -0.19999999999999996 ) =  -0.e+0*pow(x, 2) + pow(x, 4) + 0.e+0
    f( 0.0 ) =  -0.e+0*pow(x, 2) + pow(x, 4) + 0.e+0
    f( 0.20000000000000018 ) =  -0.e+0*pow(x, 2) + pow(x, 4) + 0.e+0
    f( 0.40000000000000013 ) =  -0.e+0*pow(x, 2) + pow(x, 4) + 0.e+0
    f( 0.6000000000000001 ) =  -0.e+0*pow(x, 2) + pow(x, 4) + 0.e+0
    Just for fun:  1 2 3 4
    7 
f( -1.0 ) = x**4 - 0.e+0*x**2 + 0.e+0 f( -0.8 ) = x**4 - 0.e+0*x**2 + 0.e+0 f( -0.6 ) = x**4 - 0.e+0*x**2 + 0.e+0 f( -0.3999999999999999 ) = x**4 - 0.e+0*x**2 + 0.e+0 f( -0.19999999999999996 ) = x**4 - 0.e+0*x**2 + 0.e+0 f( 0.0 ) = x**4 - 0.e+0*x**2 + 0.e+0 f( 0.20000000000000018 ) = x**4 - 0.e+0*x**2 + 0.e+0 f( 0.40000000000000013 ) = x**4 - 0.e+0*x**2 + 0.e+0 f( 0.6000000000000001 ) = x**4 - 0.e+0*x**2 + 0.e+0 Just for fun: 1 2 3 4 7

Based on reading the documentation, have also tried f.evalf(subs=x), f.evalf(subs={x: x_i}) where I redefined my loop in terms of x_i. In the first case I get a complaint about "floats not being subscriptable", and in the second case I get a complaint saying that "x is not defined".

Ok, that's all of my efforts so far. If anybody is curious, I have programmed the Thomas Algorithm for solving tri-diagonal matrices and am now create a method that applies Thomas to solve a PDE with the initial conditions given by some some equation. I want to pass that equation to my algorithm so that initial conditions can be provided on the fly.

Upvotes: 0

Views: 1073

Answers (2)

ducminh
ducminh

Reputation: 1352

After sympifying, f is an expression. We can turn f into a sympy function using lambdify:

>>> x = Symbol('x')
>>> f = lambdify(x, sympify("pow(x, 4) - 2 * pow(x, 2) + 2"))
>>> [f(0.2 * i) for i in range(5)]
[2.0, 1.9216, 1.7056, 1.4096, 1.1296]

Upvotes: 1

user6655984
user6655984

Reputation:

When sympify is executed on an string, the substring "x" gets interpreted as a symbol, namely Symbol("x"). This object has nothing to do with any Python variables you may call x. Symbol names and variable names are different things.

To replace Symbol("x") by the Python variable called x, you need

f.subs(Symbol('x'), x)

This subs is enough, floating-point evaluation happens automatically since you supplied a floating-point argument. Otherwise, evalf could be forced with

f.evalf(subs={Symbol('x'): x})

By the way, f.evalf(x) means: evaluate f returning x decimal digits; nothing to do with substitution.

Asides

Function names: x**4 and Pow(x, 4) both work, but pow(x, 4) has no meaning for SymPy.

To see the difference between variable names and symbol names, try

b = Symbol("a") 
print(b)  # prints "a"
print(a)  # undefined

Upvotes: 1

Related Questions