pecos_core/sims_rngs/
sim_rng.rs

1// Copyright 2024 The PECOS Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4// in compliance with the License.You may obtain a copy of the License at
5//
6//     https://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software distributed under the License
9// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10// or implied. See the License for the specific language governing permissions and limitations under
11// the License.
12
13use crate::sims_rngs::choices::Choices;
14use core::fmt::Debug;
15use rand::distributions::{Bernoulli, Distribution};
16use rand::{RngCore, SeedableRng};
17
18/// Represents the minimal interface needed for simulations.
19/// This trait also allows the blanket implementation provided by Rng to be overridden in favor of
20/// potentially more efficient implementations.
21pub trait SimRng: RngCore + SeedableRng + Debug {
22    /// Generate a single bool where true has a probability of `p`.
23    #[inline]
24    fn gen_bool(&mut self, p: f64) -> bool {
25        Bernoulli::new(p)
26            .expect("Failed to create Bernoulli distribution due to invalid probability")
27            .sample(self)
28    }
29
30    /// Generates a vector of bools, where true has an independent probability of `p`.
31    #[inline]
32    fn gen_bools(&mut self, p: f64, n: usize) -> Vec<bool> {
33        let bernoulli = Bernoulli::new(p)
34            .expect("Failed to create Bernoulli distribution due to invalid probability");
35        (0..n).map(|_| bernoulli.sample(self)).collect()
36    }
37
38    /// Gives true and false each with probability of 50%
39    #[inline]
40    #[allow(clippy::cast_possible_wrap, clippy::as_conversions)]
41    fn coin_flip(&mut self) -> bool {
42        (self.next_u32() as i32) < 0
43    }
44
45    /// Choose between options given a weighted probabilities.
46    #[inline]
47    fn choose_weighted<'a, T>(&mut self, choices: &'a Choices<T>) -> &'a T {
48        choices.sample(self)
49    }
50
51    #[inline]
52    #[must_use]
53    fn from_entropy() -> Self {
54        SeedableRng::from_entropy()
55    }
56}