On Wed, Mar 3, 2021 at 4:39 PM Oscar Benjamin
<[email protected]> wrote:
>
> On Wed, 3 Mar 2021 at 21:40, Aaron Meurer <[email protected]> wrote:
> >
> > On Wed, Mar 3, 2021 at 11:58 AM JSS95 <[email protected]> wrote:
> > >
> > > Also, `Q.eq(x, y)` will be able to support algebra between the relational
> > > as @sylee957 shared in this comment. `Q.eq(x, 1) + Q.eq(y, 1)` will
> > > return `AddSides(Q.eq(x, 1), Q.eq(y, 1), evaluate=True)`, which in turn
> > > will be evaluated to `Q.eq(x + y, 2)`. `Q.gt(x, 2) * -1` will return
> > > `Q.lt(-x, -2)`, and `Q.gt(x, 2) * y` will return `MultiplySides(Q.gt(x,
> > > 2), y)` if the sign of `y` cannot be determined.
> > >
> > > This way, `Q.eq` can make `Equation` no longer be required to be
> > > implemented. However this idea can be discarded if it does not get
> > > approved.
> >
> > I still think this is a bad idea. Making symbolic and boolean
> > relationals the same leads to too much type confusion. The evaluation
> > of relationals to booleans is not the only reason this is problematic.
> > There's a reason Boolean and Expr are separate objects, and for
> > example, S.true and S.false are not allowed to be treated as numbers
> > (S.true + 1 gives an error). Treating booleans and expressions
> > (numbers) as the same thing leads to all sorts of errors.
> >
> > This is the main issue for this, for reference
> > https://github.com/sympy/sympy/issues/4986.
> >
> > I appreciate that it might be confusing to users, but I think we can
> > mitigate that to some degree with error messages. If Eq and Eqn are
> > strict about their types, so that Eq only works in boolean contexts
> > and Eqn only works in expression contexts, then users can
> > unambiguously tell if they need to use the right object.
>
> We need to be very careful to define what "in expression contexts"
> means. Personally I see a big difference between allowing the use of
> operators like + and * and allowing in Eq to be used as one of the
> terms in a symbolic Add or Mul expression.
>
> To be clear the first means saying:
>
> Given an equation object eq=Eq(x, y), the Python code 2*eq will
> give Eq(2*x, 2*y).
>
> To me that does not imply that there is any mathematical meaning to
> multiplication between an equation and an integer. It just means that
> we can use Python's infix arithmetic operators for convenient
> manipulations of equations. In Python you can also add lists like [1,
> 2] + [3]. That does not imply that we should allow the list [1, 2] to
> be substituted for x in a symbolic expression like x**2 + 1.
>
> On the other hand in sympy 1.4 the Relational class which is a
> superclass of Eq was actually a subclass of Expr meaning that it could
> be used as part of any symbolic expression in any place where an
> expression ought to be e.g.:
>
> In [4]: Eq(x, 2)**(x > 1)
> Out[4]:
> x > 1
> (x = 2)
>
> To me that is just a gibberish expression object and should not be
> allowed under any variant of an equation/inequality object (I removed
> this behaviour in sympy 1.5 I think). I would not propose that any
> kind of equation object could appear in place of an expression as part
> of any *symbolic* expression. That is very different from allowing
> some operations that can conveniently manipulate equation objects
> while still keeping them entirely separate from symbolic expressions.
That's a fair point. Maybe it's wrong to say that Eqn should be an
Expr. But certainly it should not be a boolean.
>
> > > 4. Compatibility with Eq around codebase
> > >
> > > Every codebase will be modified so that `Q.eq` can be used instead of
> > > `Eq` everywhere. For example `Piecewise((1, Q.eq(x, 0)), (0, True))` will
> > > be supported, and `solveset(Q.eq(x**2, 1))` will return `{-1, 1}`.
> > >
> > > 5. Migration from Eq to Q.eq
> > >
> > > `Eq` and other relational will be retained only for backwards
> > > compatibility. Documentation for `Q.eq` will be thoroughly made and users
> > > will be informed to use `Q.eq` instead of `Eq`. After a few release,
> > > `Q.eq` will be renamed to `Eq`.
> >
> > I still maintain that adding a new *name*, Q.eq, is unnecessary and
> > confusing. A new name is appropriate for a new object (like Equation),
> > but what you are suggesting is to replace Eq with Q.eq. So why not
> > just change Eq to be what you are proposing Q.eq to be? I think we can
> > remove the automatic evaluation from Eq. It would be less of a
> > backwards compatibility break than renaming the name (you could argue
> > it isn't even technically a break, since nothing guarantees when or if
> > Eq() will evaluate to a boolean).
>
> There are different perspectives on this. It's also possible to argue
> that *any* change to anything is a compatibility break!
>
> I think in this case that this is not only a change in behaviour but
> also clearly departing from the documented purpose of the Eq class.
> These changes contradict most of the opening section of the docstring
> for Eq:
> """
> Represents that two objects are equal. If they can be easily shown to
> be definitively equal (or unequal), this will reduce to True (or
> False). Otherwise, the relation is maintained as an unevaluated
> Equality object. Use the simplify function on this object for more
> nontrivial evaluation of the equality relation.
>
> As usual, the keyword argument evaluate=False can be used to prevent
> any evaluation.
> """
> https://docs.sympy.org/latest/modules/core.html#sympy.core.relational.Equality
>
> I do think that a clear rationale is needed before any significant
> backwards compatible change and these specific points need to be
> addressed:
>
> 1. Why is an incompatible change needed?
> 2. How would the incompatibility cause downstream user/library code to break?
> 3. Does it seem like much code would break?
> 4. Are there ways to mitigate that breakage?
> 5. How would someone change code to be compatible with sympy both
> before and after the break?
Making Eq always unevaluated is a breakage in the sense that anything
that relies on it returning True or False for trivial cases will stop
working. But any code that does that should already be handling the
unevaluated case, because there are no guarantees about it when it can
evaluate, and in general, it can't. So user code, if correct, won't
break in the sense that it gets unexpected input, only in the sense
that it might stop evaluating for cases that it did before. Also the
fix would be to use ask() or doit() (whatever we decide is the best),
and should be difficult to apply. We could even do a deprecation where
make __bool__ continue to evaluate.
>
> > And to reiterate a point I made on one of your pull requests: "As an
> > aside, I never realised there were so many ways to spell '='.
> > 'Equation', 'equality', 'equal', 'equals', 'equivalent', 'eq', ....
> > And at the rate things are going, we are going to have a separate
> > class in SymPy for each one, each with its own distinct semantic
> > meaning. This is very confusing for users, so I would like to avoid
> > it."
> >
> > The way I could see this being a good idea is if we want to convert Eq
> > to instead be the symbolic equation class and make Q.eq the boolean
> > variant. But as Oscar pointed out on one of the issues, this would
> > break a lot of code that currently assumes Eq is a boolean (it's often
> > used inside of boolean expressions, like in Piecewise).
>
> I don't think that Piecewise is a problem because it can just be made
> to call ask(cond) or bool(cond). It knows the condition is supposed to
> be boolean so it can do that explicitly.
My point is that the equation class should not be usable as a boolean.
ask(Equation) should give an error. So that's problematic if we want
to make Eq the equation class and use something new for boolean
equations. Any existing code that does stuff like And(Eq(x, y), ...)
would be wrong if we did that.
>
> The problem is more code that tries to use Eq directly like:
>
> if Eq(x, y) is S.true:
> # do something
>
> For example right now all of the logic in the FiniteSet class is built
> around using this as a way of sometimes being able to tell when two
> objects are equal. I have no idea how much this is used outside of the
> sympy codebase though.
I don't know if people do that with Eq. I didn't find any instances of
it in the SymPy codebase, outside of tests that specifically test that
Eq() returns a boolean.
But that definitely is a pattern with Lt (or at least the operator <).
And we will want whatever we do with Eq to be consistent with the
inequalities, so we should consider that. Although to be sure, <
doesn't have to mean the same thing as Lt. It may actually be easier
because we can make < evaluate but Lt() not. Alternatively, we could
deprecate this pattern, in favor of something like "if ask(a < b) is
True".
Aaron Meurer
>
>
> --
> 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/CAHVvXxQhyA14kRTswJ2CSiPsBbMa9GZuvfGraprH%3Dv%3DePOYiKQ%40mail.gmail.com.
--
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/CAKgW%3D6%2BABWSJTMdRktUbZCUV2qH9LbqbuCfN3hQ52cgiP6HJNw%40mail.gmail.com.