Skip to content
This repository was archived by the owner on Jan 30, 2023. It is now read-only.

Commit 2f2d09b

Browse files
committed
16340: infrastructure for modelling full subcategories
1 parent 15658bd commit 2f2d09b

18 files changed

+539
-0
lines changed

src/sage/categories/additive_magmas.py

+17
Original file line numberDiff line numberDiff line change
@@ -551,6 +551,23 @@ def extra_super_categories(self):
551551

552552
class AdditiveUnital(CategoryWithAxiom):
553553

554+
def is_structure_category(self):
555+
r"""
556+
Return whether ``self`` is a structure category.
557+
558+
.. SEEALSO:: :meth:`Category.is_structure_category`
559+
560+
The category of unital additive magmas define the zero as
561+
new structure, and this zero shall be preserved by
562+
morphisms.
563+
564+
EXAMPLES::
565+
566+
sage: AdditiveMagmas().AdditiveUnital().is_structure_category()
567+
True
568+
"""
569+
return True
570+
554571
class SubcategoryMethods:
555572

556573
@cached_method

src/sage/categories/bialgebras.py

+19
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,25 @@ def super_categories(self):
3838
R = self.base_ring()
3939
return [Algebras(R), Coalgebras(R)]
4040

41+
def is_structure_category(self):
42+
r"""
43+
Return whether ``self`` is a structure category.
44+
45+
.. SEEALSO:: :meth:`Category.is_structure_category`
46+
47+
The category of bialgebras defines no new structure: a
48+
morphism of coalgebras and of algebras between two bialgebras
49+
is a bialgebra morphism.
50+
51+
.. TODO:: This category should be a :class:`CategoryWithAxiom`
52+
53+
EXAMPLES::
54+
55+
sage: Bialgebras(QQ).is_structure_category()
56+
False
57+
"""
58+
return False
59+
4160
class ParentMethods:
4261
pass
4362

src/sage/categories/bimodules.py

+19
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,25 @@ def super_categories(self):
152152
S = self.right_base_ring()
153153
return [LeftModules(R), RightModules(S)]
154154

155+
def is_structure_category(self):
156+
r"""
157+
Return whether ``self`` is a structure category.
158+
159+
.. SEEALSO:: :meth:`Category.is_structure_category`
160+
161+
The category of bimodules defines no new structure: a left and
162+
right module-morphism between two bimodules is a bimodule
163+
morphism.
164+
165+
.. TODO:: Should this category be a :class:`CategoryWithAxiom`?
166+
167+
EXAMPLES::
168+
169+
sage: Bimodules(QQ, ZZ).is_structure_category()
170+
False
171+
"""
172+
return False
173+
155174
class ParentMethods:
156175
pass
157176

src/sage/categories/category.py

+246
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,10 @@ def is_abelian(self):
778778
"""
779779
raise NotImplementedError("is_abelian")
780780

781+
##########################################################################
782+
# Methods related to the category hierarchy
783+
##########################################################################
784+
781785
def category_graph(self):
782786
r"""
783787
Returns the graph of all super categories of this category
@@ -1013,6 +1017,228 @@ def _super_categories_for_classes(self):
10131017
self._all_super_categories
10141018
return self._super_categories_for_classes
10151019

1020+
##########################################################################
1021+
# Methods handling of full subcategories
1022+
##########################################################################
1023+
1024+
def is_structure_category(self):
1025+
"""
1026+
Return whether ``self`` is a structure category.
1027+
1028+
In Sage, a *structure* category `C` is a category that defines
1029+
new structure or operations. Equivalently, `C` is *not* a full
1030+
subcategory of the join of its super categories: the morphisms
1031+
need to preserve more structure, and thus the homsets are
1032+
smaller.
1033+
1034+
By default, a category is a structure category, while
1035+
:ref:`category with axiom <category-primer-axioms>` or a
1036+
:ref:`functorial construction category
1037+
<category-primer-functorial-constructions>` is not.
1038+
1039+
EXAMPLES:
1040+
1041+
Here are some typical structure categories, with the
1042+
additional structure they define::
1043+
1044+
sage: Sets().is_structure_category()
1045+
True
1046+
sage: Magmas().is_structure_category() # `*`
1047+
True
1048+
sage: AdditiveMagmas().is_structure_category() # `+`
1049+
True
1050+
sage: LeftModules(ZZ).is_structure_category() # left multiplication by scalar
1051+
True
1052+
sage: Coalgebras(QQ).is_structure_category() # coproduct
1053+
True
1054+
sage: CoxeterGroups().is_structure_category() # distinguished generators
1055+
True
1056+
sage: Crystals().is_structure_category() # crystal operators
1057+
True
1058+
1059+
On the other hand, the category of semigroups is not a
1060+
structure category, since its operation `+` is already defined
1061+
by the category of magmas::
1062+
1063+
sage: Semigroups().is_structure_category()
1064+
False
1065+
1066+
Most :ref:`categories with axiom <category-primer-axioms>` and
1067+
most :ref:`functorial construction categories
1068+
<category-primer-functorial-constructions>` don't define new
1069+
structure::
1070+
1071+
sage: Sets().Finite().is_structure_category()
1072+
False
1073+
sage: Rings().Commutative().is_structure_category()
1074+
False
1075+
sage: Modules(QQ).FiniteDimensional().is_structure_category()
1076+
False
1077+
sage: Sets().CartesianProducts().is_structure_category()
1078+
False
1079+
sage: Sets().Quotients().is_structure_category()
1080+
False
1081+
sage: Modules(QQ).TensorProducts().is_structure_category()
1082+
False
1083+
sage: Algebras(QQ).Graded().is_structure_category()
1084+
False
1085+
1086+
Exceptions include the category of unital magmas or the
1087+
category of additive magmas which define a unit which is
1088+
preserved by morphisms::
1089+
1090+
sage: Magmas().Unital().is_structure_category()
1091+
True
1092+
sage: AdditiveMagmas().AdditiveUnital().is_structure_category()
1093+
True
1094+
1095+
or the category of graded modules which defines a grading
1096+
which is preserved by morphisms::
1097+
1098+
sage: Modules(ZZ).Graded().is_structure_category()
1099+
True
1100+
1101+
.. NOTE::
1102+
1103+
There are a couple categories that add some structure,
1104+
where the structure can be useful to manipulate morphisms
1105+
but where, in most use cases, we don't want the morphisms
1106+
to necessarily preserve it. For example, in the context
1107+
of finite dimensional vector spaces, having a
1108+
distinguished basis allows for representing morphisms by
1109+
matrices; yet considering only morphisms that preserve
1110+
that distinguished basis would be boring.
1111+
1112+
In such cases, we might want to eventually have two
1113+
categories, one where the additional structure is
1114+
preseved, and one where it's not necessarily preserved
1115+
(we would need to find an idiom for this).
1116+
1117+
At this point, a choice is to be made each time, according
1118+
to the main use cases. Some of those choices are yet to be
1119+
settled. For example, should by default:
1120+
1121+
- an euclidean domain morphism preserve euclidean
1122+
division?::
1123+
1124+
sage: EuclideanDomains().is_structure_category()
1125+
True
1126+
1127+
- an enumerated set morphism preserve the distinguished
1128+
enumeration?::
1129+
1130+
sage: EnumeratedSets().is_structure_category()
1131+
False
1132+
1133+
- a module with basis morphism preserve the distinguished
1134+
basis?::
1135+
1136+
sage: Modules(QQ).WithBasis().is_structure_category()
1137+
False
1138+
1139+
.. SEEALSO::
1140+
1141+
This method together with the methods overloading it
1142+
provide the basic data to determine, for a given category,
1143+
the super categories that define some structure (see
1144+
:meth:`super_structure_categories`), and to test whether a
1145+
category is a full subcategory of some other category (see
1146+
:meth:`is_full_subcategory`).
1147+
1148+
The support for modeling full subcategories has been
1149+
introduced in :trac:`16340`.
1150+
"""
1151+
return True
1152+
1153+
@cached_method
1154+
def super_structure_categories(self):
1155+
r"""
1156+
Return the super structure categories of ``self``.
1157+
1158+
OUTPUT: a frozen set
1159+
1160+
This method is used in :meth:`is_full_subcategory` for
1161+
deciding whether a category is a full subcategory of some
1162+
other category, and for documentation purposes. It is computed
1163+
recursively from the result of :meth:`is_structure_category`
1164+
on the super categories of ``self``.
1165+
1166+
EXAMPLES::
1167+
1168+
sage: Objects().super_structure_categories()
1169+
frozenset([])
1170+
1171+
sage: def structure_categories(C):
1172+
....: return Category._sort(C.super_structure_categories())
1173+
1174+
sage: structure_categories(Sets())
1175+
(Category of sets, Category of sets with partial maps)
1176+
sage: structure_categories(Magmas())
1177+
(Category of magmas, Category of sets, Category of sets with partial maps)
1178+
1179+
In the following example, we only list the smallest structure
1180+
categories to get a more readable output::
1181+
1182+
sage: def structure_categories(C):
1183+
....: return Category._sort_uniq(C.super_structure_categories())
1184+
1185+
sage: structure_categories(Magmas())
1186+
(Category of magmas,)
1187+
sage: structure_categories(Rings())
1188+
(Category of unital magmas, Category of additive unital additive magmas)
1189+
sage: structure_categories(Fields())
1190+
(Category of euclidean domains,)
1191+
sage: structure_categories(Algebras(QQ))
1192+
(Category of unital magmas,
1193+
Category of right modules over Rational Field,
1194+
Category of left modules over Rational Field)
1195+
sage: structure_categories(HopfAlgebras(QQ).Graded().WithBasis().Connected())
1196+
(Category of hopf algebras over Rational Field,
1197+
Category of graded modules over Rational Field)
1198+
"""
1199+
result = { D for C in self.super_categories() for D in C.super_structure_categories() }
1200+
if self.is_structure_category():
1201+
result.add(self)
1202+
return frozenset(result)
1203+
1204+
def is_full_subcategory(self, other):
1205+
"""
1206+
Return whether ``self`` is a full subcategory of ``other``.
1207+
1208+
This is computed by testing if ``self`` is a subcategory of
1209+
``other``, and checking whether they have the same structure,
1210+
as determined by :meth:`super_structure_categories` from the
1211+
result of :meth:`is_structure_category` on the super
1212+
categories.
1213+
1214+
EXAMPLES::
1215+
1216+
sage: Magmas().Associative().is_full_subcategory(Magmas())
1217+
True
1218+
sage: Magmas().Unital().is_full_subcategory(Magmas())
1219+
False
1220+
sage: Rings().is_full_subcategory(Magmas().Unital() & AdditiveMagmas().AdditiveUnital())
1221+
True
1222+
1223+
.. TODO::
1224+
1225+
Those are consequences of :class:`EuclideanDomains`
1226+
currently being a structure category. Is this what we
1227+
want?::
1228+
1229+
sage: EuclideanDomains().is_full_subcategory(Rings())
1230+
False
1231+
sage: Fields().is_full_subcategory(Rings())
1232+
False
1233+
"""
1234+
return self.is_subcategory(other) and \
1235+
len(self.super_structure_categories()) == \
1236+
len(other.super_structure_categories())
1237+
1238+
##########################################################################
1239+
# Test methods
1240+
##########################################################################
1241+
10161242
def _test_category_graph(self, **options):
10171243
"""
10181244
Check that the category graph matches with Python's method resolution order
@@ -1094,6 +1320,11 @@ def _test_category(self, **options):
10941320

10951321
_cmp_key = _cmp_key
10961322

1323+
1324+
##########################################################################
1325+
# Construction of the associated abstract classes for parents, elements, ...
1326+
##########################################################################
1327+
10971328
def _make_named_class(self, name, method_provider, cache=False, picklable=True):
10981329
"""
10991330
Construction of the parent/element/... class of ``self``.
@@ -2750,6 +2981,21 @@ def super_categories(self):
27502981
"""
27512982
return self.__super_categories
27522983

2984+
def is_structure_category(self):
2985+
r"""
2986+
Return whether ``self`` is a structure category.
2987+
2988+
.. SEEALSO:: :meth:`Category.is_structure_category`
2989+
2990+
A join category defines no new structure.
2991+
2992+
EXAMPLES::
2993+
2994+
sage: Modules(ZZ).is_structure_category()
2995+
False
2996+
"""
2997+
return False
2998+
27532999
def _subcategory_hook_(self, category):
27543000
"""
27553001
Returns whether ``category`` is a subcategory of this join category

src/sage/categories/category_with_axiom.py

+23
Original file line numberDiff line numberDiff line change
@@ -2190,6 +2190,29 @@ def super_categories(self):
21902190
ignore_axioms = ((base_category, axiom),),
21912191
as_list = True)
21922192

2193+
def is_structure_category(self):
2194+
r"""
2195+
Return whether ``self`` is a structure category.
2196+
2197+
.. SEEALSO:: :meth:`Category.is_structure_category`.
2198+
2199+
EXAMPLES::
2200+
2201+
By default a category with axiom does not define new
2202+
structure::
2203+
2204+
sage: Sets().Finite().is_structure_category()
2205+
False
2206+
sage: Monoids().is_structure_category()
2207+
False
2208+
2209+
TESTS::
2210+
2211+
sage: Sets().Finite().is_structure_category.__module__
2212+
'sage.categories.category_with_axiom'
2213+
"""
2214+
return False
2215+
21932216
@staticmethod
21942217
def _repr_object_names_static(category, axioms):
21952218
r"""

0 commit comments

Comments
 (0)