Convert string of a named expression in sympy to the expression itself

276 views
Skip to first unread message

Santiago S

unread,
Jan 9, 2023, 11:00:04 AM1/9/23
to sympy
I have the following code

    import sympy as sp
    a, b = sp.symbols('a,b', real=True, positive=True)
    expr2 = 1.01 * a**1.01 * b**0.99
    print(type(expr2), '->', expr2)


Now I want a function that takes the string `'expr2'` and returns the expression `1.01 * a**1.01 * b**0.99`.
The ultimate objective is to put together the strings for two different expressions `'expr2'` and `'expr3'`, which should presumably give the same result, and verify their ratio, as in

    def verify_ratio(vstr1, vstr2):
        """Compare the result of two different computations of the same quantity"""
        ratio = sp.N(sp.parsing.sympy_parser.parse_expr(vstr1)) / sp.parsing.sympy_parser.parse_expr(vstr2)
        print(vstr1 + ' / ' + vstr2, '=', sp.N(ratio))
        return

which does not work, as per what I tried:

    expr2 = 1.01 * a**1.01 * b**0.99
    print(type(expr2), '->', expr2)
       
    expr2b = sp.parsing.sympy_parser.parse_expr('expr2')
    print(type(expr2b), '->', expr2b)
   
    expr2c = sp.N(sp.parsing.sympy_parser.parse_expr('expr2'))
    print(type(expr2c), '->', expr2c)
    #print(sp.N(sp.parsing.sympy_parser.parse_expr('expr2')))
   
    expr2d = sp.sympify('expr2')
    print(type(expr2d), '->', expr2d)

with output

    <class 'sympy.core.mul.Mul'> -> 1.01*a**1.01*b**0.99
    <class 'sympy.core.symbol.Symbol'> -> expr2
    <class 'sympy.core.symbol.Symbol'> -> expr2
    <class 'sympy.core.symbol.Symbol'> -> expr2

None of my attempts achieved the objective.
Questions or links which did not help (at least for me):

 1. https://stackoverflow.com/questions/33606667/from-string-to-sympy-expression
 2. https://docs.sympy.org/latest/tutorials/intro-tutorial/basic_operations.html
 3. https://docs.sympy.org/latest/modules/parsing.html
 4. https://docs.sympy.org/latest/modules/core.html#sympy.core.sympify.sympify
 5. https://docs.sympy.org/latest/tutorials/intro-tutorial/manipulation.html


**Note**:
Besides the practical aspects of my objective, I don't know if there is any formal difference between `Symbol` (which is a specific class) and *expression*. From the sources I read (e.g., [this][1]) I did not arrive to a conclusion.
This understanding may help in solving the question.


  [1]: https://docs.sympy.org/latest/tutorials/intro-tutorial/manipulation.html

gu...@uwosh.edu

unread,
Jan 9, 2023, 11:42:26 AM1/9/23
to sympy
I am not clear why you are working with strings and not just the expressions? I think the following may be what you want:
```
>>> import sympy as sp
>>> a,b = sp.symbols('a b', positive = True)
>>> expr = 1.01*a**1.01*b**0.99
>>> expr
1.01*a**1.01*b**0.99
>>> expr1 = 2*expr
>>> expr1
2.02*a**1.01*b**0.99
>>> expr1/expr
2.00000000000000
```
Your "verify ratio function" would then just take the two expressions directly. If you are trying to do something where you need to have intermediate strings, we will need more explicit details to provide some direction.

Santiago S

unread,
Jan 9, 2023, 3:45:26 PM1/9/23
to sympy
Because I want to build the name of the expressions to check by concatenating other strings, and then evaluate.
All this within loops, etc.

gu...@uwosh.edu

unread,
Jan 9, 2023, 4:12:13 PM1/9/23
to sympy
If you really do need to process strings, I think I see where you are having an issue with your experiment. 'expr2' does not give you the string representation of 'expr2'. I think you want this sequence of commands:
```
>>> import sympy as sp
>>> a, b = sp.symbols('a,b', real=True, positive=True)
>>> expr2 = 1.01 * a**1.01 * b**0.99
>>> print(type(expr2),'->',expr2)
<class 'sympy.core.mul.Mul'> -> 1.01*a**1.01*b**0.99
>>> expr2b = sp.parsing.sympy_parser.parse_expr(str(expr2))
>>> print(type(expr2b),'->',expr2b)
<class 'sympy.core.mul.Mul'> -> 1.01*a**1.01*b**0.99
```

Is that the behavior you are trying to achieve?

One comment. This is a place where sympy does not quite abide by python standards. In sympy the call str(expression) yields the sympy code for the expression. By python standards that should actually be returned by a call to repr(expression), while str(expression) should return a human readable representation. Most of the time there is not a difference anyway for sympy expressions. If you want to abide by python standards you can replace str(expression) with repr(expression). Others may know of problems, but I have not encountered any place where repr(expression) does not work.

Oscar Benjamin

unread,
Jan 9, 2023, 5:55:44 PM1/9/23
to sy...@googlegroups.com
This question was also asked and answered in other places:

https://github.com/sympy/sympy/discussions/24483
https://stackoverflow.com/questions/75057460/convert-string-of-a-named-expression-in-sympy-to-the-expression-itself

The OP wants eval:

In [1]: expr1 = x*y + 1

In [2]: expr1
Out[2]: x⋅y + 1

In [3]: eval('expr1')
Out[3]: x⋅y + 1

However this is not a good approach. A better one would be to avoid
global variables and use a data structure such as a dict:

In [4]: my_dict = {'expr1': x*y + 1}

In [5]: my_dict['expr1']
Out[5]: x⋅y + 1

--
Oscar
> --
> You received this message because you are subscribed to the Google Groups "sympy" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to sympy+un...@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/a71eff85-9948-45cd-aab0-0a1cad1f2c4cn%40googlegroups.com.

Aaron Meurer

unread,
Jan 10, 2023, 3:08:17 AM1/10/23
to sy...@googlegroups.com
I would suggest not even working with strings at all, especially if
you are just going to parse everything with parse_expr or sympify. You
can make expr1 and expr2 symbols, and map the symbols to expressions
with a dict:

expr2 = symbols('expr1 expr2')
repl_dict = {expr2: 1.01 * a**1.01 * b**0.99}

Then when you encounter an expression that has expr2 and you want it
to instead contain 1.01 * a**1.01 * b**0.99, use
expression.subs(repl_dict).

If you find yourself doing a lot of string manipulation in SymPy, it's
generally a sign that you're doing something incorrectly, and you
should just use symbolic expressions directly instead. For example, in
your verify_ratio() function, instead of

print(vstr1 + ' / ' + vstr2, '=', sp.N(ratio))

you could just have

ratio = v1/v2
print(ratio, '=', sp.N(ratio.subs(repl_dict)))

where v1 and v2 are just the symbols expr1 and expr2.

And in fact, unless you are dealing with arbitrary user input, the
string parsing is unnecessary too.

Aaron Meurer
> To view this discussion on the web visit https://groups.google.com/d/msgid/sympy/CAHVvXxRnCPP%2BTJU1xpMf_LiLRuvoTSDQJKg1ts-RhMC4kPpO8A%40mail.gmail.com.
Reply all
Reply to author
Forward
0 new messages