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 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
//! # This lib is intended for scientific simulations //! //! * you probably want to take a look at [`GenericGraph`](generic_graph/struct.GenericGraph.html). //! * take a look at the module [`er_c`](er_c/index.html) //! or [`er_m`](er_m/index.html) if you want to do something with an **Erdős-Rényi** ensemble //! * if you want to work with a **small-world** ensemble, look at module [`sw`](sw/index.html) //! * an example for implementing your own Node can be found [here](graph/type.Graph.html#example-2). //! Note that the defined Node can be used in the Graph ensembles //! * Note: The ensembles implement the trait [`GraphIterators`](./traits/trait.GraphIterators.html), //! therefore calling, e.g., `ensemble.graph().dfs(0)` is equivalent //! to `ensemble.dfs(0)` as long as you used //! `use::net_ensembles::traits::*` //! * See also: [`GraphIteratorsMut`](./traits/trait.GraphIteratorsMut.html) //! * Note: the ensembles implement the trait //! [`MeasurableGraphQuantities`](./traits/trait.MeasurableGraphQuantities.html), //! therefore, e.g., `ensemble.graph().transitivity()` and `ensemble.transitivity()` //! are equivalent //! * for **sampling** the ensemble, take a look at [these traits](./sampling/traits/index.html) //! # Example 1 //! //! ``` //! use net_ensembles::{ErEnsembleC, EmptyNode, rand::SeedableRng}; //! use net_ensembles::traits::{WithGraph, SimpleSample, Dot}; //! use net_ensembles::{dot_options, dot_constants::*}; //! // Note: you might have to enable serde for rand_pcg //! // to do that, write the following in your Cargo.toml: //! // rand_pcg = { version = "*", features = ["serde1"]} //! use rand_pcg::Pcg64; //! use std::fs::File; //! //! let rng = Pcg64::seed_from_u64(75676526); //! // create graph with 50 vertices and target connectivity of 2.7 //! // using Pcg64 as random number generator //! // NOTE: you can exchange `EmptyNode` with anything implementing the `Node` trait //! let mut er = ErEnsembleC::<EmptyNode, _>::new(50, 2.7, rng); //! //! // create dot file to visualize the graph //! let mut f = File::create("50.dot") //! .expect("Unable to create file"); //! // look at Dot trait //! er.graph().dot( //! f, //! "" // you do not have to use dot_options //! ).unwrap(); //! //! // randomize the graph, uses SimpleSample trait //! er.randomize(); //! //! let mut f = File::create("50_1.dot") //! .expect("Unable to create file"); //! er.graph().dot_with_indices( //! f, //! dot_options!(NO_OVERLAP, MARGIN_0) //! ).unwrap(); //! //! // Note, you can also create a String this way: //! let s = er.graph().dot_string(""); //! ``` //! To visualize, you can use something like //! ```dot //! twopi 50.dot -Tpdf > 50.pdf //! circo 50_1.dot -Tpdf > 50_1.pdf //! ``` //! You can also try some of the other [roadmaps](https://www.graphviz.org/). //! # Example 2 //! You can also compute different measurable quantities, look at //! [`GenericGraph`](generic_graph/struct.GenericGraph.html) for more. //! //! ``` //! use net_ensembles::{traits::*, EmptyNode, ErEnsembleC}; //! use rand_pcg::Pcg64; //! use rand::SeedableRng; //! //! let rng = Pcg64::seed_from_u64(26); //! // create graph with 50 vertices and target connectivity of 2.7 //! // using Pcg64 as random number generator //! let er = ErEnsembleC::<EmptyNode, Pcg64>::new(50, 2.7, rng); //! println!("Number of vertices: {}", er.vertex_count()); //! println!("Number of edges: {}", er.edge_count()); //! println!("Average degree: {}", er.average_degree()); //! println!("connected components: {:?}", er.connected_components()); //! println!("transitivity: {}", er.transitivity()); //! ``` //! **Note:** Also works for small-world ensemble, i.e. for //! [`SwEnsemble`](sw/struct.SwEnsemble.html) //! # Example 3 //! ## Simple sample for small-world ensemble //! * **Note:** simple sampling also works for [`ErEnsembleC`](er_c/struct.ErEnsembleC.html) //! and [`ErEnsembleM`](er_m/struct.ErEnsembleM.html) //! * see trait [```SimpleSample```](./sampling/traits/trait.SimpleSample.html) //! ``` //! use net_ensembles::{SwEnsemble, EmptyNode}; //! use net_ensembles::traits::*; // I recommend always using this //! use rand_pcg::Pcg64; //or whatever you want to use as rng //! use rand::SeedableRng; // I use this to seed my rng, but you can use whatever //! use std::fs::File; //! use std::io::{BufWriter, Write}; //! //! let rng = Pcg64::seed_from_u64(1822); //! //! // now create small-world ensemble with 100 nodes //! // and a rewiring probability of 0.3 for each edge //! let mut sw_ensemble = SwEnsemble::<EmptyNode, Pcg64>::new(100, 0.3, rng); //! //! // setup file for writing //! let f = File::create("simple_sample_sw.dat") //! .expect("Unable to create file"); //! let mut f = BufWriter::new(f); //! f.write_all(b"#diameter bi_connect_max average_degree\n") //! .unwrap(); //! //! // simple sample for 10 steps //! sw_ensemble.simple_sample(10, //! |ensemble| //! { //! let diameter = ensemble //! .diameter() //! .unwrap(); //! //! let bi_connect_max = ensemble.graph().clone() //! .vertex_biconnected_components(false)[0]; //! //! let average_degree = ensemble.graph() //! .average_degree(); //! //! write!(f, "{} {} {}\n", diameter, bi_connect_max, average_degree) //! .unwrap(); //! } //! ); //! //! // or just collect this into a vector to print or do whatever //! let vec = sw_ensemble.simple_sample_vec(10, //! |ensemble| //! { //! let diameter = ensemble.graph() //! .diameter() //! .unwrap(); //! //! let transitivity = ensemble.graph() //! .transitivity(); //! (diameter, transitivity) //! } //! ); //! println!("{:?}", vec); //! ``` //! //! # Example 4: Save and load //! * only works if feature ```"serde_support"``` is enabled //! * Note: ```"serde_support"``` is enabled by default //! * I need the ```#[cfg(feature = "serde_support")]``` to ensure the example does compile if //! you opt out of the default feature //! * you do not have to use ```serde_json```, look [here](https://docs.serde.rs/serde/) for more info //! ``` //! use net_ensembles::traits::*; // I recommend always using this //! use serde_json; //! use rand_pcg::Pcg64; //! use net_ensembles::{ErEnsembleC, EmptyNode, rand::SeedableRng}; //! use std::fs::File; //! //! let rng = Pcg64::seed_from_u64(95); //! // create Erdős-Rényi ensemble //! let ensemble = ErEnsembleC::<EmptyNode, Pcg64>::new(200, 3.1, rng); //! //! #[cfg(feature = "serde_support")] //! { //! // storing the ensemble in a file: //! //! let er_file = File::create("erC_save.dat") //! .expect("Unable to create file"); //! //! // or serde_json::to_writer(er_file, &ensemble); //! serde_json::to_writer_pretty(er_file, &ensemble); //! //! // loading ensemble from file: //! //! let mut read = File::open("erC_save.dat") //! .expect("Unable to open file"); //! //! let er: ErEnsembleC::<EmptyNode, Pcg64> = serde_json::from_reader(read).unwrap(); //! } //! ``` //! # Example 5: Marcov Chain //! * example for a Marcov chain of connected graphs //! * you can also create a Marcov chain with unconnected graphs if you want //! * see trait [```MarcovChain```](./sampling/traits/trait.MarkovChain.html) //! ``` //! use net_ensembles::{EmptyNode, ErEnsembleM, traits::*}; //! use rand_pcg::Pcg64; //! use net_ensembles::rand::SeedableRng; // rand is reexported //! //! // first create the ensemble //! let rng = Pcg64::seed_from_u64(8745); //! let mut e = ErEnsembleM::<EmptyNode, Pcg64>::new(30, 70, rng); //! //! // ensure initial graph is connected //! while !e.graph() //! .is_connected().unwrap() { //! e.randomize(); //! } //! //! // Create marcov chain, e.g., of connected graphs //! for _ in 0..100 { //! let steps = e.m_steps(10); //! //! // reject, if the resulting graph is not connected //! if !e.graph().is_connected().unwrap() { //! e.undo_steps_quiet(steps); //! } //! // mesure whatever you want //! } //! ``` //! //! # Example 6: Define your own Data //! * Note: You will not need the cfg parts, though you have to //! use ```#[derive(Serialize, Deserialize)]``` if you use the //! default features of ```net_ensembles``` //! ``` //! use net_ensembles::{traits::*, rand::SeedableRng, SwEnsemble}; //! use rand_pcg::Pcg64; //! //! #[cfg(feature = "serde_support")] //! use serde::{Serialize, Deserialize}; //! //! #[derive(Clone, PartialEq)] //! #[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))] //! pub enum SirState{ //! Susceptible, //! Infective, //! Removed, //! } //! //! impl SirState { //! fn setState(&mut self, state: Self) { //! *self = state; //! } //! } //! //! impl Node for SirState { //! fn new_from_index(index: usize) -> Self { //! SirState::Susceptible //! } //! } //! //! // create the rng: //! let rng = Pcg64::seed_from_u64(45); //! //! let mut ensemble = SwEnsemble::<SirState, Pcg64>::new(10, 0.1, rng); //! //! // you can access or change your additional information, e.g., at vertex 0 //! ensemble //! .at_mut(0) //! .setState(SirState::Infective); //! //! // you can also iterate over your additional information: //! let count = ensemble //! .contained_iter() //! .filter(|&state| *state == SirState::Susceptible) //! .count(); //! assert!(count == 9); //! //! // or count how many Susceptible nodes are connected to a specific node, i.e., to node 0 //! let s_count = ensemble //! .contained_iter_neighbors(0) //! .filter(|&state| *state == SirState::Susceptible) //! .count(); //! //! println!("{}", s_count); //! //! // or advance the states: //! for state in ensemble.contained_iter_mut() { //! match *state { //! SirState::Infective => { *state = SirState::Removed }, //! _ => { }, //! }; //! } //! ``` #![deny(missing_docs, warnings)] pub mod generic_graph; pub mod example_nodes; pub mod graph; pub mod er_c; pub mod sw; pub mod er_m; pub mod traits; #[macro_use] pub mod dot_constants; pub mod sw_graph; pub mod iter; pub mod step_structs; pub mod sampling; pub use sw::SwEnsemble; pub use sw_graph::SwGraph; pub use er_m::ErEnsembleM; pub use er_c::ErEnsembleC; pub use graph::Graph; pub use generic_graph::GenericGraph; pub use example_nodes::EmptyNode; pub use traits::*; pub use traits::GraphErrors; pub use iter::IterWrapper; pub use step_structs::*; pub use rand;