passagemath-objects 10.6.45__cp313-cp313-musllinux_1_2_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of passagemath-objects might be problematic. Click here for more details.
- passagemath_objects/__init__.py +3 -0
- passagemath_objects-10.6.45.dist-info/METADATA +115 -0
- passagemath_objects-10.6.45.dist-info/RECORD +280 -0
- passagemath_objects-10.6.45.dist-info/WHEEL +5 -0
- passagemath_objects-10.6.45.dist-info/top_level.txt +3 -0
- passagemath_objects.libs/libgmp-0e7fc84e.so.10.5.0 +0 -0
- sage/all__sagemath_objects.py +37 -0
- sage/arith/all__sagemath_objects.py +5 -0
- sage/arith/long.pxd +411 -0
- sage/arith/numerical_approx.cpython-313-x86_64-linux-musl.so +0 -0
- sage/arith/numerical_approx.pxd +35 -0
- sage/arith/numerical_approx.pyx +75 -0
- sage/arith/power.cpython-313-x86_64-linux-musl.so +0 -0
- sage/arith/power.pxd +31 -0
- sage/arith/power.pyx +127 -0
- sage/categories/action.cpython-313-x86_64-linux-musl.so +0 -0
- sage/categories/action.pxd +29 -0
- sage/categories/action.pyx +641 -0
- sage/categories/algebra_functor.py +745 -0
- sage/categories/all__sagemath_objects.py +33 -0
- sage/categories/basic.py +62 -0
- sage/categories/cartesian_product.py +295 -0
- sage/categories/category.py +3401 -0
- sage/categories/category_cy_helper.cpython-313-x86_64-linux-musl.so +0 -0
- sage/categories/category_cy_helper.pxd +8 -0
- sage/categories/category_cy_helper.pyx +322 -0
- sage/categories/category_singleton.cpython-313-x86_64-linux-musl.so +0 -0
- sage/categories/category_singleton.pxd +3 -0
- sage/categories/category_singleton.pyx +342 -0
- sage/categories/category_types.py +637 -0
- sage/categories/category_with_axiom.py +2876 -0
- sage/categories/covariant_functorial_construction.py +703 -0
- sage/categories/facade_sets.py +228 -0
- sage/categories/functor.cpython-313-x86_64-linux-musl.so +0 -0
- sage/categories/functor.pxd +7 -0
- sage/categories/functor.pyx +691 -0
- sage/categories/homset.py +1338 -0
- sage/categories/homsets.py +364 -0
- sage/categories/isomorphic_objects.py +73 -0
- sage/categories/map.cpython-313-x86_64-linux-musl.so +0 -0
- sage/categories/map.pxd +34 -0
- sage/categories/map.pyx +2106 -0
- sage/categories/morphism.cpython-313-x86_64-linux-musl.so +0 -0
- sage/categories/morphism.pxd +14 -0
- sage/categories/morphism.pyx +895 -0
- sage/categories/objects.py +167 -0
- sage/categories/primer.py +1696 -0
- sage/categories/pushout.py +4834 -0
- sage/categories/quotients.py +64 -0
- sage/categories/realizations.py +200 -0
- sage/categories/sets_cat.py +3290 -0
- sage/categories/sets_with_partial_maps.py +52 -0
- sage/categories/subobjects.py +64 -0
- sage/categories/subquotients.py +21 -0
- sage/categories/with_realizations.py +311 -0
- sage/cpython/__init__.py +19 -0
- sage/cpython/_py2_random.py +619 -0
- sage/cpython/all.py +3 -0
- sage/cpython/atexit.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/atexit.pyx +269 -0
- sage/cpython/builtin_types.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/builtin_types.pyx +7 -0
- sage/cpython/cython_metaclass.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/cython_metaclass.h +117 -0
- sage/cpython/cython_metaclass.pxd +3 -0
- sage/cpython/cython_metaclass.pyx +130 -0
- sage/cpython/debug.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/debug.pyx +302 -0
- sage/cpython/dict_del_by_value.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/dict_del_by_value.pxd +9 -0
- sage/cpython/dict_del_by_value.pyx +191 -0
- sage/cpython/dict_internal.h +245 -0
- sage/cpython/getattr.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/getattr.pxd +9 -0
- sage/cpython/getattr.pyx +439 -0
- sage/cpython/pycore_long.h +97 -0
- sage/cpython/pycore_long.pxd +10 -0
- sage/cpython/python_debug.h +44 -0
- sage/cpython/python_debug.pxd +47 -0
- sage/cpython/pyx_visit.h +13 -0
- sage/cpython/string.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/string.pxd +76 -0
- sage/cpython/string.pyx +34 -0
- sage/cpython/string_impl.h +60 -0
- sage/cpython/type.cpython-313-x86_64-linux-musl.so +0 -0
- sage/cpython/type.pxd +2 -0
- sage/cpython/type.pyx +40 -0
- sage/cpython/wrapperdescr.pxd +67 -0
- sage/ext/all__sagemath_objects.py +3 -0
- sage/ext/ccobject.h +64 -0
- sage/ext/cplusplus.pxd +17 -0
- sage/ext/mod_int.h +30 -0
- sage/ext/mod_int.pxd +24 -0
- sage/ext/stdsage.pxd +39 -0
- sage/groups/all__sagemath_objects.py +1 -0
- sage/groups/group.cpython-313-x86_64-linux-musl.so +0 -0
- sage/groups/group.pxd +14 -0
- sage/groups/group.pyx +322 -0
- sage/groups/old.cpython-313-x86_64-linux-musl.so +0 -0
- sage/groups/old.pxd +14 -0
- sage/groups/old.pyx +219 -0
- sage/libs/all__sagemath_objects.py +3 -0
- sage/libs/gmp/__init__.py +1 -0
- sage/libs/gmp/all.pxd +6 -0
- sage/libs/gmp/binop.pxd +23 -0
- sage/libs/gmp/misc.pxd +8 -0
- sage/libs/gmp/mpf.pxd +88 -0
- sage/libs/gmp/mpn.pxd +57 -0
- sage/libs/gmp/mpq.pxd +57 -0
- sage/libs/gmp/mpz.pxd +202 -0
- sage/libs/gmp/pylong.cpython-313-x86_64-linux-musl.so +0 -0
- sage/libs/gmp/pylong.pxd +12 -0
- sage/libs/gmp/pylong.pyx +150 -0
- sage/libs/gmp/random.pxd +25 -0
- sage/libs/gmp/randomize.pxd +59 -0
- sage/libs/gmp/types.pxd +53 -0
- sage/libs/gmpxx.pxd +19 -0
- sage/misc/abstract_method.py +276 -0
- sage/misc/all__sagemath_objects.py +43 -0
- sage/misc/bindable_class.py +253 -0
- sage/misc/c3_controlled.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/c3_controlled.pxd +2 -0
- sage/misc/c3_controlled.pyx +1402 -0
- sage/misc/cachefunc.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/cachefunc.pxd +43 -0
- sage/misc/cachefunc.pyx +3781 -0
- sage/misc/call.py +188 -0
- sage/misc/classcall_metaclass.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/classcall_metaclass.pxd +14 -0
- sage/misc/classcall_metaclass.pyx +599 -0
- sage/misc/constant_function.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/constant_function.pyx +130 -0
- sage/misc/decorators.py +747 -0
- sage/misc/fast_methods.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/fast_methods.pxd +20 -0
- sage/misc/fast_methods.pyx +351 -0
- sage/misc/flatten.py +90 -0
- sage/misc/fpickle.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/fpickle.pyx +177 -0
- sage/misc/function_mangling.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/function_mangling.pxd +11 -0
- sage/misc/function_mangling.pyx +308 -0
- sage/misc/inherit_comparison.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/inherit_comparison.pxd +5 -0
- sage/misc/inherit_comparison.pyx +105 -0
- sage/misc/instancedoc.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/instancedoc.pyx +331 -0
- sage/misc/lazy_attribute.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/lazy_attribute.pyx +607 -0
- sage/misc/lazy_format.py +135 -0
- sage/misc/lazy_import.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/lazy_import.pyx +1299 -0
- sage/misc/lazy_import_cache.py +36 -0
- sage/misc/lazy_list.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/lazy_list.pxd +19 -0
- sage/misc/lazy_list.pyx +1187 -0
- sage/misc/lazy_string.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/lazy_string.pxd +7 -0
- sage/misc/lazy_string.pyx +546 -0
- sage/misc/misc.py +1066 -0
- sage/misc/misc_c.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/misc_c.pxd +3 -0
- sage/misc/misc_c.pyx +766 -0
- sage/misc/namespace_package.py +37 -0
- sage/misc/nested_class.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/nested_class.pxd +3 -0
- sage/misc/nested_class.pyx +394 -0
- sage/misc/persist.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/persist.pyx +1251 -0
- sage/misc/prandom.py +418 -0
- sage/misc/randstate.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/randstate.pxd +30 -0
- sage/misc/randstate.pyx +1059 -0
- sage/misc/repr.py +203 -0
- sage/misc/reset.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/reset.pyx +196 -0
- sage/misc/sage_ostools.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/sage_ostools.pyx +323 -0
- sage/misc/sage_timeit.py +275 -0
- sage/misc/sage_timeit_class.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/sage_timeit_class.pyx +120 -0
- sage/misc/sage_unittest.py +637 -0
- sage/misc/sageinspect.py +2768 -0
- sage/misc/session.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/session.pyx +392 -0
- sage/misc/superseded.py +557 -0
- sage/misc/test_nested_class.py +228 -0
- sage/misc/timing.py +264 -0
- sage/misc/unknown.py +222 -0
- sage/misc/verbose.py +253 -0
- sage/misc/weak_dict.cpython-313-x86_64-linux-musl.so +0 -0
- sage/misc/weak_dict.pxd +15 -0
- sage/misc/weak_dict.pyx +1231 -0
- sage/modules/all__sagemath_objects.py +1 -0
- sage/modules/module.cpython-313-x86_64-linux-musl.so +0 -0
- sage/modules/module.pxd +5 -0
- sage/modules/module.pyx +329 -0
- sage/rings/all__sagemath_objects.py +3 -0
- sage/rings/integer_fake.h +22 -0
- sage/rings/integer_fake.pxd +55 -0
- sage/sets/all__sagemath_objects.py +3 -0
- sage/sets/pythonclass.cpython-313-x86_64-linux-musl.so +0 -0
- sage/sets/pythonclass.pxd +9 -0
- sage/sets/pythonclass.pyx +247 -0
- sage/structure/__init__.py +4 -0
- sage/structure/all.py +30 -0
- sage/structure/category_object.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/category_object.pxd +28 -0
- sage/structure/category_object.pyx +1087 -0
- sage/structure/coerce.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/coerce.pxd +44 -0
- sage/structure/coerce.pyx +2107 -0
- sage/structure/coerce_actions.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/coerce_actions.pxd +27 -0
- sage/structure/coerce_actions.pyx +988 -0
- sage/structure/coerce_dict.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/coerce_dict.pxd +51 -0
- sage/structure/coerce_dict.pyx +1557 -0
- sage/structure/coerce_exceptions.py +23 -0
- sage/structure/coerce_maps.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/coerce_maps.pxd +28 -0
- sage/structure/coerce_maps.pyx +718 -0
- sage/structure/debug_options.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/debug_options.pxd +6 -0
- sage/structure/debug_options.pyx +54 -0
- sage/structure/dynamic_class.py +541 -0
- sage/structure/element.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/element.pxd +272 -0
- sage/structure/element.pyx +4772 -0
- sage/structure/element_wrapper.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/element_wrapper.pxd +12 -0
- sage/structure/element_wrapper.pyx +582 -0
- sage/structure/factorization.py +1422 -0
- sage/structure/factorization_integer.py +105 -0
- sage/structure/factory.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/factory.pyx +786 -0
- sage/structure/formal_sum.py +489 -0
- sage/structure/gens_py.py +73 -0
- sage/structure/global_options.py +1743 -0
- sage/structure/indexed_generators.py +863 -0
- sage/structure/list_clone.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/list_clone.pxd +65 -0
- sage/structure/list_clone.pyx +1867 -0
- sage/structure/list_clone_demo.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/list_clone_demo.pyx +248 -0
- sage/structure/list_clone_timings.py +179 -0
- sage/structure/list_clone_timings_cy.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/list_clone_timings_cy.pyx +86 -0
- sage/structure/mutability.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/mutability.pxd +21 -0
- sage/structure/mutability.pyx +348 -0
- sage/structure/nonexact.py +69 -0
- sage/structure/parent.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/parent.pxd +112 -0
- sage/structure/parent.pyx +3093 -0
- sage/structure/parent_base.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/parent_base.pxd +13 -0
- sage/structure/parent_base.pyx +44 -0
- sage/structure/parent_gens.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/parent_gens.pxd +22 -0
- sage/structure/parent_gens.pyx +377 -0
- sage/structure/parent_old.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/parent_old.pxd +25 -0
- sage/structure/parent_old.pyx +294 -0
- sage/structure/proof/__init__.py +1 -0
- sage/structure/proof/all.py +243 -0
- sage/structure/proof/proof.py +300 -0
- sage/structure/richcmp.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/richcmp.pxd +213 -0
- sage/structure/richcmp.pyx +495 -0
- sage/structure/sage_object.cpython-313-x86_64-linux-musl.so +0 -0
- sage/structure/sage_object.pxd +3 -0
- sage/structure/sage_object.pyx +988 -0
- sage/structure/sage_object_test.py +19 -0
- sage/structure/sequence.py +937 -0
- sage/structure/set_factories.py +1178 -0
- sage/structure/set_factories_example.py +527 -0
- sage/structure/support_view.py +179 -0
- sage/structure/test_factory.py +56 -0
- sage/structure/unique_representation.py +1359 -0
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
# cython: binding=True
|
|
2
|
+
# sage_setup: distribution = sagemath-objects
|
|
3
|
+
r"""
|
|
4
|
+
Cython-like rich comparisons in Python
|
|
5
|
+
|
|
6
|
+
With "rich comparisons", we mean the Python 3 comparisons which are
|
|
7
|
+
usually implemented in Python using methods like ``__eq__`` and
|
|
8
|
+
``__lt__``. Internally in Python, there is only one rich comparison
|
|
9
|
+
slot ``tp_richcompare``. The actual operator is passed as an integer
|
|
10
|
+
constant (defined in this module as
|
|
11
|
+
``op_LT``, ``op_LE``, ``op_EQ``, ``op_NE``, ``op_GT``, ``op_GE``).
|
|
12
|
+
|
|
13
|
+
Cython exposes rich comparisons in ``cdef`` classes as the
|
|
14
|
+
``__richcmp__`` special method. The Sage coercion model also supports
|
|
15
|
+
rich comparisons this way: for two instances ``x`` and ``y``
|
|
16
|
+
of :class:`~sage.structure.element.Element`, ``x._richcmp_(y, op)``
|
|
17
|
+
is called when the user does something like ``x <= y``
|
|
18
|
+
(possibly after coercion if ``x`` and ``y`` have different parents).
|
|
19
|
+
|
|
20
|
+
Various helper functions exist to make it easier to implement rich
|
|
21
|
+
comparison: the most important one is the :func:`richcmp` function.
|
|
22
|
+
This is analogous to the Python 2 function ``cmp()`` but implements
|
|
23
|
+
rich comparison, with the comparison operator (e.g. ``op_GE``) as
|
|
24
|
+
third argument. There is also :func:`richcmp_not_equal` which is like
|
|
25
|
+
:func:`richcmp` but it is optimized assuming that the compared objects
|
|
26
|
+
are not equal.
|
|
27
|
+
|
|
28
|
+
The functions :func:`rich_to_bool` and :func:`rich_to_bool_sgn` can be
|
|
29
|
+
used to convert results of ``cmp()`` (i.e. -1, 0 or 1) to a boolean
|
|
30
|
+
``True``/``False`` for rich comparisons.
|
|
31
|
+
|
|
32
|
+
AUTHORS:
|
|
33
|
+
|
|
34
|
+
- Jeroen Demeyer
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
# ****************************************************************************
|
|
38
|
+
# Copyright (C) 2017-2018 Jeroen Demeyer <J.Demeyer@UGent.be>
|
|
39
|
+
#
|
|
40
|
+
# This program is free software: you can redistribute it and/or modify
|
|
41
|
+
# it under the terms of the GNU General Public License as published by
|
|
42
|
+
# the Free Software Foundation, either version 2 of the License, or
|
|
43
|
+
# (at your option) any later version.
|
|
44
|
+
# https://www.gnu.org/licenses/
|
|
45
|
+
# ****************************************************************************
|
|
46
|
+
|
|
47
|
+
from cpython.object cimport PyTypeObject
|
|
48
|
+
from sage.cpython.wrapperdescr cimport get_slotdef, wrapperbase, PyDescr_NewWrapper
|
|
49
|
+
|
|
50
|
+
cdef extern from *:
|
|
51
|
+
void PyType_Modified(PyTypeObject* cls)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
op_LT = Py_LT # operator <
|
|
55
|
+
op_LE = Py_LE # operator <=
|
|
56
|
+
op_EQ = Py_EQ # operator ==
|
|
57
|
+
op_NE = Py_NE # operator !=
|
|
58
|
+
op_GT = Py_GT # operator >
|
|
59
|
+
op_GE = Py_GE # operator >=
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# Slotdefs for richcmp methods (the "bytes" below is arbitrary,
|
|
63
|
+
# any type which implements these methods would work)
|
|
64
|
+
cdef wrapperbase* richcmp_slotdef[6]
|
|
65
|
+
richcmp_slotdef[Py_EQ] = get_slotdef(bytes.__eq__)
|
|
66
|
+
richcmp_slotdef[Py_NE] = get_slotdef(bytes.__ne__)
|
|
67
|
+
richcmp_slotdef[Py_LT] = get_slotdef(bytes.__lt__)
|
|
68
|
+
richcmp_slotdef[Py_GT] = get_slotdef(bytes.__gt__)
|
|
69
|
+
richcmp_slotdef[Py_LE] = get_slotdef(bytes.__le__)
|
|
70
|
+
richcmp_slotdef[Py_GE] = get_slotdef(bytes.__ge__)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
cpdef richcmp_item(x, y, int op):
|
|
74
|
+
"""
|
|
75
|
+
This function is meant to implement lexicographic rich comparison
|
|
76
|
+
of sequences (lists, vectors, polynomials, ...).
|
|
77
|
+
The inputs ``x`` and ``y`` are corresponding items of such lists
|
|
78
|
+
which should compared.
|
|
79
|
+
|
|
80
|
+
INPUT:
|
|
81
|
+
|
|
82
|
+
- ``x``, ``y`` -- arbitrary Python objects; typically, these are
|
|
83
|
+
``X[i]`` and ``Y[i]`` for sequences ``X`` and ``Y``
|
|
84
|
+
|
|
85
|
+
- ``op`` -- comparison operator (one of ``op_LT``, ``op_LE``,
|
|
86
|
+
``op_EQ``, ``op_NE``, ``op_GT``, ``op_GE``)
|
|
87
|
+
|
|
88
|
+
OUTPUT: assuming that ``x = X[i]`` and ``y = Y[i]``:
|
|
89
|
+
|
|
90
|
+
- if the comparison ``X {op} Y`` (where ``op`` is the given
|
|
91
|
+
operation) could not be decided yet (i.e. we should compare the
|
|
92
|
+
next items in the list): return ``NotImplemented``
|
|
93
|
+
|
|
94
|
+
- otherwise, if the comparison ``X {op} Y`` could be decided:
|
|
95
|
+
return ``x {op} y``, which should then also be the result for
|
|
96
|
+
``X {op} Y``.
|
|
97
|
+
|
|
98
|
+
.. NOTE::
|
|
99
|
+
|
|
100
|
+
Since ``x {op} y`` cannot return ``NotImplemented``, the two
|
|
101
|
+
cases above are mutually exclusive.
|
|
102
|
+
|
|
103
|
+
The semantics of the comparison is different from Python lists or
|
|
104
|
+
tuples in the case that the order is not total. Assume that ``A``
|
|
105
|
+
and ``B`` are lists whose rich comparison is implemented using
|
|
106
|
+
``richcmp_item`` (as in EXAMPLES below). Then
|
|
107
|
+
|
|
108
|
+
- ``A == B`` iff ``A[i] == B[i]`` for all indices `i`.
|
|
109
|
+
|
|
110
|
+
- ``A != B`` iff ``A[i] != B[i]`` for some index `i`.
|
|
111
|
+
|
|
112
|
+
- ``A < B`` iff ``A[i] < B[i]`` for some index `i` and
|
|
113
|
+
for all `j < i`, ``A[j] <= B[j]``.
|
|
114
|
+
|
|
115
|
+
- ``A <= B`` iff ``A < B`` or ``A[i] <= B[i]`` for all `i`.
|
|
116
|
+
|
|
117
|
+
- ``A > B`` iff ``A[i] > B[i]`` for some index `i` and
|
|
118
|
+
for all `j < i`, ``A[j] >= B[j]``.
|
|
119
|
+
|
|
120
|
+
- ``A >= B`` iff ``A > B`` or ``A[i] >= B[i]`` for all `i`.
|
|
121
|
+
|
|
122
|
+
See below for a detailed description of the exact semantics of
|
|
123
|
+
``richcmp_item`` in general.
|
|
124
|
+
|
|
125
|
+
EXAMPLES::
|
|
126
|
+
|
|
127
|
+
sage: from sage.structure.richcmp import *
|
|
128
|
+
sage: @richcmp_method
|
|
129
|
+
....: class Listcmp(list):
|
|
130
|
+
....: def __richcmp__(self, other, op):
|
|
131
|
+
....: for i in range(len(self)): # Assume equal lengths
|
|
132
|
+
....: res = richcmp_item(self[i], other[i], op)
|
|
133
|
+
....: if res is not NotImplemented:
|
|
134
|
+
....: return res
|
|
135
|
+
....: return rich_to_bool(op, 0) # Consider the lists to be equal
|
|
136
|
+
sage: a = Listcmp([0, 1, 3])
|
|
137
|
+
sage: b = Listcmp([0, 2, 1])
|
|
138
|
+
sage: a == a
|
|
139
|
+
True
|
|
140
|
+
sage: a != a
|
|
141
|
+
False
|
|
142
|
+
sage: a < a
|
|
143
|
+
False
|
|
144
|
+
sage: a <= a
|
|
145
|
+
True
|
|
146
|
+
sage: a > a
|
|
147
|
+
False
|
|
148
|
+
sage: a >= a
|
|
149
|
+
True
|
|
150
|
+
sage: a == b, b == a
|
|
151
|
+
(False, False)
|
|
152
|
+
sage: a != b, b != a
|
|
153
|
+
(True, True)
|
|
154
|
+
sage: a < b, b > a
|
|
155
|
+
(True, True)
|
|
156
|
+
sage: a <= b, b >= a
|
|
157
|
+
(True, True)
|
|
158
|
+
sage: a > b, b < a
|
|
159
|
+
(False, False)
|
|
160
|
+
sage: a >= b, b <= a
|
|
161
|
+
(False, False)
|
|
162
|
+
|
|
163
|
+
The above tests used a list of integers, where the result of
|
|
164
|
+
comparisons are the same as for Python lists.
|
|
165
|
+
|
|
166
|
+
If we want to see the difference, we need more general entries in
|
|
167
|
+
the list. The comparison rules are made to be consistent with
|
|
168
|
+
setwise operations. If `A` and `B` are sets, we define ``A {op} B``
|
|
169
|
+
to be true if ``a {op} B`` is true for every `a` in `A` and
|
|
170
|
+
`b` in `B`. Interval comparisons are a special case of this. For
|
|
171
|
+
lists of non-empty(!) sets, we want that ``[A1, A2] {op} [B1, B2]``
|
|
172
|
+
is true if and only if ``[a1, a2] {op} [b1, b2]`` is true for all
|
|
173
|
+
elements. We verify this::
|
|
174
|
+
|
|
175
|
+
sage: @richcmp_method
|
|
176
|
+
....: class Setcmp(tuple):
|
|
177
|
+
....: def __richcmp__(self, other, op):
|
|
178
|
+
....: return all(richcmp(x, y, op) for x in self for y in other)
|
|
179
|
+
sage: sym = {op_EQ: "==", op_NE: "!=", op_LT: "<", op_GT: ">", op_LE: "<=", op_GE: ">="}
|
|
180
|
+
sage: for A1 in Set(range(4)).subsets(): # long time
|
|
181
|
+
....: if not A1: continue
|
|
182
|
+
....: for B1 in Set(range(4)).subsets():
|
|
183
|
+
....: if not B1: continue
|
|
184
|
+
....: for A2 in Set(range(4)).subsets():
|
|
185
|
+
....: if not A2: continue
|
|
186
|
+
....: for B2 in Set(range(3)).subsets():
|
|
187
|
+
....: if not B2: continue
|
|
188
|
+
....: L1 = Listcmp([Setcmp(A1), Setcmp(A2)])
|
|
189
|
+
....: L2 = Listcmp([Setcmp(B1), Setcmp(B2)])
|
|
190
|
+
....: for op in range(6):
|
|
191
|
+
....: reslist = richcmp(L1, L2, op)
|
|
192
|
+
....: reselt = all(richcmp([a1, a2], [b1, b2], op) for a1 in A1 for a2 in A2 for b1 in B1 for b2 in B2)
|
|
193
|
+
....: assert reslist is reselt
|
|
194
|
+
|
|
195
|
+
EXACT SEMANTICS:
|
|
196
|
+
|
|
197
|
+
Above, we only described how ``richcmp_item`` behaves when it is
|
|
198
|
+
used to compare sequences. Here, we specify the exact semantics.
|
|
199
|
+
First of all, recall that the result of ``richcmp_item(x, y, op)``
|
|
200
|
+
is either ``NotImplemented`` or ``x {op} y``.
|
|
201
|
+
|
|
202
|
+
- if ``op`` is ``==``: return ``NotImplemented`` if ``x == y``.
|
|
203
|
+
If ``x == y`` is false, then return ``x == y``.
|
|
204
|
+
|
|
205
|
+
- if ``op`` is ``!=``: return ``NotImplemented`` if not ``x != y``.
|
|
206
|
+
If ``x != y`` is true, then return ``x != y``.
|
|
207
|
+
|
|
208
|
+
- if ``op`` is ``<``: return ``NotImplemented`` if ``x == y``.
|
|
209
|
+
If ``x < y`` or not ``x <= y``, return ``x < y``.
|
|
210
|
+
Otherwise (if both ``x == y`` and ``x < y`` are false but
|
|
211
|
+
``x <= y`` is true), return ``NotImplemented``.
|
|
212
|
+
|
|
213
|
+
- if ``op`` is ``<=``: return ``NotImplemented`` if ``x == y``.
|
|
214
|
+
If ``x < y`` or not ``x <= y``, return ``x <= y``.
|
|
215
|
+
Otherwise (if both ``x == y`` and ``x < y`` are false but
|
|
216
|
+
``x <= y`` is true), return ``NotImplemented``.
|
|
217
|
+
|
|
218
|
+
- the ``>`` and ``>=`` operators are analogous to ``<`` and ``<=``.
|
|
219
|
+
"""
|
|
220
|
+
if op == Py_NE:
|
|
221
|
+
res = (x != y)
|
|
222
|
+
if not res:
|
|
223
|
+
return NotImplemented
|
|
224
|
+
return res # (x != y) --> True
|
|
225
|
+
|
|
226
|
+
# If x and y are equal, we cannot decide
|
|
227
|
+
res = (x == y)
|
|
228
|
+
if res:
|
|
229
|
+
return NotImplemented
|
|
230
|
+
|
|
231
|
+
if op == Py_EQ:
|
|
232
|
+
return res # not (x == y) --> False
|
|
233
|
+
|
|
234
|
+
# At this point, {op} is < or <= or > or >=. In the comments below,
|
|
235
|
+
# we always refer to < and <= but > and >= are obviously analogous.
|
|
236
|
+
|
|
237
|
+
# Compute x {op} y and convert to boolean (0 or 1)
|
|
238
|
+
res = PyObject_RichCompare(x, y, op)
|
|
239
|
+
cdef bint bres = res
|
|
240
|
+
|
|
241
|
+
# true (1) for <= and >= and false (0) for < and >
|
|
242
|
+
cdef bint op_is_not_strict = op & 1
|
|
243
|
+
|
|
244
|
+
if bres != op_is_not_strict:
|
|
245
|
+
# If we are asked to compute (x < y) and (x < y) is true,
|
|
246
|
+
# return (x < y) which is true.
|
|
247
|
+
# If we are asked to compute (x <= y) and (x <= y) is false,
|
|
248
|
+
# return (x <= y) which is false.
|
|
249
|
+
return res
|
|
250
|
+
|
|
251
|
+
# Finally, check the inequality with the other strictness
|
|
252
|
+
# (< becomes <= and vice versa; this corresponds to replacing op by
|
|
253
|
+
# op ^ 1). This check is redundant in the typical case that (x <= y)
|
|
254
|
+
# is equivalent to (x < y or x == y): since (x == y) returned false,
|
|
255
|
+
# we expect that this PyObject_RichCompare() call returns the same
|
|
256
|
+
# boolean result as the previous one.
|
|
257
|
+
cdef bint xres = PyObject_RichCompare(x, y, op ^ 1)
|
|
258
|
+
if xres == bres: # As expected
|
|
259
|
+
return res
|
|
260
|
+
|
|
261
|
+
# OK, we are in a special case now. We checked that (x == y) is
|
|
262
|
+
# false, that (x < y) is false but (x <= y) is true.
|
|
263
|
+
# Since we want to give more importance to the < and <= results than
|
|
264
|
+
# the == result, we treat this case as equality. Therefore, we
|
|
265
|
+
# cannot decide.
|
|
266
|
+
return NotImplemented
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
cdef slot_tp_richcompare(self, other, int op):
|
|
270
|
+
"""
|
|
271
|
+
Function to put in the ``tp_richcompare`` slot.
|
|
272
|
+
"""
|
|
273
|
+
return self.__richcmp__(other, op)
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
def richcmp_method(cls):
|
|
277
|
+
"""
|
|
278
|
+
Class decorator to implement rich comparison using the special
|
|
279
|
+
method ``__richcmp__`` (analogous to Cython) instead of the 6
|
|
280
|
+
methods ``__eq__`` and friends.
|
|
281
|
+
|
|
282
|
+
This changes the class in-place and returns the given class.
|
|
283
|
+
|
|
284
|
+
EXAMPLES::
|
|
285
|
+
|
|
286
|
+
sage: from sage.structure.richcmp import *
|
|
287
|
+
sage: sym = {op_EQ: "==", op_NE: "!=", op_LT: "<", op_GT: ">", op_LE: "<=", op_GE: ">="}
|
|
288
|
+
sage: @richcmp_method
|
|
289
|
+
....: class A(str):
|
|
290
|
+
....: def __richcmp__(self, other, op):
|
|
291
|
+
....: print("%s %s %s" % (self, sym[op], other))
|
|
292
|
+
sage: A("left") < A("right")
|
|
293
|
+
left < right
|
|
294
|
+
sage: object() <= A("right")
|
|
295
|
+
right >= <object object at ...>
|
|
296
|
+
|
|
297
|
+
We can call this comparison with the usual Python special methods::
|
|
298
|
+
|
|
299
|
+
sage: x = A("left"); y = A("right")
|
|
300
|
+
sage: x.__eq__(y)
|
|
301
|
+
left == right
|
|
302
|
+
sage: A.__eq__(x, y)
|
|
303
|
+
left == right
|
|
304
|
+
|
|
305
|
+
Everything still works in subclasses::
|
|
306
|
+
|
|
307
|
+
sage: class B(A):
|
|
308
|
+
....: pass
|
|
309
|
+
sage: x = B("left"); y = B("right")
|
|
310
|
+
sage: x != y
|
|
311
|
+
left != right
|
|
312
|
+
sage: x.__ne__(y)
|
|
313
|
+
left != right
|
|
314
|
+
sage: B.__ne__(x, y)
|
|
315
|
+
left != right
|
|
316
|
+
|
|
317
|
+
We can override ``__richcmp__`` with standard Python rich
|
|
318
|
+
comparison methods and conversely::
|
|
319
|
+
|
|
320
|
+
sage: class C(A):
|
|
321
|
+
....: def __ne__(self, other):
|
|
322
|
+
....: return False
|
|
323
|
+
sage: C("left") != C("right")
|
|
324
|
+
False
|
|
325
|
+
sage: C("left") == C("right") # Calls __eq__ from class A
|
|
326
|
+
left == right
|
|
327
|
+
|
|
328
|
+
sage: class Base():
|
|
329
|
+
....: def __eq__(self, other):
|
|
330
|
+
....: return False
|
|
331
|
+
sage: @richcmp_method
|
|
332
|
+
....: class Derived(Base):
|
|
333
|
+
....: def __richcmp__(self, other, op):
|
|
334
|
+
....: return True
|
|
335
|
+
sage: Derived() == Derived()
|
|
336
|
+
True
|
|
337
|
+
|
|
338
|
+
TESTS::
|
|
339
|
+
|
|
340
|
+
sage: richcmp_method(None)
|
|
341
|
+
Traceback (most recent call last):
|
|
342
|
+
...
|
|
343
|
+
TypeError: None is not a class
|
|
344
|
+
|
|
345
|
+
sage: @richcmp_method
|
|
346
|
+
....: class X():
|
|
347
|
+
....: def __eq__(self, other):
|
|
348
|
+
....: pass
|
|
349
|
+
....: def __richcmp__(self, other, op):
|
|
350
|
+
....: pass
|
|
351
|
+
Traceback (most recent call last):
|
|
352
|
+
...
|
|
353
|
+
TypeError: class <class '__main__.X'> defines __eq__ which cannot be combined with @richcmp_method
|
|
354
|
+
"""
|
|
355
|
+
if not isinstance(cls, type):
|
|
356
|
+
raise TypeError(f"{cls!r} is not a class")
|
|
357
|
+
cdef PyTypeObject* tp = <PyTypeObject*>cls
|
|
358
|
+
tp.tp_richcompare = slot_tp_richcompare
|
|
359
|
+
|
|
360
|
+
# Install slot wrappers in the class dict
|
|
361
|
+
cdef dict D = <dict>(tp.tp_dict)
|
|
362
|
+
cdef wrapperbase* slotdef
|
|
363
|
+
for slotdef in richcmp_slotdef:
|
|
364
|
+
name = <object>slotdef.name_strobj
|
|
365
|
+
if name in D:
|
|
366
|
+
raise TypeError("class %r defines %s which cannot be combined with @richcmp_method" % (cls, name))
|
|
367
|
+
D[name] = PyDescr_NewWrapper(tp, slotdef, <void*>slot_tp_richcompare)
|
|
368
|
+
|
|
369
|
+
PyType_Modified(tp)
|
|
370
|
+
|
|
371
|
+
return cls
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def richcmp_by_eq_and_lt(eq_attr, lt_attr):
|
|
375
|
+
r"""
|
|
376
|
+
Create a rich comparison method for a partial order, where the
|
|
377
|
+
order is specified by methods called ``eq_attr`` and ``lt_attr``.
|
|
378
|
+
|
|
379
|
+
INPUT when creating the method:
|
|
380
|
+
|
|
381
|
+
- ``eq_attr`` -- attribute name for equality comparison
|
|
382
|
+
|
|
383
|
+
- ``lt_attr`` -- attribute name for less-than comparison
|
|
384
|
+
|
|
385
|
+
INPUT when calling the method:
|
|
386
|
+
|
|
387
|
+
- ``self`` -- objects having methods ``eq_attr`` and ``lt_attr``
|
|
388
|
+
|
|
389
|
+
- ``other`` -- arbitrary object. If it does have ``eq_attr`` and
|
|
390
|
+
``lt_attr`` methods, these are used for the comparison. Otherwise,
|
|
391
|
+
the comparison is undefined.
|
|
392
|
+
|
|
393
|
+
- ``op`` -- a rich comparison operation (e.g. ``op_EQ``)
|
|
394
|
+
|
|
395
|
+
.. NOTE::
|
|
396
|
+
|
|
397
|
+
For efficiency, identical objects (when ``self is other``)
|
|
398
|
+
always compare equal.
|
|
399
|
+
|
|
400
|
+
.. NOTE::
|
|
401
|
+
|
|
402
|
+
The order is partial, so ``x <= y`` is implemented as
|
|
403
|
+
``x == y or x < y``. It is not required that this is the
|
|
404
|
+
negation of ``y < x``.
|
|
405
|
+
|
|
406
|
+
.. NOTE::
|
|
407
|
+
|
|
408
|
+
This function is intended to be used as a method ``_richcmp_``
|
|
409
|
+
in a class derived from :class:`sage.structure.element.Element`
|
|
410
|
+
or a method ``__richcmp__`` in a class using
|
|
411
|
+
:func:`richcmp_method`.
|
|
412
|
+
|
|
413
|
+
EXAMPLES::
|
|
414
|
+
|
|
415
|
+
sage: from sage.structure.richcmp import richcmp_by_eq_and_lt
|
|
416
|
+
sage: from sage.structure.element import Element
|
|
417
|
+
|
|
418
|
+
sage: class C(Element):
|
|
419
|
+
....: def __init__(self, a, b):
|
|
420
|
+
....: super().__init__(ZZ)
|
|
421
|
+
....: self.a = a
|
|
422
|
+
....: self.b = b
|
|
423
|
+
....: _richcmp_ = richcmp_by_eq_and_lt("eq", "lt")
|
|
424
|
+
....: def eq(self, other):
|
|
425
|
+
....: return self.a == other.a and self.b == other.b
|
|
426
|
+
....: def lt(self, other):
|
|
427
|
+
....: return self.a < other.a and self.b < other.b
|
|
428
|
+
|
|
429
|
+
sage: x = C(1,2); y = C(2,1); z = C(3,3)
|
|
430
|
+
|
|
431
|
+
sage: x == x, x <= x, x == C(1,2), x <= C(1,2) # indirect doctest
|
|
432
|
+
(True, True, True, True)
|
|
433
|
+
sage: y == z, y != z
|
|
434
|
+
(False, True)
|
|
435
|
+
|
|
436
|
+
sage: x < y, y < x, x > y, y > x, x <= y, y <= x, x >= y, y >= x
|
|
437
|
+
(False, False, False, False, False, False, False, False)
|
|
438
|
+
sage: y < z, z < y, y > z, z > y, y <= z, z <= y, y >= z, z >= y
|
|
439
|
+
(True, False, False, True, True, False, False, True)
|
|
440
|
+
sage: z < x, x < z, z > x, x > z, z <= x, x <= z, z >= x, x >= z
|
|
441
|
+
(False, True, True, False, False, True, True, False)
|
|
442
|
+
|
|
443
|
+
A simple example using ``richcmp_method``::
|
|
444
|
+
|
|
445
|
+
sage: from sage.structure.richcmp import richcmp_method, richcmp_by_eq_and_lt
|
|
446
|
+
sage: @richcmp_method
|
|
447
|
+
....: class C():
|
|
448
|
+
....: __richcmp__ = richcmp_by_eq_and_lt("_eq", "_lt")
|
|
449
|
+
....: def _eq(self, other):
|
|
450
|
+
....: return True
|
|
451
|
+
....: def _lt(self, other):
|
|
452
|
+
....: return True
|
|
453
|
+
sage: a = C(); b = C()
|
|
454
|
+
sage: a == b
|
|
455
|
+
True
|
|
456
|
+
sage: a > b # Calls b._lt(a)
|
|
457
|
+
True
|
|
458
|
+
sage: class X(): pass
|
|
459
|
+
sage: x = X()
|
|
460
|
+
sage: a == x # Does not call a._eq(x) because x does not have _eq
|
|
461
|
+
False
|
|
462
|
+
"""
|
|
463
|
+
def richcmp(self, other, int op):
|
|
464
|
+
if self is other:
|
|
465
|
+
return rich_to_bool(op, 0)
|
|
466
|
+
|
|
467
|
+
cdef bint equal_types = (type(self) is type(other))
|
|
468
|
+
# Check whether "other" is of the right type
|
|
469
|
+
if not equal_types:
|
|
470
|
+
try:
|
|
471
|
+
other_eq = getattr(other, eq_attr)
|
|
472
|
+
other_lt = getattr(other, lt_attr)
|
|
473
|
+
except AttributeError:
|
|
474
|
+
return NotImplemented
|
|
475
|
+
|
|
476
|
+
# Check equality first if needed
|
|
477
|
+
if op != Py_LT and op != Py_GT:
|
|
478
|
+
if equal_types:
|
|
479
|
+
other_eq = getattr(other, eq_attr)
|
|
480
|
+
if other_eq(self):
|
|
481
|
+
return rich_to_bool(op, 0)
|
|
482
|
+
if op == Py_EQ:
|
|
483
|
+
return False
|
|
484
|
+
if op == Py_NE:
|
|
485
|
+
return True
|
|
486
|
+
|
|
487
|
+
if op == Py_LT or op == Py_LE:
|
|
488
|
+
self_lt = getattr(self, lt_attr)
|
|
489
|
+
return self_lt(other)
|
|
490
|
+
else:
|
|
491
|
+
if equal_types:
|
|
492
|
+
other_lt = getattr(other, lt_attr)
|
|
493
|
+
return other_lt(self)
|
|
494
|
+
|
|
495
|
+
return richcmp
|
|
Binary file
|