phppythonsympymathjaxasciimath

Parsing AsciiMath to Python expression


I am attempting to pass 2 functions to a python script via JSON in order to evaluate their equivalence. The issue I am having is that the input is in AsciiMath notation. It seems sympify has no issue parsing the expressions from the strings if the format is consistent with that of Python expressions. Is there a way to parse AsciiMath notation into something Python can interpret? I have been unable to find any libraries that offer such a feature.

PHP:

$data = array("2*x", "x*2"); // returns true as expected
$data = array("2x", "x2"); // AsciiMath notation does not work
$result = shell_exec('python /path/check.py ' . escapeshellarg(json_encode($data)));

Python:

import sys, json
from sympy import *

# Load the json data sent from PHP
try:
    data = json.loads(sys.argv[1])
except:
    sys.exit(1)

x = Symbol('x')

# Convert string inputs to expressions
user_response = sympify(data[0])
correct_answer = sympify(data[1])

# Perform equivalence comparison
result = user_response == correct_answer

# Return result
print json.dumps(result)

Solution

  • When asking a question like this, you should demonstrate the problem. Here's what I think is happening.

    With one set of expressions, sympify works fine:

    In [144]: sympify('2*x')==sympify('x*2')                                             
    Out[144]: True
    

    But with the other pair:

    In [145]: sympify('2x')==sympify('x2')                                               
    ---------------------------------------------------------------------------
    SyntaxError                               Traceback (most recent call last)
    /usr/local/lib/python3.6/dist-packages/sympy/core/sympify.py in sympify(a, locals, convert_xor, strict, rational, evaluate)
        367         a = a.replace('\n', '')
    --> 368         expr = parse_expr(a, local_dict=locals, transformations=transformations, evaluate=evaluate)
        369     except (TokenError, SyntaxError) as exc:
     ...
    SympifyError: Sympify of expression 'could not parse '2x'' failed, because of exception being raised:
    SyntaxError: invalid syntax (<string>, line 1)
    

    That's just for the '2x' string. For the other string:

    In [146]: sympify('x2')                                                              
    Out[146]: x₂
    

    sympify is expecting strings that could evaluated in a sympy environment

    Converts an arbitrary expression to a type that can be used inside SymPy.

    It says arbitrary, but the docs are somewhat more restrictive, as described.

    It currently accepts as arguments:
       - any object defined in sympy
       - standard numeric python types: int, long, float, Decimal
       - strings (like "0.09" or "2e-19")
       - booleans, including ``None`` (will leave ``None`` unchanged)
       - lists, sets or tuples containing any of the above
    

    In the context of the question that means expressions using x which was defined with

    x = Symbol('x')
    

    but ones using y would have problems.

    ===

    sympify produces a sympy expression:

    In [161]: expr = sympify('2*x')                                                      
    
    In [162]: type(expr)                                                                 
    Out[162]: sympy.core.mul.Mul
    

    which can then be 'evaluated' in various ways. I could describe this a 'modified', except sympy stresses that the expression is immutable. These actions all produce new expressions or values:

    In [163]: expr.subs(x,21)                                                            
    Out[163]: 42
    
    In [164]: expr.diff(x)                                                               
    Out[164]: 2
    
    In [165]: expr.integrate(x)                                                          
    Out[165]: 
     2
    x 
    

    ===

    Also such an expression cannot be evaluated by the core Python interpreter,

    Define a new symbol, and expression:

    In [166]: y = Symbol('y')                                                            
    In [167]: expr = sympify('2*y')                                                      
    
    In [168]: expr                                                                       
    Out[168]: 2⋅y
    

    Reassigning y to be a Python integer, does not change the value of expr:

    In [169]: y = 21                                                                         
    In [170]: expr                                                                       
    Out[170]: 2⋅y
    

    but it does allow us to evaluate a regular Python expression:

    In [171]: 2*y                                                                        
    Out[171]: 42
    

    But the same Python expression using x symbol produces a sympy expression:

    In [172]: 2*x                                                                        
    Out[172]: 2⋅x
    

    ===

    https://docs.sympy.org/latest/modules/parsing.html

    This parsing module has means of handling expressions like '2x'. At least the docs show:

    (again in a isympy session):

    In [173]: from sympy.parsing.sympy_parser import parse_expr                          
    
    In [174]: from sympy.parsing.sympy_parser import parse_expr, standard_transformations
         ...: , implicit_multiplication_application                                      
    
    In [175]: transformations=(standard_transformations + (implicit_multiplication_applic
         ...: ation,))                                                                   
    
    In [176]: parse_expr('2x', transformations=transformations)                          
    Out[176]: 2⋅x
    
    In [177]: parse_expr('x2', transformations=transformations)                          
    Out[177]: 2⋅x
    

    So it does handle your example, but I don't know enough of asciimatch to know how much else works.

    That page also talks about a LaTeX parser, https://docs.sympy.org/latest/modules/parsing.html#experimental-latex-parsing