Source code for sympy.printing.pretty.pretty

from __future__ import print_function, division

from sympy.core import S
from sympy.core.containers import Tuple
from sympy.core.function import _coeff_isneg
from sympy.core.mul import Mul
from sympy.core.numbers import Rational
from sympy.core.power import Pow
from sympy.core.relational import Equality
from sympy.core.symbol import Symbol
from sympy.printing.precedence import PRECEDENCE, precedence
from sympy.utilities import group
from sympy.utilities.iterables import has_variety
from sympy.core.sympify import SympifyError
from sympy.core.compatibility import u, range
from sympy.core.add import Add

from sympy.printing.printer import Printer
from sympy.printing.str import sstr
from sympy.printing.conventions import requires_partial

from .stringpict import prettyForm, stringPict
from .pretty_symbology import xstr, hobj, vobj, xobj, xsym, pretty_symbol, \
    pretty_atom, pretty_use_unicode, pretty_try_use_unicode, greek_unicode, U, \
    annotated

from sympy.utilities import default_sort_key

# rename for usage from outside
pprint_use_unicode = pretty_use_unicode
pprint_try_use_unicode = pretty_try_use_unicode


[docs]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, } def __init__(self, settings=None): Printer.__init__(self, settings) self.emptyPrinter = lambda x: prettyForm(xstr(x)) @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): symb = pretty_symbol(e.name) return prettyForm(symb) _print_RandomSymbol = _print_Symbol 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_Atom(self, e): try: # print atoms like Exp1 or Pi return prettyForm(pretty_atom(e.__class__.__name__)) 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_Reals = _print_Atom _print_Complexes = _print_Atom 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)) return pform def _print_Not(self, e): from sympy 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=u("\N{NOT IDENTICAL TO}")) if isinstance(arg, Implies): return self._print_Implies(arg, altchar=u("\N{RIGHTWARDS ARROW WITH STROKE}")) if arg.is_Boolean and not arg.is_Not: pform = prettyForm(*pform.parens()) return prettyForm(*pform.left(u("\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(u(' %s ') % char)) pform = prettyForm(*pform.right(pform_arg)) return pform def _print_And(self, e): if self._use_unicode: return self.__print_Boolean(e, u("\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, u("\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, u("\N{XOR}")) else: return self._print_Function(e, sort=True) def _print_Nand(self, e): if self._use_unicode: return self.__print_Boolean(e, u("\N{NAND}")) else: return self._print_Function(e, sort=True) def _print_Nor(self, e): if self._use_unicode: return self.__print_Boolean(e, u("\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 u("\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 u("\N{IDENTICAL TO}")) 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 _print_Determinant = _print_Abs 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) and self._use_unicode: deriv_symbol = U('PARTIAL DIFFERENTIAL') else: deriv_symbol = r'd' syms = list(reversed(deriv.variables)) x = None for sym, num in group(syms, multiple=False): s = self._print(sym) ds = prettyForm(*s.left(deriv_symbol)) if 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 len(syms) > 1: pform = pform**prettyForm(str(len(syms))) 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_PDF(self, pdf): lim = self._print(pdf.pdf.args[0]) lim = prettyForm(*lim.right(', ')) lim = prettyForm(*lim.right(self._print(pdf.domain[0]))) lim = prettyForm(*lim.right(', ')) lim = prettyForm(*lim.right(self._print(pdf.domain[1]))) lim = prettyForm(*lim.parens()) f = self._print(pdf.pdf.args[1]) f = prettyForm(*f.right(', ')) f = prettyForm(*f.right(lim)) f = prettyForm(*f.parens()) pform = prettyForm('PDF') pform = prettyForm(*pform.right(f)) return pform 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: x = lim[0] # 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 = u('\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: width = (func_height + 2) * 5 // 3 - 2 sign_lines = [] sign_lines.append(corner_chr + (horizontal_chr*width) + corner_chr) for i in range(func_height + 1): sign_lines.append(vertical_chr + (' '*width) + vertical_chr) pretty_sign = stringPict('') pretty_sign = prettyForm(*pretty_sign.stack(*sign_lines)) pretty_upper = self._print(lim[2]) pretty_lower = self._print(Equality(lim[0], lim[1])) 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_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 == '<^>' or how == "<" 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("\%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, 0 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: if len(lim) == 3: prettyUpper = self._print(lim[2]) prettyLower = self._print(Equality(lim[0], lim[1])) elif len(lim) == 2: prettyUpper = self._print("") prettyLower = self._print(Equality(lim[0], lim[1])) elif len(lim) == 1: prettyUpper = self._print("") prettyLower = self._print(lim[0]) 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) - adjustment 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)) prettyF.baseline = max_upper + sign_height//2 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(u('\N{BOX DRAWINGS LIGHT HORIZONTAL}\N{RIGHTWARDS ARROW}'))) else: LimArg = prettyForm(*LimArg.right('->')) LimArg = prettyForm(*LimArg.right(self._print(z0))) if z0 in (S.Infinity, S.NegativeInfinity): dir = "" else: if self._use_unicode: dir = u('\N{SUPERSCRIPT PLUS SIGN}') if str(dir) == "+" else u('\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): D = self._print_matrix_contents(e) D = prettyForm(*D.parens('[', ']')) return D _print_ImmutableMatrix = _print_MatrixBase _print_Matrix = _print_MatrixBase 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 from sympy import Symbol 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) 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 prettyFunc = self._print(m.parent) def ppslice(x): x = list(x) if x[2] == 1: del x[2] if x[1] == x[0] + 1: del x[1] if x[0] == 0: x[0] = '' return prettyForm(*self._print_seq(x, delimiter=':')) prettyArgs = self._print_seq((ppslice(m.rowslice), ppslice(m.colslice)), 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): pform = self._print(expr.arg) from sympy.matrices import MatrixSymbol if not isinstance(expr.arg, MatrixSymbol): pform = prettyForm(*pform.parens()) pform = pform**(prettyForm('T')) return pform def _print_Adjoint(self, expr): pform = self._print(expr.arg) if self._use_unicode: dag = prettyForm(u('\N{DAGGER}')) else: dag = prettyForm('+') from sympy.matrices import MatrixSymbol if not isinstance(expr.arg, MatrixSymbol): 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): return self._print_seq(expr.args, None, None, ' + ') def _print_MatMul(self, expr): args = list(expr.args) from sympy import Add, MatAdd, HadamardProduct for i, a in enumerate(args): if (isinstance(a, (Add, MatAdd, HadamardProduct)) and len(expr.args) > 1): args[i] = prettyForm(*self._print(a).parens()) else: args[i] = self._print(a) return prettyForm.__mul__(*args) 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): pform = prettyForm(*pform.parens()) pform = pform**(self._print(expr.exp)) return pform def _print_HadamardProduct(self, expr): from sympy import MatAdd, 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))) _print_MatrixSymbol = _print_Symbol def _print_FunctionMatrix(self, X): D = self._print(X.lamda.expr) D = prettyForm(*D.parens('[', ']')) return D 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(u("") + k._pretty_form) #Same for -1 elif v == -1: o1.append(u("(-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(u(" + ")): o1[0] = o1[0][3:] elif o1[0].startswith(" "): o1[0] = o1[0][1:] #Fixing the newlines lengths = [] strs = [''] for i, partstr in enumerate(o1): # XXX: What is this hack? if '\n' in partstr: tempstr = partstr tempstr = tempstr.replace(vectstrs[i], '') tempstr = tempstr.replace(u('\N{RIGHT PARENTHESIS UPPER HOOK}'), u('\N{RIGHT PARENTHESIS UPPER HOOK}') + ' ' + vectstrs[i]) o1[i] = tempstr o1 = [x.split('\n') for x in o1] n_newlines = max([len(x) for x in o1]) for parts in o1: lengths.append(len(parts[0])) 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 == 0: strs[0] += parts[0] + ' + ' 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(u('\n').join([s[:-3] for s in strs])) 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 _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): tmp = prettyForm(*p1.right(p2)) sep = stringPict(vobj('|', tmp.height()), baseline=tmp.baseline) return prettyForm(*p1.right(sep, p2)) 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_Function(self, e, sort=False): # XXX works only for applied functions func = e.func args = e.args if sort: args = sorted(args, key=default_sort_key) func_name = func.__name__ prettyFunc = self._print(Symbol(func_name)) prettyArgs = prettyForm(*self._print_seq(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_GeometryEntity(self, expr): # GeometryEntity is based on Tuple but should not print like a Tuple return self.emptyPrinter(expr) def _print_Lambda(self, e): vars, expr = e.args if self._use_unicode: arrow = u(" \N{RIGHTWARDS ARROW FROM BAR} ") else: arrow = " -> " if len(vars) == 1: var_form = self._print(vars[0]) else: var_form = self._print(tuple(vars)) 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(u(" \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_gamma(self, e): if self._use_unicode: pform = self._print(e.args[0]) pform = prettyForm(*pform.parens()) pform = prettyForm(*pform.left(greek_unicode['Gamma'])) return pform else: return self._print_Function(e) def _print_uppergamma(self, e): if self._use_unicode: pform = self._print(e.args[0]) pform = prettyForm(*pform.right(', ', self._print(e.args[1]))) pform = prettyForm(*pform.parens()) pform = prettyForm(*pform.left(greek_unicode['Gamma'])) return pform else: return self._print_Function(e) def _print_lowergamma(self, e): if self._use_unicode: pform = self._print(e.args[0]) pform = prettyForm(*pform.right(', ', self._print(e.args[1]))) pform = prettyForm(*pform.parens()) pform = prettyForm(*pform.left(greek_unicode['gamma'])) return pform else: return self._print_Function(e) def _print_expint(self, e): from sympy import Function 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) 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_Add(self, expr, order=None): if self.order == 'none': terms = list(expr.args) else: 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: 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 _coeff_isneg(term): coeff, other = term.as_coeff_mul(rational=False) pform = self._print(Mul(-coeff, *other, evaluate=False)) 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): 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 = product.args # 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) from sympy import Integral, Piecewise, Product, Sum # Convert to pretty forms. Add parens to Add instances if there # is more than one term in the numer/denom for i in range(0, len(a)): if (a[i].is_Add and len(a) > 1) or (i != len(a) - 1 and isinstance(a[i], (Integral, Piecewise, Product, Sum))): a[i] = prettyForm(*self._print(a[i]).parens()) elif a[i].is_Relational: a[i] = prettyForm(*self._print(a[i]).parens()) else: a[i] = self._print(a[i]) for i in range(0, len(b)): if (b[i].is_Add and len(b) > 1) or (i != len(b) - 1 and isinstance(b[i], (Integral, Piecewise, Product, Sum))): b[i] = prettyForm(*self._print(b[i]).parens()) else: b[i] = self._print(b[i]) # 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, expt): 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 expt is S.Half and bpretty.height() == 1 and (bpretty.width() == 1 or (base.is_Integer and base.is_nonnegative))): return prettyForm(*bpretty.left(u('\N{SQUARE ROOT}'))) # Construct root sign, start with the \/ shape _zZ = xobj('/', 1) rootsign = xobj('\\', 1) + _zZ # Make exponent number to put above it if isinstance(expt, Rational): exp = str(expt.q) if exp == '2': exp = '' else: exp = str(expt.args[0]) exp = exp.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: return self._print_nth_root(b, e) 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_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): from sympy import Pow return self._print(Pow(p.sets[0], len(p.sets), evaluate=False)) else: prod_char = u("\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 = u("\N{HORIZONTAL ELLIPSIS}") else: dots = '...' if s.start.is_infinite: printset = s.start, dots, s[-1] - s.step, s[-1] elif s.stop.is_infinite or 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_AccumuBounds(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 = ' \ ' 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 = u("\N{SMALL ELEMENT OF}") else: inn = 'in' variables = self._print_seq(ts.lamda.variables) expr = self._print(ts.lamda.expr) bar = self._print("|") base = self._print(ts.base_set) return self._print_seq((expr, bar, variables, inn, base), "{", "}", ' ') def _print_ConditionSet(self, ts): if self._use_unicode: inn = u("\N{SMALL ELEMENT OF}") # using _and because and is a keyword and it is bad practice to # overwrite them _and = u("\N{LOGICAL AND}") else: inn = 'in' _and = 'and' variables = self._print_seq(Tuple(ts.sym)) try: cond = self._print(ts.condition.as_expr()) except AttributeError: cond = self._print(ts.condition) if self._use_unicode: cond = self._print_seq(cond, "(", ")") bar = self._print("|") base = self._print(ts.base_set) return self._print_seq((variables, bar, variables, inn, base, _and, cond), "{", "}", ' ') def _print_ComplexRegion(self, ts): if self._use_unicode: inn = u("\N{SMALL ELEMENT OF}") else: inn = 'in' variables = self._print_seq(ts.variables) expr = self._print(ts.expr) bar = self._print("|") prodsets = self._print(ts.sets) return self._print_seq((expr, bar, variables, inn, prodsets), "{", "}", ' ') def _print_Contains(self, e): var, set = e.args if self._use_unicode: el = u(" \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 self._use_unicode: dots = u("\N{HORIZONTAL ELLIPSIS}") else: dots = '...' return self._print_Add(s.truncate()) + self._print(dots) def _print_FormalPowerSeries(self, s): return self._print_Add(s.truncate()) def _print_SeqFormula(self, s): if self._use_unicode: dots = u("\N{HORIZONTAL ELLIPSIS}") else: dots = '...' 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): s = None for item in seq: pform = self._print(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=True)) 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): items = sorted(s, key=default_sort_key) pretty = self._print_seq(items, '[', ']') pretty = prettyForm(*pretty.parens('(', ')', ifascii_nougly=True)) pretty = prettyForm(*stringPict.next(type(s).__name__, pretty)) return pretty _print_frozenset = _print_set def _print_PolyRing(self, ring): return prettyForm(sstr(ring)) def _print_FracField(self, field): return prettyForm(sstr(field)) 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 = u('\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(u('\N{DOUBLE-STRUCK CAPITAL Z}')) else: return prettyForm('ZZ') def _print_RationalField(self, expr): if self._use_unicode: return prettyForm(u('\N{DOUBLE-STRUCK CAPITAL Q}')) else: return prettyForm('QQ') def _print_RealField(self, domain): if self._use_unicode: prefix = u('\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 = u('\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_euler(self, e): pform = prettyForm("E") arg = self._print(e.args[0]) pform_arg = prettyForm(" "*arg.width()) pform_arg = prettyForm(*pform_arg.below(arg)) pform = prettyForm(*pform.right(pform_arg)) return pform def _print_catalan(self, e): pform = prettyForm("C") arg = self._print(e.args[0]) pform_arg = prettyForm(" "*arg.width()) pform_arg = prettyForm(*pform_arg.below(arg)) pform = prettyForm(*pform.right(pform_arg)) return pform 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): try: pform = self._print('Domain: ') pform = prettyForm(*pform.right(self._print(d.as_boolean()))) return pform except Exception: try: 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 except: 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 from sympy import Symbol 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_BaseScalarField(self, field): string = field._coord_sys._names[field._index] return self._print(pretty_symbol(string)) def _print_BaseVectorField(self, field): s = U('PARTIAL DIFFERENTIAL') + '_' + field._coord_sys._names[field._index] return self._print(pretty_symbol(s)) def _print_Differential(self, diff): field = diff._form_field if hasattr(field, '_coord_sys'): string = field._coord_sys._names[field._index] return self._print(u('\N{DOUBLE-STRUCK ITALIC SMALL D} ') + pretty_symbol(string)) else: pform = self._print(field) pform = prettyForm(*pform.parens()) return prettyForm(*pform.left(u("\N{DOUBLE-STRUCK ITALIC SMALL 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
[docs]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)
[docs]def pretty_print(expr, **settings): """Prints expr in pretty form. pprint is just a shortcut for this function. Parameters ========== expr : expression the expression to print wrap_line : bool, optional line wrapping enabled/disabled, defaults to True num_columns : int or None, optional 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 use unicode characters, such as the Greek letter pi instead of the string pi. full_prec : bool or string, optional use full precision. Default to "auto" order : bool or string, optional set to 'none' for long expressions if slow; default is None use_unicode_sqrt_char : bool, optional use compact single-character square root symbol (when unambiguous); default is True. """ print(pretty(expr, **settings))
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()))