use crate::{
ebi_framework::{displayable::Displayable, ebi_command::EbiCommand},
ebi_traits::{
ebi_trait_finite_stochastic_language::EbiTraitFiniteStochasticLanguage,
ebi_trait_stochastic_deterministic_semantics::{
EbiTraitStochasticDeterministicSemantics, StochasticDeterministicSemantics,
},
},
};
use core::hash::Hash;
use ebi_objects::{
Activity, FiniteStochasticLanguage,
anyhow::{Result, anyhow},
ebi_arithmetic::{Fraction, One, OneMinus, Signed, Zero},
};
use fnv::FnvBuildHasher;
use priority_queue::PriorityQueue;
use std::{
cmp::Ordering,
collections::HashMap,
fmt::{Debug, Display},
ops::{AddAssign, SubAssign},
};
pub trait ProbabilityQueries {
fn analyse_minimum_probability(&self, at_least: &Fraction) -> Result<FiniteStochasticLanguage>;
fn analyse_most_likely_traces(
&self,
number_of_traces: &usize,
) -> Result<FiniteStochasticLanguage>;
fn analyse_probability_coverage(&self, coverage: &Fraction)
-> Result<FiniteStochasticLanguage>;
}
impl ProbabilityQueries for EbiTraitStochasticDeterministicSemantics {
fn analyse_minimum_probability(&self, at_least: &Fraction) -> Result<FiniteStochasticLanguage> {
match self {
EbiTraitStochasticDeterministicSemantics::AutomatonState(sem) => {
sem.analyse_minimum_probability(at_least)
}
EbiTraitStochasticDeterministicSemantics::AutomatonStateDistribution(sem) => {
sem.analyse_minimum_probability(at_least)
}
EbiTraitStochasticDeterministicSemantics::Usize(sem) => {
sem.analyse_minimum_probability(at_least)
}
EbiTraitStochasticDeterministicSemantics::UsizeDistribution(sem) => {
sem.analyse_minimum_probability(at_least)
}
EbiTraitStochasticDeterministicSemantics::LPNMarkingDistribution(sem) => {
sem.analyse_minimum_probability(at_least)
}
EbiTraitStochasticDeterministicSemantics::TreeMarkingDistribution(sem) => {
sem.analyse_minimum_probability(at_least)
}
}
}
fn analyse_most_likely_traces(
&self,
number_of_traces: &usize,
) -> Result<FiniteStochasticLanguage> {
match self {
EbiTraitStochasticDeterministicSemantics::AutomatonState(sem) => {
sem.analyse_most_likely_traces(number_of_traces)
}
EbiTraitStochasticDeterministicSemantics::AutomatonStateDistribution(sem) => {
sem.analyse_most_likely_traces(number_of_traces)
}
EbiTraitStochasticDeterministicSemantics::Usize(sem) => {
sem.analyse_most_likely_traces(number_of_traces)
}
EbiTraitStochasticDeterministicSemantics::UsizeDistribution(sem) => {
sem.analyse_most_likely_traces(number_of_traces)
}
EbiTraitStochasticDeterministicSemantics::LPNMarkingDistribution(sem) => {
sem.analyse_most_likely_traces(number_of_traces)
}
EbiTraitStochasticDeterministicSemantics::TreeMarkingDistribution(sem) => {
sem.analyse_most_likely_traces(number_of_traces)
}
}
}
fn analyse_probability_coverage(
&self,
coverage: &Fraction,
) -> Result<FiniteStochasticLanguage> {
match self {
EbiTraitStochasticDeterministicSemantics::AutomatonState(sem) => {
sem.analyse_probability_coverage(coverage)
}
EbiTraitStochasticDeterministicSemantics::AutomatonStateDistribution(sem) => {
sem.analyse_probability_coverage(coverage)
}
EbiTraitStochasticDeterministicSemantics::Usize(sem) => {
sem.analyse_probability_coverage(coverage)
}
EbiTraitStochasticDeterministicSemantics::UsizeDistribution(sem) => {
sem.analyse_probability_coverage(coverage)
}
EbiTraitStochasticDeterministicSemantics::LPNMarkingDistribution(sem) => {
sem.analyse_probability_coverage(coverage)
}
EbiTraitStochasticDeterministicSemantics::TreeMarkingDistribution(sem) => {
sem.analyse_probability_coverage(coverage)
}
}
}
}
impl ProbabilityQueries for dyn EbiTraitFiniteStochasticLanguage {
fn analyse_most_likely_traces(
&self,
number_of_traces: &usize,
) -> Result<FiniteStochasticLanguage> {
if self.number_of_traces() == 0 {
Ok(FiniteStochasticLanguage::new_with_activity_key(
self.activity_key().clone(),
))
} else if number_of_traces.is_one() {
let mut result = FiniteStochasticLanguage::new_hashmap();
let (mut max_trace, mut max_probability) =
self.iter_traces_probabilities().next().ok_or_else(|| {
anyhow!("Finite stochastic language is empty where it should not.")
})?;
for (trace, probability) in self.iter_traces_probabilities() {
if probability > max_probability {
max_trace = trace;
max_probability = probability;
}
}
result.insert(max_trace.clone(), max_probability.clone());
Ok((self.activity_key().clone(), result).into())
} else {
let mut result = vec![];
for (trace, probability) in self.iter_traces_probabilities() {
match result.binary_search_by(|&(_, cmp_probability): &(_, &Fraction)| {
cmp_probability.cmp(probability)
}) {
Ok(index) => {
if index < number_of_traces - 1 {
result.insert(index, (trace, probability))
}
}
Err(index) => {
if index < number_of_traces - 1 {
result.insert(index, (trace, probability))
}
}
}
}
let mut result2 = FiniteStochasticLanguage::new_hashmap();
for (trace, probability) in result {
result2.insert(trace.clone(), probability.clone());
}
Ok((self.activity_key().clone(), result2).into())
}
}
fn analyse_minimum_probability(&self, at_least: &Fraction) -> Result<FiniteStochasticLanguage> {
let mut result = vec![];
for (trace, probability) in self.iter_traces_probabilities() {
if probability >= at_least {
result.push((trace, probability));
}
}
let mut result2 = FiniteStochasticLanguage::new_hashmap();
for (trace, probability) in result {
result2.insert(trace.clone(), probability.clone());
}
Ok((self.activity_key().clone(), result2).into())
}
fn analyse_probability_coverage(
&self,
coverage: &Fraction,
) -> Result<FiniteStochasticLanguage> {
if coverage.is_zero() {
return Ok((
self.activity_key().clone(),
FiniteStochasticLanguage::new_hashmap(),
)
.into());
} else if self.number_of_traces() == 0 {
return Err(anyhow!(
"A coverage of {:.4} is unattainable as the stochastic language is empty.",
coverage
));
}
let mut result = vec![self.iter_traces_probabilities().next().unwrap()];
let mut sum = result[0].1.clone();
for (trace, probability) in self.iter_traces_probabilities().skip(1) {
if &sum < coverage || probability > result[0].1 {
match result.binary_search_by(|&(_, cmp_probability): &(_, &Fraction)| {
cmp_probability.cmp(probability)
}) {
Ok(index) | Err(index) => result.insert(index, (trace, probability)),
}
sum += probability;
let mut new_sum = &sum - result[0].1;
while &new_sum > coverage {
result.remove(0);
sum = new_sum;
new_sum = &sum - result[0].1;
}
}
}
if &sum < coverage {
return Err(anyhow!(
"A coverage of {:.4} is unattainable as the stochastic language has a sum probability of {:.4}.",
coverage,
sum
));
}
let mut result2 = FiniteStochasticLanguage::new_hashmap();
for (trace, probability) in result {
result2.insert(trace.clone(), probability.clone());
}
Ok((self.activity_key().clone(), result2).into())
}
}
impl<DState: Displayable, LState: Displayable> dyn StochasticDeterministicSemantics<DetState = DState, LivState = LState> {
pub fn iterate_most_likely_traces<F>(
&self,
mut stop: F,
mut sum: MaybeConstant,
mut total_non_livelock_probability: MaybeConstant,
) -> Result<Vec<(Vec<Activity>, Fraction)>>
where
F: FnMut(
&Vec<(Vec<Activity>, Fraction)>,
&Fraction,
&MaybeConstant,
&MaybeConstant,
) -> Result<bool>,
{
let mut queue = PriorityQueue::new();
queue.push(
Z::Prefix(
Fraction::one(),
vec![],
self.get_deterministic_initial_state()?
.ok_or_else(|| anyhow!("Cannot get deterministic initial state."))?,
),
Fraction::one(),
);
let mut s = vec![];
while let Some((z, priority)) = queue.pop() {
match z {
Z::Prefix(prefix_probability, prefix, q_state) => {
if stop(
&s,
&prefix_probability,
&sum,
&total_non_livelock_probability,
)? {
return Ok(s);
}
let termination_probability =
self.get_deterministic_termination_probability(&q_state);
log::debug!("\ttermination probability {:.4}", termination_probability);
if termination_probability.is_positive() {
let mut trace_probability = termination_probability;
trace_probability *= &prefix_probability;
queue.push(Z::Trace(prefix.clone()), trace_probability);
log::debug!(
"\tpush trace of length {} to queue, queue length {}",
prefix.len(),
queue.len()
);
}
let enabled_activities = self.get_deterministic_enabled_activities(&q_state);
log::debug!("\tenabled activities: {}", enabled_activities.len());
for activity in enabled_activities {
log::debug!(
"\t\tconsider activity {:?} {}",
activity,
self.activity_key().deprocess_activity(&activity)
);
let new_q_state =
self.execute_deterministic_activity(&q_state, activity)?;
log::debug!("\t\tq-state after activity {:?}", new_q_state);
let livelock_probability = self
.get_deterministic_non_decreasing_livelock_probability(
&mut new_q_state.clone(),
)?;
if !livelock_probability.is_one() {
let probability_activity =
self.get_deterministic_activity_probability(&q_state, activity);
let mut new_probability = prefix_probability.clone();
new_probability *= probability_activity;
let mut new_prefix = prefix.clone();
new_prefix.push(activity);
let mut new_priority = new_probability.clone();
new_priority *= livelock_probability.one_minus();
queue.push(
Z::Prefix(new_probability, new_prefix, new_q_state),
new_priority,
);
log::debug!("\t\t\tpush prefix to queue, queue length {}", queue.len());
} else {
total_non_livelock_probability -= &prefix_probability;
}
}
}
Z::Trace(trace) => {
if stop(&s, &priority, &sum, &total_non_livelock_probability)? {
return Ok(s);
}
sum += &priority;
s.push((trace, priority));
}
}
}
Ok(s)
}
}
#[derive(Debug)]
pub enum Z<FS: Hash + Display + Debug + Clone + Eq> {
Prefix(Fraction, Vec<Activity>, FS),
Trace(Vec<Activity>),
}
impl<FS: Hash + Display + Debug + Clone + Eq> Eq for Z<FS> {}
impl<FS: Hash + Display + Debug + Clone + Eq> PartialEq for Z<FS> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Prefix(_, l0, _), Self::Prefix(_, r0, _)) => l0 == r0,
(Self::Trace(l0), Self::Trace(r0)) => l0 == r0,
_ => false,
}
}
}
impl<FS: Hash + Display + Debug + Clone + Eq> Hash for Z<FS> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
Z::Prefix(_, t, _) => t.hash(state),
Z::Trace(t) => t.hash(state),
}
}
}
pub enum MaybeConstant {
Some(Fraction),
None(Fraction),
}
impl MaybeConstant {
pub fn fraction(&self) -> &Fraction {
match &self {
MaybeConstant::Some(fraction) => fraction,
MaybeConstant::None(fraction) => fraction,
}
}
pub fn some_zero() -> MaybeConstant {
Self::Some(Fraction::zero())
}
pub fn some_one() -> MaybeConstant {
Self::Some(Fraction::one())
}
pub fn none_zero() -> MaybeConstant {
Self::None(Fraction::zero())
}
pub fn none_one() -> MaybeConstant {
Self::None(Fraction::one())
}
}
impl AddAssign<&Fraction> for MaybeConstant {
fn add_assign(&mut self, rhs: &Fraction) {
match self {
MaybeConstant::Some(fraction) => *fraction += rhs,
MaybeConstant::None(_) => {}
}
}
}
impl SubAssign<&Fraction> for MaybeConstant {
fn sub_assign(&mut self, rhs: &Fraction) {
match self {
MaybeConstant::Some(fraction) => *fraction -= rhs,
MaybeConstant::None(_) => {}
}
}
}
impl PartialEq<Fraction> for MaybeConstant {
fn eq(&self, other: &Fraction) -> bool {
match self {
MaybeConstant::Some(fraction) => fraction.eq(other),
MaybeConstant::None(fraction) => fraction.eq(other),
}
}
}
impl PartialOrd<Fraction> for MaybeConstant {
fn partial_cmp(&self, other: &Fraction) -> Option<Ordering> {
match self {
MaybeConstant::Some(fraction) => fraction.partial_cmp(other),
MaybeConstant::None(fraction) => fraction.partial_cmp(other),
}
}
}
impl<DState: Displayable, LState: Displayable> ProbabilityQueries
for dyn StochasticDeterministicSemantics<DetState = DState, LivState = LState>
{
fn analyse_minimum_probability(&self, at_least: &Fraction) -> Result<FiniteStochasticLanguage> {
if !at_least.is_positive() && self.infinitely_many_traces()? {
return Err(anyhow!(
"All traces were requested, but as the model has infinitely many traces, this is impossible."
));
}
let progress_bar = EbiCommand::get_progress_bar_message(
"found 0 traces; lowest considered prefix probability 0.0000000".to_owned(),
);
let s = self.iterate_most_likely_traces(
|s, prefix_probability, _, _| {
progress_bar.set_message(format!(
"found {} traces; lowest considered prefix probability {:.8}",
s.len(),
prefix_probability
));
Ok(prefix_probability < at_least)
},
MaybeConstant::none_zero(),
MaybeConstant::none_one(),
)?;
progress_bar.finish_and_clear();
let map: HashMap<_, _, FnvBuildHasher> = s.into_iter().collect();
Ok((self.activity_key().clone(), map).into())
}
fn analyse_most_likely_traces(
&self,
number_of_traces: &usize,
) -> Result<FiniteStochasticLanguage> {
let progress_bar = EbiCommand::get_progress_bar_ticks(*number_of_traces);
let mut last_number_of_traces = 0;
let s = self.iterate_most_likely_traces(
|s, _, _, _| {
if last_number_of_traces != s.len() {
progress_bar.set_position(s.len().try_into().unwrap());
last_number_of_traces = s.len();
}
Ok(s.len() >= *number_of_traces)
},
MaybeConstant::none_zero(),
MaybeConstant::none_one(),
)?;
progress_bar.finish_and_clear();
let map: HashMap<_, _, FnvBuildHasher> = s.into_iter().collect();
Ok((self.activity_key().clone(), map).into())
}
fn analyse_probability_coverage(
&self,
coverage: &Fraction,
) -> Result<FiniteStochasticLanguage> {
if !coverage.is_positive() {
return Ok(HashMap::new().into());
}
if coverage > &Fraction::one() {
return Err(anyhow!("A coverage of {} is unattainable.", coverage));
}
let progress_bar = EbiCommand::get_progress_bar_message(
"found 0 traces, which cover 0.0000000".to_owned(),
);
let mut last_number_of_traces = 0;
let s = self.iterate_most_likely_traces(
|s, _, sum, total_non_livelock_probability| {
if last_number_of_traces != s.len() {
progress_bar.set_message(format!(
"found {} traces, which cover {:.8}",
s.len(),
sum.fraction()
));
last_number_of_traces = s.len();
}
if total_non_livelock_probability < coverage {
Err(anyhow!("A probability coverage of {} was requested, but only {} is available due to livelocks.", coverage, total_non_livelock_probability.fraction()))
} else {
Ok(sum >= coverage)
}
},
MaybeConstant::some_zero(),
MaybeConstant::some_one(),
)?;
progress_bar.finish_and_clear();
let map: HashMap<_, _, FnvBuildHasher> = s.into_iter().collect();
Ok((self.activity_key().clone(), map).into())
}
}
#[cfg(test)]
mod tests {
use crate::{
ebi_framework::trait_importers::ToStochasticDeterministicSemanticsTrait,
ebi_traits::{
ebi_trait_finite_stochastic_language::EbiTraitFiniteStochasticLanguage,
ebi_trait_stochastic_deterministic_semantics::{
EbiTraitStochasticDeterministicSemantics, StochasticDeterministicSemantics,
},
},
semantics::labelled_petri_net_semantics::LPNMarking,
stochastic_deterministic_semantics::deterministic_semantics_for_stochastic_semantics::PMarking,
techniques::probability_queries::ProbabilityQueries,
};
use ebi_objects::{
EventLogXes, FiniteStochasticLanguage, HasActivityKey, NumberOfTraces,
StochasticDeterministicFiniteAutomaton, StochasticLabelledPetriNet,
ebi_arithmetic::{Fraction, One, Zero, f},
};
use std::fs;
#[test]
fn slpn_cover_prefix() {
let fin = fs::read_to_string("testfiles/aa-aaa-bb.slpn").unwrap();
let mut slpn: Box<
dyn StochasticDeterministicSemantics<
DetState = PMarking<LPNMarking>,
LivState = LPNMarking,
>,
> = Box::new(fin.parse::<StochasticLabelledPetriNet>().unwrap());
let state1 = slpn.get_deterministic_initial_state().unwrap().unwrap();
let enabled1 = slpn.get_deterministic_enabled_activities(&state1);
assert_eq!(enabled1.len(), 2);
let a = slpn.activity_key_mut().process_activity("a");
let state2 = slpn.execute_deterministic_activity(&state1, a).unwrap();
let enabled2 = slpn.get_deterministic_enabled_activities(&state2);
assert_eq!(enabled2.len(), 1);
let state3 = slpn.execute_deterministic_activity(&state2, a).unwrap();
assert_eq!(state3.p_marking.len(), 2);
assert_eq!(
slpn.get_deterministic_termination_probability(&state3),
Fraction::from((1, 10))
);
assert_eq!(
slpn.analyse_probability_coverage(&Fraction::from((1, 1)))
.unwrap()
.number_of_traces(),
3
);
}
#[test]
fn slpn_cover_bs() {
let fin = fs::read_to_string("testfiles/infinite_bs.slpn").unwrap();
let slpn: Box<
dyn StochasticDeterministicSemantics<
DetState = PMarking<LPNMarking>,
LivState = LPNMarking,
>,
> = Box::new(fin.parse::<StochasticLabelledPetriNet>().unwrap());
assert_eq!(
slpn.analyse_probability_coverage(&Fraction::from((4, 10)))
.unwrap()
.number_of_traces(),
1
);
}
#[test]
fn slpn_minprob_bs() {
let fin = fs::read_to_string("testfiles/infinite_bs.slpn").unwrap();
let slpn: Box<
dyn StochasticDeterministicSemantics<
DetState = PMarking<LPNMarking>,
LivState = LPNMarking,
>,
> = Box::new(fin.parse::<StochasticLabelledPetriNet>().unwrap());
assert_eq!(
slpn.analyse_minimum_probability(&Fraction::from((51, 100)))
.unwrap()
.number_of_traces(),
0
);
}
#[test]
fn slpn_cover_silent_livelock() {
let fin = fs::read_to_string("testfiles/livelock_empty_lang_multiple_silent.slpn").unwrap();
let slpn: Box<
dyn StochasticDeterministicSemantics<
DetState = PMarking<LPNMarking>,
LivState = LPNMarking,
>,
> = Box::new(fin.parse::<StochasticLabelledPetriNet>().unwrap());
let slang2 = slpn
.analyse_probability_coverage(&Fraction::zero())
.unwrap();
assert_eq!(slang2.number_of_traces(), 0);
}
#[test]
fn slpn_cover_empty_net() {
let fin = fs::read_to_string("testfiles/empty_net.slpn").unwrap();
let slpn = Box::new(fin.parse::<StochasticLabelledPetriNet>().unwrap());
let state = slpn.get_deterministic_initial_state().unwrap().unwrap();
assert_eq!(slpn.get_deterministic_enabled_activities(&state).len(), 0);
let slpn: Box<
dyn StochasticDeterministicSemantics<
DetState = PMarking<LPNMarking>,
LivState = LPNMarking,
>,
> = Box::new(fin.parse::<StochasticLabelledPetriNet>().unwrap());
let slang2 = slpn
.analyse_probability_coverage(&Fraction::zero())
.unwrap();
assert_eq!(slang2.number_of_traces(), 0);
let fin2 = fs::read_to_string("testfiles/empty_trace.slang").unwrap();
let slang3 = fin2.parse::<FiniteStochasticLanguage>().unwrap();
assert_eq!(
slpn.analyse_probability_coverage(&Fraction::from((1, 2)))
.unwrap(),
slang3
);
}
#[test]
fn slpn_cover_infinite_bs() {
let fin = fs::read_to_string("testfiles/infinite_bs.slpn").unwrap();
let slpn: Box<
dyn StochasticDeterministicSemantics<
DetState = PMarking<LPNMarking>,
LivState = LPNMarking,
>,
> = Box::new(fin.parse::<StochasticLabelledPetriNet>().unwrap());
let state1 = slpn.get_deterministic_initial_state().unwrap().unwrap();
let enabled1 = slpn.get_deterministic_enabled_activities(&state1);
assert_eq!(enabled1.len(), 2);
}
#[test]
fn slpn_empty_lang_labelled_cover() {
let fin = fs::read_to_string("testfiles/livelock_empty_lang_labelled.slpn").unwrap();
let slpn = Box::new(fin.parse::<StochasticLabelledPetriNet>().unwrap());
let state = slpn.get_deterministic_initial_state().unwrap().unwrap();
assert_eq!(slpn.get_deterministic_enabled_activities(&state).len(), 1);
assert_eq!(
slpn.get_deterministic_termination_probability(&state),
Fraction::zero()
);
let slpn: Box<
dyn StochasticDeterministicSemantics<
DetState = PMarking<LPNMarking>,
LivState = LPNMarking,
>,
> = slpn;
let slang2 = slpn
.analyse_probability_coverage(&Fraction::zero())
.unwrap();
assert_eq!(slang2.number_of_traces(), 0);
let fin2 = fs::read_to_string("testfiles/empty.slang").unwrap();
let slang3 = fin2.parse::<FiniteStochasticLanguage>().unwrap();
assert_eq!(
slpn.analyse_probability_coverage(&Fraction::from((1, 2)))
.unwrap(),
slang3
);
}
#[test]
fn slpn_empty_lang_silent_cover() {
let fin = fs::read_to_string("testfiles/livelock_empty_lang_silent.slpn").unwrap();
let slpn = Box::new(fin.parse::<StochasticLabelledPetriNet>().unwrap());
let state = slpn.get_deterministic_initial_state().unwrap().unwrap();
assert_eq!(slpn.get_deterministic_enabled_activities(&state).len(), 0);
assert_eq!(
slpn.get_deterministic_termination_probability(&state),
Fraction::zero()
);
let slpn: Box<
dyn StochasticDeterministicSemantics<
DetState = PMarking<LPNMarking>,
LivState = LPNMarking,
>,
> = slpn;
let slang2 = slpn
.analyse_probability_coverage(&Fraction::zero())
.unwrap();
assert_eq!(slang2.number_of_traces(), 0);
let fin2 = fs::read_to_string("testfiles/empty.slang").unwrap();
let slang3 = fin2.parse::<FiniteStochasticLanguage>().unwrap();
assert_eq!(
slpn.analyse_probability_coverage(&Fraction::zero())
.unwrap(),
slang3
);
}
#[test]
fn slpn_cover_nothing() {
let fin = fs::read_to_string("testfiles/aa-ab-ba_ali.slpn").unwrap();
let slpn: Box<
dyn StochasticDeterministicSemantics<
DetState = PMarking<LPNMarking>,
LivState = LPNMarking,
>,
> = Box::new(fin.parse::<StochasticLabelledPetriNet>().unwrap());
let slang2 = slpn
.analyse_probability_coverage(&Fraction::zero())
.unwrap();
assert_eq!(slang2.number_of_traces(), 0);
}
#[test]
fn slang_cover_empty() {
let fin = fs::read_to_string("testfiles/empty.slang").unwrap();
let slang: Box<dyn EbiTraitFiniteStochasticLanguage> =
Box::new(fin.parse::<FiniteStochasticLanguage>().unwrap());
let slang2 = slang
.analyse_probability_coverage(&Fraction::zero())
.unwrap();
assert_eq!(slang2.number_of_traces(), 0);
let slang3 = slang.analyse_probability_coverage(&Fraction::one());
assert!(slang3.is_err());
assert!(
slang
.analyse_probability_coverage(&Fraction::from((1, 2)))
.is_err()
);
}
#[test]
fn slpn_cover_empty() {
let fin = fs::read_to_string("testfiles/livelock_empty_lang_labelled.slpn").unwrap();
let slpn: Box<
dyn StochasticDeterministicSemantics<
DetState = PMarking<LPNMarking>,
LivState = LPNMarking,
>,
> = Box::new(fin.parse::<StochasticLabelledPetriNet>().unwrap());
let slang2 = slpn
.analyse_probability_coverage(&Fraction::zero())
.unwrap();
assert_eq!(slang2.number_of_traces(), 0);
}
#[test]
fn slpn_minprob_livelock() {
let fin = fs::read_to_string("testfiles/a-b-c-livelock.slpn").unwrap();
let slpn = fin.parse::<StochasticLabelledPetriNet>().unwrap();
let x: Box<
dyn StochasticDeterministicSemantics<
DetState = PMarking<LPNMarking>,
LivState = LPNMarking,
>,
> = Box::new(slpn);
let slang1 = x
.analyse_minimum_probability(&Fraction::from((1, 5)))
.unwrap();
let fin2 = fs::read_to_string("testfiles/a-b-c-livelock.slang").unwrap();
let slang2 = fin2.parse::<FiniteStochasticLanguage>().unwrap();
assert_eq!(slang1, slang2);
}
#[test]
fn slang_minprob_one_deterministic() {
let fin = fs::read_to_string("testfiles/aa-ab-ba.slang").unwrap();
let slang = fin.parse::<FiniteStochasticLanguage>().unwrap();
let semantics = slang.to_stochastic_deterministic_semantics_trait();
assert_eq!(
semantics
.analyse_minimum_probability(&Fraction::one())
.unwrap()
.number_of_traces(),
0
);
}
#[test]
fn slang_minprob_one() {
let fin = fs::read_to_string("testfiles/aa-ab-ba.slang").unwrap();
let slang = fin.parse::<FiniteStochasticLanguage>().unwrap();
let slang2: &dyn EbiTraitFiniteStochasticLanguage = &slang;
assert_eq!(
slang2
.analyse_minimum_probability(&Fraction::one())
.unwrap()
.number_of_traces(),
0
);
}
#[test]
fn slang_minprob_zero() {
let fin = fs::read_to_string("testfiles/aa-ab-ba.slang").unwrap();
let slang = fin.parse::<FiniteStochasticLanguage>().unwrap();
let slang2: &dyn EbiTraitFiniteStochasticLanguage = &slang;
let slang3 = slang2
.analyse_minimum_probability(&Fraction::zero())
.unwrap();
assert_eq!(slang, slang3)
}
#[test]
fn slang_minprob_zero_through_sdfa() {
let fin = fs::read_to_string("testfiles/aa-ab-ba.slang").unwrap();
let slang = fin.parse::<FiniteStochasticLanguage>().unwrap();
assert_eq!(slang.number_of_traces(), 3);
let mut sdfa: StochasticDeterministicFiniteAutomaton = slang.clone().into();
assert_eq!(sdfa.terminating_probabilities.len(), 6);
assert_eq!(sdfa.sources.len(), 5);
let state = sdfa.get_deterministic_initial_state().unwrap().unwrap();
assert_eq!(state.0, 0);
assert_eq!(sdfa.get_deterministic_enabled_activities(&state).len(), 2);
let b = sdfa.activity_key_mut().process_activity("a");
sdfa.execute_deterministic_activity(&state, b).unwrap();
let semantics = EbiTraitStochasticDeterministicSemantics::AutomatonState(Box::new(sdfa));
let slang2 = semantics
.analyse_minimum_probability(&Fraction::zero())
.unwrap();
assert_eq!(slang, slang2)
}
#[test]
fn sdfa_minprob_one() {
let fin = fs::read_to_string("testfiles/aa-ab-ba.sdfa").unwrap();
let sdfa = fin
.parse::<StochasticDeterministicFiniteAutomaton>()
.unwrap();
let semantics = sdfa.to_stochastic_deterministic_semantics_trait();
assert_eq!(
semantics
.analyse_minimum_probability(&Fraction::one())
.unwrap()
.number_of_traces(),
0
);
}
#[test]
fn sdfa_minprob_zero() {
let fin = fs::read_to_string("testfiles/aa-ab-ba.sdfa").unwrap();
let sdfa = fin
.parse::<StochasticDeterministicFiniteAutomaton>()
.unwrap();
let semantics = sdfa.to_stochastic_deterministic_semantics_trait();
let slang2 = semantics
.analyse_minimum_probability(&Fraction::zero())
.unwrap();
let should_string = fs::read_to_string("testfiles/aa-ab-ba.slang").unwrap();
let should_slang = should_string.parse::<FiniteStochasticLanguage>().unwrap();
assert_eq!(should_slang, slang2)
}
#[test]
fn mode() {
let fin = fs::read_to_string("testfiles/aa-ab-ba_uni.slpn").unwrap();
let slpn = fin.parse::<StochasticLabelledPetriNet>().unwrap();
let x: Box<
dyn StochasticDeterministicSemantics<
DetState = PMarking<LPNMarking>,
LivState = LPNMarking,
>,
> = Box::new(slpn);
let slang = x.analyse_most_likely_traces(&1).unwrap();
let fout = fs::read_to_string("testfiles/ba.slang").unwrap();
assert_eq!(fout, slang.to_string())
}
#[test]
fn convert_converage() {
let fin = fs::read_to_string("testfiles/a-b.xes").unwrap();
let xes = fin.parse::<EventLogXes>().unwrap();
let slang = FiniteStochasticLanguage::from(xes);
let boxx: Box<dyn EbiTraitFiniteStochasticLanguage> = Box::new(slang);
boxx.analyse_probability_coverage(&f!((4, 5))).unwrap();
}
}