Filtration types¶
A filtration is a sequence of cells sorted by a real-valued function. Oineus
ships builders for the four filtrations you will reach for most often
(Freudenthal, cubical, Vietoris-Rips, alpha) plus a constructor for
user-defined simplicial filtrations. Every builder returns a filtration
object that you can hand to oineus.Decomposition, the one-shot
helpers (oineus.compute_diagrams_ls(),
oineus.compute_diagrams_vr(),
oineus.compute_diagrams_alpha()), or any of the differentiable
builders in oineus.diff.
Picking a filtration¶
Builder |
Input |
Cells produced |
Typical use |
|---|---|---|---|
\(d\)-D NumPy array |
triangulated \(d\)-cube grid, lower/upper star |
Image and volume sublevel-set persistence; smaller than cubical. |
|
\(d\)-D NumPy array |
genuine cubical complex |
When you need pixel/voxel adjacency or want to match GUDHI/cubical-literature conventions. |
|
\((n, d)\) points or \((n, n)\) pairwise distances |
full \(k\)-skeleton of VR |
Generic point clouds in any dimension. |
|
\((n, 2)\) or \((n, 3)\) points |
alpha complex via diode |
2D/3D point clouds; much fewer cells than VR. |
|
list of |
user-specified simplicial complex |
Bring-your-own filtration. |
For low-dimensional point clouds the rule of thumb is alpha first, VR only if you need cells of dimension \(\geq d\) (where \(d\) is the ambient dimension) or your geometry breaks Delaunay assumptions.
Function data on a grid¶
Freudenthal (triangulated grid)¶
import numpy as np
import oineus as oin
img = np.load("scan.npy") # shape (Z, Y, X), dtype float
fil = oin.freudenthal_filtration(img, negate=False, max_dim=2, n_threads=4)
dcmp = oin.Decomposition(fil, dualize=True)
dcmp.reduce(oin.ReductionParams(n_threads=4))
dgms = dcmp.diagram(fil)
print(dgms.in_dimension(0).shape, dgms.in_dimension(1).shape)
The one-shot equivalent is oineus.compute_diagrams_ls(), which builds
the Freudenthal filtration, reduces, and returns
oineus.Diagrams in one call.
Cubical¶
cube_fil = oin.cube_filtration(img, negate=False, values_on="vertices")
values_on is the cubical-only knob worth knowing about:
"vertices"(default): each vertex gets its data value; higher-dimensional cubes inherit the max (or min, withnegate=True) of their vertices. This is the lower/upper-star convention."top_cells": each top-dimensional cube gets its data value; lower cubes inherit the min (or max withnegate=True). Useful when the data lives on voxels rather than vertices, and matches the cubical convention in GUDHI.
Sublevel vs. superlevel sets¶
By default the filtration is built in increasing order of value (sublevel
sets). Pass negate=True to flip the sign and obtain superlevel persistence.
The resulting diagrams have the same persistence pairs, just reflected through
the diagonal.
Periodic boundaries¶
freudenthal_filtration(..., wrap=True) wraps the grid into a \(d\)-torus.
Lower-star persistence on a constant array then reports \(H_1\) of the torus,
\(H_2\) of the torus, etc. Currently the cubical builder does not support
wrap=True.
Point clouds¶
Vietoris-Rips¶
pts = np.load("points.npy") # shape (n, d)
fil = oin.vr_filtration(pts, max_dim=2, max_diameter=2.0, n_threads=4)
dcmp = oin.Decomposition(fil, dualize=True)
dcmp.reduce(oin.ReductionParams(n_threads=4))
dgms = dcmp.diagram(fil)
Notes:
max_dimcaps the simplex dimension. For \(H_k\) you need cells up through dimension \(k+1\).max_diametertruncates the filtration. With no truncation the VR complex on \(n\) points has \(\binom{n}{k+1}\) \(k\)-simplices, which is huge; tighteningmax_diameteris usually the difference between “runs in a second” and “exhausts memory”.from_pwdists=Truetakes an \((n, n)\) symmetric distance matrix instead of raw coordinates. Combine with a custom metric (geodesic, \(L^1\), …) to do VR on any metric space.The in-order enumeration is the VRE algorithm from Vejdemo-Johansson, Matuszewski & Bauer; see the docstring for the citation.
Alpha¶
dgms = oin.compute_diagrams_alpha(pts) # one-shot
# or, if you want to keep the filtration around for downstream work:
fil = oin.alpha_filtration(pts)
Alpha needs the optional diode dependency,
which provides the CGAL-backed Delaunay construction. The defaults are
suitable for most point clouds; the knobs you might want:
exact=True– use CGAL’s exact kernel for the Delaunay construction. Slow but immune to numerical pathologies.periodic=Trueplus a bounding box (bbox_min,bbox_max, orcompute_bounding_box=True) – periodic alpha shapes on a \(d\)-torus.weights– 1D array of vertex weights; produces weighted (regular) alpha shapes in 3D.
Custom simplicial filtrations¶
For one-off filtrations – toy examples, programmatically constructed
complexes, anything you cannot get out of a builder – pass a list of
(id, vertices, value) triples:
data = [
(0, [0], 0.2),
(1, [1], 0.1),
(2, [2], 0.3),
(3, [0, 1], 0.9),
(4, [0, 2], 0.5),
(5, [1, 2], 0.8),
(6, [0, 1, 2], 1.0),
]
fil = oin.list_to_filtration(data)
Or build the simplices explicitly with oineus.Simplex and pass
them to oineus.Filtration:
v0, v1, v2 = oin.Simplex([0], 0.2), oin.Simplex([1], 0.1), oin.Simplex([2], 0.3)
e1, e2, e3 = oin.Simplex([0, 1], 0.9), oin.Simplex([0, 2], 0.5), oin.Simplex([1, 2], 0.8)
t = oin.Simplex([0, 1, 2], 1.0)
fil = oin.Filtration([v0, v1, v2, e1, e2, e3, t], negate=False, n_threads=1)
The Filtration constructor sorts the simplices into a valid filtration
order and assigns each one a sorted_id. The id you supplied is kept as
simplex.id so you can recover the original ordering.
Vertices must be tagged with their vertex labels in sorted order
(Simplex([0, 1, 2], ...), not Simplex([2, 0, 1], ...)), and any face of a
simplex in the list must also be in the list (you cannot include the triangle
\(\{0, 1, 2\}\) without the three edges and three vertices).
See also¶
Inside the decomposition – once you have a
Filtration, what to do with it.Differentiable persistence diagrams – the same filtrations as differentiable layers over PyTorch tensors.
Performance –
max_dim,max_diameter, andn_threadsare where most of the runtime knobs live.