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