A simple python project for computing Persistent homoLogy. THIS REPO IS NO LONGER MAINTAINED as it has been integrated into SageMath ! The algorithm implemented is described in this article by Afra Zomorodian and Gunnar Carlsson.
Install directly from github with python3 -m pip install git+https://github.com/quenouillaume/persil
You can update the module with python3 -m pip install --upgrade --user git+https://github.com/quenouillaume/persil
Download repository as a ZIP file, then open a terminal in your downloads folder and enter:
python /m pip install persil-main.zip
To update, download the latest version as a ZIP file, then, as before, open a terminal in your downloads folder and enter:
python /m pip install --upgrade --user persil-main.zip
Load Sage with
module load gcc/8.3.0
module load sage/9.1
Then, to install:
sage -pip install --user git+https://github.com/quenouillaume/persil/
To upgrade, use:
sage -pip install --upgrade --user git+https://github.com/quenouillaume/persil/
I have not yet written a guide, but it will come soon ! For now, you can use the following code as example.
This code computes the peristent homology for the complex described in Zomorodian+Carlsson's article.
from persil.simplexchain import *
from persil.homology import *
# First step: create a list of simplices and filtration values (also called degrees)
list_simplex_degree = [([0],0), ([1],0), ([2],1), ([3],1), ([0, 1],1), ([1, 2],1), ([0, 3],2), ([2, 3],2), ([0, 2],3), ([0, 1, 2],4), ([0, 2, 3],5)]
# add them one by one in a fresh complex
fc = FilteredComplex()
for (simplex, value) in list_simplex_degree:
fc.insert(simplex,value)
# compute persistent homology in Z/2Z
zc = ZomorodianCarlsson(fc)
zc.computeIntervals()
for i in range(2):
print(zc.getIntervals(i))
This code outputs:
[(0, 1), (1, 1), (1, 2), (0, inf)]
[(3, 4), (2, 5)]
On the same complex as above, shows the persistence diagram for dimension 0
from persil.simplexchain import *
from persil.homology import *
from persil.graphical import *
# First step: create a list of simplices and filtration values (also called degrees)
list_simplex_degree = [([0],0), ([1],0), ([2],1), ([3],1), ([0, 1],1), ([1, 2],1), ([0, 3],2), ([2, 3],2), ([0, 2],3), ([0, 1, 2],4), ([0, 2, 3],5)]
# add them one by one in a fresh complex
fc = FilteredComplex()
for (simplex, value) in list_simplex_degree:
fc.insert(simplex,value)
# compute persistent homology in Z/2Z
zc = ZomorodianCarlsson(fc)
zc.computeIntervals()
persistence_diagram(zc.intervals[0])
This draws a persistence diagram with one vertical line and 3 points !
The RipsComplex class is used to construct Rips complexes from a cloud point. Initialize it as follows:
r = RipsComplex(pointList,distance,threshold)
where:
pointList
is a list of pointsdistance
is a function taking two points as argument and returning their distance as a floatthreshold
is the maximum distance to be considered when constructing the complex. It can be omitted, in which case the program will compute the entire Rips complex, but this can get quite long.- Additionally, you can add the optional argument
verbose = True
, which will make the construction print info on the progress of the construction
Once the object is initialized, compute the Complex with:
r.compute_skeleton(d)
where d
is the maximum desired dimension. For instance if d
is 2, the resulting complex will contain points, edges and triangles.
Finally, you can access the Rips complex with r.complex
. You can then compute its homology like in the previous examples.
If you are working with points in the 2d plane, you can plot the point cloud and the neibourhood graph with r.plot()
. This technically also works with points in higher dimension but it will only plot a projection on the two first axes.
Here is a full example:
import random
from numpy import sqrt
from persil import *
def euclidianDistance(x,y):
return sqrt( sum([(x[i] - y[i])**2 for i in range(len(x))]))
def randomPoints(n,D): # returns a list of n random points in the unit cube of dimension D
l = [ tuple([random.random() for i in range(D)]) for j in range(n)]
return l
l = randomPoints(1000,3)
r = RipsComplex(l,euclidianDistance,0.23,verbose = True)
r.compute_skeleton(2)
zc = ZomorodianCarlsson(r.complex, strict = True,verbose = True)
zc.computeIntervals()
persistence_diagram(zc.intervals[1])