mathml.py 75 KB

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