use crate::error::SheafError;
use crate::laplacian::SheafLaplacian;
use crate::sheaf::CellularSheaf;
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct GlobalSection {
pub values: Vec<Vec<f64>>,
pub is_exact: bool,
pub residual: f64,
}
impl GlobalSection {
pub fn new(sheaf: &CellularSheaf, values: Vec<Vec<f64>>, tol: f64) -> Result<Self, SheafError> {
sheaf.validate()?;
if values.len() != sheaf.node_count() {
return Err(SheafError::InvalidNode(values.len()));
}
for (i, v) in values.iter().enumerate() {
if v.len() != sheaf.stalk_dims[i] {
return Err(SheafError::BeliefDimensionMismatch {
agent: format!("node_{i}"),
expected: sheaf.stalk_dims[i],
got: v.len(),
});
}
}
let lap = SheafLaplacian::from_sheaf(sheaf)?;
let flat = values.iter().flatten().copied().collect::<Vec<_>>();
let residual = lap.residual_norm(&flat);
let is_exact = residual < tol;
Ok(Self {
values,
is_exact,
residual,
})
}
pub fn find(sheaf: &CellularSheaf, max_iter: usize, tol: f64) -> Result<Self, SheafError> {
sheaf.validate()?;
let lap = SheafLaplacian::from_sheaf(sheaf)?;
let (eigenvalue, flat) = lap.smallest_eigenvalue(max_iter, tol);
let mut values = Vec::new();
let mut offset = 0;
for &d in &sheaf.stalk_dims {
values.push(flat[offset..offset + d].to_vec());
offset += d;
}
let residual = lap.residual_norm(&flat);
let is_exact = eigenvalue.abs() < tol;
Ok(Self {
values,
is_exact,
residual,
})
}
pub fn flatten(&self) -> Vec<f64> {
self.values.iter().flatten().copied().collect()
}
}