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.

Reply via email to