pretty.py 103 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937
  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, is_subscriptable_in_unicode, center_pad, root as nth_root
  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=pretty_atom('NotEquiv'))
  199. if isinstance(arg, Implies):
  200. return self._print_Implies(arg, altchar=pretty_atom('NotArrow'))
  201. if arg.is_Boolean and not arg.is_Not:
  202. pform = prettyForm(*pform.parens())
  203. return prettyForm(*pform.left(pretty_atom('Not')))
  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, pretty_atom('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, pretty_atom('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, pretty_atom("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, pretty_atom('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, pretty_atom('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 pretty_atom('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 pretty_atom('Equiv'))
  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 = xobj('UpTack', 1)
  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(f"{xobj('-', 1)}{pretty_atom('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 = pretty_atom('SuperscriptPlus') if str(dir) == "+" else pretty_atom('SuperscriptMinus')
  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. left, right = center_pad(s.width(), maxw[j])
  589. s = prettyForm(*s.right(right))
  590. s = prettyForm(*s.left(left))
  591. # we don't need vcenter cells -- this is automatically done in
  592. # a pretty way because when their baselines are taking into
  593. # account in .right()
  594. if D_row is None:
  595. D_row = s # first box in a row
  596. continue
  597. D_row = prettyForm(*D_row.right(' '*hsep)) # h-spacer
  598. D_row = prettyForm(*D_row.right(s))
  599. if D is None:
  600. D = D_row # first row in a picture
  601. continue
  602. # v-spacer
  603. for _ in range(vsep):
  604. D = prettyForm(*D.below(' '))
  605. D = prettyForm(*D.below(D_row))
  606. if D is None:
  607. D = prettyForm('') # Empty Matrix
  608. return D
  609. def _print_MatrixBase(self, e, lparens='[', rparens=']'):
  610. D = self._print_matrix_contents(e)
  611. D.baseline = D.height()//2
  612. D = prettyForm(*D.parens(lparens, rparens))
  613. return D
  614. def _print_Determinant(self, e):
  615. mat = e.arg
  616. if mat.is_MatrixExpr:
  617. from sympy.matrices.expressions.blockmatrix import BlockMatrix
  618. if isinstance(mat, BlockMatrix):
  619. return self._print_MatrixBase(mat.blocks, lparens='|', rparens='|')
  620. D = self._print(mat)
  621. D.baseline = D.height()//2
  622. return prettyForm(*D.parens('|', '|'))
  623. else:
  624. return self._print_MatrixBase(mat, lparens='|', rparens='|')
  625. def _print_TensorProduct(self, expr):
  626. # This should somehow share the code with _print_WedgeProduct:
  627. if self._use_unicode:
  628. circled_times = "\u2297"
  629. else:
  630. circled_times = ".*"
  631. return self._print_seq(expr.args, None, None, circled_times,
  632. parenthesize=lambda x: precedence_traditional(x) <= PRECEDENCE["Mul"])
  633. def _print_WedgeProduct(self, expr):
  634. # This should somehow share the code with _print_TensorProduct:
  635. if self._use_unicode:
  636. wedge_symbol = "\u2227"
  637. else:
  638. wedge_symbol = '/\\'
  639. return self._print_seq(expr.args, None, None, wedge_symbol,
  640. parenthesize=lambda x: precedence_traditional(x) <= PRECEDENCE["Mul"])
  641. def _print_Trace(self, e):
  642. D = self._print(e.arg)
  643. D = prettyForm(*D.parens('(',')'))
  644. D.baseline = D.height()//2
  645. D = prettyForm(*D.left('\n'*(0) + 'tr'))
  646. return D
  647. def _print_MatrixElement(self, expr):
  648. from sympy.matrices import MatrixSymbol
  649. if (isinstance(expr.parent, MatrixSymbol)
  650. and expr.i.is_number and expr.j.is_number):
  651. return self._print(
  652. Symbol(expr.parent.name + '_%d%d' % (expr.i, expr.j)))
  653. else:
  654. prettyFunc = self._print(expr.parent)
  655. prettyFunc = prettyForm(*prettyFunc.parens())
  656. prettyIndices = self._print_seq((expr.i, expr.j), delimiter=', '
  657. ).parens(left='[', right=']')[0]
  658. pform = prettyForm(binding=prettyForm.FUNC,
  659. *stringPict.next(prettyFunc, prettyIndices))
  660. # store pform parts so it can be reassembled e.g. when powered
  661. pform.prettyFunc = prettyFunc
  662. pform.prettyArgs = prettyIndices
  663. return pform
  664. def _print_MatrixSlice(self, m):
  665. # XXX works only for applied functions
  666. from sympy.matrices import MatrixSymbol
  667. prettyFunc = self._print(m.parent)
  668. if not isinstance(m.parent, MatrixSymbol):
  669. prettyFunc = prettyForm(*prettyFunc.parens())
  670. def ppslice(x, dim):
  671. x = list(x)
  672. if x[2] == 1:
  673. del x[2]
  674. if x[0] == 0:
  675. x[0] = ''
  676. if x[1] == dim:
  677. x[1] = ''
  678. return prettyForm(*self._print_seq(x, delimiter=':'))
  679. prettyArgs = self._print_seq((ppslice(m.rowslice, m.parent.rows),
  680. ppslice(m.colslice, m.parent.cols)), delimiter=', ').parens(left='[', right=']')[0]
  681. pform = prettyForm(
  682. binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
  683. # store pform parts so it can be reassembled e.g. when powered
  684. pform.prettyFunc = prettyFunc
  685. pform.prettyArgs = prettyArgs
  686. return pform
  687. def _print_Transpose(self, expr):
  688. mat = expr.arg
  689. pform = self._print(mat)
  690. from sympy.matrices import MatrixSymbol, BlockMatrix
  691. if (not isinstance(mat, MatrixSymbol) and
  692. not isinstance(mat, BlockMatrix) and mat.is_MatrixExpr):
  693. pform = prettyForm(*pform.parens())
  694. pform = pform**(prettyForm('T'))
  695. return pform
  696. def _print_Adjoint(self, expr):
  697. mat = expr.arg
  698. pform = self._print(mat)
  699. if self._use_unicode:
  700. dag = prettyForm(pretty_atom('Dagger'))
  701. else:
  702. dag = prettyForm('+')
  703. from sympy.matrices import MatrixSymbol, BlockMatrix
  704. if (not isinstance(mat, MatrixSymbol) and
  705. not isinstance(mat, BlockMatrix) and mat.is_MatrixExpr):
  706. pform = prettyForm(*pform.parens())
  707. pform = pform**dag
  708. return pform
  709. def _print_BlockMatrix(self, B):
  710. if B.blocks.shape == (1, 1):
  711. return self._print(B.blocks[0, 0])
  712. return self._print(B.blocks)
  713. def _print_MatAdd(self, expr):
  714. s = None
  715. for item in expr.args:
  716. pform = self._print(item)
  717. if s is None:
  718. s = pform # First element
  719. else:
  720. coeff = item.as_coeff_mmul()[0]
  721. if S(coeff).could_extract_minus_sign():
  722. s = prettyForm(*stringPict.next(s, ' '))
  723. pform = self._print(item)
  724. else:
  725. s = prettyForm(*stringPict.next(s, ' + '))
  726. s = prettyForm(*stringPict.next(s, pform))
  727. return s
  728. def _print_MatMul(self, expr):
  729. args = list(expr.args)
  730. from sympy.matrices.expressions.hadamard import HadamardProduct
  731. from sympy.matrices.expressions.kronecker import KroneckerProduct
  732. from sympy.matrices.expressions.matadd import MatAdd
  733. for i, a in enumerate(args):
  734. if (isinstance(a, (Add, MatAdd, HadamardProduct, KroneckerProduct))
  735. and len(expr.args) > 1):
  736. args[i] = prettyForm(*self._print(a).parens())
  737. else:
  738. args[i] = self._print(a)
  739. return prettyForm.__mul__(*args)
  740. def _print_Identity(self, expr):
  741. if self._use_unicode:
  742. return prettyForm(pretty_atom('IdentityMatrix'))
  743. else:
  744. return prettyForm('I')
  745. def _print_ZeroMatrix(self, expr):
  746. if self._use_unicode:
  747. return prettyForm(pretty_atom('ZeroMatrix'))
  748. else:
  749. return prettyForm('0')
  750. def _print_OneMatrix(self, expr):
  751. if self._use_unicode:
  752. return prettyForm(pretty_atom("OneMatrix"))
  753. else:
  754. return prettyForm('1')
  755. def _print_DotProduct(self, expr):
  756. args = list(expr.args)
  757. for i, a in enumerate(args):
  758. args[i] = self._print(a)
  759. return prettyForm.__mul__(*args)
  760. def _print_MatPow(self, expr):
  761. pform = self._print(expr.base)
  762. from sympy.matrices import MatrixSymbol
  763. if not isinstance(expr.base, MatrixSymbol) and expr.base.is_MatrixExpr:
  764. pform = prettyForm(*pform.parens())
  765. pform = pform**(self._print(expr.exp))
  766. return pform
  767. def _print_HadamardProduct(self, expr):
  768. from sympy.matrices.expressions.hadamard import HadamardProduct
  769. from sympy.matrices.expressions.matadd import MatAdd
  770. from sympy.matrices.expressions.matmul import MatMul
  771. if self._use_unicode:
  772. delim = pretty_atom('Ring')
  773. else:
  774. delim = '.*'
  775. return self._print_seq(expr.args, None, None, delim,
  776. parenthesize=lambda x: isinstance(x, (MatAdd, MatMul, HadamardProduct)))
  777. def _print_HadamardPower(self, expr):
  778. # from sympy import MatAdd, MatMul
  779. if self._use_unicode:
  780. circ = pretty_atom('Ring')
  781. else:
  782. circ = self._print('.')
  783. pretty_base = self._print(expr.base)
  784. pretty_exp = self._print(expr.exp)
  785. if precedence(expr.exp) < PRECEDENCE["Mul"]:
  786. pretty_exp = prettyForm(*pretty_exp.parens())
  787. pretty_circ_exp = prettyForm(
  788. binding=prettyForm.LINE,
  789. *stringPict.next(circ, pretty_exp)
  790. )
  791. return pretty_base**pretty_circ_exp
  792. def _print_KroneckerProduct(self, expr):
  793. from sympy.matrices.expressions.matadd import MatAdd
  794. from sympy.matrices.expressions.matmul import MatMul
  795. if self._use_unicode:
  796. delim = f" {pretty_atom('TensorProduct')} "
  797. else:
  798. delim = ' x '
  799. return self._print_seq(expr.args, None, None, delim,
  800. parenthesize=lambda x: isinstance(x, (MatAdd, MatMul)))
  801. def _print_FunctionMatrix(self, X):
  802. D = self._print(X.lamda.expr)
  803. D = prettyForm(*D.parens('[', ']'))
  804. return D
  805. def _print_TransferFunction(self, expr):
  806. if not expr.num == 1:
  807. num, den = expr.num, expr.den
  808. res = Mul(num, Pow(den, -1, evaluate=False), evaluate=False)
  809. return self._print_Mul(res)
  810. else:
  811. return self._print(1)/self._print(expr.den)
  812. def _print_Series(self, expr):
  813. args = list(expr.args)
  814. for i, a in enumerate(expr.args):
  815. args[i] = prettyForm(*self._print(a).parens())
  816. return prettyForm.__mul__(*args)
  817. def _print_MIMOSeries(self, expr):
  818. from sympy.physics.control.lti import MIMOParallel
  819. args = list(expr.args)
  820. pretty_args = []
  821. for a in reversed(args):
  822. if (isinstance(a, MIMOParallel) and len(expr.args) > 1):
  823. expression = self._print(a)
  824. expression.baseline = expression.height()//2
  825. pretty_args.append(prettyForm(*expression.parens()))
  826. else:
  827. expression = self._print(a)
  828. expression.baseline = expression.height()//2
  829. pretty_args.append(expression)
  830. return prettyForm.__mul__(*pretty_args)
  831. def _print_Parallel(self, expr):
  832. s = None
  833. for item in expr.args:
  834. pform = self._print(item)
  835. if s is None:
  836. s = pform # First element
  837. else:
  838. s = prettyForm(*stringPict.next(s))
  839. s.baseline = s.height()//2
  840. s = prettyForm(*stringPict.next(s, ' + '))
  841. s = prettyForm(*stringPict.next(s, pform))
  842. return s
  843. def _print_MIMOParallel(self, expr):
  844. from sympy.physics.control.lti import TransferFunctionMatrix
  845. s = None
  846. for item in expr.args:
  847. pform = self._print(item)
  848. if s is None:
  849. s = pform # First element
  850. else:
  851. s = prettyForm(*stringPict.next(s))
  852. s.baseline = s.height()//2
  853. s = prettyForm(*stringPict.next(s, ' + '))
  854. if isinstance(item, TransferFunctionMatrix):
  855. s.baseline = s.height() - 1
  856. s = prettyForm(*stringPict.next(s, pform))
  857. # s.baseline = s.height()//2
  858. return s
  859. def _print_Feedback(self, expr):
  860. from sympy.physics.control import TransferFunction, Series
  861. num, tf = expr.sys1, TransferFunction(1, 1, expr.var)
  862. num_arg_list = list(num.args) if isinstance(num, Series) else [num]
  863. den_arg_list = list(expr.sys2.args) if \
  864. isinstance(expr.sys2, Series) else [expr.sys2]
  865. if isinstance(num, Series) and isinstance(expr.sys2, Series):
  866. den = Series(*num_arg_list, *den_arg_list)
  867. elif isinstance(num, Series) and isinstance(expr.sys2, TransferFunction):
  868. if expr.sys2 == tf:
  869. den = Series(*num_arg_list)
  870. else:
  871. den = Series(*num_arg_list, expr.sys2)
  872. elif isinstance(num, TransferFunction) and isinstance(expr.sys2, Series):
  873. if num == tf:
  874. den = Series(*den_arg_list)
  875. else:
  876. den = Series(num, *den_arg_list)
  877. else:
  878. if num == tf:
  879. den = Series(*den_arg_list)
  880. elif expr.sys2 == tf:
  881. den = Series(*num_arg_list)
  882. else:
  883. den = Series(*num_arg_list, *den_arg_list)
  884. denom = prettyForm(*stringPict.next(self._print(tf)))
  885. denom.baseline = denom.height()//2
  886. denom = prettyForm(*stringPict.next(denom, ' + ')) if expr.sign == -1 \
  887. else prettyForm(*stringPict.next(denom, ' - '))
  888. denom = prettyForm(*stringPict.next(denom, self._print(den)))
  889. return self._print(num)/denom
  890. def _print_MIMOFeedback(self, expr):
  891. from sympy.physics.control import MIMOSeries, TransferFunctionMatrix
  892. inv_mat = self._print(MIMOSeries(expr.sys2, expr.sys1))
  893. plant = self._print(expr.sys1)
  894. _feedback = prettyForm(*stringPict.next(inv_mat))
  895. _feedback = prettyForm(*stringPict.right("I + ", _feedback)) if expr.sign == -1 \
  896. else prettyForm(*stringPict.right("I - ", _feedback))
  897. _feedback = prettyForm(*stringPict.parens(_feedback))
  898. _feedback.baseline = 0
  899. _feedback = prettyForm(*stringPict.right(_feedback, '-1 '))
  900. _feedback.baseline = _feedback.height()//2
  901. _feedback = prettyForm.__mul__(_feedback, prettyForm(" "))
  902. if isinstance(expr.sys1, TransferFunctionMatrix):
  903. _feedback.baseline = _feedback.height() - 1
  904. _feedback = prettyForm(*stringPict.next(_feedback, plant))
  905. return _feedback
  906. def _print_TransferFunctionMatrix(self, expr):
  907. mat = self._print(expr._expr_mat)
  908. mat.baseline = mat.height() - 1
  909. subscript = greek_unicode['tau'] if self._use_unicode else r'{t}'
  910. mat = prettyForm(*mat.right(subscript))
  911. return mat
  912. def _print_StateSpace(self, expr):
  913. from sympy.matrices.expressions.blockmatrix import BlockMatrix
  914. A = expr._A
  915. B = expr._B
  916. C = expr._C
  917. D = expr._D
  918. mat = BlockMatrix([[A, B], [C, D]])
  919. return self._print(mat.blocks)
  920. def _print_BasisDependent(self, expr):
  921. from sympy.vector import Vector
  922. if not self._use_unicode:
  923. raise NotImplementedError("ASCII pretty printing of BasisDependent is not implemented")
  924. if expr == expr.zero:
  925. return prettyForm(expr.zero._pretty_form)
  926. o1 = []
  927. vectstrs = []
  928. if isinstance(expr, Vector):
  929. items = expr.separate().items()
  930. else:
  931. items = [(0, expr)]
  932. for system, vect in items:
  933. inneritems = list(vect.components.items())
  934. inneritems.sort(key = lambda x: x[0].__str__())
  935. for k, v in inneritems:
  936. #if the coef of the basis vector is 1
  937. #we skip the 1
  938. if v == 1:
  939. o1.append("" +
  940. k._pretty_form)
  941. #Same for -1
  942. elif v == -1:
  943. o1.append("(-1) " +
  944. k._pretty_form)
  945. #For a general expr
  946. else:
  947. #We always wrap the measure numbers in
  948. #parentheses
  949. arg_str = self._print(
  950. v).parens()[0]
  951. o1.append(arg_str + ' ' + k._pretty_form)
  952. vectstrs.append(k._pretty_form)
  953. #outstr = u("").join(o1)
  954. if o1[0].startswith(" + "):
  955. o1[0] = o1[0][3:]
  956. elif o1[0].startswith(" "):
  957. o1[0] = o1[0][1:]
  958. #Fixing the newlines
  959. lengths = []
  960. strs = ['']
  961. flag = []
  962. for i, partstr in enumerate(o1):
  963. flag.append(0)
  964. # XXX: What is this hack?
  965. if '\n' in partstr:
  966. tempstr = partstr
  967. tempstr = tempstr.replace(vectstrs[i], '')
  968. if xobj(')_ext', 1) in tempstr: # If scalar is a fraction
  969. for paren in range(len(tempstr)):
  970. flag[i] = 1
  971. if tempstr[paren] == xobj(')_ext', 1) and tempstr[paren + 1] == '\n':
  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
  974. tempstr = tempstr[:paren] + xobj(')_ext', 1)\
  975. + ' ' + vectstrs[i] + tempstr[paren + 1:]
  976. break
  977. elif xobj(')_lower_hook', 1) in tempstr:
  978. # We want to place the vector string after all the right parentheses, because
  979. # otherwise, the vector will be in the middle of the string. For this reason,
  980. # we insert the vector string at the rightmost index.
  981. index = tempstr.rfind(xobj(')_lower_hook', 1))
  982. if index != -1: # then this character was found in this string
  983. flag[i] = 1
  984. tempstr = tempstr[:index] + xobj(')_lower_hook', 1)\
  985. + ' ' + vectstrs[i] + tempstr[index + 1:]
  986. o1[i] = tempstr
  987. o1 = [x.split('\n') for x in o1]
  988. n_newlines = max(len(x) for x in o1) # Width of part in its pretty form
  989. if 1 in flag: # If there was a fractional scalar
  990. for i, parts in enumerate(o1):
  991. if len(parts) == 1: # If part has no newline
  992. parts.insert(0, ' ' * (len(parts[0])))
  993. flag[i] = 1
  994. for i, parts in enumerate(o1):
  995. lengths.append(len(parts[flag[i]]))
  996. for j in range(n_newlines):
  997. if j+1 <= len(parts):
  998. if j >= len(strs):
  999. strs.append(' ' * (sum(lengths[:-1]) +
  1000. 3*(len(lengths)-1)))
  1001. if j == flag[i]:
  1002. strs[flag[i]] += parts[flag[i]] + ' + '
  1003. else:
  1004. strs[j] += parts[j] + ' '*(lengths[-1] -
  1005. len(parts[j])+
  1006. 3)
  1007. else:
  1008. if j >= len(strs):
  1009. strs.append(' ' * (sum(lengths[:-1]) +
  1010. 3*(len(lengths)-1)))
  1011. strs[j] += ' '*(lengths[-1]+3)
  1012. return prettyForm('\n'.join([s[:-3] for s in strs]))
  1013. def _print_NDimArray(self, expr):
  1014. from sympy.matrices.immutable import ImmutableMatrix
  1015. if expr.rank() == 0:
  1016. return self._print(expr[()])
  1017. level_str = [[]] + [[] for i in range(expr.rank())]
  1018. shape_ranges = [list(range(i)) for i in expr.shape]
  1019. # leave eventual matrix elements unflattened
  1020. mat = lambda x: ImmutableMatrix(x, evaluate=False)
  1021. for outer_i in itertools.product(*shape_ranges):
  1022. level_str[-1].append(expr[outer_i])
  1023. even = True
  1024. for back_outer_i in range(expr.rank()-1, -1, -1):
  1025. if len(level_str[back_outer_i+1]) < expr.shape[back_outer_i]:
  1026. break
  1027. if even:
  1028. level_str[back_outer_i].append(level_str[back_outer_i+1])
  1029. else:
  1030. level_str[back_outer_i].append(mat(
  1031. level_str[back_outer_i+1]))
  1032. if len(level_str[back_outer_i + 1]) == 1:
  1033. level_str[back_outer_i][-1] = mat(
  1034. [[level_str[back_outer_i][-1]]])
  1035. even = not even
  1036. level_str[back_outer_i+1] = []
  1037. out_expr = level_str[0][0]
  1038. if expr.rank() % 2 == 1:
  1039. out_expr = mat([out_expr])
  1040. return self._print(out_expr)
  1041. def _printer_tensor_indices(self, name, indices, index_map={}):
  1042. center = stringPict(name)
  1043. top = stringPict(" "*center.width())
  1044. bot = stringPict(" "*center.width())
  1045. last_valence = None
  1046. prev_map = None
  1047. for index in indices:
  1048. indpic = self._print(index.args[0])
  1049. if ((index in index_map) or prev_map) and last_valence == index.is_up:
  1050. if index.is_up:
  1051. top = prettyForm(*stringPict.next(top, ","))
  1052. else:
  1053. bot = prettyForm(*stringPict.next(bot, ","))
  1054. if index in index_map:
  1055. indpic = prettyForm(*stringPict.next(indpic, "="))
  1056. indpic = prettyForm(*stringPict.next(indpic, self._print(index_map[index])))
  1057. prev_map = True
  1058. else:
  1059. prev_map = False
  1060. if index.is_up:
  1061. top = stringPict(*top.right(indpic))
  1062. center = stringPict(*center.right(" "*indpic.width()))
  1063. bot = stringPict(*bot.right(" "*indpic.width()))
  1064. else:
  1065. bot = stringPict(*bot.right(indpic))
  1066. center = stringPict(*center.right(" "*indpic.width()))
  1067. top = stringPict(*top.right(" "*indpic.width()))
  1068. last_valence = index.is_up
  1069. pict = prettyForm(*center.above(top))
  1070. pict = prettyForm(*pict.below(bot))
  1071. return pict
  1072. def _print_Tensor(self, expr):
  1073. name = expr.args[0].name
  1074. indices = expr.get_indices()
  1075. return self._printer_tensor_indices(name, indices)
  1076. def _print_TensorElement(self, expr):
  1077. name = expr.expr.args[0].name
  1078. indices = expr.expr.get_indices()
  1079. index_map = expr.index_map
  1080. return self._printer_tensor_indices(name, indices, index_map)
  1081. def _print_TensMul(self, expr):
  1082. sign, args = expr._get_args_for_traditional_printer()
  1083. args = [
  1084. prettyForm(*self._print(i).parens()) if
  1085. precedence_traditional(i) < PRECEDENCE["Mul"] else self._print(i)
  1086. for i in args
  1087. ]
  1088. pform = prettyForm.__mul__(*args)
  1089. if sign:
  1090. return prettyForm(*pform.left(sign))
  1091. else:
  1092. return pform
  1093. def _print_TensAdd(self, expr):
  1094. args = [
  1095. prettyForm(*self._print(i).parens()) if
  1096. precedence_traditional(i) < PRECEDENCE["Mul"] else self._print(i)
  1097. for i in expr.args
  1098. ]
  1099. return prettyForm.__add__(*args)
  1100. def _print_TensorIndex(self, expr):
  1101. sym = expr.args[0]
  1102. if not expr.is_up:
  1103. sym = -sym
  1104. return self._print(sym)
  1105. def _print_PartialDerivative(self, deriv):
  1106. if self._use_unicode:
  1107. deriv_symbol = U('PARTIAL DIFFERENTIAL')
  1108. else:
  1109. deriv_symbol = r'd'
  1110. x = None
  1111. for variable in reversed(deriv.variables):
  1112. s = self._print(variable)
  1113. ds = prettyForm(*s.left(deriv_symbol))
  1114. if x is None:
  1115. x = ds
  1116. else:
  1117. x = prettyForm(*x.right(' '))
  1118. x = prettyForm(*x.right(ds))
  1119. f = prettyForm(
  1120. binding=prettyForm.FUNC, *self._print(deriv.expr).parens())
  1121. pform = prettyForm(deriv_symbol)
  1122. if len(deriv.variables) > 1:
  1123. pform = pform**self._print(len(deriv.variables))
  1124. pform = prettyForm(*pform.below(stringPict.LINE, x))
  1125. pform.baseline = pform.baseline + 1
  1126. pform = prettyForm(*stringPict.next(pform, f))
  1127. pform.binding = prettyForm.MUL
  1128. return pform
  1129. def _print_Piecewise(self, pexpr):
  1130. P = {}
  1131. for n, ec in enumerate(pexpr.args):
  1132. P[n, 0] = self._print(ec.expr)
  1133. if ec.cond == True:
  1134. P[n, 1] = prettyForm('otherwise')
  1135. else:
  1136. P[n, 1] = prettyForm(
  1137. *prettyForm('for ').right(self._print(ec.cond)))
  1138. hsep = 2
  1139. vsep = 1
  1140. len_args = len(pexpr.args)
  1141. # max widths
  1142. maxw = [max(P[i, j].width() for i in range(len_args))
  1143. for j in range(2)]
  1144. # FIXME: Refactor this code and matrix into some tabular environment.
  1145. # drawing result
  1146. D = None
  1147. for i in range(len_args):
  1148. D_row = None
  1149. for j in range(2):
  1150. p = P[i, j]
  1151. assert p.width() <= maxw[j]
  1152. wdelta = maxw[j] - p.width()
  1153. wleft = wdelta // 2
  1154. wright = wdelta - wleft
  1155. p = prettyForm(*p.right(' '*wright))
  1156. p = prettyForm(*p.left(' '*wleft))
  1157. if D_row is None:
  1158. D_row = p
  1159. continue
  1160. D_row = prettyForm(*D_row.right(' '*hsep)) # h-spacer
  1161. D_row = prettyForm(*D_row.right(p))
  1162. if D is None:
  1163. D = D_row # first row in a picture
  1164. continue
  1165. # v-spacer
  1166. for _ in range(vsep):
  1167. D = prettyForm(*D.below(' '))
  1168. D = prettyForm(*D.below(D_row))
  1169. D = prettyForm(*D.parens('{', ''))
  1170. D.baseline = D.height()//2
  1171. D.binding = prettyForm.OPEN
  1172. return D
  1173. def _print_ITE(self, ite):
  1174. from sympy.functions.elementary.piecewise import Piecewise
  1175. return self._print(ite.rewrite(Piecewise))
  1176. def _hprint_vec(self, v):
  1177. D = None
  1178. for a in v:
  1179. p = a
  1180. if D is None:
  1181. D = p
  1182. else:
  1183. D = prettyForm(*D.right(', '))
  1184. D = prettyForm(*D.right(p))
  1185. if D is None:
  1186. D = stringPict(' ')
  1187. return D
  1188. def _hprint_vseparator(self, p1, p2, left=None, right=None, delimiter='', ifascii_nougly=False):
  1189. if ifascii_nougly and not self._use_unicode:
  1190. return self._print_seq((p1, '|', p2), left=left, right=right,
  1191. delimiter=delimiter, ifascii_nougly=True)
  1192. tmp = self._print_seq((p1, p2,), left=left, right=right, delimiter=delimiter)
  1193. sep = stringPict(vobj('|', tmp.height()), baseline=tmp.baseline)
  1194. return self._print_seq((p1, sep, p2), left=left, right=right,
  1195. delimiter=delimiter)
  1196. def _print_hyper(self, e):
  1197. # FIXME refactor Matrix, Piecewise, and this into a tabular environment
  1198. ap = [self._print(a) for a in e.ap]
  1199. bq = [self._print(b) for b in e.bq]
  1200. P = self._print(e.argument)
  1201. P.baseline = P.height()//2
  1202. # Drawing result - first create the ap, bq vectors
  1203. D = None
  1204. for v in [ap, bq]:
  1205. D_row = self._hprint_vec(v)
  1206. if D is None:
  1207. D = D_row # first row in a picture
  1208. else:
  1209. D = prettyForm(*D.below(' '))
  1210. D = prettyForm(*D.below(D_row))
  1211. # make sure that the argument `z' is centred vertically
  1212. D.baseline = D.height()//2
  1213. # insert horizontal separator
  1214. P = prettyForm(*P.left(' '))
  1215. D = prettyForm(*D.right(' '))
  1216. # insert separating `|`
  1217. D = self._hprint_vseparator(D, P)
  1218. # add parens
  1219. D = prettyForm(*D.parens('(', ')'))
  1220. # create the F symbol
  1221. above = D.height()//2 - 1
  1222. below = D.height() - above - 1
  1223. sz, t, b, add, img = annotated('F')
  1224. F = prettyForm('\n' * (above - t) + img + '\n' * (below - b),
  1225. baseline=above + sz)
  1226. add = (sz + 1)//2
  1227. F = prettyForm(*F.left(self._print(len(e.ap))))
  1228. F = prettyForm(*F.right(self._print(len(e.bq))))
  1229. F.baseline = above + add
  1230. D = prettyForm(*F.right(' ', D))
  1231. return D
  1232. def _print_meijerg(self, e):
  1233. # FIXME refactor Matrix, Piecewise, and this into a tabular environment
  1234. v = {}
  1235. v[(0, 0)] = [self._print(a) for a in e.an]
  1236. v[(0, 1)] = [self._print(a) for a in e.aother]
  1237. v[(1, 0)] = [self._print(b) for b in e.bm]
  1238. v[(1, 1)] = [self._print(b) for b in e.bother]
  1239. P = self._print(e.argument)
  1240. P.baseline = P.height()//2
  1241. vp = {}
  1242. for idx in v:
  1243. vp[idx] = self._hprint_vec(v[idx])
  1244. for i in range(2):
  1245. maxw = max(vp[(0, i)].width(), vp[(1, i)].width())
  1246. for j in range(2):
  1247. s = vp[(j, i)]
  1248. left = (maxw - s.width()) // 2
  1249. right = maxw - left - s.width()
  1250. s = prettyForm(*s.left(' ' * left))
  1251. s = prettyForm(*s.right(' ' * right))
  1252. vp[(j, i)] = s
  1253. D1 = prettyForm(*vp[(0, 0)].right(' ', vp[(0, 1)]))
  1254. D1 = prettyForm(*D1.below(' '))
  1255. D2 = prettyForm(*vp[(1, 0)].right(' ', vp[(1, 1)]))
  1256. D = prettyForm(*D1.below(D2))
  1257. # make sure that the argument `z' is centred vertically
  1258. D.baseline = D.height()//2
  1259. # insert horizontal separator
  1260. P = prettyForm(*P.left(' '))
  1261. D = prettyForm(*D.right(' '))
  1262. # insert separating `|`
  1263. D = self._hprint_vseparator(D, P)
  1264. # add parens
  1265. D = prettyForm(*D.parens('(', ')'))
  1266. # create the G symbol
  1267. above = D.height()//2 - 1
  1268. below = D.height() - above - 1
  1269. sz, t, b, add, img = annotated('G')
  1270. F = prettyForm('\n' * (above - t) + img + '\n' * (below - b),
  1271. baseline=above + sz)
  1272. pp = self._print(len(e.ap))
  1273. pq = self._print(len(e.bq))
  1274. pm = self._print(len(e.bm))
  1275. pn = self._print(len(e.an))
  1276. def adjust(p1, p2):
  1277. diff = p1.width() - p2.width()
  1278. if diff == 0:
  1279. return p1, p2
  1280. elif diff > 0:
  1281. return p1, prettyForm(*p2.left(' '*diff))
  1282. else:
  1283. return prettyForm(*p1.left(' '*-diff)), p2
  1284. pp, pm = adjust(pp, pm)
  1285. pq, pn = adjust(pq, pn)
  1286. pu = prettyForm(*pm.right(', ', pn))
  1287. pl = prettyForm(*pp.right(', ', pq))
  1288. ht = F.baseline - above - 2
  1289. if ht > 0:
  1290. pu = prettyForm(*pu.below('\n'*ht))
  1291. p = prettyForm(*pu.below(pl))
  1292. F.baseline = above
  1293. F = prettyForm(*F.right(p))
  1294. F.baseline = above + add
  1295. D = prettyForm(*F.right(' ', D))
  1296. return D
  1297. def _print_ExpBase(self, e):
  1298. # TODO should exp_polar be printed differently?
  1299. # what about exp_polar(0), exp_polar(1)?
  1300. base = prettyForm(pretty_atom('Exp1', 'e'))
  1301. return base ** self._print(e.args[0])
  1302. def _print_Exp1(self, e):
  1303. return prettyForm(pretty_atom('Exp1', 'e'))
  1304. def _print_Function(self, e, sort=False, func_name=None, left='(',
  1305. right=')'):
  1306. # optional argument func_name for supplying custom names
  1307. # XXX works only for applied functions
  1308. return self._helper_print_function(e.func, e.args, sort=sort, func_name=func_name, left=left, right=right)
  1309. def _print_mathieuc(self, e):
  1310. return self._print_Function(e, func_name='C')
  1311. def _print_mathieus(self, e):
  1312. return self._print_Function(e, func_name='S')
  1313. def _print_mathieucprime(self, e):
  1314. return self._print_Function(e, func_name="C'")
  1315. def _print_mathieusprime(self, e):
  1316. return self._print_Function(e, func_name="S'")
  1317. def _helper_print_function(self, func, args, sort=False, func_name=None,
  1318. delimiter=', ', elementwise=False, left='(',
  1319. right=')'):
  1320. if sort:
  1321. args = sorted(args, key=default_sort_key)
  1322. if not func_name and hasattr(func, "__name__"):
  1323. func_name = func.__name__
  1324. if func_name:
  1325. prettyFunc = self._print(Symbol(func_name))
  1326. else:
  1327. prettyFunc = prettyForm(*self._print(func).parens())
  1328. if elementwise:
  1329. if self._use_unicode:
  1330. circ = pretty_atom('Modifier Letter Low Ring')
  1331. else:
  1332. circ = '.'
  1333. circ = self._print(circ)
  1334. prettyFunc = prettyForm(
  1335. binding=prettyForm.LINE,
  1336. *stringPict.next(prettyFunc, circ)
  1337. )
  1338. prettyArgs = prettyForm(*self._print_seq(args, delimiter=delimiter).parens(
  1339. left=left, right=right))
  1340. pform = prettyForm(
  1341. binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
  1342. # store pform parts so it can be reassembled e.g. when powered
  1343. pform.prettyFunc = prettyFunc
  1344. pform.prettyArgs = prettyArgs
  1345. return pform
  1346. def _print_ElementwiseApplyFunction(self, e):
  1347. func = e.function
  1348. arg = e.expr
  1349. args = [arg]
  1350. return self._helper_print_function(func, args, delimiter="", elementwise=True)
  1351. @property
  1352. def _special_function_classes(self):
  1353. from sympy.functions.special.tensor_functions import KroneckerDelta
  1354. from sympy.functions.special.gamma_functions import gamma, lowergamma
  1355. from sympy.functions.special.zeta_functions import lerchphi
  1356. from sympy.functions.special.beta_functions import beta
  1357. from sympy.functions.special.delta_functions import DiracDelta
  1358. from sympy.functions.special.error_functions import Chi
  1359. return {KroneckerDelta: [greek_unicode['delta'], 'delta'],
  1360. gamma: [greek_unicode['Gamma'], 'Gamma'],
  1361. lerchphi: [greek_unicode['Phi'], 'lerchphi'],
  1362. lowergamma: [greek_unicode['gamma'], 'gamma'],
  1363. beta: [greek_unicode['Beta'], 'B'],
  1364. DiracDelta: [greek_unicode['delta'], 'delta'],
  1365. Chi: ['Chi', 'Chi']}
  1366. def _print_FunctionClass(self, expr):
  1367. for cls in self._special_function_classes:
  1368. if issubclass(expr, cls) and expr.__name__ == cls.__name__:
  1369. if self._use_unicode:
  1370. return prettyForm(self._special_function_classes[cls][0])
  1371. else:
  1372. return prettyForm(self._special_function_classes[cls][1])
  1373. func_name = expr.__name__
  1374. return prettyForm(pretty_symbol(func_name))
  1375. def _print_GeometryEntity(self, expr):
  1376. # GeometryEntity is based on Tuple but should not print like a Tuple
  1377. return self.emptyPrinter(expr)
  1378. def _print_polylog(self, e):
  1379. subscript = self._print(e.args[0])
  1380. if self._use_unicode and is_subscriptable_in_unicode(subscript):
  1381. return self._print_Function(Function('Li_%s' % subscript)(e.args[1]))
  1382. return self._print_Function(e)
  1383. def _print_lerchphi(self, e):
  1384. func_name = greek_unicode['Phi'] if self._use_unicode else 'lerchphi'
  1385. return self._print_Function(e, func_name=func_name)
  1386. def _print_dirichlet_eta(self, e):
  1387. func_name = greek_unicode['eta'] if self._use_unicode else 'dirichlet_eta'
  1388. return self._print_Function(e, func_name=func_name)
  1389. def _print_Heaviside(self, e):
  1390. func_name = greek_unicode['theta'] if self._use_unicode else 'Heaviside'
  1391. if e.args[1] is S.Half:
  1392. pform = prettyForm(*self._print(e.args[0]).parens())
  1393. pform = prettyForm(*pform.left(func_name))
  1394. return pform
  1395. else:
  1396. return self._print_Function(e, func_name=func_name)
  1397. def _print_fresnels(self, e):
  1398. return self._print_Function(e, func_name="S")
  1399. def _print_fresnelc(self, e):
  1400. return self._print_Function(e, func_name="C")
  1401. def _print_airyai(self, e):
  1402. return self._print_Function(e, func_name="Ai")
  1403. def _print_airybi(self, e):
  1404. return self._print_Function(e, func_name="Bi")
  1405. def _print_airyaiprime(self, e):
  1406. return self._print_Function(e, func_name="Ai'")
  1407. def _print_airybiprime(self, e):
  1408. return self._print_Function(e, func_name="Bi'")
  1409. def _print_LambertW(self, e):
  1410. return self._print_Function(e, func_name="W")
  1411. def _print_Covariance(self, e):
  1412. return self._print_Function(e, func_name="Cov")
  1413. def _print_Variance(self, e):
  1414. return self._print_Function(e, func_name="Var")
  1415. def _print_Probability(self, e):
  1416. return self._print_Function(e, func_name="P")
  1417. def _print_Expectation(self, e):
  1418. return self._print_Function(e, func_name="E", left='[', right=']')
  1419. def _print_Lambda(self, e):
  1420. expr = e.expr
  1421. sig = e.signature
  1422. if self._use_unicode:
  1423. arrow = f" {pretty_atom('ArrowFromBar')} "
  1424. else:
  1425. arrow = " -> "
  1426. if len(sig) == 1 and sig[0].is_symbol:
  1427. sig = sig[0]
  1428. var_form = self._print(sig)
  1429. return prettyForm(*stringPict.next(var_form, arrow, self._print(expr)), binding=8)
  1430. def _print_Order(self, expr):
  1431. pform = self._print(expr.expr)
  1432. if (expr.point and any(p != S.Zero for p in expr.point)) or \
  1433. len(expr.variables) > 1:
  1434. pform = prettyForm(*pform.right("; "))
  1435. if len(expr.variables) > 1:
  1436. pform = prettyForm(*pform.right(self._print(expr.variables)))
  1437. elif len(expr.variables):
  1438. pform = prettyForm(*pform.right(self._print(expr.variables[0])))
  1439. if self._use_unicode:
  1440. pform = prettyForm(*pform.right(f" {pretty_atom('Arrow')} "))
  1441. else:
  1442. pform = prettyForm(*pform.right(" -> "))
  1443. if len(expr.point) > 1:
  1444. pform = prettyForm(*pform.right(self._print(expr.point)))
  1445. else:
  1446. pform = prettyForm(*pform.right(self._print(expr.point[0])))
  1447. pform = prettyForm(*pform.parens())
  1448. pform = prettyForm(*pform.left("O"))
  1449. return pform
  1450. def _print_SingularityFunction(self, e):
  1451. if self._use_unicode:
  1452. shift = self._print(e.args[0]-e.args[1])
  1453. n = self._print(e.args[2])
  1454. base = prettyForm("<")
  1455. base = prettyForm(*base.right(shift))
  1456. base = prettyForm(*base.right(">"))
  1457. pform = base**n
  1458. return pform
  1459. else:
  1460. n = self._print(e.args[2])
  1461. shift = self._print(e.args[0]-e.args[1])
  1462. base = self._print_seq(shift, "<", ">", ' ')
  1463. return base**n
  1464. def _print_beta(self, e):
  1465. func_name = greek_unicode['Beta'] if self._use_unicode else 'B'
  1466. return self._print_Function(e, func_name=func_name)
  1467. def _print_betainc(self, e):
  1468. func_name = "B'"
  1469. return self._print_Function(e, func_name=func_name)
  1470. def _print_betainc_regularized(self, e):
  1471. func_name = 'I'
  1472. return self._print_Function(e, func_name=func_name)
  1473. def _print_gamma(self, e):
  1474. func_name = greek_unicode['Gamma'] if self._use_unicode else 'Gamma'
  1475. return self._print_Function(e, func_name=func_name)
  1476. def _print_uppergamma(self, e):
  1477. func_name = greek_unicode['Gamma'] if self._use_unicode else 'Gamma'
  1478. return self._print_Function(e, func_name=func_name)
  1479. def _print_lowergamma(self, e):
  1480. func_name = greek_unicode['gamma'] if self._use_unicode else 'lowergamma'
  1481. return self._print_Function(e, func_name=func_name)
  1482. def _print_DiracDelta(self, e):
  1483. if self._use_unicode:
  1484. if len(e.args) == 2:
  1485. a = prettyForm(greek_unicode['delta'])
  1486. b = self._print(e.args[1])
  1487. b = prettyForm(*b.parens())
  1488. c = self._print(e.args[0])
  1489. c = prettyForm(*c.parens())
  1490. pform = a**b
  1491. pform = prettyForm(*pform.right(' '))
  1492. pform = prettyForm(*pform.right(c))
  1493. return pform
  1494. pform = self._print(e.args[0])
  1495. pform = prettyForm(*pform.parens())
  1496. pform = prettyForm(*pform.left(greek_unicode['delta']))
  1497. return pform
  1498. else:
  1499. return self._print_Function(e)
  1500. def _print_expint(self, e):
  1501. subscript = self._print(e.args[0])
  1502. if self._use_unicode and is_subscriptable_in_unicode(subscript):
  1503. return self._print_Function(Function('E_%s' % subscript)(e.args[1]))
  1504. return self._print_Function(e)
  1505. def _print_Chi(self, e):
  1506. # This needs a special case since otherwise it comes out as greek
  1507. # letter chi...
  1508. prettyFunc = prettyForm("Chi")
  1509. prettyArgs = prettyForm(*self._print_seq(e.args).parens())
  1510. pform = prettyForm(
  1511. binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
  1512. # store pform parts so it can be reassembled e.g. when powered
  1513. pform.prettyFunc = prettyFunc
  1514. pform.prettyArgs = prettyArgs
  1515. return pform
  1516. def _print_elliptic_e(self, e):
  1517. pforma0 = self._print(e.args[0])
  1518. if len(e.args) == 1:
  1519. pform = pforma0
  1520. else:
  1521. pforma1 = self._print(e.args[1])
  1522. pform = self._hprint_vseparator(pforma0, pforma1)
  1523. pform = prettyForm(*pform.parens())
  1524. pform = prettyForm(*pform.left('E'))
  1525. return pform
  1526. def _print_elliptic_k(self, e):
  1527. pform = self._print(e.args[0])
  1528. pform = prettyForm(*pform.parens())
  1529. pform = prettyForm(*pform.left('K'))
  1530. return pform
  1531. def _print_elliptic_f(self, e):
  1532. pforma0 = self._print(e.args[0])
  1533. pforma1 = self._print(e.args[1])
  1534. pform = self._hprint_vseparator(pforma0, pforma1)
  1535. pform = prettyForm(*pform.parens())
  1536. pform = prettyForm(*pform.left('F'))
  1537. return pform
  1538. def _print_elliptic_pi(self, e):
  1539. name = greek_unicode['Pi'] if self._use_unicode else 'Pi'
  1540. pforma0 = self._print(e.args[0])
  1541. pforma1 = self._print(e.args[1])
  1542. if len(e.args) == 2:
  1543. pform = self._hprint_vseparator(pforma0, pforma1)
  1544. else:
  1545. pforma2 = self._print(e.args[2])
  1546. pforma = self._hprint_vseparator(pforma1, pforma2, ifascii_nougly=False)
  1547. pforma = prettyForm(*pforma.left('; '))
  1548. pform = prettyForm(*pforma.left(pforma0))
  1549. pform = prettyForm(*pform.parens())
  1550. pform = prettyForm(*pform.left(name))
  1551. return pform
  1552. def _print_GoldenRatio(self, expr):
  1553. if self._use_unicode:
  1554. return prettyForm(pretty_symbol('phi'))
  1555. return self._print(Symbol("GoldenRatio"))
  1556. def _print_EulerGamma(self, expr):
  1557. if self._use_unicode:
  1558. return prettyForm(pretty_symbol('gamma'))
  1559. return self._print(Symbol("EulerGamma"))
  1560. def _print_Catalan(self, expr):
  1561. return self._print(Symbol("G"))
  1562. def _print_Mod(self, expr):
  1563. pform = self._print(expr.args[0])
  1564. if pform.binding > prettyForm.MUL:
  1565. pform = prettyForm(*pform.parens())
  1566. pform = prettyForm(*pform.right(' mod '))
  1567. pform = prettyForm(*pform.right(self._print(expr.args[1])))
  1568. pform.binding = prettyForm.OPEN
  1569. return pform
  1570. def _print_Add(self, expr, order=None):
  1571. terms = self._as_ordered_terms(expr, order=order)
  1572. pforms, indices = [], []
  1573. def pretty_negative(pform, index):
  1574. """Prepend a minus sign to a pretty form. """
  1575. #TODO: Move this code to prettyForm
  1576. if index == 0:
  1577. if pform.height() > 1:
  1578. pform_neg = '- '
  1579. else:
  1580. pform_neg = '-'
  1581. else:
  1582. pform_neg = ' - '
  1583. if (pform.binding > prettyForm.NEG
  1584. or pform.binding == prettyForm.ADD):
  1585. p = stringPict(*pform.parens())
  1586. else:
  1587. p = pform
  1588. p = stringPict.next(pform_neg, p)
  1589. # Lower the binding to NEG, even if it was higher. Otherwise, it
  1590. # will print as a + ( - (b)), instead of a - (b).
  1591. return prettyForm(binding=prettyForm.NEG, *p)
  1592. for i, term in enumerate(terms):
  1593. if term.is_Mul and term.could_extract_minus_sign():
  1594. coeff, other = term.as_coeff_mul(rational=False)
  1595. if coeff == -1:
  1596. negterm = Mul(*other, evaluate=False)
  1597. else:
  1598. negterm = Mul(-coeff, *other, evaluate=False)
  1599. pform = self._print(negterm)
  1600. pforms.append(pretty_negative(pform, i))
  1601. elif term.is_Rational and term.q > 1:
  1602. pforms.append(None)
  1603. indices.append(i)
  1604. elif term.is_Number and term < 0:
  1605. pform = self._print(-term)
  1606. pforms.append(pretty_negative(pform, i))
  1607. elif term.is_Relational:
  1608. pforms.append(prettyForm(*self._print(term).parens()))
  1609. else:
  1610. pforms.append(self._print(term))
  1611. if indices:
  1612. large = True
  1613. for pform in pforms:
  1614. if pform is not None and pform.height() > 1:
  1615. break
  1616. else:
  1617. large = False
  1618. for i in indices:
  1619. term, negative = terms[i], False
  1620. if term < 0:
  1621. term, negative = -term, True
  1622. if large:
  1623. pform = prettyForm(str(term.p))/prettyForm(str(term.q))
  1624. else:
  1625. pform = self._print(term)
  1626. if negative:
  1627. pform = pretty_negative(pform, i)
  1628. pforms[i] = pform
  1629. return prettyForm.__add__(*pforms)
  1630. def _print_Mul(self, product):
  1631. from sympy.physics.units import Quantity
  1632. # Check for unevaluated Mul. In this case we need to make sure the
  1633. # identities are visible, multiple Rational factors are not combined
  1634. # etc so we display in a straight-forward form that fully preserves all
  1635. # args and their order.
  1636. args = product.args
  1637. if args[0] is S.One or any(isinstance(arg, Number) for arg in args[1:]):
  1638. strargs = list(map(self._print, args))
  1639. # XXX: This is a hack to work around the fact that
  1640. # prettyForm.__mul__ absorbs a leading -1 in the args. Probably it
  1641. # would be better to fix this in prettyForm.__mul__ instead.
  1642. negone = strargs[0] == '-1'
  1643. if negone:
  1644. strargs[0] = prettyForm('1', 0, 0)
  1645. obj = prettyForm.__mul__(*strargs)
  1646. if negone:
  1647. obj = prettyForm('-' + obj.s, obj.baseline, obj.binding)
  1648. return obj
  1649. a = [] # items in the numerator
  1650. b = [] # items that are in the denominator (if any)
  1651. if self.order not in ('old', 'none'):
  1652. args = product.as_ordered_factors()
  1653. else:
  1654. args = list(product.args)
  1655. # If quantities are present append them at the back
  1656. args = sorted(args, key=lambda x: isinstance(x, Quantity) or
  1657. (isinstance(x, Pow) and isinstance(x.base, Quantity)))
  1658. # Gather terms for numerator/denominator
  1659. for item in args:
  1660. if item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative:
  1661. if item.exp != -1:
  1662. b.append(Pow(item.base, -item.exp, evaluate=False))
  1663. else:
  1664. b.append(Pow(item.base, -item.exp))
  1665. elif item.is_Rational and item is not S.Infinity:
  1666. if item.p != 1:
  1667. a.append( Rational(item.p) )
  1668. if item.q != 1:
  1669. b.append( Rational(item.q) )
  1670. else:
  1671. a.append(item)
  1672. # Convert to pretty forms. Parentheses are added by `__mul__`.
  1673. a = [self._print(ai) for ai in a]
  1674. b = [self._print(bi) for bi in b]
  1675. # Construct a pretty form
  1676. if len(b) == 0:
  1677. return prettyForm.__mul__(*a)
  1678. else:
  1679. if len(a) == 0:
  1680. a.append( self._print(S.One) )
  1681. return prettyForm.__mul__(*a)/prettyForm.__mul__(*b)
  1682. # A helper function for _print_Pow to print x**(1/n)
  1683. def _print_nth_root(self, base, root):
  1684. bpretty = self._print(base)
  1685. # In very simple cases, use a single-char root sign
  1686. if (self._settings['use_unicode_sqrt_char'] and self._use_unicode
  1687. and root == 2 and bpretty.height() == 1
  1688. and (bpretty.width() == 1
  1689. or (base.is_Integer and base.is_nonnegative))):
  1690. return prettyForm(*bpretty.left(nth_root[2]))
  1691. # Construct root sign, start with the \/ shape
  1692. _zZ = xobj('/', 1)
  1693. rootsign = xobj('\\', 1) + _zZ
  1694. # Constructing the number to put on root
  1695. rpretty = self._print(root)
  1696. # roots look bad if they are not a single line
  1697. if rpretty.height() != 1:
  1698. return self._print(base)**self._print(1/root)
  1699. # If power is half, no number should appear on top of root sign
  1700. exp = '' if root == 2 else str(rpretty).ljust(2)
  1701. if len(exp) > 2:
  1702. rootsign = ' '*(len(exp) - 2) + rootsign
  1703. # Stack the exponent
  1704. rootsign = stringPict(exp + '\n' + rootsign)
  1705. rootsign.baseline = 0
  1706. # Diagonal: length is one less than height of base
  1707. linelength = bpretty.height() - 1
  1708. diagonal = stringPict('\n'.join(
  1709. ' '*(linelength - i - 1) + _zZ + ' '*i
  1710. for i in range(linelength)
  1711. ))
  1712. # Put baseline just below lowest line: next to exp
  1713. diagonal.baseline = linelength - 1
  1714. # Make the root symbol
  1715. rootsign = prettyForm(*rootsign.right(diagonal))
  1716. # Det the baseline to match contents to fix the height
  1717. # but if the height of bpretty is one, the rootsign must be one higher
  1718. rootsign.baseline = max(1, bpretty.baseline)
  1719. #build result
  1720. s = prettyForm(hobj('_', 2 + bpretty.width()))
  1721. s = prettyForm(*bpretty.above(s))
  1722. s = prettyForm(*s.left(rootsign))
  1723. return s
  1724. def _print_Pow(self, power):
  1725. from sympy.simplify.simplify import fraction
  1726. b, e = power.as_base_exp()
  1727. if power.is_commutative:
  1728. if e is S.NegativeOne:
  1729. return prettyForm("1")/self._print(b)
  1730. n, d = fraction(e)
  1731. if n is S.One and d.is_Atom and not e.is_Integer and (e.is_Rational or d.is_Symbol) \
  1732. and self._settings['root_notation']:
  1733. return self._print_nth_root(b, d)
  1734. if e.is_Rational and e < 0:
  1735. return prettyForm("1")/self._print(Pow(b, -e, evaluate=False))
  1736. if b.is_Relational:
  1737. return prettyForm(*self._print(b).parens()).__pow__(self._print(e))
  1738. return self._print(b)**self._print(e)
  1739. def _print_UnevaluatedExpr(self, expr):
  1740. return self._print(expr.args[0])
  1741. def __print_numer_denom(self, p, q):
  1742. if q == 1:
  1743. if p < 0:
  1744. return prettyForm(str(p), binding=prettyForm.NEG)
  1745. else:
  1746. return prettyForm(str(p))
  1747. elif abs(p) >= 10 and abs(q) >= 10:
  1748. # If more than one digit in numer and denom, print larger fraction
  1749. if p < 0:
  1750. return prettyForm(str(p), binding=prettyForm.NEG)/prettyForm(str(q))
  1751. # Old printing method:
  1752. #pform = prettyForm(str(-p))/prettyForm(str(q))
  1753. #return prettyForm(binding=prettyForm.NEG, *pform.left('- '))
  1754. else:
  1755. return prettyForm(str(p))/prettyForm(str(q))
  1756. else:
  1757. return None
  1758. def _print_Rational(self, expr):
  1759. result = self.__print_numer_denom(expr.p, expr.q)
  1760. if result is not None:
  1761. return result
  1762. else:
  1763. return self.emptyPrinter(expr)
  1764. def _print_Fraction(self, expr):
  1765. result = self.__print_numer_denom(expr.numerator, expr.denominator)
  1766. if result is not None:
  1767. return result
  1768. else:
  1769. return self.emptyPrinter(expr)
  1770. def _print_ProductSet(self, p):
  1771. if len(p.sets) >= 1 and not has_variety(p.sets):
  1772. return self._print(p.sets[0]) ** self._print(len(p.sets))
  1773. else:
  1774. prod_char = pretty_atom('Multiplication') if self._use_unicode else 'x'
  1775. return self._print_seq(p.sets, None, None, ' %s ' % prod_char,
  1776. parenthesize=lambda set: set.is_Union or
  1777. set.is_Intersection or set.is_ProductSet)
  1778. def _print_FiniteSet(self, s):
  1779. items = sorted(s.args, key=default_sort_key)
  1780. return self._print_seq(items, '{', '}', ', ' )
  1781. def _print_Range(self, s):
  1782. if self._use_unicode:
  1783. dots = pretty_atom('Dots')
  1784. else:
  1785. dots = '...'
  1786. if s.start.is_infinite and s.stop.is_infinite:
  1787. if s.step.is_positive:
  1788. printset = dots, -1, 0, 1, dots
  1789. else:
  1790. printset = dots, 1, 0, -1, dots
  1791. elif s.start.is_infinite:
  1792. printset = dots, s[-1] - s.step, s[-1]
  1793. elif s.stop.is_infinite:
  1794. it = iter(s)
  1795. printset = next(it), next(it), dots
  1796. elif len(s) > 4:
  1797. it = iter(s)
  1798. printset = next(it), next(it), dots, s[-1]
  1799. else:
  1800. printset = tuple(s)
  1801. return self._print_seq(printset, '{', '}', ', ' )
  1802. def _print_Interval(self, i):
  1803. if i.start == i.end:
  1804. return self._print_seq(i.args[:1], '{', '}')
  1805. else:
  1806. if i.left_open:
  1807. left = '('
  1808. else:
  1809. left = '['
  1810. if i.right_open:
  1811. right = ')'
  1812. else:
  1813. right = ']'
  1814. return self._print_seq(i.args[:2], left, right)
  1815. def _print_AccumulationBounds(self, i):
  1816. left = '<'
  1817. right = '>'
  1818. return self._print_seq(i.args[:2], left, right)
  1819. def _print_Intersection(self, u):
  1820. delimiter = ' %s ' % pretty_atom('Intersection', 'n')
  1821. return self._print_seq(u.args, None, None, delimiter,
  1822. parenthesize=lambda set: set.is_ProductSet or
  1823. set.is_Union or set.is_Complement)
  1824. def _print_Union(self, u):
  1825. union_delimiter = ' %s ' % pretty_atom('Union', 'U')
  1826. return self._print_seq(u.args, None, None, union_delimiter,
  1827. parenthesize=lambda set: set.is_ProductSet or
  1828. set.is_Intersection or set.is_Complement)
  1829. def _print_SymmetricDifference(self, u):
  1830. if not self._use_unicode:
  1831. raise NotImplementedError("ASCII pretty printing of SymmetricDifference is not implemented")
  1832. sym_delimeter = ' %s ' % pretty_atom('SymmetricDifference')
  1833. return self._print_seq(u.args, None, None, sym_delimeter)
  1834. def _print_Complement(self, u):
  1835. delimiter = r' \ '
  1836. return self._print_seq(u.args, None, None, delimiter,
  1837. parenthesize=lambda set: set.is_ProductSet or set.is_Intersection
  1838. or set.is_Union)
  1839. def _print_ImageSet(self, ts):
  1840. if self._use_unicode:
  1841. inn = pretty_atom("SmallElementOf")
  1842. else:
  1843. inn = 'in'
  1844. fun = ts.lamda
  1845. sets = ts.base_sets
  1846. signature = fun.signature
  1847. expr = self._print(fun.expr)
  1848. # TODO: the stuff to the left of the | and the stuff to the right of
  1849. # the | should have independent baselines, that way something like
  1850. # ImageSet(Lambda(x, 1/x**2), S.Naturals) prints the "x in N" part
  1851. # centered on the right instead of aligned with the fraction bar on
  1852. # the left. The same also applies to ConditionSet and ComplexRegion
  1853. if len(signature) == 1:
  1854. S = self._print_seq((signature[0], inn, sets[0]),
  1855. delimiter=' ')
  1856. return self._hprint_vseparator(expr, S,
  1857. left='{', right='}',
  1858. ifascii_nougly=True, delimiter=' ')
  1859. else:
  1860. pargs = tuple(j for var, setv in zip(signature, sets) for j in
  1861. (var, ' ', inn, ' ', setv, ", "))
  1862. S = self._print_seq(pargs[:-1], delimiter='')
  1863. return self._hprint_vseparator(expr, S,
  1864. left='{', right='}',
  1865. ifascii_nougly=True, delimiter=' ')
  1866. def _print_ConditionSet(self, ts):
  1867. if self._use_unicode:
  1868. inn = pretty_atom('SmallElementOf')
  1869. # using _and because and is a keyword and it is bad practice to
  1870. # overwrite them
  1871. _and = pretty_atom('And')
  1872. else:
  1873. inn = 'in'
  1874. _and = 'and'
  1875. variables = self._print_seq(Tuple(ts.sym))
  1876. as_expr = getattr(ts.condition, 'as_expr', None)
  1877. if as_expr is not None:
  1878. cond = self._print(ts.condition.as_expr())
  1879. else:
  1880. cond = self._print(ts.condition)
  1881. if self._use_unicode:
  1882. cond = self._print(cond)
  1883. cond = prettyForm(*cond.parens())
  1884. if ts.base_set is S.UniversalSet:
  1885. return self._hprint_vseparator(variables, cond, left="{",
  1886. right="}", ifascii_nougly=True,
  1887. delimiter=' ')
  1888. base = self._print(ts.base_set)
  1889. C = self._print_seq((variables, inn, base, _and, cond),
  1890. delimiter=' ')
  1891. return self._hprint_vseparator(variables, C, left="{", right="}",
  1892. ifascii_nougly=True, delimiter=' ')
  1893. def _print_ComplexRegion(self, ts):
  1894. if self._use_unicode:
  1895. inn = pretty_atom('SmallElementOf')
  1896. else:
  1897. inn = 'in'
  1898. variables = self._print_seq(ts.variables)
  1899. expr = self._print(ts.expr)
  1900. prodsets = self._print(ts.sets)
  1901. C = self._print_seq((variables, inn, prodsets),
  1902. delimiter=' ')
  1903. return self._hprint_vseparator(expr, C, left="{", right="}",
  1904. ifascii_nougly=True, delimiter=' ')
  1905. def _print_Contains(self, e):
  1906. var, set = e.args
  1907. if self._use_unicode:
  1908. el = f" {pretty_atom('ElementOf')} "
  1909. return prettyForm(*stringPict.next(self._print(var),
  1910. el, self._print(set)), binding=8)
  1911. else:
  1912. return prettyForm(sstr(e))
  1913. def _print_FourierSeries(self, s):
  1914. if s.an.formula is S.Zero and s.bn.formula is S.Zero:
  1915. return self._print(s.a0)
  1916. if self._use_unicode:
  1917. dots = pretty_atom('Dots')
  1918. else:
  1919. dots = '...'
  1920. return self._print_Add(s.truncate()) + self._print(dots)
  1921. def _print_FormalPowerSeries(self, s):
  1922. return self._print_Add(s.infinite)
  1923. def _print_SetExpr(self, se):
  1924. pretty_set = prettyForm(*self._print(se.set).parens())
  1925. pretty_name = self._print(Symbol("SetExpr"))
  1926. return prettyForm(*pretty_name.right(pretty_set))
  1927. def _print_SeqFormula(self, s):
  1928. if self._use_unicode:
  1929. dots = pretty_atom('Dots')
  1930. else:
  1931. dots = '...'
  1932. if len(s.start.free_symbols) > 0 or len(s.stop.free_symbols) > 0:
  1933. raise NotImplementedError("Pretty printing of sequences with symbolic bound not implemented")
  1934. if s.start is S.NegativeInfinity:
  1935. stop = s.stop
  1936. printset = (dots, s.coeff(stop - 3), s.coeff(stop - 2),
  1937. s.coeff(stop - 1), s.coeff(stop))
  1938. elif s.stop is S.Infinity or s.length > 4:
  1939. printset = s[:4]
  1940. printset.append(dots)
  1941. printset = tuple(printset)
  1942. else:
  1943. printset = tuple(s)
  1944. return self._print_list(printset)
  1945. _print_SeqPer = _print_SeqFormula
  1946. _print_SeqAdd = _print_SeqFormula
  1947. _print_SeqMul = _print_SeqFormula
  1948. def _print_seq(self, seq, left=None, right=None, delimiter=', ',
  1949. parenthesize=lambda x: False, ifascii_nougly=True):
  1950. pforms = []
  1951. for item in seq:
  1952. pform = self._print(item)
  1953. if parenthesize(item):
  1954. pform = prettyForm(*pform.parens())
  1955. if pforms:
  1956. pforms.append(delimiter)
  1957. pforms.append(pform)
  1958. if not pforms:
  1959. s = stringPict('')
  1960. else:
  1961. s = prettyForm(*stringPict.next(*pforms))
  1962. s = prettyForm(*s.parens(left, right, ifascii_nougly=ifascii_nougly))
  1963. return s
  1964. def join(self, delimiter, args):
  1965. pform = None
  1966. for arg in args:
  1967. if pform is None:
  1968. pform = arg
  1969. else:
  1970. pform = prettyForm(*pform.right(delimiter))
  1971. pform = prettyForm(*pform.right(arg))
  1972. if pform is None:
  1973. return prettyForm("")
  1974. else:
  1975. return pform
  1976. def _print_list(self, l):
  1977. return self._print_seq(l, '[', ']')
  1978. def _print_tuple(self, t):
  1979. if len(t) == 1:
  1980. ptuple = prettyForm(*stringPict.next(self._print(t[0]), ','))
  1981. return prettyForm(*ptuple.parens('(', ')', ifascii_nougly=True))
  1982. else:
  1983. return self._print_seq(t, '(', ')')
  1984. def _print_Tuple(self, expr):
  1985. return self._print_tuple(expr)
  1986. def _print_dict(self, d):
  1987. keys = sorted(d.keys(), key=default_sort_key)
  1988. items = []
  1989. for k in keys:
  1990. K = self._print(k)
  1991. V = self._print(d[k])
  1992. s = prettyForm(*stringPict.next(K, ': ', V))
  1993. items.append(s)
  1994. return self._print_seq(items, '{', '}')
  1995. def _print_Dict(self, d):
  1996. return self._print_dict(d)
  1997. def _print_set(self, s):
  1998. if not s:
  1999. return prettyForm('set()')
  2000. items = sorted(s, key=default_sort_key)
  2001. pretty = self._print_seq(items)
  2002. pretty = prettyForm(*pretty.parens('{', '}', ifascii_nougly=True))
  2003. return pretty
  2004. def _print_frozenset(self, s):
  2005. if not s:
  2006. return prettyForm('frozenset()')
  2007. items = sorted(s, key=default_sort_key)
  2008. pretty = self._print_seq(items)
  2009. pretty = prettyForm(*pretty.parens('{', '}', ifascii_nougly=True))
  2010. pretty = prettyForm(*pretty.parens('(', ')', ifascii_nougly=True))
  2011. pretty = prettyForm(*stringPict.next(type(s).__name__, pretty))
  2012. return pretty
  2013. def _print_UniversalSet(self, s):
  2014. if self._use_unicode:
  2015. return prettyForm(pretty_atom('Universe'))
  2016. else:
  2017. return prettyForm('UniversalSet')
  2018. def _print_PolyRing(self, ring):
  2019. return prettyForm(sstr(ring))
  2020. def _print_FracField(self, field):
  2021. return prettyForm(sstr(field))
  2022. def _print_FreeGroupElement(self, elm):
  2023. return prettyForm(str(elm))
  2024. def _print_PolyElement(self, poly):
  2025. return prettyForm(sstr(poly))
  2026. def _print_FracElement(self, frac):
  2027. return prettyForm(sstr(frac))
  2028. def _print_AlgebraicNumber(self, expr):
  2029. if expr.is_aliased:
  2030. return self._print(expr.as_poly().as_expr())
  2031. else:
  2032. return self._print(expr.as_expr())
  2033. def _print_ComplexRootOf(self, expr):
  2034. args = [self._print_Add(expr.expr, order='lex'), expr.index]
  2035. pform = prettyForm(*self._print_seq(args).parens())
  2036. pform = prettyForm(*pform.left('CRootOf'))
  2037. return pform
  2038. def _print_RootSum(self, expr):
  2039. args = [self._print_Add(expr.expr, order='lex')]
  2040. if expr.fun is not S.IdentityFunction:
  2041. args.append(self._print(expr.fun))
  2042. pform = prettyForm(*self._print_seq(args).parens())
  2043. pform = prettyForm(*pform.left('RootSum'))
  2044. return pform
  2045. def _print_FiniteField(self, expr):
  2046. if self._use_unicode:
  2047. form = f"{pretty_atom('Integers')}_%d"
  2048. else:
  2049. form = 'GF(%d)'
  2050. return prettyForm(pretty_symbol(form % expr.mod))
  2051. def _print_IntegerRing(self, expr):
  2052. if self._use_unicode:
  2053. return prettyForm(pretty_atom('Integers'))
  2054. else:
  2055. return prettyForm('ZZ')
  2056. def _print_RationalField(self, expr):
  2057. if self._use_unicode:
  2058. return prettyForm(pretty_atom('Rationals'))
  2059. else:
  2060. return prettyForm('QQ')
  2061. def _print_RealField(self, domain):
  2062. if self._use_unicode:
  2063. prefix = pretty_atom("Reals")
  2064. else:
  2065. prefix = 'RR'
  2066. if domain.has_default_precision:
  2067. return prettyForm(prefix)
  2068. else:
  2069. return self._print(pretty_symbol(prefix + "_" + str(domain.precision)))
  2070. def _print_ComplexField(self, domain):
  2071. if self._use_unicode:
  2072. prefix = pretty_atom('Complexes')
  2073. else:
  2074. prefix = 'CC'
  2075. if domain.has_default_precision:
  2076. return prettyForm(prefix)
  2077. else:
  2078. return self._print(pretty_symbol(prefix + "_" + str(domain.precision)))
  2079. def _print_PolynomialRing(self, expr):
  2080. args = list(expr.symbols)
  2081. if not expr.order.is_default:
  2082. order = prettyForm(*prettyForm("order=").right(self._print(expr.order)))
  2083. args.append(order)
  2084. pform = self._print_seq(args, '[', ']')
  2085. pform = prettyForm(*pform.left(self._print(expr.domain)))
  2086. return pform
  2087. def _print_FractionField(self, expr):
  2088. args = list(expr.symbols)
  2089. if not expr.order.is_default:
  2090. order = prettyForm(*prettyForm("order=").right(self._print(expr.order)))
  2091. args.append(order)
  2092. pform = self._print_seq(args, '(', ')')
  2093. pform = prettyForm(*pform.left(self._print(expr.domain)))
  2094. return pform
  2095. def _print_PolynomialRingBase(self, expr):
  2096. g = expr.symbols
  2097. if str(expr.order) != str(expr.default_order):
  2098. g = g + ("order=" + str(expr.order),)
  2099. pform = self._print_seq(g, '[', ']')
  2100. pform = prettyForm(*pform.left(self._print(expr.domain)))
  2101. return pform
  2102. def _print_GroebnerBasis(self, basis):
  2103. exprs = [ self._print_Add(arg, order=basis.order)
  2104. for arg in basis.exprs ]
  2105. exprs = prettyForm(*self.join(", ", exprs).parens(left="[", right="]"))
  2106. gens = [ self._print(gen) for gen in basis.gens ]
  2107. domain = prettyForm(
  2108. *prettyForm("domain=").right(self._print(basis.domain)))
  2109. order = prettyForm(
  2110. *prettyForm("order=").right(self._print(basis.order)))
  2111. pform = self.join(", ", [exprs] + gens + [domain, order])
  2112. pform = prettyForm(*pform.parens())
  2113. pform = prettyForm(*pform.left(basis.__class__.__name__))
  2114. return pform
  2115. def _print_Subs(self, e):
  2116. pform = self._print(e.expr)
  2117. pform = prettyForm(*pform.parens())
  2118. h = pform.height() if pform.height() > 1 else 2
  2119. rvert = stringPict(vobj('|', h), baseline=pform.baseline)
  2120. pform = prettyForm(*pform.right(rvert))
  2121. b = pform.baseline
  2122. pform.baseline = pform.height() - 1
  2123. pform = prettyForm(*pform.right(self._print_seq([
  2124. self._print_seq((self._print(v[0]), xsym('=='), self._print(v[1])),
  2125. delimiter='') for v in zip(e.variables, e.point) ])))
  2126. pform.baseline = b
  2127. return pform
  2128. def _print_number_function(self, e, name):
  2129. # Print name_arg[0] for one argument or name_arg[0](arg[1])
  2130. # for more than one argument
  2131. pform = prettyForm(name)
  2132. arg = self._print(e.args[0])
  2133. pform_arg = prettyForm(" "*arg.width())
  2134. pform_arg = prettyForm(*pform_arg.below(arg))
  2135. pform = prettyForm(*pform.right(pform_arg))
  2136. if len(e.args) == 1:
  2137. return pform
  2138. m, x = e.args
  2139. # TODO: copy-pasted from _print_Function: can we do better?
  2140. prettyFunc = pform
  2141. prettyArgs = prettyForm(*self._print_seq([x]).parens())
  2142. pform = prettyForm(
  2143. binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
  2144. pform.prettyFunc = prettyFunc
  2145. pform.prettyArgs = prettyArgs
  2146. return pform
  2147. def _print_euler(self, e):
  2148. return self._print_number_function(e, "E")
  2149. def _print_catalan(self, e):
  2150. return self._print_number_function(e, "C")
  2151. def _print_bernoulli(self, e):
  2152. return self._print_number_function(e, "B")
  2153. _print_bell = _print_bernoulli
  2154. def _print_lucas(self, e):
  2155. return self._print_number_function(e, "L")
  2156. def _print_fibonacci(self, e):
  2157. return self._print_number_function(e, "F")
  2158. def _print_tribonacci(self, e):
  2159. return self._print_number_function(e, "T")
  2160. def _print_stieltjes(self, e):
  2161. if self._use_unicode:
  2162. return self._print_number_function(e, greek_unicode['gamma'])
  2163. else:
  2164. return self._print_number_function(e, "stieltjes")
  2165. def _print_KroneckerDelta(self, e):
  2166. pform = self._print(e.args[0])
  2167. pform = prettyForm(*pform.right(prettyForm(',')))
  2168. pform = prettyForm(*pform.right(self._print(e.args[1])))
  2169. if self._use_unicode:
  2170. a = stringPict(pretty_symbol('delta'))
  2171. else:
  2172. a = stringPict('d')
  2173. b = pform
  2174. top = stringPict(*b.left(' '*a.width()))
  2175. bot = stringPict(*a.right(' '*b.width()))
  2176. return prettyForm(binding=prettyForm.POW, *bot.below(top))
  2177. def _print_RandomDomain(self, d):
  2178. if hasattr(d, 'as_boolean'):
  2179. pform = self._print('Domain: ')
  2180. pform = prettyForm(*pform.right(self._print(d.as_boolean())))
  2181. return pform
  2182. elif hasattr(d, 'set'):
  2183. pform = self._print('Domain: ')
  2184. pform = prettyForm(*pform.right(self._print(d.symbols)))
  2185. pform = prettyForm(*pform.right(self._print(' in ')))
  2186. pform = prettyForm(*pform.right(self._print(d.set)))
  2187. return pform
  2188. elif hasattr(d, 'symbols'):
  2189. pform = self._print('Domain on ')
  2190. pform = prettyForm(*pform.right(self._print(d.symbols)))
  2191. return pform
  2192. else:
  2193. return self._print(None)
  2194. def _print_DMP(self, p):
  2195. try:
  2196. if p.ring is not None:
  2197. # TODO incorporate order
  2198. return self._print(p.ring.to_sympy(p))
  2199. except SympifyError:
  2200. pass
  2201. return self._print(repr(p))
  2202. def _print_DMF(self, p):
  2203. return self._print_DMP(p)
  2204. def _print_Object(self, object):
  2205. return self._print(pretty_symbol(object.name))
  2206. def _print_Morphism(self, morphism):
  2207. arrow = xsym("-->")
  2208. domain = self._print(morphism.domain)
  2209. codomain = self._print(morphism.codomain)
  2210. tail = domain.right(arrow, codomain)[0]
  2211. return prettyForm(tail)
  2212. def _print_NamedMorphism(self, morphism):
  2213. pretty_name = self._print(pretty_symbol(morphism.name))
  2214. pretty_morphism = self._print_Morphism(morphism)
  2215. return prettyForm(pretty_name.right(":", pretty_morphism)[0])
  2216. def _print_IdentityMorphism(self, morphism):
  2217. from sympy.categories import NamedMorphism
  2218. return self._print_NamedMorphism(
  2219. NamedMorphism(morphism.domain, morphism.codomain, "id"))
  2220. def _print_CompositeMorphism(self, morphism):
  2221. circle = xsym(".")
  2222. # All components of the morphism have names and it is thus
  2223. # possible to build the name of the composite.
  2224. component_names_list = [pretty_symbol(component.name) for
  2225. component in morphism.components]
  2226. component_names_list.reverse()
  2227. component_names = circle.join(component_names_list) + ":"
  2228. pretty_name = self._print(component_names)
  2229. pretty_morphism = self._print_Morphism(morphism)
  2230. return prettyForm(pretty_name.right(pretty_morphism)[0])
  2231. def _print_Category(self, category):
  2232. return self._print(pretty_symbol(category.name))
  2233. def _print_Diagram(self, diagram):
  2234. if not diagram.premises:
  2235. # This is an empty diagram.
  2236. return self._print(S.EmptySet)
  2237. pretty_result = self._print(diagram.premises)
  2238. if diagram.conclusions:
  2239. results_arrow = " %s " % xsym("==>")
  2240. pretty_conclusions = self._print(diagram.conclusions)[0]
  2241. pretty_result = pretty_result.right(
  2242. results_arrow, pretty_conclusions)
  2243. return prettyForm(pretty_result[0])
  2244. def _print_DiagramGrid(self, grid):
  2245. from sympy.matrices import Matrix
  2246. matrix = Matrix([[grid[i, j] if grid[i, j] else Symbol(" ")
  2247. for j in range(grid.width)]
  2248. for i in range(grid.height)])
  2249. return self._print_matrix_contents(matrix)
  2250. def _print_FreeModuleElement(self, m):
  2251. # Print as row vector for convenience, for now.
  2252. return self._print_seq(m, '[', ']')
  2253. def _print_SubModule(self, M):
  2254. gens = [[M.ring.to_sympy(g) for g in gen] for gen in M.gens]
  2255. return self._print_seq(gens, '<', '>')
  2256. def _print_FreeModule(self, M):
  2257. return self._print(M.ring)**self._print(M.rank)
  2258. def _print_ModuleImplementedIdeal(self, M):
  2259. sym = M.ring.to_sympy
  2260. return self._print_seq([sym(x) for [x] in M._module.gens], '<', '>')
  2261. def _print_QuotientRing(self, R):
  2262. return self._print(R.ring) / self._print(R.base_ideal)
  2263. def _print_QuotientRingElement(self, R):
  2264. return self._print(R.ring.to_sympy(R)) + self._print(R.ring.base_ideal)
  2265. def _print_QuotientModuleElement(self, m):
  2266. return self._print(m.data) + self._print(m.module.killed_module)
  2267. def _print_QuotientModule(self, M):
  2268. return self._print(M.base) / self._print(M.killed_module)
  2269. def _print_MatrixHomomorphism(self, h):
  2270. matrix = self._print(h._sympy_matrix())
  2271. matrix.baseline = matrix.height() // 2
  2272. pform = prettyForm(*matrix.right(' : ', self._print(h.domain),
  2273. ' %s> ' % hobj('-', 2), self._print(h.codomain)))
  2274. return pform
  2275. def _print_Manifold(self, manifold):
  2276. return self._print(manifold.name)
  2277. def _print_Patch(self, patch):
  2278. return self._print(patch.name)
  2279. def _print_CoordSystem(self, coords):
  2280. return self._print(coords.name)
  2281. def _print_BaseScalarField(self, field):
  2282. string = field._coord_sys.symbols[field._index].name
  2283. return self._print(pretty_symbol(string))
  2284. def _print_BaseVectorField(self, field):
  2285. s = U('PARTIAL DIFFERENTIAL') + '_' + field._coord_sys.symbols[field._index].name
  2286. return self._print(pretty_symbol(s))
  2287. def _print_Differential(self, diff):
  2288. if self._use_unicode:
  2289. d = pretty_atom('Differential')
  2290. else:
  2291. d = 'd'
  2292. field = diff._form_field
  2293. if hasattr(field, '_coord_sys'):
  2294. string = field._coord_sys.symbols[field._index].name
  2295. return self._print(d + ' ' + pretty_symbol(string))
  2296. else:
  2297. pform = self._print(field)
  2298. pform = prettyForm(*pform.parens())
  2299. return prettyForm(*pform.left(d))
  2300. def _print_Tr(self, p):
  2301. #TODO: Handle indices
  2302. pform = self._print(p.args[0])
  2303. pform = prettyForm(*pform.left('%s(' % (p.__class__.__name__)))
  2304. pform = prettyForm(*pform.right(')'))
  2305. return pform
  2306. def _print_primenu(self, e):
  2307. pform = self._print(e.args[0])
  2308. pform = prettyForm(*pform.parens())
  2309. if self._use_unicode:
  2310. pform = prettyForm(*pform.left(greek_unicode['nu']))
  2311. else:
  2312. pform = prettyForm(*pform.left('nu'))
  2313. return pform
  2314. def _print_primeomega(self, e):
  2315. pform = self._print(e.args[0])
  2316. pform = prettyForm(*pform.parens())
  2317. if self._use_unicode:
  2318. pform = prettyForm(*pform.left(greek_unicode['Omega']))
  2319. else:
  2320. pform = prettyForm(*pform.left('Omega'))
  2321. return pform
  2322. def _print_Quantity(self, e):
  2323. if e.name.name == 'degree':
  2324. if self._use_unicode:
  2325. pform = self._print(pretty_atom('Degree'))
  2326. else:
  2327. pform = self._print(chr(176))
  2328. return pform
  2329. else:
  2330. return self.emptyPrinter(e)
  2331. def _print_AssignmentBase(self, e):
  2332. op = prettyForm(' ' + xsym(e.op) + ' ')
  2333. l = self._print(e.lhs)
  2334. r = self._print(e.rhs)
  2335. pform = prettyForm(*stringPict.next(l, op, r))
  2336. return pform
  2337. def _print_Str(self, s):
  2338. return self._print(s.name)
  2339. @print_function(PrettyPrinter)
  2340. def pretty(expr, **settings):
  2341. """Returns a string containing the prettified form of expr.
  2342. For information on keyword arguments see pretty_print function.
  2343. """
  2344. pp = PrettyPrinter(settings)
  2345. # XXX: this is an ugly hack, but at least it works
  2346. use_unicode = pp._settings['use_unicode']
  2347. uflag = pretty_use_unicode(use_unicode)
  2348. try:
  2349. return pp.doprint(expr)
  2350. finally:
  2351. pretty_use_unicode(uflag)
  2352. def pretty_print(expr, **kwargs):
  2353. """Prints expr in pretty form.
  2354. pprint is just a shortcut for this function.
  2355. Parameters
  2356. ==========
  2357. expr : expression
  2358. The expression to print.
  2359. wrap_line : bool, optional (default=True)
  2360. Line wrapping enabled/disabled.
  2361. num_columns : int or None, optional (default=None)
  2362. Number of columns before line breaking (default to None which reads
  2363. the terminal width), useful when using SymPy without terminal.
  2364. use_unicode : bool or None, optional (default=None)
  2365. Use unicode characters, such as the Greek letter pi instead of
  2366. the string pi.
  2367. full_prec : bool or string, optional (default="auto")
  2368. Use full precision.
  2369. order : bool or string, optional (default=None)
  2370. Set to 'none' for long expressions if slow; default is None.
  2371. use_unicode_sqrt_char : bool, optional (default=True)
  2372. Use compact single-character square root symbol (when unambiguous).
  2373. root_notation : bool, optional (default=True)
  2374. Set to 'False' for printing exponents of the form 1/n in fractional form.
  2375. By default exponent is printed in root form.
  2376. mat_symbol_style : string, optional (default="plain")
  2377. Set to "bold" for printing MatrixSymbols using a bold mathematical symbol face.
  2378. By default the standard face is used.
  2379. imaginary_unit : string, optional (default="i")
  2380. Letter to use for imaginary unit when use_unicode is True.
  2381. Can be "i" (default) or "j".
  2382. """
  2383. print(pretty(expr, **kwargs))
  2384. pprint = pretty_print
  2385. def pager_print(expr, **settings):
  2386. """Prints expr using the pager, in pretty form.
  2387. This invokes a pager command using pydoc. Lines are not wrapped
  2388. automatically. This routine is meant to be used with a pager that allows
  2389. sideways scrolling, like ``less -S``.
  2390. Parameters are the same as for ``pretty_print``. If you wish to wrap lines,
  2391. pass ``num_columns=None`` to auto-detect the width of the terminal.
  2392. """
  2393. from pydoc import pager
  2394. from locale import getpreferredencoding
  2395. if 'num_columns' not in settings:
  2396. settings['num_columns'] = 500000 # disable line wrap
  2397. pager(pretty(expr, **settings).encode(getpreferredencoding()))