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