Simplicial sets - Topology

Skip to content
Back to top
View this page
Edit this page

# 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 nonnegative integers; the set \(X_n\) is called the set of \(n\)-simplices. These sets are connected by 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}\]

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

    sage: simplicial_sets.Torus()
    Torus
    sage: simplicial_sets.RealProjectiveSpace(7)                                        # needs sage.groups
    RP^7
    sage: S5 = simplicial_sets.Sphere(5); S5
    S^5
    sage: S5.nondegenerate_simplices()
    [v_0, sigma_5]

Python

    >>> from sage.all import *
    >>> simplicial_sets.Torus()
    Torus
    >>> simplicial_sets.RealProjectiveSpace(Integer(7))                                        # needs sage.groups
    RP^7
    >>> S5 = simplicial_sets.Sphere(Integer(5)); S5
    S^5
    >>> 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

    sage: Sigma4 = groups.permutation.Symmetric(4)                                      # needs sage.groups
    sage: Sigma4.nerve()                                                                # needs sage.groups
    Nerve of Symmetric group of order 4! as a permutation group

[Python]

    >>> from sage.all import *
    >>> Sigma4 = groups.permutation.Symmetric(Integer(4))                                      # needs sage.groups
    >>> Sigma4.nerve()                                                                # needs sage.groups
    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

    sage: simplicial_sets.ClassifyingSpace(Sigma4)                                      # needs sage.groups
    Classifying space of Symmetric group of order 4! as a permutation group

Python

    >>> from sage.all import *
    >>> simplicial_sets.ClassifyingSpace(Sigma4)                                      # needs sage.groups
    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

    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)

[Python]

    >>> from sage.all import *
    >>> T = simplicial_sets.Torus()
    >>> S3 = simplicial_sets.Sphere(Integer(3))
    >>> T.is_pointed() and S3.is_pointed()
    True
    >>> T.wedge(S3)
    Wedge: (Torus v S^3)
    >>> T.disjoint_union(S3) == T.coproduct(S3)
    False

    >>> W = T.wedge(S3)
    >>> W.inclusion_map(Integer(0)).domain()
    Torus
    >>> W.projection_map(Integer(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

    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)

Python

    >>> from sage.all import *
    >>> pt = simplicial_sets.Simplex(Integer(0))
    >>> edge = pt.cone()
    >>> S1 = edge.quotient(edge.n_skeleton(Integer(0)))
    >>> 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

    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]

[Python]

    >>> from sage.all import *
    >>> S5 = S1.suspension(Integer(4))
    >>> S5
    Sigma^4(Quotient: (Cone of 0-simplex/Simplicial set with 2 non-degenerate simplices))
    >>> 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

    sage: Z1 = S1.unset_base_point()
    sage: Z1.suspension(4).f_vector()
    [2, 2, 2, 2, 1, 1]

Python

    >>> from sage.all import *
    >>> Z1 = S1.unset_base_point()
    >>> Z1.suspension(Integer(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

    sage: simplicial_sets.Simplex(0).cone().f_vector()
    [2, 1]
    sage: simplicial_sets.Point().cone().f_vector()
    [1]

[Python]

    >>> from sage.all import *
    >>> simplicial_sets.Simplex(Integer(0)).cone().f_vector()
    [2, 1]
    >>> 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

    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

Python

    >>> from sage.all import *
    >>> T = simplicial_sets.Torus()
    >>> T == simplicial_sets.Torus()
    False
    >>> T == T
    True
    >>> simplicial_sets.Torus() == simplicial_sets.Torus()
    False
    >>> 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

    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)

[Python]

    >>> from sage.all import *
    >>> X = simplicial_sets.Simplex(Integer(2))
    >>> e,f,g = X.n_cells(Integer(1))
    >>> Y = X.subsimplicial_set([e,f,g])
    >>> Z = X.quotient(Y)

Or equivalently:

Sage

    sage: Y = X.n_skeleton(1)
    sage: Z = X.quotient(Y)
    sage: Z
    Quotient: (2-simplex/Simplicial set with 6 non-degenerate simplices)

Python

    >>> from sage.all import *
    >>> Y = X.n_skeleton(Integer(1))
    >>> Z = X.quotient(Y)
    >>> 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

    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

[Python]

    >>> from sage.all import *
    >>> inc = Y.inclusion_map()
    >>> inc.domain() == Y and inc.codomain() == X
    True
    >>> quo = Z.quotient_map()
    >>> quo.domain()
    2-simplex
    >>> quo.codomain() == Z
    True

You can compute homology groups and the fundamental group of any simplicial set:

Sage

    sage: S1 = simplicial_sets.Sphere(1)
    sage: eight = S1.wedge(S1)
    sage: eight.fundamental_group()                                                     # needs sage.groups
    Finitely presented group < e0, e1 | >

    sage: # needs sage.groups
    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)                                  # needs sage.groups
    sage: RP6.homology(reduced=False, base_ring=GF(2))                                  # needs sage.groups sage.modules
    {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)                                     # needs sage.groups sage.modules
    {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}

Python

    >>> from sage.all import *
    >>> S1 = simplicial_sets.Sphere(Integer(1))
    >>> eight = S1.wedge(S1)
    >>> eight.fundamental_group()                                                     # needs sage.groups
    Finitely presented group < e0, e1 | >

    >>> # needs sage.groups
    >>> Sigma3 = groups.permutation.Symmetric(Integer(3))
    >>> BSigma3 = Sigma3.nerve()
    >>> pi = BSigma3.fundamental_group(); pi
    Finitely presented group < e1, e2 | e2^2, e1^3, (e2*e1)^2 >
    >>> pi.order()
    6
    >>> pi.is_abelian()
    False

    >>> RP6 = simplicial_sets.RealProjectiveSpace(Integer(6))                                  # needs sage.groups
    >>> RP6.homology(reduced=False, base_ring=GF(Integer(2)))                                  # needs sage.groups sage.modules
    {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}
    >>> RP6.homology(reduced=False, base_ring=QQ)                                     # needs sage.groups sage.modules
    {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

    sage: # needs sage.groups
    sage: G = groups.misc.MultiplicativeAbelian([3])
    sage: B3 = simplicial_sets.ClassifyingSpace(G)
    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))                                             # needs sage.modules
    {0: 0, 1: Z x C3, 2: C3, 3: C3}

[Python]

    >>> from sage.all import *
    >>> # needs sage.groups
    >>> G = groups.misc.MultiplicativeAbelian([Integer(3)])
    >>> B3 = simplicial_sets.ClassifyingSpace(G)
    >>> B3.disjoint_union(B3).n_skeleton(Integer(3))
    Disjoint union: (Simplicial set with 15 non-degenerate simplices
                      u Simplicial set with 15 non-degenerate simplices)
    >>> S1 = simplicial_sets.Sphere(Integer(1))
    >>> B3.product(S1).homology(range(Integer(4)))                                             # needs sage.modules
    {0: 0, 1: Z x C3, 2: C3, 3: C3}

Without the `range` argument, this would raise an error, since `B3` is infinite:

Sage

    sage: B3.product(S1).homology()                                                     # needs sage.groups sage.modules
    Traceback (most recent call last):
    ...
    NotImplementedError: this simplicial set may be infinite,
    so specify dimensions when computing homology

Python

    >>> from sage.all import *
    >>> B3.product(S1).homology()                                                     # needs sage.groups sage.modules
    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

    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)})

[Python]

    >>> from sage.all import *
    >>> from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
    >>> v = AbstractSimplex(Integer(0), name='v')
    >>> w = AbstractSimplex(Integer(0), name='w')
    >>> e = AbstractSimplex(Integer(1), name='e')
    >>> f = AbstractSimplex(Integer(1), name='f')
    >>> 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

    sage: X.homology(1)                                                                 # needs sage.modules
    Z

Python

    >>> from sage.all import *
    >>> X.homology(Integer(1))                                                                 # needs sage.modules
    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` – nonnegative integer; the dimension of the underlying non-degenerate simplex

  - `degeneracies` – (default: `None`) list or tuple of nonnegative 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 method `AbstractSimplex_class.apply_degeneracies()`.

  EXAMPLES:

  Sage

      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

  Python

      >>> from sage.all import *
      >>> from sage.topology.simplicial_set import AbstractSimplex
      >>> AbstractSimplex(Integer(3), (Integer(3), Integer(1)))
      s_3 s_1 Delta^3
      >>> AbstractSimplex(Integer(3), None)
      Delta^3
      >>> AbstractSimplex(Integer(3))
      Delta^3

  Simplices may be named (or renamed), affecting how they are printed:

  Sage

      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

  [Python]

      >>> from sage.all import *
      >>> AbstractSimplex(Integer(0))
      Delta^0
      >>> v = AbstractSimplex(Integer(0), name='v')
      >>> v
      v
      >>> v.rename('w_0')
      >>> v
      w_0
      >>> latex(v)
      w_0
      >>> latex(AbstractSimplex(Integer(0), latex_name='\\sigma'))
      \sigma

  The simplicial identities are used to put the degeneracies in standard decreasing form:

  Sage

      sage: x = AbstractSimplex(0, (0, 0, 0))
      sage: x
      s_2 s_1 s_0 Delta^0
      sage: x.degeneracies()
      [2, 1, 0]

  Python

      >>> from sage.all import *
      >>> x = AbstractSimplex(Integer(0), (Integer(0), Integer(0), Integer(0)))
      >>> x
      s_2 s_1 s_0 Delta^0
      >>> x.degeneracies()
      [2, 1, 0]

  Use of the `underlying` argument:

  Sage

      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

  [Python]

      >>> from sage.all import *
      >>> v = AbstractSimplex(Integer(0), name='v')
      >>> e = AbstractSimplex(Integer(0), (Integer(0),), underlying=v)
      >>> e
      s_0 v
      >>> e.nondegenerate() is v
      True

      >>> e.dimension()
      1
      >>> e.is_degenerate()
      True

  Distinct non-degenerate simplices are never equal:

  Sage

      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

  Python

      >>> from sage.all import *
      >>> AbstractSimplex(Integer(0), None) == AbstractSimplex(Integer(0), None)
      False
      >>> AbstractSimplex(Integer(0), (Integer(2),Integer(1),Integer(0))) == AbstractSimplex(Integer(0), (Integer(2),Integer(1),Integer(0)))
      False

      >>> e = AbstractSimplex(Integer(0), ((Integer(0),)))
      >>> f = AbstractSimplex(Integer(0), ((Integer(0),)))
      >>> e == f
      False
      >>> 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 constructing `AbstractSimplex(0)` and then applying degeneracies to it, and you always get distinct simplices from different calls to `AbstractSimplex(0)`. On the other hand, if you apply degeneracies to the same non-degenerate simplex, the resulting simplices are equal:

  Sage

      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

  [Python]

      >>> from sage.all import *
      >>> v = AbstractSimplex(Integer(0))
      >>> v.apply_degeneracies(Integer(1), Integer(0)) == v.apply_degeneracies(Integer(1), Integer(0))
      True
      >>> AbstractSimplex(Integer(1), (Integer(0),), underlying=v) == AbstractSimplex(Integer(1), (Integer(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 dimension

  - `degeneracies` – (optional) iterable, the indices of the degeneracy maps

  - `underlying` – (optional) a non-degenerate simplex

  - `name` – (optional) string

  - `latex_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` – integer

    EXAMPLES:

    Sage

        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

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex
        >>> v = AbstractSimplex(Integer(0))
        >>> e = v.apply_degeneracies(Integer(0))
        >>> e.nondegenerate() == v
        True
        >>> f = e.apply_degeneracies(Integer(0))
        >>> f
        s_1 s_0 Delta^0
        >>> f.degeneracies()
        [1, 0]
        >>> f.nondegenerate() == v
        True
        >>> v.apply_degeneracies(Integer(1), Integer(0))
        s_1 s_0 Delta^0

  degeneracies()

    Return the list of indices for the degeneracy maps for this simplex.

    EXAMPLES:

    Sage

        sage: from sage.topology.simplicial_set import AbstractSimplex
        sage: AbstractSimplex(4, (0,0,0)).degeneracies()
        [2, 1, 0]
        sage: AbstractSimplex(4, None).degeneracies()
        []

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex
        >>> AbstractSimplex(Integer(4), (Integer(0),Integer(0),Integer(0))).degeneracies()
        [2, 1, 0]
        >>> AbstractSimplex(Integer(4), None).degeneracies()
        []

  dimension()

    The dimension of this simplex.

    EXAMPLES:

    Sage

        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

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex
        >>> AbstractSimplex(Integer(3), (Integer(2),Integer(1))).dimension()
        5
        >>> AbstractSimplex(Integer(3), None).dimension()
        3
        >>> AbstractSimplex(Integer(7)).dimension()
        7

  is_degenerate()

    Return `True` if this simplex is degenerate.

    EXAMPLES:

    Sage

        sage: from sage.topology.simplicial_set import AbstractSimplex
        sage: AbstractSimplex(3, (2,1)).is_degenerate()
        True
        sage: AbstractSimplex(3, None).is_degenerate()
        False

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex
        >>> AbstractSimplex(Integer(3), (Integer(2),Integer(1))).is_degenerate()
        True
        >>> AbstractSimplex(Integer(3), None).is_degenerate()
        False

  is_nondegenerate()

    Return `True` if this simplex is non-degenerate.

    EXAMPLES:

    Sage

        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

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex
        >>> AbstractSimplex(Integer(3), (Integer(2),Integer(1))).is_nondegenerate()
        False
        >>> AbstractSimplex(Integer(3), None).is_nondegenerate()
        True
        >>> AbstractSimplex(Integer(5)).is_nondegenerate()
        True

  nondegenerate()

    The non-degenerate simplex underlying this one.

    Therefore return itself if this simplex is non-degenerate.

    EXAMPLES:

    Sage

        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

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex
        >>> v = AbstractSimplex(Integer(0), name='v')
        >>> sigma = v.apply_degeneracies(Integer(1), Integer(0))
        >>> sigma.nondegenerate()
        v
        >>> tau = AbstractSimplex(Integer(1), (Integer(3),Integer(2),Integer(1)))
        >>> x = tau.nondegenerate(); x
        Delta^1
        >>> x == tau.nondegenerate()
        True

        >>> AbstractSimplex(Integer(1), None)
        Delta^1
        >>> AbstractSimplex(Integer(1), None) == x
        False
        >>> AbstractSimplex(Integer(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` – nonnegative integer; the dimension

  - `name` – (optional) string; a name for this simplex

  - `latex_name` – (optional) string; a name for this simplex to use in the LaTeX representation

  EXAMPLES:

  Sage

      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'>

  Python

      >>> from sage.all import *
      >>> from sage.topology.simplicial_set import AbstractSimplex
      >>> v = AbstractSimplex(Integer(0), name='v')
      >>> v
      v
      >>> 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

      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

  [Python]

      >>> from sage.all import *
      >>> v == AbstractSimplex(Integer(0), name='v')
      False
      >>> AbstractSimplex(Integer(3)) == AbstractSimplex(Integer(3))
      False

      >>> from sage.topology.simplicial_set import NonDegenerateSimplex
      >>> x = NonDegenerateSimplex(Integer(0), name='x')
      >>> x == NonDegenerateSimplex(Integer(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 nonnegative 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` and `Nerve` for two examples. In particular, any such class must implement a method `n_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, like `is_pointed` and `is_finite`, work correctly.

  Note that the method `subsimplicial_set()` calls `n_skeleton()`, so to avoid circularity, the `n_skeleton()` method should call `simplicial_set_constructions.SubSimplicialSet` directly, not `subsimplicial_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 dimension `dim - dim_left`, if `dim` is the dimension of the starting simplex. The results are obtained by applying iterated face maps to `simplex`. Writing \(d\) for `dim` and \(j\) for `dim_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: list containing the triple `(c, left, right)`, where `left` and `right` are the two simplices described above. If either `left` or `right` 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

        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)]

    Python

        >>> from sage.all import *
        >>> S2 = simplicial_sets.Sphere(Integer(2))
        >>> sigma = S2.n_cells(Integer(2))[Integer(0)]
        >>> S2.alexander_whitney(sigma, Integer(0))
        [(1, v_0, sigma_2)]
        >>> S2.alexander_whitney(sigma, Integer(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

        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})

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
        >>> v = AbstractSimplex(Integer(0), name='v')
        >>> w = AbstractSimplex(Integer(0), name='w')
        >>> degen = v.apply_degeneracies(Integer(0))
        >>> tau = AbstractSimplex(Integer(2), name='tau')
        >>> Y = SimplicialSet({tau: (degen, degen, degen), w: None})

    `Y` is the disjoint union of a 2-sphere, with vertex `v` and non-degenerate 2-simplex `tau`, and a point `w`.

    Sage

        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]

    [Python]

        >>> from sage.all import *
        >>> Y.all_n_simplices(Integer(0))
        [v, w]
        >>> Y.all_n_simplices(Integer(1))
        [s_0 v, s_0 w]
        >>> Y.all_n_simplices(Integer(2))
        [tau, s_1 s_0 v, s_1 s_0 w]

    An example involving an infinite simplicial set:

    Sage

        sage: C3 = groups.misc.MultiplicativeAbelian([3])                           # needs sage.groups
        sage: BC3 = simplicial_sets.ClassifyingSpace(C3)                            # needs sage.groups
        sage: BC3.all_n_simplices(2)                                                # needs sage.groups
        [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]

    Python

        >>> from sage.all import *
        >>> C3 = groups.misc.MultiplicativeAbelian([Integer(3)])                           # needs sage.groups
        >>> BC3 = simplicial_sets.ClassifyingSpace(C3)                            # needs sage.groups
        >>> BC3.all_n_simplices(Integer(2))                                                # needs sage.groups
        [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 \(i\)-th Betti number is the rank of the \(i\)-th homology group.

    INPUT:

    - `dim` – (default: `None`) if `None`, then return the homology in every dimension. If `dim` is an integer or list, return the homology in the given dimensions. (Actually, if `dim` is a list, return the homology in the range from `min(dim)` to `max(dim)`.)

    - `subcomplex` – (default: `None`) a subcomplex of 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

        sage: simplicial_sets.Sphere(5).betti()                                     # needs sage.modules
        {0: 1, 1: 0, 2: 0, 3: 0, 4: 0, 5: 1}

        sage: C3 = groups.misc.MultiplicativeAbelian([3])                           # needs sage.groups
        sage: BC3 = simplicial_sets.ClassifyingSpace(C3)                            # needs sage.groups
        sage: BC3.betti(range(4))                                                   # needs sage.groups sage.modules
        {0: 1, 1: 0, 2: 0, 3: 0}

    Python

        >>> from sage.all import *
        >>> simplicial_sets.Sphere(Integer(5)).betti()                                     # needs sage.modules
        {0: 1, 1: 0, 2: 0, 3: 0, 4: 0, 5: 1}

        >>> C3 = groups.misc.MultiplicativeAbelian([Integer(3)])                           # needs sage.groups
        >>> BC3 = simplicial_sets.ClassifyingSpace(C3)                            # needs sage.groups
        >>> BC3.betti(range(Integer(4)))                                                   # needs sage.groups sage.modules
        {0: 1, 1: 0, 2: 0, 3: 0}

  cartesian_product(*others)

    alias of `product()`.

  cells(subcomplex=None, max_dim=None)

    Return a dictionary of all non-degenerate simplices.

    INPUT:

    - `subcomplex` – (optional) a subsimplicial set of this simplicial set. If `subcomplex` is specified, then return the simplices in the quotient by the subcomplex.

    - `max_dim` – (default: `None`) 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

        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]}

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
        >>> v = AbstractSimplex(Integer(0))
        >>> w = AbstractSimplex(Integer(0))
        >>> S0 = SimplicialSet({v: None, w: None})
        >>> S0.cells()
        {0: [Delta^0, Delta^0]}

        >>> v.rename('v')
        >>> w.rename('w')
        >>> S0.cells()
        {0: [v, w]}

        >>> e = AbstractSimplex(Integer(1), name='e')
        >>> S1 = SimplicialSet({e: (v, v)})
        >>> S1.cells()
        {0: [v], 1: [e]}

        >>> S0.cells(S0.subsimplicial_set([v, w]))
        {0: [*]}

        >>> X = SimplicialSet({e: (v,w)})
        >>> X.cells(X.subsimplicial_set([v, w]))
        {0: [*], 1: [e]}

    Test an infinite example:

    Sage

        sage: # needs sage.groups
        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

    [Python]

        >>> from sage.all import *
        >>> # needs sage.groups
        >>> C3 = groups.misc.MultiplicativeAbelian([Integer(3)])
        >>> BC3 = simplicial_sets.ClassifyingSpace(C3)
        >>> BC3.cells(max_dim=Integer(2))
        {0: [1], 1: [f, f^2], 2: [f * f, f * f^2, f^2 * f, f^2 * f^2]}
        >>> 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` – if `None`, 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` – (default: \(\ZZ\)) commutative ring

    - `augmented` – boolean (default: `False`); if `True`, return the augmented chain complex (that is, include a class in dimension \(-1\) corresponding to the empty cell)

    - `cochain` – boolean (default: `False`); if `True`, return the cochain complex (that is, the dual of the chain complex)

    - `verbose` – boolean (default: `False`); ignored

    - `subcomplex` – (default: `None`) if present, compute the chain complex relative to this subcomplex

    - `check` – boolean (default: `False`); if `True`, 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

        sage: simplicial_sets.Sphere(5).chain_complex()                             # needs sage.modules
        Chain complex with at most 3 nonzero terms over Integer Ring

        sage: C3 = groups.misc.MultiplicativeAbelian([3])                           # needs sage.groups
        sage: BC3 = simplicial_sets.ClassifyingSpace(C3)                            # needs sage.groups
        sage: BC3.chain_complex(range(4), base_ring=GF(3))                          # needs sage.groups sage.modules
        Chain complex with at most 4 nonzero terms over Finite Field of size 3

    Python

        >>> from sage.all import *
        >>> simplicial_sets.Sphere(Integer(5)).chain_complex()                             # needs sage.modules
        Chain complex with at most 3 nonzero terms over Integer Ring

        >>> C3 = groups.misc.MultiplicativeAbelian([Integer(3)])                           # needs sage.groups
        >>> BC3 = simplicial_sets.ClassifyingSpace(C3)                            # needs sage.groups
        >>> BC3.chain_complex(range(Integer(4)), base_ring=GF(Integer(3)))                          # needs sage.groups sage.modules
        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` – (default: `None`) if `None`, then return the homology in every dimension. If `dim` is an integer or list, return the homology in the given dimensions. (Actually, if `dim` is a list, return the homology in the range from `min(dim)` to `max(dim)`.)

    - `base_ring` – (default: `ZZ`) commutative ring; must be `ZZ` or a field

    Other arguments are also allowed, the same as for the `homology()` method – see `cell_complex.GenericCellComplex.homology()` for complete documentation – except that `homology()` accepts a `cohomology` key word, while this function does not: `cohomology` is automatically true here. Indeed, this function just calls `homology()` with argument `cohomology=True`.

    Note

    If this simplicial set is not finite, you must specify dimensions in which to compute homology via the argument `dim`.

    EXAMPLES:

    Sage

        sage: simplicial_sets.KleinBottle().homology(1)                             # needs sage.modules
        Z x C2
        sage: simplicial_sets.KleinBottle().cohomology(1)                           # needs sage.modules
        Z
        sage: simplicial_sets.KleinBottle().cohomology(2)                           # needs sage.modules
        C2

    Python

        >>> from sage.all import *
        >>> simplicial_sets.KleinBottle().homology(Integer(1))                             # needs sage.modules
        Z x C2
        >>> simplicial_sets.KleinBottle().cohomology(Integer(1))                           # needs sage.modules
        Z
        >>> simplicial_sets.KleinBottle().cohomology(Integer(2))                           # needs sage.modules
        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

        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()
        *

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
        >>> v = AbstractSimplex(Integer(0), name='v')
        >>> e = AbstractSimplex(Integer(1), name='e')
        >>> X = SimplicialSet({e: (v, v)})
        >>> CX = X.cone()  # unreduced cone, since X not pointed
        >>> CX.nondegenerate_simplices()
        [*, v, (v,*), e, (e,*)]
        >>> CX.base_point()
        *

    \(X\) as a subset of the cone, and also the map from \(X\), in the unreduced case:

    Sage

        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]

    [Python]

        >>> from sage.all import *
        >>> CX.base_as_subset()
        Simplicial set with 2 non-degenerate simplices
        >>> 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

        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]

    Python

        >>> from sage.all import *
        >>> X = X.set_base_point(v)
        >>> CX = X.cone()  # reduced cone
        >>> CX.nondegenerate_simplices()
        [*, e, (e,*)]
        >>> 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` – (default: `None`) if `None`, the codomain is the standard one-point space constructed by `Point()`. Otherwise, either the codomain must be a pointed simplicial set, in which case the map is constant at the base point, or `point` must be specified.

    - `point` – (default: `None`) if specified, it must be a 0-simplex in the codomain, and it will be the target of the constant map

    EXAMPLES:

    Sage

        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)                              # needs sage.groups
        sage: Sigma3.nerve().constant_map()                                         # needs sage.groups
        Simplicial set morphism:
          From: Nerve of Symmetric group of order 3! as a permutation group
          To:   Point
          Defn: Constant map at *

    Python

        >>> from sage.all import *
        >>> S4 = simplicial_sets.Sphere(Integer(4))
        >>> S4.constant_map()
        Simplicial set morphism:
          From: S^4
          To:   Point
          Defn: Constant map at *
        >>> S0 = simplicial_sets.Sphere(Integer(0))
        >>> S4.constant_map(codomain=S0)
        Simplicial set morphism:
          From: S^4
          To:   S^0
          Defn: Constant map at v_0

        >>> Sigma3 = groups.permutation.Symmetric(Integer(3))                              # needs sage.groups
        >>> Sigma3.nerve().constant_map()                                         # needs sage.groups
        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

        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)

    Python

        >>> from sage.all import *
        >>> S2 = simplicial_sets.Sphere(Integer(2))
        >>> K = simplicial_sets.KleinBottle()
        >>> D3 = simplicial_sets.Simplex(Integer(3))
        >>> Y = S2.unset_base_point()
        >>> Z = K.unset_base_point()

        >>> S2.coproduct(K).is_pointed()
        True
        >>> S2.coproduct(K)
        Wedge: (S^2 v Klein bottle)
        >>> D3.coproduct(Y, Z).is_pointed()
        False
        >>> 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

        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}]

    [Python]

        >>> from sage.all import *
        >>> S2.coproduct(K).inclusion_map(Integer(0))
        Simplicial set morphism:
          From: S^2
          To:   Wedge: (S^2 v Klein bottle)
          Defn: [v_0, sigma_2] --> [*, sigma_2]
        >>> D3.coproduct(Y, Z).inclusion_map(Integer(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

        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)

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
        >>> v = AbstractSimplex(Integer(0), name='v')
        >>> w = AbstractSimplex(Integer(0), name='w')
        >>> e = AbstractSimplex(Integer(1), name='e')
        >>> f = AbstractSimplex(Integer(1), name='f')
        >>> X = SimplicialSet({e: (v, v)})
        >>> Y = SimplicialSet({f: (v, w)})
        >>> Z = X.disjoint_union(Y)

    Since `X` and `Y` have simplices in common, Sage uses a copy of `Y` when constructing the disjoint union. Note the name conflict in the list of simplices: `v` appears twice:

    Sage

        sage: Z = X.disjoint_union(Y)
        sage: Z.nondegenerate_simplices()
        [v, v, w, e, f]

    [Python]

        >>> from sage.all import *
        >>> Z = X.disjoint_union(Y)
        >>> Z.nondegenerate_simplices()
        [v, v, w, e, f]

    Factors and inclusion maps:

    Sage

        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)

    Python

        >>> from sage.all import *
        >>> T = simplicial_sets.Torus()
        >>> S2 = simplicial_sets.Sphere(Integer(2))
        >>> A = T.disjoint_union(S2)
        >>> A.factors()
        (Torus, S^2)
        >>> i = A.inclusion_map(Integer(0))
        >>> i.domain()
        Torus
        >>> i.codomain()
        Disjoint union: (Torus u S^2)

    Empty factors are ignored:

    Sage

        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)

    [Python]

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set_examples import Empty
        >>> E = Empty()
        >>> K = S2.disjoint_union(S2, E, E, S2)
        >>> K == S2.disjoint_union(S2, S2)
        True
        >>> 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 set

    - `i` – integer

    EXAMPLES:

    Sage

        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

    Python

        >>> from sage.all import *
        >>> S2 = simplicial_sets.Sphere(Integer(2))
        >>> sigma = S2.n_cells(Integer(2))[Integer(0)]
        >>> v_0 = S2.n_cells(Integer(0))[Integer(0)]
        >>> S2.face(sigma, Integer(0))
        s_0 v_0
        >>> S2.face(sigma, Integer(0)) == v_0.apply_degeneracies(Integer(0))
        True
        >>> S2.face(S2.face(sigma, Integer(0)), Integer(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

        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: # needs sage.groups
        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)

    Python

        >>> from sage.all import *
        >>> S2 = simplicial_sets.Sphere(Integer(2))
        >>> sigma = S2.n_cells(Integer(2))[Integer(0)]
        >>> S2.faces(sigma)
        (s_0 v_0, s_0 v_0, s_0 v_0)
        >>> S2.faces(sigma.apply_degeneracies(Integer(0)))
        [sigma_2, sigma_2, s_1 s_0 v_0, s_1 s_0 v_0]

        >>> # needs sage.groups
        >>> C3 = groups.misc.MultiplicativeAbelian([Integer(3)])
        >>> BC3 = simplicial_sets.ClassifyingSpace(C3)
        >>> f2 = BC3.n_cells(Integer(1))[Integer(1)]; f2
        f^2
        >>> BC3.faces(f2)
        (1, 1)

  graph()

    Return the 1-skeleton of this simplicial set, as a graph.

    EXAMPLES:

    Sage

        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: # needs pyparsing
        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)                              # needs sage.groups
        sage: Sigma3.nerve().is_connected()                                         # needs sage.groups
        True

    Python

        >>> from sage.all import *
        >>> Delta3 = simplicial_sets.Simplex(Integer(3))
        >>> G = Delta3.graph()
        >>> 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))]

        >>> T = simplicial_sets.Torus()
        >>> T.graph()
        Looped multi-graph on 1 vertex
        >>> len(T.graph().edges(sort=False))
        3

        >>> # needs pyparsing
        >>> CP3 = simplicial_sets.ComplexProjectiveSpace(Integer(3))
        >>> G = CP3.graph()
        >>> len(G.vertices(sort=False))
        1
        >>> len(G.edges(sort=False))
        0

        >>> Sigma3 = groups.permutation.Symmetric(Integer(3))                              # needs sage.groups
        >>> Sigma3.nerve().is_connected()                                         # needs sage.groups
        True

  homology(dim=None, **kwds)

    Return the (reduced) homology of this simplicial set.

    INPUT:

    - `dim` – (default: `None`) if `None`, then return the homology in every dimension. If `dim` is an integer or list, return the homology in the given dimensions. (Actually, if `dim` is a list, return the homology in the range from `min(dim)` to `max(dim)`.)

    - `base_ring` – (default: `ZZ`) commutative ring; must be `ZZ` 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

        sage: simplicial_sets.Sphere(5).homology()                                  # needs sage.modules
        {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: Z}

        sage: C3 = groups.misc.MultiplicativeAbelian([3])                           # needs sage.groups
        sage: BC3 = simplicial_sets.ClassifyingSpace(C3)                            # needs sage.groups
        sage: BC3.homology(range(4), base_ring=GF(3))                               # needs sage.groups sage.modules
        {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: # needs sage.groups
        sage: C2 = groups.misc.MultiplicativeAbelian([2])
        sage: BC2 = simplicial_sets.ClassifyingSpace(C2)
        sage: BK = BC2.product(BC2)
        sage: BK.homology(range(4))                                                 # needs sage.modules
        {0: 0, 1: C2 x C2, 2: C2, 3: C2 x C2 x C2}

    Python

        >>> from sage.all import *
        >>> simplicial_sets.Sphere(Integer(5)).homology()                                  # needs sage.modules
        {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: Z}

        >>> C3 = groups.misc.MultiplicativeAbelian([Integer(3)])                           # needs sage.groups
        >>> BC3 = simplicial_sets.ClassifyingSpace(C3)                            # needs sage.groups
        >>> BC3.homology(range(Integer(4)), base_ring=GF(Integer(3)))                               # needs sage.groups sage.modules
        {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}

        >>> # needs sage.groups
        >>> C2 = groups.misc.MultiplicativeAbelian([Integer(2)])
        >>> BC2 = simplicial_sets.ClassifyingSpace(C2)
        >>> BK = BC2.product(BC2)
        >>> BK.homology(range(Integer(4)))                                                 # needs sage.modules
        {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

        sage: S3 = simplicial_sets.Sphere(3)
        sage: S3.identity()
        Simplicial set endomorphism of S^3
          Defn: Identity map

        sage: # needs sage.groups
        sage: C3 = groups.misc.MultiplicativeAbelian([3])
        sage: BC3 = simplicial_sets.ClassifyingSpace(C3)
        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)]

    Python

        >>> from sage.all import *
        >>> S3 = simplicial_sets.Sphere(Integer(3))
        >>> S3.identity()
        Simplicial set endomorphism of S^3
          Defn: Identity map

        >>> # needs sage.groups
        >>> C3 = groups.misc.MultiplicativeAbelian([Integer(3)])
        >>> BC3 = simplicial_sets.ClassifyingSpace(C3)
        >>> one = BC3.identity()
        >>> [(sigma, one(sigma)) for sigma in BC3.n_cells(Integer(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

        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

    Python

        >>> from sage.all import *
        >>> T = simplicial_sets.Torus()
        >>> K = simplicial_sets.KleinBottle()
        >>> X = T.disjoint_union(K)
        >>> T.is_connected()
        True
        >>> K.is_connected()
        True
        >>> X.is_connected()
        False
        >>> simplicial_sets.Sphere(Integer(0)).is_connected()
        False

  is_reduced()

    Return `True` if this simplicial set has only one vertex.

    EXAMPLES:

    Sage

        sage: simplicial_sets.Sphere(0).is_reduced()
        False
        sage: simplicial_sets.Sphere(3).is_reduced()
        True

    Python

        >>> from sage.all import *
        >>> simplicial_sets.Sphere(Integer(0)).is_reduced()
        False
        >>> simplicial_sets.Sphere(Integer(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

        sage: K = simplicial_sets.Simplex(2)
        sage: K.join(K)
        Traceback (most recent call last):
        ...
        NotImplementedError: joins are not implemented for simplicial sets

    Python

        >>> from sage.all import *
        >>> K = simplicial_sets.Simplex(Integer(2))
        >>> 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 argument `subcomplex` is present, then return the `n`-dimensional faces in the quotient by this subcomplex.

    INPUT:

    - `n` – the dimension

    - `subcomplex` – (default: `None`) a subcomplex of this cell complex. Return the cells which are in the quotient by this subcomplex.

    EXAMPLES:

    Sage

        sage: simplicial_sets.Sphere(3).n_cells(3)
        [sigma_3]
        sage: simplicial_sets.Sphere(3).n_cells(2)
        []
        sage: C2 = groups.misc.MultiplicativeAbelian([2])                           # needs sage.groups
        sage: BC2 = C2.nerve()                                                      # needs sage.groups
        sage: BC2.n_cells(3)                                                        # needs sage.groups
        [f * f * f]

    Python

        >>> from sage.all import *
        >>> simplicial_sets.Sphere(Integer(3)).n_cells(Integer(3))
        [sigma_3]
        >>> simplicial_sets.Sphere(Integer(3)).n_cells(Integer(2))
        []
        >>> C2 = groups.misc.MultiplicativeAbelian([Integer(2)])                           # needs sage.groups
        >>> BC2 = C2.nerve()                                                      # needs sage.groups
        >>> BC2.n_cells(Integer(3))                                                        # needs sage.groups
        [f * f * f]

  n_chains(n, base_ring=Integer Ring, cochains=False)

    Return the free module of (normalized) chains in degree `n` over `base_ring`.

    This is the free module on the nondegenerate simplices in the given dimension.

    INPUT:

    - `n` – integer

    - `base_ring` – ring (default: \(\ZZ\))

    - `cochains` – boolean (default: `False`); if `True`, 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

        sage: S3 = simplicial_sets.Sphere(3)
        sage: C = S3.n_chains(3, cochains=True)                                     # needs sage.modules
        sage: list(C.basis())                                                       # needs sage.modules
        [\chi_sigma_3]

        sage: # needs sage.groups
        sage: Sigma3 = groups.permutation.Symmetric(3)
        sage: BSigma3 = simplicial_sets.ClassifyingSpace(Sigma3)
        sage: list(BSigma3.n_chains(1).basis())                                     # needs sage.modules
        [(1,2), (1,2,3), (1,3), (1,3,2), (2,3)]
        sage: list(BSigma3.n_chains(1, cochains=True).basis())                      # needs sage.modules
        [\chi_(1,2), \chi_(1,2,3), \chi_(1,3), \chi_(1,3,2), \chi_(2,3)]

    Python

        >>> from sage.all import *
        >>> S3 = simplicial_sets.Sphere(Integer(3))
        >>> C = S3.n_chains(Integer(3), cochains=True)                                     # needs sage.modules
        >>> list(C.basis())                                                       # needs sage.modules
        [\chi_sigma_3]

        >>> # needs sage.groups
        >>> Sigma3 = groups.permutation.Symmetric(Integer(3))
        >>> BSigma3 = simplicial_sets.ClassifyingSpace(Sigma3)
        >>> list(BSigma3.n_chains(Integer(1)).basis())                                     # needs sage.modules
        [(1,2), (1,2,3), (1,3), (1,3,2), (2,3)]
        >>> list(BSigma3.n_chains(Integer(1), cochains=True).basis())                      # needs sage.modules
        [\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` – (default: `None`) 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

        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]

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
        >>> v = AbstractSimplex(Integer(0))
        >>> w = AbstractSimplex(Integer(0))
        >>> S0 = SimplicialSet({v: None, w: None})
        >>> S0.nondegenerate_simplices()
        [Delta^0, Delta^0]

    Name the vertices and reconstruct the simplicial set: they should be ordered alphabetically:

    Sage

        sage: v.rename('v')
        sage: w.rename('w')
        sage: S0 = SimplicialSet({v: None, w: None})
        sage: S0.nondegenerate_simplices()
        [v, w]

    [Python]

        >>> from sage.all import *
        >>> v.rename('v')
        >>> w.rename('w')
        >>> S0 = SimplicialSet({v: None, w: None})
        >>> S0.nondegenerate_simplices()
        [v, w]

    Rename but do not reconstruct the set; the ordering does not take the new names into account:

    Sage

        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]

    Python

        >>> from sage.all import *
        >>> v.rename('z')
        >>> S0.nondegenerate_simplices() # old ordering is used
        [z, w]

        >>> X0 = SimplicialSet({v: None, w: None})
        >>> X0.nondegenerate_simplices() # new ordering is used
        [w, z]

    Test an infinite example:

    Sage

        sage: # needs sage.groups
        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

    [Python]

        >>> from sage.all import *
        >>> # needs sage.groups
        >>> C3 = groups.misc.MultiplicativeAbelian([Integer(3)])
        >>> BC3 = simplicial_sets.ClassifyingSpace(C3)
        >>> BC3.nondegenerate_simplices(Integer(2))
        [1, f, f^2, f * f, f * f^2, f^2 * f, f^2 * f^2]
        >>> 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

        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)

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
        >>> v = AbstractSimplex(Integer(0), name='v')
        >>> w = AbstractSimplex(Integer(0), name='w')
        >>> e = AbstractSimplex(Integer(1), name='e')
        >>> X = SimplicialSet({e: (v, w)})
        >>> 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

        sage: square.f_vector()
        [4, 5, 2]

        sage: S1 = simplicial_sets.Sphere(1)
        sage: T = S1.product(S1)
        sage: T.homology(reduced=False)                                             # needs sage.modules
        {0: Z, 1: Z x Z, 2: Z}

    [Python]

        >>> from sage.all import *
        >>> square.f_vector()
        [4, 5, 2]

        >>> S1 = simplicial_sets.Sphere(Integer(1))
        >>> T = S1.product(S1)
        >>> T.homology(reduced=False)                                             # needs sage.modules
        {0: Z, 1: Z x Z, 2: Z}

    Since `S1` is pointed, so is `T`:

    Sage

        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)                                         # needs sage.modules
        {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: # needs sage.groups
        sage: G = groups.misc.MultiplicativeAbelian([2])
        sage: B = simplicial_sets.ClassifyingSpace(G)
        sage: B.rename('RP^oo')
        sage: X = B.product(B, S2); X
        RP^oo x RP^oo x S^2
        sage: X.factor(1)
        RP^oo
        sage: X.factors()
        (RP^oo, RP^oo, S^2)

    Python

        >>> from sage.all import *
        >>> S1.is_pointed()
        True
        >>> S1.base_point()
        v_0
        >>> T.is_pointed()
        True
        >>> T.base_point()
        (v_0, v_0)

        >>> S2 = simplicial_sets.Sphere(Integer(2))
        >>> S3 = simplicial_sets.Sphere(Integer(3))
        >>> S2xS3 = S2.product(S3)
        >>> S2xS3.homology(reduced=False)                                         # needs sage.modules
        {0: Z, 1: 0, 2: Z, 3: Z, 4: 0, 5: Z}

        >>> S2xS3.factors() == (S2, S3)
        True
        >>> S2xS3.factors() == (S3, S2)
        False

        >>> # needs sage.groups
        >>> G = groups.misc.MultiplicativeAbelian([Integer(2)])
        >>> B = simplicial_sets.ClassifyingSpace(G)
        >>> B.rename('RP^oo')
        >>> X = B.product(B, S2); X
        RP^oo x RP^oo x S^2
        >>> X.factor(Integer(1))
        RP^oo
        >>> X.factors()
        (RP^oo, RP^oo, S^2)

    Projection maps and wedges:

    Sage

        sage: S2xS3.projection_map(0)
        Simplicial set morphism:
          From: S^2 x S^3
          To:   S^2
          Defn: ...
        sage: S2xS3.wedge_as_subset().homology()                                    # needs sage.modules
        {0: 0, 1: 0, 2: Z, 3: Z}

    [Python]

        >>> from sage.all import *
        >>> S2xS3.projection_map(Integer(0))
        Simplicial set morphism:
          From: S^2 x S^3
          To:   S^2
          Defn: ...
        >>> S2xS3.wedge_as_subset().homology()                                    # needs sage.modules
        {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

        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)]

    Python

        >>> from sage.all import *
        >>> one = S2.identity()
        >>> const = S2.constant_map(codomain=S3)
        >>> 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

        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)                                                         # needs sage.modules
        Z x Z

    Python

        >>> from sage.all import *
        >>> S2 = simplicial_sets.Sphere(Integer(2))
        >>> pt = simplicial_sets.Point()
        >>> P = pt.pullback(S2.constant_map(), S2.constant_map())
        >>> P.homology(Integer(2))                                                         # needs sage.modules
        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

        sage: S2 = simplicial_sets.Sphere(2)
        sage: one = S2.Hom(S2).identity()
        sage: P = S2.pullback(one, one)
        sage: P.homology()                                                          # needs sage.modules
        {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

    [Python]

        >>> from sage.all import *
        >>> S2 = simplicial_sets.Sphere(Integer(2))
        >>> one = S2.Hom(S2).identity()
        >>> P = S2.pullback(one, one)
        >>> P.homology()                                                          # needs sage.modules
        {0: 0, 1: 0, 2: Z}

        >>> P.defining_map(Integer(0)) == one
        True
        >>> P.structure_map(Integer(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]
        >>> P.structure_map(Integer(0)).domain() == P
        True
        >>> P.structure_map(Integer(0)).codomain() == S2
        True

    The universal property:

    Sage

        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

    Python

        >>> from sage.all import *
        >>> S1 = simplicial_sets.Sphere(Integer(1))
        >>> T = S1.product(S1)
        >>> K = T.factor(Integer(0), as_subset=True)
        >>> f = S1.Hom(T)({S1.n_cells(Integer(0))[Integer(0)]: K.n_cells(Integer(0))[Integer(0)],
        ...                S1.n_cells(Integer(1))[Integer(0)]: K.n_cells(Integer(1))[Integer(0)]})
        >>> D = S1.cone()          # the cone C(S^1)
        >>> g = D.map_from_base()  # map from S^1 to C(S^1)
        >>> P = T.product(D)
        >>> h = P.universal_property(f, g)
        >>> h.domain() == S1
        True
        >>> 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

        sage: K = simplicial_sets.Simplex(4)
        sage: L = K.n_skeleton(3)
        sage: S4 = L.pushout(L.constant_map(), L.inclusion_map()); 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)                                                        # needs sage.modules
        Z

    Python

        >>> from sage.all import *
        >>> K = simplicial_sets.Simplex(Integer(4))
        >>> L = K.n_skeleton(Integer(3))
        >>> S4 = L.pushout(L.constant_map(), L.inclusion_map()); 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)]
        >>> len(S4.nondegenerate_simplices())
        2
        >>> S4.homology(Integer(4))                                                        # needs sage.modules
        Z

    The associated maps:

    Sage

        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]})

    [Python]

        >>> from sage.all import *
        >>> S1 = simplicial_sets.Sphere(Integer(1))
        >>> T = S1.product(S1)
        >>> K = T.factor(Integer(0), as_subset=True)
        >>> W = S1.wedge(T)  # wedge, constructed as a pushout
        >>> W.defining_map(Integer(1))
        Simplicial set morphism:
          From: Point
          To:   S^1 x S^1
          Defn: Constant map at (v_0, v_0)
        >>> W.structure_map(Integer(0))
        Simplicial set morphism:
          From: S^1
          To:   Wedge: (S^1 v S^1 x S^1)
          Defn: [v_0, sigma_1] --> [*, sigma_1]

        >>> f = S1.Hom(T)({S1.n_cells(Integer(0))[Integer(0)]: K.n_cells(Integer(0))[Integer(0)],
        ...                S1.n_cells(Integer(1))[Integer(0)]: K.n_cells(Integer(1))[Integer(0)]})

    The maps \(f: S^1 \to T\) and \(1: T \to T\) induce a map \(S^1 \vee T \to T\):

    Sage

        sage: g = W.universal_property(f, Hom(T,T).identity())
        sage: g.domain() == W
        True
        sage: g.codomain() == T
        True

    Python

        >>> from sage.all import *
        >>> g = W.universal_property(f, Hom(T,T).identity())
        >>> g.domain() == W
        True
        >>> 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` – string (default: `'*'`); name to be given to the new vertex

    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

        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)                                                         # needs sage.modules
        Z

        sage: E = SimplicialSet({e: (v, w)})
        sage: Z = E.quotient([v, w])
        sage: Z.nondegenerate_simplices()
        [*, e]
        sage: Z.homology(1)                                                         # needs sage.modules
        Z

        sage: F = E.quotient([v])
        sage: F.nondegenerate_simplices()
        [*, w, e]
        sage: F.base_point()
        *

        sage: # needs sage.groups
        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))                                       # needs sage.modules
        {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]

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
        >>> v = AbstractSimplex(Integer(0), name='v')
        >>> w = AbstractSimplex(Integer(0), name='w')
        >>> e = AbstractSimplex(Integer(1), name='e')
        >>> f = AbstractSimplex(Integer(1), name='f')
        >>> X = SimplicialSet({e: (v, w), f: (v, w)})
        >>> Y = X.quotient([f])
        >>> Y.nondegenerate_simplices()
        [*, e]
        >>> Y.homology(Integer(1))                                                         # needs sage.modules
        Z

        >>> E = SimplicialSet({e: (v, w)})
        >>> Z = E.quotient([v, w])
        >>> Z.nondegenerate_simplices()
        [*, e]
        >>> Z.homology(Integer(1))                                                         # needs sage.modules
        Z

        >>> F = E.quotient([v])
        >>> F.nondegenerate_simplices()
        [*, w, e]
        >>> F.base_point()
        *

        >>> # needs sage.groups
        >>> RP5 = simplicial_sets.RealProjectiveSpace(Integer(5))
        >>> RP2 = RP5.n_skeleton(Integer(2))
        >>> RP5_2 = RP5.quotient(RP2)
        >>> RP5_2.homology(base_ring=GF(Integer(2)))                                       # needs sage.modules
        {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}
        >>> RP5_2.ambient()
        RP^5
        >>> RP5_2.subcomplex()
        Simplicial set with 3 non-degenerate simplices
        >>> 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

        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,)

    [Python]

        >>> from sage.all import *
        >>> K = simplicial_sets.Simplex(Integer(3))
        >>> K.is_pointed()
        False
        >>> L = K.subsimplicial_set([K.n_cells(Integer(1))[-Integer(1)]])
        >>> L.nondegenerate_simplices()
        [(2,), (3,), (2, 3)]
        >>> K.quotient([K.n_cells(Integer(1))[-Integer(1)]]).base_point()
        *

        >>> K = K.set_base_point(K.n_cells(Integer(0))[Integer(0)])
        >>> K.base_point()
        (0,)
        >>> L = K.subsimplicial_set([K.n_cells(Integer(1))[-Integer(1)]])
        >>> L.nondegenerate_simplices()
        [(2,), (3,), (2, 3)]
        >>> 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

        sage: K = simplicial_sets.Simplex(2)
        sage: K.is_reduced()
        False
        sage: X = K.reduce()
        sage: X.is_reduced()
        True

    Python

        >>> from sage.all import *
        >>> K = simplicial_sets.Simplex(Integer(2))
        >>> K.is_reduced()
        False
        >>> X = K.reduce()
        >>> X.is_reduced()
        True

    `X` is reduced, so calling `reduce` on it again returns `X` itself:

    Sage

        sage: X is X.reduce()
        True
        sage: K is K.reduce()
        False

    [Python]

        >>> from sage.all import *
        >>> X is X.reduce()
        True
        >>> K is K.reduce()
        False

    Raise an error for disconnected simplicial sets:

    Sage

        sage: S0 = simplicial_sets.Sphere(0)
        sage: S0.reduce()
        Traceback (most recent call last):
        ...
        ValueError: this simplicial set is not connected

    Python

        >>> from sage.all import *
        >>> S0 = simplicial_sets.Sphere(Integer(0))
        >>> 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. Or `s` can be `None`, in which case the LaTeX name is unset.

    EXAMPLES:

    Sage

        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

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
        >>> v = AbstractSimplex(Integer(0))
        >>> X = SimplicialSet({v: None}, latex_name='*')
        >>> latex(X)
        *
        >>> X.rename_latex('x_0')
        >>> 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, and `simplices` should be a subcomplex of that.

    EXAMPLES:

    Sage

        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]); 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

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
        >>> v = AbstractSimplex(Integer(0), name='v')
        >>> w = AbstractSimplex(Integer(0), name='w')
        >>> e = AbstractSimplex(Integer(1), name='e')
        >>> f = AbstractSimplex(Integer(1), name='f')

        >>> X = SimplicialSet({e: (v, w), f: (w, v)})
        >>> Y = X.subsimplicial_set([e]); Y
        Simplicial set with 3 non-degenerate simplices
        >>> Y.nondegenerate_simplices()
        [v, w, e]

        >>> S3 = simplicial_complexes.Sphere(Integer(3))
        >>> K = SimplicialSet(S3)
        >>> tau = K.n_cells(Integer(3))[Integer(0)]
        >>> tau.dimension()
        3
        >>> 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

        sage: # needs sage.groups
        sage: RP4 = simplicial_sets.RealProjectiveSpace(4)
        sage: M = RP4.n_skeleton(2); 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]

    [Python]

        >>> from sage.all import *
        >>> # needs sage.groups
        >>> RP4 = simplicial_sets.RealProjectiveSpace(Integer(4))
        >>> M = RP4.n_skeleton(Integer(2)); M
        Simplicial set with 3 non-degenerate simplices
        >>> M.ambient_space()
        RP^4
        >>> 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

        sage: # needs sage.groups
        sage: G = groups.misc.MultiplicativeAbelian([2])
        sage: B = simplicial_sets.ClassifyingSpace(G)
        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

    Python

        >>> from sage.all import *
        >>> # needs sage.groups
        >>> G = groups.misc.MultiplicativeAbelian([Integer(2)])
        >>> B = simplicial_sets.ClassifyingSpace(G)
        >>> BxB = B.product(B)
        >>> BxB.n_cells(Integer(2))[Integer(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)]
        >>> BxB.subsimplicial_set(BxB.n_cells(Integer(2))[Integer(5):])
        Simplicial set with 8 non-degenerate simplices

  suspension(n=1)

    Return the (reduced) \(n\)-th suspension of this simplicial set.

    INPUT:

    - `n` – integer (default: 1); 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

        sage: # needs sage.groups
        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

    Python

        >>> from sage.all import *
        >>> # needs sage.groups
        >>> RP4 = simplicial_sets.RealProjectiveSpace(Integer(4))
        >>> S1 = simplicial_sets.Sphere(Integer(1))
        >>> SigmaRP4 = RP4.suspension()
        >>> S1_smash_RP4 = S1.smash_product(RP4)
        >>> 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

        sage: SigmaRP4.f_vector()                                                   # needs sage.groups
        [1, 0, 1, 1, 1, 1]
        sage: S1_smash_RP4.f_vector()                                               # needs sage.groups
        [1, 1, 4, 6, 8, 5]

    [Python]

        >>> from sage.all import *
        >>> SigmaRP4.f_vector()                                                   # needs sage.groups
        [1, 0, 1, 1, 1, 1]
        >>> S1_smash_RP4.f_vector()                                               # needs sage.groups
        [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

        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()                                                          # needs sage.modules
        {0: 0, 1: Z x Z}
        sage: S2 = simplicial_sets.Sphere(2)
        sage: X.wedge(S2).homology(reduced=False)                                   # needs sage.modules
        {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]

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
        >>> v = AbstractSimplex(Integer(0), name='v')
        >>> e = AbstractSimplex(Integer(1), name='e')
        >>> w = AbstractSimplex(Integer(0), name='w')
        >>> f = AbstractSimplex(Integer(1), name='f')
        >>> X = SimplicialSet({e: (v, v)}, base_point=v)
        >>> Y = SimplicialSet({f: (w, w)}, base_point=w)
        >>> W = X.wedge(Y)
        >>> W.nondegenerate_simplices()
        [*, e, f]
        >>> W.homology()                                                          # needs sage.modules
        {0: 0, 1: Z x Z}
        >>> S2 = simplicial_sets.Sphere(Integer(2))
        >>> X.wedge(S2).homology(reduced=False)                                   # needs sage.modules
        {0: Z, 1: Z, 2: Z}
        >>> X.wedge(X).nondegenerate_simplices()
        [*, e, e]

        >>> S3 = simplicial_sets.Sphere(Integer(3))
        >>> W = S2.wedge(S3, S2)
        >>> W.inclusion_map(Integer(2))
        Simplicial set morphism:
          From: S^2
          To:   Wedge: (S^2 v S^3 v S^2)
          Defn: [v_0, sigma_2] --> [*, sigma_2]
        >>> W.projection_map(Integer(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 to `S2`:

    Sage

        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

    [Python]

        >>> from sage.all import *
        >>> S2.f_vector()
        [1, 0, 1]
        >>> W.projection_map(Integer(2)).codomain().f_vector()
        [1, 0, 1]
        >>> (W.projection_map(Integer(2)) * W.inclusion_map(Integer(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 nonnegative 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` – (default: `None`) 0-simplex in this simplicial set, its base point

  - `name` – string (default: `None`); the name of the simplicial set

  - `check` – boolean (default: `True`); if `True`, check the simplicial identity on the face maps when defining the simplicial set

  - `category` – (default: `None`) 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` – string (default: `None`); 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 from `data` if they (or their degeneracies) are faces of other simplices; otherwise they must be included with value `None`.

  See `simplicial_set` and the methods for simplicial sets for more information and examples.

  EXAMPLES:

  Sage

      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')

  Python

      >>> from sage.all import *
      >>> from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
      >>> u = AbstractSimplex(Integer(0), name='u')
      >>> v = AbstractSimplex(Integer(0), name='v')
      >>> w = AbstractSimplex(Integer(0), name='w')
      >>> e = AbstractSimplex(Integer(1), name='e')
      >>> f = AbstractSimplex(Integer(1), name='f')

  In the following simplicial set, `u` is an isolated vertex:

  Sage

      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

  [Python]

      >>> from sage.all import *
      >>> X = SimplicialSet({e: (v,w), f: (w,w), u: None})
      >>> X
      Simplicial set with 5 non-degenerate simplices
      >>> X.rename('X')
      >>> X
      X
      >>> X = SimplicialSet({e: (v,w), f: (w,w), u: None}, name='Y')
      >>> 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 (default: `QQ`); 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\) via `phi.pi()` and `phi.iota()`. Then one can recover \(C\) and \(M\) from, for example, `phi.pi().domain()` and `phi.pi().codomain()`, respectively.

    EXAMPLES:

    Sage

        sage: RP2 = simplicial_sets.RealProjectiveSpace(2)                          # needs sage.groups
        sage: phi, M = RP2.algebraic_topological_model(GF(2))                       # needs sage.groups
        sage: M.homology()                                                          # needs sage.groups sage.modules
        {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)                            # needs sage.modules
        sage: M.homology()                                                          # needs sage.modules
        {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}

    Python

        >>> from sage.all import *
        >>> RP2 = simplicial_sets.RealProjectiveSpace(Integer(2))                          # needs sage.groups
        >>> phi, M = RP2.algebraic_topological_model(GF(Integer(2)))                       # needs sage.groups
        >>> M.homology()                                                          # needs sage.groups sage.modules
        {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}

        >>> T = simplicial_sets.Torus()
        >>> phi, M = T.algebraic_topological_model(QQ)                            # needs sage.modules
        >>> M.homology()                                                          # needs sage.modules
        {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` – if `None`, 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` – commutative ring (default: \(\ZZ\))

    - `augmented` – boolean (default: `False`); if `True`, return the augmented chain complex (that is, include a class in dimension \(-1\) corresponding to the empty cell).

    - `cochain` – boolean (default: `False`); if `True`, return the cochain complex (that is, the dual of the chain complex).

    - `verbose` – boolean (default: `False`); ignored

    - `subcomplex` – (default: `None`) if present, compute the chain complex relative to this subcomplex

    - `check` – boolean (default: `False`); if `True`, 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

        sage: # needs sage.modules
        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)                          # needs sage.groups
        sage: RP2 = RP5.n_skeleton(2)                                               # needs sage.groups
        sage: RP5.chain_complex(subcomplex=RP2).homology()                          # needs sage.groups sage.modules
        {0: Z, 3: C2, 4: 0, 5: Z}

    Python

        >>> from sage.all import *
        >>> # needs sage.modules
        >>> from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
        >>> v = AbstractSimplex(Integer(0))
        >>> degen = v.apply_degeneracies(Integer(1), Integer(0)) # s_1 s_0 applied to v
        >>> sigma = AbstractSimplex(Integer(3))
        >>> S3 = SimplicialSet({sigma: (degen, degen, degen, degen)})  # the 3-sphere
        >>> S3.chain_complex().homology()
        {0: Z, 3: Z}
        >>> S3.chain_complex(augmented=True).homology()
        {-1: 0, 0: 0, 3: Z}
        >>> S3.chain_complex(dimensions=range(Integer(3)), base_ring=QQ).homology()
        {0: Vector space of dimension 1 over Rational Field}

        >>> RP5 = simplicial_sets.RealProjectiveSpace(Integer(5))                          # needs sage.groups
        >>> RP2 = RP5.n_skeleton(Integer(2))                                               # needs sage.groups
        >>> RP5.chain_complex(subcomplex=RP2).homology()                          # needs sage.groups sage.modules
        {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

        sage: simplicial_sets.RealProjectiveSpace(4).euler_characteristic()         # needs sage.groups
        1
        sage: simplicial_sets.Sphere(6).euler_characteristic()
        2
        sage: simplicial_sets.KleinBottle().euler_characteristic()
        0

    Python

        >>> from sage.all import *
        >>> simplicial_sets.RealProjectiveSpace(Integer(4)).euler_characteristic()         # needs sage.groups
        1
        >>> simplicial_sets.Sphere(Integer(6)).euler_characteristic()
        2
        >>> 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

        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]

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
        >>> v = AbstractSimplex(Integer(0))
        >>> w = AbstractSimplex(Integer(0))
        >>> S0 = SimplicialSet({v: None, w: None})
        >>> S0.f_vector()
        [2]

        >>> e = AbstractSimplex(Integer(1))
        >>> S1 = SimplicialSet({e: (v, v)})
        >>> S1.f_vector()
        [1, 1]
        >>> simplicial_sets.Sphere(Integer(3)).f_vector()
        [1, 0, 0, 1]

  face_data()

    Return the face-map data – a dictionary – defining this simplicial set.

    EXAMPLES:

    Sage

        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

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
        >>> v = AbstractSimplex(Integer(0), name='v')
        >>> w = AbstractSimplex(Integer(0), name='w')
        >>> e = AbstractSimplex(Integer(1), name='e')
        >>> X = SimplicialSet({e: (v, w)})
        >>> X.face_data()[e]
        (v, w)

        >>> Y = SimplicialSet({v: None, w: None})
        >>> v in Y.face_data()
        True
        >>> 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

        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})

    Python

        >>> from sage.all import *
        >>> from sage.topology.simplicial_set import AbstractSimplex, SimplicialSet
        >>> v = AbstractSimplex(Integer(0), name='v')
        >>> w = AbstractSimplex(Integer(0), name='w')
        >>> degen = v.apply_degeneracies(Integer(0))
        >>> tau = AbstractSimplex(Integer(2), name='tau')
        >>> Y = SimplicialSet({tau: (degen, degen, degen), w: None})

    `Y` is the disjoint union of a 2-sphere, with vertex `v` and non-degenerate 2-simplex `tau`, and a point `w`.

    Sage

        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]

    [Python]

        >>> from sage.all import *
        >>> Y.nondegenerate_simplices()
        [v, w, tau]
        >>> Y.n_skeleton(Integer(1)).nondegenerate_simplices()
        [v, w]
        >>> Y.n_skeleton(Integer(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

      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)}

  Python

      >>> from sage.all import *
      >>> from sage.topology.simplicial_set import all_degeneracies
      >>> all_degeneracies(Integer(0), Integer(3))
      {(2, 1, 0)}
      >>> all_degeneracies(Integer(1), Integer(1))
      {(0,), (1,)}
      >>> all_degeneracies(Integer(1), Integer(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` – integer

  - `I` – 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

      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)

  Python

      >>> from sage.all import *
      >>> from sage.topology.simplicial_set import face_degeneracies
      >>> face_degeneracies(Integer(0), (Integer(1), Integer(0)))
      ([0], None)
      >>> face_degeneracies(Integer(1), (Integer(1), Integer(0)))
      ([0], None)
      >>> face_degeneracies(Integer(2), (Integer(1), Integer(0)))
      ([0], None)
      >>> face_degeneracies(Integer(3), (Integer(1), Integer(0)))
      ([1, 0], 1)
      >>> face_degeneracies(Integer(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 by `simplicial_complex.SimplicialComplex._contractible_subcomplex()`. This will produce a simplicial set no larger than, and sometimes much smaller than, the initial simplicial complex.

  EXAMPLES:

  Sage

      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); 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()                                                             # needs sage.modules
      {0: 0, 1: 0, 2: Z}

      sage: Z = simplicial_complexes.SurfaceOfGenus(3)
      sage: Z.f_vector()
      [1, 15, 57, 38]
      sage: Z.homology()                                                              # needs sage.modules
      {0: 0, 1: Z^6, 2: Z}
      sage: M = shrink_simplicial_complex(Z)
      sage: M.f_vector()  # random
      [1, 32, 27]
      sage: M.homology()                                                              # needs sage.modules
      {0: 0, 1: Z^6, 2: Z}

  Python

      >>> from sage.all import *
      >>> from sage.topology.simplicial_set import shrink_simplicial_complex
      >>> K = simplicial_complexes.Simplex(Integer(3))
      >>> X = shrink_simplicial_complex(K)
      >>> X.f_vector()
      [1]

      >>> Y = simplicial_complexes.Sphere(Integer(2))
      >>> S2 = shrink_simplicial_complex(Y); S2
      Quotient: (Simplicial set with
                 14 non-degenerate simplices/Simplicial set with
                                             13 non-degenerate simplices)
      >>> S2.f_vector()
      [1, 0, 1]
      >>> S2.homology()                                                             # needs sage.modules
      {0: 0, 1: 0, 2: Z}

      >>> Z = simplicial_complexes.SurfaceOfGenus(Integer(3))
      >>> Z.f_vector()
      [1, 15, 57, 38]
      >>> Z.homology()                                                              # needs sage.modules
      {0: 0, 1: Z^6, 2: Z}
      >>> M = shrink_simplicial_complex(Z)
      >>> M.f_vector()  # random
      [1, 32, 27]
      >>> M.homology()                                                              # needs sage.modules
      {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

      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)

  Python

      >>> from sage.all import *
      >>> from sage.topology.simplicial_set import standardize_degeneracies
      >>> standardize_degeneracies(Integer(0), Integer(0))
      (1, 0)
      >>> standardize_degeneracies(Integer(0), Integer(0), Integer(0), Integer(0))
      (3, 2, 1, 0)
      >>> standardize_degeneracies(Integer(1), Integer(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

      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)

  Python

      >>> from sage.all import *
      >>> from sage.topology.simplicial_set import standardize_face_maps
      >>> standardize_face_maps(Integer(0), Integer(1))
      (0, 0)
      >>> standardize_face_maps(Integer(0), Integer(2))
      (1, 0)
      >>> standardize_face_maps(Integer(1), Integer(3), Integer(5))
      (3, 2, 1)