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 4 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.homology.simplicial_complex_morphism.SimplicialComplexMorphism(f, X, Y)

Bases: sage.categories.morphism.Morphism

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

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

Returns the associated chain complex morphism of self.

EXAMPLES:

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)
sage: 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()
sage: 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: 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)

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)
sage: h
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
[1]
sage: h.to_matrix(1) # in degree 1
[1]
[1]
sage: h.to_matrix()  # the entire homomorphism
[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)
sage: coh.to_matrix(1)
[1 1]
sage: h.to_matrix() == coh.to_matrix().transpose()
True

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

sage: x,y = list(T.cohomology_ring(QQ).basis(1))
sage: coh(x)
h^{1,0}
sage: coh(2*x+3*y)
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()
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()
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()

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

Returns 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()
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()
True
sage.homology.simplicial_complex_morphism.is_SimplicialComplexMorphism(x)

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

EXAMPLES:

sage: from sage.homology.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