1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
//! This module contains definitions for the network models and their constructing algorithms.
use crate::{cn, Network};
use rand::prelude::{Rng, SliceRandom};
/// Decides the algorithm used to connect the nodes during [`Network`]'s initialization. It can
/// also be used for identification purposes when the [`Model::Custom`] variant is used.
#[derive(Debug, Clone, PartialEq)]
pub enum Model {
/// The Erdos–Renyi random network model.
ER {
/// The probability of connecting any given pair of nodes.
p: f64,
/// Should the network be in one piece
whole: bool,
},
/// The Barabasi–Albert preferential attachment model.
BA {
/// The initial number of clustered nodes.
m0: usize,
/// The number of nodes added in each step during network creation.
/// Keep in mind that this should be strictly less or equal m0 and the Barabasi-Albert
/// initialization function **will panic** if this is not the case.
m: usize,
},
/// Custom model, can be dynamically assigned to a network using [`Network::set_model`].
Custom(String),
/// Placeholder for a network with no specified model. When a network is initialized with this
/// model no immediate connections will be made.
None,
}
impl Model {
/// Clear the network's links and reinitialize them according to the Erdos-Renyi model.
///
/// See [`Model::ER`] for more detailed explanation.
pub fn init_er(net: &mut Network, p: f64, whole: bool) {
let net_len = net.size();
net.disconnect_all();
if p <= 0. || p > 1. {
panic!("{}", cn::Err::BadProbability(p));
}
for i in 0..net_len {
for j in i + 1..net_len {
if net.rng().unwrap().gen::<f64>() <= p {
net.link(i, j).unwrap();
}
}
}
if whole {
net.stitch_together();
}
net.model = Model::ER { p, whole };
}
/// Clear the network's links and reinitialize them according to the Barabasi-Albert model.
///
/// See [`Model::BA`] for more detailed model explanation.
pub fn init_ba(net: &mut Network, m0: usize, m: usize) {
if m0 < 1 || m == 0 || m > m0 || m0 > net.size() {
panic!("Incorrect model parameters: m0 = {}, m = {}", m0, m);
}
net.disconnect_all();
// Initial cluster - connect everything to everything
for i in 0..m0 {
if m0 == 1 {
break;
}
for j in i + 1..m0 {
net.link(i, j).unwrap();
}
}
// Attach the other nodes one by one
for current_idx in m0..net.size() {
let chosen: Vec<usize> = net
.nodes()
.filter(|&node| node < current_idx)
.map(|node| (node, net.deg_of(node).unwrap()))
.collect::<Vec<_>>() // <- This is sadly needed
.choose_multiple_weighted(&mut *net.rng().unwrap(), m, |&(_index, deg)| deg as f64)
.unwrap()
.map(|&(idx, _deg)| idx)
.collect();
for other in chosen {
net.link(current_idx, other).unwrap();
}
}
}
}
impl Default for Model {
fn default() -> Self {
Model::None
}
}