use crate::TransitionSystemGenerator;
use crate::channel_system::{
Channel, ChannelSystem, ChannelSystemBuilder, ChannelSystemRun, Event, EventType,
};
use crate::{DummyRng, Expression, Time, Val, transition_system::TransitionSystem};
#[derive(Debug, Clone)]
pub enum Atom {
State(Channel, usize),
Event(Event),
}
#[derive(Debug, Clone)]
pub struct CsModel {
cs: ChannelSystem,
ports: Vec<Vec<Option<Val>>>,
predicates: Vec<Expression<Atom>>,
}
impl CsModel {
pub fn new(cs: ChannelSystemBuilder) -> Self {
let cs = cs.build();
Self {
ports: cs
.channels()
.iter()
.map(|(types, _)| vec![None; types.len()])
.collect(),
cs,
predicates: Vec::new(),
}
}
pub fn add_port(&mut self, channel: Channel, idx: usize, default: Val) {
self.ports[u16::from(channel) as usize][idx] = Some(default);
}
pub fn add_predicate(&mut self, predicate: Expression<Atom>) -> usize {
let _ = predicate.eval(
&|port| match port {
Atom::State(channel, idx) => self.ports[u16::from(*channel) as usize][*idx]
.expect("port must have been initialized"),
Atom::Event(_event) => Val::Boolean(false),
},
&mut DummyRng,
);
self.predicates.push(predicate);
self.predicates.len() - 1
}
}
impl TransitionSystemGenerator for CsModel {
type Ts<'a>
= CsModelRun<'a>
where
Self: 'a;
fn generate<'a>(&'a self) -> Self::Ts<'a> {
CsModelRun {
cs: self.cs.new_instance(),
ports: self.ports.clone(),
predicates: &self.predicates,
last_event: None,
}
}
}
#[derive(Debug, Clone)]
pub struct CsModelRun<'def> {
cs: ChannelSystemRun<'def>,
ports: Vec<Vec<Option<Val>>>,
predicates: &'def [Expression<Atom>],
last_event: Option<Event>,
}
impl<'def> TransitionSystem for CsModelRun<'def> {
type Event = Event;
fn transition(&mut self) -> Option<Event> {
let event = self.cs.montecarlo_execution();
if let Some(ref event) = event
&& let EventType::Send(ref vals) = event.event_type
{
let port = self
.ports
.get_mut(u16::from(event.channel) as usize)
.expect("port must exist");
port.iter_mut().zip(vals).for_each(|(p, &v)| {
if p.is_some() {
*p = Some(v)
}
});
}
self.last_event = event.clone();
event
}
#[inline]
fn time(&self) -> Time {
self.cs.time()
}
#[inline]
fn time_tick(&mut self) {
self.cs.wait(1).expect("time error")
}
fn labels(&self) -> impl Iterator<Item = bool> {
self.predicates.iter().map(|prop| {
if let Val::Boolean(b) = prop.eval(
&|port| match port {
Atom::State(channel, idx) => self.ports[u16::from(*channel) as usize][*idx]
.expect("port must exist and be initialized"),
Atom::Event(event) => {
Val::Boolean(self.last_event.as_ref().is_some_and(|e| e == event))
}
},
&mut DummyRng,
) {
b
} else {
panic!("propositions should evaluate to boolean values")
}
})
}
#[inline]
fn state(&self) -> impl Iterator<Item = Val> {
self.ports.iter().flat_map(|p| p.iter().filter_map(|p| *p))
}
}