Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

2. A filtration and a basis

For persistent homology the rows need filtration values. Implement HasRowFiltration on the oracle:

/// Step 2: the filtration on rows (cells), read off the volume. Implementing it on the oracle, rather than attaching
/// a closure with `with_filtration`, leaves room to override the optional hooks later.
impl HasRowFiltration for Boundary<'_> {
    type FiltrationT = NotNan<f32>;

    fn filtration_value(&self, row: Cell) -> NotNan<f32> {
        NotNan::new(self.0.value(row.0)).unwrap()
    }
}

The filtration type must be Ord; NotNan from ordered-float is the usual choice. (For a quick experiment you can attach a closure instead, with Boundary(&volume).with_filtration(|cell| ...), but implementing the trait on your own type leaves room for the optional hooks in step 5.)

Rows are now ordered by (value, label), so the basis must be too:

/// As `basis_by_number`, but in filtration order: by value, then number.
fn basis(volume: &Volume, max_dim: usize) -> SplitBasis<Cell> {
    let mut dims: Vec<Vec<Cell>> = vec![vec![]; max_dim + 1];
    for cell in 0..volume.n_cells() {
        let dim = volume.dimension(cell);
        if dim <= max_dim {
            dims[dim].push(Cell(cell));
        }
    }
    for cells in &mut dims {
        cells.sort_by_key(|&cell| (NotNan::new(volume.value(cell.0)).unwrap(), cell));
    }
    SplitBasis::from_dimensions(dims)
}
    // Step 2: the lower-star filtration, by homology, with the standard algorithm.
    // Every cell, cubes included, is a column.
    let d = Boundary(&volume).with_basis(basis(&volume, 3));
    let standard = timed("homology, standard algorithm", || {
        barcode::homology(&d, Algorithm::Standard(Standard::new()), false)
    });
    println!("    {}", summary(&volume, &standard));

The result is a list of Bars: birth cell and value, death cell and value (None if essential), and optionally a representative.

You can now compute persistent homology. But the standard algorithm reduces every column, cubes included, and builds every column in full. On a 40³ volume (493,039 cells) that takes 5.4 s.