Hi.  Here are my opinions on the matter.
On Feb 26, 2010, at 4:30 PM, Brian Granger wrote:

> Hi, 
> 
> Here is my summary of some bugs i have found in Relational.  I would fix 
> them, but I think there are larger issues that need discussing.
> 
> What is the truth value of a symbolic expression?
> =================================================
> 
> The current general pattern is that symbolic expressions evaluate to True:
> 
> In [61]: bool(x)
> Out[61]: True
> 
> In [62]: bool(x+1)
> Out[62]: True
> 
> In [63]: bool(x*2)
> Out[63]: True
> 
> In [64]: bool(2*x)
> Out[64]: True
> 
> In [65]: bool(x>0)
> Out[65]: True
> 
> But:
> 
> 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([])).
I'm not sure what to do about the relational (see below). 
> 
> 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. 

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.  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).    

Also, should we prevent bool(relational) from working otherwise, much like the 
TypeError you get when you do 1j < 1?  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).  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.  
> 
> 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)

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.  

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.

Reply via email to