Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
_cmp should try _richcmp_ if _cmp_ failed
Browse files Browse the repository at this point in the history
  • Loading branch information
jdemeyer committed May 6, 2015
1 parent 6a3cb27 commit bb98fd0
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 23 deletions.
2 changes: 1 addition & 1 deletion src/sage/structure/element.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ cdef class Element(SageObject):
cpdef _richcmp_(left, Element right, int op)
cpdef int _cmp_(left, Element right) except -2
cdef _richcmp(self, right, int op)
cdef _cmp(self, right)
cdef int _cmp(self, right) except -2
cdef _set_parent_c(self, Parent parent)
cpdef base_extend(self, R)

Expand Down
96 changes: 74 additions & 22 deletions src/sage/structure/element.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -906,30 +906,80 @@ cdef class Element(SageObject):
"""
return not self

cdef _cmp(left, right):
cdef int _cmp(self, other) except -2:
"""
Compare left and right.
Compare ``left`` and ``right`` using the coercion framework.
``self`` and ``other`` are coerced to a common parent and then
``_cmp_`` and ``_richcmp_`` are tried.
EXAMPLES:
We create an ``Element`` class where we define ``__cmp__``
and ``_richcmp_`` and check that comparison works::
sage: cython('''
....: from sage.structure.sage_object cimport rich_to_bool
....: from sage.structure.element cimport Element
....: cdef class FloatCmp(Element):
....: cdef float x
....: def __init__(self, float v):
....: self.x = v
....: def __cmp__(self, other):
....: return (<Element>self)._cmp(other)
....: cpdef _richcmp_(self, Element other, int op):
....: cdef float x1 = (<FloatCmp>self).x
....: cdef float x2 = (<FloatCmp>other).x
....: return rich_to_bool(op, (x1 > x2) - (x1 < x2) )
....: ''')
sage: a = FloatCmp(1)
sage: b = FloatCmp(2)
sage: cmp(a, b)
-1
sage: b.__cmp__(a)
1
sage: a <= b, b <= a
(True, False)
This works despite ``_cmp_`` not being implemented::
sage: a._cmp_(b)
Traceback (most recent call last):
...
NotImplementedError: comparison not implemented for <type '...FloatCmp'>
"""
global coercion_model
cdef int r
if not have_same_parent_c(left, right):
if left is None or left is Ellipsis:
return -1
elif right is None or right is Ellipsis:
return 1
if have_same_parent_c(self, other):
left = self
right = other
else:
try:
_left, _right = coercion_model.canonical_coercion(left, right)
if isinstance(_left, Element):
return (<Element>_left)._cmp_(_right)
return cmp(_left, _right)
left, right = coercion_model.canonical_coercion(self, other)
except TypeError:
r = cmp(type(left), type(right))
if r == 0:
r = -1
return r
# Compare by id()
if (<unsigned long><PyObject*>self) >= (<unsigned long><PyObject*>other):
# It cannot happen that self is other, since they don't
# have the same parent.
return 1
else:
return -1

# Same parents
return left._cmp_(<Element>right)
if not isinstance(left, Element):
assert type(left) is type(right)
return cmp(left, right)

# Now we have two Sage Elements with the same parent
try:
# First attempt: use _cmp_()
return (<Element>left)._cmp_(<Element>right)
except NotImplementedError:
# Second attempt: use _richcmp_()
if (<Element>left)._richcmp_(<Element>right, Py_EQ):
return 0
if (<Element>left)._richcmp_(<Element>right, Py_LT):
return -1
if (<Element>left)._richcmp_(<Element>right, Py_GT):
return 1
raise

cdef _richcmp(self, other, int op):
"""
Expand Down Expand Up @@ -971,13 +1021,14 @@ cdef class Element(SageObject):
# Different parents => coerce
try:
left, right = coercion_model.canonical_coercion(self, other)
except (TypeError, NotImplementedError):
pass
else:
if isinstance(left, Element):
return (<Element>left)._richcmp(<Element>right, op)
# left and right are the same non-Element type:
# use a plain cmp()
return rich_to_bool(op, cmp(left, right))
except (TypeError, NotImplementedError):
pass

# Comparing with coercion didn't work, try something else.

Expand Down Expand Up @@ -3313,7 +3364,8 @@ def coerce(Parent p, x):
return p(x)

def coerce_cmp(x,y):
global coercion_model
from sage.misc.superseded import deprecation
deprecation(18322, 'the global coerce_cmp() function is deprecated')
cdef int c
try:
x, y = coercion_model.canonical_coercion(x, y)
Expand Down

0 comments on commit bb98fd0

Please sign in to comment.