Morphisms of simplicial complexes#

AUTHORS:

  • Benjamin Antieau <d.ben.antieau@gmail.com> (2009.06)

  • Travis Scrimshaw (2012-08-18): Made all simplicial complexes immutable to work with the homset cache.

This module implements morphisms of simplicial complexes. The input is given by a dictionary on the vertex set of a simplicial complex. The initialization checks that faces are sent to faces.

There is also the capability to create the fiber product of two morphisms with the same codomain.

EXAMPLES:

sage: S = SimplicialComplex([[0,2],[1,5],[3,4]], is_mutable=False)
sage: H = Hom(S,S.product(S, is_mutable=False))
sage: H.diagonal_morphism()
Simplicial complex morphism:
  From: Simplicial complex with vertex set (0, 1, 2, 3, 4, 5) and facets {(0, 2), (1, 5), (3, 4)}
  To: Simplicial complex with 36 vertices and 18 facets
  Defn: [0, 1, 2, 3, 4, 5] --> ['L0R0', 'L1R1', 'L2R2', 'L3R3', 'L4R4', 'L5R5']

sage: S = SimplicialComplex([[0,2],[1,5],[3,4]], is_mutable=False)
sage: T = SimplicialComplex([[0,2],[1,3]], is_mutable=False)
sage: f = {0:0,1:1,2:2,3:1,4:3,5:3}
sage: H = Hom(S,T)
sage: x = H(f)
sage: x.image()
Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 2), (1, 3)}
sage: x.is_surjective()
True
sage: x.is_injective()
False
sage: x.is_identity()
False

sage: S = simplicial_complexes.Sphere(2)
sage: H = Hom(S,S)
sage: i = H.identity()
sage: i.image()
Simplicial complex with vertex set (0, 1, 2, 3) and facets {(0, 1, 2), (0, 1, 3), (0, 2, 3), (1, 2, 3)}
sage: i.is_surjective()
True
sage: i.is_injective()
True
sage: i.is_identity()
True

sage: S = simplicial_complexes.Sphere(2)
sage: H = Hom(S,S)
sage: i = H.identity()
sage: j = i.fiber_product(i)
sage: j
Simplicial complex morphism:
  From: Simplicial complex with 4 vertices and 4 facets
  To:   Minimal triangulation of the 2-sphere
  Defn: L0R0 |--> 0
        L1R1 |--> 1
        L2R2 |--> 2
        L3R3 |--> 3
sage: S = simplicial_complexes.Sphere(2)
sage: T = S.product(SimplicialComplex([[0,1]]), rename_vertices = False, is_mutable=False)
sage: H = Hom(T,S)
sage: T
Simplicial complex with 8 vertices and 12 facets
sage: sorted(T.vertices())
[(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1), (3, 0), (3, 1)]
sage: f = {(0, 0): 0, (0, 1): 0, (1, 0): 1, (1, 1): 1, (2, 0): 2, (2, 1): 2, (3, 0): 3, (3, 1): 3}
sage: x = H(f)
sage: U = simplicial_complexes.Sphere(1)
sage: G = Hom(U,S)
sage: U
Minimal triangulation of the 1-sphere
sage: g = {0:0,1:1,2:2}
sage: y = G(g)
sage: z = y.fiber_product(x)
sage: z                                     # this is the mapping path space
Simplicial complex morphism:
  From: Simplicial complex with 6 vertices and ... facets
  To:   Minimal triangulation of the 2-sphere
  Defn: ['L0R(0, 0)', 'L0R(0, 1)', 'L1R(1, 0)', 'L1R(1, 1)', 'L2R(2, 0)', 'L2R(2, 1)'] --> [0, 0, 1, 1, 2, 2]
class sage.topology.simplicial_complex_morphism.SimplicialComplexMorphism(f, X, Y)#

Bases: Morphism

An element of this class is a morphism of simplicial complexes.

associated_chain_complex_morphism(base_ring=Integer Ring, augmented=False, cochain=False)#

Return the associated chain complex morphism of self.

EXAMPLES:

sage: # needs sage.modules
sage: S = simplicial_complexes.Sphere(1)
sage: T = simplicial_complexes.Sphere(2)
sage: H = Hom(S, T)
sage: f = {0:0, 1:1, 2:2}
sage: x = H(f); x
Simplicial complex morphism:
  From: Minimal triangulation of the 1-sphere
  To:   Minimal triangulation of the 2-sphere
  Defn: 0 |--> 0
        1 |--> 1
        2 |--> 2
sage: a = x.associated_chain_complex_morphism(); a
Chain complex morphism:
  From: Chain complex with at most 2 nonzero terms over Integer Ring
  To:   Chain complex with at most 3 nonzero terms over Integer Ring
sage: a._matrix_dictionary
{0: [1 0 0]
    [0 1 0]
    [0 0 1]
    [0 0 0],
 1: [1 0 0]
    [0 1 0]
    [0 0 0]
    [0 0 1]
    [0 0 0]
    [0 0 0],
 2: []}
sage: x.associated_chain_complex_morphism(augmented=True)
Chain complex morphism:
  From: Chain complex with at most 3 nonzero terms over Integer Ring
  To:   Chain complex with at most 4 nonzero terms over Integer Ring
sage: x.associated_chain_complex_morphism(cochain=True)
Chain complex morphism:
  From: Chain complex with at most 3 nonzero terms over Integer Ring
  To:   Chain complex with at most 2 nonzero terms over Integer Ring
sage: x.associated_chain_complex_morphism(augmented=True, cochain=True)
Chain complex morphism:
  From: Chain complex with at most 4 nonzero terms over Integer Ring
  To:   Chain complex with at most 3 nonzero terms over Integer Ring
sage: x.associated_chain_complex_morphism(base_ring=GF(11))
Chain complex morphism:
  From: Chain complex with at most 2 nonzero terms over Finite Field of size 11
  To:   Chain complex with at most 3 nonzero terms over Finite Field of size 11

Some simplicial maps which reverse the orientation of a few simplices:

sage: # needs sage.modules
sage: g = {0:1, 1:2, 2:0}
sage: H(g).associated_chain_complex_morphism()._matrix_dictionary
{0: [0 0 1]
    [1 0 0]
    [0 1 0]
    [0 0 0],
 1: [ 0 -1  0]
    [ 0  0 -1]
    [ 0  0  0]
    [ 1  0  0]
    [ 0  0  0]
    [ 0  0  0],
 2: []}
sage: X = SimplicialComplex([[0, 1]], is_mutable=False)
sage: Hom(X,X)({0:1, 1:0}).associated_chain_complex_morphism()._matrix_dictionary
{0: [0 1]
    [1 0],
 1: [-1]}
fiber_product(other, rename_vertices=True)#

Fiber product of self and other. Both morphisms should have the same codomain. The method returns a morphism of simplicial complexes, which is the morphism from the space of the fiber product to the codomain.

EXAMPLES:

sage: S = SimplicialComplex([[0,1],[1,2]], is_mutable=False)
sage: T = SimplicialComplex([[0,2],[1]], is_mutable=False)
sage: U = SimplicialComplex([[0,1],[2]], is_mutable=False)
sage: H = Hom(S,U)
sage: G = Hom(T,U)
sage: f = {0:0,1:1,2:0}
sage: g = {0:0,1:1,2:1}
sage: x = H(f)
sage: y = G(g)
sage: z = x.fiber_product(y)
sage: z
Simplicial complex morphism:
  From: Simplicial complex with 4 vertices and facets {...}
  To:   Simplicial complex with vertex set (0, 1, 2) and facets {(2,), (0, 1)}
  Defn: L0R0 |--> 0
        L1R1 |--> 1
        L1R2 |--> 1
        L2R0 |--> 0
image()#

Computes the image simplicial complex of \(f\).

EXAMPLES:

sage: S = SimplicialComplex([[0,1],[2,3]], is_mutable=False)
sage: T = SimplicialComplex([[0,1]], is_mutable=False)
sage: f = {0:0,1:1,2:0,3:1}
sage: H = Hom(S,T)
sage: x = H(f)
sage: x.image()
Simplicial complex with vertex set (0, 1) and facets {(0, 1)}

sage: S = SimplicialComplex(is_mutable=False)
sage: H = Hom(S,S)
sage: i = H.identity()
sage: i.image()
Simplicial complex with vertex set () and facets {()}
sage: i.is_surjective()
True
sage: S = SimplicialComplex([[0,1]], is_mutable=False)
sage: T = SimplicialComplex([[0,1], [0,2]], is_mutable=False)
sage: f = {0:0,1:1}
sage: g = {0:0,1:1}
sage: k = {0:0,1:2}
sage: H = Hom(S,T)
sage: x = H(f)
sage: y = H(g)
sage: z = H(k)
sage: x == y
True
sage: x == z
False
sage: x.image()
Simplicial complex with vertex set (0, 1) and facets {(0, 1)}
sage: y.image()
Simplicial complex with vertex set (0, 1) and facets {(0, 1)}
sage: z.image()
Simplicial complex with vertex set (0, 2) and facets {(0, 2)}
induced_homology_morphism(base_ring=None, cohomology=False)#

Return the map in (co)homology induced by this map.

INPUT:

  • base_ring – must be a field (optional, default QQ)

  • cohomology – boolean (optional, default False). If True, the map induced in cohomology rather than homology.

EXAMPLES:

sage: S = simplicial_complexes.Sphere(1)
sage: T = S.product(S, is_mutable=False)
sage: H = Hom(S,T)
sage: diag = H.diagonal_morphism()
sage: h = diag.induced_homology_morphism(QQ); h                             # needs sage.modules
Graded vector space morphism:
  From: Homology module of
        Minimal triangulation of the 1-sphere over Rational Field
  To:   Homology module of
        Simplicial complex with 9 vertices and 18 facets over Rational Field
  Defn: induced by:
    Simplicial complex morphism:
      From: Minimal triangulation of the 1-sphere
      To:   Simplicial complex with 9 vertices and 18 facets
      Defn: 0 |--> L0R0
            1 |--> L1R1
            2 |--> L2R2

We can view the matrix form for the homomorphism:

sage: h.to_matrix(0)  # in degree 0                                         # needs sage.modules
[1]
sage: h.to_matrix(1)  # in degree 1                                         # needs sage.modules
[1]
[1]
sage: h.to_matrix()   # the entire homomorphism                             # needs sage.modules
[1|0]
[-+-]
[0|1]
[0|1]
[-+-]
[0|0]

The map on cohomology should be dual to the map on homology:

sage: coh = diag.induced_homology_morphism(QQ, cohomology=True)             # needs sage.modules
sage: coh.to_matrix(1)                                                      # needs sage.modules
[1 1]
sage: h.to_matrix() == coh.to_matrix().transpose()                          # needs sage.modules
True

We can evaluate the map on (co)homology classes:

sage: x,y = list(T.cohomology_ring(QQ).basis(1))                            # needs sage.modules
sage: coh(x)                                                                # needs sage.modules
h^{1,0}
sage: coh(2*x + 3*y)                                                        # needs sage.modules
5*h^{1,0}

Note that the complexes must be immutable for this to work. Many, but not all, complexes are immutable when constructed:

sage: S.is_immutable()
True
sage: S.barycentric_subdivision().is_immutable()
False
sage: S2 = S.suspension()
sage: S2.is_immutable()
False
sage: h = Hom(S, S2)({0: 0, 1: 1, 2: 2}).induced_homology_morphism()        # needs sage.modules
Traceback (most recent call last):
...
ValueError: the domain and codomain complexes must be immutable
sage: S2.set_immutable(); S2.is_immutable()
True
sage: h = Hom(S, S2)({0: 0, 1: 1, 2: 2}).induced_homology_morphism()        # needs sage.modules
is_contiguous_to(other)#

Return True if self is contiguous to other.

Two morphisms \(f_0, f_1: K \to L\) are contiguous if for any simplex \(\sigma \in K\), the union \(f_0(\sigma) \cup f_1(\sigma)\) is a simplex in \(L\). This is not a transitive relation, but it induces an equivalence relation on simplicial maps: \(f\) is equivalent to \(g\) if there is a finite sequence \(f_0 = f\), \(f_1\), …, \(f_n = g\) such that \(f_i\) and \(f_{i+1}\) are contiguous for each \(i\).

This is related to maps being homotopic: if they are contiguous, then they induce homotopic maps on the geometric realizations. Given two homotopic maps on the geometric realizations, then after barycentrically subdividing \(n\) times for some \(n\), the maps have simplicial approximations which are in the same contiguity class. (This last fact is only true if the domain is a finite simplicial complex, by the way.)

See Section 3.5 of Spanier [Spa1966] for details.

ALGORITHM:

It is enough to check when \(\sigma\) ranges over the facets.

INPUT:

  • other – a simplicial complex morphism with the same domain and codomain as self

EXAMPLES:

sage: K = simplicial_complexes.Simplex(1)
sage: L = simplicial_complexes.Sphere(1)
sage: H = Hom(K, L)
sage: f = H({0: 0, 1: 1})
sage: g = H({0: 0, 1: 0})
sage: f.is_contiguous_to(f)
True
sage: f.is_contiguous_to(g)
True
sage: h = H({0: 1, 1: 2})
sage: f.is_contiguous_to(h)
False
is_identity()#

If self is an identity morphism, returns True. Otherwise, False.

EXAMPLES:

sage: T = simplicial_complexes.Sphere(1)
sage: G = Hom(T,T)
sage: T
Minimal triangulation of the 1-sphere
sage: j = G({0:0,1:1,2:2})
sage: j.is_identity()
True

sage: S = simplicial_complexes.Sphere(2)
sage: T = simplicial_complexes.Sphere(3)
sage: H = Hom(S,T)
sage: f = {0:0,1:1,2:2,3:3}
sage: x = H(f)
sage: x
Simplicial complex morphism:
  From: Minimal triangulation of the 2-sphere
  To:   Minimal triangulation of the 3-sphere
  Defn: 0 |--> 0
        1 |--> 1
        2 |--> 2
        3 |--> 3
sage: x.is_identity()
False
is_injective()#

Return True if and only if self is injective.

EXAMPLES:

sage: S = simplicial_complexes.Sphere(1)
sage: T = simplicial_complexes.Sphere(2)
sage: U = simplicial_complexes.Sphere(3)
sage: H = Hom(T,S)
sage: G = Hom(T,U)
sage: f = {0:0,1:1,2:0,3:1}
sage: x = H(f)
sage: g = {0:0,1:1,2:2,3:3}
sage: y = G(g)
sage: x.is_injective()
False
sage: y.is_injective()
True
is_surjective()#

Return True if and only if self is surjective.

EXAMPLES:

sage: S = SimplicialComplex([(0,1,2)], is_mutable=False)
sage: S
Simplicial complex with vertex set (0, 1, 2) and facets {(0, 1, 2)}
sage: T = SimplicialComplex([(0,1)], is_mutable=False)
sage: T
Simplicial complex with vertex set (0, 1) and facets {(0, 1)}
sage: H = Hom(S,T)
sage: x = H({0:0,1:1,2:1})
sage: x.is_surjective()
True

sage: S = SimplicialComplex([[0,1],[2,3]], is_mutable=False)
sage: T = SimplicialComplex([[0,1]], is_mutable=False)
sage: f = {0:0,1:1,2:0,3:1}
sage: H = Hom(S,T)
sage: x = H(f)
sage: x.is_surjective()
True
mapping_torus()#

The mapping torus of a simplicial complex endomorphism

The mapping torus is the simplicial complex formed by taking the product of the domain of self with a \(4\) point interval \([I_0, I_1, I_2, I_3]\) and identifying vertices of the form \((I_0, v)\) with \((I_3, w)\) where \(w\) is the image of \(v\) under the given morphism.

See Wikipedia article Mapping torus

EXAMPLES:

sage: C = simplicial_complexes.Sphere(1)            # Circle
sage: T = Hom(C,C).identity().mapping_torus() ; T   # Torus
Simplicial complex with 9 vertices and 18 facets
sage: T.homology() == simplicial_complexes.Torus().homology()               # needs sage.modules
True

sage: f = Hom(C,C)({0:0, 1:2, 2:1})
sage: K = f.mapping_torus(); K                      # Klein Bottle
Simplicial complex with 9 vertices and 18 facets
sage: K.homology() == simplicial_complexes.KleinBottle().homology()         # needs sage.modules
True
sage.topology.simplicial_complex_morphism.is_SimplicialComplexMorphism(x)#

Return True if and only if x is a morphism of simplicial complexes.

EXAMPLES:

sage: from sage.topology.simplicial_complex_morphism import is_SimplicialComplexMorphism
sage: S = SimplicialComplex([[0,1],[3,4]], is_mutable=False)
sage: H = Hom(S,S)
sage: f = {0:0,1:1,3:3,4:4}
sage: x = H(f)
sage: is_SimplicialComplexMorphism(x)
True