use super::digest::diagrams_equal;
use super::digest::graph_digest;
use super::model::{
CheckedGraded, GradedComplex, GradedReductionCertificate, GradedReductionRepair,
GradedReductionRepairWork,
};
use super::reduction::{check_all, reduce_all_dimensions};
use super::repair::{graded_repair_mode, repair_all_dimensions, require_fixed_envelope};
use super::validation::{check_compute_diagram, checked_threshold, validate};
use crate::certificate::{CertificateError, CertificateLimits, ChangeColumn};
use crate::{Diagram, RipsParams, SparseDistanceMatrix};
impl GradedReductionCertificate {
pub fn build(
input: &SparseDistanceMatrix,
params: &RipsParams,
limits: CertificateLimits,
) -> Result<Self, CertificateError> {
validate(input, params, limits)?;
let threshold = checked_threshold(params.threshold)?;
let complex = GradedComplex::build(input, params.max_dim, threshold, limits)?;
let columns = reduce_all_dimensions(&complex, params.max_dim, params.modulus, limits)?;
let checked = check_all(&complex, params.modulus, &columns, limits)?;
check_compute_diagram(input, params, &checked.diagram)?;
Ok(Self {
vertex_count: input.len(),
max_dim: params.max_dim,
threshold: params.threshold,
modulus: params.modulus,
graph_digest: graph_digest(input, threshold),
columns,
diagram: checked.diagram,
})
}
pub fn repair(
&self,
current: &SparseDistanceMatrix,
updated: &SparseDistanceMatrix,
limits: CertificateLimits,
) -> Result<GradedReductionRepair, CertificateError> {
let old_complex = self.verify_parts(current, limits)?.0;
require_fixed_envelope(current, updated, self.threshold)?;
let threshold = checked_threshold(self.threshold)?;
let new_complex = GradedComplex::build(updated, self.max_dim, threshold, limits)?;
let (columns, work) = repair_all_dimensions(
&old_complex,
&new_complex,
&self.columns,
self.modulus,
limits,
)?;
let checked = check_all(&new_complex, self.modulus, &columns, limits)?;
let work = GradedReductionRepairWork { dimensions: work };
Ok(GradedReductionRepair {
certificate: Self {
vertex_count: updated.len(),
max_dim: self.max_dim,
threshold: self.threshold,
modulus: self.modulus,
graph_digest: graph_digest(updated, threshold),
columns,
diagram: checked.diagram,
},
mode: graded_repair_mode(&work),
work,
})
}
pub fn verify(
&self,
input: &SparseDistanceMatrix,
limits: CertificateLimits,
) -> Result<Diagram, CertificateError> {
Ok(self.verify_parts(input, limits)?.1.diagram)
}
pub fn max_dim(&self) -> usize {
self.max_dim
}
pub fn modulus(&self) -> u32 {
self.modulus
}
pub fn threshold(&self) -> Option<f64> {
self.threshold
}
pub fn graph_digest(&self) -> &[u8; 32] {
&self.graph_digest
}
pub fn columns(&self, simplex_dimension: usize) -> Option<&[ChangeColumn]> {
simplex_dimension
.checked_sub(1)
.and_then(|index| self.columns.get(index))
.map(Vec::as_slice)
}
pub fn graded_columns(&self) -> &[Vec<ChangeColumn>] {
&self.columns
}
pub fn column_count(&self) -> usize {
self.columns.iter().map(Vec::len).sum()
}
pub fn diagram(&self) -> &Diagram {
&self.diagram
}
fn verify_parts(
&self,
input: &SparseDistanceMatrix,
limits: CertificateLimits,
) -> Result<(GradedComplex, CheckedGraded), CertificateError> {
let params = RipsParams::new(self.max_dim).with_modulus(self.modulus);
validate(input, ¶ms, limits)?;
if input.len() != self.vertex_count {
return Err(CertificateError::new(format!(
"input has {} vertices, graded certificate records {}",
input.len(),
self.vertex_count
)));
}
if self.columns.len() != self.max_dim + 1 {
return Err(CertificateError::new(
"graded certificate has the wrong boundary-dimension count",
));
}
let threshold = checked_threshold(self.threshold)?;
if graph_digest(input, threshold) != self.graph_digest {
return Err(CertificateError::new(
"graded certificate graph binding does not match",
));
}
let complex = GradedComplex::build(input, self.max_dim, threshold, limits)?;
let checked = check_all(&complex, self.modulus, &self.columns, limits)?;
if !diagrams_equal(&checked.diagram, &self.diagram) {
return Err(CertificateError::new(
"graded certificate diagram differs from the checked reductions",
));
}
Ok((complex, checked))
}
}