holos-tda 0.9.0

Vietoris-Rips persistence and checked degree-Rips modules
Documentation
use crate::Diagram;
use crate::certificate::{CertificateError, CertificateLimits};
use crate::filtration::{FilteredSimplicialComplex, ScalarGrade};

pub(super) fn validate_parameters(
    complex: &FilteredSimplicialComplex<ScalarGrade>,
    max_homology_dimension: usize,
    modulus: u32,
    limits: CertificateLimits,
) -> Result<(), CertificateError> {
    if max_homology_dimension > limits.max_dimension
        || complex.max_dimension() < max_homology_dimension + 1
    {
        return Err(certificate_error(
            "explicit complex does not cover the requested homology dimensions",
        ));
    }
    if !supported_prime(modulus) {
        return Err(certificate_error(
            "explicit certificate modulus must be a prime below 32768",
        ));
    }
    validate_complex_counts(complex, max_homology_dimension, limits)
}

fn validate_complex_counts(
    complex: &FilteredSimplicialComplex<ScalarGrade>,
    max_homology_dimension: usize,
    limits: CertificateLimits,
) -> Result<(), CertificateError> {
    for dimension in 0..=max_homology_dimension + 1 {
        let count = complex.simplices()[dimension].len();
        let maximum = simplex_limit(dimension, limits);
        if count > maximum {
            return Err(certificate_error(format!(
                "explicit simplex count in dimension {dimension} exceeds its limit"
            )));
        }
    }
    Ok(())
}

pub(super) fn truncate_complex(
    complex: &FilteredSimplicialComplex<ScalarGrade>,
    max_homology_dimension: usize,
) -> Result<FilteredSimplicialComplex<ScalarGrade>, CertificateError> {
    FilteredSimplicialComplex::new(
        complex.vertex_labels().to_vec(),
        complex.simplices()[..=max_homology_dimension + 1].to_vec(),
    )
    .map_err(|error| certificate_error(error.to_string()))
}

fn supported_prime(value: u32) -> bool {
    if !(2..32_768).contains(&value) {
        return false;
    }
    let mut divisor = 2u32;
    while divisor * divisor <= value {
        if value % divisor == 0 {
            return false;
        }
        divisor += 1;
    }
    true
}

pub(super) fn simplex_limit(dimension: usize, limits: CertificateLimits) -> usize {
    match dimension {
        0 => limits.max_vertices,
        1 => limits.max_edges,
        2 => limits.max_triangles,
        _ => limits.max_higher_simplices,
    }
}

pub(super) fn diagrams_equal(left: &Diagram, right: &Diagram) -> bool {
    left.bars.len() == right.bars.len()
        && left.bars.iter().zip(&right.bars).all(|(left, right)| {
            left.dim == right.dim
                && left.birth.to_bits() == right.birth.to_bits()
                && left.death.to_bits() == right.death.to_bits()
        })
}

pub(super) fn certificate_error(message: impl Into<String>) -> CertificateError {
    CertificateError::new(message)
}