use crate::graph::FleetGraph;
pub struct HolonomyVerifier<'a> {
graph: &'a FleetGraph,
}
impl<'a> HolonomyVerifier<'a> {
pub fn new(graph: &'a FleetGraph) -> Self {
HolonomyVerifier { graph }
}
pub fn verify_all(&self) -> HolonomyReport {
let cycles = self.graph.find_cycles();
let mut violations = Vec::new();
for cycle in &cycles {
if !self.verify_cycle(cycle) {
violations.push(cycle.clone());
}
}
HolonomyReport {
total_cycles: cycles.len(),
all_consistent: violations.is_empty(),
violations,
betti1: self.graph.betti1(),
}
}
fn verify_cycle(&self, cycle: &[String]) -> bool {
let edge_count = self.count_constraint_edges_in_cycle(cycle);
edge_count % 2 == 0
}
fn count_constraint_edges_in_cycle(&self, cycle: &[String]) -> usize {
if cycle.len() < 2 {
return 0;
}
let mut count = 0;
for i in 0..cycle.len() {
let from = &cycle[i];
let to = &cycle[(i + 1) % cycle.len()];
for edge in self.graph.edges() {
if (edge.from == *from && edge.to == *to)
|| (edge.from == *to && edge.to == *from)
{
if edge.constraint_flow {
count += 1;
}
break;
}
}
}
count
}
}
#[derive(Debug)]
pub struct HolonomyReport {
pub total_cycles: usize,
pub violations: Vec<Vec<String>>,
pub betti1: usize,
pub all_consistent: bool,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty_graph_is_consistent() {
let graph = FleetGraph::new();
let verifier = HolonomyVerifier::new(&graph);
let report = verifier.verify_all();
assert!(report.all_consistent);
assert_eq!(report.total_cycles, 0);
}
}