I think the only way is to move SymPy away from its current approach
of automatically evaluating things when expressions are constructed.
To take a concrete example from
https://github.com/sympy/sympy/issues/10800, consider this expression:
a = 2*Integral(sin(exp(x)), (x, 1, oo))+2*Si(E)
This expression currently causes evalf() to hang (which is of course,
a separate issue, but it's useful to use it to just get an idea of
where evalf() is overused).
Try doing almost anything with this expression and you'll see where
evalf() is being used. You can't even print the expression, because
the printer wants to numerically evaluate every numerical
subexpression so that they can be printed in order. You can't create
the expression a > 0 because > wants to automatically evaluate to True
or False when the arguments are numeric. This expression is numeric
(it is actually equal to pi, as doit() will reveal), but just because
something is known to be a number doesn't mean that we can efficiently
compute that number.
Obviously, the best "fix" here is to make it so that a.evalf()
actually computes quickly. But even if it computed a value, it would
still take some time to do that. There's no reason why the printers
really need to evaluate expressions just to sort them. And there's no
reason why > needs to automatically evaluate. If a user creates a >
expression and wants to know if it can be simplified they can call
simplify() or doit().
This is just one example. This sort of thing happens all the time with
assumptions, and with other sorts of automatic simplifications. We
could try to come up with a design where things can evaluate, but only
in cases where they involve only minimal calculations like you
suggested. For example, assumptions might automatically evaluate
simple deductions like positive -> real, but bypass complex things
that require computation like _eval_is_real. This would be complicated
to implement. Better would be to use a design where calculation is not
expected to be done automatically in the first place. This represents
a pretty big change in the way SymPy works, though.
If you look at the matrix expressions, they are close to the sort of
design we should be aiming for. If you create any expression with
matrix expressions, it is completely unevaluated, and only when you
call doit() does it attempt any simplifications, even really basic
ones (with the exception of shape checking, which already might be too
much).
>>> A = MatrixSymbol("A", n, n)
>>> MatAdd(A, A)
A + A
>>> MatAdd(A, A).doit()
2*A
Note that this is different from calling +, which calls doit() automatically
>>> A + A
2*A
The important difference is that an algorithm that manipulates matrix
expressions which pulls them apart and rebuilds them with args will
effectively create the class directly using MatAdd, not +, so the
evaluation will not happen there. Those algorithms are where the
performance difference between evaluating and not evaluating will
matter the most.
Ideally a class like Add would not even have a __new__ method, so that
it is not possible for it to evaluate directly in its constructor.
Instead all evaluation would happen in a different method like doit().
Certain evaluations like x + x -> 2*x would still happen when using +
so that the end-user experience is still practical.
This would also have the side effect of making unevaluated expressions
easier to work with. Right now you have to create them with things
like evaluate=False, and they are buggy when you use them. If they
were directly supported as the "default" way that expressions work,
then it would be straightforward to use them, and every function would
handle them correctly.
If we don't remove the automatic evaluations then any other approach
will always be an uphill battle to get performance, because for any
automatic simplification you can construct expressions that make it
too slow, and because they happen automatically, it will completely
remove any other performance gains you might have had.
Aaron Meurer
> --
> You received this message because you are subscribed to the Google Groups "sympy" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to
sympy+un...@googlegroups.com.
> To view this discussion on the web visit
https://groups.google.com/d/msgid/sympy/e99b97c2-4904-45be-852b-1a507915a22fn%40googlegroups.com.