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
//! This module contains definitions for the network models and their constructing algorithms.
use crate::algorithms;
use super::Network;
use crate::CNErr;
use rand::prelude::*;
use serde::{Serialize, Deserialize};
/// `Model` decides the algorithm used to connect the nodes during `Network`'s
/// initialization.
#[derive(Debug, Clone, Serialize, Deserialize)]
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 fuction **will panic** if this is not the case.
m: usize,
},
/// Placeholder for a network with no connections.
None,
}
impl Model {
/// Initialize (or reinitialize) the network's links according to the Erdos-Renyi model.
/// See the [Model](enum.Model.html) for more detailed model explanation.
///
/// If `whole` is `true` then the network is artificially stitched together after
/// initialization, otherwise there is no guarantee that there are no 'outsiders' or even
/// separate networks.
///
/// Beware that the network is **not** cleared before linking.
pub fn init_er(net: &mut Network, p: f64, whole: bool) {
let net_len = net.size();
if p <= 0. || p > 1. {
CNErr::BadProbability(p).panic();
}
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 {
algorithms::stitch_together(net);
}
net.model = Model::ER { p, whole };
}
/// Initialize (or reinitialize) the network's links according to the Barabasi-Albert model.
/// See the [Model](enum.Model.html) for more detailed model explanation.
///
/// The links *are* cleared before re-linking because of the nature of initialization algorithm
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() {
for other in net
.nodes()
.filter(|&node| *node.index() < current_idx)
.map(|node| (*node.index(), *node.deg() as i32))
.collect::<Vec<_>>() // This is sadly needed
.choose_multiple_weighted(net.rng.get_mut(), m, |(_index, deg)| *deg)
.unwrap()
.map(|&(idx, _deg)| idx)
{
net.link(current_idx, other).unwrap();
}
}
}
}