use std::f64::INFINITY;
use serde::{Deserialize, Serialize};
use crate::input_modeling::dynamic_rng::SimulationRng;
use crate::input_modeling::dyn_rng;
use crate::models::{DevsModel, Model, ModelMessage, ModelRecord, Reportable};
use crate::utils::errors::SimulationError;
use crate::utils::set_panic_hook;
pub mod coupling;
pub mod services;
pub mod web;
pub use self::coupling::{Connector, Message};
pub use self::services::Services;
pub use self::web::Simulation as WebSimulation;
#[derive(Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Simulation {
models: Vec<Model>,
connectors: Vec<Connector>,
messages: Vec<Message>,
services: Services,
}
impl Simulation {
pub fn post(models: Vec<Model>, connectors: Vec<Connector>) -> Self {
set_panic_hook();
Self {
models,
connectors,
..Self::default()
}
}
pub fn post_with_rng(
models: Vec<Model>,
connectors: Vec<Connector>,
global_rng: impl SimulationRng + 'static,
) -> Self {
set_panic_hook();
Self {
models,
connectors,
services: Services {
global_rng: dyn_rng(global_rng),
global_time: 0.0,
},
..Self::default()
}
}
pub fn set_rng(&mut self, rng: impl SimulationRng + 'static) {
self.services.global_rng = dyn_rng(rng)
}
pub fn put(&mut self, models: Vec<Model>, connectors: Vec<Connector>) {
self.models = models;
self.connectors = connectors;
}
pub fn get_messages(&self) -> &Vec<Message> {
&self.messages
}
pub fn get_global_time(&self) -> f64 {
self.services.global_time()
}
pub fn get_status(&self, model_id: &str) -> Result<String, SimulationError> {
Ok(self
.models
.iter()
.find(|model| model.id() == model_id)
.ok_or(SimulationError::ModelNotFound)?
.status())
}
pub fn get_records(&self, model_id: &str) -> Result<&Vec<ModelRecord>, SimulationError> {
Ok(self
.models
.iter()
.find(|model| model.id() == model_id)
.ok_or(SimulationError::ModelNotFound)?
.records())
}
pub fn reset(&mut self) {
self.reset_messages();
self.reset_global_time();
}
pub fn reset_messages(&mut self) {
self.messages = Vec::new();
}
pub fn reset_global_time(&mut self) {
self.services.set_global_time(0.0);
}
pub fn models(&mut self) -> Vec<&mut Model> {
self.models.iter_mut().collect()
}
fn get_message_target_ids(&self, source_id: &str, source_port: &str) -> Vec<String> {
self.connectors
.iter()
.filter_map(|connector| {
if connector.source_id() == source_id && connector.source_port() == source_port {
Some(connector.target_id().to_string())
} else {
None
}
})
.collect()
}
fn get_message_target_ports(&self, source_id: &str, source_port: &str) -> Vec<String> {
self.connectors
.iter()
.filter_map(|connector| {
if connector.source_id() == source_id && connector.source_port() == source_port {
Some(connector.target_port().to_string())
} else {
None
}
})
.collect()
}
pub fn inject_input(&mut self, message: Message) {
self.messages.push(message);
}
pub fn step(&mut self) -> Result<Vec<Message>, SimulationError> {
let messages = self.messages.clone();
let mut next_messages: Vec<Message> = Vec::new();
if !messages.is_empty() {
(0..self.models.len()).try_for_each(|model_index| -> Result<(), SimulationError> {
let model_messages: Vec<ModelMessage> = messages
.iter()
.filter_map(|message| {
if message.target_id() == self.models[model_index].id() {
Some(ModelMessage {
port_name: message.target_port().to_string(),
content: message.content().to_string(),
})
} else {
None
}
})
.collect();
model_messages
.iter()
.try_for_each(|model_message| -> Result<(), SimulationError> {
self.models[model_index].events_ext(model_message, &mut self.services)
})
})?;
}
let until_next_event: f64;
if self.messages.is_empty() {
until_next_event = self.models().iter().fold(INFINITY, |min, model| {
f64::min(min, model.until_next_event())
});
} else {
until_next_event = 0.0;
}
self.models().iter_mut().for_each(|model| {
model.time_advance(until_next_event);
});
self.services
.set_global_time(self.services.global_time() + until_next_event);
let errors: Result<Vec<()>, SimulationError> = (0..self.models.len())
.map(|model_index| -> Result<(), SimulationError> {
if self.models[model_index].until_next_event() == 0.0 {
self.models[model_index]
.events_int(&mut self.services)?
.iter()
.for_each(|outgoing_message| {
let target_ids = self.get_message_target_ids(
self.models[model_index].id(), &outgoing_message.port_name, );
let target_ports = self.get_message_target_ports(
self.models[model_index].id(), &outgoing_message.port_name, );
target_ids.iter().zip(target_ports.iter()).for_each(
|(target_id, target_port)| {
next_messages.push(Message::new(
self.models[model_index].id().to_string(),
outgoing_message.port_name.clone(),
target_id.clone(),
target_port.clone(),
self.services.global_time(),
outgoing_message.content.clone(),
));
},
);
});
}
Ok(())
})
.collect();
errors?;
self.messages = next_messages;
Ok(self.get_messages().clone())
}
pub fn step_until(&mut self, until: f64) -> Result<Vec<Message>, SimulationError> {
let mut message_records: Vec<Message> = Vec::new();
loop {
self.step()?;
if self.services.global_time() < until {
message_records.extend(self.get_messages().clone());
} else {
break;
}
}
Ok(message_records)
}
pub fn step_n(&mut self, n: usize) -> Result<Vec<Message>, SimulationError> {
let mut message_records: Vec<Message> = Vec::new();
(0..n)
.map(|_| -> Result<Vec<Message>, SimulationError> {
self.step()?;
message_records.extend(self.messages.clone());
Ok(Vec::new())
})
.find(Result::is_err)
.unwrap_or(Ok(message_records))
}
}