On Tue, Mar 30, 2010 at 3:26 AM, jegerjensen <[email protected]> wrote: > Am I right that you have concluded that bool() of a relational should > always return True?
The problem with them always returning True, is that this behavior is implemented in the __nonzero__ method of Relational. This method is also used to order Relationals in expressions. Thus, it needs to return 1, 0, -1 to allow that ordering. > That would allow some rather weird things: > > In [1]: if x < y and x > y: > ...: print "I would not expect to see this printed" With our current code base, I would not ever do this. The reason (see my other email) is that x<y can either be a bool that represents mathematical < OR bool(Lt()) which is is the more primitive type of truth. For now I would do: e = x<y if isinstance(e, Relational): ... elif isinstance(e, bool): ... A pain, but until we decide what to do with all of this, this is the safe thing to do. Cheers, Brian > Today I get no output from this and it would surprise me to get > anything else. > > Instead I propose that we just agree that bool(x<y) has nothing to do > with the mathematical relation, but will completely hand over the > relation to python for evaluation. (Isn't this the present > behavior?) If we accept this rule, Out[65] and Out[66] are not > inconsistent, but shows rather how python works internally. The > language reference states that "objects of different types always > compare unequal, and are ordered consistently but arbitrarily.". > > If on the other hand you want to test the mathematical expression, you > should use ask() as you have discussed, or maybe a method like > Relational.is_valid(). > > Øyvind > > On 27 Feb, 11:16, Brian Granger <[email protected]> wrote: >> Aaron, >> >> Thanks for looking at this. >> >> I'm still working out how the new assumptions work myself. They are not >> >> > fully merged in yet, so I don't know how much will actually work. I guess >> > you would just have to try it. We may need to finish merging the >> > assumptions in order to full sort out inequalities (ironically, we need >> > assumptions to do inequalities, but we also need to ability to solve >> > inequalities to have some kinds of assumptions). >> >> OK. Hopefully others can fill in some details about the status of the new >> assumptions system. >> >> > Yes, Ask(whatever, assumptions) will return True if whatever is true under >> > assumptions, False if it is false, and None if it is undetermined. Or at >> > least it is supposed to, again, the system is not fully merged in yet, so >> > there could be problems. This is to become the standard interface. I >> > believe your concerns were one of the reasons for creating the new >> > assumptions system in the first place. >> >> Nice, that sounds like it should address this issue exactly. >> >> I agree that that __nonzero__ is a mess. Based on your discussion below, I> >> think the inequalities should automatically return True or False if it is >> > number < number, and if it stays as an inequality class, then the bool >> > should just be false (i.e., replace __nonzero__ with simply "return True"). >> >> Yes, __nonzero__ should just return True to be consistent with how it is >> handled elsewhere in sympy. I also agree for numbers. The only case the >> this doesn't cover is other object that have well defined < and > that >> should be simplified to True or False when compared. >> >> > I think I figured out most of your problems. See the attached patch for a >> > demonstration (it needs cleaning up, and I only did StrictInequality). See >> > also the commit message. >> >> Nice, this will help me to get going. If I have a chance this weekend I >> will continue the work you started and report back. >> >> Thanks Aaron! >> >> Cheers, >> >> Brian >> >> > -- >> > You received this message because you are subscribed to the Google Groups >> > "sympy" group. >> > To post to this group, send email to [email protected]. >> > To unsubscribe from this group, send email to >> > [email protected] <sympy%[email protected]>. >> > For more options, visit this group at >> >http://groups.google.com/group/sympy?hl=en. >> >> > Someone else will need to answer your question on how far we are with the >> > assumptions system. I haven't been working on it. >> >> > Aaron Meurer >> > On Feb 26, 2010, at 9:25 PM, Brian Granger wrote: >> >> > Aaron, >> >> > Thanks for the thoughtful replies. As I have been looking at this further, >> > I think the core question is this: how are Sympy objects converted to >> > bools? >> >> > Is seem that there are two notions: >> >> > * The primitive notion of truth built into python itself. This is handled >> > by Python in the __nonzero__ method. The pattern followed in 90% of Sympy >> > is that __nonzero__ returns True unless the object is Zero. In this >> > concept >> > of truth is makes sense to ask the truth value of single objects: >> >> > bool(x) >> > bool(1) >> > etc. >> >> > * The mathematical idea related to whether or not a relational equation is >> > satisfied: >> >> > 1 < 0 >> > x < y >> > 2*x + y == 0 >> >> > To me it seems that these two types of truth concepts should be >> > *completely* orthogonal. What are the consequences of this? >> >> > 1. Converting a relational equation to a boolean using bool [bool(x<0)] is >> > not asking the mathematical question "is x less than 0". It is asking the >> > the more primitive question of "is this a nonzero python object". >> >> > 2. There must be a different API for testing if a relational equation is >> > satisfied. I don't see this separate interface. Maybe it is the >> > assumption >> > system, but assumptions seem to be different conceptually than equations. >> > But I don't really understand how assumptions work in sympy. Whatever this >> > other API is, it needs to be capable of giving the following answers: >> >> > * It is satisfied >> > * It is not satisfied >> > * It is undetermined. >> >> > The current situation is lacking in two respects: >> >> > * The classes in relational (Equality, Inequality, StrictInequality, etc.) >> > violate this clean separation of truth types by having __nonzero__ method >> > that combines and confuses the two types. You see things like this: >> >> > def __nonzero__(self): >> > if self.lhs.is_comparable and self.rhs.is_comparable: >> > if self.lhs.is_Number and self.rhs.is_Number: >> > return self.lhs < self.rhs >> > return self.lhs.evalf()<self.rhs.evalf() >> > return self.lhs.compare(self.rhs)==-1 >> >> > * There is no standard interface for asking about the second (relational >> > equation) type of truth. This is probably why Relational classes are >> > confusing the two. >> >> > I tried commenting out the __nonzero__ method in Relational, but a good >> > number of tests fail - some with a RuntimeError saying the recursion limit >> > has been reached. >> >> > I am not sure how to proceed. What is the most up to date description of >> > the assumption system in sympy? Is the new assumption system in place and >> > the recommended approach. >> >> > Cheers, >> >> > Brian >> >> > On Fri, Feb 26, 2010 at 7:11 PM, Aaron S. Meurer <[email protected]>wrote: >> >> >> On Feb 26, 2010, at 5:40 PM, Brian Granger wrote: >> >> >> Aaron, >> >> >> Thanks for the response...replies inline >> >> >> > In [66]: bool(x<0) >> >>> > Out[66]: False >> >> >>> > This is obviously not consistent and it a bug in Relational.__nonzero__ >> >> >>> Yes, let's make any SymPy expression return True if and only if it is not >> >>> the object S.Zero (or maybe also some empty containers, like Matrix([])). >> >> >> Yep and that is what Basic.__nonzero__ does. >> >> >>> I'm not sure what to do about the relational (see below). >> >> >> Right. >> >> >>> > Relational classes don't properly evaluate to booleans >> >>> > ====================================================== >> >> >>> > Consider these examples: >> >> >>> > In [67]: Eq(0,0) >> >>> > Out[67]: 0 == 0 >> >> >>> > In [68]: Ge(1,0) >> >>> > Out[68]: 0 <= 1 >> >> >>> > Obviously, these should resolve to booleans. You may think, why >> >>> wouldn't >> >>> > you just do 0==0 or 1<0? But consider this: >> >> >>> Just to be clear we overload __lt__, etc. to return the Le() class, but >> >>> == is just the simple equality testing (not the Eq class). This is fine, >> >>> but like you say, there needs to still be a way to do actual comparison. >> >>> The problem I have seen is that it likes to turn things into booleans >> >>> that >> >>> don't make sense that way, other than being non-empty. For example, the >> >>> x<0 >> >>> above. >> >> >> Right. >> >> >>> Another thing, automatic evaluation should proceed on a SymPy object only >> >>> if three conditions are met: >> >>> 1. The evaluation will always make the object simpler. >> >>> 2. The evaluation is very cheap in every case. >> >>> 3. The evaluation is so trivial that no one will ever not want it done. >> >> >>> For example, we auto-simplify exp(x)*exp(x) to exp(2*x), but we leave >> >>> exp(x)*exp(y) alone, because if we auto-combined it, it would be >> >>> impossible >> >>> to actually get exp(x)*exp(y) instead of exp(x + y) (things used to be >> >>> this >> >>> way back in SymPy 0.6.4 until I spent a very headacheful few weeks >> >>> changing >> >>> it last summer). >> >> >>> (1) is clearly the case for turning inequalities into booleans. (2) will >> >>> only be true for the simple case of number < number. >> >> >> I could imagine other mathematical objects that have a clear concept of < >> >> and > and that are cheap to find. >> >> >> Yes. I think we are simplifying things like x < x + 1 right now too. But >> >> there is also (3) to consider for that. >> >> >>> Otherwise, even if the assumption for Ask(x - y, Q.positive) is True for >> >>> x > y, we should leave it alone in Gt.__new__ and leave the work to >> >>> refine(). Actually, even if this were cheap, I would still want to >> >>> leave it >> >>> alone because of (3). >> >> >> Yes, I agree that refine should be used in this cases. >> >> >>> Also, should we prevent bool(relational) from working otherwise, much >> >>> like the TypeError you get when you do 1j < 1? >> >> >> The problem with this is that there is little different between bool(x) >> >> and bool(x<0). >> >> >>> I would rather have bool(x<y) raise an error than mislead me by >> >>> returning True (misleading in the sense that bool(x>y) would also be >> >>> True). >> >> >> But it would also be misleading that bool(2*x) is True, but bool(x<0) >> >> raises an exception. >> >> >> I guess the problem is what if you want to do an actual comparison. We >> >> override <, >, etc., but that is what you would normally use in an if >> >> statement, though I guess you should really be making a call to Ask(). So >> >> as long as this is clear, it shouldn't be a problem either way. >> >> >>> Semantically speaking, relational.__nonzero__ should be True unless the >> >>> relational is explicitly False, and relational.__bool__ should be either >> >>> the >> >>> explicit truth value of the relational or raise TypeError if there is >> >>> none, >> >>> but I do not know the actual implementation difference between these two >> >>> in >> >>> Python. >> >> >> Yes, there is this issue as well. >> >> >>> > In [69]: e = Ge(x,0) >> >> >>> > In [70]: e.subs(x,1) >> >>> > Out[70]: 0 <= 1 # Just Ge(1,0)! >> >> >>> > Thus. it is common and easy to get Relational classes that should >> >>> evaluate to >> >>> > a boolean but don't. This behavior also affects boolean logic classes >> >>> > like And/Or, etc. as well as Interval: >> >> >>> > In [71]: e = And(x>0,x<1) >> >> >>> > In [72]: e.subs(x,0.5) >> >>> > Out[72]: And(0 < 0.5, 0.5 < 1) >> >> >>> > The problem is that the __new__ method of Relational does NOT actually >> >>> > try to compare the lhs and rhs. That is, Ge.__new__(lhs, rhs) doesn't >> >>> actually >> >>> > try lhs >= rhs. But, we can't have it try that or it will generate an >> >>> > infinite loop! Resolving this will be quite subtle. >> >> >>> This should at least work with refine: >> >> >>> In [17]: refine(e.subs(x,0.5)) >> >>> Out[17]: And(0 < 0.5, 0.5 < 1) >> >> ... >> >> les mer » > > -- > You received this message because you are subscribed to the Google Groups > "sympy" group. > To post to this group, send email to [email protected]. > To unsubscribe from this group, send email to > [email protected]. > For more options, visit this group at > http://groups.google.com/group/sympy?hl=en. > > -- You received this message because you are subscribed to the Google Groups "sympy" group. To post to this group, send email to [email protected]. To unsubscribe from this group, send email to [email protected]. For more options, visit this group at http://groups.google.com/group/sympy?hl=en.
