Coverage for /usr/lib/python3/dist-packages/sympy/printing/mathml.py: 12%
1577 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1"""
2A MathML printer.
3"""
5from __future__ import annotations
6from typing import Any
8from sympy.core.mul import Mul
9from sympy.core.singleton import S
10from sympy.core.sorting import default_sort_key
11from sympy.core.sympify import sympify
12from sympy.printing.conventions import split_super_sub, requires_partial
13from sympy.printing.precedence import \
14 precedence_traditional, PRECEDENCE, PRECEDENCE_TRADITIONAL
15from sympy.printing.pretty.pretty_symbology import greek_unicode
16from sympy.printing.printer import Printer, print_function
18from mpmath.libmp import prec_to_dps, repr_dps, to_str as mlib_to_str
21class MathMLPrinterBase(Printer):
22 """Contains common code required for MathMLContentPrinter and
23 MathMLPresentationPrinter.
24 """
26 _default_settings: dict[str, Any] = {
27 "order": None,
28 "encoding": "utf-8",
29 "fold_frac_powers": False,
30 "fold_func_brackets": False,
31 "fold_short_frac": None,
32 "inv_trig_style": "abbreviated",
33 "ln_notation": False,
34 "long_frac_ratio": None,
35 "mat_delim": "[",
36 "mat_symbol_style": "plain",
37 "mul_symbol": None,
38 "root_notation": True,
39 "symbol_names": {},
40 "mul_symbol_mathml_numbers": '·',
41 }
43 def __init__(self, settings=None):
44 Printer.__init__(self, settings)
45 from xml.dom.minidom import Document, Text
47 self.dom = Document()
49 # Workaround to allow strings to remain unescaped
50 # Based on
51 # https://stackoverflow.com/questions/38015864/python-xml-dom-minidom-\
52 # please-dont-escape-my-strings/38041194
53 class RawText(Text):
54 def writexml(self, writer, indent='', addindent='', newl=''):
55 if self.data:
56 writer.write('{}{}{}'.format(indent, self.data, newl))
58 def createRawTextNode(data):
59 r = RawText()
60 r.data = data
61 r.ownerDocument = self.dom
62 return r
64 self.dom.createTextNode = createRawTextNode
66 def doprint(self, expr):
67 """
68 Prints the expression as MathML.
69 """
70 mathML = Printer._print(self, expr)
71 unistr = mathML.toxml()
72 xmlbstr = unistr.encode('ascii', 'xmlcharrefreplace')
73 res = xmlbstr.decode()
74 return res
76 def apply_patch(self):
77 # Applying the patch of xml.dom.minidom bug
78 # Date: 2011-11-18
79 # Description: http://ronrothman.com/public/leftbraned/xml-dom-minidom\
80 # -toprettyxml-and-silly-whitespace/#best-solution
81 # Issue: https://bugs.python.org/issue4147
82 # Patch: https://hg.python.org/cpython/rev/7262f8f276ff/
84 from xml.dom.minidom import Element, Text, Node, _write_data
86 def writexml(self, writer, indent="", addindent="", newl=""):
87 # indent = current indentation
88 # addindent = indentation to add to higher levels
89 # newl = newline string
90 writer.write(indent + "<" + self.tagName)
92 attrs = self._get_attributes()
93 a_names = list(attrs.keys())
94 a_names.sort()
96 for a_name in a_names:
97 writer.write(" %s=\"" % a_name)
98 _write_data(writer, attrs[a_name].value)
99 writer.write("\"")
100 if self.childNodes:
101 writer.write(">")
102 if (len(self.childNodes) == 1 and
103 self.childNodes[0].nodeType == Node.TEXT_NODE):
104 self.childNodes[0].writexml(writer, '', '', '')
105 else:
106 writer.write(newl)
107 for node in self.childNodes:
108 node.writexml(
109 writer, indent + addindent, addindent, newl)
110 writer.write(indent)
111 writer.write("</%s>%s" % (self.tagName, newl))
112 else:
113 writer.write("/>%s" % (newl))
114 self._Element_writexml_old = Element.writexml
115 Element.writexml = writexml
117 def writexml(self, writer, indent="", addindent="", newl=""):
118 _write_data(writer, "%s%s%s" % (indent, self.data, newl))
119 self._Text_writexml_old = Text.writexml
120 Text.writexml = writexml
122 def restore_patch(self):
123 from xml.dom.minidom import Element, Text
124 Element.writexml = self._Element_writexml_old
125 Text.writexml = self._Text_writexml_old
128class MathMLContentPrinter(MathMLPrinterBase):
129 """Prints an expression to the Content MathML markup language.
131 References: https://www.w3.org/TR/MathML2/chapter4.html
132 """
133 printmethod = "_mathml_content"
135 def mathml_tag(self, e):
136 """Returns the MathML tag for an expression."""
137 translate = {
138 'Add': 'plus',
139 'Mul': 'times',
140 'Derivative': 'diff',
141 'Number': 'cn',
142 'int': 'cn',
143 'Pow': 'power',
144 'Max': 'max',
145 'Min': 'min',
146 'Abs': 'abs',
147 'And': 'and',
148 'Or': 'or',
149 'Xor': 'xor',
150 'Not': 'not',
151 'Implies': 'implies',
152 'Symbol': 'ci',
153 'MatrixSymbol': 'ci',
154 'RandomSymbol': 'ci',
155 'Integral': 'int',
156 'Sum': 'sum',
157 'sin': 'sin',
158 'cos': 'cos',
159 'tan': 'tan',
160 'cot': 'cot',
161 'csc': 'csc',
162 'sec': 'sec',
163 'sinh': 'sinh',
164 'cosh': 'cosh',
165 'tanh': 'tanh',
166 'coth': 'coth',
167 'csch': 'csch',
168 'sech': 'sech',
169 'asin': 'arcsin',
170 'asinh': 'arcsinh',
171 'acos': 'arccos',
172 'acosh': 'arccosh',
173 'atan': 'arctan',
174 'atanh': 'arctanh',
175 'atan2': 'arctan',
176 'acot': 'arccot',
177 'acoth': 'arccoth',
178 'asec': 'arcsec',
179 'asech': 'arcsech',
180 'acsc': 'arccsc',
181 'acsch': 'arccsch',
182 'log': 'ln',
183 'Equality': 'eq',
184 'Unequality': 'neq',
185 'GreaterThan': 'geq',
186 'LessThan': 'leq',
187 'StrictGreaterThan': 'gt',
188 'StrictLessThan': 'lt',
189 'Union': 'union',
190 'Intersection': 'intersect',
191 }
193 for cls in e.__class__.__mro__:
194 n = cls.__name__
195 if n in translate:
196 return translate[n]
197 # Not found in the MRO set
198 n = e.__class__.__name__
199 return n.lower()
201 def _print_Mul(self, expr):
203 if expr.could_extract_minus_sign():
204 x = self.dom.createElement('apply')
205 x.appendChild(self.dom.createElement('minus'))
206 x.appendChild(self._print_Mul(-expr))
207 return x
209 from sympy.simplify import fraction
210 numer, denom = fraction(expr)
212 if denom is not S.One:
213 x = self.dom.createElement('apply')
214 x.appendChild(self.dom.createElement('divide'))
215 x.appendChild(self._print(numer))
216 x.appendChild(self._print(denom))
217 return x
219 coeff, terms = expr.as_coeff_mul()
220 if coeff is S.One and len(terms) == 1:
221 # XXX since the negative coefficient has been handled, I don't
222 # think a coeff of 1 can remain
223 return self._print(terms[0])
225 if self.order != 'old':
226 terms = Mul._from_args(terms).as_ordered_factors()
228 x = self.dom.createElement('apply')
229 x.appendChild(self.dom.createElement('times'))
230 if coeff != 1:
231 x.appendChild(self._print(coeff))
232 for term in terms:
233 x.appendChild(self._print(term))
234 return x
236 def _print_Add(self, expr, order=None):
237 args = self._as_ordered_terms(expr, order=order)
238 lastProcessed = self._print(args[0])
239 plusNodes = []
240 for arg in args[1:]:
241 if arg.could_extract_minus_sign():
242 # use minus
243 x = self.dom.createElement('apply')
244 x.appendChild(self.dom.createElement('minus'))
245 x.appendChild(lastProcessed)
246 x.appendChild(self._print(-arg))
247 # invert expression since this is now minused
248 lastProcessed = x
249 if arg == args[-1]:
250 plusNodes.append(lastProcessed)
251 else:
252 plusNodes.append(lastProcessed)
253 lastProcessed = self._print(arg)
254 if arg == args[-1]:
255 plusNodes.append(self._print(arg))
256 if len(plusNodes) == 1:
257 return lastProcessed
258 x = self.dom.createElement('apply')
259 x.appendChild(self.dom.createElement('plus'))
260 while plusNodes:
261 x.appendChild(plusNodes.pop(0))
262 return x
264 def _print_Piecewise(self, expr):
265 if expr.args[-1].cond != True:
266 # We need the last conditional to be a True, otherwise the resulting
267 # function may not return a result.
268 raise ValueError("All Piecewise expressions must contain an "
269 "(expr, True) statement to be used as a default "
270 "condition. Without one, the generated "
271 "expression may not evaluate to anything under "
272 "some condition.")
273 root = self.dom.createElement('piecewise')
274 for i, (e, c) in enumerate(expr.args):
275 if i == len(expr.args) - 1 and c == True:
276 piece = self.dom.createElement('otherwise')
277 piece.appendChild(self._print(e))
278 else:
279 piece = self.dom.createElement('piece')
280 piece.appendChild(self._print(e))
281 piece.appendChild(self._print(c))
282 root.appendChild(piece)
283 return root
285 def _print_MatrixBase(self, m):
286 x = self.dom.createElement('matrix')
287 for i in range(m.rows):
288 x_r = self.dom.createElement('matrixrow')
289 for j in range(m.cols):
290 x_r.appendChild(self._print(m[i, j]))
291 x.appendChild(x_r)
292 return x
294 def _print_Rational(self, e):
295 if e.q == 1:
296 # don't divide
297 x = self.dom.createElement('cn')
298 x.appendChild(self.dom.createTextNode(str(e.p)))
299 return x
300 x = self.dom.createElement('apply')
301 x.appendChild(self.dom.createElement('divide'))
302 # numerator
303 xnum = self.dom.createElement('cn')
304 xnum.appendChild(self.dom.createTextNode(str(e.p)))
305 # denominator
306 xdenom = self.dom.createElement('cn')
307 xdenom.appendChild(self.dom.createTextNode(str(e.q)))
308 x.appendChild(xnum)
309 x.appendChild(xdenom)
310 return x
312 def _print_Limit(self, e):
313 x = self.dom.createElement('apply')
314 x.appendChild(self.dom.createElement(self.mathml_tag(e)))
316 x_1 = self.dom.createElement('bvar')
317 x_2 = self.dom.createElement('lowlimit')
318 x_1.appendChild(self._print(e.args[1]))
319 x_2.appendChild(self._print(e.args[2]))
321 x.appendChild(x_1)
322 x.appendChild(x_2)
323 x.appendChild(self._print(e.args[0]))
324 return x
326 def _print_ImaginaryUnit(self, e):
327 return self.dom.createElement('imaginaryi')
329 def _print_EulerGamma(self, e):
330 return self.dom.createElement('eulergamma')
332 def _print_GoldenRatio(self, e):
333 """We use unicode #x3c6 for Greek letter phi as defined here
334 https://www.w3.org/2003/entities/2007doc/isogrk1.html"""
335 x = self.dom.createElement('cn')
336 x.appendChild(self.dom.createTextNode("\N{GREEK SMALL LETTER PHI}"))
337 return x
339 def _print_Exp1(self, e):
340 return self.dom.createElement('exponentiale')
342 def _print_Pi(self, e):
343 return self.dom.createElement('pi')
345 def _print_Infinity(self, e):
346 return self.dom.createElement('infinity')
348 def _print_NaN(self, e):
349 return self.dom.createElement('notanumber')
351 def _print_EmptySet(self, e):
352 return self.dom.createElement('emptyset')
354 def _print_BooleanTrue(self, e):
355 return self.dom.createElement('true')
357 def _print_BooleanFalse(self, e):
358 return self.dom.createElement('false')
360 def _print_NegativeInfinity(self, e):
361 x = self.dom.createElement('apply')
362 x.appendChild(self.dom.createElement('minus'))
363 x.appendChild(self.dom.createElement('infinity'))
364 return x
366 def _print_Integral(self, e):
367 def lime_recur(limits):
368 x = self.dom.createElement('apply')
369 x.appendChild(self.dom.createElement(self.mathml_tag(e)))
370 bvar_elem = self.dom.createElement('bvar')
371 bvar_elem.appendChild(self._print(limits[0][0]))
372 x.appendChild(bvar_elem)
374 if len(limits[0]) == 3:
375 low_elem = self.dom.createElement('lowlimit')
376 low_elem.appendChild(self._print(limits[0][1]))
377 x.appendChild(low_elem)
378 up_elem = self.dom.createElement('uplimit')
379 up_elem.appendChild(self._print(limits[0][2]))
380 x.appendChild(up_elem)
381 if len(limits[0]) == 2:
382 up_elem = self.dom.createElement('uplimit')
383 up_elem.appendChild(self._print(limits[0][1]))
384 x.appendChild(up_elem)
385 if len(limits) == 1:
386 x.appendChild(self._print(e.function))
387 else:
388 x.appendChild(lime_recur(limits[1:]))
389 return x
391 limits = list(e.limits)
392 limits.reverse()
393 return lime_recur(limits)
395 def _print_Sum(self, e):
396 # Printer can be shared because Sum and Integral have the
397 # same internal representation.
398 return self._print_Integral(e)
400 def _print_Symbol(self, sym):
401 ci = self.dom.createElement(self.mathml_tag(sym))
403 def join(items):
404 if len(items) > 1:
405 mrow = self.dom.createElement('mml:mrow')
406 for i, item in enumerate(items):
407 if i > 0:
408 mo = self.dom.createElement('mml:mo')
409 mo.appendChild(self.dom.createTextNode(" "))
410 mrow.appendChild(mo)
411 mi = self.dom.createElement('mml:mi')
412 mi.appendChild(self.dom.createTextNode(item))
413 mrow.appendChild(mi)
414 return mrow
415 else:
416 mi = self.dom.createElement('mml:mi')
417 mi.appendChild(self.dom.createTextNode(items[0]))
418 return mi
420 # translate name, supers and subs to unicode characters
421 def translate(s):
422 if s in greek_unicode:
423 return greek_unicode.get(s)
424 else:
425 return s
427 name, supers, subs = split_super_sub(sym.name)
428 name = translate(name)
429 supers = [translate(sup) for sup in supers]
430 subs = [translate(sub) for sub in subs]
432 mname = self.dom.createElement('mml:mi')
433 mname.appendChild(self.dom.createTextNode(name))
434 if not supers:
435 if not subs:
436 ci.appendChild(self.dom.createTextNode(name))
437 else:
438 msub = self.dom.createElement('mml:msub')
439 msub.appendChild(mname)
440 msub.appendChild(join(subs))
441 ci.appendChild(msub)
442 else:
443 if not subs:
444 msup = self.dom.createElement('mml:msup')
445 msup.appendChild(mname)
446 msup.appendChild(join(supers))
447 ci.appendChild(msup)
448 else:
449 msubsup = self.dom.createElement('mml:msubsup')
450 msubsup.appendChild(mname)
451 msubsup.appendChild(join(subs))
452 msubsup.appendChild(join(supers))
453 ci.appendChild(msubsup)
454 return ci
456 _print_MatrixSymbol = _print_Symbol
457 _print_RandomSymbol = _print_Symbol
459 def _print_Pow(self, e):
460 # Here we use root instead of power if the exponent is the reciprocal
461 # of an integer
462 if (self._settings['root_notation'] and e.exp.is_Rational
463 and e.exp.p == 1):
464 x = self.dom.createElement('apply')
465 x.appendChild(self.dom.createElement('root'))
466 if e.exp.q != 2:
467 xmldeg = self.dom.createElement('degree')
468 xmlcn = self.dom.createElement('cn')
469 xmlcn.appendChild(self.dom.createTextNode(str(e.exp.q)))
470 xmldeg.appendChild(xmlcn)
471 x.appendChild(xmldeg)
472 x.appendChild(self._print(e.base))
473 return x
475 x = self.dom.createElement('apply')
476 x_1 = self.dom.createElement(self.mathml_tag(e))
477 x.appendChild(x_1)
478 x.appendChild(self._print(e.base))
479 x.appendChild(self._print(e.exp))
480 return x
482 def _print_Number(self, e):
483 x = self.dom.createElement(self.mathml_tag(e))
484 x.appendChild(self.dom.createTextNode(str(e)))
485 return x
487 def _print_Float(self, e):
488 x = self.dom.createElement(self.mathml_tag(e))
489 repr_e = mlib_to_str(e._mpf_, repr_dps(e._prec))
490 x.appendChild(self.dom.createTextNode(repr_e))
491 return x
493 def _print_Derivative(self, e):
494 x = self.dom.createElement('apply')
495 diff_symbol = self.mathml_tag(e)
496 if requires_partial(e.expr):
497 diff_symbol = 'partialdiff'
498 x.appendChild(self.dom.createElement(diff_symbol))
499 x_1 = self.dom.createElement('bvar')
501 for sym, times in reversed(e.variable_count):
502 x_1.appendChild(self._print(sym))
503 if times > 1:
504 degree = self.dom.createElement('degree')
505 degree.appendChild(self._print(sympify(times)))
506 x_1.appendChild(degree)
508 x.appendChild(x_1)
509 x.appendChild(self._print(e.expr))
510 return x
512 def _print_Function(self, e):
513 x = self.dom.createElement("apply")
514 x.appendChild(self.dom.createElement(self.mathml_tag(e)))
515 for arg in e.args:
516 x.appendChild(self._print(arg))
517 return x
519 def _print_Basic(self, e):
520 x = self.dom.createElement(self.mathml_tag(e))
521 for arg in e.args:
522 x.appendChild(self._print(arg))
523 return x
525 def _print_AssocOp(self, e):
526 x = self.dom.createElement('apply')
527 x_1 = self.dom.createElement(self.mathml_tag(e))
528 x.appendChild(x_1)
529 for arg in e.args:
530 x.appendChild(self._print(arg))
531 return x
533 def _print_Relational(self, e):
534 x = self.dom.createElement('apply')
535 x.appendChild(self.dom.createElement(self.mathml_tag(e)))
536 x.appendChild(self._print(e.lhs))
537 x.appendChild(self._print(e.rhs))
538 return x
540 def _print_list(self, seq):
541 """MathML reference for the <list> element:
542 https://www.w3.org/TR/MathML2/chapter4.html#contm.list"""
543 dom_element = self.dom.createElement('list')
544 for item in seq:
545 dom_element.appendChild(self._print(item))
546 return dom_element
548 def _print_int(self, p):
549 dom_element = self.dom.createElement(self.mathml_tag(p))
550 dom_element.appendChild(self.dom.createTextNode(str(p)))
551 return dom_element
553 _print_Implies = _print_AssocOp
554 _print_Not = _print_AssocOp
555 _print_Xor = _print_AssocOp
557 def _print_FiniteSet(self, e):
558 x = self.dom.createElement('set')
559 for arg in e.args:
560 x.appendChild(self._print(arg))
561 return x
563 def _print_Complement(self, e):
564 x = self.dom.createElement('apply')
565 x.appendChild(self.dom.createElement('setdiff'))
566 for arg in e.args:
567 x.appendChild(self._print(arg))
568 return x
570 def _print_ProductSet(self, e):
571 x = self.dom.createElement('apply')
572 x.appendChild(self.dom.createElement('cartesianproduct'))
573 for arg in e.args:
574 x.appendChild(self._print(arg))
575 return x
577 # XXX Symmetric difference is not supported for MathML content printers.
580class MathMLPresentationPrinter(MathMLPrinterBase):
581 """Prints an expression to the Presentation MathML markup language.
583 References: https://www.w3.org/TR/MathML2/chapter3.html
584 """
585 printmethod = "_mathml_presentation"
587 def mathml_tag(self, e):
588 """Returns the MathML tag for an expression."""
589 translate = {
590 'Number': 'mn',
591 'Limit': '→',
592 'Derivative': 'ⅆ',
593 'int': 'mn',
594 'Symbol': 'mi',
595 'Integral': '∫',
596 'Sum': '∑',
597 'sin': 'sin',
598 'cos': 'cos',
599 'tan': 'tan',
600 'cot': 'cot',
601 'asin': 'arcsin',
602 'asinh': 'arcsinh',
603 'acos': 'arccos',
604 'acosh': 'arccosh',
605 'atan': 'arctan',
606 'atanh': 'arctanh',
607 'acot': 'arccot',
608 'atan2': 'arctan',
609 'Equality': '=',
610 'Unequality': '≠',
611 'GreaterThan': '≥',
612 'LessThan': '≤',
613 'StrictGreaterThan': '>',
614 'StrictLessThan': '<',
615 'lerchphi': 'Φ',
616 'zeta': 'ζ',
617 'dirichlet_eta': 'η',
618 'elliptic_k': 'Κ',
619 'lowergamma': 'γ',
620 'uppergamma': 'Γ',
621 'gamma': 'Γ',
622 'totient': 'ϕ',
623 'reduced_totient': 'λ',
624 'primenu': 'ν',
625 'primeomega': 'Ω',
626 'fresnels': 'S',
627 'fresnelc': 'C',
628 'LambertW': 'W',
629 'Heaviside': 'Θ',
630 'BooleanTrue': 'True',
631 'BooleanFalse': 'False',
632 'NoneType': 'None',
633 'mathieus': 'S',
634 'mathieuc': 'C',
635 'mathieusprime': 'S′',
636 'mathieucprime': 'C′',
637 }
639 def mul_symbol_selection():
640 if (self._settings["mul_symbol"] is None or
641 self._settings["mul_symbol"] == 'None'):
642 return '⁢'
643 elif self._settings["mul_symbol"] == 'times':
644 return '×'
645 elif self._settings["mul_symbol"] == 'dot':
646 return '·'
647 elif self._settings["mul_symbol"] == 'ldot':
648 return '․'
649 elif not isinstance(self._settings["mul_symbol"], str):
650 raise TypeError
651 else:
652 return self._settings["mul_symbol"]
653 for cls in e.__class__.__mro__:
654 n = cls.__name__
655 if n in translate:
656 return translate[n]
657 # Not found in the MRO set
658 if e.__class__.__name__ == "Mul":
659 return mul_symbol_selection()
660 n = e.__class__.__name__
661 return n.lower()
663 def parenthesize(self, item, level, strict=False):
664 prec_val = precedence_traditional(item)
665 if (prec_val < level) or ((not strict) and prec_val <= level):
666 brac = self.dom.createElement('mfenced')
667 brac.appendChild(self._print(item))
668 return brac
669 else:
670 return self._print(item)
672 def _print_Mul(self, expr):
674 def multiply(expr, mrow):
675 from sympy.simplify import fraction
676 numer, denom = fraction(expr)
677 if denom is not S.One:
678 frac = self.dom.createElement('mfrac')
679 if self._settings["fold_short_frac"] and len(str(expr)) < 7:
680 frac.setAttribute('bevelled', 'true')
681 xnum = self._print(numer)
682 xden = self._print(denom)
683 frac.appendChild(xnum)
684 frac.appendChild(xden)
685 mrow.appendChild(frac)
686 return mrow
688 coeff, terms = expr.as_coeff_mul()
689 if coeff is S.One and len(terms) == 1:
690 mrow.appendChild(self._print(terms[0]))
691 return mrow
692 if self.order != 'old':
693 terms = Mul._from_args(terms).as_ordered_factors()
695 if coeff != 1:
696 x = self._print(coeff)
697 y = self.dom.createElement('mo')
698 y.appendChild(self.dom.createTextNode(self.mathml_tag(expr)))
699 mrow.appendChild(x)
700 mrow.appendChild(y)
701 for term in terms:
702 mrow.appendChild(self.parenthesize(term, PRECEDENCE['Mul']))
703 if not term == terms[-1]:
704 y = self.dom.createElement('mo')
705 y.appendChild(self.dom.createTextNode(self.mathml_tag(expr)))
706 mrow.appendChild(y)
707 return mrow
708 mrow = self.dom.createElement('mrow')
709 if expr.could_extract_minus_sign():
710 x = self.dom.createElement('mo')
711 x.appendChild(self.dom.createTextNode('-'))
712 mrow.appendChild(x)
713 mrow = multiply(-expr, mrow)
714 else:
715 mrow = multiply(expr, mrow)
717 return mrow
719 def _print_Add(self, expr, order=None):
720 mrow = self.dom.createElement('mrow')
721 args = self._as_ordered_terms(expr, order=order)
722 mrow.appendChild(self._print(args[0]))
723 for arg in args[1:]:
724 if arg.could_extract_minus_sign():
725 # use minus
726 x = self.dom.createElement('mo')
727 x.appendChild(self.dom.createTextNode('-'))
728 y = self._print(-arg)
729 # invert expression since this is now minused
730 else:
731 x = self.dom.createElement('mo')
732 x.appendChild(self.dom.createTextNode('+'))
733 y = self._print(arg)
734 mrow.appendChild(x)
735 mrow.appendChild(y)
737 return mrow
739 def _print_MatrixBase(self, m):
740 table = self.dom.createElement('mtable')
741 for i in range(m.rows):
742 x = self.dom.createElement('mtr')
743 for j in range(m.cols):
744 y = self.dom.createElement('mtd')
745 y.appendChild(self._print(m[i, j]))
746 x.appendChild(y)
747 table.appendChild(x)
748 if self._settings["mat_delim"] == '':
749 return table
750 brac = self.dom.createElement('mfenced')
751 if self._settings["mat_delim"] == "[":
752 brac.setAttribute('close', ']')
753 brac.setAttribute('open', '[')
754 brac.appendChild(table)
755 return brac
757 def _get_printed_Rational(self, e, folded=None):
758 if e.p < 0:
759 p = -e.p
760 else:
761 p = e.p
762 x = self.dom.createElement('mfrac')
763 if folded or self._settings["fold_short_frac"]:
764 x.setAttribute('bevelled', 'true')
765 x.appendChild(self._print(p))
766 x.appendChild(self._print(e.q))
767 if e.p < 0:
768 mrow = self.dom.createElement('mrow')
769 mo = self.dom.createElement('mo')
770 mo.appendChild(self.dom.createTextNode('-'))
771 mrow.appendChild(mo)
772 mrow.appendChild(x)
773 return mrow
774 else:
775 return x
777 def _print_Rational(self, e):
778 if e.q == 1:
779 # don't divide
780 return self._print(e.p)
782 return self._get_printed_Rational(e, self._settings["fold_short_frac"])
784 def _print_Limit(self, e):
785 mrow = self.dom.createElement('mrow')
786 munder = self.dom.createElement('munder')
787 mi = self.dom.createElement('mi')
788 mi.appendChild(self.dom.createTextNode('lim'))
790 x = self.dom.createElement('mrow')
791 x_1 = self._print(e.args[1])
792 arrow = self.dom.createElement('mo')
793 arrow.appendChild(self.dom.createTextNode(self.mathml_tag(e)))
794 x_2 = self._print(e.args[2])
795 x.appendChild(x_1)
796 x.appendChild(arrow)
797 x.appendChild(x_2)
799 munder.appendChild(mi)
800 munder.appendChild(x)
801 mrow.appendChild(munder)
802 mrow.appendChild(self._print(e.args[0]))
804 return mrow
806 def _print_ImaginaryUnit(self, e):
807 x = self.dom.createElement('mi')
808 x.appendChild(self.dom.createTextNode('ⅈ'))
809 return x
811 def _print_GoldenRatio(self, e):
812 x = self.dom.createElement('mi')
813 x.appendChild(self.dom.createTextNode('Φ'))
814 return x
816 def _print_Exp1(self, e):
817 x = self.dom.createElement('mi')
818 x.appendChild(self.dom.createTextNode('ⅇ'))
819 return x
821 def _print_Pi(self, e):
822 x = self.dom.createElement('mi')
823 x.appendChild(self.dom.createTextNode('π'))
824 return x
826 def _print_Infinity(self, e):
827 x = self.dom.createElement('mi')
828 x.appendChild(self.dom.createTextNode('∞'))
829 return x
831 def _print_NegativeInfinity(self, e):
832 mrow = self.dom.createElement('mrow')
833 y = self.dom.createElement('mo')
834 y.appendChild(self.dom.createTextNode('-'))
835 x = self._print_Infinity(e)
836 mrow.appendChild(y)
837 mrow.appendChild(x)
838 return mrow
840 def _print_HBar(self, e):
841 x = self.dom.createElement('mi')
842 x.appendChild(self.dom.createTextNode('ℏ'))
843 return x
845 def _print_EulerGamma(self, e):
846 x = self.dom.createElement('mi')
847 x.appendChild(self.dom.createTextNode('γ'))
848 return x
850 def _print_TribonacciConstant(self, e):
851 x = self.dom.createElement('mi')
852 x.appendChild(self.dom.createTextNode('TribonacciConstant'))
853 return x
855 def _print_Dagger(self, e):
856 msup = self.dom.createElement('msup')
857 msup.appendChild(self._print(e.args[0]))
858 msup.appendChild(self.dom.createTextNode('†'))
859 return msup
861 def _print_Contains(self, e):
862 mrow = self.dom.createElement('mrow')
863 mrow.appendChild(self._print(e.args[0]))
864 mo = self.dom.createElement('mo')
865 mo.appendChild(self.dom.createTextNode('∈'))
866 mrow.appendChild(mo)
867 mrow.appendChild(self._print(e.args[1]))
868 return mrow
870 def _print_HilbertSpace(self, e):
871 x = self.dom.createElement('mi')
872 x.appendChild(self.dom.createTextNode('ℋ'))
873 return x
875 def _print_ComplexSpace(self, e):
876 msup = self.dom.createElement('msup')
877 msup.appendChild(self.dom.createTextNode('𝒞'))
878 msup.appendChild(self._print(e.args[0]))
879 return msup
881 def _print_FockSpace(self, e):
882 x = self.dom.createElement('mi')
883 x.appendChild(self.dom.createTextNode('ℱ'))
884 return x
887 def _print_Integral(self, expr):
888 intsymbols = {1: "∫", 2: "∬", 3: "∭"}
890 mrow = self.dom.createElement('mrow')
891 if len(expr.limits) <= 3 and all(len(lim) == 1 for lim in expr.limits):
892 # Only up to three-integral signs exists
893 mo = self.dom.createElement('mo')
894 mo.appendChild(self.dom.createTextNode(intsymbols[len(expr.limits)]))
895 mrow.appendChild(mo)
896 else:
897 # Either more than three or limits provided
898 for lim in reversed(expr.limits):
899 mo = self.dom.createElement('mo')
900 mo.appendChild(self.dom.createTextNode(intsymbols[1]))
901 if len(lim) == 1:
902 mrow.appendChild(mo)
903 if len(lim) == 2:
904 msup = self.dom.createElement('msup')
905 msup.appendChild(mo)
906 msup.appendChild(self._print(lim[1]))
907 mrow.appendChild(msup)
908 if len(lim) == 3:
909 msubsup = self.dom.createElement('msubsup')
910 msubsup.appendChild(mo)
911 msubsup.appendChild(self._print(lim[1]))
912 msubsup.appendChild(self._print(lim[2]))
913 mrow.appendChild(msubsup)
914 # print function
915 mrow.appendChild(self.parenthesize(expr.function, PRECEDENCE["Mul"],
916 strict=True))
917 # print integration variables
918 for lim in reversed(expr.limits):
919 d = self.dom.createElement('mo')
920 d.appendChild(self.dom.createTextNode('ⅆ'))
921 mrow.appendChild(d)
922 mrow.appendChild(self._print(lim[0]))
923 return mrow
925 def _print_Sum(self, e):
926 limits = list(e.limits)
927 subsup = self.dom.createElement('munderover')
928 low_elem = self._print(limits[0][1])
929 up_elem = self._print(limits[0][2])
930 summand = self.dom.createElement('mo')
931 summand.appendChild(self.dom.createTextNode(self.mathml_tag(e)))
933 low = self.dom.createElement('mrow')
934 var = self._print(limits[0][0])
935 equal = self.dom.createElement('mo')
936 equal.appendChild(self.dom.createTextNode('='))
937 low.appendChild(var)
938 low.appendChild(equal)
939 low.appendChild(low_elem)
941 subsup.appendChild(summand)
942 subsup.appendChild(low)
943 subsup.appendChild(up_elem)
945 mrow = self.dom.createElement('mrow')
946 mrow.appendChild(subsup)
947 if len(str(e.function)) == 1:
948 mrow.appendChild(self._print(e.function))
949 else:
950 fence = self.dom.createElement('mfenced')
951 fence.appendChild(self._print(e.function))
952 mrow.appendChild(fence)
954 return mrow
956 def _print_Symbol(self, sym, style='plain'):
957 def join(items):
958 if len(items) > 1:
959 mrow = self.dom.createElement('mrow')
960 for i, item in enumerate(items):
961 if i > 0:
962 mo = self.dom.createElement('mo')
963 mo.appendChild(self.dom.createTextNode(" "))
964 mrow.appendChild(mo)
965 mi = self.dom.createElement('mi')
966 mi.appendChild(self.dom.createTextNode(item))
967 mrow.appendChild(mi)
968 return mrow
969 else:
970 mi = self.dom.createElement('mi')
971 mi.appendChild(self.dom.createTextNode(items[0]))
972 return mi
974 # translate name, supers and subs to unicode characters
975 def translate(s):
976 if s in greek_unicode:
977 return greek_unicode.get(s)
978 else:
979 return s
981 name, supers, subs = split_super_sub(sym.name)
982 name = translate(name)
983 supers = [translate(sup) for sup in supers]
984 subs = [translate(sub) for sub in subs]
986 mname = self.dom.createElement('mi')
987 mname.appendChild(self.dom.createTextNode(name))
988 if len(supers) == 0:
989 if len(subs) == 0:
990 x = mname
991 else:
992 x = self.dom.createElement('msub')
993 x.appendChild(mname)
994 x.appendChild(join(subs))
995 else:
996 if len(subs) == 0:
997 x = self.dom.createElement('msup')
998 x.appendChild(mname)
999 x.appendChild(join(supers))
1000 else:
1001 x = self.dom.createElement('msubsup')
1002 x.appendChild(mname)
1003 x.appendChild(join(subs))
1004 x.appendChild(join(supers))
1005 # Set bold font?
1006 if style == 'bold':
1007 x.setAttribute('mathvariant', 'bold')
1008 return x
1010 def _print_MatrixSymbol(self, sym):
1011 return self._print_Symbol(sym,
1012 style=self._settings['mat_symbol_style'])
1014 _print_RandomSymbol = _print_Symbol
1016 def _print_conjugate(self, expr):
1017 enc = self.dom.createElement('menclose')
1018 enc.setAttribute('notation', 'top')
1019 enc.appendChild(self._print(expr.args[0]))
1020 return enc
1022 def _print_operator_after(self, op, expr):
1023 row = self.dom.createElement('mrow')
1024 row.appendChild(self.parenthesize(expr, PRECEDENCE["Func"]))
1025 mo = self.dom.createElement('mo')
1026 mo.appendChild(self.dom.createTextNode(op))
1027 row.appendChild(mo)
1028 return row
1030 def _print_factorial(self, expr):
1031 return self._print_operator_after('!', expr.args[0])
1033 def _print_factorial2(self, expr):
1034 return self._print_operator_after('!!', expr.args[0])
1036 def _print_binomial(self, expr):
1037 brac = self.dom.createElement('mfenced')
1038 frac = self.dom.createElement('mfrac')
1039 frac.setAttribute('linethickness', '0')
1040 frac.appendChild(self._print(expr.args[0]))
1041 frac.appendChild(self._print(expr.args[1]))
1042 brac.appendChild(frac)
1043 return brac
1045 def _print_Pow(self, e):
1046 # Here we use root instead of power if the exponent is the
1047 # reciprocal of an integer
1048 if (e.exp.is_Rational and abs(e.exp.p) == 1 and e.exp.q != 1 and
1049 self._settings['root_notation']):
1050 if e.exp.q == 2:
1051 x = self.dom.createElement('msqrt')
1052 x.appendChild(self._print(e.base))
1053 if e.exp.q != 2:
1054 x = self.dom.createElement('mroot')
1055 x.appendChild(self._print(e.base))
1056 x.appendChild(self._print(e.exp.q))
1057 if e.exp.p == -1:
1058 frac = self.dom.createElement('mfrac')
1059 frac.appendChild(self._print(1))
1060 frac.appendChild(x)
1061 return frac
1062 else:
1063 return x
1065 if e.exp.is_Rational and e.exp.q != 1:
1066 if e.exp.is_negative:
1067 top = self.dom.createElement('mfrac')
1068 top.appendChild(self._print(1))
1069 x = self.dom.createElement('msup')
1070 x.appendChild(self.parenthesize(e.base, PRECEDENCE['Pow']))
1071 x.appendChild(self._get_printed_Rational(-e.exp,
1072 self._settings['fold_frac_powers']))
1073 top.appendChild(x)
1074 return top
1075 else:
1076 x = self.dom.createElement('msup')
1077 x.appendChild(self.parenthesize(e.base, PRECEDENCE['Pow']))
1078 x.appendChild(self._get_printed_Rational(e.exp,
1079 self._settings['fold_frac_powers']))
1080 return x
1082 if e.exp.is_negative:
1083 top = self.dom.createElement('mfrac')
1084 top.appendChild(self._print(1))
1085 if e.exp == -1:
1086 top.appendChild(self._print(e.base))
1087 else:
1088 x = self.dom.createElement('msup')
1089 x.appendChild(self.parenthesize(e.base, PRECEDENCE['Pow']))
1090 x.appendChild(self._print(-e.exp))
1091 top.appendChild(x)
1092 return top
1094 x = self.dom.createElement('msup')
1095 x.appendChild(self.parenthesize(e.base, PRECEDENCE['Pow']))
1096 x.appendChild(self._print(e.exp))
1097 return x
1099 def _print_Number(self, e):
1100 x = self.dom.createElement(self.mathml_tag(e))
1101 x.appendChild(self.dom.createTextNode(str(e)))
1102 return x
1104 def _print_AccumulationBounds(self, i):
1105 brac = self.dom.createElement('mfenced')
1106 brac.setAttribute('close', '\u27e9')
1107 brac.setAttribute('open', '\u27e8')
1108 brac.appendChild(self._print(i.min))
1109 brac.appendChild(self._print(i.max))
1110 return brac
1112 def _print_Derivative(self, e):
1114 if requires_partial(e.expr):
1115 d = '∂'
1116 else:
1117 d = self.mathml_tag(e)
1119 # Determine denominator
1120 m = self.dom.createElement('mrow')
1121 dim = 0 # Total diff dimension, for numerator
1122 for sym, num in reversed(e.variable_count):
1123 dim += num
1124 if num >= 2:
1125 x = self.dom.createElement('msup')
1126 xx = self.dom.createElement('mo')
1127 xx.appendChild(self.dom.createTextNode(d))
1128 x.appendChild(xx)
1129 x.appendChild(self._print(num))
1130 else:
1131 x = self.dom.createElement('mo')
1132 x.appendChild(self.dom.createTextNode(d))
1133 m.appendChild(x)
1134 y = self._print(sym)
1135 m.appendChild(y)
1137 mnum = self.dom.createElement('mrow')
1138 if dim >= 2:
1139 x = self.dom.createElement('msup')
1140 xx = self.dom.createElement('mo')
1141 xx.appendChild(self.dom.createTextNode(d))
1142 x.appendChild(xx)
1143 x.appendChild(self._print(dim))
1144 else:
1145 x = self.dom.createElement('mo')
1146 x.appendChild(self.dom.createTextNode(d))
1148 mnum.appendChild(x)
1149 mrow = self.dom.createElement('mrow')
1150 frac = self.dom.createElement('mfrac')
1151 frac.appendChild(mnum)
1152 frac.appendChild(m)
1153 mrow.appendChild(frac)
1155 # Print function
1156 mrow.appendChild(self._print(e.expr))
1158 return mrow
1160 def _print_Function(self, e):
1161 mrow = self.dom.createElement('mrow')
1162 x = self.dom.createElement('mi')
1163 if self.mathml_tag(e) == 'log' and self._settings["ln_notation"]:
1164 x.appendChild(self.dom.createTextNode('ln'))
1165 else:
1166 x.appendChild(self.dom.createTextNode(self.mathml_tag(e)))
1167 y = self.dom.createElement('mfenced')
1168 for arg in e.args:
1169 y.appendChild(self._print(arg))
1170 mrow.appendChild(x)
1171 mrow.appendChild(y)
1172 return mrow
1174 def _print_Float(self, expr):
1175 # Based off of that in StrPrinter
1176 dps = prec_to_dps(expr._prec)
1177 str_real = mlib_to_str(expr._mpf_, dps, strip_zeros=True)
1179 # Must always have a mul symbol (as 2.5 10^{20} just looks odd)
1180 # thus we use the number separator
1181 separator = self._settings['mul_symbol_mathml_numbers']
1182 mrow = self.dom.createElement('mrow')
1183 if 'e' in str_real:
1184 (mant, exp) = str_real.split('e')
1186 if exp[0] == '+':
1187 exp = exp[1:]
1189 mn = self.dom.createElement('mn')
1190 mn.appendChild(self.dom.createTextNode(mant))
1191 mrow.appendChild(mn)
1192 mo = self.dom.createElement('mo')
1193 mo.appendChild(self.dom.createTextNode(separator))
1194 mrow.appendChild(mo)
1195 msup = self.dom.createElement('msup')
1196 mn = self.dom.createElement('mn')
1197 mn.appendChild(self.dom.createTextNode("10"))
1198 msup.appendChild(mn)
1199 mn = self.dom.createElement('mn')
1200 mn.appendChild(self.dom.createTextNode(exp))
1201 msup.appendChild(mn)
1202 mrow.appendChild(msup)
1203 return mrow
1204 elif str_real == "+inf":
1205 return self._print_Infinity(None)
1206 elif str_real == "-inf":
1207 return self._print_NegativeInfinity(None)
1208 else:
1209 mn = self.dom.createElement('mn')
1210 mn.appendChild(self.dom.createTextNode(str_real))
1211 return mn
1213 def _print_polylog(self, expr):
1214 mrow = self.dom.createElement('mrow')
1215 m = self.dom.createElement('msub')
1217 mi = self.dom.createElement('mi')
1218 mi.appendChild(self.dom.createTextNode('Li'))
1219 m.appendChild(mi)
1220 m.appendChild(self._print(expr.args[0]))
1221 mrow.appendChild(m)
1222 brac = self.dom.createElement('mfenced')
1223 brac.appendChild(self._print(expr.args[1]))
1224 mrow.appendChild(brac)
1225 return mrow
1227 def _print_Basic(self, e):
1228 mrow = self.dom.createElement('mrow')
1229 mi = self.dom.createElement('mi')
1230 mi.appendChild(self.dom.createTextNode(self.mathml_tag(e)))
1231 mrow.appendChild(mi)
1232 brac = self.dom.createElement('mfenced')
1233 for arg in e.args:
1234 brac.appendChild(self._print(arg))
1235 mrow.appendChild(brac)
1236 return mrow
1238 def _print_Tuple(self, e):
1239 mrow = self.dom.createElement('mrow')
1240 x = self.dom.createElement('mfenced')
1241 for arg in e.args:
1242 x.appendChild(self._print(arg))
1243 mrow.appendChild(x)
1244 return mrow
1246 def _print_Interval(self, i):
1247 mrow = self.dom.createElement('mrow')
1248 brac = self.dom.createElement('mfenced')
1249 if i.start == i.end:
1250 # Most often, this type of Interval is converted to a FiniteSet
1251 brac.setAttribute('close', '}')
1252 brac.setAttribute('open', '{')
1253 brac.appendChild(self._print(i.start))
1254 else:
1255 if i.right_open:
1256 brac.setAttribute('close', ')')
1257 else:
1258 brac.setAttribute('close', ']')
1260 if i.left_open:
1261 brac.setAttribute('open', '(')
1262 else:
1263 brac.setAttribute('open', '[')
1264 brac.appendChild(self._print(i.start))
1265 brac.appendChild(self._print(i.end))
1267 mrow.appendChild(brac)
1268 return mrow
1270 def _print_Abs(self, expr, exp=None):
1271 mrow = self.dom.createElement('mrow')
1272 x = self.dom.createElement('mfenced')
1273 x.setAttribute('close', '|')
1274 x.setAttribute('open', '|')
1275 x.appendChild(self._print(expr.args[0]))
1276 mrow.appendChild(x)
1277 return mrow
1279 _print_Determinant = _print_Abs
1281 def _print_re_im(self, c, expr):
1282 mrow = self.dom.createElement('mrow')
1283 mi = self.dom.createElement('mi')
1284 mi.setAttribute('mathvariant', 'fraktur')
1285 mi.appendChild(self.dom.createTextNode(c))
1286 mrow.appendChild(mi)
1287 brac = self.dom.createElement('mfenced')
1288 brac.appendChild(self._print(expr))
1289 mrow.appendChild(brac)
1290 return mrow
1292 def _print_re(self, expr, exp=None):
1293 return self._print_re_im('R', expr.args[0])
1295 def _print_im(self, expr, exp=None):
1296 return self._print_re_im('I', expr.args[0])
1298 def _print_AssocOp(self, e):
1299 mrow = self.dom.createElement('mrow')
1300 mi = self.dom.createElement('mi')
1301 mi.appendChild(self.dom.createTextNode(self.mathml_tag(e)))
1302 mrow.appendChild(mi)
1303 for arg in e.args:
1304 mrow.appendChild(self._print(arg))
1305 return mrow
1307 def _print_SetOp(self, expr, symbol, prec):
1308 mrow = self.dom.createElement('mrow')
1309 mrow.appendChild(self.parenthesize(expr.args[0], prec))
1310 for arg in expr.args[1:]:
1311 x = self.dom.createElement('mo')
1312 x.appendChild(self.dom.createTextNode(symbol))
1313 y = self.parenthesize(arg, prec)
1314 mrow.appendChild(x)
1315 mrow.appendChild(y)
1316 return mrow
1318 def _print_Union(self, expr):
1319 prec = PRECEDENCE_TRADITIONAL['Union']
1320 return self._print_SetOp(expr, '∪', prec)
1322 def _print_Intersection(self, expr):
1323 prec = PRECEDENCE_TRADITIONAL['Intersection']
1324 return self._print_SetOp(expr, '∩', prec)
1326 def _print_Complement(self, expr):
1327 prec = PRECEDENCE_TRADITIONAL['Complement']
1328 return self._print_SetOp(expr, '∖', prec)
1330 def _print_SymmetricDifference(self, expr):
1331 prec = PRECEDENCE_TRADITIONAL['SymmetricDifference']
1332 return self._print_SetOp(expr, '∆', prec)
1334 def _print_ProductSet(self, expr):
1335 prec = PRECEDENCE_TRADITIONAL['ProductSet']
1336 return self._print_SetOp(expr, '×', prec)
1338 def _print_FiniteSet(self, s):
1339 return self._print_set(s.args)
1341 def _print_set(self, s):
1342 items = sorted(s, key=default_sort_key)
1343 brac = self.dom.createElement('mfenced')
1344 brac.setAttribute('close', '}')
1345 brac.setAttribute('open', '{')
1346 for item in items:
1347 brac.appendChild(self._print(item))
1348 return brac
1350 _print_frozenset = _print_set
1352 def _print_LogOp(self, args, symbol):
1353 mrow = self.dom.createElement('mrow')
1354 if args[0].is_Boolean and not args[0].is_Not:
1355 brac = self.dom.createElement('mfenced')
1356 brac.appendChild(self._print(args[0]))
1357 mrow.appendChild(brac)
1358 else:
1359 mrow.appendChild(self._print(args[0]))
1360 for arg in args[1:]:
1361 x = self.dom.createElement('mo')
1362 x.appendChild(self.dom.createTextNode(symbol))
1363 if arg.is_Boolean and not arg.is_Not:
1364 y = self.dom.createElement('mfenced')
1365 y.appendChild(self._print(arg))
1366 else:
1367 y = self._print(arg)
1368 mrow.appendChild(x)
1369 mrow.appendChild(y)
1370 return mrow
1372 def _print_BasisDependent(self, expr):
1373 from sympy.vector import Vector
1375 if expr == expr.zero:
1376 # Not clear if this is ever called
1377 return self._print(expr.zero)
1378 if isinstance(expr, Vector):
1379 items = expr.separate().items()
1380 else:
1381 items = [(0, expr)]
1383 mrow = self.dom.createElement('mrow')
1384 for system, vect in items:
1385 inneritems = list(vect.components.items())
1386 inneritems.sort(key = lambda x:x[0].__str__())
1387 for i, (k, v) in enumerate(inneritems):
1388 if v == 1:
1389 if i: # No + for first item
1390 mo = self.dom.createElement('mo')
1391 mo.appendChild(self.dom.createTextNode('+'))
1392 mrow.appendChild(mo)
1393 mrow.appendChild(self._print(k))
1394 elif v == -1:
1395 mo = self.dom.createElement('mo')
1396 mo.appendChild(self.dom.createTextNode('-'))
1397 mrow.appendChild(mo)
1398 mrow.appendChild(self._print(k))
1399 else:
1400 if i: # No + for first item
1401 mo = self.dom.createElement('mo')
1402 mo.appendChild(self.dom.createTextNode('+'))
1403 mrow.appendChild(mo)
1404 mbrac = self.dom.createElement('mfenced')
1405 mbrac.appendChild(self._print(v))
1406 mrow.appendChild(mbrac)
1407 mo = self.dom.createElement('mo')
1408 mo.appendChild(self.dom.createTextNode('⁢'))
1409 mrow.appendChild(mo)
1410 mrow.appendChild(self._print(k))
1411 return mrow
1414 def _print_And(self, expr):
1415 args = sorted(expr.args, key=default_sort_key)
1416 return self._print_LogOp(args, '∧')
1418 def _print_Or(self, expr):
1419 args = sorted(expr.args, key=default_sort_key)
1420 return self._print_LogOp(args, '∨')
1422 def _print_Xor(self, expr):
1423 args = sorted(expr.args, key=default_sort_key)
1424 return self._print_LogOp(args, '⊻')
1426 def _print_Implies(self, expr):
1427 return self._print_LogOp(expr.args, '⇒')
1429 def _print_Equivalent(self, expr):
1430 args = sorted(expr.args, key=default_sort_key)
1431 return self._print_LogOp(args, '⇔')
1433 def _print_Not(self, e):
1434 mrow = self.dom.createElement('mrow')
1435 mo = self.dom.createElement('mo')
1436 mo.appendChild(self.dom.createTextNode('¬'))
1437 mrow.appendChild(mo)
1438 if (e.args[0].is_Boolean):
1439 x = self.dom.createElement('mfenced')
1440 x.appendChild(self._print(e.args[0]))
1441 else:
1442 x = self._print(e.args[0])
1443 mrow.appendChild(x)
1444 return mrow
1446 def _print_bool(self, e):
1447 mi = self.dom.createElement('mi')
1448 mi.appendChild(self.dom.createTextNode(self.mathml_tag(e)))
1449 return mi
1451 _print_BooleanTrue = _print_bool
1452 _print_BooleanFalse = _print_bool
1454 def _print_NoneType(self, e):
1455 mi = self.dom.createElement('mi')
1456 mi.appendChild(self.dom.createTextNode(self.mathml_tag(e)))
1457 return mi
1459 def _print_Range(self, s):
1460 dots = "\u2026"
1461 brac = self.dom.createElement('mfenced')
1462 brac.setAttribute('close', '}')
1463 brac.setAttribute('open', '{')
1465 if s.start.is_infinite and s.stop.is_infinite:
1466 if s.step.is_positive:
1467 printset = dots, -1, 0, 1, dots
1468 else:
1469 printset = dots, 1, 0, -1, dots
1470 elif s.start.is_infinite:
1471 printset = dots, s[-1] - s.step, s[-1]
1472 elif s.stop.is_infinite:
1473 it = iter(s)
1474 printset = next(it), next(it), dots
1475 elif len(s) > 4:
1476 it = iter(s)
1477 printset = next(it), next(it), dots, s[-1]
1478 else:
1479 printset = tuple(s)
1481 for el in printset:
1482 if el == dots:
1483 mi = self.dom.createElement('mi')
1484 mi.appendChild(self.dom.createTextNode(dots))
1485 brac.appendChild(mi)
1486 else:
1487 brac.appendChild(self._print(el))
1489 return brac
1491 def _hprint_variadic_function(self, expr):
1492 args = sorted(expr.args, key=default_sort_key)
1493 mrow = self.dom.createElement('mrow')
1494 mo = self.dom.createElement('mo')
1495 mo.appendChild(self.dom.createTextNode((str(expr.func)).lower()))
1496 mrow.appendChild(mo)
1497 brac = self.dom.createElement('mfenced')
1498 for symbol in args:
1499 brac.appendChild(self._print(symbol))
1500 mrow.appendChild(brac)
1501 return mrow
1503 _print_Min = _print_Max = _hprint_variadic_function
1505 def _print_exp(self, expr):
1506 msup = self.dom.createElement('msup')
1507 msup.appendChild(self._print_Exp1(None))
1508 msup.appendChild(self._print(expr.args[0]))
1509 return msup
1511 def _print_Relational(self, e):
1512 mrow = self.dom.createElement('mrow')
1513 mrow.appendChild(self._print(e.lhs))
1514 x = self.dom.createElement('mo')
1515 x.appendChild(self.dom.createTextNode(self.mathml_tag(e)))
1516 mrow.appendChild(x)
1517 mrow.appendChild(self._print(e.rhs))
1518 return mrow
1520 def _print_int(self, p):
1521 dom_element = self.dom.createElement(self.mathml_tag(p))
1522 dom_element.appendChild(self.dom.createTextNode(str(p)))
1523 return dom_element
1525 def _print_BaseScalar(self, e):
1526 msub = self.dom.createElement('msub')
1527 index, system = e._id
1528 mi = self.dom.createElement('mi')
1529 mi.setAttribute('mathvariant', 'bold')
1530 mi.appendChild(self.dom.createTextNode(system._variable_names[index]))
1531 msub.appendChild(mi)
1532 mi = self.dom.createElement('mi')
1533 mi.setAttribute('mathvariant', 'bold')
1534 mi.appendChild(self.dom.createTextNode(system._name))
1535 msub.appendChild(mi)
1536 return msub
1538 def _print_BaseVector(self, e):
1539 msub = self.dom.createElement('msub')
1540 index, system = e._id
1541 mover = self.dom.createElement('mover')
1542 mi = self.dom.createElement('mi')
1543 mi.setAttribute('mathvariant', 'bold')
1544 mi.appendChild(self.dom.createTextNode(system._vector_names[index]))
1545 mover.appendChild(mi)
1546 mo = self.dom.createElement('mo')
1547 mo.appendChild(self.dom.createTextNode('^'))
1548 mover.appendChild(mo)
1549 msub.appendChild(mover)
1550 mi = self.dom.createElement('mi')
1551 mi.setAttribute('mathvariant', 'bold')
1552 mi.appendChild(self.dom.createTextNode(system._name))
1553 msub.appendChild(mi)
1554 return msub
1556 def _print_VectorZero(self, e):
1557 mover = self.dom.createElement('mover')
1558 mi = self.dom.createElement('mi')
1559 mi.setAttribute('mathvariant', 'bold')
1560 mi.appendChild(self.dom.createTextNode("0"))
1561 mover.appendChild(mi)
1562 mo = self.dom.createElement('mo')
1563 mo.appendChild(self.dom.createTextNode('^'))
1564 mover.appendChild(mo)
1565 return mover
1567 def _print_Cross(self, expr):
1568 mrow = self.dom.createElement('mrow')
1569 vec1 = expr._expr1
1570 vec2 = expr._expr2
1571 mrow.appendChild(self.parenthesize(vec1, PRECEDENCE['Mul']))
1572 mo = self.dom.createElement('mo')
1573 mo.appendChild(self.dom.createTextNode('×'))
1574 mrow.appendChild(mo)
1575 mrow.appendChild(self.parenthesize(vec2, PRECEDENCE['Mul']))
1576 return mrow
1578 def _print_Curl(self, expr):
1579 mrow = self.dom.createElement('mrow')
1580 mo = self.dom.createElement('mo')
1581 mo.appendChild(self.dom.createTextNode('∇'))
1582 mrow.appendChild(mo)
1583 mo = self.dom.createElement('mo')
1584 mo.appendChild(self.dom.createTextNode('×'))
1585 mrow.appendChild(mo)
1586 mrow.appendChild(self.parenthesize(expr._expr, PRECEDENCE['Mul']))
1587 return mrow
1589 def _print_Divergence(self, expr):
1590 mrow = self.dom.createElement('mrow')
1591 mo = self.dom.createElement('mo')
1592 mo.appendChild(self.dom.createTextNode('∇'))
1593 mrow.appendChild(mo)
1594 mo = self.dom.createElement('mo')
1595 mo.appendChild(self.dom.createTextNode('·'))
1596 mrow.appendChild(mo)
1597 mrow.appendChild(self.parenthesize(expr._expr, PRECEDENCE['Mul']))
1598 return mrow
1600 def _print_Dot(self, expr):
1601 mrow = self.dom.createElement('mrow')
1602 vec1 = expr._expr1
1603 vec2 = expr._expr2
1604 mrow.appendChild(self.parenthesize(vec1, PRECEDENCE['Mul']))
1605 mo = self.dom.createElement('mo')
1606 mo.appendChild(self.dom.createTextNode('·'))
1607 mrow.appendChild(mo)
1608 mrow.appendChild(self.parenthesize(vec2, PRECEDENCE['Mul']))
1609 return mrow
1611 def _print_Gradient(self, expr):
1612 mrow = self.dom.createElement('mrow')
1613 mo = self.dom.createElement('mo')
1614 mo.appendChild(self.dom.createTextNode('∇'))
1615 mrow.appendChild(mo)
1616 mrow.appendChild(self.parenthesize(expr._expr, PRECEDENCE['Mul']))
1617 return mrow
1619 def _print_Laplacian(self, expr):
1620 mrow = self.dom.createElement('mrow')
1621 mo = self.dom.createElement('mo')
1622 mo.appendChild(self.dom.createTextNode('∆'))
1623 mrow.appendChild(mo)
1624 mrow.appendChild(self.parenthesize(expr._expr, PRECEDENCE['Mul']))
1625 return mrow
1627 def _print_Integers(self, e):
1628 x = self.dom.createElement('mi')
1629 x.setAttribute('mathvariant', 'normal')
1630 x.appendChild(self.dom.createTextNode('ℤ'))
1631 return x
1633 def _print_Complexes(self, e):
1634 x = self.dom.createElement('mi')
1635 x.setAttribute('mathvariant', 'normal')
1636 x.appendChild(self.dom.createTextNode('ℂ'))
1637 return x
1639 def _print_Reals(self, e):
1640 x = self.dom.createElement('mi')
1641 x.setAttribute('mathvariant', 'normal')
1642 x.appendChild(self.dom.createTextNode('ℝ'))
1643 return x
1645 def _print_Naturals(self, e):
1646 x = self.dom.createElement('mi')
1647 x.setAttribute('mathvariant', 'normal')
1648 x.appendChild(self.dom.createTextNode('ℕ'))
1649 return x
1651 def _print_Naturals0(self, e):
1652 sub = self.dom.createElement('msub')
1653 x = self.dom.createElement('mi')
1654 x.setAttribute('mathvariant', 'normal')
1655 x.appendChild(self.dom.createTextNode('ℕ'))
1656 sub.appendChild(x)
1657 sub.appendChild(self._print(S.Zero))
1658 return sub
1660 def _print_SingularityFunction(self, expr):
1661 shift = expr.args[0] - expr.args[1]
1662 power = expr.args[2]
1663 sup = self.dom.createElement('msup')
1664 brac = self.dom.createElement('mfenced')
1665 brac.setAttribute('close', '\u27e9')
1666 brac.setAttribute('open', '\u27e8')
1667 brac.appendChild(self._print(shift))
1668 sup.appendChild(brac)
1669 sup.appendChild(self._print(power))
1670 return sup
1672 def _print_NaN(self, e):
1673 x = self.dom.createElement('mi')
1674 x.appendChild(self.dom.createTextNode('NaN'))
1675 return x
1677 def _print_number_function(self, e, name):
1678 # Print name_arg[0] for one argument or name_arg[0](arg[1])
1679 # for more than one argument
1680 sub = self.dom.createElement('msub')
1681 mi = self.dom.createElement('mi')
1682 mi.appendChild(self.dom.createTextNode(name))
1683 sub.appendChild(mi)
1684 sub.appendChild(self._print(e.args[0]))
1685 if len(e.args) == 1:
1686 return sub
1687 # TODO: copy-pasted from _print_Function: can we do better?
1688 mrow = self.dom.createElement('mrow')
1689 y = self.dom.createElement('mfenced')
1690 for arg in e.args[1:]:
1691 y.appendChild(self._print(arg))
1692 mrow.appendChild(sub)
1693 mrow.appendChild(y)
1694 return mrow
1696 def _print_bernoulli(self, e):
1697 return self._print_number_function(e, 'B')
1699 _print_bell = _print_bernoulli
1701 def _print_catalan(self, e):
1702 return self._print_number_function(e, 'C')
1704 def _print_euler(self, e):
1705 return self._print_number_function(e, 'E')
1707 def _print_fibonacci(self, e):
1708 return self._print_number_function(e, 'F')
1710 def _print_lucas(self, e):
1711 return self._print_number_function(e, 'L')
1713 def _print_stieltjes(self, e):
1714 return self._print_number_function(e, 'γ')
1716 def _print_tribonacci(self, e):
1717 return self._print_number_function(e, 'T')
1719 def _print_ComplexInfinity(self, e):
1720 x = self.dom.createElement('mover')
1721 mo = self.dom.createElement('mo')
1722 mo.appendChild(self.dom.createTextNode('∞'))
1723 x.appendChild(mo)
1724 mo = self.dom.createElement('mo')
1725 mo.appendChild(self.dom.createTextNode('~'))
1726 x.appendChild(mo)
1727 return x
1729 def _print_EmptySet(self, e):
1730 x = self.dom.createElement('mo')
1731 x.appendChild(self.dom.createTextNode('∅'))
1732 return x
1734 def _print_UniversalSet(self, e):
1735 x = self.dom.createElement('mo')
1736 x.appendChild(self.dom.createTextNode('𝕌'))
1737 return x
1739 def _print_Adjoint(self, expr):
1740 from sympy.matrices import MatrixSymbol
1741 mat = expr.arg
1742 sup = self.dom.createElement('msup')
1743 if not isinstance(mat, MatrixSymbol):
1744 brac = self.dom.createElement('mfenced')
1745 brac.appendChild(self._print(mat))
1746 sup.appendChild(brac)
1747 else:
1748 sup.appendChild(self._print(mat))
1749 mo = self.dom.createElement('mo')
1750 mo.appendChild(self.dom.createTextNode('†'))
1751 sup.appendChild(mo)
1752 return sup
1754 def _print_Transpose(self, expr):
1755 from sympy.matrices import MatrixSymbol
1756 mat = expr.arg
1757 sup = self.dom.createElement('msup')
1758 if not isinstance(mat, MatrixSymbol):
1759 brac = self.dom.createElement('mfenced')
1760 brac.appendChild(self._print(mat))
1761 sup.appendChild(brac)
1762 else:
1763 sup.appendChild(self._print(mat))
1764 mo = self.dom.createElement('mo')
1765 mo.appendChild(self.dom.createTextNode('T'))
1766 sup.appendChild(mo)
1767 return sup
1769 def _print_Inverse(self, expr):
1770 from sympy.matrices import MatrixSymbol
1771 mat = expr.arg
1772 sup = self.dom.createElement('msup')
1773 if not isinstance(mat, MatrixSymbol):
1774 brac = self.dom.createElement('mfenced')
1775 brac.appendChild(self._print(mat))
1776 sup.appendChild(brac)
1777 else:
1778 sup.appendChild(self._print(mat))
1779 sup.appendChild(self._print(-1))
1780 return sup
1782 def _print_MatMul(self, expr):
1783 from sympy.matrices.expressions.matmul import MatMul
1785 x = self.dom.createElement('mrow')
1786 args = expr.args
1787 if isinstance(args[0], Mul):
1788 args = args[0].as_ordered_factors() + list(args[1:])
1789 else:
1790 args = list(args)
1792 if isinstance(expr, MatMul) and expr.could_extract_minus_sign():
1793 if args[0] == -1:
1794 args = args[1:]
1795 else:
1796 args[0] = -args[0]
1797 mo = self.dom.createElement('mo')
1798 mo.appendChild(self.dom.createTextNode('-'))
1799 x.appendChild(mo)
1801 for arg in args[:-1]:
1802 x.appendChild(self.parenthesize(arg, precedence_traditional(expr),
1803 False))
1804 mo = self.dom.createElement('mo')
1805 mo.appendChild(self.dom.createTextNode('⁢'))
1806 x.appendChild(mo)
1807 x.appendChild(self.parenthesize(args[-1], precedence_traditional(expr),
1808 False))
1809 return x
1811 def _print_MatPow(self, expr):
1812 from sympy.matrices import MatrixSymbol
1813 base, exp = expr.base, expr.exp
1814 sup = self.dom.createElement('msup')
1815 if not isinstance(base, MatrixSymbol):
1816 brac = self.dom.createElement('mfenced')
1817 brac.appendChild(self._print(base))
1818 sup.appendChild(brac)
1819 else:
1820 sup.appendChild(self._print(base))
1821 sup.appendChild(self._print(exp))
1822 return sup
1824 def _print_HadamardProduct(self, expr):
1825 x = self.dom.createElement('mrow')
1826 args = expr.args
1827 for arg in args[:-1]:
1828 x.appendChild(
1829 self.parenthesize(arg, precedence_traditional(expr), False))
1830 mo = self.dom.createElement('mo')
1831 mo.appendChild(self.dom.createTextNode('∘'))
1832 x.appendChild(mo)
1833 x.appendChild(
1834 self.parenthesize(args[-1], precedence_traditional(expr), False))
1835 return x
1837 def _print_ZeroMatrix(self, Z):
1838 x = self.dom.createElement('mn')
1839 x.appendChild(self.dom.createTextNode('𝟘'))
1840 return x
1842 def _print_OneMatrix(self, Z):
1843 x = self.dom.createElement('mn')
1844 x.appendChild(self.dom.createTextNode('𝟙'))
1845 return x
1847 def _print_Identity(self, I):
1848 x = self.dom.createElement('mi')
1849 x.appendChild(self.dom.createTextNode('𝕀'))
1850 return x
1852 def _print_floor(self, e):
1853 mrow = self.dom.createElement('mrow')
1854 x = self.dom.createElement('mfenced')
1855 x.setAttribute('close', '\u230B')
1856 x.setAttribute('open', '\u230A')
1857 x.appendChild(self._print(e.args[0]))
1858 mrow.appendChild(x)
1859 return mrow
1861 def _print_ceiling(self, e):
1862 mrow = self.dom.createElement('mrow')
1863 x = self.dom.createElement('mfenced')
1864 x.setAttribute('close', '\u2309')
1865 x.setAttribute('open', '\u2308')
1866 x.appendChild(self._print(e.args[0]))
1867 mrow.appendChild(x)
1868 return mrow
1870 def _print_Lambda(self, e):
1871 x = self.dom.createElement('mfenced')
1872 mrow = self.dom.createElement('mrow')
1873 symbols = e.args[0]
1874 if len(symbols) == 1:
1875 symbols = self._print(symbols[0])
1876 else:
1877 symbols = self._print(symbols)
1878 mrow.appendChild(symbols)
1879 mo = self.dom.createElement('mo')
1880 mo.appendChild(self.dom.createTextNode('↦'))
1881 mrow.appendChild(mo)
1882 mrow.appendChild(self._print(e.args[1]))
1883 x.appendChild(mrow)
1884 return x
1886 def _print_tuple(self, e):
1887 x = self.dom.createElement('mfenced')
1888 for i in e:
1889 x.appendChild(self._print(i))
1890 return x
1892 def _print_IndexedBase(self, e):
1893 return self._print(e.label)
1895 def _print_Indexed(self, e):
1896 x = self.dom.createElement('msub')
1897 x.appendChild(self._print(e.base))
1898 if len(e.indices) == 1:
1899 x.appendChild(self._print(e.indices[0]))
1900 return x
1901 x.appendChild(self._print(e.indices))
1902 return x
1904 def _print_MatrixElement(self, e):
1905 x = self.dom.createElement('msub')
1906 x.appendChild(self.parenthesize(e.parent, PRECEDENCE["Atom"], strict = True))
1907 brac = self.dom.createElement('mfenced')
1908 brac.setAttribute("close", "")
1909 brac.setAttribute("open", "")
1910 for i in e.indices:
1911 brac.appendChild(self._print(i))
1912 x.appendChild(brac)
1913 return x
1915 def _print_elliptic_f(self, e):
1916 x = self.dom.createElement('mrow')
1917 mi = self.dom.createElement('mi')
1918 mi.appendChild(self.dom.createTextNode('𝖥'))
1919 x.appendChild(mi)
1920 y = self.dom.createElement('mfenced')
1921 y.setAttribute("separators", "|")
1922 for i in e.args:
1923 y.appendChild(self._print(i))
1924 x.appendChild(y)
1925 return x
1927 def _print_elliptic_e(self, e):
1928 x = self.dom.createElement('mrow')
1929 mi = self.dom.createElement('mi')
1930 mi.appendChild(self.dom.createTextNode('𝖤'))
1931 x.appendChild(mi)
1932 y = self.dom.createElement('mfenced')
1933 y.setAttribute("separators", "|")
1934 for i in e.args:
1935 y.appendChild(self._print(i))
1936 x.appendChild(y)
1937 return x
1939 def _print_elliptic_pi(self, e):
1940 x = self.dom.createElement('mrow')
1941 mi = self.dom.createElement('mi')
1942 mi.appendChild(self.dom.createTextNode('𝛱'))
1943 x.appendChild(mi)
1944 y = self.dom.createElement('mfenced')
1945 if len(e.args) == 2:
1946 y.setAttribute("separators", "|")
1947 else:
1948 y.setAttribute("separators", ";|")
1949 for i in e.args:
1950 y.appendChild(self._print(i))
1951 x.appendChild(y)
1952 return x
1954 def _print_Ei(self, e):
1955 x = self.dom.createElement('mrow')
1956 mi = self.dom.createElement('mi')
1957 mi.appendChild(self.dom.createTextNode('Ei'))
1958 x.appendChild(mi)
1959 x.appendChild(self._print(e.args))
1960 return x
1962 def _print_expint(self, e):
1963 x = self.dom.createElement('mrow')
1964 y = self.dom.createElement('msub')
1965 mo = self.dom.createElement('mo')
1966 mo.appendChild(self.dom.createTextNode('E'))
1967 y.appendChild(mo)
1968 y.appendChild(self._print(e.args[0]))
1969 x.appendChild(y)
1970 x.appendChild(self._print(e.args[1:]))
1971 return x
1973 def _print_jacobi(self, e):
1974 x = self.dom.createElement('mrow')
1975 y = self.dom.createElement('msubsup')
1976 mo = self.dom.createElement('mo')
1977 mo.appendChild(self.dom.createTextNode('P'))
1978 y.appendChild(mo)
1979 y.appendChild(self._print(e.args[0]))
1980 y.appendChild(self._print(e.args[1:3]))
1981 x.appendChild(y)
1982 x.appendChild(self._print(e.args[3:]))
1983 return x
1985 def _print_gegenbauer(self, e):
1986 x = self.dom.createElement('mrow')
1987 y = self.dom.createElement('msubsup')
1988 mo = self.dom.createElement('mo')
1989 mo.appendChild(self.dom.createTextNode('C'))
1990 y.appendChild(mo)
1991 y.appendChild(self._print(e.args[0]))
1992 y.appendChild(self._print(e.args[1:2]))
1993 x.appendChild(y)
1994 x.appendChild(self._print(e.args[2:]))
1995 return x
1997 def _print_chebyshevt(self, e):
1998 x = self.dom.createElement('mrow')
1999 y = self.dom.createElement('msub')
2000 mo = self.dom.createElement('mo')
2001 mo.appendChild(self.dom.createTextNode('T'))
2002 y.appendChild(mo)
2003 y.appendChild(self._print(e.args[0]))
2004 x.appendChild(y)
2005 x.appendChild(self._print(e.args[1:]))
2006 return x
2008 def _print_chebyshevu(self, e):
2009 x = self.dom.createElement('mrow')
2010 y = self.dom.createElement('msub')
2011 mo = self.dom.createElement('mo')
2012 mo.appendChild(self.dom.createTextNode('U'))
2013 y.appendChild(mo)
2014 y.appendChild(self._print(e.args[0]))
2015 x.appendChild(y)
2016 x.appendChild(self._print(e.args[1:]))
2017 return x
2019 def _print_legendre(self, e):
2020 x = self.dom.createElement('mrow')
2021 y = self.dom.createElement('msub')
2022 mo = self.dom.createElement('mo')
2023 mo.appendChild(self.dom.createTextNode('P'))
2024 y.appendChild(mo)
2025 y.appendChild(self._print(e.args[0]))
2026 x.appendChild(y)
2027 x.appendChild(self._print(e.args[1:]))
2028 return x
2030 def _print_assoc_legendre(self, e):
2031 x = self.dom.createElement('mrow')
2032 y = self.dom.createElement('msubsup')
2033 mo = self.dom.createElement('mo')
2034 mo.appendChild(self.dom.createTextNode('P'))
2035 y.appendChild(mo)
2036 y.appendChild(self._print(e.args[0]))
2037 y.appendChild(self._print(e.args[1:2]))
2038 x.appendChild(y)
2039 x.appendChild(self._print(e.args[2:]))
2040 return x
2042 def _print_laguerre(self, e):
2043 x = self.dom.createElement('mrow')
2044 y = self.dom.createElement('msub')
2045 mo = self.dom.createElement('mo')
2046 mo.appendChild(self.dom.createTextNode('L'))
2047 y.appendChild(mo)
2048 y.appendChild(self._print(e.args[0]))
2049 x.appendChild(y)
2050 x.appendChild(self._print(e.args[1:]))
2051 return x
2053 def _print_assoc_laguerre(self, e):
2054 x = self.dom.createElement('mrow')
2055 y = self.dom.createElement('msubsup')
2056 mo = self.dom.createElement('mo')
2057 mo.appendChild(self.dom.createTextNode('L'))
2058 y.appendChild(mo)
2059 y.appendChild(self._print(e.args[0]))
2060 y.appendChild(self._print(e.args[1:2]))
2061 x.appendChild(y)
2062 x.appendChild(self._print(e.args[2:]))
2063 return x
2065 def _print_hermite(self, e):
2066 x = self.dom.createElement('mrow')
2067 y = self.dom.createElement('msub')
2068 mo = self.dom.createElement('mo')
2069 mo.appendChild(self.dom.createTextNode('H'))
2070 y.appendChild(mo)
2071 y.appendChild(self._print(e.args[0]))
2072 x.appendChild(y)
2073 x.appendChild(self._print(e.args[1:]))
2074 return x
2077@print_function(MathMLPrinterBase)
2078def mathml(expr, printer='content', **settings):
2079 """Returns the MathML representation of expr. If printer is presentation
2080 then prints Presentation MathML else prints content MathML.
2081 """
2082 if printer == 'presentation':
2083 return MathMLPresentationPrinter(settings).doprint(expr)
2084 else:
2085 return MathMLContentPrinter(settings).doprint(expr)
2088def print_mathml(expr, printer='content', **settings):
2089 """
2090 Prints a pretty representation of the MathML code for expr. If printer is
2091 presentation then prints Presentation MathML else prints content MathML.
2093 Examples
2094 ========
2096 >>> ##
2097 >>> from sympy import print_mathml
2098 >>> from sympy.abc import x
2099 >>> print_mathml(x+1) #doctest: +NORMALIZE_WHITESPACE
2100 <apply>
2101 <plus/>
2102 <ci>x</ci>
2103 <cn>1</cn>
2104 </apply>
2105 >>> print_mathml(x+1, printer='presentation')
2106 <mrow>
2107 <mi>x</mi>
2108 <mo>+</mo>
2109 <mn>1</mn>
2110 </mrow>
2112 """
2113 if printer == 'presentation':
2114 s = MathMLPresentationPrinter(settings)
2115 else:
2116 s = MathMLContentPrinter(settings)
2117 xml = s._print(sympify(expr))
2118 s.apply_patch()
2119 pretty_xml = xml.toprettyxml()
2120 s.restore_patch()
2122 print(pretty_xml)
2125# For backward compatibility
2126MathMLPrinter = MathMLContentPrinter