Coverage for /usr/lib/python3/dist-packages/sympy/printing/pretty/pretty.py: 14%

1956 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1import itertools 

2 

3from sympy.core import S 

4from sympy.core.add import Add 

5from sympy.core.containers import Tuple 

6from sympy.core.function import Function 

7from sympy.core.mul import Mul 

8from sympy.core.numbers import Number, Rational 

9from sympy.core.power import Pow 

10from sympy.core.sorting import default_sort_key 

11from sympy.core.symbol import Symbol 

12from sympy.core.sympify import SympifyError 

13from sympy.printing.conventions import requires_partial 

14from sympy.printing.precedence import PRECEDENCE, precedence, precedence_traditional 

15from sympy.printing.printer import Printer, print_function 

16from sympy.printing.str import sstr 

17from sympy.utilities.iterables import has_variety 

18from sympy.utilities.exceptions import sympy_deprecation_warning 

19 

20from sympy.printing.pretty.stringpict import prettyForm, stringPict 

21from sympy.printing.pretty.pretty_symbology import hobj, vobj, xobj, \ 

22 xsym, pretty_symbol, pretty_atom, pretty_use_unicode, greek_unicode, U, \ 

23 pretty_try_use_unicode, annotated 

24 

25# rename for usage from outside 

26pprint_use_unicode = pretty_use_unicode 

27pprint_try_use_unicode = pretty_try_use_unicode 

28 

29 

30class PrettyPrinter(Printer): 

31 """Printer, which converts an expression into 2D ASCII-art figure.""" 

32 printmethod = "_pretty" 

33 

34 _default_settings = { 

35 "order": None, 

36 "full_prec": "auto", 

37 "use_unicode": None, 

38 "wrap_line": True, 

39 "num_columns": None, 

40 "use_unicode_sqrt_char": True, 

41 "root_notation": True, 

42 "mat_symbol_style": "plain", 

43 "imaginary_unit": "i", 

44 "perm_cyclic": True 

45 } 

46 

47 def __init__(self, settings=None): 

48 Printer.__init__(self, settings) 

49 

50 if not isinstance(self._settings['imaginary_unit'], str): 

51 raise TypeError("'imaginary_unit' must a string, not {}".format(self._settings['imaginary_unit'])) 

52 elif self._settings['imaginary_unit'] not in ("i", "j"): 

53 raise ValueError("'imaginary_unit' must be either 'i' or 'j', not '{}'".format(self._settings['imaginary_unit'])) 

54 

55 def emptyPrinter(self, expr): 

56 return prettyForm(str(expr)) 

57 

58 @property 

59 def _use_unicode(self): 

60 if self._settings['use_unicode']: 

61 return True 

62 else: 

63 return pretty_use_unicode() 

64 

65 def doprint(self, expr): 

66 return self._print(expr).render(**self._settings) 

67 

68 # empty op so _print(stringPict) returns the same 

69 def _print_stringPict(self, e): 

70 return e 

71 

72 def _print_basestring(self, e): 

73 return prettyForm(e) 

74 

75 def _print_atan2(self, e): 

76 pform = prettyForm(*self._print_seq(e.args).parens()) 

77 pform = prettyForm(*pform.left('atan2')) 

78 return pform 

79 

80 def _print_Symbol(self, e, bold_name=False): 

81 symb = pretty_symbol(e.name, bold_name) 

82 return prettyForm(symb) 

83 _print_RandomSymbol = _print_Symbol 

84 def _print_MatrixSymbol(self, e): 

85 return self._print_Symbol(e, self._settings['mat_symbol_style'] == "bold") 

86 

87 def _print_Float(self, e): 

88 # we will use StrPrinter's Float printer, but we need to handle the 

89 # full_prec ourselves, according to the self._print_level 

90 full_prec = self._settings["full_prec"] 

91 if full_prec == "auto": 

92 full_prec = self._print_level == 1 

93 return prettyForm(sstr(e, full_prec=full_prec)) 

94 

95 def _print_Cross(self, e): 

96 vec1 = e._expr1 

97 vec2 = e._expr2 

98 pform = self._print(vec2) 

99 pform = prettyForm(*pform.left('(')) 

100 pform = prettyForm(*pform.right(')')) 

101 pform = prettyForm(*pform.left(self._print(U('MULTIPLICATION SIGN')))) 

102 pform = prettyForm(*pform.left(')')) 

103 pform = prettyForm(*pform.left(self._print(vec1))) 

104 pform = prettyForm(*pform.left('(')) 

105 return pform 

106 

107 def _print_Curl(self, e): 

108 vec = e._expr 

109 pform = self._print(vec) 

110 pform = prettyForm(*pform.left('(')) 

111 pform = prettyForm(*pform.right(')')) 

112 pform = prettyForm(*pform.left(self._print(U('MULTIPLICATION SIGN')))) 

113 pform = prettyForm(*pform.left(self._print(U('NABLA')))) 

114 return pform 

115 

116 def _print_Divergence(self, e): 

117 vec = e._expr 

118 pform = self._print(vec) 

119 pform = prettyForm(*pform.left('(')) 

120 pform = prettyForm(*pform.right(')')) 

121 pform = prettyForm(*pform.left(self._print(U('DOT OPERATOR')))) 

122 pform = prettyForm(*pform.left(self._print(U('NABLA')))) 

123 return pform 

124 

125 def _print_Dot(self, e): 

126 vec1 = e._expr1 

127 vec2 = e._expr2 

128 pform = self._print(vec2) 

129 pform = prettyForm(*pform.left('(')) 

130 pform = prettyForm(*pform.right(')')) 

131 pform = prettyForm(*pform.left(self._print(U('DOT OPERATOR')))) 

132 pform = prettyForm(*pform.left(')')) 

133 pform = prettyForm(*pform.left(self._print(vec1))) 

134 pform = prettyForm(*pform.left('(')) 

135 return pform 

136 

137 def _print_Gradient(self, e): 

138 func = e._expr 

139 pform = self._print(func) 

140 pform = prettyForm(*pform.left('(')) 

141 pform = prettyForm(*pform.right(')')) 

142 pform = prettyForm(*pform.left(self._print(U('NABLA')))) 

143 return pform 

144 

145 def _print_Laplacian(self, e): 

146 func = e._expr 

147 pform = self._print(func) 

148 pform = prettyForm(*pform.left('(')) 

149 pform = prettyForm(*pform.right(')')) 

150 pform = prettyForm(*pform.left(self._print(U('INCREMENT')))) 

151 return pform 

152 

153 def _print_Atom(self, e): 

154 try: 

155 # print atoms like Exp1 or Pi 

156 return prettyForm(pretty_atom(e.__class__.__name__, printer=self)) 

157 except KeyError: 

158 return self.emptyPrinter(e) 

159 

160 # Infinity inherits from Number, so we have to override _print_XXX order 

161 _print_Infinity = _print_Atom 

162 _print_NegativeInfinity = _print_Atom 

163 _print_EmptySet = _print_Atom 

164 _print_Naturals = _print_Atom 

165 _print_Naturals0 = _print_Atom 

166 _print_Integers = _print_Atom 

167 _print_Rationals = _print_Atom 

168 _print_Complexes = _print_Atom 

169 

170 _print_EmptySequence = _print_Atom 

171 

172 def _print_Reals(self, e): 

173 if self._use_unicode: 

174 return self._print_Atom(e) 

175 else: 

176 inf_list = ['-oo', 'oo'] 

177 return self._print_seq(inf_list, '(', ')') 

178 

179 def _print_subfactorial(self, e): 

180 x = e.args[0] 

181 pform = self._print(x) 

182 # Add parentheses if needed 

183 if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol): 

184 pform = prettyForm(*pform.parens()) 

185 pform = prettyForm(*pform.left('!')) 

186 return pform 

187 

188 def _print_factorial(self, e): 

189 x = e.args[0] 

190 pform = self._print(x) 

191 # Add parentheses if needed 

192 if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol): 

193 pform = prettyForm(*pform.parens()) 

194 pform = prettyForm(*pform.right('!')) 

195 return pform 

196 

197 def _print_factorial2(self, e): 

198 x = e.args[0] 

199 pform = self._print(x) 

200 # Add parentheses if needed 

201 if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol): 

202 pform = prettyForm(*pform.parens()) 

203 pform = prettyForm(*pform.right('!!')) 

204 return pform 

205 

206 def _print_binomial(self, e): 

207 n, k = e.args 

208 

209 n_pform = self._print(n) 

210 k_pform = self._print(k) 

211 

212 bar = ' '*max(n_pform.width(), k_pform.width()) 

213 

214 pform = prettyForm(*k_pform.above(bar)) 

215 pform = prettyForm(*pform.above(n_pform)) 

216 pform = prettyForm(*pform.parens('(', ')')) 

217 

218 pform.baseline = (pform.baseline + 1)//2 

219 

220 return pform 

221 

222 def _print_Relational(self, e): 

223 op = prettyForm(' ' + xsym(e.rel_op) + ' ') 

224 

225 l = self._print(e.lhs) 

226 r = self._print(e.rhs) 

227 pform = prettyForm(*stringPict.next(l, op, r), binding=prettyForm.OPEN) 

228 return pform 

229 

230 def _print_Not(self, e): 

231 from sympy.logic.boolalg import (Equivalent, Implies) 

232 if self._use_unicode: 

233 arg = e.args[0] 

234 pform = self._print(arg) 

235 if isinstance(arg, Equivalent): 

236 return self._print_Equivalent(arg, altchar="\N{LEFT RIGHT DOUBLE ARROW WITH STROKE}") 

237 if isinstance(arg, Implies): 

238 return self._print_Implies(arg, altchar="\N{RIGHTWARDS ARROW WITH STROKE}") 

239 

240 if arg.is_Boolean and not arg.is_Not: 

241 pform = prettyForm(*pform.parens()) 

242 

243 return prettyForm(*pform.left("\N{NOT SIGN}")) 

244 else: 

245 return self._print_Function(e) 

246 

247 def __print_Boolean(self, e, char, sort=True): 

248 args = e.args 

249 if sort: 

250 args = sorted(e.args, key=default_sort_key) 

251 arg = args[0] 

252 pform = self._print(arg) 

253 

254 if arg.is_Boolean and not arg.is_Not: 

255 pform = prettyForm(*pform.parens()) 

256 

257 for arg in args[1:]: 

258 pform_arg = self._print(arg) 

259 

260 if arg.is_Boolean and not arg.is_Not: 

261 pform_arg = prettyForm(*pform_arg.parens()) 

262 

263 pform = prettyForm(*pform.right(' %s ' % char)) 

264 pform = prettyForm(*pform.right(pform_arg)) 

265 

266 return pform 

267 

268 def _print_And(self, e): 

269 if self._use_unicode: 

270 return self.__print_Boolean(e, "\N{LOGICAL AND}") 

271 else: 

272 return self._print_Function(e, sort=True) 

273 

274 def _print_Or(self, e): 

275 if self._use_unicode: 

276 return self.__print_Boolean(e, "\N{LOGICAL OR}") 

277 else: 

278 return self._print_Function(e, sort=True) 

279 

280 def _print_Xor(self, e): 

281 if self._use_unicode: 

282 return self.__print_Boolean(e, "\N{XOR}") 

283 else: 

284 return self._print_Function(e, sort=True) 

285 

286 def _print_Nand(self, e): 

287 if self._use_unicode: 

288 return self.__print_Boolean(e, "\N{NAND}") 

289 else: 

290 return self._print_Function(e, sort=True) 

291 

292 def _print_Nor(self, e): 

293 if self._use_unicode: 

294 return self.__print_Boolean(e, "\N{NOR}") 

295 else: 

296 return self._print_Function(e, sort=True) 

297 

298 def _print_Implies(self, e, altchar=None): 

299 if self._use_unicode: 

300 return self.__print_Boolean(e, altchar or "\N{RIGHTWARDS ARROW}", sort=False) 

301 else: 

302 return self._print_Function(e) 

303 

304 def _print_Equivalent(self, e, altchar=None): 

305 if self._use_unicode: 

306 return self.__print_Boolean(e, altchar or "\N{LEFT RIGHT DOUBLE ARROW}") 

307 else: 

308 return self._print_Function(e, sort=True) 

309 

310 def _print_conjugate(self, e): 

311 pform = self._print(e.args[0]) 

312 return prettyForm( *pform.above( hobj('_', pform.width())) ) 

313 

314 def _print_Abs(self, e): 

315 pform = self._print(e.args[0]) 

316 pform = prettyForm(*pform.parens('|', '|')) 

317 return pform 

318 

319 def _print_floor(self, e): 

320 if self._use_unicode: 

321 pform = self._print(e.args[0]) 

322 pform = prettyForm(*pform.parens('lfloor', 'rfloor')) 

323 return pform 

324 else: 

325 return self._print_Function(e) 

326 

327 def _print_ceiling(self, e): 

328 if self._use_unicode: 

329 pform = self._print(e.args[0]) 

330 pform = prettyForm(*pform.parens('lceil', 'rceil')) 

331 return pform 

332 else: 

333 return self._print_Function(e) 

334 

335 def _print_Derivative(self, deriv): 

336 if requires_partial(deriv.expr) and self._use_unicode: 

337 deriv_symbol = U('PARTIAL DIFFERENTIAL') 

338 else: 

339 deriv_symbol = r'd' 

340 x = None 

341 count_total_deriv = 0 

342 

343 for sym, num in reversed(deriv.variable_count): 

344 s = self._print(sym) 

345 ds = prettyForm(*s.left(deriv_symbol)) 

346 count_total_deriv += num 

347 

348 if (not num.is_Integer) or (num > 1): 

349 ds = ds**prettyForm(str(num)) 

350 

351 if x is None: 

352 x = ds 

353 else: 

354 x = prettyForm(*x.right(' ')) 

355 x = prettyForm(*x.right(ds)) 

356 

357 f = prettyForm( 

358 binding=prettyForm.FUNC, *self._print(deriv.expr).parens()) 

359 

360 pform = prettyForm(deriv_symbol) 

361 

362 if (count_total_deriv > 1) != False: 

363 pform = pform**prettyForm(str(count_total_deriv)) 

364 

365 pform = prettyForm(*pform.below(stringPict.LINE, x)) 

366 pform.baseline = pform.baseline + 1 

367 pform = prettyForm(*stringPict.next(pform, f)) 

368 pform.binding = prettyForm.MUL 

369 

370 return pform 

371 

372 def _print_Cycle(self, dc): 

373 from sympy.combinatorics.permutations import Permutation, Cycle 

374 # for Empty Cycle 

375 if dc == Cycle(): 

376 cyc = stringPict('') 

377 return prettyForm(*cyc.parens()) 

378 

379 dc_list = Permutation(dc.list()).cyclic_form 

380 # for Identity Cycle 

381 if dc_list == []: 

382 cyc = self._print(dc.size - 1) 

383 return prettyForm(*cyc.parens()) 

384 

385 cyc = stringPict('') 

386 for i in dc_list: 

387 l = self._print(str(tuple(i)).replace(',', '')) 

388 cyc = prettyForm(*cyc.right(l)) 

389 return cyc 

390 

391 def _print_Permutation(self, expr): 

392 from sympy.combinatorics.permutations import Permutation, Cycle 

393 

394 perm_cyclic = Permutation.print_cyclic 

395 if perm_cyclic is not None: 

396 sympy_deprecation_warning( 

397 f""" 

398 Setting Permutation.print_cyclic is deprecated. Instead use 

399 init_printing(perm_cyclic={perm_cyclic}). 

400 """, 

401 deprecated_since_version="1.6", 

402 active_deprecations_target="deprecated-permutation-print_cyclic", 

403 stacklevel=7, 

404 ) 

405 else: 

406 perm_cyclic = self._settings.get("perm_cyclic", True) 

407 

408 if perm_cyclic: 

409 return self._print_Cycle(Cycle(expr)) 

410 

411 lower = expr.array_form 

412 upper = list(range(len(lower))) 

413 

414 result = stringPict('') 

415 first = True 

416 for u, l in zip(upper, lower): 

417 s1 = self._print(u) 

418 s2 = self._print(l) 

419 col = prettyForm(*s1.below(s2)) 

420 if first: 

421 first = False 

422 else: 

423 col = prettyForm(*col.left(" ")) 

424 result = prettyForm(*result.right(col)) 

425 return prettyForm(*result.parens()) 

426 

427 

428 def _print_Integral(self, integral): 

429 f = integral.function 

430 

431 # Add parentheses if arg involves addition of terms and 

432 # create a pretty form for the argument 

433 prettyF = self._print(f) 

434 # XXX generalize parens 

435 if f.is_Add: 

436 prettyF = prettyForm(*prettyF.parens()) 

437 

438 # dx dy dz ... 

439 arg = prettyF 

440 for x in integral.limits: 

441 prettyArg = self._print(x[0]) 

442 # XXX qparens (parens if needs-parens) 

443 if prettyArg.width() > 1: 

444 prettyArg = prettyForm(*prettyArg.parens()) 

445 

446 arg = prettyForm(*arg.right(' d', prettyArg)) 

447 

448 # \int \int \int ... 

449 firstterm = True 

450 s = None 

451 for lim in integral.limits: 

452 # Create bar based on the height of the argument 

453 h = arg.height() 

454 H = h + 2 

455 

456 # XXX hack! 

457 ascii_mode = not self._use_unicode 

458 if ascii_mode: 

459 H += 2 

460 

461 vint = vobj('int', H) 

462 

463 # Construct the pretty form with the integral sign and the argument 

464 pform = prettyForm(vint) 

465 pform.baseline = arg.baseline + ( 

466 H - h)//2 # covering the whole argument 

467 

468 if len(lim) > 1: 

469 # Create pretty forms for endpoints, if definite integral. 

470 # Do not print empty endpoints. 

471 if len(lim) == 2: 

472 prettyA = prettyForm("") 

473 prettyB = self._print(lim[1]) 

474 if len(lim) == 3: 

475 prettyA = self._print(lim[1]) 

476 prettyB = self._print(lim[2]) 

477 

478 if ascii_mode: # XXX hack 

479 # Add spacing so that endpoint can more easily be 

480 # identified with the correct integral sign 

481 spc = max(1, 3 - prettyB.width()) 

482 prettyB = prettyForm(*prettyB.left(' ' * spc)) 

483 

484 spc = max(1, 4 - prettyA.width()) 

485 prettyA = prettyForm(*prettyA.right(' ' * spc)) 

486 

487 pform = prettyForm(*pform.above(prettyB)) 

488 pform = prettyForm(*pform.below(prettyA)) 

489 

490 if not ascii_mode: # XXX hack 

491 pform = prettyForm(*pform.right(' ')) 

492 

493 if firstterm: 

494 s = pform # first term 

495 firstterm = False 

496 else: 

497 s = prettyForm(*s.left(pform)) 

498 

499 pform = prettyForm(*arg.left(s)) 

500 pform.binding = prettyForm.MUL 

501 return pform 

502 

503 def _print_Product(self, expr): 

504 func = expr.term 

505 pretty_func = self._print(func) 

506 

507 horizontal_chr = xobj('_', 1) 

508 corner_chr = xobj('_', 1) 

509 vertical_chr = xobj('|', 1) 

510 

511 if self._use_unicode: 

512 # use unicode corners 

513 horizontal_chr = xobj('-', 1) 

514 corner_chr = '\N{BOX DRAWINGS LIGHT DOWN AND HORIZONTAL}' 

515 

516 func_height = pretty_func.height() 

517 

518 first = True 

519 max_upper = 0 

520 sign_height = 0 

521 

522 for lim in expr.limits: 

523 pretty_lower, pretty_upper = self.__print_SumProduct_Limits(lim) 

524 

525 width = (func_height + 2) * 5 // 3 - 2 

526 sign_lines = [horizontal_chr + corner_chr + (horizontal_chr * (width-2)) + corner_chr + horizontal_chr] 

527 for _ in range(func_height + 1): 

528 sign_lines.append(' ' + vertical_chr + (' ' * (width-2)) + vertical_chr + ' ') 

529 

530 pretty_sign = stringPict('') 

531 pretty_sign = prettyForm(*pretty_sign.stack(*sign_lines)) 

532 

533 

534 max_upper = max(max_upper, pretty_upper.height()) 

535 

536 if first: 

537 sign_height = pretty_sign.height() 

538 

539 pretty_sign = prettyForm(*pretty_sign.above(pretty_upper)) 

540 pretty_sign = prettyForm(*pretty_sign.below(pretty_lower)) 

541 

542 if first: 

543 pretty_func.baseline = 0 

544 first = False 

545 

546 height = pretty_sign.height() 

547 padding = stringPict('') 

548 padding = prettyForm(*padding.stack(*[' ']*(height - 1))) 

549 pretty_sign = prettyForm(*pretty_sign.right(padding)) 

550 

551 pretty_func = prettyForm(*pretty_sign.right(pretty_func)) 

552 

553 pretty_func.baseline = max_upper + sign_height//2 

554 pretty_func.binding = prettyForm.MUL 

555 return pretty_func 

556 

557 def __print_SumProduct_Limits(self, lim): 

558 def print_start(lhs, rhs): 

559 op = prettyForm(' ' + xsym("==") + ' ') 

560 l = self._print(lhs) 

561 r = self._print(rhs) 

562 pform = prettyForm(*stringPict.next(l, op, r)) 

563 return pform 

564 

565 prettyUpper = self._print(lim[2]) 

566 prettyLower = print_start(lim[0], lim[1]) 

567 return prettyLower, prettyUpper 

568 

569 def _print_Sum(self, expr): 

570 ascii_mode = not self._use_unicode 

571 

572 def asum(hrequired, lower, upper, use_ascii): 

573 def adjust(s, wid=None, how='<^>'): 

574 if not wid or len(s) > wid: 

575 return s 

576 need = wid - len(s) 

577 if how in ('<^>', "<") or how not in list('<^>'): 

578 return s + ' '*need 

579 half = need//2 

580 lead = ' '*half 

581 if how == ">": 

582 return " "*need + s 

583 return lead + s + ' '*(need - len(lead)) 

584 

585 h = max(hrequired, 2) 

586 d = h//2 

587 w = d + 1 

588 more = hrequired % 2 

589 

590 lines = [] 

591 if use_ascii: 

592 lines.append("_"*(w) + ' ') 

593 lines.append(r"\%s`" % (' '*(w - 1))) 

594 for i in range(1, d): 

595 lines.append('%s\\%s' % (' '*i, ' '*(w - i))) 

596 if more: 

597 lines.append('%s)%s' % (' '*(d), ' '*(w - d))) 

598 for i in reversed(range(1, d)): 

599 lines.append('%s/%s' % (' '*i, ' '*(w - i))) 

600 lines.append("/" + "_"*(w - 1) + ',') 

601 return d, h + more, lines, more 

602 else: 

603 w = w + more 

604 d = d + more 

605 vsum = vobj('sum', 4) 

606 lines.append("_"*(w)) 

607 for i in range(0, d): 

608 lines.append('%s%s%s' % (' '*i, vsum[2], ' '*(w - i - 1))) 

609 for i in reversed(range(0, d)): 

610 lines.append('%s%s%s' % (' '*i, vsum[4], ' '*(w - i - 1))) 

611 lines.append(vsum[8]*(w)) 

612 return d, h + 2*more, lines, more 

613 

614 f = expr.function 

615 

616 prettyF = self._print(f) 

617 

618 if f.is_Add: # add parens 

619 prettyF = prettyForm(*prettyF.parens()) 

620 

621 H = prettyF.height() + 2 

622 

623 # \sum \sum \sum ... 

624 first = True 

625 max_upper = 0 

626 sign_height = 0 

627 

628 for lim in expr.limits: 

629 prettyLower, prettyUpper = self.__print_SumProduct_Limits(lim) 

630 

631 max_upper = max(max_upper, prettyUpper.height()) 

632 

633 # Create sum sign based on the height of the argument 

634 d, h, slines, adjustment = asum( 

635 H, prettyLower.width(), prettyUpper.width(), ascii_mode) 

636 prettySign = stringPict('') 

637 prettySign = prettyForm(*prettySign.stack(*slines)) 

638 

639 if first: 

640 sign_height = prettySign.height() 

641 

642 prettySign = prettyForm(*prettySign.above(prettyUpper)) 

643 prettySign = prettyForm(*prettySign.below(prettyLower)) 

644 

645 if first: 

646 # change F baseline so it centers on the sign 

647 prettyF.baseline -= d - (prettyF.height()//2 - 

648 prettyF.baseline) 

649 first = False 

650 

651 # put padding to the right 

652 pad = stringPict('') 

653 pad = prettyForm(*pad.stack(*[' ']*h)) 

654 prettySign = prettyForm(*prettySign.right(pad)) 

655 # put the present prettyF to the right 

656 prettyF = prettyForm(*prettySign.right(prettyF)) 

657 

658 # adjust baseline of ascii mode sigma with an odd height so that it is 

659 # exactly through the center 

660 ascii_adjustment = ascii_mode if not adjustment else 0 

661 prettyF.baseline = max_upper + sign_height//2 + ascii_adjustment 

662 

663 prettyF.binding = prettyForm.MUL 

664 return prettyF 

665 

666 def _print_Limit(self, l): 

667 e, z, z0, dir = l.args 

668 

669 E = self._print(e) 

670 if precedence(e) <= PRECEDENCE["Mul"]: 

671 E = prettyForm(*E.parens('(', ')')) 

672 Lim = prettyForm('lim') 

673 

674 LimArg = self._print(z) 

675 if self._use_unicode: 

676 LimArg = prettyForm(*LimArg.right('\N{BOX DRAWINGS LIGHT HORIZONTAL}\N{RIGHTWARDS ARROW}')) 

677 else: 

678 LimArg = prettyForm(*LimArg.right('->')) 

679 LimArg = prettyForm(*LimArg.right(self._print(z0))) 

680 

681 if str(dir) == '+-' or z0 in (S.Infinity, S.NegativeInfinity): 

682 dir = "" 

683 else: 

684 if self._use_unicode: 

685 dir = '\N{SUPERSCRIPT PLUS SIGN}' if str(dir) == "+" else '\N{SUPERSCRIPT MINUS}' 

686 

687 LimArg = prettyForm(*LimArg.right(self._print(dir))) 

688 

689 Lim = prettyForm(*Lim.below(LimArg)) 

690 Lim = prettyForm(*Lim.right(E), binding=prettyForm.MUL) 

691 

692 return Lim 

693 

694 def _print_matrix_contents(self, e): 

695 """ 

696 This method factors out what is essentially grid printing. 

697 """ 

698 M = e # matrix 

699 Ms = {} # i,j -> pretty(M[i,j]) 

700 for i in range(M.rows): 

701 for j in range(M.cols): 

702 Ms[i, j] = self._print(M[i, j]) 

703 

704 # h- and v- spacers 

705 hsep = 2 

706 vsep = 1 

707 

708 # max width for columns 

709 maxw = [-1] * M.cols 

710 

711 for j in range(M.cols): 

712 maxw[j] = max([Ms[i, j].width() for i in range(M.rows)] or [0]) 

713 

714 # drawing result 

715 D = None 

716 

717 for i in range(M.rows): 

718 

719 D_row = None 

720 for j in range(M.cols): 

721 s = Ms[i, j] 

722 

723 # reshape s to maxw 

724 # XXX this should be generalized, and go to stringPict.reshape ? 

725 assert s.width() <= maxw[j] 

726 

727 # hcenter it, +0.5 to the right 2 

728 # ( it's better to align formula starts for say 0 and r ) 

729 # XXX this is not good in all cases -- maybe introduce vbaseline? 

730 wdelta = maxw[j] - s.width() 

731 wleft = wdelta // 2 

732 wright = wdelta - wleft 

733 

734 s = prettyForm(*s.right(' '*wright)) 

735 s = prettyForm(*s.left(' '*wleft)) 

736 

737 # we don't need vcenter cells -- this is automatically done in 

738 # a pretty way because when their baselines are taking into 

739 # account in .right() 

740 

741 if D_row is None: 

742 D_row = s # first box in a row 

743 continue 

744 

745 D_row = prettyForm(*D_row.right(' '*hsep)) # h-spacer 

746 D_row = prettyForm(*D_row.right(s)) 

747 

748 if D is None: 

749 D = D_row # first row in a picture 

750 continue 

751 

752 # v-spacer 

753 for _ in range(vsep): 

754 D = prettyForm(*D.below(' ')) 

755 

756 D = prettyForm(*D.below(D_row)) 

757 

758 if D is None: 

759 D = prettyForm('') # Empty Matrix 

760 

761 return D 

762 

763 def _print_MatrixBase(self, e, lparens='[', rparens=']'): 

764 D = self._print_matrix_contents(e) 

765 D.baseline = D.height()//2 

766 D = prettyForm(*D.parens(lparens, rparens)) 

767 return D 

768 

769 def _print_Determinant(self, e): 

770 mat = e.arg 

771 if mat.is_MatrixExpr: 

772 from sympy.matrices.expressions.blockmatrix import BlockMatrix 

773 if isinstance(mat, BlockMatrix): 

774 return self._print_MatrixBase(mat.blocks, lparens='|', rparens='|') 

775 D = self._print(mat) 

776 D.baseline = D.height()//2 

777 return prettyForm(*D.parens('|', '|')) 

778 else: 

779 return self._print_MatrixBase(mat, lparens='|', rparens='|') 

780 

781 def _print_TensorProduct(self, expr): 

782 # This should somehow share the code with _print_WedgeProduct: 

783 if self._use_unicode: 

784 circled_times = "\u2297" 

785 else: 

786 circled_times = ".*" 

787 return self._print_seq(expr.args, None, None, circled_times, 

788 parenthesize=lambda x: precedence_traditional(x) <= PRECEDENCE["Mul"]) 

789 

790 def _print_WedgeProduct(self, expr): 

791 # This should somehow share the code with _print_TensorProduct: 

792 if self._use_unicode: 

793 wedge_symbol = "\u2227" 

794 else: 

795 wedge_symbol = '/\\' 

796 return self._print_seq(expr.args, None, None, wedge_symbol, 

797 parenthesize=lambda x: precedence_traditional(x) <= PRECEDENCE["Mul"]) 

798 

799 def _print_Trace(self, e): 

800 D = self._print(e.arg) 

801 D = prettyForm(*D.parens('(',')')) 

802 D.baseline = D.height()//2 

803 D = prettyForm(*D.left('\n'*(0) + 'tr')) 

804 return D 

805 

806 

807 def _print_MatrixElement(self, expr): 

808 from sympy.matrices import MatrixSymbol 

809 if (isinstance(expr.parent, MatrixSymbol) 

810 and expr.i.is_number and expr.j.is_number): 

811 return self._print( 

812 Symbol(expr.parent.name + '_%d%d' % (expr.i, expr.j))) 

813 else: 

814 prettyFunc = self._print(expr.parent) 

815 prettyFunc = prettyForm(*prettyFunc.parens()) 

816 prettyIndices = self._print_seq((expr.i, expr.j), delimiter=', ' 

817 ).parens(left='[', right=']')[0] 

818 pform = prettyForm(binding=prettyForm.FUNC, 

819 *stringPict.next(prettyFunc, prettyIndices)) 

820 

821 # store pform parts so it can be reassembled e.g. when powered 

822 pform.prettyFunc = prettyFunc 

823 pform.prettyArgs = prettyIndices 

824 

825 return pform 

826 

827 

828 def _print_MatrixSlice(self, m): 

829 # XXX works only for applied functions 

830 from sympy.matrices import MatrixSymbol 

831 prettyFunc = self._print(m.parent) 

832 if not isinstance(m.parent, MatrixSymbol): 

833 prettyFunc = prettyForm(*prettyFunc.parens()) 

834 def ppslice(x, dim): 

835 x = list(x) 

836 if x[2] == 1: 

837 del x[2] 

838 if x[0] == 0: 

839 x[0] = '' 

840 if x[1] == dim: 

841 x[1] = '' 

842 return prettyForm(*self._print_seq(x, delimiter=':')) 

843 prettyArgs = self._print_seq((ppslice(m.rowslice, m.parent.rows), 

844 ppslice(m.colslice, m.parent.cols)), delimiter=', ').parens(left='[', right=']')[0] 

845 

846 pform = prettyForm( 

847 binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs)) 

848 

849 # store pform parts so it can be reassembled e.g. when powered 

850 pform.prettyFunc = prettyFunc 

851 pform.prettyArgs = prettyArgs 

852 

853 return pform 

854 

855 def _print_Transpose(self, expr): 

856 mat = expr.arg 

857 pform = self._print(mat) 

858 from sympy.matrices import MatrixSymbol, BlockMatrix 

859 if (not isinstance(mat, MatrixSymbol) and 

860 not isinstance(mat, BlockMatrix) and mat.is_MatrixExpr): 

861 pform = prettyForm(*pform.parens()) 

862 pform = pform**(prettyForm('T')) 

863 return pform 

864 

865 def _print_Adjoint(self, expr): 

866 mat = expr.arg 

867 pform = self._print(mat) 

868 if self._use_unicode: 

869 dag = prettyForm('\N{DAGGER}') 

870 else: 

871 dag = prettyForm('+') 

872 from sympy.matrices import MatrixSymbol, BlockMatrix 

873 if (not isinstance(mat, MatrixSymbol) and 

874 not isinstance(mat, BlockMatrix) and mat.is_MatrixExpr): 

875 pform = prettyForm(*pform.parens()) 

876 pform = pform**dag 

877 return pform 

878 

879 def _print_BlockMatrix(self, B): 

880 if B.blocks.shape == (1, 1): 

881 return self._print(B.blocks[0, 0]) 

882 return self._print(B.blocks) 

883 

884 def _print_MatAdd(self, expr): 

885 s = None 

886 for item in expr.args: 

887 pform = self._print(item) 

888 if s is None: 

889 s = pform # First element 

890 else: 

891 coeff = item.as_coeff_mmul()[0] 

892 if S(coeff).could_extract_minus_sign(): 

893 s = prettyForm(*stringPict.next(s, ' ')) 

894 pform = self._print(item) 

895 else: 

896 s = prettyForm(*stringPict.next(s, ' + ')) 

897 s = prettyForm(*stringPict.next(s, pform)) 

898 

899 return s 

900 

901 def _print_MatMul(self, expr): 

902 args = list(expr.args) 

903 from sympy.matrices.expressions.hadamard import HadamardProduct 

904 from sympy.matrices.expressions.kronecker import KroneckerProduct 

905 from sympy.matrices.expressions.matadd import MatAdd 

906 for i, a in enumerate(args): 

907 if (isinstance(a, (Add, MatAdd, HadamardProduct, KroneckerProduct)) 

908 and len(expr.args) > 1): 

909 args[i] = prettyForm(*self._print(a).parens()) 

910 else: 

911 args[i] = self._print(a) 

912 

913 return prettyForm.__mul__(*args) 

914 

915 def _print_Identity(self, expr): 

916 if self._use_unicode: 

917 return prettyForm('\N{MATHEMATICAL DOUBLE-STRUCK CAPITAL I}') 

918 else: 

919 return prettyForm('I') 

920 

921 def _print_ZeroMatrix(self, expr): 

922 if self._use_unicode: 

923 return prettyForm('\N{MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO}') 

924 else: 

925 return prettyForm('0') 

926 

927 def _print_OneMatrix(self, expr): 

928 if self._use_unicode: 

929 return prettyForm('\N{MATHEMATICAL DOUBLE-STRUCK DIGIT ONE}') 

930 else: 

931 return prettyForm('1') 

932 

933 def _print_DotProduct(self, expr): 

934 args = list(expr.args) 

935 

936 for i, a in enumerate(args): 

937 args[i] = self._print(a) 

938 return prettyForm.__mul__(*args) 

939 

940 def _print_MatPow(self, expr): 

941 pform = self._print(expr.base) 

942 from sympy.matrices import MatrixSymbol 

943 if not isinstance(expr.base, MatrixSymbol) and expr.base.is_MatrixExpr: 

944 pform = prettyForm(*pform.parens()) 

945 pform = pform**(self._print(expr.exp)) 

946 return pform 

947 

948 def _print_HadamardProduct(self, expr): 

949 from sympy.matrices.expressions.hadamard import HadamardProduct 

950 from sympy.matrices.expressions.matadd import MatAdd 

951 from sympy.matrices.expressions.matmul import MatMul 

952 if self._use_unicode: 

953 delim = pretty_atom('Ring') 

954 else: 

955 delim = '.*' 

956 return self._print_seq(expr.args, None, None, delim, 

957 parenthesize=lambda x: isinstance(x, (MatAdd, MatMul, HadamardProduct))) 

958 

959 def _print_HadamardPower(self, expr): 

960 # from sympy import MatAdd, MatMul 

961 if self._use_unicode: 

962 circ = pretty_atom('Ring') 

963 else: 

964 circ = self._print('.') 

965 pretty_base = self._print(expr.base) 

966 pretty_exp = self._print(expr.exp) 

967 if precedence(expr.exp) < PRECEDENCE["Mul"]: 

968 pretty_exp = prettyForm(*pretty_exp.parens()) 

969 pretty_circ_exp = prettyForm( 

970 binding=prettyForm.LINE, 

971 *stringPict.next(circ, pretty_exp) 

972 ) 

973 return pretty_base**pretty_circ_exp 

974 

975 def _print_KroneckerProduct(self, expr): 

976 from sympy.matrices.expressions.matadd import MatAdd 

977 from sympy.matrices.expressions.matmul import MatMul 

978 if self._use_unicode: 

979 delim = ' \N{N-ARY CIRCLED TIMES OPERATOR} ' 

980 else: 

981 delim = ' x ' 

982 return self._print_seq(expr.args, None, None, delim, 

983 parenthesize=lambda x: isinstance(x, (MatAdd, MatMul))) 

984 

985 def _print_FunctionMatrix(self, X): 

986 D = self._print(X.lamda.expr) 

987 D = prettyForm(*D.parens('[', ']')) 

988 return D 

989 

990 def _print_TransferFunction(self, expr): 

991 if not expr.num == 1: 

992 num, den = expr.num, expr.den 

993 res = Mul(num, Pow(den, -1, evaluate=False), evaluate=False) 

994 return self._print_Mul(res) 

995 else: 

996 return self._print(1)/self._print(expr.den) 

997 

998 def _print_Series(self, expr): 

999 args = list(expr.args) 

1000 for i, a in enumerate(expr.args): 

1001 args[i] = prettyForm(*self._print(a).parens()) 

1002 return prettyForm.__mul__(*args) 

1003 

1004 def _print_MIMOSeries(self, expr): 

1005 from sympy.physics.control.lti import MIMOParallel 

1006 args = list(expr.args) 

1007 pretty_args = [] 

1008 for i, a in enumerate(reversed(args)): 

1009 if (isinstance(a, MIMOParallel) and len(expr.args) > 1): 

1010 expression = self._print(a) 

1011 expression.baseline = expression.height()//2 

1012 pretty_args.append(prettyForm(*expression.parens())) 

1013 else: 

1014 expression = self._print(a) 

1015 expression.baseline = expression.height()//2 

1016 pretty_args.append(expression) 

1017 return prettyForm.__mul__(*pretty_args) 

1018 

1019 def _print_Parallel(self, expr): 

1020 s = None 

1021 for item in expr.args: 

1022 pform = self._print(item) 

1023 if s is None: 

1024 s = pform # First element 

1025 else: 

1026 s = prettyForm(*stringPict.next(s)) 

1027 s.baseline = s.height()//2 

1028 s = prettyForm(*stringPict.next(s, ' + ')) 

1029 s = prettyForm(*stringPict.next(s, pform)) 

1030 return s 

1031 

1032 def _print_MIMOParallel(self, expr): 

1033 from sympy.physics.control.lti import TransferFunctionMatrix 

1034 s = None 

1035 for item in expr.args: 

1036 pform = self._print(item) 

1037 if s is None: 

1038 s = pform # First element 

1039 else: 

1040 s = prettyForm(*stringPict.next(s)) 

1041 s.baseline = s.height()//2 

1042 s = prettyForm(*stringPict.next(s, ' + ')) 

1043 if isinstance(item, TransferFunctionMatrix): 

1044 s.baseline = s.height() - 1 

1045 s = prettyForm(*stringPict.next(s, pform)) 

1046 # s.baseline = s.height()//2 

1047 return s 

1048 

1049 def _print_Feedback(self, expr): 

1050 from sympy.physics.control import TransferFunction, Series 

1051 

1052 num, tf = expr.sys1, TransferFunction(1, 1, expr.var) 

1053 num_arg_list = list(num.args) if isinstance(num, Series) else [num] 

1054 den_arg_list = list(expr.sys2.args) if \ 

1055 isinstance(expr.sys2, Series) else [expr.sys2] 

1056 

1057 if isinstance(num, Series) and isinstance(expr.sys2, Series): 

1058 den = Series(*num_arg_list, *den_arg_list) 

1059 elif isinstance(num, Series) and isinstance(expr.sys2, TransferFunction): 

1060 if expr.sys2 == tf: 

1061 den = Series(*num_arg_list) 

1062 else: 

1063 den = Series(*num_arg_list, expr.sys2) 

1064 elif isinstance(num, TransferFunction) and isinstance(expr.sys2, Series): 

1065 if num == tf: 

1066 den = Series(*den_arg_list) 

1067 else: 

1068 den = Series(num, *den_arg_list) 

1069 else: 

1070 if num == tf: 

1071 den = Series(*den_arg_list) 

1072 elif expr.sys2 == tf: 

1073 den = Series(*num_arg_list) 

1074 else: 

1075 den = Series(*num_arg_list, *den_arg_list) 

1076 

1077 denom = prettyForm(*stringPict.next(self._print(tf))) 

1078 denom.baseline = denom.height()//2 

1079 denom = prettyForm(*stringPict.next(denom, ' + ')) if expr.sign == -1 \ 

1080 else prettyForm(*stringPict.next(denom, ' - ')) 

1081 denom = prettyForm(*stringPict.next(denom, self._print(den))) 

1082 

1083 return self._print(num)/denom 

1084 

1085 def _print_MIMOFeedback(self, expr): 

1086 from sympy.physics.control import MIMOSeries, TransferFunctionMatrix 

1087 

1088 inv_mat = self._print(MIMOSeries(expr.sys2, expr.sys1)) 

1089 plant = self._print(expr.sys1) 

1090 _feedback = prettyForm(*stringPict.next(inv_mat)) 

1091 _feedback = prettyForm(*stringPict.right("I + ", _feedback)) if expr.sign == -1 \ 

1092 else prettyForm(*stringPict.right("I - ", _feedback)) 

1093 _feedback = prettyForm(*stringPict.parens(_feedback)) 

1094 _feedback.baseline = 0 

1095 _feedback = prettyForm(*stringPict.right(_feedback, '-1 ')) 

1096 _feedback.baseline = _feedback.height()//2 

1097 _feedback = prettyForm.__mul__(_feedback, prettyForm(" ")) 

1098 if isinstance(expr.sys1, TransferFunctionMatrix): 

1099 _feedback.baseline = _feedback.height() - 1 

1100 _feedback = prettyForm(*stringPict.next(_feedback, plant)) 

1101 return _feedback 

1102 

1103 def _print_TransferFunctionMatrix(self, expr): 

1104 mat = self._print(expr._expr_mat) 

1105 mat.baseline = mat.height() - 1 

1106 subscript = greek_unicode['tau'] if self._use_unicode else r'{t}' 

1107 mat = prettyForm(*mat.right(subscript)) 

1108 return mat 

1109 

1110 def _print_BasisDependent(self, expr): 

1111 from sympy.vector import Vector 

1112 

1113 if not self._use_unicode: 

1114 raise NotImplementedError("ASCII pretty printing of BasisDependent is not implemented") 

1115 

1116 if expr == expr.zero: 

1117 return prettyForm(expr.zero._pretty_form) 

1118 o1 = [] 

1119 vectstrs = [] 

1120 if isinstance(expr, Vector): 

1121 items = expr.separate().items() 

1122 else: 

1123 items = [(0, expr)] 

1124 for system, vect in items: 

1125 inneritems = list(vect.components.items()) 

1126 inneritems.sort(key = lambda x: x[0].__str__()) 

1127 for k, v in inneritems: 

1128 #if the coef of the basis vector is 1 

1129 #we skip the 1 

1130 if v == 1: 

1131 o1.append("" + 

1132 k._pretty_form) 

1133 #Same for -1 

1134 elif v == -1: 

1135 o1.append("(-1) " + 

1136 k._pretty_form) 

1137 #For a general expr 

1138 else: 

1139 #We always wrap the measure numbers in 

1140 #parentheses 

1141 arg_str = self._print( 

1142 v).parens()[0] 

1143 

1144 o1.append(arg_str + ' ' + k._pretty_form) 

1145 vectstrs.append(k._pretty_form) 

1146 

1147 #outstr = u("").join(o1) 

1148 if o1[0].startswith(" + "): 

1149 o1[0] = o1[0][3:] 

1150 elif o1[0].startswith(" "): 

1151 o1[0] = o1[0][1:] 

1152 #Fixing the newlines 

1153 lengths = [] 

1154 strs = [''] 

1155 flag = [] 

1156 for i, partstr in enumerate(o1): 

1157 flag.append(0) 

1158 # XXX: What is this hack? 

1159 if '\n' in partstr: 

1160 tempstr = partstr 

1161 tempstr = tempstr.replace(vectstrs[i], '') 

1162 if '\N{RIGHT PARENTHESIS EXTENSION}' in tempstr: # If scalar is a fraction 

1163 for paren in range(len(tempstr)): 

1164 flag[i] = 1 

1165 if tempstr[paren] == '\N{RIGHT PARENTHESIS EXTENSION}' and tempstr[paren + 1] == '\n': 

1166 # We want to place the vector string after all the right parentheses, because 

1167 # otherwise, the vector will be in the middle of the string 

1168 tempstr = tempstr[:paren] + '\N{RIGHT PARENTHESIS EXTENSION}'\ 

1169 + ' ' + vectstrs[i] + tempstr[paren + 1:] 

1170 break 

1171 elif '\N{RIGHT PARENTHESIS LOWER HOOK}' in tempstr: 

1172 # We want to place the vector string after all the right parentheses, because 

1173 # otherwise, the vector will be in the middle of the string. For this reason, 

1174 # we insert the vector string at the rightmost index. 

1175 index = tempstr.rfind('\N{RIGHT PARENTHESIS LOWER HOOK}') 

1176 if index != -1: # then this character was found in this string 

1177 flag[i] = 1 

1178 tempstr = tempstr[:index] + '\N{RIGHT PARENTHESIS LOWER HOOK}'\ 

1179 + ' ' + vectstrs[i] + tempstr[index + 1:] 

1180 o1[i] = tempstr 

1181 

1182 o1 = [x.split('\n') for x in o1] 

1183 n_newlines = max([len(x) for x in o1]) # Width of part in its pretty form 

1184 

1185 if 1 in flag: # If there was a fractional scalar 

1186 for i, parts in enumerate(o1): 

1187 if len(parts) == 1: # If part has no newline 

1188 parts.insert(0, ' ' * (len(parts[0]))) 

1189 flag[i] = 1 

1190 

1191 for i, parts in enumerate(o1): 

1192 lengths.append(len(parts[flag[i]])) 

1193 for j in range(n_newlines): 

1194 if j+1 <= len(parts): 

1195 if j >= len(strs): 

1196 strs.append(' ' * (sum(lengths[:-1]) + 

1197 3*(len(lengths)-1))) 

1198 if j == flag[i]: 

1199 strs[flag[i]] += parts[flag[i]] + ' + ' 

1200 else: 

1201 strs[j] += parts[j] + ' '*(lengths[-1] - 

1202 len(parts[j])+ 

1203 3) 

1204 else: 

1205 if j >= len(strs): 

1206 strs.append(' ' * (sum(lengths[:-1]) + 

1207 3*(len(lengths)-1))) 

1208 strs[j] += ' '*(lengths[-1]+3) 

1209 

1210 return prettyForm('\n'.join([s[:-3] for s in strs])) 

1211 

1212 def _print_NDimArray(self, expr): 

1213 from sympy.matrices.immutable import ImmutableMatrix 

1214 

1215 if expr.rank() == 0: 

1216 return self._print(expr[()]) 

1217 

1218 level_str = [[]] + [[] for i in range(expr.rank())] 

1219 shape_ranges = [list(range(i)) for i in expr.shape] 

1220 # leave eventual matrix elements unflattened 

1221 mat = lambda x: ImmutableMatrix(x, evaluate=False) 

1222 for outer_i in itertools.product(*shape_ranges): 

1223 level_str[-1].append(expr[outer_i]) 

1224 even = True 

1225 for back_outer_i in range(expr.rank()-1, -1, -1): 

1226 if len(level_str[back_outer_i+1]) < expr.shape[back_outer_i]: 

1227 break 

1228 if even: 

1229 level_str[back_outer_i].append(level_str[back_outer_i+1]) 

1230 else: 

1231 level_str[back_outer_i].append(mat( 

1232 level_str[back_outer_i+1])) 

1233 if len(level_str[back_outer_i + 1]) == 1: 

1234 level_str[back_outer_i][-1] = mat( 

1235 [[level_str[back_outer_i][-1]]]) 

1236 even = not even 

1237 level_str[back_outer_i+1] = [] 

1238 

1239 out_expr = level_str[0][0] 

1240 if expr.rank() % 2 == 1: 

1241 out_expr = mat([out_expr]) 

1242 

1243 return self._print(out_expr) 

1244 

1245 def _printer_tensor_indices(self, name, indices, index_map={}): 

1246 center = stringPict(name) 

1247 top = stringPict(" "*center.width()) 

1248 bot = stringPict(" "*center.width()) 

1249 

1250 last_valence = None 

1251 prev_map = None 

1252 

1253 for i, index in enumerate(indices): 

1254 indpic = self._print(index.args[0]) 

1255 if ((index in index_map) or prev_map) and last_valence == index.is_up: 

1256 if index.is_up: 

1257 top = prettyForm(*stringPict.next(top, ",")) 

1258 else: 

1259 bot = prettyForm(*stringPict.next(bot, ",")) 

1260 if index in index_map: 

1261 indpic = prettyForm(*stringPict.next(indpic, "=")) 

1262 indpic = prettyForm(*stringPict.next(indpic, self._print(index_map[index]))) 

1263 prev_map = True 

1264 else: 

1265 prev_map = False 

1266 if index.is_up: 

1267 top = stringPict(*top.right(indpic)) 

1268 center = stringPict(*center.right(" "*indpic.width())) 

1269 bot = stringPict(*bot.right(" "*indpic.width())) 

1270 else: 

1271 bot = stringPict(*bot.right(indpic)) 

1272 center = stringPict(*center.right(" "*indpic.width())) 

1273 top = stringPict(*top.right(" "*indpic.width())) 

1274 last_valence = index.is_up 

1275 

1276 pict = prettyForm(*center.above(top)) 

1277 pict = prettyForm(*pict.below(bot)) 

1278 return pict 

1279 

1280 def _print_Tensor(self, expr): 

1281 name = expr.args[0].name 

1282 indices = expr.get_indices() 

1283 return self._printer_tensor_indices(name, indices) 

1284 

1285 def _print_TensorElement(self, expr): 

1286 name = expr.expr.args[0].name 

1287 indices = expr.expr.get_indices() 

1288 index_map = expr.index_map 

1289 return self._printer_tensor_indices(name, indices, index_map) 

1290 

1291 def _print_TensMul(self, expr): 

1292 sign, args = expr._get_args_for_traditional_printer() 

1293 args = [ 

1294 prettyForm(*self._print(i).parens()) if 

1295 precedence_traditional(i) < PRECEDENCE["Mul"] else self._print(i) 

1296 for i in args 

1297 ] 

1298 pform = prettyForm.__mul__(*args) 

1299 if sign: 

1300 return prettyForm(*pform.left(sign)) 

1301 else: 

1302 return pform 

1303 

1304 def _print_TensAdd(self, expr): 

1305 args = [ 

1306 prettyForm(*self._print(i).parens()) if 

1307 precedence_traditional(i) < PRECEDENCE["Mul"] else self._print(i) 

1308 for i in expr.args 

1309 ] 

1310 return prettyForm.__add__(*args) 

1311 

1312 def _print_TensorIndex(self, expr): 

1313 sym = expr.args[0] 

1314 if not expr.is_up: 

1315 sym = -sym 

1316 return self._print(sym) 

1317 

1318 def _print_PartialDerivative(self, deriv): 

1319 if self._use_unicode: 

1320 deriv_symbol = U('PARTIAL DIFFERENTIAL') 

1321 else: 

1322 deriv_symbol = r'd' 

1323 x = None 

1324 

1325 for variable in reversed(deriv.variables): 

1326 s = self._print(variable) 

1327 ds = prettyForm(*s.left(deriv_symbol)) 

1328 

1329 if x is None: 

1330 x = ds 

1331 else: 

1332 x = prettyForm(*x.right(' ')) 

1333 x = prettyForm(*x.right(ds)) 

1334 

1335 f = prettyForm( 

1336 binding=prettyForm.FUNC, *self._print(deriv.expr).parens()) 

1337 

1338 pform = prettyForm(deriv_symbol) 

1339 

1340 if len(deriv.variables) > 1: 

1341 pform = pform**self._print(len(deriv.variables)) 

1342 

1343 pform = prettyForm(*pform.below(stringPict.LINE, x)) 

1344 pform.baseline = pform.baseline + 1 

1345 pform = prettyForm(*stringPict.next(pform, f)) 

1346 pform.binding = prettyForm.MUL 

1347 

1348 return pform 

1349 

1350 def _print_Piecewise(self, pexpr): 

1351 

1352 P = {} 

1353 for n, ec in enumerate(pexpr.args): 

1354 P[n, 0] = self._print(ec.expr) 

1355 if ec.cond == True: 

1356 P[n, 1] = prettyForm('otherwise') 

1357 else: 

1358 P[n, 1] = prettyForm( 

1359 *prettyForm('for ').right(self._print(ec.cond))) 

1360 hsep = 2 

1361 vsep = 1 

1362 len_args = len(pexpr.args) 

1363 

1364 # max widths 

1365 maxw = [max([P[i, j].width() for i in range(len_args)]) 

1366 for j in range(2)] 

1367 

1368 # FIXME: Refactor this code and matrix into some tabular environment. 

1369 # drawing result 

1370 D = None 

1371 

1372 for i in range(len_args): 

1373 D_row = None 

1374 for j in range(2): 

1375 p = P[i, j] 

1376 assert p.width() <= maxw[j] 

1377 

1378 wdelta = maxw[j] - p.width() 

1379 wleft = wdelta // 2 

1380 wright = wdelta - wleft 

1381 

1382 p = prettyForm(*p.right(' '*wright)) 

1383 p = prettyForm(*p.left(' '*wleft)) 

1384 

1385 if D_row is None: 

1386 D_row = p 

1387 continue 

1388 

1389 D_row = prettyForm(*D_row.right(' '*hsep)) # h-spacer 

1390 D_row = prettyForm(*D_row.right(p)) 

1391 if D is None: 

1392 D = D_row # first row in a picture 

1393 continue 

1394 

1395 # v-spacer 

1396 for _ in range(vsep): 

1397 D = prettyForm(*D.below(' ')) 

1398 

1399 D = prettyForm(*D.below(D_row)) 

1400 

1401 D = prettyForm(*D.parens('{', '')) 

1402 D.baseline = D.height()//2 

1403 D.binding = prettyForm.OPEN 

1404 return D 

1405 

1406 def _print_ITE(self, ite): 

1407 from sympy.functions.elementary.piecewise import Piecewise 

1408 return self._print(ite.rewrite(Piecewise)) 

1409 

1410 def _hprint_vec(self, v): 

1411 D = None 

1412 

1413 for a in v: 

1414 p = a 

1415 if D is None: 

1416 D = p 

1417 else: 

1418 D = prettyForm(*D.right(', ')) 

1419 D = prettyForm(*D.right(p)) 

1420 if D is None: 

1421 D = stringPict(' ') 

1422 

1423 return D 

1424 

1425 def _hprint_vseparator(self, p1, p2, left=None, right=None, delimiter='', ifascii_nougly=False): 

1426 if ifascii_nougly and not self._use_unicode: 

1427 return self._print_seq((p1, '|', p2), left=left, right=right, 

1428 delimiter=delimiter, ifascii_nougly=True) 

1429 tmp = self._print_seq((p1, p2,), left=left, right=right, delimiter=delimiter) 

1430 sep = stringPict(vobj('|', tmp.height()), baseline=tmp.baseline) 

1431 return self._print_seq((p1, sep, p2), left=left, right=right, 

1432 delimiter=delimiter) 

1433 

1434 def _print_hyper(self, e): 

1435 # FIXME refactor Matrix, Piecewise, and this into a tabular environment 

1436 ap = [self._print(a) for a in e.ap] 

1437 bq = [self._print(b) for b in e.bq] 

1438 

1439 P = self._print(e.argument) 

1440 P.baseline = P.height()//2 

1441 

1442 # Drawing result - first create the ap, bq vectors 

1443 D = None 

1444 for v in [ap, bq]: 

1445 D_row = self._hprint_vec(v) 

1446 if D is None: 

1447 D = D_row # first row in a picture 

1448 else: 

1449 D = prettyForm(*D.below(' ')) 

1450 D = prettyForm(*D.below(D_row)) 

1451 

1452 # make sure that the argument `z' is centred vertically 

1453 D.baseline = D.height()//2 

1454 

1455 # insert horizontal separator 

1456 P = prettyForm(*P.left(' ')) 

1457 D = prettyForm(*D.right(' ')) 

1458 

1459 # insert separating `|` 

1460 D = self._hprint_vseparator(D, P) 

1461 

1462 # add parens 

1463 D = prettyForm(*D.parens('(', ')')) 

1464 

1465 # create the F symbol 

1466 above = D.height()//2 - 1 

1467 below = D.height() - above - 1 

1468 

1469 sz, t, b, add, img = annotated('F') 

1470 F = prettyForm('\n' * (above - t) + img + '\n' * (below - b), 

1471 baseline=above + sz) 

1472 add = (sz + 1)//2 

1473 

1474 F = prettyForm(*F.left(self._print(len(e.ap)))) 

1475 F = prettyForm(*F.right(self._print(len(e.bq)))) 

1476 F.baseline = above + add 

1477 

1478 D = prettyForm(*F.right(' ', D)) 

1479 

1480 return D 

1481 

1482 def _print_meijerg(self, e): 

1483 # FIXME refactor Matrix, Piecewise, and this into a tabular environment 

1484 

1485 v = {} 

1486 v[(0, 0)] = [self._print(a) for a in e.an] 

1487 v[(0, 1)] = [self._print(a) for a in e.aother] 

1488 v[(1, 0)] = [self._print(b) for b in e.bm] 

1489 v[(1, 1)] = [self._print(b) for b in e.bother] 

1490 

1491 P = self._print(e.argument) 

1492 P.baseline = P.height()//2 

1493 

1494 vp = {} 

1495 for idx in v: 

1496 vp[idx] = self._hprint_vec(v[idx]) 

1497 

1498 for i in range(2): 

1499 maxw = max(vp[(0, i)].width(), vp[(1, i)].width()) 

1500 for j in range(2): 

1501 s = vp[(j, i)] 

1502 left = (maxw - s.width()) // 2 

1503 right = maxw - left - s.width() 

1504 s = prettyForm(*s.left(' ' * left)) 

1505 s = prettyForm(*s.right(' ' * right)) 

1506 vp[(j, i)] = s 

1507 

1508 D1 = prettyForm(*vp[(0, 0)].right(' ', vp[(0, 1)])) 

1509 D1 = prettyForm(*D1.below(' ')) 

1510 D2 = prettyForm(*vp[(1, 0)].right(' ', vp[(1, 1)])) 

1511 D = prettyForm(*D1.below(D2)) 

1512 

1513 # make sure that the argument `z' is centred vertically 

1514 D.baseline = D.height()//2 

1515 

1516 # insert horizontal separator 

1517 P = prettyForm(*P.left(' ')) 

1518 D = prettyForm(*D.right(' ')) 

1519 

1520 # insert separating `|` 

1521 D = self._hprint_vseparator(D, P) 

1522 

1523 # add parens 

1524 D = prettyForm(*D.parens('(', ')')) 

1525 

1526 # create the G symbol 

1527 above = D.height()//2 - 1 

1528 below = D.height() - above - 1 

1529 

1530 sz, t, b, add, img = annotated('G') 

1531 F = prettyForm('\n' * (above - t) + img + '\n' * (below - b), 

1532 baseline=above + sz) 

1533 

1534 pp = self._print(len(e.ap)) 

1535 pq = self._print(len(e.bq)) 

1536 pm = self._print(len(e.bm)) 

1537 pn = self._print(len(e.an)) 

1538 

1539 def adjust(p1, p2): 

1540 diff = p1.width() - p2.width() 

1541 if diff == 0: 

1542 return p1, p2 

1543 elif diff > 0: 

1544 return p1, prettyForm(*p2.left(' '*diff)) 

1545 else: 

1546 return prettyForm(*p1.left(' '*-diff)), p2 

1547 pp, pm = adjust(pp, pm) 

1548 pq, pn = adjust(pq, pn) 

1549 pu = prettyForm(*pm.right(', ', pn)) 

1550 pl = prettyForm(*pp.right(', ', pq)) 

1551 

1552 ht = F.baseline - above - 2 

1553 if ht > 0: 

1554 pu = prettyForm(*pu.below('\n'*ht)) 

1555 p = prettyForm(*pu.below(pl)) 

1556 

1557 F.baseline = above 

1558 F = prettyForm(*F.right(p)) 

1559 

1560 F.baseline = above + add 

1561 

1562 D = prettyForm(*F.right(' ', D)) 

1563 

1564 return D 

1565 

1566 def _print_ExpBase(self, e): 

1567 # TODO should exp_polar be printed differently? 

1568 # what about exp_polar(0), exp_polar(1)? 

1569 base = prettyForm(pretty_atom('Exp1', 'e')) 

1570 return base ** self._print(e.args[0]) 

1571 

1572 def _print_Exp1(self, e): 

1573 return prettyForm(pretty_atom('Exp1', 'e')) 

1574 

1575 def _print_Function(self, e, sort=False, func_name=None, left='(', 

1576 right=')'): 

1577 # optional argument func_name for supplying custom names 

1578 # XXX works only for applied functions 

1579 return self._helper_print_function(e.func, e.args, sort=sort, func_name=func_name, left=left, right=right) 

1580 

1581 def _print_mathieuc(self, e): 

1582 return self._print_Function(e, func_name='C') 

1583 

1584 def _print_mathieus(self, e): 

1585 return self._print_Function(e, func_name='S') 

1586 

1587 def _print_mathieucprime(self, e): 

1588 return self._print_Function(e, func_name="C'") 

1589 

1590 def _print_mathieusprime(self, e): 

1591 return self._print_Function(e, func_name="S'") 

1592 

1593 def _helper_print_function(self, func, args, sort=False, func_name=None, 

1594 delimiter=', ', elementwise=False, left='(', 

1595 right=')'): 

1596 if sort: 

1597 args = sorted(args, key=default_sort_key) 

1598 

1599 if not func_name and hasattr(func, "__name__"): 

1600 func_name = func.__name__ 

1601 

1602 if func_name: 

1603 prettyFunc = self._print(Symbol(func_name)) 

1604 else: 

1605 prettyFunc = prettyForm(*self._print(func).parens()) 

1606 

1607 if elementwise: 

1608 if self._use_unicode: 

1609 circ = pretty_atom('Modifier Letter Low Ring') 

1610 else: 

1611 circ = '.' 

1612 circ = self._print(circ) 

1613 prettyFunc = prettyForm( 

1614 binding=prettyForm.LINE, 

1615 *stringPict.next(prettyFunc, circ) 

1616 ) 

1617 

1618 prettyArgs = prettyForm(*self._print_seq(args, delimiter=delimiter).parens( 

1619 left=left, right=right)) 

1620 

1621 pform = prettyForm( 

1622 binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs)) 

1623 

1624 # store pform parts so it can be reassembled e.g. when powered 

1625 pform.prettyFunc = prettyFunc 

1626 pform.prettyArgs = prettyArgs 

1627 

1628 return pform 

1629 

1630 def _print_ElementwiseApplyFunction(self, e): 

1631 func = e.function 

1632 arg = e.expr 

1633 args = [arg] 

1634 return self._helper_print_function(func, args, delimiter="", elementwise=True) 

1635 

1636 @property 

1637 def _special_function_classes(self): 

1638 from sympy.functions.special.tensor_functions import KroneckerDelta 

1639 from sympy.functions.special.gamma_functions import gamma, lowergamma 

1640 from sympy.functions.special.zeta_functions import lerchphi 

1641 from sympy.functions.special.beta_functions import beta 

1642 from sympy.functions.special.delta_functions import DiracDelta 

1643 from sympy.functions.special.error_functions import Chi 

1644 return {KroneckerDelta: [greek_unicode['delta'], 'delta'], 

1645 gamma: [greek_unicode['Gamma'], 'Gamma'], 

1646 lerchphi: [greek_unicode['Phi'], 'lerchphi'], 

1647 lowergamma: [greek_unicode['gamma'], 'gamma'], 

1648 beta: [greek_unicode['Beta'], 'B'], 

1649 DiracDelta: [greek_unicode['delta'], 'delta'], 

1650 Chi: ['Chi', 'Chi']} 

1651 

1652 def _print_FunctionClass(self, expr): 

1653 for cls in self._special_function_classes: 

1654 if issubclass(expr, cls) and expr.__name__ == cls.__name__: 

1655 if self._use_unicode: 

1656 return prettyForm(self._special_function_classes[cls][0]) 

1657 else: 

1658 return prettyForm(self._special_function_classes[cls][1]) 

1659 func_name = expr.__name__ 

1660 return prettyForm(pretty_symbol(func_name)) 

1661 

1662 def _print_GeometryEntity(self, expr): 

1663 # GeometryEntity is based on Tuple but should not print like a Tuple 

1664 return self.emptyPrinter(expr) 

1665 

1666 def _print_lerchphi(self, e): 

1667 func_name = greek_unicode['Phi'] if self._use_unicode else 'lerchphi' 

1668 return self._print_Function(e, func_name=func_name) 

1669 

1670 def _print_dirichlet_eta(self, e): 

1671 func_name = greek_unicode['eta'] if self._use_unicode else 'dirichlet_eta' 

1672 return self._print_Function(e, func_name=func_name) 

1673 

1674 def _print_Heaviside(self, e): 

1675 func_name = greek_unicode['theta'] if self._use_unicode else 'Heaviside' 

1676 if e.args[1] is S.Half: 

1677 pform = prettyForm(*self._print(e.args[0]).parens()) 

1678 pform = prettyForm(*pform.left(func_name)) 

1679 return pform 

1680 else: 

1681 return self._print_Function(e, func_name=func_name) 

1682 

1683 def _print_fresnels(self, e): 

1684 return self._print_Function(e, func_name="S") 

1685 

1686 def _print_fresnelc(self, e): 

1687 return self._print_Function(e, func_name="C") 

1688 

1689 def _print_airyai(self, e): 

1690 return self._print_Function(e, func_name="Ai") 

1691 

1692 def _print_airybi(self, e): 

1693 return self._print_Function(e, func_name="Bi") 

1694 

1695 def _print_airyaiprime(self, e): 

1696 return self._print_Function(e, func_name="Ai'") 

1697 

1698 def _print_airybiprime(self, e): 

1699 return self._print_Function(e, func_name="Bi'") 

1700 

1701 def _print_LambertW(self, e): 

1702 return self._print_Function(e, func_name="W") 

1703 

1704 def _print_Covariance(self, e): 

1705 return self._print_Function(e, func_name="Cov") 

1706 

1707 def _print_Variance(self, e): 

1708 return self._print_Function(e, func_name="Var") 

1709 

1710 def _print_Probability(self, e): 

1711 return self._print_Function(e, func_name="P") 

1712 

1713 def _print_Expectation(self, e): 

1714 return self._print_Function(e, func_name="E", left='[', right=']') 

1715 

1716 def _print_Lambda(self, e): 

1717 expr = e.expr 

1718 sig = e.signature 

1719 if self._use_unicode: 

1720 arrow = " \N{RIGHTWARDS ARROW FROM BAR} " 

1721 else: 

1722 arrow = " -> " 

1723 if len(sig) == 1 and sig[0].is_symbol: 

1724 sig = sig[0] 

1725 var_form = self._print(sig) 

1726 

1727 return prettyForm(*stringPict.next(var_form, arrow, self._print(expr)), binding=8) 

1728 

1729 def _print_Order(self, expr): 

1730 pform = self._print(expr.expr) 

1731 if (expr.point and any(p != S.Zero for p in expr.point)) or \ 

1732 len(expr.variables) > 1: 

1733 pform = prettyForm(*pform.right("; ")) 

1734 if len(expr.variables) > 1: 

1735 pform = prettyForm(*pform.right(self._print(expr.variables))) 

1736 elif len(expr.variables): 

1737 pform = prettyForm(*pform.right(self._print(expr.variables[0]))) 

1738 if self._use_unicode: 

1739 pform = prettyForm(*pform.right(" \N{RIGHTWARDS ARROW} ")) 

1740 else: 

1741 pform = prettyForm(*pform.right(" -> ")) 

1742 if len(expr.point) > 1: 

1743 pform = prettyForm(*pform.right(self._print(expr.point))) 

1744 else: 

1745 pform = prettyForm(*pform.right(self._print(expr.point[0]))) 

1746 pform = prettyForm(*pform.parens()) 

1747 pform = prettyForm(*pform.left("O")) 

1748 return pform 

1749 

1750 def _print_SingularityFunction(self, e): 

1751 if self._use_unicode: 

1752 shift = self._print(e.args[0]-e.args[1]) 

1753 n = self._print(e.args[2]) 

1754 base = prettyForm("<") 

1755 base = prettyForm(*base.right(shift)) 

1756 base = prettyForm(*base.right(">")) 

1757 pform = base**n 

1758 return pform 

1759 else: 

1760 n = self._print(e.args[2]) 

1761 shift = self._print(e.args[0]-e.args[1]) 

1762 base = self._print_seq(shift, "<", ">", ' ') 

1763 return base**n 

1764 

1765 def _print_beta(self, e): 

1766 func_name = greek_unicode['Beta'] if self._use_unicode else 'B' 

1767 return self._print_Function(e, func_name=func_name) 

1768 

1769 def _print_betainc(self, e): 

1770 func_name = "B'" 

1771 return self._print_Function(e, func_name=func_name) 

1772 

1773 def _print_betainc_regularized(self, e): 

1774 func_name = 'I' 

1775 return self._print_Function(e, func_name=func_name) 

1776 

1777 def _print_gamma(self, e): 

1778 func_name = greek_unicode['Gamma'] if self._use_unicode else 'Gamma' 

1779 return self._print_Function(e, func_name=func_name) 

1780 

1781 def _print_uppergamma(self, e): 

1782 func_name = greek_unicode['Gamma'] if self._use_unicode else 'Gamma' 

1783 return self._print_Function(e, func_name=func_name) 

1784 

1785 def _print_lowergamma(self, e): 

1786 func_name = greek_unicode['gamma'] if self._use_unicode else 'lowergamma' 

1787 return self._print_Function(e, func_name=func_name) 

1788 

1789 def _print_DiracDelta(self, e): 

1790 if self._use_unicode: 

1791 if len(e.args) == 2: 

1792 a = prettyForm(greek_unicode['delta']) 

1793 b = self._print(e.args[1]) 

1794 b = prettyForm(*b.parens()) 

1795 c = self._print(e.args[0]) 

1796 c = prettyForm(*c.parens()) 

1797 pform = a**b 

1798 pform = prettyForm(*pform.right(' ')) 

1799 pform = prettyForm(*pform.right(c)) 

1800 return pform 

1801 pform = self._print(e.args[0]) 

1802 pform = prettyForm(*pform.parens()) 

1803 pform = prettyForm(*pform.left(greek_unicode['delta'])) 

1804 return pform 

1805 else: 

1806 return self._print_Function(e) 

1807 

1808 def _print_expint(self, e): 

1809 if e.args[0].is_Integer and self._use_unicode: 

1810 return self._print_Function(Function('E_%s' % e.args[0])(e.args[1])) 

1811 return self._print_Function(e) 

1812 

1813 def _print_Chi(self, e): 

1814 # This needs a special case since otherwise it comes out as greek 

1815 # letter chi... 

1816 prettyFunc = prettyForm("Chi") 

1817 prettyArgs = prettyForm(*self._print_seq(e.args).parens()) 

1818 

1819 pform = prettyForm( 

1820 binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs)) 

1821 

1822 # store pform parts so it can be reassembled e.g. when powered 

1823 pform.prettyFunc = prettyFunc 

1824 pform.prettyArgs = prettyArgs 

1825 

1826 return pform 

1827 

1828 def _print_elliptic_e(self, e): 

1829 pforma0 = self._print(e.args[0]) 

1830 if len(e.args) == 1: 

1831 pform = pforma0 

1832 else: 

1833 pforma1 = self._print(e.args[1]) 

1834 pform = self._hprint_vseparator(pforma0, pforma1) 

1835 pform = prettyForm(*pform.parens()) 

1836 pform = prettyForm(*pform.left('E')) 

1837 return pform 

1838 

1839 def _print_elliptic_k(self, e): 

1840 pform = self._print(e.args[0]) 

1841 pform = prettyForm(*pform.parens()) 

1842 pform = prettyForm(*pform.left('K')) 

1843 return pform 

1844 

1845 def _print_elliptic_f(self, e): 

1846 pforma0 = self._print(e.args[0]) 

1847 pforma1 = self._print(e.args[1]) 

1848 pform = self._hprint_vseparator(pforma0, pforma1) 

1849 pform = prettyForm(*pform.parens()) 

1850 pform = prettyForm(*pform.left('F')) 

1851 return pform 

1852 

1853 def _print_elliptic_pi(self, e): 

1854 name = greek_unicode['Pi'] if self._use_unicode else 'Pi' 

1855 pforma0 = self._print(e.args[0]) 

1856 pforma1 = self._print(e.args[1]) 

1857 if len(e.args) == 2: 

1858 pform = self._hprint_vseparator(pforma0, pforma1) 

1859 else: 

1860 pforma2 = self._print(e.args[2]) 

1861 pforma = self._hprint_vseparator(pforma1, pforma2, ifascii_nougly=False) 

1862 pforma = prettyForm(*pforma.left('; ')) 

1863 pform = prettyForm(*pforma.left(pforma0)) 

1864 pform = prettyForm(*pform.parens()) 

1865 pform = prettyForm(*pform.left(name)) 

1866 return pform 

1867 

1868 def _print_GoldenRatio(self, expr): 

1869 if self._use_unicode: 

1870 return prettyForm(pretty_symbol('phi')) 

1871 return self._print(Symbol("GoldenRatio")) 

1872 

1873 def _print_EulerGamma(self, expr): 

1874 if self._use_unicode: 

1875 return prettyForm(pretty_symbol('gamma')) 

1876 return self._print(Symbol("EulerGamma")) 

1877 

1878 def _print_Catalan(self, expr): 

1879 return self._print(Symbol("G")) 

1880 

1881 def _print_Mod(self, expr): 

1882 pform = self._print(expr.args[0]) 

1883 if pform.binding > prettyForm.MUL: 

1884 pform = prettyForm(*pform.parens()) 

1885 pform = prettyForm(*pform.right(' mod ')) 

1886 pform = prettyForm(*pform.right(self._print(expr.args[1]))) 

1887 pform.binding = prettyForm.OPEN 

1888 return pform 

1889 

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

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

1892 pforms, indices = [], [] 

1893 

1894 def pretty_negative(pform, index): 

1895 """Prepend a minus sign to a pretty form. """ 

1896 #TODO: Move this code to prettyForm 

1897 if index == 0: 

1898 if pform.height() > 1: 

1899 pform_neg = '- ' 

1900 else: 

1901 pform_neg = '-' 

1902 else: 

1903 pform_neg = ' - ' 

1904 

1905 if (pform.binding > prettyForm.NEG 

1906 or pform.binding == prettyForm.ADD): 

1907 p = stringPict(*pform.parens()) 

1908 else: 

1909 p = pform 

1910 p = stringPict.next(pform_neg, p) 

1911 # Lower the binding to NEG, even if it was higher. Otherwise, it 

1912 # will print as a + ( - (b)), instead of a - (b). 

1913 return prettyForm(binding=prettyForm.NEG, *p) 

1914 

1915 for i, term in enumerate(terms): 

1916 if term.is_Mul and term.could_extract_minus_sign(): 

1917 coeff, other = term.as_coeff_mul(rational=False) 

1918 if coeff == -1: 

1919 negterm = Mul(*other, evaluate=False) 

1920 else: 

1921 negterm = Mul(-coeff, *other, evaluate=False) 

1922 pform = self._print(negterm) 

1923 pforms.append(pretty_negative(pform, i)) 

1924 elif term.is_Rational and term.q > 1: 

1925 pforms.append(None) 

1926 indices.append(i) 

1927 elif term.is_Number and term < 0: 

1928 pform = self._print(-term) 

1929 pforms.append(pretty_negative(pform, i)) 

1930 elif term.is_Relational: 

1931 pforms.append(prettyForm(*self._print(term).parens())) 

1932 else: 

1933 pforms.append(self._print(term)) 

1934 

1935 if indices: 

1936 large = True 

1937 

1938 for pform in pforms: 

1939 if pform is not None and pform.height() > 1: 

1940 break 

1941 else: 

1942 large = False 

1943 

1944 for i in indices: 

1945 term, negative = terms[i], False 

1946 

1947 if term < 0: 

1948 term, negative = -term, True 

1949 

1950 if large: 

1951 pform = prettyForm(str(term.p))/prettyForm(str(term.q)) 

1952 else: 

1953 pform = self._print(term) 

1954 

1955 if negative: 

1956 pform = pretty_negative(pform, i) 

1957 

1958 pforms[i] = pform 

1959 

1960 return prettyForm.__add__(*pforms) 

1961 

1962 def _print_Mul(self, product): 

1963 from sympy.physics.units import Quantity 

1964 

1965 # Check for unevaluated Mul. In this case we need to make sure the 

1966 # identities are visible, multiple Rational factors are not combined 

1967 # etc so we display in a straight-forward form that fully preserves all 

1968 # args and their order. 

1969 args = product.args 

1970 if args[0] is S.One or any(isinstance(arg, Number) for arg in args[1:]): 

1971 strargs = list(map(self._print, args)) 

1972 # XXX: This is a hack to work around the fact that 

1973 # prettyForm.__mul__ absorbs a leading -1 in the args. Probably it 

1974 # would be better to fix this in prettyForm.__mul__ instead. 

1975 negone = strargs[0] == '-1' 

1976 if negone: 

1977 strargs[0] = prettyForm('1', 0, 0) 

1978 obj = prettyForm.__mul__(*strargs) 

1979 if negone: 

1980 obj = prettyForm('-' + obj.s, obj.baseline, obj.binding) 

1981 return obj 

1982 

1983 a = [] # items in the numerator 

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

1985 

1986 if self.order not in ('old', 'none'): 

1987 args = product.as_ordered_factors() 

1988 else: 

1989 args = list(product.args) 

1990 

1991 # If quantities are present append them at the back 

1992 args = sorted(args, key=lambda x: isinstance(x, Quantity) or 

1993 (isinstance(x, Pow) and isinstance(x.base, Quantity))) 

1994 

1995 # Gather terms for numerator/denominator 

1996 for item in args: 

1997 if item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative: 

1998 if item.exp != -1: 

1999 b.append(Pow(item.base, -item.exp, evaluate=False)) 

2000 else: 

2001 b.append(Pow(item.base, -item.exp)) 

2002 elif item.is_Rational and item is not S.Infinity: 

2003 if item.p != 1: 

2004 a.append( Rational(item.p) ) 

2005 if item.q != 1: 

2006 b.append( Rational(item.q) ) 

2007 else: 

2008 a.append(item) 

2009 

2010 # Convert to pretty forms. Parentheses are added by `__mul__`. 

2011 a = [self._print(ai) for ai in a] 

2012 b = [self._print(bi) for bi in b] 

2013 

2014 # Construct a pretty form 

2015 if len(b) == 0: 

2016 return prettyForm.__mul__(*a) 

2017 else: 

2018 if len(a) == 0: 

2019 a.append( self._print(S.One) ) 

2020 return prettyForm.__mul__(*a)/prettyForm.__mul__(*b) 

2021 

2022 # A helper function for _print_Pow to print x**(1/n) 

2023 def _print_nth_root(self, base, root): 

2024 bpretty = self._print(base) 

2025 

2026 # In very simple cases, use a single-char root sign 

2027 if (self._settings['use_unicode_sqrt_char'] and self._use_unicode 

2028 and root == 2 and bpretty.height() == 1 

2029 and (bpretty.width() == 1 

2030 or (base.is_Integer and base.is_nonnegative))): 

2031 return prettyForm(*bpretty.left('\N{SQUARE ROOT}')) 

2032 

2033 # Construct root sign, start with the \/ shape 

2034 _zZ = xobj('/', 1) 

2035 rootsign = xobj('\\', 1) + _zZ 

2036 # Constructing the number to put on root 

2037 rpretty = self._print(root) 

2038 # roots look bad if they are not a single line 

2039 if rpretty.height() != 1: 

2040 return self._print(base)**self._print(1/root) 

2041 # If power is half, no number should appear on top of root sign 

2042 exp = '' if root == 2 else str(rpretty).ljust(2) 

2043 if len(exp) > 2: 

2044 rootsign = ' '*(len(exp) - 2) + rootsign 

2045 # Stack the exponent 

2046 rootsign = stringPict(exp + '\n' + rootsign) 

2047 rootsign.baseline = 0 

2048 # Diagonal: length is one less than height of base 

2049 linelength = bpretty.height() - 1 

2050 diagonal = stringPict('\n'.join( 

2051 ' '*(linelength - i - 1) + _zZ + ' '*i 

2052 for i in range(linelength) 

2053 )) 

2054 # Put baseline just below lowest line: next to exp 

2055 diagonal.baseline = linelength - 1 

2056 # Make the root symbol 

2057 rootsign = prettyForm(*rootsign.right(diagonal)) 

2058 # Det the baseline to match contents to fix the height 

2059 # but if the height of bpretty is one, the rootsign must be one higher 

2060 rootsign.baseline = max(1, bpretty.baseline) 

2061 #build result 

2062 s = prettyForm(hobj('_', 2 + bpretty.width())) 

2063 s = prettyForm(*bpretty.above(s)) 

2064 s = prettyForm(*s.left(rootsign)) 

2065 return s 

2066 

2067 def _print_Pow(self, power): 

2068 from sympy.simplify.simplify import fraction 

2069 b, e = power.as_base_exp() 

2070 if power.is_commutative: 

2071 if e is S.NegativeOne: 

2072 return prettyForm("1")/self._print(b) 

2073 n, d = fraction(e) 

2074 if n is S.One and d.is_Atom and not e.is_Integer and (e.is_Rational or d.is_Symbol) \ 

2075 and self._settings['root_notation']: 

2076 return self._print_nth_root(b, d) 

2077 if e.is_Rational and e < 0: 

2078 return prettyForm("1")/self._print(Pow(b, -e, evaluate=False)) 

2079 

2080 if b.is_Relational: 

2081 return prettyForm(*self._print(b).parens()).__pow__(self._print(e)) 

2082 

2083 return self._print(b)**self._print(e) 

2084 

2085 def _print_UnevaluatedExpr(self, expr): 

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

2087 

2088 def __print_numer_denom(self, p, q): 

2089 if q == 1: 

2090 if p < 0: 

2091 return prettyForm(str(p), binding=prettyForm.NEG) 

2092 else: 

2093 return prettyForm(str(p)) 

2094 elif abs(p) >= 10 and abs(q) >= 10: 

2095 # If more than one digit in numer and denom, print larger fraction 

2096 if p < 0: 

2097 return prettyForm(str(p), binding=prettyForm.NEG)/prettyForm(str(q)) 

2098 # Old printing method: 

2099 #pform = prettyForm(str(-p))/prettyForm(str(q)) 

2100 #return prettyForm(binding=prettyForm.NEG, *pform.left('- ')) 

2101 else: 

2102 return prettyForm(str(p))/prettyForm(str(q)) 

2103 else: 

2104 return None 

2105 

2106 def _print_Rational(self, expr): 

2107 result = self.__print_numer_denom(expr.p, expr.q) 

2108 

2109 if result is not None: 

2110 return result 

2111 else: 

2112 return self.emptyPrinter(expr) 

2113 

2114 def _print_Fraction(self, expr): 

2115 result = self.__print_numer_denom(expr.numerator, expr.denominator) 

2116 

2117 if result is not None: 

2118 return result 

2119 else: 

2120 return self.emptyPrinter(expr) 

2121 

2122 def _print_ProductSet(self, p): 

2123 if len(p.sets) >= 1 and not has_variety(p.sets): 

2124 return self._print(p.sets[0]) ** self._print(len(p.sets)) 

2125 else: 

2126 prod_char = "\N{MULTIPLICATION SIGN}" if self._use_unicode else 'x' 

2127 return self._print_seq(p.sets, None, None, ' %s ' % prod_char, 

2128 parenthesize=lambda set: set.is_Union or 

2129 set.is_Intersection or set.is_ProductSet) 

2130 

2131 def _print_FiniteSet(self, s): 

2132 items = sorted(s.args, key=default_sort_key) 

2133 return self._print_seq(items, '{', '}', ', ' ) 

2134 

2135 def _print_Range(self, s): 

2136 

2137 if self._use_unicode: 

2138 dots = "\N{HORIZONTAL ELLIPSIS}" 

2139 else: 

2140 dots = '...' 

2141 

2142 if s.start.is_infinite and s.stop.is_infinite: 

2143 if s.step.is_positive: 

2144 printset = dots, -1, 0, 1, dots 

2145 else: 

2146 printset = dots, 1, 0, -1, dots 

2147 elif s.start.is_infinite: 

2148 printset = dots, s[-1] - s.step, s[-1] 

2149 elif s.stop.is_infinite: 

2150 it = iter(s) 

2151 printset = next(it), next(it), dots 

2152 elif len(s) > 4: 

2153 it = iter(s) 

2154 printset = next(it), next(it), dots, s[-1] 

2155 else: 

2156 printset = tuple(s) 

2157 

2158 return self._print_seq(printset, '{', '}', ', ' ) 

2159 

2160 def _print_Interval(self, i): 

2161 if i.start == i.end: 

2162 return self._print_seq(i.args[:1], '{', '}') 

2163 

2164 else: 

2165 if i.left_open: 

2166 left = '(' 

2167 else: 

2168 left = '[' 

2169 

2170 if i.right_open: 

2171 right = ')' 

2172 else: 

2173 right = ']' 

2174 

2175 return self._print_seq(i.args[:2], left, right) 

2176 

2177 def _print_AccumulationBounds(self, i): 

2178 left = '<' 

2179 right = '>' 

2180 

2181 return self._print_seq(i.args[:2], left, right) 

2182 

2183 def _print_Intersection(self, u): 

2184 

2185 delimiter = ' %s ' % pretty_atom('Intersection', 'n') 

2186 

2187 return self._print_seq(u.args, None, None, delimiter, 

2188 parenthesize=lambda set: set.is_ProductSet or 

2189 set.is_Union or set.is_Complement) 

2190 

2191 def _print_Union(self, u): 

2192 

2193 union_delimiter = ' %s ' % pretty_atom('Union', 'U') 

2194 

2195 return self._print_seq(u.args, None, None, union_delimiter, 

2196 parenthesize=lambda set: set.is_ProductSet or 

2197 set.is_Intersection or set.is_Complement) 

2198 

2199 def _print_SymmetricDifference(self, u): 

2200 if not self._use_unicode: 

2201 raise NotImplementedError("ASCII pretty printing of SymmetricDifference is not implemented") 

2202 

2203 sym_delimeter = ' %s ' % pretty_atom('SymmetricDifference') 

2204 

2205 return self._print_seq(u.args, None, None, sym_delimeter) 

2206 

2207 def _print_Complement(self, u): 

2208 

2209 delimiter = r' \ ' 

2210 

2211 return self._print_seq(u.args, None, None, delimiter, 

2212 parenthesize=lambda set: set.is_ProductSet or set.is_Intersection 

2213 or set.is_Union) 

2214 

2215 def _print_ImageSet(self, ts): 

2216 if self._use_unicode: 

2217 inn = "\N{SMALL ELEMENT OF}" 

2218 else: 

2219 inn = 'in' 

2220 fun = ts.lamda 

2221 sets = ts.base_sets 

2222 signature = fun.signature 

2223 expr = self._print(fun.expr) 

2224 

2225 # TODO: the stuff to the left of the | and the stuff to the right of 

2226 # the | should have independent baselines, that way something like 

2227 # ImageSet(Lambda(x, 1/x**2), S.Naturals) prints the "x in N" part 

2228 # centered on the right instead of aligned with the fraction bar on 

2229 # the left. The same also applies to ConditionSet and ComplexRegion 

2230 if len(signature) == 1: 

2231 S = self._print_seq((signature[0], inn, sets[0]), 

2232 delimiter=' ') 

2233 return self._hprint_vseparator(expr, S, 

2234 left='{', right='}', 

2235 ifascii_nougly=True, delimiter=' ') 

2236 else: 

2237 pargs = tuple(j for var, setv in zip(signature, sets) for j in 

2238 (var, ' ', inn, ' ', setv, ", ")) 

2239 S = self._print_seq(pargs[:-1], delimiter='') 

2240 return self._hprint_vseparator(expr, S, 

2241 left='{', right='}', 

2242 ifascii_nougly=True, delimiter=' ') 

2243 

2244 def _print_ConditionSet(self, ts): 

2245 if self._use_unicode: 

2246 inn = "\N{SMALL ELEMENT OF}" 

2247 # using _and because and is a keyword and it is bad practice to 

2248 # overwrite them 

2249 _and = "\N{LOGICAL AND}" 

2250 else: 

2251 inn = 'in' 

2252 _and = 'and' 

2253 

2254 variables = self._print_seq(Tuple(ts.sym)) 

2255 as_expr = getattr(ts.condition, 'as_expr', None) 

2256 if as_expr is not None: 

2257 cond = self._print(ts.condition.as_expr()) 

2258 else: 

2259 cond = self._print(ts.condition) 

2260 if self._use_unicode: 

2261 cond = self._print(cond) 

2262 cond = prettyForm(*cond.parens()) 

2263 

2264 if ts.base_set is S.UniversalSet: 

2265 return self._hprint_vseparator(variables, cond, left="{", 

2266 right="}", ifascii_nougly=True, 

2267 delimiter=' ') 

2268 

2269 base = self._print(ts.base_set) 

2270 C = self._print_seq((variables, inn, base, _and, cond), 

2271 delimiter=' ') 

2272 return self._hprint_vseparator(variables, C, left="{", right="}", 

2273 ifascii_nougly=True, delimiter=' ') 

2274 

2275 def _print_ComplexRegion(self, ts): 

2276 if self._use_unicode: 

2277 inn = "\N{SMALL ELEMENT OF}" 

2278 else: 

2279 inn = 'in' 

2280 variables = self._print_seq(ts.variables) 

2281 expr = self._print(ts.expr) 

2282 prodsets = self._print(ts.sets) 

2283 

2284 C = self._print_seq((variables, inn, prodsets), 

2285 delimiter=' ') 

2286 return self._hprint_vseparator(expr, C, left="{", right="}", 

2287 ifascii_nougly=True, delimiter=' ') 

2288 

2289 def _print_Contains(self, e): 

2290 var, set = e.args 

2291 if self._use_unicode: 

2292 el = " \N{ELEMENT OF} " 

2293 return prettyForm(*stringPict.next(self._print(var), 

2294 el, self._print(set)), binding=8) 

2295 else: 

2296 return prettyForm(sstr(e)) 

2297 

2298 def _print_FourierSeries(self, s): 

2299 if s.an.formula is S.Zero and s.bn.formula is S.Zero: 

2300 return self._print(s.a0) 

2301 if self._use_unicode: 

2302 dots = "\N{HORIZONTAL ELLIPSIS}" 

2303 else: 

2304 dots = '...' 

2305 return self._print_Add(s.truncate()) + self._print(dots) 

2306 

2307 def _print_FormalPowerSeries(self, s): 

2308 return self._print_Add(s.infinite) 

2309 

2310 def _print_SetExpr(self, se): 

2311 pretty_set = prettyForm(*self._print(se.set).parens()) 

2312 pretty_name = self._print(Symbol("SetExpr")) 

2313 return prettyForm(*pretty_name.right(pretty_set)) 

2314 

2315 def _print_SeqFormula(self, s): 

2316 if self._use_unicode: 

2317 dots = "\N{HORIZONTAL ELLIPSIS}" 

2318 else: 

2319 dots = '...' 

2320 

2321 if len(s.start.free_symbols) > 0 or len(s.stop.free_symbols) > 0: 

2322 raise NotImplementedError("Pretty printing of sequences with symbolic bound not implemented") 

2323 

2324 if s.start is S.NegativeInfinity: 

2325 stop = s.stop 

2326 printset = (dots, s.coeff(stop - 3), s.coeff(stop - 2), 

2327 s.coeff(stop - 1), s.coeff(stop)) 

2328 elif s.stop is S.Infinity or s.length > 4: 

2329 printset = s[:4] 

2330 printset.append(dots) 

2331 printset = tuple(printset) 

2332 else: 

2333 printset = tuple(s) 

2334 return self._print_list(printset) 

2335 

2336 _print_SeqPer = _print_SeqFormula 

2337 _print_SeqAdd = _print_SeqFormula 

2338 _print_SeqMul = _print_SeqFormula 

2339 

2340 def _print_seq(self, seq, left=None, right=None, delimiter=', ', 

2341 parenthesize=lambda x: False, ifascii_nougly=True): 

2342 try: 

2343 pforms = [] 

2344 for item in seq: 

2345 pform = self._print(item) 

2346 if parenthesize(item): 

2347 pform = prettyForm(*pform.parens()) 

2348 if pforms: 

2349 pforms.append(delimiter) 

2350 pforms.append(pform) 

2351 

2352 if not pforms: 

2353 s = stringPict('') 

2354 else: 

2355 s = prettyForm(*stringPict.next(*pforms)) 

2356 

2357 # XXX: Under the tests from #15686 the above raises: 

2358 # AttributeError: 'Fake' object has no attribute 'baseline' 

2359 # This is caught below but that is not the right way to 

2360 # fix it. 

2361 

2362 except AttributeError: 

2363 s = None 

2364 for item in seq: 

2365 pform = self.doprint(item) 

2366 if parenthesize(item): 

2367 pform = prettyForm(*pform.parens()) 

2368 if s is None: 

2369 # first element 

2370 s = pform 

2371 else : 

2372 s = prettyForm(*stringPict.next(s, delimiter)) 

2373 s = prettyForm(*stringPict.next(s, pform)) 

2374 

2375 if s is None: 

2376 s = stringPict('') 

2377 

2378 s = prettyForm(*s.parens(left, right, ifascii_nougly=ifascii_nougly)) 

2379 return s 

2380 

2381 def join(self, delimiter, args): 

2382 pform = None 

2383 

2384 for arg in args: 

2385 if pform is None: 

2386 pform = arg 

2387 else: 

2388 pform = prettyForm(*pform.right(delimiter)) 

2389 pform = prettyForm(*pform.right(arg)) 

2390 

2391 if pform is None: 

2392 return prettyForm("") 

2393 else: 

2394 return pform 

2395 

2396 def _print_list(self, l): 

2397 return self._print_seq(l, '[', ']') 

2398 

2399 def _print_tuple(self, t): 

2400 if len(t) == 1: 

2401 ptuple = prettyForm(*stringPict.next(self._print(t[0]), ',')) 

2402 return prettyForm(*ptuple.parens('(', ')', ifascii_nougly=True)) 

2403 else: 

2404 return self._print_seq(t, '(', ')') 

2405 

2406 def _print_Tuple(self, expr): 

2407 return self._print_tuple(expr) 

2408 

2409 def _print_dict(self, d): 

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

2411 items = [] 

2412 

2413 for k in keys: 

2414 K = self._print(k) 

2415 V = self._print(d[k]) 

2416 s = prettyForm(*stringPict.next(K, ': ', V)) 

2417 

2418 items.append(s) 

2419 

2420 return self._print_seq(items, '{', '}') 

2421 

2422 def _print_Dict(self, d): 

2423 return self._print_dict(d) 

2424 

2425 def _print_set(self, s): 

2426 if not s: 

2427 return prettyForm('set()') 

2428 items = sorted(s, key=default_sort_key) 

2429 pretty = self._print_seq(items) 

2430 pretty = prettyForm(*pretty.parens('{', '}', ifascii_nougly=True)) 

2431 return pretty 

2432 

2433 def _print_frozenset(self, s): 

2434 if not s: 

2435 return prettyForm('frozenset()') 

2436 items = sorted(s, key=default_sort_key) 

2437 pretty = self._print_seq(items) 

2438 pretty = prettyForm(*pretty.parens('{', '}', ifascii_nougly=True)) 

2439 pretty = prettyForm(*pretty.parens('(', ')', ifascii_nougly=True)) 

2440 pretty = prettyForm(*stringPict.next(type(s).__name__, pretty)) 

2441 return pretty 

2442 

2443 def _print_UniversalSet(self, s): 

2444 if self._use_unicode: 

2445 return prettyForm("\N{MATHEMATICAL DOUBLE-STRUCK CAPITAL U}") 

2446 else: 

2447 return prettyForm('UniversalSet') 

2448 

2449 def _print_PolyRing(self, ring): 

2450 return prettyForm(sstr(ring)) 

2451 

2452 def _print_FracField(self, field): 

2453 return prettyForm(sstr(field)) 

2454 

2455 def _print_FreeGroupElement(self, elm): 

2456 return prettyForm(str(elm)) 

2457 

2458 def _print_PolyElement(self, poly): 

2459 return prettyForm(sstr(poly)) 

2460 

2461 def _print_FracElement(self, frac): 

2462 return prettyForm(sstr(frac)) 

2463 

2464 def _print_AlgebraicNumber(self, expr): 

2465 if expr.is_aliased: 

2466 return self._print(expr.as_poly().as_expr()) 

2467 else: 

2468 return self._print(expr.as_expr()) 

2469 

2470 def _print_ComplexRootOf(self, expr): 

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

2472 pform = prettyForm(*self._print_seq(args).parens()) 

2473 pform = prettyForm(*pform.left('CRootOf')) 

2474 return pform 

2475 

2476 def _print_RootSum(self, expr): 

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

2478 

2479 if expr.fun is not S.IdentityFunction: 

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

2481 

2482 pform = prettyForm(*self._print_seq(args).parens()) 

2483 pform = prettyForm(*pform.left('RootSum')) 

2484 

2485 return pform 

2486 

2487 def _print_FiniteField(self, expr): 

2488 if self._use_unicode: 

2489 form = '\N{DOUBLE-STRUCK CAPITAL Z}_%d' 

2490 else: 

2491 form = 'GF(%d)' 

2492 

2493 return prettyForm(pretty_symbol(form % expr.mod)) 

2494 

2495 def _print_IntegerRing(self, expr): 

2496 if self._use_unicode: 

2497 return prettyForm('\N{DOUBLE-STRUCK CAPITAL Z}') 

2498 else: 

2499 return prettyForm('ZZ') 

2500 

2501 def _print_RationalField(self, expr): 

2502 if self._use_unicode: 

2503 return prettyForm('\N{DOUBLE-STRUCK CAPITAL Q}') 

2504 else: 

2505 return prettyForm('QQ') 

2506 

2507 def _print_RealField(self, domain): 

2508 if self._use_unicode: 

2509 prefix = '\N{DOUBLE-STRUCK CAPITAL R}' 

2510 else: 

2511 prefix = 'RR' 

2512 

2513 if domain.has_default_precision: 

2514 return prettyForm(prefix) 

2515 else: 

2516 return self._print(pretty_symbol(prefix + "_" + str(domain.precision))) 

2517 

2518 def _print_ComplexField(self, domain): 

2519 if self._use_unicode: 

2520 prefix = '\N{DOUBLE-STRUCK CAPITAL C}' 

2521 else: 

2522 prefix = 'CC' 

2523 

2524 if domain.has_default_precision: 

2525 return prettyForm(prefix) 

2526 else: 

2527 return self._print(pretty_symbol(prefix + "_" + str(domain.precision))) 

2528 

2529 def _print_PolynomialRing(self, expr): 

2530 args = list(expr.symbols) 

2531 

2532 if not expr.order.is_default: 

2533 order = prettyForm(*prettyForm("order=").right(self._print(expr.order))) 

2534 args.append(order) 

2535 

2536 pform = self._print_seq(args, '[', ']') 

2537 pform = prettyForm(*pform.left(self._print(expr.domain))) 

2538 

2539 return pform 

2540 

2541 def _print_FractionField(self, expr): 

2542 args = list(expr.symbols) 

2543 

2544 if not expr.order.is_default: 

2545 order = prettyForm(*prettyForm("order=").right(self._print(expr.order))) 

2546 args.append(order) 

2547 

2548 pform = self._print_seq(args, '(', ')') 

2549 pform = prettyForm(*pform.left(self._print(expr.domain))) 

2550 

2551 return pform 

2552 

2553 def _print_PolynomialRingBase(self, expr): 

2554 g = expr.symbols 

2555 if str(expr.order) != str(expr.default_order): 

2556 g = g + ("order=" + str(expr.order),) 

2557 pform = self._print_seq(g, '[', ']') 

2558 pform = prettyForm(*pform.left(self._print(expr.domain))) 

2559 

2560 return pform 

2561 

2562 def _print_GroebnerBasis(self, basis): 

2563 exprs = [ self._print_Add(arg, order=basis.order) 

2564 for arg in basis.exprs ] 

2565 exprs = prettyForm(*self.join(", ", exprs).parens(left="[", right="]")) 

2566 

2567 gens = [ self._print(gen) for gen in basis.gens ] 

2568 

2569 domain = prettyForm( 

2570 *prettyForm("domain=").right(self._print(basis.domain))) 

2571 order = prettyForm( 

2572 *prettyForm("order=").right(self._print(basis.order))) 

2573 

2574 pform = self.join(", ", [exprs] + gens + [domain, order]) 

2575 

2576 pform = prettyForm(*pform.parens()) 

2577 pform = prettyForm(*pform.left(basis.__class__.__name__)) 

2578 

2579 return pform 

2580 

2581 def _print_Subs(self, e): 

2582 pform = self._print(e.expr) 

2583 pform = prettyForm(*pform.parens()) 

2584 

2585 h = pform.height() if pform.height() > 1 else 2 

2586 rvert = stringPict(vobj('|', h), baseline=pform.baseline) 

2587 pform = prettyForm(*pform.right(rvert)) 

2588 

2589 b = pform.baseline 

2590 pform.baseline = pform.height() - 1 

2591 pform = prettyForm(*pform.right(self._print_seq([ 

2592 self._print_seq((self._print(v[0]), xsym('=='), self._print(v[1])), 

2593 delimiter='') for v in zip(e.variables, e.point) ]))) 

2594 

2595 pform.baseline = b 

2596 return pform 

2597 

2598 def _print_number_function(self, e, name): 

2599 # Print name_arg[0] for one argument or name_arg[0](arg[1]) 

2600 # for more than one argument 

2601 pform = prettyForm(name) 

2602 arg = self._print(e.args[0]) 

2603 pform_arg = prettyForm(" "*arg.width()) 

2604 pform_arg = prettyForm(*pform_arg.below(arg)) 

2605 pform = prettyForm(*pform.right(pform_arg)) 

2606 if len(e.args) == 1: 

2607 return pform 

2608 m, x = e.args 

2609 # TODO: copy-pasted from _print_Function: can we do better? 

2610 prettyFunc = pform 

2611 prettyArgs = prettyForm(*self._print_seq([x]).parens()) 

2612 pform = prettyForm( 

2613 binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs)) 

2614 pform.prettyFunc = prettyFunc 

2615 pform.prettyArgs = prettyArgs 

2616 return pform 

2617 

2618 def _print_euler(self, e): 

2619 return self._print_number_function(e, "E") 

2620 

2621 def _print_catalan(self, e): 

2622 return self._print_number_function(e, "C") 

2623 

2624 def _print_bernoulli(self, e): 

2625 return self._print_number_function(e, "B") 

2626 

2627 _print_bell = _print_bernoulli 

2628 

2629 def _print_lucas(self, e): 

2630 return self._print_number_function(e, "L") 

2631 

2632 def _print_fibonacci(self, e): 

2633 return self._print_number_function(e, "F") 

2634 

2635 def _print_tribonacci(self, e): 

2636 return self._print_number_function(e, "T") 

2637 

2638 def _print_stieltjes(self, e): 

2639 if self._use_unicode: 

2640 return self._print_number_function(e, '\N{GREEK SMALL LETTER GAMMA}') 

2641 else: 

2642 return self._print_number_function(e, "stieltjes") 

2643 

2644 def _print_KroneckerDelta(self, e): 

2645 pform = self._print(e.args[0]) 

2646 pform = prettyForm(*pform.right(prettyForm(','))) 

2647 pform = prettyForm(*pform.right(self._print(e.args[1]))) 

2648 if self._use_unicode: 

2649 a = stringPict(pretty_symbol('delta')) 

2650 else: 

2651 a = stringPict('d') 

2652 b = pform 

2653 top = stringPict(*b.left(' '*a.width())) 

2654 bot = stringPict(*a.right(' '*b.width())) 

2655 return prettyForm(binding=prettyForm.POW, *bot.below(top)) 

2656 

2657 def _print_RandomDomain(self, d): 

2658 if hasattr(d, 'as_boolean'): 

2659 pform = self._print('Domain: ') 

2660 pform = prettyForm(*pform.right(self._print(d.as_boolean()))) 

2661 return pform 

2662 elif hasattr(d, 'set'): 

2663 pform = self._print('Domain: ') 

2664 pform = prettyForm(*pform.right(self._print(d.symbols))) 

2665 pform = prettyForm(*pform.right(self._print(' in '))) 

2666 pform = prettyForm(*pform.right(self._print(d.set))) 

2667 return pform 

2668 elif hasattr(d, 'symbols'): 

2669 pform = self._print('Domain on ') 

2670 pform = prettyForm(*pform.right(self._print(d.symbols))) 

2671 return pform 

2672 else: 

2673 return self._print(None) 

2674 

2675 def _print_DMP(self, p): 

2676 try: 

2677 if p.ring is not None: 

2678 # TODO incorporate order 

2679 return self._print(p.ring.to_sympy(p)) 

2680 except SympifyError: 

2681 pass 

2682 return self._print(repr(p)) 

2683 

2684 def _print_DMF(self, p): 

2685 return self._print_DMP(p) 

2686 

2687 def _print_Object(self, object): 

2688 return self._print(pretty_symbol(object.name)) 

2689 

2690 def _print_Morphism(self, morphism): 

2691 arrow = xsym("-->") 

2692 

2693 domain = self._print(morphism.domain) 

2694 codomain = self._print(morphism.codomain) 

2695 tail = domain.right(arrow, codomain)[0] 

2696 

2697 return prettyForm(tail) 

2698 

2699 def _print_NamedMorphism(self, morphism): 

2700 pretty_name = self._print(pretty_symbol(morphism.name)) 

2701 pretty_morphism = self._print_Morphism(morphism) 

2702 return prettyForm(pretty_name.right(":", pretty_morphism)[0]) 

2703 

2704 def _print_IdentityMorphism(self, morphism): 

2705 from sympy.categories import NamedMorphism 

2706 return self._print_NamedMorphism( 

2707 NamedMorphism(morphism.domain, morphism.codomain, "id")) 

2708 

2709 def _print_CompositeMorphism(self, morphism): 

2710 

2711 circle = xsym(".") 

2712 

2713 # All components of the morphism have names and it is thus 

2714 # possible to build the name of the composite. 

2715 component_names_list = [pretty_symbol(component.name) for 

2716 component in morphism.components] 

2717 component_names_list.reverse() 

2718 component_names = circle.join(component_names_list) + ":" 

2719 

2720 pretty_name = self._print(component_names) 

2721 pretty_morphism = self._print_Morphism(morphism) 

2722 return prettyForm(pretty_name.right(pretty_morphism)[0]) 

2723 

2724 def _print_Category(self, category): 

2725 return self._print(pretty_symbol(category.name)) 

2726 

2727 def _print_Diagram(self, diagram): 

2728 if not diagram.premises: 

2729 # This is an empty diagram. 

2730 return self._print(S.EmptySet) 

2731 

2732 pretty_result = self._print(diagram.premises) 

2733 if diagram.conclusions: 

2734 results_arrow = " %s " % xsym("==>") 

2735 

2736 pretty_conclusions = self._print(diagram.conclusions)[0] 

2737 pretty_result = pretty_result.right( 

2738 results_arrow, pretty_conclusions) 

2739 

2740 return prettyForm(pretty_result[0]) 

2741 

2742 def _print_DiagramGrid(self, grid): 

2743 from sympy.matrices import Matrix 

2744 matrix = Matrix([[grid[i, j] if grid[i, j] else Symbol(" ") 

2745 for j in range(grid.width)] 

2746 for i in range(grid.height)]) 

2747 return self._print_matrix_contents(matrix) 

2748 

2749 def _print_FreeModuleElement(self, m): 

2750 # Print as row vector for convenience, for now. 

2751 return self._print_seq(m, '[', ']') 

2752 

2753 def _print_SubModule(self, M): 

2754 return self._print_seq(M.gens, '<', '>') 

2755 

2756 def _print_FreeModule(self, M): 

2757 return self._print(M.ring)**self._print(M.rank) 

2758 

2759 def _print_ModuleImplementedIdeal(self, M): 

2760 return self._print_seq([x for [x] in M._module.gens], '<', '>') 

2761 

2762 def _print_QuotientRing(self, R): 

2763 return self._print(R.ring) / self._print(R.base_ideal) 

2764 

2765 def _print_QuotientRingElement(self, R): 

2766 return self._print(R.data) + self._print(R.ring.base_ideal) 

2767 

2768 def _print_QuotientModuleElement(self, m): 

2769 return self._print(m.data) + self._print(m.module.killed_module) 

2770 

2771 def _print_QuotientModule(self, M): 

2772 return self._print(M.base) / self._print(M.killed_module) 

2773 

2774 def _print_MatrixHomomorphism(self, h): 

2775 matrix = self._print(h._sympy_matrix()) 

2776 matrix.baseline = matrix.height() // 2 

2777 pform = prettyForm(*matrix.right(' : ', self._print(h.domain), 

2778 ' %s> ' % hobj('-', 2), self._print(h.codomain))) 

2779 return pform 

2780 

2781 def _print_Manifold(self, manifold): 

2782 return self._print(manifold.name) 

2783 

2784 def _print_Patch(self, patch): 

2785 return self._print(patch.name) 

2786 

2787 def _print_CoordSystem(self, coords): 

2788 return self._print(coords.name) 

2789 

2790 def _print_BaseScalarField(self, field): 

2791 string = field._coord_sys.symbols[field._index].name 

2792 return self._print(pretty_symbol(string)) 

2793 

2794 def _print_BaseVectorField(self, field): 

2795 s = U('PARTIAL DIFFERENTIAL') + '_' + field._coord_sys.symbols[field._index].name 

2796 return self._print(pretty_symbol(s)) 

2797 

2798 def _print_Differential(self, diff): 

2799 if self._use_unicode: 

2800 d = '\N{DOUBLE-STRUCK ITALIC SMALL D}' 

2801 else: 

2802 d = 'd' 

2803 field = diff._form_field 

2804 if hasattr(field, '_coord_sys'): 

2805 string = field._coord_sys.symbols[field._index].name 

2806 return self._print(d + ' ' + pretty_symbol(string)) 

2807 else: 

2808 pform = self._print(field) 

2809 pform = prettyForm(*pform.parens()) 

2810 return prettyForm(*pform.left(d)) 

2811 

2812 def _print_Tr(self, p): 

2813 #TODO: Handle indices 

2814 pform = self._print(p.args[0]) 

2815 pform = prettyForm(*pform.left('%s(' % (p.__class__.__name__))) 

2816 pform = prettyForm(*pform.right(')')) 

2817 return pform 

2818 

2819 def _print_primenu(self, e): 

2820 pform = self._print(e.args[0]) 

2821 pform = prettyForm(*pform.parens()) 

2822 if self._use_unicode: 

2823 pform = prettyForm(*pform.left(greek_unicode['nu'])) 

2824 else: 

2825 pform = prettyForm(*pform.left('nu')) 

2826 return pform 

2827 

2828 def _print_primeomega(self, e): 

2829 pform = self._print(e.args[0]) 

2830 pform = prettyForm(*pform.parens()) 

2831 if self._use_unicode: 

2832 pform = prettyForm(*pform.left(greek_unicode['Omega'])) 

2833 else: 

2834 pform = prettyForm(*pform.left('Omega')) 

2835 return pform 

2836 

2837 def _print_Quantity(self, e): 

2838 if e.name.name == 'degree': 

2839 pform = self._print("\N{DEGREE SIGN}") 

2840 return pform 

2841 else: 

2842 return self.emptyPrinter(e) 

2843 

2844 def _print_AssignmentBase(self, e): 

2845 

2846 op = prettyForm(' ' + xsym(e.op) + ' ') 

2847 

2848 l = self._print(e.lhs) 

2849 r = self._print(e.rhs) 

2850 pform = prettyForm(*stringPict.next(l, op, r)) 

2851 return pform 

2852 

2853 def _print_Str(self, s): 

2854 return self._print(s.name) 

2855 

2856 

2857@print_function(PrettyPrinter) 

2858def pretty(expr, **settings): 

2859 """Returns a string containing the prettified form of expr. 

2860 

2861 For information on keyword arguments see pretty_print function. 

2862 

2863 """ 

2864 pp = PrettyPrinter(settings) 

2865 

2866 # XXX: this is an ugly hack, but at least it works 

2867 use_unicode = pp._settings['use_unicode'] 

2868 uflag = pretty_use_unicode(use_unicode) 

2869 

2870 try: 

2871 return pp.doprint(expr) 

2872 finally: 

2873 pretty_use_unicode(uflag) 

2874 

2875 

2876def pretty_print(expr, **kwargs): 

2877 """Prints expr in pretty form. 

2878 

2879 pprint is just a shortcut for this function. 

2880 

2881 Parameters 

2882 ========== 

2883 

2884 expr : expression 

2885 The expression to print. 

2886 

2887 wrap_line : bool, optional (default=True) 

2888 Line wrapping enabled/disabled. 

2889 

2890 num_columns : int or None, optional (default=None) 

2891 Number of columns before line breaking (default to None which reads 

2892 the terminal width), useful when using SymPy without terminal. 

2893 

2894 use_unicode : bool or None, optional (default=None) 

2895 Use unicode characters, such as the Greek letter pi instead of 

2896 the string pi. 

2897 

2898 full_prec : bool or string, optional (default="auto") 

2899 Use full precision. 

2900 

2901 order : bool or string, optional (default=None) 

2902 Set to 'none' for long expressions if slow; default is None. 

2903 

2904 use_unicode_sqrt_char : bool, optional (default=True) 

2905 Use compact single-character square root symbol (when unambiguous). 

2906 

2907 root_notation : bool, optional (default=True) 

2908 Set to 'False' for printing exponents of the form 1/n in fractional form. 

2909 By default exponent is printed in root form. 

2910 

2911 mat_symbol_style : string, optional (default="plain") 

2912 Set to "bold" for printing MatrixSymbols using a bold mathematical symbol face. 

2913 By default the standard face is used. 

2914 

2915 imaginary_unit : string, optional (default="i") 

2916 Letter to use for imaginary unit when use_unicode is True. 

2917 Can be "i" (default) or "j". 

2918 """ 

2919 print(pretty(expr, **kwargs)) 

2920 

2921pprint = pretty_print 

2922 

2923 

2924def pager_print(expr, **settings): 

2925 """Prints expr using the pager, in pretty form. 

2926 

2927 This invokes a pager command using pydoc. Lines are not wrapped 

2928 automatically. This routine is meant to be used with a pager that allows 

2929 sideways scrolling, like ``less -S``. 

2930 

2931 Parameters are the same as for ``pretty_print``. If you wish to wrap lines, 

2932 pass ``num_columns=None`` to auto-detect the width of the terminal. 

2933 

2934 """ 

2935 from pydoc import pager 

2936 from locale import getpreferredencoding 

2937 if 'num_columns' not in settings: 

2938 settings['num_columns'] = 500000 # disable line wrap 

2939 pager(pretty(expr, **settings).encode(getpreferredencoding()))