Carlsson and de Silva introduced zigzag persistence, a generalization of ordinary persistent
homology that allows linear maps connecting homology groups to point in either direction in the sequence, e.g.:
\(H_*(K_1) \to H_*(K_2) \leftarrow H_*(K_3) \to H_*(K_4) \leftarrow \ldots\)
To express such a zigzag filtration, we consider the maximal simplicial
complex, \(\cup K_i\), and encode it as
a Filtration
:
>>> f = d.Filtration([[0], [1], [0,1], [2], [0,2], [1,2]])
For each simplex in the complex, we specify a list of times when it enters and
leaves the filtration. This information is provided as a list of lists,
times
. For the i-th simplex in the filtration, times[i]
is a list of
times, where values in even positions (counting from 0) specify when the
simplex is added to the complex and odd positions when it is removed:
>>> times = [[.4, .6, .7], [.1], [.9], [.9], [.9], [.9]]
Given the two inputs, we can compute zigzag persistent homology
of the corresponding sequence of simplicial complexes, using
zigzag_homology_persistence()
:
>>> zz, dgms, cells = d.zigzag_homology_persistence(f, times)
The function returns a triple: an internal representation of
ZigzagPersistence
, which stores cycles still alive
in the right-most homology group in the sequence, the persistence diagrams that
represent the decomposition of the sequence, auxiliary map to translate from
internal indices used in the cycles into the indices of the simplices in the
Filtration
:
>>> print(zz)
Zigzag persistence with 2 alive cycles
>>> for i,dgm in enumerate(dgms):
... print("Dimension:", i)
... for p in dgm:
... print(p)
Dimension: 0
(0.4,0.6)
(0.7,0.9)
(0.1,inf)
Dimension: 1
(0.9,inf)
>>> for z in zz:
... print(z)
1*0
1*4 + 1*5 + 1*6
>>> for x in sorted(cells):
... print(x)
(0, 1)
(2, 0)
(3, 3)
(4, 2)
(5, 4)
(6, 5)
The first and the third element of the triple, combined, can be used to extract representative cycles. The third element is the map from the cycle’s internal representation to the filtration indices. The following snippet outputs the cycles in terms of the simplices.
>>> for z in zz:
... print(' + '.join("%d * (%s)" % (x.element, f[cells[x.index]]) for x in z))
1 * (<1> 0)
1 * (<0,1> 0) + 1 * (<0,2> 0) + 1 * (<1,2> 0)
zigzag_homology_persistence()
takes an optional callback argument,
which gets called back after every step of the zigzag. The function receives four arguments, (i,t,d,zz).
i is the index of the simplex being added or removed. t is the current
time. d is the direction: True
if the simplex is being added, False
,
if removed. zz is the current state of ZigzagPersistence
.
>>> def detail(i,t,d,zz,cells):
... print(i,t,d)
... for z in zz:
... print(z, ' -> ', ' + '.join("%d * (%s)" % (x.element, f[cells[x.index]]) for x in z))
>>> zz, dgms, cells = d.zigzag_homology_persistence(f, times, callback = detail)
1 0.10000000149011612 True
1*0 -> 1 * (<1> 0)
0 0.4000000059604645 True
1*0 -> 1 * (<1> 0)
1*1 -> 1 * (<0> 0)
0 0.6000000238418579 False
1*0 -> 1 * (<1> 0)
0 0.699999988079071 True
1*0 -> 1 * (<1> 0)
1*2 -> 1 * (<0> 0)
3 0.8999999761581421 True
1*0 -> 1 * (<1> 0)
1*2 -> 1 * (<0> 0)
1*3 -> 1 * (<2> 0)
2 0.8999999761581421 True
1*0 -> 1 * (<1> 0)
1*3 -> 1 * (<2> 0)
4 0.8999999761581421 True
1*0 -> 1 * (<1> 0)
5 0.8999999761581421 True
1*0 -> 1 * (<1> 0)
1*4 + 1*5 + 1*6 -> 1 * (<0,1> 0) + 1 * (<0,2> 0) + 1 * (<1,2> 0)