holos-tda 0.9.0

Vietoris-Rips persistence and checked degree-Rips modules
Documentation
use super::*;
use crate::{
    FilteredSimplex, FlagComplexParams, RipsParams, SparseDistanceMatrix, rips_persistence_sparse,
};

fn cycle_complex() -> FilteredSimplicialComplex<ScalarGrade> {
    let zero = ScalarGrade::new(0.0).unwrap();
    let one = ScalarGrade::new(1.0).unwrap();
    FilteredSimplicialComplex::new(
        vec![0, 1, 2, 3],
        vec![
            (0..4)
                .map(|vertex| FilteredSimplex::new(vec![vertex], zero))
                .collect(),
            vec![
                FilteredSimplex::new(vec![0, 1], one),
                FilteredSimplex::new(vec![0, 3], one),
                FilteredSimplex::new(vec![1, 2], one),
                FilteredSimplex::new(vec![2, 3], one),
            ],
            Vec::new(),
        ],
    )
    .unwrap()
}

#[test]
fn explicit_cycle_has_one_essential_h1_class() {
    let certificate =
        ExplicitReductionCertificate::build(&cycle_complex(), 1, 3, CertificateLimits::default())
            .unwrap();
    assert_eq!(certificate.diagram().in_dim(1).count(), 1);
    assert!(
        certificate
            .diagram()
            .in_dim(1)
            .next()
            .unwrap()
            .is_essential()
    );
    certificate.verify(CertificateLimits::default()).unwrap();
}

#[test]
fn explicit_flag_certificate_matches_the_implicit_engine() {
    let graph = SparseDistanceMatrix::from_triplets(
        4,
        &[
            (0, 1, 1.0),
            (1, 2, 1.0),
            (2, 3, 1.0),
            (0, 3, 1.0),
            (0, 2, 2.0),
            (1, 3, 2.0),
        ],
    )
    .unwrap();
    let complex = FilteredSimplicialComplex::from_flag_graph(
        &graph,
        &[0, 1, 2, 3],
        FlagComplexParams {
            max_dimension: 2,
            threshold: None,
            limits: crate::ComplexLimits::default(),
        },
    )
    .unwrap();
    let explicit =
        ExplicitReductionCertificate::build(&complex, 1, 5, CertificateLimits::default()).unwrap();
    let implicit = rips_persistence_sparse(&graph, &RipsParams::new(1).with_modulus(5)).unwrap();
    assert!(diagrams_equal(explicit.diagram(), &implicit));
}

#[test]
fn explicit_artifact_round_trips_and_rejects_mutation() {
    let certificate =
        ExplicitReductionCertificate::build(&cycle_complex(), 1, 2, CertificateLimits::default())
            .unwrap();
    let mut bytes = certificate.encode(CertificateLimits::default()).unwrap();
    let decoded =
        ExplicitReductionCertificate::decode(&bytes, CertificateLimits::default()).unwrap();
    assert!(diagrams_equal(certificate.diagram(), decoded.diagram()));
    let checked = holos_tda_check::verify_explicit_persistence(
        &bytes,
        holos_tda_check::ProofLimits::default(),
    )
    .unwrap();
    assert_eq!(checked.max_homology_dimension, 1);
    assert_eq!(checked.modulus, 2);
    assert_eq!(checked.bars.len(), certificate.diagram().bars.len());
    bytes[20] ^= 1;
    assert!(ExplicitReductionCertificate::decode(&bytes, CertificateLimits::default()).is_err());
}