use rand::rngs::SmallRng;
use crate::{
Expression, Time, TransitionSystem, Val,
program_graph::{
Action, PgExpression, ProgramGraph, ProgramGraphBuilder, ProgramGraphRun, Var,
},
transition_system::TransitionSystemGenerator,
};
#[derive(Debug, Clone)]
pub struct PgModel {
pg: ProgramGraph,
global_vars: Vec<Var>,
predicates: Vec<Expression<Var>>,
}
impl PgModel {
pub fn new(
pg: ProgramGraphBuilder,
global_vars: Vec<Var>,
predicates: Vec<PgExpression>,
) -> Self {
let pg = pg.build();
Self {
pg,
global_vars,
predicates,
}
}
}
impl TransitionSystemGenerator for PgModel {
type Ts<'a>
= PgModelRun<'a>
where
Self: 'a;
fn generate<'a>(&'a self) -> Self::Ts<'a> {
PgModelRun {
pg: self.pg.new_instance(),
rng: rand::make_rng(),
global_vars: &self.global_vars,
predicates: &self.predicates,
time: 0,
}
}
}
#[derive(Debug, Clone)]
pub struct PgModelRun<'def> {
pg: ProgramGraphRun<'def>,
rng: SmallRng,
global_vars: &'def [Var],
predicates: &'def [Expression<Var>],
time: Time,
}
impl<'def> TransitionSystem for PgModelRun<'def> {
type Event = Action;
fn transition(&mut self) -> Option<Action> {
self.pg.montecarlo(&mut self.rng)
}
fn time(&self) -> Time {
self.time
}
fn time_tick(&mut self) {
self.time += 1;
}
fn labels(&self) -> impl Iterator<Item = bool> {
self.predicates.iter().map(|p| {
if let Val::Boolean(b) = self.pg.eval(p) {
b
} else {
panic!("non-bool pred")
}
})
}
fn state(&self) -> impl Iterator<Item = Val> {
self.global_vars
.as_ref()
.iter()
.map(|var| self.pg.val(*var).expect("value"))
}
}