12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939 |
- import itertools
- from sympy.core import S
- from sympy.core.add import Add
- from sympy.core.containers import Tuple
- from sympy.core.function import Function
- from sympy.core.mul import Mul
- from sympy.core.numbers import Number, Rational
- from sympy.core.power import Pow
- from sympy.core.sorting import default_sort_key
- from sympy.core.symbol import Symbol
- from sympy.core.sympify import SympifyError
- from sympy.printing.conventions import requires_partial
- from sympy.printing.precedence import PRECEDENCE, precedence, precedence_traditional
- from sympy.printing.printer import Printer, print_function
- from sympy.printing.str import sstr
- from sympy.utilities.iterables import has_variety
- from sympy.utilities.exceptions import sympy_deprecation_warning
- from sympy.printing.pretty.stringpict import prettyForm, stringPict
- from sympy.printing.pretty.pretty_symbology import hobj, vobj, xobj, \
- xsym, pretty_symbol, pretty_atom, pretty_use_unicode, greek_unicode, U, \
- pretty_try_use_unicode, annotated
- # rename for usage from outside
- pprint_use_unicode = pretty_use_unicode
- pprint_try_use_unicode = pretty_try_use_unicode
- class PrettyPrinter(Printer):
- """Printer, which converts an expression into 2D ASCII-art figure."""
- printmethod = "_pretty"
- _default_settings = {
- "order": None,
- "full_prec": "auto",
- "use_unicode": None,
- "wrap_line": True,
- "num_columns": None,
- "use_unicode_sqrt_char": True,
- "root_notation": True,
- "mat_symbol_style": "plain",
- "imaginary_unit": "i",
- "perm_cyclic": True
- }
- def __init__(self, settings=None):
- Printer.__init__(self, settings)
- if not isinstance(self._settings['imaginary_unit'], str):
- raise TypeError("'imaginary_unit' must a string, not {}".format(self._settings['imaginary_unit']))
- elif self._settings['imaginary_unit'] not in ("i", "j"):
- raise ValueError("'imaginary_unit' must be either 'i' or 'j', not '{}'".format(self._settings['imaginary_unit']))
- def emptyPrinter(self, expr):
- return prettyForm(str(expr))
- @property
- def _use_unicode(self):
- if self._settings['use_unicode']:
- return True
- else:
- return pretty_use_unicode()
- def doprint(self, expr):
- return self._print(expr).render(**self._settings)
- # empty op so _print(stringPict) returns the same
- def _print_stringPict(self, e):
- return e
- def _print_basestring(self, e):
- return prettyForm(e)
- def _print_atan2(self, e):
- pform = prettyForm(*self._print_seq(e.args).parens())
- pform = prettyForm(*pform.left('atan2'))
- return pform
- def _print_Symbol(self, e, bold_name=False):
- symb = pretty_symbol(e.name, bold_name)
- return prettyForm(symb)
- _print_RandomSymbol = _print_Symbol
- def _print_MatrixSymbol(self, e):
- return self._print_Symbol(e, self._settings['mat_symbol_style'] == "bold")
- def _print_Float(self, e):
- # we will use StrPrinter's Float printer, but we need to handle the
- # full_prec ourselves, according to the self._print_level
- full_prec = self._settings["full_prec"]
- if full_prec == "auto":
- full_prec = self._print_level == 1
- return prettyForm(sstr(e, full_prec=full_prec))
- def _print_Cross(self, e):
- vec1 = e._expr1
- vec2 = e._expr2
- pform = self._print(vec2)
- pform = prettyForm(*pform.left('('))
- pform = prettyForm(*pform.right(')'))
- pform = prettyForm(*pform.left(self._print(U('MULTIPLICATION SIGN'))))
- pform = prettyForm(*pform.left(')'))
- pform = prettyForm(*pform.left(self._print(vec1)))
- pform = prettyForm(*pform.left('('))
- return pform
- def _print_Curl(self, e):
- vec = e._expr
- pform = self._print(vec)
- pform = prettyForm(*pform.left('('))
- pform = prettyForm(*pform.right(')'))
- pform = prettyForm(*pform.left(self._print(U('MULTIPLICATION SIGN'))))
- pform = prettyForm(*pform.left(self._print(U('NABLA'))))
- return pform
- def _print_Divergence(self, e):
- vec = e._expr
- pform = self._print(vec)
- pform = prettyForm(*pform.left('('))
- pform = prettyForm(*pform.right(')'))
- pform = prettyForm(*pform.left(self._print(U('DOT OPERATOR'))))
- pform = prettyForm(*pform.left(self._print(U('NABLA'))))
- return pform
- def _print_Dot(self, e):
- vec1 = e._expr1
- vec2 = e._expr2
- pform = self._print(vec2)
- pform = prettyForm(*pform.left('('))
- pform = prettyForm(*pform.right(')'))
- pform = prettyForm(*pform.left(self._print(U('DOT OPERATOR'))))
- pform = prettyForm(*pform.left(')'))
- pform = prettyForm(*pform.left(self._print(vec1)))
- pform = prettyForm(*pform.left('('))
- return pform
- def _print_Gradient(self, e):
- func = e._expr
- pform = self._print(func)
- pform = prettyForm(*pform.left('('))
- pform = prettyForm(*pform.right(')'))
- pform = prettyForm(*pform.left(self._print(U('NABLA'))))
- return pform
- def _print_Laplacian(self, e):
- func = e._expr
- pform = self._print(func)
- pform = prettyForm(*pform.left('('))
- pform = prettyForm(*pform.right(')'))
- pform = prettyForm(*pform.left(self._print(U('INCREMENT'))))
- return pform
- def _print_Atom(self, e):
- try:
- # print atoms like Exp1 or Pi
- return prettyForm(pretty_atom(e.__class__.__name__, printer=self))
- except KeyError:
- return self.emptyPrinter(e)
- # Infinity inherits from Number, so we have to override _print_XXX order
- _print_Infinity = _print_Atom
- _print_NegativeInfinity = _print_Atom
- _print_EmptySet = _print_Atom
- _print_Naturals = _print_Atom
- _print_Naturals0 = _print_Atom
- _print_Integers = _print_Atom
- _print_Rationals = _print_Atom
- _print_Complexes = _print_Atom
- _print_EmptySequence = _print_Atom
- def _print_Reals(self, e):
- if self._use_unicode:
- return self._print_Atom(e)
- else:
- inf_list = ['-oo', 'oo']
- return self._print_seq(inf_list, '(', ')')
- def _print_subfactorial(self, e):
- x = e.args[0]
- pform = self._print(x)
- # Add parentheses if needed
- if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol):
- pform = prettyForm(*pform.parens())
- pform = prettyForm(*pform.left('!'))
- return pform
- def _print_factorial(self, e):
- x = e.args[0]
- pform = self._print(x)
- # Add parentheses if needed
- if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol):
- pform = prettyForm(*pform.parens())
- pform = prettyForm(*pform.right('!'))
- return pform
- def _print_factorial2(self, e):
- x = e.args[0]
- pform = self._print(x)
- # Add parentheses if needed
- if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol):
- pform = prettyForm(*pform.parens())
- pform = prettyForm(*pform.right('!!'))
- return pform
- def _print_binomial(self, e):
- n, k = e.args
- n_pform = self._print(n)
- k_pform = self._print(k)
- bar = ' '*max(n_pform.width(), k_pform.width())
- pform = prettyForm(*k_pform.above(bar))
- pform = prettyForm(*pform.above(n_pform))
- pform = prettyForm(*pform.parens('(', ')'))
- pform.baseline = (pform.baseline + 1)//2
- return pform
- def _print_Relational(self, e):
- op = prettyForm(' ' + xsym(e.rel_op) + ' ')
- l = self._print(e.lhs)
- r = self._print(e.rhs)
- pform = prettyForm(*stringPict.next(l, op, r), binding=prettyForm.OPEN)
- return pform
- def _print_Not(self, e):
- from sympy.logic.boolalg import (Equivalent, Implies)
- if self._use_unicode:
- arg = e.args[0]
- pform = self._print(arg)
- if isinstance(arg, Equivalent):
- return self._print_Equivalent(arg, altchar="\N{LEFT RIGHT DOUBLE ARROW WITH STROKE}")
- if isinstance(arg, Implies):
- return self._print_Implies(arg, altchar="\N{RIGHTWARDS ARROW WITH STROKE}")
- if arg.is_Boolean and not arg.is_Not:
- pform = prettyForm(*pform.parens())
- return prettyForm(*pform.left("\N{NOT SIGN}"))
- else:
- return self._print_Function(e)
- def __print_Boolean(self, e, char, sort=True):
- args = e.args
- if sort:
- args = sorted(e.args, key=default_sort_key)
- arg = args[0]
- pform = self._print(arg)
- if arg.is_Boolean and not arg.is_Not:
- pform = prettyForm(*pform.parens())
- for arg in args[1:]:
- pform_arg = self._print(arg)
- if arg.is_Boolean and not arg.is_Not:
- pform_arg = prettyForm(*pform_arg.parens())
- pform = prettyForm(*pform.right(' %s ' % char))
- pform = prettyForm(*pform.right(pform_arg))
- return pform
- def _print_And(self, e):
- if self._use_unicode:
- return self.__print_Boolean(e, "\N{LOGICAL AND}")
- else:
- return self._print_Function(e, sort=True)
- def _print_Or(self, e):
- if self._use_unicode:
- return self.__print_Boolean(e, "\N{LOGICAL OR}")
- else:
- return self._print_Function(e, sort=True)
- def _print_Xor(self, e):
- if self._use_unicode:
- return self.__print_Boolean(e, "\N{XOR}")
- else:
- return self._print_Function(e, sort=True)
- def _print_Nand(self, e):
- if self._use_unicode:
- return self.__print_Boolean(e, "\N{NAND}")
- else:
- return self._print_Function(e, sort=True)
- def _print_Nor(self, e):
- if self._use_unicode:
- return self.__print_Boolean(e, "\N{NOR}")
- else:
- return self._print_Function(e, sort=True)
- def _print_Implies(self, e, altchar=None):
- if self._use_unicode:
- return self.__print_Boolean(e, altchar or "\N{RIGHTWARDS ARROW}", sort=False)
- else:
- return self._print_Function(e)
- def _print_Equivalent(self, e, altchar=None):
- if self._use_unicode:
- return self.__print_Boolean(e, altchar or "\N{LEFT RIGHT DOUBLE ARROW}")
- else:
- return self._print_Function(e, sort=True)
- def _print_conjugate(self, e):
- pform = self._print(e.args[0])
- return prettyForm( *pform.above( hobj('_', pform.width())) )
- def _print_Abs(self, e):
- pform = self._print(e.args[0])
- pform = prettyForm(*pform.parens('|', '|'))
- return pform
- def _print_floor(self, e):
- if self._use_unicode:
- pform = self._print(e.args[0])
- pform = prettyForm(*pform.parens('lfloor', 'rfloor'))
- return pform
- else:
- return self._print_Function(e)
- def _print_ceiling(self, e):
- if self._use_unicode:
- pform = self._print(e.args[0])
- pform = prettyForm(*pform.parens('lceil', 'rceil'))
- return pform
- else:
- return self._print_Function(e)
- def _print_Derivative(self, deriv):
- if requires_partial(deriv.expr) and self._use_unicode:
- deriv_symbol = U('PARTIAL DIFFERENTIAL')
- else:
- deriv_symbol = r'd'
- x = None
- count_total_deriv = 0
- for sym, num in reversed(deriv.variable_count):
- s = self._print(sym)
- ds = prettyForm(*s.left(deriv_symbol))
- count_total_deriv += num
- if (not num.is_Integer) or (num > 1):
- ds = ds**prettyForm(str(num))
- if x is None:
- x = ds
- else:
- x = prettyForm(*x.right(' '))
- x = prettyForm(*x.right(ds))
- f = prettyForm(
- binding=prettyForm.FUNC, *self._print(deriv.expr).parens())
- pform = prettyForm(deriv_symbol)
- if (count_total_deriv > 1) != False:
- pform = pform**prettyForm(str(count_total_deriv))
- pform = prettyForm(*pform.below(stringPict.LINE, x))
- pform.baseline = pform.baseline + 1
- pform = prettyForm(*stringPict.next(pform, f))
- pform.binding = prettyForm.MUL
- return pform
- def _print_Cycle(self, dc):
- from sympy.combinatorics.permutations import Permutation, Cycle
- # for Empty Cycle
- if dc == Cycle():
- cyc = stringPict('')
- return prettyForm(*cyc.parens())
- dc_list = Permutation(dc.list()).cyclic_form
- # for Identity Cycle
- if dc_list == []:
- cyc = self._print(dc.size - 1)
- return prettyForm(*cyc.parens())
- cyc = stringPict('')
- for i in dc_list:
- l = self._print(str(tuple(i)).replace(',', ''))
- cyc = prettyForm(*cyc.right(l))
- return cyc
- def _print_Permutation(self, expr):
- from sympy.combinatorics.permutations import Permutation, Cycle
- perm_cyclic = Permutation.print_cyclic
- if perm_cyclic is not None:
- sympy_deprecation_warning(
- f"""
- Setting Permutation.print_cyclic is deprecated. Instead use
- init_printing(perm_cyclic={perm_cyclic}).
- """,
- deprecated_since_version="1.6",
- active_deprecations_target="deprecated-permutation-print_cyclic",
- stacklevel=7,
- )
- else:
- perm_cyclic = self._settings.get("perm_cyclic", True)
- if perm_cyclic:
- return self._print_Cycle(Cycle(expr))
- lower = expr.array_form
- upper = list(range(len(lower)))
- result = stringPict('')
- first = True
- for u, l in zip(upper, lower):
- s1 = self._print(u)
- s2 = self._print(l)
- col = prettyForm(*s1.below(s2))
- if first:
- first = False
- else:
- col = prettyForm(*col.left(" "))
- result = prettyForm(*result.right(col))
- return prettyForm(*result.parens())
- def _print_Integral(self, integral):
- f = integral.function
- # Add parentheses if arg involves addition of terms and
- # create a pretty form for the argument
- prettyF = self._print(f)
- # XXX generalize parens
- if f.is_Add:
- prettyF = prettyForm(*prettyF.parens())
- # dx dy dz ...
- arg = prettyF
- for x in integral.limits:
- prettyArg = self._print(x[0])
- # XXX qparens (parens if needs-parens)
- if prettyArg.width() > 1:
- prettyArg = prettyForm(*prettyArg.parens())
- arg = prettyForm(*arg.right(' d', prettyArg))
- # \int \int \int ...
- firstterm = True
- s = None
- for lim in integral.limits:
- # Create bar based on the height of the argument
- h = arg.height()
- H = h + 2
- # XXX hack!
- ascii_mode = not self._use_unicode
- if ascii_mode:
- H += 2
- vint = vobj('int', H)
- # Construct the pretty form with the integral sign and the argument
- pform = prettyForm(vint)
- pform.baseline = arg.baseline + (
- H - h)//2 # covering the whole argument
- if len(lim) > 1:
- # Create pretty forms for endpoints, if definite integral.
- # Do not print empty endpoints.
- if len(lim) == 2:
- prettyA = prettyForm("")
- prettyB = self._print(lim[1])
- if len(lim) == 3:
- prettyA = self._print(lim[1])
- prettyB = self._print(lim[2])
- if ascii_mode: # XXX hack
- # Add spacing so that endpoint can more easily be
- # identified with the correct integral sign
- spc = max(1, 3 - prettyB.width())
- prettyB = prettyForm(*prettyB.left(' ' * spc))
- spc = max(1, 4 - prettyA.width())
- prettyA = prettyForm(*prettyA.right(' ' * spc))
- pform = prettyForm(*pform.above(prettyB))
- pform = prettyForm(*pform.below(prettyA))
- if not ascii_mode: # XXX hack
- pform = prettyForm(*pform.right(' '))
- if firstterm:
- s = pform # first term
- firstterm = False
- else:
- s = prettyForm(*s.left(pform))
- pform = prettyForm(*arg.left(s))
- pform.binding = prettyForm.MUL
- return pform
- def _print_Product(self, expr):
- func = expr.term
- pretty_func = self._print(func)
- horizontal_chr = xobj('_', 1)
- corner_chr = xobj('_', 1)
- vertical_chr = xobj('|', 1)
- if self._use_unicode:
- # use unicode corners
- horizontal_chr = xobj('-', 1)
- corner_chr = '\N{BOX DRAWINGS LIGHT DOWN AND HORIZONTAL}'
- func_height = pretty_func.height()
- first = True
- max_upper = 0
- sign_height = 0
- for lim in expr.limits:
- pretty_lower, pretty_upper = self.__print_SumProduct_Limits(lim)
- width = (func_height + 2) * 5 // 3 - 2
- sign_lines = [horizontal_chr + corner_chr + (horizontal_chr * (width-2)) + corner_chr + horizontal_chr]
- for _ in range(func_height + 1):
- sign_lines.append(' ' + vertical_chr + (' ' * (width-2)) + vertical_chr + ' ')
- pretty_sign = stringPict('')
- pretty_sign = prettyForm(*pretty_sign.stack(*sign_lines))
- max_upper = max(max_upper, pretty_upper.height())
- if first:
- sign_height = pretty_sign.height()
- pretty_sign = prettyForm(*pretty_sign.above(pretty_upper))
- pretty_sign = prettyForm(*pretty_sign.below(pretty_lower))
- if first:
- pretty_func.baseline = 0
- first = False
- height = pretty_sign.height()
- padding = stringPict('')
- padding = prettyForm(*padding.stack(*[' ']*(height - 1)))
- pretty_sign = prettyForm(*pretty_sign.right(padding))
- pretty_func = prettyForm(*pretty_sign.right(pretty_func))
- pretty_func.baseline = max_upper + sign_height//2
- pretty_func.binding = prettyForm.MUL
- return pretty_func
- def __print_SumProduct_Limits(self, lim):
- def print_start(lhs, rhs):
- op = prettyForm(' ' + xsym("==") + ' ')
- l = self._print(lhs)
- r = self._print(rhs)
- pform = prettyForm(*stringPict.next(l, op, r))
- return pform
- prettyUpper = self._print(lim[2])
- prettyLower = print_start(lim[0], lim[1])
- return prettyLower, prettyUpper
- def _print_Sum(self, expr):
- ascii_mode = not self._use_unicode
- def asum(hrequired, lower, upper, use_ascii):
- def adjust(s, wid=None, how='<^>'):
- if not wid or len(s) > wid:
- return s
- need = wid - len(s)
- if how in ('<^>', "<") or how not in list('<^>'):
- return s + ' '*need
- half = need//2
- lead = ' '*half
- if how == ">":
- return " "*need + s
- return lead + s + ' '*(need - len(lead))
- h = max(hrequired, 2)
- d = h//2
- w = d + 1
- more = hrequired % 2
- lines = []
- if use_ascii:
- lines.append("_"*(w) + ' ')
- lines.append(r"\%s`" % (' '*(w - 1)))
- for i in range(1, d):
- lines.append('%s\\%s' % (' '*i, ' '*(w - i)))
- if more:
- lines.append('%s)%s' % (' '*(d), ' '*(w - d)))
- for i in reversed(range(1, d)):
- lines.append('%s/%s' % (' '*i, ' '*(w - i)))
- lines.append("/" + "_"*(w - 1) + ',')
- return d, h + more, lines, more
- else:
- w = w + more
- d = d + more
- vsum = vobj('sum', 4)
- lines.append("_"*(w))
- for i in range(0, d):
- lines.append('%s%s%s' % (' '*i, vsum[2], ' '*(w - i - 1)))
- for i in reversed(range(0, d)):
- lines.append('%s%s%s' % (' '*i, vsum[4], ' '*(w - i - 1)))
- lines.append(vsum[8]*(w))
- return d, h + 2*more, lines, more
- f = expr.function
- prettyF = self._print(f)
- if f.is_Add: # add parens
- prettyF = prettyForm(*prettyF.parens())
- H = prettyF.height() + 2
- # \sum \sum \sum ...
- first = True
- max_upper = 0
- sign_height = 0
- for lim in expr.limits:
- prettyLower, prettyUpper = self.__print_SumProduct_Limits(lim)
- max_upper = max(max_upper, prettyUpper.height())
- # Create sum sign based on the height of the argument
- d, h, slines, adjustment = asum(
- H, prettyLower.width(), prettyUpper.width(), ascii_mode)
- prettySign = stringPict('')
- prettySign = prettyForm(*prettySign.stack(*slines))
- if first:
- sign_height = prettySign.height()
- prettySign = prettyForm(*prettySign.above(prettyUpper))
- prettySign = prettyForm(*prettySign.below(prettyLower))
- if first:
- # change F baseline so it centers on the sign
- prettyF.baseline -= d - (prettyF.height()//2 -
- prettyF.baseline)
- first = False
- # put padding to the right
- pad = stringPict('')
- pad = prettyForm(*pad.stack(*[' ']*h))
- prettySign = prettyForm(*prettySign.right(pad))
- # put the present prettyF to the right
- prettyF = prettyForm(*prettySign.right(prettyF))
- # adjust baseline of ascii mode sigma with an odd height so that it is
- # exactly through the center
- ascii_adjustment = ascii_mode if not adjustment else 0
- prettyF.baseline = max_upper + sign_height//2 + ascii_adjustment
- prettyF.binding = prettyForm.MUL
- return prettyF
- def _print_Limit(self, l):
- e, z, z0, dir = l.args
- E = self._print(e)
- if precedence(e) <= PRECEDENCE["Mul"]:
- E = prettyForm(*E.parens('(', ')'))
- Lim = prettyForm('lim')
- LimArg = self._print(z)
- if self._use_unicode:
- LimArg = prettyForm(*LimArg.right('\N{BOX DRAWINGS LIGHT HORIZONTAL}\N{RIGHTWARDS ARROW}'))
- else:
- LimArg = prettyForm(*LimArg.right('->'))
- LimArg = prettyForm(*LimArg.right(self._print(z0)))
- if str(dir) == '+-' or z0 in (S.Infinity, S.NegativeInfinity):
- dir = ""
- else:
- if self._use_unicode:
- dir = '\N{SUPERSCRIPT PLUS SIGN}' if str(dir) == "+" else '\N{SUPERSCRIPT MINUS}'
- LimArg = prettyForm(*LimArg.right(self._print(dir)))
- Lim = prettyForm(*Lim.below(LimArg))
- Lim = prettyForm(*Lim.right(E), binding=prettyForm.MUL)
- return Lim
- def _print_matrix_contents(self, e):
- """
- This method factors out what is essentially grid printing.
- """
- M = e # matrix
- Ms = {} # i,j -> pretty(M[i,j])
- for i in range(M.rows):
- for j in range(M.cols):
- Ms[i, j] = self._print(M[i, j])
- # h- and v- spacers
- hsep = 2
- vsep = 1
- # max width for columns
- maxw = [-1] * M.cols
- for j in range(M.cols):
- maxw[j] = max([Ms[i, j].width() for i in range(M.rows)] or [0])
- # drawing result
- D = None
- for i in range(M.rows):
- D_row = None
- for j in range(M.cols):
- s = Ms[i, j]
- # reshape s to maxw
- # XXX this should be generalized, and go to stringPict.reshape ?
- assert s.width() <= maxw[j]
- # hcenter it, +0.5 to the right 2
- # ( it's better to align formula starts for say 0 and r )
- # XXX this is not good in all cases -- maybe introduce vbaseline?
- wdelta = maxw[j] - s.width()
- wleft = wdelta // 2
- wright = wdelta - wleft
- s = prettyForm(*s.right(' '*wright))
- s = prettyForm(*s.left(' '*wleft))
- # we don't need vcenter cells -- this is automatically done in
- # a pretty way because when their baselines are taking into
- # account in .right()
- if D_row is None:
- D_row = s # first box in a row
- continue
- D_row = prettyForm(*D_row.right(' '*hsep)) # h-spacer
- D_row = prettyForm(*D_row.right(s))
- if D is None:
- D = D_row # first row in a picture
- continue
- # v-spacer
- for _ in range(vsep):
- D = prettyForm(*D.below(' '))
- D = prettyForm(*D.below(D_row))
- if D is None:
- D = prettyForm('') # Empty Matrix
- return D
- def _print_MatrixBase(self, e, lparens='[', rparens=']'):
- D = self._print_matrix_contents(e)
- D.baseline = D.height()//2
- D = prettyForm(*D.parens(lparens, rparens))
- return D
- def _print_Determinant(self, e):
- mat = e.arg
- if mat.is_MatrixExpr:
- from sympy.matrices.expressions.blockmatrix import BlockMatrix
- if isinstance(mat, BlockMatrix):
- return self._print_MatrixBase(mat.blocks, lparens='|', rparens='|')
- D = self._print(mat)
- D.baseline = D.height()//2
- return prettyForm(*D.parens('|', '|'))
- else:
- return self._print_MatrixBase(mat, lparens='|', rparens='|')
- def _print_TensorProduct(self, expr):
- # This should somehow share the code with _print_WedgeProduct:
- if self._use_unicode:
- circled_times = "\u2297"
- else:
- circled_times = ".*"
- return self._print_seq(expr.args, None, None, circled_times,
- parenthesize=lambda x: precedence_traditional(x) <= PRECEDENCE["Mul"])
- def _print_WedgeProduct(self, expr):
- # This should somehow share the code with _print_TensorProduct:
- if self._use_unicode:
- wedge_symbol = "\u2227"
- else:
- wedge_symbol = '/\\'
- return self._print_seq(expr.args, None, None, wedge_symbol,
- parenthesize=lambda x: precedence_traditional(x) <= PRECEDENCE["Mul"])
- def _print_Trace(self, e):
- D = self._print(e.arg)
- D = prettyForm(*D.parens('(',')'))
- D.baseline = D.height()//2
- D = prettyForm(*D.left('\n'*(0) + 'tr'))
- return D
- def _print_MatrixElement(self, expr):
- from sympy.matrices import MatrixSymbol
- if (isinstance(expr.parent, MatrixSymbol)
- and expr.i.is_number and expr.j.is_number):
- return self._print(
- Symbol(expr.parent.name + '_%d%d' % (expr.i, expr.j)))
- else:
- prettyFunc = self._print(expr.parent)
- prettyFunc = prettyForm(*prettyFunc.parens())
- prettyIndices = self._print_seq((expr.i, expr.j), delimiter=', '
- ).parens(left='[', right=']')[0]
- pform = prettyForm(binding=prettyForm.FUNC,
- *stringPict.next(prettyFunc, prettyIndices))
- # store pform parts so it can be reassembled e.g. when powered
- pform.prettyFunc = prettyFunc
- pform.prettyArgs = prettyIndices
- return pform
- def _print_MatrixSlice(self, m):
- # XXX works only for applied functions
- from sympy.matrices import MatrixSymbol
- prettyFunc = self._print(m.parent)
- if not isinstance(m.parent, MatrixSymbol):
- prettyFunc = prettyForm(*prettyFunc.parens())
- def ppslice(x, dim):
- x = list(x)
- if x[2] == 1:
- del x[2]
- if x[0] == 0:
- x[0] = ''
- if x[1] == dim:
- x[1] = ''
- return prettyForm(*self._print_seq(x, delimiter=':'))
- prettyArgs = self._print_seq((ppslice(m.rowslice, m.parent.rows),
- ppslice(m.colslice, m.parent.cols)), delimiter=', ').parens(left='[', right=']')[0]
- pform = prettyForm(
- binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
- # store pform parts so it can be reassembled e.g. when powered
- pform.prettyFunc = prettyFunc
- pform.prettyArgs = prettyArgs
- return pform
- def _print_Transpose(self, expr):
- mat = expr.arg
- pform = self._print(mat)
- from sympy.matrices import MatrixSymbol, BlockMatrix
- if (not isinstance(mat, MatrixSymbol) and
- not isinstance(mat, BlockMatrix) and mat.is_MatrixExpr):
- pform = prettyForm(*pform.parens())
- pform = pform**(prettyForm('T'))
- return pform
- def _print_Adjoint(self, expr):
- mat = expr.arg
- pform = self._print(mat)
- if self._use_unicode:
- dag = prettyForm('\N{DAGGER}')
- else:
- dag = prettyForm('+')
- from sympy.matrices import MatrixSymbol, BlockMatrix
- if (not isinstance(mat, MatrixSymbol) and
- not isinstance(mat, BlockMatrix) and mat.is_MatrixExpr):
- pform = prettyForm(*pform.parens())
- pform = pform**dag
- return pform
- def _print_BlockMatrix(self, B):
- if B.blocks.shape == (1, 1):
- return self._print(B.blocks[0, 0])
- return self._print(B.blocks)
- def _print_MatAdd(self, expr):
- s = None
- for item in expr.args:
- pform = self._print(item)
- if s is None:
- s = pform # First element
- else:
- coeff = item.as_coeff_mmul()[0]
- if S(coeff).could_extract_minus_sign():
- s = prettyForm(*stringPict.next(s, ' '))
- pform = self._print(item)
- else:
- s = prettyForm(*stringPict.next(s, ' + '))
- s = prettyForm(*stringPict.next(s, pform))
- return s
- def _print_MatMul(self, expr):
- args = list(expr.args)
- from sympy.matrices.expressions.hadamard import HadamardProduct
- from sympy.matrices.expressions.kronecker import KroneckerProduct
- from sympy.matrices.expressions.matadd import MatAdd
- for i, a in enumerate(args):
- if (isinstance(a, (Add, MatAdd, HadamardProduct, KroneckerProduct))
- and len(expr.args) > 1):
- args[i] = prettyForm(*self._print(a).parens())
- else:
- args[i] = self._print(a)
- return prettyForm.__mul__(*args)
- def _print_Identity(self, expr):
- if self._use_unicode:
- return prettyForm('\N{MATHEMATICAL DOUBLE-STRUCK CAPITAL I}')
- else:
- return prettyForm('I')
- def _print_ZeroMatrix(self, expr):
- if self._use_unicode:
- return prettyForm('\N{MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO}')
- else:
- return prettyForm('0')
- def _print_OneMatrix(self, expr):
- if self._use_unicode:
- return prettyForm('\N{MATHEMATICAL DOUBLE-STRUCK DIGIT ONE}')
- else:
- return prettyForm('1')
- def _print_DotProduct(self, expr):
- args = list(expr.args)
- for i, a in enumerate(args):
- args[i] = self._print(a)
- return prettyForm.__mul__(*args)
- def _print_MatPow(self, expr):
- pform = self._print(expr.base)
- from sympy.matrices import MatrixSymbol
- if not isinstance(expr.base, MatrixSymbol) and expr.base.is_MatrixExpr:
- pform = prettyForm(*pform.parens())
- pform = pform**(self._print(expr.exp))
- return pform
- def _print_HadamardProduct(self, expr):
- from sympy.matrices.expressions.hadamard import HadamardProduct
- from sympy.matrices.expressions.matadd import MatAdd
- from sympy.matrices.expressions.matmul import MatMul
- if self._use_unicode:
- delim = pretty_atom('Ring')
- else:
- delim = '.*'
- return self._print_seq(expr.args, None, None, delim,
- parenthesize=lambda x: isinstance(x, (MatAdd, MatMul, HadamardProduct)))
- def _print_HadamardPower(self, expr):
- # from sympy import MatAdd, MatMul
- if self._use_unicode:
- circ = pretty_atom('Ring')
- else:
- circ = self._print('.')
- pretty_base = self._print(expr.base)
- pretty_exp = self._print(expr.exp)
- if precedence(expr.exp) < PRECEDENCE["Mul"]:
- pretty_exp = prettyForm(*pretty_exp.parens())
- pretty_circ_exp = prettyForm(
- binding=prettyForm.LINE,
- *stringPict.next(circ, pretty_exp)
- )
- return pretty_base**pretty_circ_exp
- def _print_KroneckerProduct(self, expr):
- from sympy.matrices.expressions.matadd import MatAdd
- from sympy.matrices.expressions.matmul import MatMul
- if self._use_unicode:
- delim = ' \N{N-ARY CIRCLED TIMES OPERATOR} '
- else:
- delim = ' x '
- return self._print_seq(expr.args, None, None, delim,
- parenthesize=lambda x: isinstance(x, (MatAdd, MatMul)))
- def _print_FunctionMatrix(self, X):
- D = self._print(X.lamda.expr)
- D = prettyForm(*D.parens('[', ']'))
- return D
- def _print_TransferFunction(self, expr):
- if not expr.num == 1:
- num, den = expr.num, expr.den
- res = Mul(num, Pow(den, -1, evaluate=False), evaluate=False)
- return self._print_Mul(res)
- else:
- return self._print(1)/self._print(expr.den)
- def _print_Series(self, expr):
- args = list(expr.args)
- for i, a in enumerate(expr.args):
- args[i] = prettyForm(*self._print(a).parens())
- return prettyForm.__mul__(*args)
- def _print_MIMOSeries(self, expr):
- from sympy.physics.control.lti import MIMOParallel
- args = list(expr.args)
- pretty_args = []
- for i, a in enumerate(reversed(args)):
- if (isinstance(a, MIMOParallel) and len(expr.args) > 1):
- expression = self._print(a)
- expression.baseline = expression.height()//2
- pretty_args.append(prettyForm(*expression.parens()))
- else:
- expression = self._print(a)
- expression.baseline = expression.height()//2
- pretty_args.append(expression)
- return prettyForm.__mul__(*pretty_args)
- def _print_Parallel(self, expr):
- s = None
- for item in expr.args:
- pform = self._print(item)
- if s is None:
- s = pform # First element
- else:
- s = prettyForm(*stringPict.next(s))
- s.baseline = s.height()//2
- s = prettyForm(*stringPict.next(s, ' + '))
- s = prettyForm(*stringPict.next(s, pform))
- return s
- def _print_MIMOParallel(self, expr):
- from sympy.physics.control.lti import TransferFunctionMatrix
- s = None
- for item in expr.args:
- pform = self._print(item)
- if s is None:
- s = pform # First element
- else:
- s = prettyForm(*stringPict.next(s))
- s.baseline = s.height()//2
- s = prettyForm(*stringPict.next(s, ' + '))
- if isinstance(item, TransferFunctionMatrix):
- s.baseline = s.height() - 1
- s = prettyForm(*stringPict.next(s, pform))
- # s.baseline = s.height()//2
- return s
- def _print_Feedback(self, expr):
- from sympy.physics.control import TransferFunction, Series
- num, tf = expr.sys1, TransferFunction(1, 1, expr.var)
- num_arg_list = list(num.args) if isinstance(num, Series) else [num]
- den_arg_list = list(expr.sys2.args) if \
- isinstance(expr.sys2, Series) else [expr.sys2]
- if isinstance(num, Series) and isinstance(expr.sys2, Series):
- den = Series(*num_arg_list, *den_arg_list)
- elif isinstance(num, Series) and isinstance(expr.sys2, TransferFunction):
- if expr.sys2 == tf:
- den = Series(*num_arg_list)
- else:
- den = Series(*num_arg_list, expr.sys2)
- elif isinstance(num, TransferFunction) and isinstance(expr.sys2, Series):
- if num == tf:
- den = Series(*den_arg_list)
- else:
- den = Series(num, *den_arg_list)
- else:
- if num == tf:
- den = Series(*den_arg_list)
- elif expr.sys2 == tf:
- den = Series(*num_arg_list)
- else:
- den = Series(*num_arg_list, *den_arg_list)
- denom = prettyForm(*stringPict.next(self._print(tf)))
- denom.baseline = denom.height()//2
- denom = prettyForm(*stringPict.next(denom, ' + ')) if expr.sign == -1 \
- else prettyForm(*stringPict.next(denom, ' - '))
- denom = prettyForm(*stringPict.next(denom, self._print(den)))
- return self._print(num)/denom
- def _print_MIMOFeedback(self, expr):
- from sympy.physics.control import MIMOSeries, TransferFunctionMatrix
- inv_mat = self._print(MIMOSeries(expr.sys2, expr.sys1))
- plant = self._print(expr.sys1)
- _feedback = prettyForm(*stringPict.next(inv_mat))
- _feedback = prettyForm(*stringPict.right("I + ", _feedback)) if expr.sign == -1 \
- else prettyForm(*stringPict.right("I - ", _feedback))
- _feedback = prettyForm(*stringPict.parens(_feedback))
- _feedback.baseline = 0
- _feedback = prettyForm(*stringPict.right(_feedback, '-1 '))
- _feedback.baseline = _feedback.height()//2
- _feedback = prettyForm.__mul__(_feedback, prettyForm(" "))
- if isinstance(expr.sys1, TransferFunctionMatrix):
- _feedback.baseline = _feedback.height() - 1
- _feedback = prettyForm(*stringPict.next(_feedback, plant))
- return _feedback
- def _print_TransferFunctionMatrix(self, expr):
- mat = self._print(expr._expr_mat)
- mat.baseline = mat.height() - 1
- subscript = greek_unicode['tau'] if self._use_unicode else r'{t}'
- mat = prettyForm(*mat.right(subscript))
- return mat
- def _print_BasisDependent(self, expr):
- from sympy.vector import Vector
- if not self._use_unicode:
- raise NotImplementedError("ASCII pretty printing of BasisDependent is not implemented")
- if expr == expr.zero:
- return prettyForm(expr.zero._pretty_form)
- o1 = []
- vectstrs = []
- if isinstance(expr, Vector):
- items = expr.separate().items()
- else:
- items = [(0, expr)]
- for system, vect in items:
- inneritems = list(vect.components.items())
- inneritems.sort(key = lambda x: x[0].__str__())
- for k, v in inneritems:
- #if the coef of the basis vector is 1
- #we skip the 1
- if v == 1:
- o1.append("" +
- k._pretty_form)
- #Same for -1
- elif v == -1:
- o1.append("(-1) " +
- k._pretty_form)
- #For a general expr
- else:
- #We always wrap the measure numbers in
- #parentheses
- arg_str = self._print(
- v).parens()[0]
- o1.append(arg_str + ' ' + k._pretty_form)
- vectstrs.append(k._pretty_form)
- #outstr = u("").join(o1)
- if o1[0].startswith(" + "):
- o1[0] = o1[0][3:]
- elif o1[0].startswith(" "):
- o1[0] = o1[0][1:]
- #Fixing the newlines
- lengths = []
- strs = ['']
- flag = []
- for i, partstr in enumerate(o1):
- flag.append(0)
- # XXX: What is this hack?
- if '\n' in partstr:
- tempstr = partstr
- tempstr = tempstr.replace(vectstrs[i], '')
- if '\N{RIGHT PARENTHESIS EXTENSION}' in tempstr: # If scalar is a fraction
- for paren in range(len(tempstr)):
- flag[i] = 1
- if tempstr[paren] == '\N{RIGHT PARENTHESIS EXTENSION}' and tempstr[paren + 1] == '\n':
- # We want to place the vector string after all the right parentheses, because
- # otherwise, the vector will be in the middle of the string
- tempstr = tempstr[:paren] + '\N{RIGHT PARENTHESIS EXTENSION}'\
- + ' ' + vectstrs[i] + tempstr[paren + 1:]
- break
- elif '\N{RIGHT PARENTHESIS LOWER HOOK}' in tempstr:
- # We want to place the vector string after all the right parentheses, because
- # otherwise, the vector will be in the middle of the string. For this reason,
- # we insert the vector string at the rightmost index.
- index = tempstr.rfind('\N{RIGHT PARENTHESIS LOWER HOOK}')
- if index != -1: # then this character was found in this string
- flag[i] = 1
- tempstr = tempstr[:index] + '\N{RIGHT PARENTHESIS LOWER HOOK}'\
- + ' ' + vectstrs[i] + tempstr[index + 1:]
- o1[i] = tempstr
- o1 = [x.split('\n') for x in o1]
- n_newlines = max([len(x) for x in o1]) # Width of part in its pretty form
- if 1 in flag: # If there was a fractional scalar
- for i, parts in enumerate(o1):
- if len(parts) == 1: # If part has no newline
- parts.insert(0, ' ' * (len(parts[0])))
- flag[i] = 1
- for i, parts in enumerate(o1):
- lengths.append(len(parts[flag[i]]))
- for j in range(n_newlines):
- if j+1 <= len(parts):
- if j >= len(strs):
- strs.append(' ' * (sum(lengths[:-1]) +
- 3*(len(lengths)-1)))
- if j == flag[i]:
- strs[flag[i]] += parts[flag[i]] + ' + '
- else:
- strs[j] += parts[j] + ' '*(lengths[-1] -
- len(parts[j])+
- 3)
- else:
- if j >= len(strs):
- strs.append(' ' * (sum(lengths[:-1]) +
- 3*(len(lengths)-1)))
- strs[j] += ' '*(lengths[-1]+3)
- return prettyForm('\n'.join([s[:-3] for s in strs]))
- def _print_NDimArray(self, expr):
- from sympy.matrices.immutable import ImmutableMatrix
- if expr.rank() == 0:
- return self._print(expr[()])
- level_str = [[]] + [[] for i in range(expr.rank())]
- shape_ranges = [list(range(i)) for i in expr.shape]
- # leave eventual matrix elements unflattened
- mat = lambda x: ImmutableMatrix(x, evaluate=False)
- for outer_i in itertools.product(*shape_ranges):
- level_str[-1].append(expr[outer_i])
- even = True
- for back_outer_i in range(expr.rank()-1, -1, -1):
- if len(level_str[back_outer_i+1]) < expr.shape[back_outer_i]:
- break
- if even:
- level_str[back_outer_i].append(level_str[back_outer_i+1])
- else:
- level_str[back_outer_i].append(mat(
- level_str[back_outer_i+1]))
- if len(level_str[back_outer_i + 1]) == 1:
- level_str[back_outer_i][-1] = mat(
- [[level_str[back_outer_i][-1]]])
- even = not even
- level_str[back_outer_i+1] = []
- out_expr = level_str[0][0]
- if expr.rank() % 2 == 1:
- out_expr = mat([out_expr])
- return self._print(out_expr)
- def _printer_tensor_indices(self, name, indices, index_map={}):
- center = stringPict(name)
- top = stringPict(" "*center.width())
- bot = stringPict(" "*center.width())
- last_valence = None
- prev_map = None
- for i, index in enumerate(indices):
- indpic = self._print(index.args[0])
- if ((index in index_map) or prev_map) and last_valence == index.is_up:
- if index.is_up:
- top = prettyForm(*stringPict.next(top, ","))
- else:
- bot = prettyForm(*stringPict.next(bot, ","))
- if index in index_map:
- indpic = prettyForm(*stringPict.next(indpic, "="))
- indpic = prettyForm(*stringPict.next(indpic, self._print(index_map[index])))
- prev_map = True
- else:
- prev_map = False
- if index.is_up:
- top = stringPict(*top.right(indpic))
- center = stringPict(*center.right(" "*indpic.width()))
- bot = stringPict(*bot.right(" "*indpic.width()))
- else:
- bot = stringPict(*bot.right(indpic))
- center = stringPict(*center.right(" "*indpic.width()))
- top = stringPict(*top.right(" "*indpic.width()))
- last_valence = index.is_up
- pict = prettyForm(*center.above(top))
- pict = prettyForm(*pict.below(bot))
- return pict
- def _print_Tensor(self, expr):
- name = expr.args[0].name
- indices = expr.get_indices()
- return self._printer_tensor_indices(name, indices)
- def _print_TensorElement(self, expr):
- name = expr.expr.args[0].name
- indices = expr.expr.get_indices()
- index_map = expr.index_map
- return self._printer_tensor_indices(name, indices, index_map)
- def _print_TensMul(self, expr):
- sign, args = expr._get_args_for_traditional_printer()
- args = [
- prettyForm(*self._print(i).parens()) if
- precedence_traditional(i) < PRECEDENCE["Mul"] else self._print(i)
- for i in args
- ]
- pform = prettyForm.__mul__(*args)
- if sign:
- return prettyForm(*pform.left(sign))
- else:
- return pform
- def _print_TensAdd(self, expr):
- args = [
- prettyForm(*self._print(i).parens()) if
- precedence_traditional(i) < PRECEDENCE["Mul"] else self._print(i)
- for i in expr.args
- ]
- return prettyForm.__add__(*args)
- def _print_TensorIndex(self, expr):
- sym = expr.args[0]
- if not expr.is_up:
- sym = -sym
- return self._print(sym)
- def _print_PartialDerivative(self, deriv):
- if self._use_unicode:
- deriv_symbol = U('PARTIAL DIFFERENTIAL')
- else:
- deriv_symbol = r'd'
- x = None
- for variable in reversed(deriv.variables):
- s = self._print(variable)
- ds = prettyForm(*s.left(deriv_symbol))
- if x is None:
- x = ds
- else:
- x = prettyForm(*x.right(' '))
- x = prettyForm(*x.right(ds))
- f = prettyForm(
- binding=prettyForm.FUNC, *self._print(deriv.expr).parens())
- pform = prettyForm(deriv_symbol)
- if len(deriv.variables) > 1:
- pform = pform**self._print(len(deriv.variables))
- pform = prettyForm(*pform.below(stringPict.LINE, x))
- pform.baseline = pform.baseline + 1
- pform = prettyForm(*stringPict.next(pform, f))
- pform.binding = prettyForm.MUL
- return pform
- def _print_Piecewise(self, pexpr):
- P = {}
- for n, ec in enumerate(pexpr.args):
- P[n, 0] = self._print(ec.expr)
- if ec.cond == True:
- P[n, 1] = prettyForm('otherwise')
- else:
- P[n, 1] = prettyForm(
- *prettyForm('for ').right(self._print(ec.cond)))
- hsep = 2
- vsep = 1
- len_args = len(pexpr.args)
- # max widths
- maxw = [max([P[i, j].width() for i in range(len_args)])
- for j in range(2)]
- # FIXME: Refactor this code and matrix into some tabular environment.
- # drawing result
- D = None
- for i in range(len_args):
- D_row = None
- for j in range(2):
- p = P[i, j]
- assert p.width() <= maxw[j]
- wdelta = maxw[j] - p.width()
- wleft = wdelta // 2
- wright = wdelta - wleft
- p = prettyForm(*p.right(' '*wright))
- p = prettyForm(*p.left(' '*wleft))
- if D_row is None:
- D_row = p
- continue
- D_row = prettyForm(*D_row.right(' '*hsep)) # h-spacer
- D_row = prettyForm(*D_row.right(p))
- if D is None:
- D = D_row # first row in a picture
- continue
- # v-spacer
- for _ in range(vsep):
- D = prettyForm(*D.below(' '))
- D = prettyForm(*D.below(D_row))
- D = prettyForm(*D.parens('{', ''))
- D.baseline = D.height()//2
- D.binding = prettyForm.OPEN
- return D
- def _print_ITE(self, ite):
- from sympy.functions.elementary.piecewise import Piecewise
- return self._print(ite.rewrite(Piecewise))
- def _hprint_vec(self, v):
- D = None
- for a in v:
- p = a
- if D is None:
- D = p
- else:
- D = prettyForm(*D.right(', '))
- D = prettyForm(*D.right(p))
- if D is None:
- D = stringPict(' ')
- return D
- def _hprint_vseparator(self, p1, p2, left=None, right=None, delimiter='', ifascii_nougly=False):
- if ifascii_nougly and not self._use_unicode:
- return self._print_seq((p1, '|', p2), left=left, right=right,
- delimiter=delimiter, ifascii_nougly=True)
- tmp = self._print_seq((p1, p2,), left=left, right=right, delimiter=delimiter)
- sep = stringPict(vobj('|', tmp.height()), baseline=tmp.baseline)
- return self._print_seq((p1, sep, p2), left=left, right=right,
- delimiter=delimiter)
- def _print_hyper(self, e):
- # FIXME refactor Matrix, Piecewise, and this into a tabular environment
- ap = [self._print(a) for a in e.ap]
- bq = [self._print(b) for b in e.bq]
- P = self._print(e.argument)
- P.baseline = P.height()//2
- # Drawing result - first create the ap, bq vectors
- D = None
- for v in [ap, bq]:
- D_row = self._hprint_vec(v)
- if D is None:
- D = D_row # first row in a picture
- else:
- D = prettyForm(*D.below(' '))
- D = prettyForm(*D.below(D_row))
- # make sure that the argument `z' is centred vertically
- D.baseline = D.height()//2
- # insert horizontal separator
- P = prettyForm(*P.left(' '))
- D = prettyForm(*D.right(' '))
- # insert separating `|`
- D = self._hprint_vseparator(D, P)
- # add parens
- D = prettyForm(*D.parens('(', ')'))
- # create the F symbol
- above = D.height()//2 - 1
- below = D.height() - above - 1
- sz, t, b, add, img = annotated('F')
- F = prettyForm('\n' * (above - t) + img + '\n' * (below - b),
- baseline=above + sz)
- add = (sz + 1)//2
- F = prettyForm(*F.left(self._print(len(e.ap))))
- F = prettyForm(*F.right(self._print(len(e.bq))))
- F.baseline = above + add
- D = prettyForm(*F.right(' ', D))
- return D
- def _print_meijerg(self, e):
- # FIXME refactor Matrix, Piecewise, and this into a tabular environment
- v = {}
- v[(0, 0)] = [self._print(a) for a in e.an]
- v[(0, 1)] = [self._print(a) for a in e.aother]
- v[(1, 0)] = [self._print(b) for b in e.bm]
- v[(1, 1)] = [self._print(b) for b in e.bother]
- P = self._print(e.argument)
- P.baseline = P.height()//2
- vp = {}
- for idx in v:
- vp[idx] = self._hprint_vec(v[idx])
- for i in range(2):
- maxw = max(vp[(0, i)].width(), vp[(1, i)].width())
- for j in range(2):
- s = vp[(j, i)]
- left = (maxw - s.width()) // 2
- right = maxw - left - s.width()
- s = prettyForm(*s.left(' ' * left))
- s = prettyForm(*s.right(' ' * right))
- vp[(j, i)] = s
- D1 = prettyForm(*vp[(0, 0)].right(' ', vp[(0, 1)]))
- D1 = prettyForm(*D1.below(' '))
- D2 = prettyForm(*vp[(1, 0)].right(' ', vp[(1, 1)]))
- D = prettyForm(*D1.below(D2))
- # make sure that the argument `z' is centred vertically
- D.baseline = D.height()//2
- # insert horizontal separator
- P = prettyForm(*P.left(' '))
- D = prettyForm(*D.right(' '))
- # insert separating `|`
- D = self._hprint_vseparator(D, P)
- # add parens
- D = prettyForm(*D.parens('(', ')'))
- # create the G symbol
- above = D.height()//2 - 1
- below = D.height() - above - 1
- sz, t, b, add, img = annotated('G')
- F = prettyForm('\n' * (above - t) + img + '\n' * (below - b),
- baseline=above + sz)
- pp = self._print(len(e.ap))
- pq = self._print(len(e.bq))
- pm = self._print(len(e.bm))
- pn = self._print(len(e.an))
- def adjust(p1, p2):
- diff = p1.width() - p2.width()
- if diff == 0:
- return p1, p2
- elif diff > 0:
- return p1, prettyForm(*p2.left(' '*diff))
- else:
- return prettyForm(*p1.left(' '*-diff)), p2
- pp, pm = adjust(pp, pm)
- pq, pn = adjust(pq, pn)
- pu = prettyForm(*pm.right(', ', pn))
- pl = prettyForm(*pp.right(', ', pq))
- ht = F.baseline - above - 2
- if ht > 0:
- pu = prettyForm(*pu.below('\n'*ht))
- p = prettyForm(*pu.below(pl))
- F.baseline = above
- F = prettyForm(*F.right(p))
- F.baseline = above + add
- D = prettyForm(*F.right(' ', D))
- return D
- def _print_ExpBase(self, e):
- # TODO should exp_polar be printed differently?
- # what about exp_polar(0), exp_polar(1)?
- base = prettyForm(pretty_atom('Exp1', 'e'))
- return base ** self._print(e.args[0])
- def _print_Exp1(self, e):
- return prettyForm(pretty_atom('Exp1', 'e'))
- def _print_Function(self, e, sort=False, func_name=None, left='(',
- right=')'):
- # optional argument func_name for supplying custom names
- # XXX works only for applied functions
- return self._helper_print_function(e.func, e.args, sort=sort, func_name=func_name, left=left, right=right)
- def _print_mathieuc(self, e):
- return self._print_Function(e, func_name='C')
- def _print_mathieus(self, e):
- return self._print_Function(e, func_name='S')
- def _print_mathieucprime(self, e):
- return self._print_Function(e, func_name="C'")
- def _print_mathieusprime(self, e):
- return self._print_Function(e, func_name="S'")
- def _helper_print_function(self, func, args, sort=False, func_name=None,
- delimiter=', ', elementwise=False, left='(',
- right=')'):
- if sort:
- args = sorted(args, key=default_sort_key)
- if not func_name and hasattr(func, "__name__"):
- func_name = func.__name__
- if func_name:
- prettyFunc = self._print(Symbol(func_name))
- else:
- prettyFunc = prettyForm(*self._print(func).parens())
- if elementwise:
- if self._use_unicode:
- circ = pretty_atom('Modifier Letter Low Ring')
- else:
- circ = '.'
- circ = self._print(circ)
- prettyFunc = prettyForm(
- binding=prettyForm.LINE,
- *stringPict.next(prettyFunc, circ)
- )
- prettyArgs = prettyForm(*self._print_seq(args, delimiter=delimiter).parens(
- left=left, right=right))
- pform = prettyForm(
- binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
- # store pform parts so it can be reassembled e.g. when powered
- pform.prettyFunc = prettyFunc
- pform.prettyArgs = prettyArgs
- return pform
- def _print_ElementwiseApplyFunction(self, e):
- func = e.function
- arg = e.expr
- args = [arg]
- return self._helper_print_function(func, args, delimiter="", elementwise=True)
- @property
- def _special_function_classes(self):
- from sympy.functions.special.tensor_functions import KroneckerDelta
- from sympy.functions.special.gamma_functions import gamma, lowergamma
- from sympy.functions.special.zeta_functions import lerchphi
- from sympy.functions.special.beta_functions import beta
- from sympy.functions.special.delta_functions import DiracDelta
- from sympy.functions.special.error_functions import Chi
- return {KroneckerDelta: [greek_unicode['delta'], 'delta'],
- gamma: [greek_unicode['Gamma'], 'Gamma'],
- lerchphi: [greek_unicode['Phi'], 'lerchphi'],
- lowergamma: [greek_unicode['gamma'], 'gamma'],
- beta: [greek_unicode['Beta'], 'B'],
- DiracDelta: [greek_unicode['delta'], 'delta'],
- Chi: ['Chi', 'Chi']}
- def _print_FunctionClass(self, expr):
- for cls in self._special_function_classes:
- if issubclass(expr, cls) and expr.__name__ == cls.__name__:
- if self._use_unicode:
- return prettyForm(self._special_function_classes[cls][0])
- else:
- return prettyForm(self._special_function_classes[cls][1])
- func_name = expr.__name__
- return prettyForm(pretty_symbol(func_name))
- def _print_GeometryEntity(self, expr):
- # GeometryEntity is based on Tuple but should not print like a Tuple
- return self.emptyPrinter(expr)
- def _print_lerchphi(self, e):
- func_name = greek_unicode['Phi'] if self._use_unicode else 'lerchphi'
- return self._print_Function(e, func_name=func_name)
- def _print_dirichlet_eta(self, e):
- func_name = greek_unicode['eta'] if self._use_unicode else 'dirichlet_eta'
- return self._print_Function(e, func_name=func_name)
- def _print_Heaviside(self, e):
- func_name = greek_unicode['theta'] if self._use_unicode else 'Heaviside'
- if e.args[1] is S.Half:
- pform = prettyForm(*self._print(e.args[0]).parens())
- pform = prettyForm(*pform.left(func_name))
- return pform
- else:
- return self._print_Function(e, func_name=func_name)
- def _print_fresnels(self, e):
- return self._print_Function(e, func_name="S")
- def _print_fresnelc(self, e):
- return self._print_Function(e, func_name="C")
- def _print_airyai(self, e):
- return self._print_Function(e, func_name="Ai")
- def _print_airybi(self, e):
- return self._print_Function(e, func_name="Bi")
- def _print_airyaiprime(self, e):
- return self._print_Function(e, func_name="Ai'")
- def _print_airybiprime(self, e):
- return self._print_Function(e, func_name="Bi'")
- def _print_LambertW(self, e):
- return self._print_Function(e, func_name="W")
- def _print_Covariance(self, e):
- return self._print_Function(e, func_name="Cov")
- def _print_Variance(self, e):
- return self._print_Function(e, func_name="Var")
- def _print_Probability(self, e):
- return self._print_Function(e, func_name="P")
- def _print_Expectation(self, e):
- return self._print_Function(e, func_name="E", left='[', right=']')
- def _print_Lambda(self, e):
- expr = e.expr
- sig = e.signature
- if self._use_unicode:
- arrow = " \N{RIGHTWARDS ARROW FROM BAR} "
- else:
- arrow = " -> "
- if len(sig) == 1 and sig[0].is_symbol:
- sig = sig[0]
- var_form = self._print(sig)
- return prettyForm(*stringPict.next(var_form, arrow, self._print(expr)), binding=8)
- def _print_Order(self, expr):
- pform = self._print(expr.expr)
- if (expr.point and any(p != S.Zero for p in expr.point)) or \
- len(expr.variables) > 1:
- pform = prettyForm(*pform.right("; "))
- if len(expr.variables) > 1:
- pform = prettyForm(*pform.right(self._print(expr.variables)))
- elif len(expr.variables):
- pform = prettyForm(*pform.right(self._print(expr.variables[0])))
- if self._use_unicode:
- pform = prettyForm(*pform.right(" \N{RIGHTWARDS ARROW} "))
- else:
- pform = prettyForm(*pform.right(" -> "))
- if len(expr.point) > 1:
- pform = prettyForm(*pform.right(self._print(expr.point)))
- else:
- pform = prettyForm(*pform.right(self._print(expr.point[0])))
- pform = prettyForm(*pform.parens())
- pform = prettyForm(*pform.left("O"))
- return pform
- def _print_SingularityFunction(self, e):
- if self._use_unicode:
- shift = self._print(e.args[0]-e.args[1])
- n = self._print(e.args[2])
- base = prettyForm("<")
- base = prettyForm(*base.right(shift))
- base = prettyForm(*base.right(">"))
- pform = base**n
- return pform
- else:
- n = self._print(e.args[2])
- shift = self._print(e.args[0]-e.args[1])
- base = self._print_seq(shift, "<", ">", ' ')
- return base**n
- def _print_beta(self, e):
- func_name = greek_unicode['Beta'] if self._use_unicode else 'B'
- return self._print_Function(e, func_name=func_name)
- def _print_betainc(self, e):
- func_name = "B'"
- return self._print_Function(e, func_name=func_name)
- def _print_betainc_regularized(self, e):
- func_name = 'I'
- return self._print_Function(e, func_name=func_name)
- def _print_gamma(self, e):
- func_name = greek_unicode['Gamma'] if self._use_unicode else 'Gamma'
- return self._print_Function(e, func_name=func_name)
- def _print_uppergamma(self, e):
- func_name = greek_unicode['Gamma'] if self._use_unicode else 'Gamma'
- return self._print_Function(e, func_name=func_name)
- def _print_lowergamma(self, e):
- func_name = greek_unicode['gamma'] if self._use_unicode else 'lowergamma'
- return self._print_Function(e, func_name=func_name)
- def _print_DiracDelta(self, e):
- if self._use_unicode:
- if len(e.args) == 2:
- a = prettyForm(greek_unicode['delta'])
- b = self._print(e.args[1])
- b = prettyForm(*b.parens())
- c = self._print(e.args[0])
- c = prettyForm(*c.parens())
- pform = a**b
- pform = prettyForm(*pform.right(' '))
- pform = prettyForm(*pform.right(c))
- return pform
- pform = self._print(e.args[0])
- pform = prettyForm(*pform.parens())
- pform = prettyForm(*pform.left(greek_unicode['delta']))
- return pform
- else:
- return self._print_Function(e)
- def _print_expint(self, e):
- if e.args[0].is_Integer and self._use_unicode:
- return self._print_Function(Function('E_%s' % e.args[0])(e.args[1]))
- return self._print_Function(e)
- def _print_Chi(self, e):
- # This needs a special case since otherwise it comes out as greek
- # letter chi...
- prettyFunc = prettyForm("Chi")
- prettyArgs = prettyForm(*self._print_seq(e.args).parens())
- pform = prettyForm(
- binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
- # store pform parts so it can be reassembled e.g. when powered
- pform.prettyFunc = prettyFunc
- pform.prettyArgs = prettyArgs
- return pform
- def _print_elliptic_e(self, e):
- pforma0 = self._print(e.args[0])
- if len(e.args) == 1:
- pform = pforma0
- else:
- pforma1 = self._print(e.args[1])
- pform = self._hprint_vseparator(pforma0, pforma1)
- pform = prettyForm(*pform.parens())
- pform = prettyForm(*pform.left('E'))
- return pform
- def _print_elliptic_k(self, e):
- pform = self._print(e.args[0])
- pform = prettyForm(*pform.parens())
- pform = prettyForm(*pform.left('K'))
- return pform
- def _print_elliptic_f(self, e):
- pforma0 = self._print(e.args[0])
- pforma1 = self._print(e.args[1])
- pform = self._hprint_vseparator(pforma0, pforma1)
- pform = prettyForm(*pform.parens())
- pform = prettyForm(*pform.left('F'))
- return pform
- def _print_elliptic_pi(self, e):
- name = greek_unicode['Pi'] if self._use_unicode else 'Pi'
- pforma0 = self._print(e.args[0])
- pforma1 = self._print(e.args[1])
- if len(e.args) == 2:
- pform = self._hprint_vseparator(pforma0, pforma1)
- else:
- pforma2 = self._print(e.args[2])
- pforma = self._hprint_vseparator(pforma1, pforma2, ifascii_nougly=False)
- pforma = prettyForm(*pforma.left('; '))
- pform = prettyForm(*pforma.left(pforma0))
- pform = prettyForm(*pform.parens())
- pform = prettyForm(*pform.left(name))
- return pform
- def _print_GoldenRatio(self, expr):
- if self._use_unicode:
- return prettyForm(pretty_symbol('phi'))
- return self._print(Symbol("GoldenRatio"))
- def _print_EulerGamma(self, expr):
- if self._use_unicode:
- return prettyForm(pretty_symbol('gamma'))
- return self._print(Symbol("EulerGamma"))
- def _print_Catalan(self, expr):
- return self._print(Symbol("G"))
- def _print_Mod(self, expr):
- pform = self._print(expr.args[0])
- if pform.binding > prettyForm.MUL:
- pform = prettyForm(*pform.parens())
- pform = prettyForm(*pform.right(' mod '))
- pform = prettyForm(*pform.right(self._print(expr.args[1])))
- pform.binding = prettyForm.OPEN
- return pform
- def _print_Add(self, expr, order=None):
- terms = self._as_ordered_terms(expr, order=order)
- pforms, indices = [], []
- def pretty_negative(pform, index):
- """Prepend a minus sign to a pretty form. """
- #TODO: Move this code to prettyForm
- if index == 0:
- if pform.height() > 1:
- pform_neg = '- '
- else:
- pform_neg = '-'
- else:
- pform_neg = ' - '
- if (pform.binding > prettyForm.NEG
- or pform.binding == prettyForm.ADD):
- p = stringPict(*pform.parens())
- else:
- p = pform
- p = stringPict.next(pform_neg, p)
- # Lower the binding to NEG, even if it was higher. Otherwise, it
- # will print as a + ( - (b)), instead of a - (b).
- return prettyForm(binding=prettyForm.NEG, *p)
- for i, term in enumerate(terms):
- if term.is_Mul and term.could_extract_minus_sign():
- coeff, other = term.as_coeff_mul(rational=False)
- if coeff == -1:
- negterm = Mul(*other, evaluate=False)
- else:
- negterm = Mul(-coeff, *other, evaluate=False)
- pform = self._print(negterm)
- pforms.append(pretty_negative(pform, i))
- elif term.is_Rational and term.q > 1:
- pforms.append(None)
- indices.append(i)
- elif term.is_Number and term < 0:
- pform = self._print(-term)
- pforms.append(pretty_negative(pform, i))
- elif term.is_Relational:
- pforms.append(prettyForm(*self._print(term).parens()))
- else:
- pforms.append(self._print(term))
- if indices:
- large = True
- for pform in pforms:
- if pform is not None and pform.height() > 1:
- break
- else:
- large = False
- for i in indices:
- term, negative = terms[i], False
- if term < 0:
- term, negative = -term, True
- if large:
- pform = prettyForm(str(term.p))/prettyForm(str(term.q))
- else:
- pform = self._print(term)
- if negative:
- pform = pretty_negative(pform, i)
- pforms[i] = pform
- return prettyForm.__add__(*pforms)
- def _print_Mul(self, product):
- from sympy.physics.units import Quantity
- # Check for unevaluated Mul. In this case we need to make sure the
- # identities are visible, multiple Rational factors are not combined
- # etc so we display in a straight-forward form that fully preserves all
- # args and their order.
- args = product.args
- if args[0] is S.One or any(isinstance(arg, Number) for arg in args[1:]):
- strargs = list(map(self._print, args))
- # XXX: This is a hack to work around the fact that
- # prettyForm.__mul__ absorbs a leading -1 in the args. Probably it
- # would be better to fix this in prettyForm.__mul__ instead.
- negone = strargs[0] == '-1'
- if negone:
- strargs[0] = prettyForm('1', 0, 0)
- obj = prettyForm.__mul__(*strargs)
- if negone:
- obj = prettyForm('-' + obj.s, obj.baseline, obj.binding)
- return obj
- a = [] # items in the numerator
- b = [] # items that are in the denominator (if any)
- if self.order not in ('old', 'none'):
- args = product.as_ordered_factors()
- else:
- args = list(product.args)
- # If quantities are present append them at the back
- args = sorted(args, key=lambda x: isinstance(x, Quantity) or
- (isinstance(x, Pow) and isinstance(x.base, Quantity)))
- # Gather terms for numerator/denominator
- for item in args:
- if item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative:
- if item.exp != -1:
- b.append(Pow(item.base, -item.exp, evaluate=False))
- else:
- b.append(Pow(item.base, -item.exp))
- elif item.is_Rational and item is not S.Infinity:
- if item.p != 1:
- a.append( Rational(item.p) )
- if item.q != 1:
- b.append( Rational(item.q) )
- else:
- a.append(item)
- # Convert to pretty forms. Parentheses are added by `__mul__`.
- a = [self._print(ai) for ai in a]
- b = [self._print(bi) for bi in b]
- # Construct a pretty form
- if len(b) == 0:
- return prettyForm.__mul__(*a)
- else:
- if len(a) == 0:
- a.append( self._print(S.One) )
- return prettyForm.__mul__(*a)/prettyForm.__mul__(*b)
- # A helper function for _print_Pow to print x**(1/n)
- def _print_nth_root(self, base, root):
- bpretty = self._print(base)
- # In very simple cases, use a single-char root sign
- if (self._settings['use_unicode_sqrt_char'] and self._use_unicode
- and root == 2 and bpretty.height() == 1
- and (bpretty.width() == 1
- or (base.is_Integer and base.is_nonnegative))):
- return prettyForm(*bpretty.left('\N{SQUARE ROOT}'))
- # Construct root sign, start with the \/ shape
- _zZ = xobj('/', 1)
- rootsign = xobj('\\', 1) + _zZ
- # Constructing the number to put on root
- rpretty = self._print(root)
- # roots look bad if they are not a single line
- if rpretty.height() != 1:
- return self._print(base)**self._print(1/root)
- # If power is half, no number should appear on top of root sign
- exp = '' if root == 2 else str(rpretty).ljust(2)
- if len(exp) > 2:
- rootsign = ' '*(len(exp) - 2) + rootsign
- # Stack the exponent
- rootsign = stringPict(exp + '\n' + rootsign)
- rootsign.baseline = 0
- # Diagonal: length is one less than height of base
- linelength = bpretty.height() - 1
- diagonal = stringPict('\n'.join(
- ' '*(linelength - i - 1) + _zZ + ' '*i
- for i in range(linelength)
- ))
- # Put baseline just below lowest line: next to exp
- diagonal.baseline = linelength - 1
- # Make the root symbol
- rootsign = prettyForm(*rootsign.right(diagonal))
- # Det the baseline to match contents to fix the height
- # but if the height of bpretty is one, the rootsign must be one higher
- rootsign.baseline = max(1, bpretty.baseline)
- #build result
- s = prettyForm(hobj('_', 2 + bpretty.width()))
- s = prettyForm(*bpretty.above(s))
- s = prettyForm(*s.left(rootsign))
- return s
- def _print_Pow(self, power):
- from sympy.simplify.simplify import fraction
- b, e = power.as_base_exp()
- if power.is_commutative:
- if e is S.NegativeOne:
- return prettyForm("1")/self._print(b)
- n, d = fraction(e)
- if n is S.One and d.is_Atom and not e.is_Integer and (e.is_Rational or d.is_Symbol) \
- and self._settings['root_notation']:
- return self._print_nth_root(b, d)
- if e.is_Rational and e < 0:
- return prettyForm("1")/self._print(Pow(b, -e, evaluate=False))
- if b.is_Relational:
- return prettyForm(*self._print(b).parens()).__pow__(self._print(e))
- return self._print(b)**self._print(e)
- def _print_UnevaluatedExpr(self, expr):
- return self._print(expr.args[0])
- def __print_numer_denom(self, p, q):
- if q == 1:
- if p < 0:
- return prettyForm(str(p), binding=prettyForm.NEG)
- else:
- return prettyForm(str(p))
- elif abs(p) >= 10 and abs(q) >= 10:
- # If more than one digit in numer and denom, print larger fraction
- if p < 0:
- return prettyForm(str(p), binding=prettyForm.NEG)/prettyForm(str(q))
- # Old printing method:
- #pform = prettyForm(str(-p))/prettyForm(str(q))
- #return prettyForm(binding=prettyForm.NEG, *pform.left('- '))
- else:
- return prettyForm(str(p))/prettyForm(str(q))
- else:
- return None
- def _print_Rational(self, expr):
- result = self.__print_numer_denom(expr.p, expr.q)
- if result is not None:
- return result
- else:
- return self.emptyPrinter(expr)
- def _print_Fraction(self, expr):
- result = self.__print_numer_denom(expr.numerator, expr.denominator)
- if result is not None:
- return result
- else:
- return self.emptyPrinter(expr)
- def _print_ProductSet(self, p):
- if len(p.sets) >= 1 and not has_variety(p.sets):
- return self._print(p.sets[0]) ** self._print(len(p.sets))
- else:
- prod_char = "\N{MULTIPLICATION SIGN}" if self._use_unicode else 'x'
- return self._print_seq(p.sets, None, None, ' %s ' % prod_char,
- parenthesize=lambda set: set.is_Union or
- set.is_Intersection or set.is_ProductSet)
- def _print_FiniteSet(self, s):
- items = sorted(s.args, key=default_sort_key)
- return self._print_seq(items, '{', '}', ', ' )
- def _print_Range(self, s):
- if self._use_unicode:
- dots = "\N{HORIZONTAL ELLIPSIS}"
- else:
- dots = '...'
- if s.start.is_infinite and s.stop.is_infinite:
- if s.step.is_positive:
- printset = dots, -1, 0, 1, dots
- else:
- printset = dots, 1, 0, -1, dots
- elif s.start.is_infinite:
- printset = dots, s[-1] - s.step, s[-1]
- elif s.stop.is_infinite:
- it = iter(s)
- printset = next(it), next(it), dots
- elif len(s) > 4:
- it = iter(s)
- printset = next(it), next(it), dots, s[-1]
- else:
- printset = tuple(s)
- return self._print_seq(printset, '{', '}', ', ' )
- def _print_Interval(self, i):
- if i.start == i.end:
- return self._print_seq(i.args[:1], '{', '}')
- else:
- if i.left_open:
- left = '('
- else:
- left = '['
- if i.right_open:
- right = ')'
- else:
- right = ']'
- return self._print_seq(i.args[:2], left, right)
- def _print_AccumulationBounds(self, i):
- left = '<'
- right = '>'
- return self._print_seq(i.args[:2], left, right)
- def _print_Intersection(self, u):
- delimiter = ' %s ' % pretty_atom('Intersection', 'n')
- return self._print_seq(u.args, None, None, delimiter,
- parenthesize=lambda set: set.is_ProductSet or
- set.is_Union or set.is_Complement)
- def _print_Union(self, u):
- union_delimiter = ' %s ' % pretty_atom('Union', 'U')
- return self._print_seq(u.args, None, None, union_delimiter,
- parenthesize=lambda set: set.is_ProductSet or
- set.is_Intersection or set.is_Complement)
- def _print_SymmetricDifference(self, u):
- if not self._use_unicode:
- raise NotImplementedError("ASCII pretty printing of SymmetricDifference is not implemented")
- sym_delimeter = ' %s ' % pretty_atom('SymmetricDifference')
- return self._print_seq(u.args, None, None, sym_delimeter)
- def _print_Complement(self, u):
- delimiter = r' \ '
- return self._print_seq(u.args, None, None, delimiter,
- parenthesize=lambda set: set.is_ProductSet or set.is_Intersection
- or set.is_Union)
- def _print_ImageSet(self, ts):
- if self._use_unicode:
- inn = "\N{SMALL ELEMENT OF}"
- else:
- inn = 'in'
- fun = ts.lamda
- sets = ts.base_sets
- signature = fun.signature
- expr = self._print(fun.expr)
- # TODO: the stuff to the left of the | and the stuff to the right of
- # the | should have independent baselines, that way something like
- # ImageSet(Lambda(x, 1/x**2), S.Naturals) prints the "x in N" part
- # centered on the right instead of aligned with the fraction bar on
- # the left. The same also applies to ConditionSet and ComplexRegion
- if len(signature) == 1:
- S = self._print_seq((signature[0], inn, sets[0]),
- delimiter=' ')
- return self._hprint_vseparator(expr, S,
- left='{', right='}',
- ifascii_nougly=True, delimiter=' ')
- else:
- pargs = tuple(j for var, setv in zip(signature, sets) for j in
- (var, ' ', inn, ' ', setv, ", "))
- S = self._print_seq(pargs[:-1], delimiter='')
- return self._hprint_vseparator(expr, S,
- left='{', right='}',
- ifascii_nougly=True, delimiter=' ')
- def _print_ConditionSet(self, ts):
- if self._use_unicode:
- inn = "\N{SMALL ELEMENT OF}"
- # using _and because and is a keyword and it is bad practice to
- # overwrite them
- _and = "\N{LOGICAL AND}"
- else:
- inn = 'in'
- _and = 'and'
- variables = self._print_seq(Tuple(ts.sym))
- as_expr = getattr(ts.condition, 'as_expr', None)
- if as_expr is not None:
- cond = self._print(ts.condition.as_expr())
- else:
- cond = self._print(ts.condition)
- if self._use_unicode:
- cond = self._print(cond)
- cond = prettyForm(*cond.parens())
- if ts.base_set is S.UniversalSet:
- return self._hprint_vseparator(variables, cond, left="{",
- right="}", ifascii_nougly=True,
- delimiter=' ')
- base = self._print(ts.base_set)
- C = self._print_seq((variables, inn, base, _and, cond),
- delimiter=' ')
- return self._hprint_vseparator(variables, C, left="{", right="}",
- ifascii_nougly=True, delimiter=' ')
- def _print_ComplexRegion(self, ts):
- if self._use_unicode:
- inn = "\N{SMALL ELEMENT OF}"
- else:
- inn = 'in'
- variables = self._print_seq(ts.variables)
- expr = self._print(ts.expr)
- prodsets = self._print(ts.sets)
- C = self._print_seq((variables, inn, prodsets),
- delimiter=' ')
- return self._hprint_vseparator(expr, C, left="{", right="}",
- ifascii_nougly=True, delimiter=' ')
- def _print_Contains(self, e):
- var, set = e.args
- if self._use_unicode:
- el = " \N{ELEMENT OF} "
- return prettyForm(*stringPict.next(self._print(var),
- el, self._print(set)), binding=8)
- else:
- return prettyForm(sstr(e))
- def _print_FourierSeries(self, s):
- if s.an.formula is S.Zero and s.bn.formula is S.Zero:
- return self._print(s.a0)
- if self._use_unicode:
- dots = "\N{HORIZONTAL ELLIPSIS}"
- else:
- dots = '...'
- return self._print_Add(s.truncate()) + self._print(dots)
- def _print_FormalPowerSeries(self, s):
- return self._print_Add(s.infinite)
- def _print_SetExpr(self, se):
- pretty_set = prettyForm(*self._print(se.set).parens())
- pretty_name = self._print(Symbol("SetExpr"))
- return prettyForm(*pretty_name.right(pretty_set))
- def _print_SeqFormula(self, s):
- if self._use_unicode:
- dots = "\N{HORIZONTAL ELLIPSIS}"
- else:
- dots = '...'
- if len(s.start.free_symbols) > 0 or len(s.stop.free_symbols) > 0:
- raise NotImplementedError("Pretty printing of sequences with symbolic bound not implemented")
- if s.start is S.NegativeInfinity:
- stop = s.stop
- printset = (dots, s.coeff(stop - 3), s.coeff(stop - 2),
- s.coeff(stop - 1), s.coeff(stop))
- elif s.stop is S.Infinity or s.length > 4:
- printset = s[:4]
- printset.append(dots)
- printset = tuple(printset)
- else:
- printset = tuple(s)
- return self._print_list(printset)
- _print_SeqPer = _print_SeqFormula
- _print_SeqAdd = _print_SeqFormula
- _print_SeqMul = _print_SeqFormula
- def _print_seq(self, seq, left=None, right=None, delimiter=', ',
- parenthesize=lambda x: False, ifascii_nougly=True):
- try:
- pforms = []
- for item in seq:
- pform = self._print(item)
- if parenthesize(item):
- pform = prettyForm(*pform.parens())
- if pforms:
- pforms.append(delimiter)
- pforms.append(pform)
- if not pforms:
- s = stringPict('')
- else:
- s = prettyForm(*stringPict.next(*pforms))
- # XXX: Under the tests from #15686 the above raises:
- # AttributeError: 'Fake' object has no attribute 'baseline'
- # This is caught below but that is not the right way to
- # fix it.
- except AttributeError:
- s = None
- for item in seq:
- pform = self.doprint(item)
- if parenthesize(item):
- pform = prettyForm(*pform.parens())
- if s is None:
- # first element
- s = pform
- else :
- s = prettyForm(*stringPict.next(s, delimiter))
- s = prettyForm(*stringPict.next(s, pform))
- if s is None:
- s = stringPict('')
- s = prettyForm(*s.parens(left, right, ifascii_nougly=ifascii_nougly))
- return s
- def join(self, delimiter, args):
- pform = None
- for arg in args:
- if pform is None:
- pform = arg
- else:
- pform = prettyForm(*pform.right(delimiter))
- pform = prettyForm(*pform.right(arg))
- if pform is None:
- return prettyForm("")
- else:
- return pform
- def _print_list(self, l):
- return self._print_seq(l, '[', ']')
- def _print_tuple(self, t):
- if len(t) == 1:
- ptuple = prettyForm(*stringPict.next(self._print(t[0]), ','))
- return prettyForm(*ptuple.parens('(', ')', ifascii_nougly=True))
- else:
- return self._print_seq(t, '(', ')')
- def _print_Tuple(self, expr):
- return self._print_tuple(expr)
- def _print_dict(self, d):
- keys = sorted(d.keys(), key=default_sort_key)
- items = []
- for k in keys:
- K = self._print(k)
- V = self._print(d[k])
- s = prettyForm(*stringPict.next(K, ': ', V))
- items.append(s)
- return self._print_seq(items, '{', '}')
- def _print_Dict(self, d):
- return self._print_dict(d)
- def _print_set(self, s):
- if not s:
- return prettyForm('set()')
- items = sorted(s, key=default_sort_key)
- pretty = self._print_seq(items)
- pretty = prettyForm(*pretty.parens('{', '}', ifascii_nougly=True))
- return pretty
- def _print_frozenset(self, s):
- if not s:
- return prettyForm('frozenset()')
- items = sorted(s, key=default_sort_key)
- pretty = self._print_seq(items)
- pretty = prettyForm(*pretty.parens('{', '}', ifascii_nougly=True))
- pretty = prettyForm(*pretty.parens('(', ')', ifascii_nougly=True))
- pretty = prettyForm(*stringPict.next(type(s).__name__, pretty))
- return pretty
- def _print_UniversalSet(self, s):
- if self._use_unicode:
- return prettyForm("\N{MATHEMATICAL DOUBLE-STRUCK CAPITAL U}")
- else:
- return prettyForm('UniversalSet')
- def _print_PolyRing(self, ring):
- return prettyForm(sstr(ring))
- def _print_FracField(self, field):
- return prettyForm(sstr(field))
- def _print_FreeGroupElement(self, elm):
- return prettyForm(str(elm))
- def _print_PolyElement(self, poly):
- return prettyForm(sstr(poly))
- def _print_FracElement(self, frac):
- return prettyForm(sstr(frac))
- def _print_AlgebraicNumber(self, expr):
- if expr.is_aliased:
- return self._print(expr.as_poly().as_expr())
- else:
- return self._print(expr.as_expr())
- def _print_ComplexRootOf(self, expr):
- args = [self._print_Add(expr.expr, order='lex'), expr.index]
- pform = prettyForm(*self._print_seq(args).parens())
- pform = prettyForm(*pform.left('CRootOf'))
- return pform
- def _print_RootSum(self, expr):
- args = [self._print_Add(expr.expr, order='lex')]
- if expr.fun is not S.IdentityFunction:
- args.append(self._print(expr.fun))
- pform = prettyForm(*self._print_seq(args).parens())
- pform = prettyForm(*pform.left('RootSum'))
- return pform
- def _print_FiniteField(self, expr):
- if self._use_unicode:
- form = '\N{DOUBLE-STRUCK CAPITAL Z}_%d'
- else:
- form = 'GF(%d)'
- return prettyForm(pretty_symbol(form % expr.mod))
- def _print_IntegerRing(self, expr):
- if self._use_unicode:
- return prettyForm('\N{DOUBLE-STRUCK CAPITAL Z}')
- else:
- return prettyForm('ZZ')
- def _print_RationalField(self, expr):
- if self._use_unicode:
- return prettyForm('\N{DOUBLE-STRUCK CAPITAL Q}')
- else:
- return prettyForm('QQ')
- def _print_RealField(self, domain):
- if self._use_unicode:
- prefix = '\N{DOUBLE-STRUCK CAPITAL R}'
- else:
- prefix = 'RR'
- if domain.has_default_precision:
- return prettyForm(prefix)
- else:
- return self._print(pretty_symbol(prefix + "_" + str(domain.precision)))
- def _print_ComplexField(self, domain):
- if self._use_unicode:
- prefix = '\N{DOUBLE-STRUCK CAPITAL C}'
- else:
- prefix = 'CC'
- if domain.has_default_precision:
- return prettyForm(prefix)
- else:
- return self._print(pretty_symbol(prefix + "_" + str(domain.precision)))
- def _print_PolynomialRing(self, expr):
- args = list(expr.symbols)
- if not expr.order.is_default:
- order = prettyForm(*prettyForm("order=").right(self._print(expr.order)))
- args.append(order)
- pform = self._print_seq(args, '[', ']')
- pform = prettyForm(*pform.left(self._print(expr.domain)))
- return pform
- def _print_FractionField(self, expr):
- args = list(expr.symbols)
- if not expr.order.is_default:
- order = prettyForm(*prettyForm("order=").right(self._print(expr.order)))
- args.append(order)
- pform = self._print_seq(args, '(', ')')
- pform = prettyForm(*pform.left(self._print(expr.domain)))
- return pform
- def _print_PolynomialRingBase(self, expr):
- g = expr.symbols
- if str(expr.order) != str(expr.default_order):
- g = g + ("order=" + str(expr.order),)
- pform = self._print_seq(g, '[', ']')
- pform = prettyForm(*pform.left(self._print(expr.domain)))
- return pform
- def _print_GroebnerBasis(self, basis):
- exprs = [ self._print_Add(arg, order=basis.order)
- for arg in basis.exprs ]
- exprs = prettyForm(*self.join(", ", exprs).parens(left="[", right="]"))
- gens = [ self._print(gen) for gen in basis.gens ]
- domain = prettyForm(
- *prettyForm("domain=").right(self._print(basis.domain)))
- order = prettyForm(
- *prettyForm("order=").right(self._print(basis.order)))
- pform = self.join(", ", [exprs] + gens + [domain, order])
- pform = prettyForm(*pform.parens())
- pform = prettyForm(*pform.left(basis.__class__.__name__))
- return pform
- def _print_Subs(self, e):
- pform = self._print(e.expr)
- pform = prettyForm(*pform.parens())
- h = pform.height() if pform.height() > 1 else 2
- rvert = stringPict(vobj('|', h), baseline=pform.baseline)
- pform = prettyForm(*pform.right(rvert))
- b = pform.baseline
- pform.baseline = pform.height() - 1
- pform = prettyForm(*pform.right(self._print_seq([
- self._print_seq((self._print(v[0]), xsym('=='), self._print(v[1])),
- delimiter='') for v in zip(e.variables, e.point) ])))
- pform.baseline = b
- return pform
- def _print_number_function(self, e, name):
- # Print name_arg[0] for one argument or name_arg[0](arg[1])
- # for more than one argument
- pform = prettyForm(name)
- arg = self._print(e.args[0])
- pform_arg = prettyForm(" "*arg.width())
- pform_arg = prettyForm(*pform_arg.below(arg))
- pform = prettyForm(*pform.right(pform_arg))
- if len(e.args) == 1:
- return pform
- m, x = e.args
- # TODO: copy-pasted from _print_Function: can we do better?
- prettyFunc = pform
- prettyArgs = prettyForm(*self._print_seq([x]).parens())
- pform = prettyForm(
- binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
- pform.prettyFunc = prettyFunc
- pform.prettyArgs = prettyArgs
- return pform
- def _print_euler(self, e):
- return self._print_number_function(e, "E")
- def _print_catalan(self, e):
- return self._print_number_function(e, "C")
- def _print_bernoulli(self, e):
- return self._print_number_function(e, "B")
- _print_bell = _print_bernoulli
- def _print_lucas(self, e):
- return self._print_number_function(e, "L")
- def _print_fibonacci(self, e):
- return self._print_number_function(e, "F")
- def _print_tribonacci(self, e):
- return self._print_number_function(e, "T")
- def _print_stieltjes(self, e):
- if self._use_unicode:
- return self._print_number_function(e, '\N{GREEK SMALL LETTER GAMMA}')
- else:
- return self._print_number_function(e, "stieltjes")
- def _print_KroneckerDelta(self, e):
- pform = self._print(e.args[0])
- pform = prettyForm(*pform.right(prettyForm(',')))
- pform = prettyForm(*pform.right(self._print(e.args[1])))
- if self._use_unicode:
- a = stringPict(pretty_symbol('delta'))
- else:
- a = stringPict('d')
- b = pform
- top = stringPict(*b.left(' '*a.width()))
- bot = stringPict(*a.right(' '*b.width()))
- return prettyForm(binding=prettyForm.POW, *bot.below(top))
- def _print_RandomDomain(self, d):
- if hasattr(d, 'as_boolean'):
- pform = self._print('Domain: ')
- pform = prettyForm(*pform.right(self._print(d.as_boolean())))
- return pform
- elif hasattr(d, 'set'):
- pform = self._print('Domain: ')
- pform = prettyForm(*pform.right(self._print(d.symbols)))
- pform = prettyForm(*pform.right(self._print(' in ')))
- pform = prettyForm(*pform.right(self._print(d.set)))
- return pform
- elif hasattr(d, 'symbols'):
- pform = self._print('Domain on ')
- pform = prettyForm(*pform.right(self._print(d.symbols)))
- return pform
- else:
- return self._print(None)
- def _print_DMP(self, p):
- try:
- if p.ring is not None:
- # TODO incorporate order
- return self._print(p.ring.to_sympy(p))
- except SympifyError:
- pass
- return self._print(repr(p))
- def _print_DMF(self, p):
- return self._print_DMP(p)
- def _print_Object(self, object):
- return self._print(pretty_symbol(object.name))
- def _print_Morphism(self, morphism):
- arrow = xsym("-->")
- domain = self._print(morphism.domain)
- codomain = self._print(morphism.codomain)
- tail = domain.right(arrow, codomain)[0]
- return prettyForm(tail)
- def _print_NamedMorphism(self, morphism):
- pretty_name = self._print(pretty_symbol(morphism.name))
- pretty_morphism = self._print_Morphism(morphism)
- return prettyForm(pretty_name.right(":", pretty_morphism)[0])
- def _print_IdentityMorphism(self, morphism):
- from sympy.categories import NamedMorphism
- return self._print_NamedMorphism(
- NamedMorphism(morphism.domain, morphism.codomain, "id"))
- def _print_CompositeMorphism(self, morphism):
- circle = xsym(".")
- # All components of the morphism have names and it is thus
- # possible to build the name of the composite.
- component_names_list = [pretty_symbol(component.name) for
- component in morphism.components]
- component_names_list.reverse()
- component_names = circle.join(component_names_list) + ":"
- pretty_name = self._print(component_names)
- pretty_morphism = self._print_Morphism(morphism)
- return prettyForm(pretty_name.right(pretty_morphism)[0])
- def _print_Category(self, category):
- return self._print(pretty_symbol(category.name))
- def _print_Diagram(self, diagram):
- if not diagram.premises:
- # This is an empty diagram.
- return self._print(S.EmptySet)
- pretty_result = self._print(diagram.premises)
- if diagram.conclusions:
- results_arrow = " %s " % xsym("==>")
- pretty_conclusions = self._print(diagram.conclusions)[0]
- pretty_result = pretty_result.right(
- results_arrow, pretty_conclusions)
- return prettyForm(pretty_result[0])
- def _print_DiagramGrid(self, grid):
- from sympy.matrices import Matrix
- matrix = Matrix([[grid[i, j] if grid[i, j] else Symbol(" ")
- for j in range(grid.width)]
- for i in range(grid.height)])
- return self._print_matrix_contents(matrix)
- def _print_FreeModuleElement(self, m):
- # Print as row vector for convenience, for now.
- return self._print_seq(m, '[', ']')
- def _print_SubModule(self, M):
- return self._print_seq(M.gens, '<', '>')
- def _print_FreeModule(self, M):
- return self._print(M.ring)**self._print(M.rank)
- def _print_ModuleImplementedIdeal(self, M):
- return self._print_seq([x for [x] in M._module.gens], '<', '>')
- def _print_QuotientRing(self, R):
- return self._print(R.ring) / self._print(R.base_ideal)
- def _print_QuotientRingElement(self, R):
- return self._print(R.data) + self._print(R.ring.base_ideal)
- def _print_QuotientModuleElement(self, m):
- return self._print(m.data) + self._print(m.module.killed_module)
- def _print_QuotientModule(self, M):
- return self._print(M.base) / self._print(M.killed_module)
- def _print_MatrixHomomorphism(self, h):
- matrix = self._print(h._sympy_matrix())
- matrix.baseline = matrix.height() // 2
- pform = prettyForm(*matrix.right(' : ', self._print(h.domain),
- ' %s> ' % hobj('-', 2), self._print(h.codomain)))
- return pform
- def _print_Manifold(self, manifold):
- return self._print(manifold.name)
- def _print_Patch(self, patch):
- return self._print(patch.name)
- def _print_CoordSystem(self, coords):
- return self._print(coords.name)
- def _print_BaseScalarField(self, field):
- string = field._coord_sys.symbols[field._index].name
- return self._print(pretty_symbol(string))
- def _print_BaseVectorField(self, field):
- s = U('PARTIAL DIFFERENTIAL') + '_' + field._coord_sys.symbols[field._index].name
- return self._print(pretty_symbol(s))
- def _print_Differential(self, diff):
- if self._use_unicode:
- d = '\N{DOUBLE-STRUCK ITALIC SMALL D}'
- else:
- d = 'd'
- field = diff._form_field
- if hasattr(field, '_coord_sys'):
- string = field._coord_sys.symbols[field._index].name
- return self._print(d + ' ' + pretty_symbol(string))
- else:
- pform = self._print(field)
- pform = prettyForm(*pform.parens())
- return prettyForm(*pform.left(d))
- def _print_Tr(self, p):
- #TODO: Handle indices
- pform = self._print(p.args[0])
- pform = prettyForm(*pform.left('%s(' % (p.__class__.__name__)))
- pform = prettyForm(*pform.right(')'))
- return pform
- def _print_primenu(self, e):
- pform = self._print(e.args[0])
- pform = prettyForm(*pform.parens())
- if self._use_unicode:
- pform = prettyForm(*pform.left(greek_unicode['nu']))
- else:
- pform = prettyForm(*pform.left('nu'))
- return pform
- def _print_primeomega(self, e):
- pform = self._print(e.args[0])
- pform = prettyForm(*pform.parens())
- if self._use_unicode:
- pform = prettyForm(*pform.left(greek_unicode['Omega']))
- else:
- pform = prettyForm(*pform.left('Omega'))
- return pform
- def _print_Quantity(self, e):
- if e.name.name == 'degree':
- pform = self._print("\N{DEGREE SIGN}")
- return pform
- else:
- return self.emptyPrinter(e)
- def _print_AssignmentBase(self, e):
- op = prettyForm(' ' + xsym(e.op) + ' ')
- l = self._print(e.lhs)
- r = self._print(e.rhs)
- pform = prettyForm(*stringPict.next(l, op, r))
- return pform
- def _print_Str(self, s):
- return self._print(s.name)
- @print_function(PrettyPrinter)
- def pretty(expr, **settings):
- """Returns a string containing the prettified form of expr.
- For information on keyword arguments see pretty_print function.
- """
- pp = PrettyPrinter(settings)
- # XXX: this is an ugly hack, but at least it works
- use_unicode = pp._settings['use_unicode']
- uflag = pretty_use_unicode(use_unicode)
- try:
- return pp.doprint(expr)
- finally:
- pretty_use_unicode(uflag)
- def pretty_print(expr, **kwargs):
- """Prints expr in pretty form.
- pprint is just a shortcut for this function.
- Parameters
- ==========
- expr : expression
- The expression to print.
- wrap_line : bool, optional (default=True)
- Line wrapping enabled/disabled.
- num_columns : int or None, optional (default=None)
- Number of columns before line breaking (default to None which reads
- the terminal width), useful when using SymPy without terminal.
- use_unicode : bool or None, optional (default=None)
- Use unicode characters, such as the Greek letter pi instead of
- the string pi.
- full_prec : bool or string, optional (default="auto")
- Use full precision.
- order : bool or string, optional (default=None)
- Set to 'none' for long expressions if slow; default is None.
- use_unicode_sqrt_char : bool, optional (default=True)
- Use compact single-character square root symbol (when unambiguous).
- root_notation : bool, optional (default=True)
- Set to 'False' for printing exponents of the form 1/n in fractional form.
- By default exponent is printed in root form.
- mat_symbol_style : string, optional (default="plain")
- Set to "bold" for printing MatrixSymbols using a bold mathematical symbol face.
- By default the standard face is used.
- imaginary_unit : string, optional (default="i")
- Letter to use for imaginary unit when use_unicode is True.
- Can be "i" (default) or "j".
- """
- print(pretty(expr, **kwargs))
- pprint = pretty_print
- def pager_print(expr, **settings):
- """Prints expr using the pager, in pretty form.
- This invokes a pager command using pydoc. Lines are not wrapped
- automatically. This routine is meant to be used with a pager that allows
- sideways scrolling, like ``less -S``.
- Parameters are the same as for ``pretty_print``. If you wish to wrap lines,
- pass ``num_columns=None`` to auto-detect the width of the terminal.
- """
- from pydoc import pager
- from locale import getpreferredencoding
- if 'num_columns' not in settings:
- settings['num_columns'] = 500000 # disable line wrap
- pager(pretty(expr, **settings).encode(getpreferredencoding()))
|