pretty.py 103 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939
  1. import itertools
  2. from sympy.core import S
  3. from sympy.core.add import Add
  4. from sympy.core.containers import Tuple
  5. from sympy.core.function import Function
  6. from sympy.core.mul import Mul
  7. from sympy.core.numbers import Number, Rational
  8. from sympy.core.power import Pow
  9. from sympy.core.sorting import default_sort_key
  10. from sympy.core.symbol import Symbol
  11. from sympy.core.sympify import SympifyError
  12. from sympy.printing.conventions import requires_partial
  13. from sympy.printing.precedence import PRECEDENCE, precedence, precedence_traditional
  14. from sympy.printing.printer import Printer, print_function
  15. from sympy.printing.str import sstr
  16. from sympy.utilities.iterables import has_variety
  17. from sympy.utilities.exceptions import sympy_deprecation_warning
  18. from sympy.printing.pretty.stringpict import prettyForm, stringPict
  19. from sympy.printing.pretty.pretty_symbology import hobj, vobj, xobj, \
  20. xsym, pretty_symbol, pretty_atom, pretty_use_unicode, greek_unicode, U, \
  21. pretty_try_use_unicode, annotated
  22. # rename for usage from outside
  23. pprint_use_unicode = pretty_use_unicode
  24. pprint_try_use_unicode = pretty_try_use_unicode
  25. class PrettyPrinter(Printer):
  26. """Printer, which converts an expression into 2D ASCII-art figure."""
  27. printmethod = "_pretty"
  28. _default_settings = {
  29. "order": None,
  30. "full_prec": "auto",
  31. "use_unicode": None,
  32. "wrap_line": True,
  33. "num_columns": None,
  34. "use_unicode_sqrt_char": True,
  35. "root_notation": True,
  36. "mat_symbol_style": "plain",
  37. "imaginary_unit": "i",
  38. "perm_cyclic": True
  39. }
  40. def __init__(self, settings=None):
  41. Printer.__init__(self, settings)
  42. if not isinstance(self._settings['imaginary_unit'], str):
  43. raise TypeError("'imaginary_unit' must a string, not {}".format(self._settings['imaginary_unit']))
  44. elif self._settings['imaginary_unit'] not in ("i", "j"):
  45. raise ValueError("'imaginary_unit' must be either 'i' or 'j', not '{}'".format(self._settings['imaginary_unit']))
  46. def emptyPrinter(self, expr):
  47. return prettyForm(str(expr))
  48. @property
  49. def _use_unicode(self):
  50. if self._settings['use_unicode']:
  51. return True
  52. else:
  53. return pretty_use_unicode()
  54. def doprint(self, expr):
  55. return self._print(expr).render(**self._settings)
  56. # empty op so _print(stringPict) returns the same
  57. def _print_stringPict(self, e):
  58. return e
  59. def _print_basestring(self, e):
  60. return prettyForm(e)
  61. def _print_atan2(self, e):
  62. pform = prettyForm(*self._print_seq(e.args).parens())
  63. pform = prettyForm(*pform.left('atan2'))
  64. return pform
  65. def _print_Symbol(self, e, bold_name=False):
  66. symb = pretty_symbol(e.name, bold_name)
  67. return prettyForm(symb)
  68. _print_RandomSymbol = _print_Symbol
  69. def _print_MatrixSymbol(self, e):
  70. return self._print_Symbol(e, self._settings['mat_symbol_style'] == "bold")
  71. def _print_Float(self, e):
  72. # we will use StrPrinter's Float printer, but we need to handle the
  73. # full_prec ourselves, according to the self._print_level
  74. full_prec = self._settings["full_prec"]
  75. if full_prec == "auto":
  76. full_prec = self._print_level == 1
  77. return prettyForm(sstr(e, full_prec=full_prec))
  78. def _print_Cross(self, e):
  79. vec1 = e._expr1
  80. vec2 = e._expr2
  81. pform = self._print(vec2)
  82. pform = prettyForm(*pform.left('('))
  83. pform = prettyForm(*pform.right(')'))
  84. pform = prettyForm(*pform.left(self._print(U('MULTIPLICATION SIGN'))))
  85. pform = prettyForm(*pform.left(')'))
  86. pform = prettyForm(*pform.left(self._print(vec1)))
  87. pform = prettyForm(*pform.left('('))
  88. return pform
  89. def _print_Curl(self, e):
  90. vec = e._expr
  91. pform = self._print(vec)
  92. pform = prettyForm(*pform.left('('))
  93. pform = prettyForm(*pform.right(')'))
  94. pform = prettyForm(*pform.left(self._print(U('MULTIPLICATION SIGN'))))
  95. pform = prettyForm(*pform.left(self._print(U('NABLA'))))
  96. return pform
  97. def _print_Divergence(self, e):
  98. vec = e._expr
  99. pform = self._print(vec)
  100. pform = prettyForm(*pform.left('('))
  101. pform = prettyForm(*pform.right(')'))
  102. pform = prettyForm(*pform.left(self._print(U('DOT OPERATOR'))))
  103. pform = prettyForm(*pform.left(self._print(U('NABLA'))))
  104. return pform
  105. def _print_Dot(self, e):
  106. vec1 = e._expr1
  107. vec2 = e._expr2
  108. pform = self._print(vec2)
  109. pform = prettyForm(*pform.left('('))
  110. pform = prettyForm(*pform.right(')'))
  111. pform = prettyForm(*pform.left(self._print(U('DOT OPERATOR'))))
  112. pform = prettyForm(*pform.left(')'))
  113. pform = prettyForm(*pform.left(self._print(vec1)))
  114. pform = prettyForm(*pform.left('('))
  115. return pform
  116. def _print_Gradient(self, e):
  117. func = e._expr
  118. pform = self._print(func)
  119. pform = prettyForm(*pform.left('('))
  120. pform = prettyForm(*pform.right(')'))
  121. pform = prettyForm(*pform.left(self._print(U('NABLA'))))
  122. return pform
  123. def _print_Laplacian(self, e):
  124. func = e._expr
  125. pform = self._print(func)
  126. pform = prettyForm(*pform.left('('))
  127. pform = prettyForm(*pform.right(')'))
  128. pform = prettyForm(*pform.left(self._print(U('INCREMENT'))))
  129. return pform
  130. def _print_Atom(self, e):
  131. try:
  132. # print atoms like Exp1 or Pi
  133. return prettyForm(pretty_atom(e.__class__.__name__, printer=self))
  134. except KeyError:
  135. return self.emptyPrinter(e)
  136. # Infinity inherits from Number, so we have to override _print_XXX order
  137. _print_Infinity = _print_Atom
  138. _print_NegativeInfinity = _print_Atom
  139. _print_EmptySet = _print_Atom
  140. _print_Naturals = _print_Atom
  141. _print_Naturals0 = _print_Atom
  142. _print_Integers = _print_Atom
  143. _print_Rationals = _print_Atom
  144. _print_Complexes = _print_Atom
  145. _print_EmptySequence = _print_Atom
  146. def _print_Reals(self, e):
  147. if self._use_unicode:
  148. return self._print_Atom(e)
  149. else:
  150. inf_list = ['-oo', 'oo']
  151. return self._print_seq(inf_list, '(', ')')
  152. def _print_subfactorial(self, e):
  153. x = e.args[0]
  154. pform = self._print(x)
  155. # Add parentheses if needed
  156. if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol):
  157. pform = prettyForm(*pform.parens())
  158. pform = prettyForm(*pform.left('!'))
  159. return pform
  160. def _print_factorial(self, e):
  161. x = e.args[0]
  162. pform = self._print(x)
  163. # Add parentheses if needed
  164. if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol):
  165. pform = prettyForm(*pform.parens())
  166. pform = prettyForm(*pform.right('!'))
  167. return pform
  168. def _print_factorial2(self, e):
  169. x = e.args[0]
  170. pform = self._print(x)
  171. # Add parentheses if needed
  172. if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol):
  173. pform = prettyForm(*pform.parens())
  174. pform = prettyForm(*pform.right('!!'))
  175. return pform
  176. def _print_binomial(self, e):
  177. n, k = e.args
  178. n_pform = self._print(n)
  179. k_pform = self._print(k)
  180. bar = ' '*max(n_pform.width(), k_pform.width())
  181. pform = prettyForm(*k_pform.above(bar))
  182. pform = prettyForm(*pform.above(n_pform))
  183. pform = prettyForm(*pform.parens('(', ')'))
  184. pform.baseline = (pform.baseline + 1)//2
  185. return pform
  186. def _print_Relational(self, e):
  187. op = prettyForm(' ' + xsym(e.rel_op) + ' ')
  188. l = self._print(e.lhs)
  189. r = self._print(e.rhs)
  190. pform = prettyForm(*stringPict.next(l, op, r), binding=prettyForm.OPEN)
  191. return pform
  192. def _print_Not(self, e):
  193. from sympy.logic.boolalg import (Equivalent, Implies)
  194. if self._use_unicode:
  195. arg = e.args[0]
  196. pform = self._print(arg)
  197. if isinstance(arg, Equivalent):
  198. return self._print_Equivalent(arg, altchar="\N{LEFT RIGHT DOUBLE ARROW WITH STROKE}")
  199. if isinstance(arg, Implies):
  200. return self._print_Implies(arg, altchar="\N{RIGHTWARDS ARROW WITH STROKE}")
  201. if arg.is_Boolean and not arg.is_Not:
  202. pform = prettyForm(*pform.parens())
  203. return prettyForm(*pform.left("\N{NOT SIGN}"))
  204. else:
  205. return self._print_Function(e)
  206. def __print_Boolean(self, e, char, sort=True):
  207. args = e.args
  208. if sort:
  209. args = sorted(e.args, key=default_sort_key)
  210. arg = args[0]
  211. pform = self._print(arg)
  212. if arg.is_Boolean and not arg.is_Not:
  213. pform = prettyForm(*pform.parens())
  214. for arg in args[1:]:
  215. pform_arg = self._print(arg)
  216. if arg.is_Boolean and not arg.is_Not:
  217. pform_arg = prettyForm(*pform_arg.parens())
  218. pform = prettyForm(*pform.right(' %s ' % char))
  219. pform = prettyForm(*pform.right(pform_arg))
  220. return pform
  221. def _print_And(self, e):
  222. if self._use_unicode:
  223. return self.__print_Boolean(e, "\N{LOGICAL AND}")
  224. else:
  225. return self._print_Function(e, sort=True)
  226. def _print_Or(self, e):
  227. if self._use_unicode:
  228. return self.__print_Boolean(e, "\N{LOGICAL OR}")
  229. else:
  230. return self._print_Function(e, sort=True)
  231. def _print_Xor(self, e):
  232. if self._use_unicode:
  233. return self.__print_Boolean(e, "\N{XOR}")
  234. else:
  235. return self._print_Function(e, sort=True)
  236. def _print_Nand(self, e):
  237. if self._use_unicode:
  238. return self.__print_Boolean(e, "\N{NAND}")
  239. else:
  240. return self._print_Function(e, sort=True)
  241. def _print_Nor(self, e):
  242. if self._use_unicode:
  243. return self.__print_Boolean(e, "\N{NOR}")
  244. else:
  245. return self._print_Function(e, sort=True)
  246. def _print_Implies(self, e, altchar=None):
  247. if self._use_unicode:
  248. return self.__print_Boolean(e, altchar or "\N{RIGHTWARDS ARROW}", sort=False)
  249. else:
  250. return self._print_Function(e)
  251. def _print_Equivalent(self, e, altchar=None):
  252. if self._use_unicode:
  253. return self.__print_Boolean(e, altchar or "\N{LEFT RIGHT DOUBLE ARROW}")
  254. else:
  255. return self._print_Function(e, sort=True)
  256. def _print_conjugate(self, e):
  257. pform = self._print(e.args[0])
  258. return prettyForm( *pform.above( hobj('_', pform.width())) )
  259. def _print_Abs(self, e):
  260. pform = self._print(e.args[0])
  261. pform = prettyForm(*pform.parens('|', '|'))
  262. return pform
  263. def _print_floor(self, e):
  264. if self._use_unicode:
  265. pform = self._print(e.args[0])
  266. pform = prettyForm(*pform.parens('lfloor', 'rfloor'))
  267. return pform
  268. else:
  269. return self._print_Function(e)
  270. def _print_ceiling(self, e):
  271. if self._use_unicode:
  272. pform = self._print(e.args[0])
  273. pform = prettyForm(*pform.parens('lceil', 'rceil'))
  274. return pform
  275. else:
  276. return self._print_Function(e)
  277. def _print_Derivative(self, deriv):
  278. if requires_partial(deriv.expr) and self._use_unicode:
  279. deriv_symbol = U('PARTIAL DIFFERENTIAL')
  280. else:
  281. deriv_symbol = r'd'
  282. x = None
  283. count_total_deriv = 0
  284. for sym, num in reversed(deriv.variable_count):
  285. s = self._print(sym)
  286. ds = prettyForm(*s.left(deriv_symbol))
  287. count_total_deriv += num
  288. if (not num.is_Integer) or (num > 1):
  289. ds = ds**prettyForm(str(num))
  290. if x is None:
  291. x = ds
  292. else:
  293. x = prettyForm(*x.right(' '))
  294. x = prettyForm(*x.right(ds))
  295. f = prettyForm(
  296. binding=prettyForm.FUNC, *self._print(deriv.expr).parens())
  297. pform = prettyForm(deriv_symbol)
  298. if (count_total_deriv > 1) != False:
  299. pform = pform**prettyForm(str(count_total_deriv))
  300. pform = prettyForm(*pform.below(stringPict.LINE, x))
  301. pform.baseline = pform.baseline + 1
  302. pform = prettyForm(*stringPict.next(pform, f))
  303. pform.binding = prettyForm.MUL
  304. return pform
  305. def _print_Cycle(self, dc):
  306. from sympy.combinatorics.permutations import Permutation, Cycle
  307. # for Empty Cycle
  308. if dc == Cycle():
  309. cyc = stringPict('')
  310. return prettyForm(*cyc.parens())
  311. dc_list = Permutation(dc.list()).cyclic_form
  312. # for Identity Cycle
  313. if dc_list == []:
  314. cyc = self._print(dc.size - 1)
  315. return prettyForm(*cyc.parens())
  316. cyc = stringPict('')
  317. for i in dc_list:
  318. l = self._print(str(tuple(i)).replace(',', ''))
  319. cyc = prettyForm(*cyc.right(l))
  320. return cyc
  321. def _print_Permutation(self, expr):
  322. from sympy.combinatorics.permutations import Permutation, Cycle
  323. perm_cyclic = Permutation.print_cyclic
  324. if perm_cyclic is not None:
  325. sympy_deprecation_warning(
  326. f"""
  327. Setting Permutation.print_cyclic is deprecated. Instead use
  328. init_printing(perm_cyclic={perm_cyclic}).
  329. """,
  330. deprecated_since_version="1.6",
  331. active_deprecations_target="deprecated-permutation-print_cyclic",
  332. stacklevel=7,
  333. )
  334. else:
  335. perm_cyclic = self._settings.get("perm_cyclic", True)
  336. if perm_cyclic:
  337. return self._print_Cycle(Cycle(expr))
  338. lower = expr.array_form
  339. upper = list(range(len(lower)))
  340. result = stringPict('')
  341. first = True
  342. for u, l in zip(upper, lower):
  343. s1 = self._print(u)
  344. s2 = self._print(l)
  345. col = prettyForm(*s1.below(s2))
  346. if first:
  347. first = False
  348. else:
  349. col = prettyForm(*col.left(" "))
  350. result = prettyForm(*result.right(col))
  351. return prettyForm(*result.parens())
  352. def _print_Integral(self, integral):
  353. f = integral.function
  354. # Add parentheses if arg involves addition of terms and
  355. # create a pretty form for the argument
  356. prettyF = self._print(f)
  357. # XXX generalize parens
  358. if f.is_Add:
  359. prettyF = prettyForm(*prettyF.parens())
  360. # dx dy dz ...
  361. arg = prettyF
  362. for x in integral.limits:
  363. prettyArg = self._print(x[0])
  364. # XXX qparens (parens if needs-parens)
  365. if prettyArg.width() > 1:
  366. prettyArg = prettyForm(*prettyArg.parens())
  367. arg = prettyForm(*arg.right(' d', prettyArg))
  368. # \int \int \int ...
  369. firstterm = True
  370. s = None
  371. for lim in integral.limits:
  372. # Create bar based on the height of the argument
  373. h = arg.height()
  374. H = h + 2
  375. # XXX hack!
  376. ascii_mode = not self._use_unicode
  377. if ascii_mode:
  378. H += 2
  379. vint = vobj('int', H)
  380. # Construct the pretty form with the integral sign and the argument
  381. pform = prettyForm(vint)
  382. pform.baseline = arg.baseline + (
  383. H - h)//2 # covering the whole argument
  384. if len(lim) > 1:
  385. # Create pretty forms for endpoints, if definite integral.
  386. # Do not print empty endpoints.
  387. if len(lim) == 2:
  388. prettyA = prettyForm("")
  389. prettyB = self._print(lim[1])
  390. if len(lim) == 3:
  391. prettyA = self._print(lim[1])
  392. prettyB = self._print(lim[2])
  393. if ascii_mode: # XXX hack
  394. # Add spacing so that endpoint can more easily be
  395. # identified with the correct integral sign
  396. spc = max(1, 3 - prettyB.width())
  397. prettyB = prettyForm(*prettyB.left(' ' * spc))
  398. spc = max(1, 4 - prettyA.width())
  399. prettyA = prettyForm(*prettyA.right(' ' * spc))
  400. pform = prettyForm(*pform.above(prettyB))
  401. pform = prettyForm(*pform.below(prettyA))
  402. if not ascii_mode: # XXX hack
  403. pform = prettyForm(*pform.right(' '))
  404. if firstterm:
  405. s = pform # first term
  406. firstterm = False
  407. else:
  408. s = prettyForm(*s.left(pform))
  409. pform = prettyForm(*arg.left(s))
  410. pform.binding = prettyForm.MUL
  411. return pform
  412. def _print_Product(self, expr):
  413. func = expr.term
  414. pretty_func = self._print(func)
  415. horizontal_chr = xobj('_', 1)
  416. corner_chr = xobj('_', 1)
  417. vertical_chr = xobj('|', 1)
  418. if self._use_unicode:
  419. # use unicode corners
  420. horizontal_chr = xobj('-', 1)
  421. corner_chr = '\N{BOX DRAWINGS LIGHT DOWN AND HORIZONTAL}'
  422. func_height = pretty_func.height()
  423. first = True
  424. max_upper = 0
  425. sign_height = 0
  426. for lim in expr.limits:
  427. pretty_lower, pretty_upper = self.__print_SumProduct_Limits(lim)
  428. width = (func_height + 2) * 5 // 3 - 2
  429. sign_lines = [horizontal_chr + corner_chr + (horizontal_chr * (width-2)) + corner_chr + horizontal_chr]
  430. for _ in range(func_height + 1):
  431. sign_lines.append(' ' + vertical_chr + (' ' * (width-2)) + vertical_chr + ' ')
  432. pretty_sign = stringPict('')
  433. pretty_sign = prettyForm(*pretty_sign.stack(*sign_lines))
  434. max_upper = max(max_upper, pretty_upper.height())
  435. if first:
  436. sign_height = pretty_sign.height()
  437. pretty_sign = prettyForm(*pretty_sign.above(pretty_upper))
  438. pretty_sign = prettyForm(*pretty_sign.below(pretty_lower))
  439. if first:
  440. pretty_func.baseline = 0
  441. first = False
  442. height = pretty_sign.height()
  443. padding = stringPict('')
  444. padding = prettyForm(*padding.stack(*[' ']*(height - 1)))
  445. pretty_sign = prettyForm(*pretty_sign.right(padding))
  446. pretty_func = prettyForm(*pretty_sign.right(pretty_func))
  447. pretty_func.baseline = max_upper + sign_height//2
  448. pretty_func.binding = prettyForm.MUL
  449. return pretty_func
  450. def __print_SumProduct_Limits(self, lim):
  451. def print_start(lhs, rhs):
  452. op = prettyForm(' ' + xsym("==") + ' ')
  453. l = self._print(lhs)
  454. r = self._print(rhs)
  455. pform = prettyForm(*stringPict.next(l, op, r))
  456. return pform
  457. prettyUpper = self._print(lim[2])
  458. prettyLower = print_start(lim[0], lim[1])
  459. return prettyLower, prettyUpper
  460. def _print_Sum(self, expr):
  461. ascii_mode = not self._use_unicode
  462. def asum(hrequired, lower, upper, use_ascii):
  463. def adjust(s, wid=None, how='<^>'):
  464. if not wid or len(s) > wid:
  465. return s
  466. need = wid - len(s)
  467. if how in ('<^>', "<") or how not in list('<^>'):
  468. return s + ' '*need
  469. half = need//2
  470. lead = ' '*half
  471. if how == ">":
  472. return " "*need + s
  473. return lead + s + ' '*(need - len(lead))
  474. h = max(hrequired, 2)
  475. d = h//2
  476. w = d + 1
  477. more = hrequired % 2
  478. lines = []
  479. if use_ascii:
  480. lines.append("_"*(w) + ' ')
  481. lines.append(r"\%s`" % (' '*(w - 1)))
  482. for i in range(1, d):
  483. lines.append('%s\\%s' % (' '*i, ' '*(w - i)))
  484. if more:
  485. lines.append('%s)%s' % (' '*(d), ' '*(w - d)))
  486. for i in reversed(range(1, d)):
  487. lines.append('%s/%s' % (' '*i, ' '*(w - i)))
  488. lines.append("/" + "_"*(w - 1) + ',')
  489. return d, h + more, lines, more
  490. else:
  491. w = w + more
  492. d = d + more
  493. vsum = vobj('sum', 4)
  494. lines.append("_"*(w))
  495. for i in range(0, d):
  496. lines.append('%s%s%s' % (' '*i, vsum[2], ' '*(w - i - 1)))
  497. for i in reversed(range(0, d)):
  498. lines.append('%s%s%s' % (' '*i, vsum[4], ' '*(w - i - 1)))
  499. lines.append(vsum[8]*(w))
  500. return d, h + 2*more, lines, more
  501. f = expr.function
  502. prettyF = self._print(f)
  503. if f.is_Add: # add parens
  504. prettyF = prettyForm(*prettyF.parens())
  505. H = prettyF.height() + 2
  506. # \sum \sum \sum ...
  507. first = True
  508. max_upper = 0
  509. sign_height = 0
  510. for lim in expr.limits:
  511. prettyLower, prettyUpper = self.__print_SumProduct_Limits(lim)
  512. max_upper = max(max_upper, prettyUpper.height())
  513. # Create sum sign based on the height of the argument
  514. d, h, slines, adjustment = asum(
  515. H, prettyLower.width(), prettyUpper.width(), ascii_mode)
  516. prettySign = stringPict('')
  517. prettySign = prettyForm(*prettySign.stack(*slines))
  518. if first:
  519. sign_height = prettySign.height()
  520. prettySign = prettyForm(*prettySign.above(prettyUpper))
  521. prettySign = prettyForm(*prettySign.below(prettyLower))
  522. if first:
  523. # change F baseline so it centers on the sign
  524. prettyF.baseline -= d - (prettyF.height()//2 -
  525. prettyF.baseline)
  526. first = False
  527. # put padding to the right
  528. pad = stringPict('')
  529. pad = prettyForm(*pad.stack(*[' ']*h))
  530. prettySign = prettyForm(*prettySign.right(pad))
  531. # put the present prettyF to the right
  532. prettyF = prettyForm(*prettySign.right(prettyF))
  533. # adjust baseline of ascii mode sigma with an odd height so that it is
  534. # exactly through the center
  535. ascii_adjustment = ascii_mode if not adjustment else 0
  536. prettyF.baseline = max_upper + sign_height//2 + ascii_adjustment
  537. prettyF.binding = prettyForm.MUL
  538. return prettyF
  539. def _print_Limit(self, l):
  540. e, z, z0, dir = l.args
  541. E = self._print(e)
  542. if precedence(e) <= PRECEDENCE["Mul"]:
  543. E = prettyForm(*E.parens('(', ')'))
  544. Lim = prettyForm('lim')
  545. LimArg = self._print(z)
  546. if self._use_unicode:
  547. LimArg = prettyForm(*LimArg.right('\N{BOX DRAWINGS LIGHT HORIZONTAL}\N{RIGHTWARDS ARROW}'))
  548. else:
  549. LimArg = prettyForm(*LimArg.right('->'))
  550. LimArg = prettyForm(*LimArg.right(self._print(z0)))
  551. if str(dir) == '+-' or z0 in (S.Infinity, S.NegativeInfinity):
  552. dir = ""
  553. else:
  554. if self._use_unicode:
  555. dir = '\N{SUPERSCRIPT PLUS SIGN}' if str(dir) == "+" else '\N{SUPERSCRIPT MINUS}'
  556. LimArg = prettyForm(*LimArg.right(self._print(dir)))
  557. Lim = prettyForm(*Lim.below(LimArg))
  558. Lim = prettyForm(*Lim.right(E), binding=prettyForm.MUL)
  559. return Lim
  560. def _print_matrix_contents(self, e):
  561. """
  562. This method factors out what is essentially grid printing.
  563. """
  564. M = e # matrix
  565. Ms = {} # i,j -> pretty(M[i,j])
  566. for i in range(M.rows):
  567. for j in range(M.cols):
  568. Ms[i, j] = self._print(M[i, j])
  569. # h- and v- spacers
  570. hsep = 2
  571. vsep = 1
  572. # max width for columns
  573. maxw = [-1] * M.cols
  574. for j in range(M.cols):
  575. maxw[j] = max([Ms[i, j].width() for i in range(M.rows)] or [0])
  576. # drawing result
  577. D = None
  578. for i in range(M.rows):
  579. D_row = None
  580. for j in range(M.cols):
  581. s = Ms[i, j]
  582. # reshape s to maxw
  583. # XXX this should be generalized, and go to stringPict.reshape ?
  584. assert s.width() <= maxw[j]
  585. # hcenter it, +0.5 to the right 2
  586. # ( it's better to align formula starts for say 0 and r )
  587. # XXX this is not good in all cases -- maybe introduce vbaseline?
  588. wdelta = maxw[j] - s.width()
  589. wleft = wdelta // 2
  590. wright = wdelta - wleft
  591. s = prettyForm(*s.right(' '*wright))
  592. s = prettyForm(*s.left(' '*wleft))
  593. # we don't need vcenter cells -- this is automatically done in
  594. # a pretty way because when their baselines are taking into
  595. # account in .right()
  596. if D_row is None:
  597. D_row = s # first box in a row
  598. continue
  599. D_row = prettyForm(*D_row.right(' '*hsep)) # h-spacer
  600. D_row = prettyForm(*D_row.right(s))
  601. if D is None:
  602. D = D_row # first row in a picture
  603. continue
  604. # v-spacer
  605. for _ in range(vsep):
  606. D = prettyForm(*D.below(' '))
  607. D = prettyForm(*D.below(D_row))
  608. if D is None:
  609. D = prettyForm('') # Empty Matrix
  610. return D
  611. def _print_MatrixBase(self, e, lparens='[', rparens=']'):
  612. D = self._print_matrix_contents(e)
  613. D.baseline = D.height()//2
  614. D = prettyForm(*D.parens(lparens, rparens))
  615. return D
  616. def _print_Determinant(self, e):
  617. mat = e.arg
  618. if mat.is_MatrixExpr:
  619. from sympy.matrices.expressions.blockmatrix import BlockMatrix
  620. if isinstance(mat, BlockMatrix):
  621. return self._print_MatrixBase(mat.blocks, lparens='|', rparens='|')
  622. D = self._print(mat)
  623. D.baseline = D.height()//2
  624. return prettyForm(*D.parens('|', '|'))
  625. else:
  626. return self._print_MatrixBase(mat, lparens='|', rparens='|')
  627. def _print_TensorProduct(self, expr):
  628. # This should somehow share the code with _print_WedgeProduct:
  629. if self._use_unicode:
  630. circled_times = "\u2297"
  631. else:
  632. circled_times = ".*"
  633. return self._print_seq(expr.args, None, None, circled_times,
  634. parenthesize=lambda x: precedence_traditional(x) <= PRECEDENCE["Mul"])
  635. def _print_WedgeProduct(self, expr):
  636. # This should somehow share the code with _print_TensorProduct:
  637. if self._use_unicode:
  638. wedge_symbol = "\u2227"
  639. else:
  640. wedge_symbol = '/\\'
  641. return self._print_seq(expr.args, None, None, wedge_symbol,
  642. parenthesize=lambda x: precedence_traditional(x) <= PRECEDENCE["Mul"])
  643. def _print_Trace(self, e):
  644. D = self._print(e.arg)
  645. D = prettyForm(*D.parens('(',')'))
  646. D.baseline = D.height()//2
  647. D = prettyForm(*D.left('\n'*(0) + 'tr'))
  648. return D
  649. def _print_MatrixElement(self, expr):
  650. from sympy.matrices import MatrixSymbol
  651. if (isinstance(expr.parent, MatrixSymbol)
  652. and expr.i.is_number and expr.j.is_number):
  653. return self._print(
  654. Symbol(expr.parent.name + '_%d%d' % (expr.i, expr.j)))
  655. else:
  656. prettyFunc = self._print(expr.parent)
  657. prettyFunc = prettyForm(*prettyFunc.parens())
  658. prettyIndices = self._print_seq((expr.i, expr.j), delimiter=', '
  659. ).parens(left='[', right=']')[0]
  660. pform = prettyForm(binding=prettyForm.FUNC,
  661. *stringPict.next(prettyFunc, prettyIndices))
  662. # store pform parts so it can be reassembled e.g. when powered
  663. pform.prettyFunc = prettyFunc
  664. pform.prettyArgs = prettyIndices
  665. return pform
  666. def _print_MatrixSlice(self, m):
  667. # XXX works only for applied functions
  668. from sympy.matrices import MatrixSymbol
  669. prettyFunc = self._print(m.parent)
  670. if not isinstance(m.parent, MatrixSymbol):
  671. prettyFunc = prettyForm(*prettyFunc.parens())
  672. def ppslice(x, dim):
  673. x = list(x)
  674. if x[2] == 1:
  675. del x[2]
  676. if x[0] == 0:
  677. x[0] = ''
  678. if x[1] == dim:
  679. x[1] = ''
  680. return prettyForm(*self._print_seq(x, delimiter=':'))
  681. prettyArgs = self._print_seq((ppslice(m.rowslice, m.parent.rows),
  682. ppslice(m.colslice, m.parent.cols)), delimiter=', ').parens(left='[', right=']')[0]
  683. pform = prettyForm(
  684. binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
  685. # store pform parts so it can be reassembled e.g. when powered
  686. pform.prettyFunc = prettyFunc
  687. pform.prettyArgs = prettyArgs
  688. return pform
  689. def _print_Transpose(self, expr):
  690. mat = expr.arg
  691. pform = self._print(mat)
  692. from sympy.matrices import MatrixSymbol, BlockMatrix
  693. if (not isinstance(mat, MatrixSymbol) and
  694. not isinstance(mat, BlockMatrix) and mat.is_MatrixExpr):
  695. pform = prettyForm(*pform.parens())
  696. pform = pform**(prettyForm('T'))
  697. return pform
  698. def _print_Adjoint(self, expr):
  699. mat = expr.arg
  700. pform = self._print(mat)
  701. if self._use_unicode:
  702. dag = prettyForm('\N{DAGGER}')
  703. else:
  704. dag = prettyForm('+')
  705. from sympy.matrices import MatrixSymbol, BlockMatrix
  706. if (not isinstance(mat, MatrixSymbol) and
  707. not isinstance(mat, BlockMatrix) and mat.is_MatrixExpr):
  708. pform = prettyForm(*pform.parens())
  709. pform = pform**dag
  710. return pform
  711. def _print_BlockMatrix(self, B):
  712. if B.blocks.shape == (1, 1):
  713. return self._print(B.blocks[0, 0])
  714. return self._print(B.blocks)
  715. def _print_MatAdd(self, expr):
  716. s = None
  717. for item in expr.args:
  718. pform = self._print(item)
  719. if s is None:
  720. s = pform # First element
  721. else:
  722. coeff = item.as_coeff_mmul()[0]
  723. if S(coeff).could_extract_minus_sign():
  724. s = prettyForm(*stringPict.next(s, ' '))
  725. pform = self._print(item)
  726. else:
  727. s = prettyForm(*stringPict.next(s, ' + '))
  728. s = prettyForm(*stringPict.next(s, pform))
  729. return s
  730. def _print_MatMul(self, expr):
  731. args = list(expr.args)
  732. from sympy.matrices.expressions.hadamard import HadamardProduct
  733. from sympy.matrices.expressions.kronecker import KroneckerProduct
  734. from sympy.matrices.expressions.matadd import MatAdd
  735. for i, a in enumerate(args):
  736. if (isinstance(a, (Add, MatAdd, HadamardProduct, KroneckerProduct))
  737. and len(expr.args) > 1):
  738. args[i] = prettyForm(*self._print(a).parens())
  739. else:
  740. args[i] = self._print(a)
  741. return prettyForm.__mul__(*args)
  742. def _print_Identity(self, expr):
  743. if self._use_unicode:
  744. return prettyForm('\N{MATHEMATICAL DOUBLE-STRUCK CAPITAL I}')
  745. else:
  746. return prettyForm('I')
  747. def _print_ZeroMatrix(self, expr):
  748. if self._use_unicode:
  749. return prettyForm('\N{MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO}')
  750. else:
  751. return prettyForm('0')
  752. def _print_OneMatrix(self, expr):
  753. if self._use_unicode:
  754. return prettyForm('\N{MATHEMATICAL DOUBLE-STRUCK DIGIT ONE}')
  755. else:
  756. return prettyForm('1')
  757. def _print_DotProduct(self, expr):
  758. args = list(expr.args)
  759. for i, a in enumerate(args):
  760. args[i] = self._print(a)
  761. return prettyForm.__mul__(*args)
  762. def _print_MatPow(self, expr):
  763. pform = self._print(expr.base)
  764. from sympy.matrices import MatrixSymbol
  765. if not isinstance(expr.base, MatrixSymbol) and expr.base.is_MatrixExpr:
  766. pform = prettyForm(*pform.parens())
  767. pform = pform**(self._print(expr.exp))
  768. return pform
  769. def _print_HadamardProduct(self, expr):
  770. from sympy.matrices.expressions.hadamard import HadamardProduct
  771. from sympy.matrices.expressions.matadd import MatAdd
  772. from sympy.matrices.expressions.matmul import MatMul
  773. if self._use_unicode:
  774. delim = pretty_atom('Ring')
  775. else:
  776. delim = '.*'
  777. return self._print_seq(expr.args, None, None, delim,
  778. parenthesize=lambda x: isinstance(x, (MatAdd, MatMul, HadamardProduct)))
  779. def _print_HadamardPower(self, expr):
  780. # from sympy import MatAdd, MatMul
  781. if self._use_unicode:
  782. circ = pretty_atom('Ring')
  783. else:
  784. circ = self._print('.')
  785. pretty_base = self._print(expr.base)
  786. pretty_exp = self._print(expr.exp)
  787. if precedence(expr.exp) < PRECEDENCE["Mul"]:
  788. pretty_exp = prettyForm(*pretty_exp.parens())
  789. pretty_circ_exp = prettyForm(
  790. binding=prettyForm.LINE,
  791. *stringPict.next(circ, pretty_exp)
  792. )
  793. return pretty_base**pretty_circ_exp
  794. def _print_KroneckerProduct(self, expr):
  795. from sympy.matrices.expressions.matadd import MatAdd
  796. from sympy.matrices.expressions.matmul import MatMul
  797. if self._use_unicode:
  798. delim = ' \N{N-ARY CIRCLED TIMES OPERATOR} '
  799. else:
  800. delim = ' x '
  801. return self._print_seq(expr.args, None, None, delim,
  802. parenthesize=lambda x: isinstance(x, (MatAdd, MatMul)))
  803. def _print_FunctionMatrix(self, X):
  804. D = self._print(X.lamda.expr)
  805. D = prettyForm(*D.parens('[', ']'))
  806. return D
  807. def _print_TransferFunction(self, expr):
  808. if not expr.num == 1:
  809. num, den = expr.num, expr.den
  810. res = Mul(num, Pow(den, -1, evaluate=False), evaluate=False)
  811. return self._print_Mul(res)
  812. else:
  813. return self._print(1)/self._print(expr.den)
  814. def _print_Series(self, expr):
  815. args = list(expr.args)
  816. for i, a in enumerate(expr.args):
  817. args[i] = prettyForm(*self._print(a).parens())
  818. return prettyForm.__mul__(*args)
  819. def _print_MIMOSeries(self, expr):
  820. from sympy.physics.control.lti import MIMOParallel
  821. args = list(expr.args)
  822. pretty_args = []
  823. for i, a in enumerate(reversed(args)):
  824. if (isinstance(a, MIMOParallel) and len(expr.args) > 1):
  825. expression = self._print(a)
  826. expression.baseline = expression.height()//2
  827. pretty_args.append(prettyForm(*expression.parens()))
  828. else:
  829. expression = self._print(a)
  830. expression.baseline = expression.height()//2
  831. pretty_args.append(expression)
  832. return prettyForm.__mul__(*pretty_args)
  833. def _print_Parallel(self, expr):
  834. s = None
  835. for item in expr.args:
  836. pform = self._print(item)
  837. if s is None:
  838. s = pform # First element
  839. else:
  840. s = prettyForm(*stringPict.next(s))
  841. s.baseline = s.height()//2
  842. s = prettyForm(*stringPict.next(s, ' + '))
  843. s = prettyForm(*stringPict.next(s, pform))
  844. return s
  845. def _print_MIMOParallel(self, expr):
  846. from sympy.physics.control.lti import TransferFunctionMatrix
  847. s = None
  848. for item in expr.args:
  849. pform = self._print(item)
  850. if s is None:
  851. s = pform # First element
  852. else:
  853. s = prettyForm(*stringPict.next(s))
  854. s.baseline = s.height()//2
  855. s = prettyForm(*stringPict.next(s, ' + '))
  856. if isinstance(item, TransferFunctionMatrix):
  857. s.baseline = s.height() - 1
  858. s = prettyForm(*stringPict.next(s, pform))
  859. # s.baseline = s.height()//2
  860. return s
  861. def _print_Feedback(self, expr):
  862. from sympy.physics.control import TransferFunction, Series
  863. num, tf = expr.sys1, TransferFunction(1, 1, expr.var)
  864. num_arg_list = list(num.args) if isinstance(num, Series) else [num]
  865. den_arg_list = list(expr.sys2.args) if \
  866. isinstance(expr.sys2, Series) else [expr.sys2]
  867. if isinstance(num, Series) and isinstance(expr.sys2, Series):
  868. den = Series(*num_arg_list, *den_arg_list)
  869. elif isinstance(num, Series) and isinstance(expr.sys2, TransferFunction):
  870. if expr.sys2 == tf:
  871. den = Series(*num_arg_list)
  872. else:
  873. den = Series(*num_arg_list, expr.sys2)
  874. elif isinstance(num, TransferFunction) and isinstance(expr.sys2, Series):
  875. if num == tf:
  876. den = Series(*den_arg_list)
  877. else:
  878. den = Series(num, *den_arg_list)
  879. else:
  880. if num == tf:
  881. den = Series(*den_arg_list)
  882. elif expr.sys2 == tf:
  883. den = Series(*num_arg_list)
  884. else:
  885. den = Series(*num_arg_list, *den_arg_list)
  886. denom = prettyForm(*stringPict.next(self._print(tf)))
  887. denom.baseline = denom.height()//2
  888. denom = prettyForm(*stringPict.next(denom, ' + ')) if expr.sign == -1 \
  889. else prettyForm(*stringPict.next(denom, ' - '))
  890. denom = prettyForm(*stringPict.next(denom, self._print(den)))
  891. return self._print(num)/denom
  892. def _print_MIMOFeedback(self, expr):
  893. from sympy.physics.control import MIMOSeries, TransferFunctionMatrix
  894. inv_mat = self._print(MIMOSeries(expr.sys2, expr.sys1))
  895. plant = self._print(expr.sys1)
  896. _feedback = prettyForm(*stringPict.next(inv_mat))
  897. _feedback = prettyForm(*stringPict.right("I + ", _feedback)) if expr.sign == -1 \
  898. else prettyForm(*stringPict.right("I - ", _feedback))
  899. _feedback = prettyForm(*stringPict.parens(_feedback))
  900. _feedback.baseline = 0
  901. _feedback = prettyForm(*stringPict.right(_feedback, '-1 '))
  902. _feedback.baseline = _feedback.height()//2
  903. _feedback = prettyForm.__mul__(_feedback, prettyForm(" "))
  904. if isinstance(expr.sys1, TransferFunctionMatrix):
  905. _feedback.baseline = _feedback.height() - 1
  906. _feedback = prettyForm(*stringPict.next(_feedback, plant))
  907. return _feedback
  908. def _print_TransferFunctionMatrix(self, expr):
  909. mat = self._print(expr._expr_mat)
  910. mat.baseline = mat.height() - 1
  911. subscript = greek_unicode['tau'] if self._use_unicode else r'{t}'
  912. mat = prettyForm(*mat.right(subscript))
  913. return mat
  914. def _print_BasisDependent(self, expr):
  915. from sympy.vector import Vector
  916. if not self._use_unicode:
  917. raise NotImplementedError("ASCII pretty printing of BasisDependent is not implemented")
  918. if expr == expr.zero:
  919. return prettyForm(expr.zero._pretty_form)
  920. o1 = []
  921. vectstrs = []
  922. if isinstance(expr, Vector):
  923. items = expr.separate().items()
  924. else:
  925. items = [(0, expr)]
  926. for system, vect in items:
  927. inneritems = list(vect.components.items())
  928. inneritems.sort(key = lambda x: x[0].__str__())
  929. for k, v in inneritems:
  930. #if the coef of the basis vector is 1
  931. #we skip the 1
  932. if v == 1:
  933. o1.append("" +
  934. k._pretty_form)
  935. #Same for -1
  936. elif v == -1:
  937. o1.append("(-1) " +
  938. k._pretty_form)
  939. #For a general expr
  940. else:
  941. #We always wrap the measure numbers in
  942. #parentheses
  943. arg_str = self._print(
  944. v).parens()[0]
  945. o1.append(arg_str + ' ' + k._pretty_form)
  946. vectstrs.append(k._pretty_form)
  947. #outstr = u("").join(o1)
  948. if o1[0].startswith(" + "):
  949. o1[0] = o1[0][3:]
  950. elif o1[0].startswith(" "):
  951. o1[0] = o1[0][1:]
  952. #Fixing the newlines
  953. lengths = []
  954. strs = ['']
  955. flag = []
  956. for i, partstr in enumerate(o1):
  957. flag.append(0)
  958. # XXX: What is this hack?
  959. if '\n' in partstr:
  960. tempstr = partstr
  961. tempstr = tempstr.replace(vectstrs[i], '')
  962. if '\N{RIGHT PARENTHESIS EXTENSION}' in tempstr: # If scalar is a fraction
  963. for paren in range(len(tempstr)):
  964. flag[i] = 1
  965. if tempstr[paren] == '\N{RIGHT PARENTHESIS EXTENSION}' and tempstr[paren + 1] == '\n':
  966. # We want to place the vector string after all the right parentheses, because
  967. # otherwise, the vector will be in the middle of the string
  968. tempstr = tempstr[:paren] + '\N{RIGHT PARENTHESIS EXTENSION}'\
  969. + ' ' + vectstrs[i] + tempstr[paren + 1:]
  970. break
  971. elif '\N{RIGHT PARENTHESIS LOWER HOOK}' in tempstr:
  972. # We want to place the vector string after all the right parentheses, because
  973. # otherwise, the vector will be in the middle of the string. For this reason,
  974. # we insert the vector string at the rightmost index.
  975. index = tempstr.rfind('\N{RIGHT PARENTHESIS LOWER HOOK}')
  976. if index != -1: # then this character was found in this string
  977. flag[i] = 1
  978. tempstr = tempstr[:index] + '\N{RIGHT PARENTHESIS LOWER HOOK}'\
  979. + ' ' + vectstrs[i] + tempstr[index + 1:]
  980. o1[i] = tempstr
  981. o1 = [x.split('\n') for x in o1]
  982. n_newlines = max([len(x) for x in o1]) # Width of part in its pretty form
  983. if 1 in flag: # If there was a fractional scalar
  984. for i, parts in enumerate(o1):
  985. if len(parts) == 1: # If part has no newline
  986. parts.insert(0, ' ' * (len(parts[0])))
  987. flag[i] = 1
  988. for i, parts in enumerate(o1):
  989. lengths.append(len(parts[flag[i]]))
  990. for j in range(n_newlines):
  991. if j+1 <= len(parts):
  992. if j >= len(strs):
  993. strs.append(' ' * (sum(lengths[:-1]) +
  994. 3*(len(lengths)-1)))
  995. if j == flag[i]:
  996. strs[flag[i]] += parts[flag[i]] + ' + '
  997. else:
  998. strs[j] += parts[j] + ' '*(lengths[-1] -
  999. len(parts[j])+
  1000. 3)
  1001. else:
  1002. if j >= len(strs):
  1003. strs.append(' ' * (sum(lengths[:-1]) +
  1004. 3*(len(lengths)-1)))
  1005. strs[j] += ' '*(lengths[-1]+3)
  1006. return prettyForm('\n'.join([s[:-3] for s in strs]))
  1007. def _print_NDimArray(self, expr):
  1008. from sympy.matrices.immutable import ImmutableMatrix
  1009. if expr.rank() == 0:
  1010. return self._print(expr[()])
  1011. level_str = [[]] + [[] for i in range(expr.rank())]
  1012. shape_ranges = [list(range(i)) for i in expr.shape]
  1013. # leave eventual matrix elements unflattened
  1014. mat = lambda x: ImmutableMatrix(x, evaluate=False)
  1015. for outer_i in itertools.product(*shape_ranges):
  1016. level_str[-1].append(expr[outer_i])
  1017. even = True
  1018. for back_outer_i in range(expr.rank()-1, -1, -1):
  1019. if len(level_str[back_outer_i+1]) < expr.shape[back_outer_i]:
  1020. break
  1021. if even:
  1022. level_str[back_outer_i].append(level_str[back_outer_i+1])
  1023. else:
  1024. level_str[back_outer_i].append(mat(
  1025. level_str[back_outer_i+1]))
  1026. if len(level_str[back_outer_i + 1]) == 1:
  1027. level_str[back_outer_i][-1] = mat(
  1028. [[level_str[back_outer_i][-1]]])
  1029. even = not even
  1030. level_str[back_outer_i+1] = []
  1031. out_expr = level_str[0][0]
  1032. if expr.rank() % 2 == 1:
  1033. out_expr = mat([out_expr])
  1034. return self._print(out_expr)
  1035. def _printer_tensor_indices(self, name, indices, index_map={}):
  1036. center = stringPict(name)
  1037. top = stringPict(" "*center.width())
  1038. bot = stringPict(" "*center.width())
  1039. last_valence = None
  1040. prev_map = None
  1041. for i, index in enumerate(indices):
  1042. indpic = self._print(index.args[0])
  1043. if ((index in index_map) or prev_map) and last_valence == index.is_up:
  1044. if index.is_up:
  1045. top = prettyForm(*stringPict.next(top, ","))
  1046. else:
  1047. bot = prettyForm(*stringPict.next(bot, ","))
  1048. if index in index_map:
  1049. indpic = prettyForm(*stringPict.next(indpic, "="))
  1050. indpic = prettyForm(*stringPict.next(indpic, self._print(index_map[index])))
  1051. prev_map = True
  1052. else:
  1053. prev_map = False
  1054. if index.is_up:
  1055. top = stringPict(*top.right(indpic))
  1056. center = stringPict(*center.right(" "*indpic.width()))
  1057. bot = stringPict(*bot.right(" "*indpic.width()))
  1058. else:
  1059. bot = stringPict(*bot.right(indpic))
  1060. center = stringPict(*center.right(" "*indpic.width()))
  1061. top = stringPict(*top.right(" "*indpic.width()))
  1062. last_valence = index.is_up
  1063. pict = prettyForm(*center.above(top))
  1064. pict = prettyForm(*pict.below(bot))
  1065. return pict
  1066. def _print_Tensor(self, expr):
  1067. name = expr.args[0].name
  1068. indices = expr.get_indices()
  1069. return self._printer_tensor_indices(name, indices)
  1070. def _print_TensorElement(self, expr):
  1071. name = expr.expr.args[0].name
  1072. indices = expr.expr.get_indices()
  1073. index_map = expr.index_map
  1074. return self._printer_tensor_indices(name, indices, index_map)
  1075. def _print_TensMul(self, expr):
  1076. sign, args = expr._get_args_for_traditional_printer()
  1077. args = [
  1078. prettyForm(*self._print(i).parens()) if
  1079. precedence_traditional(i) < PRECEDENCE["Mul"] else self._print(i)
  1080. for i in args
  1081. ]
  1082. pform = prettyForm.__mul__(*args)
  1083. if sign:
  1084. return prettyForm(*pform.left(sign))
  1085. else:
  1086. return pform
  1087. def _print_TensAdd(self, expr):
  1088. args = [
  1089. prettyForm(*self._print(i).parens()) if
  1090. precedence_traditional(i) < PRECEDENCE["Mul"] else self._print(i)
  1091. for i in expr.args
  1092. ]
  1093. return prettyForm.__add__(*args)
  1094. def _print_TensorIndex(self, expr):
  1095. sym = expr.args[0]
  1096. if not expr.is_up:
  1097. sym = -sym
  1098. return self._print(sym)
  1099. def _print_PartialDerivative(self, deriv):
  1100. if self._use_unicode:
  1101. deriv_symbol = U('PARTIAL DIFFERENTIAL')
  1102. else:
  1103. deriv_symbol = r'd'
  1104. x = None
  1105. for variable in reversed(deriv.variables):
  1106. s = self._print(variable)
  1107. ds = prettyForm(*s.left(deriv_symbol))
  1108. if x is None:
  1109. x = ds
  1110. else:
  1111. x = prettyForm(*x.right(' '))
  1112. x = prettyForm(*x.right(ds))
  1113. f = prettyForm(
  1114. binding=prettyForm.FUNC, *self._print(deriv.expr).parens())
  1115. pform = prettyForm(deriv_symbol)
  1116. if len(deriv.variables) > 1:
  1117. pform = pform**self._print(len(deriv.variables))
  1118. pform = prettyForm(*pform.below(stringPict.LINE, x))
  1119. pform.baseline = pform.baseline + 1
  1120. pform = prettyForm(*stringPict.next(pform, f))
  1121. pform.binding = prettyForm.MUL
  1122. return pform
  1123. def _print_Piecewise(self, pexpr):
  1124. P = {}
  1125. for n, ec in enumerate(pexpr.args):
  1126. P[n, 0] = self._print(ec.expr)
  1127. if ec.cond == True:
  1128. P[n, 1] = prettyForm('otherwise')
  1129. else:
  1130. P[n, 1] = prettyForm(
  1131. *prettyForm('for ').right(self._print(ec.cond)))
  1132. hsep = 2
  1133. vsep = 1
  1134. len_args = len(pexpr.args)
  1135. # max widths
  1136. maxw = [max([P[i, j].width() for i in range(len_args)])
  1137. for j in range(2)]
  1138. # FIXME: Refactor this code and matrix into some tabular environment.
  1139. # drawing result
  1140. D = None
  1141. for i in range(len_args):
  1142. D_row = None
  1143. for j in range(2):
  1144. p = P[i, j]
  1145. assert p.width() <= maxw[j]
  1146. wdelta = maxw[j] - p.width()
  1147. wleft = wdelta // 2
  1148. wright = wdelta - wleft
  1149. p = prettyForm(*p.right(' '*wright))
  1150. p = prettyForm(*p.left(' '*wleft))
  1151. if D_row is None:
  1152. D_row = p
  1153. continue
  1154. D_row = prettyForm(*D_row.right(' '*hsep)) # h-spacer
  1155. D_row = prettyForm(*D_row.right(p))
  1156. if D is None:
  1157. D = D_row # first row in a picture
  1158. continue
  1159. # v-spacer
  1160. for _ in range(vsep):
  1161. D = prettyForm(*D.below(' '))
  1162. D = prettyForm(*D.below(D_row))
  1163. D = prettyForm(*D.parens('{', ''))
  1164. D.baseline = D.height()//2
  1165. D.binding = prettyForm.OPEN
  1166. return D
  1167. def _print_ITE(self, ite):
  1168. from sympy.functions.elementary.piecewise import Piecewise
  1169. return self._print(ite.rewrite(Piecewise))
  1170. def _hprint_vec(self, v):
  1171. D = None
  1172. for a in v:
  1173. p = a
  1174. if D is None:
  1175. D = p
  1176. else:
  1177. D = prettyForm(*D.right(', '))
  1178. D = prettyForm(*D.right(p))
  1179. if D is None:
  1180. D = stringPict(' ')
  1181. return D
  1182. def _hprint_vseparator(self, p1, p2, left=None, right=None, delimiter='', ifascii_nougly=False):
  1183. if ifascii_nougly and not self._use_unicode:
  1184. return self._print_seq((p1, '|', p2), left=left, right=right,
  1185. delimiter=delimiter, ifascii_nougly=True)
  1186. tmp = self._print_seq((p1, p2,), left=left, right=right, delimiter=delimiter)
  1187. sep = stringPict(vobj('|', tmp.height()), baseline=tmp.baseline)
  1188. return self._print_seq((p1, sep, p2), left=left, right=right,
  1189. delimiter=delimiter)
  1190. def _print_hyper(self, e):
  1191. # FIXME refactor Matrix, Piecewise, and this into a tabular environment
  1192. ap = [self._print(a) for a in e.ap]
  1193. bq = [self._print(b) for b in e.bq]
  1194. P = self._print(e.argument)
  1195. P.baseline = P.height()//2
  1196. # Drawing result - first create the ap, bq vectors
  1197. D = None
  1198. for v in [ap, bq]:
  1199. D_row = self._hprint_vec(v)
  1200. if D is None:
  1201. D = D_row # first row in a picture
  1202. else:
  1203. D = prettyForm(*D.below(' '))
  1204. D = prettyForm(*D.below(D_row))
  1205. # make sure that the argument `z' is centred vertically
  1206. D.baseline = D.height()//2
  1207. # insert horizontal separator
  1208. P = prettyForm(*P.left(' '))
  1209. D = prettyForm(*D.right(' '))
  1210. # insert separating `|`
  1211. D = self._hprint_vseparator(D, P)
  1212. # add parens
  1213. D = prettyForm(*D.parens('(', ')'))
  1214. # create the F symbol
  1215. above = D.height()//2 - 1
  1216. below = D.height() - above - 1
  1217. sz, t, b, add, img = annotated('F')
  1218. F = prettyForm('\n' * (above - t) + img + '\n' * (below - b),
  1219. baseline=above + sz)
  1220. add = (sz + 1)//2
  1221. F = prettyForm(*F.left(self._print(len(e.ap))))
  1222. F = prettyForm(*F.right(self._print(len(e.bq))))
  1223. F.baseline = above + add
  1224. D = prettyForm(*F.right(' ', D))
  1225. return D
  1226. def _print_meijerg(self, e):
  1227. # FIXME refactor Matrix, Piecewise, and this into a tabular environment
  1228. v = {}
  1229. v[(0, 0)] = [self._print(a) for a in e.an]
  1230. v[(0, 1)] = [self._print(a) for a in e.aother]
  1231. v[(1, 0)] = [self._print(b) for b in e.bm]
  1232. v[(1, 1)] = [self._print(b) for b in e.bother]
  1233. P = self._print(e.argument)
  1234. P.baseline = P.height()//2
  1235. vp = {}
  1236. for idx in v:
  1237. vp[idx] = self._hprint_vec(v[idx])
  1238. for i in range(2):
  1239. maxw = max(vp[(0, i)].width(), vp[(1, i)].width())
  1240. for j in range(2):
  1241. s = vp[(j, i)]
  1242. left = (maxw - s.width()) // 2
  1243. right = maxw - left - s.width()
  1244. s = prettyForm(*s.left(' ' * left))
  1245. s = prettyForm(*s.right(' ' * right))
  1246. vp[(j, i)] = s
  1247. D1 = prettyForm(*vp[(0, 0)].right(' ', vp[(0, 1)]))
  1248. D1 = prettyForm(*D1.below(' '))
  1249. D2 = prettyForm(*vp[(1, 0)].right(' ', vp[(1, 1)]))
  1250. D = prettyForm(*D1.below(D2))
  1251. # make sure that the argument `z' is centred vertically
  1252. D.baseline = D.height()//2
  1253. # insert horizontal separator
  1254. P = prettyForm(*P.left(' '))
  1255. D = prettyForm(*D.right(' '))
  1256. # insert separating `|`
  1257. D = self._hprint_vseparator(D, P)
  1258. # add parens
  1259. D = prettyForm(*D.parens('(', ')'))
  1260. # create the G symbol
  1261. above = D.height()//2 - 1
  1262. below = D.height() - above - 1
  1263. sz, t, b, add, img = annotated('G')
  1264. F = prettyForm('\n' * (above - t) + img + '\n' * (below - b),
  1265. baseline=above + sz)
  1266. pp = self._print(len(e.ap))
  1267. pq = self._print(len(e.bq))
  1268. pm = self._print(len(e.bm))
  1269. pn = self._print(len(e.an))
  1270. def adjust(p1, p2):
  1271. diff = p1.width() - p2.width()
  1272. if diff == 0:
  1273. return p1, p2
  1274. elif diff > 0:
  1275. return p1, prettyForm(*p2.left(' '*diff))
  1276. else:
  1277. return prettyForm(*p1.left(' '*-diff)), p2
  1278. pp, pm = adjust(pp, pm)
  1279. pq, pn = adjust(pq, pn)
  1280. pu = prettyForm(*pm.right(', ', pn))
  1281. pl = prettyForm(*pp.right(', ', pq))
  1282. ht = F.baseline - above - 2
  1283. if ht > 0:
  1284. pu = prettyForm(*pu.below('\n'*ht))
  1285. p = prettyForm(*pu.below(pl))
  1286. F.baseline = above
  1287. F = prettyForm(*F.right(p))
  1288. F.baseline = above + add
  1289. D = prettyForm(*F.right(' ', D))
  1290. return D
  1291. def _print_ExpBase(self, e):
  1292. # TODO should exp_polar be printed differently?
  1293. # what about exp_polar(0), exp_polar(1)?
  1294. base = prettyForm(pretty_atom('Exp1', 'e'))
  1295. return base ** self._print(e.args[0])
  1296. def _print_Exp1(self, e):
  1297. return prettyForm(pretty_atom('Exp1', 'e'))
  1298. def _print_Function(self, e, sort=False, func_name=None, left='(',
  1299. right=')'):
  1300. # optional argument func_name for supplying custom names
  1301. # XXX works only for applied functions
  1302. return self._helper_print_function(e.func, e.args, sort=sort, func_name=func_name, left=left, right=right)
  1303. def _print_mathieuc(self, e):
  1304. return self._print_Function(e, func_name='C')
  1305. def _print_mathieus(self, e):
  1306. return self._print_Function(e, func_name='S')
  1307. def _print_mathieucprime(self, e):
  1308. return self._print_Function(e, func_name="C'")
  1309. def _print_mathieusprime(self, e):
  1310. return self._print_Function(e, func_name="S'")
  1311. def _helper_print_function(self, func, args, sort=False, func_name=None,
  1312. delimiter=', ', elementwise=False, left='(',
  1313. right=')'):
  1314. if sort:
  1315. args = sorted(args, key=default_sort_key)
  1316. if not func_name and hasattr(func, "__name__"):
  1317. func_name = func.__name__
  1318. if func_name:
  1319. prettyFunc = self._print(Symbol(func_name))
  1320. else:
  1321. prettyFunc = prettyForm(*self._print(func).parens())
  1322. if elementwise:
  1323. if self._use_unicode:
  1324. circ = pretty_atom('Modifier Letter Low Ring')
  1325. else:
  1326. circ = '.'
  1327. circ = self._print(circ)
  1328. prettyFunc = prettyForm(
  1329. binding=prettyForm.LINE,
  1330. *stringPict.next(prettyFunc, circ)
  1331. )
  1332. prettyArgs = prettyForm(*self._print_seq(args, delimiter=delimiter).parens(
  1333. left=left, right=right))
  1334. pform = prettyForm(
  1335. binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
  1336. # store pform parts so it can be reassembled e.g. when powered
  1337. pform.prettyFunc = prettyFunc
  1338. pform.prettyArgs = prettyArgs
  1339. return pform
  1340. def _print_ElementwiseApplyFunction(self, e):
  1341. func = e.function
  1342. arg = e.expr
  1343. args = [arg]
  1344. return self._helper_print_function(func, args, delimiter="", elementwise=True)
  1345. @property
  1346. def _special_function_classes(self):
  1347. from sympy.functions.special.tensor_functions import KroneckerDelta
  1348. from sympy.functions.special.gamma_functions import gamma, lowergamma
  1349. from sympy.functions.special.zeta_functions import lerchphi
  1350. from sympy.functions.special.beta_functions import beta
  1351. from sympy.functions.special.delta_functions import DiracDelta
  1352. from sympy.functions.special.error_functions import Chi
  1353. return {KroneckerDelta: [greek_unicode['delta'], 'delta'],
  1354. gamma: [greek_unicode['Gamma'], 'Gamma'],
  1355. lerchphi: [greek_unicode['Phi'], 'lerchphi'],
  1356. lowergamma: [greek_unicode['gamma'], 'gamma'],
  1357. beta: [greek_unicode['Beta'], 'B'],
  1358. DiracDelta: [greek_unicode['delta'], 'delta'],
  1359. Chi: ['Chi', 'Chi']}
  1360. def _print_FunctionClass(self, expr):
  1361. for cls in self._special_function_classes:
  1362. if issubclass(expr, cls) and expr.__name__ == cls.__name__:
  1363. if self._use_unicode:
  1364. return prettyForm(self._special_function_classes[cls][0])
  1365. else:
  1366. return prettyForm(self._special_function_classes[cls][1])
  1367. func_name = expr.__name__
  1368. return prettyForm(pretty_symbol(func_name))
  1369. def _print_GeometryEntity(self, expr):
  1370. # GeometryEntity is based on Tuple but should not print like a Tuple
  1371. return self.emptyPrinter(expr)
  1372. def _print_lerchphi(self, e):
  1373. func_name = greek_unicode['Phi'] if self._use_unicode else 'lerchphi'
  1374. return self._print_Function(e, func_name=func_name)
  1375. def _print_dirichlet_eta(self, e):
  1376. func_name = greek_unicode['eta'] if self._use_unicode else 'dirichlet_eta'
  1377. return self._print_Function(e, func_name=func_name)
  1378. def _print_Heaviside(self, e):
  1379. func_name = greek_unicode['theta'] if self._use_unicode else 'Heaviside'
  1380. if e.args[1] is S.Half:
  1381. pform = prettyForm(*self._print(e.args[0]).parens())
  1382. pform = prettyForm(*pform.left(func_name))
  1383. return pform
  1384. else:
  1385. return self._print_Function(e, func_name=func_name)
  1386. def _print_fresnels(self, e):
  1387. return self._print_Function(e, func_name="S")
  1388. def _print_fresnelc(self, e):
  1389. return self._print_Function(e, func_name="C")
  1390. def _print_airyai(self, e):
  1391. return self._print_Function(e, func_name="Ai")
  1392. def _print_airybi(self, e):
  1393. return self._print_Function(e, func_name="Bi")
  1394. def _print_airyaiprime(self, e):
  1395. return self._print_Function(e, func_name="Ai'")
  1396. def _print_airybiprime(self, e):
  1397. return self._print_Function(e, func_name="Bi'")
  1398. def _print_LambertW(self, e):
  1399. return self._print_Function(e, func_name="W")
  1400. def _print_Covariance(self, e):
  1401. return self._print_Function(e, func_name="Cov")
  1402. def _print_Variance(self, e):
  1403. return self._print_Function(e, func_name="Var")
  1404. def _print_Probability(self, e):
  1405. return self._print_Function(e, func_name="P")
  1406. def _print_Expectation(self, e):
  1407. return self._print_Function(e, func_name="E", left='[', right=']')
  1408. def _print_Lambda(self, e):
  1409. expr = e.expr
  1410. sig = e.signature
  1411. if self._use_unicode:
  1412. arrow = " \N{RIGHTWARDS ARROW FROM BAR} "
  1413. else:
  1414. arrow = " -> "
  1415. if len(sig) == 1 and sig[0].is_symbol:
  1416. sig = sig[0]
  1417. var_form = self._print(sig)
  1418. return prettyForm(*stringPict.next(var_form, arrow, self._print(expr)), binding=8)
  1419. def _print_Order(self, expr):
  1420. pform = self._print(expr.expr)
  1421. if (expr.point and any(p != S.Zero for p in expr.point)) or \
  1422. len(expr.variables) > 1:
  1423. pform = prettyForm(*pform.right("; "))
  1424. if len(expr.variables) > 1:
  1425. pform = prettyForm(*pform.right(self._print(expr.variables)))
  1426. elif len(expr.variables):
  1427. pform = prettyForm(*pform.right(self._print(expr.variables[0])))
  1428. if self._use_unicode:
  1429. pform = prettyForm(*pform.right(" \N{RIGHTWARDS ARROW} "))
  1430. else:
  1431. pform = prettyForm(*pform.right(" -> "))
  1432. if len(expr.point) > 1:
  1433. pform = prettyForm(*pform.right(self._print(expr.point)))
  1434. else:
  1435. pform = prettyForm(*pform.right(self._print(expr.point[0])))
  1436. pform = prettyForm(*pform.parens())
  1437. pform = prettyForm(*pform.left("O"))
  1438. return pform
  1439. def _print_SingularityFunction(self, e):
  1440. if self._use_unicode:
  1441. shift = self._print(e.args[0]-e.args[1])
  1442. n = self._print(e.args[2])
  1443. base = prettyForm("<")
  1444. base = prettyForm(*base.right(shift))
  1445. base = prettyForm(*base.right(">"))
  1446. pform = base**n
  1447. return pform
  1448. else:
  1449. n = self._print(e.args[2])
  1450. shift = self._print(e.args[0]-e.args[1])
  1451. base = self._print_seq(shift, "<", ">", ' ')
  1452. return base**n
  1453. def _print_beta(self, e):
  1454. func_name = greek_unicode['Beta'] if self._use_unicode else 'B'
  1455. return self._print_Function(e, func_name=func_name)
  1456. def _print_betainc(self, e):
  1457. func_name = "B'"
  1458. return self._print_Function(e, func_name=func_name)
  1459. def _print_betainc_regularized(self, e):
  1460. func_name = 'I'
  1461. return self._print_Function(e, func_name=func_name)
  1462. def _print_gamma(self, e):
  1463. func_name = greek_unicode['Gamma'] if self._use_unicode else 'Gamma'
  1464. return self._print_Function(e, func_name=func_name)
  1465. def _print_uppergamma(self, e):
  1466. func_name = greek_unicode['Gamma'] if self._use_unicode else 'Gamma'
  1467. return self._print_Function(e, func_name=func_name)
  1468. def _print_lowergamma(self, e):
  1469. func_name = greek_unicode['gamma'] if self._use_unicode else 'lowergamma'
  1470. return self._print_Function(e, func_name=func_name)
  1471. def _print_DiracDelta(self, e):
  1472. if self._use_unicode:
  1473. if len(e.args) == 2:
  1474. a = prettyForm(greek_unicode['delta'])
  1475. b = self._print(e.args[1])
  1476. b = prettyForm(*b.parens())
  1477. c = self._print(e.args[0])
  1478. c = prettyForm(*c.parens())
  1479. pform = a**b
  1480. pform = prettyForm(*pform.right(' '))
  1481. pform = prettyForm(*pform.right(c))
  1482. return pform
  1483. pform = self._print(e.args[0])
  1484. pform = prettyForm(*pform.parens())
  1485. pform = prettyForm(*pform.left(greek_unicode['delta']))
  1486. return pform
  1487. else:
  1488. return self._print_Function(e)
  1489. def _print_expint(self, e):
  1490. if e.args[0].is_Integer and self._use_unicode:
  1491. return self._print_Function(Function('E_%s' % e.args[0])(e.args[1]))
  1492. return self._print_Function(e)
  1493. def _print_Chi(self, e):
  1494. # This needs a special case since otherwise it comes out as greek
  1495. # letter chi...
  1496. prettyFunc = prettyForm("Chi")
  1497. prettyArgs = prettyForm(*self._print_seq(e.args).parens())
  1498. pform = prettyForm(
  1499. binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
  1500. # store pform parts so it can be reassembled e.g. when powered
  1501. pform.prettyFunc = prettyFunc
  1502. pform.prettyArgs = prettyArgs
  1503. return pform
  1504. def _print_elliptic_e(self, e):
  1505. pforma0 = self._print(e.args[0])
  1506. if len(e.args) == 1:
  1507. pform = pforma0
  1508. else:
  1509. pforma1 = self._print(e.args[1])
  1510. pform = self._hprint_vseparator(pforma0, pforma1)
  1511. pform = prettyForm(*pform.parens())
  1512. pform = prettyForm(*pform.left('E'))
  1513. return pform
  1514. def _print_elliptic_k(self, e):
  1515. pform = self._print(e.args[0])
  1516. pform = prettyForm(*pform.parens())
  1517. pform = prettyForm(*pform.left('K'))
  1518. return pform
  1519. def _print_elliptic_f(self, e):
  1520. pforma0 = self._print(e.args[0])
  1521. pforma1 = self._print(e.args[1])
  1522. pform = self._hprint_vseparator(pforma0, pforma1)
  1523. pform = prettyForm(*pform.parens())
  1524. pform = prettyForm(*pform.left('F'))
  1525. return pform
  1526. def _print_elliptic_pi(self, e):
  1527. name = greek_unicode['Pi'] if self._use_unicode else 'Pi'
  1528. pforma0 = self._print(e.args[0])
  1529. pforma1 = self._print(e.args[1])
  1530. if len(e.args) == 2:
  1531. pform = self._hprint_vseparator(pforma0, pforma1)
  1532. else:
  1533. pforma2 = self._print(e.args[2])
  1534. pforma = self._hprint_vseparator(pforma1, pforma2, ifascii_nougly=False)
  1535. pforma = prettyForm(*pforma.left('; '))
  1536. pform = prettyForm(*pforma.left(pforma0))
  1537. pform = prettyForm(*pform.parens())
  1538. pform = prettyForm(*pform.left(name))
  1539. return pform
  1540. def _print_GoldenRatio(self, expr):
  1541. if self._use_unicode:
  1542. return prettyForm(pretty_symbol('phi'))
  1543. return self._print(Symbol("GoldenRatio"))
  1544. def _print_EulerGamma(self, expr):
  1545. if self._use_unicode:
  1546. return prettyForm(pretty_symbol('gamma'))
  1547. return self._print(Symbol("EulerGamma"))
  1548. def _print_Catalan(self, expr):
  1549. return self._print(Symbol("G"))
  1550. def _print_Mod(self, expr):
  1551. pform = self._print(expr.args[0])
  1552. if pform.binding > prettyForm.MUL:
  1553. pform = prettyForm(*pform.parens())
  1554. pform = prettyForm(*pform.right(' mod '))
  1555. pform = prettyForm(*pform.right(self._print(expr.args[1])))
  1556. pform.binding = prettyForm.OPEN
  1557. return pform
  1558. def _print_Add(self, expr, order=None):
  1559. terms = self._as_ordered_terms(expr, order=order)
  1560. pforms, indices = [], []
  1561. def pretty_negative(pform, index):
  1562. """Prepend a minus sign to a pretty form. """
  1563. #TODO: Move this code to prettyForm
  1564. if index == 0:
  1565. if pform.height() > 1:
  1566. pform_neg = '- '
  1567. else:
  1568. pform_neg = '-'
  1569. else:
  1570. pform_neg = ' - '
  1571. if (pform.binding > prettyForm.NEG
  1572. or pform.binding == prettyForm.ADD):
  1573. p = stringPict(*pform.parens())
  1574. else:
  1575. p = pform
  1576. p = stringPict.next(pform_neg, p)
  1577. # Lower the binding to NEG, even if it was higher. Otherwise, it
  1578. # will print as a + ( - (b)), instead of a - (b).
  1579. return prettyForm(binding=prettyForm.NEG, *p)
  1580. for i, term in enumerate(terms):
  1581. if term.is_Mul and term.could_extract_minus_sign():
  1582. coeff, other = term.as_coeff_mul(rational=False)
  1583. if coeff == -1:
  1584. negterm = Mul(*other, evaluate=False)
  1585. else:
  1586. negterm = Mul(-coeff, *other, evaluate=False)
  1587. pform = self._print(negterm)
  1588. pforms.append(pretty_negative(pform, i))
  1589. elif term.is_Rational and term.q > 1:
  1590. pforms.append(None)
  1591. indices.append(i)
  1592. elif term.is_Number and term < 0:
  1593. pform = self._print(-term)
  1594. pforms.append(pretty_negative(pform, i))
  1595. elif term.is_Relational:
  1596. pforms.append(prettyForm(*self._print(term).parens()))
  1597. else:
  1598. pforms.append(self._print(term))
  1599. if indices:
  1600. large = True
  1601. for pform in pforms:
  1602. if pform is not None and pform.height() > 1:
  1603. break
  1604. else:
  1605. large = False
  1606. for i in indices:
  1607. term, negative = terms[i], False
  1608. if term < 0:
  1609. term, negative = -term, True
  1610. if large:
  1611. pform = prettyForm(str(term.p))/prettyForm(str(term.q))
  1612. else:
  1613. pform = self._print(term)
  1614. if negative:
  1615. pform = pretty_negative(pform, i)
  1616. pforms[i] = pform
  1617. return prettyForm.__add__(*pforms)
  1618. def _print_Mul(self, product):
  1619. from sympy.physics.units import Quantity
  1620. # Check for unevaluated Mul. In this case we need to make sure the
  1621. # identities are visible, multiple Rational factors are not combined
  1622. # etc so we display in a straight-forward form that fully preserves all
  1623. # args and their order.
  1624. args = product.args
  1625. if args[0] is S.One or any(isinstance(arg, Number) for arg in args[1:]):
  1626. strargs = list(map(self._print, args))
  1627. # XXX: This is a hack to work around the fact that
  1628. # prettyForm.__mul__ absorbs a leading -1 in the args. Probably it
  1629. # would be better to fix this in prettyForm.__mul__ instead.
  1630. negone = strargs[0] == '-1'
  1631. if negone:
  1632. strargs[0] = prettyForm('1', 0, 0)
  1633. obj = prettyForm.__mul__(*strargs)
  1634. if negone:
  1635. obj = prettyForm('-' + obj.s, obj.baseline, obj.binding)
  1636. return obj
  1637. a = [] # items in the numerator
  1638. b = [] # items that are in the denominator (if any)
  1639. if self.order not in ('old', 'none'):
  1640. args = product.as_ordered_factors()
  1641. else:
  1642. args = list(product.args)
  1643. # If quantities are present append them at the back
  1644. args = sorted(args, key=lambda x: isinstance(x, Quantity) or
  1645. (isinstance(x, Pow) and isinstance(x.base, Quantity)))
  1646. # Gather terms for numerator/denominator
  1647. for item in args:
  1648. if item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative:
  1649. if item.exp != -1:
  1650. b.append(Pow(item.base, -item.exp, evaluate=False))
  1651. else:
  1652. b.append(Pow(item.base, -item.exp))
  1653. elif item.is_Rational and item is not S.Infinity:
  1654. if item.p != 1:
  1655. a.append( Rational(item.p) )
  1656. if item.q != 1:
  1657. b.append( Rational(item.q) )
  1658. else:
  1659. a.append(item)
  1660. # Convert to pretty forms. Parentheses are added by `__mul__`.
  1661. a = [self._print(ai) for ai in a]
  1662. b = [self._print(bi) for bi in b]
  1663. # Construct a pretty form
  1664. if len(b) == 0:
  1665. return prettyForm.__mul__(*a)
  1666. else:
  1667. if len(a) == 0:
  1668. a.append( self._print(S.One) )
  1669. return prettyForm.__mul__(*a)/prettyForm.__mul__(*b)
  1670. # A helper function for _print_Pow to print x**(1/n)
  1671. def _print_nth_root(self, base, root):
  1672. bpretty = self._print(base)
  1673. # In very simple cases, use a single-char root sign
  1674. if (self._settings['use_unicode_sqrt_char'] and self._use_unicode
  1675. and root == 2 and bpretty.height() == 1
  1676. and (bpretty.width() == 1
  1677. or (base.is_Integer and base.is_nonnegative))):
  1678. return prettyForm(*bpretty.left('\N{SQUARE ROOT}'))
  1679. # Construct root sign, start with the \/ shape
  1680. _zZ = xobj('/', 1)
  1681. rootsign = xobj('\\', 1) + _zZ
  1682. # Constructing the number to put on root
  1683. rpretty = self._print(root)
  1684. # roots look bad if they are not a single line
  1685. if rpretty.height() != 1:
  1686. return self._print(base)**self._print(1/root)
  1687. # If power is half, no number should appear on top of root sign
  1688. exp = '' if root == 2 else str(rpretty).ljust(2)
  1689. if len(exp) > 2:
  1690. rootsign = ' '*(len(exp) - 2) + rootsign
  1691. # Stack the exponent
  1692. rootsign = stringPict(exp + '\n' + rootsign)
  1693. rootsign.baseline = 0
  1694. # Diagonal: length is one less than height of base
  1695. linelength = bpretty.height() - 1
  1696. diagonal = stringPict('\n'.join(
  1697. ' '*(linelength - i - 1) + _zZ + ' '*i
  1698. for i in range(linelength)
  1699. ))
  1700. # Put baseline just below lowest line: next to exp
  1701. diagonal.baseline = linelength - 1
  1702. # Make the root symbol
  1703. rootsign = prettyForm(*rootsign.right(diagonal))
  1704. # Det the baseline to match contents to fix the height
  1705. # but if the height of bpretty is one, the rootsign must be one higher
  1706. rootsign.baseline = max(1, bpretty.baseline)
  1707. #build result
  1708. s = prettyForm(hobj('_', 2 + bpretty.width()))
  1709. s = prettyForm(*bpretty.above(s))
  1710. s = prettyForm(*s.left(rootsign))
  1711. return s
  1712. def _print_Pow(self, power):
  1713. from sympy.simplify.simplify import fraction
  1714. b, e = power.as_base_exp()
  1715. if power.is_commutative:
  1716. if e is S.NegativeOne:
  1717. return prettyForm("1")/self._print(b)
  1718. n, d = fraction(e)
  1719. if n is S.One and d.is_Atom and not e.is_Integer and (e.is_Rational or d.is_Symbol) \
  1720. and self._settings['root_notation']:
  1721. return self._print_nth_root(b, d)
  1722. if e.is_Rational and e < 0:
  1723. return prettyForm("1")/self._print(Pow(b, -e, evaluate=False))
  1724. if b.is_Relational:
  1725. return prettyForm(*self._print(b).parens()).__pow__(self._print(e))
  1726. return self._print(b)**self._print(e)
  1727. def _print_UnevaluatedExpr(self, expr):
  1728. return self._print(expr.args[0])
  1729. def __print_numer_denom(self, p, q):
  1730. if q == 1:
  1731. if p < 0:
  1732. return prettyForm(str(p), binding=prettyForm.NEG)
  1733. else:
  1734. return prettyForm(str(p))
  1735. elif abs(p) >= 10 and abs(q) >= 10:
  1736. # If more than one digit in numer and denom, print larger fraction
  1737. if p < 0:
  1738. return prettyForm(str(p), binding=prettyForm.NEG)/prettyForm(str(q))
  1739. # Old printing method:
  1740. #pform = prettyForm(str(-p))/prettyForm(str(q))
  1741. #return prettyForm(binding=prettyForm.NEG, *pform.left('- '))
  1742. else:
  1743. return prettyForm(str(p))/prettyForm(str(q))
  1744. else:
  1745. return None
  1746. def _print_Rational(self, expr):
  1747. result = self.__print_numer_denom(expr.p, expr.q)
  1748. if result is not None:
  1749. return result
  1750. else:
  1751. return self.emptyPrinter(expr)
  1752. def _print_Fraction(self, expr):
  1753. result = self.__print_numer_denom(expr.numerator, expr.denominator)
  1754. if result is not None:
  1755. return result
  1756. else:
  1757. return self.emptyPrinter(expr)
  1758. def _print_ProductSet(self, p):
  1759. if len(p.sets) >= 1 and not has_variety(p.sets):
  1760. return self._print(p.sets[0]) ** self._print(len(p.sets))
  1761. else:
  1762. prod_char = "\N{MULTIPLICATION SIGN}" if self._use_unicode else 'x'
  1763. return self._print_seq(p.sets, None, None, ' %s ' % prod_char,
  1764. parenthesize=lambda set: set.is_Union or
  1765. set.is_Intersection or set.is_ProductSet)
  1766. def _print_FiniteSet(self, s):
  1767. items = sorted(s.args, key=default_sort_key)
  1768. return self._print_seq(items, '{', '}', ', ' )
  1769. def _print_Range(self, s):
  1770. if self._use_unicode:
  1771. dots = "\N{HORIZONTAL ELLIPSIS}"
  1772. else:
  1773. dots = '...'
  1774. if s.start.is_infinite and s.stop.is_infinite:
  1775. if s.step.is_positive:
  1776. printset = dots, -1, 0, 1, dots
  1777. else:
  1778. printset = dots, 1, 0, -1, dots
  1779. elif s.start.is_infinite:
  1780. printset = dots, s[-1] - s.step, s[-1]
  1781. elif s.stop.is_infinite:
  1782. it = iter(s)
  1783. printset = next(it), next(it), dots
  1784. elif len(s) > 4:
  1785. it = iter(s)
  1786. printset = next(it), next(it), dots, s[-1]
  1787. else:
  1788. printset = tuple(s)
  1789. return self._print_seq(printset, '{', '}', ', ' )
  1790. def _print_Interval(self, i):
  1791. if i.start == i.end:
  1792. return self._print_seq(i.args[:1], '{', '}')
  1793. else:
  1794. if i.left_open:
  1795. left = '('
  1796. else:
  1797. left = '['
  1798. if i.right_open:
  1799. right = ')'
  1800. else:
  1801. right = ']'
  1802. return self._print_seq(i.args[:2], left, right)
  1803. def _print_AccumulationBounds(self, i):
  1804. left = '<'
  1805. right = '>'
  1806. return self._print_seq(i.args[:2], left, right)
  1807. def _print_Intersection(self, u):
  1808. delimiter = ' %s ' % pretty_atom('Intersection', 'n')
  1809. return self._print_seq(u.args, None, None, delimiter,
  1810. parenthesize=lambda set: set.is_ProductSet or
  1811. set.is_Union or set.is_Complement)
  1812. def _print_Union(self, u):
  1813. union_delimiter = ' %s ' % pretty_atom('Union', 'U')
  1814. return self._print_seq(u.args, None, None, union_delimiter,
  1815. parenthesize=lambda set: set.is_ProductSet or
  1816. set.is_Intersection or set.is_Complement)
  1817. def _print_SymmetricDifference(self, u):
  1818. if not self._use_unicode:
  1819. raise NotImplementedError("ASCII pretty printing of SymmetricDifference is not implemented")
  1820. sym_delimeter = ' %s ' % pretty_atom('SymmetricDifference')
  1821. return self._print_seq(u.args, None, None, sym_delimeter)
  1822. def _print_Complement(self, u):
  1823. delimiter = r' \ '
  1824. return self._print_seq(u.args, None, None, delimiter,
  1825. parenthesize=lambda set: set.is_ProductSet or set.is_Intersection
  1826. or set.is_Union)
  1827. def _print_ImageSet(self, ts):
  1828. if self._use_unicode:
  1829. inn = "\N{SMALL ELEMENT OF}"
  1830. else:
  1831. inn = 'in'
  1832. fun = ts.lamda
  1833. sets = ts.base_sets
  1834. signature = fun.signature
  1835. expr = self._print(fun.expr)
  1836. # TODO: the stuff to the left of the | and the stuff to the right of
  1837. # the | should have independent baselines, that way something like
  1838. # ImageSet(Lambda(x, 1/x**2), S.Naturals) prints the "x in N" part
  1839. # centered on the right instead of aligned with the fraction bar on
  1840. # the left. The same also applies to ConditionSet and ComplexRegion
  1841. if len(signature) == 1:
  1842. S = self._print_seq((signature[0], inn, sets[0]),
  1843. delimiter=' ')
  1844. return self._hprint_vseparator(expr, S,
  1845. left='{', right='}',
  1846. ifascii_nougly=True, delimiter=' ')
  1847. else:
  1848. pargs = tuple(j for var, setv in zip(signature, sets) for j in
  1849. (var, ' ', inn, ' ', setv, ", "))
  1850. S = self._print_seq(pargs[:-1], delimiter='')
  1851. return self._hprint_vseparator(expr, S,
  1852. left='{', right='}',
  1853. ifascii_nougly=True, delimiter=' ')
  1854. def _print_ConditionSet(self, ts):
  1855. if self._use_unicode:
  1856. inn = "\N{SMALL ELEMENT OF}"
  1857. # using _and because and is a keyword and it is bad practice to
  1858. # overwrite them
  1859. _and = "\N{LOGICAL AND}"
  1860. else:
  1861. inn = 'in'
  1862. _and = 'and'
  1863. variables = self._print_seq(Tuple(ts.sym))
  1864. as_expr = getattr(ts.condition, 'as_expr', None)
  1865. if as_expr is not None:
  1866. cond = self._print(ts.condition.as_expr())
  1867. else:
  1868. cond = self._print(ts.condition)
  1869. if self._use_unicode:
  1870. cond = self._print(cond)
  1871. cond = prettyForm(*cond.parens())
  1872. if ts.base_set is S.UniversalSet:
  1873. return self._hprint_vseparator(variables, cond, left="{",
  1874. right="}", ifascii_nougly=True,
  1875. delimiter=' ')
  1876. base = self._print(ts.base_set)
  1877. C = self._print_seq((variables, inn, base, _and, cond),
  1878. delimiter=' ')
  1879. return self._hprint_vseparator(variables, C, left="{", right="}",
  1880. ifascii_nougly=True, delimiter=' ')
  1881. def _print_ComplexRegion(self, ts):
  1882. if self._use_unicode:
  1883. inn = "\N{SMALL ELEMENT OF}"
  1884. else:
  1885. inn = 'in'
  1886. variables = self._print_seq(ts.variables)
  1887. expr = self._print(ts.expr)
  1888. prodsets = self._print(ts.sets)
  1889. C = self._print_seq((variables, inn, prodsets),
  1890. delimiter=' ')
  1891. return self._hprint_vseparator(expr, C, left="{", right="}",
  1892. ifascii_nougly=True, delimiter=' ')
  1893. def _print_Contains(self, e):
  1894. var, set = e.args
  1895. if self._use_unicode:
  1896. el = " \N{ELEMENT OF} "
  1897. return prettyForm(*stringPict.next(self._print(var),
  1898. el, self._print(set)), binding=8)
  1899. else:
  1900. return prettyForm(sstr(e))
  1901. def _print_FourierSeries(self, s):
  1902. if s.an.formula is S.Zero and s.bn.formula is S.Zero:
  1903. return self._print(s.a0)
  1904. if self._use_unicode:
  1905. dots = "\N{HORIZONTAL ELLIPSIS}"
  1906. else:
  1907. dots = '...'
  1908. return self._print_Add(s.truncate()) + self._print(dots)
  1909. def _print_FormalPowerSeries(self, s):
  1910. return self._print_Add(s.infinite)
  1911. def _print_SetExpr(self, se):
  1912. pretty_set = prettyForm(*self._print(se.set).parens())
  1913. pretty_name = self._print(Symbol("SetExpr"))
  1914. return prettyForm(*pretty_name.right(pretty_set))
  1915. def _print_SeqFormula(self, s):
  1916. if self._use_unicode:
  1917. dots = "\N{HORIZONTAL ELLIPSIS}"
  1918. else:
  1919. dots = '...'
  1920. if len(s.start.free_symbols) > 0 or len(s.stop.free_symbols) > 0:
  1921. raise NotImplementedError("Pretty printing of sequences with symbolic bound not implemented")
  1922. if s.start is S.NegativeInfinity:
  1923. stop = s.stop
  1924. printset = (dots, s.coeff(stop - 3), s.coeff(stop - 2),
  1925. s.coeff(stop - 1), s.coeff(stop))
  1926. elif s.stop is S.Infinity or s.length > 4:
  1927. printset = s[:4]
  1928. printset.append(dots)
  1929. printset = tuple(printset)
  1930. else:
  1931. printset = tuple(s)
  1932. return self._print_list(printset)
  1933. _print_SeqPer = _print_SeqFormula
  1934. _print_SeqAdd = _print_SeqFormula
  1935. _print_SeqMul = _print_SeqFormula
  1936. def _print_seq(self, seq, left=None, right=None, delimiter=', ',
  1937. parenthesize=lambda x: False, ifascii_nougly=True):
  1938. try:
  1939. pforms = []
  1940. for item in seq:
  1941. pform = self._print(item)
  1942. if parenthesize(item):
  1943. pform = prettyForm(*pform.parens())
  1944. if pforms:
  1945. pforms.append(delimiter)
  1946. pforms.append(pform)
  1947. if not pforms:
  1948. s = stringPict('')
  1949. else:
  1950. s = prettyForm(*stringPict.next(*pforms))
  1951. # XXX: Under the tests from #15686 the above raises:
  1952. # AttributeError: 'Fake' object has no attribute 'baseline'
  1953. # This is caught below but that is not the right way to
  1954. # fix it.
  1955. except AttributeError:
  1956. s = None
  1957. for item in seq:
  1958. pform = self.doprint(item)
  1959. if parenthesize(item):
  1960. pform = prettyForm(*pform.parens())
  1961. if s is None:
  1962. # first element
  1963. s = pform
  1964. else :
  1965. s = prettyForm(*stringPict.next(s, delimiter))
  1966. s = prettyForm(*stringPict.next(s, pform))
  1967. if s is None:
  1968. s = stringPict('')
  1969. s = prettyForm(*s.parens(left, right, ifascii_nougly=ifascii_nougly))
  1970. return s
  1971. def join(self, delimiter, args):
  1972. pform = None
  1973. for arg in args:
  1974. if pform is None:
  1975. pform = arg
  1976. else:
  1977. pform = prettyForm(*pform.right(delimiter))
  1978. pform = prettyForm(*pform.right(arg))
  1979. if pform is None:
  1980. return prettyForm("")
  1981. else:
  1982. return pform
  1983. def _print_list(self, l):
  1984. return self._print_seq(l, '[', ']')
  1985. def _print_tuple(self, t):
  1986. if len(t) == 1:
  1987. ptuple = prettyForm(*stringPict.next(self._print(t[0]), ','))
  1988. return prettyForm(*ptuple.parens('(', ')', ifascii_nougly=True))
  1989. else:
  1990. return self._print_seq(t, '(', ')')
  1991. def _print_Tuple(self, expr):
  1992. return self._print_tuple(expr)
  1993. def _print_dict(self, d):
  1994. keys = sorted(d.keys(), key=default_sort_key)
  1995. items = []
  1996. for k in keys:
  1997. K = self._print(k)
  1998. V = self._print(d[k])
  1999. s = prettyForm(*stringPict.next(K, ': ', V))
  2000. items.append(s)
  2001. return self._print_seq(items, '{', '}')
  2002. def _print_Dict(self, d):
  2003. return self._print_dict(d)
  2004. def _print_set(self, s):
  2005. if not s:
  2006. return prettyForm('set()')
  2007. items = sorted(s, key=default_sort_key)
  2008. pretty = self._print_seq(items)
  2009. pretty = prettyForm(*pretty.parens('{', '}', ifascii_nougly=True))
  2010. return pretty
  2011. def _print_frozenset(self, s):
  2012. if not s:
  2013. return prettyForm('frozenset()')
  2014. items = sorted(s, key=default_sort_key)
  2015. pretty = self._print_seq(items)
  2016. pretty = prettyForm(*pretty.parens('{', '}', ifascii_nougly=True))
  2017. pretty = prettyForm(*pretty.parens('(', ')', ifascii_nougly=True))
  2018. pretty = prettyForm(*stringPict.next(type(s).__name__, pretty))
  2019. return pretty
  2020. def _print_UniversalSet(self, s):
  2021. if self._use_unicode:
  2022. return prettyForm("\N{MATHEMATICAL DOUBLE-STRUCK CAPITAL U}")
  2023. else:
  2024. return prettyForm('UniversalSet')
  2025. def _print_PolyRing(self, ring):
  2026. return prettyForm(sstr(ring))
  2027. def _print_FracField(self, field):
  2028. return prettyForm(sstr(field))
  2029. def _print_FreeGroupElement(self, elm):
  2030. return prettyForm(str(elm))
  2031. def _print_PolyElement(self, poly):
  2032. return prettyForm(sstr(poly))
  2033. def _print_FracElement(self, frac):
  2034. return prettyForm(sstr(frac))
  2035. def _print_AlgebraicNumber(self, expr):
  2036. if expr.is_aliased:
  2037. return self._print(expr.as_poly().as_expr())
  2038. else:
  2039. return self._print(expr.as_expr())
  2040. def _print_ComplexRootOf(self, expr):
  2041. args = [self._print_Add(expr.expr, order='lex'), expr.index]
  2042. pform = prettyForm(*self._print_seq(args).parens())
  2043. pform = prettyForm(*pform.left('CRootOf'))
  2044. return pform
  2045. def _print_RootSum(self, expr):
  2046. args = [self._print_Add(expr.expr, order='lex')]
  2047. if expr.fun is not S.IdentityFunction:
  2048. args.append(self._print(expr.fun))
  2049. pform = prettyForm(*self._print_seq(args).parens())
  2050. pform = prettyForm(*pform.left('RootSum'))
  2051. return pform
  2052. def _print_FiniteField(self, expr):
  2053. if self._use_unicode:
  2054. form = '\N{DOUBLE-STRUCK CAPITAL Z}_%d'
  2055. else:
  2056. form = 'GF(%d)'
  2057. return prettyForm(pretty_symbol(form % expr.mod))
  2058. def _print_IntegerRing(self, expr):
  2059. if self._use_unicode:
  2060. return prettyForm('\N{DOUBLE-STRUCK CAPITAL Z}')
  2061. else:
  2062. return prettyForm('ZZ')
  2063. def _print_RationalField(self, expr):
  2064. if self._use_unicode:
  2065. return prettyForm('\N{DOUBLE-STRUCK CAPITAL Q}')
  2066. else:
  2067. return prettyForm('QQ')
  2068. def _print_RealField(self, domain):
  2069. if self._use_unicode:
  2070. prefix = '\N{DOUBLE-STRUCK CAPITAL R}'
  2071. else:
  2072. prefix = 'RR'
  2073. if domain.has_default_precision:
  2074. return prettyForm(prefix)
  2075. else:
  2076. return self._print(pretty_symbol(prefix + "_" + str(domain.precision)))
  2077. def _print_ComplexField(self, domain):
  2078. if self._use_unicode:
  2079. prefix = '\N{DOUBLE-STRUCK CAPITAL C}'
  2080. else:
  2081. prefix = 'CC'
  2082. if domain.has_default_precision:
  2083. return prettyForm(prefix)
  2084. else:
  2085. return self._print(pretty_symbol(prefix + "_" + str(domain.precision)))
  2086. def _print_PolynomialRing(self, expr):
  2087. args = list(expr.symbols)
  2088. if not expr.order.is_default:
  2089. order = prettyForm(*prettyForm("order=").right(self._print(expr.order)))
  2090. args.append(order)
  2091. pform = self._print_seq(args, '[', ']')
  2092. pform = prettyForm(*pform.left(self._print(expr.domain)))
  2093. return pform
  2094. def _print_FractionField(self, expr):
  2095. args = list(expr.symbols)
  2096. if not expr.order.is_default:
  2097. order = prettyForm(*prettyForm("order=").right(self._print(expr.order)))
  2098. args.append(order)
  2099. pform = self._print_seq(args, '(', ')')
  2100. pform = prettyForm(*pform.left(self._print(expr.domain)))
  2101. return pform
  2102. def _print_PolynomialRingBase(self, expr):
  2103. g = expr.symbols
  2104. if str(expr.order) != str(expr.default_order):
  2105. g = g + ("order=" + str(expr.order),)
  2106. pform = self._print_seq(g, '[', ']')
  2107. pform = prettyForm(*pform.left(self._print(expr.domain)))
  2108. return pform
  2109. def _print_GroebnerBasis(self, basis):
  2110. exprs = [ self._print_Add(arg, order=basis.order)
  2111. for arg in basis.exprs ]
  2112. exprs = prettyForm(*self.join(", ", exprs).parens(left="[", right="]"))
  2113. gens = [ self._print(gen) for gen in basis.gens ]
  2114. domain = prettyForm(
  2115. *prettyForm("domain=").right(self._print(basis.domain)))
  2116. order = prettyForm(
  2117. *prettyForm("order=").right(self._print(basis.order)))
  2118. pform = self.join(", ", [exprs] + gens + [domain, order])
  2119. pform = prettyForm(*pform.parens())
  2120. pform = prettyForm(*pform.left(basis.__class__.__name__))
  2121. return pform
  2122. def _print_Subs(self, e):
  2123. pform = self._print(e.expr)
  2124. pform = prettyForm(*pform.parens())
  2125. h = pform.height() if pform.height() > 1 else 2
  2126. rvert = stringPict(vobj('|', h), baseline=pform.baseline)
  2127. pform = prettyForm(*pform.right(rvert))
  2128. b = pform.baseline
  2129. pform.baseline = pform.height() - 1
  2130. pform = prettyForm(*pform.right(self._print_seq([
  2131. self._print_seq((self._print(v[0]), xsym('=='), self._print(v[1])),
  2132. delimiter='') for v in zip(e.variables, e.point) ])))
  2133. pform.baseline = b
  2134. return pform
  2135. def _print_number_function(self, e, name):
  2136. # Print name_arg[0] for one argument or name_arg[0](arg[1])
  2137. # for more than one argument
  2138. pform = prettyForm(name)
  2139. arg = self._print(e.args[0])
  2140. pform_arg = prettyForm(" "*arg.width())
  2141. pform_arg = prettyForm(*pform_arg.below(arg))
  2142. pform = prettyForm(*pform.right(pform_arg))
  2143. if len(e.args) == 1:
  2144. return pform
  2145. m, x = e.args
  2146. # TODO: copy-pasted from _print_Function: can we do better?
  2147. prettyFunc = pform
  2148. prettyArgs = prettyForm(*self._print_seq([x]).parens())
  2149. pform = prettyForm(
  2150. binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
  2151. pform.prettyFunc = prettyFunc
  2152. pform.prettyArgs = prettyArgs
  2153. return pform
  2154. def _print_euler(self, e):
  2155. return self._print_number_function(e, "E")
  2156. def _print_catalan(self, e):
  2157. return self._print_number_function(e, "C")
  2158. def _print_bernoulli(self, e):
  2159. return self._print_number_function(e, "B")
  2160. _print_bell = _print_bernoulli
  2161. def _print_lucas(self, e):
  2162. return self._print_number_function(e, "L")
  2163. def _print_fibonacci(self, e):
  2164. return self._print_number_function(e, "F")
  2165. def _print_tribonacci(self, e):
  2166. return self._print_number_function(e, "T")
  2167. def _print_stieltjes(self, e):
  2168. if self._use_unicode:
  2169. return self._print_number_function(e, '\N{GREEK SMALL LETTER GAMMA}')
  2170. else:
  2171. return self._print_number_function(e, "stieltjes")
  2172. def _print_KroneckerDelta(self, e):
  2173. pform = self._print(e.args[0])
  2174. pform = prettyForm(*pform.right(prettyForm(',')))
  2175. pform = prettyForm(*pform.right(self._print(e.args[1])))
  2176. if self._use_unicode:
  2177. a = stringPict(pretty_symbol('delta'))
  2178. else:
  2179. a = stringPict('d')
  2180. b = pform
  2181. top = stringPict(*b.left(' '*a.width()))
  2182. bot = stringPict(*a.right(' '*b.width()))
  2183. return prettyForm(binding=prettyForm.POW, *bot.below(top))
  2184. def _print_RandomDomain(self, d):
  2185. if hasattr(d, 'as_boolean'):
  2186. pform = self._print('Domain: ')
  2187. pform = prettyForm(*pform.right(self._print(d.as_boolean())))
  2188. return pform
  2189. elif hasattr(d, 'set'):
  2190. pform = self._print('Domain: ')
  2191. pform = prettyForm(*pform.right(self._print(d.symbols)))
  2192. pform = prettyForm(*pform.right(self._print(' in ')))
  2193. pform = prettyForm(*pform.right(self._print(d.set)))
  2194. return pform
  2195. elif hasattr(d, 'symbols'):
  2196. pform = self._print('Domain on ')
  2197. pform = prettyForm(*pform.right(self._print(d.symbols)))
  2198. return pform
  2199. else:
  2200. return self._print(None)
  2201. def _print_DMP(self, p):
  2202. try:
  2203. if p.ring is not None:
  2204. # TODO incorporate order
  2205. return self._print(p.ring.to_sympy(p))
  2206. except SympifyError:
  2207. pass
  2208. return self._print(repr(p))
  2209. def _print_DMF(self, p):
  2210. return self._print_DMP(p)
  2211. def _print_Object(self, object):
  2212. return self._print(pretty_symbol(object.name))
  2213. def _print_Morphism(self, morphism):
  2214. arrow = xsym("-->")
  2215. domain = self._print(morphism.domain)
  2216. codomain = self._print(morphism.codomain)
  2217. tail = domain.right(arrow, codomain)[0]
  2218. return prettyForm(tail)
  2219. def _print_NamedMorphism(self, morphism):
  2220. pretty_name = self._print(pretty_symbol(morphism.name))
  2221. pretty_morphism = self._print_Morphism(morphism)
  2222. return prettyForm(pretty_name.right(":", pretty_morphism)[0])
  2223. def _print_IdentityMorphism(self, morphism):
  2224. from sympy.categories import NamedMorphism
  2225. return self._print_NamedMorphism(
  2226. NamedMorphism(morphism.domain, morphism.codomain, "id"))
  2227. def _print_CompositeMorphism(self, morphism):
  2228. circle = xsym(".")
  2229. # All components of the morphism have names and it is thus
  2230. # possible to build the name of the composite.
  2231. component_names_list = [pretty_symbol(component.name) for
  2232. component in morphism.components]
  2233. component_names_list.reverse()
  2234. component_names = circle.join(component_names_list) + ":"
  2235. pretty_name = self._print(component_names)
  2236. pretty_morphism = self._print_Morphism(morphism)
  2237. return prettyForm(pretty_name.right(pretty_morphism)[0])
  2238. def _print_Category(self, category):
  2239. return self._print(pretty_symbol(category.name))
  2240. def _print_Diagram(self, diagram):
  2241. if not diagram.premises:
  2242. # This is an empty diagram.
  2243. return self._print(S.EmptySet)
  2244. pretty_result = self._print(diagram.premises)
  2245. if diagram.conclusions:
  2246. results_arrow = " %s " % xsym("==>")
  2247. pretty_conclusions = self._print(diagram.conclusions)[0]
  2248. pretty_result = pretty_result.right(
  2249. results_arrow, pretty_conclusions)
  2250. return prettyForm(pretty_result[0])
  2251. def _print_DiagramGrid(self, grid):
  2252. from sympy.matrices import Matrix
  2253. matrix = Matrix([[grid[i, j] if grid[i, j] else Symbol(" ")
  2254. for j in range(grid.width)]
  2255. for i in range(grid.height)])
  2256. return self._print_matrix_contents(matrix)
  2257. def _print_FreeModuleElement(self, m):
  2258. # Print as row vector for convenience, for now.
  2259. return self._print_seq(m, '[', ']')
  2260. def _print_SubModule(self, M):
  2261. return self._print_seq(M.gens, '<', '>')
  2262. def _print_FreeModule(self, M):
  2263. return self._print(M.ring)**self._print(M.rank)
  2264. def _print_ModuleImplementedIdeal(self, M):
  2265. return self._print_seq([x for [x] in M._module.gens], '<', '>')
  2266. def _print_QuotientRing(self, R):
  2267. return self._print(R.ring) / self._print(R.base_ideal)
  2268. def _print_QuotientRingElement(self, R):
  2269. return self._print(R.data) + self._print(R.ring.base_ideal)
  2270. def _print_QuotientModuleElement(self, m):
  2271. return self._print(m.data) + self._print(m.module.killed_module)
  2272. def _print_QuotientModule(self, M):
  2273. return self._print(M.base) / self._print(M.killed_module)
  2274. def _print_MatrixHomomorphism(self, h):
  2275. matrix = self._print(h._sympy_matrix())
  2276. matrix.baseline = matrix.height() // 2
  2277. pform = prettyForm(*matrix.right(' : ', self._print(h.domain),
  2278. ' %s> ' % hobj('-', 2), self._print(h.codomain)))
  2279. return pform
  2280. def _print_Manifold(self, manifold):
  2281. return self._print(manifold.name)
  2282. def _print_Patch(self, patch):
  2283. return self._print(patch.name)
  2284. def _print_CoordSystem(self, coords):
  2285. return self._print(coords.name)
  2286. def _print_BaseScalarField(self, field):
  2287. string = field._coord_sys.symbols[field._index].name
  2288. return self._print(pretty_symbol(string))
  2289. def _print_BaseVectorField(self, field):
  2290. s = U('PARTIAL DIFFERENTIAL') + '_' + field._coord_sys.symbols[field._index].name
  2291. return self._print(pretty_symbol(s))
  2292. def _print_Differential(self, diff):
  2293. if self._use_unicode:
  2294. d = '\N{DOUBLE-STRUCK ITALIC SMALL D}'
  2295. else:
  2296. d = 'd'
  2297. field = diff._form_field
  2298. if hasattr(field, '_coord_sys'):
  2299. string = field._coord_sys.symbols[field._index].name
  2300. return self._print(d + ' ' + pretty_symbol(string))
  2301. else:
  2302. pform = self._print(field)
  2303. pform = prettyForm(*pform.parens())
  2304. return prettyForm(*pform.left(d))
  2305. def _print_Tr(self, p):
  2306. #TODO: Handle indices
  2307. pform = self._print(p.args[0])
  2308. pform = prettyForm(*pform.left('%s(' % (p.__class__.__name__)))
  2309. pform = prettyForm(*pform.right(')'))
  2310. return pform
  2311. def _print_primenu(self, e):
  2312. pform = self._print(e.args[0])
  2313. pform = prettyForm(*pform.parens())
  2314. if self._use_unicode:
  2315. pform = prettyForm(*pform.left(greek_unicode['nu']))
  2316. else:
  2317. pform = prettyForm(*pform.left('nu'))
  2318. return pform
  2319. def _print_primeomega(self, e):
  2320. pform = self._print(e.args[0])
  2321. pform = prettyForm(*pform.parens())
  2322. if self._use_unicode:
  2323. pform = prettyForm(*pform.left(greek_unicode['Omega']))
  2324. else:
  2325. pform = prettyForm(*pform.left('Omega'))
  2326. return pform
  2327. def _print_Quantity(self, e):
  2328. if e.name.name == 'degree':
  2329. pform = self._print("\N{DEGREE SIGN}")
  2330. return pform
  2331. else:
  2332. return self.emptyPrinter(e)
  2333. def _print_AssignmentBase(self, e):
  2334. op = prettyForm(' ' + xsym(e.op) + ' ')
  2335. l = self._print(e.lhs)
  2336. r = self._print(e.rhs)
  2337. pform = prettyForm(*stringPict.next(l, op, r))
  2338. return pform
  2339. def _print_Str(self, s):
  2340. return self._print(s.name)
  2341. @print_function(PrettyPrinter)
  2342. def pretty(expr, **settings):
  2343. """Returns a string containing the prettified form of expr.
  2344. For information on keyword arguments see pretty_print function.
  2345. """
  2346. pp = PrettyPrinter(settings)
  2347. # XXX: this is an ugly hack, but at least it works
  2348. use_unicode = pp._settings['use_unicode']
  2349. uflag = pretty_use_unicode(use_unicode)
  2350. try:
  2351. return pp.doprint(expr)
  2352. finally:
  2353. pretty_use_unicode(uflag)
  2354. def pretty_print(expr, **kwargs):
  2355. """Prints expr in pretty form.
  2356. pprint is just a shortcut for this function.
  2357. Parameters
  2358. ==========
  2359. expr : expression
  2360. The expression to print.
  2361. wrap_line : bool, optional (default=True)
  2362. Line wrapping enabled/disabled.
  2363. num_columns : int or None, optional (default=None)
  2364. Number of columns before line breaking (default to None which reads
  2365. the terminal width), useful when using SymPy without terminal.
  2366. use_unicode : bool or None, optional (default=None)
  2367. Use unicode characters, such as the Greek letter pi instead of
  2368. the string pi.
  2369. full_prec : bool or string, optional (default="auto")
  2370. Use full precision.
  2371. order : bool or string, optional (default=None)
  2372. Set to 'none' for long expressions if slow; default is None.
  2373. use_unicode_sqrt_char : bool, optional (default=True)
  2374. Use compact single-character square root symbol (when unambiguous).
  2375. root_notation : bool, optional (default=True)
  2376. Set to 'False' for printing exponents of the form 1/n in fractional form.
  2377. By default exponent is printed in root form.
  2378. mat_symbol_style : string, optional (default="plain")
  2379. Set to "bold" for printing MatrixSymbols using a bold mathematical symbol face.
  2380. By default the standard face is used.
  2381. imaginary_unit : string, optional (default="i")
  2382. Letter to use for imaginary unit when use_unicode is True.
  2383. Can be "i" (default) or "j".
  2384. """
  2385. print(pretty(expr, **kwargs))
  2386. pprint = pretty_print
  2387. def pager_print(expr, **settings):
  2388. """Prints expr using the pager, in pretty form.
  2389. This invokes a pager command using pydoc. Lines are not wrapped
  2390. automatically. This routine is meant to be used with a pager that allows
  2391. sideways scrolling, like ``less -S``.
  2392. Parameters are the same as for ``pretty_print``. If you wish to wrap lines,
  2393. pass ``num_columns=None`` to auto-detect the width of the terminal.
  2394. """
  2395. from pydoc import pager
  2396. from locale import getpreferredencoding
  2397. if 'num_columns' not in settings:
  2398. settings['num_columns'] = 500000 # disable line wrap
  2399. pager(pretty(expr, **settings).encode(getpreferredencoding()))