Skip to main content

holos_tda/program/
model.rs

1use crate::{
2    AtlasArtifact, BasisClassId, CertificateLimits, ClassCorrespondence, Diagram, EdgeKey,
3    ExplainedDiagram, IntervalGroupId, ReductionGuardKind, Result, RipsParams,
4    SparseDistanceMatrix,
5};
6
7/// One atom in a compiled sparse persistence program.
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct ProgramAtomInfo {
10    /// Stable position in the program decomposition.
11    pub id: usize,
12    /// Original labeled vertices in ascending order.
13    pub vertices: Vec<usize>,
14    /// Original labeled edges in ascending endpoint order.
15    pub edges: Vec<EdgeKey>,
16    /// Vertices shared with another atom.
17    pub separator_vertices: Vec<usize>,
18    /// Whether the atom can contain positive-dimensional homology.
19    pub cyclic: bool,
20}
21
22/// Structural and algebraic size of a compiled program.
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub struct ProgramSummary {
25    /// Vertex-biconnected atoms, including bridge atoms.
26    pub atoms: usize,
27    /// Atoms that contain a graph cycle.
28    pub cyclic_atoms: usize,
29    /// Distinct articulation vertices.
30    pub articulation_vertices: usize,
31    /// Wider zero-filtration simplex separators used by the program.
32    pub zero_simplex_separators: usize,
33    /// Largest separator used by the program.
34    pub widest_separator: usize,
35    /// Candidate vertex sets checked during bounded separator search.
36    pub separator_candidates_checked: usize,
37    /// Whether bounded separator search visited every candidate in scope.
38    pub separator_search_complete: bool,
39    /// Edges in the largest cyclic atom.
40    pub largest_cyclic_atom_edges: usize,
41    /// Distinct reduction guards before transitive removal.
42    pub complete_guards: usize,
43    /// Result-sensitive guards across all cyclic atoms.
44    pub guards: usize,
45}
46
47/// Exact work charged to one program evaluation or update.
48#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
49pub struct ProgramWork {
50    /// Listed edges compared with the current program input.
51    pub edges_checked: usize,
52    /// Edges read by the H0 computation.
53    pub h0_edges_scanned: usize,
54    /// Result-sensitive algebraic guards checked.
55    pub guards_checked: usize,
56    /// Cyclic atoms containing a changed edge.
57    pub atoms_touched: usize,
58    /// Touched atoms reused without reduction.
59    pub atoms_reused: usize,
60    /// Touched atoms repaired by reducing a suffix.
61    pub atoms_repaired: usize,
62    /// Touched atoms whose explained state was rebuilt without suffix repair.
63    pub atoms_rebuilt: usize,
64    /// Boundary columns retained during reduction repair.
65    pub reduction_columns_reused: usize,
66    /// Boundary columns processed during reduction repair.
67    pub reduction_columns_reduced: usize,
68    /// Sparse column additions performed during reduction repair.
69    pub reduction_column_additions: usize,
70}
71
72/// Why a program update changed execution state.
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74#[non_exhaustive]
75pub enum ProgramEventKind {
76    /// The labeled vertex set changed.
77    VertexSetChanged,
78    /// The complete listed edge set changed.
79    EdgeSetChanged,
80    /// An edge crossed the fixed threshold.
81    ThresholdCrossing,
82    /// A result-sensitive algebraic guard failed.
83    GuardFailed,
84    /// A touched cyclic atom rebuilt its explained state.
85    AtomRebuilt,
86    /// A touched cyclic atom repaired a reduction suffix.
87    ReductionSuffixRepaired,
88    /// A wider separator stopped being a zero-filtration simplex.
89    SeparatorContractChanged,
90}
91
92/// One event reported by a program update.
93#[derive(Debug, Clone, PartialEq, Eq)]
94pub struct ProgramEvent {
95    /// Kind of change.
96    pub kind: ProgramEventKind,
97    /// Affected atom, when one exists.
98    pub atom: Option<usize>,
99    /// Affected edge, when one exists.
100    pub edge: Option<EdgeKey>,
101    /// Failed guard kind, when one exists.
102    pub guard: Option<ReductionGuardKind>,
103}
104
105/// How a program produced an updated result.
106#[derive(Debug, Clone, Copy, PartialEq, Eq)]
107pub enum ProgramUpdateMode {
108    /// All touched atoms retained their checked reductions.
109    Reused,
110    /// At least one touched atom was repaired or rebuilt locally.
111    Repaired,
112    /// The graph topology or threshold membership changed.
113    Recompiled,
114}
115
116/// Control over exact relations to the preceding class spaces.
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
118#[non_exhaustive]
119pub enum CorrespondenceMode {
120    /// Return exact relations on every common filtered subcomplex.
121    #[default]
122    Exact,
123    /// Keep the exact current state. Leave correspondence empty.
124    Omit,
125}
126
127/// Algebraic relation between class spaces across one update.
128#[derive(Debug, Clone, Copy, PartialEq, Eq)]
129#[non_exhaustive]
130pub enum ContinuationKind {
131    /// One old space maps bijectively to one new space.
132    Isomorphism,
133    /// One old space contributes to several new spaces.
134    Split,
135    /// Several old spaces contribute to one new space.
136    Merge,
137    /// Several old and new spaces share exact basis vectors.
138    Mixing,
139    /// A new space has no exact old basis vector.
140    Birth,
141    /// An old space has no exact new basis vector.
142    Death,
143    /// A proper subset of the vectors has an exact declared continuation.
144    Ambiguous,
145}
146
147/// One exact equality between an old and new canonical basis vector.
148#[derive(Debug, Clone, Copy, PartialEq, Eq)]
149pub struct BasisTransport {
150    /// Old basis identifier.
151    pub old: BasisClassId,
152    /// New basis identifier.
153    pub new: BasisClassId,
154    /// Nonzero coefficient in the shared prime field.
155    pub coefficient: u32,
156}
157
158/// One path-relative class-space continuation record.
159#[derive(Debug, Clone, PartialEq, Eq)]
160pub struct ClassContinuation {
161    /// Algebraic shape of the relation.
162    pub kind: ContinuationKind,
163    /// Old class spaces in the connected relation component.
164    pub old_spaces: Vec<IntervalGroupId>,
165    /// New class spaces in the connected relation component.
166    pub new_spaces: Vec<IntervalGroupId>,
167    /// Exact shared canonical basis vectors.
168    pub transport: Vec<BasisTransport>,
169}
170
171/// Diagram-only evaluation from unchanged program certificates.
172#[derive(Debug, Clone)]
173pub struct ProgramEvaluation {
174    /// Exact H0 and H1 diagram.
175    pub diagram: Diagram,
176    /// Work charged to the evaluation.
177    pub work: ProgramWork,
178}
179
180/// How a diagram-only state produced an updated diagram.
181#[derive(Debug, Clone, Copy, PartialEq, Eq)]
182pub enum ProgramDiagramUpdateMode {
183    /// Existing checked regions produced the updated diagram.
184    Reused,
185    /// A complete compositional program was compiled as the exact fallback.
186    Recompiled,
187}
188
189/// Result of advancing a diagram-only program state.
190#[derive(Debug, Clone)]
191pub struct ProgramDiagramUpdate {
192    /// Exact H0 and H1 diagram at the new input.
193    pub diagram: Diagram,
194    /// How the diagram was produced.
195    pub mode: ProgramDiagramUpdateMode,
196    /// Topology or region events encountered during the update.
197    pub events: Vec<ProgramEvent>,
198    /// Exact work charged to the update.
199    pub work: ProgramWork,
200}
201
202/// Result of advancing a persistence program.
203#[derive(Debug, Clone)]
204pub struct ProgramUpdate {
205    /// Exact diagram and canonical H1 class spaces at the new input.
206    pub result: ExplainedDiagram,
207    /// How the program produced this result.
208    pub mode: ProgramUpdateMode,
209    /// Events encountered during the update.
210    pub events: Vec<ProgramEvent>,
211    /// Algebraic class-space continuation records.
212    pub continuation: Vec<ClassContinuation>,
213    /// Exact linear relations on common filtered subcomplexes.
214    pub correspondence: Vec<ClassCorrespondence>,
215    /// Exact work charged to the update.
216    pub work: ProgramWork,
217}
218
219/// Immutable state from which a program can be restored or branched.
220#[derive(Debug, Clone)]
221pub struct ProgramCheckpoint {
222    pub(super) program: PersistenceProgram,
223}
224
225impl ProgramCheckpoint {
226    /// Program state stored by this checkpoint.
227    pub fn program(&self) -> &PersistenceProgram {
228        &self.program
229    }
230
231    /// Advance independent alternatives from this checkpoint.
232    pub fn branch(&self, alternatives: &[SparseDistanceMatrix]) -> Result<Vec<ProgramBranch>> {
233        self.program.branch(alternatives)
234    }
235
236    /// Advance alternatives with explicit correspondence control.
237    pub fn branch_with(
238        &self,
239        alternatives: &[SparseDistanceMatrix],
240        correspondence_mode: CorrespondenceMode,
241    ) -> Result<Vec<ProgramBranch>> {
242        self.program.branch_with(alternatives, correspondence_mode)
243    }
244}
245
246/// One independently advanced program branch.
247#[derive(Debug, Clone)]
248pub struct ProgramBranch {
249    /// Position of the alternative in the input batch.
250    pub index: usize,
251    /// Exact update from the shared branch point.
252    pub update: ProgramUpdate,
253    pub(super) program: PersistenceProgram,
254}
255
256/// Stateful diagram evaluation with lazy materialization of class spaces.
257#[derive(Debug, Clone)]
258pub struct ProgramDiagramState {
259    pub(super) program: PersistenceProgram,
260    pub(super) graph: SparseDistanceMatrix,
261    pub(super) diagram: Diagram,
262    pub(super) dirty: bool,
263}
264
265impl ProgramBranch {
266    /// Program at the end of this branch.
267    pub fn program(&self) -> &PersistenceProgram {
268        &self.program
269    }
270
271    /// Consume this branch and return its program.
272    pub fn into_program(self) -> PersistenceProgram {
273        self.program
274    }
275
276    /// Consume this branch and return its update and program.
277    pub fn into_parts(self) -> (ProgramUpdate, PersistenceProgram) {
278        (self.update, self.program)
279    }
280}
281
282#[derive(Debug, Clone)]
283pub(crate) struct ProgramAtomState {
284    pub(crate) info_index: usize,
285    pub(crate) vertices: Vec<usize>,
286    pub(crate) edges: Vec<EdgeKey>,
287    pub(crate) edge_positions: Vec<usize>,
288    pub(crate) artifact: AtlasArtifact,
289    pub(crate) certified_graph: SparseDistanceMatrix,
290    pub(crate) region: crate::CertifiedReductionRegion,
291    pub(crate) explained: ExplainedDiagram,
292}
293
294/// Exact H0 and H1 program compiled over sparse graph atoms.
295#[derive(Debug, Clone)]
296pub struct PersistenceProgram {
297    pub(super) params: RipsParams,
298    pub(super) limits: CertificateLimits,
299    pub(super) graph: SparseDistanceMatrix,
300    pub(super) topology: Vec<EdgeKey>,
301    pub(super) active: Vec<bool>,
302    pub(super) separator_edges: Vec<EdgeKey>,
303    pub(super) h0_deaths: Vec<EdgeKey>,
304    pub(super) h0_essential: usize,
305    pub(super) atoms: Vec<ProgramAtomInfo>,
306    pub(super) states: Vec<ProgramAtomState>,
307    pub(super) summary: ProgramSummary,
308    pub(super) result: ExplainedDiagram,
309}