sheaf_coherence/
section.rs1use crate::error::SheafError;
2use crate::laplacian::SheafLaplacian;
3use crate::sheaf::CellularSheaf;
4
5#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
11pub struct GlobalSection {
12 pub values: Vec<Vec<f64>>,
14 pub is_exact: bool,
16 pub residual: f64,
18}
19
20impl GlobalSection {
21 pub fn new(sheaf: &CellularSheaf, values: Vec<Vec<f64>>, tol: f64) -> Result<Self, SheafError> {
23 sheaf.validate()?;
24 if values.len() != sheaf.node_count() {
25 return Err(SheafError::InvalidNode(values.len()));
26 }
27 for (i, v) in values.iter().enumerate() {
28 if v.len() != sheaf.stalk_dims[i] {
29 return Err(SheafError::BeliefDimensionMismatch {
30 agent: format!("node_{i}"),
31 expected: sheaf.stalk_dims[i],
32 got: v.len(),
33 });
34 }
35 }
36
37 let lap = SheafLaplacian::from_sheaf(sheaf)?;
38 let flat = values.iter().flatten().copied().collect::<Vec<_>>();
39 let residual = lap.residual_norm(&flat);
40 let is_exact = residual < tol;
41
42 Ok(Self {
43 values,
44 is_exact,
45 residual,
46 })
47 }
48
49 pub fn find(sheaf: &CellularSheaf, max_iter: usize, tol: f64) -> Result<Self, SheafError> {
52 sheaf.validate()?;
53 let lap = SheafLaplacian::from_sheaf(sheaf)?;
54
55 let (eigenvalue, flat) = lap.smallest_eigenvalue(max_iter, tol);
56
57 let mut values = Vec::new();
59 let mut offset = 0;
60 for &d in &sheaf.stalk_dims {
61 values.push(flat[offset..offset + d].to_vec());
62 offset += d;
63 }
64
65 let residual = lap.residual_norm(&flat);
66 let is_exact = eigenvalue.abs() < tol;
67
68 Ok(Self {
69 values,
70 is_exact,
71 residual,
72 })
73 }
74
75 pub fn flatten(&self) -> Vec<f64> {
77 self.values.iter().flatten().copied().collect()
78 }
79}