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

1""" 

2A Printer for generating readable representation of most SymPy classes. 

3""" 

4 

5from __future__ import annotations 

6from typing import Any 

7 

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 

16 

17from mpmath.libmp import prec_to_dps, to_str as mlib_to_str 

18 

19 

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 } 

31 

32 _relationals: dict[str, str] = {} 

33 

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) 

39 

40 def stringify(self, args, sep, level=0): 

41 return sep.join([self.parenthesize(item, level) for item in args]) 

42 

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) 

50 

51 def _print_Add(self, expr, order=None): 

52 terms = self._as_ordered_terms(expr, order=order) 

53 

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) 

71 

72 def _print_BooleanTrue(self, expr): 

73 return "True" 

74 

75 def _print_BooleanFalse(self, expr): 

76 return "False" 

77 

78 def _print_Not(self, expr): 

79 return '~%s' %(self.parenthesize(expr.args[0],PRECEDENCE["Not"])) 

80 

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"]) 

88 

89 def _print_Or(self, expr): 

90 return self.stringify(expr.args, " | ", PRECEDENCE["BitwiseOr"]) 

91 

92 def _print_Xor(self, expr): 

93 return self.stringify(expr.args, " ^ ", PRECEDENCE["BitwiseXor"]) 

94 

95 def _print_AppliedPredicate(self, expr): 

96 return '%s(%s)' % ( 

97 self._print(expr.function), self.stringify(expr.arguments, ", ")) 

98 

99 def _print_Basic(self, expr): 

100 l = [self._print(o) for o in expr.args] 

101 return expr.__class__.__name__ + "(%s)" % ", ".join(l) 

102 

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) 

107 

108 def _print_Catalan(self, expr): 

109 return 'Catalan' 

110 

111 def _print_ComplexInfinity(self, expr): 

112 return 'zoo' 

113 

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 

120 

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)) 

125 

126 def _print_dict(self, d): 

127 keys = sorted(d.keys(), key=default_sort_key) 

128 items = [] 

129 

130 for key in keys: 

131 item = "%s: %s" % (self._print(key), self._print(d[key])) 

132 items.append(item) 

133 

134 return "{%s}" % ", ".join(items) 

135 

136 def _print_Dict(self, expr): 

137 return self._print_dict(expr) 

138 

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) 

147 

148 def _print_Dummy(self, expr): 

149 return '_' + expr.name 

150 

151 def _print_EulerGamma(self, expr): 

152 return 'EulerGamma' 

153 

154 def _print_Exp1(self, expr): 

155 return 'E' 

156 

157 def _print_ExprCondPair(self, expr): 

158 return '(%s, %s)' % (self._print(expr.expr), self._print(expr.cond)) 

159 

160 def _print_Function(self, expr): 

161 return expr.func.__name__ + "(%s)" % self.stringify(expr.args, ", ") 

162 

163 def _print_GoldenRatio(self, expr): 

164 return 'GoldenRatio' 

165 

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, ", ") 

170 

171 def _print_TribonacciConstant(self, expr): 

172 return 'TribonacciConstant' 

173 

174 def _print_ImaginaryUnit(self, expr): 

175 return 'I' 

176 

177 def _print_Infinity(self, expr): 

178 return 'oo' 

179 

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) 

188 

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}) 

207 

208 def _print_AccumulationBounds(self, i): 

209 return "AccumBounds(%s, %s)" % (self._print(i.min), 

210 self._print(i.max)) 

211 

212 def _print_Inverse(self, I): 

213 return "%s**(-1)" % self.parenthesize(I.arg, PRECEDENCE["Pow"]) 

214 

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)) 

221 

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) 

225 

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))) 

229 

230 

231 def _print_list(self, expr): 

232 return "[%s]" % self.stringify(expr, ", ") 

233 

234 def _print_List(self, expr): 

235 return self._print_list(expr) 

236 

237 def _print_MatrixBase(self, expr): 

238 return expr._format_str(self) 

239 

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)) 

243 

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) + ']') 

257 

258 def _print_DeferredVector(self, expr): 

259 return expr.name 

260 

261 def _print_Mul(self, expr): 

262 

263 prec = precedence(expr) 

264 

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 

285 

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))] 

290 

291 nfactors = pre + [self.parenthesize(a, prec, strict=False) 

292 for a in n] 

293 if not nfactors: 

294 nfactors = ['1'] 

295 

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] 

303 

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 

311 

312 c, e = expr.as_coeff_Mul() 

313 if c < 0: 

314 expr = _keep_coeff(-c, e) 

315 sign = "-" 

316 else: 

317 sign = "" 

318 

319 a = [] # items in the numerator 

320 b = [] # items that are in the denominator (if any) 

321 

322 pow_paren = [] # Will collect all pow with more than one base element and exp = -1 

323 

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) 

329 

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) 

361 

362 a = a or [S.One] 

363 

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] 

366 

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)] 

371 

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) 

378 

379 def _print_MatMul(self, expr): 

380 c, m = expr.as_coeff_mmul() 

381 

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 = "-" 

391 

392 return sign + '*'.join( 

393 [self.parenthesize(arg, precedence(expr)) for arg in expr.args] 

394 ) 

395 

396 def _print_ElementwiseApplyFunction(self, expr): 

397 return "{}.({})".format( 

398 expr.function, 

399 self._print(expr.expr), 

400 ) 

401 

402 def _print_NaN(self, expr): 

403 return 'nan' 

404 

405 def _print_NegativeInfinity(self, expr): 

406 return '-oo' 

407 

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) 

416 

417 def _print_Ordinal(self, expr): 

418 return expr.__str__() 

419 

420 def _print_Cycle(self, expr): 

421 return expr.__str__() 

422 

423 def _print_Permutation(self, expr): 

424 from sympy.combinatorics.permutations import Permutation, Cycle 

425 from sympy.utilities.exceptions import sympy_deprecation_warning 

426 

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) 

440 

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 

463 

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)) 

471 

472 def _print_TensorIndex(self, expr): 

473 return expr._print() 

474 

475 def _print_TensorHead(self, expr): 

476 return expr._print() 

477 

478 def _print_Tensor(self, expr): 

479 return expr._print() 

480 

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 ) 

487 

488 def _print_TensAdd(self, expr): 

489 return expr._print() 

490 

491 def _print_ArraySymbol(self, expr): 

492 return self._print(expr.name) 

493 

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])) 

497 

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) 

501 

502 def _print_Pi(self, expr): 

503 return 'pi' 

504 

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)) 

509 

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)) 

514 

515 def _print_FreeGroupElement(self, elm): 

516 return elm.__str__() 

517 

518 def _print_GaussianElement(self, poly): 

519 return "(%s + %s*I)" % (poly.x, poly.y) 

520 

521 def _print_PolyElement(self, poly): 

522 return poly.str(self, PRECEDENCE, "%s**%s", "*") 

523 

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 

531 

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 ] 

535 

536 for monom, coeff in expr.terms(): 

537 s_monom = [] 

538 

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) 

545 

546 s_monom = "*".join(s_monom) 

547 

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 

558 

559 if coeff is S.NegativeOne: 

560 terms.extend(['-', s_monom]) 

561 continue 

562 

563 s_coeff = self._print(coeff) 

564 

565 if not s_monom: 

566 s_term = s_coeff 

567 else: 

568 s_term = s_coeff + "*" + s_monom 

569 

570 if s_term.startswith('-'): 

571 terms.extend(['-', s_term[1:]]) 

572 else: 

573 terms.extend(['+', s_term]) 

574 

575 if terms[0] in ('-', '+'): 

576 modifier = terms.pop(0) 

577 

578 if modifier == '-': 

579 terms[0] = '-' + terms[0] 

580 

581 format = expr.__class__.__name__ + "(%s, %s" 

582 

583 from sympy.polys.polyerrors import PolynomialError 

584 

585 try: 

586 format += ", modulus=%s" % expr.get_modulus() 

587 except PolynomialError: 

588 format += ", domain='%s'" % expr.get_domain() 

589 

590 format += ")" 

591 

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] 

595 

596 return format % (' '.join(terms), ', '.join(gens)) 

597 

598 def _print_UniversalSet(self, p): 

599 return 'UniversalSet' 

600 

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()) 

606 

607 def _print_Pow(self, expr, rational=False): 

608 """Printing helper function for ``Pow`` 

609 

610 Parameters 

611 ========== 

612 

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. 

617 

618 See examples for additional details 

619 

620 Examples 

621 ======== 

622 

623 >>> from sympy import sqrt, StrPrinter 

624 >>> from sympy.abc import x 

625 

626 How ``rational`` keyword works with ``sqrt``: 

627 

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)' 

637 

638 Notes 

639 ===== 

640 

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) 

646 

647 if expr.exp is S.Half and not rational: 

648 return "sqrt(%s)" % self._print(expr.base) 

649 

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)) 

659 

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) 

667 

668 def _print_UnevaluatedExpr(self, expr): 

669 return self._print(expr.args[0]) 

670 

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)) 

675 

676 def _print_Integer(self, expr): 

677 if self._settings.get("sympy_integers", False): 

678 return "S(%s)" % (expr) 

679 return str(expr.p) 

680 

681 def _print_Integers(self, expr): 

682 return 'Integers' 

683 

684 def _print_Naturals(self, expr): 

685 return 'Naturals' 

686 

687 def _print_Naturals0(self, expr): 

688 return 'Naturals0' 

689 

690 def _print_Rationals(self, expr): 

691 return 'Rationals' 

692 

693 def _print_Reals(self, expr): 

694 return 'Reals' 

695 

696 def _print_Complexes(self, expr): 

697 return 'Complexes' 

698 

699 def _print_EmptySet(self, expr): 

700 return 'EmptySet' 

701 

702 def _print_EmptySequence(self, expr): 

703 return 'EmptySequence' 

704 

705 def _print_int(self, expr): 

706 return str(expr) 

707 

708 def _print_mpz(self, expr): 

709 return str(expr) 

710 

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) 

718 

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) 

724 

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) 

730 

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) 

736 

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 

760 

761 def _print_Relational(self, expr): 

762 

763 charmap = { 

764 "==": "Eq", 

765 "!=": "Ne", 

766 ":=": "Assignment", 

767 '+=': "AddAugmentedAssignment", 

768 "-=": "SubAugmentedAssignment", 

769 "*=": "MulAugmentedAssignment", 

770 "/=": "DivAugmentedAssignment", 

771 "%=": "ModAugmentedAssignment", 

772 } 

773 

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)) 

777 

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))) 

781 

782 def _print_ComplexRootOf(self, expr): 

783 return "CRootOf(%s, %d)" % (self._print_Add(expr.expr, order='lex'), 

784 expr.index) 

785 

786 def _print_RootSum(self, expr): 

787 args = [self._print_Add(expr.expr, order='lex')] 

788 

789 if expr.fun is not S.IdentityFunction: 

790 args.append(self._print(expr.fun)) 

791 

792 return "RootSum(%s)" % ", ".join(args) 

793 

794 def _print_GroebnerBasis(self, basis): 

795 cls = basis.__class__.__name__ 

796 

797 exprs = [self._print_Add(arg, order=basis.order) for arg in basis.exprs] 

798 exprs = "[%s]" % ", ".join(exprs) 

799 

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) 

803 

804 args = [exprs] + gens + [domain, order] 

805 

806 return "%s(%s)" % (cls, ", ".join(args)) 

807 

808 def _print_set(self, s): 

809 items = sorted(s, key=default_sort_key) 

810 

811 args = ', '.join(self._print(item) for item in items) 

812 if not args: 

813 return "set()" 

814 return '{%s}' % args 

815 

816 def _print_FiniteSet(self, s): 

817 from sympy.sets.sets import FiniteSet 

818 items = sorted(s, key=default_sort_key) 

819 

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) 

824 

825 def _print_Partition(self, s): 

826 items = sorted(s, key=default_sort_key) 

827 

828 args = ', '.join(self._print(arg) for arg in items) 

829 return 'Partition({})'.format(args) 

830 

831 def _print_frozenset(self, s): 

832 if not s: 

833 return "frozenset()" 

834 return "frozenset(%s)" % self._print_set(s) 

835 

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) 

844 

845 def _print_Symbol(self, expr): 

846 return expr.name 

847 _print_MatrixSymbol = _print_Symbol 

848 _print_RandomSymbol = _print_Symbol 

849 

850 def _print_Identity(self, expr): 

851 return "I" 

852 

853 def _print_ZeroMatrix(self, expr): 

854 return "0" 

855 

856 def _print_OneMatrix(self, expr): 

857 return "1" 

858 

859 def _print_Predicate(self, expr): 

860 return "Q.%s" % expr.name 

861 

862 def _print_str(self, expr): 

863 return str(expr) 

864 

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, ", ") 

870 

871 def _print_Tuple(self, expr): 

872 return self._print_tuple(expr) 

873 

874 def _print_Transpose(self, T): 

875 return "%s.T" % self.parenthesize(T.arg, PRECEDENCE["Pow"]) 

876 

877 def _print_Uniform(self, expr): 

878 return "Uniform(%s, %s)" % (self._print(expr.a), self._print(expr.b)) 

879 

880 def _print_Quantity(self, expr): 

881 if self._settings.get("abbrev", False): 

882 return "%s" % expr.abbrev 

883 return "%s" % expr.name 

884 

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) 

889 

890 def _print_Dimension(self, expr): 

891 return str(expr) 

892 

893 def _print_Wild(self, expr): 

894 return expr.name + '_' 

895 

896 def _print_WildFunction(self, expr): 

897 return expr.name + '_' 

898 

899 def _print_WildDot(self, expr): 

900 return expr.name 

901 

902 def _print_WildPlus(self, expr): 

903 return expr.name 

904 

905 def _print_WildStar(self, expr): 

906 return expr.name 

907 

908 def _print_Zero(self, expr): 

909 if self._settings.get("sympy_integers", False): 

910 return "S(0)" 

911 return "0" 

912 

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 

920 

921 cls = p.__class__.__name__ 

922 rep = self._print(p.rep) 

923 dom = self._print(p.dom) 

924 ring = self._print(p.ring) 

925 

926 return "%s(%s, %s, %s)" % (cls, rep, dom, ring) 

927 

928 def _print_DMF(self, expr): 

929 return self._print_DMP(expr) 

930 

931 def _print_Object(self, obj): 

932 return 'Object("%s")' % obj.name 

933 

934 def _print_IdentityMorphism(self, morphism): 

935 return 'IdentityMorphism(%s)' % morphism.domain 

936 

937 def _print_NamedMorphism(self, morphism): 

938 return 'NamedMorphism(%s, %s, "%s")' % \ 

939 (morphism.domain, morphism.codomain, morphism.name) 

940 

941 def _print_Category(self, category): 

942 return 'Category("%s")' % category.name 

943 

944 def _print_Manifold(self, manifold): 

945 return manifold.name.name 

946 

947 def _print_Patch(self, patch): 

948 return patch.name.name 

949 

950 def _print_CoordSystem(self, coords): 

951 return coords.name.name 

952 

953 def _print_BaseScalarField(self, field): 

954 return field._coord_sys.symbols[field._index].name 

955 

956 def _print_BaseVectorField(self, field): 

957 return 'e_%s' % field._coord_sys.symbols[field._index].name 

958 

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) 

965 

966 def _print_Tr(self, expr): 

967 #TODO : Handle indices 

968 return "%s(%s)" % ("Tr", self._print(expr.args[0])) 

969 

970 def _print_Str(self, s): 

971 return self._print(s.name) 

972 

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)) 

978 

979 

980@print_function(StrPrinter) 

981def sstr(expr, **settings): 

982 """Returns the expression as a string. 

983 

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. 

987 

988 Examples 

989 ======== 

990 

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 """ 

996 

997 p = StrPrinter(settings) 

998 s = p.doprint(expr) 

999 

1000 return s 

1001 

1002 

1003class StrReprPrinter(StrPrinter): 

1004 """(internal) -- see sstrrepr""" 

1005 

1006 def _print_str(self, s): 

1007 return repr(s) 

1008 

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)) 

1012 

1013 

1014@print_function(StrReprPrinter) 

1015def sstrrepr(expr, **settings): 

1016 """return expr in mixed str/repr form 

1017 

1018 i.e. strings are returned in repr form with quotes, and everything else 

1019 is returned in str form. 

1020 

1021 This function could be useful for hooking into sys.displayhook 

1022 """ 

1023 

1024 p = StrReprPrinter(settings) 

1025 s = p.doprint(expr) 

1026 

1027 return s