Spaces:
Sleeping
Sleeping
""" | |
A Printer for generating readable representation of most SymPy classes. | |
""" | |
from __future__ import annotations | |
from typing import Any | |
from sympy.core import S, Rational, Pow, Basic, Mul, Number | |
from sympy.core.mul import _keep_coeff | |
from sympy.core.numbers import Integer | |
from sympy.core.relational import Relational | |
from sympy.core.sorting import default_sort_key | |
from sympy.utilities.iterables import sift | |
from .precedence import precedence, PRECEDENCE | |
from .printer import Printer, print_function | |
from mpmath.libmp import prec_to_dps, to_str as mlib_to_str | |
class StrPrinter(Printer): | |
printmethod = "_sympystr" | |
_default_settings: dict[str, Any] = { | |
"order": None, | |
"full_prec": "auto", | |
"sympy_integers": False, | |
"abbrev": False, | |
"perm_cyclic": True, | |
"min": None, | |
"max": None, | |
} | |
_relationals: dict[str, str] = {} | |
def parenthesize(self, item, level, strict=False): | |
if (precedence(item) < level) or ((not strict) and precedence(item) <= level): | |
return "(%s)" % self._print(item) | |
else: | |
return self._print(item) | |
def stringify(self, args, sep, level=0): | |
return sep.join([self.parenthesize(item, level) for item in args]) | |
def emptyPrinter(self, expr): | |
if isinstance(expr, str): | |
return expr | |
elif isinstance(expr, Basic): | |
return repr(expr) | |
else: | |
return str(expr) | |
def _print_Add(self, expr, order=None): | |
terms = self._as_ordered_terms(expr, order=order) | |
prec = precedence(expr) | |
l = [] | |
for term in terms: | |
t = self._print(term) | |
if t.startswith('-') and not term.is_Add: | |
sign = "-" | |
t = t[1:] | |
else: | |
sign = "+" | |
if precedence(term) < prec or term.is_Add: | |
l.extend([sign, "(%s)" % t]) | |
else: | |
l.extend([sign, t]) | |
sign = l.pop(0) | |
if sign == '+': | |
sign = "" | |
return sign + ' '.join(l) | |
def _print_BooleanTrue(self, expr): | |
return "True" | |
def _print_BooleanFalse(self, expr): | |
return "False" | |
def _print_Not(self, expr): | |
return '~%s' %(self.parenthesize(expr.args[0],PRECEDENCE["Not"])) | |
def _print_And(self, expr): | |
args = list(expr.args) | |
for j, i in enumerate(args): | |
if isinstance(i, Relational) and ( | |
i.canonical.rhs is S.NegativeInfinity): | |
args.insert(0, args.pop(j)) | |
return self.stringify(args, " & ", PRECEDENCE["BitwiseAnd"]) | |
def _print_Or(self, expr): | |
return self.stringify(expr.args, " | ", PRECEDENCE["BitwiseOr"]) | |
def _print_Xor(self, expr): | |
return self.stringify(expr.args, " ^ ", PRECEDENCE["BitwiseXor"]) | |
def _print_AppliedPredicate(self, expr): | |
return '%s(%s)' % ( | |
self._print(expr.function), self.stringify(expr.arguments, ", ")) | |
def _print_Basic(self, expr): | |
l = [self._print(o) for o in expr.args] | |
return expr.__class__.__name__ + "(%s)" % ", ".join(l) | |
def _print_BlockMatrix(self, B): | |
if B.blocks.shape == (1, 1): | |
self._print(B.blocks[0, 0]) | |
return self._print(B.blocks) | |
def _print_Catalan(self, expr): | |
return 'Catalan' | |
def _print_ComplexInfinity(self, expr): | |
return 'zoo' | |
def _print_ConditionSet(self, s): | |
args = tuple([self._print(i) for i in (s.sym, s.condition)]) | |
if s.base_set is S.UniversalSet: | |
return 'ConditionSet(%s, %s)' % args | |
args += (self._print(s.base_set),) | |
return 'ConditionSet(%s, %s, %s)' % args | |
def _print_Derivative(self, expr): | |
dexpr = expr.expr | |
dvars = [i[0] if i[1] == 1 else i for i in expr.variable_count] | |
return 'Derivative(%s)' % ", ".join((self._print(arg) for arg in [dexpr] + dvars)) | |
def _print_dict(self, d): | |
keys = sorted(d.keys(), key=default_sort_key) | |
items = [] | |
for key in keys: | |
item = "%s: %s" % (self._print(key), self._print(d[key])) | |
items.append(item) | |
return "{%s}" % ", ".join(items) | |
def _print_Dict(self, expr): | |
return self._print_dict(expr) | |
def _print_RandomDomain(self, d): | |
if hasattr(d, 'as_boolean'): | |
return 'Domain: ' + self._print(d.as_boolean()) | |
elif hasattr(d, 'set'): | |
return ('Domain: ' + self._print(d.symbols) + ' in ' + | |
self._print(d.set)) | |
else: | |
return 'Domain on ' + self._print(d.symbols) | |
def _print_Dummy(self, expr): | |
return '_' + expr.name | |
def _print_EulerGamma(self, expr): | |
return 'EulerGamma' | |
def _print_Exp1(self, expr): | |
return 'E' | |
def _print_ExprCondPair(self, expr): | |
return '(%s, %s)' % (self._print(expr.expr), self._print(expr.cond)) | |
def _print_Function(self, expr): | |
return expr.func.__name__ + "(%s)" % self.stringify(expr.args, ", ") | |
def _print_GoldenRatio(self, expr): | |
return 'GoldenRatio' | |
def _print_Heaviside(self, expr): | |
# Same as _print_Function but uses pargs to suppress default 1/2 for | |
# 2nd args | |
return expr.func.__name__ + "(%s)" % self.stringify(expr.pargs, ", ") | |
def _print_TribonacciConstant(self, expr): | |
return 'TribonacciConstant' | |
def _print_ImaginaryUnit(self, expr): | |
return 'I' | |
def _print_Infinity(self, expr): | |
return 'oo' | |
def _print_Integral(self, expr): | |
def _xab_tostr(xab): | |
if len(xab) == 1: | |
return self._print(xab[0]) | |
else: | |
return self._print((xab[0],) + tuple(xab[1:])) | |
L = ', '.join([_xab_tostr(l) for l in expr.limits]) | |
return 'Integral(%s, %s)' % (self._print(expr.function), L) | |
def _print_Interval(self, i): | |
fin = 'Interval{m}({a}, {b})' | |
a, b, l, r = i.args | |
if a.is_infinite and b.is_infinite: | |
m = '' | |
elif a.is_infinite and not r: | |
m = '' | |
elif b.is_infinite and not l: | |
m = '' | |
elif not l and not r: | |
m = '' | |
elif l and r: | |
m = '.open' | |
elif l: | |
m = '.Lopen' | |
else: | |
m = '.Ropen' | |
return fin.format(**{'a': a, 'b': b, 'm': m}) | |
def _print_AccumulationBounds(self, i): | |
return "AccumBounds(%s, %s)" % (self._print(i.min), | |
self._print(i.max)) | |
def _print_Inverse(self, I): | |
return "%s**(-1)" % self.parenthesize(I.arg, PRECEDENCE["Pow"]) | |
def _print_Lambda(self, obj): | |
expr = obj.expr | |
sig = obj.signature | |
if len(sig) == 1 and sig[0].is_symbol: | |
sig = sig[0] | |
return "Lambda(%s, %s)" % (self._print(sig), self._print(expr)) | |
def _print_LatticeOp(self, expr): | |
args = sorted(expr.args, key=default_sort_key) | |
return expr.func.__name__ + "(%s)" % ", ".join(self._print(arg) for arg in args) | |
def _print_Limit(self, expr): | |
e, z, z0, dir = expr.args | |
return "Limit(%s, %s, %s, dir='%s')" % tuple(map(self._print, (e, z, z0, dir))) | |
def _print_list(self, expr): | |
return "[%s]" % self.stringify(expr, ", ") | |
def _print_List(self, expr): | |
return self._print_list(expr) | |
def _print_MatrixBase(self, expr): | |
return expr._format_str(self) | |
def _print_MatrixElement(self, expr): | |
return self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) \ | |
+ '[%s, %s]' % (self._print(expr.i), self._print(expr.j)) | |
def _print_MatrixSlice(self, expr): | |
def strslice(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 ':'.join((self._print(arg) for arg in x)) | |
return (self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) + '[' + | |
strslice(expr.rowslice, expr.parent.rows) + ', ' + | |
strslice(expr.colslice, expr.parent.cols) + ']') | |
def _print_DeferredVector(self, expr): | |
return expr.name | |
def _print_Mul(self, expr): | |
prec = precedence(expr) | |
# 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 = expr.args | |
if args[0] is S.One or any( | |
isinstance(a, Number) or | |
a.is_Pow and all(ai.is_Integer for ai in a.args) | |
for a in args[1:]): | |
d, n = sift(args, lambda x: | |
isinstance(x, Pow) and bool(x.exp.as_coeff_Mul()[0] < 0), | |
binary=True) | |
for i, di in enumerate(d): | |
if di.exp.is_Number: | |
e = -di.exp | |
else: | |
dargs = list(di.exp.args) | |
dargs[0] = -dargs[0] | |
e = Mul._from_args(dargs) | |
d[i] = Pow(di.base, e, evaluate=False) if e - 1 else di.base | |
pre = [] | |
# don't parenthesize first factor if negative | |
if n and not n[0].is_Add and n[0].could_extract_minus_sign(): | |
pre = [self._print(n.pop(0))] | |
nfactors = pre + [self.parenthesize(a, prec, strict=False) | |
for a in n] | |
if not nfactors: | |
nfactors = ['1'] | |
# don't parenthesize first of denominator unless singleton | |
if len(d) > 1 and d[0].could_extract_minus_sign(): | |
pre = [self._print(d.pop(0))] | |
else: | |
pre = [] | |
dfactors = pre + [self.parenthesize(a, prec, strict=False) | |
for a in d] | |
n = '*'.join(nfactors) | |
d = '*'.join(dfactors) | |
if len(dfactors) > 1: | |
return '%s/(%s)' % (n, d) | |
elif dfactors: | |
return '%s/%s' % (n, d) | |
return n | |
c, e = expr.as_coeff_Mul() | |
if c < 0: | |
expr = _keep_coeff(-c, e) | |
sign = "-" | |
else: | |
sign = "" | |
a = [] # items in the numerator | |
b = [] # items that are in the denominator (if any) | |
pow_paren = [] # Will collect all pow with more than one base element and exp = -1 | |
if self.order not in ('old', 'none'): | |
args = expr.as_ordered_factors() | |
else: | |
# use make_args in case expr was something like -x -> x | |
args = Mul.make_args(expr) | |
# Gather args for numerator/denominator | |
def apow(i): | |
b, e = i.as_base_exp() | |
eargs = list(Mul.make_args(e)) | |
if eargs[0] is S.NegativeOne: | |
eargs = eargs[1:] | |
else: | |
eargs[0] = -eargs[0] | |
e = Mul._from_args(eargs) | |
if isinstance(i, Pow): | |
return i.func(b, e, evaluate=False) | |
return i.func(e, evaluate=False) | |
for item in args: | |
if (item.is_commutative and | |
isinstance(item, Pow) and | |
bool(item.exp.as_coeff_Mul()[0] < 0)): | |
if item.exp is not S.NegativeOne: | |
b.append(apow(item)) | |
else: | |
if (len(item.args[0].args) != 1 and | |
isinstance(item.base, (Mul, Pow))): | |
# To avoid situations like #14160 | |
pow_paren.append(item) | |
b.append(item.base) | |
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) | |
a = a or [S.One] | |
a_str = [self.parenthesize(x, prec, strict=False) for x in a] | |
b_str = [self.parenthesize(x, prec, strict=False) for x in b] | |
# To parenthesize Pow with exp = -1 and having more than one Symbol | |
for item in pow_paren: | |
if item.base in b: | |
b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)] | |
if not b: | |
return sign + '*'.join(a_str) | |
elif len(b) == 1: | |
return sign + '*'.join(a_str) + "/" + b_str[0] | |
else: | |
return sign + '*'.join(a_str) + "/(%s)" % '*'.join(b_str) | |
def _print_MatMul(self, expr): | |
c, m = expr.as_coeff_mmul() | |
sign = "" | |
if c.is_number: | |
re, im = c.as_real_imag() | |
if im.is_zero and re.is_negative: | |
expr = _keep_coeff(-c, m) | |
sign = "-" | |
elif re.is_zero and im.is_negative: | |
expr = _keep_coeff(-c, m) | |
sign = "-" | |
return sign + '*'.join( | |
[self.parenthesize(arg, precedence(expr)) for arg in expr.args] | |
) | |
def _print_ElementwiseApplyFunction(self, expr): | |
return "{}.({})".format( | |
expr.function, | |
self._print(expr.expr), | |
) | |
def _print_NaN(self, expr): | |
return 'nan' | |
def _print_NegativeInfinity(self, expr): | |
return '-oo' | |
def _print_Order(self, expr): | |
if not expr.variables or all(p is S.Zero for p in expr.point): | |
if len(expr.variables) <= 1: | |
return 'O(%s)' % self._print(expr.expr) | |
else: | |
return 'O(%s)' % self.stringify((expr.expr,) + expr.variables, ', ', 0) | |
else: | |
return 'O(%s)' % self.stringify(expr.args, ', ', 0) | |
def _print_Ordinal(self, expr): | |
return expr.__str__() | |
def _print_Cycle(self, expr): | |
return expr.__str__() | |
def _print_Permutation(self, expr): | |
from sympy.combinatorics.permutations import Permutation, Cycle | |
from sympy.utilities.exceptions import sympy_deprecation_warning | |
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: | |
if not expr.size: | |
return '()' | |
# before taking Cycle notation, see if the last element is | |
# a singleton and move it to the head of the string | |
s = Cycle(expr)(expr.size - 1).__repr__()[len('Cycle'):] | |
last = s.rfind('(') | |
if not last == 0 and ',' not in s[last:]: | |
s = s[last:] + s[:last] | |
s = s.replace(',', '') | |
return s | |
else: | |
s = expr.support() | |
if not s: | |
if expr.size < 5: | |
return 'Permutation(%s)' % self._print(expr.array_form) | |
return 'Permutation([], size=%s)' % self._print(expr.size) | |
trim = self._print(expr.array_form[:s[-1] + 1]) + ', size=%s' % self._print(expr.size) | |
use = full = self._print(expr.array_form) | |
if len(trim) < len(full): | |
use = trim | |
return 'Permutation(%s)' % use | |
def _print_Subs(self, obj): | |
expr, old, new = obj.args | |
if len(obj.point) == 1: | |
old = old[0] | |
new = new[0] | |
return "Subs(%s, %s, %s)" % ( | |
self._print(expr), self._print(old), self._print(new)) | |
def _print_TensorIndex(self, expr): | |
return expr._print() | |
def _print_TensorHead(self, expr): | |
return expr._print() | |
def _print_Tensor(self, expr): | |
return expr._print() | |
def _print_TensMul(self, expr): | |
# prints expressions like "A(a)", "3*A(a)", "(1+x)*A(a)" | |
sign, args = expr._get_args_for_traditional_printer() | |
return sign + "*".join( | |
[self.parenthesize(arg, precedence(expr)) for arg in args] | |
) | |
def _print_TensAdd(self, expr): | |
return expr._print() | |
def _print_ArraySymbol(self, expr): | |
return self._print(expr.name) | |
def _print_ArrayElement(self, expr): | |
return "%s[%s]" % ( | |
self.parenthesize(expr.name, PRECEDENCE["Func"], True), ", ".join([self._print(i) for i in expr.indices])) | |
def _print_PermutationGroup(self, expr): | |
p = [' %s' % self._print(a) for a in expr.args] | |
return 'PermutationGroup([\n%s])' % ',\n'.join(p) | |
def _print_Pi(self, expr): | |
return 'pi' | |
def _print_PolyRing(self, ring): | |
return "Polynomial ring in %s over %s with %s order" % \ | |
(", ".join((self._print(rs) for rs in ring.symbols)), | |
self._print(ring.domain), self._print(ring.order)) | |
def _print_FracField(self, field): | |
return "Rational function field in %s over %s with %s order" % \ | |
(", ".join((self._print(fs) for fs in field.symbols)), | |
self._print(field.domain), self._print(field.order)) | |
def _print_FreeGroupElement(self, elm): | |
return elm.__str__() | |
def _print_GaussianElement(self, poly): | |
return "(%s + %s*I)" % (poly.x, poly.y) | |
def _print_PolyElement(self, poly): | |
return poly.str(self, PRECEDENCE, "%s**%s", "*") | |
def _print_FracElement(self, frac): | |
if frac.denom == 1: | |
return self._print(frac.numer) | |
else: | |
numer = self.parenthesize(frac.numer, PRECEDENCE["Mul"], strict=True) | |
denom = self.parenthesize(frac.denom, PRECEDENCE["Atom"], strict=True) | |
return numer + "/" + denom | |
def _print_Poly(self, expr): | |
ATOM_PREC = PRECEDENCE["Atom"] - 1 | |
terms, gens = [], [ self.parenthesize(s, ATOM_PREC) for s in expr.gens ] | |
for monom, coeff in expr.terms(): | |
s_monom = [] | |
for i, e in enumerate(monom): | |
if e > 0: | |
if e == 1: | |
s_monom.append(gens[i]) | |
else: | |
s_monom.append(gens[i] + "**%d" % e) | |
s_monom = "*".join(s_monom) | |
if coeff.is_Add: | |
if s_monom: | |
s_coeff = "(" + self._print(coeff) + ")" | |
else: | |
s_coeff = self._print(coeff) | |
else: | |
if s_monom: | |
if coeff is S.One: | |
terms.extend(['+', s_monom]) | |
continue | |
if coeff is S.NegativeOne: | |
terms.extend(['-', s_monom]) | |
continue | |
s_coeff = self._print(coeff) | |
if not s_monom: | |
s_term = s_coeff | |
else: | |
s_term = s_coeff + "*" + s_monom | |
if s_term.startswith('-'): | |
terms.extend(['-', s_term[1:]]) | |
else: | |
terms.extend(['+', s_term]) | |
if terms[0] in ('-', '+'): | |
modifier = terms.pop(0) | |
if modifier == '-': | |
terms[0] = '-' + terms[0] | |
format = expr.__class__.__name__ + "(%s, %s" | |
from sympy.polys.polyerrors import PolynomialError | |
try: | |
format += ", modulus=%s" % expr.get_modulus() | |
except PolynomialError: | |
format += ", domain='%s'" % expr.get_domain() | |
format += ")" | |
for index, item in enumerate(gens): | |
if len(item) > 2 and (item[:1] == "(" and item[len(item) - 1:] == ")"): | |
gens[index] = item[1:len(item) - 1] | |
return format % (' '.join(terms), ', '.join(gens)) | |
def _print_UniversalSet(self, p): | |
return 'UniversalSet' | |
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_Pow(self, expr, rational=False): | |
"""Printing helper function for ``Pow`` | |
Parameters | |
========== | |
rational : bool, optional | |
If ``True``, it will not attempt printing ``sqrt(x)`` or | |
``x**S.Half`` as ``sqrt``, and will use ``x**(1/2)`` | |
instead. | |
See examples for additional details | |
Examples | |
======== | |
>>> from sympy import sqrt, StrPrinter | |
>>> from sympy.abc import x | |
How ``rational`` keyword works with ``sqrt``: | |
>>> printer = StrPrinter() | |
>>> printer._print_Pow(sqrt(x), rational=True) | |
'x**(1/2)' | |
>>> printer._print_Pow(sqrt(x), rational=False) | |
'sqrt(x)' | |
>>> printer._print_Pow(1/sqrt(x), rational=True) | |
'x**(-1/2)' | |
>>> printer._print_Pow(1/sqrt(x), rational=False) | |
'1/sqrt(x)' | |
Notes | |
===== | |
``sqrt(x)`` is canonicalized as ``Pow(x, S.Half)`` in SymPy, | |
so there is no need of defining a separate printer for ``sqrt``. | |
Instead, it should be handled here as well. | |
""" | |
PREC = precedence(expr) | |
if expr.exp is S.Half and not rational: | |
return "sqrt(%s)" % self._print(expr.base) | |
if expr.is_commutative: | |
if -expr.exp is S.Half and not rational: | |
# Note: Don't test "expr.exp == -S.Half" here, because that will | |
# match -0.5, which we don't want. | |
return "%s/sqrt(%s)" % tuple((self._print(arg) for arg in (S.One, expr.base))) | |
if expr.exp is -S.One: | |
# Similarly to the S.Half case, don't test with "==" here. | |
return '%s/%s' % (self._print(S.One), | |
self.parenthesize(expr.base, PREC, strict=False)) | |
e = self.parenthesize(expr.exp, PREC, strict=False) | |
if self.printmethod == '_sympyrepr' and expr.exp.is_Rational and expr.exp.q != 1: | |
# the parenthesized exp should be '(Rational(a, b))' so strip parens, | |
# but just check to be sure. | |
if e.startswith('(Rational'): | |
return '%s**%s' % (self.parenthesize(expr.base, PREC, strict=False), e[1:-1]) | |
return '%s**%s' % (self.parenthesize(expr.base, PREC, strict=False), e) | |
def _print_UnevaluatedExpr(self, expr): | |
return self._print(expr.args[0]) | |
def _print_MatPow(self, expr): | |
PREC = precedence(expr) | |
return '%s**%s' % (self.parenthesize(expr.base, PREC, strict=False), | |
self.parenthesize(expr.exp, PREC, strict=False)) | |
def _print_Integer(self, expr): | |
if self._settings.get("sympy_integers", False): | |
return "S(%s)" % (expr) | |
return str(expr.p) | |
def _print_Integers(self, expr): | |
return 'Integers' | |
def _print_Naturals(self, expr): | |
return 'Naturals' | |
def _print_Naturals0(self, expr): | |
return 'Naturals0' | |
def _print_Rationals(self, expr): | |
return 'Rationals' | |
def _print_Reals(self, expr): | |
return 'Reals' | |
def _print_Complexes(self, expr): | |
return 'Complexes' | |
def _print_EmptySet(self, expr): | |
return 'EmptySet' | |
def _print_EmptySequence(self, expr): | |
return 'EmptySequence' | |
def _print_int(self, expr): | |
return str(expr) | |
def _print_mpz(self, expr): | |
return str(expr) | |
def _print_Rational(self, expr): | |
if expr.q == 1: | |
return str(expr.p) | |
else: | |
if self._settings.get("sympy_integers", False): | |
return "S(%s)/%s" % (expr.p, expr.q) | |
return "%s/%s" % (expr.p, expr.q) | |
def _print_PythonRational(self, expr): | |
if expr.q == 1: | |
return str(expr.p) | |
else: | |
return "%d/%d" % (expr.p, expr.q) | |
def _print_Fraction(self, expr): | |
if expr.denominator == 1: | |
return str(expr.numerator) | |
else: | |
return "%s/%s" % (expr.numerator, expr.denominator) | |
def _print_mpq(self, expr): | |
if expr.denominator == 1: | |
return str(expr.numerator) | |
else: | |
return "%s/%s" % (expr.numerator, expr.denominator) | |
def _print_Float(self, expr): | |
prec = expr._prec | |
if prec < 5: | |
dps = 0 | |
else: | |
dps = prec_to_dps(expr._prec) | |
if self._settings["full_prec"] is True: | |
strip = False | |
elif self._settings["full_prec"] is False: | |
strip = True | |
elif self._settings["full_prec"] == "auto": | |
strip = self._print_level > 1 | |
low = self._settings["min"] if "min" in self._settings else None | |
high = self._settings["max"] if "max" in self._settings else None | |
rv = mlib_to_str(expr._mpf_, dps, strip_zeros=strip, min_fixed=low, max_fixed=high) | |
if rv.startswith('-.0'): | |
rv = '-0.' + rv[3:] | |
elif rv.startswith('.0'): | |
rv = '0.' + rv[2:] | |
if rv.startswith('+'): | |
# e.g., +inf -> inf | |
rv = rv[1:] | |
return rv | |
def _print_Relational(self, expr): | |
charmap = { | |
"==": "Eq", | |
"!=": "Ne", | |
":=": "Assignment", | |
'+=': "AddAugmentedAssignment", | |
"-=": "SubAugmentedAssignment", | |
"*=": "MulAugmentedAssignment", | |
"/=": "DivAugmentedAssignment", | |
"%=": "ModAugmentedAssignment", | |
} | |
if expr.rel_op in charmap: | |
return '%s(%s, %s)' % (charmap[expr.rel_op], self._print(expr.lhs), | |
self._print(expr.rhs)) | |
return '%s %s %s' % (self.parenthesize(expr.lhs, precedence(expr)), | |
self._relationals.get(expr.rel_op) or expr.rel_op, | |
self.parenthesize(expr.rhs, precedence(expr))) | |
def _print_ComplexRootOf(self, expr): | |
return "CRootOf(%s, %d)" % (self._print_Add(expr.expr, order='lex'), | |
expr.index) | |
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)) | |
return "RootSum(%s)" % ", ".join(args) | |
def _print_GroebnerBasis(self, basis): | |
cls = basis.__class__.__name__ | |
exprs = [self._print_Add(arg, order=basis.order) for arg in basis.exprs] | |
exprs = "[%s]" % ", ".join(exprs) | |
gens = [ self._print(gen) for gen in basis.gens ] | |
domain = "domain='%s'" % self._print(basis.domain) | |
order = "order='%s'" % self._print(basis.order) | |
args = [exprs] + gens + [domain, order] | |
return "%s(%s)" % (cls, ", ".join(args)) | |
def _print_set(self, s): | |
items = sorted(s, key=default_sort_key) | |
args = ', '.join(self._print(item) for item in items) | |
if not args: | |
return "set()" | |
return '{%s}' % args | |
def _print_FiniteSet(self, s): | |
from sympy.sets.sets import FiniteSet | |
items = sorted(s, key=default_sort_key) | |
args = ', '.join(self._print(item) for item in items) | |
if any(item.has(FiniteSet) for item in items): | |
return 'FiniteSet({})'.format(args) | |
return '{{{}}}'.format(args) | |
def _print_Partition(self, s): | |
items = sorted(s, key=default_sort_key) | |
args = ', '.join(self._print(arg) for arg in items) | |
return 'Partition({})'.format(args) | |
def _print_frozenset(self, s): | |
if not s: | |
return "frozenset()" | |
return "frozenset(%s)" % self._print_set(s) | |
def _print_Sum(self, expr): | |
def _xab_tostr(xab): | |
if len(xab) == 1: | |
return self._print(xab[0]) | |
else: | |
return self._print((xab[0],) + tuple(xab[1:])) | |
L = ', '.join([_xab_tostr(l) for l in expr.limits]) | |
return 'Sum(%s, %s)' % (self._print(expr.function), L) | |
def _print_Symbol(self, expr): | |
return expr.name | |
_print_MatrixSymbol = _print_Symbol | |
_print_RandomSymbol = _print_Symbol | |
def _print_Identity(self, expr): | |
return "I" | |
def _print_ZeroMatrix(self, expr): | |
return "0" | |
def _print_OneMatrix(self, expr): | |
return "1" | |
def _print_Predicate(self, expr): | |
return "Q.%s" % expr.name | |
def _print_str(self, expr): | |
return str(expr) | |
def _print_tuple(self, expr): | |
if len(expr) == 1: | |
return "(%s,)" % self._print(expr[0]) | |
else: | |
return "(%s)" % self.stringify(expr, ", ") | |
def _print_Tuple(self, expr): | |
return self._print_tuple(expr) | |
def _print_Transpose(self, T): | |
return "%s.T" % self.parenthesize(T.arg, PRECEDENCE["Pow"]) | |
def _print_Uniform(self, expr): | |
return "Uniform(%s, %s)" % (self._print(expr.a), self._print(expr.b)) | |
def _print_Quantity(self, expr): | |
if self._settings.get("abbrev", False): | |
return "%s" % expr.abbrev | |
return "%s" % expr.name | |
def _print_Quaternion(self, expr): | |
s = [self.parenthesize(i, PRECEDENCE["Mul"], strict=True) for i in expr.args] | |
a = [s[0]] + [i+"*"+j for i, j in zip(s[1:], "ijk")] | |
return " + ".join(a) | |
def _print_Dimension(self, expr): | |
return str(expr) | |
def _print_Wild(self, expr): | |
return expr.name + '_' | |
def _print_WildFunction(self, expr): | |
return expr.name + '_' | |
def _print_WildDot(self, expr): | |
return expr.name | |
def _print_WildPlus(self, expr): | |
return expr.name | |
def _print_WildStar(self, expr): | |
return expr.name | |
def _print_Zero(self, expr): | |
if self._settings.get("sympy_integers", False): | |
return "S(0)" | |
return self._print_Integer(Integer(0)) | |
def _print_DMP(self, p): | |
cls = p.__class__.__name__ | |
rep = self._print(p.to_list()) | |
dom = self._print(p.dom) | |
return "%s(%s, %s)" % (cls, rep, dom) | |
def _print_DMF(self, expr): | |
cls = expr.__class__.__name__ | |
num = self._print(expr.num) | |
den = self._print(expr.den) | |
dom = self._print(expr.dom) | |
return "%s(%s, %s, %s)" % (cls, num, den, dom) | |
def _print_Object(self, obj): | |
return 'Object("%s")' % obj.name | |
def _print_IdentityMorphism(self, morphism): | |
return 'IdentityMorphism(%s)' % morphism.domain | |
def _print_NamedMorphism(self, morphism): | |
return 'NamedMorphism(%s, %s, "%s")' % \ | |
(morphism.domain, morphism.codomain, morphism.name) | |
def _print_Category(self, category): | |
return 'Category("%s")' % category.name | |
def _print_Manifold(self, manifold): | |
return manifold.name.name | |
def _print_Patch(self, patch): | |
return patch.name.name | |
def _print_CoordSystem(self, coords): | |
return coords.name.name | |
def _print_BaseScalarField(self, field): | |
return field._coord_sys.symbols[field._index].name | |
def _print_BaseVectorField(self, field): | |
return 'e_%s' % field._coord_sys.symbols[field._index].name | |
def _print_Differential(self, diff): | |
field = diff._form_field | |
if hasattr(field, '_coord_sys'): | |
return 'd%s' % field._coord_sys.symbols[field._index].name | |
else: | |
return 'd(%s)' % self._print(field) | |
def _print_Tr(self, expr): | |
#TODO : Handle indices | |
return "%s(%s)" % ("Tr", self._print(expr.args[0])) | |
def _print_Str(self, s): | |
return self._print(s.name) | |
def _print_AppliedBinaryRelation(self, expr): | |
rel = expr.function | |
return '%s(%s, %s)' % (self._print(rel), | |
self._print(expr.lhs), | |
self._print(expr.rhs)) | |
def sstr(expr, **settings): | |
"""Returns the expression as a string. | |
For large expressions where speed is a concern, use the setting | |
order='none'. If abbrev=True setting is used then units are printed in | |
abbreviated form. | |
Examples | |
======== | |
>>> from sympy import symbols, Eq, sstr | |
>>> a, b = symbols('a b') | |
>>> sstr(Eq(a + b, 0)) | |
'Eq(a + b, 0)' | |
""" | |
p = StrPrinter(settings) | |
s = p.doprint(expr) | |
return s | |
class StrReprPrinter(StrPrinter): | |
"""(internal) -- see sstrrepr""" | |
def _print_str(self, s): | |
return repr(s) | |
def _print_Str(self, s): | |
# Str does not to be printed same as str here | |
return "%s(%s)" % (s.__class__.__name__, self._print(s.name)) | |
def sstrrepr(expr, **settings): | |
"""return expr in mixed str/repr form | |
i.e. strings are returned in repr form with quotes, and everything else | |
is returned in str form. | |
This function could be useful for hooking into sys.displayhook | |
""" | |
p = StrReprPrinter(settings) | |
s = p.doprint(expr) | |
return s | |