Spaces:
Sleeping
Sleeping
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, is_subscriptable_in_unicode, center_pad, root as nth_root | |
# 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)) | |
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=pretty_atom('NotEquiv')) | |
if isinstance(arg, Implies): | |
return self._print_Implies(arg, altchar=pretty_atom('NotArrow')) | |
if arg.is_Boolean and not arg.is_Not: | |
pform = prettyForm(*pform.parens()) | |
return prettyForm(*pform.left(pretty_atom('Not'))) | |
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, pretty_atom('And')) | |
else: | |
return self._print_Function(e, sort=True) | |
def _print_Or(self, e): | |
if self._use_unicode: | |
return self.__print_Boolean(e, pretty_atom('Or')) | |
else: | |
return self._print_Function(e, sort=True) | |
def _print_Xor(self, e): | |
if self._use_unicode: | |
return self.__print_Boolean(e, pretty_atom("Xor")) | |
else: | |
return self._print_Function(e, sort=True) | |
def _print_Nand(self, e): | |
if self._use_unicode: | |
return self.__print_Boolean(e, pretty_atom('Nand')) | |
else: | |
return self._print_Function(e, sort=True) | |
def _print_Nor(self, e): | |
if self._use_unicode: | |
return self.__print_Boolean(e, pretty_atom('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 pretty_atom('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 pretty_atom('Equiv')) | |
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 = xobj('UpTack', 1) | |
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(f"{xobj('-', 1)}{pretty_atom('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 = pretty_atom('SuperscriptPlus') if str(dir) == "+" else pretty_atom('SuperscriptMinus') | |
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? | |
left, right = center_pad(s.width(), maxw[j]) | |
s = prettyForm(*s.right(right)) | |
s = prettyForm(*s.left(left)) | |
# 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(pretty_atom('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(pretty_atom('IdentityMatrix')) | |
else: | |
return prettyForm('I') | |
def _print_ZeroMatrix(self, expr): | |
if self._use_unicode: | |
return prettyForm(pretty_atom('ZeroMatrix')) | |
else: | |
return prettyForm('0') | |
def _print_OneMatrix(self, expr): | |
if self._use_unicode: | |
return prettyForm(pretty_atom("OneMatrix")) | |
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 = f" {pretty_atom('TensorProduct')} " | |
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 a in 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_StateSpace(self, expr): | |
from sympy.matrices.expressions.blockmatrix import BlockMatrix | |
A = expr._A | |
B = expr._B | |
C = expr._C | |
D = expr._D | |
mat = BlockMatrix([[A, B], [C, D]]) | |
return self._print(mat.blocks) | |
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 xobj(')_ext', 1) in tempstr: # If scalar is a fraction | |
for paren in range(len(tempstr)): | |
flag[i] = 1 | |
if tempstr[paren] == xobj(')_ext', 1) 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] + xobj(')_ext', 1)\ | |
+ ' ' + vectstrs[i] + tempstr[paren + 1:] | |
break | |
elif xobj(')_lower_hook', 1) 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(xobj(')_lower_hook', 1)) | |
if index != -1: # then this character was found in this string | |
flag[i] = 1 | |
tempstr = tempstr[:index] + xobj(')_lower_hook', 1)\ | |
+ ' ' + 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 index in 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) | |
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_polylog(self, e): | |
subscript = self._print(e.args[0]) | |
if self._use_unicode and is_subscriptable_in_unicode(subscript): | |
return self._print_Function(Function('Li_%s' % subscript)(e.args[1])) | |
return self._print_Function(e) | |
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 = f" {pretty_atom('ArrowFromBar')} " | |
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(f" {pretty_atom('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): | |
subscript = self._print(e.args[0]) | |
if self._use_unicode and is_subscriptable_in_unicode(subscript): | |
return self._print_Function(Function('E_%s' % subscript)(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(nth_root[2])) | |
# 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 = pretty_atom('Multiplication') 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 = pretty_atom('Dots') | |
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 = pretty_atom("SmallElementOf") | |
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 = pretty_atom('SmallElementOf') | |
# using _and because and is a keyword and it is bad practice to | |
# overwrite them | |
_and = pretty_atom('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 = pretty_atom('SmallElementOf') | |
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 = f" {pretty_atom('ElementOf')} " | |
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 = pretty_atom('Dots') | |
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 = pretty_atom('Dots') | |
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): | |
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)) | |
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(pretty_atom('Universe')) | |
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 = f"{pretty_atom('Integers')}_%d" | |
else: | |
form = 'GF(%d)' | |
return prettyForm(pretty_symbol(form % expr.mod)) | |
def _print_IntegerRing(self, expr): | |
if self._use_unicode: | |
return prettyForm(pretty_atom('Integers')) | |
else: | |
return prettyForm('ZZ') | |
def _print_RationalField(self, expr): | |
if self._use_unicode: | |
return prettyForm(pretty_atom('Rationals')) | |
else: | |
return prettyForm('QQ') | |
def _print_RealField(self, domain): | |
if self._use_unicode: | |
prefix = pretty_atom("Reals") | |
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 = pretty_atom('Complexes') | |
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, greek_unicode['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): | |
gens = [[M.ring.to_sympy(g) for g in gen] for gen in M.gens] | |
return self._print_seq(gens, '<', '>') | |
def _print_FreeModule(self, M): | |
return self._print(M.ring)**self._print(M.rank) | |
def _print_ModuleImplementedIdeal(self, M): | |
sym = M.ring.to_sympy | |
return self._print_seq([sym(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.ring.to_sympy(R)) + 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 = pretty_atom('Differential') | |
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': | |
if self._use_unicode: | |
pform = self._print(pretty_atom('Degree')) | |
else: | |
pform = self._print(chr(176)) | |
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) | |
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())) | |