ai-content-maker/.venv/Lib/site-packages/sympy/printing/pretty/pretty.py

2940 lines
103 KiB
Python
Raw Normal View History

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