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