# \[ANN\] Ripserer - Efficient Persistent Homology Computation in Julia

**URL:** https://discourse.julialang.org/t/ann-ripserer-efficient-persistent-homology-computation-in-julia/40639
**Category:** Package Announcements
**Created:** [June 3, 2020, 12:25am UTC](https://discourse.julialang.org/t/ann-ripserer-efficient-persistent-homology-computation-in-julia/40639 "2020-06-03T00:25:35Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![mtsch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mtsch/32/2072_2.png) [@mtsch](https://discourse.julialang.org/u/mtsch)
#### Post date: [June 3, 2020, 12:25am UTC](https://discourse.julialang.org/t/ann-ripserer-efficient-persistent-homology-computation-in-julia/40639/1 "2020-06-03T00:25:35Z")

</div>

Hi guys,

I’m pleased to announce [Ripserer.jl](https://github.com/mtsch/Ripserer.jl), a pure Julia library for computing persistent homology. It uses the same algorithm as Ripser, which is known to be one of the fastest pieces of software for this purpose.

The list of supported features currently includes the following:

- Vietoris-Rips persistent homology.
- Sublevel set persistent homology for multidimensional image and time series data.
- Calculation of persistent homology with coefficients in any (possibly user defined) field  
with the default of intgers mod `p` for a prime `p`.
- Sparse distance matrix and thresholding support.
- Computing and plotting representative cocycles of persistent cohomology.
- Generic API.
- Persistence diagram plotting.
- Bottleneck and Wasserstein distance computation.
- Persistence images.

The last three live in a separate package, [PersistenceDiagrams.jl](https://github.com/mtsch/PersistenceDiagrams.jl).

For a quick demo, please checkout the Examples section in the [docs](https://mtsch.github.io/Ripserer.jl/dev/). If you’re unfamiliar with persistent homology, I recommend starting with [this blogpost](https://towardsdatascience.com/persistent-homology-with-examples-1974d4b9c3d0?gi=ab59278a7966).

The main benefit (in my opinion) of this project is its generic API, which allows you to easily add new features to Ripserer without having to maintain your own fork of the project. For example, cubical persistent homology is implemented in [190 lines of code](https://github.com/mtsch/Ripserer.jl/blob/master/src/cubical.jl), which include docstrings.

The packages are registered, but still in development, so keep that in mind if APIs change unexpectedly. All ideas, feedback, issues and pull requests are more than welcome!

---

<div class="post-metadata">

### Author: ![yakir12](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yakir12/32/297_2.png) [@yakir12](https://discourse.julialang.org/u/yakir12)
#### Post date: [June 3, 2020, 11:27am UTC](https://discourse.julialang.org/t/ann-ripserer-efficient-persistent-homology-computation-in-julia/40639/2 "2020-06-03T11:27:39Z")

</div>

Wah, very cool. Thank you for linking that blog post as well, I needed it. But yea, that piqued my interest. It would be worth adding more examples of where this can be used and implemented. Looking forward to trying it out on images and trajectories. Nice!

---

<div class="post-metadata">

### Author: ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)
#### Post date: [June 3, 2020, 12:04pm UTC](https://discourse.julialang.org/t/ann-ripserer-efficient-persistent-homology-computation-in-julia/40639/3 "2020-06-03T12:04:04Z")

</div>

Nice. How does it compare with existing packages in Julia for persistence homology? I remember at least two packages implementing similar functionality.

---

<div class="post-metadata">

### Author: ![mtsch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mtsch/32/2072_2.png) [@mtsch](https://discourse.julialang.org/u/mtsch)
#### Post date: [June 3, 2020, 1:25pm UTC](https://discourse.julialang.org/t/ann-ripserer-efficient-persistent-homology-computation-in-julia/40639/4 "2020-06-03T13:25:58Z")

</div>

> [@yakir12](#):
>
> Wah, very cool. Thank you for linking that blog post as well, I needed it. But yea, that piqued my interest. It would be worth adding more examples of where this can be used and implemented. Looking forward to trying it out on images and trajectories. Nice!

Thanks! Sadly, I haven’t had the chance to use this stuff in the real world yet, but I’m planning on adding a few more realistic examples. Pull requests or issues with examples or ideas would be very welcome!

> [@juliohm](#):
>
> Nice. How does it compare with existing packages in Julia for persistence homology? I remember at least two packages implementing similar functionality.

Yeah, there are quite a few projects out there. Here’s a quick overview of what I know about:

- [Ripser.jl](https://github.com/mtsch/Ripser.jl): my wrapper of the original C++ program. Very bare-bones and a bit outdated, but does essentially the same thing. Being a C++ wrapper, things like cubical homology are out of the question. According to my benchmarks, it’s around 30% faster. I’m still working on getting that number lower and from what I’ve seen Ripserer will actually outperform it once Julia 1.5 comes out. I haven’t tested enough to be sure.
- [Sparips.jl](https://github.com/mtsch/Ripser.jl): this is a preprocessor that comes with a different wrapper of Ripser. The preprocessor allows you to compute persistent homology of very large datasets. Stealing its code and adding it to Ripserer is on my TODO list.
- [ComputationalHomology.jl](https://github.com/wildart/ComputationalHomology.jl): haven’t used it yet, but from the looks of it, it does quite a few things besides persistent homology. From what I’ve heard, the persistent homology algorithm is orders of magnitude slower than Ripserer.
- [PersistentCohomology.jl](https://github.com/piever/PersistentCohomology.jl): does essentially the same thing, but with a different algorithm, that is orders of magnitude slower.
- [Eirene.jl](https://github.com/Eetion/Eirene.jl): Not really a package, but more like an interactive tool for computing persistent homology. I tried wrapping my head around the algorithm it uses and failed. Has heaps of features. From what I heard its actually pretty fast. I still haven’t taken the time to learn to use it.

---

<div class="post-metadata">

### Author: ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)
#### Post date: [June 3, 2020, 3:37pm UTC](https://discourse.julialang.org/t/ann-ripserer-efficient-persistent-homology-computation-in-julia/40639/5 "2020-06-03T15:37:22Z")

</div>

Love this kind of careful comparison ❤

---

<div class="post-metadata">

### Author: ![saschatimme](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/saschatimme/32/10313_2.png) [@saschatimme](https://discourse.julialang.org/u/saschatimme)
#### Post date: [June 3, 2020, 3:44pm UTC](https://discourse.julialang.org/t/ann-ripserer-efficient-persistent-homology-computation-in-julia/40639/6 "2020-06-03T15:44:23Z")

</div>

Very nice.

> - Calculation of persistent homology with coefficients in any (possibly user defined) field with the default of intgers mod `p` for a prime `p` .

Do you also have plans to support computing over the integers? I know this is terrible computationally, but from a math point of this would be quite interesting.

---

<div class="post-metadata">

### Author: ![piever](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/piever/32/1815_2.png) [@piever](https://discourse.julialang.org/u/piever)
#### Post date: [June 3, 2020, 6:27pm UTC](https://discourse.julialang.org/t/ann-ripserer-efficient-persistent-homology-computation-in-julia/40639/7 "2020-06-03T18:27:04Z")

</div>

Really nice work!

> [@mtsch](#):
>
> [PersistentCohomology.jl](https://github.com/piever/PersistentCohomology.jl): does essentially the same thing, but with a different algorithm, that is orders of magnitude slower.

I also noticed performance was not great with PersistentCohomology but could not quite figure out why. Is the difference at the algorithmic level? PersistentCohomology uses the persistent cocycle algorithm from the [de Silva et al. paper](https://link.springer.com/article/10.1007/s00454-011-9344-x), are there algorithms that are much more efficient?

---

<div class="post-metadata">

### Author: ![mtsch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mtsch/32/2072_2.png) [@mtsch](https://discourse.julialang.org/u/mtsch)
#### Post date: [June 4, 2020, 1:59am UTC](https://discourse.julialang.org/t/ann-ripserer-efficient-persistent-homology-computation-in-julia/40639/8 "2020-06-04T01:59:37Z")

</div>

> [@saschatimme](#):
>
> Do you also have plans to support computing over the integers? I know this is terrible computationally, but from a math point of this would be quite interesting.

Sadly, that would require a completely different algorithm and is out of the scope of this project. I think I read somewhere ComputationalHomology.jl can do that, but I haven’t tried it.

> [@piever](#):
>
> I also noticed performance was not great with PersistentCohomology but could not quite figure out why. Is the difference at the algorithmic level? PersistentCohomology uses the persistent cocycle algorithm from the [de Silva et al. paper](https://link.springer.com/article/10.1007/s00454-011-9344-x), are there algorithms that are much more efficient?

I really recommend reading [Uli’s paper on Ripser](https://arxiv.org/abs/1908.02518) or [watching his talk](https://www.youtube.com/watch?v=Gh3R7tCsSp0&). I think he explains it better than I could, but essentially, it comes down to three things:

- The twist optimization. This allows you to skip the reduction of some columns by ordering simplices by dimension.
- Emergent pairs. This skips computing some zero length persistence intervals, like the ones that appear on each triangle.
- The simplicial complex and some parts of the reduction matrix are not stored in memory, but rather recomputed on the fly. It turns out that reducing memory accesses makes a huge difference in speed. The CPU cache has nightmares about persistent homology computations.

Feel free to hit me up if you have any other specific questions on the algorithm.

By the way, have you looked at computing circular coordinates from persistent cohomology? That would be a really cool thing to have, but I haven’t looked into it enough to be sure it’s feasible.

---

<div class="post-metadata">

### Author: ![piever](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/piever/32/1815_2.png) [@piever](https://discourse.julialang.org/u/piever)
#### Post date: [June 5, 2020, 9:49am UTC](https://discourse.julialang.org/t/ann-ripserer-efficient-persistent-homology-computation-in-julia/40639/9 "2020-06-05T09:49:40Z")

</div>

> [@mtsch](#):
>
> By the way, have you looked at computing circular coordinates from persistent cohomology? That would be a really cool thing to have, but I haven’t looked into it enough to be sure it’s feasible.

No, I’ve never looked into that. I was mainly playing with implementations to see if it is possible to get an algorithm that is in some sense “functorial”, in that if there is a discrete group action (say a mirror symmetry) that preserves the filtration, then it is possible to see the effect of the group action on the cornerpoints. I haven’t done that yet (and am not actively working on it at the moment), but I’ll be curious to know if you end up having that feature at some point.

---

<div class="post-metadata">

### Author: ![mtsch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mtsch/32/2072_2.png) [@mtsch](https://discourse.julialang.org/u/mtsch)
#### Post date: [June 7, 2020, 4:25am UTC](https://discourse.julialang.org/t/ann-ripserer-efficient-persistent-homology-computation-in-julia/40639/10 "2020-06-07T04:25:33Z")

</div>

I’m not sure I understand this correctly. Do you want to map a function (mapping a simplex to a different simplex) on the simplices of the filtration and observe what happens to the results?  
I think something like that could be done by defining a new simplex type that applies the function in the constructor. In theory, things should just work after that.

---

<div class="post-metadata">

### Author: ![chakravala](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chakravala/32/6832_2.png) [@chakravala](https://discourse.julialang.org/u/chakravala)
#### Post date: [June 7, 2020, 3:05pm UTC](https://discourse.julialang.org/t/ann-ripserer-efficient-persistent-homology-computation-in-julia/40639/11 "2020-06-07T15:05:20Z")

</div>

Another library for persistent homology is

> **[GitHub - yossibokorbleile/DiscretePersistentHomologyTransform.jl:...](https://github.com/yossibokorbleile/DiscretePersistentHomologyTransform.jl)**
>
> Implementation of the Persistent Homology Transform - GitHub - yossibokorbleile/DiscretePersistentHomologyTransform.jl: Implementation of the Persistent Homology Transform

Also, my package [Grassmann.jl](https://github.com/chakravala/Grassmann.jl) supports homology and cohomology computations, although it’s not specifically designed for persistent homology, and also defines an interface for `Simplex`, `SubManifold` and `Chain` types (along with the boundary and coboundary operations), which are the foundation of simplicial homology.

---

<div class="post-metadata">

### Author: ![piever](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/piever/32/1815_2.png) [@piever](https://discourse.julialang.org/u/piever)
#### Post date: [June 10, 2020, 2:56pm UTC](https://discourse.julialang.org/t/ann-ripserer-efficient-persistent-homology-computation-in-julia/40639/12 "2020-06-10T14:56:31Z")

</div>

> [@mtsch](#):
>
> Do you want to map a function (mapping a simplex to a different simplex) on the simplices of the filtration and observe what happens to the results?

The idea is that if you have a finite group G of symmetries acting on a filtration of topological spaces (or on a filtration of simplicial complexes), then the homology groups are not in \mathbf{Vec}\_\mathbb{K} (where \mathbb{K} is the base field), but really they are in \mathrm{Rep}\_\mathbb{K}(G), the category of group representations of G, and cornerpoints in the persistence diagram are indecomposable representations of G, each drawn in a color that represents the isomorphism class of the indecomposable representation. Shameless self-plug: see the section “multicolored persistence” in [this paper](http://www.tac.mta.ca/tac/volumes/35/9/35-09.pdf), figure 2 may help to get some intuition.

I think it’d be nice if eventually there would be an efficient way to compute these “multicolored persistence diagrams”. To come back to your question, in practice I guess it boils to something that needs as input a filtration of simplices with a group of permutation acting on them (so each simplex has an “orbit” of other simplices on which it is mapped by this group). If the group is for example \mathbb{Z}\_2, then it is either mapped onto itself, or onto another simplex.

> [@mtsch](#):
>
> I think something like that could be done by defining a new simplex type that applies the function in the constructor.

This is probably a very good intuition. I was using simple tuples for simplexes, but with a custom type (encoding for example the “orbit” that the simplex belongs to, or something like that) could actually be enough to recover the multicolored diagram.

---

<div class="post-metadata">

### Author: ![mtsch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mtsch/32/2072_2.png) [@mtsch](https://discourse.julialang.org/u/mtsch)
#### Post date: [June 13, 2020, 9:55am UTC](https://discourse.julialang.org/t/ann-ripserer-efficient-persistent-homology-computation-in-julia/40639/13 "2020-06-13T09:55:28Z")

</div>

> [@chakravala](#):
>
> Also, my package [Grassmann.jl](https://github.com/chakravala/Grassmann.jl) supports homology and cohomology computations, although it’s not specifically designed for persistent homology, and also defines an interface for `Simplex` , `SubManifold` and `Chain` types (along with the boundary and coboundary operations), which are the foundation of simplicial homology.

Nice! I really should get into your package some time, looks like it can do some pretty cool things. Maybe it would be possible to somehow integrate with Ripserer… I wouldn’t however change the `Simplex` type I’m using in the main project because it’s very specialized for this specific algorithm.

@piever I skimmed through the paper and it that looks pretty cool! I’ll try to go through the paper some time soon. If you ever feel an urge to work on this kind of stuff again, let me know.
