holos-tda 0.9.0

Vietoris-Rips persistence and checked degree-Rips modules
Documentation
use std::collections::BTreeMap;

use crate::certificate::CertificateError;

use super::model::{InterfaceCell, RelativeInterfaceCertificate};
use super::validation::cell_order;

pub(super) fn check_composition_children<'a>(
    children: &[&'a RelativeInterfaceCertificate],
) -> Result<&'a RelativeInterfaceCertificate, CertificateError> {
    let first = children
        .first()
        .copied()
        .ok_or_else(|| CertificateError::new("relative composition requires a child"))?;
    for child in children {
        if child.max_dim != first.max_dim || child.modulus != first.modulus {
            return Err(CertificateError::new(
                "relative composition requires one dimension and coefficient field",
            ));
        }
    }
    Ok(first)
}

pub(super) fn merge_child_cells(
    children: &[&RelativeInterfaceCertificate],
    max_dim: usize,
) -> Result<Vec<Vec<InterfaceCell>>, CertificateError> {
    let mut dimensions = vec![DimensionMap::new(); max_dim + 2];
    for child in children {
        merge_one_child(&mut dimensions, &child.core_cells)?;
    }
    Ok(maps_to_cells(dimensions))
}

fn merge_one_child(
    dimensions: &mut [DimensionMap],
    child: &[Vec<InterfaceCell>],
) -> Result<(), CertificateError> {
    for (dimension, cells) in child.iter().enumerate() {
        for cell in cells {
            merge_interface_cell(&mut dimensions[dimension], cell)?;
        }
    }
    Ok(())
}

fn merge_interface_cell(
    cells: &mut DimensionMap,
    cell: &InterfaceCell,
) -> Result<(), CertificateError> {
    if let Some(existing) = cells.get(&cell.vertices) {
        if existing != cell {
            return Err(CertificateError::new(
                "identified interface cells have different filtered boundaries",
            ));
        }
        return Ok(());
    }
    cells.insert(cell.vertices.clone(), cell.clone());
    Ok(())
}

pub(super) type DimensionMap = BTreeMap<Vec<usize>, InterfaceCell>;

pub(super) fn cells_to_maps(
    cells: Vec<Vec<InterfaceCell>>,
) -> Result<Vec<DimensionMap>, CertificateError> {
    cells
        .into_iter()
        .map(|dimension| {
            let expected = dimension.len();
            let map: DimensionMap = dimension
                .into_iter()
                .map(|cell| (cell.vertices.clone(), cell))
                .collect();
            if map.len() != expected {
                Err(CertificateError::new("relative interface repeats a cell"))
            } else {
                Ok(map)
            }
        })
        .collect()
}

pub(super) fn maps_to_cells(maps: Vec<DimensionMap>) -> Vec<Vec<InterfaceCell>> {
    maps.into_iter()
        .map(|dimension| {
            let mut cells: Vec<_> = dimension.into_values().collect();
            cells.sort_by(cell_order);
            cells
        })
        .collect()
}