draft implementation of arbitrary PDF
[sympy.git] / sympy / printing / str.py
blob615c2f006caa46ca5775f9c0ef9da54b3dee9860
1 """
2 A Printer for generating readable representation of most sympy classes.
3 """
5 from printer import Printer
6 from sympy.printing.precedence import precedence, PRECEDENCE
7 from sympy.core.basic import S
8 from sympy.core.numbers import One, Rational
9 from sympy.core.power import Pow
10 from sympy.core.symbol import Symbol, Wild
11 from sympy.core.basic import Basic
13 import sympy.mpmath.lib as mlib
15 class StrPrinter(Printer):
16 def parenthesize(self, item, level):
17 if precedence(item) <= level:
18 return "(%s)"%self._print(item)
19 else:
20 return self._print(item)
22 def stringify(self, args, sep, level=0):
23 return sep.join([self.parenthesize(item, level) for item in args])
25 def emptyPrinter(self, expr):
26 if isinstance(expr, str):
27 return expr
28 elif isinstance(expr, Basic):
29 if hasattr(expr, args):
30 return repr(expr)
31 else:
32 raise
33 else:
34 return str(expr)
36 def _print_Add(self, expr):
37 args = list(expr.args)
39 # Now we need to sort the factors in Add, which are in "rest". Any
40 # ordering is fine, but some ordering looks better and some looks bad.
41 # This particular solution is slow, but it ensures a sane ordering. It
42 # can of course be improved:
44 args.sort(Basic._compare_pretty)
45 PREC = precedence(expr)
46 l = []
47 for term in args:
48 t = self._print(term)
49 if t.startswith('-'):
50 sign = "-"
51 t = t[1:]
52 else:
53 sign = "+"
54 if precedence(term) < PREC:
55 l.extend([sign, "(%s)"%t])
56 else:
57 l.extend([sign, t])
58 sign = l.pop(0)
59 if sign=='+':
60 sign = ""
61 return sign + ' '.join(l)
63 def _print_Basic(self, expr):
64 l = [self._print(o) for o in expr.args]
65 return expr.__class__.__name__ + "(%s)"%", ".join(l)
67 def _print_Catalan(self, expr):
68 return 'Catalan'
70 def _print_ComplexInfinity(self, expr):
71 return 'zoo'
73 def _print_Derivative(self, expr):
74 return 'D(%s)'%", ".join(map(self._print, expr.args))
76 def _print_dict(self, expr):
77 keys = expr.keys()
78 keys.sort( Basic.compare_pretty )
80 items = []
81 for key in keys:
82 item = "%s: %s" % (self._print(key), self._print(expr[key]))
83 items.append(item)
85 return "{%s}"%", ".join(items)
87 def _print_Dummy(self, expr):
88 return '_' + expr.name
90 def _print_EulerGamma(self, expr):
91 return 'EulerGamma'
93 def _print_Exp1(self, expr):
94 return 'E'
96 def _print_Factorial(self, expr):
97 return "%s!" % self.parenthesize(expr.args[0], PRECEDENCE["Pow"])
99 def _print_Function(self, expr):
100 return expr.func.__name__ + "(%s)"%self.stringify(expr.args, ", ")
102 def _print_GeometryEntity(self, expr):
103 # GeometryEntity is special -- it's base is tuple
104 return str(expr)
106 def _print_GoldenRatio(self, expr):
107 return 'GoldenRatio'
109 def _print_ImaginaryUnit(self, expr):
110 return 'I'
112 def _print_Infinity(self, expr):
113 return 'oo'
115 def _print_Integer(self, expr):
116 return self._print(expr.p)
118 def _print_Integral(self, expr):
119 def _xab_tostr(xab):
120 x, ab = xab
121 if ab is None:
122 return self._print(x)
123 else:
124 return self._print((x,) + ab)
125 L = ', '.join([_xab_tostr(l) for l in expr.limits])
126 return 'Integral(%s, %s)' % (self._print(expr.function), L)
128 def _print_Interval(self, expr):
129 return '[%s, %s]'%(expr.start, expr.end)
131 def _print_Limit(self, expr):
132 e, z, z0, dir = expr.args
133 if dir == "+":
134 return "Limit(%s, %s, %s)" % (e, z, z0)
135 else:
136 return "Limit(%s, %s, %s, dir='%s')" % (e, z, z0, dir)
138 def _print_list(self, expr):
139 return "[%s]"%self.stringify(expr, ", ")
141 def _print_Matrix(self, expr):
142 return expr._format_str(lambda elem: self._print(elem))
144 def _print_Mul(self, expr):
145 coeff, terms = expr.as_coeff_terms()
146 if coeff.is_negative:
147 coeff = -coeff
148 if coeff is not S.One:
149 terms = (coeff,) + terms
150 sign = "-"
151 else:
152 terms = (coeff,) + terms
153 sign = ""
155 a = [] # items in the numerator
156 b = [] # items that are in the denominator (if any)
158 # Gather terms for numerator/denominator
159 for item in terms:
160 if item.is_Pow and item.exp.is_Rational and item.exp.is_negative:
161 b.append(Pow(item.base, -item.exp))
162 elif item.is_Rational:
163 if item.p != 1:
164 a.append(Rational(item.p))
165 if item.q != 1:
166 b.append(Rational(item.q))
167 else:
168 a.append(item)
170 if len(a)==0:
171 a = [S.One]
173 a_str = map(lambda x:self.parenthesize(x, precedence(expr)), a)
174 b_str = map(lambda x:self.parenthesize(x, precedence(expr)), b)
176 if len(b)==0:
177 return sign + '*'.join(a_str)
178 elif len(b)==1:
179 if len(a)==1 and not (a[0].is_Atom or a[0].is_Add):
180 return sign + "1/%s*"%b_str[0] + '*'.join(a_str)
181 else:
182 return sign + '*'.join(a_str) + "/%s"%b_str[0]
183 else:
184 return sign + '*'.join(a_str) + "/(%s)"%'*'.join(b_str)
186 def _print_NaN(self, expr):
187 return 'nan'
189 def _print_NegativeInfinity(self, expr):
190 return '-oo'
192 def _print_NegativeOne(self, expr):
193 return "-1"
195 def _print_Normal(self, expr):
196 return "Normal(%s, %s)"%(expr.mu, expr.sigma)
198 def _print_One(self, expr):
199 return "1"
201 def _print_Order(self, expr):
202 if len(expr.symbols) <= 1:
203 return 'O(%s)'%self._print(expr.expr)
204 else:
205 return 'O(%s)'%self.stringify(expr.args, ', ', 0)
207 def _print_PDF(self, expr):
208 return 'PDF(%s, (%s, %s, %s))' % \
209 (self._print(expr.pdf.args[1]), self._print(expr.pdf.args[0]), \
210 self._print(expr.domain[0]), self._print(expr.domain[1]))
212 def _print_Pi(self, expr):
213 return 'pi'
215 def _print_Poly(self, expr):
216 terms, symbols = [], [ self._print(s) for s in expr.symbols ]
218 for coeff, monom in expr.iter_terms():
219 s_monom = []
221 for i, exp in enumerate(monom):
222 if exp > 0:
223 if exp == 1:
224 s_monom.append(symbols[i])
225 else:
226 s_monom.append(symbols[i] + "**%d" % exp)
228 s_monom = "*".join(s_monom)
230 if coeff.is_Add:
231 if s_monom:
232 s_coeff = "(" + self._print(coeff) + ")"
233 else:
234 s_coeff = self._print(coeff)
235 else:
236 if s_monom and abs(coeff) is S.One:
237 if coeff.is_negative:
238 terms.extend(['-', s_monom])
239 else:
240 terms.extend(['+', s_monom])
242 continue
243 else:
244 s_coeff = self._print(coeff)
246 if not s_monom:
247 s_term = s_coeff
248 else:
249 s_term = s_coeff + "*" + s_monom
251 if s_term.startswith('-'):
252 terms.extend(['-', s_term[1:]])
253 else:
254 terms.extend(['+', s_term])
256 if terms[0] in ['-', '+']:
257 modifier = terms.pop(0)
259 if modifier == '-':
260 terms[0] = '-' + terms[0]
262 format = expr.__class__.__name__ + "(%s, %s"
264 if expr.is_multivariate and expr.order != 'grlex':
265 format += ", order='%s')" % expr.order
266 else:
267 format += ")"
269 return format % (' '.join(terms), ', '.join(symbols))
271 def _print_Polynomial(self, expr):
272 return self._print(expr.sympy_expr)
274 def _print_Pow(self, expr):
275 PREC = precedence(expr)
276 if expr.exp is S.NegativeOne:
277 return '1/%s'%(self.parenthesize(expr.base, PREC))
278 else:
279 return '%s**%s'%(self.parenthesize(expr.base, PREC),
280 self.parenthesize(expr.exp, PREC))
282 def _print_Rational(self, expr):
283 return '%s/%s'%(expr.p, expr.q)
285 def _print_Real(self, expr):
286 prec = expr._prec
287 if prec < 5:
288 dps = 0
289 else:
290 dps = mlib.prec_to_dps(expr._prec)
291 return mlib.to_str(expr._mpf_, dps, strip_zeros=False)
293 def _print_Relational(self, expr):
294 return '%s %s %s'%(self.parenthesize(expr.lhs, precedence(expr)),
295 expr.rel_op,
296 self.parenthesize(expr.rhs, precedence(expr)))
298 def _print_RootOf(self, expr):
299 poly = self._print(expr.poly)
300 return "RootOf(%s, index=%d)" % \
301 (poly[1+poly.index("("):-1], expr.index)
303 def _print_RootsOf(self, expr):
304 poly = self._print(expr.poly)
305 return "RootsOf(" + poly[1+poly.index("("):]
307 def _print_RootSum(self, expr):
308 func = self._print(expr.function)
309 poly = self._print(expr.roots.poly)
310 return "RootSum(%s, %s)" % \
311 (func, poly[1+poly.index("("):-1])
313 def _print_Sample(self, expr):
314 return "Sample([%s])"%self.stringify(expr, ", ", 0)
316 def __print_set(self, expr):
317 items = list(expr)
318 items.sort( Basic.compare_pretty )
320 args = ', '.join(self._print(item) for item in items)
321 if args:
322 args = '[%s]' % args
323 return '%s(%s)' % (type(expr).__name__, args)
325 _print_set = __print_set
326 _print_frozenset = __print_set
328 def _print_SMatrix(self, expr):
329 return self._print(expr.toMatrix())
331 def _print_Sum(self, expr):
332 return 'Sum(%s, (%s))'%(self._print(expr.function), self.stringify(expr.limits[0], ', '))
334 def _print_Sum2(self, expr):
335 return "Sum2(%r, (%r, %r, %r))" % (expr.f, expr.i, expr.a, expr.b)
337 def _print_Symbol(self, expr):
338 return expr.name
340 def _print_tuple(self, expr):
341 if len(expr)==1:
342 return "(%s,)"%self._print(expr[0])
343 else:
344 return "(%s)"%self.stringify(expr, ", ")
346 def _print_Uniform(self, expr):
347 return "Uniform(%s, %s)"%(expr.a, expr.b)
349 def _print_Unit(self, expr):
350 return expr.abbrev
352 def _print_Wild(self, expr):
353 return expr.name + '_'
355 def _print_WildFunction(self, expr):
356 return expr.name + '_'
358 def _print_Zero(self, expr):
359 return "0"
362 def sstr(expr):
363 """return expr in str form"""
365 p = StrPrinter()
366 s = p.doprint(expr)
368 return s
371 class StrReprPrinter(StrPrinter):
372 """(internal) -- see sstrrepr"""
374 def _print_basestring(self, s):
375 return repr(s)
377 def sstrrepr(expr):
378 """return expr in mixed str/repr form
380 i.e. strings are returned in repr form with quotes, and everything else
381 is returned in str form.
383 This function could be useful for hooking into sys.displayhook
386 p = StrReprPrinter()
387 s = p.doprint(expr)
389 return s