mathml.py 74 KB

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