des_sim/modeling/sampler/instance/
exponential.rs1use crate::modeling::sampler::{DurationSampler, PendingDuration};
9use crate::primitive::time::SimTime;
10use rand::Rng;
11use rand::distr::Distribution;
12use rand_distr::{Exp, ExpError};
13
14#[derive(Debug, Clone)]
16pub struct ExponentialSampler {
17 dist: Exp<f64>,
18}
19
20impl DurationSampler for ExponentialSampler {
21 fn sample(&mut self, rng: &mut dyn Rng, _current_tick: SimTime) -> PendingDuration {
22 PendingDuration::new(self.dist.sample(rng))
23 }
24}
25
26impl ExponentialSampler {
27 pub fn new(lambda: f64) -> Result<Self, ExpError> {
30 Exp::new(lambda).map(|dist| ExponentialSampler { dist })
31 }
32}
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37 use rand::SeedableRng;
38 use rand::rngs::SmallRng;
39
40 #[test]
41 fn test_new_valid_lambda() {
42 let lambda = 0.5;
43 let sampler = ExponentialSampler::new(lambda);
44 assert!(sampler.is_ok());
45 }
46
47 #[test]
48 fn test_new_invalid_lambda() {
49 let lambda = -0.5;
50 let sampler = ExponentialSampler::new(lambda);
51 assert_eq!(sampler.err(), Some(ExpError::LambdaTooSmall));
52
53 let lambda = f64::NAN;
54 let sampler = ExponentialSampler::new(lambda);
55 assert_eq!(sampler.err(), Some(ExpError::LambdaTooSmall));
56 }
57
58 #[test]
59 fn test_sample_produces_positive_duration() {
60 let lambda = 1.0;
61 let mut sampler = ExponentialSampler::new(lambda).unwrap();
62 let mut rng = SmallRng::seed_from_u64(2);
63 let current_tick = SimTime::from_ticks(0);
64
65 for _ in 0..1000 {
66 let duration = sampler.sample(&mut rng, current_tick);
67 assert!(duration.raw_value() > 0.0);
68 }
69 }
70
71 #[test]
72 fn test_sample_with_different_lambda() {
73 let lambda_high = 10.0; let mut sampler_high = ExponentialSampler::new(lambda_high).unwrap();
75 let mut rng_high = SmallRng::seed_from_u64(2);
76 let current_tick = SimTime::from_ticks(0);
77
78 let mut sum_high = 0.0;
79 for _ in 0..1000 {
80 sum_high += sampler_high.sample(&mut rng_high, current_tick).raw_value();
81 }
82 let avg_high = sum_high / 1000.0;
83 assert!(avg_high > 0.05 && avg_high < 0.2); let lambda_low = 0.1; let mut sampler_low = ExponentialSampler::new(lambda_low).unwrap();
88 let mut rng_low = SmallRng::seed_from_u64(2);
89
90 let mut sum_low = 0.0;
91 for _ in 0..1000 {
92 sum_low += sampler_low.sample(&mut rng_low, current_tick).raw_value();
93 }
94 let avg_low = sum_low / 1000.0;
95 assert!(avg_low > 5.0 && avg_low < 15.0); assert!(avg_high < avg_low);
100 }
101}