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).
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. 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"). 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. 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]. >> > 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. > > > -- > 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.
-- 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.
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, |
0001-Basic-demonstrative-fixes-for-StrictInequality.patch
Description: Binary data
