""" A Printer for generating readable representation of most SymPy classes. """ from typing import Any, Dict as tDict from sympy.core import S, Rational, Pow, Basic, Mul, Number from sympy.core.mul import _keep_coeff from sympy.core.relational import Relational from sympy.core.sorting import default_sort_key from sympy.core.sympify import SympifyError from sympy.sets.sets import FiniteSet 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 = { "order": None, "full_prec": "auto", "sympy_integers": False, "abbrev": False, "perm_cyclic": True, "min": None, "max": None, } # type: tDict[str, Any] _relationals = dict() # type: tDict[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('-'): sign = "-" t = t[1:] else: sign = "+" if precedence(term) < PREC: 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(map(lambda arg: self._print(arg), [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 if str(dir) == "+": return "Limit(%s, %s, %s)" % tuple(map(self._print, (e, z, z0))) else: 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(map(lambda arg: self._print(arg), 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 n[0].could_extract_minus_sign(): pre = [str(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 = [str(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(map(lambda rs: self._print(rs), 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(map(lambda fs: self._print(fs), 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(map(lambda arg: self._print(arg), (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): 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 "0" 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 cls = p.__class__.__name__ rep = self._print(p.rep) dom = self._print(p.dom) ring = self._print(p.ring) return "%s(%s, %s, %s)" % (cls, rep, dom, ring) def _print_DMF(self, expr): return self._print_DMP(expr) 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)) @print_function(StrPrinter) 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)) @print_function(StrReprPrinter) 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