str.py 32 KB

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