New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
pretty printing gets stuck doing evalf #10800
Comments
|
Why don't we just use |
Does ordered also use evalf? I've noticed that it can also be slow. |
By default it only uses |
Here's another simple printing failure:
|
It does get called. An easy way to check is to put a stack print in
So it looks like Also worth noting: |
The original examples in this thread now works fine:
I guess that's because it now returns a different result. Whatever result it previously returned may still not be printable... |
Replace the integral with one that can't be computed. For example, |
@asmeurer Python 3.6.9 (default, Nov 7 2019, 10:44:02)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(SymPyConsole)
>>> a = 2*integrate(sin(exp(x)), (x, 1, oo))+2*Si(E)
>>> a
π Attaching a |
That's just because the integral now evaluates. If you try to print the unevaluated integral you will see the error:
|
The problem is that the printing code tries to sort some expressions (not sure why). The assumptions system attempts to numerically evaluate the expressions as part of a comparison like
|
Certainly evalf should be improved, but we shouldn't assume that it will be fast for every object. Here is the issue >>> pi + E # Sorted from smallest to largest
E + pi
>>> (pi - E).is_positive
True So if we remove evalf from the assumptions, it would remove a lot of functionality and would probably break things. So I'm not sure how to fix it. Clearly it shouldn't try to evaluate very slow to evaluate things, but I don't know if it should try to remove evaluation entirely. Maybe for certain objects like Sum and Integral the evaluation shouldn't be enabled by default for such things. I don't know if the printing sorting is that important, but the assumptions calling evalf could cause issues in other contexts as well. I don't know how much performance is affected in general just from "normal" functions evaluating (throughout SymPy, not just in the printers). Maybe we should try removing the evalf calls from the assumptions and seeing 1) what fails, and 2) if it affects performance benchmarks outside of the printers. |
See also #17609 |
Oh that's a good point. Even "normal" expressions can cause issues with evalf. I think we should have a "fast" evalf that gives up on anything that could potentially be slow (like integration) or produce excessively large expressions. The question is to what degree can we disable only the "bad" things, without disabling entire classes of expressions wholesale. It would be nice if mpmath itself had some sort of mode to do a fail if the internal values get too large. I think the problem is that mpmath represents things as It would also help if the slower mpmath functions like quad had a timeout ability. Maybe those flags do exist (it looks like we can use |
In evalf there is already a limit on the mantissa so we can have one for the exponent as well. As I said in #17609 the obvious place to check this would be In [2]: import decimal
In [3]: decimal.getcontext()
Out[3]: Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[], traps=[InvalidOperation, DivisionByZero, Overflow]) Emax there is the maximum value that any exponent can have in the default decimal context. You can change the context but you are still limited by |
Current status, >>> a = 2*integrate(sin(exp(x)), (x, 1, oo))+2*Si(E)
>>> a
π
>>> a = 2*Integral(sin(exp(x)), (x, 1, oo))+2*Si(E)
>>> a
^CTraceback (most recent call last):
File "/usr/lib/python3.6/code.py", line 91, in runcode
exec(code, self.locals)
File "<console>", line 1, in <module>
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/interactive/printing.py", line 29, in _displayhook
print(stringify_func(arg, **settings))
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/printing/pretty/pretty.py", line 2647, in pretty
return pp.doprint(expr)
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/printing/pretty/pretty.py", line 65, in doprint
return self._print(expr).render(**self._settings)
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/printing/printer.py", line 289, in _print
return getattr(self, printmethod)(expr, **kwargs)
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/printing/pretty/pretty.py", line 1707, in _print_Add
terms = self._as_ordered_terms(expr, order=order)
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/printing/printer.py", line 308, in _as_ordered_terms
return expr.as_ordered_terms(order=order)
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/core/expr.py", line 1149, in as_ordered_terms
terms, gens = self.as_terms()
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/core/expr.py", line 1188, in as_terms
coeff *= complex(factor)
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/core/expr.py", line 332, in __complex__
result = self.evalf()
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/core/evalf.py", line 1462, in evalf
result = evalf(self, prec + 4, options)
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/core/evalf.py", line 1314, in evalf
r = rf(x, prec, options)
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/core/evalf.py", line 1044, in evalf_integral
result = do_integral(expr, workprec, options)
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/core/evalf.py", line 1003, in do_integral
result, quadrature_error = quadts(f, [xlow, xhigh], error=1)
File "/usr/local/lib/python3.6/dist-packages/mpmath-1.1.0-py3.6.egg/mpmath/calculus/quadrature.py", line 785, in quadts
return ctx.quad(*args, **kwargs)
File "/usr/local/lib/python3.6/dist-packages/mpmath-1.1.0-py3.6.egg/mpmath/calculus/quadrature.py", line 742, in quad
v, err = rule.summation(f, points[0], prec, epsilon, m, verbose)
File "/usr/local/lib/python3.6/dist-packages/mpmath-1.1.0-py3.6.egg/mpmath/calculus/quadrature.py", line 232, in summation
results.append(self.sum_next(f, nodes, degree, prec, results, verbose))
File "/usr/local/lib/python3.6/dist-packages/mpmath-1.1.0-py3.6.egg/mpmath/calculus/quadrature.py", line 304, in sum_next
S += self.ctx.fdot((w,f(x)) for (x,w) in nodes)
File "/usr/local/lib/python3.6/dist-packages/mpmath-1.1.0-py3.6.egg/mpmath/ctx_mp_python.py", line 944, in fdot
for a, b in A:
File "/usr/local/lib/python3.6/dist-packages/mpmath-1.1.0-py3.6.egg/mpmath/calculus/quadrature.py", line 304, in <genexpr>
S += self.ctx.fdot((w,f(x)) for (x,w) in nodes)
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/core/evalf.py", line 976, in f
re, im, re_acc, im_acc = evalf(func, mp.prec, {'subs': {x: t}})
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/core/evalf.py", line 1314, in evalf
r = rf(x, prec, options)
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/core/evalf.py", line 813, in evalf_trig
re, im, re_acc, im_acc = evalf(arg, xprec, options)
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/core/evalf.py", line 1314, in evalf
r = rf(x, prec, options)
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/core/evalf.py", line 1283, in <lambda>
Pow(S.Exp1, x.args[0], evaluate=False), prec, options),
File "/home/czgdp1807ssd/sympy_project/sympy/sympy/core/evalf.py", line 742, in evalf_pow
return mpf_exp(yre, target_prec), None, target_prec, None
File "/usr/local/lib/python3.6/dist-packages/mpmath-1.1.0-py3.6.egg/mpmath/libmp/libelefun.py", line 1176, in mpf_exp
lg2 = ln2_fixed(wpmod)
File "/usr/local/lib/python3.6/dist-packages/mpmath-1.1.0-py3.6.egg/mpmath/libmp/libelefun.py", line 99, in g
f.memo_val = f(newprec, **kwargs)
File "/usr/local/lib/python3.6/dist-packages/mpmath-1.1.0-py3.6.egg/mpmath/libmp/libelefun.py", line 168, in ln2_fixed
return machin([(18, 26), (-2, 4801), (8, 8749)], prec, True)
File "/usr/local/lib/python3.6/dist-packages/mpmath-1.1.0-py3.6.egg/mpmath/libmp/libelefun.py", line 156, in machin
s += MPZ(a) * acot_fixed(MPZ(b), prec+extraprec, hyperbolic)
File "/usr/local/lib/python3.6/dist-packages/mpmath-1.1.0-py3.6.egg/mpmath/libmp/libelefun.py", line 143, in acot_fixed
p, q, r = bsp_acot(a, 0,N, hyperbolic)
File "/usr/local/lib/python3.6/dist-packages/mpmath-1.1.0-py3.6.egg/mpmath/libmp/libelefun.py", line 131, in bsp_acot
p1, q1, r1 = bsp_acot(q, a, m, hyperbolic)
File "/usr/local/lib/python3.6/dist-packages/mpmath-1.1.0-py3.6.egg/mpmath/libmp/libelefun.py", line 131, in bsp_acot
p1, q1, r1 = bsp_acot(q, a, m, hyperbolic)
File "/usr/local/lib/python3.6/dist-packages/mpmath-1.1.0-py3.6.egg/mpmath/libmp/libelefun.py", line 131, in bsp_acot
p1, q1, r1 = bsp_acot(q, a, m, hyperbolic)
[Previous line repeated 2 more times]
File "/usr/local/lib/python3.6/dist-packages/mpmath-1.1.0-py3.6.egg/mpmath/libmp/libelefun.py", line 132, in bsp_acot
p2, q2, r2 = bsp_acot(q, m, b, hyperbolic)
File "/usr/local/lib/python3.6/dist-packages/mpmath-1.1.0-py3.6.egg/mpmath/libmp/libelefun.py", line 133, in bsp_acot
return q2*p1 + r1*p2, q1*q2, r1*r2
KeyboardInterrupt This issue is still open for work. |
Use |
It shouldn't sort at all. The args of an Add are already sorted, and even if they weren't, it doesn't matter if something prints as x + y or y + x. The only ordering that really matters is printing the monomials of a polynomial in order, so that >>> pi + E + 3
E + 3 + pi which is something that I don't think anyone actually expects, or even realizes is there. But it incurs a huge cost in the printing, which should be an extremely cheap operation. |
The printer shouldn't be calling evalf at all for any expression. We really need to fix this.
The text was updated successfully, but these errors were encountered: