use super::ebi_trait_finite_language::EbiTraitFiniteLanguage;
use crate::{
ebi_framework::{
ebi_command::EbiCommand, ebi_input::EbiInput, ebi_trait::FromEbiTraitObject,
ebi_trait_object::EbiTraitObject, trait_importers::ToQueriableStochasticLanguageTrait,
},
follower_semantics::FollowerSemantics,
};
use ebi_objects::{
ActivityKeyTranslator, CompressedEventLog, DirectlyFollowsGraph, EventLog, EventLogPython,
EventLogTraceAttributes, EventLogXes, FiniteStochasticLanguage, HasActivityKey, Importable,
StochasticDirectlyFollowsModel, StochasticLabelledPetriNet,
anyhow::{Context, Error, Result, anyhow},
ebi_arithmetic::{Fraction, Zero},
ebi_objects::{
compressed_event_log_trace_attributes::CompressedEventLogTraceAttributes,
event_log_csv::EventLogCsv, event_log_ocel::EventLogOcel,
},
};
use std::sync::{Arc, Mutex};
pub trait EbiTraitQueriableStochasticLanguage: HasActivityKey + Sync {
fn get_probability(&self, follower: &FollowerSemantics) -> Result<Fraction>;
fn get_probability_language(
&mut self,
log: Box<dyn EbiTraitFiniteLanguage>,
) -> Result<Fraction> {
let translator = ActivityKeyTranslator::new(log.activity_key(), self.activity_key_mut());
let progress_bar = EbiCommand::get_progress_bar_ticks(log.number_of_traces());
let error: Arc<Mutex<Option<Error>>> = Arc::new(Mutex::new(None));
let sum = log
.iter_traces()
.filter_map(|log_trace| {
let trace = translator.translate_trace(log_trace);
let c = self
.get_probability(&FollowerSemantics::Trace(&trace))
.with_context(|| format!("cannot compute probability of trace {:?}", trace));
progress_bar.inc(1);
match c {
Result::Ok(c) => Some(c),
Err(err) => {
let error = Arc::clone(&error);
*error.lock().unwrap() = Some(err);
None
}
}
})
.sum();
progress_bar.finish_and_clear();
if let Result::Ok(mutex) = Arc::try_unwrap(error) {
if let Result::Ok(err) = mutex.into_inner() {
if let Some(err) = err {
return Err(err);
}
}
}
Ok(sum)
}
}
impl FromEbiTraitObject for dyn EbiTraitQueriableStochasticLanguage {
fn from_trait_object(object: EbiInput) -> Result<Box<Self>> {
match object {
EbiInput::Trait(EbiTraitObject::QueriableStochasticLanguage(e), _) => Ok(e),
_ => Err(anyhow!(
"cannot read {} {} as a queriable stochastic language",
object.get_type().get_article(),
object.get_type()
)),
}
}
}
impl EbiTraitQueriableStochasticLanguage for FiniteStochasticLanguage {
fn get_probability(&self, follower: &FollowerSemantics) -> Result<Fraction> {
match follower {
FollowerSemantics::Trace(trace) => {
return match self.traces.get(*trace) {
Some(x) => Ok(x.clone()),
None => Ok(Fraction::zero()),
};
}
}
}
}
impl<T> ToQueriableStochasticLanguageTrait for T
where
T: EbiTraitQueriableStochasticLanguage + Importable + 'static,
{
fn to_queriable_stochastic_language_trait(
self,
) -> Box<dyn EbiTraitQueriableStochasticLanguage> {
Box::new(self)
}
}
macro_rules! queriable_via_slpn {
($t:ident) => {
impl ToQueriableStochasticLanguageTrait for $t {
fn to_queriable_stochastic_language_trait(
self,
) -> Box<dyn EbiTraitQueriableStochasticLanguage> {
let lpn: StochasticLabelledPetriNet = self.into();
Box::new(lpn)
}
}
};
}
macro_rules! queriable_via_slang {
($t:ident) => {
impl ToQueriableStochasticLanguageTrait for $t {
fn to_queriable_stochastic_language_trait(
self,
) -> Box<dyn EbiTraitQueriableStochasticLanguage> {
Box::new(FiniteStochasticLanguage::from(self))
}
}
};
}
queriable_via_slpn!(DirectlyFollowsGraph);
queriable_via_slpn!(StochasticDirectlyFollowsModel);
queriable_via_slang!(EventLog);
queriable_via_slang!(EventLogTraceAttributes);
queriable_via_slang!(CompressedEventLog);
queriable_via_slang!(CompressedEventLogTraceAttributes);
queriable_via_slang!(EventLogXes);
queriable_via_slang!(EventLogCsv);
queriable_via_slang!(EventLogOcel);
queriable_via_slang!(EventLogPython);
#[cfg(test)]
mod tests {
use crate::ebi_traits::ebi_trait_queriable_stochastic_language::EbiTraitQueriableStochasticLanguage;
use ebi_objects::{
FiniteLanguage, StochasticLabelledPetriNet,
ebi_arithmetic::{Fraction, Zero},
};
use std::fs;
#[test]
fn emsc() {
let fin1 = fs::read_to_string("testfiles/aa-ab-ba_ali.slpn").unwrap();
let mut slpn: StochasticLabelledPetriNet =
fin1.parse::<StochasticLabelledPetriNet>().unwrap();
let fin2 = fs::read_to_string("testfiles/aa.lang").unwrap();
let slang2 = Box::new(fin2.parse::<FiniteLanguage>().unwrap());
let probability = slpn.get_probability_language(slang2).unwrap();
assert_eq!(probability, Fraction::zero());
}
}