Topics

representatives of bars, homology classes. . . perhaps with better formatting

Ryan Budney
 

Greetings, 
 
Say I've computed persistent homology of some RIPS complex in Dionysus.  How does one go the extra step to find a cycle representative in a homology class?  i.e. I would like to identify the bar, and determine which linear combination of simplices represent the bar. 
 
In the process of writing this question I likely have answered it.  But it would be nice to get confirmation, and perhaps this will be useful to others.
 
To make this concrete and fairly simple, let me use the vertices of a square of side-length two as my data set.
 
import dionysus as di
 
## generate square as a list
 
A = []
for i in [-1,1]:
    for j in [-1, 1]:
        cv = [i, i]
        cv[1] *= j
        A.append(cv)
 
## convert to numpy array
A = np.array(A, float)
 
## generate the associated RIPS complex
X = di.fill_rips(A, 3, 3.0)
 
## compute persistent homology
hfp = di.homology_persistence(X)
 
## here is where I get a bit fuzzy.  My understanding is hfp is a reduced
## matrix that describes the persistent homology.  But I'm not certain how 
## to read it.  Here is some code of Dmitriy's that I lifted from a 2018 thread.
 
for i,c in enumerate(hfp):
  print(X[i],end=': ')
  print(" + ".join(["%d * %s" % (x.element, X[x.index]) for x in c]))
 
If I execute the above code, I get this as output.
 
<0> 0: 
<1> 0: 
<2> 0: 
<3> 0: 
<0,1> 2: 1 * <0> 0 + 1 * <1> 0
<0,3> 2: 1 * <0> 0 + 1 * <3> 0
<1,2> 2: 1 * <1> 0 + 1 * <2> 0
<2,3> 2: 
<0,2> 2.82843: 
<1,3> 2.82843: 
<0,1,2> 2.82843: 1 * <0,1> 2 + 1 * <1,2> 2 + 1 * <0,2> 2.82843
<0,1,3> 2.82843: 1 * <0,1> 2 + 1 * <0,3> 2 + 1 * <1,3> 2.82843
<0,2,3> 2.82843: 1 * <0,1> 2 + 1 * <0,3> 2 + 1 * <1,2> 2 + 1 * <2,3> 2
<1,2,3> 2.82843: 
<0,1,2,3> 2.82843: 1 * <0,1,2> 2.82843 + 1 * <0,1,3> 2.82843 + 1 * <0,2,3> 2.82843 + 1 * <1,2,3> 2.82843
 
What I'd like to do now is see the bars from this output.  My initial impression is this "hfp" object represents the entire chain complex in reduced form. 
 
This persistent homology of our square has four H_0 bars that merge into one at length-parameter 2.  And it has a single H_1 bar that starts at length parameter 2, and dies as 2\sqrt{2}.  Here is how I merge this understanding with the Dionysus output, line-by-line:
 
<0> 0: 
<1> 0: 
<2> 0: 
<3> 0: 
 
These lines say the four vertices labelled <0>, <1>, <2>, <3> appear at length parameter 0.  The fact that there's nothing to the right of the colon indicates bars are created at length-parameter zero. 
 
The lines:
 
<0,1> 2: 1 * <0> 0 + 1 * <1> 0
<0,3> 2: 1 * <0> 0 + 1 * <3> 0
<1,2> 2: 1 * <1> 0 + 1 * <2> 0
 
say at length-parameter 2, the three edges <0,1>, <0,3>, <1,2> are created and they merge the four 0-cycles into one. 
 
The line:
 
<2,3> 2: 
 
indicates the last edge <2,3> is creating a 1-cycle, at side-length 2.  So this helps me.  It's telling me that generally one has to combine these relations to discover the cycle representatives. 
 
The remaining lines are relatively degenerate:
 
<0,2> 2.82843: 
<1,3> 2.82843: 
<0,1,2> 2.82843: 1 * <0,1> 2 + 1 * <1,2> 2 + 1 * <0,2> 2.82843
<0,1,3> 2.82843: 1 * <0,1> 2 + 1 * <0,3> 2 + 1 * <1,3> 2.82843
<0,2,3> 2.82843: 1 * <0,1> 2 + 1 * <0,3> 2 + 1 * <1,2> 2 + 1 * <2,3> 2
<1,2,3> 2.82843: 
<0,1,2,3> 2.82843: 1 * <0,1,2> 2.82843 + 1 * <0,1,3> 2.82843 + 1 * <0,2,3> 2.82843 + 1 * <1,2,3> 2.82843
 
This says at length 2\sqrt{2} two new 1-cycles are created and simultaneously destroyed, but then also a 2-cycle is created and simultaneously destroyed, i.e. bars of length 0. 
 
Thanks, 

Dmitriy Morozov
 

Hi Ryan,

Your understanding is correct. I just want to add a couple of small things.

This persistent homology of our square has four H_0 bars that merge into one at length-parameter 2.  And it has a single H_1 bar that starts at length parameter 2, and dies as 2\sqrt{2}.  Here is how I merge this understanding with the Dionysus output, line-by-line:
 
<0> 0: 
<1> 0: 
<2> 0: 
<3> 0: 
 
These lines say the four vertices labelled <0>, <1>, <2>, <3> appear at length parameter 0.  The fact that there's nothing to the right of the colon indicates bars are created at length-parameter zero. 

That's right. If there is nothing to the right of the colon (i.e., if the respective column c (=hfp[i]) is empty), then you have a birth in the filtration, when you add that simplex. It's a little tricky to get the representative cycle that's born (it's much easier to get it when it dies). But in the 0-dimensional case, it's just the vertex.
 
The lines:
 
<0,1> 2: 1 * <0> 0 + 1 * <1> 0
<0,3> 2: 1 * <0> 0 + 1 * <3> 0
<1,2> 2: 1 * <1> 0 + 1 * <2> 0
 
say at length-parameter 2, the three edges <0,1>, <0,3>, <1,2> are created and they merge the four 0-cycles into one. 

Right. The precise meaning of the stuff after the colon is that it's the cycle that was non-zero before, but becomes zero after the addition of the simplex before the colon. Moreover, the cycle is reduced, i.e., it's the oldest such cycle. You can get its birth by taking the maximum birth time, or by looking at hfp.pair(i), which will give you the index of the simplex that gave birth to the cycle.
 
The line:
 
<2,3> 2: 
 
indicates the last edge <2,3> is creating a 1-cycle, at side-length 2.  So this helps me.  It's telling me that generally one has to combine these relations to discover the cycle representatives. 

If you want to find representative of the essential cycles, then you need to do extra work. But if you are only looking for representatives for finite bars, then it's best to just check at the time of death.
 
The remaining lines are relatively degenerate:
 
<0,2> 2.82843: 
<1,3> 2.82843: 
<0,1,2> 2.82843: 1 * <0,1> 2 + 1 * <1,2> 2 + 1 * <0,2> 2.82843
<0,1,3> 2.82843: 1 * <0,1> 2 + 1 * <0,3> 2 + 1 * <1,3> 2.82843
<0,2,3> 2.82843: 1 * <0,1> 2 + 1 * <0,3> 2 + 1 * <1,2> 2 + 1 * <2,3> 2
<1,2,3> 2.82843: 
<0,1,2,3> 2.82843: 1 * <0,1,2> 2.82843 + 1 * <0,1,3> 2.82843 + 1 * <0,2,3> 2.82843 + 1 * <1,2,3> 2.82843
 
This says at length 2\sqrt{2} two new 1-cycles are created and simultaneously destroyed, but then also a 2-cycle is created and simultaneously destroyed, i.e. bars of length 0. 

Right, but the line for <0,2,3> also tells you that you have a bar [2,2.82843], and specifically it gives you a cycle that was born when <2,3> entered the filtration and that got killed when <0,2,3> entered the filtration.
 
I hope this helps.
Dmitriy