use std::collections::HashSet;
pub fn generate_random_connected_graph_data(
n: usize,
m: usize,
seed: u64,
) -> (Vec<u32>, Vec<(u32, u32)>) {
if n == 0 {
return (Vec::new(), Vec::new());
}
if m < n - 1 {
panic!(
"Cannot create connected graph with {} nodes and {} edges. Minimum required: {}",
n,
m,
n - 1
);
}
let max_edges = n * (n - 1);
if m > max_edges {
panic!(
"Cannot generate {} edges with {} nodes. Maximum possible: {}",
m, n, max_edges
);
}
let node_keys: Vec<u32> = (0..n as u32).collect();
let mut rng_state = seed;
let mut edge_set = HashSet::new();
let mut nodes_in_tree = HashSet::new();
nodes_in_tree.insert(0u32);
for i in 1..n as u32 {
rng_state = rng_state.wrapping_mul(1664525).wrapping_add(1013904223);
let tree_nodes: Vec<_> = nodes_in_tree.iter().copied().collect();
let random_tree_node = tree_nodes[(rng_state as usize) % tree_nodes.len()];
rng_state = rng_state.wrapping_mul(1664525).wrapping_add(1013904223);
if rng_state % 2 == 0 {
edge_set.insert((random_tree_node, i));
} else {
edge_set.insert((i, random_tree_node));
}
nodes_in_tree.insert(i);
}
while edge_set.len() < m {
rng_state = rng_state.wrapping_mul(1664525).wrapping_add(1013904223);
let source = (rng_state as u32) % (n as u32);
rng_state = rng_state.wrapping_mul(1664525).wrapping_add(1013904223);
let target = (rng_state as u32) % (n as u32);
if source != target {
edge_set.insert((source, target));
}
}
let edge_pairs: Vec<(u32, u32)> = edge_set.into_iter().collect();
(node_keys, edge_pairs)
}
#[cfg(test)]
mod connected_graph_tests {
use super::*;
use graph::core::Graph;
use graph::edge::Edge;
use graph::node::Node;
use graph::utils::build_graph;
use std::collections::HashSet;
fn is_connected(nodes: &[u32], edges: &[(u32, u32)]) -> bool {
use strongly_connected_components::scc;
if nodes.is_empty() {
return true;
}
let graph_nodes: Vec<Node> = nodes.iter().map(|&key| Node::new(key)).collect();
let mut graph_edges = Vec::new();
for &(source, target) in edges {
graph_edges.push(Edge::new(source, target));
graph_edges.push(Edge::new(target, source)); }
let undirected_graph = Graph::new(graph_nodes, graph_edges);
let components = scc(&undirected_graph);
components.len() == 1
}
#[test]
fn test_generate_random_connected_graph_data_basic() {
let (nodes, edges) = generate_random_connected_graph_data(5, 8, 42);
assert_eq!(nodes.len(), 5);
assert_eq!(nodes, vec![0, 1, 2, 3, 4]);
assert_eq!(edges.len(), 8);
for (source, target) in &edges {
assert_ne!(source, target, "Self-loop found: {} -> {}", source, target);
assert!(*source < 5, "Source node {} out of range", source);
assert!(*target < 5, "Target node {} out of range", target);
}
assert!(
is_connected(&nodes, &edges),
"Generated graph is not connected"
);
}
#[test]
fn test_generate_random_connected_graph_data_deterministic() {
let (nodes1, edges1) = generate_random_connected_graph_data(4, 6, 123);
let (nodes2, edges2) = generate_random_connected_graph_data(4, 6, 123);
assert_eq!(nodes1, nodes2);
assert_eq!(edges1, edges2);
let (nodes3, edges3) = generate_random_connected_graph_data(4, 6, 456);
assert_eq!(nodes1, nodes3); assert_ne!(edges1, edges3);
assert!(is_connected(&nodes1, &edges1));
assert!(is_connected(&nodes3, &edges3));
}
#[test]
fn test_generate_random_connected_graph_data_minimum_edges() {
let n = 6;
let m = n - 1; let (nodes, edges) = generate_random_connected_graph_data(n, m, 789);
assert_eq!(nodes.len(), n);
assert_eq!(edges.len(), m);
assert!(
is_connected(&nodes, &edges),
"Graph with minimum edges is not connected"
);
}
#[test]
fn test_generate_random_connected_graph_data_no_duplicates() {
let (_, edges) = generate_random_connected_graph_data(6, 15, 789);
let edge_set: HashSet<_> = edges.iter().collect();
assert_eq!(edges.len(), edge_set.len(), "Duplicate edges found");
}
#[test]
fn test_generate_random_connected_graph_data_edge_cases() {
let (nodes, edges) = generate_random_connected_graph_data(1, 0, 1);
assert_eq!(nodes, vec![0]);
assert_eq!(edges, vec![]);
assert!(is_connected(&nodes, &edges));
let (nodes, edges) = generate_random_connected_graph_data(2, 1, 2);
assert_eq!(nodes, vec![0, 1]);
assert_eq!(edges.len(), 1);
assert!(is_connected(&nodes, &edges));
let (nodes, edges) = generate_random_connected_graph_data(0, 0, 3);
assert_eq!(nodes, vec![]);
assert_eq!(edges, vec![]);
assert!(is_connected(&nodes, &edges)); }
#[test]
fn test_generate_random_connected_graph_data_maximum_edges() {
let n = 4;
let max_edges = n * (n - 1); let (nodes, edges) = generate_random_connected_graph_data(n, max_edges, 999);
assert_eq!(nodes.len(), n);
assert_eq!(edges.len(), max_edges);
assert!(is_connected(&nodes, &edges));
let edge_set: HashSet<_> = edges.iter().collect();
assert_eq!(edges.len(), edge_set.len());
for (source, target) in &edges {
assert_ne!(source, target);
assert!(*source < n as u32);
assert!(*target < n as u32);
}
}
#[test]
#[should_panic(expected = "Cannot create connected graph")]
fn test_generate_random_connected_graph_data_too_few_edges() {
generate_random_connected_graph_data(5, 3, 123); }
#[test]
#[should_panic(expected = "Cannot generate")]
fn test_generate_random_connected_graph_data_too_many_edges() {
let n = 3;
let max_possible = n * (n - 1); generate_random_connected_graph_data(n, max_possible + 1, 123); }
#[test]
fn test_generate_random_connected_graph_data_connectivity_multiple_seeds() {
let test_cases = vec![
(3, 3, 1), (5, 8, 42), (7, 15, 999), (10, 20, 555), ];
for (n, m, seed) in test_cases {
let (nodes, edges) = generate_random_connected_graph_data(n, m, seed);
assert!(
is_connected(&nodes, &edges),
"Graph with {} nodes and {} edges (seed {}) is not connected",
n,
m,
seed
);
}
}
#[test]
fn test_generate_random_connected_graph_data_spanning_tree_property() {
let n = 8;
let m = n - 1;
let (nodes, edges) = generate_random_connected_graph_data(n, m, 123);
assert_eq!(edges.len(), m);
assert!(is_connected(&nodes, &edges));
}
#[test]
fn test_generate_random_connected_graph_data_with_build_graph() {
let (nodes, edges) = generate_random_connected_graph_data(5, 10, 42);
let graph = build_graph(nodes.clone(), edges.clone());
assert_eq!(graph.get_node_keys().len(), 5);
assert_eq!(graph.get_edges().len(), 10);
for i in 0..5 {
assert!(graph.has_node(i));
}
assert!(is_connected(&nodes, &edges));
}
#[test]
fn test_generate_random_connected_graph_data_distribution() {
let n = 6;
let m = 12;
let mut all_results = Vec::new();
for seed in 0..10 {
let (nodes, edges) = generate_random_connected_graph_data(n, m, seed);
assert!(is_connected(&nodes, &edges));
all_results.push(edges);
}
let first_result = &all_results[0];
let all_identical = all_results.iter().all(|edges| edges == first_result);
assert!(
!all_identical,
"All results are identical - poor randomness"
);
}
#[test]
fn test_generate_random_connected_graph_data_seed_consistency() {
for seed in [1, 42, 100, 999, 1234567890] {
let result1 = generate_random_connected_graph_data(5, 8, seed);
let result2 = generate_random_connected_graph_data(5, 8, seed);
assert_eq!(result1, result2, "Inconsistent results for seed {}", seed);
assert!(is_connected(&result1.0, &result1.1));
assert!(is_connected(&result2.0, &result2.1));
}
}
}