How to evaluate an expression-tree in sympy?

1.1k Views Asked by At

This might be a very basic question, but I am wondering if I am missing a sympy-functionality after reading through the documentation, or if there is really non included for this use-case.

I have the following expressions:

a = sympify("b + 5")
b = sympify("c + 5")
c = sympify("5")

I am trying to evaluate a. Is there any way that sympy does all the recursive search and replace for you or do I really have to do it manually?

Such as:

eval(str(eval(str(a))))
1

There are 1 best solutions below

6
On BEST ANSWER

Make a distinction between the symbols and the expressions:

import sympy as sy
a, b, c = sy.symbols('a:c')

a_expr = sy.sympify("b + 5")
b_expr = sy.sympify("c + 5")
c_expr = sy.sympify("5")

sy.solve([sy.Eq(a,a_expr), sy.Eq(b,b_expr), sy.Eq(c,c_expr)])

yields

{c: 5, b: 10, a: 15}

Above, a is a Symbol, but a_expr is an expression:

In [117]: type(a)
Out[117]: sympy.core.symbol.Symbol

In [118]: type(a_expr)
Out[118]: sympy.core.add.Add

Given a dict of formulas such as

formulas = {'a': 'b+5', 'b': 'c+5', 'c': '5'}

you could form the equations with a list comprehension

equations = [sy.Eq(sy.symbols(variable), sy.sympify(expr))
             for variable, expr in formulas.items()]

and solve the system of equations with

solution = sy.solve(equations)
# {c: 5, b: 10, a: 15}

Why you should not use sympy.var:

When dealing with dynamic variables -- variables whose names are unknown until run-time -- it is advisable to avoid using sy.var. sy.var adds the name of the variable to the global namespace. The only purpose in doing this is if you are going to reference the variable by name. But by hypothesis the variable names are unknown until run-time. So the script code should not -- in fact, should not be able to -- reference the variables by name. So using sy.var should be useless if the variables are truly dynamic.

That's no real problem, however. The dynamic variables names (as strings) can be listed with

In [22]: formulas.keys()
Out[22]: ['a', 'c', 'b']

and the sy.Symbols can be listed with

In [23]: solution.keys()
Out[23]: [c, b, a]

So you can write loops to access each variable without ever having to define a global variable name for each Symbol.