use serde::{Deserialize, Serialize};
use crate::cover::OpenCover;
use crate::section::SectionFamily;
use crate::cochain::compute_cohomology;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PersistencePoint {
pub birth: f64,
pub death: f64,
pub degree: usize,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct PersistenceDiagram {
pub points: Vec<PersistencePoint>,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub struct CohomologySnapshot {
pub resolution: f64,
pub h0_dimension: usize,
pub h1_dimension: usize,
}
pub fn persistent_cohomology(
stages: &[(f64, OpenCover, SectionFamily)],
tol: f64,
) -> (Vec<CohomologySnapshot>, PersistenceDiagram) {
let mut snapshots = Vec::new();
let mut prev_h0 = None;
let mut prev_h1 = None;
let mut h0_births: Vec<f64> = Vec::new();
let mut h1_births: Vec<f64> = Vec::new();
let mut points = Vec::new();
for (resolution, cover, _sections) in stages {
let (h0, h1) = compute_cohomology(cover, tol);
snapshots.push(CohomologySnapshot {
resolution: *resolution,
h0_dimension: h0.dimension,
h1_dimension: h1.dimension,
});
if let Some(prev) = prev_h0 {
if h0.dimension > prev {
let n_new = h0.dimension - prev;
for _ in 0..n_new {
h0_births.push(*resolution);
}
} else if h0.dimension < prev {
let n_died = prev - h0.dimension;
for _ in 0..n_died {
if let Some(birth) = h0_births.pop() {
points.push(PersistencePoint {
birth,
death: *resolution,
degree: 0,
});
}
}
}
} else {
for _ in 0..h0.dimension {
h0_births.push(*resolution);
}
}
if let Some(prev) = prev_h1 {
if h1.dimension > prev {
let n_new = h1.dimension - prev;
for _ in 0..n_new {
h1_births.push(*resolution);
}
} else if h1.dimension < prev {
let n_died = prev - h1.dimension;
for _ in 0..n_died {
if let Some(birth) = h1_births.pop() {
points.push(PersistencePoint {
birth,
death: *resolution,
degree: 1,
});
}
}
}
} else {
for _ in 0..h1.dimension {
h1_births.push(*resolution);
}
}
prev_h0 = Some(h0.dimension);
prev_h1 = Some(h1.dimension);
}
if let Some(&last_res) = stages.last().map(|(r, _, _)| r) {
for birth in h0_births {
points.push(PersistencePoint {
birth,
death: f64::INFINITY,
degree: 0,
});
}
for birth in h1_births {
points.push(PersistencePoint {
birth,
death: f64::INFINITY,
degree: 1,
});
}
}
(snapshots, PersistenceDiagram { points })
}
pub fn refine_cover(cover: &OpenCover, resolution: usize) -> OpenCover {
if resolution <= 1 {
return cover.clone();
}
let mut new_sets = Vec::new();
for set in &cover.sets {
if set.len() <= resolution {
new_sets.push(set.clone());
} else {
let chunk_size = (set.len() + resolution - 1) / resolution;
for chunk in set.chunks(chunk_size) {
new_sets.push(chunk.to_vec());
}
}
}
OpenCover::new(new_sets)
}
pub fn refinement_sequence(cover: &OpenCover, max_resolution: usize) -> Vec<OpenCover> {
(1..=max_resolution)
.map(|r| refine_cover(cover, r))
.collect()
}