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) >>> >> >> Not sure what you mean by this. Are you saying you *should* get this: >> >> In [17]: refine(e.subs(x,0.5)) >> Out[17]: True >> >> Yes, that is what I mean. Refine should recursively check if an >> inequality will evaluate to True or False, even in the case where it is only >> because of assumptions on variables. So this should return True also: >> >> In [6]: refine(x > y, Assume(x - y, Q.positive)) >> Out[6]: y < x >> >> But like you say, 0 < 0.5 should automatically return True even without >> refine(), unless some evaluate=False flag is sent to Lt(). >> >> >> >> >>> I wonder if internally, x > y should be represented as Assume(x - y, >>> Q.positive) and x >= y as Assume(x - y, Q.nonnegative) (except there doesn't >>> seem to be a Q.nonnegative yet for some reason), except that it would also >>> have to keep track of what the original kind of inequality it was and what >>> terms were on what side. Anyway, Ask(x - y, Q.positive) is the proper way >>> to evaluate x < y, not checking x>=y, etc. >>> >>> >> Not sure about using Assume for all of this. Inequalities seem different >> than assumptions to me… >> >> An inequality is not different from assumptions. x < y is the same as >> saying x - y is positive. It's similar to how we usually use x - y in SymPy >> instead of x == y. Expressions are assumed by default to be equal to 0. >> This is why having an assumptions system that allows assumptions on >> expressions instead of just variables is essential for inequality >> manipulation. Any SymPy algorithm when presented with an Equality class >> will first subtract one side from the other and proceed with it as an >> expression (c.f. the top of the sources of solve and dsolve()). I would >> imagine that a similar thing would be true for an inequality, only also >> carrying the Assume(…, Q.positive) or Assume(…, Q.nonnegative) object around >> with it, where … is the smaller side subtracted from the larger. >> >> By the way, another thing that I have noticed about inequalities, though >> it is only moderately annoying rather than show stopping, is that they do >> not always retain the order that they are initialized in: >> >> In [9]: x > y >> Out[9]: y < x >> >> Internally, there should be little distinction between x > y and y < x, >> but for humans, reading inequalities can be much easier if they are in a >> certain order, which will be the order that the user enters them in. >> >> Aaron Meurer >> >> >> Brian >> >> >>> Aaron Meurer >>> > >>> > 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. >>> >>> -- >>> 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. >>> >>> >> >> >> -- >> 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] <sympy%[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. > > > > -- 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.
