Coverage for /usr/lib/python3/dist-packages/sympy/printing/str.py: 36%
636 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1"""
2A Printer for generating readable representation of most SymPy classes.
3"""
5from __future__ import annotations
6from typing import Any
8from sympy.core import S, Rational, Pow, Basic, Mul, Number
9from sympy.core.mul import _keep_coeff
10from sympy.core.relational import Relational
11from sympy.core.sorting import default_sort_key
12from sympy.core.sympify import SympifyError
13from sympy.utilities.iterables import sift
14from .precedence import precedence, PRECEDENCE
15from .printer import Printer, print_function
17from mpmath.libmp import prec_to_dps, to_str as mlib_to_str
20class StrPrinter(Printer):
21 printmethod = "_sympystr"
22 _default_settings: dict[str, Any] = {
23 "order": None,
24 "full_prec": "auto",
25 "sympy_integers": False,
26 "abbrev": False,
27 "perm_cyclic": True,
28 "min": None,
29 "max": None,
30 }
32 _relationals: dict[str, str] = {}
34 def parenthesize(self, item, level, strict=False):
35 if (precedence(item) < level) or ((not strict) and precedence(item) <= level):
36 return "(%s)" % self._print(item)
37 else:
38 return self._print(item)
40 def stringify(self, args, sep, level=0):
41 return sep.join([self.parenthesize(item, level) for item in args])
43 def emptyPrinter(self, expr):
44 if isinstance(expr, str):
45 return expr
46 elif isinstance(expr, Basic):
47 return repr(expr)
48 else:
49 return str(expr)
51 def _print_Add(self, expr, order=None):
52 terms = self._as_ordered_terms(expr, order=order)
54 prec = precedence(expr)
55 l = []
56 for term in terms:
57 t = self._print(term)
58 if t.startswith('-') and not term.is_Add:
59 sign = "-"
60 t = t[1:]
61 else:
62 sign = "+"
63 if precedence(term) < prec or term.is_Add:
64 l.extend([sign, "(%s)" % t])
65 else:
66 l.extend([sign, t])
67 sign = l.pop(0)
68 if sign == '+':
69 sign = ""
70 return sign + ' '.join(l)
72 def _print_BooleanTrue(self, expr):
73 return "True"
75 def _print_BooleanFalse(self, expr):
76 return "False"
78 def _print_Not(self, expr):
79 return '~%s' %(self.parenthesize(expr.args[0],PRECEDENCE["Not"]))
81 def _print_And(self, expr):
82 args = list(expr.args)
83 for j, i in enumerate(args):
84 if isinstance(i, Relational) and (
85 i.canonical.rhs is S.NegativeInfinity):
86 args.insert(0, args.pop(j))
87 return self.stringify(args, " & ", PRECEDENCE["BitwiseAnd"])
89 def _print_Or(self, expr):
90 return self.stringify(expr.args, " | ", PRECEDENCE["BitwiseOr"])
92 def _print_Xor(self, expr):
93 return self.stringify(expr.args, " ^ ", PRECEDENCE["BitwiseXor"])
95 def _print_AppliedPredicate(self, expr):
96 return '%s(%s)' % (
97 self._print(expr.function), self.stringify(expr.arguments, ", "))
99 def _print_Basic(self, expr):
100 l = [self._print(o) for o in expr.args]
101 return expr.__class__.__name__ + "(%s)" % ", ".join(l)
103 def _print_BlockMatrix(self, B):
104 if B.blocks.shape == (1, 1):
105 self._print(B.blocks[0, 0])
106 return self._print(B.blocks)
108 def _print_Catalan(self, expr):
109 return 'Catalan'
111 def _print_ComplexInfinity(self, expr):
112 return 'zoo'
114 def _print_ConditionSet(self, s):
115 args = tuple([self._print(i) for i in (s.sym, s.condition)])
116 if s.base_set is S.UniversalSet:
117 return 'ConditionSet(%s, %s)' % args
118 args += (self._print(s.base_set),)
119 return 'ConditionSet(%s, %s, %s)' % args
121 def _print_Derivative(self, expr):
122 dexpr = expr.expr
123 dvars = [i[0] if i[1] == 1 else i for i in expr.variable_count]
124 return 'Derivative(%s)' % ", ".join((self._print(arg) for arg in [dexpr] + dvars))
126 def _print_dict(self, d):
127 keys = sorted(d.keys(), key=default_sort_key)
128 items = []
130 for key in keys:
131 item = "%s: %s" % (self._print(key), self._print(d[key]))
132 items.append(item)
134 return "{%s}" % ", ".join(items)
136 def _print_Dict(self, expr):
137 return self._print_dict(expr)
139 def _print_RandomDomain(self, d):
140 if hasattr(d, 'as_boolean'):
141 return 'Domain: ' + self._print(d.as_boolean())
142 elif hasattr(d, 'set'):
143 return ('Domain: ' + self._print(d.symbols) + ' in ' +
144 self._print(d.set))
145 else:
146 return 'Domain on ' + self._print(d.symbols)
148 def _print_Dummy(self, expr):
149 return '_' + expr.name
151 def _print_EulerGamma(self, expr):
152 return 'EulerGamma'
154 def _print_Exp1(self, expr):
155 return 'E'
157 def _print_ExprCondPair(self, expr):
158 return '(%s, %s)' % (self._print(expr.expr), self._print(expr.cond))
160 def _print_Function(self, expr):
161 return expr.func.__name__ + "(%s)" % self.stringify(expr.args, ", ")
163 def _print_GoldenRatio(self, expr):
164 return 'GoldenRatio'
166 def _print_Heaviside(self, expr):
167 # Same as _print_Function but uses pargs to suppress default 1/2 for
168 # 2nd args
169 return expr.func.__name__ + "(%s)" % self.stringify(expr.pargs, ", ")
171 def _print_TribonacciConstant(self, expr):
172 return 'TribonacciConstant'
174 def _print_ImaginaryUnit(self, expr):
175 return 'I'
177 def _print_Infinity(self, expr):
178 return 'oo'
180 def _print_Integral(self, expr):
181 def _xab_tostr(xab):
182 if len(xab) == 1:
183 return self._print(xab[0])
184 else:
185 return self._print((xab[0],) + tuple(xab[1:]))
186 L = ', '.join([_xab_tostr(l) for l in expr.limits])
187 return 'Integral(%s, %s)' % (self._print(expr.function), L)
189 def _print_Interval(self, i):
190 fin = 'Interval{m}({a}, {b})'
191 a, b, l, r = i.args
192 if a.is_infinite and b.is_infinite:
193 m = ''
194 elif a.is_infinite and not r:
195 m = ''
196 elif b.is_infinite and not l:
197 m = ''
198 elif not l and not r:
199 m = ''
200 elif l and r:
201 m = '.open'
202 elif l:
203 m = '.Lopen'
204 else:
205 m = '.Ropen'
206 return fin.format(**{'a': a, 'b': b, 'm': m})
208 def _print_AccumulationBounds(self, i):
209 return "AccumBounds(%s, %s)" % (self._print(i.min),
210 self._print(i.max))
212 def _print_Inverse(self, I):
213 return "%s**(-1)" % self.parenthesize(I.arg, PRECEDENCE["Pow"])
215 def _print_Lambda(self, obj):
216 expr = obj.expr
217 sig = obj.signature
218 if len(sig) == 1 and sig[0].is_symbol:
219 sig = sig[0]
220 return "Lambda(%s, %s)" % (self._print(sig), self._print(expr))
222 def _print_LatticeOp(self, expr):
223 args = sorted(expr.args, key=default_sort_key)
224 return expr.func.__name__ + "(%s)" % ", ".join(self._print(arg) for arg in args)
226 def _print_Limit(self, expr):
227 e, z, z0, dir = expr.args
228 return "Limit(%s, %s, %s, dir='%s')" % tuple(map(self._print, (e, z, z0, dir)))
231 def _print_list(self, expr):
232 return "[%s]" % self.stringify(expr, ", ")
234 def _print_List(self, expr):
235 return self._print_list(expr)
237 def _print_MatrixBase(self, expr):
238 return expr._format_str(self)
240 def _print_MatrixElement(self, expr):
241 return self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) \
242 + '[%s, %s]' % (self._print(expr.i), self._print(expr.j))
244 def _print_MatrixSlice(self, expr):
245 def strslice(x, dim):
246 x = list(x)
247 if x[2] == 1:
248 del x[2]
249 if x[0] == 0:
250 x[0] = ''
251 if x[1] == dim:
252 x[1] = ''
253 return ':'.join((self._print(arg) for arg in x))
254 return (self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) + '[' +
255 strslice(expr.rowslice, expr.parent.rows) + ', ' +
256 strslice(expr.colslice, expr.parent.cols) + ']')
258 def _print_DeferredVector(self, expr):
259 return expr.name
261 def _print_Mul(self, expr):
263 prec = precedence(expr)
265 # Check for unevaluated Mul. In this case we need to make sure the
266 # identities are visible, multiple Rational factors are not combined
267 # etc so we display in a straight-forward form that fully preserves all
268 # args and their order.
269 args = expr.args
270 if args[0] is S.One or any(
271 isinstance(a, Number) or
272 a.is_Pow and all(ai.is_Integer for ai in a.args)
273 for a in args[1:]):
274 d, n = sift(args, lambda x:
275 isinstance(x, Pow) and bool(x.exp.as_coeff_Mul()[0] < 0),
276 binary=True)
277 for i, di in enumerate(d):
278 if di.exp.is_Number:
279 e = -di.exp
280 else:
281 dargs = list(di.exp.args)
282 dargs[0] = -dargs[0]
283 e = Mul._from_args(dargs)
284 d[i] = Pow(di.base, e, evaluate=False) if e - 1 else di.base
286 pre = []
287 # don't parenthesize first factor if negative
288 if n and not n[0].is_Add and n[0].could_extract_minus_sign():
289 pre = [self._print(n.pop(0))]
291 nfactors = pre + [self.parenthesize(a, prec, strict=False)
292 for a in n]
293 if not nfactors:
294 nfactors = ['1']
296 # don't parenthesize first of denominator unless singleton
297 if len(d) > 1 and d[0].could_extract_minus_sign():
298 pre = [self._print(d.pop(0))]
299 else:
300 pre = []
301 dfactors = pre + [self.parenthesize(a, prec, strict=False)
302 for a in d]
304 n = '*'.join(nfactors)
305 d = '*'.join(dfactors)
306 if len(dfactors) > 1:
307 return '%s/(%s)' % (n, d)
308 elif dfactors:
309 return '%s/%s' % (n, d)
310 return n
312 c, e = expr.as_coeff_Mul()
313 if c < 0:
314 expr = _keep_coeff(-c, e)
315 sign = "-"
316 else:
317 sign = ""
319 a = [] # items in the numerator
320 b = [] # items that are in the denominator (if any)
322 pow_paren = [] # Will collect all pow with more than one base element and exp = -1
324 if self.order not in ('old', 'none'):
325 args = expr.as_ordered_factors()
326 else:
327 # use make_args in case expr was something like -x -> x
328 args = Mul.make_args(expr)
330 # Gather args for numerator/denominator
331 def apow(i):
332 b, e = i.as_base_exp()
333 eargs = list(Mul.make_args(e))
334 if eargs[0] is S.NegativeOne:
335 eargs = eargs[1:]
336 else:
337 eargs[0] = -eargs[0]
338 e = Mul._from_args(eargs)
339 if isinstance(i, Pow):
340 return i.func(b, e, evaluate=False)
341 return i.func(e, evaluate=False)
342 for item in args:
343 if (item.is_commutative and
344 isinstance(item, Pow) and
345 bool(item.exp.as_coeff_Mul()[0] < 0)):
346 if item.exp is not S.NegativeOne:
347 b.append(apow(item))
348 else:
349 if (len(item.args[0].args) != 1 and
350 isinstance(item.base, (Mul, Pow))):
351 # To avoid situations like #14160
352 pow_paren.append(item)
353 b.append(item.base)
354 elif item.is_Rational and item is not S.Infinity:
355 if item.p != 1:
356 a.append(Rational(item.p))
357 if item.q != 1:
358 b.append(Rational(item.q))
359 else:
360 a.append(item)
362 a = a or [S.One]
364 a_str = [self.parenthesize(x, prec, strict=False) for x in a]
365 b_str = [self.parenthesize(x, prec, strict=False) for x in b]
367 # To parenthesize Pow with exp = -1 and having more than one Symbol
368 for item in pow_paren:
369 if item.base in b:
370 b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)]
372 if not b:
373 return sign + '*'.join(a_str)
374 elif len(b) == 1:
375 return sign + '*'.join(a_str) + "/" + b_str[0]
376 else:
377 return sign + '*'.join(a_str) + "/(%s)" % '*'.join(b_str)
379 def _print_MatMul(self, expr):
380 c, m = expr.as_coeff_mmul()
382 sign = ""
383 if c.is_number:
384 re, im = c.as_real_imag()
385 if im.is_zero and re.is_negative:
386 expr = _keep_coeff(-c, m)
387 sign = "-"
388 elif re.is_zero and im.is_negative:
389 expr = _keep_coeff(-c, m)
390 sign = "-"
392 return sign + '*'.join(
393 [self.parenthesize(arg, precedence(expr)) for arg in expr.args]
394 )
396 def _print_ElementwiseApplyFunction(self, expr):
397 return "{}.({})".format(
398 expr.function,
399 self._print(expr.expr),
400 )
402 def _print_NaN(self, expr):
403 return 'nan'
405 def _print_NegativeInfinity(self, expr):
406 return '-oo'
408 def _print_Order(self, expr):
409 if not expr.variables or all(p is S.Zero for p in expr.point):
410 if len(expr.variables) <= 1:
411 return 'O(%s)' % self._print(expr.expr)
412 else:
413 return 'O(%s)' % self.stringify((expr.expr,) + expr.variables, ', ', 0)
414 else:
415 return 'O(%s)' % self.stringify(expr.args, ', ', 0)
417 def _print_Ordinal(self, expr):
418 return expr.__str__()
420 def _print_Cycle(self, expr):
421 return expr.__str__()
423 def _print_Permutation(self, expr):
424 from sympy.combinatorics.permutations import Permutation, Cycle
425 from sympy.utilities.exceptions import sympy_deprecation_warning
427 perm_cyclic = Permutation.print_cyclic
428 if perm_cyclic is not None:
429 sympy_deprecation_warning(
430 f"""
431 Setting Permutation.print_cyclic is deprecated. Instead use
432 init_printing(perm_cyclic={perm_cyclic}).
433 """,
434 deprecated_since_version="1.6",
435 active_deprecations_target="deprecated-permutation-print_cyclic",
436 stacklevel=7,
437 )
438 else:
439 perm_cyclic = self._settings.get("perm_cyclic", True)
441 if perm_cyclic:
442 if not expr.size:
443 return '()'
444 # before taking Cycle notation, see if the last element is
445 # a singleton and move it to the head of the string
446 s = Cycle(expr)(expr.size - 1).__repr__()[len('Cycle'):]
447 last = s.rfind('(')
448 if not last == 0 and ',' not in s[last:]:
449 s = s[last:] + s[:last]
450 s = s.replace(',', '')
451 return s
452 else:
453 s = expr.support()
454 if not s:
455 if expr.size < 5:
456 return 'Permutation(%s)' % self._print(expr.array_form)
457 return 'Permutation([], size=%s)' % self._print(expr.size)
458 trim = self._print(expr.array_form[:s[-1] + 1]) + ', size=%s' % self._print(expr.size)
459 use = full = self._print(expr.array_form)
460 if len(trim) < len(full):
461 use = trim
462 return 'Permutation(%s)' % use
464 def _print_Subs(self, obj):
465 expr, old, new = obj.args
466 if len(obj.point) == 1:
467 old = old[0]
468 new = new[0]
469 return "Subs(%s, %s, %s)" % (
470 self._print(expr), self._print(old), self._print(new))
472 def _print_TensorIndex(self, expr):
473 return expr._print()
475 def _print_TensorHead(self, expr):
476 return expr._print()
478 def _print_Tensor(self, expr):
479 return expr._print()
481 def _print_TensMul(self, expr):
482 # prints expressions like "A(a)", "3*A(a)", "(1+x)*A(a)"
483 sign, args = expr._get_args_for_traditional_printer()
484 return sign + "*".join(
485 [self.parenthesize(arg, precedence(expr)) for arg in args]
486 )
488 def _print_TensAdd(self, expr):
489 return expr._print()
491 def _print_ArraySymbol(self, expr):
492 return self._print(expr.name)
494 def _print_ArrayElement(self, expr):
495 return "%s[%s]" % (
496 self.parenthesize(expr.name, PRECEDENCE["Func"], True), ", ".join([self._print(i) for i in expr.indices]))
498 def _print_PermutationGroup(self, expr):
499 p = [' %s' % self._print(a) for a in expr.args]
500 return 'PermutationGroup([\n%s])' % ',\n'.join(p)
502 def _print_Pi(self, expr):
503 return 'pi'
505 def _print_PolyRing(self, ring):
506 return "Polynomial ring in %s over %s with %s order" % \
507 (", ".join((self._print(rs) for rs in ring.symbols)),
508 self._print(ring.domain), self._print(ring.order))
510 def _print_FracField(self, field):
511 return "Rational function field in %s over %s with %s order" % \
512 (", ".join((self._print(fs) for fs in field.symbols)),
513 self._print(field.domain), self._print(field.order))
515 def _print_FreeGroupElement(self, elm):
516 return elm.__str__()
518 def _print_GaussianElement(self, poly):
519 return "(%s + %s*I)" % (poly.x, poly.y)
521 def _print_PolyElement(self, poly):
522 return poly.str(self, PRECEDENCE, "%s**%s", "*")
524 def _print_FracElement(self, frac):
525 if frac.denom == 1:
526 return self._print(frac.numer)
527 else:
528 numer = self.parenthesize(frac.numer, PRECEDENCE["Mul"], strict=True)
529 denom = self.parenthesize(frac.denom, PRECEDENCE["Atom"], strict=True)
530 return numer + "/" + denom
532 def _print_Poly(self, expr):
533 ATOM_PREC = PRECEDENCE["Atom"] - 1
534 terms, gens = [], [ self.parenthesize(s, ATOM_PREC) for s in expr.gens ]
536 for monom, coeff in expr.terms():
537 s_monom = []
539 for i, e in enumerate(monom):
540 if e > 0:
541 if e == 1:
542 s_monom.append(gens[i])
543 else:
544 s_monom.append(gens[i] + "**%d" % e)
546 s_monom = "*".join(s_monom)
548 if coeff.is_Add:
549 if s_monom:
550 s_coeff = "(" + self._print(coeff) + ")"
551 else:
552 s_coeff = self._print(coeff)
553 else:
554 if s_monom:
555 if coeff is S.One:
556 terms.extend(['+', s_monom])
557 continue
559 if coeff is S.NegativeOne:
560 terms.extend(['-', s_monom])
561 continue
563 s_coeff = self._print(coeff)
565 if not s_monom:
566 s_term = s_coeff
567 else:
568 s_term = s_coeff + "*" + s_monom
570 if s_term.startswith('-'):
571 terms.extend(['-', s_term[1:]])
572 else:
573 terms.extend(['+', s_term])
575 if terms[0] in ('-', '+'):
576 modifier = terms.pop(0)
578 if modifier == '-':
579 terms[0] = '-' + terms[0]
581 format = expr.__class__.__name__ + "(%s, %s"
583 from sympy.polys.polyerrors import PolynomialError
585 try:
586 format += ", modulus=%s" % expr.get_modulus()
587 except PolynomialError:
588 format += ", domain='%s'" % expr.get_domain()
590 format += ")"
592 for index, item in enumerate(gens):
593 if len(item) > 2 and (item[:1] == "(" and item[len(item) - 1:] == ")"):
594 gens[index] = item[1:len(item) - 1]
596 return format % (' '.join(terms), ', '.join(gens))
598 def _print_UniversalSet(self, p):
599 return 'UniversalSet'
601 def _print_AlgebraicNumber(self, expr):
602 if expr.is_aliased:
603 return self._print(expr.as_poly().as_expr())
604 else:
605 return self._print(expr.as_expr())
607 def _print_Pow(self, expr, rational=False):
608 """Printing helper function for ``Pow``
610 Parameters
611 ==========
613 rational : bool, optional
614 If ``True``, it will not attempt printing ``sqrt(x)`` or
615 ``x**S.Half`` as ``sqrt``, and will use ``x**(1/2)``
616 instead.
618 See examples for additional details
620 Examples
621 ========
623 >>> from sympy import sqrt, StrPrinter
624 >>> from sympy.abc import x
626 How ``rational`` keyword works with ``sqrt``:
628 >>> printer = StrPrinter()
629 >>> printer._print_Pow(sqrt(x), rational=True)
630 'x**(1/2)'
631 >>> printer._print_Pow(sqrt(x), rational=False)
632 'sqrt(x)'
633 >>> printer._print_Pow(1/sqrt(x), rational=True)
634 'x**(-1/2)'
635 >>> printer._print_Pow(1/sqrt(x), rational=False)
636 '1/sqrt(x)'
638 Notes
639 =====
641 ``sqrt(x)`` is canonicalized as ``Pow(x, S.Half)`` in SymPy,
642 so there is no need of defining a separate printer for ``sqrt``.
643 Instead, it should be handled here as well.
644 """
645 PREC = precedence(expr)
647 if expr.exp is S.Half and not rational:
648 return "sqrt(%s)" % self._print(expr.base)
650 if expr.is_commutative:
651 if -expr.exp is S.Half and not rational:
652 # Note: Don't test "expr.exp == -S.Half" here, because that will
653 # match -0.5, which we don't want.
654 return "%s/sqrt(%s)" % tuple((self._print(arg) for arg in (S.One, expr.base)))
655 if expr.exp is -S.One:
656 # Similarly to the S.Half case, don't test with "==" here.
657 return '%s/%s' % (self._print(S.One),
658 self.parenthesize(expr.base, PREC, strict=False))
660 e = self.parenthesize(expr.exp, PREC, strict=False)
661 if self.printmethod == '_sympyrepr' and expr.exp.is_Rational and expr.exp.q != 1:
662 # the parenthesized exp should be '(Rational(a, b))' so strip parens,
663 # but just check to be sure.
664 if e.startswith('(Rational'):
665 return '%s**%s' % (self.parenthesize(expr.base, PREC, strict=False), e[1:-1])
666 return '%s**%s' % (self.parenthesize(expr.base, PREC, strict=False), e)
668 def _print_UnevaluatedExpr(self, expr):
669 return self._print(expr.args[0])
671 def _print_MatPow(self, expr):
672 PREC = precedence(expr)
673 return '%s**%s' % (self.parenthesize(expr.base, PREC, strict=False),
674 self.parenthesize(expr.exp, PREC, strict=False))
676 def _print_Integer(self, expr):
677 if self._settings.get("sympy_integers", False):
678 return "S(%s)" % (expr)
679 return str(expr.p)
681 def _print_Integers(self, expr):
682 return 'Integers'
684 def _print_Naturals(self, expr):
685 return 'Naturals'
687 def _print_Naturals0(self, expr):
688 return 'Naturals0'
690 def _print_Rationals(self, expr):
691 return 'Rationals'
693 def _print_Reals(self, expr):
694 return 'Reals'
696 def _print_Complexes(self, expr):
697 return 'Complexes'
699 def _print_EmptySet(self, expr):
700 return 'EmptySet'
702 def _print_EmptySequence(self, expr):
703 return 'EmptySequence'
705 def _print_int(self, expr):
706 return str(expr)
708 def _print_mpz(self, expr):
709 return str(expr)
711 def _print_Rational(self, expr):
712 if expr.q == 1:
713 return str(expr.p)
714 else:
715 if self._settings.get("sympy_integers", False):
716 return "S(%s)/%s" % (expr.p, expr.q)
717 return "%s/%s" % (expr.p, expr.q)
719 def _print_PythonRational(self, expr):
720 if expr.q == 1:
721 return str(expr.p)
722 else:
723 return "%d/%d" % (expr.p, expr.q)
725 def _print_Fraction(self, expr):
726 if expr.denominator == 1:
727 return str(expr.numerator)
728 else:
729 return "%s/%s" % (expr.numerator, expr.denominator)
731 def _print_mpq(self, expr):
732 if expr.denominator == 1:
733 return str(expr.numerator)
734 else:
735 return "%s/%s" % (expr.numerator, expr.denominator)
737 def _print_Float(self, expr):
738 prec = expr._prec
739 if prec < 5:
740 dps = 0
741 else:
742 dps = prec_to_dps(expr._prec)
743 if self._settings["full_prec"] is True:
744 strip = False
745 elif self._settings["full_prec"] is False:
746 strip = True
747 elif self._settings["full_prec"] == "auto":
748 strip = self._print_level > 1
749 low = self._settings["min"] if "min" in self._settings else None
750 high = self._settings["max"] if "max" in self._settings else None
751 rv = mlib_to_str(expr._mpf_, dps, strip_zeros=strip, min_fixed=low, max_fixed=high)
752 if rv.startswith('-.0'):
753 rv = '-0.' + rv[3:]
754 elif rv.startswith('.0'):
755 rv = '0.' + rv[2:]
756 if rv.startswith('+'):
757 # e.g., +inf -> inf
758 rv = rv[1:]
759 return rv
761 def _print_Relational(self, expr):
763 charmap = {
764 "==": "Eq",
765 "!=": "Ne",
766 ":=": "Assignment",
767 '+=': "AddAugmentedAssignment",
768 "-=": "SubAugmentedAssignment",
769 "*=": "MulAugmentedAssignment",
770 "/=": "DivAugmentedAssignment",
771 "%=": "ModAugmentedAssignment",
772 }
774 if expr.rel_op in charmap:
775 return '%s(%s, %s)' % (charmap[expr.rel_op], self._print(expr.lhs),
776 self._print(expr.rhs))
778 return '%s %s %s' % (self.parenthesize(expr.lhs, precedence(expr)),
779 self._relationals.get(expr.rel_op) or expr.rel_op,
780 self.parenthesize(expr.rhs, precedence(expr)))
782 def _print_ComplexRootOf(self, expr):
783 return "CRootOf(%s, %d)" % (self._print_Add(expr.expr, order='lex'),
784 expr.index)
786 def _print_RootSum(self, expr):
787 args = [self._print_Add(expr.expr, order='lex')]
789 if expr.fun is not S.IdentityFunction:
790 args.append(self._print(expr.fun))
792 return "RootSum(%s)" % ", ".join(args)
794 def _print_GroebnerBasis(self, basis):
795 cls = basis.__class__.__name__
797 exprs = [self._print_Add(arg, order=basis.order) for arg in basis.exprs]
798 exprs = "[%s]" % ", ".join(exprs)
800 gens = [ self._print(gen) for gen in basis.gens ]
801 domain = "domain='%s'" % self._print(basis.domain)
802 order = "order='%s'" % self._print(basis.order)
804 args = [exprs] + gens + [domain, order]
806 return "%s(%s)" % (cls, ", ".join(args))
808 def _print_set(self, s):
809 items = sorted(s, key=default_sort_key)
811 args = ', '.join(self._print(item) for item in items)
812 if not args:
813 return "set()"
814 return '{%s}' % args
816 def _print_FiniteSet(self, s):
817 from sympy.sets.sets import FiniteSet
818 items = sorted(s, key=default_sort_key)
820 args = ', '.join(self._print(item) for item in items)
821 if any(item.has(FiniteSet) for item in items):
822 return 'FiniteSet({})'.format(args)
823 return '{{{}}}'.format(args)
825 def _print_Partition(self, s):
826 items = sorted(s, key=default_sort_key)
828 args = ', '.join(self._print(arg) for arg in items)
829 return 'Partition({})'.format(args)
831 def _print_frozenset(self, s):
832 if not s:
833 return "frozenset()"
834 return "frozenset(%s)" % self._print_set(s)
836 def _print_Sum(self, expr):
837 def _xab_tostr(xab):
838 if len(xab) == 1:
839 return self._print(xab[0])
840 else:
841 return self._print((xab[0],) + tuple(xab[1:]))
842 L = ', '.join([_xab_tostr(l) for l in expr.limits])
843 return 'Sum(%s, %s)' % (self._print(expr.function), L)
845 def _print_Symbol(self, expr):
846 return expr.name
847 _print_MatrixSymbol = _print_Symbol
848 _print_RandomSymbol = _print_Symbol
850 def _print_Identity(self, expr):
851 return "I"
853 def _print_ZeroMatrix(self, expr):
854 return "0"
856 def _print_OneMatrix(self, expr):
857 return "1"
859 def _print_Predicate(self, expr):
860 return "Q.%s" % expr.name
862 def _print_str(self, expr):
863 return str(expr)
865 def _print_tuple(self, expr):
866 if len(expr) == 1:
867 return "(%s,)" % self._print(expr[0])
868 else:
869 return "(%s)" % self.stringify(expr, ", ")
871 def _print_Tuple(self, expr):
872 return self._print_tuple(expr)
874 def _print_Transpose(self, T):
875 return "%s.T" % self.parenthesize(T.arg, PRECEDENCE["Pow"])
877 def _print_Uniform(self, expr):
878 return "Uniform(%s, %s)" % (self._print(expr.a), self._print(expr.b))
880 def _print_Quantity(self, expr):
881 if self._settings.get("abbrev", False):
882 return "%s" % expr.abbrev
883 return "%s" % expr.name
885 def _print_Quaternion(self, expr):
886 s = [self.parenthesize(i, PRECEDENCE["Mul"], strict=True) for i in expr.args]
887 a = [s[0]] + [i+"*"+j for i, j in zip(s[1:], "ijk")]
888 return " + ".join(a)
890 def _print_Dimension(self, expr):
891 return str(expr)
893 def _print_Wild(self, expr):
894 return expr.name + '_'
896 def _print_WildFunction(self, expr):
897 return expr.name + '_'
899 def _print_WildDot(self, expr):
900 return expr.name
902 def _print_WildPlus(self, expr):
903 return expr.name
905 def _print_WildStar(self, expr):
906 return expr.name
908 def _print_Zero(self, expr):
909 if self._settings.get("sympy_integers", False):
910 return "S(0)"
911 return "0"
913 def _print_DMP(self, p):
914 try:
915 if p.ring is not None:
916 # TODO incorporate order
917 return self._print(p.ring.to_sympy(p))
918 except SympifyError:
919 pass
921 cls = p.__class__.__name__
922 rep = self._print(p.rep)
923 dom = self._print(p.dom)
924 ring = self._print(p.ring)
926 return "%s(%s, %s, %s)" % (cls, rep, dom, ring)
928 def _print_DMF(self, expr):
929 return self._print_DMP(expr)
931 def _print_Object(self, obj):
932 return 'Object("%s")' % obj.name
934 def _print_IdentityMorphism(self, morphism):
935 return 'IdentityMorphism(%s)' % morphism.domain
937 def _print_NamedMorphism(self, morphism):
938 return 'NamedMorphism(%s, %s, "%s")' % \
939 (morphism.domain, morphism.codomain, morphism.name)
941 def _print_Category(self, category):
942 return 'Category("%s")' % category.name
944 def _print_Manifold(self, manifold):
945 return manifold.name.name
947 def _print_Patch(self, patch):
948 return patch.name.name
950 def _print_CoordSystem(self, coords):
951 return coords.name.name
953 def _print_BaseScalarField(self, field):
954 return field._coord_sys.symbols[field._index].name
956 def _print_BaseVectorField(self, field):
957 return 'e_%s' % field._coord_sys.symbols[field._index].name
959 def _print_Differential(self, diff):
960 field = diff._form_field
961 if hasattr(field, '_coord_sys'):
962 return 'd%s' % field._coord_sys.symbols[field._index].name
963 else:
964 return 'd(%s)' % self._print(field)
966 def _print_Tr(self, expr):
967 #TODO : Handle indices
968 return "%s(%s)" % ("Tr", self._print(expr.args[0]))
970 def _print_Str(self, s):
971 return self._print(s.name)
973 def _print_AppliedBinaryRelation(self, expr):
974 rel = expr.function
975 return '%s(%s, %s)' % (self._print(rel),
976 self._print(expr.lhs),
977 self._print(expr.rhs))
980@print_function(StrPrinter)
981def sstr(expr, **settings):
982 """Returns the expression as a string.
984 For large expressions where speed is a concern, use the setting
985 order='none'. If abbrev=True setting is used then units are printed in
986 abbreviated form.
988 Examples
989 ========
991 >>> from sympy import symbols, Eq, sstr
992 >>> a, b = symbols('a b')
993 >>> sstr(Eq(a + b, 0))
994 'Eq(a + b, 0)'
995 """
997 p = StrPrinter(settings)
998 s = p.doprint(expr)
1000 return s
1003class StrReprPrinter(StrPrinter):
1004 """(internal) -- see sstrrepr"""
1006 def _print_str(self, s):
1007 return repr(s)
1009 def _print_Str(self, s):
1010 # Str does not to be printed same as str here
1011 return "%s(%s)" % (s.__class__.__name__, self._print(s.name))
1014@print_function(StrReprPrinter)
1015def sstrrepr(expr, **settings):
1016 """return expr in mixed str/repr form
1018 i.e. strings are returned in repr form with quotes, and everything else
1019 is returned in str form.
1021 This function could be useful for hooking into sys.displayhook
1022 """
1024 p = StrReprPrinter(settings)
1025 s = p.doprint(expr)
1027 return s