On Sat, 13 Jun 2020 at 00:22, Aaron Meurer <[email protected]> wrote:
>
> On Sun, Jun 7, 2020 at 4:08 PM Oscar Benjamin
> <[email protected]> wrote:
> >
> > 3. What are the limitation of the new module? Where is it not implemented?
> >
> > The new assumptions were made a lot faster last Summer. Their slowness
> > was one major limitation before. They are still slow in comparison to
> > the old assumptions. The real limitation is the fact that the old
> > assumptions are used all across the codebase in both elementary
> > evaluations and in more complex routines. A huge amount of code would
> > need to be changed in order to make it so that general routines like
> > "integrate" use the new assumptions.
>
> The biggest thing that is missing is the other direction, to make
> expr.is_integer check ask(Q.integer(expr)). With the improved
> performance, this may now be possible to do, although I suspect more
> work is still required to make it so we don't slow down SymPy. For
> instance, IMO we need a better model of assumptions evaluation so that
> we can do fast checks vs. slow checks. The (new) assumptions do
> various levels of checks starting from a simple "is this already
> assumed" going all the way to a full SAT solve. But there's no way to
> limit how far it tries to go to get an answer. It's either all or
> nothing.

We can't have `expr.is_integer` call `ask(Q.integer(expr))` without
first making the new assumptions free standing. At the moment the new
assumptions are propped up by the old and depend heavily on them for
their queries.

The old assumptions for something like `expr.is_integer` are *already*
too slow. This is the main cause of slowness when working with large
expressions as you can see if you profile e.g. a slow call to expand:
https://github.com/sympy/sympy/pull/19485#issuecomment-639416355

If the new assumptions are any slower then I don't think that we
should use them by default in evaluation. Instead I would much rather
remove the slower parts of the old assumptions and implement the more
complicated ways of evaluating queries in the new assumptions and then
have those used judiciously so core evaluation can use the old
assumptions and be fast while key algorithms or APIs can choose at the
appropriate place to use the new assumptions to answer a critical
query or to simplify something important like a Piecewise.

> One goal is to remove assumptions based evaluation, or at least limit
> it to only cases where the assumptions can be computed quickly. The
> "n" in cos(n*pi) can be an arbitrarily complicated expression. With
> the new assumptions, it may require a lot of computation to compute
> whether or not n is an integer. This is due to the fact that the new
> assumptions allow assuming more complicated logical predicates and
> more complicated logical queries.

It would be very difficult to remove assumptions based evaluation but
it would be potentially worthwhile. The goal as I would put it is to
limit evaluation itself. We should also remove the slower parts of the
old assumptions when the new assumptions can pick up the slack.

> > There are other problems with the new assumptions such as the idea
> > that we can have a global flag as the "with assuming(...)" API
> > implies. The "assuming" context manager seems like a fundamentally bad
> > idea to me because the intention is that it will bring in a global
> > flag that will alter the behavour of every other part of the codebase.
> > That means that it breaks thread-safety, that the cache would need to
> > be cleared every time anything is assumed, that code is unpredictable
> > because its behaviour can be manipulated from outside and many more
> > problems. Basically the assuming API implies a massive and very
> > complicated global variable and those are not usually good.
> >
> > If we want to use the new assumptions properly as part of lots of
> > different functions around the codebase then the clean way is for most
> > APIs to grow an assumptions keyword e.g.:
> >
> >     sol = solve(a*x - b, x, assumptions=Q.nonzero(a))
>
> But then any function that calls solve() must also have that keyword
> argument, or you won't be able to make use of the assumptions. The end
> result is that you have to extend the API of hundreds of functions,
> and you can still easily have functions that don't support the API.

That's correct. It will be a lot of work. Changing the API is the
easier part compared to identifying and implementing support for the
new assumptions in the right places.

> The context manager is simpler API wise although I can see how there
> are technical issues with things like the cache.
>
> I don't think the "globalness" of the new assumptions can be avoided.
> With the old assumptions, you can only assume things about symbols, so
> it's easy to make Symbol('x') and Symbol('x', positive=True) compare
> unequal. But for something like, x > y (Q.positive(x - y)), it has to
> be stored separately from the expressions that contain x and y.

The assumptions should be stored in the call stack as an explicit
local variable. They should be provided as an explicit parameter to
API that needs them. That API should document what it will potentially
use the assumptions for.

The other problem with "with assuming" is that it's very confusing for
users to know when it should have any effect. The "new" assumptions
have been new for years and throughout that time people have been
trying to use "with assuming" because it claims to be able to affect
everything when even now it still affects nothing. An explicit
parameter can clearly document when and how the new assumptions are
being used as support for using them is added (which will still take
years from now).

--
Oscar

-- 
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 [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/sympy/CAHVvXxQZ7S8%3DdZZ2DcpcpS_2cHbufwsp%2BYz0iCGtjN_ExC9Gyw%40mail.gmail.com.

Reply via email to