All,

I should clarify the current state of things because I am the one who
last touched the code in this respect.

* There is now logic in Relational that tries to actually evaluate the
truth value of a Relational when it is constructed.  Thus you get the
following:

In [20]: Lt(0,2)
Out[20]: True

In [21]: Lt(2,0)
Out[21]: False

This uses the new _eval_relation to and is a mathematical test.

* When Relationals are symbolic, if you do .subs on them, you can get
to a bool.  Again, this result has a mathematical meaning:

In [22]: Lt(x,0).subs(x,-1)
Out[22]: True

In [23]: Lt(x,0).subs(x,1)
Out[23]: False

* The only time you access the other meaning (the more primitive
Python one) is if you *cast* a Relational to a bool:

In [24]: bool(Lt(x,y))
Out[24]: True

But currently, you don't always get true:

In [25]: bool(Lt(x,0))
Out[25]: False

The reason is that the __nonzero__ methods of different Relational
subclasses use the .compare method in different ways.  I didn't write
this code, BUT I seem to remember that many tests fail if you simply
have __nonzero__ return True.  I didn't investigate why, but my guess
is that this is used to order different Relationals in expressions.

* Doing the following is dangerous:

if x < y:
   ...

The reason is that depending on what x and y are, you may be getting
back the primitive or Mathematical version of less than.

* There is another inconsistency in that == and != don't return
Relational subclasses, but <, >, <= and >= do.

* Some of this changes with python 3, so whatever we do, we need to
move towards a solutions that won't change the user interface of sympy
when we transition to python 3.

Here is what I propose:

Someone (unfortunately I don't have time right now, I may have time
later in the quarter) should go through and write a summary
(preferably in the dev section of the Sphinx docs) that summarizes:

* How Python 2 and 3 handle object equality, comparisons, etc.  This
includes cmp, bool, all the __lt__ methods, __nonzero__, etc.

* How we currently handle mathematical truth in sympy.  This is mostly
focused on the math of the Relational classes and how they are
constructed (x<y shorthand for Lt(x,y)).

* How we currently handle the more primitive type of truth in sympy.
This is relevant in both casting sympy objects to bool AND how we
order sympy objects in expressions.

* A proposal of how to handle all of this in a uniform and consistent
manner in both python 2 and 3.

I think we should do this before making any major changes to how all
this is handled.  Otherwise, we are going chase our tails around and
go crazy.

Cheers,

Brian

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?
> That would allow some rather weird things:
>
> In [1]: if x < y and x > y:
>   ...:     print "I would not expect to see this printed"
>
> 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.

Reply via email to