fgblomqvist
fgblomqvist

Reputation: 2424

Using SymPy to generically parse and solve equations

I want to be able to parse string equations (that are equal to 0) and then solve them by using a dictionary of variables that I have access to.

For example:

s = '(x/z)-y'
eq = parse(s)
eq.solve({'x': 10, 'y': 5})
print(eq)
>>> {'z': 2}

Now I had written code that did something like this a month ago, but I just can't find it. I do remember however that I used SymPy and its sympify function, along with its solve function. I have checked the documentation on these functions, but I've not been able to wrap my head around how to get them to work as I want.

And an extra question: Would it be possible to wrap the variables somehow so that I could use something more than just a letter for them? Example: Instead of just 'x' I could have '{myvar-42}'

EDIT:

Okay I finally succeeded writing some code that did what I wanted to:

eq = sympify('(x/y)-z', locals={'x': 10, 'z': 5})
solution = solve(eq, dict=True)
print(solution)
>>> [{'z': 2}]

But my "extra" question remains.

Upvotes: 7

Views: 4318

Answers (1)

asmeurer
asmeurer

Reputation: 91490

As you've discovered, sympify converts strings into SymPy expressions.

To answer your other question, Symbol names can be anything, but sympify will only parse valid Python identifiers to Symbol names. But you can do

>>> Symbol('{myvar-42}') + 1
{myvar-42} + 1

And note that valid Python idenfifiers do not have to be single letters. They can be any combination of letters, numbers, and underscores that does not start with a number, like x_2 or abc123.

If you need to still do string parsing but want non-valid Python identifiers as Symbol names, probably the cleanest way would be to use normal names and substitute them in for other ones, like

>>> expr = sympify('x + 1')
>>> expr.subs(Symbol('x'), Symbol('{myvar-42}')
{myvar-42} + 1

Finally, to replace the symbols with letters, you can use the locals argument to sympify, as you have done, or, if you want to replace them later, use subs:

>>> x, y, z = symbols('x y z')
>>> expr = sympify('x/z - y')
>>> expr.subs({x: 10, y: 5})
10/z - 5

Upvotes: 6

Related Questions