From 45f2a690d039276b797d503f6f37ee3250c81a47 Mon Sep 17 00:00:00 2001 From: Peter Baratta Date: Thu, 17 Jan 2013 06:51:57 -0700 Subject: [PATCH] Commented on high level functions --- lms/lib/symmath/formula.py | 16 ++++++++++---- lms/lib/symmath/symmath_check.py | 37 +++++++++++++++++++++++++++++--- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/lms/lib/symmath/formula.py b/lms/lib/symmath/formula.py index bab0ab3691..c34156da52 100644 --- a/lms/lib/symmath/formula.py +++ b/lms/lib/symmath/formula.py @@ -154,8 +154,9 @@ def my_sympify(expr, normphase=False, matrix=False, abcsym=False, do_qubit=False class formula(object): ''' - Representation of a mathematical formula object. Accepts mathml math expression for constructing, - and can produce sympy translation. The formula may or may not include an assignment (=). + Representation of a mathematical formula object. Accepts mathml math expression + for constructing, and can produce sympy translation. The formula may or may not + include an assignment (=). ''' def __init__(self, expr, asciimath='', options=None): self.expr = expr.strip() @@ -194,8 +195,12 @@ class formula(object): def preprocess_pmathml(self, xml): ''' - Pre-process presentation MathML from ASCIIMathML to make it more acceptable for SnuggleTeX, and also - to accomodate some sympy conventions (eg hat(i) for \hat{i}). + Pre-process presentation MathML from ASCIIMathML to make it more + acceptable for SnuggleTeX, and also to accomodate some sympy + conventions (eg hat(i) for \hat{i}). + + This method would be a good spot to look for an integral and convert + it, if possible... ''' if type(xml) == str or type(xml) == unicode: @@ -266,6 +271,9 @@ class formula(object): ''' Return sympy expression for the math formula. The math formula is converted to Content MathML then that is parsed. + + This is a recursive function, called on every CMML node. Support for + more functions can be added by modifying opdict, abould halfway down ''' if self.the_sympy: return self.the_sympy diff --git a/lms/lib/symmath/symmath_check.py b/lms/lib/symmath/symmath_check.py index bcb4a0d490..3cc4fd7d3c 100644 --- a/lms/lib/symmath/symmath_check.py +++ b/lms/lib/symmath/symmath_check.py @@ -157,13 +157,33 @@ def symmath_check(expect, ans, dynamath=None, options=None, debug=None, xml=None ''' Check a symbolic mathematical expression using sympy. The input may be presentation MathML. Uses formula. + + This is the default Symbolic Response checking function + + Desc of args: + expect is a sympy string representing the correct answer. It is interpreted + using my_sympify (from formula.py), which reads strings as sympy input + (e.g. 'integrate(x^2, (x,1,2))' would be valid, and evaluate to give 1.5) + + ans is student-typed answer. It is expected to be ascii math, but the code + below would support a sympy string. + + dynamath is the PMathML string converted by MathJax. It is used if + evaluation with ans is not sufficient. + + options is a string with these possible substrings, set as an xml property + of the problem: + -matrix - make a sympy matrix, rather than a list of lists, if possible + -qubit - passed to my_sympify + -imaginary - used in formla, presumably to signal to use i as sqrt(-1)? + -numerical - force numerical comparison. ''' msg = '' # msg += '

abname=%s' % abname # msg += '

adict=%s' % (repr(adict).replace('<','<')) - threshold = 1.0e-3 + threshold = 1.0e-3 # for numerical comparison (also with matrices) DEBUG = debug if xml is not None: @@ -184,13 +204,17 @@ def symmath_check(expect, ans, dynamath=None, options=None, debug=None, xml=None msg += '

Error %s in parsing OUR expected answer "%s"

' % (err, expect) return {'ok': False, 'msg': make_error_message(msg)} + + ###### Sympy input ####### # if expected answer is a number, try parsing provided answer as a number also try: fans = my_sympify(str(ans), matrix=do_matrix, do_qubit=do_qubit) except Exception, err: fans = None - if hasattr(fexpect, 'is_number') and fexpect.is_number and fans and hasattr(fans, 'is_number') and fans.is_number: + # do a numerical comparison if both expected and answer are numbers + if (hasattr(fexpect, 'is_number') and fexpect.is_number and fans + and hasattr(fans, 'is_number') and fans.is_number): if abs(abs(fans - fexpect) / fexpect) < threshold: return {'ok': True, 'msg': msg} else: @@ -208,6 +232,8 @@ def symmath_check(expect, ans, dynamath=None, options=None, debug=None, xml=None msg += '

You entered: %s

' % to_latex(fans) return {'ok': True, 'msg': msg} + + ###### PMathML input ###### # convert mathml answer to formula try: if dynamath: @@ -216,6 +242,7 @@ def symmath_check(expect, ans, dynamath=None, options=None, debug=None, xml=None mmlans = None if not mmlans: return {'ok': False, 'msg': '[symmath_check] failed to get MathML for input; dynamath=%s' % dynamath} + f = formula(mmlans, options=options) # get sympy representation of the formula @@ -238,7 +265,7 @@ def symmath_check(expect, ans, dynamath=None, options=None, debug=None, xml=None msg += '
' return {'ok': False, 'msg': make_error_message(msg)} - # compare with expected + # do numerical comparison with expected if hasattr(fexpect, 'is_number') and fexpect.is_number: if hasattr(fsym, 'is_number') and fsym.is_number: if abs(abs(fsym - fexpect) / fexpect) < threshold: @@ -250,6 +277,10 @@ def symmath_check(expect, ans, dynamath=None, options=None, debug=None, xml=None # msg += "

cmathml =

%s

" % str(f.cmathml).replace('<','<') return {'ok': False, 'msg': make_error_message(msg)} + # Here is a good spot for adding calls to X.simplify() or X.expand(), + # allowing equivalence over binomial expansion or trig identities + + # exactly the same? if fexpect == fsym: return {'ok': True, 'msg': msg}