#![allow(clippy::many_single_char_names)]
mod common;
use common::{
Hyperedge,
Vertex,
};
use hypergraph::{
HyperedgeIndex,
Hypergraph,
HypergraphQuery,
VertexIndex,
};
fn build_acyclic() -> (
Hypergraph<Vertex<'static>, Hyperedge<'static>>,
[VertexIndex; 4],
[HyperedgeIndex; 3],
) {
let mut g = Hypergraph::<Vertex, Hyperedge>::new();
let a = g.add_vertex(Vertex::new("a")).unwrap();
let b = g.add_vertex(Vertex::new("b")).unwrap();
let c = g.add_vertex(Vertex::new("c")).unwrap();
let d = g.add_vertex(Vertex::new("d")).unwrap();
let e0 = g
.add_hyperedge(vec![a, b], Hyperedge::new("e0", 1))
.unwrap();
let e1 = g
.add_hyperedge(vec![b, c], Hyperedge::new("e1", 2))
.unwrap();
let e2 = g
.add_hyperedge(vec![b, d], Hyperedge::new("e2", 3))
.unwrap();
(g, [a, b, c, d], [e0, e1, e2])
}
fn build_cyclic() -> (
Hypergraph<Vertex<'static>, Hyperedge<'static>>,
[VertexIndex; 4],
[HyperedgeIndex; 3],
) {
let mut g = Hypergraph::<Vertex, Hyperedge>::new();
let a = g.add_vertex(Vertex::new("a")).unwrap();
let b = g.add_vertex(Vertex::new("b")).unwrap();
let c = g.add_vertex(Vertex::new("c")).unwrap();
let d = g.add_vertex(Vertex::new("d")).unwrap();
let e0 = g
.add_hyperedge(vec![a, b], Hyperedge::new("e0", 1))
.unwrap();
let e1 = g
.add_hyperedge(vec![b, c], Hyperedge::new("e1", 1))
.unwrap();
let e2 = g
.add_hyperedge(vec![c, a], Hyperedge::new("e2", 1))
.unwrap();
(g, [a, b, c, d], [e0, e1, e2])
}
#[test]
fn query_count_vertices() {
let (g, _, _) = build_acyclic();
assert_eq!(HypergraphQuery::count_vertices(&g), 4);
}
#[test]
fn query_count_hyperedges() {
let (g, _, _) = build_acyclic();
assert_eq!(HypergraphQuery::count_hyperedges(&g), 3);
}
#[test]
fn query_is_empty_false() {
let (g, _, _) = build_acyclic();
assert!(!HypergraphQuery::is_empty(&g));
}
#[test]
fn query_is_empty_true() {
let g = Hypergraph::<Vertex, Hyperedge>::new();
assert!(HypergraphQuery::is_empty(&g));
}
#[test]
fn query_vertex_indices() {
let (g, [a, b, c, d], _) = build_acyclic();
let mut got = HypergraphQuery::vertex_indices(&g).unwrap();
got.sort();
assert_eq!(got, vec![a, b, c, d]);
}
#[test]
fn query_hyperedge_indices() {
let (g, _, [e0, e1, e2]) = build_acyclic();
let mut got = HypergraphQuery::hyperedge_indices(&g).unwrap();
got.sort();
assert_eq!(got, vec![e0, e1, e2]);
}
#[test]
fn query_get_vertex_weight() {
let (g, [a, _, _, _], _) = build_acyclic();
assert_eq!(
HypergraphQuery::get_vertex_weight(&g, a).unwrap(),
Vertex::new("a")
);
}
#[test]
fn query_get_vertex_weight_not_found() {
let (g, _, _) = build_acyclic();
let missing = VertexIndex(999);
assert!(HypergraphQuery::get_vertex_weight(&g, missing).is_err());
}
#[test]
fn query_get_hyperedge_weight() {
let (g, _, [e0, _, _]) = build_acyclic();
assert_eq!(
HypergraphQuery::get_hyperedge_weight(&g, e0).unwrap(),
Hyperedge::new("e0", 1)
);
}
#[test]
fn query_get_hyperedge_weight_not_found() {
let (g, _, _) = build_acyclic();
let missing = HyperedgeIndex(999);
assert!(HypergraphQuery::get_hyperedge_weight(&g, missing).is_err());
}
#[test]
fn query_get_vertex_hyperedges() {
let (g, [_, b, _, _], [e0, e1, e2]) = build_acyclic();
let mut got = HypergraphQuery::get_vertex_hyperedges(&g, b).unwrap();
got.sort();
assert_eq!(got, vec![e0, e1, e2]);
}
#[test]
fn query_get_hyperedge_vertices() {
let (g, [a, b, _, _], [e0, _, _]) = build_acyclic();
assert_eq!(
HypergraphQuery::get_hyperedge_vertices(&g, e0).unwrap(),
vec![a, b]
);
}
#[test]
fn query_get_adjacent_vertices_from() {
let (g, [_, b, c, d], _) = build_acyclic();
let mut got = HypergraphQuery::get_adjacent_vertices_from(&g, b).unwrap();
got.sort();
assert_eq!(got, vec![c, d]);
}
#[test]
fn query_get_adjacent_vertices_to() {
let (g, [a, b, _, _], _) = build_acyclic();
let got = HypergraphQuery::get_adjacent_vertices_to(&g, b).unwrap();
assert_eq!(got, vec![a]);
}
#[test]
fn query_get_full_adjacent_vertices_from() {
let (g, [a, b, _, _], [e0, _, _]) = build_acyclic();
let got = HypergraphQuery::get_full_adjacent_vertices_from(&g, a).unwrap();
assert_eq!(got.len(), 1);
let (neighbor, hes) = &got[0];
assert_eq!(*neighbor, b);
assert_eq!(hes, &[e0]);
}
#[test]
fn query_get_full_adjacent_vertices_to() {
let (g, [a, b, _, _], [e0, _, _]) = build_acyclic();
let got = HypergraphQuery::get_full_adjacent_vertices_to(&g, b).unwrap();
assert_eq!(got.len(), 1);
let (predecessor, hes) = &got[0];
assert_eq!(*predecessor, a);
assert_eq!(hes, &[e0]);
}
#[test]
fn query_get_vertex_degree_in() {
let (g, [_, b, _, _], _) = build_acyclic();
assert_eq!(HypergraphQuery::get_vertex_degree_in(&g, b).unwrap(), 1);
}
#[test]
fn query_get_vertex_degree_out() {
let (g, [_, b, _, _], _) = build_acyclic();
assert_eq!(HypergraphQuery::get_vertex_degree_out(&g, b).unwrap(), 2);
}
#[test]
fn query_get_hyperedges_connecting() {
let (g, [a, b, _, _], [e0, _, _]) = build_acyclic();
assert_eq!(
HypergraphQuery::get_hyperedges_connecting(&g, a, b).unwrap(),
vec![e0]
);
}
#[test]
fn query_get_hyperedges_connecting_none() {
let (g, [a, _, c, _], _) = build_acyclic();
assert_eq!(
HypergraphQuery::get_hyperedges_connecting(&g, a, c).unwrap(),
vec![]
);
}
#[test]
fn query_get_hyperedges_intersections() {
let (g, [_, b, _, _], [e0, e1, e2]) = build_acyclic();
let mut got = HypergraphQuery::get_hyperedges_intersections(&g, &[e0, e1, e2]).unwrap();
got.sort();
assert_eq!(got, vec![b]);
}
#[test]
fn query_get_hyperedges_intersections_too_few() {
let (g, _, [e0, _, _]) = build_acyclic();
assert!(HypergraphQuery::get_hyperedges_intersections(&g, &[e0]).is_err());
}
#[test]
fn query_find_hyperedges_by_weight() {
let (g, _, [e0, _, _]) = build_acyclic();
assert_eq!(
HypergraphQuery::find_hyperedges_by_weight(&g, Hyperedge::new("e0", 1)).unwrap(),
vec![e0]
);
}
#[test]
fn query_get_full_vertex_hyperedges() {
let (g, [a, b, _, _], _) = build_acyclic();
let got = HypergraphQuery::get_full_vertex_hyperedges(&g, a).unwrap();
assert_eq!(got, vec![vec![a, b]]);
}
#[test]
fn query_contains_vertex_true() {
let (g, _, _) = build_acyclic();
assert!(HypergraphQuery::contains_vertex(&g, Vertex::new("a")).unwrap());
}
#[test]
fn query_contains_vertex_false() {
let (g, _, _) = build_acyclic();
assert!(!HypergraphQuery::contains_vertex(&g, Vertex::new("z")).unwrap());
}
#[test]
fn query_get_vertex_index() {
let (g, [a, _, _, _], _) = build_acyclic();
assert_eq!(
HypergraphQuery::get_vertex_index(&g, Vertex::new("a")).unwrap(),
vec![a]
);
}
#[test]
fn query_get_bfs() {
let (g, [a, b, c, d], _) = build_acyclic();
let got = HypergraphQuery::get_bfs(&g, a).unwrap();
assert_eq!(got[0], a);
assert_eq!(got[1], b);
let rest: Vec<_> = got[2..].to_vec();
assert!(rest.contains(&c));
assert!(rest.contains(&d));
}
#[test]
fn query_get_dfs() {
let (g, [a, b, _, _], _) = build_acyclic();
let got = HypergraphQuery::get_dfs(&g, a).unwrap();
assert_eq!(got[0], a);
assert_eq!(got[1], b);
}
#[test]
fn query_is_reachable_true() {
let (g, [a, _, c, _], _) = build_acyclic();
assert!(HypergraphQuery::is_reachable(&g, a, c).unwrap());
}
#[test]
fn query_is_reachable_self() {
let (g, [a, _, _, _], _) = build_acyclic();
assert!(HypergraphQuery::is_reachable(&g, a, a).unwrap());
}
#[test]
fn query_is_reachable_false() {
let (g, [a, _, _, d], _) = build_acyclic();
assert!(!HypergraphQuery::is_reachable(&g, d, a).unwrap());
}
#[test]
fn query_is_acyclic_true() {
let (g, _, _) = build_acyclic();
assert!(HypergraphQuery::is_acyclic(&g));
}
#[test]
fn query_is_acyclic_false() {
let (g, _, _) = build_cyclic();
assert!(!HypergraphQuery::is_acyclic(&g));
}
#[test]
fn query_get_all_paths() {
let (g, [a, _, c, _], _) = build_acyclic();
let got = HypergraphQuery::get_all_paths(&g, a, c).unwrap();
assert_eq!(got.len(), 1);
assert_eq!(got[0][0], a);
assert_eq!(*got[0].last().unwrap(), c);
}
#[test]
fn query_get_all_paths_same_vertex() {
let (g, [a, _, _, _], _) = build_acyclic();
assert_eq!(
HypergraphQuery::get_all_paths(&g, a, a).unwrap(),
vec![vec![a]]
);
}
#[test]
fn query_topological_sort_acyclic() {
let (g, [a, b, _, _], _) = build_acyclic();
let order = HypergraphQuery::topological_sort(&g).unwrap();
let pos_a = order.iter().position(|&v| v == a).unwrap();
let pos_b = order.iter().position(|&v| v == b).unwrap();
assert!(pos_a < pos_b, "a must come before b in topological order");
}
#[test]
fn query_topological_sort_cyclic_errors() {
let (g, _, _) = build_cyclic();
assert!(HypergraphQuery::topological_sort(&g).is_err());
}
#[test]
fn query_strongly_connected_components() {
let (g, [a, b, c, d], _) = build_cyclic();
let sccs = HypergraphQuery::strongly_connected_components(&g).unwrap();
let big_scc: Vec<_> = {
let mut v = vec![a, b, c];
v.sort();
v
};
let small_scc = vec![d];
assert!(sccs.contains(&big_scc));
assert!(sccs.contains(&small_scc));
}
#[test]
fn query_connected_components() {
let mut g = Hypergraph::<Vertex, Hyperedge>::new();
let a = g.add_vertex(Vertex::new("a")).unwrap();
let b = g.add_vertex(Vertex::new("b")).unwrap();
let c = g.add_vertex(Vertex::new("c")).unwrap();
let d = g.add_vertex(Vertex::new("d")).unwrap();
g.add_hyperedge(vec![a, b], Hyperedge::new("e0", 1))
.unwrap();
g.add_hyperedge(vec![c, d], Hyperedge::new("e1", 1))
.unwrap();
let components = HypergraphQuery::connected_components(&g).unwrap();
assert_eq!(components.len(), 2);
let first: Vec<_> = {
let mut v = vec![a, b];
v.sort();
v
};
let second: Vec<_> = {
let mut v = vec![c, d];
v.sort();
v
};
assert!(components.contains(&first));
assert!(components.contains(&second));
}
#[test]
fn query_get_dijkstra_connections() {
let (g, [a, b, c, _], [e0, e1, _]) = build_acyclic();
let path = HypergraphQuery::get_dijkstra_connections(&g, a, c).unwrap();
assert_eq!(path, vec![(a, None), (b, Some(e0)), (c, Some(e1))]);
}
#[test]
fn query_get_dijkstra_connections_with_cost() {
let (g, [a, _, c, _], _) = build_acyclic();
let (cost, path) = HypergraphQuery::get_dijkstra_connections_with_cost(&g, a, c).unwrap();
assert_eq!(cost, 3); assert_eq!(path[0].0, a);
assert_eq!(path.last().unwrap().0, c);
}
#[test]
fn query_get_dijkstra_from() {
let (g, [a, b, c, d], _) = build_acyclic();
let distances = HypergraphQuery::get_dijkstra_from(&g, a).unwrap();
assert_eq!(distances[&a], 0);
assert_eq!(distances[&b], 1);
assert_eq!(distances[&c], 3); assert_eq!(distances[&d], 4); }