Simplicial sets#
AUTHORS:
John H. Palmieri (2016-07)
This module implements simplicial sets.
A simplicial set \(X\) is a collection of sets \(X_n\) indexed by the non-negative integers; the set \(X_n\) is called the set of \(n\)-simplices. These sets are connected by maps
satisfying the simplicial identities:
See Wikipedia article Simplicial_set, Peter May’s seminal book [May1967], or Greg Friedman’s “Illustrated introduction” arXiv 0809.4221 for more information.
Several simplicial sets are predefined, and users can construct others
either by hand (using SimplicialSet_finite
) or from existing
ones using pushouts, pullbacks, etc.
EXAMPLES:
Some of the predefined simplicial sets:
sage: simplicial_sets.Torus()
Torus
sage: simplicial_sets.RealProjectiveSpace(7)
RP^7
sage: S5 = simplicial_sets.Sphere(5)
sage: S5
S^5
sage: S5.nondegenerate_simplices()
[v_0, sigma_5]
One class of infinite simplicial sets is available: classifying spaces of groups, or more generally, nerves of finite monoids:
sage: Sigma4 = groups.permutation.Symmetric(4)
sage: Sigma4.nerve()
Nerve of Symmetric group of order 4! as a permutation group
The same simplicial set (albeit with a different name) can also be constructed as
sage: simplicial_sets.ClassifyingSpace(Sigma4)
Classifying space of Symmetric group of order 4! as a permutation group
Type simplicial_sets.
and hit the Tab key to get a full list
of the predefined simplicial sets.
You can construct new simplicial sets from old by taking quotients, subsimplicial sets, disjoint unions, wedges (if they are pointed), smash products (if they are pointed and finite), products, pushouts, pullbacks, cones, and suspensions, most of which also have maps associated with them. Wedges, for example:
sage: T = simplicial_sets.Torus()
sage: S3 = simplicial_sets.Sphere(3)
sage: T.is_pointed() and S3.is_pointed()
True
sage: T.wedge(S3)
Wedge: (Torus v S^3)
sage: T.disjoint_union(S3) == T.coproduct(S3)
False
sage: W = T.wedge(S3)
sage: W.inclusion_map(0).domain()
Torus
sage: W.projection_map(1).codomain()
Quotient: (Wedge: (Torus v S^3)/Simplicial set with 6 non-degenerate simplices)
If the \(1\)-sphere were not already available via
simplicial_sets.Sphere(1)
, you could construct it as follows:
sage: pt = simplicial_sets.Simplex(0)
sage: edge = pt.cone()
sage: S1 = edge.quotient(edge.n_skeleton(0))
sage: S1
Quotient: (Cone of 0-simplex/Simplicial set with 2 non-degenerate simplices)
At this point, S1
is pointed: every quotient is automatically
given a base point, namely the image of the subcomplex. So its
suspension is the reduced suspension, and therefore is small:
sage: S5 = S1.suspension(4)
sage: S5
Sigma^4(Quotient: (Cone of 0-simplex/Simplicial set with 2 non-degenerate simplices))
sage: S5.f_vector()
[1, 0, 0, 0, 0, 1]
If we forget about the base point in S1
, we would get the
unreduced suspension instead:
sage: Z1 = S1.unset_base_point()
sage: Z1.suspension(4).f_vector()
[2, 2, 2, 2, 1, 1]
The cone on a pointed simplicial set is the reduced cone. The
\(n\)-simplex in Sage is not pointed, but the simplicial set Point
is.
sage: simplicial_sets.Simplex(0).cone().f_vector()
[2, 1]
sage: simplicial_sets.Point().cone().f_vector()
[1]
For most simplicial sets (the Point
is the main exception), each
time it is constructed, it gives a distinct copy, and two distinct
simplicial sets are never equal:
sage: T = simplicial_sets.Torus()
sage: T == simplicial_sets.Torus()
False
sage: T == T
True
sage: simplicial_sets.Torus() == simplicial_sets.Torus()
False
sage: simplicial_sets.Point() == simplicial_sets.Point()
True
You can construct subsimplicial sets by specifying a list of simplices, and then you can define the quotient simplicial set:
sage: X = simplicial_sets.Simplex(2)
sage: e,f,g = X.n_cells(1)
sage: Y = X.subsimplicial_set([e,f,g])
sage: Z = X.quotient(Y)
Or equivalently:
sage: Y = X.n_skeleton(1)
sage: Z = X.quotient(Y)
sage: Z
Quotient: (2-simplex/Simplicial set with 6 non-degenerate simplices)
Note that subsimplicial sets and quotients come equipped with inclusion and quotient morphisms:
sage: inc = Y.inclusion_map()
sage: inc.domain() == Y and inc.codomain() == X
True
sage: quo = Z.quotient_map()
sage: quo.domain()
2-simplex
sage: quo.codomain() == Z
True
You can compute homology groups and the fundamental group of any simplicial set:
sage: S1 = simplicial_sets.Sphere(1)
sage: eight = S1.wedge(S1)
sage: eight.fundamental_group()
Finitely presented group < e0, e1 | >
sage: Sigma3 = groups.permutation.Symmetric(3)
sage: BSigma3 = Sigma3.nerve()
sage: pi = BSigma3.fundamental_group(); pi
Finitely presented group < e1, e2 | e2^2, e1^3, (e2*e1)^2 >
sage: pi.order()
6
sage: pi.is_abelian()
False
sage: RP6 = simplicial_sets.RealProjectiveSpace(6)
sage: RP6.homology(reduced=False, base_ring=GF(2))
{0: Vector space of dimension 1 over Finite Field of size 2,
1: Vector space of dimension 1 over Finite Field of size 2,
2: Vector space of dimension 1 over Finite Field of size 2,
3: Vector space of dimension 1 over Finite Field of size 2,
4: Vector space of dimension 1 over Finite Field of size 2,
5: Vector space of dimension 1 over Finite Field of size 2,
6: Vector space of dimension 1 over Finite Field of size 2}
sage: RP6.homology(reduced=False, base_ring=QQ)
{0: Vector space of dimension 1 over Rational Field,
1: Vector space of dimension 0 over Rational Field,
2: Vector space of dimension 0 over Rational Field,
3: Vector space of dimension 0 over Rational Field,
4: Vector space of dimension 0 over Rational Field,
5: Vector space of dimension 0 over Rational Field,
6: Vector space of dimension 0 over Rational Field}
When infinite simplicial sets are involved, most computations are done by taking an \(n\)-skeleton for an appropriate \(n\), either implicitly or explicitly:
sage: B3 = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([3]))
sage: B3.disjoint_union(B3).n_skeleton(3)
Disjoint union: (Simplicial set with 15 non-degenerate simplices u Simplicial set with 15 non-degenerate simplices)
sage: S1 = simplicial_sets.Sphere(1)
sage: B3.product(S1).homology(range(4))
{0: 0, 1: Z x C3, 2: C3, 3: C3}
Without the range
argument, this would raise an error, since
B3
is infinite:
sage: B3.product(S1).homology()
Traceback (most recent call last):
...
NotImplementedError: this simplicial set may be infinite, so specify dimensions when computing homology
It should be easy to construct many simplicial sets from the predefined ones using pushouts, pullbacks, etc., but they can also be constructed “by hand”: first define some simplices, then define a simplicial set by specifying their faces:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
sage: v = AbstractSimplex(0, name='v')
sage: w = AbstractSimplex(0, name='w')
sage: e = AbstractSimplex(1, name='e')
sage: f = AbstractSimplex(1, name='f')
sage: X = SimplicialSet({e: (v,w), f: (w,w)})
Now \(e\) is an edge from \(v\) to \(w\) and \(f\) is an edge starting and ending at \(w\). Therefore the first homology group of \(X\) should be a copy of the integers:
sage: X.homology(1)
Z
- sage.topology.simplicial_set.AbstractSimplex(dim, degeneracies=(), underlying=None, name=None, latex_name=None)#
An abstract simplex, a building block of a simplicial set.
In a simplicial set, a simplex either is non-degenerate or is obtained by applying degeneracy maps to a non-degenerate simplex.
INPUT:
dim
– a non-negative integer, the dimension of the underlying non-degenerate simplex.degeneracies
(optional, defaultNone
) – a list or tuple of non-negative integers, the degeneracies to be applied.underlying
(optional) – a non-degenerate simplex to which the degeneracies are being applied.name
(optional) – string, a name for this simplex.latex_name
(optional) – string, a name for this simplex to use in the LaTeX representation.
So to define a simplex formed by applying the degeneracy maps \(s_2 s_1\) to a 1-simplex, call
AbstractSimplex(1, (2, 1))
.Specify
underlying
if you need to keep explicit track of the underlying non-degenerate simplex, for example when computing faces of another simplex. This is mainly for use by the methodAbstractSimplex_class.apply_degeneracies()
.EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex sage: AbstractSimplex(3, (3, 1)) s_3 s_1 Delta^3 sage: AbstractSimplex(3, None) Delta^3 sage: AbstractSimplex(3) Delta^3
Simplices may be named (or renamed), affecting how they are printed:
sage: AbstractSimplex(0) Delta^0 sage: v = AbstractSimplex(0, name='v') sage: v v sage: v.rename('w_0') sage: v w_0 sage: latex(v) w_0 sage: latex(AbstractSimplex(0, latex_name='\\sigma')) \sigma
The simplicial identities are used to put the degeneracies in standard decreasing form:
sage: x = AbstractSimplex(0, (0, 0, 0)) sage: x s_2 s_1 s_0 Delta^0 sage: x.degeneracies() [2, 1, 0]
Use of the
underlying
argument:sage: v = AbstractSimplex(0, name='v') sage: e = AbstractSimplex(0, (0,), underlying=v) sage: e s_0 v sage: e.nondegenerate() is v True sage: e.dimension() 1 sage: e.is_degenerate() True
Distinct non-degenerate simplices are never equal:
sage: AbstractSimplex(0, None) == AbstractSimplex(0, None) False sage: AbstractSimplex(0, (2,1,0)) == AbstractSimplex(0, (2,1,0)) False sage: e = AbstractSimplex(0, ((0,))) sage: f = AbstractSimplex(0, ((0,))) sage: e == f False sage: e.nondegenerate() == f.nondegenerate() False
This means that if, when defining a simplicial set, you specify the faces of a 2-simplex as:
(e, e, e)
then the faces are the same degenerate vertex, but if you specify the faces as:
(AbstractSimplex(0, ((0,))), AbstractSimplex(0, ((0,))), AbstractSimplex(0, ((0,))))
then the faces are three different degenerate vertices.
View a command like
AbstractSimplex(0, (2,1,0))
as first constructingAbstractSimplex(0)
and then applying degeneracies to it, and you always get distinct simplices from different calls toAbstractSimplex(0)
. On the other hand, if you apply degeneracies to the same non-degenerate simplex, the resulting simplices are equal:sage: v = AbstractSimplex(0) sage: v.apply_degeneracies(1, 0) == v.apply_degeneracies(1, 0) True sage: AbstractSimplex(1, (0,), underlying=v) == AbstractSimplex(1, (0,), underlying=v) True
- class sage.topology.simplicial_set.AbstractSimplex_class(dim, degeneracies=(), underlying=None, name=None, latex_name=None)#
Bases:
SageObject
A simplex of dimension
dim
.INPUT:
dim
– integer, the dimensiondegeneracies
(optional) – iterable, the indices of the degeneracy mapsunderlying
(optional) – a non-degenerate simplexname
(optional) – stringlatex_name
(optional) – string
Users should not call this directly, but instead use
AbstractSimplex()
. See that function for more documentation.- apply_degeneracies(*args)#
Apply the degeneracies given by the arguments
args
to this simplex.INPUT:
args
– integers
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex sage: v = AbstractSimplex(0) sage: e = v.apply_degeneracies(0) sage: e.nondegenerate() == v True sage: f = e.apply_degeneracies(0) sage: f s_1 s_0 Delta^0 sage: f.degeneracies() [1, 0] sage: f.nondegenerate() == v True sage: v.apply_degeneracies(1, 0) s_1 s_0 Delta^0
- degeneracies()#
Return the list of indices for the degeneracy maps for this simplex.
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex sage: AbstractSimplex(4, (0,0,0)).degeneracies() [2, 1, 0] sage: AbstractSimplex(4, None).degeneracies() []
- dimension()#
The dimension of this simplex.
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex sage: AbstractSimplex(3, (2,1)).dimension() 5 sage: AbstractSimplex(3, None).dimension() 3 sage: AbstractSimplex(7).dimension() 7
- is_degenerate()#
True if this simplex is degenerate.
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex sage: AbstractSimplex(3, (2,1)).is_degenerate() True sage: AbstractSimplex(3, None).is_degenerate() False
- is_nondegenerate()#
True if this simplex is non-degenerate.
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex sage: AbstractSimplex(3, (2,1)).is_nondegenerate() False sage: AbstractSimplex(3, None).is_nondegenerate() True sage: AbstractSimplex(5).is_nondegenerate() True
- nondegenerate()#
The non-degenerate simplex underlying this one.
Therefore return itself if this simplex is non-degenerate.
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex sage: v = AbstractSimplex(0, name='v') sage: sigma = v.apply_degeneracies(1, 0) sage: sigma.nondegenerate() v sage: tau = AbstractSimplex(1, (3,2,1)) sage: x = tau.nondegenerate(); x Delta^1 sage: x == tau.nondegenerate() True sage: AbstractSimplex(1, None) Delta^1 sage: AbstractSimplex(1, None) == x False sage: AbstractSimplex(1, None) == tau.nondegenerate() False
- class sage.topology.simplicial_set.NonDegenerateSimplex(dim, name=None, latex_name=None)#
Bases:
AbstractSimplex_class
,WithEqualityById
A nondegenerate simplex.
INPUT:
dim
– non-negative integer, the dimensionname
(optional) – string, a name for this simplex.latex_name
(optional) – string, a name for this simplex to use in the LaTeX representation.
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex sage: v = AbstractSimplex(0, name='v') sage: v v sage: type(v) <class 'sage.topology.simplicial_set.NonDegenerateSimplex'>
Distinct non-degenerate simplices should never be equal, even if they have the same starting data.
sage: v == AbstractSimplex(0, name='v') False sage: AbstractSimplex(3) == AbstractSimplex(3) False sage: from sage.topology.simplicial_set import NonDegenerateSimplex sage: x = NonDegenerateSimplex(0, name='x') sage: x == NonDegenerateSimplex(0, name='x') False
- sage.topology.simplicial_set.SimplicialSet#
alias of
SimplicialSet_finite
- class sage.topology.simplicial_set.SimplicialSet_arbitrary#
Bases:
Parent
A simplicial set.
A simplicial set \(X\) is a collection of sets \(X_n\), the n-simplices, indexed by the non-negative integers, together with maps
\[\begin{split}d_i: X_n \to X_{n-1}, \ \ 0 \leq i \leq n \ \ \text{(face maps)} \\ s_j: X_n \to X_{n+1}, \ \ 0 \leq j \leq n \ \ \text{(degeneracy maps)}\end{split}\]satisfying the simplicial identities:
\[\begin{split}d_i d_j &= d_{j-1} d_i \ \ \text{if } i<j \\ d_i s_j &= s_{j-1} d_i \ \ \text{if } i<j \\ d_j s_j &= 1 = d_{j+1} s_j \\ d_i s_j &= s_{j} d_{i-1} \ \ \text{if } i>j+1 \\ s_i s_j &= s_{j+1} s_{i} \ \ \text{if } i<j+1\end{split}\]This class is not fully implemented and is not intended to be called directly by users. It is intended instead to be used by other classes which inherit from this one. See
SimplicialSet_finite
andNerve
for two examples. In particular, any such class must implement a methodn_skeleton
– without this, most computations will be impossible. It must also implement an__init__
method which should also set the category, so that methods defined at the category level, likeis_pointed
andis_finite
, work correctly.Note that the method
subsimplicial_set()
callsn_skeleton()
, so to avoid circularity, then_skeleton()
method should callsimplicial_set_constructions.SubSimplicialSet
directly, notsubsimplicial_set()
.- alexander_whitney(simplex, dim_left)#
Return the ‘subdivision’ of
simplex
in this simplicial set into a pair of simplices.The left factor should have dimension
dim_left
, so the right factor should have dimensiondim - dim_left
, ifdim
is the dimension of the starting simplex. The results are obtained by applying iterated face maps tosimplex
. Writing \(d\) fordim
and \(j\) fordim_left
: apply \(d_{j+1} d_{j+2} ... d_{d}\) to get the left factor, \(d_0 ... d_0\) to get the right factor.INPUT:
dim_left
– integer, the dimension of the left-hand factor
OUTPUT: a list containing the triple
(c, left, right)
, whereleft
andright
are the two simplices described above. If eitherleft
orright
is degenerate,c
is 0; otherwise,c
is 1. This is so that, when used to compute cup products, it is easy to ignore terms which have degenerate factors.EXAMPLES:
sage: S2 = simplicial_sets.Sphere(2) sage: sigma = S2.n_cells(2)[0] sage: S2.alexander_whitney(sigma, 0) [(1, v_0, sigma_2)] sage: S2.alexander_whitney(sigma, 1) [(0, s_0 v_0, s_0 v_0)]
- all_n_simplices(n)#
Return a list of all simplices, non-degenerate and degenerate, in dimension
n
.EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0, name='v') sage: w = AbstractSimplex(0, name='w') sage: degen = v.apply_degeneracies(0) sage: tau = AbstractSimplex(2, name='tau') sage: Y = SimplicialSet({tau: (degen, degen, degen), w: None})
Y
is the disjoint union of a 2-sphere, with vertexv
and non-degenerate 2-simplextau
, and a pointw
.sage: Y.all_n_simplices(0) [v, w] sage: Y.all_n_simplices(1) [s_0 v, s_0 w] sage: Y.all_n_simplices(2) [tau, s_1 s_0 v, s_1 s_0 w]
An example involving an infinite simplicial set:
sage: C3 = groups.misc.MultiplicativeAbelian([3]) sage: BC3 = simplicial_sets.ClassifyingSpace(C3) sage: BC3.all_n_simplices(2) [f * f, f * f^2, f^2 * f, f^2 * f^2, s_0 f, s_0 f^2, s_1 f, s_1 f^2, s_1 s_0 1]
- betti(dim=None, subcomplex=None)#
The Betti numbers of this simplicial complex as a dictionary (or a single Betti number, if only one dimension is given): the ith Betti number is the rank of the ith homology group.
INPUT:
dim
(optional, defaultNone
– IfNone
, then return the homology in every dimension. Ifdim
is an integer or list, return the homology in the given dimensions. (Actually, ifdim
is a list, return the homology in the range frommin(dim)
tomax(dim)
.)subcomplex
(optional, defaultNone
) – a subcomplexof this cell complex. Compute the Betti numbers of the homology relative to this subcomplex.
Note
If this simplicial set is not finite, you must specify dimensions in which to compute Betti numbers via the argument
dim
.EXAMPLES:
Build the two-sphere as a three-fold join of a two-point space with itself:
sage: simplicial_sets.Sphere(5).betti() {0: 1, 1: 0, 2: 0, 3: 0, 4: 0, 5: 1} sage: C3 = groups.misc.MultiplicativeAbelian([3]) sage: BC3 = simplicial_sets.ClassifyingSpace(C3) sage: BC3.betti(range(4)) {0: 1, 1: 0, 2: 0, 3: 0}
- cartesian_product(*others)#
Return the product of this simplicial set with
others
.INPUT:
others
– one or several simplicial sets
If \(X\) and \(Y\) are simplicial sets, then their product \(X \times Y\) is defined to be the simplicial set with \(n\)-simplices \(X_n \times Y_n\). See
simplicial_set_constructions.ProductOfSimplicialSets
for more information.If a simplicial set is constructed as a product, the factors are recorded and are accessible via the method
simplicial_set_constructions.Factors.factors()
. If each factor is finite, then you can also construct the projection maps onto each factor, the wedge as a subcomplex, and the fat wedge as a subcomplex.EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0, name='v') sage: w = AbstractSimplex(0, name='w') sage: e = AbstractSimplex(1, name='e') sage: X = SimplicialSet({e: (v, w)}) sage: square = X.product(X)
square
is now the standard triangulation of the square: 4 vertices, 5 edges (the four on the border and the diagonal), 2 triangles:sage: square.f_vector() [4, 5, 2] sage: S1 = simplicial_sets.Sphere(1) sage: T = S1.product(S1) sage: T.homology(reduced=False) {0: Z, 1: Z x Z, 2: Z}
Since
S1
is pointed, so isT
:sage: S1.is_pointed() True sage: S1.base_point() v_0 sage: T.is_pointed() True sage: T.base_point() (v_0, v_0) sage: S2 = simplicial_sets.Sphere(2) sage: S3 = simplicial_sets.Sphere(3) sage: S2xS3 = S2.product(S3) sage: S2xS3.homology(reduced=False) {0: Z, 1: 0, 2: Z, 3: Z, 4: 0, 5: Z} sage: S2xS3.factors() == (S2, S3) True sage: S2xS3.factors() == (S3, S2) False sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) sage: B.rename('RP^oo') sage: X = B.product(B, S2) sage: X RP^oo x RP^oo x S^2 sage: X.factor(1) RP^oo sage: X.factors() (RP^oo, RP^oo, S^2)
Projection maps and wedges:
sage: S2xS3.projection_map(0) Simplicial set morphism: From: S^2 x S^3 To: S^2 Defn: ... sage: S2xS3.wedge_as_subset().homology() {0: 0, 1: 0, 2: Z, 3: Z}
In the case of pointed simplicial sets, there is an inclusion of each factor into the product. These are not automatically defined in Sage, but they are easy to construct using identity maps and constant maps and the universal property of the product:
sage: one = S2.identity() sage: const = S2.constant_map(codomain=S3) sage: S2xS3.universal_property(one, const) Simplicial set morphism: From: S^2 To: S^2 x S^3 Defn: [v_0, sigma_2] --> [(v_0, v_0), (sigma_2, s_1 s_0 v_0)]
- cells(subcomplex=None, max_dim=None)#
Return a dictionary of all non-degenerate simplices.
INPUT:
subcomplex
(optional) – a subsimplicial set of this simplicial set. Ifsubcomplex
is specified, then return the simplices in the quotient by the subcomplex.max_dim
– optional, defaultNone
. If specified, return the non-degenerate simplices of this dimension or smaller. This argument is required if this simplicial set is infinite.
Each key is a dimension, and the corresponding value is the list of simplices in that dimension.
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0) sage: w = AbstractSimplex(0) sage: S0 = SimplicialSet({v: None, w: None}) sage: S0.cells() {0: [Delta^0, Delta^0]} sage: v.rename('v') sage: w.rename('w') sage: S0.cells() {0: [v, w]} sage: e = AbstractSimplex(1, name='e') sage: S1 = SimplicialSet({e: (v, v)}) sage: S1.cells() {0: [v], 1: [e]} sage: S0.cells(S0.subsimplicial_set([v, w])) {0: [*]} sage: X = SimplicialSet({e: (v,w)}) sage: X.cells(X.subsimplicial_set([v, w])) {0: [*], 1: [e]}
Test an infinite example:
sage: C3 = groups.misc.MultiplicativeAbelian([3]) sage: BC3 = simplicial_sets.ClassifyingSpace(C3) sage: BC3.cells(max_dim=2) {0: [1], 1: [f, f^2], 2: [f * f, f * f^2, f^2 * f, f^2 * f^2]} sage: BC3.cells() Traceback (most recent call last): ... NotImplementedError: this simplicial set may be infinite, so specify max_dim
- chain_complex(dimensions=None, base_ring=Integer Ring, augmented=False, cochain=False, verbose=False, subcomplex=None, check=False)#
Return the normalized chain complex.
INPUT:
dimensions
– ifNone
, compute the chain complex in all dimensions. If a list or tuple of integers, compute the chain complex in those dimensions, setting the chain groups in all other dimensions to zero.base_ring
(optional, defaultZZ
) – commutative ringaugmented
(optional, defaultFalse
) – ifTrue
, return the augmented chain complex (that is, include a class in dimension \(-1\) corresponding to the empty cell).cochain
(optional, defaultFalse
) – ifTrue
, return the cochain complex (that is, the dual of the chain complex).verbose
(optional, defaultFalse
) – ignored.subcomplex
(optional, defaultNone
) – if present, compute the chain complex relative to this subcomplex.check
(optional, defaultFalse
) – IfTrue
, make sure that the chain complex is actually a chain complex: the differentials are composable and their product is zero.
Note
If this simplicial set is not finite, you must specify dimensions in which to compute its chain complex via the argument
dimensions
.EXAMPLES:
sage: simplicial_sets.Sphere(5).chain_complex() Chain complex with at most 3 nonzero terms over Integer Ring sage: C3 = groups.misc.MultiplicativeAbelian([3]) sage: BC3 = simplicial_sets.ClassifyingSpace(C3) sage: BC3.chain_complex(range(4), base_ring=GF(3)) Chain complex with at most 4 nonzero terms over Finite Field of size 3
- cohomology(dim=None, **kwds)#
Return the cohomology of this simplicial set.
INPUT:
dim
(optional, defaultNone
– IfNone
, then return the homology in every dimension. Ifdim
is an integer or list, return the homology in the given dimensions. (Actually, ifdim
is a list, return the homology in the range frommin(dim)
tomax(dim)
.)base_ring
(optional, defaultZZ
) – commutative ring, must beZZ
or a field.
Other arguments are also allowed, the same as for the
homology()
method – seecell_complex.GenericCellComplex.homology()
for complete documentation – except thathomology()
accepts acohomology
key word, while this function does not:cohomology
is automatically true here. Indeed, this function just callshomology()
with argumentcohomology=True
.Note
If this simplicial set is not finite, you must specify dimensions in which to compute homology via the argument
dim
.EXAMPLES:
sage: simplicial_sets.KleinBottle().homology(1) Z x C2 sage: simplicial_sets.KleinBottle().cohomology(1) Z sage: simplicial_sets.KleinBottle().cohomology(2) C2
- cone()#
Return the (reduced) cone on this simplicial set.
If this simplicial set \(X\) is not pointed, construct the ordinary cone: add a point \(v\) (which will become the base point) and for each simplex \(\sigma\) in \(X\), add both \(\sigma\) and a simplex made up of \(v\) and \(\sigma\) (topologically, form the join of \(v\) and \(\sigma\)).
If this simplicial set is pointed, then construct the reduced cone: take the quotient of the unreduced cone by the 1-simplex connecting the old base point to the new one.
In either case, as long as the simplicial set is finite, it comes equipped in Sage with a map from it into the cone.
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0, name='v') sage: e = AbstractSimplex(1, name='e') sage: X = SimplicialSet({e: (v, v)}) sage: CX = X.cone() # unreduced cone, since X not pointed sage: CX.nondegenerate_simplices() [*, v, (v,*), e, (e,*)] sage: CX.base_point() *
\(X\) as a subset of the cone, and also the map from \(X\), in the unreduced case:
sage: CX.base_as_subset() Simplicial set with 2 non-degenerate simplices sage: CX.map_from_base() Simplicial set morphism: From: Simplicial set with 2 non-degenerate simplices To: Cone of Simplicial set with 2 non-degenerate simplices Defn: [v, e] --> [v, e]
In the reduced case, only the map from \(X\) is available:
sage: X = X.set_base_point(v) sage: CX = X.cone() # reduced cone sage: CX.nondegenerate_simplices() [*, e, (e,*)] sage: CX.map_from_base() Simplicial set morphism: From: Simplicial set with 2 non-degenerate simplices To: Reduced cone of Simplicial set with 2 non-degenerate simplices Defn: [v, e] --> [*, e]
- constant_map(codomain=None, point=None)#
Return a constant map with this simplicial set as its domain.
INPUT:
codomain
– optional, defaultNone
. IfNone
, the codomain is the standard one-point space constructed byPoint()
. Otherwise, either the codomain must be a pointed simplicial set, in which case the map is constant at the base point, orpoint
must be specified.point
– optional, defaultNone
. If specified, it must be a 0-simplex in the codomain, and it will be the target of the constant map.
EXAMPLES:
sage: S4 = simplicial_sets.Sphere(4) sage: S4.constant_map() Simplicial set morphism: From: S^4 To: Point Defn: Constant map at * sage: S0 = simplicial_sets.Sphere(0) sage: S4.constant_map(codomain=S0) Simplicial set morphism: From: S^4 To: S^0 Defn: Constant map at v_0 sage: Sigma3 = groups.permutation.Symmetric(3) sage: Sigma3.nerve().constant_map() Simplicial set morphism: From: Nerve of Symmetric group of order 3! as a permutation group To: Point Defn: Constant map at *
- coproduct(*others)#
Return the coproduct of this simplicial set with
others
.INPUT:
others
– one or several simplicial sets
If these simplicial sets are pointed, return their wedge sum; if they are not, return their disjoint union. If some are pointed and some are not, raise an error: it is not clear in which category to work.
EXAMPLES:
sage: S2 = simplicial_sets.Sphere(2) sage: K = simplicial_sets.KleinBottle() sage: D3 = simplicial_sets.Simplex(3) sage: Y = S2.unset_base_point() sage: Z = K.unset_base_point() sage: S2.coproduct(K).is_pointed() True sage: S2.coproduct(K) Wedge: (S^2 v Klein bottle) sage: D3.coproduct(Y, Z).is_pointed() False sage: D3.coproduct(Y, Z) Disjoint union: (3-simplex u Simplicial set with 2 non-degenerate simplices u Simplicial set with 6 non-degenerate simplices)
The coproduct comes equipped with an inclusion map from each summand, as long as the summands are all finite:
sage: S2.coproduct(K).inclusion_map(0) Simplicial set morphism: From: S^2 To: Wedge: (S^2 v Klein bottle) Defn: [v_0, sigma_2] --> [*, sigma_2] sage: D3.coproduct(Y, Z).inclusion_map(2) Simplicial set morphism: From: Simplicial set with 6 non-degenerate simplices To: Disjoint union: (3-simplex u Simplicial set with 2 non-degenerate simplices u Simplicial set with 6 non-degenerate simplices) Defn: [Delta_{0,0}, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}] --> [Delta_{0,0}, Delta_{1,0}, Delta_{1,1}, Delta_{1,2}, Delta_{2,0}, Delta_{2,1}]
- disjoint_union(*others)#
Return the disjoint union of this simplicial set with
others
.INPUT:
others
– one or several simplicial sets
As long as the factors are all finite, the inclusion map from each factor is available. Any factors which are empty are ignored completely: they do not appear in the list of factors, etc.
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0, name='v') sage: w = AbstractSimplex(0, name='w') sage: e = AbstractSimplex(1, name='e') sage: f = AbstractSimplex(1, name='f') sage: X = SimplicialSet({e: (v, v)}) sage: Y = SimplicialSet({f: (v, w)}) sage: Z = X.disjoint_union(Y)
Since
X
andY
have simplices in common, Sage uses a copy ofY
when constructing the disjoint union. Note the name conflict in the list of simplices:v
appears twice:sage: Z = X.disjoint_union(Y) sage: Z.nondegenerate_simplices() [v, v, w, e, f]
Factors and inclusion maps:
sage: T = simplicial_sets.Torus() sage: S2 = simplicial_sets.Sphere(2) sage: A = T.disjoint_union(S2) sage: A.factors() (Torus, S^2) sage: i = A.inclusion_map(0) sage: i.domain() Torus sage: i.codomain() Disjoint union: (Torus u S^2)
Empty factors are ignored:
sage: from sage.topology.simplicial_set_examples import Empty sage: E = Empty() sage: K = S2.disjoint_union(S2, E, E, S2) sage: K == S2.disjoint_union(S2, S2) True sage: K.factors() (S^2, S^2, S^2)
- face(simplex, i)#
Return the \(i\)-th face of
simplex
in this simplicial set.INPUT:
simplex
– a simplex in this simplicial seti
– integer
EXAMPLES:
sage: S2 = simplicial_sets.Sphere(2) sage: sigma = S2.n_cells(2)[0] sage: v_0 = S2.n_cells(0)[0] sage: S2.face(sigma, 0) s_0 v_0 sage: S2.face(sigma, 0) == v_0.apply_degeneracies(0) True sage: S2.face(S2.face(sigma, 0), 0) == v_0 True
- faces(simplex)#
Return the list of faces of
simplex
in this simplicial set.INPUT:
simplex
– a simplex in this simplicial set, either degenerate or not
EXAMPLES:
sage: S2 = simplicial_sets.Sphere(2) sage: sigma = S2.n_cells(2)[0] sage: S2.faces(sigma) (s_0 v_0, s_0 v_0, s_0 v_0) sage: S2.faces(sigma.apply_degeneracies(0)) [sigma_2, sigma_2, s_1 s_0 v_0, s_1 s_0 v_0] sage: C3 = groups.misc.MultiplicativeAbelian([3]) sage: BC3 = simplicial_sets.ClassifyingSpace(C3) sage: f2 = BC3.n_cells(1)[1]; f2 f^2 sage: BC3.faces(f2) (1, 1)
- graph()#
Return the 1-skeleton of this simplicial set, as a graph.
EXAMPLES:
sage: Delta3 = simplicial_sets.Simplex(3) sage: G = Delta3.graph() sage: G.edges(sort=True) [((0,), (1,), (0, 1)), ((0,), (2,), (0, 2)), ((0,), (3,), (0, 3)), ((1,), (2,), (1, 2)), ((1,), (3,), (1, 3)), ((2,), (3,), (2, 3))] sage: T = simplicial_sets.Torus() sage: T.graph() Looped multi-graph on 1 vertex sage: len(T.graph().edges(sort=False)) 3 sage: CP3 = simplicial_sets.ComplexProjectiveSpace(3) sage: G = CP3.graph() sage: len(G.vertices(sort=False)) 1 sage: len(G.edges(sort=False)) 0 sage: Sigma3 = groups.permutation.Symmetric(3) sage: Sigma3.nerve().is_connected() True
- homology(dim=None, **kwds)#
Return the (reduced) homology of this simplicial set.
INPUT:
dim
(optional, defaultNone
– IfNone
, then return the homology in every dimension. Ifdim
is an integer or list, return the homology in the given dimensions. (Actually, ifdim
is a list, return the homology in the range frommin(dim)
tomax(dim)
.)base_ring
(optional, defaultZZ
) – commutative ring, must beZZ
or a field.
Other arguments are also allowed: see the documentation for
cell_complex.GenericCellComplex.homology()
.Note
If this simplicial set is not finite, you must specify dimensions in which to compute homology via the argument
dim
.EXAMPLES:
sage: simplicial_sets.Sphere(5).homology() {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: Z} sage: C3 = groups.misc.MultiplicativeAbelian([3]) sage: BC3 = simplicial_sets.ClassifyingSpace(C3) sage: BC3.homology(range(4), base_ring=GF(3)) {0: Vector space of dimension 0 over Finite Field of size 3, 1: Vector space of dimension 1 over Finite Field of size 3, 2: Vector space of dimension 1 over Finite Field of size 3, 3: Vector space of dimension 1 over Finite Field of size 3} sage: BC2 = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) sage: BK = BC2.product(BC2) sage: BK.homology(range(4)) {0: 0, 1: C2 x C2, 2: C2, 3: C2 x C2 x C2}
- identity()#
Return the identity map on this simplicial set.
EXAMPLES:
sage: S3 = simplicial_sets.Sphere(3) sage: S3.identity() Simplicial set endomorphism of S^3 Defn: Identity map sage: BC3 = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([3])) sage: one = BC3.identity() sage: [(sigma, one(sigma)) for sigma in BC3.n_cells(2)] [(f * f, f * f), (f * f^2, f * f^2), (f^2 * f, f^2 * f), (f^2 * f^2, f^2 * f^2)]
- is_connected()#
Return
True
if this simplicial set is connected.EXAMPLES:
sage: T = simplicial_sets.Torus() sage: K = simplicial_sets.KleinBottle() sage: X = T.disjoint_union(K) sage: T.is_connected() True sage: K.is_connected() True sage: X.is_connected() False sage: simplicial_sets.Sphere(0).is_connected() False
- is_reduced()#
Return
True
if this simplicial set has only one vertex.EXAMPLES:
sage: simplicial_sets.Sphere(0).is_reduced() False sage: simplicial_sets.Sphere(3).is_reduced() True
- join(*others)#
The join of this simplicial set with
others
.Not implemented. See https://ncatlab.org/nlab/show/join+of+simplicial+sets for a few descriptions, for anyone interested in implementing this. See also P. J. Ehlers and Tim Porter, Joins for (Augmented) Simplicial Sets, Jour. Pure Applied Algebra, 145 (2000) 37-44 arXiv 9904039.
others
– one or several simplicial sets
EXAMPLES:
sage: K = simplicial_sets.Simplex(2) sage: K.join(K) Traceback (most recent call last): ... NotImplementedError: joins are not implemented for simplicial sets
- n_cells(n, subcomplex=None)#
Return the list of cells of dimension
n
of this cell complex. If the optional argumentsubcomplex
is present, then return then
-dimensional faces in the quotient by this subcomplex.INPUT:
n
– the dimensionsubcomplex
(optional, defaultNone
) – a subcomplex of this cell complex. Return the cells which are in the quotient by this subcomplex.
EXAMPLES:
sage: simplicial_sets.Sphere(3).n_cells(3) [sigma_3] sage: simplicial_sets.Sphere(3).n_cells(2) [] sage: C2 = groups.misc.MultiplicativeAbelian([2]) sage: BC2 = C2.nerve() sage: BC2.n_cells(3) [f * f * f]
- n_chains(n, base_ring=Integer Ring, cochains=False)#
Return the free module of (normalized) chains in degree
n
overbase_ring
.This is the free module on the nondegenerate simplices in the given dimension.
INPUT:
n
– integerbase_ring
– ring (optional, default \(\ZZ\))cochains
– boolean (optional, defaultFalse
); ifTrue
, return cochains instead
The only difference between chains and cochains is notation: the generator corresponding to the dual of a simplex
sigma
is written as"\chi_sigma"
in the group of cochains.EXAMPLES:
sage: S3 = simplicial_sets.Sphere(3) sage: C = S3.n_chains(3, cochains=True) sage: list(C.basis()) [\chi_sigma_3] sage: Sigma3 = groups.permutation.Symmetric(3) sage: BSigma3 = simplicial_sets.ClassifyingSpace(Sigma3) sage: list(BSigma3.n_chains(1).basis()) [(1,2), (1,2,3), (1,3), (1,3,2), (2,3)] sage: list(BSigma3.n_chains(1, cochains=True).basis()) [\chi_(1,2), \chi_(1,2,3), \chi_(1,3), \chi_(1,3,2), \chi_(2,3)]
- nondegenerate_simplices(max_dim=None)#
Return the sorted list of non-degenerate simplices in this simplicial set.
INPUT:
max_dim
– optional, defaultNone
. If specified, return the non-degenerate simplices of this dimension or smaller. This argument is required if this simplicial set is infinite.
The sorting is in increasing order of dimension, and within each dimension, by the name (if present) of each simplex.
Note
The sorting is done when the simplicial set is constructed, so changing the name of a simplex after construction will not affect the ordering.
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0) sage: w = AbstractSimplex(0) sage: S0 = SimplicialSet({v: None, w: None}) sage: S0.nondegenerate_simplices() [Delta^0, Delta^0]
Name the vertices and reconstruct the simplicial set: they should be ordered alphabetically:
sage: v.rename('v') sage: w.rename('w') sage: S0 = SimplicialSet({v: None, w: None}) sage: S0.nondegenerate_simplices() [v, w]
Rename but do not reconstruct the set; the ordering does not take the new names into account:
sage: v.rename('z') sage: S0.nondegenerate_simplices() # old ordering is used [z, w] sage: X0 = SimplicialSet({v: None, w: None}) sage: X0.nondegenerate_simplices() # new ordering is used [w, z]
Test an infinite example:
sage: C3 = groups.misc.MultiplicativeAbelian([3]) sage: BC3 = simplicial_sets.ClassifyingSpace(C3) sage: BC3.nondegenerate_simplices(2) [1, f, f^2, f * f, f * f^2, f^2 * f, f^2 * f^2] sage: BC3.nondegenerate_simplices() Traceback (most recent call last): ... NotImplementedError: this simplicial set may be infinite, so specify max_dim
- product(*others)#
Return the product of this simplicial set with
others
.INPUT:
others
– one or several simplicial sets
If \(X\) and \(Y\) are simplicial sets, then their product \(X \times Y\) is defined to be the simplicial set with \(n\)-simplices \(X_n \times Y_n\). See
simplicial_set_constructions.ProductOfSimplicialSets
for more information.If a simplicial set is constructed as a product, the factors are recorded and are accessible via the method
simplicial_set_constructions.Factors.factors()
. If each factor is finite, then you can also construct the projection maps onto each factor, the wedge as a subcomplex, and the fat wedge as a subcomplex.EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0, name='v') sage: w = AbstractSimplex(0, name='w') sage: e = AbstractSimplex(1, name='e') sage: X = SimplicialSet({e: (v, w)}) sage: square = X.product(X)
square
is now the standard triangulation of the square: 4 vertices, 5 edges (the four on the border and the diagonal), 2 triangles:sage: square.f_vector() [4, 5, 2] sage: S1 = simplicial_sets.Sphere(1) sage: T = S1.product(S1) sage: T.homology(reduced=False) {0: Z, 1: Z x Z, 2: Z}
Since
S1
is pointed, so isT
:sage: S1.is_pointed() True sage: S1.base_point() v_0 sage: T.is_pointed() True sage: T.base_point() (v_0, v_0) sage: S2 = simplicial_sets.Sphere(2) sage: S3 = simplicial_sets.Sphere(3) sage: S2xS3 = S2.product(S3) sage: S2xS3.homology(reduced=False) {0: Z, 1: 0, 2: Z, 3: Z, 4: 0, 5: Z} sage: S2xS3.factors() == (S2, S3) True sage: S2xS3.factors() == (S3, S2) False sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) sage: B.rename('RP^oo') sage: X = B.product(B, S2) sage: X RP^oo x RP^oo x S^2 sage: X.factor(1) RP^oo sage: X.factors() (RP^oo, RP^oo, S^2)
Projection maps and wedges:
sage: S2xS3.projection_map(0) Simplicial set morphism: From: S^2 x S^3 To: S^2 Defn: ... sage: S2xS3.wedge_as_subset().homology() {0: 0, 1: 0, 2: Z, 3: Z}
In the case of pointed simplicial sets, there is an inclusion of each factor into the product. These are not automatically defined in Sage, but they are easy to construct using identity maps and constant maps and the universal property of the product:
sage: one = S2.identity() sage: const = S2.constant_map(codomain=S3) sage: S2xS3.universal_property(one, const) Simplicial set morphism: From: S^2 To: S^2 x S^3 Defn: [v_0, sigma_2] --> [(v_0, v_0), (sigma_2, s_1 s_0 v_0)]
- pullback(*maps)#
Return the pullback obtained from given
maps
.INPUT:
maps
– several maps of simplicial sets, each of which has this simplicial set as its codomain
If only a single map \(f: X \to Y\) is given, then return \(X\). If more than one map is given, say \(f_i: X_i \to Y\) for \(0 \leq i \leq m\), then return the pullback defined by those maps. If no maps are given, return the one-point simplicial set.
In addition to the defining maps \(f_i\) used to construct the pullback \(P\), there are also maps \(\bar{f}_i: P \to X_i\), which we refer to as structure maps or projection maps. The pullback also has a universal property: given maps \(g_i: Z \to X_i\) such that \(f_i g_i = f_j g_j\) for all \(i\), \(j\), then there is a unique map \(g: Z \to P\) making the appropriate diagram commute: that is, \(\bar{f}_i g = g_i\) for all \(i\). For example, given maps \(f: X \to Y\) and \(g: X \to Z\), there is an induced map \(g: X \to Y \times Z\).
In Sage, a pullback is equipped with its defining maps, and as long as the simplicial sets involved are finite, you can also access the structure maps and the universal property.
EXAMPLES:
Construct a product as a pullback:
sage: S2 = simplicial_sets.Sphere(2) sage: pt = simplicial_sets.Point() sage: P = pt.pullback(S2.constant_map(), S2.constant_map()) sage: P.homology(2) Z x Z
If the pullback is defined via maps \(f_i: X_i \to Y\), then there are structure maps \(\bar{f}_i: Y_i \to P\). The structure maps are only available in Sage when all of the maps involved have finite domains.
sage: S2 = simplicial_sets.Sphere(2) sage: one = S2.Hom(S2).identity() sage: P = S2.pullback(one, one) sage: P.homology() {0: 0, 1: 0, 2: Z} sage: P.defining_map(0) == one True sage: P.structure_map(1) Simplicial set morphism: From: Pullback of maps: Simplicial set endomorphism of S^2 Defn: Identity map Simplicial set endomorphism of S^2 Defn: Identity map To: S^2 Defn: [(v_0, v_0), (sigma_2, sigma_2)] --> [v_0, sigma_2] sage: P.structure_map(0).domain() == P True sage: P.structure_map(0).codomain() == S2 True
The universal property:
sage: S1 = simplicial_sets.Sphere(1) sage: T = S1.product(S1) sage: K = T.factor(0, as_subset=True) sage: f = S1.Hom(T)({S1.n_cells(0)[0]:K.n_cells(0)[0], S1.n_cells(1)[0]:K.n_cells(1)[0]}) sage: D = S1.cone() # the cone C(S^1) sage: g = D.map_from_base() # map from S^1 to C(S^1) sage: P = T.product(D) sage: h = P.universal_property(f, g) sage: h.domain() == S1 True sage: h.codomain() == P True
- pushout(*maps)#
Return the pushout obtained from given
maps
.INPUT:
maps
– several maps of simplicial sets, each of which has this simplicial set as its domain
If only a single map \(f: X \to Y\) is given, then return \(Y\). If more than one map is given, say \(f_i: X \to Y_i\) for \(0 \leq i \leq m\), then return the pushout defined by those maps. If no maps are given, return the empty simplicial set.
In addition to the defining maps \(f_i\) used to construct the pushout \(P\), there are also maps \(\bar{f}_i: Y_i \to P\), which we refer to as structure maps. The pushout also has a universal property: given maps \(g_i: Y_i \to Z\) such that \(g_i f_i = g_j f_j\) for all \(i\), \(j\), then there is a unique map \(g: P \to Z\) making the appropriate diagram commute: that is, \(g \bar{f}_i = g_i\) for all \(i\).
In Sage, a pushout is equipped with its defining maps, and as long as the simplicial sets involved are finite, you can also access the structure maps and the universal property.
EXAMPLES:
Construct the 4-sphere as a quotient of a 4-simplex:
sage: K = simplicial_sets.Simplex(4) sage: L = K.n_skeleton(3) sage: S4 = L.pushout(L.constant_map(), L.inclusion_map()) sage: S4 Pushout of maps: Simplicial set morphism: From: Simplicial set with 30 non-degenerate simplices To: Point Defn: Constant map at * Simplicial set morphism: From: Simplicial set with 30 non-degenerate simplices To: 4-simplex Defn: [(0,), (1,), (2,), (3,), (4,), (0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4), (0, 1, 2), (0, 1, 3), (0, 1, 4), (0, 2, 3), (0, 2, 4), (0, 3, 4), (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4), (0, 1, 2, 3), (0, 1, 2, 4), (0, 1, 3, 4), (0, 2, 3, 4), (1, 2, 3, 4)] --> [(0,), (1,), (2,), (3,), (4,), (0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4), (0, 1, 2), (0, 1, 3), (0, 1, 4), (0, 2, 3), (0, 2, 4), (0, 3, 4), (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4), (0, 1, 2, 3), (0, 1, 2, 4), (0, 1, 3, 4), (0, 2, 3, 4), (1, 2, 3, 4)] sage: len(S4.nondegenerate_simplices()) 2 sage: S4.homology(4) Z
The associated maps:
sage: S1 = simplicial_sets.Sphere(1) sage: T = S1.product(S1) sage: K = T.factor(0, as_subset=True) sage: W = S1.wedge(T) # wedge, constructed as a pushout sage: W.defining_map(1) Simplicial set morphism: From: Point To: S^1 x S^1 Defn: Constant map at (v_0, v_0) sage: W.structure_map(0) Simplicial set morphism: From: S^1 To: Wedge: (S^1 v S^1 x S^1) Defn: [v_0, sigma_1] --> [*, sigma_1] sage: f = S1.Hom(T)({S1.n_cells(0)[0]:K.n_cells(0)[0], S1.n_cells(1)[0]:K.n_cells(1)[0]})
The maps \(f: S^1 \to T\) and \(1: T \to T\) induce a map \(S^1 \vee T \to T\):
sage: g = W.universal_property(f, Hom(T,T).identity()) sage: g.domain() == W True sage: g.codomain() == T True
- quotient(subcomplex, vertex_name='*')#
Return the quotient of this simplicial set by
subcomplex
.That is,
subcomplex
is replaced by a vertex.INPUT:
subcomplex
– subsimplicial set of this simplicial set, or a list, tuple, or set of simplices defining a subsimplicial set.vertex_name
(optional) – string, name to be given to the new vertex. By default, use'*'
.
In Sage, from a quotient simplicial set, you can recover the ambient space, the subcomplex, and (if the ambient space is finite) the quotient map.
Base points: if the original simplicial set has a base point not contained in
subcomplex
and if the original simplicial set is finite, then use its image as the base point for the quotient. In all other cases,*
is the base point.EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0, name='v') sage: w = AbstractSimplex(0, name='w') sage: e = AbstractSimplex(1, name='e') sage: f = AbstractSimplex(1, name='f') sage: X = SimplicialSet({e: (v, w), f: (v, w)}) sage: Y = X.quotient([f]) sage: Y.nondegenerate_simplices() [*, e] sage: Y.homology(1) Z sage: E = SimplicialSet({e: (v, w)}) sage: Z = E.quotient([v, w]) sage: Z.nondegenerate_simplices() [*, e] sage: Z.homology(1) Z sage: F = E.quotient([v]) sage: F.nondegenerate_simplices() [*, w, e] sage: F.base_point() * sage: RP5 = simplicial_sets.RealProjectiveSpace(5) sage: RP2 = RP5.n_skeleton(2) sage: RP5_2 = RP5.quotient(RP2) sage: RP5_2.homology(base_ring=GF(2)) {0: Vector space of dimension 0 over Finite Field of size 2, 1: Vector space of dimension 0 over Finite Field of size 2, 2: Vector space of dimension 0 over Finite Field of size 2, 3: Vector space of dimension 1 over Finite Field of size 2, 4: Vector space of dimension 1 over Finite Field of size 2, 5: Vector space of dimension 1 over Finite Field of size 2} sage: RP5_2.ambient() RP^5 sage: RP5_2.subcomplex() Simplicial set with 3 non-degenerate simplices sage: RP5_2.quotient_map() Simplicial set morphism: From: RP^5 To: Quotient: (RP^5/Simplicial set with 3 non-degenerate simplices) Defn: [1, f, f * f, f * f * f, f * f * f * f, f * f * f * f * f] --> [*, s_0 *, s_1 s_0 *, f * f * f, f * f * f * f, f * f * f * f * f]
Behavior of base points:
sage: K = simplicial_sets.Simplex(3) sage: K.is_pointed() False sage: L = K.subsimplicial_set([K.n_cells(1)[-1]]) sage: L.nondegenerate_simplices() [(2,), (3,), (2, 3)] sage: K.quotient([K.n_cells(1)[-1]]).base_point() * sage: K = K.set_base_point(K.n_cells(0)[0]) sage: K.base_point() (0,) sage: L = K.subsimplicial_set([K.n_cells(1)[-1]]) sage: L.nondegenerate_simplices() [(2,), (3,), (2, 3)] sage: K.quotient(L).base_point() (0,)
- reduce()#
Reduce this simplicial set.
That is, take the quotient by a spanning tree of the 1-skeleton, so that the resulting simplicial set has only one vertex. This only makes sense if the simplicial set is connected, so raise an error if not. If already reduced, return itself.
EXAMPLES:
sage: K = simplicial_sets.Simplex(2) sage: K.is_reduced() False sage: X = K.reduce() sage: X.is_reduced() True
X
is reduced, so callingreduce
on it again returnsX
itself:sage: X is X.reduce() True sage: K is K.reduce() False
Raise an error for disconnected simplicial sets:
sage: S0 = simplicial_sets.Sphere(0) sage: S0.reduce() Traceback (most recent call last): ... ValueError: this simplicial set is not connected
- rename_latex(s)#
Rename or set the LaTeX name for this simplicial set.
INPUT:
s
– string, the LaTeX representation. Ors
can beNone
, in which case the LaTeX name is unset.
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0) sage: X = SimplicialSet({v: None}, latex_name='*') sage: latex(X) * sage: X.rename_latex('x_0') sage: latex(X) x_0
- subsimplicial_set(simplices)#
Return the sub-simplicial set of this simplicial set determined by
simplices
, a set of nondegenerate simplices.INPUT:
simplices
– set, list, or tuple of nondegenerate simplices in this simplicial set, or a simplicial complex – see below.
Each sub-simplicial set comes equipped with an inclusion map to its ambient space, and you can easily recover its ambient space.
If
simplices
is a simplicial complex, then the original simplicial set should itself have been converted from a simplicial complex, andsimplices
should be a subcomplex of that.EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0, name='v') sage: w = AbstractSimplex(0, name='w') sage: e = AbstractSimplex(1, name='e') sage: f = AbstractSimplex(1, name='f') sage: X = SimplicialSet({e: (v, w), f: (w, v)}) sage: Y = X.subsimplicial_set([e]) sage: Y Simplicial set with 3 non-degenerate simplices sage: Y.nondegenerate_simplices() [v, w, e] sage: S3 = simplicial_complexes.Sphere(3) sage: K = SimplicialSet(S3) sage: tau = K.n_cells(3)[0] sage: tau.dimension() 3 sage: K.subsimplicial_set([tau]) Simplicial set with 15 non-degenerate simplices
A subsimplicial set knows about its ambient space and the inclusion map into it:
sage: RP4 = simplicial_sets.RealProjectiveSpace(4) sage: M = RP4.n_skeleton(2) sage: M Simplicial set with 3 non-degenerate simplices sage: M.ambient_space() RP^4 sage: M.inclusion_map() Simplicial set morphism: From: Simplicial set with 3 non-degenerate simplices To: RP^4 Defn: [1, f, f * f] --> [1, f, f * f]
An infinite ambient simplicial set:
sage: B = simplicial_sets.ClassifyingSpace(groups.misc.MultiplicativeAbelian([2])) sage: BxB = B.product(B) sage: BxB.n_cells(2)[5:] [(s_0 f, s_1 f), (s_1 f, f * f), (s_1 f, s_0 f), (s_1 s_0 1, f * f)] sage: BxB.subsimplicial_set(BxB.n_cells(2)[5:]) Simplicial set with 8 non-degenerate simplices
- suspension(n=1)#
Return the (reduced) \(n\)-th suspension of this simplicial set.
INPUT:
n
(optional, default 1) – integer, suspend this many times.
If this simplicial set \(X\) is not pointed, return the suspension: the quotient \(CX/X\), where \(CX\) is the (ordinary, unreduced) cone on \(X\). If \(X\) is pointed, then use the reduced cone instead, and so return the reduced suspension.
EXAMPLES:
sage: RP4 = simplicial_sets.RealProjectiveSpace(4) sage: S1 = simplicial_sets.Sphere(1) sage: SigmaRP4 = RP4.suspension() sage: S1_smash_RP4 = S1.smash_product(RP4) sage: SigmaRP4.homology() == S1_smash_RP4.homology() True
The version of the suspension obtained by the smash product is typically less efficient than the reduced suspension produced here:
sage: SigmaRP4.f_vector() [1, 0, 1, 1, 1, 1] sage: S1_smash_RP4.f_vector() [1, 1, 4, 6, 8, 5]
- wedge(*others)#
Return the wedge sum of this pointed simplicial set with
others
.others
– one or several simplicial sets
This constructs the quotient of the disjoint union in which the base points of all of the simplicial sets have been identified. This is the coproduct in the category of pointed simplicial sets.
This raises an error if any of the factors is not pointed.
From the wedge, you can access the factors, and if the simplicial sets involved are all finite, you can also access the inclusion map of each factor into the wedge, as well as the projection map onto each factor.
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0, name='v') sage: e = AbstractSimplex(1, name='e') sage: w = AbstractSimplex(0, name='w') sage: f = AbstractSimplex(1, name='f') sage: X = SimplicialSet({e: (v, v)}, base_point=v) sage: Y = SimplicialSet({f: (w, w)}, base_point=w) sage: W = X.wedge(Y) sage: W.nondegenerate_simplices() [*, e, f] sage: W.homology() {0: 0, 1: Z x Z} sage: S2 = simplicial_sets.Sphere(2) sage: X.wedge(S2).homology(reduced=False) {0: Z, 1: Z, 2: Z} sage: X.wedge(X).nondegenerate_simplices() [*, e, e] sage: S3 = simplicial_sets.Sphere(3) sage: W = S2.wedge(S3, S2) sage: W.inclusion_map(2) Simplicial set morphism: From: S^2 To: Wedge: (S^2 v S^3 v S^2) Defn: [v_0, sigma_2] --> [*, sigma_2] sage: W.projection_map(1) Simplicial set morphism: From: Wedge: (S^2 v S^3 v S^2) To: Quotient: (Wedge: (S^2 v S^3 v S^2)/Simplicial set with 3 non-degenerate simplices) Defn: [*, sigma_2, sigma_2, sigma_3] --> [*, s_1 s_0 *, s_1 s_0 *, sigma_3]
Note that the codomain of the projection map is not identical to the original
S2
, but is instead a quotient of the wedge which is isomorphic toS2
:sage: S2.f_vector() [1, 0, 1] sage: W.projection_map(2).codomain().f_vector() [1, 0, 1] sage: (W.projection_map(2) * W.inclusion_map(2)).is_bijective() True
- class sage.topology.simplicial_set.SimplicialSet_finite(data, base_point=None, name=None, check=True, category=None, latex_name=None)#
Bases:
SimplicialSet_arbitrary
,GenericCellComplex
A finite simplicial set.
A simplicial set \(X\) is a collection of sets \(X_n\), the n-simplices, indexed by the non-negative integers, together with face maps \(d_i\) and degeneracy maps \(s_j\). A simplex is degenerate if it is in the image of some \(s_j\), and a simplicial set is finite if there are only finitely many non-degenerate simplices.
INPUT:
data
– the data defining the simplicial set. See below for details.base_point
(optional, defaultNone
) – 0-simplex in this simplicial set, its base pointname
(optional, defaultNone
) – string, the name of the simplicial setcheck
(optional, defaultTrue
) – boolean. IfTrue
, check the simplicial identity on the face maps when defining the simplicial set.category
(optional, defaultNone
) – the category in which to define this simplicial set. The default is either finite simplicial sets or finite pointed simplicial sets, depending on whether a base point is defined.latex_name
(optional, defaultNone
) – string, the LaTeX representation of the simplicial set.
data
should have one of the following forms: it could be a simplicial complex or \(\Delta\)-complex, in case it is converted to a simplicial set. Alternatively, it could be a dictionary. The keys are the nondegenerate simplices of the simplicial set, and the value corresponding to a simplex \(\sigma\) is a tuple listing the faces of \(\sigma\). The 0-dimensional simplices may be omitted fromdata
if they (or their degeneracies) are faces of other simplices; otherwise they must be included with valueNone
.See
simplicial_set
and the methods for simplicial sets for more information and examples.EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: u = AbstractSimplex(0, name='u') sage: v = AbstractSimplex(0, name='v') sage: w = AbstractSimplex(0, name='w') sage: e = AbstractSimplex(1, name='e') sage: f = AbstractSimplex(1, name='f')
In the following simplicial set,
u
is an isolated vertex:sage: X = SimplicialSet({e: (v,w), f: (w,w), u: None}) sage: X Simplicial set with 5 non-degenerate simplices sage: X.rename('X') sage: X X sage: X = SimplicialSet({e: (v,w), f: (w,w), u: None}, name='Y') sage: X Y
- algebraic_topological_model(base_ring=None)#
Return the algebraic topological model for this simplicial set with coefficients in
base_ring
.The term “algebraic topological model” is defined by Pilarczyk and Réal [PR2015].
INPUT:
base_ring
- coefficient ring (optional, defaultQQ
). Must be a field.
Denote by \(C\) the chain complex associated to this simplicial set. The algebraic topological model is a chain complex \(M\) with zero differential, with the same homology as \(C\), along with chain maps \(\pi: C \to M\) and \(\iota: M \to C\) satisfying \(\iota \pi = 1_M\) and \(\pi \iota\) chain homotopic to \(1_C\). The chain homotopy \(\phi\) must satisfy
\(\phi \phi = 0\),
\(\pi \phi = 0\),
\(\phi \iota = 0\).
Such a chain homotopy is called a chain contraction.
OUTPUT: a pair consisting of
chain contraction
phi
associated to \(C\), \(M\), \(\pi\), and \(\iota\)the chain complex \(M\)
Note that from the chain contraction
phi
, one can recover the chain maps \(\pi\) and \(\iota\) viaphi.pi()
andphi.iota()
. Then one can recover \(C\) and \(M\) from, for example,phi.pi().domain()
andphi.pi().codomain()
, respectively.EXAMPLES:
sage: RP2 = simplicial_sets.RealProjectiveSpace(2) sage: phi, M = RP2.algebraic_topological_model(GF(2)) sage: M.homology() {0: Vector space of dimension 1 over Finite Field of size 2, 1: Vector space of dimension 1 over Finite Field of size 2, 2: Vector space of dimension 1 over Finite Field of size 2} sage: T = simplicial_sets.Torus() sage: phi, M = T.algebraic_topological_model(QQ) sage: M.homology() {0: Vector space of dimension 1 over Rational Field, 1: Vector space of dimension 2 over Rational Field, 2: Vector space of dimension 1 over Rational Field}
- chain_complex(dimensions=None, base_ring=Integer Ring, augmented=False, cochain=False, verbose=False, subcomplex=None, check=False)#
Return the normalized chain complex.
INPUT:
dimensions
– ifNone
, compute the chain complex in all dimensions. If a list or tuple of integers, compute the chain complex in those dimensions, setting the chain groups in all other dimensions to zero.base_ring
(optional, defaultZZ
) – commutative ringaugmented
(optional, defaultFalse
) – ifTrue
, return the augmented chain complex (that is, include a class in dimension \(-1\) corresponding to the empty cell).cochain
(optional, defaultFalse
) – ifTrue
, return the cochain complex (that is, the dual of the chain complex).verbose
(optional, defaultFalse
) – ignored.subcomplex
(optional, defaultNone
) – if present, compute the chain complex relative to this subcomplex.check
(optional, defaultFalse
) – IfTrue
, make sure that the chain complex is actually a chain complex: the differentials are composable and their product is zero.
The normalized chain complex of a simplicial set is isomorphic to the chain complex obtained by modding out by degenerate simplices, and the latter is what is actually constructed here.
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0) sage: degen = v.apply_degeneracies(1, 0) # s_1 s_0 applied to v sage: sigma = AbstractSimplex(3) sage: S3 = SimplicialSet({sigma: (degen, degen, degen, degen)}) # the 3-sphere sage: S3.chain_complex().homology() {0: Z, 3: Z} sage: S3.chain_complex(augmented=True).homology() {-1: 0, 0: 0, 3: Z} sage: S3.chain_complex(dimensions=range(3), base_ring=QQ).homology() {0: Vector space of dimension 1 over Rational Field} sage: RP5 = simplicial_sets.RealProjectiveSpace(5) sage: RP2 = RP5.n_skeleton(2) sage: RP5.chain_complex(subcomplex=RP2).homology() {0: Z, 3: C2, 4: 0, 5: Z}
- euler_characteristic()#
Return the Euler characteristic of this simplicial set: the alternating sum over \(n \geq 0\) of the number of nondegenerate \(n\)-simplices.
EXAMPLES:
sage: simplicial_sets.RealProjectiveSpace(4).euler_characteristic() 1 sage: simplicial_sets.Sphere(6).euler_characteristic() 2 sage: simplicial_sets.KleinBottle().euler_characteristic() 0
- f_vector()#
Return the list of the number of non-degenerate simplices in each dimension.
Unlike for some other cell complexes in Sage, this does not include the empty simplex in dimension \(-1\); thus its \(i\)-th entry is the number of \(i\)-dimensional simplices.
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0) sage: w = AbstractSimplex(0) sage: S0 = SimplicialSet({v: None, w: None}) sage: S0.f_vector() [2] sage: e = AbstractSimplex(1) sage: S1 = SimplicialSet({e: (v, v)}) sage: S1.f_vector() [1, 1] sage: simplicial_sets.Sphere(3).f_vector() [1, 0, 0, 1]
- face_data()#
Return the face-map data – a dictionary – defining this simplicial set.
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0, name='v') sage: w = AbstractSimplex(0, name='w') sage: e = AbstractSimplex(1, name='e') sage: X = SimplicialSet({e: (v, w)}) sage: X.face_data()[e] (v, w) sage: Y = SimplicialSet({v: None, w: None}) sage: v in Y.face_data() True sage: Y.face_data()[v] is None True
- n_skeleton(n)#
Return the \(n\)-skeleton of this simplicial set.
That is, the subsimplicial set generated by all nondegenerate simplices of dimension at most \(n\).
INPUT:
n
– the dimension
EXAMPLES:
sage: from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet sage: v = AbstractSimplex(0, name='v') sage: w = AbstractSimplex(0, name='w') sage: degen = v.apply_degeneracies(0) sage: tau = AbstractSimplex(2, name='tau') sage: Y = SimplicialSet({tau: (degen, degen, degen), w: None})
Y
is the disjoint union of a 2-sphere, with vertexv
and non-degenerate 2-simplextau
, and a pointw
.sage: Y.nondegenerate_simplices() [v, w, tau] sage: Y.n_skeleton(1).nondegenerate_simplices() [v, w] sage: Y.n_skeleton(2).nondegenerate_simplices() [v, w, tau]
- sage.topology.simplicial_set.all_degeneracies(n, l=1)#
Return list of all composites of degeneracies (written in “admissible” form, i.e., as a strictly decreasing sequence) of length \(l\) on an \(n\)-simplex.
INPUT:
n
,l
– integers
On an \(n\)-simplex, one may apply the degeneracies \(s_i\) for \(0 \leq i \leq n\). Then on the resulting \(n+1\)-simplex, one may apply \(s_i\) for \(0 \leq i \leq n+1\), and so on. But one also has to take into account the simplicial identity
\[s_i s_j = s_{j+1} s_i \ \ \text{if } i \leq j.\]There are \(\binom{l+n}{n}\) such composites: each non-degenerate \(n\)-simplex leads to \(\binom{l+n}{n}\) degenerate \(l+n\) simplices.
EXAMPLES:
sage: from sage.topology.simplicial_set import all_degeneracies sage: all_degeneracies(0, 3) {(2, 1, 0)} sage: all_degeneracies(1, 1) {(0,), (1,)} sage: all_degeneracies(1, 3) {(2, 1, 0), (3, 1, 0), (3, 2, 0), (3, 2, 1)}
- sage.topology.simplicial_set.face_degeneracies(m, I)#
Return the result of applying the face map \(d_m\) to the iterated degeneracy \(s_I = s_{i_1} s_{i_2} ... s_{i_n}\).
INPUT:
m
– integerI
– tuple(i_1, i_2, ..., i_n)
of integers. We assume that this sequence is strictly decreasing.
Using the simplicial identities (see
simplicial_set
), we can rewrite\[d_m s_{i_1} s_{i_2} ... s_{i_n}\]in one of the forms
\[s_{j_1} s_{j_2} ... s_{j_n} d_t, \quad s_{j_1} s_{j_2} ... s_{j_{n-1}}.\]OUTPUT: the pair
(J, t)
or(J, None)
.J
is returned as a list.EXAMPLES:
sage: from sage.topology.simplicial_set import face_degeneracies sage: face_degeneracies(0, (1, 0)) ([0], None) sage: face_degeneracies(1, (1, 0)) ([0], None) sage: face_degeneracies(2, (1, 0)) ([0], None) sage: face_degeneracies(3, (1, 0)) ([1, 0], 1) sage: face_degeneracies(3, ()) ([], 3)
- sage.topology.simplicial_set.shrink_simplicial_complex(K)#
Convert the simplicial complex
K
to a “small” simplicial set.First convert
K
naively, then mod out by a large contractible subcomplex, as found bysimplicial_complex.SimplicialComplex._contractible_subcomplex()
. This will produce a simplicial set no larger than, and sometimes much smaller than, the initial simplicial complex.EXAMPLES:
sage: from sage.topology.simplicial_set import shrink_simplicial_complex sage: K = simplicial_complexes.Simplex(3) sage: X = shrink_simplicial_complex(K) sage: X.f_vector() [1] sage: Y = simplicial_complexes.Sphere(2) sage: S2 = shrink_simplicial_complex(Y) sage: S2 Quotient: (Simplicial set with 14 non-degenerate simplices/Simplicial set with 13 non-degenerate simplices) sage: S2.f_vector() [1, 0, 1] sage: S2.homology() {0: 0, 1: 0, 2: Z} sage: Z = simplicial_complexes.SurfaceOfGenus(3) sage: Z.f_vector() [1, 15, 57, 38] sage: Z.homology() {0: 0, 1: Z^6, 2: Z} sage: M = shrink_simplicial_complex(Z) sage: M.f_vector() # random [1, 32, 27] sage: M.homology() {0: 0, 1: Z^6, 2: Z}
- sage.topology.simplicial_set.standardize_degeneracies(*L)#
Return list of indices of degeneracy maps in standard (decreasing) order.
INPUT:
L
– list of integers, representing a composition of degeneracies in a simplicial set.
OUTPUT:
an equivalent list of degeneracies, standardized to be written in decreasing order, using the simplicial identity
\[s_i s_j = s_{j+1} s_i \ \ \text{if } i \leq j.\]For example, \(s_0 s_2 = s_3 s_0\) and \(s_0 s_0 = s_1 s_0\).
EXAMPLES:
sage: from sage.topology.simplicial_set import standardize_degeneracies sage: standardize_degeneracies(0, 0) (1, 0) sage: standardize_degeneracies(0, 0, 0, 0) (3, 2, 1, 0) sage: standardize_degeneracies(1, 2) (3, 1)
- sage.topology.simplicial_set.standardize_face_maps(*L)#
Return list of indices of face maps in standard (non-increasing) order.
INPUT:
L
– list of integers, representing a composition of face maps in a simplicial set.
OUTPUT:
an equivalent list of face maps, standardized to be written in non-increasing order, using the simplicial identity
\[d_i d_j = d_{j-1} d_i \ \ \text{if } i<j.\]For example, \(d_0 d_2 = d_1 d_0\) and \(d_0 d_1 = d_0 d_0\).
EXAMPLES:
sage: from sage.topology.simplicial_set import standardize_face_maps sage: standardize_face_maps(0, 1) (0, 0) sage: standardize_face_maps(0, 2) (1, 0) sage: standardize_face_maps(1, 3, 5) (3, 2, 1)