Skip to content

Commit a52589b

Browse files
committed
Merge branch 'Caellian-main'
2 parents f22f683 + e5bbbd7 commit a52589b

14 files changed

Lines changed: 171 additions & 120 deletions

File tree

sim/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ getrandom = { version = "0.2", features = ["js"] }
2222
js-sys = "0.3"
2323
lazy_static = "1.4"
2424
num-traits = "0.2"
25+
rand_core = { version = "0.6", features = ["serde1"] }
2526
rand = { version = "0.8", features = ["serde1"] }
2627
rand_distr = { version = "0.4" }
2728
rand_pcg = { version = "0.3", features = ["serde1"] }
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use std::{cell::RefCell, rc::Rc};
2+
3+
pub trait SimulationRng: std::fmt::Debug + rand_core::RngCore {}
4+
impl<T: std::fmt::Debug + rand_core::RngCore> SimulationRng for T {}
5+
pub type DynRng = Rc<RefCell<dyn SimulationRng>>;
6+
7+
pub(crate) fn default_rng() -> DynRng {
8+
Rc::new(RefCell::new(rand_pcg::Pcg64Mcg::new(42)))
9+
}
10+
11+
pub fn dyn_rng<Rng: SimulationRng + 'static>(rng: Rng) -> DynRng {
12+
Rc::new(RefCell::new(rng))
13+
}
14+
15+
pub fn some_dyn_rng<Rng: SimulationRng + 'static>(rng: Rng) -> Option<DynRng> {
16+
Some(dyn_rng(rng))
17+
}

sim/src/input_modeling/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,11 @@
66
77
pub mod random_variable;
88
pub mod thinning;
9-
pub mod uniform_rng;
9+
pub mod dynamic_rng;
1010

1111
pub use random_variable::Boolean as BooleanRandomVariable;
1212
pub use random_variable::Continuous as ContinuousRandomVariable;
1313
pub use random_variable::Discrete as DiscreteRandomVariable;
1414
pub use random_variable::Index as IndexRandomVariable;
1515
pub use thinning::Thinning;
16-
pub use uniform_rng::UniformRNG;
16+
pub use dynamic_rng::{dyn_rng, some_dyn_rng};

sim/src/input_modeling/random_variable.rs

Lines changed: 33 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use rand_distr::{Beta, Exp, Gamma, LogNormal, Normal, Triangular, Uniform, Weibu
1111
// Discrete distributions
1212
use rand_distr::{Bernoulli, Geometric, Poisson, WeightedIndex};
1313

14-
use super::UniformRNG;
14+
use super::dynamic_rng::DynRng;
1515
use crate::utils::errors::SimulationError;
1616

1717
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -66,29 +66,24 @@ impl Continuous {
6666
/// The generation of random variates drives stochastic behaviors during
6767
/// simulation execution. This function requires the random number
6868
/// generator of the simulation, and produces a f64 random variate.
69-
pub fn random_variate(&mut self, uniform_rng: &mut UniformRNG) -> Result<f64, SimulationError> {
69+
pub fn random_variate(&mut self, uniform_rng: DynRng) -> Result<f64, SimulationError> {
70+
let mut rng = (*uniform_rng).borrow_mut();
7071
match self {
71-
Continuous::Beta { alpha, beta } => {
72-
Ok(Beta::new(*alpha, *beta)?.sample(uniform_rng.rng()))
73-
}
74-
Continuous::Exp { lambda } => Ok(Exp::new(*lambda)?.sample(uniform_rng.rng())),
75-
Continuous::Gamma { shape, scale } => {
76-
Ok(Gamma::new(*shape, *scale)?.sample(uniform_rng.rng()))
77-
}
72+
Continuous::Beta { alpha, beta } => Ok(Beta::new(*alpha, *beta)?.sample(&mut *rng)),
73+
Continuous::Exp { lambda } => Ok(Exp::new(*lambda)?.sample(&mut *rng)),
74+
Continuous::Gamma { shape, scale } => Ok(Gamma::new(*shape, *scale)?.sample(&mut *rng)),
7875
Continuous::LogNormal { mu, sigma } => {
79-
Ok(LogNormal::new(*mu, *sigma)?.sample(uniform_rng.rng()))
76+
Ok(LogNormal::new(*mu, *sigma)?.sample(&mut *rng))
8077
}
8178
Continuous::Normal { mean, std_dev } => {
82-
Ok(Normal::new(*mean, *std_dev)?.sample(uniform_rng.rng()))
79+
Ok(Normal::new(*mean, *std_dev)?.sample(&mut *rng))
8380
}
8481
Continuous::Triangular { min, max, mode } => {
85-
Ok(Triangular::new(*min, *max, *mode)?.sample(uniform_rng.rng()))
86-
}
87-
Continuous::Uniform { min, max } => {
88-
Ok(Uniform::new(*min, *max).sample(uniform_rng.rng()))
82+
Ok(Triangular::new(*min, *max, *mode)?.sample(&mut *rng))
8983
}
84+
Continuous::Uniform { min, max } => Ok(Uniform::new(*min, *max).sample(&mut *rng)),
9085
Continuous::Weibull { shape, scale } => {
91-
Ok(Weibull::new(*shape, *scale)?.sample(uniform_rng.rng()))
86+
Ok(Weibull::new(*shape, *scale)?.sample(&mut *rng))
9287
}
9388
}
9489
}
@@ -98,12 +93,10 @@ impl Boolean {
9893
/// The generation of random variates drives stochastic behaviors during
9994
/// simulation execution. This function requires the random number
10095
/// generator of the simulation, and produces a boolean random variate.
101-
pub fn random_variate(
102-
&mut self,
103-
uniform_rng: &mut UniformRNG,
104-
) -> Result<bool, SimulationError> {
96+
pub fn random_variate(&mut self, uniform_rng: DynRng) -> Result<bool, SimulationError> {
97+
let mut rng = (*uniform_rng).borrow_mut();
10598
match self {
106-
Boolean::Bernoulli { p } => Ok(Bernoulli::new(*p)?.sample(uniform_rng.rng())),
99+
Boolean::Bernoulli { p } => Ok(Bernoulli::new(*p)?.sample(&mut *rng)),
107100
}
108101
}
109102
}
@@ -112,15 +105,12 @@ impl Discrete {
112105
/// The generation of random variates drives stochastic behaviors during
113106
/// simulation execution. This function requires the random number
114107
/// generator of the simulation, and produces a u64 random variate.
115-
pub fn random_variate(&mut self, uniform_rng: &mut UniformRNG) -> Result<u64, SimulationError> {
108+
pub fn random_variate(&mut self, uniform_rng: DynRng) -> Result<u64, SimulationError> {
109+
let mut rng = (*uniform_rng).borrow_mut();
116110
match self {
117-
Discrete::Geometric { p } => Ok(Geometric::new(*p)?.sample(uniform_rng.rng())),
118-
Discrete::Poisson { lambda } => {
119-
Ok(Poisson::new(*lambda)?.sample(uniform_rng.rng()) as u64)
120-
}
121-
Discrete::Uniform { min, max } => {
122-
Ok(Uniform::new(*min, *max).sample(uniform_rng.rng()))
123-
}
111+
Discrete::Geometric { p } => Ok(Geometric::new(*p)?.sample(&mut *rng)),
112+
Discrete::Poisson { lambda } => Ok(Poisson::new(*lambda)?.sample(&mut *rng) as u64),
113+
Discrete::Uniform { min, max } => Ok(Uniform::new(*min, *max).sample(&mut *rng)),
124114
}
125115
}
126116
}
@@ -129,21 +119,21 @@ impl Index {
129119
/// The generation of random variates drives stochastic behaviors during
130120
/// simulation execution. This function requires the random number
131121
/// generator of the simulation, and produces a usize random variate.
132-
pub fn random_variate(
133-
&mut self,
134-
uniform_rng: &mut UniformRNG,
135-
) -> Result<usize, SimulationError> {
122+
pub fn random_variate(&mut self, uniform_rng: DynRng) -> Result<usize, SimulationError> {
123+
let mut rng = (*uniform_rng).borrow_mut();
136124
match self {
137-
Index::Uniform { min, max } => Ok(Uniform::new(*min, *max).sample(uniform_rng.rng())),
125+
Index::Uniform { min, max } => Ok(Uniform::new(*min, *max).sample(&mut *rng)),
138126
Index::WeightedIndex { weights } => {
139-
Ok(WeightedIndex::new(weights.clone())?.sample(uniform_rng.rng()))
127+
Ok(WeightedIndex::new(weights.clone())?.sample(&mut *rng))
140128
}
141129
}
142130
}
143131
}
144132

145133
#[cfg(test)]
146134
mod tests {
135+
use crate::input_modeling::dynamic_rng::default_rng;
136+
147137
use super::*;
148138

149139
enum RandomVariable {
@@ -171,14 +161,14 @@ mod tests {
171161
}
172162

173163
fn empirical_mean(random_variable: &mut RandomVariable, sample_size: usize) -> f64 {
174-
let mut uniform_rng = UniformRNG::default();
164+
let uniform_rng = default_rng();
175165
(0..sample_size)
176166
.map(|_| match random_variable {
177167
RandomVariable::Continuous(variable) => {
178-
variable.random_variate(&mut uniform_rng).unwrap()
168+
variable.random_variate(uniform_rng.clone()).unwrap()
179169
}
180170
RandomVariable::Discrete(variable) => {
181-
variable.random_variate(&mut uniform_rng).unwrap() as f64
171+
variable.random_variate(uniform_rng.clone()).unwrap() as f64
182172
}
183173
})
184174
.sum::<f64>()
@@ -187,26 +177,26 @@ mod tests {
187177

188178
fn chi_square(test: &mut ChiSquareTest, expected_counts: &[usize]) -> f64 {
189179
let mut class_counts = vec![0; expected_counts.len()];
190-
let mut uniform_rng = UniformRNG::default();
180+
let uniform_rng = default_rng();
191181
let sample_size = expected_counts.iter().sum();
192182
(0..sample_size).for_each(|_| {
193183
let index = match test {
194184
ChiSquareTest::Continuous {
195185
variable,
196186
bin_mapping_fn,
197-
} => bin_mapping_fn(variable.random_variate(&mut uniform_rng).unwrap()),
187+
} => bin_mapping_fn(variable.random_variate(uniform_rng.clone()).unwrap()),
198188
ChiSquareTest::Boolean {
199189
variable,
200190
bin_mapping_fn,
201-
} => bin_mapping_fn(variable.random_variate(&mut uniform_rng).unwrap()),
191+
} => bin_mapping_fn(variable.random_variate(uniform_rng.clone()).unwrap()),
202192
ChiSquareTest::Discrete {
203193
variable,
204194
bin_mapping_fn,
205-
} => bin_mapping_fn(variable.random_variate(&mut uniform_rng).unwrap()),
195+
} => bin_mapping_fn(variable.random_variate(uniform_rng.clone()).unwrap()),
206196
ChiSquareTest::Index {
207197
variable,
208198
bin_mapping_fn,
209-
} => bin_mapping_fn(variable.random_variate(&mut uniform_rng).unwrap()),
199+
} => bin_mapping_fn(variable.random_variate(uniform_rng.clone()).unwrap()),
210200
};
211201
class_counts[index] += 1
212202
});

sim/src/input_modeling/uniform_rng.rs

Lines changed: 0 additions & 56 deletions
This file was deleted.

sim/src/models/exclusive_gateway.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize};
44

55
use super::model_trait::{DevsModel, Reportable, ReportableModel, SerializableModel};
66
use super::{ModelMessage, ModelRecord};
7+
use crate::input_modeling::dynamic_rng::DynRng;
78
use crate::input_modeling::IndexRandomVariable;
89
use crate::simulator::Services;
910
use crate::utils::errors::SimulationError;
@@ -28,6 +29,8 @@ pub struct ExclusiveGateway {
2829
store_records: bool,
2930
#[serde(default)]
3031
state: State,
32+
#[serde(skip)]
33+
rng: Option<DynRng>,
3134
}
3235

3336
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -75,6 +78,7 @@ impl ExclusiveGateway {
7578
flow_paths_out: Vec<String>,
7679
port_weights: IndexRandomVariable,
7780
store_records: bool,
81+
rng: Option<DynRng>,
7882
) -> Self {
7983
Self {
8084
ports_in: PortsIn {
@@ -86,6 +90,7 @@ impl ExclusiveGateway {
8690
port_weights,
8791
store_records,
8892
state: State::default(),
93+
rng,
8994
}
9095
}
9196

@@ -107,7 +112,10 @@ impl ExclusiveGateway {
107112
fn send_jobs(&mut self, services: &mut Services) -> Result<Vec<ModelMessage>, SimulationError> {
108113
self.state.phase = Phase::Passive;
109114
self.state.until_next_event = INFINITY;
110-
let departure_port_index = self.port_weights.random_variate(services.uniform_rng())?;
115+
let departure_port_index = match &self.rng {
116+
Some(rng) => self.port_weights.random_variate(rng.clone())?,
117+
None => self.port_weights.random_variate(services.global_rng())?,
118+
};
111119
Ok((0..self.state.jobs.len())
112120
.map(|_| {
113121
self.record(

sim/src/models/generator.rs

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use serde::{Deserialize, Serialize};
22

33
use super::model_trait::{DevsModel, Reportable, ReportableModel, SerializableModel};
44
use super::{ModelMessage, ModelRecord};
5+
use crate::input_modeling::dynamic_rng::DynRng;
56
use crate::input_modeling::ContinuousRandomVariable;
67
use crate::input_modeling::Thinning;
78
use crate::simulator::Services;
@@ -34,6 +35,8 @@ pub struct Generator {
3435
store_records: bool,
3536
#[serde(default)]
3637
state: State,
38+
#[serde(skip)]
39+
rng: Option<DynRng>,
3740
}
3841

3942
#[derive(Debug, Clone, Serialize, Deserialize)]
@@ -79,6 +82,7 @@ impl Generator {
7982
thinning: Option<Thinning>,
8083
job_port: String,
8184
store_records: bool,
85+
rng: Option<DynRng>,
8286
) -> Self {
8387
Self {
8488
message_interdeparture_time,
@@ -87,16 +91,22 @@ impl Generator {
8791
ports_out: PortsOut { job: job_port },
8892
store_records,
8993
state: State::default(),
94+
rng,
9095
}
9196
}
9297

9398
fn release_job(
9499
&mut self,
95100
services: &mut Services,
96101
) -> Result<Vec<ModelMessage>, SimulationError> {
97-
let interdeparture = self
98-
.message_interdeparture_time
99-
.random_variate(services.uniform_rng())?;
102+
let interdeparture = match &self.rng {
103+
Some(rng) => self
104+
.message_interdeparture_time
105+
.random_variate(rng.clone())?,
106+
None => self
107+
.message_interdeparture_time
108+
.random_variate(services.global_rng())?,
109+
};
100110
self.state.phase = Phase::Generating;
101111
self.state.until_next_event = interdeparture;
102112
self.state.until_job = interdeparture;
@@ -116,9 +126,14 @@ impl Generator {
116126
&mut self,
117127
services: &mut Services,
118128
) -> Result<Vec<ModelMessage>, SimulationError> {
119-
let interdeparture = self
120-
.message_interdeparture_time
121-
.random_variate(services.uniform_rng())?;
129+
let interdeparture = match &self.rng {
130+
Some(rng) => self
131+
.message_interdeparture_time
132+
.random_variate(rng.clone())?,
133+
None => self
134+
.message_interdeparture_time
135+
.random_variate(services.global_rng())?,
136+
};
122137
self.state.phase = Phase::Generating;
123138
self.state.until_next_event = interdeparture;
124139
self.state.until_job = interdeparture;

0 commit comments

Comments
 (0)