use std::fmt;
use crate::{Bar, CriticalPair, Diagram, Error};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CertificateError {
message: String,
}
impl CertificateError {
pub(crate) fn new(message: impl Into<String>) -> Self {
Self {
message: message.into(),
}
}
pub fn message(&self) -> &str {
&self.message
}
}
impl fmt::Display for CertificateError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "reduction certificate: {}", self.message)
}
}
impl std::error::Error for CertificateError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct CertificateLimits {
pub max_bytes: usize,
pub max_vertices: usize,
pub max_edges: usize,
pub max_triangles: usize,
pub max_higher_simplices: usize,
pub max_dimension: usize,
pub max_terms: usize,
pub max_bars: usize,
}
impl Default for CertificateLimits {
fn default() -> Self {
Self {
max_bytes: 1 << 30,
max_vertices: 1_000_000,
max_edges: 20_000_000,
max_triangles: 100_000_000,
max_higher_simplices: 100_000_000,
max_dimension: 8,
max_terms: 200_000_000,
max_bars: 100_000_000,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct CertificateTerm {
pub index: usize,
pub coefficient: u32,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ChangeColumn {
pub terms: Vec<CertificateTerm>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ReductionRepairMode {
Reused,
SuffixRepaired,
Rebuilt,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct ReductionRepairWork {
pub edge_columns_reused: usize,
pub edge_columns_reduced: usize,
pub triangle_columns_reused: usize,
pub triangle_columns_reduced: usize,
pub column_additions: usize,
}
impl ReductionRepairWork {
pub fn columns(&self) -> usize {
self.edge_columns_reused
+ self.edge_columns_reduced
+ self.triangle_columns_reused
+ self.triangle_columns_reduced
}
pub fn columns_reused(&self) -> usize {
self.edge_columns_reused + self.triangle_columns_reused
}
pub fn columns_reduced(&self) -> usize {
self.edge_columns_reduced + self.triangle_columns_reduced
}
}
#[derive(Debug, Clone)]
pub struct ReductionRepair {
pub(super) certificate: ReductionCertificate,
pub(super) mode: ReductionRepairMode,
pub(super) work: ReductionRepairWork,
}
impl ReductionRepair {
pub fn certificate(&self) -> &ReductionCertificate {
&self.certificate
}
pub fn mode(&self) -> ReductionRepairMode {
self.mode
}
pub fn work(&self) -> ReductionRepairWork {
self.work
}
pub(crate) fn into_certificate(self) -> ReductionCertificate {
self.certificate
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct FiltrationSimplex {
pub(super) vertices: Vec<usize>,
}
impl FiltrationSimplex {
pub(super) fn new(vertices: impl Into<Vec<usize>>) -> Self {
Self {
vertices: vertices.into(),
}
}
pub fn dimension(&self) -> usize {
self.vertices.len().saturating_sub(1)
}
pub fn vertices(&self) -> &[usize] {
&self.vertices
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[non_exhaustive]
pub enum ReductionGuardKind {
ChangeOfBasis,
Pivot,
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ReductionGuard {
pub(super) kind: ReductionGuardKind,
pub(super) earlier: FiltrationSimplex,
pub(super) later: FiltrationSimplex,
}
impl ReductionGuard {
pub fn kind(&self) -> ReductionGuardKind {
self.kind
}
pub fn earlier(&self) -> &FiltrationSimplex {
&self.earlier
}
pub fn later(&self) -> &FiltrationSimplex {
&self.later
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum RegionViolationKind {
VertexSetChanged,
EdgeSetChanged,
ThresholdCrossing,
GuardFailed,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RegionViolation {
pub(super) kind: RegionViolationKind,
pub(super) guard_index: Option<usize>,
pub(super) first: Option<FiltrationSimplex>,
pub(super) second: Option<FiltrationSimplex>,
}
impl RegionViolation {
pub fn kind(&self) -> RegionViolationKind {
self.kind
}
pub fn guard_index(&self) -> Option<usize> {
self.guard_index
}
pub fn first(&self) -> Option<&FiltrationSimplex> {
self.first.as_ref()
}
pub fn second(&self) -> Option<&FiltrationSimplex> {
self.second.as_ref()
}
}
#[derive(Debug, Clone)]
pub struct CertifiedRegionEvaluation {
pub(super) diagram: Diagram,
pub(super) h1_pairs: Vec<(Bar, CriticalPair)>,
pub(super) guards_checked: usize,
}
impl CertifiedRegionEvaluation {
pub fn diagram(&self) -> &Diagram {
&self.diagram
}
pub fn h1_critical_pairs(&self) -> &[(Bar, CriticalPair)] {
&self.h1_pairs
}
pub fn guards_checked(&self) -> usize {
self.guards_checked
}
}
#[derive(Debug, Clone)]
pub(super) struct RegionH1Pair {
pub(super) birth: [usize; 2],
pub(super) death: Option<[usize; 3]>,
}
#[derive(Debug, Clone, Copy)]
pub(super) enum RegionValueFormula {
Vertex,
Edge(usize),
Triangle([usize; 3]),
}
impl RegionValueFormula {
pub(super) fn value(self, edge_value: impl Fn(usize) -> f64) -> f64 {
match self {
Self::Vertex => 0.0,
Self::Edge(edge) => edge_value(edge),
Self::Triangle([first, second, third]) => edge_value(first)
.max(edge_value(second))
.max(edge_value(third)),
}
}
}
#[derive(Debug, Clone)]
pub struct CertifiedReductionRegion {
pub(super) vertex_count: usize,
pub(super) threshold: Option<f64>,
pub(super) topology: Vec<[usize; 2]>,
pub(super) active: Vec<bool>,
pub(super) complete_guards: Vec<ReductionGuard>,
pub(super) guards: Vec<ReductionGuard>,
pub(super) guard_indices: Vec<(usize, usize)>,
pub(super) guard_ranks: Vec<u128>,
pub(super) guard_formulas: Vec<RegionValueFormula>,
pub(super) h0_deaths: Vec<[usize; 2]>,
pub(super) h0_essential: usize,
pub(super) h1_pairs: Vec<RegionH1Pair>,
pub(super) h1_formulas: Vec<(usize, Option<[usize; 3]>)>,
}
#[derive(Debug, Clone)]
pub struct ReductionCertificate {
pub(super) vertex_count: usize,
pub(super) threshold: Option<f64>,
pub(super) modulus: u32,
pub(super) graph_digest: [u8; 32],
pub(super) edge_columns: Vec<ChangeColumn>,
pub(super) triangle_columns: Vec<ChangeColumn>,
pub(super) diagram: Diagram,
}
pub(super) type CertificateResult<T> = std::result::Result<T, CertificateError>;
impl From<CertificateError> for Error {
fn from(error: CertificateError) -> Self {
Self::InvalidInput(error.to_string())
}
}