from __future__ import print_function, division
import itertools
from sympy.core import S
from sympy.core.containers import Tuple
from sympy.core.function import _coeff_isneg
from sympy.core.mod import Mod
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, precedence_traditional
from sympy.utilities import group
from sympy.utilities.iterables import has_variety
from sympy.core.sympify import SympifyError
from sympy.core.compatibility import 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_Cross(self, e):
vec1 = e._expr1
vec2 = e._expr2
pform = self._print(vec2)
pform = prettyForm(*pform.left('('))
pform = prettyForm(*pform.right(')'))
pform = prettyForm(*pform.left(self._print(U('MULTIPLICATION SIGN'))))
pform = prettyForm(*pform.left(')'))
pform = prettyForm(*pform.left(self._print(vec1)))
pform = prettyForm(*pform.left('('))
return pform
def _print_Curl(self, e):
vec = e._expr
pform = self._print(vec)
pform = prettyForm(*pform.left('('))
pform = prettyForm(*pform.right(')'))
pform = prettyForm(*pform.left(self._print(U('MULTIPLICATION SIGN'))))
pform = prettyForm(*pform.left(self._print(U('NABLA'))))
return pform
def _print_Divergence(self, e):
vec = e._expr
pform = self._print(vec)
pform = prettyForm(*pform.left('('))
pform = prettyForm(*pform.right(')'))
pform = prettyForm(*pform.left(self._print(U('DOT OPERATOR'))))
pform = prettyForm(*pform.left(self._print(U('NABLA'))))
return pform
def _print_Dot(self, e):
vec1 = e._expr1
vec2 = e._expr2
pform = self._print(vec2)
pform = prettyForm(*pform.left('('))
pform = prettyForm(*pform.right(')'))
pform = prettyForm(*pform.left(self._print(U('DOT OPERATOR'))))
pform = prettyForm(*pform.left(')'))
pform = prettyForm(*pform.left(self._print(vec1)))
pform = prettyForm(*pform.left('('))
return pform
def _print_Gradient(self, e):
func = e._expr
pform = self._print(func)
pform = prettyForm(*pform.left('('))
pform = prettyForm(*pform.right(')'))
pform = prettyForm(*pform.left(self._print(U('DOT OPERATOR'))))
pform = prettyForm(*pform.left(self._print(U('NABLA'))))
return pform
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_Complexes = _print_Atom
def _print_Reals(self, e):
if self._use_unicode:
return self._print_Atom(e)
else:
inf_list = ['-oo', 'oo']
return self._print_seq(inf_list, '(', ')')
def _print_subfactorial(self, e):
x = e.args[0]
pform = self._print(x)
# Add parentheses if needed
if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol):
pform = prettyForm(*pform.parens())
pform = prettyForm(*pform.left('!'))
return pform
def _print_factorial(self, e):
x = e.args[0]
pform = self._print(x)
# Add parentheses if needed
if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol):
pform = prettyForm(*pform.parens())
pform = prettyForm(*pform.right('!'))
return pform
def _print_factorial2(self, e):
x = e.args[0]
pform = self._print(x)
# Add parentheses if needed
if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol):
pform = prettyForm(*pform.parens())
pform = prettyForm(*pform.right('!!'))
return pform
def _print_binomial(self, e):
n, k = e.args
n_pform = self._print(n)
k_pform = self._print(k)
bar = ' '*max(n_pform.width(), k_pform.width())
pform = prettyForm(*k_pform.above(bar))
pform = prettyForm(*pform.above(n_pform))
pform = prettyForm(*pform.parens('(', ')'))
pform.baseline = (pform.baseline + 1)//2
return pform
def _print_Relational(self, e):
op = prettyForm(' ' + xsym(e.rel_op) + ' ')
l = self._print(e.lhs)
r = self._print(e.rhs)
pform = prettyForm(*stringPict.next(l, op, r))
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{LEFT RIGHT DOUBLE ARROW WITH STROKE}")
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{LEFT RIGHT DOUBLE ARROW}")
else:
return self._print_Function(e, sort=True)
def _print_conjugate(self, e):
pform = self._print(e.args[0])
return prettyForm( *pform.above( hobj('_', pform.width())) )
def _print_Abs(self, e):
pform = self._print(e.args[0])
pform = prettyForm(*pform.parens('|', '|'))
return pform
_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'
x = None
count_total_deriv = 0
for sym, num in reversed(deriv.variable_count):
s = self._print(sym)
ds = prettyForm(*s.left(deriv_symbol))
count_total_deriv += num
if (not num.is_Integer) or (num > 1):
ds = ds**prettyForm(str(num))
if x is None:
x = ds
else:
x = prettyForm(*x.right(' '))
x = prettyForm(*x.right(ds))
f = prettyForm(
binding=prettyForm.FUNC, *self._print(deriv.expr).parens())
pform = prettyForm(deriv_symbol)
if (count_total_deriv > 1) != False:
pform = pform**prettyForm(str(count_total_deriv))
pform = prettyForm(*pform.below(stringPict.LINE, x))
pform.baseline = pform.baseline + 1
pform = prettyForm(*stringPict.next(pform, f))
pform.binding = prettyForm.MUL
return pform
def _print_Cycle(self, dc):
from sympy.combinatorics.permutations import Permutation, Cycle
# for Empty Cycle
if dc == Cycle():
cyc = stringPict('')
return prettyForm(*cyc.parens())
dc_list = Permutation(dc.list()).cyclic_form
# for Identity Cycle
if dc_list == []:
cyc = self._print(dc.size - 1)
return prettyForm(*cyc.parens())
cyc = stringPict('')
for i in dc_list:
l = self._print(str(tuple(i)).replace(',', ''))
cyc = prettyForm(*cyc.right(l))
return cyc
def _print_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(r"\%s`" % (' '*(w - 1)))
for i in range(1, d):
lines.append('%s\\%s' % (' '*i, ' '*(w - i)))
if more:
lines.append('%s)%s' % (' '*(d), ' '*(w - d)))
for i in reversed(range(1, d)):
lines.append('%s/%s' % (' '*i, ' '*(w - i)))
lines.append("/" + "_"*(w - 1) + ',')
return d, h + more, lines, 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 str(dir) == '+-' or 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.baseline = D.height()//2
D = prettyForm(*D.parens('[', ']'))
return D
_print_ImmutableMatrix = _print_MatrixBase
_print_Matrix = _print_MatrixBase
def _print_TensorProduct(self, expr):
# This should somehow share the code with _print_WedgeProduct:
circled_times = "\u2297"
return self._print_seq(expr.args, None, None, circled_times,
parenthesize=lambda x: precedence_traditional(x) <= PRECEDENCE["Mul"])
def _print_WedgeProduct(self, expr):
# This should somehow share the code with _print_TensorProduct:
wedge_symbol = u"\u2227"
return self._print_seq(expr.args, None, None, wedge_symbol,
parenthesize=lambda x: precedence_traditional(x) <= PRECEDENCE["Mul"])
def _print_Trace(self, e):
D = self._print(e.arg)
D = prettyForm(*D.parens('(',')'))
D.baseline = D.height()//2
D = prettyForm(*D.left('\n'*(0) + 'tr'))
return D
def _print_MatrixElement(self, expr):
from sympy.matrices import MatrixSymbol
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)
prettyFunc = prettyForm(*prettyFunc.parens())
prettyIndices = self._print_seq((expr.i, expr.j), delimiter=', '
).parens(left='[', right=']')[0]
pform = prettyForm(binding=prettyForm.FUNC,
*stringPict.next(prettyFunc, prettyIndices))
# store pform parts so it can be reassembled e.g. when powered
pform.prettyFunc = prettyFunc
pform.prettyArgs = prettyIndices
return pform
def _print_MatrixSlice(self, m):
# XXX works only for applied functions
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):
s = None
for item in expr.args:
pform = self._print(item)
if s is None:
s = pform # First element
else:
coeff = item.as_coeff_mmul()[0]
if _coeff_isneg(S(coeff)):
s = prettyForm(*stringPict.next(s, ' '))
pform = self._print(item)
else:
s = prettyForm(*stringPict.next(s, ' + '))
s = prettyForm(*stringPict.next(s, pform))
return s
def _print_MatMul(self, expr):
args = list(expr.args)
from sympy 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)))
def _print_KroneckerProduct(self, expr):
from sympy import MatAdd, MatMul
if self._use_unicode:
delim = u' \N{N-ARY CIRCLED TIMES OPERATOR} '
else:
delim = ' x '
return self._print_seq(expr.args, None, None, delim,
parenthesize=lambda x: isinstance(x, (MatAdd, MatMul)))
_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 = ['']
flag = []
for i, partstr in enumerate(o1):
flag.append(0)
# XXX: What is this hack?
if '\n' in partstr:
tempstr = partstr
tempstr = tempstr.replace(vectstrs[i], '')
if u'\N{right parenthesis extension}' in tempstr: # If scalar is a fraction
for paren in range(len(tempstr)):
flag[i] = 1
if tempstr[paren] == u'\N{right parenthesis extension}':
tempstr = tempstr[:paren] + u'\N{right parenthesis extension}'\
+ ' ' + vectstrs[i] + tempstr[paren + 1:]
break
elif u'\N{RIGHT PARENTHESIS LOWER HOOK}' in tempstr:
flag[i] = 1
tempstr = tempstr.replace(u'\N{RIGHT PARENTHESIS LOWER HOOK}',
u'\N{RIGHT PARENTHESIS LOWER HOOK}'
+ ' ' + vectstrs[i])
else:
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]) # Width of part in its pretty form
if 1 in flag: # If there was a fractional scalar
for i, parts in enumerate(o1):
if len(parts) == 1: # If part has no newline
parts.insert(0, ' ' * (len(parts[0])))
flag[i] = 1
for i, parts in enumerate(o1):
lengths.append(len(parts[flag[i]]))
for j in range(n_newlines):
if j+1 <= len(parts):
if j >= len(strs):
strs.append(' ' * (sum(lengths[:-1]) +
3*(len(lengths)-1)))
if j == flag[i]:
strs[flag[i]] += parts[flag[i]] + ' + '
else:
strs[j] += parts[j] + ' '*(lengths[-1] -
len(parts[j])+
3)
else:
if j >= len(strs):
strs.append(' ' * (sum(lengths[:-1]) +
3*(len(lengths)-1)))
strs[j] += ' '*(lengths[-1]+3)
return prettyForm(u'\n'.join([s[:-3] for s in strs]))
def _print_NDimArray(self, expr):
from sympy import ImmutableMatrix
if expr.rank() == 0:
return self._print(expr[()])
level_str = [[]] + [[] for i in range(expr.rank())]
shape_ranges = [list(range(i)) for i in expr.shape]
for outer_i in itertools.product(*shape_ranges):
level_str[-1].append(expr[outer_i])
even = True
for back_outer_i in range(expr.rank()-1, -1, -1):
if len(level_str[back_outer_i+1]) < expr.shape[back_outer_i]:
break
if even:
level_str[back_outer_i].append(level_str[back_outer_i+1])
else:
level_str[back_outer_i].append(ImmutableMatrix(level_str[back_outer_i+1]))
if len(level_str[back_outer_i + 1]) == 1:
level_str[back_outer_i][-1] = ImmutableMatrix([[level_str[back_outer_i][-1]]])
even = not even
level_str[back_outer_i+1] = []
out_expr = level_str[0][0]
if expr.rank() % 2 == 1:
out_expr = ImmutableMatrix([out_expr])
return self._print(out_expr)
_print_ImmutableDenseNDimArray = _print_NDimArray
_print_ImmutableSparseNDimArray = _print_NDimArray
_print_MutableDenseNDimArray = _print_NDimArray
_print_MutableSparseNDimArray = _print_NDimArray
def _print_Piecewise(self, pexpr):
P = {}
for n, ec in enumerate(pexpr.args):
P[n, 0] = self._print(ec.expr)
if ec.cond == True:
P[n, 1] = prettyForm('otherwise')
else:
P[n, 1] = prettyForm(
*prettyForm('for ').right(self._print(ec.cond)))
hsep = 2
vsep = 1
len_args = len(pexpr.args)
# max widths
maxw = [max([P[i, j].width() for i in range(len_args)])
for j in range(2)]
# FIXME: Refactor this code and matrix into some tabular environment.
# drawing result
D = None
for i in range(len_args):
D_row = None
for j in range(2):
p = P[i, j]
assert p.width() <= maxw[j]
wdelta = maxw[j] - p.width()
wleft = wdelta // 2
wright = wdelta - wleft
p = prettyForm(*p.right(' '*wright))
p = prettyForm(*p.left(' '*wleft))
if D_row is None:
D_row = p
continue
D_row = prettyForm(*D_row.right(' '*hsep)) # h-spacer
D_row = prettyForm(*D_row.right(p))
if D is None:
D = D_row # first row in a picture
continue
# v-spacer
for _ in range(vsep):
D = prettyForm(*D.below(' '))
D = prettyForm(*D.below(D_row))
D = prettyForm(*D.parens('{', ''))
D.baseline = D.height()//2
D.binding = prettyForm.OPEN
return D
def _print_ITE(self, ite):
from sympy.functions.elementary.piecewise import Piecewise
return self._print(ite.rewrite(Piecewise))
def _hprint_vec(self, v):
D = None
for a in v:
p = a
if D is None:
D = p
else:
D = prettyForm(*D.right(', '))
D = prettyForm(*D.right(p))
if D is None:
D = stringPict(' ')
return D
def _hprint_vseparator(self, p1, p2):
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, func_name=None):
# optional argument func_name for supplying custom names
# XXX works only for applied functions
func = e.func
args = e.args
if sort:
args = sorted(args, key=default_sort_key)
if not func_name:
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
@property
def _special_function_classes(self):
from sympy.functions.special.tensor_functions import KroneckerDelta
from sympy.functions.special.gamma_functions import gamma, lowergamma
from sympy.functions.special.beta_functions import beta
from sympy.functions.special.delta_functions import DiracDelta
from sympy.functions.special.error_functions import Chi
return {KroneckerDelta: [greek_unicode['delta'], 'delta'],
gamma: [greek_unicode['Gamma'], 'Gamma'],
lowergamma: [greek_unicode['gamma'], 'gamma'],
beta: [greek_unicode['Beta'], 'B'],
DiracDelta: [greek_unicode['delta'], 'delta'],
Chi: ['Chi', 'Chi']}
def _print_FunctionClass(self, expr):
for cls in self._special_function_classes:
if issubclass(expr, cls) and expr.__name__ == cls.__name__:
if self._use_unicode:
return prettyForm(self._special_function_classes[cls][0])
else:
return prettyForm(self._special_function_classes[cls][1])
func_name = expr.__name__
return prettyForm(pretty_symbol(func_name))
def _print_GeometryEntity(self, expr):
# GeometryEntity is based on Tuple but should not print like a Tuple
return self.emptyPrinter(expr)
def _print_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_SingularityFunction(self, e):
if self._use_unicode:
shift = self._print(e.args[0]-e.args[1])
n = self._print(e.args[2])
base = prettyForm("<")
base = prettyForm(*base.right(shift))
base = prettyForm(*base.right(">"))
pform = base**n
return pform
else:
n = self._print(e.args[2])
shift = self._print(e.args[0]-e.args[1])
base = self._print_seq(shift, "<", ">", ' ')
return base**n
def _print_beta(self, e):
func_name = greek_unicode['Beta'] if self._use_unicode else 'B'
return self._print_Function(e, func_name=func_name)
def _print_gamma(self, e):
func_name = greek_unicode['Gamma'] if self._use_unicode else 'Gamma'
return self._print_Function(e, func_name=func_name)
def _print_uppergamma(self, e):
func_name = greek_unicode['Gamma'] if self._use_unicode else 'Gamma'
return self._print_Function(e, func_name=func_name)
def _print_lowergamma(self, e):
func_name = greek_unicode['gamma'] if self._use_unicode else 'lowergamma'
return self._print_Function(e, func_name=func_name)
def _print_DiracDelta(self, e):
if self._use_unicode:
if len(e.args) == 2:
a = prettyForm(greek_unicode['delta'])
b = self._print(e.args[1])
b = prettyForm(*b.parens())
c = self._print(e.args[0])
c = prettyForm(*c.parens())
pform = a**b
pform = prettyForm(*pform.right(' '))
pform = prettyForm(*pform.right(c))
return pform
pform = self._print(e.args[0])
pform = prettyForm(*pform.parens())
pform = prettyForm(*pform.left(greek_unicode['delta']))
return pform
else:
return self._print_Function(e)
def _print_expint(self, e):
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_Mod(self, expr):
pform = self._print(expr.args[0])
if pform.binding > prettyForm.MUL:
pform = prettyForm(*pform.parens())
pform = prettyForm(*pform.right(' mod '))
pform = prettyForm(*pform.right(self._print(expr.args[1])))
pform.binding = prettyForm.OPEN
return pform
def _print_Add(self, expr, order=None):
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
or pform.binding == prettyForm.ADD):
p = stringPict(*pform.parens())
else:
p = pform
p = stringPict.next(pform_neg, p)
# Lower the binding to NEG, even if it was higher. Otherwise, it
# will print as a + ( - (b)), instead of a - (b).
return prettyForm(binding=prettyForm.NEG, *p)
for i, term in enumerate(terms):
if term.is_Mul and _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):
from sympy.physics.units import Quantity
a = [] # items in the numerator
b = [] # items that are in the denominator (if any)
if self.order not in ('old', 'none'):
args = product.as_ordered_factors()
else:
args = list(product.args)
# If quantities are present append them at the back
args = sorted(args, key=lambda x: isinstance(x, Quantity) or
(isinstance(x, Pow) and isinstance(x.base, Quantity)))
# Gather terms for numerator/denominator
for item in args:
if item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative:
if item.exp != -1:
b.append(Pow(item.base, -item.exp, evaluate=False))
else:
b.append(Pow(item.base, -item.exp))
elif item.is_Rational and item is not S.Infinity:
if item.p != 1:
a.append( Rational(item.p) )
if item.q != 1:
b.append( Rational(item.q) )
else:
a.append(item)
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_UnevaluatedExpr(self, expr):
return self._print(expr.args[0])
def __print_numer_denom(self, p, q):
if q == 1:
if p < 0:
return prettyForm(str(p), binding=prettyForm.NEG)
else:
return prettyForm(str(p))
elif abs(p) >= 10 and abs(q) >= 10:
# If more than one digit in numer and denom, print larger fraction
if p < 0:
return prettyForm(str(p), binding=prettyForm.NEG)/prettyForm(str(q))
# Old printing method:
#pform = prettyForm(str(-p))/prettyForm(str(q))
#return prettyForm(binding=prettyForm.NEG, *pform.left('- '))
else:
return prettyForm(str(p))/prettyForm(str(q))
else:
return None
def _print_Rational(self, expr):
result = self.__print_numer_denom(expr.p, expr.q)
if result is not None:
return result
else:
return self.emptyPrinter(expr)
def _print_Fraction(self, expr):
result = self.__print_numer_denom(expr.numerator, expr.denominator)
if result is not None:
return result
else:
return self.emptyPrinter(expr)
def _print_ProductSet(self, p):
if len(p.sets) > 1 and not has_variety(p.sets):
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_AccumulationBounds(self, i):
left = '<'
right = '>'
return self._print_seq(i.args[:2], left, right)
def _print_Intersection(self, u):
delimiter = ' %s ' % pretty_atom('Intersection', 'n')
return self._print_seq(u.args, None, None, delimiter,
parenthesize=lambda set: set.is_ProductSet or
set.is_Union or set.is_Complement)
def _print_Union(self, u):
union_delimiter = ' %s ' % pretty_atom('Union', 'U')
return self._print_seq(u.args, None, None, union_delimiter,
parenthesize=lambda set: set.is_ProductSet or
set.is_Intersection or set.is_Complement)
def _print_SymmetricDifference(self, u):
if not self._use_unicode:
raise NotImplementedError("ASCII pretty printing of SymmetricDifference is not implemented")
sym_delimeter = ' %s ' % pretty_atom('SymmetricDifference')
return self._print_seq(u.args, None, None, sym_delimeter)
def _print_Complement(self, u):
delimiter = r' \ '
return self._print_seq(u.args, None, None, delimiter,
parenthesize=lambda set: set.is_ProductSet or set.is_Intersection
or set.is_Union)
def _print_ImageSet(self, ts):
if self._use_unicode:
inn = u"\N{SMALL ELEMENT OF}"
else:
inn = 'in'
variables = ts.lamda.variables
expr = self._print(ts.lamda.expr)
bar = self._print("|")
sets = [self._print(i) for i in ts.args[1:]]
if len(sets) == 1:
return self._print_seq((expr, bar, variables[0], inn, sets[0]), "{", "}", ' ')
else:
pargs = tuple(j for var, setv in zip(variables, sets) for j in (var, inn, setv, ","))
return self._print_seq((expr, bar) + pargs[:-1], "{", "}", ' ')
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("|")
if ts.base_set is S.UniversalSet:
return self._print_seq((variables, bar, cond), "{", "}", ' ')
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.infinite)
def _print_SetExpr(self, se):
pretty_set = prettyForm(*self._print(se.set).parens())
pretty_name = self._print(Symbol("SetExpr"))
return prettyForm(*pretty_name.right(pretty_set))
def _print_SeqFormula(self, s):
if self._use_unicode:
dots = 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):
if not s:
return prettyForm('set()')
items = sorted(s, key=default_sort_key)
pretty = self._print_seq(items)
pretty = prettyForm(*pretty.parens('{', '}', ifascii_nougly=True))
return pretty
def _print_frozenset(self, s):
if not s:
return prettyForm('frozenset()')
items = sorted(s, key=default_sort_key)
pretty = self._print_seq(items)
pretty = prettyForm(*pretty.parens('{', '}', ifascii_nougly=True))
pretty = prettyForm(*pretty.parens('(', ')', ifascii_nougly=True))
pretty = prettyForm(*stringPict.next(type(s).__name__, pretty))
return pretty
def _print_PolyRing(self, ring):
return prettyForm(sstr(ring))
def _print_FracField(self, field):
return prettyForm(sstr(field))
def _print_FreeGroupElement(self, elm):
return prettyForm(str(elm))
def _print_PolyElement(self, poly):
return prettyForm(sstr(poly))
def _print_FracElement(self, frac):
return prettyForm(sstr(frac))
def _print_AlgebraicNumber(self, expr):
if expr.is_aliased:
return self._print(expr.as_poly().as_expr())
else:
return self._print(expr.as_expr())
def _print_ComplexRootOf(self, expr):
args = [self._print_Add(expr.expr, order='lex'), expr.index]
pform = prettyForm(*self._print_seq(args).parens())
pform = prettyForm(*pform.left('CRootOf'))
return pform
def _print_RootSum(self, expr):
args = [self._print_Add(expr.expr, order='lex')]
if expr.fun is not S.IdentityFunction:
args.append(self._print(expr.fun))
pform = prettyForm(*self._print_seq(args).parens())
pform = prettyForm(*pform.left('RootSum'))
return pform
def _print_FiniteField(self, expr):
if self._use_unicode:
form = 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))
if len(e.args) == 1:
return pform
m, x = e.args
# TODO: copy-pasted from _print_Function: can we do better?
prettyFunc = pform
prettyArgs = prettyForm(*self._print_seq([x]).parens())
pform = prettyForm(
binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
pform.prettyFunc = prettyFunc
pform.prettyArgs = prettyArgs
return pform
def _print_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):
if hasattr(d, 'as_boolean'):
pform = self._print('Domain: ')
pform = prettyForm(*pform.right(self._print(d.as_boolean())))
return pform
elif hasattr(d, 'set'):
pform = self._print('Domain: ')
pform = prettyForm(*pform.right(self._print(d.symbols)))
pform = prettyForm(*pform.right(self._print(' in ')))
pform = prettyForm(*pform.right(self._print(d.set)))
return pform
elif hasattr(d, 'symbols'):
pform = self._print('Domain on ')
pform = prettyForm(*pform.right(self._print(d.symbols)))
return pform
else:
return self._print(None)
def _print_DMP(self, p):
try:
if p.ring is not None:
# TODO incorporate order
return self._print(p.ring.to_sympy(p))
except SympifyError:
pass
return self._print(repr(p))
def _print_DMF(self, p):
return self._print_DMP(p)
def _print_Object(self, object):
return self._print(pretty_symbol(object.name))
def _print_Morphism(self, morphism):
arrow = xsym("-->")
domain = self._print(morphism.domain)
codomain = self._print(morphism.codomain)
tail = domain.right(arrow, codomain)[0]
return prettyForm(tail)
def _print_NamedMorphism(self, morphism):
pretty_name = self._print(pretty_symbol(morphism.name))
pretty_morphism = self._print_Morphism(morphism)
return prettyForm(pretty_name.right(":", pretty_morphism)[0])
def _print_IdentityMorphism(self, morphism):
from sympy.categories import NamedMorphism
return self._print_NamedMorphism(
NamedMorphism(morphism.domain, morphism.codomain, "id"))
def _print_CompositeMorphism(self, morphism):
circle = xsym(".")
# All components of the morphism have names and it is thus
# possible to build the name of the composite.
component_names_list = [pretty_symbol(component.name) for
component in morphism.components]
component_names_list.reverse()
component_names = circle.join(component_names_list) + ":"
pretty_name = self._print(component_names)
pretty_morphism = self._print_Morphism(morphism)
return prettyForm(pretty_name.right(pretty_morphism)[0])
def _print_Category(self, category):
return self._print(pretty_symbol(category.name))
def _print_Diagram(self, diagram):
if not diagram.premises:
# This is an empty diagram.
return self._print(S.EmptySet)
pretty_result = self._print(diagram.premises)
if diagram.conclusions:
results_arrow = " %s " % xsym("==>")
pretty_conclusions = self._print(diagram.conclusions)[0]
pretty_result = pretty_result.right(
results_arrow, pretty_conclusions)
return prettyForm(pretty_result[0])
def _print_DiagramGrid(self, grid):
from sympy.matrices import Matrix
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
def _print_primenu(self, e):
pform = self._print(e.args[0])
pform = prettyForm(*pform.parens())
if self._use_unicode:
pform = prettyForm(*pform.left(greek_unicode['nu']))
else:
pform = prettyForm(*pform.left('nu'))
return pform
def _print_primeomega(self, e):
pform = self._print(e.args[0])
pform = prettyForm(*pform.parens())
if self._use_unicode:
pform = prettyForm(*pform.left(greek_unicode['Omega']))
else:
pform = prettyForm(*pform.left('Omega'))
return pform
def _print_Quantity(self, e):
if e.name.name == 'degree':
pform = self._print(u"\N{DEGREE SIGN}")
return pform
else:
return self.emptyPrinter(e)
def _print_AssignmentBase(self, e):
op = prettyForm(' ' + xsym(e.op) + ' ')
l = self._print(e.lhs)
r = self._print(e.rhs)
pform = prettyForm(*stringPict.next(l, op, r))
return pform
[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, wrap_line=True, num_columns=None, use_unicode=None,
full_prec="auto", order=None, use_unicode_sqrt_char=True):
"""Prints expr in pretty form.
pprint is just a shortcut for this function.
Parameters
==========
expr : expression
The expression to print.
wrap_line : bool, optional (default=True)
Line wrapping enabled/disabled.
num_columns : int or None, optional (default=None)
Number of columns before line breaking (default to None which reads
the terminal width), useful when using SymPy without terminal.
use_unicode : bool or None, optional (default=None)
Use unicode characters, such as the Greek letter pi instead of
the string pi.
full_prec : bool or string, optional (default="auto")
Use full precision.
order : bool or string, optional (default=None)
Set to 'none' for long expressions if slow; default is None.
use_unicode_sqrt_char : bool, optional (default=True)
Use compact single-character square root symbol (when unambiguous).
"""
print(pretty(expr, wrap_line=wrap_line, num_columns=num_columns,
use_unicode=use_unicode, full_prec=full_prec, order=order,
use_unicode_sqrt_char=use_unicode_sqrt_char))
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()))