This design pattern is largely inspired from Axiom and its
followers (Aldor, Fricas, MuPAD, …). It differs from those by:

blending in the Magma inspired concept of Parent/Element

being built on top of (and not into) the standard Python object
oriented and class hierarchy mechanism. This did not require
changing the language, and could in principle be implemented in
any language supporting the creation of new classes dynamically.

The general philosophy is that Building mathematical information
into the system yields more expressive, more conceptual and, at
the end, easier to maintain and faster code (within a programming
realm; this would not necessarily apply to specialized libraries
like gmp!).

Categories in Sage provide a library of interrelated bookshelves, with
each bookshelf containing algorithms, tests, documentation, or some
mathematical facts about the objects of a given category (e.g. groups).

Categories in Sage provide a large hierarchy of abstract classes for
mathematical objects. To keep it maintainable, the inheritance
information between the classes is not hardcoded but instead
reconstructed dynamically from duplication free semantic information.

What makes binary powering work in the above examples? In both cases,
we have a set endowed with a multiplicative binary operation which
is associative and which has a unit element. Such a set is called a
monoid, and binary powering (to a non-negative power) works generally
for any monoid.

Sage knows about monoids:

sage: Monoids()Category of monoids

and sure enough, binary powering is defined there:

sage: m._pow_int.__module__'sage.categories.monoids'

That’s our bookshelf! And it’s used in many places:

sage: GL(2,ZZ)inMonoids()Truesage: NNinMonoids()True

For a less trivial bookshelf we can consider euclidean rings: once we
know how to do euclidean division in some set \(R\), we can compute
gcd’s in \(R\) generically using the Euclidean algorithm.

We are in fact very lucky: abstract algebra provides us right away
with a large and robust set of bookshelves which is the result of
centuries of work of mathematicians to identify the important
concepts. This includes for example:

sage: Sets()Category of setssage: Groups()Category of groupssage: Rings()Category of ringssage: Fields()Category of fieldssage: HopfAlgebras(QQ)Category of hopf algebras over Rational Field

Each of the above is called a category. It typically specifies what
are the operations on the elements, as well as the axioms satisfied by
those operations. For example the category of groups specifies that a
group is a set endowed with a binary operation (the multiplication)
which is associative and admits a unit and inverses.

Each set in Sage knows which bookshelf of generic algorithms it can
use, that is to which category it belongs:

A parent is a Python instance modelling a set of mathematical
elements together with its additional (algebraic) structure.

Examples include the ring of integers, the group \(S_3\), the set of
prime numbers, the set of linear maps between two given vector
spaces, and a given finite semigroup.

These sets are often equipped with additional structure: the set
of all integers forms a ring. The main way of encoding this
information is specifying which categories a parent belongs to.

It is completely possible to have different Python instances
modelling the same set of elements. For example, one might want
to consider the ring of integers, or the poset of integers under
their standard order, or the poset of integers under divisibility,
or the semiring of integers under the operations of maximum and
addition. Each of these would be a different instance, belonging
to different categories.

For a given model, there should be a unique instance in Sage
representing that parent:

sage: IntegerRing()isIntegerRing()True

Element

An element is a Python instance modelling a mathematical element
of a set.

Examples of element include \(5\) in the integer ring, \(x^3 - x\) in
the polynomial ring in \(x\) over the rationals, \(4 + O(3^3)\) in the
3-adics, the transposition \((1 2)\) in \(S_3\), and the identity
morphism in the set of linear maps from \(\QQ^3\) to \(\QQ^3\).

Every element in Sage has a parent. The standard idiom in Sage
for creating elements is to create their parent, and then provide
enough data to define the element:

sage: R=PolynomialRing(ZZ,name='x')sage: R([1,2,3])3*x^2 + 2*x + 1

One can also create elements using various methods on the parent
and arithmetic of elements:

sage: x=R.gen()sage: 1+2*x+3*x^23*x^2 + 2*x + 1

Unlike parents, elements in Sage are not necessarily unique:

sage: ZZ(5040)isZZ(5040)False

Many parents model algebraic structures, and their elements
support arithmetic operations. One often further wants to do
arithmetic by combining elements from different parents: adding
together integers and rationals for example. Sage supports this
feature using coercion (see sage.structure.coerce for more
details).

It is possible for a parent to also have simultaneously the
structure of an element. Consider for example the monoid of all
finite groups, endowed with the Cartesian product operation.
Then, every finite group (which is a parent) is also an element of
this monoid. This is not yet implemented, and the design details
are not yet fixed but experiments are underway in this direction.

Examples of categories include the category of finite semigroups,
the category of all (Python) objects, the category of
\(\ZZ\)-algebras, and the category of Cartesian products of
\(\ZZ\)-algebras:

sage: FiniteSemigroups()Category of finite semigroupssage: Objects()Category of objectssage: Algebras(ZZ)Category of algebras over Integer Ringsage: Algebras(ZZ).CartesianProducts()Category of Cartesian products of algebras over Integer Ring

Mind the ‘s’ in the names of the categories above;
GroupAlgebra and GroupAlgebras are distinct things.

Every parent belongs to a collection of categories. Moreover,
categories are interrelated by the super categories
relation. For example, the category of rings is a super category
of the category of fields, because every field is also a ring.

A category serves two roles:

to provide a model for the mathematical concept of a category
and the associated structures: homsets, morphisms, functorial
constructions, axioms.

to organize and promote generic code, naming conventions,
documentation, and tests across similar mathematical structures.

CategoryObject

Objects of a mathematical category are not necessarily parents.
Parent has a superclass that provides a means of modeling such.

For example, the category of schemes does not have a faithful
forgetful functor to the category of sets, so it does not make
sense to talk about schemes as parents.

Morphisms, Homsets

As category theorists will expect, Morphisms and Homsets will
play an ever more important role, as support for them will
improve.

Much of the mathematical information in Sage is encoded as relations
between elements and their parents, parents and their categories, and
categories and their super categories:

Sage uses the classical design paradigm of Object Oriented Programming
(OOP). Its fundamental principle is that any object that a program is
to manipulate should be modelled by an instance of a class. The
class implements:

a data structure: which describes how the object is stored,

methods: which describe the operations on the object.

The instance itself contains the data for the given object, according
to the specified data structure.

Hence, all the objects mentioned above should be instances of some
classes. For example, an integer in Sage is an instance of the class
Integer (and it knows about it!):

Factoring integers, expressions, or polynomials are distinct tasks,
with completely different algorithms. Yet, from a user (or caller)
point of view, all those objects can be manipulated alike. This
illustrates the OOP concepts of polymorphism, data abstraction,
and encapsulation.

Let us be curious, and see where some methods are defined. This can be
done by introspection:

sage: i._mul_??# not tested

For plain Python methods, one can also just ask in which module they
are implemented:

We see that integers and polynomials have each their own
multiplication method: the multiplication algorithms are indeed
unrelated and deeply tied to their respective datastructures. On the
other hand, as we have seen above, they share the same powering method
because the set \(\ZZ\) of integers, and the set \(\QQ[x]\) of
polynomials are both semigroups. Namely, the class for integers and
the class for polynomials both derive from an abstract class for
semigroup elements, which factors out the generic methods like
_pow_. This illustrates the use of hierarchy of classes to share
common code between classes having common behaviour.

OOP design is all about isolating the objects that one wants to model
together with their operations, and designing an appropriate hierarchy
of classes for organizing the code. As we have seen above, the design
of the class hierarchy is easy since it can be modelled upon the
hierarchy of categories (bookshelves). Here is for example a piece of
the hierarchy of classes for an element of a group of permutations:

On the top, we see concrete classes that describe the data structure
for matrices and provide the operations that are tied to this data
structure. Then follow abstract classes that are attached to the
hierarchy of categories and provide generic algorithms.

This is a progress upon systems like Axiom or MuPAD where a parent
is modelled by the class of its elements; this oversimplification
leads to confusion between methods on parents and elements, and
makes parents special; in particular it prevents potentially
interesting constructions like “groups of groups”.

As we have just seen, when we manipulate groups, we actually
manipulate several kinds of objects:

groups

group elements

morphisms between groups

and even the category of groups itself!

Thus, on the group bookshelf, we want to put generic code for each of
the above. We therefore need three, parallel hierarchies of abstract
classes:

Group, Monoid, Semigroup, Magma, …

GroupElement, MonoidElement, SemigroupElement, MagmaElement, …

GroupMorphism, SemigroupElement, SemigroupMorphism, MagmaMorphism, …

(and in fact many more as we will see).

We could implement the above hierarchies as usual:

class Group(Monoid): # generic methods that apply to all groupsclass GroupElement(MonoidElement): # generic methods that apply to all group elementsclass GroupMorphism(MonoidMorphism): # generic methods that apply to all group morphisms

And indeed that’s how it was done in Sage before 2009, and there are
still many traces of this. The drawback of this approach is
duplication: the fact that a group is a monoid is repeated three times
above!

Instead, Sage now uses the following syntax, where the Groups
bookshelf is structured into units with nested classes:

With this syntax, the information that a group is a monoid is
specified only once, in the Category.super_categories()
method. And indeed, when the category of inverse unital magmas was
introduced, there was a single point of truth to update in order to
reflect the fact that a group is an inverse unital magma:

The price to pay (there is no free lunch) is that some magic is
required to construct the actual hierarchy of classes for parents,
elements, and morphisms. Namely, Groups.ElementMethods should be
seen as just a bag of methods, and the actual class
Groups().element_class is constructed from it by adding the
appropriate super classes according to
Groups().super_categories():

Another advantage of building the hierarchy of classes dynamically is
that, for parametrized categories, the hierarchy may depend on the
parameters. For example an algebra over \(\QQ\) is a \(\QQ\)-vector space,
but an algebra over \(\ZZ\) is not (it is just a \(\ZZ\)-module)!

Note

At this point this whole infrastructure may feel like
overdesigning, right? We felt like this too! But we will see later
that, once one gets used to it, this approach scales very
naturally.

From a computer science point of view, this infrastructure
implements, on top of standard multiple inheritance, a dynamic
composition mechanism of mixin classes (Wikipedia article Mixin),
governed by mathematical properties.

For implementation details on how the hierarchy of classes for
parents and elements is constructed, see Category.

We have seen above that, for example, the category of sets is a super
category of the category of groups. This models the fact that a group
can be unambiguously considered as a set by forgetting its group
operation. In object-oriented parlance, we want the relation “a group
is a set”, so that groups can directly inherit code implemented on
sets.

Formally, a category Cs() is a super category of a category
Ds() if Sage considers any object of Ds() to be an object of
Cs(), up to an implicit application of a canonical functor from
Ds() to Cs(). This functor is normally an inclusion of
categories or a forgetful functor. Reciprocally, Ds() is said to
be a subcategory of Cs().

Warning

This terminology deviates from the usual mathematical definition
of subcategory and is subject to change. Indeed, the forgetful
functor from the category of groups to the category of sets is not
an inclusion of categories, as it is not injective: a given set
may admit more than one group structure. See trac ticket #16183 for
more details. The name supercategory is also used with a
different meaning in certain areas of mathematics.

Well, more precisely, that’s how things should be, but there is
still some work to do in this direction. For example, the inverse
operation is not specified above. Also, we are still missing a
good programmatic syntax to specify the input and output types of
the methods. Finally, in many cases the implementer must provide
at least one of two methods, each having a default implementation
using the other one (e.g. listing or iterating for a finite
enumerated set); there is currently no good programmatic way to
specify this.

Another feature that parents and elements receive from categories is
generic tests; their purpose is to check (at least to some extent)
that the parent satisfies the required mathematical properties (is my
semigroup indeed associative?) and is implemented according to the
specifications (does the method an_element indeed return an
element of the parent?):

We can recover instantly the actual values of x, y, z, that is,
a counterexample to the associativity of our broken semigroup, using post
mortem introspection with the Python debugger pdb (this does not
work yet in the notebook):

Categories provide a natural hierarchy of bookshelves to organize
not only code, but also specifications and testing tools.

Everything about, say, algebras with a distinguished basis is
gathered in AlgebrasWithBasis or its super categories.
This includes properties and algorithms for elements, parents,
morphisms, but also, as we will see, for constructions like
Cartesian products or quotients.

The mathematical relations between elements, parents, and categories
translate dynamically into a traditional hierarchy of classes.

This design enforces robustness and consistency, which is
particularly welcome given that Python is an interpreted language
without static type checking.

In this section, we study an existing parent in detail; a good followup is to
go through the sage.categories.tutorial or the thematic tutorial on
coercion and categories (“How to implement new algebraic structures in Sage”)
to learn how to implement a new one!

We consider the example of finite semigroup provided by the category:

sage: S=FiniteSemigroups().example();SAn example of a finite semigroup: the left regular band generated by ('a', 'b', 'c', 'd')sage: S?# not tested

Where do all the operations on S and its elements come from?

sage: x=S('a')

_repr_ is a technical method which comes with the data structure
(ElementWrapper); since it’s implemented in Cython, we need
to use Sage’s introspection tools to recover where it’s implemented:

__mul__ is a generic method provided by the Magmas
category (a magma is a set with an inner law \(*\), not necessarily
associative). If the two arguments are in the same parent, it will
call the method _mul_, and otherwise let the coercionmodel try to discover how to do the
multiplication:

sage: x.__mul__??# not tested

Since it is a speed critical method, it is implemented in Cython
in a separate file:

sage: x._mul_.__module__'sage.categories.coercion_methods'

_mul_ is a default implementation, also provided by the
Magmas category, that delegates the work to the method
product of the parent (following the advice: if you do not know
what to do, ask your parent); it’s also a speed critical method:

cayley_graph is a generic method on the parent, provided by the
FiniteSemigroups category:

sage: S.cayley_graph.__module__'sage.categories.semigroups'

multiplication_table is a generic method on the parent, provided
by the Magmas category (it does not require associativity):

sage: S.multiplication_table.__module__'sage.categories.magmas'

Consider now the implementation of the semigroup:

sage: S??# not tested

This implementation specifies a data structure for the parents and the
elements, and makes a promise: the implemented parent is a finite
semigroup. Then it fulfills the promise by implementing the basic
operation product. It also implements the optional method
semigroup_generators. In exchange, \(S\) and its elements receive
generic implementations of all the other operations. \(S\) may override
any of those by more efficient ones. It may typically implement the
element method is_idempotent to always return True.

A (not yet complete) list of mandatory and optional methods to be
implemented can be found by introspection with:

product does not appear in the list because a default implementation
is provided in term of the method _mul_ on elements. Of course, at
least one of them should be implemented. On the other hand, a default
implementation for __contains__ is provided by Parent.

Some parent constructors (not enough!) allow to specify the desired
category for the parent. This can typically be used to specify
additional properties of the parent that we know to hold a priori. For
example, permutation groups are by default in the category of finite
permutation groups (no surprise):

This feature can even be used, typically in experimental code, to add
more structure to existing parents, and in particular to add methods
for the parents or the elements, without touching the code base:

In this section, we explore more advanced features of categories.
Along the way, we illustrate that a large hierarchy of categories is
desirable to model complicated mathematics, and that scaling to
support such a large hierarchy is the driving motivation for the
design of the category infrastructure.

Sage has support for a certain number of so-called covariant
functorial constructions which can be used to construct new parents
from existing ones while carrying over as much as possible of their
algebraic structure. This includes:

In which category should this new parent be? Since \(A\) and \(B\) are
vector spaces, the result is, as a vector space, the direct sum
\(A \oplus B \oplus B\), hence the notation. Also, since both \(A\) and \(B\)
are monoids, \(A \times B \times B\) is naturally endowed with a monoid
structure for pointwise multiplication:

The pointwise product can be implemented generically for all magmas
(i.e. sets endowed with a multiplicative operation) that are
constructed as Cartesian products. It’s thus implemented in the
Magmas category:

The support for nested classes in Python is relatively
recent. Their intensive use for the category infrastructure did
reveal some glitches in their implementation, in particular around
class naming and introspection. Sage currently works around the
more annoying ones but some remain visible. See
e.g. sage.misc.nested_class_test.

This reveals the parallel hierarchy of categories for Cartesian
products of semigroups magmas, … We are thus glad that Sage uses
its knowledge that a monoid is a semigroup to automatically deduce
that a Cartesian product of monoids is a Cartesian product of
semigroups, and build the hierarchy of classes for parents and
elements accordingly.

In general, the Cartesian product of \(A\) and \(B\) can potentially be an
algebra, a coalgebra, a differential module, and be finite
dimensional, or graded, or …. This can only be decided at runtime,
by introspection into the properties of \(A\) and \(B\); furthermore, the
number of possible combinations (e.g. finite dimensional differential
algebra) grows exponentially with the number of properties.

In fact, the category of groups can be defined by stating that a
group is a magma, that is a set endowed with an internal binary
multiplication, which satisfies the above axioms. Accordingly, we can
construct the category of groups from the category of magmas:

sage: Magmas().Associative().Unital().Inverse()Category of groups

In general, we can construct new categories in Sage by specifying the
axioms that are satisfied by the operations of the super
categories. For example, starting from the category of magmas, we can
construct all the following categories just by specifying the axioms
satisfied by the multiplication:

Here, Associative, Unital, Commutative are axioms. In
general, any category Cs in Sage can declare a new axiom
A. Then, the category with axiomCs.A() models the
subcategory of the objects of Cs satisfying the axiom
A. Similarly, for any subcategory Ds of Cs, Ds.A()
models the subcategory of the objects of Ds satisfying the axiom
A. In most cases, it’s a full subcategory (see
Wikipedia article Subcategory).

For example, the category of sets defines the Finite axiom, and
this axiom is available in the subcategory of groups:

The meaning of each axiom is described in the documentation of the
corresponding method, which can be obtained as usual by
instrospection:

sage: C=Groups()sage: C.Finite?# not tested

The purpose of categories with axioms is no different from other
categories: to provide bookshelves of code, documentation,
mathematical knowledge, tests, for their objects. The extra feature is
that, when intersecting categories, axioms are automatically combined
together:

For a more advanced example, Sage knows that a ring is a set \(C\)
endowed with a multiplication which distributes over addition, such
that \((C, +)\) is a commutative additive group and \((C, *)\) is a monoid:

When an axiom specifies the properties of some operations in Sage,
the notations for those operations are tied to this axiom. For
example, as we have seen above, we need two distinct axioms for
associativity: the axiom “AdditiveAssociative” is about the
properties of the addition \(+\), whereas the axiom “Associative” is
about the properties of the multiplication \(*\).

We are touching here an inherent limitation of the current
infrastructure. There is indeed no support for providing generic
code that is independent of the notations. In particular, the
category hierarchy about additive structures (additive monoids,
additive groups, …) is completely duplicated by that for
multiplicative structures (monoids, groups, …).

As far as we know, none of the existing computer algebra systems
has a good solution for this problem. The difficulty is that this
is not only about a single notation but a bunch of operators and
methods: +,-,zero,summation,sum,... in one case, *,/,one,product,prod,factor,... in the other. Sharing something
between the two hierarchies of categories would only be useful if
one could write generic code that applies in both cases; for that
one needs to somehow automatically substitute the right operations
in the right spots in the code. That’s kind of what we are doing
manually between
e.g. AdditiveMagmas.ParentMethods.addition_table() and
Magmas.ParentMethods.multiplication_table(), but doing this
systematically is a different beast from what we have been doing
so far with just usual inheritance.

A nice feature of the notation Cs.A() is that, from a single entry
point (say the category Magmas as above), one can explore a
whole range of related categories, typically with the help of
introspection to discover which axioms are available, and without
having to import new Python modules. This feature will be used in
trac ticket #15741 to unclutter the global name space from, for example,
the many variants of the category of algebras like:

sage: FiniteDimensionalAlgebrasWithBasis(QQ)Category of finite dimensional algebras with basis over Rational Field

There will of course be a deprecation step, but it’s recommended to
prefer right away the more flexible notation:

sage: Algebras(QQ).WithBasis().FiniteDimensional()Category of finite dimensional algebras with basis over Rational Field

Design discussion

How far should this be pushed? Fields should definitely
stay, but should FiniteGroups or DivisionRings
be removed from the global namespace? Do we want to further
completely deprecate the notation FiniteGroups()`infavorof``Groups().Finite()?

This is the covariance property: for A an axiom or a covariant
functorial construction, if Ds is a subcategory of Cs, then
Ds.A() is a subcategory of Cs.A().

What happens if we consider reciprocally an object of Cs.A() which
is also in Ds? A finite dimensional module which is also an
algebra is a finite dimensional algebra:

sage: Modules(QQ).FiniteDimensional()&Algebras(QQ)Category of finite dimensional algebras over Rational Field

On the other hand, a graded module \(O\) which is also an algebra is not
necessarily a graded algebra! Indeed, the grading on \(O\) may not be
compatible with the product on \(O\):

sage: Modules(QQ).Graded()&Algebras(QQ)Join of Category of algebras over Rational Field and Category of graded vector spaces over Rational Field

The relevant difference between FiniteDimensional and Graded
is that FiniteDimensional is a statement about the properties of
O seen as a module (and thus does not depend on the given
category), whereas Graded is a statement about the properties of
O and all its operations in the given category.

In general, if a category satisfies a given axiom, any subcategory
also satisfies that axiom. Another formulation is that, for an axiom
A defined in a super category Cs of Ds, Ds.A() is the
intersection of the categories Ds and Cs.A():

On the other hand, axioms do not necessarily commute with functorial
constructions, even if the current printout may missuggest so:

sage: As=Algebras(QQ).Graded().WithBasis();AsCategory of graded algebras with basis over Rational Fieldsage: Bs=Algebras(QQ).WithBasis().Graded();BsCategory of graded algebras with basis over Rational Fieldsage: AsisBsFalse

This is because Bs is the category of algebras endowed with basis,
which are further graded; in particular the basis must respect the
grading (i.e. be made of homogeneous elements). On the other hand,
As is the category of graded algebras, which are further endowed
with some basis; that basis need not respect the grading. In fact
As is really a join category:

sage: type(As)<class 'sage.categories.category.JoinCategory_with_category'>sage: As._repr_(as_join=True)'Join of Category of algebras with basis over Rational Field and Category of graded algebras over Rational Field'

Todo

Improve the printing of functorial constructions and joins to
raise this potentially dangerous ambiguity.

As we have seen, there is a combinatorial explosion of possible
classes. Constructing by hand the full class hierarchy would not scale
unless one would restrict to a very rigid subset. Even if it was
possible to construct automatically the full hierarchy, this would not
scale with respect to system resources.

When designing software systems with large hierarchies of abstract
classes for business objects, the difficulty is usually to identify a
proper set of key concepts. Here we are lucky, as the key concepts
have been long identified and are relatively few:

Operations (\(+\), \(*\), …)

Axioms on those operations (associativity, …)

Constructions (Cartesian products, …)

Better, those concepts are sufficiently well known so that a user can
reasonably be expected to be familiar with the concepts that are
involved for his own needs.

Instead, the difficulty is concentrated in the huge number of possible
combinations, an unpredictable large subset of which being potentially
of interest; at the same time, only a small – but moving – subset
has code naturally attached to it.

This has led to the current design, where one focuses on writing the
relatively few classes for which there is actual code or mathematical
information, and lets Sage compose dynamically and lazily those
building blocks to construct the minimal hierarchy of classes needed
for the computation at hand. This allows for the infrastructure to
scale smoothly as bookshelves are added, extended, or reorganized.

Each category \(C\)must be provided with a method
C.super_categories() and can be provided with a method
C._subcategory_hook_(D). Also, it may be needed to insert \(C\) into
the output of the super_categories() method of some other
category. This determines the position of \(C\) in the category graph.

A category may provide methods that can be used by all its objects,
respectively by all elements of its objects.

Each category should come with a good example, in
sage.categories.examples.

C.super_categories()must return a list of categories, namely
the immediate super categories of \(C\). Of course, if you know that
your new category \(C\) is an immediate super category of some existing
category \(D\), then you should also update the method
D.super_categories to include \(C\).

The immediate super categories of \(C\)should not be joincategories. Furthermore, one always should have:

Cs().is_subcategory( Category.join(Cs().super_categories()) )Cs()._cmp_key > other._cmp_key for other in Cs().super_categories()

In several cases, the category \(C\) is directly provided with a generic
implementation of super_categories; a typical example is when \(C\)
implements an axiom or a functorial construction; in such a case, \(C\)
may implement C.extra_super_categories() to complement the super
categories discovered by the generic implementation. This method needs
not return immediate super categories; instead it’s usually best to
specify the largest super category providing the desired mathematical
information. For example, the category
Magmas.Commutative.Algebras just states that the algebra of a
commutative magma is a commutative magma. This is sufficient to let
Sage deduce that it’s in fact a commutative algebra.

Different objects of the same category share some algebraic features, and
very often these features can be encoded in a method, in a generic way.
For example, for every commutative additive monoid, it makes sense to ask
for the sum of a list of elements. Sage’s category framework allows to
provide a generic implementation for all objects of a category.

If you want to provide your new category with generic methods for
objects (or elements of objects), then you simply add a nested class
called ParentMethods (or ElementMethods). The methods of that
class will automatically become methods of the objects (or the
elements). For instance:

The generic method C.all_super_categories() determines recursively
the list of all super categories of \(C\).

The order of the categories in this list does influence the
inheritance of methods for parents and elements. Namely, if \(P\) is an
object in the category \(C\) and if \(C_1\) and \(C_2\) are both super
categories of \(C\) defining some method foo in ParentMethods,
then \(P\) will use \(C_1\)’s version of foo if and only if \(C_1\)
appears in C.all_super_categories() before \(C_2\).

However this must be considered as an implementation detail: if
\(C_1\) and \(C_2\) are incomparable categories, then the order in which
they appear must be mathematically irrelevant: in particular, the
methods foo in \(C_1\) and \(C_2\) must have the same semantic. Code
should not rely on any specific order, as it is subject to later
change. Whenever one of the implementations is preferred in some common
subcategory of \(C_1\) and \(C_2\), for example for efficiency reasons,
the ambiguity should be resolved explicitly by defining a
method foo in this category. See the method some_elements in
the code of the category FiniteCoxeterGroups for an example.

Since trac ticket #11943, C.all_super_categories() is computed by the
so-called C3 algorithm used by Python to compute Method Resolution
Order of new-style classes. Thus the order in
C.all_super_categories(), C.parent_class.mro() and
C.element_class.mro() are guaranteed to be consistent.

Since trac ticket #13589, the C3 algorithm is put under control of some
total order on categories. This order is not necessarily meaningful,
but it guarantees that C3 always finds a consistent Method
Resolution Order. For background, see
sage.misc.c3_controlled. A visible effect is that the order in
which categories are specified in C.super_categories(), or in a
join category, no longer influences the result of
C.all_super_categories().

The default implementation of the method C.is_subcategory(D) is to
look up whether \(D\) appears in C.all_super_categories(). However,
building the list of all the super categories of \(C\) is an expensive
operation that is sometimes best avoided. For example, if both \(C\) and
\(D\) are categories defined over a base, but the bases differ, then one
knows right away that they can not be subcategories of each other.

When such a short-path is known, one can implement a method
_subcategory_hook_. Then, C.is_subcategory(D) first calls
D._subcategory_hook_(C). If this returns Unknown, then
C.is_subcategory(D) tries to find D in
C.all_super_categories(). Otherwise, C.is_subcategory(D)
returns the result of D._subcategory_hook_(C).

By default, D._subcategory_hook_(C) tests whether
issubclass(C.parent_class,D.parent_class), which is very often
giving the right answer: