Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# -*- coding: utf-8 -*- Homology and cohomology with a basis
This module provides homology and cohomology vector spaces suitable for computing cup products and cohomology operations.
REFERENCES:
- [GDR2003]_ - [GDR1999]_
AUTHORS:
- John H. Palmieri, Travis Scrimshaw (2015-09) """
######################################################################## # Copyright (C) 2015 John H. Palmieri <palmieri@math.washington.edu> # Travis Scrimshaw <tscrimsh at umn.edu> # # Distributed under the terms of the GNU General Public License (GPL) # as published by the Free Software Foundation; either version 2 of # the License, or (at your option) any later version. # # http://www.gnu.org/licenses/ ########################################################################
r""" Homology (or cohomology) vector space.
This provides enough structure to allow the computation of cup products and cohomology operations. See the class :class:`CohomologyRing` (which derives from this) for examples.
It also requires field coefficients (hence the "VectorSpace" in the name of the class).
.. NOTE::
This is not intended to be created directly by the user, but instead via the methods :meth:`~sage.homology.cell_complex.GenericCellComplex.homology_with_basis` and :meth:`~sage.homology.cell_complex.GenericCellComplex.cohomology_ring` for the class of :class:`cell complexes<sage.homology.cell_complex.GenericCellComplex>`.
INPUT:
- ``base_ring`` -- must be a field - ``cell_complex`` -- the cell complex whose homology we are computing - ``cohomology`` -- (default: ``False``) if ``True``, return the cohomology as a module - ``category`` -- (optional) a subcategory of modules with basis
EXAMPLES:
Homology classes are denoted by ``h_{d,i}`` where ``d`` is the degree of the homology class and ``i`` is their index in the list of basis elements in that degree. Cohomology classes are denoted ``h^{1,0}``::
sage: RP2 = cubical_complexes.RealProjectivePlane() sage: RP2.homology_with_basis(GF(2)) Homology module of Cubical complex with 21 vertices and 81 cubes over Finite Field of size 2 sage: RP2.cohomology_ring(GF(2)) Cohomology ring of Cubical complex with 21 vertices and 81 cubes over Finite Field of size 2 sage: simplicial_complexes.Torus().homology_with_basis(QQ) Homology module of Minimal triangulation of the torus over Rational Field
To access a basis element, use its degree and index (0 or 1 in the 1st cohomology group of a torus)::
sage: H = simplicial_complexes.Torus().cohomology_ring(QQ) sage: H.basis(1) Finite family {(1, 0): h^{1,0}, (1, 1): h^{1,1}} sage: x = H.basis()[1,0]; x h^{1,0} sage: y = H.basis()[1,1]; y h^{1,1} sage: 2*x-3*y 2*h^{1,0} - 3*h^{1,1}
You can compute cup products of cohomology classes::
sage: x.cup_product(y) -h^{2,0} sage: y.cup_product(x) h^{2,0} sage: x.cup_product(x) 0
This works with simplicial, cubical, and `\Delta`-complexes, and also simplicial sets::
sage: Klein_c = cubical_complexes.KleinBottle() sage: H = Klein_c.cohomology_ring(GF(2)) sage: x,y = H.basis(1) sage: x.cup_product(x) h^{2,0} sage: x.cup_product(y) 0 sage: y.cup_product(y) h^{2,0}
sage: Klein_d = delta_complexes.KleinBottle() sage: H = Klein_d.cohomology_ring(GF(2)) sage: u,v = H.basis(1) sage: u.cup_product(u) h^{2,0} sage: u.cup_product(v) 0 sage: v.cup_product(v) h^{2,0}
sage: X = simplicial_sets.RealProjectiveSpace(6) sage: H_X = X.cohomology_ring(GF(2)) sage: a = H_X.basis()[1,0] sage: a**6 h^{6,0} sage: a**7 0
All products of positive-dimensional elements in a suspension should be zero::
sage: Y = X.suspension() sage: H_Y = Y.cohomology_ring(GF(2)) sage: b = H_Y.basis()[2,0] sage: b**2 0 sage: B = sorted(H_Y.basis())[1:] sage: B [h^{2,0}, h^{3,0}, h^{4,0}, h^{5,0}, h^{6,0}, h^{7,0}] sage: import itertools sage: [a*b for (a,b) in itertools.combinations(B, 2)] [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
The basis elements in the simplicial complex case have been chosen differently; apply the change of basis `x \mapsto a + b`, `y \mapsto b` to see the same product structure. ::
sage: Klein_s = simplicial_complexes.KleinBottle() sage: H = Klein_s.cohomology_ring(GF(2)) sage: a,b = H.basis(1) sage: a.cup_product(a) 0 sage: a.cup_product(b) h^{2,0} sage: (a+b).cup_product(a+b) h^{2,0} sage: b.cup_product(b) h^{2,0} """ """ Initialize ``self``.
EXAMPLES::
sage: RP2 = simplicial_complexes.ProjectivePlane() sage: H = RP2.homology_with_basis(QQ) sage: TestSuite(H).run() sage: H = RP2.homology_with_basis(GF(2)) sage: TestSuite(H).run() sage: H = RP2.cohomology_ring(GF(2)) sage: TestSuite(H).run() sage: H = RP2.cohomology_ring(GF(5)) sage: TestSuite(H).run() sage: H = simplicial_complexes.ComplexProjectivePlane().cohomology_ring() sage: TestSuite(H).run() """ # phi is the associated chain contraction. # M is the homology chain complex. # We only need the rank of M in each degree, and since # we're working over a field, we don't need to dualize M # if working with cohomology. for deg in range(cell_complex.dimension()+1)} for i in self._graded_indices[deg]]
""" Return (the degree ``d`` homogeneous component of) the basis of this graded vector space.
INPUT:
- ``d`` -- (optional) the degree
EXAMPLES::
sage: RP2 = simplicial_complexes.ProjectivePlane() sage: H = RP2.homology_with_basis(QQ) sage: H.basis() Finite family {(0, 0): h_{0,0}} sage: H.basis(0) Finite family {(0, 0): h_{0,0}} sage: H.basis(1) Finite family {} sage: H.basis(2) Finite family {} """ else:
r""" Return the degree of the basis element indexed by ``i``.
EXAMPLES::
sage: H = simplicial_complexes.Torus().homology_with_basis(GF(7)) sage: H.degree_on_basis((2,0)) 2 """
r""" The chain contraction associated to this homology computation.
That is, to work with chain representatives of homology classes, we need the chain complex `C` associated to the cell complex, the chain complex `H` of its homology (with trivial differential), chain maps `\pi: C \to H` and `\iota: H \to C`, and a chain contraction `\phi` giving a chain homotopy between `1_C` and `\iota \circ \pi`.
OUTPUT: `\phi`
See :class:`~sage.homology.chain_homotopy.ChainContraction` for information about chain contractions, and see :func:`~sage.homology.algebraic_topological_model.algebraic_topological_model` for the construction of this particular chain contraction `\phi`.
EXAMPLES::
sage: H = simplicial_complexes.Simplex(2).homology_with_basis(QQ) sage: H.contraction() Chain homotopy between: Chain complex endomorphism of Chain complex with at most 3 nonzero terms over Rational Field and Chain complex endomorphism of Chain complex with at most 3 nonzero terms over Rational Field
From the chain contraction, one can also recover the maps `\pi` and `\iota`::
sage: phi = H.contraction() sage: phi.pi() Chain complex morphism: From: Chain complex with at most 3 nonzero terms over Rational Field To: Chain complex with at most 1 nonzero terms over Rational Field sage: phi.iota() Chain complex morphism: From: Chain complex with at most 1 nonzero terms over Rational Field To: Chain complex with at most 3 nonzero terms over Rational Field """
""" The cell complex whose homology is being computed.
EXAMPLES::
sage: H = simplicial_complexes.Simplex(2).homology_with_basis(QQ) sage: H.complex() The 2-simplex """
""" EXAMPLES::
sage: simplicial_complexes.Torus().homology_with_basis(QQ) Homology module of Minimal triangulation of the torus over Rational Field """ base = "Cohomology" else:
""" Return ``'h_{i[0],i[1]}'`` for homology, ``'h^{i[0],i[1]}'`` for cohomology, for the basis element indexed by ``i``.
EXAMPLES::
sage: H = simplicial_complexes.Torus().homology_with_basis(QQ) sage: H.basis()[1,0] # indirect doctest h_{1,0} sage: latex(H.basis()[1,1]) # indirect doctest h_{1,1} sage: co = simplicial_complexes.KleinBottle().cohomology_ring(GF(2)) sage: co.basis()[1,0] # indirect doctest h^{1,0}
"""
def _to_cycle_on_basis(self, i): """ Return the (co)cycle representative of the basis element indexed by ``i``.
.. SEEALSO::
:meth:`HomologyVectorSpaceWithBasis.Element.to_cocycle`
EXAMPLES::
sage: S2 = simplicial_complexes.Sphere(2) sage: H = S2.homology_with_basis(QQ) sage: H._to_cycle_on_basis((2,0)) -(0, 1, 2) + (0, 1, 3) - (0, 2, 3) + (1, 2, 3)
sage: S2.cohomology_ring(QQ)._to_cycle_on_basis((2,0)) \chi_(1, 2, 3) sage: S2.cohomology_ring(QQ)._to_cycle_on_basis((0,0)) \chi_(0,) + \chi_(1,) + \chi_(2,) + \chi_(3,)
sage: RP3 = simplicial_complexes.RealProjectiveSpace(3) sage: H = RP3.cohomology_ring(GF(2)) sage: H._to_cycle_on_basis((0,0)) \chi_(1,) + \chi_(2,) + \chi_(3,) + \chi_(4,) + \chi_(5,) + \chi_(6,) + \chi_(7,) + \chi_(8,) + \chi_(9,) + \chi_(10,) + \chi_(11,) sage: H._to_cycle_on_basis((1,0)) \chi_(2, 4) + \chi_(2, 5) + \chi_(2, 8) + \chi_(2, 10) + \chi_(3, 4) + \chi_(3, 6) + \chi_(3, 8) + \chi_(3, 9) + \chi_(4, 5) + \chi_(4, 6) + \chi_(4, 11) + \chi_(5, 7) + \chi_(5, 9) + \chi_(6, 7) + \chi_(6, 10) + \chi_(7, 8) + \chi_(9, 10) sage: H._to_cycle_on_basis((2,0)) \chi_(3, 5, 9) + \chi_(3, 6, 10) + \chi_(3, 9, 10) + \chi_(4, 5, 7) + \chi_(4, 5, 9) + \chi_(4, 6, 7) + \chi_(6, 7, 10) sage: H._to_cycle_on_basis((3,0)) \chi_(5, 6, 7, 8) """ cochains=self._cohomology)
r""" (Co)cycle representative of this homogeneous (co)homology class.
EXAMPLES::
sage: S2 = simplicial_complexes.Sphere(2) sage: H = S2.homology_with_basis(QQ) sage: h20 = H.basis()[2,0]; h20 h_{2,0} sage: h20.to_cycle() -(0, 1, 2) + (0, 1, 3) - (0, 2, 3) + (1, 2, 3)
Chains are written as linear combinations of simplices `\sigma`. Cochains are written as linear combinations of characteristic functions `\chi_{\sigma}` for those simplices::
sage: S2.cohomology_ring(QQ).basis()[2,0].to_cycle() \chi_(1, 2, 3) sage: S2.cohomology_ring(QQ).basis()[0,0].to_cycle() \chi_(0,) + \chi_(1,) + \chi_(2,) + \chi_(3,) """ raise ValueError("only defined for homogeneous elements")
""" The cohomology ring.
.. NOTE::
This is not intended to be created directly by the user, but instead via the :meth:`cohomology ring<sage.homology.cell_complex.GenericCellComplex.cohomology_ring>` of a :class:`cell complex<sage.homology.cell_complex.GenericCellComplex>`.
INPUT:
- ``base_ring`` -- must be a field - ``cell_complex`` -- the cell complex whose homology we are computing
EXAMPLES::
sage: CP2 = simplicial_complexes.ComplexProjectivePlane() sage: H = CP2.cohomology_ring(QQ) sage: H.basis(2) Finite family {(2, 0): h^{2,0}} sage: x = H.basis(2)[2,0]
The product structure is the cup product::
sage: x.cup_product(x) -h^{4,0} sage: x * x -h^{4,0}
There are mod 2 cohomology operations defined, also, for simplicial complexes and simplicial sets::
sage: Hmod2 = CP2.cohomology_ring(GF(2)) sage: y = Hmod2.basis(2)[2,0] sage: y.Sq(2) h^{4,0}
sage: Y = simplicial_sets.RealProjectiveSpace(6).suspension() sage: H_Y = Y.cohomology_ring(GF(2)) sage: b = H_Y.basis()[2,0] sage: b.Sq(1) h^{3,0} sage: b.Sq(2) 0 sage: c = H_Y.basis()[4,0] sage: c.Sq(1) h^{5,0} sage: c.Sq(2) h^{6,0} sage: c.Sq(3) h^{7,0} sage: c.Sq(4) 0 """ """ Initialize ``self``.
EXAMPLES::
sage: RP2 = simplicial_complexes.ProjectivePlane() sage: H = RP2.cohomology_ring(GF(2)) sage: TestSuite(H).run() sage: H = RP2.cohomology_ring(GF(5)) sage: TestSuite(H).run() """
""" EXAMPLES::
sage: simplicial_complexes.Torus().cohomology_ring(QQ) Cohomology ring of Minimal triangulation of the torus over Rational Field """
def one(self): """ The multiplicative identity element.
EXAMPLES::
sage: H = simplicial_complexes.Torus().cohomology_ring(QQ) sage: H.one() h^{0,0} sage: all(H.one() * x == x == x * H.one() for x in H.basis()) True """
def product_on_basis(self, li, ri): r""" The cup product of the basis elements indexed by ``li`` and ``ri`` in this cohomology ring.
INPUT:
- ``li``, ``ri`` -- index of a cohomology class
.. SEEALSO::
:meth:`CohomologyRing.Element.cup_product` -- the documentation for this method describes the algorithm.
EXAMPLES::
sage: RP3 = simplicial_complexes.RealProjectiveSpace(3) sage: H = RP3.cohomology_ring(GF(2)) sage: c = H.basis()[1,0] sage: c.cup_product(c).cup_product(c) # indirect doctest h^{3,0}
sage: T = simplicial_complexes.Torus() sage: x,y = T.cohomology_ring(QQ).basis(1) sage: x.cup_product(y) -h^{2,0} sage: x.cup_product(x) 0
sage: one = T.cohomology_ring(QQ).basis()[0,0] sage: x.cup_product(one) h^{1,0} sage: one.cup_product(y) == y True sage: one.cup_product(one) h^{0,0} sage: x.cup_product(y) + y.cup_product(x) 0
This also works with cubical complexes::
sage: T = cubical_complexes.Torus() sage: x,y = T.cohomology_ring(QQ).basis(1) sage: x.cup_product(y) -h^{2,0} sage: x.cup_product(x) 0
`\Delta`-complexes::
sage: T_d = delta_complexes.Torus() sage: a,b = T_d.cohomology_ring(QQ).basis(1) sage: a.cup_product(b) h^{2,0} sage: b.cup_product(a) -h^{2,0} sage: RP2 = delta_complexes.RealProjectivePlane() sage: w = RP2.cohomology_ring(GF(2)).basis()[1,0] sage: w.cup_product(w) h^{2,0}
and simplicial sets::
sage: from sage.homology.simplicial_set_examples import RealProjectiveSpace sage: RP5 = RealProjectiveSpace(5) sage: x = RP5.cohomology_ring(GF(2)).basis()[1,0] sage: x**4 h^{4,0}
A non-connected example::
sage: K = cubical_complexes.Torus().disjoint_union(cubical_complexes.Torus()) sage: a,b,c,d = K.cohomology_ring(QQ).basis(1) sage: x,y = K.cohomology_ring(QQ).basis(0) sage: a.cup_product(x) == a True sage: a.cup_product(y) 0 """
r""" Return the cup product of this element and ``other``.
Algorithm: see González-Díaz and Réal [GDR2003]_, p. 88. Given two cohomology classes, lift them to cocycle representatives via the chain contraction for this complex, using :meth:`~HomologyVectorSpaceWithBasis.Element.to_cycle`. In the sum of their dimensions, look at all of the homology classes `\gamma`: lift each of those to a cycle representative, apply the Alexander-Whitney diagonal map to each cell in the cycle, evaluate the two cocycles on these factors, and multiply. The result is the value of the cup product cocycle on this homology class. After this has been done for all homology classes, since homology and cohomology are dual, one can tell which cohomology class corresponds to the cup product.
.. SEEALSO::
:meth:`CohomologyRing.product_on_basis`
EXAMPLES::
sage: RP3 = simplicial_complexes.RealProjectiveSpace(3) sage: H = RP3.cohomology_ring(GF(2)) sage: c = H.basis()[1,0] sage: c.cup_product(c) h^{2,0} sage: c * c * c h^{3,0}
We can also take powers::
sage: RP2 = simplicial_complexes.RealProjectivePlane() sage: a = RP2.cohomology_ring(GF(2)).basis()[1,0] sage: a**0 h^{0,0} sage: a**1 h^{1,0} sage: a**2 h^{2,0} sage: a**3 0
A non-connected example::
sage: K = cubical_complexes.Torus().disjoint_union(cubical_complexes.Sphere(2)) sage: a,b = K.cohomology_ring(QQ).basis(2) sage: a**0 h^{0,0} + h^{0,1}
"""
r""" Return the result of applying `Sq^i` to this element.
INPUT:
- ``i`` -- nonnegative integer
.. WARNING::
This is only implemented for simplicial complexes.
This cohomology operation is only defined in characteristic 2.
Algorithm: see González-Díaz and Réal [GDR1999]_, Corollary 3.2.
EXAMPLES::
sage: RP2 = simplicial_complexes.RealProjectiveSpace(2) sage: x = RP2.cohomology_ring(GF(2)).basis()[1,0] sage: x.Sq(1) h^{2,0}
sage: K = RP2.suspension() sage: K.set_immutable() sage: y = K.cohomology_ring(GF(2)).basis()[2,0] sage: y.Sq(1) h^{3,0}
sage: RP4 = simplicial_complexes.RealProjectiveSpace(4) sage: H = RP4.cohomology_ring(GF(2)) sage: x = H.basis()[1,0] sage: y = H.basis()[2,0] sage: z = H.basis()[3,0] sage: x.Sq(1) == y True sage: z.Sq(1) # long time h^{4,0}
This calculation is much faster with simplicial sets (on one machine, 20 seconds with a simplicial complex, 4 ms with a simplicial set). ::
sage: RP4_ss = simplicial_sets.RealProjectiveSpace(4) sage: z_ss = RP4_ss.cohomology_ring(GF(2)).basis()[3,0] sage: z_ss.Sq(1) h^{4,0}
TESTS::
sage: T = cubical_complexes.Torus() sage: x = T.cohomology_ring(GF(2)).basis()[1,0] sage: x.Sq(1) Traceback (most recent call last): ... NotImplementedError: Steenrod squares are only implemented for simplicial complexes and simplicial sets sage: S2 = simplicial_complexes.Sphere(2) sage: x = S2.cohomology_ring(GF(7)).basis()[2,0] sage: x.Sq(1) Traceback (most recent call last): ... ValueError: Steenrod squares are only defined in characteristic 2 """ 'simplicial complexes and simplicial sets') # We keep the same notation as in [GDR1999]. # The trivial cases: # Sq^0 is the identity. return self
# Construct each graded component of ``self``
# Do the square on each graded component of ``self``. # Make it into an actual element continue
# Now assemble the indices over which the sums take place. # S(n) is defined to be floor((m+1)/2) + floor(n/2). sums = [[S_n]] else: for l in sum_indices(n-1, i_n, S_n)] # At this point, 'sums' is a list of lists of the form # [i_n, i_{n-1}, ..., i_0]. (It is reversed from the # obvious order because this is closer to the order in # which the face maps will be applied.) Now we sum over # these, according to the formula in [GDR1999], Corollary 3.2. # Since we are working with a simplicial complex, 'cell' is a simplex. else: except IndexError: pass
and left.is_nondegenerate() and right.is_nondegenerate()) or not hasattr(left, 'is_nondegenerate')):
r""" This is a recursive function for computing the indices for the nested sums in González-Díaz and Réal [GDR1999]_, Corollary 3.2.
In the paper, given indices `i_n`, `i_{n-1}`, ..., `i_{k+1}`, given `k`, and given `S(k+1)`, the number `S(k)` is defined to be
.. MATH::
S(k) = -S(k+1) + floor(k/2) + floor((k+1)/2) + i_{k+1},
and `i_k` ranges from `S(k)` to `i_{k+1}-1`. There are two special cases: if `k=0`, then `i_0 = S(0)`. Also, the initial case of `S(k)` is `S(n)`, which is set in the method :meth:`Sq` before calling this function. For this function, given `k`, `i_{k+1}`, and `S(k+1)`, return a list consisting of the allowable possible indices `[i_k, i_{k-1}, ..., i_1, i_0]` given by the above formula.
INPUT:
- ``k`` -- non-negative integer - ``i_k_plus_one`` -- the positive integer `i_{k+1}` - ``S_k_plus_one`` -- the integer `S(k+1)`
EXAMPLES::
sage: from sage.homology.homology_vector_space_with_basis import sum_indices sage: sum_indices(1, 3, 3) [[1, 0], [2, 1]] sage: sum_indices(0, 4, 2) [[2]] """ for l in sum_indices(k-1, i_k, S_k)]
|