rant_simulator/simulate/period/
mod.rs1#[cfg(test)]
2mod test;
3
4pub struct SimulationOptions {
5 pub iterations: usize,
6 pub max_period: usize,
7 pub delta: f64,
8}
9
10#[derive(Debug, PartialEq)]
11pub enum Cycle<S> {
12 FixedPoint(S),
13 Cycle(Vec<S>),
14 Divergence,
15}
16
17impl<S> Cycle<S>
18where
19 S: Copy,
20{
21 fn from_history(history: &[S], last_encounter: usize) -> Self {
22 let cycle_length = history.len() - last_encounter - 1;
23
24 match cycle_length {
25 0 => Cycle::FixedPoint(history[last_encounter]),
26 _ => Cycle::Cycle(history.iter().skip(last_encounter).copied().collect()),
27 }
28 }
29}
30
31pub fn simulate<State, Parameters>(
32 initial_state: State,
33 parameters: &Parameters,
34 function: impl Fn(State, &Parameters) -> State,
35 distance: impl Fn(&State, &State) -> f64,
36 options: SimulationOptions,
37) -> Cycle<State>
38where
39 State: Default + Copy,
40{
41 let history_length = options.max_period;
42 let mut history = vec![State::default(); history_length];
43 let mut x = initial_state;
44
45 for _ in 0..options.iterations - history_length {
46 x = function(x, parameters);
47 }
48
49 for item in history.iter_mut() {
50 *item = x;
52 x = function(x, parameters);
53 }
54
55 let last_encounter = history
56 .iter()
57 .rev()
58 .take(options.max_period)
59 .position(|h| distance(h, &x) < options.delta)
60 .map(|pos| history_length - pos - 1);
61
62 match last_encounter {
63 Some(last_encounter) => Cycle::from_history(&history, last_encounter),
64 None => Cycle::Divergence, }
66}