fn lcg_next(state: &mut u64) -> u64 {
*state = state.wrapping_mul(1664525).wrapping_add(1013904223);
*state
}
fn mix64(mut z: u64) -> u64 {
z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
z ^ (z >> 31)
}
pub fn generate_random_graph_data(n: usize, m: usize, seed: u64) -> (Vec<u32>, Vec<(u32, u32)>) {
if n == 0 {
return (Vec::new(), Vec::new());
}
let node_keys: Vec<u32> = (0..n as u32).collect();
let mut rng_state = seed;
let mut edges = Vec::with_capacity(m);
for _ in 0..m {
let from = (mix64(lcg_next(&mut rng_state)) % (n as u64)) as u32;
let mut to = (mix64(lcg_next(&mut rng_state)) % (n as u64)) as u32;
if to == from {
to = ((to as usize + 1) % n) as u32;
}
edges.push((from, to));
}
(node_keys, edges)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_generate_random_graph_data_basic() {
let (nodes, edges) = generate_random_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);
}
}
#[test]
fn test_generate_random_graph_data_deterministic() {
let (nodes1, edges1) = generate_random_graph_data(4, 6, 123);
let (nodes2, edges2) = generate_random_graph_data(4, 6, 123);
assert_eq!(nodes1, nodes2);
assert_eq!(edges1, edges2);
let (nodes3, edges3) = generate_random_graph_data(4, 6, 456);
assert_eq!(nodes1, nodes3); assert_ne!(edges1, edges3); }
#[test]
fn test_generate_random_graph_data_edge_cases() {
let (nodes, edges) = generate_random_graph_data(1, 0, 1);
assert_eq!(nodes, vec![0]);
assert_eq!(edges, vec![]);
let (nodes, edges) = generate_random_graph_data(2, 1, 2);
assert_eq!(nodes, vec![0, 1]);
assert_eq!(edges.len(), 1);
let edge = edges[0];
assert!(edge == (0, 1) || edge == (1, 0));
let (nodes, edges) = generate_random_graph_data(0, 0, 3);
assert_eq!(nodes, vec![]);
assert_eq!(edges, vec![]);
}
#[test]
fn test_generate_random_graph_data_distribution() {
let n = 5;
let m = 10;
let mut all_results = Vec::new();
for seed in 0..10 {
let (_, edges) = generate_random_graph_data(n, m, seed);
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_graph_data_node_coverage() {
let (_nodes, edges) = generate_random_graph_data(10, 30, 555);
let mut nodes_in_edges = std::collections::HashSet::new();
for (source, target) in &edges {
nodes_in_edges.insert(*source);
nodes_in_edges.insert(*target);
}
assert!(
nodes_in_edges.len() >= 7,
"Only {} out of 10 nodes appear in edges",
nodes_in_edges.len()
);
}
#[test]
fn test_generate_random_graph_data_seed_consistency_across_calls() {
for seed in [1, 42, 100, 999, 1234567890] {
let result1 = generate_random_graph_data(5, 8, seed);
let result2 = generate_random_graph_data(5, 8, seed);
assert_eq!(result1, result2, "Inconsistent results for seed {}", seed);
}
}
}