cnetworks/
model.rs

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