Spaces:
Sleeping
Sleeping
""" | |
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 | |
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 | |
def _print_Lambda(self, e): | |
# MathML reference for the lambda element: | |
# https://www.w3.org/TR/MathML2/chapter4.html#id.4.2.1.7 | |
x = self.dom.createElement(self.mathml_tag(e)) | |
for arg in e.signature: | |
x_1 = self.dom.createElement('bvar') | |
x_1.appendChild(self._print(arg)) | |
x.appendChild(x_1) | |
x.appendChild(self._print(e.expr)) | |
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′', | |
'Lambda': 'lambda', | |
} | |
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 | |
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)) | |
pretty_xml = xml.toprettyxml() | |
print(pretty_xml) | |
# For backward compatibility | |
MathMLPrinter = MathMLContentPrinter | |