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
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1import itertools
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
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
25# rename for usage from outside
26pprint_use_unicode = pretty_use_unicode
27pprint_try_use_unicode = pretty_try_use_unicode
30class PrettyPrinter(Printer):
31 """Printer, which converts an expression into 2D ASCII-art figure."""
32 printmethod = "_pretty"
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 }
47 def __init__(self, settings=None):
48 Printer.__init__(self, settings)
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']))
55 def emptyPrinter(self, expr):
56 return prettyForm(str(expr))
58 @property
59 def _use_unicode(self):
60 if self._settings['use_unicode']:
61 return True
62 else:
63 return pretty_use_unicode()
65 def doprint(self, expr):
66 return self._print(expr).render(**self._settings)
68 # empty op so _print(stringPict) returns the same
69 def _print_stringPict(self, e):
70 return e
72 def _print_basestring(self, e):
73 return prettyForm(e)
75 def _print_atan2(self, e):
76 pform = prettyForm(*self._print_seq(e.args).parens())
77 pform = prettyForm(*pform.left('atan2'))
78 return pform
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")
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))
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
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
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
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
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
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
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)
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
170 _print_EmptySequence = _print_Atom
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, '(', ')')
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
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
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
206 def _print_binomial(self, e):
207 n, k = e.args
209 n_pform = self._print(n)
210 k_pform = self._print(k)
212 bar = ' '*max(n_pform.width(), k_pform.width())
214 pform = prettyForm(*k_pform.above(bar))
215 pform = prettyForm(*pform.above(n_pform))
216 pform = prettyForm(*pform.parens('(', ')'))
218 pform.baseline = (pform.baseline + 1)//2
220 return pform
222 def _print_Relational(self, e):
223 op = prettyForm(' ' + xsym(e.rel_op) + ' ')
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
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}")
240 if arg.is_Boolean and not arg.is_Not:
241 pform = prettyForm(*pform.parens())
243 return prettyForm(*pform.left("\N{NOT SIGN}"))
244 else:
245 return self._print_Function(e)
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)
254 if arg.is_Boolean and not arg.is_Not:
255 pform = prettyForm(*pform.parens())
257 for arg in args[1:]:
258 pform_arg = self._print(arg)
260 if arg.is_Boolean and not arg.is_Not:
261 pform_arg = prettyForm(*pform_arg.parens())
263 pform = prettyForm(*pform.right(' %s ' % char))
264 pform = prettyForm(*pform.right(pform_arg))
266 return pform
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)
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)
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)
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)
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)
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)
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)
310 def _print_conjugate(self, e):
311 pform = self._print(e.args[0])
312 return prettyForm( *pform.above( hobj('_', pform.width())) )
314 def _print_Abs(self, e):
315 pform = self._print(e.args[0])
316 pform = prettyForm(*pform.parens('|', '|'))
317 return pform
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)
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)
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
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
348 if (not num.is_Integer) or (num > 1):
349 ds = ds**prettyForm(str(num))
351 if x is None:
352 x = ds
353 else:
354 x = prettyForm(*x.right(' '))
355 x = prettyForm(*x.right(ds))
357 f = prettyForm(
358 binding=prettyForm.FUNC, *self._print(deriv.expr).parens())
360 pform = prettyForm(deriv_symbol)
362 if (count_total_deriv > 1) != False:
363 pform = pform**prettyForm(str(count_total_deriv))
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
370 return pform
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())
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())
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
391 def _print_Permutation(self, expr):
392 from sympy.combinatorics.permutations import Permutation, Cycle
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)
408 if perm_cyclic:
409 return self._print_Cycle(Cycle(expr))
411 lower = expr.array_form
412 upper = list(range(len(lower)))
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())
428 def _print_Integral(self, integral):
429 f = integral.function
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())
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())
446 arg = prettyForm(*arg.right(' d', prettyArg))
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
456 # XXX hack!
457 ascii_mode = not self._use_unicode
458 if ascii_mode:
459 H += 2
461 vint = vobj('int', H)
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
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])
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))
484 spc = max(1, 4 - prettyA.width())
485 prettyA = prettyForm(*prettyA.right(' ' * spc))
487 pform = prettyForm(*pform.above(prettyB))
488 pform = prettyForm(*pform.below(prettyA))
490 if not ascii_mode: # XXX hack
491 pform = prettyForm(*pform.right(' '))
493 if firstterm:
494 s = pform # first term
495 firstterm = False
496 else:
497 s = prettyForm(*s.left(pform))
499 pform = prettyForm(*arg.left(s))
500 pform.binding = prettyForm.MUL
501 return pform
503 def _print_Product(self, expr):
504 func = expr.term
505 pretty_func = self._print(func)
507 horizontal_chr = xobj('_', 1)
508 corner_chr = xobj('_', 1)
509 vertical_chr = xobj('|', 1)
511 if self._use_unicode:
512 # use unicode corners
513 horizontal_chr = xobj('-', 1)
514 corner_chr = '\N{BOX DRAWINGS LIGHT DOWN AND HORIZONTAL}'
516 func_height = pretty_func.height()
518 first = True
519 max_upper = 0
520 sign_height = 0
522 for lim in expr.limits:
523 pretty_lower, pretty_upper = self.__print_SumProduct_Limits(lim)
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 + ' ')
530 pretty_sign = stringPict('')
531 pretty_sign = prettyForm(*pretty_sign.stack(*sign_lines))
534 max_upper = max(max_upper, pretty_upper.height())
536 if first:
537 sign_height = pretty_sign.height()
539 pretty_sign = prettyForm(*pretty_sign.above(pretty_upper))
540 pretty_sign = prettyForm(*pretty_sign.below(pretty_lower))
542 if first:
543 pretty_func.baseline = 0
544 first = False
546 height = pretty_sign.height()
547 padding = stringPict('')
548 padding = prettyForm(*padding.stack(*[' ']*(height - 1)))
549 pretty_sign = prettyForm(*pretty_sign.right(padding))
551 pretty_func = prettyForm(*pretty_sign.right(pretty_func))
553 pretty_func.baseline = max_upper + sign_height//2
554 pretty_func.binding = prettyForm.MUL
555 return pretty_func
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
565 prettyUpper = self._print(lim[2])
566 prettyLower = print_start(lim[0], lim[1])
567 return prettyLower, prettyUpper
569 def _print_Sum(self, expr):
570 ascii_mode = not self._use_unicode
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))
585 h = max(hrequired, 2)
586 d = h//2
587 w = d + 1
588 more = hrequired % 2
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
614 f = expr.function
616 prettyF = self._print(f)
618 if f.is_Add: # add parens
619 prettyF = prettyForm(*prettyF.parens())
621 H = prettyF.height() + 2
623 # \sum \sum \sum ...
624 first = True
625 max_upper = 0
626 sign_height = 0
628 for lim in expr.limits:
629 prettyLower, prettyUpper = self.__print_SumProduct_Limits(lim)
631 max_upper = max(max_upper, prettyUpper.height())
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))
639 if first:
640 sign_height = prettySign.height()
642 prettySign = prettyForm(*prettySign.above(prettyUpper))
643 prettySign = prettyForm(*prettySign.below(prettyLower))
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
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))
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
663 prettyF.binding = prettyForm.MUL
664 return prettyF
666 def _print_Limit(self, l):
667 e, z, z0, dir = l.args
669 E = self._print(e)
670 if precedence(e) <= PRECEDENCE["Mul"]:
671 E = prettyForm(*E.parens('(', ')'))
672 Lim = prettyForm('lim')
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)))
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}'
687 LimArg = prettyForm(*LimArg.right(self._print(dir)))
689 Lim = prettyForm(*Lim.below(LimArg))
690 Lim = prettyForm(*Lim.right(E), binding=prettyForm.MUL)
692 return Lim
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])
704 # h- and v- spacers
705 hsep = 2
706 vsep = 1
708 # max width for columns
709 maxw = [-1] * M.cols
711 for j in range(M.cols):
712 maxw[j] = max([Ms[i, j].width() for i in range(M.rows)] or [0])
714 # drawing result
715 D = None
717 for i in range(M.rows):
719 D_row = None
720 for j in range(M.cols):
721 s = Ms[i, j]
723 # reshape s to maxw
724 # XXX this should be generalized, and go to stringPict.reshape ?
725 assert s.width() <= maxw[j]
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
734 s = prettyForm(*s.right(' '*wright))
735 s = prettyForm(*s.left(' '*wleft))
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()
741 if D_row is None:
742 D_row = s # first box in a row
743 continue
745 D_row = prettyForm(*D_row.right(' '*hsep)) # h-spacer
746 D_row = prettyForm(*D_row.right(s))
748 if D is None:
749 D = D_row # first row in a picture
750 continue
752 # v-spacer
753 for _ in range(vsep):
754 D = prettyForm(*D.below(' '))
756 D = prettyForm(*D.below(D_row))
758 if D is None:
759 D = prettyForm('') # Empty Matrix
761 return D
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
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='|')
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"])
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"])
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
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))
821 # store pform parts so it can be reassembled e.g. when powered
822 pform.prettyFunc = prettyFunc
823 pform.prettyArgs = prettyIndices
825 return pform
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]
846 pform = prettyForm(
847 binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
849 # store pform parts so it can be reassembled e.g. when powered
850 pform.prettyFunc = prettyFunc
851 pform.prettyArgs = prettyArgs
853 return pform
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
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
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)
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))
899 return s
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)
913 return prettyForm.__mul__(*args)
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')
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')
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')
933 def _print_DotProduct(self, expr):
934 args = list(expr.args)
936 for i, a in enumerate(args):
937 args[i] = self._print(a)
938 return prettyForm.__mul__(*args)
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
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)))
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
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)))
985 def _print_FunctionMatrix(self, X):
986 D = self._print(X.lamda.expr)
987 D = prettyForm(*D.parens('[', ']'))
988 return D
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)
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)
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)
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
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
1049 def _print_Feedback(self, expr):
1050 from sympy.physics.control import TransferFunction, Series
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]
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)
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)))
1083 return self._print(num)/denom
1085 def _print_MIMOFeedback(self, expr):
1086 from sympy.physics.control import MIMOSeries, TransferFunctionMatrix
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
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
1110 def _print_BasisDependent(self, expr):
1111 from sympy.vector import Vector
1113 if not self._use_unicode:
1114 raise NotImplementedError("ASCII pretty printing of BasisDependent is not implemented")
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]
1144 o1.append(arg_str + ' ' + k._pretty_form)
1145 vectstrs.append(k._pretty_form)
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
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
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
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)
1210 return prettyForm('\n'.join([s[:-3] for s in strs]))
1212 def _print_NDimArray(self, expr):
1213 from sympy.matrices.immutable import ImmutableMatrix
1215 if expr.rank() == 0:
1216 return self._print(expr[()])
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] = []
1239 out_expr = level_str[0][0]
1240 if expr.rank() % 2 == 1:
1241 out_expr = mat([out_expr])
1243 return self._print(out_expr)
1245 def _printer_tensor_indices(self, name, indices, index_map={}):
1246 center = stringPict(name)
1247 top = stringPict(" "*center.width())
1248 bot = stringPict(" "*center.width())
1250 last_valence = None
1251 prev_map = None
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
1276 pict = prettyForm(*center.above(top))
1277 pict = prettyForm(*pict.below(bot))
1278 return pict
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)
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)
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
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)
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)
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
1325 for variable in reversed(deriv.variables):
1326 s = self._print(variable)
1327 ds = prettyForm(*s.left(deriv_symbol))
1329 if x is None:
1330 x = ds
1331 else:
1332 x = prettyForm(*x.right(' '))
1333 x = prettyForm(*x.right(ds))
1335 f = prettyForm(
1336 binding=prettyForm.FUNC, *self._print(deriv.expr).parens())
1338 pform = prettyForm(deriv_symbol)
1340 if len(deriv.variables) > 1:
1341 pform = pform**self._print(len(deriv.variables))
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
1348 return pform
1350 def _print_Piecewise(self, pexpr):
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)
1364 # max widths
1365 maxw = [max([P[i, j].width() for i in range(len_args)])
1366 for j in range(2)]
1368 # FIXME: Refactor this code and matrix into some tabular environment.
1369 # drawing result
1370 D = None
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]
1378 wdelta = maxw[j] - p.width()
1379 wleft = wdelta // 2
1380 wright = wdelta - wleft
1382 p = prettyForm(*p.right(' '*wright))
1383 p = prettyForm(*p.left(' '*wleft))
1385 if D_row is None:
1386 D_row = p
1387 continue
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
1395 # v-spacer
1396 for _ in range(vsep):
1397 D = prettyForm(*D.below(' '))
1399 D = prettyForm(*D.below(D_row))
1401 D = prettyForm(*D.parens('{', ''))
1402 D.baseline = D.height()//2
1403 D.binding = prettyForm.OPEN
1404 return D
1406 def _print_ITE(self, ite):
1407 from sympy.functions.elementary.piecewise import Piecewise
1408 return self._print(ite.rewrite(Piecewise))
1410 def _hprint_vec(self, v):
1411 D = None
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(' ')
1423 return D
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)
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]
1439 P = self._print(e.argument)
1440 P.baseline = P.height()//2
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))
1452 # make sure that the argument `z' is centred vertically
1453 D.baseline = D.height()//2
1455 # insert horizontal separator
1456 P = prettyForm(*P.left(' '))
1457 D = prettyForm(*D.right(' '))
1459 # insert separating `|`
1460 D = self._hprint_vseparator(D, P)
1462 # add parens
1463 D = prettyForm(*D.parens('(', ')'))
1465 # create the F symbol
1466 above = D.height()//2 - 1
1467 below = D.height() - above - 1
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
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
1478 D = prettyForm(*F.right(' ', D))
1480 return D
1482 def _print_meijerg(self, e):
1483 # FIXME refactor Matrix, Piecewise, and this into a tabular environment
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]
1491 P = self._print(e.argument)
1492 P.baseline = P.height()//2
1494 vp = {}
1495 for idx in v:
1496 vp[idx] = self._hprint_vec(v[idx])
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
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))
1513 # make sure that the argument `z' is centred vertically
1514 D.baseline = D.height()//2
1516 # insert horizontal separator
1517 P = prettyForm(*P.left(' '))
1518 D = prettyForm(*D.right(' '))
1520 # insert separating `|`
1521 D = self._hprint_vseparator(D, P)
1523 # add parens
1524 D = prettyForm(*D.parens('(', ')'))
1526 # create the G symbol
1527 above = D.height()//2 - 1
1528 below = D.height() - above - 1
1530 sz, t, b, add, img = annotated('G')
1531 F = prettyForm('\n' * (above - t) + img + '\n' * (below - b),
1532 baseline=above + sz)
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))
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))
1552 ht = F.baseline - above - 2
1553 if ht > 0:
1554 pu = prettyForm(*pu.below('\n'*ht))
1555 p = prettyForm(*pu.below(pl))
1557 F.baseline = above
1558 F = prettyForm(*F.right(p))
1560 F.baseline = above + add
1562 D = prettyForm(*F.right(' ', D))
1564 return D
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])
1572 def _print_Exp1(self, e):
1573 return prettyForm(pretty_atom('Exp1', 'e'))
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)
1581 def _print_mathieuc(self, e):
1582 return self._print_Function(e, func_name='C')
1584 def _print_mathieus(self, e):
1585 return self._print_Function(e, func_name='S')
1587 def _print_mathieucprime(self, e):
1588 return self._print_Function(e, func_name="C'")
1590 def _print_mathieusprime(self, e):
1591 return self._print_Function(e, func_name="S'")
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)
1599 if not func_name and hasattr(func, "__name__"):
1600 func_name = func.__name__
1602 if func_name:
1603 prettyFunc = self._print(Symbol(func_name))
1604 else:
1605 prettyFunc = prettyForm(*self._print(func).parens())
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 )
1618 prettyArgs = prettyForm(*self._print_seq(args, delimiter=delimiter).parens(
1619 left=left, right=right))
1621 pform = prettyForm(
1622 binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
1624 # store pform parts so it can be reassembled e.g. when powered
1625 pform.prettyFunc = prettyFunc
1626 pform.prettyArgs = prettyArgs
1628 return pform
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)
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']}
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))
1662 def _print_GeometryEntity(self, expr):
1663 # GeometryEntity is based on Tuple but should not print like a Tuple
1664 return self.emptyPrinter(expr)
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)
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)
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)
1683 def _print_fresnels(self, e):
1684 return self._print_Function(e, func_name="S")
1686 def _print_fresnelc(self, e):
1687 return self._print_Function(e, func_name="C")
1689 def _print_airyai(self, e):
1690 return self._print_Function(e, func_name="Ai")
1692 def _print_airybi(self, e):
1693 return self._print_Function(e, func_name="Bi")
1695 def _print_airyaiprime(self, e):
1696 return self._print_Function(e, func_name="Ai'")
1698 def _print_airybiprime(self, e):
1699 return self._print_Function(e, func_name="Bi'")
1701 def _print_LambertW(self, e):
1702 return self._print_Function(e, func_name="W")
1704 def _print_Covariance(self, e):
1705 return self._print_Function(e, func_name="Cov")
1707 def _print_Variance(self, e):
1708 return self._print_Function(e, func_name="Var")
1710 def _print_Probability(self, e):
1711 return self._print_Function(e, func_name="P")
1713 def _print_Expectation(self, e):
1714 return self._print_Function(e, func_name="E", left='[', right=']')
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)
1727 return prettyForm(*stringPict.next(var_form, arrow, self._print(expr)), binding=8)
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
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
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)
1769 def _print_betainc(self, e):
1770 func_name = "B'"
1771 return self._print_Function(e, func_name=func_name)
1773 def _print_betainc_regularized(self, e):
1774 func_name = 'I'
1775 return self._print_Function(e, func_name=func_name)
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)
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)
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)
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)
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)
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())
1819 pform = prettyForm(
1820 binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs))
1822 # store pform parts so it can be reassembled e.g. when powered
1823 pform.prettyFunc = prettyFunc
1824 pform.prettyArgs = prettyArgs
1826 return pform
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
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
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
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
1868 def _print_GoldenRatio(self, expr):
1869 if self._use_unicode:
1870 return prettyForm(pretty_symbol('phi'))
1871 return self._print(Symbol("GoldenRatio"))
1873 def _print_EulerGamma(self, expr):
1874 if self._use_unicode:
1875 return prettyForm(pretty_symbol('gamma'))
1876 return self._print(Symbol("EulerGamma"))
1878 def _print_Catalan(self, expr):
1879 return self._print(Symbol("G"))
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
1890 def _print_Add(self, expr, order=None):
1891 terms = self._as_ordered_terms(expr, order=order)
1892 pforms, indices = [], []
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 = ' - '
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)
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))
1935 if indices:
1936 large = True
1938 for pform in pforms:
1939 if pform is not None and pform.height() > 1:
1940 break
1941 else:
1942 large = False
1944 for i in indices:
1945 term, negative = terms[i], False
1947 if term < 0:
1948 term, negative = -term, True
1950 if large:
1951 pform = prettyForm(str(term.p))/prettyForm(str(term.q))
1952 else:
1953 pform = self._print(term)
1955 if negative:
1956 pform = pretty_negative(pform, i)
1958 pforms[i] = pform
1960 return prettyForm.__add__(*pforms)
1962 def _print_Mul(self, product):
1963 from sympy.physics.units import Quantity
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
1983 a = [] # items in the numerator
1984 b = [] # items that are in the denominator (if any)
1986 if self.order not in ('old', 'none'):
1987 args = product.as_ordered_factors()
1988 else:
1989 args = list(product.args)
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)))
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)
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]
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)
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)
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}'))
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
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))
2080 if b.is_Relational:
2081 return prettyForm(*self._print(b).parens()).__pow__(self._print(e))
2083 return self._print(b)**self._print(e)
2085 def _print_UnevaluatedExpr(self, expr):
2086 return self._print(expr.args[0])
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
2106 def _print_Rational(self, expr):
2107 result = self.__print_numer_denom(expr.p, expr.q)
2109 if result is not None:
2110 return result
2111 else:
2112 return self.emptyPrinter(expr)
2114 def _print_Fraction(self, expr):
2115 result = self.__print_numer_denom(expr.numerator, expr.denominator)
2117 if result is not None:
2118 return result
2119 else:
2120 return self.emptyPrinter(expr)
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)
2131 def _print_FiniteSet(self, s):
2132 items = sorted(s.args, key=default_sort_key)
2133 return self._print_seq(items, '{', '}', ', ' )
2135 def _print_Range(self, s):
2137 if self._use_unicode:
2138 dots = "\N{HORIZONTAL ELLIPSIS}"
2139 else:
2140 dots = '...'
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)
2158 return self._print_seq(printset, '{', '}', ', ' )
2160 def _print_Interval(self, i):
2161 if i.start == i.end:
2162 return self._print_seq(i.args[:1], '{', '}')
2164 else:
2165 if i.left_open:
2166 left = '('
2167 else:
2168 left = '['
2170 if i.right_open:
2171 right = ')'
2172 else:
2173 right = ']'
2175 return self._print_seq(i.args[:2], left, right)
2177 def _print_AccumulationBounds(self, i):
2178 left = '<'
2179 right = '>'
2181 return self._print_seq(i.args[:2], left, right)
2183 def _print_Intersection(self, u):
2185 delimiter = ' %s ' % pretty_atom('Intersection', 'n')
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)
2191 def _print_Union(self, u):
2193 union_delimiter = ' %s ' % pretty_atom('Union', 'U')
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)
2199 def _print_SymmetricDifference(self, u):
2200 if not self._use_unicode:
2201 raise NotImplementedError("ASCII pretty printing of SymmetricDifference is not implemented")
2203 sym_delimeter = ' %s ' % pretty_atom('SymmetricDifference')
2205 return self._print_seq(u.args, None, None, sym_delimeter)
2207 def _print_Complement(self, u):
2209 delimiter = r' \ '
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)
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)
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=' ')
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'
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())
2264 if ts.base_set is S.UniversalSet:
2265 return self._hprint_vseparator(variables, cond, left="{",
2266 right="}", ifascii_nougly=True,
2267 delimiter=' ')
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=' ')
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)
2284 C = self._print_seq((variables, inn, prodsets),
2285 delimiter=' ')
2286 return self._hprint_vseparator(expr, C, left="{", right="}",
2287 ifascii_nougly=True, delimiter=' ')
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))
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)
2307 def _print_FormalPowerSeries(self, s):
2308 return self._print_Add(s.infinite)
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))
2315 def _print_SeqFormula(self, s):
2316 if self._use_unicode:
2317 dots = "\N{HORIZONTAL ELLIPSIS}"
2318 else:
2319 dots = '...'
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")
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)
2336 _print_SeqPer = _print_SeqFormula
2337 _print_SeqAdd = _print_SeqFormula
2338 _print_SeqMul = _print_SeqFormula
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)
2352 if not pforms:
2353 s = stringPict('')
2354 else:
2355 s = prettyForm(*stringPict.next(*pforms))
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.
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))
2375 if s is None:
2376 s = stringPict('')
2378 s = prettyForm(*s.parens(left, right, ifascii_nougly=ifascii_nougly))
2379 return s
2381 def join(self, delimiter, args):
2382 pform = None
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))
2391 if pform is None:
2392 return prettyForm("")
2393 else:
2394 return pform
2396 def _print_list(self, l):
2397 return self._print_seq(l, '[', ']')
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, '(', ')')
2406 def _print_Tuple(self, expr):
2407 return self._print_tuple(expr)
2409 def _print_dict(self, d):
2410 keys = sorted(d.keys(), key=default_sort_key)
2411 items = []
2413 for k in keys:
2414 K = self._print(k)
2415 V = self._print(d[k])
2416 s = prettyForm(*stringPict.next(K, ': ', V))
2418 items.append(s)
2420 return self._print_seq(items, '{', '}')
2422 def _print_Dict(self, d):
2423 return self._print_dict(d)
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
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
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')
2449 def _print_PolyRing(self, ring):
2450 return prettyForm(sstr(ring))
2452 def _print_FracField(self, field):
2453 return prettyForm(sstr(field))
2455 def _print_FreeGroupElement(self, elm):
2456 return prettyForm(str(elm))
2458 def _print_PolyElement(self, poly):
2459 return prettyForm(sstr(poly))
2461 def _print_FracElement(self, frac):
2462 return prettyForm(sstr(frac))
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())
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
2476 def _print_RootSum(self, expr):
2477 args = [self._print_Add(expr.expr, order='lex')]
2479 if expr.fun is not S.IdentityFunction:
2480 args.append(self._print(expr.fun))
2482 pform = prettyForm(*self._print_seq(args).parens())
2483 pform = prettyForm(*pform.left('RootSum'))
2485 return pform
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)'
2493 return prettyForm(pretty_symbol(form % expr.mod))
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')
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')
2507 def _print_RealField(self, domain):
2508 if self._use_unicode:
2509 prefix = '\N{DOUBLE-STRUCK CAPITAL R}'
2510 else:
2511 prefix = 'RR'
2513 if domain.has_default_precision:
2514 return prettyForm(prefix)
2515 else:
2516 return self._print(pretty_symbol(prefix + "_" + str(domain.precision)))
2518 def _print_ComplexField(self, domain):
2519 if self._use_unicode:
2520 prefix = '\N{DOUBLE-STRUCK CAPITAL C}'
2521 else:
2522 prefix = 'CC'
2524 if domain.has_default_precision:
2525 return prettyForm(prefix)
2526 else:
2527 return self._print(pretty_symbol(prefix + "_" + str(domain.precision)))
2529 def _print_PolynomialRing(self, expr):
2530 args = list(expr.symbols)
2532 if not expr.order.is_default:
2533 order = prettyForm(*prettyForm("order=").right(self._print(expr.order)))
2534 args.append(order)
2536 pform = self._print_seq(args, '[', ']')
2537 pform = prettyForm(*pform.left(self._print(expr.domain)))
2539 return pform
2541 def _print_FractionField(self, expr):
2542 args = list(expr.symbols)
2544 if not expr.order.is_default:
2545 order = prettyForm(*prettyForm("order=").right(self._print(expr.order)))
2546 args.append(order)
2548 pform = self._print_seq(args, '(', ')')
2549 pform = prettyForm(*pform.left(self._print(expr.domain)))
2551 return pform
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)))
2560 return pform
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="]"))
2567 gens = [ self._print(gen) for gen in basis.gens ]
2569 domain = prettyForm(
2570 *prettyForm("domain=").right(self._print(basis.domain)))
2571 order = prettyForm(
2572 *prettyForm("order=").right(self._print(basis.order)))
2574 pform = self.join(", ", [exprs] + gens + [domain, order])
2576 pform = prettyForm(*pform.parens())
2577 pform = prettyForm(*pform.left(basis.__class__.__name__))
2579 return pform
2581 def _print_Subs(self, e):
2582 pform = self._print(e.expr)
2583 pform = prettyForm(*pform.parens())
2585 h = pform.height() if pform.height() > 1 else 2
2586 rvert = stringPict(vobj('|', h), baseline=pform.baseline)
2587 pform = prettyForm(*pform.right(rvert))
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) ])))
2595 pform.baseline = b
2596 return pform
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
2618 def _print_euler(self, e):
2619 return self._print_number_function(e, "E")
2621 def _print_catalan(self, e):
2622 return self._print_number_function(e, "C")
2624 def _print_bernoulli(self, e):
2625 return self._print_number_function(e, "B")
2627 _print_bell = _print_bernoulli
2629 def _print_lucas(self, e):
2630 return self._print_number_function(e, "L")
2632 def _print_fibonacci(self, e):
2633 return self._print_number_function(e, "F")
2635 def _print_tribonacci(self, e):
2636 return self._print_number_function(e, "T")
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")
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))
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)
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))
2684 def _print_DMF(self, p):
2685 return self._print_DMP(p)
2687 def _print_Object(self, object):
2688 return self._print(pretty_symbol(object.name))
2690 def _print_Morphism(self, morphism):
2691 arrow = xsym("-->")
2693 domain = self._print(morphism.domain)
2694 codomain = self._print(morphism.codomain)
2695 tail = domain.right(arrow, codomain)[0]
2697 return prettyForm(tail)
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])
2704 def _print_IdentityMorphism(self, morphism):
2705 from sympy.categories import NamedMorphism
2706 return self._print_NamedMorphism(
2707 NamedMorphism(morphism.domain, morphism.codomain, "id"))
2709 def _print_CompositeMorphism(self, morphism):
2711 circle = xsym(".")
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) + ":"
2720 pretty_name = self._print(component_names)
2721 pretty_morphism = self._print_Morphism(morphism)
2722 return prettyForm(pretty_name.right(pretty_morphism)[0])
2724 def _print_Category(self, category):
2725 return self._print(pretty_symbol(category.name))
2727 def _print_Diagram(self, diagram):
2728 if not diagram.premises:
2729 # This is an empty diagram.
2730 return self._print(S.EmptySet)
2732 pretty_result = self._print(diagram.premises)
2733 if diagram.conclusions:
2734 results_arrow = " %s " % xsym("==>")
2736 pretty_conclusions = self._print(diagram.conclusions)[0]
2737 pretty_result = pretty_result.right(
2738 results_arrow, pretty_conclusions)
2740 return prettyForm(pretty_result[0])
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)
2749 def _print_FreeModuleElement(self, m):
2750 # Print as row vector for convenience, for now.
2751 return self._print_seq(m, '[', ']')
2753 def _print_SubModule(self, M):
2754 return self._print_seq(M.gens, '<', '>')
2756 def _print_FreeModule(self, M):
2757 return self._print(M.ring)**self._print(M.rank)
2759 def _print_ModuleImplementedIdeal(self, M):
2760 return self._print_seq([x for [x] in M._module.gens], '<', '>')
2762 def _print_QuotientRing(self, R):
2763 return self._print(R.ring) / self._print(R.base_ideal)
2765 def _print_QuotientRingElement(self, R):
2766 return self._print(R.data) + self._print(R.ring.base_ideal)
2768 def _print_QuotientModuleElement(self, m):
2769 return self._print(m.data) + self._print(m.module.killed_module)
2771 def _print_QuotientModule(self, M):
2772 return self._print(M.base) / self._print(M.killed_module)
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
2781 def _print_Manifold(self, manifold):
2782 return self._print(manifold.name)
2784 def _print_Patch(self, patch):
2785 return self._print(patch.name)
2787 def _print_CoordSystem(self, coords):
2788 return self._print(coords.name)
2790 def _print_BaseScalarField(self, field):
2791 string = field._coord_sys.symbols[field._index].name
2792 return self._print(pretty_symbol(string))
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))
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))
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
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
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
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)
2844 def _print_AssignmentBase(self, e):
2846 op = prettyForm(' ' + xsym(e.op) + ' ')
2848 l = self._print(e.lhs)
2849 r = self._print(e.rhs)
2850 pform = prettyForm(*stringPict.next(l, op, r))
2851 return pform
2853 def _print_Str(self, s):
2854 return self._print(s.name)
2857@print_function(PrettyPrinter)
2858def pretty(expr, **settings):
2859 """Returns a string containing the prettified form of expr.
2861 For information on keyword arguments see pretty_print function.
2863 """
2864 pp = PrettyPrinter(settings)
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)
2870 try:
2871 return pp.doprint(expr)
2872 finally:
2873 pretty_use_unicode(uflag)
2876def pretty_print(expr, **kwargs):
2877 """Prints expr in pretty form.
2879 pprint is just a shortcut for this function.
2881 Parameters
2882 ==========
2884 expr : expression
2885 The expression to print.
2887 wrap_line : bool, optional (default=True)
2888 Line wrapping enabled/disabled.
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.
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.
2898 full_prec : bool or string, optional (default="auto")
2899 Use full precision.
2901 order : bool or string, optional (default=None)
2902 Set to 'none' for long expressions if slow; default is None.
2904 use_unicode_sqrt_char : bool, optional (default=True)
2905 Use compact single-character square root symbol (when unambiguous).
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.
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.
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))
2921pprint = pretty_print
2924def pager_print(expr, **settings):
2925 """Prints expr using the pager, in pretty form.
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``.
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.
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()))