Search code examples
pythonsympysymbolic-math

Sympify returning different expression for same input


I have a list of strings I need to parse to SymPy expressions. The problem is, if one of them raises a SympifyError exception, the following string will not return the same SymPy expression an identical string returned before the exception.

For example, the following code:

import traceback

from sympy.core import sympify
from sympy.core.evaluate import evaluate
from sympy.core.sympify import SympifyError

if __name__ == '__main__':

    equations = ['Eq(sin(pi/6), x/10)', 'Eq(x, 3))', 'Eq(sin(pi/6), x/10)']

    for equation in equations:

        try:
            with evaluate(False):
                expr = sympify(equation)

            print(expr)

        except SympifyError:
            traceback.print_exc()

outputs:

Traceback (most recent call last):
Eq(sin(pi/6), x/10)
  File "C:\Users\vini_\Anaconda3\lib\site-packages\sympy\core\sympify.py", line 354, in sympify
Eq(sin(pi/6**1), x/10**1)
    expr = parse_expr(a, local_dict=locals, transformations=transformations, evaluate=evaluate)
  File "C:\Users\vini_\Anaconda3\lib\site-packages\sympy\parsing\sympy_parser.py", line 889, in parse_expr
    code = stringify_expr(s, local_dict, global_dict, transformations)
  File "C:\Users\vini_\Anaconda3\lib\site-packages\sympy\parsing\sympy_parser.py", line 791, in stringify_expr
    for toknum, tokval, _, _, _ in generate_tokens(input_code.readline):
  File "C:\Users\vini_\Anaconda3\lib\site-packages\sympy\parsing\sympy_tokenize.py", line 384, in generate_tokens
    raise TokenError("EOF in multi-line statement", (lnum, 0))
sympy.parsing.sympy_tokenize.TokenError: ('EOF in multi-line statement', (2, 0))

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:/Users/vini_/PycharmProjects/bugfix_simpify/main.py", line 22, in <module>
    expr = sympify(equation)
  File "C:\Users\vini_\Anaconda3\lib\site-packages\sympy\core\sympify.py", line 356, in sympify
    raise SympifyError('could not parse %r' % a, exc)
sympy.core.sympify.SympifyError: Sympify of expression 'could not parse 'Eq(x, 3))'' failed, because of exception being raised:
TokenError: ('EOF in multi-line statement', (2, 0))

Note that the first and third strings are identical, but their output is different (there's an additional **1. The second one is intentionally incorrect (unbalanced parenthesis). I'm using the evaluate(False) line because I need the expression to be as close as possible to the original string.

What am I doing wrong? Is there any way to fix it so that the output is the same for identical input strings?

Environment: Python 3.6.1; SymPy 1.1.1

Thanks in advance.


Solution

  • Your problem vanishes when I move the context manager evaluate outside the tryexcept expression:

    import traceback
    
    from sympy.core import sympify
    from sympy.core.evaluate import evaluate
    from sympy.core.sympify import SympifyError
    
    equations = ['Eq(sin(pi/6), x/10)', 'Eq(x, 3))', 'Eq(sin(pi/6), x/10)']
    
    for equation in equations:
        with evaluate(False):
            try:
                expr = sympify(equation)
            except SympifyError:
                traceback.print_exc()
            else:
                print(expr)
    

    While this is something you probably should have done anyway (always put as little as possible in the try clause), you should not have encountered this problem, which seems to be a bug – probably related to the context manager evaluate not being properly closed. Here is a much simpler script (obtained by reducing yours) producing a similar problem:

    from sympy import sympify, evaluate
    from sympy.abc import x,y
    
    try:
        with evaluate(False):
            sympify(")")
    except:
        pass
    
    (x+y).simplify()
    

    I reported this bug.