persistence_agent/
boundary.rs1use crate::error::PersistenceError;
2use crate::vietoris_rips::VietorisRipsComplex;
3
4#[derive(Debug, Clone)]
6pub struct BoundaryMatrix {
7 pub matrix: Vec<Vec<u8>>,
8 pub n_simplices: usize,
9}
10
11impl BoundaryMatrix {
12 pub fn build(vr: &VietorisRipsComplex) -> Result<Self, PersistenceError> {
21 let n = vr.n_simplices();
22 if n == 0 {
23 return Err(PersistenceError::EmptyFiltration);
24 }
25
26 let mut simplex_index = std::collections::HashMap::new();
28 for (i, s) in vr.simplices.iter().enumerate() {
29 simplex_index.insert(s.clone(), i);
30 }
31
32 let mut matrix = vec![vec![0u8; n]; n];
33
34 for (col_idx, simplex) in vr.simplices.iter().enumerate() {
35 if simplex.len() <= 1 {
36 continue;
38 }
39 for skip in 0..simplex.len() {
41 let face: Vec<usize> = simplex
42 .iter()
43 .enumerate()
44 .filter(|(i, _)| *i != skip)
45 .map(|(_, &v)| v)
46 .collect();
47 if let Some(&row_idx) = simplex_index.get(&face) {
48 matrix[col_idx][row_idx] ^= 1;
49 }
50 }
51 }
52
53 Ok(Self {
54 matrix,
55 n_simplices: n,
56 })
57 }
58
59 pub fn reduce(&mut self) -> std::collections::HashMap<usize, usize> {
63 let n = self.n_simplices;
64 let mut low_to_col: std::collections::HashMap<usize, usize> =
65 std::collections::HashMap::new();
66
67 for j in 0..n {
68 while let Some(lj) = self.low(j) {
69 if let Some(&k) = low_to_col.get(&lj) {
70 self.add_columns(k, j);
71 } else {
72 low_to_col.insert(lj, j);
73 break;
74 }
75 }
76 }
77
78 low_to_col
79 }
80
81 pub fn low(&self, j: usize) -> Option<usize> {
83 self.matrix[j]
84 .iter()
85 .enumerate()
86 .rev()
87 .find(|(_, &v)| v == 1)
88 .map(|(i, _)| i)
89 }
90
91 fn add_columns(&mut self, src: usize, dst: usize) {
93 for i in 0..self.n_simplices {
94 self.matrix[dst][i] ^= self.matrix[src][i];
95 }
96 }
97}