# Chains and cochains¶

This module implements formal linear combinations of cells of a given cell complex (Chains) and their dual (Cochains). It is closely related to the sage.homology.chain_complex module. The main differences are that chains and cochains here are of homogeneous dimension only, and that they reference their cell complex.

class sage.homology.chains.CellComplexReference(cell_complex, degree, cells=None)

Bases: object

Auxiliary base class for chains and cochains

INPUT:

• cell_complex – The cell complex to reference
• degree – integer. The degree of the (co)chains
• cells – tuple of cells or None. Does not necessarily have to be the cells in the given degree, for computational purposes this could also be any collection that is in one-to-one correspondence with the cells. If None, the cells of the complex in the given degree are used.

EXAMPLES:

sage: X = simplicial_complexes.Simplex(2)
sage: from sage.homology.chains import CellComplexReference
sage: c = CellComplexReference(X, 1)
sage: c.cell_complex() is X
True

cell_complex()

Return the underlying cell complex

OUTPUT:

A cell complex.

EXAMPLES:

sage: X = simplicial_complexes.Simplex(2)
sage: X.n_chains(1).cell_complex() is X
True

degree()

Return the dimension of the cells

OUTPUT:

Integer. The dimension of the cells.

EXAMPLES:

sage: X = simplicial_complexes.Simplex(2)
sage: X.n_chains(1).degree()
1

class sage.homology.chains.Chains(cell_complex, degree, cells=None, base_ring=None)

Class for the free module of chains in a given degree.

INPUT:

• n_cells – tuple of $$n$$-cells, which thus forms a basis for this module
• base_ring – optional (default $$\ZZ$$)

One difference between chains and cochains is notation. In a simplicial complex, for example, a simplex (0,1,2) is written as “(0,1,2)” in the group of chains but as “\chi_(0,1,2)” in the group of cochains.

Also, since the free modules of chains and cochains are dual, there is a pairing $$\langle c, z \rangle$$, sending a cochain $$c$$ and a chain $$z$$ to a scalar.

EXAMPLES:

sage: S2 = simplicial_complexes.Sphere(2)
sage: C_2 = S2.n_chains(1)
sage: C_2_co = S2.n_chains(1, cochains=True)
sage: x = C_2.basis()[Simplex((0,2))]
sage: y = C_2.basis()[Simplex((1,3))]
sage: z = x+2*y
sage: a = C_2_co.basis()[Simplex((1,3))]
sage: b = C_2_co.basis()[Simplex((0,3))]
sage: c = 3*a-2*b
sage: z
(0, 2) + 2*(1, 3)
sage: c
-2*\chi_(0, 3) + 3*\chi_(1, 3)
sage: c.eval(z)
6

class Element

Bases: sage.modules.with_basis.indexed_element.IndexedFreeModuleElement

boundary()

Return the boundary of the chain

OUTPUT:

The boundary as a chain in one degree lower.

EXAMPLES:

sage: square = cubical_complexes.Cube(2)
sage: C1 = square.n_chains(1, QQ)
sage: from sage.homology.cubical_complex import Cube
sage: chain = C1(Cube([[1, 1], [0, 1]])) - 2 * C1(Cube([[0, 1], [0, 0]]))
sage: chain
-2*[0,1] x [0,0] + [1,1] x [0,1]
sage: chain.boundary()
2*[0,0] x [0,0] - 3*[1,1] x [0,0] + [1,1] x [1,1]

is_boundary()

Test whether the chain is a boundary

OUTPUT:

Boolean. Whether the chain is the boundary() of a chain in one degree higher.

EXAMPLES:

sage: square = cubical_complexes.Cube(2)
sage: C1 = square.n_chains(1, QQ)
sage: from sage.homology.cubical_complex import Cube
sage: chain = C1(Cube([[1, 1], [0, 1]])) - C1(Cube([[0, 1], [0, 0]]))
sage: chain.is_boundary()
False

is_cycle()

Test whether the chain is a cycle

OUTPUT:

Boolean. Whether the boundary() vanishes.

EXAMPLES:

sage: square = cubical_complexes.Cube(2)
sage: C1 = square.n_chains(1, QQ)
sage: from sage.homology.cubical_complex import Cube
sage: chain = C1(Cube([[1, 1], [0, 1]])) - C1(Cube([[0, 1], [0, 0]]))
sage: chain.is_cycle()
False

to_complex()

Return the corresponding chain complex element

OUTPUT:

An element of the chain complex, see sage.homology.chain_complex.

EXAMPLES:

sage: square = cubical_complexes.Cube(2)
sage: C1 = square.n_chains(1, QQ)
sage: from sage.homology.cubical_complex import Cube
sage: chain = C1(Cube([[1, 1], [0, 1]]))
sage: chain.to_complex()
Chain(1:(0, 0, 0, 1))
sage: ascii_art(_)
d_0  [0]  d_1  [0]  d_2       d_3
0 <---- [0] <---- [0] <---- [0] <---- 0
[0]       [0]
[0]       [1]

chain_complex()

Return the chain complex.

OUTPUT:

Chain complex, see sage.homology.chain_complex.

EXAMPLES:

sage: square = cubical_complexes.Cube(2)
sage: CC = square.n_chains(2, QQ).chain_complex(); CC
Chain complex with at most 3 nonzero terms over Rational Field
sage: ascii_art(CC)
[-1 -1  0  0]       [-1]
[ 1  0 -1  0]       [ 1]
[ 0  1  0 -1]       [-1]
[ 0  0  1  1]       [ 1]
0 <-- C_0 <-------------- C_1 <----- C_2 <-- 0

dual()

Return the cochains.

OUTPUT:

The cochains of the same cells with the same base ring.

EXAMPLES:

sage: square = cubical_complexes.Cube(2)
sage: chains = square.n_chains(1, ZZ);  chains
Free module generated by {[0,0] x [0,1], [0,1] x [0,0], [0,1] x [1,1], [1,1] x [0,1]} over Integer Ring
sage: chains.dual()
Free module generated by {[0,0] x [0,1], [0,1] x [0,0], [0,1] x [1,1], [1,1] x [0,1]} over Integer Ring
sage: type(chains)
<class 'sage.homology.chains.Chains_with_category'>
sage: type(chains.dual())
<class 'sage.homology.chains.Cochains_with_category'>

class sage.homology.chains.Cochains(cell_complex, degree, cells=None, base_ring=None)

Class for the free module of cochains in a given degree.

INPUT:

• n_cells – tuple of $$n$$-cells, which thus forms a basis for this module
• base_ring – optional (default $$\ZZ$$)

One difference between chains and cochains is notation. In a simplicial complex, for example, a simplex (0,1,2) is written as “(0,1,2)” in the group of chains but as “\chi_(0,1,2)” in the group of cochains.

Also, since the free modules of chains and cochains are dual, there is a pairing $$\langle c, z \rangle$$, sending a cochain $$c$$ and a chain $$z$$ to a scalar.

EXAMPLES:

sage: S2 = simplicial_complexes.Sphere(2)
sage: C_2 = S2.n_chains(1)
sage: C_2_co = S2.n_chains(1, cochains=True)
sage: x = C_2.basis()[Simplex((0,2))]
sage: y = C_2.basis()[Simplex((1,3))]
sage: z = x+2*y
sage: a = C_2_co.basis()[Simplex((1,3))]
sage: b = C_2_co.basis()[Simplex((0,3))]
sage: c = 3*a-2*b
sage: z
(0, 2) + 2*(1, 3)
sage: c
-2*\chi_(0, 3) + 3*\chi_(1, 3)
sage: c.eval(z)
6

class Element

Bases: sage.modules.with_basis.indexed_element.IndexedFreeModuleElement

coboundary()

Return the coboundary of this cochain

OUTPUT:

The coboundary as a cochain in one degree higher.

EXAMPLES:

sage: square = cubical_complexes.Cube(2)
sage: C1 = square.n_chains(1, QQ, cochains=True)
sage: from sage.homology.cubical_complex import Cube
sage: cochain = C1(Cube([[1, 1], [0, 1]])) - 2 * C1(Cube([[0, 1], [0, 0]]))
sage: cochain
-2*\chi_[0,1] x [0,0] + \chi_[1,1] x [0,1]
sage: cochain.coboundary()
-\chi_[0,1] x [0,1]

cup_product(cochain)

Return the cup product with another cochain.

INPUT:

• cochain – cochain over the same cell complex

EXAMPLES:

sage: T2 = simplicial_complexes.Torus()
sage: C1 = T2.n_chains(1, base_ring=ZZ, cochains=True)
sage: def l(i, j):
....:      return C1(Simplex([i, j]))
sage: l1 = l(1, 3) + l(1, 4) + l(1, 6) + l(2, 4) - l(4, 5) + l(5, 6)
sage: l2 = l(1, 6) - l(2, 3) - l(2, 5) + l(3, 6) - l(4, 5) + l(5, 6)


The two one-cocycles are cohomology generators:

sage: l1.is_cocycle(), l1.is_coboundary()
(True, False)
sage: l2.is_cocycle(), l2.is_coboundary()
(True, False)


Their cup product is a two-cocycle that is again non-trivial in cohomology:

sage: l12 = l1.cup_product(l2)
sage: l12
\chi_(1, 3, 6) - \chi_(2, 4, 5) - \chi_(4, 5, 6)
sage: l1.parent().degree(), l2.parent().degree(), l12.parent().degree()
(1, 1, 2)
sage: l12.is_cocycle(), l12.is_coboundary()
(True, False)

eval(other)

Evaluate this cochain on the chain other.

INPUT:

• other – a chain for the same cell complex in the same dimension with the same base ring

OUTPUT: scalar

EXAMPLES:

sage: S2 = simplicial_complexes.Sphere(2)
sage: C_2 = S2.n_chains(1)
sage: C_2_co = S2.n_chains(1, cochains=True)
sage: x = C_2.basis()[Simplex((0,2))]
sage: y = C_2.basis()[Simplex((1,3))]
sage: z = x+2*y
sage: a = C_2_co.basis()[Simplex((1,3))]
sage: b = C_2_co.basis()[Simplex((0,3))]
sage: c = 3*a-2*b
sage: z
(0, 2) + 2*(1, 3)
sage: c
-2*\chi_(0, 3) + 3*\chi_(1, 3)
sage: c.eval(z)
6

is_coboundary()

Test whether the cochain is a coboundary

OUTPUT:

Boolean. Whether the cochain is the coboundary() of a cochain in one degree lower.

EXAMPLES:

sage: square = cubical_complexes.Cube(2)
sage: C1 = square.n_chains(1, QQ, cochains=True)
sage: from sage.homology.cubical_complex import Cube
sage: cochain = C1(Cube([[1, 1], [0, 1]])) - C1(Cube([[0, 1], [0, 0]]))
sage: cochain.is_coboundary()
True

is_cocycle()

Test whether the cochain is a cocycle

OUTPUT:

Boolean. Whether the coboundary() vanishes.

EXAMPLES:

sage: square = cubical_complexes.Cube(2)
sage: C1 = square.n_chains(1, QQ, cochains=True)
sage: from sage.homology.cubical_complex import Cube
sage: cochain = C1(Cube([[1, 1], [0, 1]])) - C1(Cube([[0, 1], [0, 0]]))
sage: cochain.is_cocycle()
True

to_complex()

Return the corresponding cochain complex element

OUTPUT:

An element of the cochain complex, see sage.homology.chain_complex.

EXAMPLES:

sage: square = cubical_complexes.Cube(2)
sage: C1 = square.n_chains(1, QQ, cochains=True)
sage: from sage.homology.cubical_complex import Cube
sage: cochain = C1(Cube([[1, 1], [0, 1]]))
sage: cochain.to_complex()
Chain(1:(0, 0, 0, 1))
sage: ascii_art(_)
d_2       d_1  [0]  d_0  [0]  d_-1
0 <---- [0] <---- [0] <---- [0] <----- 0
[0]       [0]
[1]       [0]

cochain_complex()

Return the cochain complex.

OUTPUT:

Cochain complex, see sage.homology.chain_complex.

EXAMPLES:

sage: square = cubical_complexes.Cube(2)
sage: C2 = square.n_chains(2, QQ, cochains=True)
sage: C2.cochain_complex()
Chain complex with at most 3 nonzero terms over Rational Field
sage: ascii_art(C2.cochain_complex())
[-1  1  0  0]
[-1  0  1  0]
[ 0 -1  0  1]
[-1  1 -1  1]       [ 0  0 -1  1]
0 <-- C_2 <-------------- C_1 <-------------- C_0 <-- 0

dual()

Return the chains

OUTPUT:

The chains of the same cells with the same base ring.

EXAMPLES:

sage: square = cubical_complexes.Cube(2)
sage: cochains = square.n_chains(1, ZZ, cochains=True);  cochains
Free module generated by {[0,0] x [0,1], [0,1] x [0,0], [0,1] x [1,1], [1,1] x [0,1]} over Integer Ring
sage: cochains.dual()
Free module generated by {[0,0] x [0,1], [0,1] x [0,0], [0,1] x [1,1], [1,1] x [0,1]} over Integer Ring
sage: type(cochains)
<class 'sage.homology.chains.Cochains_with_category'>
sage: type(cochains.dual())
<class 'sage.homology.chains.Chains_with_category'>