On Mar 30, 2010, at 4:26 AM, jegerjensen wrote: > Am I right that you have concluded that bool() of a relational should > always return True? > That would allow some rather weird things: > > In [1]: if x < y and x > y: > ...: print "I would not expect to see this printed" > But why would you want to do this? "if x < y" doesn't make sense if x and y are symbols.
> 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. But then we loose the shortcut x < y => Lt(x, y). > (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. > This will change in Python 3. There, objects have to be the same type to be compared. Aaron Meurer > 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.
