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}