You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2127 lines
74 KiB
2127 lines
74 KiB
5 months ago
|
"""
|
||
|
A MathML printer.
|
||
|
"""
|
||
|
|
||
|
from __future__ import annotations
|
||
|
from typing import Any
|
||
|
|
||
|
from sympy.core.mul import Mul
|
||
|
from sympy.core.singleton import S
|
||
|
from sympy.core.sorting import default_sort_key
|
||
|
from sympy.core.sympify import sympify
|
||
|
from sympy.printing.conventions import split_super_sub, requires_partial
|
||
|
from sympy.printing.precedence import \
|
||
|
precedence_traditional, PRECEDENCE, PRECEDENCE_TRADITIONAL
|
||
|
from sympy.printing.pretty.pretty_symbology import greek_unicode
|
||
|
from sympy.printing.printer import Printer, print_function
|
||
|
|
||
|
from mpmath.libmp import prec_to_dps, repr_dps, to_str as mlib_to_str
|
||
|
|
||
|
|
||
|
class MathMLPrinterBase(Printer):
|
||
|
"""Contains common code required for MathMLContentPrinter and
|
||
|
MathMLPresentationPrinter.
|
||
|
"""
|
||
|
|
||
|
_default_settings: dict[str, Any] = {
|
||
|
"order": None,
|
||
|
"encoding": "utf-8",
|
||
|
"fold_frac_powers": False,
|
||
|
"fold_func_brackets": False,
|
||
|
"fold_short_frac": None,
|
||
|
"inv_trig_style": "abbreviated",
|
||
|
"ln_notation": False,
|
||
|
"long_frac_ratio": None,
|
||
|
"mat_delim": "[",
|
||
|
"mat_symbol_style": "plain",
|
||
|
"mul_symbol": None,
|
||
|
"root_notation": True,
|
||
|
"symbol_names": {},
|
||
|
"mul_symbol_mathml_numbers": '·',
|
||
|
}
|
||
|
|
||
|
def __init__(self, settings=None):
|
||
|
Printer.__init__(self, settings)
|
||
|
from xml.dom.minidom import Document, Text
|
||
|
|
||
|
self.dom = Document()
|
||
|
|
||
|
# Workaround to allow strings to remain unescaped
|
||
|
# Based on
|
||
|
# https://stackoverflow.com/questions/38015864/python-xml-dom-minidom-\
|
||
|
# please-dont-escape-my-strings/38041194
|
||
|
class RawText(Text):
|
||
|
def writexml(self, writer, indent='', addindent='', newl=''):
|
||
|
if self.data:
|
||
|
writer.write('{}{}{}'.format(indent, self.data, newl))
|
||
|
|
||
|
def createRawTextNode(data):
|
||
|
r = RawText()
|
||
|
r.data = data
|
||
|
r.ownerDocument = self.dom
|
||
|
return r
|
||
|
|
||
|
self.dom.createTextNode = createRawTextNode
|
||
|
|
||
|
def doprint(self, expr):
|
||
|
"""
|
||
|
Prints the expression as MathML.
|
||
|
"""
|
||
|
mathML = Printer._print(self, expr)
|
||
|
unistr = mathML.toxml()
|
||
|
xmlbstr = unistr.encode('ascii', 'xmlcharrefreplace')
|
||
|
res = xmlbstr.decode()
|
||
|
return res
|
||
|
|
||
|
def apply_patch(self):
|
||
|
# Applying the patch of xml.dom.minidom bug
|
||
|
# Date: 2011-11-18
|
||
|
# Description: http://ronrothman.com/public/leftbraned/xml-dom-minidom\
|
||
|
# -toprettyxml-and-silly-whitespace/#best-solution
|
||
|
# Issue: https://bugs.python.org/issue4147
|
||
|
# Patch: https://hg.python.org/cpython/rev/7262f8f276ff/
|
||
|
|
||
|
from xml.dom.minidom import Element, Text, Node, _write_data
|
||
|
|
||
|
def writexml(self, writer, indent="", addindent="", newl=""):
|
||
|
# indent = current indentation
|
||
|
# addindent = indentation to add to higher levels
|
||
|
# newl = newline string
|
||
|
writer.write(indent + "<" + self.tagName)
|
||
|
|
||
|
attrs = self._get_attributes()
|
||
|
a_names = list(attrs.keys())
|
||
|
a_names.sort()
|
||
|
|
||
|
for a_name in a_names:
|
||
|
writer.write(" %s=\"" % a_name)
|
||
|
_write_data(writer, attrs[a_name].value)
|
||
|
writer.write("\"")
|
||
|
if self.childNodes:
|
||
|
writer.write(">")
|
||
|
if (len(self.childNodes) == 1 and
|
||
|
self.childNodes[0].nodeType == Node.TEXT_NODE):
|
||
|
self.childNodes[0].writexml(writer, '', '', '')
|
||
|
else:
|
||
|
writer.write(newl)
|
||
|
for node in self.childNodes:
|
||
|
node.writexml(
|
||
|
writer, indent + addindent, addindent, newl)
|
||
|
writer.write(indent)
|
||
|
writer.write("</%s>%s" % (self.tagName, newl))
|
||
|
else:
|
||
|
writer.write("/>%s" % (newl))
|
||
|
self._Element_writexml_old = Element.writexml
|
||
|
Element.writexml = writexml
|
||
|
|
||
|
def writexml(self, writer, indent="", addindent="", newl=""):
|
||
|
_write_data(writer, "%s%s%s" % (indent, self.data, newl))
|
||
|
self._Text_writexml_old = Text.writexml
|
||
|
Text.writexml = writexml
|
||
|
|
||
|
def restore_patch(self):
|
||
|
from xml.dom.minidom import Element, Text
|
||
|
Element.writexml = self._Element_writexml_old
|
||
|
Text.writexml = self._Text_writexml_old
|
||
|
|
||
|
|
||
|
class MathMLContentPrinter(MathMLPrinterBase):
|
||
|
"""Prints an expression to the Content MathML markup language.
|
||
|
|
||
|
References: https://www.w3.org/TR/MathML2/chapter4.html
|
||
|
"""
|
||
|
printmethod = "_mathml_content"
|
||
|
|
||
|
def mathml_tag(self, e):
|
||
|
"""Returns the MathML tag for an expression."""
|
||
|
translate = {
|
||
|
'Add': 'plus',
|
||
|
'Mul': 'times',
|
||
|
'Derivative': 'diff',
|
||
|
'Number': 'cn',
|
||
|
'int': 'cn',
|
||
|
'Pow': 'power',
|
||
|
'Max': 'max',
|
||
|
'Min': 'min',
|
||
|
'Abs': 'abs',
|
||
|
'And': 'and',
|
||
|
'Or': 'or',
|
||
|
'Xor': 'xor',
|
||
|
'Not': 'not',
|
||
|
'Implies': 'implies',
|
||
|
'Symbol': 'ci',
|
||
|
'MatrixSymbol': 'ci',
|
||
|
'RandomSymbol': 'ci',
|
||
|
'Integral': 'int',
|
||
|
'Sum': 'sum',
|
||
|
'sin': 'sin',
|
||
|
'cos': 'cos',
|
||
|
'tan': 'tan',
|
||
|
'cot': 'cot',
|
||
|
'csc': 'csc',
|
||
|
'sec': 'sec',
|
||
|
'sinh': 'sinh',
|
||
|
'cosh': 'cosh',
|
||
|
'tanh': 'tanh',
|
||
|
'coth': 'coth',
|
||
|
'csch': 'csch',
|
||
|
'sech': 'sech',
|
||
|
'asin': 'arcsin',
|
||
|
'asinh': 'arcsinh',
|
||
|
'acos': 'arccos',
|
||
|
'acosh': 'arccosh',
|
||
|
'atan': 'arctan',
|
||
|
'atanh': 'arctanh',
|
||
|
'atan2': 'arctan',
|
||
|
'acot': 'arccot',
|
||
|
'acoth': 'arccoth',
|
||
|
'asec': 'arcsec',
|
||
|
'asech': 'arcsech',
|
||
|
'acsc': 'arccsc',
|
||
|
'acsch': 'arccsch',
|
||
|
'log': 'ln',
|
||
|
'Equality': 'eq',
|
||
|
'Unequality': 'neq',
|
||
|
'GreaterThan': 'geq',
|
||
|
'LessThan': 'leq',
|
||
|
'StrictGreaterThan': 'gt',
|
||
|
'StrictLessThan': 'lt',
|
||
|
'Union': 'union',
|
||
|
'Intersection': 'intersect',
|
||
|
}
|
||
|
|
||
|
for cls in e.__class__.__mro__:
|
||
|
n = cls.__name__
|
||
|
if n in translate:
|
||
|
return translate[n]
|
||
|
# Not found in the MRO set
|
||
|
n = e.__class__.__name__
|
||
|
return n.lower()
|
||
|
|
||
|
def _print_Mul(self, expr):
|
||
|
|
||
|
if expr.could_extract_minus_sign():
|
||
|
x = self.dom.createElement('apply')
|
||
|
x.appendChild(self.dom.createElement('minus'))
|
||
|
x.appendChild(self._print_Mul(-expr))
|
||
|
return x
|
||
|
|
||
|
from sympy.simplify import fraction
|
||
|
numer, denom = fraction(expr)
|
||
|
|
||
|
if denom is not S.One:
|
||
|
x = self.dom.createElement('apply')
|
||
|
x.appendChild(self.dom.createElement('divide'))
|
||
|
x.appendChild(self._print(numer))
|
||
|
x.appendChild(self._print(denom))
|
||
|
return x
|
||
|
|
||
|
coeff, terms = expr.as_coeff_mul()
|
||
|
if coeff is S.One and len(terms) == 1:
|
||
|
# XXX since the negative coefficient has been handled, I don't
|
||
|
# think a coeff of 1 can remain
|
||
|
return self._print(terms[0])
|
||
|
|
||
|
if self.order != 'old':
|
||
|
terms = Mul._from_args(terms).as_ordered_factors()
|
||
|
|
||
|
x = self.dom.createElement('apply')
|
||
|
x.appendChild(self.dom.createElement('times'))
|
||
|
if coeff != 1:
|
||
|
x.appendChild(self._print(coeff))
|
||
|
for term in terms:
|
||
|
x.appendChild(self._print(term))
|
||
|
return x
|
||
|
|
||
|
def _print_Add(self, expr, order=None):
|
||
|
args = self._as_ordered_terms(expr, order=order)
|
||
|
lastProcessed = self._print(args[0])
|
||
|
plusNodes = []
|
||
|
for arg in args[1:]:
|
||
|
if arg.could_extract_minus_sign():
|
||
|
# use minus
|
||
|
x = self.dom.createElement('apply')
|
||
|
x.appendChild(self.dom.createElement('minus'))
|
||
|
x.appendChild(lastProcessed)
|
||
|
x.appendChild(self._print(-arg))
|
||
|
# invert expression since this is now minused
|
||
|
lastProcessed = x
|
||
|
if arg == args[-1]:
|
||
|
plusNodes.append(lastProcessed)
|
||
|
else:
|
||
|
plusNodes.append(lastProcessed)
|
||
|
lastProcessed = self._print(arg)
|
||
|
if arg == args[-1]:
|
||
|
plusNodes.append(self._print(arg))
|
||
|
if len(plusNodes) == 1:
|
||
|
return lastProcessed
|
||
|
x = self.dom.createElement('apply')
|
||
|
x.appendChild(self.dom.createElement('plus'))
|
||
|
while plusNodes:
|
||
|
x.appendChild(plusNodes.pop(0))
|
||
|
return x
|
||
|
|
||
|
def _print_Piecewise(self, expr):
|
||
|
if expr.args[-1].cond != True:
|
||
|
# We need the last conditional to be a True, otherwise the resulting
|
||
|
# function may not return a result.
|
||
|
raise ValueError("All Piecewise expressions must contain an "
|
||
|
"(expr, True) statement to be used as a default "
|
||
|
"condition. Without one, the generated "
|
||
|
"expression may not evaluate to anything under "
|
||
|
"some condition.")
|
||
|
root = self.dom.createElement('piecewise')
|
||
|
for i, (e, c) in enumerate(expr.args):
|
||
|
if i == len(expr.args) - 1 and c == True:
|
||
|
piece = self.dom.createElement('otherwise')
|
||
|
piece.appendChild(self._print(e))
|
||
|
else:
|
||
|
piece = self.dom.createElement('piece')
|
||
|
piece.appendChild(self._print(e))
|
||
|
piece.appendChild(self._print(c))
|
||
|
root.appendChild(piece)
|
||
|
return root
|
||
|
|
||
|
def _print_MatrixBase(self, m):
|
||
|
x = self.dom.createElement('matrix')
|
||
|
for i in range(m.rows):
|
||
|
x_r = self.dom.createElement('matrixrow')
|
||
|
for j in range(m.cols):
|
||
|
x_r.appendChild(self._print(m[i, j]))
|
||
|
x.appendChild(x_r)
|
||
|
return x
|
||
|
|
||
|
def _print_Rational(self, e):
|
||
|
if e.q == 1:
|
||
|
# don't divide
|
||
|
x = self.dom.createElement('cn')
|
||
|
x.appendChild(self.dom.createTextNode(str(e.p)))
|
||
|
return x
|
||
|
x = self.dom.createElement('apply')
|
||
|
x.appendChild(self.dom.createElement('divide'))
|
||
|
# numerator
|
||
|
xnum = self.dom.createElement('cn')
|
||
|
xnum.appendChild(self.dom.createTextNode(str(e.p)))
|
||
|
# denominator
|
||
|
xdenom = self.dom.createElement('cn')
|
||
|
xdenom.appendChild(self.dom.createTextNode(str(e.q)))
|
||
|
x.appendChild(xnum)
|
||
|
x.appendChild(xdenom)
|
||
|
return x
|
||
|
|
||
|
def _print_Limit(self, e):
|
||
|
x = self.dom.createElement('apply')
|
||
|
x.appendChild(self.dom.createElement(self.mathml_tag(e)))
|
||
|
|
||
|
x_1 = self.dom.createElement('bvar')
|
||
|
x_2 = self.dom.createElement('lowlimit')
|
||
|
x_1.appendChild(self._print(e.args[1]))
|
||
|
x_2.appendChild(self._print(e.args[2]))
|
||
|
|
||
|
x.appendChild(x_1)
|
||
|
x.appendChild(x_2)
|
||
|
x.appendChild(self._print(e.args[0]))
|
||
|
return x
|
||
|
|
||
|
def _print_ImaginaryUnit(self, e):
|
||
|
return self.dom.createElement('imaginaryi')
|
||
|
|
||
|
def _print_EulerGamma(self, e):
|
||
|
return self.dom.createElement('eulergamma')
|
||
|
|
||
|
def _print_GoldenRatio(self, e):
|
||
|
"""We use unicode #x3c6 for Greek letter phi as defined here
|
||
|
https://www.w3.org/2003/entities/2007doc/isogrk1.html"""
|
||
|
x = self.dom.createElement('cn')
|
||
|
x.appendChild(self.dom.createTextNode("\N{GREEK SMALL LETTER PHI}"))
|
||
|
return x
|
||
|
|
||
|
def _print_Exp1(self, e):
|
||
|
return self.dom.createElement('exponentiale')
|
||
|
|
||
|
def _print_Pi(self, e):
|
||
|
return self.dom.createElement('pi')
|
||
|
|
||
|
def _print_Infinity(self, e):
|
||
|
return self.dom.createElement('infinity')
|
||
|
|
||
|
def _print_NaN(self, e):
|
||
|
return self.dom.createElement('notanumber')
|
||
|
|
||
|
def _print_EmptySet(self, e):
|
||
|
return self.dom.createElement('emptyset')
|
||
|
|
||
|
def _print_BooleanTrue(self, e):
|
||
|
return self.dom.createElement('true')
|
||
|
|
||
|
def _print_BooleanFalse(self, e):
|
||
|
return self.dom.createElement('false')
|
||
|
|
||
|
def _print_NegativeInfinity(self, e):
|
||
|
x = self.dom.createElement('apply')
|
||
|
x.appendChild(self.dom.createElement('minus'))
|
||
|
x.appendChild(self.dom.createElement('infinity'))
|
||
|
return x
|
||
|
|
||
|
def _print_Integral(self, e):
|
||
|
def lime_recur(limits):
|
||
|
x = self.dom.createElement('apply')
|
||
|
x.appendChild(self.dom.createElement(self.mathml_tag(e)))
|
||
|
bvar_elem = self.dom.createElement('bvar')
|
||
|
bvar_elem.appendChild(self._print(limits[0][0]))
|
||
|
x.appendChild(bvar_elem)
|
||
|
|
||
|
if len(limits[0]) == 3:
|
||
|
low_elem = self.dom.createElement('lowlimit')
|
||
|
low_elem.appendChild(self._print(limits[0][1]))
|
||
|
x.appendChild(low_elem)
|
||
|
up_elem = self.dom.createElement('uplimit')
|
||
|
up_elem.appendChild(self._print(limits[0][2]))
|
||
|
x.appendChild(up_elem)
|
||
|
if len(limits[0]) == 2:
|
||
|
up_elem = self.dom.createElement('uplimit')
|
||
|
up_elem.appendChild(self._print(limits[0][1]))
|
||
|
x.appendChild(up_elem)
|
||
|
if len(limits) == 1:
|
||
|
x.appendChild(self._print(e.function))
|
||
|
else:
|
||
|
x.appendChild(lime_recur(limits[1:]))
|
||
|
return x
|
||
|
|
||
|
limits = list(e.limits)
|
||
|
limits.reverse()
|
||
|
return lime_recur(limits)
|
||
|
|
||
|
def _print_Sum(self, e):
|
||
|
# Printer can be shared because Sum and Integral have the
|
||
|
# same internal representation.
|
||
|
return self._print_Integral(e)
|
||
|
|
||
|
def _print_Symbol(self, sym):
|
||
|
ci = self.dom.createElement(self.mathml_tag(sym))
|
||
|
|
||
|
def join(items):
|
||
|
if len(items) > 1:
|
||
|
mrow = self.dom.createElement('mml:mrow')
|
||
|
for i, item in enumerate(items):
|
||
|
if i > 0:
|
||
|
mo = self.dom.createElement('mml:mo')
|
||
|
mo.appendChild(self.dom.createTextNode(" "))
|
||
|
mrow.appendChild(mo)
|
||
|
mi = self.dom.createElement('mml:mi')
|
||
|
mi.appendChild(self.dom.createTextNode(item))
|
||
|
mrow.appendChild(mi)
|
||
|
return mrow
|
||
|
else:
|
||
|
mi = self.dom.createElement('mml:mi')
|
||
|
mi.appendChild(self.dom.createTextNode(items[0]))
|
||
|
return mi
|
||
|
|
||
|
# translate name, supers and subs to unicode characters
|
||
|
def translate(s):
|
||
|
if s in greek_unicode:
|
||
|
return greek_unicode.get(s)
|
||
|
else:
|
||
|
return s
|
||
|
|
||
|
name, supers, subs = split_super_sub(sym.name)
|
||
|
name = translate(name)
|
||
|
supers = [translate(sup) for sup in supers]
|
||
|
subs = [translate(sub) for sub in subs]
|
||
|
|
||
|
mname = self.dom.createElement('mml:mi')
|
||
|
mname.appendChild(self.dom.createTextNode(name))
|
||
|
if not supers:
|
||
|
if not subs:
|
||
|
ci.appendChild(self.dom.createTextNode(name))
|
||
|
else:
|
||
|
msub = self.dom.createElement('mml:msub')
|
||
|
msub.appendChild(mname)
|
||
|
msub.appendChild(join(subs))
|
||
|
ci.appendChild(msub)
|
||
|
else:
|
||
|
if not subs:
|
||
|
msup = self.dom.createElement('mml:msup')
|
||
|
msup.appendChild(mname)
|
||
|
msup.appendChild(join(supers))
|
||
|
ci.appendChild(msup)
|
||
|
else:
|
||
|
msubsup = self.dom.createElement('mml:msubsup')
|
||
|
msubsup.appendChild(mname)
|
||
|
msubsup.appendChild(join(subs))
|
||
|
msubsup.appendChild(join(supers))
|
||
|
ci.appendChild(msubsup)
|
||
|
return ci
|
||
|
|
||
|
_print_MatrixSymbol = _print_Symbol
|
||
|
_print_RandomSymbol = _print_Symbol
|
||
|
|
||
|
def _print_Pow(self, e):
|
||
|
# Here we use root instead of power if the exponent is the reciprocal
|
||
|
# of an integer
|
||
|
if (self._settings['root_notation'] and e.exp.is_Rational
|
||
|
and e.exp.p == 1):
|
||
|
x = self.dom.createElement('apply')
|
||
|
x.appendChild(self.dom.createElement('root'))
|
||
|
if e.exp.q != 2:
|
||
|
xmldeg = self.dom.createElement('degree')
|
||
|
xmlcn = self.dom.createElement('cn')
|
||
|
xmlcn.appendChild(self.dom.createTextNode(str(e.exp.q)))
|
||
|
xmldeg.appendChild(xmlcn)
|
||
|
x.appendChild(xmldeg)
|
||
|
x.appendChild(self._print(e.base))
|
||
|
return x
|
||
|
|
||
|
x = self.dom.createElement('apply')
|
||
|
x_1 = self.dom.createElement(self.mathml_tag(e))
|
||
|
x.appendChild(x_1)
|
||
|
x.appendChild(self._print(e.base))
|
||
|
x.appendChild(self._print(e.exp))
|
||
|
return x
|
||
|
|
||
|
def _print_Number(self, e):
|
||
|
x = self.dom.createElement(self.mathml_tag(e))
|
||
|
x.appendChild(self.dom.createTextNode(str(e)))
|
||
|
return x
|
||
|
|
||
|
def _print_Float(self, e):
|
||
|
x = self.dom.createElement(self.mathml_tag(e))
|
||
|
repr_e = mlib_to_str(e._mpf_, repr_dps(e._prec))
|
||
|
x.appendChild(self.dom.createTextNode(repr_e))
|
||
|
return x
|
||
|
|
||
|
def _print_Derivative(self, e):
|
||
|
x = self.dom.createElement('apply')
|
||
|
diff_symbol = self.mathml_tag(e)
|
||
|
if requires_partial(e.expr):
|
||
|
diff_symbol = 'partialdiff'
|
||
|
x.appendChild(self.dom.createElement(diff_symbol))
|
||
|
x_1 = self.dom.createElement('bvar')
|
||
|
|
||
|
for sym, times in reversed(e.variable_count):
|
||
|
x_1.appendChild(self._print(sym))
|
||
|
if times > 1:
|
||
|
degree = self.dom.createElement('degree')
|
||
|
degree.appendChild(self._print(sympify(times)))
|
||
|
x_1.appendChild(degree)
|
||
|
|
||
|
x.appendChild(x_1)
|
||
|
x.appendChild(self._print(e.expr))
|
||
|
return x
|
||
|
|
||
|
def _print_Function(self, e):
|
||
|
x = self.dom.createElement("apply")
|
||
|
x.appendChild(self.dom.createElement(self.mathml_tag(e)))
|
||
|
for arg in e.args:
|
||
|
x.appendChild(self._print(arg))
|
||
|
return x
|
||
|
|
||
|
def _print_Basic(self, e):
|
||
|
x = self.dom.createElement(self.mathml_tag(e))
|
||
|
for arg in e.args:
|
||
|
x.appendChild(self._print(arg))
|
||
|
return x
|
||
|
|
||
|
def _print_AssocOp(self, e):
|
||
|
x = self.dom.createElement('apply')
|
||
|
x_1 = self.dom.createElement(self.mathml_tag(e))
|
||
|
x.appendChild(x_1)
|
||
|
for arg in e.args:
|
||
|
x.appendChild(self._print(arg))
|
||
|
return x
|
||
|
|
||
|
def _print_Relational(self, e):
|
||
|
x = self.dom.createElement('apply')
|
||
|
x.appendChild(self.dom.createElement(self.mathml_tag(e)))
|
||
|
x.appendChild(self._print(e.lhs))
|
||
|
x.appendChild(self._print(e.rhs))
|
||
|
return x
|
||
|
|
||
|
def _print_list(self, seq):
|
||
|
"""MathML reference for the <list> element:
|
||
|
https://www.w3.org/TR/MathML2/chapter4.html#contm.list"""
|
||
|
dom_element = self.dom.createElement('list')
|
||
|
for item in seq:
|
||
|
dom_element.appendChild(self._print(item))
|
||
|
return dom_element
|
||
|
|
||
|
def _print_int(self, p):
|
||
|
dom_element = self.dom.createElement(self.mathml_tag(p))
|
||
|
dom_element.appendChild(self.dom.createTextNode(str(p)))
|
||
|
return dom_element
|
||
|
|
||
|
_print_Implies = _print_AssocOp
|
||
|
_print_Not = _print_AssocOp
|
||
|
_print_Xor = _print_AssocOp
|
||
|
|
||
|
def _print_FiniteSet(self, e):
|
||
|
x = self.dom.createElement('set')
|
||
|
for arg in e.args:
|
||
|
x.appendChild(self._print(arg))
|
||
|
return x
|
||
|
|
||
|
def _print_Complement(self, e):
|
||
|
x = self.dom.createElement('apply')
|
||
|
x.appendChild(self.dom.createElement('setdiff'))
|
||
|
for arg in e.args:
|
||
|
x.appendChild(self._print(arg))
|
||
|
return x
|
||
|
|
||
|
def _print_ProductSet(self, e):
|
||
|
x = self.dom.createElement('apply')
|
||
|
x.appendChild(self.dom.createElement('cartesianproduct'))
|
||
|
for arg in e.args:
|
||
|
x.appendChild(self._print(arg))
|
||
|
return x
|
||
|
|
||
|
# XXX Symmetric difference is not supported for MathML content printers.
|
||
|
|
||
|
|
||
|
class MathMLPresentationPrinter(MathMLPrinterBase):
|
||
|
"""Prints an expression to the Presentation MathML markup language.
|
||
|
|
||
|
References: https://www.w3.org/TR/MathML2/chapter3.html
|
||
|
"""
|
||
|
printmethod = "_mathml_presentation"
|
||
|
|
||
|
def mathml_tag(self, e):
|
||
|
"""Returns the MathML tag for an expression."""
|
||
|
translate = {
|
||
|
'Number': 'mn',
|
||
|
'Limit': '→',
|
||
|
'Derivative': 'ⅆ',
|
||
|
'int': 'mn',
|
||
|
'Symbol': 'mi',
|
||
|
'Integral': '∫',
|
||
|
'Sum': '∑',
|
||
|
'sin': 'sin',
|
||
|
'cos': 'cos',
|
||
|
'tan': 'tan',
|
||
|
'cot': 'cot',
|
||
|
'asin': 'arcsin',
|
||
|
'asinh': 'arcsinh',
|
||
|
'acos': 'arccos',
|
||
|
'acosh': 'arccosh',
|
||
|
'atan': 'arctan',
|
||
|
'atanh': 'arctanh',
|
||
|
'acot': 'arccot',
|
||
|
'atan2': 'arctan',
|
||
|
'Equality': '=',
|
||
|
'Unequality': '≠',
|
||
|
'GreaterThan': '≥',
|
||
|
'LessThan': '≤',
|
||
|
'StrictGreaterThan': '>',
|
||
|
'StrictLessThan': '<',
|
||
|
'lerchphi': 'Φ',
|
||
|
'zeta': 'ζ',
|
||
|
'dirichlet_eta': 'η',
|
||
|
'elliptic_k': 'Κ',
|
||
|
'lowergamma': 'γ',
|
||
|
'uppergamma': 'Γ',
|
||
|
'gamma': 'Γ',
|
||
|
'totient': 'ϕ',
|
||
|
'reduced_totient': 'λ',
|
||
|
'primenu': 'ν',
|
||
|
'primeomega': 'Ω',
|
||
|
'fresnels': 'S',
|
||
|
'fresnelc': 'C',
|
||
|
'LambertW': 'W',
|
||
|
'Heaviside': 'Θ',
|
||
|
'BooleanTrue': 'True',
|
||
|
'BooleanFalse': 'False',
|
||
|
'NoneType': 'None',
|
||
|
'mathieus': 'S',
|
||
|
'mathieuc': 'C',
|
||
|
'mathieusprime': 'S′',
|
||
|
'mathieucprime': 'C′',
|
||
|
}
|
||
|
|
||
|
def mul_symbol_selection():
|
||
|
if (self._settings["mul_symbol"] is None or
|
||
|
self._settings["mul_symbol"] == 'None'):
|
||
|
return '⁢'
|
||
|
elif self._settings["mul_symbol"] == 'times':
|
||
|
return '×'
|
||
|
elif self._settings["mul_symbol"] == 'dot':
|
||
|
return '·'
|
||
|
elif self._settings["mul_symbol"] == 'ldot':
|
||
|
return '․'
|
||
|
elif not isinstance(self._settings["mul_symbol"], str):
|
||
|
raise TypeError
|
||
|
else:
|
||
|
return self._settings["mul_symbol"]
|
||
|
for cls in e.__class__.__mro__:
|
||
|
n = cls.__name__
|
||
|
if n in translate:
|
||
|
return translate[n]
|
||
|
# Not found in the MRO set
|
||
|
if e.__class__.__name__ == "Mul":
|
||
|
return mul_symbol_selection()
|
||
|
n = e.__class__.__name__
|
||
|
return n.lower()
|
||
|
|
||
|
def parenthesize(self, item, level, strict=False):
|
||
|
prec_val = precedence_traditional(item)
|
||
|
if (prec_val < level) or ((not strict) and prec_val <= level):
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
brac.appendChild(self._print(item))
|
||
|
return brac
|
||
|
else:
|
||
|
return self._print(item)
|
||
|
|
||
|
def _print_Mul(self, expr):
|
||
|
|
||
|
def multiply(expr, mrow):
|
||
|
from sympy.simplify import fraction
|
||
|
numer, denom = fraction(expr)
|
||
|
if denom is not S.One:
|
||
|
frac = self.dom.createElement('mfrac')
|
||
|
if self._settings["fold_short_frac"] and len(str(expr)) < 7:
|
||
|
frac.setAttribute('bevelled', 'true')
|
||
|
xnum = self._print(numer)
|
||
|
xden = self._print(denom)
|
||
|
frac.appendChild(xnum)
|
||
|
frac.appendChild(xden)
|
||
|
mrow.appendChild(frac)
|
||
|
return mrow
|
||
|
|
||
|
coeff, terms = expr.as_coeff_mul()
|
||
|
if coeff is S.One and len(terms) == 1:
|
||
|
mrow.appendChild(self._print(terms[0]))
|
||
|
return mrow
|
||
|
if self.order != 'old':
|
||
|
terms = Mul._from_args(terms).as_ordered_factors()
|
||
|
|
||
|
if coeff != 1:
|
||
|
x = self._print(coeff)
|
||
|
y = self.dom.createElement('mo')
|
||
|
y.appendChild(self.dom.createTextNode(self.mathml_tag(expr)))
|
||
|
mrow.appendChild(x)
|
||
|
mrow.appendChild(y)
|
||
|
for term in terms:
|
||
|
mrow.appendChild(self.parenthesize(term, PRECEDENCE['Mul']))
|
||
|
if not term == terms[-1]:
|
||
|
y = self.dom.createElement('mo')
|
||
|
y.appendChild(self.dom.createTextNode(self.mathml_tag(expr)))
|
||
|
mrow.appendChild(y)
|
||
|
return mrow
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
if expr.could_extract_minus_sign():
|
||
|
x = self.dom.createElement('mo')
|
||
|
x.appendChild(self.dom.createTextNode('-'))
|
||
|
mrow.appendChild(x)
|
||
|
mrow = multiply(-expr, mrow)
|
||
|
else:
|
||
|
mrow = multiply(expr, mrow)
|
||
|
|
||
|
return mrow
|
||
|
|
||
|
def _print_Add(self, expr, order=None):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
args = self._as_ordered_terms(expr, order=order)
|
||
|
mrow.appendChild(self._print(args[0]))
|
||
|
for arg in args[1:]:
|
||
|
if arg.could_extract_minus_sign():
|
||
|
# use minus
|
||
|
x = self.dom.createElement('mo')
|
||
|
x.appendChild(self.dom.createTextNode('-'))
|
||
|
y = self._print(-arg)
|
||
|
# invert expression since this is now minused
|
||
|
else:
|
||
|
x = self.dom.createElement('mo')
|
||
|
x.appendChild(self.dom.createTextNode('+'))
|
||
|
y = self._print(arg)
|
||
|
mrow.appendChild(x)
|
||
|
mrow.appendChild(y)
|
||
|
|
||
|
return mrow
|
||
|
|
||
|
def _print_MatrixBase(self, m):
|
||
|
table = self.dom.createElement('mtable')
|
||
|
for i in range(m.rows):
|
||
|
x = self.dom.createElement('mtr')
|
||
|
for j in range(m.cols):
|
||
|
y = self.dom.createElement('mtd')
|
||
|
y.appendChild(self._print(m[i, j]))
|
||
|
x.appendChild(y)
|
||
|
table.appendChild(x)
|
||
|
if self._settings["mat_delim"] == '':
|
||
|
return table
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
if self._settings["mat_delim"] == "[":
|
||
|
brac.setAttribute('close', ']')
|
||
|
brac.setAttribute('open', '[')
|
||
|
brac.appendChild(table)
|
||
|
return brac
|
||
|
|
||
|
def _get_printed_Rational(self, e, folded=None):
|
||
|
if e.p < 0:
|
||
|
p = -e.p
|
||
|
else:
|
||
|
p = e.p
|
||
|
x = self.dom.createElement('mfrac')
|
||
|
if folded or self._settings["fold_short_frac"]:
|
||
|
x.setAttribute('bevelled', 'true')
|
||
|
x.appendChild(self._print(p))
|
||
|
x.appendChild(self._print(e.q))
|
||
|
if e.p < 0:
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('-'))
|
||
|
mrow.appendChild(mo)
|
||
|
mrow.appendChild(x)
|
||
|
return mrow
|
||
|
else:
|
||
|
return x
|
||
|
|
||
|
def _print_Rational(self, e):
|
||
|
if e.q == 1:
|
||
|
# don't divide
|
||
|
return self._print(e.p)
|
||
|
|
||
|
return self._get_printed_Rational(e, self._settings["fold_short_frac"])
|
||
|
|
||
|
def _print_Limit(self, e):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
munder = self.dom.createElement('munder')
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.appendChild(self.dom.createTextNode('lim'))
|
||
|
|
||
|
x = self.dom.createElement('mrow')
|
||
|
x_1 = self._print(e.args[1])
|
||
|
arrow = self.dom.createElement('mo')
|
||
|
arrow.appendChild(self.dom.createTextNode(self.mathml_tag(e)))
|
||
|
x_2 = self._print(e.args[2])
|
||
|
x.appendChild(x_1)
|
||
|
x.appendChild(arrow)
|
||
|
x.appendChild(x_2)
|
||
|
|
||
|
munder.appendChild(mi)
|
||
|
munder.appendChild(x)
|
||
|
mrow.appendChild(munder)
|
||
|
mrow.appendChild(self._print(e.args[0]))
|
||
|
|
||
|
return mrow
|
||
|
|
||
|
def _print_ImaginaryUnit(self, e):
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.appendChild(self.dom.createTextNode('ⅈ'))
|
||
|
return x
|
||
|
|
||
|
def _print_GoldenRatio(self, e):
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.appendChild(self.dom.createTextNode('Φ'))
|
||
|
return x
|
||
|
|
||
|
def _print_Exp1(self, e):
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.appendChild(self.dom.createTextNode('ⅇ'))
|
||
|
return x
|
||
|
|
||
|
def _print_Pi(self, e):
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.appendChild(self.dom.createTextNode('π'))
|
||
|
return x
|
||
|
|
||
|
def _print_Infinity(self, e):
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.appendChild(self.dom.createTextNode('∞'))
|
||
|
return x
|
||
|
|
||
|
def _print_NegativeInfinity(self, e):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
y = self.dom.createElement('mo')
|
||
|
y.appendChild(self.dom.createTextNode('-'))
|
||
|
x = self._print_Infinity(e)
|
||
|
mrow.appendChild(y)
|
||
|
mrow.appendChild(x)
|
||
|
return mrow
|
||
|
|
||
|
def _print_HBar(self, e):
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.appendChild(self.dom.createTextNode('ℏ'))
|
||
|
return x
|
||
|
|
||
|
def _print_EulerGamma(self, e):
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.appendChild(self.dom.createTextNode('γ'))
|
||
|
return x
|
||
|
|
||
|
def _print_TribonacciConstant(self, e):
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.appendChild(self.dom.createTextNode('TribonacciConstant'))
|
||
|
return x
|
||
|
|
||
|
def _print_Dagger(self, e):
|
||
|
msup = self.dom.createElement('msup')
|
||
|
msup.appendChild(self._print(e.args[0]))
|
||
|
msup.appendChild(self.dom.createTextNode('†'))
|
||
|
return msup
|
||
|
|
||
|
def _print_Contains(self, e):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
mrow.appendChild(self._print(e.args[0]))
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('∈'))
|
||
|
mrow.appendChild(mo)
|
||
|
mrow.appendChild(self._print(e.args[1]))
|
||
|
return mrow
|
||
|
|
||
|
def _print_HilbertSpace(self, e):
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.appendChild(self.dom.createTextNode('ℋ'))
|
||
|
return x
|
||
|
|
||
|
def _print_ComplexSpace(self, e):
|
||
|
msup = self.dom.createElement('msup')
|
||
|
msup.appendChild(self.dom.createTextNode('𝒞'))
|
||
|
msup.appendChild(self._print(e.args[0]))
|
||
|
return msup
|
||
|
|
||
|
def _print_FockSpace(self, e):
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.appendChild(self.dom.createTextNode('ℱ'))
|
||
|
return x
|
||
|
|
||
|
|
||
|
def _print_Integral(self, expr):
|
||
|
intsymbols = {1: "∫", 2: "∬", 3: "∭"}
|
||
|
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
if len(expr.limits) <= 3 and all(len(lim) == 1 for lim in expr.limits):
|
||
|
# Only up to three-integral signs exists
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode(intsymbols[len(expr.limits)]))
|
||
|
mrow.appendChild(mo)
|
||
|
else:
|
||
|
# Either more than three or limits provided
|
||
|
for lim in reversed(expr.limits):
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode(intsymbols[1]))
|
||
|
if len(lim) == 1:
|
||
|
mrow.appendChild(mo)
|
||
|
if len(lim) == 2:
|
||
|
msup = self.dom.createElement('msup')
|
||
|
msup.appendChild(mo)
|
||
|
msup.appendChild(self._print(lim[1]))
|
||
|
mrow.appendChild(msup)
|
||
|
if len(lim) == 3:
|
||
|
msubsup = self.dom.createElement('msubsup')
|
||
|
msubsup.appendChild(mo)
|
||
|
msubsup.appendChild(self._print(lim[1]))
|
||
|
msubsup.appendChild(self._print(lim[2]))
|
||
|
mrow.appendChild(msubsup)
|
||
|
# print function
|
||
|
mrow.appendChild(self.parenthesize(expr.function, PRECEDENCE["Mul"],
|
||
|
strict=True))
|
||
|
# print integration variables
|
||
|
for lim in reversed(expr.limits):
|
||
|
d = self.dom.createElement('mo')
|
||
|
d.appendChild(self.dom.createTextNode('ⅆ'))
|
||
|
mrow.appendChild(d)
|
||
|
mrow.appendChild(self._print(lim[0]))
|
||
|
return mrow
|
||
|
|
||
|
def _print_Sum(self, e):
|
||
|
limits = list(e.limits)
|
||
|
subsup = self.dom.createElement('munderover')
|
||
|
low_elem = self._print(limits[0][1])
|
||
|
up_elem = self._print(limits[0][2])
|
||
|
summand = self.dom.createElement('mo')
|
||
|
summand.appendChild(self.dom.createTextNode(self.mathml_tag(e)))
|
||
|
|
||
|
low = self.dom.createElement('mrow')
|
||
|
var = self._print(limits[0][0])
|
||
|
equal = self.dom.createElement('mo')
|
||
|
equal.appendChild(self.dom.createTextNode('='))
|
||
|
low.appendChild(var)
|
||
|
low.appendChild(equal)
|
||
|
low.appendChild(low_elem)
|
||
|
|
||
|
subsup.appendChild(summand)
|
||
|
subsup.appendChild(low)
|
||
|
subsup.appendChild(up_elem)
|
||
|
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
mrow.appendChild(subsup)
|
||
|
if len(str(e.function)) == 1:
|
||
|
mrow.appendChild(self._print(e.function))
|
||
|
else:
|
||
|
fence = self.dom.createElement('mfenced')
|
||
|
fence.appendChild(self._print(e.function))
|
||
|
mrow.appendChild(fence)
|
||
|
|
||
|
return mrow
|
||
|
|
||
|
def _print_Symbol(self, sym, style='plain'):
|
||
|
def join(items):
|
||
|
if len(items) > 1:
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
for i, item in enumerate(items):
|
||
|
if i > 0:
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode(" "))
|
||
|
mrow.appendChild(mo)
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.appendChild(self.dom.createTextNode(item))
|
||
|
mrow.appendChild(mi)
|
||
|
return mrow
|
||
|
else:
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.appendChild(self.dom.createTextNode(items[0]))
|
||
|
return mi
|
||
|
|
||
|
# translate name, supers and subs to unicode characters
|
||
|
def translate(s):
|
||
|
if s in greek_unicode:
|
||
|
return greek_unicode.get(s)
|
||
|
else:
|
||
|
return s
|
||
|
|
||
|
name, supers, subs = split_super_sub(sym.name)
|
||
|
name = translate(name)
|
||
|
supers = [translate(sup) for sup in supers]
|
||
|
subs = [translate(sub) for sub in subs]
|
||
|
|
||
|
mname = self.dom.createElement('mi')
|
||
|
mname.appendChild(self.dom.createTextNode(name))
|
||
|
if len(supers) == 0:
|
||
|
if len(subs) == 0:
|
||
|
x = mname
|
||
|
else:
|
||
|
x = self.dom.createElement('msub')
|
||
|
x.appendChild(mname)
|
||
|
x.appendChild(join(subs))
|
||
|
else:
|
||
|
if len(subs) == 0:
|
||
|
x = self.dom.createElement('msup')
|
||
|
x.appendChild(mname)
|
||
|
x.appendChild(join(supers))
|
||
|
else:
|
||
|
x = self.dom.createElement('msubsup')
|
||
|
x.appendChild(mname)
|
||
|
x.appendChild(join(subs))
|
||
|
x.appendChild(join(supers))
|
||
|
# Set bold font?
|
||
|
if style == 'bold':
|
||
|
x.setAttribute('mathvariant', 'bold')
|
||
|
return x
|
||
|
|
||
|
def _print_MatrixSymbol(self, sym):
|
||
|
return self._print_Symbol(sym,
|
||
|
style=self._settings['mat_symbol_style'])
|
||
|
|
||
|
_print_RandomSymbol = _print_Symbol
|
||
|
|
||
|
def _print_conjugate(self, expr):
|
||
|
enc = self.dom.createElement('menclose')
|
||
|
enc.setAttribute('notation', 'top')
|
||
|
enc.appendChild(self._print(expr.args[0]))
|
||
|
return enc
|
||
|
|
||
|
def _print_operator_after(self, op, expr):
|
||
|
row = self.dom.createElement('mrow')
|
||
|
row.appendChild(self.parenthesize(expr, PRECEDENCE["Func"]))
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode(op))
|
||
|
row.appendChild(mo)
|
||
|
return row
|
||
|
|
||
|
def _print_factorial(self, expr):
|
||
|
return self._print_operator_after('!', expr.args[0])
|
||
|
|
||
|
def _print_factorial2(self, expr):
|
||
|
return self._print_operator_after('!!', expr.args[0])
|
||
|
|
||
|
def _print_binomial(self, expr):
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
frac = self.dom.createElement('mfrac')
|
||
|
frac.setAttribute('linethickness', '0')
|
||
|
frac.appendChild(self._print(expr.args[0]))
|
||
|
frac.appendChild(self._print(expr.args[1]))
|
||
|
brac.appendChild(frac)
|
||
|
return brac
|
||
|
|
||
|
def _print_Pow(self, e):
|
||
|
# Here we use root instead of power if the exponent is the
|
||
|
# reciprocal of an integer
|
||
|
if (e.exp.is_Rational and abs(e.exp.p) == 1 and e.exp.q != 1 and
|
||
|
self._settings['root_notation']):
|
||
|
if e.exp.q == 2:
|
||
|
x = self.dom.createElement('msqrt')
|
||
|
x.appendChild(self._print(e.base))
|
||
|
if e.exp.q != 2:
|
||
|
x = self.dom.createElement('mroot')
|
||
|
x.appendChild(self._print(e.base))
|
||
|
x.appendChild(self._print(e.exp.q))
|
||
|
if e.exp.p == -1:
|
||
|
frac = self.dom.createElement('mfrac')
|
||
|
frac.appendChild(self._print(1))
|
||
|
frac.appendChild(x)
|
||
|
return frac
|
||
|
else:
|
||
|
return x
|
||
|
|
||
|
if e.exp.is_Rational and e.exp.q != 1:
|
||
|
if e.exp.is_negative:
|
||
|
top = self.dom.createElement('mfrac')
|
||
|
top.appendChild(self._print(1))
|
||
|
x = self.dom.createElement('msup')
|
||
|
x.appendChild(self.parenthesize(e.base, PRECEDENCE['Pow']))
|
||
|
x.appendChild(self._get_printed_Rational(-e.exp,
|
||
|
self._settings['fold_frac_powers']))
|
||
|
top.appendChild(x)
|
||
|
return top
|
||
|
else:
|
||
|
x = self.dom.createElement('msup')
|
||
|
x.appendChild(self.parenthesize(e.base, PRECEDENCE['Pow']))
|
||
|
x.appendChild(self._get_printed_Rational(e.exp,
|
||
|
self._settings['fold_frac_powers']))
|
||
|
return x
|
||
|
|
||
|
if e.exp.is_negative:
|
||
|
top = self.dom.createElement('mfrac')
|
||
|
top.appendChild(self._print(1))
|
||
|
if e.exp == -1:
|
||
|
top.appendChild(self._print(e.base))
|
||
|
else:
|
||
|
x = self.dom.createElement('msup')
|
||
|
x.appendChild(self.parenthesize(e.base, PRECEDENCE['Pow']))
|
||
|
x.appendChild(self._print(-e.exp))
|
||
|
top.appendChild(x)
|
||
|
return top
|
||
|
|
||
|
x = self.dom.createElement('msup')
|
||
|
x.appendChild(self.parenthesize(e.base, PRECEDENCE['Pow']))
|
||
|
x.appendChild(self._print(e.exp))
|
||
|
return x
|
||
|
|
||
|
def _print_Number(self, e):
|
||
|
x = self.dom.createElement(self.mathml_tag(e))
|
||
|
x.appendChild(self.dom.createTextNode(str(e)))
|
||
|
return x
|
||
|
|
||
|
def _print_AccumulationBounds(self, i):
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
brac.setAttribute('close', '\u27e9')
|
||
|
brac.setAttribute('open', '\u27e8')
|
||
|
brac.appendChild(self._print(i.min))
|
||
|
brac.appendChild(self._print(i.max))
|
||
|
return brac
|
||
|
|
||
|
def _print_Derivative(self, e):
|
||
|
|
||
|
if requires_partial(e.expr):
|
||
|
d = '∂'
|
||
|
else:
|
||
|
d = self.mathml_tag(e)
|
||
|
|
||
|
# Determine denominator
|
||
|
m = self.dom.createElement('mrow')
|
||
|
dim = 0 # Total diff dimension, for numerator
|
||
|
for sym, num in reversed(e.variable_count):
|
||
|
dim += num
|
||
|
if num >= 2:
|
||
|
x = self.dom.createElement('msup')
|
||
|
xx = self.dom.createElement('mo')
|
||
|
xx.appendChild(self.dom.createTextNode(d))
|
||
|
x.appendChild(xx)
|
||
|
x.appendChild(self._print(num))
|
||
|
else:
|
||
|
x = self.dom.createElement('mo')
|
||
|
x.appendChild(self.dom.createTextNode(d))
|
||
|
m.appendChild(x)
|
||
|
y = self._print(sym)
|
||
|
m.appendChild(y)
|
||
|
|
||
|
mnum = self.dom.createElement('mrow')
|
||
|
if dim >= 2:
|
||
|
x = self.dom.createElement('msup')
|
||
|
xx = self.dom.createElement('mo')
|
||
|
xx.appendChild(self.dom.createTextNode(d))
|
||
|
x.appendChild(xx)
|
||
|
x.appendChild(self._print(dim))
|
||
|
else:
|
||
|
x = self.dom.createElement('mo')
|
||
|
x.appendChild(self.dom.createTextNode(d))
|
||
|
|
||
|
mnum.appendChild(x)
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
frac = self.dom.createElement('mfrac')
|
||
|
frac.appendChild(mnum)
|
||
|
frac.appendChild(m)
|
||
|
mrow.appendChild(frac)
|
||
|
|
||
|
# Print function
|
||
|
mrow.appendChild(self._print(e.expr))
|
||
|
|
||
|
return mrow
|
||
|
|
||
|
def _print_Function(self, e):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
x = self.dom.createElement('mi')
|
||
|
if self.mathml_tag(e) == 'log' and self._settings["ln_notation"]:
|
||
|
x.appendChild(self.dom.createTextNode('ln'))
|
||
|
else:
|
||
|
x.appendChild(self.dom.createTextNode(self.mathml_tag(e)))
|
||
|
y = self.dom.createElement('mfenced')
|
||
|
for arg in e.args:
|
||
|
y.appendChild(self._print(arg))
|
||
|
mrow.appendChild(x)
|
||
|
mrow.appendChild(y)
|
||
|
return mrow
|
||
|
|
||
|
def _print_Float(self, expr):
|
||
|
# Based off of that in StrPrinter
|
||
|
dps = prec_to_dps(expr._prec)
|
||
|
str_real = mlib_to_str(expr._mpf_, dps, strip_zeros=True)
|
||
|
|
||
|
# Must always have a mul symbol (as 2.5 10^{20} just looks odd)
|
||
|
# thus we use the number separator
|
||
|
separator = self._settings['mul_symbol_mathml_numbers']
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
if 'e' in str_real:
|
||
|
(mant, exp) = str_real.split('e')
|
||
|
|
||
|
if exp[0] == '+':
|
||
|
exp = exp[1:]
|
||
|
|
||
|
mn = self.dom.createElement('mn')
|
||
|
mn.appendChild(self.dom.createTextNode(mant))
|
||
|
mrow.appendChild(mn)
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode(separator))
|
||
|
mrow.appendChild(mo)
|
||
|
msup = self.dom.createElement('msup')
|
||
|
mn = self.dom.createElement('mn')
|
||
|
mn.appendChild(self.dom.createTextNode("10"))
|
||
|
msup.appendChild(mn)
|
||
|
mn = self.dom.createElement('mn')
|
||
|
mn.appendChild(self.dom.createTextNode(exp))
|
||
|
msup.appendChild(mn)
|
||
|
mrow.appendChild(msup)
|
||
|
return mrow
|
||
|
elif str_real == "+inf":
|
||
|
return self._print_Infinity(None)
|
||
|
elif str_real == "-inf":
|
||
|
return self._print_NegativeInfinity(None)
|
||
|
else:
|
||
|
mn = self.dom.createElement('mn')
|
||
|
mn.appendChild(self.dom.createTextNode(str_real))
|
||
|
return mn
|
||
|
|
||
|
def _print_polylog(self, expr):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
m = self.dom.createElement('msub')
|
||
|
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.appendChild(self.dom.createTextNode('Li'))
|
||
|
m.appendChild(mi)
|
||
|
m.appendChild(self._print(expr.args[0]))
|
||
|
mrow.appendChild(m)
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
brac.appendChild(self._print(expr.args[1]))
|
||
|
mrow.appendChild(brac)
|
||
|
return mrow
|
||
|
|
||
|
def _print_Basic(self, e):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.appendChild(self.dom.createTextNode(self.mathml_tag(e)))
|
||
|
mrow.appendChild(mi)
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
for arg in e.args:
|
||
|
brac.appendChild(self._print(arg))
|
||
|
mrow.appendChild(brac)
|
||
|
return mrow
|
||
|
|
||
|
def _print_Tuple(self, e):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
x = self.dom.createElement('mfenced')
|
||
|
for arg in e.args:
|
||
|
x.appendChild(self._print(arg))
|
||
|
mrow.appendChild(x)
|
||
|
return mrow
|
||
|
|
||
|
def _print_Interval(self, i):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
if i.start == i.end:
|
||
|
# Most often, this type of Interval is converted to a FiniteSet
|
||
|
brac.setAttribute('close', '}')
|
||
|
brac.setAttribute('open', '{')
|
||
|
brac.appendChild(self._print(i.start))
|
||
|
else:
|
||
|
if i.right_open:
|
||
|
brac.setAttribute('close', ')')
|
||
|
else:
|
||
|
brac.setAttribute('close', ']')
|
||
|
|
||
|
if i.left_open:
|
||
|
brac.setAttribute('open', '(')
|
||
|
else:
|
||
|
brac.setAttribute('open', '[')
|
||
|
brac.appendChild(self._print(i.start))
|
||
|
brac.appendChild(self._print(i.end))
|
||
|
|
||
|
mrow.appendChild(brac)
|
||
|
return mrow
|
||
|
|
||
|
def _print_Abs(self, expr, exp=None):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
x = self.dom.createElement('mfenced')
|
||
|
x.setAttribute('close', '|')
|
||
|
x.setAttribute('open', '|')
|
||
|
x.appendChild(self._print(expr.args[0]))
|
||
|
mrow.appendChild(x)
|
||
|
return mrow
|
||
|
|
||
|
_print_Determinant = _print_Abs
|
||
|
|
||
|
def _print_re_im(self, c, expr):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.setAttribute('mathvariant', 'fraktur')
|
||
|
mi.appendChild(self.dom.createTextNode(c))
|
||
|
mrow.appendChild(mi)
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
brac.appendChild(self._print(expr))
|
||
|
mrow.appendChild(brac)
|
||
|
return mrow
|
||
|
|
||
|
def _print_re(self, expr, exp=None):
|
||
|
return self._print_re_im('R', expr.args[0])
|
||
|
|
||
|
def _print_im(self, expr, exp=None):
|
||
|
return self._print_re_im('I', expr.args[0])
|
||
|
|
||
|
def _print_AssocOp(self, e):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.appendChild(self.dom.createTextNode(self.mathml_tag(e)))
|
||
|
mrow.appendChild(mi)
|
||
|
for arg in e.args:
|
||
|
mrow.appendChild(self._print(arg))
|
||
|
return mrow
|
||
|
|
||
|
def _print_SetOp(self, expr, symbol, prec):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
mrow.appendChild(self.parenthesize(expr.args[0], prec))
|
||
|
for arg in expr.args[1:]:
|
||
|
x = self.dom.createElement('mo')
|
||
|
x.appendChild(self.dom.createTextNode(symbol))
|
||
|
y = self.parenthesize(arg, prec)
|
||
|
mrow.appendChild(x)
|
||
|
mrow.appendChild(y)
|
||
|
return mrow
|
||
|
|
||
|
def _print_Union(self, expr):
|
||
|
prec = PRECEDENCE_TRADITIONAL['Union']
|
||
|
return self._print_SetOp(expr, '∪', prec)
|
||
|
|
||
|
def _print_Intersection(self, expr):
|
||
|
prec = PRECEDENCE_TRADITIONAL['Intersection']
|
||
|
return self._print_SetOp(expr, '∩', prec)
|
||
|
|
||
|
def _print_Complement(self, expr):
|
||
|
prec = PRECEDENCE_TRADITIONAL['Complement']
|
||
|
return self._print_SetOp(expr, '∖', prec)
|
||
|
|
||
|
def _print_SymmetricDifference(self, expr):
|
||
|
prec = PRECEDENCE_TRADITIONAL['SymmetricDifference']
|
||
|
return self._print_SetOp(expr, '∆', prec)
|
||
|
|
||
|
def _print_ProductSet(self, expr):
|
||
|
prec = PRECEDENCE_TRADITIONAL['ProductSet']
|
||
|
return self._print_SetOp(expr, '×', prec)
|
||
|
|
||
|
def _print_FiniteSet(self, s):
|
||
|
return self._print_set(s.args)
|
||
|
|
||
|
def _print_set(self, s):
|
||
|
items = sorted(s, key=default_sort_key)
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
brac.setAttribute('close', '}')
|
||
|
brac.setAttribute('open', '{')
|
||
|
for item in items:
|
||
|
brac.appendChild(self._print(item))
|
||
|
return brac
|
||
|
|
||
|
_print_frozenset = _print_set
|
||
|
|
||
|
def _print_LogOp(self, args, symbol):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
if args[0].is_Boolean and not args[0].is_Not:
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
brac.appendChild(self._print(args[0]))
|
||
|
mrow.appendChild(brac)
|
||
|
else:
|
||
|
mrow.appendChild(self._print(args[0]))
|
||
|
for arg in args[1:]:
|
||
|
x = self.dom.createElement('mo')
|
||
|
x.appendChild(self.dom.createTextNode(symbol))
|
||
|
if arg.is_Boolean and not arg.is_Not:
|
||
|
y = self.dom.createElement('mfenced')
|
||
|
y.appendChild(self._print(arg))
|
||
|
else:
|
||
|
y = self._print(arg)
|
||
|
mrow.appendChild(x)
|
||
|
mrow.appendChild(y)
|
||
|
return mrow
|
||
|
|
||
|
def _print_BasisDependent(self, expr):
|
||
|
from sympy.vector import Vector
|
||
|
|
||
|
if expr == expr.zero:
|
||
|
# Not clear if this is ever called
|
||
|
return self._print(expr.zero)
|
||
|
if isinstance(expr, Vector):
|
||
|
items = expr.separate().items()
|
||
|
else:
|
||
|
items = [(0, expr)]
|
||
|
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
for system, vect in items:
|
||
|
inneritems = list(vect.components.items())
|
||
|
inneritems.sort(key = lambda x:x[0].__str__())
|
||
|
for i, (k, v) in enumerate(inneritems):
|
||
|
if v == 1:
|
||
|
if i: # No + for first item
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('+'))
|
||
|
mrow.appendChild(mo)
|
||
|
mrow.appendChild(self._print(k))
|
||
|
elif v == -1:
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('-'))
|
||
|
mrow.appendChild(mo)
|
||
|
mrow.appendChild(self._print(k))
|
||
|
else:
|
||
|
if i: # No + for first item
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('+'))
|
||
|
mrow.appendChild(mo)
|
||
|
mbrac = self.dom.createElement('mfenced')
|
||
|
mbrac.appendChild(self._print(v))
|
||
|
mrow.appendChild(mbrac)
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('⁢'))
|
||
|
mrow.appendChild(mo)
|
||
|
mrow.appendChild(self._print(k))
|
||
|
return mrow
|
||
|
|
||
|
|
||
|
def _print_And(self, expr):
|
||
|
args = sorted(expr.args, key=default_sort_key)
|
||
|
return self._print_LogOp(args, '∧')
|
||
|
|
||
|
def _print_Or(self, expr):
|
||
|
args = sorted(expr.args, key=default_sort_key)
|
||
|
return self._print_LogOp(args, '∨')
|
||
|
|
||
|
def _print_Xor(self, expr):
|
||
|
args = sorted(expr.args, key=default_sort_key)
|
||
|
return self._print_LogOp(args, '⊻')
|
||
|
|
||
|
def _print_Implies(self, expr):
|
||
|
return self._print_LogOp(expr.args, '⇒')
|
||
|
|
||
|
def _print_Equivalent(self, expr):
|
||
|
args = sorted(expr.args, key=default_sort_key)
|
||
|
return self._print_LogOp(args, '⇔')
|
||
|
|
||
|
def _print_Not(self, e):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('¬'))
|
||
|
mrow.appendChild(mo)
|
||
|
if (e.args[0].is_Boolean):
|
||
|
x = self.dom.createElement('mfenced')
|
||
|
x.appendChild(self._print(e.args[0]))
|
||
|
else:
|
||
|
x = self._print(e.args[0])
|
||
|
mrow.appendChild(x)
|
||
|
return mrow
|
||
|
|
||
|
def _print_bool(self, e):
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.appendChild(self.dom.createTextNode(self.mathml_tag(e)))
|
||
|
return mi
|
||
|
|
||
|
_print_BooleanTrue = _print_bool
|
||
|
_print_BooleanFalse = _print_bool
|
||
|
|
||
|
def _print_NoneType(self, e):
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.appendChild(self.dom.createTextNode(self.mathml_tag(e)))
|
||
|
return mi
|
||
|
|
||
|
def _print_Range(self, s):
|
||
|
dots = "\u2026"
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
brac.setAttribute('close', '}')
|
||
|
brac.setAttribute('open', '{')
|
||
|
|
||
|
if s.start.is_infinite and s.stop.is_infinite:
|
||
|
if s.step.is_positive:
|
||
|
printset = dots, -1, 0, 1, dots
|
||
|
else:
|
||
|
printset = dots, 1, 0, -1, dots
|
||
|
elif s.start.is_infinite:
|
||
|
printset = dots, s[-1] - s.step, s[-1]
|
||
|
elif s.stop.is_infinite:
|
||
|
it = iter(s)
|
||
|
printset = next(it), next(it), dots
|
||
|
elif len(s) > 4:
|
||
|
it = iter(s)
|
||
|
printset = next(it), next(it), dots, s[-1]
|
||
|
else:
|
||
|
printset = tuple(s)
|
||
|
|
||
|
for el in printset:
|
||
|
if el == dots:
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.appendChild(self.dom.createTextNode(dots))
|
||
|
brac.appendChild(mi)
|
||
|
else:
|
||
|
brac.appendChild(self._print(el))
|
||
|
|
||
|
return brac
|
||
|
|
||
|
def _hprint_variadic_function(self, expr):
|
||
|
args = sorted(expr.args, key=default_sort_key)
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode((str(expr.func)).lower()))
|
||
|
mrow.appendChild(mo)
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
for symbol in args:
|
||
|
brac.appendChild(self._print(symbol))
|
||
|
mrow.appendChild(brac)
|
||
|
return mrow
|
||
|
|
||
|
_print_Min = _print_Max = _hprint_variadic_function
|
||
|
|
||
|
def _print_exp(self, expr):
|
||
|
msup = self.dom.createElement('msup')
|
||
|
msup.appendChild(self._print_Exp1(None))
|
||
|
msup.appendChild(self._print(expr.args[0]))
|
||
|
return msup
|
||
|
|
||
|
def _print_Relational(self, e):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
mrow.appendChild(self._print(e.lhs))
|
||
|
x = self.dom.createElement('mo')
|
||
|
x.appendChild(self.dom.createTextNode(self.mathml_tag(e)))
|
||
|
mrow.appendChild(x)
|
||
|
mrow.appendChild(self._print(e.rhs))
|
||
|
return mrow
|
||
|
|
||
|
def _print_int(self, p):
|
||
|
dom_element = self.dom.createElement(self.mathml_tag(p))
|
||
|
dom_element.appendChild(self.dom.createTextNode(str(p)))
|
||
|
return dom_element
|
||
|
|
||
|
def _print_BaseScalar(self, e):
|
||
|
msub = self.dom.createElement('msub')
|
||
|
index, system = e._id
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.setAttribute('mathvariant', 'bold')
|
||
|
mi.appendChild(self.dom.createTextNode(system._variable_names[index]))
|
||
|
msub.appendChild(mi)
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.setAttribute('mathvariant', 'bold')
|
||
|
mi.appendChild(self.dom.createTextNode(system._name))
|
||
|
msub.appendChild(mi)
|
||
|
return msub
|
||
|
|
||
|
def _print_BaseVector(self, e):
|
||
|
msub = self.dom.createElement('msub')
|
||
|
index, system = e._id
|
||
|
mover = self.dom.createElement('mover')
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.setAttribute('mathvariant', 'bold')
|
||
|
mi.appendChild(self.dom.createTextNode(system._vector_names[index]))
|
||
|
mover.appendChild(mi)
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('^'))
|
||
|
mover.appendChild(mo)
|
||
|
msub.appendChild(mover)
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.setAttribute('mathvariant', 'bold')
|
||
|
mi.appendChild(self.dom.createTextNode(system._name))
|
||
|
msub.appendChild(mi)
|
||
|
return msub
|
||
|
|
||
|
def _print_VectorZero(self, e):
|
||
|
mover = self.dom.createElement('mover')
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.setAttribute('mathvariant', 'bold')
|
||
|
mi.appendChild(self.dom.createTextNode("0"))
|
||
|
mover.appendChild(mi)
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('^'))
|
||
|
mover.appendChild(mo)
|
||
|
return mover
|
||
|
|
||
|
def _print_Cross(self, expr):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
vec1 = expr._expr1
|
||
|
vec2 = expr._expr2
|
||
|
mrow.appendChild(self.parenthesize(vec1, PRECEDENCE['Mul']))
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('×'))
|
||
|
mrow.appendChild(mo)
|
||
|
mrow.appendChild(self.parenthesize(vec2, PRECEDENCE['Mul']))
|
||
|
return mrow
|
||
|
|
||
|
def _print_Curl(self, expr):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('∇'))
|
||
|
mrow.appendChild(mo)
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('×'))
|
||
|
mrow.appendChild(mo)
|
||
|
mrow.appendChild(self.parenthesize(expr._expr, PRECEDENCE['Mul']))
|
||
|
return mrow
|
||
|
|
||
|
def _print_Divergence(self, expr):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('∇'))
|
||
|
mrow.appendChild(mo)
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('·'))
|
||
|
mrow.appendChild(mo)
|
||
|
mrow.appendChild(self.parenthesize(expr._expr, PRECEDENCE['Mul']))
|
||
|
return mrow
|
||
|
|
||
|
def _print_Dot(self, expr):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
vec1 = expr._expr1
|
||
|
vec2 = expr._expr2
|
||
|
mrow.appendChild(self.parenthesize(vec1, PRECEDENCE['Mul']))
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('·'))
|
||
|
mrow.appendChild(mo)
|
||
|
mrow.appendChild(self.parenthesize(vec2, PRECEDENCE['Mul']))
|
||
|
return mrow
|
||
|
|
||
|
def _print_Gradient(self, expr):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('∇'))
|
||
|
mrow.appendChild(mo)
|
||
|
mrow.appendChild(self.parenthesize(expr._expr, PRECEDENCE['Mul']))
|
||
|
return mrow
|
||
|
|
||
|
def _print_Laplacian(self, expr):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('∆'))
|
||
|
mrow.appendChild(mo)
|
||
|
mrow.appendChild(self.parenthesize(expr._expr, PRECEDENCE['Mul']))
|
||
|
return mrow
|
||
|
|
||
|
def _print_Integers(self, e):
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.setAttribute('mathvariant', 'normal')
|
||
|
x.appendChild(self.dom.createTextNode('ℤ'))
|
||
|
return x
|
||
|
|
||
|
def _print_Complexes(self, e):
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.setAttribute('mathvariant', 'normal')
|
||
|
x.appendChild(self.dom.createTextNode('ℂ'))
|
||
|
return x
|
||
|
|
||
|
def _print_Reals(self, e):
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.setAttribute('mathvariant', 'normal')
|
||
|
x.appendChild(self.dom.createTextNode('ℝ'))
|
||
|
return x
|
||
|
|
||
|
def _print_Naturals(self, e):
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.setAttribute('mathvariant', 'normal')
|
||
|
x.appendChild(self.dom.createTextNode('ℕ'))
|
||
|
return x
|
||
|
|
||
|
def _print_Naturals0(self, e):
|
||
|
sub = self.dom.createElement('msub')
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.setAttribute('mathvariant', 'normal')
|
||
|
x.appendChild(self.dom.createTextNode('ℕ'))
|
||
|
sub.appendChild(x)
|
||
|
sub.appendChild(self._print(S.Zero))
|
||
|
return sub
|
||
|
|
||
|
def _print_SingularityFunction(self, expr):
|
||
|
shift = expr.args[0] - expr.args[1]
|
||
|
power = expr.args[2]
|
||
|
sup = self.dom.createElement('msup')
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
brac.setAttribute('close', '\u27e9')
|
||
|
brac.setAttribute('open', '\u27e8')
|
||
|
brac.appendChild(self._print(shift))
|
||
|
sup.appendChild(brac)
|
||
|
sup.appendChild(self._print(power))
|
||
|
return sup
|
||
|
|
||
|
def _print_NaN(self, e):
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.appendChild(self.dom.createTextNode('NaN'))
|
||
|
return x
|
||
|
|
||
|
def _print_number_function(self, e, name):
|
||
|
# Print name_arg[0] for one argument or name_arg[0](arg[1])
|
||
|
# for more than one argument
|
||
|
sub = self.dom.createElement('msub')
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.appendChild(self.dom.createTextNode(name))
|
||
|
sub.appendChild(mi)
|
||
|
sub.appendChild(self._print(e.args[0]))
|
||
|
if len(e.args) == 1:
|
||
|
return sub
|
||
|
# TODO: copy-pasted from _print_Function: can we do better?
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
y = self.dom.createElement('mfenced')
|
||
|
for arg in e.args[1:]:
|
||
|
y.appendChild(self._print(arg))
|
||
|
mrow.appendChild(sub)
|
||
|
mrow.appendChild(y)
|
||
|
return mrow
|
||
|
|
||
|
def _print_bernoulli(self, e):
|
||
|
return self._print_number_function(e, 'B')
|
||
|
|
||
|
_print_bell = _print_bernoulli
|
||
|
|
||
|
def _print_catalan(self, e):
|
||
|
return self._print_number_function(e, 'C')
|
||
|
|
||
|
def _print_euler(self, e):
|
||
|
return self._print_number_function(e, 'E')
|
||
|
|
||
|
def _print_fibonacci(self, e):
|
||
|
return self._print_number_function(e, 'F')
|
||
|
|
||
|
def _print_lucas(self, e):
|
||
|
return self._print_number_function(e, 'L')
|
||
|
|
||
|
def _print_stieltjes(self, e):
|
||
|
return self._print_number_function(e, 'γ')
|
||
|
|
||
|
def _print_tribonacci(self, e):
|
||
|
return self._print_number_function(e, 'T')
|
||
|
|
||
|
def _print_ComplexInfinity(self, e):
|
||
|
x = self.dom.createElement('mover')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('∞'))
|
||
|
x.appendChild(mo)
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('~'))
|
||
|
x.appendChild(mo)
|
||
|
return x
|
||
|
|
||
|
def _print_EmptySet(self, e):
|
||
|
x = self.dom.createElement('mo')
|
||
|
x.appendChild(self.dom.createTextNode('∅'))
|
||
|
return x
|
||
|
|
||
|
def _print_UniversalSet(self, e):
|
||
|
x = self.dom.createElement('mo')
|
||
|
x.appendChild(self.dom.createTextNode('𝕌'))
|
||
|
return x
|
||
|
|
||
|
def _print_Adjoint(self, expr):
|
||
|
from sympy.matrices import MatrixSymbol
|
||
|
mat = expr.arg
|
||
|
sup = self.dom.createElement('msup')
|
||
|
if not isinstance(mat, MatrixSymbol):
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
brac.appendChild(self._print(mat))
|
||
|
sup.appendChild(brac)
|
||
|
else:
|
||
|
sup.appendChild(self._print(mat))
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('†'))
|
||
|
sup.appendChild(mo)
|
||
|
return sup
|
||
|
|
||
|
def _print_Transpose(self, expr):
|
||
|
from sympy.matrices import MatrixSymbol
|
||
|
mat = expr.arg
|
||
|
sup = self.dom.createElement('msup')
|
||
|
if not isinstance(mat, MatrixSymbol):
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
brac.appendChild(self._print(mat))
|
||
|
sup.appendChild(brac)
|
||
|
else:
|
||
|
sup.appendChild(self._print(mat))
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('T'))
|
||
|
sup.appendChild(mo)
|
||
|
return sup
|
||
|
|
||
|
def _print_Inverse(self, expr):
|
||
|
from sympy.matrices import MatrixSymbol
|
||
|
mat = expr.arg
|
||
|
sup = self.dom.createElement('msup')
|
||
|
if not isinstance(mat, MatrixSymbol):
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
brac.appendChild(self._print(mat))
|
||
|
sup.appendChild(brac)
|
||
|
else:
|
||
|
sup.appendChild(self._print(mat))
|
||
|
sup.appendChild(self._print(-1))
|
||
|
return sup
|
||
|
|
||
|
def _print_MatMul(self, expr):
|
||
|
from sympy.matrices.expressions.matmul import MatMul
|
||
|
|
||
|
x = self.dom.createElement('mrow')
|
||
|
args = expr.args
|
||
|
if isinstance(args[0], Mul):
|
||
|
args = args[0].as_ordered_factors() + list(args[1:])
|
||
|
else:
|
||
|
args = list(args)
|
||
|
|
||
|
if isinstance(expr, MatMul) and expr.could_extract_minus_sign():
|
||
|
if args[0] == -1:
|
||
|
args = args[1:]
|
||
|
else:
|
||
|
args[0] = -args[0]
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('-'))
|
||
|
x.appendChild(mo)
|
||
|
|
||
|
for arg in args[:-1]:
|
||
|
x.appendChild(self.parenthesize(arg, precedence_traditional(expr),
|
||
|
False))
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('⁢'))
|
||
|
x.appendChild(mo)
|
||
|
x.appendChild(self.parenthesize(args[-1], precedence_traditional(expr),
|
||
|
False))
|
||
|
return x
|
||
|
|
||
|
def _print_MatPow(self, expr):
|
||
|
from sympy.matrices import MatrixSymbol
|
||
|
base, exp = expr.base, expr.exp
|
||
|
sup = self.dom.createElement('msup')
|
||
|
if not isinstance(base, MatrixSymbol):
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
brac.appendChild(self._print(base))
|
||
|
sup.appendChild(brac)
|
||
|
else:
|
||
|
sup.appendChild(self._print(base))
|
||
|
sup.appendChild(self._print(exp))
|
||
|
return sup
|
||
|
|
||
|
def _print_HadamardProduct(self, expr):
|
||
|
x = self.dom.createElement('mrow')
|
||
|
args = expr.args
|
||
|
for arg in args[:-1]:
|
||
|
x.appendChild(
|
||
|
self.parenthesize(arg, precedence_traditional(expr), False))
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('∘'))
|
||
|
x.appendChild(mo)
|
||
|
x.appendChild(
|
||
|
self.parenthesize(args[-1], precedence_traditional(expr), False))
|
||
|
return x
|
||
|
|
||
|
def _print_ZeroMatrix(self, Z):
|
||
|
x = self.dom.createElement('mn')
|
||
|
x.appendChild(self.dom.createTextNode('𝟘'))
|
||
|
return x
|
||
|
|
||
|
def _print_OneMatrix(self, Z):
|
||
|
x = self.dom.createElement('mn')
|
||
|
x.appendChild(self.dom.createTextNode('𝟙'))
|
||
|
return x
|
||
|
|
||
|
def _print_Identity(self, I):
|
||
|
x = self.dom.createElement('mi')
|
||
|
x.appendChild(self.dom.createTextNode('𝕀'))
|
||
|
return x
|
||
|
|
||
|
def _print_floor(self, e):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
x = self.dom.createElement('mfenced')
|
||
|
x.setAttribute('close', '\u230B')
|
||
|
x.setAttribute('open', '\u230A')
|
||
|
x.appendChild(self._print(e.args[0]))
|
||
|
mrow.appendChild(x)
|
||
|
return mrow
|
||
|
|
||
|
def _print_ceiling(self, e):
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
x = self.dom.createElement('mfenced')
|
||
|
x.setAttribute('close', '\u2309')
|
||
|
x.setAttribute('open', '\u2308')
|
||
|
x.appendChild(self._print(e.args[0]))
|
||
|
mrow.appendChild(x)
|
||
|
return mrow
|
||
|
|
||
|
def _print_Lambda(self, e):
|
||
|
x = self.dom.createElement('mfenced')
|
||
|
mrow = self.dom.createElement('mrow')
|
||
|
symbols = e.args[0]
|
||
|
if len(symbols) == 1:
|
||
|
symbols = self._print(symbols[0])
|
||
|
else:
|
||
|
symbols = self._print(symbols)
|
||
|
mrow.appendChild(symbols)
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('↦'))
|
||
|
mrow.appendChild(mo)
|
||
|
mrow.appendChild(self._print(e.args[1]))
|
||
|
x.appendChild(mrow)
|
||
|
return x
|
||
|
|
||
|
def _print_tuple(self, e):
|
||
|
x = self.dom.createElement('mfenced')
|
||
|
for i in e:
|
||
|
x.appendChild(self._print(i))
|
||
|
return x
|
||
|
|
||
|
def _print_IndexedBase(self, e):
|
||
|
return self._print(e.label)
|
||
|
|
||
|
def _print_Indexed(self, e):
|
||
|
x = self.dom.createElement('msub')
|
||
|
x.appendChild(self._print(e.base))
|
||
|
if len(e.indices) == 1:
|
||
|
x.appendChild(self._print(e.indices[0]))
|
||
|
return x
|
||
|
x.appendChild(self._print(e.indices))
|
||
|
return x
|
||
|
|
||
|
def _print_MatrixElement(self, e):
|
||
|
x = self.dom.createElement('msub')
|
||
|
x.appendChild(self.parenthesize(e.parent, PRECEDENCE["Atom"], strict = True))
|
||
|
brac = self.dom.createElement('mfenced')
|
||
|
brac.setAttribute("close", "")
|
||
|
brac.setAttribute("open", "")
|
||
|
for i in e.indices:
|
||
|
brac.appendChild(self._print(i))
|
||
|
x.appendChild(brac)
|
||
|
return x
|
||
|
|
||
|
def _print_elliptic_f(self, e):
|
||
|
x = self.dom.createElement('mrow')
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.appendChild(self.dom.createTextNode('𝖥'))
|
||
|
x.appendChild(mi)
|
||
|
y = self.dom.createElement('mfenced')
|
||
|
y.setAttribute("separators", "|")
|
||
|
for i in e.args:
|
||
|
y.appendChild(self._print(i))
|
||
|
x.appendChild(y)
|
||
|
return x
|
||
|
|
||
|
def _print_elliptic_e(self, e):
|
||
|
x = self.dom.createElement('mrow')
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.appendChild(self.dom.createTextNode('𝖤'))
|
||
|
x.appendChild(mi)
|
||
|
y = self.dom.createElement('mfenced')
|
||
|
y.setAttribute("separators", "|")
|
||
|
for i in e.args:
|
||
|
y.appendChild(self._print(i))
|
||
|
x.appendChild(y)
|
||
|
return x
|
||
|
|
||
|
def _print_elliptic_pi(self, e):
|
||
|
x = self.dom.createElement('mrow')
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.appendChild(self.dom.createTextNode('𝛱'))
|
||
|
x.appendChild(mi)
|
||
|
y = self.dom.createElement('mfenced')
|
||
|
if len(e.args) == 2:
|
||
|
y.setAttribute("separators", "|")
|
||
|
else:
|
||
|
y.setAttribute("separators", ";|")
|
||
|
for i in e.args:
|
||
|
y.appendChild(self._print(i))
|
||
|
x.appendChild(y)
|
||
|
return x
|
||
|
|
||
|
def _print_Ei(self, e):
|
||
|
x = self.dom.createElement('mrow')
|
||
|
mi = self.dom.createElement('mi')
|
||
|
mi.appendChild(self.dom.createTextNode('Ei'))
|
||
|
x.appendChild(mi)
|
||
|
x.appendChild(self._print(e.args))
|
||
|
return x
|
||
|
|
||
|
def _print_expint(self, e):
|
||
|
x = self.dom.createElement('mrow')
|
||
|
y = self.dom.createElement('msub')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('E'))
|
||
|
y.appendChild(mo)
|
||
|
y.appendChild(self._print(e.args[0]))
|
||
|
x.appendChild(y)
|
||
|
x.appendChild(self._print(e.args[1:]))
|
||
|
return x
|
||
|
|
||
|
def _print_jacobi(self, e):
|
||
|
x = self.dom.createElement('mrow')
|
||
|
y = self.dom.createElement('msubsup')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('P'))
|
||
|
y.appendChild(mo)
|
||
|
y.appendChild(self._print(e.args[0]))
|
||
|
y.appendChild(self._print(e.args[1:3]))
|
||
|
x.appendChild(y)
|
||
|
x.appendChild(self._print(e.args[3:]))
|
||
|
return x
|
||
|
|
||
|
def _print_gegenbauer(self, e):
|
||
|
x = self.dom.createElement('mrow')
|
||
|
y = self.dom.createElement('msubsup')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('C'))
|
||
|
y.appendChild(mo)
|
||
|
y.appendChild(self._print(e.args[0]))
|
||
|
y.appendChild(self._print(e.args[1:2]))
|
||
|
x.appendChild(y)
|
||
|
x.appendChild(self._print(e.args[2:]))
|
||
|
return x
|
||
|
|
||
|
def _print_chebyshevt(self, e):
|
||
|
x = self.dom.createElement('mrow')
|
||
|
y = self.dom.createElement('msub')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('T'))
|
||
|
y.appendChild(mo)
|
||
|
y.appendChild(self._print(e.args[0]))
|
||
|
x.appendChild(y)
|
||
|
x.appendChild(self._print(e.args[1:]))
|
||
|
return x
|
||
|
|
||
|
def _print_chebyshevu(self, e):
|
||
|
x = self.dom.createElement('mrow')
|
||
|
y = self.dom.createElement('msub')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('U'))
|
||
|
y.appendChild(mo)
|
||
|
y.appendChild(self._print(e.args[0]))
|
||
|
x.appendChild(y)
|
||
|
x.appendChild(self._print(e.args[1:]))
|
||
|
return x
|
||
|
|
||
|
def _print_legendre(self, e):
|
||
|
x = self.dom.createElement('mrow')
|
||
|
y = self.dom.createElement('msub')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('P'))
|
||
|
y.appendChild(mo)
|
||
|
y.appendChild(self._print(e.args[0]))
|
||
|
x.appendChild(y)
|
||
|
x.appendChild(self._print(e.args[1:]))
|
||
|
return x
|
||
|
|
||
|
def _print_assoc_legendre(self, e):
|
||
|
x = self.dom.createElement('mrow')
|
||
|
y = self.dom.createElement('msubsup')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('P'))
|
||
|
y.appendChild(mo)
|
||
|
y.appendChild(self._print(e.args[0]))
|
||
|
y.appendChild(self._print(e.args[1:2]))
|
||
|
x.appendChild(y)
|
||
|
x.appendChild(self._print(e.args[2:]))
|
||
|
return x
|
||
|
|
||
|
def _print_laguerre(self, e):
|
||
|
x = self.dom.createElement('mrow')
|
||
|
y = self.dom.createElement('msub')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('L'))
|
||
|
y.appendChild(mo)
|
||
|
y.appendChild(self._print(e.args[0]))
|
||
|
x.appendChild(y)
|
||
|
x.appendChild(self._print(e.args[1:]))
|
||
|
return x
|
||
|
|
||
|
def _print_assoc_laguerre(self, e):
|
||
|
x = self.dom.createElement('mrow')
|
||
|
y = self.dom.createElement('msubsup')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('L'))
|
||
|
y.appendChild(mo)
|
||
|
y.appendChild(self._print(e.args[0]))
|
||
|
y.appendChild(self._print(e.args[1:2]))
|
||
|
x.appendChild(y)
|
||
|
x.appendChild(self._print(e.args[2:]))
|
||
|
return x
|
||
|
|
||
|
def _print_hermite(self, e):
|
||
|
x = self.dom.createElement('mrow')
|
||
|
y = self.dom.createElement('msub')
|
||
|
mo = self.dom.createElement('mo')
|
||
|
mo.appendChild(self.dom.createTextNode('H'))
|
||
|
y.appendChild(mo)
|
||
|
y.appendChild(self._print(e.args[0]))
|
||
|
x.appendChild(y)
|
||
|
x.appendChild(self._print(e.args[1:]))
|
||
|
return x
|
||
|
|
||
|
|
||
|
@print_function(MathMLPrinterBase)
|
||
|
def mathml(expr, printer='content', **settings):
|
||
|
"""Returns the MathML representation of expr. If printer is presentation
|
||
|
then prints Presentation MathML else prints content MathML.
|
||
|
"""
|
||
|
if printer == 'presentation':
|
||
|
return MathMLPresentationPrinter(settings).doprint(expr)
|
||
|
else:
|
||
|
return MathMLContentPrinter(settings).doprint(expr)
|
||
|
|
||
|
|
||
|
def print_mathml(expr, printer='content', **settings):
|
||
|
"""
|
||
|
Prints a pretty representation of the MathML code for expr. If printer is
|
||
|
presentation then prints Presentation MathML else prints content MathML.
|
||
|
|
||
|
Examples
|
||
|
========
|
||
|
|
||
|
>>> ##
|
||
|
>>> from sympy import print_mathml
|
||
|
>>> from sympy.abc import x
|
||
|
>>> print_mathml(x+1) #doctest: +NORMALIZE_WHITESPACE
|
||
|
<apply>
|
||
|
<plus/>
|
||
|
<ci>x</ci>
|
||
|
<cn>1</cn>
|
||
|
</apply>
|
||
|
>>> print_mathml(x+1, printer='presentation')
|
||
|
<mrow>
|
||
|
<mi>x</mi>
|
||
|
<mo>+</mo>
|
||
|
<mn>1</mn>
|
||
|
</mrow>
|
||
|
|
||
|
"""
|
||
|
if printer == 'presentation':
|
||
|
s = MathMLPresentationPrinter(settings)
|
||
|
else:
|
||
|
s = MathMLContentPrinter(settings)
|
||
|
xml = s._print(sympify(expr))
|
||
|
s.apply_patch()
|
||
|
pretty_xml = xml.toprettyxml()
|
||
|
s.restore_patch()
|
||
|
|
||
|
print(pretty_xml)
|
||
|
|
||
|
|
||
|
# For backward compatibility
|
||
|
MathMLPrinter = MathMLContentPrinter
|