mathml.py 74 KB

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