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,3379 @@
1
+ # sage_setup: distribution = sagemath-objects
2
+ r"""
3
+ Categories
4
+
5
+ AUTHORS:
6
+
7
+ - David Kohel, William Stein and Nicolas M. Thiery
8
+
9
+ Every Sage object lies in a category. Categories in Sage are
10
+ modeled on the mathematical idea of category, and are distinct from
11
+ Python classes, which are a programming construct.
12
+
13
+ In most cases, typing ``x.category()`` returns the category to which ``x``
14
+ belongs. If ``C`` is a category and ``x`` is any object, ``C(x)`` tries to
15
+ make an object in ``C`` from ``x``. Checking if ``x`` belongs to ``C`` is done
16
+ as usually by ``x in C``.
17
+
18
+ See :class:`Category` and :mod:`sage.categories.primer` for more details.
19
+
20
+ EXAMPLES:
21
+
22
+ We create a couple of categories::
23
+
24
+ sage: Sets()
25
+ Category of sets
26
+ sage: GSets(AbelianGroup([2, 4, 9])) # needs sage.groups sage.modules
27
+ Category of G-sets for Multiplicative Abelian group isomorphic to C2 x C4 x C9
28
+ sage: Semigroups()
29
+ Category of semigroups
30
+ sage: VectorSpaces(FiniteField(11))
31
+ Category of vector spaces over Finite Field of size 11
32
+ sage: Ideals(IntegerRing())
33
+ Category of ring ideals in Integer Ring
34
+
35
+ Let's request the category of some objects::
36
+
37
+ sage: V = VectorSpace(RationalField(), 3) # needs sage.modules
38
+ sage: V.category() # needs sage.modules
39
+ Category of finite dimensional vector spaces with basis
40
+ over (number fields and quotient fields and metric spaces)
41
+
42
+ sage: G = SymmetricGroup(9) # needs sage.groups
43
+ sage: G.category() # needs sage.groups
44
+ Join of
45
+ Category of finite enumerated permutation groups and
46
+ Category of finite Weyl groups and
47
+ Category of well generated finite irreducible complex reflection groups
48
+
49
+ sage: P = PerfectMatchings(3) # needs sage.combinat
50
+ sage: P.category() # needs sage.combinat
51
+ Category of finite enumerated sets
52
+
53
+ Let's check some memberships::
54
+
55
+ sage: V in VectorSpaces(QQ) # needs sage.modules
56
+ True
57
+ sage: V in VectorSpaces(FiniteField(11)) # needs sage.modules
58
+ False
59
+ sage: G in Monoids() # needs sage.groups
60
+ True
61
+ sage: P in Rings() # needs sage.combinat
62
+ False
63
+
64
+ For parametrized categories one can use the following shorthand::
65
+
66
+ sage: V in VectorSpaces # needs sage.modules
67
+ True
68
+ sage: G in VectorSpaces # needs sage.groups
69
+ False
70
+
71
+ A parent ``P`` is in a category ``C`` if ``P.category()`` is a subcategory of
72
+ ``C``.
73
+
74
+ .. NOTE::
75
+
76
+ Any object of a category should be an instance of
77
+ :class:`~sage.structure.category_object.CategoryObject`.
78
+
79
+ For backward compatibility this is not yet enforced::
80
+
81
+ sage: class A:
82
+ ....: def category(self):
83
+ ....: return Fields()
84
+ sage: A() in Rings()
85
+ True
86
+
87
+ By default, the category of an element `x` of a parent `P` is the category
88
+ of all objects of `P` (this is dubious and may be deprecated)::
89
+
90
+ sage: V = VectorSpace(RationalField(), 3) # needs sage.modules
91
+ sage: v = V.gen(1) # needs sage.modules
92
+ sage: v.category() # needs sage.modules
93
+ Category of elements of Vector space of dimension 3 over Rational Field
94
+ """
95
+
96
+ # ****************************************************************************
97
+ # Copyright (C) 2005 David Kohel <kohel@maths.usyd.edu> and
98
+ # William Stein <wstein@math.ucsd.edu>
99
+ # 2008-2014 Nicolas M. Thiery <nthiery at users.sf.net>
100
+ #
101
+ # Distributed under the terms of the GNU General Public License (GPL)
102
+ # https://www.gnu.org/licenses/
103
+ # ****************************************************************************
104
+
105
+ import inspect
106
+ from typing import Self
107
+ from warnings import warn
108
+
109
+ from sage.categories.category_cy_helper import (
110
+ _flatten_categories,
111
+ _sort_uniq,
112
+ category_sort_key,
113
+ join_as_tuple,
114
+ )
115
+ from sage.misc.abstract_method import abstract_method, abstract_methods_of_class
116
+ from sage.misc.c3_controlled import C3_sorted_merge, _cmp_key, _cmp_key_named
117
+ from sage.misc.cachefunc import cached_function, cached_method
118
+ from sage.misc.lazy_attribute import lazy_attribute
119
+ from sage.misc.unknown import Unknown
120
+ from sage.misc.weak_dict import WeakValueDictionary
121
+ from sage.structure.dynamic_class import DynamicMetaclass, dynamic_class
122
+ from sage.structure.sage_object import SageObject
123
+ from sage.structure.unique_representation import UniqueRepresentation
124
+
125
+ _join_cache = WeakValueDictionary()
126
+
127
+
128
+ HALL_OF_FAME = ['Coxeter', 'Hopf', 'Weyl', 'Lie',
129
+ 'Hecke', 'Dedekind', 'Stone']
130
+
131
+
132
+ class Category(UniqueRepresentation, SageObject):
133
+ r"""
134
+ The base class for modeling mathematical categories, like for example:
135
+
136
+ - ``Groups()`` -- the category of groups
137
+ - ``EuclideanDomains()`` -- the category of euclidean rings
138
+ - ``VectorSpaces(QQ)`` -- the category of vector spaces over the field of
139
+ rationals
140
+
141
+ See :mod:`sage.categories.primer` for an introduction to
142
+ categories in Sage, their relevance, purpose, and usage. The
143
+ documentation below will focus on their implementation.
144
+
145
+ Technically, a category is an instance of the class
146
+ :class:`Category` or some of its subclasses. Some categories, like
147
+ :class:`VectorSpaces`, are parametrized: ``VectorSpaces(QQ)`` is one of
148
+ many instances of the class :class:`VectorSpaces`. On the other
149
+ hand, ``EuclideanDomains()`` is the single instance of the class
150
+ :class:`EuclideanDomains`.
151
+
152
+ Recall that an algebraic structure (say, the ring `\QQ[x]`) is
153
+ modelled in Sage by an object which is called a parent. This
154
+ object belongs to certain categories (here ``EuclideanDomains()`` and
155
+ ``Algebras()``). The elements of the ring are themselves objects.
156
+
157
+ The class of a category (say :class:`EuclideanDomains`) can define simultaneously:
158
+
159
+ - Operations on the category itself (what is its super categories?
160
+ its category of morphisms? its dual category?).
161
+ - Generic operations on parents in this category, like the ring `\QQ[x]`.
162
+ - Generic operations on elements of such parents (e. g., the
163
+ Euclidean algorithm for computing gcds).
164
+ - Generic operations on morphisms of this category.
165
+
166
+ This is achieved as follows::
167
+
168
+ sage: from sage.categories.category import Category
169
+ sage: class EuclideanDomains(Category):
170
+ ....: # operations on the category itself
171
+ ....: def super_categories(self):
172
+ ....: [Rings()]
173
+ ....:
174
+ ....: def dummy(self): # TODO: find some good examples
175
+ ....: pass
176
+ ....:
177
+ ....: class ParentMethods: # holds the generic operations on parents
178
+ ....: # TODO: find a good example of an operation
179
+ ....: pass
180
+ ....:
181
+ ....: class ElementMethods:# holds the generic operations on elements
182
+ ....: def gcd(x, y):
183
+ ....: # Euclid algorithms
184
+ ....: pass
185
+ ....:
186
+ ....: class MorphismMethods: # holds the generic operations on morphisms
187
+ ....: # TODO: find a good example of an operation
188
+ ....: pass
189
+ ....:
190
+
191
+ Note that the nested class ``ParentMethods`` is merely a container
192
+ of operations, and does not inherit from anything. Instead, the
193
+ hierarchy relation is defined once at the level of the categories,
194
+ and the actual hierarchy of classes is built in parallel from all
195
+ the ``ParentMethods`` nested classes, and stored in the attributes
196
+ ``parent_class``. Then, a parent in a category ``C`` receives the
197
+ appropriate operations from all the super categories by usual
198
+ class inheritance from ``C.parent_class``.
199
+
200
+ Similarly, two other hierarchies of classes, for elements and
201
+ morphisms respectively, are built from all the ``ElementMethods``
202
+ and ``MorphismMethods`` nested classes.
203
+
204
+ EXAMPLES:
205
+
206
+ We define a hierarchy of four categories ``As()``, ``Bs()``,
207
+ ``Cs()``, ``Ds()`` with a diamond inheritance. Think for example:
208
+
209
+ - ``As()`` -- the category of sets
210
+ - ``Bs()`` -- the category of additive groups
211
+ - ``Cs()`` -- the category of multiplicative monoids
212
+ - ``Ds()`` -- the category of rings
213
+
214
+ ::
215
+
216
+ sage: from sage.categories.category import Category
217
+ sage: from sage.misc.lazy_attribute import lazy_attribute
218
+ sage: class As (Category):
219
+ ....: def super_categories(self):
220
+ ....: return []
221
+ ....:
222
+ ....: class ParentMethods:
223
+ ....: def fA(self):
224
+ ....: return "A"
225
+ ....: f = fA
226
+
227
+ sage: class Bs (Category):
228
+ ....: def super_categories(self):
229
+ ....: return [As()]
230
+ ....:
231
+ ....: class ParentMethods:
232
+ ....: def fB(self):
233
+ ....: return "B"
234
+
235
+ sage: class Cs (Category):
236
+ ....: def super_categories(self):
237
+ ....: return [As()]
238
+ ....:
239
+ ....: class ParentMethods:
240
+ ....: def fC(self):
241
+ ....: return "C"
242
+ ....: f = fC
243
+
244
+ sage: class Ds (Category):
245
+ ....: def super_categories(self):
246
+ ....: return [Bs(),Cs()]
247
+ ....:
248
+ ....: class ParentMethods:
249
+ ....: def fD(self):
250
+ ....: return "D"
251
+
252
+ Categories should always have unique representation; by :issue:`12215`,
253
+ this means that it will be kept in cache, but only
254
+ if there is still some strong reference to it.
255
+
256
+ We check this before proceeding::
257
+
258
+ sage: import gc
259
+ sage: idAs = id(As())
260
+ sage: _ = gc.collect()
261
+ sage: n == id(As())
262
+ False
263
+ sage: a = As()
264
+ sage: id(As()) == id(As())
265
+ True
266
+ sage: As().parent_class == As().parent_class
267
+ True
268
+
269
+ We construct a parent in the category ``Ds()`` (that, is an instance
270
+ of ``Ds().parent_class``), and check that it has access to all the
271
+ methods provided by all the categories, with the appropriate
272
+ inheritance order::
273
+
274
+ sage: D = Ds().parent_class()
275
+ sage: [ D.fA(), D.fB(), D.fC(), D.fD() ]
276
+ ['A', 'B', 'C', 'D']
277
+ sage: D.f()
278
+ 'C'
279
+
280
+ ::
281
+
282
+ sage: C = Cs().parent_class()
283
+ sage: [ C.fA(), C.fC() ]
284
+ ['A', 'C']
285
+ sage: C.f()
286
+ 'C'
287
+
288
+ Here is the parallel hierarchy of classes which has been built
289
+ automatically, together with the method resolution order (``.mro()``)::
290
+
291
+ sage: As().parent_class
292
+ <class '__main__.As.parent_class'>
293
+ sage: As().parent_class.__bases__
294
+ (<... 'object'>,)
295
+ sage: As().parent_class.mro()
296
+ [<class '__main__.As.parent_class'>, <... 'object'>]
297
+
298
+ ::
299
+
300
+ sage: Bs().parent_class
301
+ <class '__main__.Bs.parent_class'>
302
+ sage: Bs().parent_class.__bases__
303
+ (<class '__main__.As.parent_class'>,)
304
+ sage: Bs().parent_class.mro()
305
+ [<class '__main__.Bs.parent_class'>, <class '__main__.As.parent_class'>, <... 'object'>]
306
+
307
+ ::
308
+
309
+ sage: Cs().parent_class
310
+ <class '__main__.Cs.parent_class'>
311
+ sage: Cs().parent_class.__bases__
312
+ (<class '__main__.As.parent_class'>,)
313
+ sage: Cs().parent_class.__mro__
314
+ (<class '__main__.Cs.parent_class'>, <class '__main__.As.parent_class'>, <... 'object'>)
315
+
316
+ ::
317
+
318
+ sage: Ds().parent_class
319
+ <class '__main__.Ds.parent_class'>
320
+ sage: Ds().parent_class.__bases__
321
+ (<class '__main__.Cs.parent_class'>, <class '__main__.Bs.parent_class'>)
322
+ sage: Ds().parent_class.mro()
323
+ [<class '__main__.Ds.parent_class'>, <class '__main__.Cs.parent_class'>,
324
+ <class '__main__.Bs.parent_class'>, <class '__main__.As.parent_class'>, <... 'object'>]
325
+
326
+ Note that two categories in the same class need not have the
327
+ same ``super_categories``. For example, ``Algebras(QQ)`` has
328
+ ``VectorSpaces(QQ)`` as super category, whereas ``Algebras(ZZ)``
329
+ only has ``Modules(ZZ)`` as super category. In particular, the
330
+ constructed parent class and element class will differ (inheriting,
331
+ or not, methods specific for vector spaces)::
332
+
333
+ sage: Algebras(QQ).parent_class is Algebras(ZZ).parent_class
334
+ False
335
+ sage: issubclass(Algebras(QQ).parent_class, VectorSpaces(QQ).parent_class)
336
+ True
337
+
338
+ On the other hand, identical hierarchies of classes are,
339
+ preferably, built only once (e.g. for categories over a base ring)::
340
+
341
+ sage: Algebras(GF(5)).parent_class is Algebras(GF(7)).parent_class
342
+ True
343
+ sage: F = FractionField(ZZ['t'])
344
+ sage: Coalgebras(F).parent_class is Coalgebras(FractionField(F['x'])).parent_class
345
+ True
346
+
347
+ We now construct a parent in the usual way::
348
+
349
+ sage: class myparent(Parent):
350
+ ....: def __init__(self):
351
+ ....: Parent.__init__(self, category=Ds())
352
+ ....: def g(self):
353
+ ....: return "myparent"
354
+ ....: class Element():
355
+ ....: pass
356
+ sage: D = myparent()
357
+ sage: D.__class__
358
+ <class '__main__.myparent_with_category'>
359
+ sage: D.__class__.__bases__
360
+ (<class '__main__.myparent'>, <class '__main__.Ds.parent_class'>)
361
+ sage: D.__class__.mro()
362
+ [<class '__main__.myparent_with_category'>,
363
+ <class '__main__.myparent'>,
364
+ <class 'sage.structure.parent.Parent'>,
365
+ <class 'sage.structure.category_object.CategoryObject'>,
366
+ <class 'sage.structure.sage_object.SageObject'>,
367
+ <class '__main__.Ds.parent_class'>,
368
+ <class '__main__.Cs.parent_class'>,
369
+ <class '__main__.Bs.parent_class'>,
370
+ <class '__main__.As.parent_class'>,
371
+ <... 'object'>]
372
+ sage: D.fA()
373
+ 'A'
374
+ sage: D.fB()
375
+ 'B'
376
+ sage: D.fC()
377
+ 'C'
378
+ sage: D.fD()
379
+ 'D'
380
+ sage: D.f()
381
+ 'C'
382
+ sage: D.g()
383
+ 'myparent'
384
+
385
+ ::
386
+
387
+ sage: D.element_class
388
+ <class '__main__.myparent_with_category.element_class'>
389
+ sage: D.element_class.mro()
390
+ [<class '__main__.myparent_with_category.element_class'>,
391
+ <class ...__main__....Element...>,
392
+ <class '__main__.Ds.element_class'>,
393
+ <class '__main__.Cs.element_class'>,
394
+ <class '__main__.Bs.element_class'>,
395
+ <class '__main__.As.element_class'>,
396
+ <... 'object'>]
397
+
398
+
399
+ TESTS::
400
+
401
+ sage: import __main__
402
+ sage: __main__.myparent = myparent
403
+ sage: __main__.As = As
404
+ sage: __main__.Bs = Bs
405
+ sage: __main__.Cs = Cs
406
+ sage: __main__.Ds = Ds
407
+ sage: loads(dumps(Ds)) is Ds
408
+ True
409
+ sage: loads(dumps(Ds())) is Ds()
410
+ True
411
+ sage: loads(dumps(Ds().element_class)) is Ds().element_class
412
+ True
413
+
414
+ .. automethod:: Category._super_categories
415
+ .. automethod:: Category._super_categories_for_classes
416
+ .. automethod:: Category._all_super_categories
417
+ .. automethod:: Category._all_super_categories_proper
418
+ .. automethod:: Category._set_of_super_categories
419
+ .. automethod:: Category._make_named_class
420
+ .. automethod:: Category._repr_
421
+ .. automethod:: Category._repr_object_names
422
+ .. automethod:: Category._test_category
423
+ .. automethod:: Category._with_axiom
424
+ .. automethod:: Category._with_axiom_as_tuple
425
+ .. automethod:: Category._without_axioms
426
+ .. automethod:: Category._sort
427
+ .. automethod:: Category._sort_uniq
428
+ .. automethod:: Category.__classcall__
429
+ .. automethod:: Category.__init__
430
+ """
431
+ @staticmethod
432
+ def __classcall__(cls, *args, **options):
433
+ """
434
+ Input mangling for unique representation.
435
+
436
+ Let ``C = Cs(...)`` be a category. Since :issue:`12895`, the
437
+ class of ``C`` is a dynamic subclass ``Cs_with_category`` of
438
+ ``Cs`` in order for ``C`` to inherit code from the
439
+ ``SubcategoryMethods`` nested classes of its super categories.
440
+
441
+ The purpose of this ``__classcall__`` method is to ensure that
442
+ reconstructing ``C`` from its class with
443
+ ``Cs_with_category(...)`` actually calls properly ``Cs(...)``
444
+ and gives back ``C``.
445
+
446
+ .. SEEALSO:: :meth:`subcategory_class`
447
+
448
+ EXAMPLES::
449
+
450
+ sage: A = Algebras(QQ)
451
+ sage: A.__class__
452
+ <class 'sage.categories.algebras.Algebras_with_category'>
453
+ sage: A is Algebras(QQ)
454
+ True
455
+ sage: A is A.__class__(QQ)
456
+ True
457
+ """
458
+ if isinstance(cls, DynamicMetaclass):
459
+ cls = cls.__base__
460
+ return super().__classcall__(cls, *args, **options)
461
+
462
+ def __init__(self):
463
+ """
464
+ Initialize this category.
465
+
466
+ EXAMPLES::
467
+
468
+ sage: class SemiprimitiveRings(Category):
469
+ ....: def super_categories(self):
470
+ ....: return [Rings()]
471
+ ....: class ParentMethods:
472
+ ....: def jacobson_radical(self):
473
+ ....: return self.ideal(0)
474
+ sage: C = SemiprimitiveRings()
475
+ sage: C
476
+ Category of semiprimitive rings
477
+ sage: C.__class__
478
+ <class '__main__.SemiprimitiveRings_with_category'>
479
+
480
+ .. NOTE::
481
+
482
+ If the default name of the category (built from the name of
483
+ the class) is not adequate, please implement
484
+ :meth:`_repr_object_names` to customize it.
485
+ """
486
+ self.__class__ = dynamic_class("{}_with_category".format(self.__class__.__name__),
487
+ (self.__class__, self.subcategory_class, ),
488
+ cache=False, reduction=None,
489
+ doccls=self.__class__)
490
+
491
+ @lazy_attribute
492
+ def _label(self):
493
+ """
494
+ A short name of ``self``, obtained from its type.
495
+
496
+ EXAMPLES::
497
+
498
+ sage: Rings()._label
499
+ 'Rings'
500
+ """
501
+ t = str(self.__class__.__base__)
502
+ t = t[t.rfind('.') + 1:]
503
+ return t[:t.rfind("'")]
504
+
505
+ def _repr_object_names(self):
506
+ """
507
+ Return the name of the objects of this category.
508
+
509
+ EXAMPLES::
510
+
511
+ sage: FiniteGroups()._repr_object_names()
512
+ 'finite groups'
513
+ sage: AlgebrasWithBasis(QQ)._repr_object_names()
514
+ 'algebras with basis over Rational Field'
515
+
516
+ TESTS::
517
+
518
+ sage: Rings()
519
+ Category of rings
520
+ sage: Rings()._repr_object_names()
521
+ 'rings'
522
+ sage: PrincipalIdealDomains()._repr_object_names()
523
+ 'principal ideal domains'
524
+ """
525
+ words = "".join(letter if not letter.isupper() else ";" + letter
526
+ for letter in self._label).split(";")
527
+ return " ".join(w if w in HALL_OF_FAME else w.lower()
528
+ for w in words).lstrip()
529
+
530
+ def _short_name(self):
531
+ """
532
+ Return a CamelCase name for this category.
533
+
534
+ EXAMPLES::
535
+
536
+ sage: CoxeterGroups()._short_name()
537
+ 'CoxeterGroups'
538
+
539
+ sage: AlgebrasWithBasis(QQ)._short_name()
540
+ 'AlgebrasWithBasis'
541
+
542
+ Conventions for short names should be discussed at the level
543
+ of Sage, and only then applied accordingly here.
544
+ """
545
+ return self._label
546
+
547
+ @classmethod
548
+ def an_instance(cls):
549
+ """
550
+ Return an instance of this class.
551
+
552
+ EXAMPLES::
553
+
554
+ sage: Rings.an_instance()
555
+ Category of rings
556
+
557
+ Parametrized categories should overload this default
558
+ implementation to provide appropriate arguments::
559
+
560
+ sage: Algebras.an_instance()
561
+ Category of algebras over Rational Field
562
+ sage: Bimodules.an_instance() # needs sage.rings.real_mpfr
563
+ Category of bimodules over Rational Field on the left
564
+ and Real Field with 53 bits of precision on the right
565
+ sage: AlgebraIdeals.an_instance()
566
+ Category of algebra ideals
567
+ in Univariate Polynomial Ring in x over Rational Field
568
+ """
569
+ return cls()
570
+
571
+ def __call__(self, x, *args, **opts):
572
+ """
573
+ Construct an object in this category from the data in ``x``,
574
+ or throw :exc:`TypeError` or :exc:`NotImplementedError`.
575
+
576
+ If ``x`` is readily in ``self`` it is returned unchanged.
577
+ Categories wishing to extend this minimal behavior should
578
+ implement :meth:`._call_`.
579
+
580
+ EXAMPLES::
581
+
582
+ sage: Rings()(ZZ)
583
+ Integer Ring
584
+ """
585
+ if x in self:
586
+ return x
587
+ return self._call_(x, *args, **opts)
588
+
589
+ def _call_(self, x):
590
+ """
591
+ Construct an object in this category from the data in ``x``,
592
+ or throw :exc:`NotImplementedError`.
593
+
594
+ EXAMPLES::
595
+
596
+ sage: Semigroups()._call_(3)
597
+ Traceback (most recent call last):
598
+ ...
599
+ NotImplementedError
600
+ """
601
+ raise NotImplementedError
602
+
603
+ def _repr_(self):
604
+ """
605
+ Return the print representation of this category.
606
+
607
+ EXAMPLES::
608
+
609
+ sage: Sets() # indirect doctest
610
+ Category of sets
611
+ """
612
+ return "Category of {}".format(self._repr_object_names())
613
+
614
+ def _latex_(self):
615
+ r"""
616
+ Return the latex representation of this category.
617
+
618
+ EXAMPLES::
619
+
620
+ sage: latex(Sets()) # indirect doctest
621
+ \mathbf{Sets}
622
+ sage: latex(CommutativeAdditiveSemigroups())
623
+ \mathbf{CommutativeAdditiveSemigroups}
624
+ """
625
+ return "\\mathbf{%s}" % self._short_name()
626
+
627
+ # The convention for which hash function to use should be decided at the level of UniqueRepresentation
628
+ # The implementation below is bad (hash independent of the base ring)
629
+ # def __hash__(self):
630
+ # """
631
+ # Returns a hash for this category.
632
+ #
633
+ # Currently this is just the hash of the string representing the category.
634
+ #
635
+ # EXAMPLES::
636
+ #
637
+ # sage: hash(Algebras(QQ)) #indirect doctest
638
+ # 699942203
639
+ # sage: hash(Algebras(ZZ))
640
+ # 699942203
641
+ # """
642
+ # return hash(self.__category) # Any reason not to use id?
643
+
644
+ def _subcategory_hook_(self, category):
645
+ """
646
+ Quick subcategory check.
647
+
648
+ INPUT:
649
+
650
+ - ``category`` -- a category
651
+
652
+ OUTPUT:
653
+
654
+ - ``True``, if ``category`` is a subcategory of ``self``.
655
+ - ``False``, if ``category`` is not a subcategory of ``self``.
656
+ - ``Unknown``, if a quick check was not enough to determine
657
+ whether ``category`` is a subcategory of ``self`` or not.
658
+
659
+ The aim of this method is to offer a framework to add cheap
660
+ tests for subcategories. When doing
661
+ ``category.is_subcategory(self)`` (note the reverse order of
662
+ ``self`` and ``category``), this method is usually called
663
+ first. Only if it returns ``Unknown``, :meth:`is_subcategory`
664
+ will build the list of super categories of ``category``.
665
+
666
+ This method need not to handle the case where ``category`` is
667
+ ``self``; this is the first test that is done in
668
+ :meth:`is_subcategory`.
669
+
670
+ This default implementation tests whether the parent class of
671
+ ``category`` is a subclass of the parent class of ``self``.
672
+ This is most of the time a complete subcategory test.
673
+
674
+ .. WARNING::
675
+
676
+ This test is incomplete for categories in
677
+ :class:`CategoryWithParameters`, as introduced by
678
+ :issue:`11935`. This method is therefore overwritten by
679
+ :meth:`~sage.categories.category.CategoryWithParameters._subcategory_hook_`.
680
+
681
+ EXAMPLES::
682
+
683
+ sage: Rings()._subcategory_hook_(Rings())
684
+ True
685
+ """
686
+ return issubclass(category.parent_class, self.parent_class)
687
+
688
+ def __contains__(self, x) -> bool:
689
+ """
690
+ Membership testing.
691
+
692
+ Returns whether ``x`` is an object in this category, that is
693
+ if the category of ``x`` is a subcategory of ``self``.
694
+
695
+ EXAMPLES::
696
+
697
+ sage: ZZ in Sets()
698
+ True
699
+ """
700
+ try:
701
+ c = x.category()
702
+ except AttributeError:
703
+ return False
704
+ return c.is_subcategory(self)
705
+
706
+ @staticmethod
707
+ def __classcontains__(cls, x):
708
+ """
709
+ Membership testing, without arguments.
710
+
711
+ INPUT:
712
+
713
+ - ``cls`` -- a category class
714
+ - ``x`` -- any object
715
+
716
+ Returns whether ``x`` is an object of a category which is an instance
717
+ of ``cls``.
718
+
719
+ EXAMPLES:
720
+
721
+ This method makes it easy to test if an object is, say, a
722
+ vector space, without having to specify the base ring::
723
+
724
+ sage: F = FreeModule(QQ, 3) # needs sage.modules
725
+ sage: F in VectorSpaces # needs sage.modules
726
+ True
727
+
728
+ sage: F = FreeModule(ZZ, 3) # needs sage.modules
729
+ sage: F in VectorSpaces # needs sage.modules
730
+ False
731
+
732
+ sage: F in Algebras # needs sage.modules
733
+ False
734
+
735
+ TESTS:
736
+
737
+ Non category objects shall be handled properly::
738
+
739
+ sage: [1,2] in Algebras
740
+ False
741
+ """
742
+ try:
743
+ c = x.categories()
744
+ except AttributeError:
745
+ return False
746
+ return any(isinstance(cat, cls) for cat in c)
747
+
748
+ def is_abelian(self) -> bool:
749
+ """
750
+ Return whether this category is abelian.
751
+
752
+ An abelian category is a category satisfying:
753
+
754
+ - It has a zero object;
755
+ - It has all pullbacks and pushouts;
756
+ - All monomorphisms and epimorphisms are normal.
757
+
758
+ Equivalently, one can define an increasing sequence of conditions:
759
+
760
+ - A category is pre-additive if it is enriched over abelian groups
761
+ (all homsets are abelian groups and composition is bilinear);
762
+ - A pre-additive category is additive if every finite set of objects
763
+ has a biproduct (we can form direct sums and direct products);
764
+ - An additive category is pre-abelian if every morphism has both a
765
+ kernel and a cokernel;
766
+ - A pre-abelian category is abelian if every monomorphism is the
767
+ kernel of some morphism and every epimorphism is the cokernel of
768
+ some morphism.
769
+
770
+ EXAMPLES::
771
+
772
+ sage: Modules(ZZ).is_abelian()
773
+ True
774
+ sage: FreeModules(ZZ).is_abelian()
775
+ False
776
+ sage: FreeModules(QQ).is_abelian()
777
+ True
778
+ sage: CommutativeAdditiveGroups().is_abelian()
779
+ True
780
+ sage: Semigroups().is_abelian()
781
+ Traceback (most recent call last):
782
+ ...
783
+ NotImplementedError: is_abelian
784
+ """
785
+ raise NotImplementedError("is_abelian")
786
+
787
+ ##########################################################################
788
+ # Methods related to the category hierarchy
789
+ ##########################################################################
790
+
791
+ def category_graph(self):
792
+ r"""
793
+ Return the graph of all super categories of this category.
794
+
795
+ EXAMPLES::
796
+
797
+ sage: C = Algebras(QQ)
798
+ sage: G = C.category_graph() # needs sage.graphs
799
+ sage: G.is_directed_acyclic() # needs sage.graphs
800
+ True
801
+
802
+ The girth of a directed acyclic graph is infinite, however,
803
+ the girth of the underlying undirected graph is 4 in this case::
804
+
805
+ sage: Graph(G).girth() # needs sage.graphs
806
+ 4
807
+ """
808
+ return category_graph([self])
809
+
810
+ @abstract_method
811
+ def super_categories(self):
812
+ """
813
+ Return the *immediate* super categories of ``self``.
814
+
815
+ OUTPUT: a duplicate-free list of categories
816
+
817
+ Every category should implement this method.
818
+
819
+ EXAMPLES::
820
+
821
+ sage: Groups().super_categories()
822
+ [Category of monoids, Category of inverse unital magmas]
823
+ sage: Objects().super_categories()
824
+ []
825
+
826
+ .. NOTE::
827
+
828
+ Since :issue:`10963`, the order of the categories in the
829
+ result is irrelevant. For details, see
830
+ :ref:`category-primer-category-order`.
831
+
832
+ .. NOTE::
833
+
834
+ Whenever speed matters, developers are advised to use the
835
+ lazy attribute :meth:`_super_categories` instead of
836
+ calling this method.
837
+ """
838
+
839
+ @lazy_attribute
840
+ def _all_super_categories(self):
841
+ r"""
842
+ All the super categories of this category, including this category.
843
+
844
+ Since :issue:`11943`, the order of super categories is
845
+ determined by Python's method resolution order C3 algorithm.
846
+
847
+ .. SEEALSO:: :meth:`all_super_categories`
848
+
849
+ .. NOTE:: this attribute is likely to eventually become a tuple.
850
+
851
+ .. NOTE:: this sets :meth:`_super_categories_for_classes` as a side effect
852
+
853
+ EXAMPLES::
854
+
855
+ sage: C = Rings(); C
856
+ Category of rings
857
+ sage: C._all_super_categories
858
+ [Category of rings, Category of rngs, Category of semirings, ...
859
+ Category of monoids, ...
860
+ Category of commutative additive groups, ...
861
+ Category of sets, Category of sets with partial maps,
862
+ Category of objects]
863
+ """
864
+ (result, bases) = C3_sorted_merge([cat._all_super_categories
865
+ for cat in self._super_categories] +
866
+ [self._super_categories],
867
+ category_sort_key)
868
+ if not sorted(result, key=category_sort_key, reverse=True) == result:
869
+ warn("Inconsistent sorting results for all super categories of {}".format(
870
+ self.__class__))
871
+ self._super_categories_for_classes = bases
872
+ return [self] + result
873
+
874
+ @lazy_attribute
875
+ def _all_super_categories_proper(self):
876
+ r"""
877
+ All the proper super categories of this category.
878
+
879
+ Since :issue:`11943`, the order of super categories is
880
+ determined by Python's method resolution order C3 algorithm.
881
+
882
+ .. SEEALSO:: :meth:`all_super_categories`
883
+
884
+ .. NOTE:: this attribute is likely to eventually become a tuple.
885
+
886
+ EXAMPLES::
887
+
888
+ sage: C = Rings(); C
889
+ Category of rings
890
+ sage: C._all_super_categories_proper
891
+ [Category of rngs, Category of semirings, ...
892
+ Category of monoids, ...
893
+ Category of commutative additive groups, ...
894
+ Category of sets, Category of sets with partial maps,
895
+ Category of objects]
896
+ """
897
+ return self._all_super_categories[1:]
898
+
899
+ @lazy_attribute
900
+ def _set_of_super_categories(self):
901
+ """
902
+ The frozen set of all proper super categories of this category.
903
+
904
+ .. NOTE:: this is used for speeding up category containment tests.
905
+
906
+ .. SEEALSO:: :meth:`all_super_categories`
907
+
908
+ EXAMPLES::
909
+
910
+ sage: sorted(Groups()._set_of_super_categories, key=str)
911
+ [Category of inverse unital magmas,
912
+ Category of magmas,
913
+ Category of monoids,
914
+ Category of objects,
915
+ Category of semigroups,
916
+ Category of sets,
917
+ Category of sets with partial maps,
918
+ Category of unital magmas]
919
+ sage: sorted(Groups()._set_of_super_categories, key=str)
920
+ [Category of inverse unital magmas, Category of magmas, Category of monoids,
921
+ Category of objects, Category of semigroups, Category of sets,
922
+ Category of sets with partial maps, Category of unital magmas]
923
+
924
+ TESTS::
925
+
926
+ sage: C = HopfAlgebrasWithBasis(GF(7))
927
+ sage: C._set_of_super_categories == set(C._all_super_categories_proper)
928
+ True
929
+ """
930
+ return frozenset(self._all_super_categories_proper)
931
+
932
+ def all_super_categories(self, proper=False):
933
+ """
934
+ Return the list of all super categories of this category.
935
+
936
+ INPUT:
937
+
938
+ - ``proper`` -- boolean (default: ``False``); whether to exclude this category
939
+
940
+ Since :issue:`11943`, the order of super categories is
941
+ determined by Python's method resolution order C3 algorithm.
942
+
943
+ .. NOTE::
944
+
945
+ Whenever speed matters, the developers are advised to use
946
+ instead the lazy attributes :meth:`_all_super_categories`,
947
+ :meth:`_all_super_categories_proper`, or
948
+ :meth:`_set_of_super_categories`, as
949
+ appropriate. Simply because lazy attributes are much
950
+ faster than any method.
951
+
952
+ .. NOTE::
953
+
954
+ This is not the same as the concept of super category in mathematics.
955
+ In fact, this is not even the opposite relation of :meth:`is_subcategory`::
956
+
957
+ sage: A = VectorSpaces(QQ); A
958
+ Category of vector spaces over Rational Field
959
+ sage: B = VectorSpaces(QQ.category()); B
960
+ Category of vector spaces over (number fields and quotient fields and metric spaces)
961
+ sage: A.is_subcategory(B)
962
+ True
963
+ sage: B in A.all_super_categories()
964
+ False
965
+
966
+ .. SEEALSO:: :meth:`_test_category_graph`
967
+
968
+ EXAMPLES::
969
+
970
+ sage: C = Rings(); C
971
+ Category of rings
972
+ sage: C.all_super_categories()
973
+ [Category of rings, Category of rngs, Category of semirings, ...
974
+ Category of monoids, ...
975
+ Category of commutative additive groups, ...
976
+ Category of sets, Category of sets with partial maps,
977
+ Category of objects]
978
+
979
+ sage: C.all_super_categories(proper = True)
980
+ [Category of rngs, Category of semirings, ...
981
+ Category of monoids, ...
982
+ Category of commutative additive groups, ...
983
+ Category of sets, Category of sets with partial maps,
984
+ Category of objects]
985
+
986
+ sage: Sets().all_super_categories()
987
+ [Category of sets, Category of sets with partial maps, Category of objects]
988
+ sage: Sets().all_super_categories(proper=True)
989
+ [Category of sets with partial maps, Category of objects]
990
+ sage: Sets().all_super_categories() is Sets()._all_super_categories
991
+ True
992
+ sage: Sets().all_super_categories(proper=True) is Sets()._all_super_categories_proper
993
+ True
994
+ """
995
+ if proper:
996
+ return self._all_super_categories_proper
997
+ return self._all_super_categories
998
+
999
+ @lazy_attribute
1000
+ def _super_categories(self):
1001
+ """
1002
+ The immediate super categories of this category.
1003
+
1004
+ This lazy attribute caches the result of the mandatory method
1005
+ :meth:`super_categories` for speed. It also does some mangling
1006
+ (flattening join categories, sorting, ...).
1007
+
1008
+ Whenever speed matters, developers are advised to use this
1009
+ lazy attribute rather than calling :meth:`super_categories`.
1010
+
1011
+ .. NOTE::
1012
+
1013
+ This attribute is likely to eventually become a tuple.
1014
+ When this happens, we might as well use :meth:`Category._sort`,
1015
+ if not :meth:`Category._sort_uniq`.
1016
+
1017
+ EXAMPLES::
1018
+
1019
+ sage: Rings()._super_categories
1020
+ [Category of rngs, Category of semirings]
1021
+ """
1022
+ return sorted(_flatten_categories(self.super_categories(), JoinCategory), key=category_sort_key, reverse=True)
1023
+
1024
+ @lazy_attribute
1025
+ def _super_categories_for_classes(self):
1026
+ """
1027
+ The super categories of this category used for building classes.
1028
+
1029
+ This is a close variant of :meth:`_super_categories` used for
1030
+ constructing the list of the bases for :meth:`parent_class`,
1031
+ :meth:`element_class`, and friends. The purpose is ensure that
1032
+ Python will find a proper Method Resolution Order for those
1033
+ classes. For background, see :mod:`sage.misc.c3_controlled`.
1034
+
1035
+ .. SEEALSO:: :meth:`_cmp_key`.
1036
+
1037
+ .. NOTE::
1038
+
1039
+ This attribute is calculated as a by-product of computing
1040
+ :meth:`_all_super_categories`.
1041
+
1042
+ EXAMPLES::
1043
+
1044
+ sage: Rings()._super_categories_for_classes
1045
+ [Category of rngs, Category of semirings]
1046
+ """
1047
+ self._all_super_categories
1048
+ return self._super_categories_for_classes
1049
+
1050
+ ##########################################################################
1051
+ # Methods handling of full subcategories
1052
+ ##########################################################################
1053
+
1054
+ def additional_structure(self) -> Self:
1055
+ """
1056
+ Return whether ``self`` defines additional structure.
1057
+
1058
+ OUTPUT:
1059
+
1060
+ - ``self`` if ``self`` defines additional structure and
1061
+ ``None`` otherwise. This default implementation returns
1062
+ ``self``.
1063
+
1064
+ A category `C` *defines additional structure* if `C`-morphisms
1065
+ shall preserve more structure (e.g. operations) than that
1066
+ specified by the super categories of `C`. For example, the
1067
+ category of magmas defines additional structure, namely the
1068
+ operation `*` that shall be preserved by magma morphisms. On
1069
+ the other hand the category of rings does not define additional
1070
+ structure: a function between two rings that is both a unital
1071
+ magma morphism and a unital additive magma morphism is
1072
+ automatically a ring morphism.
1073
+
1074
+ Formally speaking `C` *defines additional structure*, if `C`
1075
+ is *not* a full subcategory of the join of its super
1076
+ categories: the morphisms need to preserve more structure, and
1077
+ thus the homsets are smaller.
1078
+
1079
+ By default, a category is considered as defining additional
1080
+ structure, unless it is a :ref:`category with axiom
1081
+ <category-primer-axioms>`.
1082
+
1083
+ EXAMPLES:
1084
+
1085
+ Here are some typical structure categories, with the
1086
+ additional structure they define::
1087
+
1088
+ sage: Sets().additional_structure()
1089
+ Category of sets
1090
+ sage: Magmas().additional_structure() # `*`
1091
+ Category of magmas
1092
+ sage: AdditiveMagmas().additional_structure() # `+`
1093
+ Category of additive magmas
1094
+ sage: LeftModules(ZZ).additional_structure() # left multiplication by scalar
1095
+ Category of left modules over Integer Ring
1096
+ sage: Coalgebras(QQ).additional_structure() # coproduct
1097
+ Category of coalgebras over Rational Field
1098
+ sage: Crystals().additional_structure() # crystal operators
1099
+ Category of crystals
1100
+
1101
+ On the other hand, the category of semigroups is not a
1102
+ structure category, since its operation `+` is already defined
1103
+ by the category of magmas::
1104
+
1105
+ sage: Semigroups().additional_structure()
1106
+
1107
+ Most :ref:`categories with axiom <category-primer-axioms>`
1108
+ don't define additional structure::
1109
+
1110
+ sage: Sets().Finite().additional_structure()
1111
+ sage: Rings().Commutative().additional_structure()
1112
+ sage: Modules(QQ).FiniteDimensional().additional_structure()
1113
+ sage: from sage.categories.magmatic_algebras import MagmaticAlgebras
1114
+ sage: MagmaticAlgebras(QQ).Unital().additional_structure()
1115
+
1116
+ As of Sage 6.4, the only exceptions are the category of unital
1117
+ magmas or the category of unital additive magmas (both define
1118
+ a unit which shall be preserved by morphisms)::
1119
+
1120
+ sage: Magmas().Unital().additional_structure()
1121
+ Category of unital magmas
1122
+ sage: AdditiveMagmas().AdditiveUnital().additional_structure()
1123
+ Category of additive unital additive magmas
1124
+
1125
+ Similarly, :ref:`functorial construction categories
1126
+ <category-primer-functorial-constructions>` don't define
1127
+ additional structure, unless the construction is actually
1128
+ defined by their base category. For example, the category of
1129
+ graded modules defines a grading which shall be preserved by
1130
+ morphisms::
1131
+
1132
+ sage: Modules(ZZ).Graded().additional_structure()
1133
+ Category of graded modules over Integer Ring
1134
+
1135
+ On the other hand, the category of graded algebras does not
1136
+ define additional structure; indeed an algebra morphism which
1137
+ is also a module morphism is a graded algebra morphism::
1138
+
1139
+ sage: Algebras(ZZ).Graded().additional_structure()
1140
+
1141
+ Similarly, morphisms are requested to preserve the structure
1142
+ given by the following constructions::
1143
+
1144
+ sage: Sets().Quotients().additional_structure()
1145
+ Category of quotients of sets
1146
+ sage: Sets().CartesianProducts().additional_structure()
1147
+ Category of Cartesian products of sets
1148
+ sage: Modules(QQ).TensorProducts().additional_structure()
1149
+
1150
+ This might change, as we are lacking enough data points to
1151
+ guarantee that this was the correct design decision.
1152
+
1153
+ .. NOTE::
1154
+
1155
+ In some cases a category defines additional structure,
1156
+ where the structure can be useful to manipulate morphisms
1157
+ but where, in most use cases, we don't want the morphisms
1158
+ to necessarily preserve it. For example, in the context of
1159
+ finite dimensional vector spaces, having a distinguished
1160
+ basis allows for representing morphisms by matrices; yet
1161
+ considering only morphisms that preserve that
1162
+ distinguished basis would be boring.
1163
+
1164
+ In such cases, we might want to eventually have two
1165
+ categories, one where the additional structure is
1166
+ preserved, and one where it's not necessarily preserved
1167
+ (we would need to find an idiom for this).
1168
+
1169
+ At this point, a choice is to be made each time, according
1170
+ to the main use cases. Some of those choices are yet to be
1171
+ settled. For example, should by default:
1172
+
1173
+ - an euclidean domain morphism preserve euclidean
1174
+ division? ::
1175
+
1176
+ sage: EuclideanDomains().additional_structure()
1177
+ Category of euclidean domains
1178
+
1179
+ - an enumerated set morphism preserve the distinguished
1180
+ enumeration? ::
1181
+
1182
+ sage: EnumeratedSets().additional_structure()
1183
+
1184
+ - a module with basis morphism preserve the distinguished
1185
+ basis? ::
1186
+
1187
+ sage: Modules(QQ).WithBasis().additional_structure()
1188
+
1189
+ .. SEEALSO::
1190
+
1191
+ This method together with the methods overloading it
1192
+ provide the basic data to determine, for a given category,
1193
+ the super categories that define some structure (see
1194
+ :meth:`structure`), and to test whether a category is a
1195
+ full subcategory of some other category (see
1196
+ :meth:`is_full_subcategory`). For example, the category of
1197
+ Coxeter groups is not full subcategory of the category of
1198
+ groups since morphisms need to preserve the distinguished
1199
+ generators::
1200
+
1201
+ sage: CoxeterGroups().is_full_subcategory(Groups())
1202
+ False
1203
+
1204
+ The support for modeling full subcategories has been
1205
+ introduced in :issue:`16340`.
1206
+ """
1207
+ return self
1208
+
1209
+ @cached_method
1210
+ def structure(self):
1211
+ r"""
1212
+ Return the structure ``self`` is endowed with.
1213
+
1214
+ This method returns the structure that morphisms in this
1215
+ category shall be preserving. For example, it tells that a
1216
+ ring is a set endowed with a structure of both a unital magma
1217
+ and an additive unital magma which satisfies some further
1218
+ axioms. In other words, a ring morphism is a function that
1219
+ preserves the unital magma and additive unital magma
1220
+ structure.
1221
+
1222
+ In practice, this returns the collection of all the super
1223
+ categories of ``self`` that define some additional structure,
1224
+ as a frozen set.
1225
+
1226
+ EXAMPLES::
1227
+
1228
+ sage: Objects().structure()
1229
+ frozenset()
1230
+
1231
+ sage: def structure(C):
1232
+ ....: return Category._sort(C.structure())
1233
+
1234
+ sage: structure(Sets())
1235
+ (Category of sets, Category of sets with partial maps)
1236
+ sage: structure(Magmas())
1237
+ (Category of magmas, Category of sets, Category of sets with partial maps)
1238
+
1239
+ In the following example, we only list the smallest structure
1240
+ categories to get a more readable output::
1241
+
1242
+ sage: def structure(C):
1243
+ ....: return Category._sort_uniq(C.structure())
1244
+
1245
+ sage: structure(Magmas())
1246
+ (Category of magmas,)
1247
+ sage: structure(Rings())
1248
+ (Category of unital magmas, Category of additive unital additive magmas)
1249
+ sage: structure(Fields())
1250
+ (Category of euclidean domains, Category of noetherian rings)
1251
+ sage: structure(Algebras(QQ))
1252
+ (Category of unital magmas,
1253
+ Category of right modules over Rational Field,
1254
+ Category of left modules over Rational Field)
1255
+ sage: structure(HopfAlgebras(QQ).Graded().WithBasis().Connected())
1256
+ (Category of Hopf algebras over Rational Field,
1257
+ Category of graded modules over Rational Field)
1258
+
1259
+ This method is used in :meth:`is_full_subcategory` for
1260
+ deciding whether a category is a full subcategory of some
1261
+ other category, and for documentation purposes. It is computed
1262
+ recursively from the result of :meth:`additional_structure`
1263
+ on the super categories of ``self``.
1264
+ """
1265
+ result = {D for C in self.super_categories() for D in C.structure()}
1266
+ if self.additional_structure() is not None:
1267
+ result.add(self)
1268
+ return frozenset(result)
1269
+
1270
+ def is_full_subcategory(self, other):
1271
+ """
1272
+ Return whether ``self`` is a full subcategory of ``other``.
1273
+
1274
+ A subcategory `B` of a category `A` is a *full subcategory* if
1275
+ any `A`-morphism between two objects of `B` is also a
1276
+ `B`-morphism (the reciprocal always holds: any `B`-morphism
1277
+ between two objects of `B` is an `A`-morphism).
1278
+
1279
+ This is computed by testing whether ``self`` is a subcategory
1280
+ of ``other`` and whether they have the same structure, as
1281
+ determined by :meth:`structure` from the
1282
+ result of :meth:`additional_structure` on the super
1283
+ categories.
1284
+
1285
+ .. WARNING::
1286
+
1287
+ A positive answer is guaranteed to be mathematically
1288
+ correct. A negative answer may mean that Sage has not been
1289
+ taught enough information (or can not yet within the
1290
+ current model) to derive this information. See
1291
+ :meth:`full_super_categories` for a discussion.
1292
+
1293
+ .. SEEALSO::
1294
+
1295
+ - :meth:`is_subcategory`
1296
+ - :meth:`full_super_categories`
1297
+
1298
+ EXAMPLES::
1299
+
1300
+ sage: Magmas().Associative().is_full_subcategory(Magmas())
1301
+ True
1302
+ sage: Magmas().Unital().is_full_subcategory(Magmas())
1303
+ False
1304
+ sage: Rings().is_full_subcategory(Magmas().Unital() & AdditiveMagmas().AdditiveUnital())
1305
+ True
1306
+
1307
+ Here are two typical examples of false negatives::
1308
+
1309
+ sage: Groups().is_full_subcategory(Semigroups())
1310
+ False
1311
+ sage: Groups().is_full_subcategory(Semigroups()) # todo: not implemented
1312
+ True
1313
+ sage: Fields().is_full_subcategory(Rings())
1314
+ False
1315
+ sage: Fields().is_full_subcategory(Rings()) # todo: not implemented
1316
+ True
1317
+
1318
+ .. TODO::
1319
+
1320
+ The latter is a consequence of :class:`EuclideanDomains`
1321
+ currently being a structure category. Is this what we
1322
+ want? ::
1323
+
1324
+ sage: EuclideanDomains().is_full_subcategory(Rings())
1325
+ False
1326
+ """
1327
+ return self.is_subcategory(other) and \
1328
+ len(self.structure()) == len(other.structure())
1329
+
1330
+ @cached_method
1331
+ def full_super_categories(self):
1332
+ r"""
1333
+ Return the *immediate* full super categories of ``self``.
1334
+
1335
+ .. SEEALSO::
1336
+
1337
+ - :meth:`super_categories`
1338
+ - :meth:`is_full_subcategory`
1339
+
1340
+ .. WARNING::
1341
+
1342
+ The current implementation selects the full subcategories
1343
+ among the immediate super categories of ``self``. This
1344
+ assumes that, if `C\subset B\subset A` is a chain of
1345
+ categories and `C` is a full subcategory of `A`, then `C`
1346
+ is a full subcategory of `B` and `B` is a full subcategory
1347
+ of `A`.
1348
+
1349
+ This assumption is guaranteed to hold with the current
1350
+ model and implementation of full subcategories in
1351
+ Sage. However, mathematically speaking, this is too
1352
+ restrictive. This indeed prevents the complete modelling
1353
+ of situations where any `A` morphism between elements of
1354
+ `C` automatically preserves the `B` structure. See below
1355
+ for an example.
1356
+
1357
+ EXAMPLES:
1358
+
1359
+ A semigroup morphism between two finite semigroups is a finite
1360
+ semigroup morphism::
1361
+
1362
+ sage: Semigroups().Finite().full_super_categories()
1363
+ [Category of semigroups]
1364
+
1365
+ On the other hand, a semigroup morphism between two monoids is
1366
+ not necessarily a monoid morphism (which must map the unit to
1367
+ the unit)::
1368
+
1369
+ sage: Monoids().super_categories()
1370
+ [Category of semigroups, Category of unital magmas]
1371
+ sage: Monoids().full_super_categories()
1372
+ [Category of unital magmas]
1373
+
1374
+ Any semigroup morphism between two groups is automatically a
1375
+ monoid morphism (in a group the unit is the unique idempotent,
1376
+ so it has to be mapped to the unit). Yet, due to the
1377
+ limitation of the model advertised above, Sage currently cannot
1378
+ be taught that the category of groups is a full subcategory of
1379
+ the category of semigroups::
1380
+
1381
+ sage: Groups().full_super_categories() # todo: not implemented
1382
+ [Category of monoids, Category of semigroups, Category of inverse unital magmas]
1383
+ sage: Groups().full_super_categories()
1384
+ [Category of monoids, Category of inverse unital magmas]
1385
+ """
1386
+ return [C for C in self.super_categories()
1387
+ if self.is_full_subcategory(C)]
1388
+
1389
+ ##########################################################################
1390
+ # Test methods
1391
+ ##########################################################################
1392
+
1393
+ def _test_category_graph(self, **options):
1394
+ """
1395
+ Check that the category graph matches with Python's method resolution order.
1396
+
1397
+ .. NOTE::
1398
+
1399
+ By :issue:`11943`, the list of categories returned by
1400
+ :meth:`all_super_categories` is supposed to match with the
1401
+ method resolution order of the parent and element
1402
+ classes. This method checks this.
1403
+
1404
+ Note that if
1405
+ :meth:`~sage.structure.category_object.CategoryObject._refine_category_`
1406
+ is called at unexpected times, the invariant might be false. Most
1407
+ commonly, this happens with rings like ``Zmod(n)`` or ``SR``, where
1408
+ a check like ``Zmod(n) in Fields()`` is needed (which checks the primality
1409
+ of `n`) to refine their category to be a subcategory of fields.
1410
+
1411
+ .. SEEALSO::
1412
+
1413
+ :meth:`CategoryWithParameters._make_named_class_key`
1414
+
1415
+ EXAMPLES::
1416
+
1417
+ sage: C = HopfAlgebrasWithBasis(QQ)
1418
+ sage: C.parent_class.mro() == [X.parent_class for X in C._all_super_categories] + [object]
1419
+ True
1420
+ sage: C.element_class.mro() == [X.element_class for X in C._all_super_categories] + [object]
1421
+ True
1422
+ sage: TestSuite(C).run() # indirect doctest
1423
+ """
1424
+ tester = self._tester(**options)
1425
+ tester.assertEqual(self.parent_class.mro(), [C.parent_class for C in self._all_super_categories] + [object])
1426
+ tester.assertEqual(self.element_class.mro(), [C.element_class for C in self._all_super_categories] + [object])
1427
+
1428
+ def _test_category(self, **options):
1429
+ r"""
1430
+ Run generic tests on this category.
1431
+
1432
+ .. SEEALSO:: :class:`TestSuite`.
1433
+
1434
+ EXAMPLES::
1435
+
1436
+ sage: Sets()._test_category()
1437
+
1438
+ Let us now write a couple broken categories::
1439
+
1440
+ sage: class MyObjects(Category):
1441
+ ....: pass
1442
+ sage: MyObjects()._test_category()
1443
+ Traceback (most recent call last):
1444
+ ...
1445
+ NotImplementedError: <abstract method super_categories at ...>
1446
+
1447
+ sage: class MyObjects(Category):
1448
+ ....: def super_categories(self):
1449
+ ....: return tuple()
1450
+ sage: MyObjects()._test_category()
1451
+ Traceback (most recent call last):
1452
+ ...
1453
+ AssertionError: Category of my objects.super_categories() should return a list
1454
+
1455
+ sage: class MyObjects(Category):
1456
+ ....: def super_categories(self):
1457
+ ....: return []
1458
+ sage: MyObjects()._test_category()
1459
+ Traceback (most recent call last):
1460
+ ...
1461
+ AssertionError: Category of my objects is not a subcategory of Objects()
1462
+ """
1463
+ from sage.categories.objects import Objects
1464
+ from sage.categories.sets_cat import Sets
1465
+ tester = self._tester(**options)
1466
+ tester.assertTrue(isinstance(self.super_categories(), list),
1467
+ "%s.super_categories() should return a list" % self)
1468
+ tester.assertTrue(self.is_subcategory(Objects()),
1469
+ "%s is not a subcategory of Objects()" % self)
1470
+ tester.assertTrue(isinstance(self.parent_class, type))
1471
+ tester.assertTrue(all(not isinstance(cat, JoinCategory) for cat in self._super_categories))
1472
+ if not isinstance(self, JoinCategory):
1473
+ tester.assertTrue(all(self._cmp_key > cat._cmp_key for cat in self._super_categories))
1474
+ tester.assertTrue(self.is_subcategory(Category.join(self.super_categories()))) # Not an obviously passing test with axioms
1475
+
1476
+ for category in self._all_super_categories_proper:
1477
+ if self.is_full_subcategory(category):
1478
+ tester.assertTrue(any(cat.is_subcategory(category)
1479
+ for cat in self.full_super_categories()),
1480
+ "Every full super category should be a super category"
1481
+ "of some immediate full super category")
1482
+
1483
+ if self.is_subcategory(Sets()):
1484
+ tester.assertTrue(isinstance(self.parent_class, type))
1485
+ tester.assertTrue(isinstance(self.element_class, type))
1486
+
1487
+ _cmp_key = _cmp_key
1488
+
1489
+ ##########################################################################
1490
+ # Construction of the associated abstract classes for parents, elements, ...
1491
+ ##########################################################################
1492
+
1493
+ def _make_named_class(self, name, method_provider, cache=False, picklable=True):
1494
+ """
1495
+ Construction of the parent/element/... class of ``self``.
1496
+
1497
+ INPUT:
1498
+
1499
+ - ``name`` -- string; the name of the class as an attribute of
1500
+ ``self`` (e.g. "parent_class")
1501
+ - ``method_provider`` -- string; the name of an attribute of
1502
+ ``self`` that provides methods for the new class (in
1503
+ addition to those coming from the super categories,
1504
+ e.g. "ParentMethods")
1505
+ - ``cache`` -- boolean or ``ignore_reduction`` (default: ``False``)
1506
+ (passed down to dynamic_class; for internal use only)
1507
+ - ``picklable`` -- boolean (default: ``True``)
1508
+
1509
+ ASSUMPTION:
1510
+
1511
+ It is assumed that this method is only called from a lazy
1512
+ attribute whose name coincides with the given ``name``.
1513
+
1514
+ OUTPUT:
1515
+
1516
+ A dynamic class with bases given by the corresponding named
1517
+ classes of ``self``'s super_categories, and methods taken from
1518
+ the class ``getattr(self,method_provider)``.
1519
+
1520
+ .. NOTE::
1521
+
1522
+ - In this default implementation, the reduction data of
1523
+ the named class makes it depend on ``self``. Since the
1524
+ result is going to be stored in a lazy attribute of
1525
+ ``self`` anyway, we may as well disable the caching in
1526
+ ``dynamic_class`` (hence the default value
1527
+ ``cache=False``).
1528
+
1529
+ - :class:`CategoryWithParameters` overrides this method so
1530
+ that the same parent/element/... classes can be shared
1531
+ between closely related categories.
1532
+
1533
+ - The bases of the named class may also contain the named
1534
+ classes of some indirect super categories, according to
1535
+ :meth:`_super_categories_for_classes`. This is to
1536
+ guarantee that Python will build consistent method
1537
+ resolution orders. For background, see
1538
+ :mod:`sage.misc.c3_controlled`.
1539
+
1540
+ .. SEEALSO:: :meth:`CategoryWithParameters._make_named_class`
1541
+
1542
+ EXAMPLES::
1543
+
1544
+ sage: PC = Rings()._make_named_class("parent_class", "ParentMethods"); PC
1545
+ <class 'sage.categories.rings.Rings.parent_class'>
1546
+ sage: type(PC)
1547
+ <class 'sage.structure.dynamic_class.DynamicMetaclass'>
1548
+ sage: PC.__bases__
1549
+ (<class 'sage.categories.rngs.Rngs.parent_class'>,
1550
+ <class 'sage.categories.semirings.Semirings.parent_class'>)
1551
+
1552
+ Note that, by default, the result is not cached::
1553
+
1554
+ sage: PC is Rings()._make_named_class("parent_class", "ParentMethods")
1555
+ False
1556
+
1557
+ Indeed this method is only meant to construct lazy attributes
1558
+ like ``parent_class`` which already handle this caching::
1559
+
1560
+ sage: Rings().parent_class
1561
+ <class 'sage.categories.rings.Rings.parent_class'>
1562
+
1563
+ Reduction for pickling also assumes the existence of this lazy
1564
+ attribute::
1565
+
1566
+ sage: PC._reduction
1567
+ (<built-in function getattr>, (Category of rings, 'parent_class'))
1568
+ sage: loads(dumps(PC)) is Rings().parent_class
1569
+ True
1570
+
1571
+ TESTS::
1572
+
1573
+ sage: class A: pass
1574
+ sage: class BrokenCategory(Category):
1575
+ ....: def super_categories(self): return []
1576
+ ....: ParentMethods = 1
1577
+ ....: class ElementMethods(A):
1578
+ ....: pass
1579
+ ....: class MorphismMethods():
1580
+ ....: pass
1581
+ sage: C = BrokenCategory()
1582
+ sage: C._make_named_class("parent_class", "ParentMethods")
1583
+ Traceback (most recent call last):
1584
+ ...
1585
+ AssertionError: BrokenCategory.ParentMethods should be a class
1586
+ sage: C._make_named_class("element_class", "ElementMethods")
1587
+ doctest:...: UserWarning: BrokenCategory.ElementMethods should not have a super class
1588
+ <class '__main__.BrokenCategory.element_class'>
1589
+ sage: C._make_named_class("morphism_class", "MorphismMethods")
1590
+ <class '__main__.BrokenCategory.morphism_class'>
1591
+ """
1592
+ cls = self.__class__
1593
+ if isinstance(cls, DynamicMetaclass):
1594
+ cls = cls.__base__
1595
+ class_name = "%s.%s" % (cls.__name__, name)
1596
+ method_provider_cls = getattr(self, method_provider, None)
1597
+ if method_provider_cls is None:
1598
+ # If the category provides no XXXMethods class,
1599
+ # point to the documentation of the category itself
1600
+ doccls = cls
1601
+ else:
1602
+ # Otherwise, check XXXMethods
1603
+ assert inspect.isclass(method_provider_cls), \
1604
+ "%s.%s should be a class" % (cls.__name__, method_provider)
1605
+ mro = inspect.getmro(method_provider_cls)
1606
+ if len(mro) > 2 or (len(mro) == 2 and mro[1] is not object):
1607
+ warn("%s.%s should not have a super class" % (cls.__name__, method_provider))
1608
+ # and point the documentation to it
1609
+ doccls = method_provider_cls
1610
+ if picklable:
1611
+ reduction = (getattr, (self, name))
1612
+ else:
1613
+ reduction = None
1614
+ return dynamic_class(class_name,
1615
+ tuple(getattr(cat, name) for cat in self._super_categories_for_classes),
1616
+ method_provider_cls, prepend_cls_bases=False,
1617
+ doccls=doccls, reduction=reduction, cache=cache)
1618
+
1619
+ @lazy_attribute
1620
+ def subcategory_class(self):
1621
+ """
1622
+ A common superclass for all subcategories of this category (including this one).
1623
+
1624
+ This class derives from ``D.subcategory_class`` for each super
1625
+ category `D` of ``self``, and includes all the methods from
1626
+ the nested class ``self.SubcategoryMethods``, if it exists.
1627
+
1628
+ .. SEEALSO::
1629
+
1630
+ - :issue:`12895`
1631
+ - :meth:`parent_class`
1632
+ - :meth:`element_class`
1633
+ - :meth:`_make_named_class`
1634
+
1635
+ EXAMPLES::
1636
+
1637
+ sage: cls = Rings().subcategory_class; cls
1638
+ <class 'sage.categories.rings.Rings.subcategory_class'>
1639
+ sage: type(cls)
1640
+ <class 'sage.structure.dynamic_class.DynamicMetaclass'>
1641
+
1642
+ ``Rings()`` is an instance of this class, as well as all its subcategories::
1643
+
1644
+ sage: isinstance(Rings(), cls)
1645
+ True
1646
+ sage: isinstance(AlgebrasWithBasis(QQ), cls)
1647
+ True
1648
+
1649
+ .. NOTE::
1650
+
1651
+ See the note about :meth:`_test_category_graph` regarding Python
1652
+ class hierarchy.
1653
+
1654
+ TESTS::
1655
+
1656
+ sage: cls = Algebras(QQ).subcategory_class; cls
1657
+ <class 'sage.categories.algebras.Algebras.subcategory_class'>
1658
+ sage: type(cls)
1659
+ <class 'sage.structure.dynamic_class.DynamicMetaclass'>
1660
+ """
1661
+ return self._make_named_class('subcategory_class', 'SubcategoryMethods',
1662
+ cache=False, picklable=False)
1663
+
1664
+ @lazy_attribute
1665
+ def parent_class(self):
1666
+ r"""
1667
+ A common super class for all parents in this category (and its
1668
+ subcategories).
1669
+
1670
+ This class contains the methods defined in the nested class
1671
+ ``self.ParentMethods`` (if it exists), and has as bases the
1672
+ parent classes of the super categories of ``self``.
1673
+
1674
+ .. SEEALSO::
1675
+
1676
+ - :meth:`element_class`, :meth:`morphism_class`
1677
+ - :class:`Category` for details
1678
+
1679
+ EXAMPLES::
1680
+
1681
+ sage: C = Algebras(QQ).parent_class; C
1682
+ <class 'sage.categories.algebras.Algebras.parent_class'>
1683
+ sage: type(C)
1684
+ <class 'sage.structure.dynamic_class.DynamicMetaclass'>
1685
+
1686
+ By :issue:`11935`, some categories share their parent
1687
+ classes. For example, the parent class of an algebra only
1688
+ depends on the category of the base ring. A typical example is
1689
+ the category of algebras over a finite field versus algebras
1690
+ over a non-field::
1691
+
1692
+ sage: Algebras(GF(7)).parent_class is Algebras(GF(5)).parent_class
1693
+ True
1694
+ sage: Algebras(QQ).parent_class is Algebras(ZZ).parent_class
1695
+ False
1696
+ sage: Algebras(ZZ['t']).parent_class is Algebras(ZZ['t','x']).parent_class
1697
+ True
1698
+
1699
+ See :class:`CategoryWithParameters` for an abstract base class for
1700
+ categories that depend on parameters, even though the parent
1701
+ and element classes only depend on the parent or element
1702
+ classes of its super categories. It is used in
1703
+ :class:`~sage.categories.bimodules.Bimodules`,
1704
+ :class:`~sage.categories.category_types.Category_over_base` and
1705
+ :class:`sage.categories.category.JoinCategory`.
1706
+
1707
+ .. NOTE::
1708
+
1709
+ See the note about :meth:`_test_category_graph` regarding Python
1710
+ class hierarchy.
1711
+ """
1712
+ return self._make_named_class('parent_class', 'ParentMethods')
1713
+
1714
+ @lazy_attribute
1715
+ def element_class(self):
1716
+ r"""
1717
+ A common super class for all elements of parents in this category
1718
+ (and its subcategories).
1719
+
1720
+ This class contains the methods defined in the nested class
1721
+ ``self.ElementMethods`` (if it exists), and has as bases the
1722
+ element classes of the super categories of ``self``.
1723
+
1724
+ .. SEEALSO::
1725
+
1726
+ - :meth:`parent_class`, :meth:`morphism_class`
1727
+ - :class:`Category` for details
1728
+
1729
+ EXAMPLES::
1730
+
1731
+ sage: C = Algebras(QQ).element_class; C
1732
+ <class 'sage.categories.algebras.Algebras.element_class'>
1733
+ sage: type(C)
1734
+ <class 'sage.structure.dynamic_class.DynamicMetaclass'>
1735
+
1736
+ By :issue:`11935`, some categories share their element
1737
+ classes. For example, the element class of an algebra only
1738
+ depends on the category of the base. A typical example is the
1739
+ category of algebras over a field versus algebras over a
1740
+ non-field::
1741
+
1742
+ sage: Algebras(GF(5)).element_class is Algebras(GF(3)).element_class
1743
+ True
1744
+ sage: Algebras(QQ).element_class is Algebras(ZZ).element_class
1745
+ False
1746
+ sage: Algebras(ZZ['t']).element_class is Algebras(ZZ['t','x']).element_class
1747
+ True
1748
+
1749
+ These classes are constructed with ``__slots__ = ()``, so
1750
+ instances may not have a ``__dict__``::
1751
+
1752
+ sage: E = FiniteEnumeratedSets().element_class
1753
+ sage: E.__dictoffset__
1754
+ 0
1755
+
1756
+ .. SEEALSO:: :meth:`parent_class`
1757
+
1758
+ .. NOTE::
1759
+
1760
+ See the note about :meth:`_test_category_graph` regarding Python
1761
+ class hierarchy.
1762
+ """
1763
+ return self._make_named_class('element_class', 'ElementMethods')
1764
+
1765
+ @lazy_attribute
1766
+ def morphism_class(self):
1767
+ r"""
1768
+ A common super class for all morphisms between parents in this
1769
+ category (and its subcategories).
1770
+
1771
+ This class contains the methods defined in the nested class
1772
+ ``self.MorphismMethods`` (if it exists), and has as bases the
1773
+ morphism classes of the super categories of ``self``.
1774
+
1775
+ .. SEEALSO::
1776
+
1777
+ - :meth:`parent_class`, :meth:`element_class`
1778
+ - :class:`Category` for details
1779
+
1780
+ EXAMPLES::
1781
+
1782
+ sage: C = Algebras(QQ).morphism_class; C
1783
+ <class 'sage.categories.algebras.Algebras.morphism_class'>
1784
+ sage: type(C)
1785
+ <class 'sage.structure.dynamic_class.DynamicMetaclass'>
1786
+ """
1787
+ return self._make_named_class('morphism_class', 'MorphismMethods')
1788
+
1789
+ def required_methods(self):
1790
+ """
1791
+ Return the methods that are required and optional for parents
1792
+ in this category and their elements.
1793
+
1794
+ EXAMPLES::
1795
+
1796
+ sage: Algebras(QQ).required_methods()
1797
+ {'element': {'optional': ['_add_', '_mul_'], 'required': ['__bool__']},
1798
+ 'parent': {'optional': ['algebra_generators'], 'required': ['__contains__']}}
1799
+ """
1800
+ return {"parent": abstract_methods_of_class(self.parent_class),
1801
+ "element": abstract_methods_of_class(self.element_class)}
1802
+
1803
+ # Operations on the lattice of categories
1804
+ def is_subcategory(self, c):
1805
+ """
1806
+ Return ``True`` if there is a natural forgetful functor from ``self`` to `c`.
1807
+
1808
+ EXAMPLES::
1809
+
1810
+ sage: AbGrps = CommutativeAdditiveGroups()
1811
+ sage: Rings().is_subcategory(AbGrps)
1812
+ True
1813
+ sage: AbGrps.is_subcategory(Rings())
1814
+ False
1815
+
1816
+ The ``is_subcategory`` function takes into account the
1817
+ base.
1818
+
1819
+ ::
1820
+
1821
+ sage: M3 = VectorSpaces(FiniteField(3))
1822
+ sage: M9 = VectorSpaces(FiniteField(9, 'a')) # needs sage.rings.finite_rings
1823
+ sage: M3.is_subcategory(M9) # needs sage.rings.finite_rings
1824
+ False
1825
+
1826
+ Join categories are properly handled::
1827
+
1828
+ sage: CatJ = Category.join((CommutativeAdditiveGroups(), Semigroups()))
1829
+ sage: Rings().is_subcategory(CatJ)
1830
+ True
1831
+
1832
+ ::
1833
+
1834
+ sage: V3 = VectorSpaces(FiniteField(3))
1835
+ sage: POSet = PartiallyOrderedSets()
1836
+ sage: PoV3 = Category.join((V3, POSet))
1837
+ sage: A3 = AlgebrasWithBasis(FiniteField(3))
1838
+ sage: PoA3 = Category.join((A3, POSet))
1839
+ sage: PoA3.is_subcategory(PoV3)
1840
+ True
1841
+ sage: PoV3.is_subcategory(PoV3)
1842
+ True
1843
+ sage: PoV3.is_subcategory(PoA3)
1844
+ False
1845
+ """
1846
+ if c is self:
1847
+ return True
1848
+ subcat_hook = c._subcategory_hook_(self)
1849
+ if subcat_hook is Unknown:
1850
+ return c in self._set_of_super_categories
1851
+ return subcat_hook
1852
+
1853
+ def or_subcategory(self, category=None, join=False):
1854
+ """
1855
+ Return ``category`` or ``self`` if ``category`` is ``None``.
1856
+
1857
+ INPUT:
1858
+
1859
+ - ``category`` -- a sub category of ``self``, tuple/list thereof,
1860
+ or ``None``
1861
+ - ``join`` -- boolean (default: ``False``)
1862
+
1863
+ OUTPUT: a category
1864
+
1865
+ EXAMPLES::
1866
+
1867
+ sage: Monoids().or_subcategory(Groups())
1868
+ Category of groups
1869
+ sage: Monoids().or_subcategory(None)
1870
+ Category of monoids
1871
+
1872
+ If category is a list/tuple, then a join category is returned::
1873
+
1874
+ sage: Monoids().or_subcategory((CommutativeAdditiveMonoids(), Groups()))
1875
+ Join of Category of groups and Category of commutative additive monoids
1876
+
1877
+ If ``join`` is ``False``, an error if raised if category is not a
1878
+ subcategory of ``self``::
1879
+
1880
+ sage: Monoids().or_subcategory(EnumeratedSets())
1881
+ Traceback (most recent call last):
1882
+ ...
1883
+ ValueError: Subcategory of `Category of monoids` required;
1884
+ got `Category of enumerated sets`
1885
+
1886
+ Otherwise, the two categories are joined together::
1887
+
1888
+ sage: Monoids().or_subcategory(EnumeratedSets(), join=True)
1889
+ Category of enumerated monoids
1890
+ """
1891
+ if category is None:
1892
+ return self
1893
+ if isinstance(category, (tuple, list)):
1894
+ category = Category.join(category)
1895
+ assert isinstance(category, Category)
1896
+ if join:
1897
+ return Category.join([self, category])
1898
+ else:
1899
+ if not category.is_subcategory(self):
1900
+ raise ValueError("Subcategory of `{}` required; got `{}`".format(self, category))
1901
+ return category
1902
+
1903
+ def _is_subclass(self, c):
1904
+ """
1905
+ Same as is_subcategory, but c may also be the class of a
1906
+ category instead of a category.
1907
+
1908
+ EXAMPLES::
1909
+
1910
+ sage: Fields()._is_subclass(Rings)
1911
+ True
1912
+ sage: Algebras(QQ)._is_subclass(Modules)
1913
+ True
1914
+ sage: Algebras(QQ)._is_subclass(ModulesWithBasis)
1915
+ False
1916
+ """
1917
+ assert (isinstance(c, Category) or (issubclass(c.__class__, type) and issubclass(c, Category)))
1918
+ if isinstance(c, Category):
1919
+ return self.is_subcategory(c)
1920
+ return any(isinstance(cat, c) for cat in self._all_super_categories)
1921
+
1922
+ @cached_method
1923
+ def _meet_(self, other):
1924
+ """
1925
+ Return the largest common subcategory of ``self`` and ``other``.
1926
+
1927
+ EXAMPLES::
1928
+
1929
+ sage: Monoids()._meet_(Monoids())
1930
+ Category of monoids
1931
+ sage: Rings()._meet_(Rings())
1932
+ Category of rings
1933
+ sage: Rings()._meet_(Monoids())
1934
+ Category of monoids
1935
+ sage: Monoids()._meet_(Rings())
1936
+ Category of monoids
1937
+
1938
+ sage: VectorSpaces(QQ)._meet_(Modules(ZZ))
1939
+ Category of commutative additive groups
1940
+ sage: Algebras(ZZ)._meet_(Algebras(QQ))
1941
+ Category of rings
1942
+ sage: Groups()._meet_(Rings())
1943
+ Category of monoids
1944
+ sage: Algebras(QQ)._meet_(Category.join([Fields(), ModulesWithBasis(QQ)]))
1945
+ Join of Category of rings and Category of vector spaces over Rational Field
1946
+
1947
+ Note: abstractly, the category poset is a distributive
1948
+ lattice, so this is well defined; however, the subset of those
1949
+ categories actually implemented is not: we need to also
1950
+ include their join-categories.
1951
+
1952
+ For example, the category of rings is *not* the join of the
1953
+ category of abelian groups and that of semi groups, just a
1954
+ subcategory of their join, since rings further require
1955
+ distributivity.
1956
+
1957
+ For the meet computation, there may be several lowest common
1958
+ sub categories of ``self`` and ``other``, in which case, we need to
1959
+ take the join of them all.
1960
+
1961
+ FIXME:
1962
+
1963
+ - If A is a subcategory of B, A has *more* structure than B,
1964
+ but then *less* objects in there. We should choose an
1965
+ appropriate convention for A<B. Using subcategory calls
1966
+ for A<B, but the current meet and join call for A>B.
1967
+ """
1968
+ if self is other: # useful? fast pathway
1969
+ return self
1970
+ elif self.is_subcategory(other):
1971
+ return other
1972
+ elif other.is_subcategory(self):
1973
+ # Useful fast pathway; try:
1974
+ # %time L = EllipticCurve('960d1').prove_BSD()
1975
+ return self
1976
+ else:
1977
+ return Category.join(self._meet_(sup) for sup in other._super_categories)
1978
+
1979
+ @staticmethod
1980
+ def meet(categories):
1981
+ """
1982
+ Return the meet of a list of categories.
1983
+
1984
+ INPUT:
1985
+
1986
+ - ``categories`` -- a non empty list (or iterable) of categories
1987
+
1988
+ .. SEEALSO:: :meth:`__or__` for a shortcut
1989
+
1990
+ EXAMPLES::
1991
+
1992
+ sage: Category.meet([Algebras(ZZ), Algebras(QQ), Groups()])
1993
+ Category of monoids
1994
+
1995
+ That meet of an empty list should be a category which is a
1996
+ subcategory of all categories, which does not make practical sense::
1997
+
1998
+ sage: Category.meet([])
1999
+ Traceback (most recent call last):
2000
+ ...
2001
+ ValueError: The meet of an empty list of categories is not implemented
2002
+ """
2003
+ categories = tuple(categories)
2004
+ if not categories:
2005
+ raise ValueError("The meet of an empty list of categories is not implemented")
2006
+ result = categories[0]
2007
+ for category in categories[1:]:
2008
+ result = result._meet_(category)
2009
+ return result
2010
+
2011
+ @cached_method
2012
+ def axioms(self):
2013
+ """
2014
+ Return the axioms known to be satisfied by all the objects of ``self``.
2015
+
2016
+ Technically, this is the set of all the axioms ``A`` such that, if
2017
+ ``Cs`` is the category defining ``A``, then ``self`` is a subcategory
2018
+ of ``Cs().A()``. Any additional axiom ``A`` would yield a strict
2019
+ subcategory of ``self``, at the very least ``self & Cs().A()`` where
2020
+ ``Cs`` is the category defining ``A``.
2021
+
2022
+ EXAMPLES::
2023
+
2024
+ sage: Monoids().axioms()
2025
+ frozenset({'Associative', 'Unital'})
2026
+ sage: (EnumeratedSets().Infinite() & Sets().Facade()).axioms()
2027
+ frozenset({'Enumerated', 'Facade', 'Infinite'})
2028
+ """
2029
+ return frozenset(axiom
2030
+ for category in self._super_categories
2031
+ for axiom in category.axioms())
2032
+
2033
+ @cached_method
2034
+ def _with_axiom_as_tuple(self, axiom):
2035
+ """
2036
+ Return a tuple of categories whose join is ``self._with_axiom()``.
2037
+
2038
+ INPUT:
2039
+
2040
+ - ``axiom`` -- string, the name of an axiom
2041
+
2042
+ This is a lazy version of :meth:`_with_axiom` which is used to
2043
+ avoid recursion loops during join calculations.
2044
+
2045
+ .. NOTE:: The order in the result is irrelevant.
2046
+
2047
+ EXAMPLES::
2048
+
2049
+ sage: Sets()._with_axiom_as_tuple('Finite')
2050
+ (Category of finite sets,)
2051
+ sage: Magmas()._with_axiom_as_tuple('Finite')
2052
+ (Category of magmas, Category of finite sets)
2053
+ sage: Rings().Division()._with_axiom_as_tuple('Finite')
2054
+ (Category of division rings,
2055
+ Category of finite monoids,
2056
+ Category of commutative magmas,
2057
+ Category of finite additive groups)
2058
+ sage: HopfAlgebras(QQ)._with_axiom_as_tuple('FiniteDimensional')
2059
+ (Category of Hopf algebras over Rational Field,
2060
+ Category of finite dimensional vector spaces over Rational Field)
2061
+ """
2062
+ if axiom in self.axioms():
2063
+ return (self, )
2064
+ axiom_attribute = getattr(self.__class__, axiom, None)
2065
+ if axiom_attribute is None:
2066
+ # If the axiom is not defined for this category, ignore it
2067
+ # This uses the following invariant: the categories for
2068
+ # which a given axiom is defined form a lower set
2069
+ return (self,)
2070
+ if axiom in self.__class__.__base__.__dict__:
2071
+ # self implements this axiom
2072
+ from .category_with_axiom import CategoryWithAxiom
2073
+ if inspect.isclass(axiom_attribute) and issubclass(axiom_attribute, CategoryWithAxiom):
2074
+ return (axiom_attribute(self),)
2075
+ warn(("Expecting {}.{} to be a subclass of CategoryWithAxiom to"
2076
+ " implement a category with axiom; got {}; ignoring").format(
2077
+ self.__class__.__base__.__name__, axiom, axiom_attribute))
2078
+
2079
+ # self does not implement this axiom
2080
+ result = (self, ) + tuple(cat
2081
+ for category in self._super_categories
2082
+ for cat in category._with_axiom_as_tuple(axiom))
2083
+ hook = getattr(self, axiom + "_extra_super_categories", None)
2084
+ if hook is not None:
2085
+ assert inspect.ismethod(hook)
2086
+ result += tuple(hook())
2087
+ return _sort_uniq(result)
2088
+
2089
+ @cached_method
2090
+ def _with_axiom(self, axiom):
2091
+ """
2092
+ Return the subcategory of the objects of ``self`` satisfying
2093
+ the given ``axiom``.
2094
+
2095
+ Note that this is a private method thus should not be directly
2096
+ used, see below.
2097
+
2098
+ INPUT:
2099
+
2100
+ - ``axiom`` -- string, the name of an axiom
2101
+
2102
+ EXAMPLES::
2103
+
2104
+ sage: Sets()._with_axiom("Finite") # not idiomatic
2105
+ Category of finite sets
2106
+ sage: Sets().Finite() # recommended
2107
+ Category of finite sets
2108
+
2109
+ sage: type(Magmas().Finite().Commutative())
2110
+ <class 'sage.categories.category.JoinCategory_with_category'>
2111
+ sage: Magmas().Finite().Commutative().super_categories()
2112
+ [Category of commutative magmas, Category of finite sets]
2113
+ sage: C = Algebras(QQ).WithBasis().Commutative()
2114
+ sage: C is Algebras(QQ).Commutative().WithBasis()
2115
+ True
2116
+
2117
+ When ``axiom`` is not defined for ``self``, ``self`` is returned::
2118
+
2119
+ sage: Sets()._with_axiom("Associative")
2120
+ Category of sets
2121
+
2122
+ .. WARNING:: This may be changed in the future to raise an error.
2123
+ """
2124
+ return Category.join(self._with_axiom_as_tuple(axiom))
2125
+
2126
+ def _with_axioms(self, axioms):
2127
+ """
2128
+ Return the subcategory of the objects of ``self`` satisfying
2129
+ the given ``axioms``.
2130
+
2131
+ INPUT:
2132
+
2133
+ - ``axioms`` -- list of strings; the names of the axioms
2134
+
2135
+ EXAMPLES::
2136
+
2137
+ sage: Sets()._with_axioms(["Finite"])
2138
+ Category of finite sets
2139
+ sage: Sets()._with_axioms(["Infinite"])
2140
+ Category of infinite sets
2141
+ sage: FiniteSets()._with_axioms(["Finite"])
2142
+ Category of finite sets
2143
+
2144
+ Axioms that are not defined for the ``self`` are ignored::
2145
+
2146
+ sage: Sets()._with_axioms(["FooBar"])
2147
+ Category of sets
2148
+ sage: Magmas()._with_axioms(["FooBar", "Unital"])
2149
+ Category of unital magmas
2150
+
2151
+ Note that adding several axioms at once can do more than
2152
+ adding them one by one. This is because the availability of an
2153
+ axiom may depend on another axiom. For example, for
2154
+ semigroups, the ``Inverse`` axiom is meaningless unless there
2155
+ is a unit::
2156
+
2157
+ sage: Semigroups().Inverse()
2158
+ Traceback (most recent call last):
2159
+ ...
2160
+ AttributeError: 'Semigroups_with_category' object has no attribute 'Inverse'...
2161
+ sage: Semigroups()._with_axioms(["Inverse"])
2162
+ Category of semigroups
2163
+
2164
+ So one needs to first add the ``Unital`` axiom, and then the
2165
+ ``Inverse`` axiom::
2166
+
2167
+ sage: Semigroups().Unital().Inverse()
2168
+ Category of groups
2169
+
2170
+ or to specify all of them at once, in any order::
2171
+
2172
+ sage: Semigroups()._with_axioms(["Inverse", "Unital"])
2173
+ Category of groups
2174
+ sage: Semigroups()._with_axioms(["Unital", "Inverse"])
2175
+ Category of groups
2176
+
2177
+ sage: Magmas()._with_axioms(['Commutative', 'Associative', 'Unital','Inverse'])
2178
+ Category of commutative groups
2179
+ sage: Magmas()._with_axioms(['Inverse', 'Commutative', 'Associative', 'Unital'])
2180
+ Category of commutative groups
2181
+ """
2182
+ # We repeat adding axioms until they have all been
2183
+ # integrated or nothing happens
2184
+ axioms = frozenset(axioms)
2185
+ previous = None
2186
+ result = self
2187
+ while result is not previous:
2188
+ previous = result
2189
+ for axiom in axioms:
2190
+ result = result._with_axiom(axiom)
2191
+ axioms = axioms.difference(result.axioms())
2192
+ return result
2193
+
2194
+ @cached_method
2195
+ def _without_axiom(self, axiom):
2196
+ r"""
2197
+ Return the category with axiom ``axiom`` removed.
2198
+
2199
+ OUTPUT:
2200
+
2201
+ A category ``C`` which does not have axiom ``axiom``
2202
+ and such that either ``C`` is ``self``, or adding back all the
2203
+ axioms of ``self`` gives back ``self``.
2204
+
2205
+ .. WARNING:: This is not guaranteed to be robust.
2206
+
2207
+ EXAMPLES::
2208
+
2209
+ sage: Sets()._without_axiom("Facade")
2210
+ Category of sets
2211
+ sage: Sets().Facade()._without_axiom("Facade")
2212
+ Category of sets
2213
+ sage: Algebras(QQ)._without_axiom("Unital")
2214
+ Category of associative algebras over Rational Field
2215
+ sage: Groups()._without_axiom("Unital") # todo: not implemented
2216
+ Category of semigroups
2217
+ """
2218
+ if axiom not in self.axioms():
2219
+ return self
2220
+ else:
2221
+ raise ValueError("Cannot remove axiom {} from {}".format(axiom, self))
2222
+
2223
+ def _without_axioms(self, named=False) -> Self:
2224
+ r"""
2225
+ Return the category without the axioms that have been added
2226
+ to create it.
2227
+
2228
+ INPUT:
2229
+
2230
+ - ``named`` -- boolean (default: ``False``)
2231
+
2232
+ .. TODO:: Improve this explanation.
2233
+
2234
+ If ``named`` is ``True``, then this stops at the first
2235
+ category that has an explicit name of its own. See
2236
+ :meth:`.category_with_axiom.CategoryWithAxiom._without_axioms`
2237
+
2238
+ EXAMPLES::
2239
+
2240
+ sage: Sets()._without_axioms()
2241
+ Category of sets
2242
+ sage: Semigroups()._without_axioms()
2243
+ Category of magmas
2244
+ sage: Algebras(QQ).Commutative().WithBasis()._without_axioms()
2245
+ Category of magmatic algebras over Rational Field
2246
+ sage: Algebras(QQ).Commutative().WithBasis()._without_axioms(named=True)
2247
+ Category of algebras over Rational Field
2248
+ """
2249
+ return self
2250
+
2251
+ _flatten_categories = staticmethod(_flatten_categories) # a cythonised helper
2252
+
2253
+ @staticmethod
2254
+ def _sort(categories):
2255
+ """
2256
+ Return the categories after sorting them decreasingly according
2257
+ to their comparison key.
2258
+
2259
+ .. SEEALSO:: :meth:`_cmp_key`
2260
+
2261
+ INPUT:
2262
+
2263
+ - ``categories`` -- list (or iterable) of non-join categories
2264
+
2265
+ OUTPUT: a sorted tuple of categories, possibly with repeats
2266
+
2267
+ .. NOTE::
2268
+
2269
+ The auxiliary function ``_flatten_categories`` used in the test
2270
+ below expects a second argument, which is a type such that
2271
+ instances of that type will be replaced by its super
2272
+ categories. Usually, this type is :class:`JoinCategory`.
2273
+
2274
+ EXAMPLES::
2275
+
2276
+ sage: Category._sort([Sets(), Objects(), Coalgebras(QQ), Monoids(), Sets().Finite()])
2277
+ (Category of monoids,
2278
+ Category of coalgebras over Rational Field,
2279
+ Category of finite sets,
2280
+ Category of sets,
2281
+ Category of objects)
2282
+ sage: Category._sort([Sets().Finite(), Semigroups().Finite(), Sets().Facade(),Magmas().Commutative()])
2283
+ (Category of finite semigroups,
2284
+ Category of commutative magmas,
2285
+ Category of finite sets,
2286
+ Category of facade sets)
2287
+ sage: Category._sort(Category._flatten_categories([Sets().Finite(), Algebras(QQ).WithBasis(), Semigroups().Finite(),
2288
+ ....: Sets().Facade(), Algebras(QQ).Commutative(), Algebras(QQ).Graded().WithBasis()],
2289
+ ....: sage.categories.category.JoinCategory))
2290
+ (Category of algebras with basis over Rational Field,
2291
+ Category of algebras with basis over Rational Field,
2292
+ Category of graded algebras over Rational Field,
2293
+ Category of commutative algebras over Rational Field,
2294
+ Category of finite semigroups,
2295
+ Category of finite sets,
2296
+ Category of facade sets)
2297
+ """
2298
+ return tuple(sorted(categories, key=category_sort_key, reverse=True))
2299
+
2300
+ _sort_uniq = staticmethod(_sort_uniq) # a cythonised helper
2301
+
2302
+ def __and__(self, other):
2303
+ """
2304
+ Return the intersection of two categories.
2305
+
2306
+ This is just a shortcut for :meth:`join`.
2307
+
2308
+ EXAMPLES::
2309
+
2310
+ sage: Sets().Finite() & Rings().Commutative()
2311
+ Category of finite commutative rings
2312
+ sage: Monoids() & CommutativeAdditiveMonoids()
2313
+ Join of Category of monoids and Category of commutative additive monoids
2314
+ """
2315
+ return Category.join([self, other])
2316
+
2317
+ def __or__(self, other):
2318
+ """
2319
+ Return the smallest category containing the two categories.
2320
+
2321
+ This is just a shortcut for :meth:`meet`.
2322
+
2323
+ EXAMPLES::
2324
+
2325
+ sage: Algebras(QQ) | Groups()
2326
+ Category of monoids
2327
+ """
2328
+ return Category.meet([self, other])
2329
+
2330
+ _join_cache = _join_cache
2331
+
2332
+ @staticmethod
2333
+ def join(categories, as_list=False, ignore_axioms=(), axioms=()):
2334
+ """
2335
+ Return the join of the input categories in the lattice of categories.
2336
+
2337
+ At the level of objects and morphisms, this operation
2338
+ corresponds to intersection: the objects and morphisms of a
2339
+ join category are those that belong to all its super
2340
+ categories.
2341
+
2342
+ INPUT:
2343
+
2344
+ - ``categories`` -- list (or iterable) of categories
2345
+ - ``as_list`` -- boolean (default: ``False``);
2346
+ whether the result should be returned as a list
2347
+ - ``axioms`` -- tuple of strings; the names of some
2348
+ supplementary axioms
2349
+
2350
+ .. SEEALSO:: :meth:`__and__` for a shortcut
2351
+
2352
+ EXAMPLES::
2353
+
2354
+ sage: J = Category.join((Groups(), CommutativeAdditiveMonoids())); J
2355
+ Join of Category of groups and Category of commutative additive monoids
2356
+ sage: J.super_categories()
2357
+ [Category of groups, Category of commutative additive monoids]
2358
+ sage: J.all_super_categories(proper=True)
2359
+ [Category of groups, ..., Category of magmas,
2360
+ Category of commutative additive monoids, ..., Category of additive magmas,
2361
+ Category of sets, ...]
2362
+
2363
+ As a short hand, one can use::
2364
+
2365
+ sage: Groups() & CommutativeAdditiveMonoids()
2366
+ Join of Category of groups and Category of commutative additive monoids
2367
+
2368
+ This is a commutative and associative operation::
2369
+
2370
+ sage: Groups() & Posets()
2371
+ Join of Category of groups and Category of posets
2372
+ sage: Posets() & Groups()
2373
+ Join of Category of groups and Category of posets
2374
+
2375
+ sage: Groups() & (CommutativeAdditiveMonoids() & Posets())
2376
+ Join of Category of groups
2377
+ and Category of commutative additive monoids
2378
+ and Category of posets
2379
+ sage: (Groups() & CommutativeAdditiveMonoids()) & Posets()
2380
+ Join of Category of groups
2381
+ and Category of commutative additive monoids
2382
+ and Category of posets
2383
+
2384
+ The join of a single category is the category itself::
2385
+
2386
+ sage: Category.join([Monoids()])
2387
+ Category of monoids
2388
+
2389
+ Similarly, the join of several mutually comparable categories is
2390
+ the smallest one::
2391
+
2392
+ sage: Category.join((Sets(), Rings(), Monoids()))
2393
+ Category of rings
2394
+
2395
+ In particular, the unit is the top category :class:`Objects`::
2396
+
2397
+ sage: Groups() & Objects()
2398
+ Category of groups
2399
+
2400
+ If the optional parameter ``as_list`` is ``True``, this
2401
+ returns the super categories of the join as a list, without
2402
+ constructing the join category itself::
2403
+
2404
+ sage: Category.join((Groups(), CommutativeAdditiveMonoids()), as_list=True)
2405
+ [Category of groups, Category of commutative additive monoids]
2406
+ sage: Category.join((Sets(), Rings(), Monoids()), as_list=True)
2407
+ [Category of rings]
2408
+ sage: Category.join((Modules(ZZ), FiniteFields()), as_list=True)
2409
+ [Category of finite enumerated fields, Category of modules over Integer Ring]
2410
+ sage: Category.join([], as_list=True)
2411
+ []
2412
+ sage: Category.join([Groups()], as_list=True)
2413
+ [Category of groups]
2414
+ sage: Category.join([Groups() & Posets()], as_list=True)
2415
+ [Category of groups, Category of posets]
2416
+
2417
+ Support for axiom categories (TODO: put here meaningful examples)::
2418
+
2419
+ sage: Sets().Facade() & Sets().Infinite()
2420
+ Category of facade infinite sets
2421
+ sage: Magmas().Infinite() & Sets().Facade()
2422
+ Category of facade infinite magmas
2423
+
2424
+ sage: FiniteSets() & Monoids()
2425
+ Category of finite monoids
2426
+ sage: Rings().Commutative() & Sets().Finite()
2427
+ Category of finite commutative rings
2428
+
2429
+ Note that several of the above examples are actually join
2430
+ categories; they are just nicely displayed::
2431
+
2432
+ sage: AlgebrasWithBasis(QQ) & FiniteSets().Algebras(QQ)
2433
+ Join of Category of finite dimensional algebras with basis over Rational Field
2434
+ and Category of finite set algebras over Rational Field
2435
+
2436
+ sage: UniqueFactorizationDomains() & Algebras(QQ)
2437
+ Join of Category of unique factorization domains
2438
+ and Category of commutative algebras over Rational Field
2439
+
2440
+ TESTS::
2441
+
2442
+ sage: Magmas().Unital().Commutative().Finite() is Magmas().Finite().Commutative().Unital()
2443
+ True
2444
+ sage: from sage.categories.category_with_axiom import TestObjects
2445
+ sage: T = TestObjects()
2446
+ sage: TCF = T.Commutative().Facade(); TCF
2447
+ Category of facade commutative test objects
2448
+ sage: TCF is T.Facade().Commutative()
2449
+ True
2450
+ sage: TCF is (T.Facade() & T.Commutative())
2451
+ True
2452
+ sage: TCF.axioms()
2453
+ frozenset({'Commutative', 'Facade'})
2454
+ sage: type(TCF)
2455
+ <class 'sage.categories.category_with_axiom.TestObjects.Commutative.Facade_with_category'>
2456
+
2457
+ sage: TCF = T.Commutative().FiniteDimensional()
2458
+ sage: TCF is T.FiniteDimensional().Commutative()
2459
+ True
2460
+ sage: TCF is T.Commutative() & T.FiniteDimensional()
2461
+ True
2462
+ sage: TCF is T.FiniteDimensional() & T.Commutative()
2463
+ True
2464
+ sage: type(TCF)
2465
+ <class 'sage.categories.category_with_axiom.TestObjects.Commutative.FiniteDimensional_with_category'>
2466
+
2467
+ sage: TCU = T.Commutative().Unital()
2468
+ sage: TCU is T.Unital().Commutative()
2469
+ True
2470
+ sage: TCU is T.Commutative() & T.Unital()
2471
+ True
2472
+ sage: TCU is T.Unital() & T.Commutative()
2473
+ True
2474
+
2475
+ sage: TUCF = T.Unital().Commutative().FiniteDimensional(); TUCF
2476
+ Category of finite dimensional commutative unital test objects
2477
+ sage: type(TUCF)
2478
+ <class 'sage.categories.category_with_axiom.TestObjects.FiniteDimensional.Unital.Commutative_with_category'>
2479
+
2480
+ sage: TFFC = T.Facade().FiniteDimensional().Commutative(); TFFC
2481
+ Category of facade finite dimensional commutative test objects
2482
+ sage: type(TFFC)
2483
+ <class 'sage.categories.category.JoinCategory_with_category'>
2484
+ sage: TFFC.super_categories()
2485
+ [Category of facade commutative test objects,
2486
+ Category of finite dimensional commutative test objects]
2487
+ """
2488
+ # Get the list of categories and deal with some trivial cases
2489
+ categories = list(categories)
2490
+ if not categories:
2491
+ if as_list:
2492
+ return []
2493
+ else:
2494
+ # Since Objects() is the top category, it is the neutral element of join
2495
+ from .objects import Objects
2496
+ return Objects()
2497
+ elif len(categories) == 1:
2498
+ category = categories[0]
2499
+ if as_list:
2500
+ if isinstance(category, JoinCategory):
2501
+ return category.super_categories()
2502
+ else:
2503
+ return categories
2504
+ else:
2505
+ return category
2506
+
2507
+ # Get the cache key, and look into the cache
2508
+ # Ensure associativity and commutativity by flattening
2509
+ # TODO:
2510
+ # - Do we want to store the cache after or before the mangling of the categories?
2511
+ # - Caching with ignore_axioms?
2512
+ # JoinCategory's sorting, and removing duplicates
2513
+ cache_key = _sort_uniq(_flatten_categories(categories, JoinCategory))
2514
+ if not ignore_axioms:
2515
+ try:
2516
+ out = _join_cache[cache_key]
2517
+ if as_list:
2518
+ if isinstance(out, JoinCategory):
2519
+ return out._super_categories
2520
+ return [out]
2521
+ return out
2522
+ except KeyError:
2523
+ pass
2524
+
2525
+ # Handle axioms
2526
+ result = join_as_tuple(cache_key, axioms, ignore_axioms)
2527
+ if as_list:
2528
+ return list(result)
2529
+ if len(result) == 1:
2530
+ result = result[0]
2531
+ else:
2532
+ result = JoinCategory(result)
2533
+ if not ignore_axioms:
2534
+ _join_cache[cache_key] = result
2535
+ return result
2536
+
2537
+ def category(self):
2538
+ """
2539
+ Return the category of this category. So far, all categories
2540
+ are in the category of objects.
2541
+
2542
+ EXAMPLES::
2543
+
2544
+ sage: Sets().category()
2545
+ Category of objects
2546
+ sage: VectorSpaces(QQ).category()
2547
+ Category of objects
2548
+ """
2549
+ from .objects import Objects
2550
+ return Objects()
2551
+
2552
+ def example(self, *args, **keywords):
2553
+ """
2554
+ Return an object in this category. Most of the time, this is a parent.
2555
+
2556
+ This serves three purposes:
2557
+
2558
+ - Give a typical example to better explain what the category is all about.
2559
+ (and by the way prove that the category is non empty :-) )
2560
+ - Provide a minimal template for implementing other objects in this category
2561
+ - Provide an object on which to test generic code implemented by the category
2562
+
2563
+ For all those applications, the implementation of the object
2564
+ shall be kept to a strict minimum. The object is therefore not
2565
+ meant to be used for other applications; most of the time a
2566
+ full featured version is available elsewhere in Sage, and
2567
+ should be used instead.
2568
+
2569
+ Technical note: by default ``FooBar(...).example()`` is
2570
+ constructed by looking up
2571
+ ``sage.categories.examples.foo_bar.Example`` and calling it as
2572
+ ``Example()``. Extra positional or named parameters are also
2573
+ passed down. For a category over base ring, the base ring is
2574
+ further passed down as an optional argument.
2575
+
2576
+ Categories are welcome to override this default implementation.
2577
+
2578
+ EXAMPLES::
2579
+
2580
+ sage: Semigroups().example()
2581
+ An example of a semigroup: the left zero semigroup
2582
+
2583
+ sage: Monoids().Subquotients().example()
2584
+ NotImplemented
2585
+ """
2586
+ if '.' in self.__class__.__name__:
2587
+ # this magic should not apply to nested categories like Monoids.Subquotients
2588
+ return NotImplemented
2589
+ module_name = self.__module__.replace("sage.categories", "sage.categories.examples")
2590
+ import sys
2591
+ try:
2592
+ __import__(module_name)
2593
+ module = sys.modules[module_name]
2594
+ except ImportError:
2595
+ return NotImplemented
2596
+ try:
2597
+ cls = module.Example
2598
+ except AttributeError:
2599
+ return NotImplemented
2600
+ # Add the base ring as optional argument if this is a category over base ring
2601
+ if "base_ring" not in keywords:
2602
+ try:
2603
+ keywords["base_ring"] = self.base_ring()
2604
+ except AttributeError:
2605
+ pass
2606
+ return cls(*args, **keywords)
2607
+
2608
+ def __lean_init__(self):
2609
+ r"""
2610
+ Return the category as Lean mathlib input for a typeclass.
2611
+ """
2612
+ raise NotImplementedError
2613
+
2614
+ def _lean_init_(self):
2615
+ r"""
2616
+ Return the category as Lean mathlib input for a typeclass.
2617
+ """
2618
+ return self.__lean_init__()
2619
+
2620
+
2621
+ @cached_function
2622
+ def category_sample():
2623
+ r"""
2624
+ Return a sample of categories.
2625
+
2626
+ It is constructed by looking for all concrete category classes declared in
2627
+ ``sage.categories.all``, calling :meth:`Category.an_instance` on those and
2628
+ taking all their super categories.
2629
+
2630
+ EXAMPLES::
2631
+
2632
+ sage: from sage.categories.category import category_sample
2633
+ sage: sorted(category_sample(), key=str) # needs sage.groups
2634
+ [Category of Coxeter groups,
2635
+ Category of Dedekind domains,
2636
+ Category of G-sets for Symmetric group of order 8! as a permutation group,
2637
+ Category of Hecke modules over Rational Field,
2638
+ Category of Hopf algebras over Rational Field,
2639
+ Category of Hopf algebras with basis over Rational Field,
2640
+ Category of Jacobians over Rational Field,
2641
+ Category of Lie algebras over Rational Field,
2642
+ Category of Weyl groups,
2643
+ Category of abelian varieties over Rational Field,
2644
+ Category of additive magmas, ...,
2645
+ Category of fields, ...,
2646
+ Category of graded Hopf algebras with basis over Rational Field, ...,
2647
+ Category of modular abelian varieties over Rational Field, ...,
2648
+ Category of simplicial complexes, ...,
2649
+ Category of vector spaces over Rational Field, ...
2650
+ """
2651
+ import sage.categories.all
2652
+ abstract_classes_for_categories = [Category]
2653
+ return tuple(cls.an_instance()
2654
+ for cls in sage.categories.all.__dict__.values()
2655
+ if isinstance(cls, type) and issubclass(cls, Category) and cls not in abstract_classes_for_categories)
2656
+
2657
+
2658
+ def category_graph(categories=None):
2659
+ """
2660
+ Return the graph of the categories in Sage.
2661
+
2662
+ INPUT:
2663
+
2664
+ - ``categories`` -- list (or iterable) of categories
2665
+
2666
+ If ``categories`` is specified, then the graph contains the
2667
+ mentioned categories together with all their super
2668
+ categories. Otherwise the graph contains (an instance of) each
2669
+ category in :mod:`sage.categories.all` (e.g. ``Algebras(QQ)`` for
2670
+ algebras).
2671
+
2672
+ For readability, the names of the category are shortened.
2673
+
2674
+ .. TODO:: Further remove the base ring (see also :issue:`15801`).
2675
+
2676
+ EXAMPLES::
2677
+
2678
+ sage: G = sage.categories.category.category_graph(categories=[Groups()]) # needs sage.graphs
2679
+ sage: G.vertices(sort=True) # needs sage.graphs
2680
+ ['groups', 'inverse unital magmas', 'magmas', 'monoids', 'objects',
2681
+ 'semigroups', 'sets', 'sets with partial maps', 'unital magmas']
2682
+ sage: G.plot() # needs sage.graphs sage.plot
2683
+ Graphics object consisting of 20 graphics primitives
2684
+
2685
+ sage: sage.categories.category.category_graph().plot() # needs sage.graphs sage.groups sage.plot
2686
+ Graphics object consisting of ... graphics primitives
2687
+ """
2688
+ from sage import graphs
2689
+ if categories is None:
2690
+ categories = category_sample()
2691
+ # Include all the super categories
2692
+ # Get rid of join categories
2693
+ categories = {cat for category in categories
2694
+ for cat in category.all_super_categories(proper=isinstance(category, JoinCategory))}
2695
+ g = graphs.digraph.DiGraph()
2696
+ for cat in categories:
2697
+ g.add_vertex(cat._repr_object_names())
2698
+ for source in categories:
2699
+ # Don't use super_categories() since it might contain join categories
2700
+ for target in source._super_categories:
2701
+ g.add_edge([source._repr_object_names(), target._repr_object_names()])
2702
+ return g
2703
+
2704
+
2705
+ ##############################################################################
2706
+ # Parametrized categories whose parent/element class depend only on
2707
+ # the super categories
2708
+ ##############################################################################
2709
+
2710
+ class CategoryWithParameters(Category):
2711
+ """
2712
+ A parametrized category whose parent/element classes depend only on
2713
+ its super categories.
2714
+
2715
+ Many categories in Sage are parametrized, like ``C = Algebras(K)``
2716
+ which takes a base ring as parameter. In many cases, however, the
2717
+ operations provided by ``C`` in the parent class and element class
2718
+ depend only on the super categories of ``C``. For example, the
2719
+ vector space operations are provided if and only if ``K`` is a
2720
+ field, since ``VectorSpaces(K)`` is a super category of ``C`` only
2721
+ in that case. In such cases, and as an optimization (see :issue:`11935`),
2722
+ we want to use the same parent and element class for all fields.
2723
+ This is the purpose of this abstract class.
2724
+
2725
+ Currently, :class:`~sage.categories.category.JoinCategory`,
2726
+ :class:`~sage.categories.category_types.Category_over_base` and
2727
+ :class:`~sage.categories.bimodules.Bimodules` inherit from this
2728
+ class.
2729
+
2730
+ EXAMPLES::
2731
+
2732
+ sage: C1 = Algebras(GF(5))
2733
+ sage: C2 = Algebras(GF(3))
2734
+ sage: C3 = Algebras(ZZ)
2735
+ sage: from sage.categories.category import CategoryWithParameters
2736
+ sage: isinstance(C1, CategoryWithParameters)
2737
+ True
2738
+ sage: C1.parent_class is C2.parent_class
2739
+ True
2740
+ sage: C1.parent_class is C3.parent_class
2741
+ False
2742
+
2743
+ .. automethod:: Category._make_named_class
2744
+ """
2745
+
2746
+ def _make_named_class(self, name, method_provider, cache=False, **options):
2747
+ """
2748
+ Return the parent/element/... class of ``self``.
2749
+
2750
+ INPUT:
2751
+
2752
+ - ``name`` -- string; the name of the class as an attribute
2753
+ of ``self``
2754
+ - ``method_provider`` -- string; the name of an attribute of
2755
+ ``self`` that provides methods for the new class (in
2756
+ addition to what comes from the super categories)
2757
+ - ``**options`` -- other named options to pass down to
2758
+ :meth:`Category._make_named_class`
2759
+
2760
+ ASSUMPTION:
2761
+
2762
+ It is assumed that this method is only called from a lazy
2763
+ attribute whose name coincides with the given ``name``.
2764
+ Currently, this means :meth:`Category.subcategory_class`,
2765
+ :meth:`Category.parent_class` or :meth:`element_class`.
2766
+
2767
+ Subclasses need to implement :meth:`_make_named_class_key`.
2768
+
2769
+ OUTPUT:
2770
+
2771
+ A dynamic class that has the corresponding named classes of
2772
+ the super categories of ``self`` as bases and contains the
2773
+ methods provided by ``getattr(self, method_provider)``.
2774
+
2775
+ .. NOTE::
2776
+
2777
+ This method overrides :meth:`Category._make_named_class`
2778
+ so that the returned class *only* depends on the
2779
+ corresponding named classes of the super categories and on
2780
+ the provided methods. This allows for sharing the named
2781
+ classes across closely related categories providing the
2782
+ same code to their parents, elements and so on.
2783
+
2784
+ EXAMPLES:
2785
+
2786
+ The categories of bimodules over the fields ``CC`` or ``RR``
2787
+ provide the same methods to their parents and elements::
2788
+
2789
+ sage: Bimodules(ZZ,RR).parent_class is Bimodules(ZZ,RDF).parent_class # indirect doctest
2790
+ True
2791
+ sage: Bimodules(CC,ZZ).element_class is Bimodules(RR,ZZ).element_class # needs sage.rings.real_mpfr
2792
+ True
2793
+
2794
+ On the other hand, modules over a field have more methods than
2795
+ modules over a ring::
2796
+
2797
+ sage: Modules(GF(3)).parent_class is Modules(ZZ).parent_class
2798
+ False
2799
+ sage: Modules(GF(3)).element_class is Modules(ZZ).element_class
2800
+ False
2801
+
2802
+ For a more subtle example, one could possibly share the classes for
2803
+ ``GF(3)`` and ``GF(2^3, 'x')``, but this is not currently the case::
2804
+
2805
+ sage: Modules(GF(3)).parent_class is Modules(GF(2^3,'x')).parent_class # needs sage.rings.finite_rings
2806
+ False
2807
+
2808
+ This is because those two fields do not have the exact same category::
2809
+
2810
+ sage: GF(3).category()
2811
+ Join of Category of finite enumerated fields
2812
+ and Category of subquotients of monoids
2813
+ and Category of quotients of semigroups
2814
+ sage: GF(2^3,'x').category() # needs sage.rings.finite_rings
2815
+ Category of finite enumerated fields
2816
+
2817
+ Similarly for ``QQ`` and ``RR``::
2818
+
2819
+ sage: QQ.category()
2820
+ Join of Category of number fields
2821
+ and Category of quotient fields
2822
+ and Category of metric spaces
2823
+ sage: RR.category()
2824
+ Join of Category of fields and Category of infinite sets
2825
+ and Category of complete metric spaces
2826
+ sage: Modules(QQ).parent_class is Modules(RR).parent_class
2827
+ False
2828
+
2829
+ Some other cases where one could potentially share those classes::
2830
+
2831
+ sage: MF = Modules(GF(3), dispatch=False)
2832
+ sage: MF.parent_class is Modules(ZZ).parent_class
2833
+ False
2834
+ sage: MF.element_class is Modules(ZZ).element_class
2835
+ False
2836
+
2837
+ TESTS::
2838
+
2839
+ sage: PC = Algebras(QQ).parent_class; PC # indirect doctest
2840
+ <class 'sage.categories.algebras.Algebras.parent_class'>
2841
+ sage: type(PC)
2842
+ <class 'sage.structure.dynamic_class.DynamicMetaclass'>
2843
+ sage: PC.__bases__
2844
+ (<class 'sage.categories.rings.Rings.parent_class'>,
2845
+ <class 'sage.categories.associative_algebras.AssociativeAlgebras.parent_class'>,
2846
+ <class 'sage.categories.unital_algebras.UnitalAlgebras.parent_class'>)
2847
+ sage: loads(dumps(PC)) is PC
2848
+ True
2849
+ """
2850
+ cls = self.__class__
2851
+ if isinstance(cls, DynamicMetaclass):
2852
+ cls = cls.__base__
2853
+ key = (cls, name, self._make_named_class_key(name))
2854
+ try:
2855
+ return self._make_named_class_cache[key]
2856
+ except KeyError:
2857
+ pass
2858
+ result = Category._make_named_class(self, name, method_provider,
2859
+ cache=cache, **options)
2860
+ if key[2] != self._make_named_class_key(name):
2861
+ # the object in the parameter may have had its category refined, which might modify the key
2862
+ # throw result away and recompute
2863
+ return self._make_named_class(name, method_provider, cache=cache, **options)
2864
+ self._make_named_class_cache[key] = result
2865
+ return result
2866
+
2867
+ @abstract_method
2868
+ def _make_named_class_key(self, name):
2869
+ r"""
2870
+ Return what the element/parent/... class depend on.
2871
+
2872
+ This method starts as an optimization to allow different related
2873
+ categories to share the Python types, see :issue:`11935`.
2874
+ However, because of the guarantees stated in :meth:`Category._test_category_graph`,
2875
+ the following rules must be followed.
2876
+
2877
+ - If two categories have different lists of supercategories, they must return
2878
+ different keys::
2879
+
2880
+ sage: Zmod(5) in Fields()
2881
+ True
2882
+ sage: Algebras(Zmod(5)).all_super_categories()
2883
+ [..., Category of vector spaces over Ring of integers modulo 5, ...]
2884
+ sage: Zmod(6) in Fields()
2885
+ False
2886
+ sage: Algebras(Zmod(6)).all_super_categories() # of course don't have category of vector spaces
2887
+ [..., Category of modules over Ring of integers modulo 6, ...]
2888
+ sage: # therefore:
2889
+ sage: Algebras(Zmod(5))._make_named_class_key("parent_class") != Algebras(Zmod(6))._make_named_class_key("parent_class")
2890
+ True
2891
+ sage: Algebras(Zmod(5)).parent_class != Algebras(Zmod(6)).parent_class
2892
+ True
2893
+
2894
+ - If category ``A`` is a supercategory of category ``B``,
2895
+ and category ``B`` uses the optimization, then so must ``A``.
2896
+
2897
+ For example, ``Modules(ZZ)`` is a supercategory of ``Algebras(ZZ)``,
2898
+ and ``Algebras(ZZ)`` implements the optimization::
2899
+
2900
+ sage: from sage.categories.category import CategoryWithParameters
2901
+ sage: isinstance(Algebras(ZZ), CategoryWithParameters)
2902
+ True
2903
+ sage: Algebras(ZZ).parent_class is Algebras(ZZ.category()).parent_class
2904
+ True
2905
+ sage: Modules(ZZ) in Algebras(ZZ).all_super_categories()
2906
+ True
2907
+
2908
+ This forces ``Modules(ZZ)`` to also implement the optimization::
2909
+
2910
+ sage: Modules(ZZ).parent_class is Modules(ZZ.category()).parent_class
2911
+ True
2912
+
2913
+ As a complication, computing the exact category might require some potentially
2914
+ expensive test. See :meth:`Category._test_category_graph` for more details.
2915
+
2916
+ INPUT:
2917
+
2918
+ - ``name`` -- string; the name of the class as an attribute
2919
+ of ``self``
2920
+
2921
+ .. SEEALSO::
2922
+
2923
+ - :meth:`_make_named_class`
2924
+
2925
+ The following can be read for typical implementations of this method.
2926
+
2927
+ - :meth:`sage.categories.category_types.Category_over_base._make_named_class_key`
2928
+ - :meth:`sage.categories.bimodules.Bimodules._make_named_class_key`
2929
+ - :meth:`JoinCategory._make_named_class_key`
2930
+
2931
+ EXAMPLES:
2932
+
2933
+ The parent class of an algebra depends only on the category of the base ring::
2934
+
2935
+ sage: Algebras(ZZ)._make_named_class_key("parent_class")
2936
+ Join of Category of Dedekind domains
2937
+ and Category of euclidean domains
2938
+ and Category of noetherian rings
2939
+ and Category of infinite enumerated sets
2940
+ and Category of metric spaces
2941
+
2942
+ The morphism class of a bimodule depends only on the category
2943
+ of the left and right base rings::
2944
+
2945
+ sage: Bimodules(QQ, ZZ)._make_named_class_key("morphism_class")
2946
+ (Join of Category of number fields
2947
+ and Category of quotient fields
2948
+ and Category of metric spaces,
2949
+ Join of Category of Dedekind domains
2950
+ and Category of euclidean domains
2951
+ and Category of noetherian rings
2952
+ and Category of infinite enumerated sets
2953
+ and Category of metric spaces)
2954
+
2955
+ The element class of a join category depends only on the
2956
+ element class of its super categories::
2957
+
2958
+ sage: Category.join([Groups(), Posets()])._make_named_class_key("element_class")
2959
+ (<class 'sage.categories.groups.Groups.element_class'>,
2960
+ <class 'sage.categories.posets.Posets.element_class'>)
2961
+ """
2962
+
2963
+ _make_named_class_cache = {}
2964
+
2965
+ _cmp_key = _cmp_key_named
2966
+
2967
+ def _subcategory_hook_(self, C):
2968
+ """
2969
+ A quick but partial test whether ``C`` is a subcategory of ``self``.
2970
+
2971
+ INPUT:
2972
+
2973
+ - ``C`` -- a category
2974
+
2975
+ OUTPUT:
2976
+
2977
+ ``False``, if ``C.parent_class`` is not a subclass of
2978
+ ``self.parent_class``, and :obj:`~sage.misc.unknown.Unknown`
2979
+ otherwise.
2980
+
2981
+ EXAMPLES::
2982
+
2983
+ sage: Bimodules(QQ,QQ)._subcategory_hook_(Modules(QQ))
2984
+ Unknown
2985
+ sage: Bimodules(QQ,QQ)._subcategory_hook_(Rings())
2986
+ False
2987
+ """
2988
+ if not issubclass(C.parent_class, self.parent_class):
2989
+ return False
2990
+ return Unknown
2991
+
2992
+
2993
+ #############################################################
2994
+ # Join of several categories
2995
+ #############################################################
2996
+
2997
+ class JoinCategory(CategoryWithParameters):
2998
+ """
2999
+ A class for joins of several categories. Do not use directly;
3000
+ see Category.join instead.
3001
+
3002
+ EXAMPLES::
3003
+
3004
+ sage: from sage.categories.category import JoinCategory
3005
+ sage: J = JoinCategory((Groups(), CommutativeAdditiveMonoids())); J
3006
+ Join of Category of groups and Category of commutative additive monoids
3007
+ sage: J.super_categories()
3008
+ [Category of groups, Category of commutative additive monoids]
3009
+ sage: J.all_super_categories(proper=True)
3010
+ [Category of groups, ..., Category of magmas,
3011
+ Category of commutative additive monoids, ..., Category of additive magmas,
3012
+ Category of sets, Category of sets with partial maps, Category of objects]
3013
+
3014
+ By :issue:`11935`, join categories and categories over base rings
3015
+ inherit from :class:`CategoryWithParameters`. This allows for
3016
+ sharing parent and element classes between similar categories. For
3017
+ example, since group algebras belong to a join category and since
3018
+ the underlying implementation is the same for all finite fields,
3019
+ we have::
3020
+
3021
+ sage: # needs sage.combinat sage.groups sage.rings.finite_rings
3022
+ sage: G = SymmetricGroup(10)
3023
+ sage: A3 = G.algebra(GF(3))
3024
+ sage: A5 = G.algebra(GF(5))
3025
+ sage: type(A3.category())
3026
+ <class 'sage.categories.category.JoinCategory_with_category'>
3027
+ sage: type(A3) is type(A5)
3028
+ True
3029
+
3030
+ .. automethod:: Category._repr_object_names
3031
+ .. automethod:: Category._repr_
3032
+ .. automethod:: Category._without_axioms
3033
+ """
3034
+
3035
+ def __init__(self, super_categories, **kwds):
3036
+ """
3037
+ Initialize this JoinCategory.
3038
+
3039
+ INPUT:
3040
+
3041
+ - ``super_categories`` -- categories to join; this category will
3042
+ consist of objects and morphisms that lie in all of these
3043
+ categories
3044
+
3045
+ - ``name`` -- ignored
3046
+
3047
+ TESTS::
3048
+
3049
+ sage: from sage.categories.category import JoinCategory
3050
+ sage: C = JoinCategory((Groups(), CommutativeAdditiveMonoids())); C
3051
+ Join of Category of groups and Category of commutative additive monoids
3052
+ sage: TestSuite(C).run()
3053
+ """
3054
+ assert len(super_categories) >= 2
3055
+ assert all(not isinstance(category, JoinCategory) for category in super_categories)
3056
+ # Use __super_categories to not overwrite the lazy attribute Category._super_categories
3057
+ # Maybe this would not be needed if the flattening/sorting is does consistently?
3058
+ self.__super_categories = list(super_categories)
3059
+ Category.__init__(self)
3060
+
3061
+ def _make_named_class_key(self, name):
3062
+ r"""
3063
+ Return what the element/parent/... classes depend on.
3064
+
3065
+ Since :issue:`11935`, the element/parent classes of a join
3066
+ category over base only depend on the element/parent class of
3067
+ its super categories.
3068
+
3069
+ .. SEEALSO::
3070
+
3071
+ - :meth:`CategoryWithParameters`
3072
+ - :meth:`CategoryWithParameters._make_named_class_key`
3073
+
3074
+ EXAMPLES::
3075
+
3076
+ sage: Modules(ZZ)._make_named_class_key('element_class')
3077
+ Join of Category of Dedekind domains
3078
+ and Category of euclidean domains
3079
+ and Category of noetherian rings
3080
+ and Category of infinite enumerated sets
3081
+ and Category of metric spaces
3082
+ sage: Modules(QQ)._make_named_class_key('parent_class')
3083
+ Join of Category of number fields
3084
+ and Category of quotient fields
3085
+ and Category of metric spaces
3086
+ sage: Schemes(Spec(ZZ))._make_named_class_key('parent_class')
3087
+ Category of schemes
3088
+ sage: ModularAbelianVarieties(QQ)._make_named_class_key('parent_class')
3089
+ Join of Category of number fields
3090
+ and Category of quotient fields
3091
+ and Category of metric spaces
3092
+ """
3093
+ return tuple(getattr(cat, name) for cat in self._super_categories)
3094
+
3095
+ def super_categories(self):
3096
+ """
3097
+ Return the immediate super categories, as per :meth:`Category.super_categories`.
3098
+
3099
+ EXAMPLES::
3100
+
3101
+ sage: from sage.categories.category import JoinCategory
3102
+ sage: JoinCategory((Semigroups(), FiniteEnumeratedSets())).super_categories()
3103
+ [Category of semigroups, Category of finite enumerated sets]
3104
+ """
3105
+ return self.__super_categories
3106
+
3107
+ def additional_structure(self):
3108
+ r"""
3109
+ Return ``None``.
3110
+
3111
+ Indeed, a join category defines no additional structure.
3112
+
3113
+ .. SEEALSO:: :meth:`Category.additional_structure`
3114
+
3115
+ EXAMPLES::
3116
+
3117
+ sage: Modules(ZZ).additional_structure()
3118
+ """
3119
+ return None
3120
+
3121
+ def _subcategory_hook_(self, category):
3122
+ """
3123
+ Return whether ``category`` is a subcategory of this join category.
3124
+
3125
+ INPUT:
3126
+
3127
+ - ``category`` -- a category
3128
+
3129
+ .. NOTE::
3130
+
3131
+ ``category`` is a sub-category of this join category if
3132
+ and only if it is a sub-category of all super categories
3133
+ of this join category.
3134
+
3135
+ EXAMPLES::
3136
+
3137
+ sage: base_cat = Category.join([NumberFields(), QuotientFields().Metric()])
3138
+ sage: cat = Category.join([Rings(), VectorSpaces(base_cat)])
3139
+ sage: QQ['x'].category().is_subcategory(cat) # indirect doctest
3140
+ True
3141
+ """
3142
+ return all(category.is_subcategory(X) for X in self._super_categories)
3143
+
3144
+ def is_subcategory(self, C):
3145
+ """
3146
+ Check whether this join category is subcategory of another
3147
+ category ``C``.
3148
+
3149
+ EXAMPLES::
3150
+
3151
+ sage: Category.join([Rings(),Modules(QQ)]).is_subcategory(Category.join([Rngs(),Bimodules(QQ,QQ)]))
3152
+ True
3153
+ """
3154
+ if C is self:
3155
+ return True
3156
+ hook = C._subcategory_hook_(self)
3157
+ if hook is Unknown:
3158
+ return any(X.is_subcategory(C) for X in self._super_categories)
3159
+ return hook
3160
+
3161
+ def _with_axiom(self, axiom):
3162
+ """
3163
+ Return the category obtained by adding an axiom to ``self``.
3164
+
3165
+ As mentioned in :meth:`Category._with_axiom`, this method should not be used directly
3166
+ except in internal code.
3167
+
3168
+ .. NOTE::
3169
+
3170
+ This is just an optimization of
3171
+ :meth:`Category._with_axiom`; it's not necessarily
3172
+ actually useful.
3173
+
3174
+ EXAMPLES::
3175
+
3176
+ sage: C = Category.join([Monoids(), Posets()])
3177
+ sage: C._with_axioms(["Finite"]) # not idiomatic
3178
+ Join of Category of finite monoids and Category of finite posets
3179
+ sage: C.Finite() # recommended
3180
+ Join of Category of finite monoids and Category of finite posets
3181
+
3182
+ TESTS:
3183
+
3184
+ Check that axiom categories for a join are reconstructed from
3185
+ the base categories::
3186
+
3187
+ sage: C = Category.join([Monoids(), Magmas().Commutative()])
3188
+ sage: C._with_axioms(["Finite"])
3189
+ Category of finite commutative monoids
3190
+
3191
+ This helps guaranteeing commutativity of taking axioms::
3192
+
3193
+ sage: Monoids().Finite().Commutative() is Monoids().Commutative().Finite()
3194
+ True
3195
+ """
3196
+ return Category.join([cat._with_axiom(axiom) for cat in self._super_categories])
3197
+
3198
+ @cached_method
3199
+ def _without_axiom(self, axiom):
3200
+ """
3201
+ Return this category with axiom ``axiom`` removed.
3202
+
3203
+ OUTPUT:
3204
+
3205
+ A category ``C`` which does not have axiom ``axiom`` and such
3206
+ that either ``C`` is ``self``, or adding back all the
3207
+ axioms of ``self`` gives back ``self``.
3208
+
3209
+ .. SEEALSO:: :meth:`Category._without_axiom`
3210
+
3211
+ .. WARNING:: This is not guaranteed to be robust.
3212
+
3213
+ EXAMPLES::
3214
+
3215
+ sage: C = Posets() & FiniteEnumeratedSets() & Sets().Facade(); C
3216
+ Category of facade finite enumerated posets
3217
+ sage: C._without_axiom("Facade")
3218
+ Category of finite enumerated posets
3219
+
3220
+ sage: C = Sets().Finite().Facade()
3221
+ sage: type(C)
3222
+ <class 'sage.categories.category.JoinCategory_with_category'>
3223
+ sage: C._without_axiom("Facade")
3224
+ Category of finite sets
3225
+ """
3226
+ result = Category.join(C._without_axiom(axiom) for C in self.super_categories())
3227
+ assert axiom not in result.axioms()
3228
+ assert result._with_axioms(self.axioms()) is self
3229
+ return result
3230
+
3231
+ def _without_axioms(self, named=False):
3232
+ """
3233
+ When adjoining axioms to a category, one often gets a join
3234
+ category; this method tries to recover the original
3235
+ category from this join category.
3236
+
3237
+ INPUT:
3238
+
3239
+ - ``named`` -- boolean (default: ``False``)
3240
+
3241
+ See :meth:`Category._without_axioms` for the description
3242
+ of the ``named`` parameter.
3243
+
3244
+ EXAMPLES::
3245
+
3246
+ sage: C = Category.join([Monoids(), Posets()]).Finite()
3247
+ sage: C._repr_(as_join=True)
3248
+ 'Join of Category of finite monoids and Category of finite posets'
3249
+ sage: C._without_axioms()
3250
+ Traceback (most recent call last):
3251
+ ...
3252
+ ValueError: This join category isn't built by adding axioms to a single category
3253
+ sage: C = Monoids().Infinite()
3254
+ sage: C._repr_(as_join=True)
3255
+ 'Join of Category of monoids and Category of infinite sets'
3256
+ sage: C._without_axioms()
3257
+ Category of magmas
3258
+ sage: C._without_axioms(named=True)
3259
+ Category of monoids
3260
+
3261
+ TESTS:
3262
+
3263
+ ``C`` is in fact a join category::
3264
+
3265
+ sage: from sage.categories.category import JoinCategory
3266
+ sage: isinstance(C, JoinCategory)
3267
+ True
3268
+ """
3269
+ axioms = self.axioms()
3270
+ for category in self._super_categories:
3271
+ if category._with_axioms(axioms) is self:
3272
+ return category._without_axioms(named=named)
3273
+ raise ValueError("This join category isn't built by adding axioms"
3274
+ " to a single category")
3275
+
3276
+ def _cmp_key(self):
3277
+ """
3278
+ Return a comparison key for ``self``.
3279
+
3280
+ See :meth:`Category._cmp_key` for the specifications.
3281
+
3282
+ EXAMPLES:
3283
+
3284
+ This raises an error since ``_cmp_key`` should not be called
3285
+ on join categories::
3286
+
3287
+ sage: (Magmas() & CommutativeAdditiveSemigroups())._cmp_key()
3288
+ Traceback (most recent call last):
3289
+ ...
3290
+ ValueError: _cmp_key should not be called on join categories
3291
+ """
3292
+ raise ValueError("_cmp_key should not be called on join categories")
3293
+
3294
+ def _repr_object_names(self):
3295
+ """
3296
+ Return the name of the objects of this category.
3297
+
3298
+ .. SEEALSO:: :meth:`Category._repr_object_names`, :meth:`_repr_`, :meth:`._without_axioms`
3299
+
3300
+ EXAMPLES::
3301
+
3302
+ sage: Groups().Finite().Commutative()._repr_(as_join=True)
3303
+ 'Join of Category of finite groups and Category of commutative groups'
3304
+ sage: Groups().Finite().Commutative()._repr_object_names()
3305
+ 'finite commutative groups'
3306
+
3307
+ This uses :meth:`._without_axioms` which may fail if this
3308
+ category is not obtained by adjoining axioms to some super
3309
+ categories::
3310
+
3311
+ sage: Category.join((Groups(), CommutativeAdditiveMonoids()))._repr_object_names()
3312
+ Traceback (most recent call last):
3313
+ ...
3314
+ ValueError: This join category isn't built by adding axioms to a single category
3315
+ """
3316
+ from sage.categories.category_with_axiom import CategoryWithAxiom
3317
+ return CategoryWithAxiom._repr_object_names_static(self._without_axioms(named=True), self.axioms())
3318
+
3319
+ def _repr_(self, as_join=False):
3320
+ """
3321
+ Print representation.
3322
+
3323
+ INPUT:
3324
+
3325
+ - ``as_join`` -- boolean (default: ``False``)
3326
+
3327
+ EXAMPLES::
3328
+
3329
+ sage: Category.join((Groups(), CommutativeAdditiveMonoids())) #indirect doctest
3330
+ Join of Category of groups and Category of commutative additive monoids
3331
+
3332
+ By default, when a join category is built from category by
3333
+ adjoining axioms, a nice name is printed out::
3334
+
3335
+ sage: Groups().Facade().Finite()
3336
+ Category of facade finite groups
3337
+
3338
+ But this is in fact really a join category::
3339
+
3340
+ sage: Groups().Facade().Finite()._repr_(as_join = True)
3341
+ 'Join of Category of finite groups and Category of facade sets'
3342
+
3343
+ The rationale is to make it more readable, and hide the
3344
+ technical details of how this category is constructed
3345
+ internally, especially since this construction is likely to
3346
+ change over time when new axiom categories are implemented.
3347
+
3348
+ This join category may possibly be obtained by adding axioms
3349
+ to different categories; so the result is not guaranteed to be
3350
+ unique; when this is not the case the first found is used.
3351
+
3352
+ .. SEEALSO:: :meth:`Category._repr_`, :meth:`_repr_object_names`
3353
+
3354
+ TESTS::
3355
+
3356
+ sage: Category.join((Sets().Facade(), Groups()))
3357
+ Category of facade groups
3358
+ """
3359
+ if not as_join:
3360
+ try:
3361
+ return super()._repr_()
3362
+ except ValueError:
3363
+ pass
3364
+ return "Join of " + " and ".join(str(cat) for cat in self._super_categories)
3365
+
3366
+ def __lean_init__(self):
3367
+ r"""
3368
+ Return the category as Lean mathlib input for a typeclass.
3369
+
3370
+ EXAMPLES::
3371
+
3372
+ sage: QQ.category()
3373
+ Join of Category of number fields and Category of quotient fields and Category of metric spaces
3374
+ sage: QQ.category().__lean_init__()
3375
+ Traceback (most recent call last):
3376
+ ...
3377
+ NotImplementedError
3378
+ """
3379
+ return " ".join(cat._lean_init_() for cat in self._super_categories)