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?

The problem with them always returning True, is that this behavior is
implemented in the __nonzero__ method of Relational.  This method is
also used to order Relationals in expressions.  Thus, it needs to
return 1, 0, -1 to allow that ordering.

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

With our current code base, I would not ever do this.  The reason (see
my other email) is that x<y can either be a bool that represents
mathematical < OR bool(Lt()) which is is the more primitive type of
truth.

For now I would do:
e = x<y
if isinstance(e, Relational):
  ...
elif isinstance(e, bool):
  ...

A pain, but until we decide what to do with all of this, this is the
safe thing to do.

Cheers,

Brian

> 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