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)
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