use std::collections::VecDeque;
use crate::core::{Graph, IgraphResult};
pub fn is_geodetic(graph: &Graph) -> IgraphResult<bool> {
let n = graph.vcount();
if n <= 2 {
return Ok(true);
}
let n_usize = n as usize;
let mut dist = vec![u32::MAX; n_usize];
let mut nrgeo = vec![0u32; n_usize];
let mut queue: VecDeque<u32> = VecDeque::new();
for source in 0..n {
dist.fill(u32::MAX);
nrgeo.fill(0);
dist[source as usize] = 0;
nrgeo[source as usize] = 1;
queue.clear();
queue.push_back(source);
while let Some(v) = queue.pop_front() {
let next_dist = dist[v as usize].saturating_add(1);
let neighbors = graph.neighbors(v)?;
for w in neighbors {
let w_idx = w as usize;
if dist[w_idx] == u32::MAX {
dist[w_idx] = next_dist;
nrgeo[w_idx] = 1;
queue.push_back(w);
} else if dist[w_idx] == next_dist {
nrgeo[w_idx] = nrgeo[w_idx].saturating_add(1);
if nrgeo[w_idx] > 1 {
return Ok(false);
}
}
}
}
}
Ok(true)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_graph() {
let g = Graph::with_vertices(0);
assert!(is_geodetic(&g).unwrap());
}
#[test]
fn single_vertex() {
let g = Graph::with_vertices(1);
assert!(is_geodetic(&g).unwrap());
}
#[test]
fn single_edge() {
let mut g = Graph::with_vertices(2);
g.add_edge(0, 1).unwrap();
assert!(is_geodetic(&g).unwrap());
}
#[test]
fn path_is_geodetic() {
let mut g = Graph::with_vertices(5);
g.add_edge(0, 1).unwrap();
g.add_edge(1, 2).unwrap();
g.add_edge(2, 3).unwrap();
g.add_edge(3, 4).unwrap();
assert!(is_geodetic(&g).unwrap());
}
#[test]
fn tree_is_geodetic() {
let mut g = Graph::with_vertices(7);
g.add_edge(0, 1).unwrap();
g.add_edge(0, 2).unwrap();
g.add_edge(1, 3).unwrap();
g.add_edge(1, 4).unwrap();
g.add_edge(2, 5).unwrap();
g.add_edge(2, 6).unwrap();
assert!(is_geodetic(&g).unwrap());
}
#[test]
fn triangle_is_geodetic() {
let mut g = Graph::with_vertices(3);
g.add_edge(0, 1).unwrap();
g.add_edge(1, 2).unwrap();
g.add_edge(2, 0).unwrap();
assert!(is_geodetic(&g).unwrap());
}
#[test]
fn k4_is_geodetic() {
let mut g = Graph::with_vertices(4);
for u in 0..4u32 {
for v in (u + 1)..4 {
g.add_edge(u, v).unwrap();
}
}
assert!(is_geodetic(&g).unwrap());
}
#[test]
fn cycle_4_not_geodetic() {
let mut g = Graph::with_vertices(4);
g.add_edge(0, 1).unwrap();
g.add_edge(1, 2).unwrap();
g.add_edge(2, 3).unwrap();
g.add_edge(3, 0).unwrap();
assert!(!is_geodetic(&g).unwrap());
}
#[test]
fn cycle_5_is_geodetic() {
let mut g = Graph::with_vertices(5);
g.add_edge(0, 1).unwrap();
g.add_edge(1, 2).unwrap();
g.add_edge(2, 3).unwrap();
g.add_edge(3, 4).unwrap();
g.add_edge(4, 0).unwrap();
assert!(is_geodetic(&g).unwrap());
}
#[test]
fn cycle_6_not_geodetic() {
let mut g = Graph::with_vertices(6);
g.add_edge(0, 1).unwrap();
g.add_edge(1, 2).unwrap();
g.add_edge(2, 3).unwrap();
g.add_edge(3, 4).unwrap();
g.add_edge(4, 5).unwrap();
g.add_edge(5, 0).unwrap();
assert!(!is_geodetic(&g).unwrap());
}
#[test]
fn cycle_3_is_geodetic() {
let mut g = Graph::with_vertices(3);
g.add_edge(0, 1).unwrap();
g.add_edge(1, 2).unwrap();
g.add_edge(2, 0).unwrap();
assert!(is_geodetic(&g).unwrap());
}
#[test]
fn star_is_geodetic() {
let mut g = Graph::with_vertices(5);
for i in 1..5u32 {
g.add_edge(0, i).unwrap();
}
assert!(is_geodetic(&g).unwrap());
}
#[test]
fn two_triangles_sharing_vertex_is_geodetic() {
let mut g = Graph::with_vertices(5);
g.add_edge(0, 1).unwrap();
g.add_edge(1, 2).unwrap();
g.add_edge(2, 0).unwrap();
g.add_edge(2, 3).unwrap();
g.add_edge(3, 4).unwrap();
g.add_edge(4, 2).unwrap();
assert!(is_geodetic(&g).unwrap());
}
#[test]
fn disconnected_trees_geodetic() {
let mut g = Graph::with_vertices(6);
g.add_edge(0, 1).unwrap();
g.add_edge(1, 2).unwrap();
g.add_edge(3, 4).unwrap();
g.add_edge(4, 5).unwrap();
assert!(is_geodetic(&g).unwrap());
}
#[test]
fn edgeless_is_geodetic() {
let g = Graph::with_vertices(5);
assert!(is_geodetic(&g).unwrap());
}
#[test]
fn directed_path_geodetic() {
let mut g = Graph::new(4, true).unwrap();
g.add_edge(0, 1).unwrap();
g.add_edge(1, 2).unwrap();
g.add_edge(2, 3).unwrap();
assert!(is_geodetic(&g).unwrap());
}
#[test]
fn directed_diamond_not_geodetic() {
let mut g = Graph::new(4, true).unwrap();
g.add_edge(0, 1).unwrap();
g.add_edge(0, 2).unwrap();
g.add_edge(1, 3).unwrap();
g.add_edge(2, 3).unwrap();
assert!(!is_geodetic(&g).unwrap());
}
#[test]
fn k4_minus_edge_not_geodetic() {
let mut g = Graph::with_vertices(4);
g.add_edge(0, 1).unwrap();
g.add_edge(0, 2).unwrap();
g.add_edge(0, 3).unwrap();
g.add_edge(1, 2).unwrap();
g.add_edge(1, 3).unwrap();
assert!(!is_geodetic(&g).unwrap());
}
}