use crate::graph::{Graph, DirectedGraph};
use rand::seq::SliceRandom;
use rand::Rng;
use std::collections::HashSet;
pub fn erdos_renyi(n: usize, p: f64) -> Graph {
let mut g = Graph::with_n_nodes(n);
let mut rng = rand::thread_rng();
for u in 0..n {
for v in (u + 1)..n {
if rng.gen::<f64>() < p {
g.add_edge(u, v);
}
}
}
g
}
pub fn erdos_renyi_gnm(n: usize, m: usize) -> Graph {
let mut g = Graph::with_n_nodes(n);
let mut rng = rand::thread_rng();
let max_edges = n * (n - 1) / 2;
let m = m.min(max_edges);
let mut edges: Vec<(usize, usize)> = Vec::with_capacity(m);
let mut used = HashSet::new();
while edges.len() < m {
let u = rng.gen_range(0..n);
let v = rng.gen_range(0..n);
if u == v { continue; }
let (a, b) = if u < v { (u, v) } else { (v, u) };
if used.insert((a, b)) {
edges.push((a, b));
}
}
for (u, v) in edges {
g.add_edge(u, v);
}
g
}
pub fn barabasi_albert(n: usize, m: usize) -> Graph {
if n == 0 || m == 0 { return Graph::new(); }
let m = m.min(n - 1);
let m0 = m + 1;
let mut g = Graph::with_n_nodes(m0);
for u in 0..m0 {
for v in (u + 1)..m0 {
g.add_edge(u, v);
}
}
let mut repeated: Vec<usize> = Vec::new();
for u in 0..m0 {
for _ in 0..m0 - 1 { repeated.push(u);
}
}
let mut rng = rand::thread_rng();
for new_node in m0..n {
g.add_node(new_node);
let mut targets = HashSet::new();
while targets.len() < m {
let pick = repeated[rng.gen_range(0..repeated.len())];
targets.insert(pick);
}
for &t in &targets {
g.add_edge(new_node, t);
repeated.push(new_node);
repeated.push(t);
}
}
g
}
pub fn watts_strogatz(n: usize, k: usize, beta: f64) -> Graph {
assert!(k % 2 == 0, "k must be even");
let half_k = k / 2;
let mut g = Graph::with_n_nodes(n);
let mut rng = rand::thread_rng();
let mut edge_list: Vec<(usize, usize)> = Vec::new();
for u in 0..n {
for j in 1..=half_k {
let v = (u + j) % n;
g.add_edge(u, v);
let (a, b) = if u < v { (u, v) } else { (v, u) };
edge_list.push((a, b));
}
}
for &(u, orig_v) in &edge_list {
if rng.gen::<f64>() < beta {
let neighbors = g.neighbors(u);
let neighbor_set: HashSet<usize> = neighbors.into_iter().collect();
let mut candidates: Vec<usize> = (0..n)
.filter(|&w| w != u && !neighbor_set.contains(&w))
.collect();
if candidates.is_empty() { continue; }
candidates.shuffle(&mut rng);
let w = candidates[0];
g.remove_edge(u, orig_v);
g.add_edge(u, w);
}
}
g
}
pub fn directed_erdos_renyi(n: usize, p: f64) -> DirectedGraph {
let mut g = DirectedGraph::with_n_nodes(n);
let mut rng = rand::thread_rng();
for u in 0..n {
for v in 0..n {
if u != v && rng.gen::<f64>() < p {
g.add_edge(u, v);
}
}
}
g
}