#[cfg(feature = "rand")]
use rand::{prelude::*, rngs::StdRng};
pub trait TopologySampler {
fn sample(&mut self) -> impl IntoIterator<Item = (usize, usize)>;
fn num_nodes(&mut self) -> usize;
}
impl TopologySampler for Vec<(usize, usize)> {
fn sample(&mut self) -> impl IntoIterator<Item = (usize, usize)> {
self.iter().copied()
}
fn num_nodes(&mut self) -> usize {
self.iter()
.flat_map(|(a, b)| [*a, *b])
.max()
.map(|x| x + 1)
.unwrap_or(0)
}
}
impl TopologySampler for &[(usize, usize)] {
fn sample(&mut self) -> impl IntoIterator<Item = (usize, usize)> {
self.iter().copied()
}
fn num_nodes(&mut self) -> usize {
self.iter()
.flat_map(|(a, b)| [*a, *b])
.max()
.map(|x| x + 1)
.unwrap_or(0)
}
}
#[derive(Debug, Clone, Copy)]
pub struct CompleteGraph(pub usize);
impl TopologySampler for CompleteGraph {
fn sample(&mut self) -> impl IntoIterator<Item = (usize, usize)> {
(0..self.0).flat_map(|a| ((a + 1)..self.0).map(move |b| (a, b)))
}
fn num_nodes(&mut self) -> usize {
self.0
}
}
#[derive(Debug, Clone)]
#[cfg(feature = "rand")]
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
pub struct GnpGraph<R> {
n: usize,
p: f64,
rng: R,
}
#[cfg(feature = "rand")]
impl GnpGraph<ThreadRng> {
pub fn new(n: usize, p: f64) -> Self {
Self {
n,
p,
rng: thread_rng(),
}
}
}
#[cfg(feature = "rand")]
impl GnpGraph<StdRng> {
pub fn seeded(seed: u64, n: usize, p: f64) -> Self {
Self {
n,
p,
rng: StdRng::seed_from_u64(seed),
}
}
}
#[cfg(feature = "rand")]
impl<R> GnpGraph<R> {
pub fn from_rng(rng: R, n: usize, p: f64) -> Self {
Self { n, p, rng }
}
}
#[cfg(feature = "rand")]
impl<R: RngCore> TopologySampler for GnpGraph<R> {
fn sample(&mut self) -> impl IntoIterator<Item = (usize, usize)> {
(0..self.n)
.flat_map(|a| ((a + 1)..self.n).map(move |b| (a, b)))
.filter(|_| self.rng.gen_bool(self.p))
}
fn num_nodes(&mut self) -> usize {
self.n
}
}
#[derive(Debug, Clone)]
#[cfg(feature = "rand")]
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
pub struct GnmGraph<R> {
n: usize,
m: usize,
rng: R,
}
#[cfg(feature = "rand")]
impl GnmGraph<ThreadRng> {
pub fn new(n: usize, m: usize) -> Self {
Self {
n,
m,
rng: thread_rng(),
}
}
}
#[cfg(feature = "rand")]
impl GnmGraph<StdRng> {
pub fn seeded(seed: u64, n: usize, m: usize) -> Self {
Self {
n,
m,
rng: StdRng::seed_from_u64(seed),
}
}
}
#[cfg(feature = "rand")]
impl<R> GnmGraph<R> {
pub fn from_rng(rng: R, n: usize, m: usize) -> Self {
Self { n, m, rng }
}
}
#[cfg(feature = "rand")]
impl<R: RngCore> TopologySampler for GnmGraph<R> {
fn sample(&mut self) -> impl IntoIterator<Item = (usize, usize)> {
let n = self.n;
let m = self.m;
let mut links = std::collections::HashSet::new();
while links.len() < m {
let i = self.rng.gen_range(0..n);
let j = self.rng.gen_range(0..n);
let (i, j) = if i < j { (i, j) } else { (j, i) };
if i != j {
links.insert((i, j));
}
}
links
}
fn num_nodes(&mut self) -> usize {
self.n
}
}
#[derive(Debug, Clone)]
#[cfg(feature = "rand")]
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
pub struct GeometricGraph<R> {
n: usize,
dim: usize,
dist: f64,
rng: R,
}
#[cfg(feature = "rand")]
impl GeometricGraph<ThreadRng> {
pub fn new(n: usize, dim: usize, dist: f64) -> Self {
Self {
n,
dim,
dist,
rng: thread_rng(),
}
}
}
#[cfg(feature = "rand")]
impl GeometricGraph<StdRng> {
pub fn seeded(seed: u64, n: usize, dim: usize, dist: f64) -> Self {
Self {
n,
dim,
dist,
rng: StdRng::seed_from_u64(seed),
}
}
}
#[cfg(feature = "rand")]
impl<R> GeometricGraph<R> {
pub fn from_rng(rng: R, n: usize, dim: usize, dist: f64) -> Self {
Self { n, dim, dist, rng }
}
}
#[cfg(feature = "rand")]
impl<R: RngCore> TopologySampler for GeometricGraph<R> {
fn sample(&mut self) -> impl IntoIterator<Item = (usize, usize)> {
let n = self.n;
let dim = self.dim;
let positions = Vec::from_iter(
(0..n).map(|_| Vec::from_iter((0..dim).map(|_| self.rng.gen_range(0.0..1.0)))),
);
let dist2 = self.dist * self.dist;
(1..n)
.flat_map(|j| (0..j).map(move |i| (i, j)))
.filter(move |(i, j)| {
let pi = &positions[*i];
let pj = &positions[*j];
let distance: f64 = (0..dim).map(|x| (pi[x] - pj[x])).map(|x| x * x).sum();
distance < dist2
})
}
fn num_nodes(&mut self) -> usize {
self.n
}
}
#[derive(Debug, Clone)]
#[cfg(feature = "rand")]
#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
pub struct BarabasiAlbertGraph<R> {
n: usize,
m: usize,
rng: R,
}
#[cfg(feature = "rand")]
impl BarabasiAlbertGraph<ThreadRng> {
pub fn new(n: usize, m: usize) -> Self {
Self {
n,
m,
rng: thread_rng(),
}
}
}
#[cfg(feature = "rand")]
impl BarabasiAlbertGraph<StdRng> {
pub fn seeded(seed: u64, n: usize, m: usize) -> Self {
Self {
n,
m,
rng: StdRng::seed_from_u64(seed),
}
}
}
#[cfg(feature = "rand")]
impl<R> BarabasiAlbertGraph<R> {
pub fn from_rng(rng: R, n: usize, m: usize) -> Self {
Self { n, m, rng }
}
}
#[cfg(feature = "rand")]
impl<R: RngCore> TopologySampler for BarabasiAlbertGraph<R> {
fn sample(&mut self) -> impl IntoIterator<Item = (usize, usize)> {
let n = self.n;
let m = self.m;
let rng = &mut self.rng;
let mut degree = vec![0; n];
let mut links: Vec<_> = (0..m)
.flat_map(|a| ((a + 1)..m).map(move |b| (a, b)))
.collect();
for i in 0..m {
degree[i] = m - 1;
}
if n <= (m + 1) {
return links;
}
for i in m..n {
let mut added_edges: std::collections::BTreeSet<_> = Default::default();
for _ in 0..m {
let p: Vec<_> = degree
.iter()
.enumerate()
.filter(|(j, _)| *j < i) .filter(|(j, _)| !added_edges.contains(j)) .flat_map(|(j, degree)| std::iter::repeat(j).take(*degree))
.collect();
let j = p[rng.gen_range(0..p.len())];
links.push((i, j));
*(&mut degree[i]) += 1;
*(&mut degree[j]) += 1;
added_edges.insert(j);
}
}
links
}
fn num_nodes(&mut self) -> usize {
self.n
}
}