use crate::coherence::CoherenceMeasure;
use crate::error::SheafError;
use crate::laplacian::SheafLaplacian;
use crate::section::GlobalSection;
use crate::sheaf::{CellularSheaf, SheafBuilder};
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct AgentBelief {
pub id: String,
pub belief_vector: Vec<f64>,
pub confidence: f64,
}
impl AgentBelief {
pub fn new(id: impl Into<String>, belief_vector: Vec<f64>, confidence: f64) -> Self {
Self {
id: id.into(),
belief_vector,
confidence: confidence.clamp(0.0, 1.0),
}
}
}
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct AgentSheaf {
pub agents: Vec<AgentBelief>,
pub sheaf: CellularSheaf,
}
impl AgentSheaf {
pub fn complete(agents: Vec<AgentBelief>) -> Result<Self, SheafError> {
if agents.is_empty() {
return Err(SheafError::EmptySheaf);
}
let stalk_dim = agents[0].belief_vector.len();
for a in &agents {
if a.belief_vector.len() != stalk_dim {
return Err(SheafError::BeliefDimensionMismatch {
agent: a.id.clone(),
expected: stalk_dim,
got: a.belief_vector.len(),
});
}
}
let n = agents.len();
let sheaf = CellularSheaf::complete(n, stalk_dim)?;
Ok(Self { agents, sheaf })
}
pub fn path(agents: Vec<AgentBelief>) -> Result<Self, SheafError> {
if agents.is_empty() {
return Err(SheafError::EmptySheaf);
}
let stalk_dim = agents[0].belief_vector.len();
for a in &agents {
if a.belief_vector.len() != stalk_dim {
return Err(SheafError::BeliefDimensionMismatch {
agent: a.id.clone(),
expected: stalk_dim,
got: a.belief_vector.len(),
});
}
}
let n = agents.len();
let sheaf = if n == 1 {
CellularSheaf::constant(1, stalk_dim)?
} else {
CellularSheaf::path(n, stalk_dim)?
};
Ok(Self { agents, sheaf })
}
pub fn with_edges(agents: Vec<AgentBelief>, edges: &[(usize, usize)]) -> Result<Self, SheafError> {
if agents.is_empty() {
return Err(SheafError::EmptySheaf);
}
let stalk_dim = agents[0].belief_vector.len();
for a in &agents {
if a.belief_vector.len() != stalk_dim {
return Err(SheafError::BeliefDimensionMismatch {
agent: a.id.clone(),
expected: stalk_dim,
got: a.belief_vector.len(),
});
}
}
let identity = {
let mut m = vec![vec![0.0; stalk_dim]; stalk_dim];
for (i, row) in m.iter_mut().enumerate() {
row[i] = 1.0;
}
m
};
let mut builder = SheafBuilder::default();
for _ in &agents {
builder = builder.add_node(stalk_dim);
}
for &(i, j) in edges {
builder = builder.add_edge(i, j, identity.clone());
}
let sheaf = builder.build()?;
Ok(Self { agents, sheaf })
}
pub fn flat_beliefs(&self) -> Vec<f64> {
self.agents.iter().flat_map(|a| a.belief_vector.iter().copied()).collect()
}
pub fn laplacian(&self) -> Result<SheafLaplacian, SheafError> {
SheafLaplacian::from_sheaf(&self.sheaf)
}
pub fn coherence(&self, max_iter: usize, tol: f64) -> Result<CoherenceMeasure, SheafError> {
let flat = self.flat_beliefs();
CoherenceMeasure::from_flat(&self.sheaf, &flat, max_iter, tol)
}
pub fn global_section(&self, tol: f64) -> Result<GlobalSection, SheafError> {
let values: Vec<Vec<f64>> = self.agents.iter().map(|a| a.belief_vector.clone()).collect();
GlobalSection::new(&self.sheaf, values, tol)
}
pub fn len(&self) -> usize {
self.agents.len()
}
pub fn is_empty(&self) -> bool {
self.agents.is_empty()
}
}