I think my original message was misleading. The reason we should use the predicate is not because we merely want to make an example. It's because Q.eq can do what Eq cannot. As far as I know, logical inference in assumption module use classes such as AllArgs in assumptions/sathandlers module. These classes takes predicate as arguments and loosely behave like a composite function. To make relation work with fact system (again, x > y implies that x and y are both extended real numbers), we need relational predicate. But I understand that this still might be weak reason to break the backwards compatibility.
Provided that we do not implement symbolic manipulation, I believe that the only disagreement we have here is : given that we introduced the relation predicate, do we need to have two different classes or do we need to have one class at the cost of breaking backwards compatibility? If so, then what about this? 1. Eq, Ge, and other variables return relation predicate. No Q.eq. 2. Eq(x, x) does not return True. But unlike predicates which do not evaluated by simplification, Eq(x, x).simplify() evaluates to True with deprecation warning. 3. After deprecation period is over, Eq(x, x).simplify() no longer evaluates to True. I think this can prevent the compatibility issue for most of downstream codes because the standard way to evaluate the relational has been simplifying. Eq(sin(x)**2 + cos(x)**2, 1) isn't evaluated to True without simplifying, so I believe many codes have simplifying step before expecting a boolean atomic result. Jisoo Song 2021년 3월 4일 목요일 오전 8시 56분 31초 UTC+9에 [email protected]님이 작성: > 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/d5a233f0-aef6-4762-b87e-15ad2729f00an%40googlegroups.com.
