Commit 27c3ba4a by Sarina Canelake

pep8/pylint cleanup on symmath/formula.py

parent d8144b0d
#!/usr/bin/python #!/usr/bin/python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""
Flexible python representation of a symbolic mathematical formula.
Acceptes Presentation MathML, Content MathML (and could also do OpenMath).
Provides sympy representation.
"""
# #
# File: formula.py # File: formula.py
# Date: 04-May-12 (creation) # Date: 04-May-12 (creation)
# Author: I. Chuang <ichuang@mit.edu> # Author: I. Chuang <ichuang@mit.edu>
# #
# flexible python representation of a symbolic mathematical formula.
# Acceptes Presentation MathML, Content MathML (and could also do OpenMath)
# Provides sympy representation.
import os import os
import string # pylint: disable=W0402 import string # pylint: disable=W0402
...@@ -19,11 +21,8 @@ import sympy ...@@ -19,11 +21,8 @@ import sympy
from sympy.printing.latex import LatexPrinter from sympy.printing.latex import LatexPrinter
from sympy.printing.str import StrPrinter from sympy.printing.str import StrPrinter
from sympy import latex, sympify from sympy import latex, sympify
from sympy.physics.quantum.qubit import * from sympy.physics.quantum.qubit import Qubit
from sympy.physics.quantum.state import * from sympy.physics.quantum.state import Ket
# from sympy import exp, pi, I
# from sympy.core.operations import LatticeOp
# import sympy.physics.quantum.qubit
from xml.sax.saxutils import unescape from xml.sax.saxutils import unescape
import unicodedata import unicodedata
...@@ -40,53 +39,63 @@ os.environ['PYTHONIOENCODING'] = 'utf-8' ...@@ -40,53 +39,63 @@ os.environ['PYTHONIOENCODING'] = 'utf-8'
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
class dot(sympy.operations.LatticeOp): # my dot product class dot(sympy.operations.LatticeOp): # pylint: disable=invalid-name, no-member
"""my dot product"""
zero = sympy.Symbol('dotzero') zero = sympy.Symbol('dotzero')
identity = sympy.Symbol('dotidentity') identity = sympy.Symbol('dotidentity')
#class dot(sympy.Mul): # my dot product
# is_Mul = False
def _print_dot(_self, expr):
def _print_dot(self, expr): """Print statement used for LatexPrinter"""
return r'{((%s) \cdot (%s))}' % (expr.args[0], expr.args[1]) return r'{((%s) \cdot (%s))}' % (expr.args[0], expr.args[1])
LatexPrinter._print_dot = _print_dot LatexPrinter._print_dot = _print_dot # pylint: disable=protected-access
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# unit vectors (for 8.02) # unit vectors (for 8.02)
def _print_hat(self, expr): return '\\hat{%s}' % str(expr.args[0]).lower() def _print_hat(_self, expr):
"""Print statement used for LatexPrinter"""
return '\\hat{%s}' % str(expr.args[0]).lower()
LatexPrinter._print_hat = _print_hat LatexPrinter._print_hat = _print_hat # pylint: disable=protected-access
StrPrinter._print_hat = _print_hat StrPrinter._print_hat = _print_hat # pylint: disable=protected-access
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
# helper routines # helper routines
def to_latex(x): def to_latex(expr):
if x is None: return '' """
# LatexPrinter._print_dot = _print_dot Convert expression to latex mathjax format
xs = latex(x) """
xs = xs.replace(r'\XI', 'XI') # workaround for strange greek if expr is None:
return ''
expr_s = latex(expr)
expr_s = expr_s.replace(r'\XI', 'XI') # workaround for strange greek
# substitute back into latex form for scripts # substitute back into latex form for scripts
# literally something of the form # literally something of the form
# 'scriptN' becomes '\\mathcal{N}' # 'scriptN' becomes '\\mathcal{N}'
# note: can't use something akin to the _print_hat method above because we sometimes get 'script(N)__B' or more complicated terms # note: can't use something akin to the _print_hat method above because we sometimes get 'script(N)__B' or more complicated terms
xs = re.sub(r'script([a-zA-Z0-9]+)', expr_s = re.sub(
r'script([a-zA-Z0-9]+)',
'\\mathcal{\\1}', '\\mathcal{\\1}',
xs) expr_s
)
#return '<math>%s{}{}</math>' % (xs[1:-1]) #return '<math>%s{}{}</math>' % (xs[1:-1])
if xs[0] == '$': if expr_s[0] == '$':
return '[mathjax]%s[/mathjax]<br>' % (xs[1:-1]) # for sympy v6 return '[mathjax]%s[/mathjax]<br>' % (expr_s[1:-1]) # for sympy v6
return '[mathjax]%s[/mathjax]<br>' % (xs) # for sympy v7 return '[mathjax]%s[/mathjax]<br>' % (expr_s) # for sympy v7
def my_evalf(expr, chop=False): def my_evalf(expr, chop=False):
"""
Enhanced sympy evalf to handle lists of expressions
and catch eval failures without dropping out.
"""
if type(expr) == list: if type(expr) == list:
try: try:
return [x.evalf(chop=chop) for x in expr] return [x.evalf(chop=chop) for x in expr]
...@@ -97,11 +106,11 @@ def my_evalf(expr, chop=False): ...@@ -97,11 +106,11 @@ def my_evalf(expr, chop=False):
except: except:
return expr return expr
#-----------------------------------------------------------------------------
# my version of sympify to import expression into sympy
def my_sympify(expr, normphase=False, matrix=False, abcsym=False, do_qubit=False, symtab=None): def my_sympify(expr, normphase=False, matrix=False, abcsym=False, do_qubit=False, symtab=None):
"""
Version of sympify to import expression into sympy
"""
# make all lowercase real? # make all lowercase real?
if symtab: if symtab:
varset = symtab varset = symtab
...@@ -113,16 +122,13 @@ def my_sympify(expr, normphase=False, matrix=False, abcsym=False, do_qubit=False ...@@ -113,16 +122,13 @@ def my_sympify(expr, normphase=False, matrix=False, abcsym=False, do_qubit=False
'Q': sympy.Symbol('Q'), # otherwise it is a sympy "ask key" 'Q': sympy.Symbol('Q'), # otherwise it is a sympy "ask key"
'I': sympy.Symbol('I'), # otherwise it is sqrt(-1) 'I': sympy.Symbol('I'), # otherwise it is sqrt(-1)
'N': sympy.Symbol('N'), # or it is some kind of sympy function 'N': sympy.Symbol('N'), # or it is some kind of sympy function
#'X':sympy.sympify('Matrix([[0,1],[1,0]])'),
#'Y':sympy.sympify('Matrix([[0,-I],[I,0]])'),
#'Z':sympy.sympify('Matrix([[1,0],[0,-1]])'),
'ZZ': sympy.Symbol('ZZ'), # otherwise it is the PythonIntegerRing 'ZZ': sympy.Symbol('ZZ'), # otherwise it is the PythonIntegerRing
'XI': sympy.Symbol('XI'), # otherwise it is the capital \XI 'XI': sympy.Symbol('XI'), # otherwise it is the capital \XI
'hat': sympy.Function('hat'), # for unit vectors (8.02) 'hat': sympy.Function('hat'), # for unit vectors (8.02)
} }
if do_qubit: # turn qubit(...) into Qubit instance if do_qubit: # turn qubit(...) into Qubit instance
varset.update({'qubit': sympy.physics.quantum.qubit.Qubit, varset.update({'qubit': Qubit,
'Ket': sympy.physics.quantum.state.Ket, 'Ket': Ket,
'dot': dot, 'dot': dot,
'bit': sympy.Function('bit'), 'bit': sympy.Function('bit'),
}) })
...@@ -139,17 +145,21 @@ def my_sympify(expr, normphase=False, matrix=False, abcsym=False, do_qubit=False ...@@ -139,17 +145,21 @@ def my_sympify(expr, normphase=False, matrix=False, abcsym=False, do_qubit=False
ophase = sympy.sympify('exp(-I*arg(%s))' % sexpr[0]) ophase = sympy.sympify('exp(-I*arg(%s))' % sexpr[0])
sexpr = [sympy.Mul(x, ophase) for x in sexpr] sexpr = [sympy.Mul(x, ophase) for x in sexpr]
def to_matrix(x): # if x is a list of lists, and is rectangular, then return Matrix(x) def to_matrix(expr):
if not type(x) == list: """
return x Convert a list, or list of lists to a matrix.
for row in x: """
# if expr is a list of lists, and is rectangular, then return Matrix(expr)
if not type(expr) == list:
return expr
for row in expr:
if (not type(row) == list): if (not type(row) == list):
return x return expr
rdim = len(x[0]) rdim = len(expr[0])
for row in x: for row in expr:
if not len(row) == rdim: if not len(row) == rdim:
return x return expr
return sympy.Matrix(x) return sympy.Matrix(expr)
if matrix: if matrix:
sexpr = to_matrix(sexpr) sexpr = to_matrix(sexpr)
...@@ -160,11 +170,11 @@ def my_sympify(expr, normphase=False, matrix=False, abcsym=False, do_qubit=False ...@@ -160,11 +170,11 @@ def my_sympify(expr, normphase=False, matrix=False, abcsym=False, do_qubit=False
class formula(object): class formula(object):
''' """
Representation of a mathematical formula object. Accepts mathml math expression Representation of a mathematical formula object. Accepts mathml math expression
for constructing, and can produce sympy translation. The formula may or may not for constructing, and can produce sympy translation. The formula may or may not
include an assignment (=). include an assignment (=).
''' """
def __init__(self, expr, asciimath='', options=None): def __init__(self, expr, asciimath='', options=None):
self.expr = expr.strip() self.expr = expr.strip()
self.asciimath = asciimath self.asciimath = asciimath
...@@ -173,14 +183,23 @@ class formula(object): ...@@ -173,14 +183,23 @@ class formula(object):
self.options = options self.options = options
def is_presentation_mathml(self): def is_presentation_mathml(self):
"""
Check if formula is in mathml presentation format.
"""
return '<mstyle' in self.expr return '<mstyle' in self.expr
def is_mathml(self): def is_mathml(self):
"""
Check if formula is in mathml format.
"""
return '<math ' in self.expr return '<math ' in self.expr
def fix_greek_in_mathml(self, xml): def fix_greek_in_mathml(self, xml):
def gettag(x): """
return re.sub('{http://[^}]+}', '', x.tag) Recursively fix greek letters in passed in xml.
"""
def gettag(expr):
return re.sub('{http://[^}]+}', '', expr.tag)
for k in xml: for k in xml:
tag = gettag(k) tag = gettag(k)
...@@ -188,40 +207,43 @@ class formula(object): ...@@ -188,40 +207,43 @@ class formula(object):
usym = unicode(k.text) usym = unicode(k.text)
try: try:
udata = unicodedata.name(usym) udata = unicodedata.name(usym)
except Exception, err: except Exception:
udata = None udata = None
#print "usym = %s, udata=%s" % (usym,udata) # print "usym = %s, udata=%s" % (usym,udata)
if udata: # eg "GREEK SMALL LETTER BETA" if udata: # eg "GREEK SMALL LETTER BETA"
if 'GREEK' in udata: if 'GREEK' in udata:
usym = udata.split(' ')[-1] usym = udata.split(' ')[-1]
if 'SMALL' in udata: usym = usym.lower() if 'SMALL' in udata:
usym = usym.lower()
#print "greek: ",usym #print "greek: ",usym
k.text = usym k.text = usym
self.fix_greek_in_mathml(k) self.fix_greek_in_mathml(k)
return xml return xml
def preprocess_pmathml(self, xml): def preprocess_pmathml(self, xml):
r''' r"""
Pre-process presentation MathML from ASCIIMathML to make it more Pre-process presentation MathML from ASCIIMathML to make it more
acceptable for SnuggleTeX, and also to accomodate some sympy acceptable for SnuggleTeX, and also to accomodate some sympy
conventions (eg hat(i) for \hat{i}). conventions (eg hat(i) for \hat{i}).
This method would be a good spot to look for an integral and convert This method would be a good spot to look for an integral and convert
it, if possible... it, if possible...
''' """
if type(xml) == str or type(xml) == unicode: if type(xml) == str or type(xml) == unicode:
xml = etree.fromstring(xml) # TODO: wrap in try xml = etree.fromstring(xml) # TODO: wrap in try
xml = self.fix_greek_in_mathml(xml) # convert greek utf letters to greek spelled out in ascii xml = self.fix_greek_in_mathml(xml) # convert greek utf letters to greek spelled out in ascii
def gettag(x): def gettag(expr):
return re.sub('{http://[^}]+}', '', x.tag) return re.sub('{http://[^}]+}', '', expr.tag)
# f and g are processed as functions by asciimathml, eg "f-2" turns into "<mrow><mi>f</mi><mo>-</mo></mrow><mn>2</mn>"
# this is really terrible for turning into cmathml.
# undo this here.
def fix_pmathml(xml): def fix_pmathml(xml):
"""
f and g are processed as functions by asciimathml, eg "f-2" turns
into "<mrow><mi>f</mi><mo>-</mo></mrow><mn>2</mn>" this is
really terrible for turning into cmathml. undo this here.
"""
for k in xml: for k in xml:
tag = gettag(k) tag = gettag(k)
if tag == 'mrow': if tag == 'mrow':
...@@ -235,10 +257,13 @@ class formula(object): ...@@ -235,10 +257,13 @@ class formula(object):
fix_pmathml(xml) fix_pmathml(xml)
# hat i is turned into <mover><mi>i</mi><mo>^</mo></mover> ; mangle this into <mi>hat(f)</mi>
# hat i also somtimes turned into <mover><mrow> <mi>j</mi> </mrow><mo>^</mo></mover>
def fix_hat(xml): def fix_hat(xml):
"""
hat i is turned into <mover><mi>i</mi><mo>^</mo></mover> ; mangle
this into <mi>hat(f)</mi> hat i also somtimes turned into
<mover><mrow> <mi>j</mi> </mrow><mo>^</mo></mover>
"""
for k in xml: for k in xml:
tag = gettag(k) tag = gettag(k)
if tag == 'mover': if tag == 'mover':
...@@ -255,7 +280,8 @@ class formula(object): ...@@ -255,7 +280,8 @@ class formula(object):
fix_hat(xml) fix_hat(xml)
def flatten_pmathml(xml): def flatten_pmathml(xml):
''' Give the text version of certain PMathML elements """
Give the text version of certain PMathML elements
Sometimes MathML will be given with each letter separated (it Sometimes MathML will be given with each letter separated (it
doesn't know if its implicit multiplication or what). From an xml doesn't know if its implicit multiplication or what). From an xml
...@@ -266,19 +292,23 @@ class formula(object): ...@@ -266,19 +292,23 @@ class formula(object):
<mi>x</mi> <mi>x</mi>
</mrow> </mrow>
and returns 'max', for easier use later on. and returns 'max', for easier use later on.
''' """
tag = gettag(xml) tag = gettag(xml)
if tag == 'mn': return xml.text if tag == 'mn':
elif tag == 'mi': return xml.text return xml.text
elif tag == 'mrow': return ''.join([flatten_pmathml(y) for y in xml]) elif tag == 'mi':
raise Exception, '[flatten_pmathml] unknown tag %s' % tag return xml.text
elif tag == 'mrow':
return ''.join([flatten_pmathml(y) for y in xml])
raise Exception('[flatten_pmathml] unknown tag %s' % tag)
def fix_mathvariant(parent): def fix_mathvariant(parent):
'''Fix certain kinds of math variants """
Fix certain kinds of math variants
Literally replace <mstyle mathvariant="script"><mi>N</mi></mstyle> Literally replace <mstyle mathvariant="script"><mi>N</mi></mstyle>
with 'scriptN'. There have been problems using script_N or script(N) with 'scriptN'. There have been problems using script_N or script(N)
''' """
for child in parent: for child in parent:
if (gettag(child) == 'mstyle' and child.get('mathvariant') == 'script'): if (gettag(child) == 'mstyle' and child.get('mathvariant') == 'script'):
newchild = etree.Element('mi') newchild = etree.Element('mi')
...@@ -287,12 +317,11 @@ class formula(object): ...@@ -287,12 +317,11 @@ class formula(object):
fix_mathvariant(child) fix_mathvariant(child)
fix_mathvariant(xml) fix_mathvariant(xml)
# find "tagged" superscripts # find "tagged" superscripts
# they have the character \u200b in the superscript # they have the character \u200b in the superscript
# replace them with a__b so snuggle doesn't get confused # replace them with a__b so snuggle doesn't get confused
def fix_superscripts(xml): def fix_superscripts(xml):
''' Look for and replace sup elements with 'X__Y' or 'X_Y__Z' """ Look for and replace sup elements with 'X__Y' or 'X_Y__Z'
In the javascript, variables with '__X' in them had an invisible In the javascript, variables with '__X' in them had an invisible
character inserted into the sup (to distinguish from powers) character inserted into the sup (to distinguish from powers)
...@@ -324,16 +353,18 @@ class formula(object): ...@@ -324,16 +353,18 @@ class formula(object):
</mrow> </mrow>
</msup> </msup>
to be 'x__B' to be 'x__B'
''' """
for k in xml: for k in xml:
tag = gettag(k) tag = gettag(k)
# match things like the last example-- # match things like the last example--
# the second item in msub is an mrow with the first # the second item in msub is an mrow with the first
# character equal to \u200b # character equal to \u200b
if (tag == 'msup' and if (
tag == 'msup' and
len(k) == 2 and gettag(k[1]) == 'mrow' and len(k) == 2 and gettag(k[1]) == 'mrow' and
gettag(k[1][0]) == 'mo' and k[1][0].text == u'\u200b'): # whew gettag(k[1][0]) == 'mo' and k[1][0].text == u'\u200b' # whew
):
# replace the msup with 'X__Y' # replace the msup with 'X__Y'
k[1].remove(k[1][0]) k[1].remove(k[1][0])
...@@ -344,9 +375,11 @@ class formula(object): ...@@ -344,9 +375,11 @@ class formula(object):
# match things like the middle example- # match things like the middle example-
# the third item in msubsup is an mrow with the first # the third item in msubsup is an mrow with the first
# character equal to \u200b # character equal to \u200b
if (tag == 'msubsup' and if (
tag == 'msubsup' and
len(k) == 3 and gettag(k[2]) == 'mrow' and len(k) == 3 and gettag(k[2]) == 'mrow' and
gettag(k[2][0]) == 'mo' and k[2][0].text == u'\u200b'): # whew gettag(k[2][0]) == 'mo' and k[2][0].text == u'\u200b' # whew
):
# replace the msubsup with 'X_Y__Z' # replace the msubsup with 'X_Y__Z'
k[2].remove(k[2][0]) k[2].remove(k[2][0])
...@@ -357,10 +390,12 @@ class formula(object): ...@@ -357,10 +390,12 @@ class formula(object):
fix_superscripts(k) fix_superscripts(k)
fix_superscripts(xml) fix_superscripts(xml)
# Snuggle returns an error when it sees an <msubsup>
# replace such elements with an <msup>, except the first element is of
# the form a_b. I.e. map a_b^c => (a_b)^c
def fix_msubsup(parent): def fix_msubsup(parent):
"""
Snuggle returns an error when it sees an <msubsup> replace such
elements with an <msup>, except the first element is of
the form a_b. I.e. map a_b^c => (a_b)^c
"""
for child in parent: for child in parent:
# fix msubsup # fix msubsup
if (gettag(child) == 'msubsup' and len(child) == 3): if (gettag(child) == 'msubsup' and len(child) == 3):
...@@ -375,20 +410,21 @@ class formula(object): ...@@ -375,20 +410,21 @@ class formula(object):
fix_msubsup(child) fix_msubsup(child)
fix_msubsup(xml) fix_msubsup(xml)
self.xml = xml self.xml = xml # pylint: disable=attribute-defined-outside-init
return self.xml return self.xml
def get_content_mathml(self): def get_content_mathml(self):
if self.the_cmathml: return self.the_cmathml if self.the_cmathml:
return self.the_cmathml
# pre-process the presentation mathml before sending it to snuggletex to convert to content mathml # pre-process the presentation mathml before sending it to snuggletex to convert to content mathml
try: try:
xml = self.preprocess_pmathml(self.expr) xml = self.preprocess_pmathml(self.expr)
except Exception, err: except Exception, err:
log.warning('Err %s while preprocessing; expr=%s' % (err, self.expr)) log.warning('Err %s while preprocessing; expr=%s', err, self.expr)
return "<html>Error! Cannot process pmathml</html>" return "<html>Error! Cannot process pmathml</html>"
pmathml = etree.tostring(xml, pretty_print=True) pmathml = etree.tostring(xml, pretty_print=True)
self.the_pmathml = pmathml self.the_pmathml = pmathml # pylint: disable=attribute-defined-outside-init
# convert to cmathml # convert to cmathml
self.the_cmathml = self.GetContentMathML(self.asciimath, pmathml) self.the_cmathml = self.GetContentMathML(self.asciimath, pmathml)
...@@ -397,15 +433,16 @@ class formula(object): ...@@ -397,15 +433,16 @@ class formula(object):
cmathml = property(get_content_mathml, None, None, 'content MathML representation') cmathml = property(get_content_mathml, None, None, 'content MathML representation')
def make_sympy(self, xml=None): def make_sympy(self, xml=None):
''' """
Return sympy expression for the math formula. Return sympy expression for the math formula.
The math formula is converted to Content MathML then that is parsed. The math formula is converted to Content MathML then that is parsed.
This is a recursive function, called on every CMML node. Support for This is a recursive function, called on every CMML node. Support for
more functions can be added by modifying opdict, abould halfway down more functions can be added by modifying opdict, abould halfway down
''' """
if self.the_sympy: return self.the_sympy if self.the_sympy:
return self.the_sympy
if xml is None: # root if xml is None: # root
if not self.is_mathml(): if not self.is_mathml():
...@@ -420,7 +457,7 @@ class formula(object): ...@@ -420,7 +457,7 @@ class formula(object):
msg = "Illegal math expression" msg = "Illegal math expression"
else: else:
msg = 'Err %s while converting cmathml to xml; cmml=%s' % (err, cmml) msg = 'Err %s while converting cmathml to xml; cmml=%s' % (err, cmml)
raise Exception, msg raise Exception(msg)
xml = self.fix_greek_in_mathml(xml) xml = self.fix_greek_in_mathml(xml)
self.the_sympy = self.make_sympy(xml[0]) self.the_sympy = self.make_sympy(xml[0])
else: else:
...@@ -429,36 +466,35 @@ class formula(object): ...@@ -429,36 +466,35 @@ class formula(object):
self.the_sympy = self.make_sympy(xml[0]) self.the_sympy = self.make_sympy(xml[0])
return self.the_sympy return self.the_sympy
def gettag(x): def gettag(expr):
return re.sub('{http://[^}]+}', '', x.tag) return re.sub('{http://[^}]+}', '', expr.tag)
# simple math # simple math
def op_divide(*args): def op_divide(*args):
if not len(args) == 2: if not len(args) == 2:
raise Exception, 'divide given wrong number of arguments!' raise Exception('divide given wrong number of arguments!')
# print "divide: arg0=%s, arg1=%s" % (args[0],args[1]) # print "divide: arg0=%s, arg1=%s" % (args[0],args[1])
return sympy.Mul(args[0], sympy.Pow(args[1], -1)) return sympy.Mul(args[0], sympy.Pow(args[1], -1))
def op_plus(*args): return args[0] if len(args) == 1 else op_plus(*args[:-1]) + args[-1] def op_plus(*args):
return args[0] if len(args) == 1 else op_plus(*args[:-1]) + args[-1]
def op_times(*args): return reduce(operator.mul, args) def op_times(*args):
return reduce(operator.mul, args)
def op_minus(*args): def op_minus(*args):
if len(args) == 1: if len(args) == 1:
return -args[0] return -args[0]
if not len(args) == 2: if not len(args) == 2:
raise Exception, 'minus given wrong number of arguments!' raise Exception('minus given wrong number of arguments!')
#return sympy.Add(args[0],-args[1]) #return sympy.Add(args[0],-args[1])
return args[0] - args[1] return args[0] - args[1]
opdict = {'plus': op_plus, opdict = {
'divide': operator.div, 'plus': op_plus,
'divide': operator.div, # should this be op_divide?
'times': op_times, 'times': op_times,
'minus': op_minus, 'minus': op_minus,
#'plus': sympy.Add,
#'divide' : op_divide,
#'times' : sympy.Mul,
'minus': op_minus,
'root': sympy.sqrt, 'root': sympy.sqrt,
'power': sympy.Pow, 'power': sympy.Pow,
'sin': sympy.sin, 'sin': sympy.sin,
...@@ -483,59 +519,63 @@ class formula(object): ...@@ -483,59 +519,63 @@ class formula(object):
'ln': sympy.ln, 'ln': sympy.ln,
} }
# simple sumbols # simple symbols - TODO is this code used?
nums1dict = {'pi': sympy.pi, nums1dict = {
'pi': sympy.pi,
} }
def parsePresentationMathMLSymbol(xml): def parsePresentationMathMLSymbol(xml):
''' """
Parse <msub>, <msup>, <mi>, and <mn> Parse <msub>, <msup>, <mi>, and <mn>
''' """
tag = gettag(xml) tag = gettag(xml)
if tag == 'mn': return xml.text if tag == 'mn':
elif tag == 'mi': return xml.text return xml.text
elif tag == 'msub': return '_'.join([parsePresentationMathMLSymbol(y) for y in xml]) elif tag == 'mi':
elif tag == 'msup': return '^'.join([parsePresentationMathMLSymbol(y) for y in xml]) return xml.text
raise Exception, '[parsePresentationMathMLSymbol] unknown tag %s' % tag elif tag == 'msub':
return '_'.join([parsePresentationMathMLSymbol(y) for y in xml])
elif tag == 'msup':
return '^'.join([parsePresentationMathMLSymbol(y) for y in xml])
raise Exception('[parsePresentationMathMLSymbol] unknown tag %s' % tag)
# parser tree for Content MathML # parser tree for Content MathML
tag = gettag(xml) tag = gettag(xml)
# print "tag = ",tag
# first do compound objects # first do compound objects
if tag == 'apply': # apply operator if tag == 'apply': # apply operator
opstr = gettag(xml[0]) opstr = gettag(xml[0])
if opstr in opdict: if opstr in opdict:
op = opdict[opstr] op = opdict[opstr] # pylint: disable=invalid-name
args = [self.make_sympy(x) for x in xml[1:]] args = [self.make_sympy(expr) for expr in xml[1:]]
try: try:
res = op(*args) res = op(*args)
except Exception, err: except Exception, err:
self.args = args self.args = args # pylint: disable=attribute-defined-outside-init
self.op = op self.op = op # pylint: disable=attribute-defined-outside-init, invalid-name
raise Exception, '[formula] error=%s failed to apply %s to args=%s' % (err, opstr, args) raise Exception('[formula] error=%s failed to apply %s to args=%s' % (err, opstr, args))
return res return res
else: else:
raise Exception, '[formula]: unknown operator tag %s' % (opstr) raise Exception('[formula]: unknown operator tag %s' % (opstr))
elif tag == 'list': # square bracket list elif tag == 'list': # square bracket list
if gettag(xml[0]) == 'matrix': if gettag(xml[0]) == 'matrix':
return self.make_sympy(xml[0]) return self.make_sympy(xml[0])
else: else:
return [self.make_sympy(x) for x in xml] return [self.make_sympy(expr) for expr in xml]
elif tag == 'matrix': elif tag == 'matrix':
return sympy.Matrix([self.make_sympy(x) for x in xml]) return sympy.Matrix([self.make_sympy(expr) for expr in xml])
elif tag == 'vector': elif tag == 'vector':
return [self.make_sympy(x) for x in xml] return [self.make_sympy(expr) for expr in xml]
# atoms are below # atoms are below
elif tag == 'cn': # number elif tag == 'cn': # number
return sympy.sympify(xml.text) return sympy.sympify(xml.text)
return float(xml.text) # return float(xml.text)
elif tag == 'ci': # variable (symbol) elif tag == 'ci': # variable (symbol)
if len(xml) > 0 and (gettag(xml[0]) == 'msub' or gettag(xml[0]) == 'msup'): # subscript or superscript if len(xml) > 0 and (gettag(xml[0]) == 'msub' or gettag(xml[0]) == 'msup'): # subscript or superscript
...@@ -553,27 +593,29 @@ class formula(object): ...@@ -553,27 +593,29 @@ class formula(object):
return sym return sym
else: # unknown tag else: # unknown tag
raise Exception, '[formula] unknown tag %s' % tag raise Exception('[formula] unknown tag %s' % tag)
sympy = property(make_sympy, None, None, 'sympy representation') sympy = property(make_sympy, None, None, 'sympy representation')
def GetContentMathML(self, asciimath, mathml): def GetContentMathML(self, asciimath, mathml):
# URL = 'http://192.168.1.2:8080/snuggletex-webapp-1.2.2/ASCIIMathMLUpConversionDemo' """
# URL = 'http://127.0.0.1:8080/snuggletex-webapp-1.2.2/ASCIIMathMLUpConversionDemo' Handle requests to snuggletex API to convert the Ascii math to MathML
URL = 'https://math-xserver.mitx.mit.edu/snuggletex-webapp-1.2.2/ASCIIMathMLUpConversionDemo' """
# url = 'http://192.168.1.2:8080/snuggletex-webapp-1.2.2/ASCIIMathMLUpConversionDemo'
# url = 'http://127.0.0.1:8080/snuggletex-webapp-1.2.2/ASCIIMathMLUpConversionDemo'
url = 'https://math-xserver.mitx.mit.edu/snuggletex-webapp-1.2.2/ASCIIMathMLUpConversionDemo'
if 1: if 1:
payload = {'asciiMathInput': asciimath, payload = {
'asciiMathInput': asciimath,
'asciiMathML': mathml, 'asciiMathML': mathml,
#'asciiMathML':unicode(mathml).encode('utf-8'), #'asciiMathML':unicode(mathml).encode('utf-8'),
} }
headers = {'User-Agent': "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13"} headers = {'User-Agent': "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13"}
r = requests.post(URL, data=payload, headers=headers, verify=False) request = requests.post(url, data=payload, headers=headers, verify=False)
r.encoding = 'utf-8' request.encoding = 'utf-8'
ret = r.text ret = request.text
#print "encoding: ",r.encoding # print "encoding: ", request.encoding
# return ret
mode = 0 mode = 0
cmathml = [] cmathml = []
...@@ -586,18 +628,17 @@ class formula(object): ...@@ -586,18 +628,17 @@ class formula(object):
mode = 0 mode = 0
continue continue
cmathml.append(k) cmathml.append(k)
# return '\n'.join(cmathml)
cmathml = '\n'.join(cmathml[2:]) cmathml = '\n'.join(cmathml[2:])
cmathml = '<math xmlns="http://www.w3.org/1998/Math/MathML">\n' + unescape(cmathml) + '\n</math>' cmathml = '<math xmlns="http://www.w3.org/1998/Math/MathML">\n' + unescape(cmathml) + '\n</math>'
# print cmathml # print cmathml
#return unicode(cmathml)
return cmathml return cmathml
#----------------------------------------------------------------------------- #-----------------------------------------------------------------------------
def test1(): def test1():
xmlstr = ''' """Test XML strings - addition"""
xmlstr = """
<math xmlns="http://www.w3.org/1998/Math/MathML"> <math xmlns="http://www.w3.org/1998/Math/MathML">
<apply> <apply>
<plus/> <plus/>
...@@ -605,12 +646,13 @@ def test1(): ...@@ -605,12 +646,13 @@ def test1():
<cn>2</cn> <cn>2</cn>
</apply> </apply>
</math> </math>
''' """
return formula(xmlstr) return formula(xmlstr)
def test2(): def test2():
xmlstr = u''' """Test XML strings - addition, Greek alpha"""
xmlstr = u"""
<math xmlns="http://www.w3.org/1998/Math/MathML"> <math xmlns="http://www.w3.org/1998/Math/MathML">
<apply> <apply>
<plus/> <plus/>
...@@ -622,12 +664,13 @@ def test2(): ...@@ -622,12 +664,13 @@ def test2():
</apply> </apply>
</apply> </apply>
</math> </math>
''' """
return formula(xmlstr) return formula(xmlstr)
def test3(): def test3():
xmlstr = ''' """Test XML strings - addition, Greek gamma"""
xmlstr = """
<math xmlns="http://www.w3.org/1998/Math/MathML"> <math xmlns="http://www.w3.org/1998/Math/MathML">
<apply> <apply>
<divide/> <divide/>
...@@ -639,12 +682,13 @@ def test3(): ...@@ -639,12 +682,13 @@ def test3():
</apply> </apply>
</apply> </apply>
</math> </math>
''' """
return formula(xmlstr) return formula(xmlstr)
def test4(): def test4():
xmlstr = u''' """Test XML strings - addition, Greek alpha, mfrac"""
xmlstr = u"""
<math xmlns="http://www.w3.org/1998/Math/MathML"> <math xmlns="http://www.w3.org/1998/Math/MathML">
<mstyle displaystyle="true"> <mstyle displaystyle="true">
<mn>1</mn> <mn>1</mn>
...@@ -655,12 +699,13 @@ def test4(): ...@@ -655,12 +699,13 @@ def test4():
</mfrac> </mfrac>
</mstyle> </mstyle>
</math> </math>
''' """
return formula(xmlstr) return formula(xmlstr)
def test5(): # sum of two matrices def test5():
xmlstr = u''' """Test XML strings - sum of two matrices"""
xmlstr = u"""
<math xmlns="http://www.w3.org/1998/Math/MathML"> <math xmlns="http://www.w3.org/1998/Math/MathML">
<mstyle displaystyle="true"> <mstyle displaystyle="true">
<mrow> <mrow>
...@@ -719,12 +764,13 @@ def test5(): # sum of two matrices ...@@ -719,12 +764,13 @@ def test5(): # sum of two matrices
</mrow> </mrow>
</mstyle> </mstyle>
</math> </math>
''' """
return formula(xmlstr) return formula(xmlstr)
def test6(): # imaginary numbers def test6():
xmlstr = u''' """Test XML strings - imaginary numbers"""
xmlstr = u"""
<math xmlns="http://www.w3.org/1998/Math/MathML"> <math xmlns="http://www.w3.org/1998/Math/MathML">
<mstyle displaystyle="true"> <mstyle displaystyle="true">
<mn>1</mn> <mn>1</mn>
...@@ -732,5 +778,5 @@ def test6(): # imaginary numbers ...@@ -732,5 +778,5 @@ def test6(): # imaginary numbers
<mi>i</mi> <mi>i</mi>
</mstyle> </mstyle>
</math> </math>
''' """
return formula(xmlstr, options='imaginary') return formula(xmlstr, options='imaginary')
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment