Opened 8 years ago

Closed 7 years ago

#11309 closed defect (fixed)

Sage sees - x + y > 0, - y + x >= 0, and x - y > 0 as equivalent

Reported by: tnv Owned by: burcin
Priority: major Milestone: sage-5.1
Component: symbolics Keywords: inequality equality relational sd31 __richcmp__ sd40.5
Cc: kini, kcrisman, tnv Merged in: sage-5.1.beta3
Authors: Keshav Kini, Burcin Erocal Reviewers: Karl-Dieter Crisman, ThanhVu Nguyen
Report Upstream: N/A Work issues:
Branch: Commit:
Dependencies: Stopgaps:

Description (last modified by kini)

-x + y > 0 and x - y > 0 are treated the same in Sage.

sage: version()
'Sage Version 4.6.2, Release Date: 2011-02-25'

sage: (-x +y < 0) in [x -y < 0] 
True 

Set([-x +y >= 0,x -y >= 0]) 
{-x + y >= 0} 

and they have the same Hash

sage: var('x,y') 
(x, y) 
sage: hash(-x + y > 0 )
1221566266
sage: hash(-x + y >= 0 )
1221566266
sage: hash(x - y >= 0 )
1221566266
sage: hash(-y + x >= 0 )
1221566266
sage: hash(x - y > 0 )
1221566266

It seems to me that Sage treats >, >=, and == the same (see #7660). If this is true then it's a serious problem and needs to be addressed.

Apply:

  1. trac_11309-fix-comparison-of-comparisons.patch
  2. trac_11309-equate-flipped-comparisons.patch

Attachments (2)

trac_11309-fix-comparison-of-comparisons.patch (3.6 KB) - added by kini 8 years ago.
trac_11309-equate-flipped-comparisons.patch (4.4 KB) - added by kini 7 years ago.
apply to $SAGE_ROOT/devel/sage

Download all attachments as: .zip

Change History (60)

comment:1 Changed 8 years ago by tnv

  • Description modified (diff)

comment:2 Changed 8 years ago by kini

  • Cc kini added

comment:3 Changed 8 years ago by kini

  • Description modified (diff)

comment:4 Changed 8 years ago by kini

  • Authors set to Keshav Kini, Burcin Erocal
  • Status changed from new to needs_review

Ready for review! Thanks to Burcin for walking me through the Cython code.

comment:5 Changed 8 years ago by tnv

Thanks for creating the patch!!

I don't know how to apply this patch though - if you can walk me through it then I can test.

But in the mean time, what are the result for these commands ? If the results are different than the defected version above and as expected then probably the patch is correct.

sage: (-x +y < 0) in [x -y < 0]

Set([-x +y >= 0,x -y >= 0])

sage: var('x,y') (x, y) sage: hash(-x + y > 0 ) sage: hash(-x + y >= 0 ) sage: hash(x - y >= 0 ) sage: hash(-y + x >= 0 ) sage: hash(x - y > 0 )

comment:6 Changed 8 years ago by kini

I've changed the patch a little bit just now, by the way.

To apply the patch, go to devel/sage/ inside your sage directory, and type sage -hg qimport http://trac.sagemath.org/sage_trac/raw-attachment/ticket/11309/trac_11309-fix-comparison-of-comparisons.patch, type sage -hg qpush, type sage -b, and finally launch sage to test the patch!

Your examples are fixed, yes. You can see them listed inside the patch, where I added some more examples in the documentation of the function I changed.

comment:7 Changed 8 years ago by kini

Oh, by the way, I didn't fix the hashes. They're screwed up anyway, so this solution avoids using them to decide anything about whether expressions are the same or not. We might fix that in a later ticket...

comment:8 Changed 8 years ago by tnv

Thanks for the info.

Which Sage version do I apply the patch to ? the latest 4.7 ? I'll do that tomorrow at work

if they still give the same hashes then (-x +y < 0) in [x -y < 0] still gives True and Set([-x +y >= 0,x -y >= 0]) still eliminates one of them . Correct ?

comment:9 Changed 8 years ago by kini

No, incorrect, because I changed the code to not use the hashes at all when doing the comparison. The hashes are now irrelevant to this operation. However kcrisman found a bug in my patch so I will update it again in just a second...

comment:10 Changed 8 years ago by kini

  • Status changed from needs_review to needs_work

OK, this looks like it's going to take a little while, I'm getting some unexpected doctest errors... I'll fix it in the morning :)

comment:11 Changed 8 years ago by kini

  • Status changed from needs_work to needs_review

Never mind, ready for review again!

comment:12 Changed 8 years ago by kini

  • Cc kcrisman added
  • Owner changed from burcin to (none)

comment:13 Changed 8 years ago by kini

  • Owner changed from (none) to burcin

burcin got deleted from this ticket... that trac bug is annoying!

comment:14 Changed 8 years ago by kcrisman

Code is correct (corner cases discussed in person, so that e.g. (x < y) != x is True.

GEx e seems far from where it comes from.

comment:15 Changed 8 years ago by kini

fixed! (sorry, that was left over from when I was doing something that made cython not like that declaration where it was)

comment:16 Changed 8 years ago by kini

  • Keywords relational sd31 __richcmp__ added

comment:17 Changed 8 years ago by kcrisman

This looks good. Passing relevant tests.

comment:18 Changed 8 years ago by kcrisman

  • Status changed from needs_review to positive_review

comment:19 Changed 8 years ago by jdemeyer

  • Reviewers set to Karl-Dieter Crisman

comment:20 Changed 8 years ago by tnv

It now can tell that -x +y >0 is different than -y + x >= 0 but it says that -x+y >0 is not the same as y > x ---

or may be this is another problem ?

sage: ( -x+y >0 ) == (y > x )
False

sage: (-x + y < 0)  ==  (-x < -y)
False
sage: (x + y == 0)  ==  (x == -y)
False
sage: (x - y == 0)  ==  (x == y)
False
sage: (- x + y == 0)  ==  (0 == -x + y)
False
sage: (x < y)  ==  (y > x)
False
sage: (x == y) == (-x == -y)
False
sage: (x + y < 1 )  ==  (x + y -1 < 0)
False

comment:21 Changed 8 years ago by tnv

  • Status changed from positive_review to needs_work

This patch *breaks* the following

{{ Sage 4.7 (prepatched)

sage: (- x + y == 0) == (0 == -x + y) True sage: (-x + y == 0) == (0 == -x + y) True sage: (x < y) == (y > x) True

Sage 4.7 (postpatched)

sage: (- x + y == 0) == (0 == -x + y) False sage: (-x + y == 0) == (0 == -x + y) False sage: (x < y) == (y > x) False

}}}

comment:22 Changed 8 years ago by kcrisman

Sage 4.7 (prepatched)

sage: (- x + y == 0) == (0 == -x + y) True sage: (-x + y == 0) == (0 == -x + y) True sage: (x < y) == (y > x) True

Sage 4.7 (postpatched)

sage: (- x + y == 0) == (0 == -x + y) False sage: (-x + y == 0) == (0 == -x + y) False sage: (x < y) == (y > x) False

comment:23 Changed 8 years ago by kcrisman

{{ Sage 4.7 (prepatched)

sage: (- x + y == 0) == (0 == -x + y) True sage: (-x + y == 0) == (0 == -x + y) True sage: (x < y) == (y > x) True

Sage 4.7 (postpatched)

sage: (- x + y == 0) == (0 == -x + y) False sage: (-x + y == 0) == (0 == -x + y) False sage: (x < y) == (y > x) False

}}}

comment:24 Changed 8 years ago by kcrisman

Finally used preview...

Sage 4.7 (prepatched)

sage: (- x + y == 0) == (0 == -x + y) 
True 
sage: (-x + y == 0) == (0 == -x + y) 
True 
sage: (x < y) == (y > x) 
True

Sage 4.7 (postpatched)

sage: (- x + y == 0) == (0 == -x + y) 
False 
sage: (-x + y == 0) == (0 == -x + y) 
False 
sage: (x < y) == (y > x) 
False

comment:25 Changed 8 years ago by kcrisman

-x+y >0 is not the same as y > x

Correct. We use the philosophy (used elsewhere) that a comparison is True if you can prove it is True, and that otherwise it is False. False means that we can't prove it's True, and in general these kinds of simplifications are super hard. So all your examples need to be False, sadly.

As for the thing that breaks... I agree that is a problem. Great catch! Can you put your (real) name as a reviewer? (You should also feel free to add yourself to the main Trac page as a developer/contributor.

comment:26 follow-up: Changed 8 years ago by tnv

  • Cc tnv added
  • Reviewers changed from Karl-Dieter Crisman to Karl-Dieter Crisman, ThanhVu Nguyen

just put my name as reviewer -- thanks.

From your msg, would it be reasonable to add a SMT theorem prover package to Sage ? So that it can show equivalence of expressions (at least under some specific theories).

comment:27 Changed 8 years ago by kcrisman

There are some tickets open for things like this, I think, or something related, but I don't really know. Keshav or Burcin may know more.

comment:28 Changed 8 years ago by kini

Hm. In order to eventually solve #2778 and other such things, I think we need to allow nested relations after all. I talked to Burcin on IRC and he agrees. So we would plan to have all of these return an output which is the same as the input. If you wanted to force it to resolve, you could run bool() on them, and you would always get false, except when comparing x < y and y > x, x <= y and y >= x, x == y and y == x, and x != y and y != x, for symbolic expressions x and y (on kcrisman's insistence :) ). I'll need to implement this and figure out how it influences existing doctests (probably severely), so I'm leaving this as "needs_work" for now...

comment:29 Changed 8 years ago by kini

Sorry, I meant #2744, not #2778.

comment:30 in reply to: ↑ 26 ; follow-up: Changed 8 years ago by burcin

Replying to tnv:

From your msg, would it be reasonable to add a SMT theorem prover package to Sage ? So that it can show equivalence of expressions (at least under some specific theories).

Sage is really large as it is. While I'd be really interested to have this capability in Sage, I don't know how many others would want it in the standard distribution. The first step is to start with an optional package/prototype. We can see where it goes from there. :)

Which prover are you thinking of? What would this let us do in Sage? Perhaps you should write a message to sage-devel about this.

comment:31 in reply to: ↑ 30 ; follow-up: Changed 8 years ago by tnv

Which prover are you thinking of? What would this let us do in Sage? Perhaps you should write a message to sage-devel about this.

I am thinking about the optional package too. Someone told me qepcad (not exactly SMT but can be used for many similar purpose) already in Sage as an optional package.

The good thing about these SMT solvers is that most of them support a standard language (smtlib) and therefore you can use any of the SMT's out there with a single interface. SMT can be used to show if something (a set of expressions or constraints) is valid or satisfiable under different types of theories (not just boolean), or simplify a set of expression, etc. I rely on these for implications on my project-- to see if 2 sets of expressions are equi-satisfiable .

So all the above examples of whether if exp1 == exp2 should be easily answered with SMT.

comment:32 in reply to: ↑ 31 Changed 8 years ago by burcin

Replying to tnv:

So all the above examples of whether if exp1 == exp2 should be easily answered with SMT.

I'd really like to see Sage have it's own framework to handle assumptions (see assume? -- this relies completely on maxima right now), so I'm really interested in this. I'd be glad to help with the first steps of making a package, writing an interface, etc. We should have this conversation in sage-devel instead of this ticket though. ;)

comment:33 Changed 7 years ago by kcrisman

This still applies, and fixes another issue.

sage: c = (x-2<=0)
sage: assume(c)
sage: a = (x-1<=0)
sage:  if a in sage.symbolic.assumptions._assumptions:
....:     print 'yes'
....:     
sage: assumptions()
[x - 2 <= 0]
sage: assume(a)
sage: assumptions()
[x - 2 <= 0, x - 1 <= 0]

Before, the second assumption didn't obtain, because currently

sage: c = (x-2<=0)
sage: L = [c]
sage: L
[x - 2 <= 0]
sage: a = (x-1<=0)
sage: a in L
True

which is not good. See this sage-support thread.

comment:34 Changed 7 years ago by kcrisman

Since #2744 is on sage-wishlist, would it suffice to do some sort of "switch lhs and rhs" check as a last branch in the code to fix tnv's point in comment:21 (formatted in comment:24)? It would be nice to finally resolve this at the upcoming Bug Days.

comment:35 Changed 7 years ago by ppurka

In the patch, why is this evaluated to True?

+            sage: (x < y) != (y > x)
+            True

EDIT: Oops. I should have read the earlier comments. Sorry.

Last edited 7 years ago by ppurka (previous) (diff)

comment:36 Changed 7 years ago by kini

kcrisman: OK, I'll try to implement those minimal checks for now, and we can do nesting expressions later.

comment:37 Changed 7 years ago by kini

  • Description modified (diff)
  • Status changed from needs_work to needs_review

Added a new patch. Burcin, can you look over it to make sure I'm doing this the right way? In particular are those operator comparisons optimizable somehow?

comment:38 Changed 7 years ago by kini

Update: added three more lines to the doctests

comment:39 Changed 7 years ago by kini

Hey patchbot:

Apply trac_11309-fix-comparison-of-comparisons.patch trac_11309-equate-flipped-comparisons.patch

comment:40 Changed 7 years ago by kcrisman

The code itself seems fine right now, thanks for such fast action and especially for actual comments in the code!

Did you do any timing runs on previously-working comparisons? I agree that it would be good for someone who knows to comment on whether there is some obvious optimization missing. For instance, lines 1241ff. would be nicer if it so happened there was a "operator.opposite()" function which reversed <= and >= (though someone else might want them to be complements, <= and >). Similarly for the rhs/lhs comparisons.

Keshav, do you mind putting in a test in your patch for

sage: (x-1<0) in [x-2<0]
False

just to test for the comment:33 issue? While we wait for someone more knowledgeable... but as I said it does seem good to go.

Changed 7 years ago by kini

apply to $SAGE_ROOT/devel/sage

comment:41 Changed 7 years ago by kini

Done! Glad you like the comments :)

I did not do any timing, no. I'm not sure what you mean by "lines 1241ff", but function calls should typically be avoided if you're optimizing for speed, afaik. The main thing I was wondering was, the argument op to the function _richcmp_c_impl() is an integer, but operator.* as seen in lines 1245-1252 seem to be strings, if I'm not mistaken. So I'm just wondering if that many string operations for a single comparison of symbolic expression couldn't be better optimized by somehow getting the operator of the lhs and rhs of the big relation as integers rather than strings. Well, not to mention that I'm calling .operator() a bunch of times, but I don't know if it would actually be any faster to compute it once and store it in a variable.

They say you shouldn't try to second-guess compilers... I guess the best way to find out is to try a few different ways and see how timeit behaves. I'll do that later, I guess...

Last edited 7 years ago by kini (previous) (diff)

comment:42 Changed 7 years ago by kini

Hey patchbot:

Apply trac_11309-fix-comparison-of-comparisons.patch trac_11309-equate-flipped-comparisons.patch

comment:43 Changed 7 years ago by kcrisman

  • Keywords sd40.5 added

I guess there isn't any reason to put this off, unless the timing issue really is a biggie. Did you want to run a few of them first?

comment:44 Changed 7 years ago by kcrisman

Hmm, this is a big slowdown in at least one case.

# old
sage: timeit("(x < y) != (y > x)")
625 loops, best of 3: 2.76 µs per loop
# new
sage: timeit("(x < y) != (y > x)")
625 loops, best of 3: 13.3 µs per loop

It looks like it's fairly constantly adding this. Here, in the much slower checking of a list

# old
sage: timeit("(x - 1 < 0) in [x - 2 < 0]")
625 loops, best of 3: 104 µs per loop
# new
sage: timeit("(x - 1 < 0) in [x - 2 < 0]")
625 loops, best of 3: 116 µs per loop

Here's another one.

# old
sage: timeit("(y > y) != (y > y) ")
625 loops, best of 3: 2.24 µs per loop
# new
sage: timeit("(y > y) != (y > y) ")
625 loops, best of 3: 8.45 µs per loop

comment:45 Changed 7 years ago by kini

I'm kind of OK with this slowdown. It's in the low microseconds range, and it's also understandable considering the new code actually checks some stuff, whereas the old code doesn't really.

I guess I will ping Burcin about this via email.

comment:46 follow-up: Changed 7 years ago by kini

Burcin says he's too busy to look carefully but that the code probably can't be optimized much further.

comment:47 Changed 7 years ago by kini

  • Summary changed from Sage sees -x +y > 0, -y + x >= 0, and x -y > 0 as equivalent to Sage sees - x + y > 0, - y + x >= 0, and x - y > 0 as equivalent

comment:48 in reply to: ↑ 46 Changed 7 years ago by kcrisman

  • Status changed from needs_review to positive_review

Burcin says he's too busy to look carefully but that the code probably can't be optimized much further.

Good enough for me.

comment:49 Changed 7 years ago by kini

Thanks!

comment:50 follow-up: Changed 7 years ago by tnv

I am interested in trying this patch but not sure how to apply it correctly. This is what I did on Sage 5.0 (Mac OS Snow Leopard)

$ pwd
/Users/tnguyen/Src/Devel/SAGE/sage-5.0/devel/sage
$ sage -hg qimport http://trac.sagemath.org/sage_trac/raw-attachment/ticket/11309/trac_11309-equate-flipped-comparisons.patch
adding trac_11309-equate-flipped-comparisons.patch to series file
Godel Wed May 30:23:05:42 (4714) ~/Src/Devel/SAGE/sage-5.0/devel/sage 
$ sage -hg qpushapplying trac_11309-equate-flipped-comparisons.patch
patching file sage/symbolic/expression.pyx
Hunk #1 FAILED at 1179
Hunk #2 FAILED at 1186
Hunk #3 FAILED at 1204
3 out of 3 hunks FAILED -- saving rejects to file sage/symbolic/expression.pyx.rej
patch failed, unable to continue (try -v)
patch failed, rejects left in working dir
errors during apply, please fix and refresh trac_11309-equate-flipped-comparisons.patch
Godel Wed May 30:23:05:51 (4715) ~/Src/Devel/SAGE/sage-5.0/devel/sage 

comment:51 in reply to: ↑ 50 Changed 7 years ago by ppurka

Replying to tnv:

I am interested in trying this patch but not sure how to apply it correctly.

You need to apply both the patches in the order mentioned in the description of this ticket. Try these commands (assuming you are in devel/sage)

../../sage -hg qimport -P http://trac.sagemath.org/sage_trac/raw-attachment/ticket/11309/trac_11309-fix-comparison-of-comparisons.patch
../../sage -hg qimport -P http://trac.sagemath.org/sage_trac/raw-attachment/ticket/11309/trac_11309-equate-flipped-comparisons.patch
../../sage -br

comment:52 Changed 7 years ago by kini

Patchbot: Apply trac_11309-fix-comparison-of-comparisons.patch trac_11309-equate-flipped-comparisons.patch

comment:53 follow-up: Changed 7 years ago by tnv

Hi, may be I've missed something but these patches still break things as listed in my comment:24.

(prepatched)

sage: (- x + y == 0) == (0 == -x + y) 
True 
sage: (-x + y == 0) == (0 == -x + y) 
True 
sage: (x < y) == (y > x) 
True

(postpatched)

sage: (- x + y == 0) == (0 == -x + y) 
False 
sage: (-x + y == 0) == (0 == -x + y) 
False 
sage: (x < y) == (y > x) 
False

The main reason why I report this in the first place is because of this error in which multiplying by -1 does not switch the sign. I think they are related but not sure.

sage: -1 * (x<5)
-x < -5

comment:54 Changed 7 years ago by kini

Did you forget to rebuild Sage after applying the patches?

[1] fs-boone@zhenghe /opt/sage/devel/sage $ hg qapplied
trac_13057-no-intersphinx.patch
trac_11309-fix-comparison-of-comparisons.patch
trac_11309-equate-flipped-comparisons.patch
[1] fs-boone@zhenghe /opt/sage/devel/sage $ sage -b &> /dev/null
[1] fs-boone@zhenghe /opt/sage/devel/sage $ sage -q
sage: var('y')
y
sage: (- x + y == 0) == (0 == -x + y) 
True
sage: (-x + y == 0) == (0 == -x + y) 
True
sage: (x < y) == (y > x) 
True
sage: -(x < 5)
-x < -5
sage: 

Personally I don't see why x * (y < z) should even be simplified to anything other than x * (y < z). y < z is a mathematical object which does not live in a space which has a multiplication operation - it lives in the space of logical predicates. But that is something to address in a different ticket. Testing the title of this ticket:

sage: Set([-x + y > 0, -y + x >= 0, x - y > 0])    
{-x + y > 0, x - y >= 0, x - y > 0}
sage: len(_)   
3

So the patches do at least address and solve the issue in the ticket's name.

comment:55 in reply to: ↑ 53 Changed 7 years ago by burcin

Replying to tnv:

The main reason why I report this in the first place is because of this error in which multiplying by -1 does not switch the sign. I think they are related but not sure.

sage: -1 * (x<5)
-x < -5

This is #7660. It would be quite easy to remove the if is_a_relational(left._gobj) checks in _add_, _mul_, etc. in sage/symbolic/expression.pyx` to revert back to GiNaC behavior.

comment:56 Changed 7 years ago by tnv

It seems to work fine now -- not sure what I did previously. So if you don't use hash for comparison , what do you use ? Thanks all of those who spend time to create these patches.

comment:57 Changed 7 years ago by kini

Given two relational expressions a ? b and c ! d, first I check whether ? and ! are the same relation. If so, I have a couple of cases. One, if ? and ! are both == or are both !=, then I check whether a == c and b == d, or a == d and b == c. Two, if ? and ! are some other relation than == or !=, then I only allow the case a == c and b == d.

If ? and ! are different from each other, I check whether they are reversals of each other (like one is < and the other is >, etc.). If that is the case, then I allow a == d and b == c.

In all other cases, the two relational expressions are considered unequal.

... that explanation looks kind of confusing. Maybe it's better if you just look at the patch... it's probably easier to understand :)

Last edited 7 years ago by kini (previous) (diff)

comment:58 Changed 7 years ago by jdemeyer

  • Merged in set to sage-5.1.beta3
  • Resolution set to fixed
  • Status changed from positive_review to closed
Note: See TracTickets for help on using tickets.