mod wire;
#[cfg(test)]
mod tests;
use crate::{
CohomologyLimits, Error, KineticEdge, KineticFiltration, KineticLimits, KineticZigzag, Result,
ZigzagLimits,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct KineticZigzagArtifactLimits {
pub max_bytes: usize,
pub kinetic: KineticLimits,
pub cohomology: CohomologyLimits,
pub zigzag: ZigzagLimits,
}
impl Default for KineticZigzagArtifactLimits {
fn default() -> Self {
Self {
max_bytes: 1 << 30,
kinetic: KineticLimits::default(),
cohomology: CohomologyLimits::default(),
zigzag: ZigzagLimits::default(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct KineticZigzagIntervalClaim {
pub start: usize,
pub end: usize,
pub multiplicity: usize,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct KineticZigzagArtifactSummary {
pub edges: usize,
pub nodes: usize,
pub arrows: usize,
pub intervals: usize,
pub interval_copies: usize,
}
#[derive(Debug, Clone, PartialEq)]
pub struct KineticZigzagArtifact {
vertex_count: usize,
edges: Vec<KineticEdge>,
start: f64,
end: f64,
dimension: usize,
scale: f64,
modulus: u32,
persistent_ties: usize,
node_ranks: Vec<usize>,
node_active_edges: Vec<usize>,
arrow_ranks: Vec<usize>,
generalized_ranks: Vec<usize>,
intervals: Vec<KineticZigzagIntervalClaim>,
digest: [u8; 32],
}
impl KineticZigzagArtifact {
pub fn build(
trajectory: &KineticFiltration,
dimension: usize,
scale: f64,
modulus: u32,
limits: KineticZigzagArtifactLimits,
) -> Result<(Self, KineticZigzag)> {
let zigzag = trajectory.cohomology_zigzag(
dimension,
scale,
modulus,
limits.cohomology,
limits.zigzag,
)?;
let mut artifact = Self::from_zigzag(trajectory, &zigzag);
artifact.digest = artifact.compute_digest()?;
Ok((artifact, zigzag))
}
fn from_zigzag(trajectory: &KineticFiltration, zigzag: &KineticZigzag) -> Self {
Self {
vertex_count: trajectory.vertex_count(),
edges: trajectory.edges().to_vec(),
start: trajectory.start(),
end: trajectory.end(),
dimension: zigzag.dimension,
scale: zigzag.scale,
modulus: zigzag.modulus,
persistent_ties: zigzag.persistent_ties,
node_ranks: zigzag.nodes.iter().map(|node| node.rank).collect(),
node_active_edges: zigzag.nodes.iter().map(|node| node.active_edges).collect(),
arrow_ranks: zigzag
.arrows
.iter()
.map(|arrow| arrow.restriction.rank)
.collect(),
generalized_ranks: zigzag.barcode.generalized_ranks.clone(),
intervals: zigzag
.barcode
.intervals
.iter()
.map(|interval| KineticZigzagIntervalClaim {
start: interval.start,
end: interval.end,
multiplicity: interval.multiplicity,
})
.collect(),
digest: [0; 32],
}
}
pub fn verify(&self, limits: KineticZigzagArtifactLimits) -> Result<()> {
let trajectory = KineticFiltration::new(
self.vertex_count,
self.edges.clone(),
self.start,
self.end,
limits.kinetic,
)?;
let (rebuilt, _) = Self::build(
&trajectory,
self.dimension,
self.scale,
self.modulus,
limits,
)?;
if rebuilt != *self {
return Err(Error::InvalidInput(
"kinetic zigzag differs from exact replay".into(),
));
}
Ok(())
}
pub fn vertex_count(&self) -> usize {
self.vertex_count
}
pub fn dimension(&self) -> usize {
self.dimension
}
pub fn scale(&self) -> f64 {
self.scale
}
pub fn modulus(&self) -> u32 {
self.modulus
}
pub fn intervals(&self) -> &[KineticZigzagIntervalClaim] {
&self.intervals
}
pub fn summary(&self) -> KineticZigzagArtifactSummary {
KineticZigzagArtifactSummary {
edges: self.edges.len(),
nodes: self.node_ranks.len(),
arrows: self.arrow_ranks.len(),
intervals: self.intervals.len(),
interval_copies: self.intervals.iter().map(|item| item.multiplicity).sum(),
}
}
}