Skip to main content

pure_stage/simulation/
random.rs

1// Copyright 2025 PRAGMA
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::collections::VecDeque;
16
17use rand::{
18    Rng, SeedableRng,
19    distr::uniform::{SampleRange, SampleUniform},
20    rngs::StdRng,
21};
22
23use crate::{Name, StageResponse};
24
25/// A strategy for making decisions within the simulation run.
26///
27/// While it is possible to use `Arc<Mutex<...>>` to create a shared random number generator,
28/// this is not what the SimulationBuilder is meant for: if you need to share a random number
29/// generator across threads, then the result will not be deterministic.
30pub trait EvalStrategy: Send + 'static {
31    /// pick and remove an element from the queue, which is guaranteed to be non-empty
32    fn pick_runnable(&mut self, runnable: &mut VecDeque<(Name, StageResponse)>) -> (Name, StageResponse);
33}
34
35pub struct Fifo;
36
37impl EvalStrategy for Fifo {
38    fn pick_runnable(&mut self, runnable: &mut VecDeque<(Name, StageResponse)>) -> (Name, StageResponse) {
39        runnable.pop_front().expect("runnable queue is guaranteed to be non-empty")
40    }
41}
42
43pub struct RandStdRng(pub StdRng);
44
45impl RandStdRng {
46    pub fn from_seed(seed: u64) -> Self {
47        RandStdRng(StdRng::seed_from_u64(seed))
48    }
49
50    pub fn derive(&mut self) -> Self {
51        RandStdRng(StdRng::seed_from_u64(self.0.random()))
52    }
53
54    pub fn random_range<T, R>(&mut self, range: R) -> T
55    where
56        T: SampleUniform,
57        R: SampleRange<T>,
58    {
59        self.0.random_range(range)
60    }
61}
62
63impl From<StdRng> for RandStdRng {
64    fn from(rng: StdRng) -> Self {
65        RandStdRng(rng)
66    }
67}
68
69impl EvalStrategy for RandStdRng {
70    fn pick_runnable(&mut self, runnable: &mut VecDeque<(Name, StageResponse)>) -> (Name, StageResponse) {
71        let idx = self.0.random_range(0..runnable.len());
72        runnable.remove(idx).expect("runnable queue is guaranteed to be non-empty")
73    }
74}
75
76impl EvalStrategy for Box<dyn EvalStrategy> {
77    fn pick_runnable(&mut self, runnable: &mut VecDeque<(Name, StageResponse)>) -> (Name, StageResponse) {
78        (**self).pick_runnable(runnable)
79    }
80}