Skip to main content

des_sim/modeling/sampler/combinator/
clamp.rs

1//! The `clamp` module provides the `ClampSampler`, a combinator that constrains
2//! the output of another `DurationSampler` within a specified numerical range.
3//!
4//! This ensures that sampled durations do not fall below a minimum value or
5//! exceed a maximum value, which can be useful for maintaining realistic
6//! or valid simulation parameters.
7
8use crate::modeling::sampler::{DurationSampler, PendingDuration};
9use crate::primitive::time::SimTime;
10use rand::Rng;
11
12/// A sampler that clamps the sampled value within the specified [min, max] range.
13#[derive(Debug, Clone)]
14pub struct ClampSampler<S: DurationSampler> {
15    sampler: S,
16    min: f64,
17    max: f64,
18}
19
20impl<S: DurationSampler> DurationSampler for ClampSampler<S> {
21    fn sample(&mut self, rng: &mut dyn Rng, current_tick: SimTime) -> PendingDuration {
22        self.sampler
23            .sample(rng, current_tick)
24            .apply(|v| v.clamp(self.min, self.max))
25    }
26}
27
28impl<S: DurationSampler> ClampSampler<S> {
29    /// Creates a new `ClampSampler` that constrains the output of `sampler`
30    /// between `min` and `max`.
31    pub fn new(sampler: S, min: f64, max: f64) -> Self {
32        ClampSampler { sampler, min, max }
33    }
34}
35
36#[cfg(test)]
37mod tests {
38    use super::*;
39    use crate::modeling::sampler::instance::ConstantSampler;
40    use rand::SeedableRng;
41    use rand::rngs::SmallRng;
42
43    #[test]
44    fn test_clamp_sampler_within_bounds() {
45        let mut rng = SmallRng::seed_from_u64(2);
46        let s = ConstantSampler::new(50.0);
47        let mut sampler = ClampSampler::new(s, 10.0, 100.0);
48
49        let sample = sampler.sample(&mut rng, SimTime::from_ticks(0));
50        assert_eq!(sample.raw_value(), 50.0);
51    }
52
53    #[test]
54    fn test_clamp_sampler_below_min() {
55        let mut rng = SmallRng::seed_from_u64(2);
56        let s = ConstantSampler::new(5.0);
57        let mut sampler = ClampSampler::new(s, 10.0, 100.0);
58
59        let sample = sampler.sample(&mut rng, SimTime::from_ticks(0));
60        assert_eq!(sample.raw_value(), 10.0);
61    }
62
63    #[test]
64    fn test_clamp_sampler_above_max() {
65        let mut rng = SmallRng::seed_from_u64(2);
66        let s = ConstantSampler::new(150.0);
67        let mut sampler = ClampSampler::new(s, 10.0, 100.0);
68
69        let sample = sampler.sample(&mut rng, SimTime::from_ticks(0));
70        assert_eq!(sample.raw_value(), 100.0);
71    }
72}