use rand::seq::IteratorRandom;
use rand::Rng;
use super::*;
pub trait Oracle<T: time::TimeType> {
fn choose<'e, 't>(
&self,
state: &State<T::Valuations>,
transitions: &'t Vec<Transition<'e, T>>,
) -> &'t Transition<'e, T>;
}
pub struct UniformOracle {}
impl UniformOracle {
pub fn new() -> Self {
UniformOracle {}
}
}
impl<T: time::TimeType> Oracle<T> for UniformOracle {
fn choose<'e, 't>(
&self,
_state: &State<T::Valuations>,
transitions: &'t Vec<Transition<'e, T>>,
) -> &'t Transition<'e, T> {
let mut rng = rand::thread_rng();
transitions.iter().choose(&mut rng).unwrap()
}
}
pub struct InjectionOracle {}
pub struct Simulator<O: Oracle<T>, T: time::TimeType> {
pub(crate) oracle: O,
_phontom_time_type: std::marker::PhantomData<T>,
}
impl<O: Oracle<T>, T: time::TimeType> Simulator<O, T> {
pub fn new(oracle: O) -> Self {
Simulator {
oracle,
_phontom_time_type: std::marker::PhantomData,
}
}
pub fn oracle(&self) -> &O {
&self.oracle
}
pub fn simulate(&self, explorer: &Explorer<T>, steps: usize) {
let mut rng = rand::thread_rng();
let mut state = explorer
.initial_states()
.into_iter()
.choose(&mut rng)
.unwrap();
for _ in 0..steps {
let transition = explorer
.transitions(&state)
.into_iter()
.choose(&mut rng)
.unwrap();
match transition.result_action() {
Action::Silent => println!("τ"),
Action::Labeled(labeled) => println!(
"{} {:?}",
labeled.label(&explorer.network).unwrap(),
labeled.arguments()
),
}
let destinations = explorer.destinations(&state, &transition);
let threshold: f64 = rng.gen();
let mut accumulated = 0.0;
for destination in destinations {
accumulated += destination.probability();
if accumulated >= threshold {
state = explorer.successor(&state, &transition, &destination);
break;
}
}
}
}
}