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()))