summaryrefslogtreecommitdiffstats
path: root/src/sage/structure/richcmp.pyx
diff options
context:
space:
mode:
Diffstat (limited to 'src/sage/structure/richcmp.pyx')
-rw-r--r--src/sage/structure/richcmp.pyx89
1 files changed, 89 insertions, 0 deletions
diff --git a/src/sage/structure/richcmp.pyx b/src/sage/structure/richcmp.pyx
new file mode 100644
index 00000000..7800ab3
--- /dev/null
+++ b/src/sage/structure/richcmp.pyx
@@ -0,0 +1,89 @@
+r"""
+Cython-like rich comparisons in Python
+
+With "rich comparisons", we mean the Python 3 comparisons which are
+usually implemented in Python using methods like ``__eq__`` and
+``__lt__``. Internally in Python, there is only one rich comparison
+slot ``tp_richcompare``. The actual operator is passed as an integer
+constant (defined in this module as
+``op_LT``, ``op_LE``, ``op_EQ``, ``op_NE``, ``op_GT``, ``op_GE``).
+
+Cython exposes rich comparisons in ``cdef`` classes as the
+``__richcmp__`` special method. The Sage coercion model also supports
+rich comparisons this way: for two instances ``x`` and ``y``
+of :class:`~sage.structure.element.Element`, ``x._richcmp_(y, op)``
+is called when the user does something like ``x <= y``
+(possibly after coercion if ``x`` and ``y`` have different parents).
+
+Various helper functions exist to make it easier to implement rich
+comparison: the most important one is the :func:`richcmp` function.
+This is analogous to the Python 2 function ``cmp()`` but implements
+rich comparison, with the comparison operator (e.g. ``op_GE``) as
+third argument. There is also :func:`richcmp_not_equal` which is like
+:func:`richcmp` but it is optimized assuming that the compared objects
+are not equal.
+
+The functions :func:`rich_to_bool` and :func:`rich_to_bool_sgn` can be
+used to convert results of ``cmp()`` (i.e. -1, 0 or 1) to a boolean
+``True``/``False`` for rich comparisons.
+
+AUTHORS:
+
+- Jeroen Demeyer
+"""
+
+from cpython.object cimport PyObject_RichCompare
+
+op_LT = Py_LT # operator <
+op_LE = Py_LE # operator <=
+op_EQ = Py_EQ # operator ==
+op_NE = Py_NE # operator !=
+op_GT = Py_GT # operator >
+op_GE = Py_GE # operator >=
+
+
+def richcmp(x, y, int op):
+ """
+ Return the result of the rich comparison of ``x`` and ``y`` with
+ operator ``op``.
+
+ INPUT:
+
+ - ``x``, ``y`` -- arbitrary Python objects
+
+ - ``op`` -- comparison operator (one of ``op_LT`, ``op_LE``,
+ ``op_EQ``, ``op_NE``, ``op_GT``, ``op_GE``).
+
+ EXAMPLES::
+
+ sage: from sage.structure.richcmp import *
+ sage: richcmp(3, 4, op_LT)
+ True
+ sage: richcmp(x, x^2, op_EQ)
+ x == x^2
+
+ The two examples above are completely equivalent to ``3 < 4``
+ and ``x == x^2``. For this reason, it only makes sense in practice
+ to call ``richcmp`` with a non-constant value for ``op``.
+
+ We can write a custom ``Element`` class which shows a more
+ realistic example of how to use this::
+
+ sage: from sage.structure.element import Element
+ sage: class MyElement(Element):
+ ....: def __init__(self, parent, value):
+ ....: Element.__init__(self, parent)
+ ....: self.v = value
+ ....: def _richcmp_(self, other, op):
+ ....: return richcmp(self.v, other.v, op)
+ sage: P = Parent()
+ sage: x = MyElement(P, 3)
+ sage: y = MyElement(P, 3)
+ sage: x < y
+ False
+ sage: x == y
+ True
+ sage: x > y
+ False
+ """
+ return PyObject_RichCompare(x, y, op)