use crate::ebi_objects::{
deterministic_finite_automaton::DeterministicFiniteAutomaton,
directly_follows_graph::DirectlyFollowsGraph, directly_follows_model::DirectlyFollowsModel,
labelled_petri_net::LabelledPetriNet, petri_net_markup_language::PetriNetMarkupLanguage,
process_tree::ProcessTree,
stochastic_deterministic_finite_automaton::StochasticDeterministicFiniteAutomaton,
stochastic_directly_follows_model::StochasticDirectlyFollowsModel,
stochastic_labelled_petri_net::StochasticLabelledPetriNet,
stochastic_process_tree::StochasticProcessTree,
};
use ebi_arithmetic::anyhow::{Error, anyhow};
use process_mining::{
PetriNet,
core::process_models::petri_net::{self, ArcType},
};
use std::collections::HashMap;
impl TryFrom<&LabelledPetriNet> for process_mining::PetriNet {
type Error = Error;
fn try_from(lpn: &LabelledPetriNet) -> std::result::Result<Self, Self::Error> {
log::info!("Convert LPN into PNML.");
if let Some(initial_marking) = &lpn.initial_marking {
let mut result = PetriNet::new();
let mut place2new_place = HashMap::new();
{
for place in 0..lpn.get_number_of_places() {
let new_place = result.add_place(None);
place2new_place.insert(place, new_place);
}
}
for transition in 0..lpn.transition2input_places.len() {
let new_transition = result.add_transition(
match lpn.get_transition_label(transition) {
Some(activity) => {
Some(lpn.activity_key.get_activity_label(&activity).to_string())
}
None => None,
},
None,
);
{
let mut map = HashMap::new();
for (pos, place) in lpn.transition2input_places[transition].iter().enumerate() {
*map.entry(*place).or_insert(0) += u32::try_from(
lpn.transition2input_places_cardinality[transition][pos],
)?;
}
for (place, weight) in map {
let new_place = place2new_place
.get(&place)
.ok_or(anyhow!("Non-existing place referenced."))?;
result.add_arc(
ArcType::place_to_transition(*new_place, new_transition),
Some(weight),
);
}
}
{
let mut map = HashMap::new();
for (pos, place) in lpn.transition2output_places[transition].iter().enumerate()
{
*map.entry(*place).or_insert(0) += u32::try_from(
lpn.transition2output_places_cardinality[transition][pos],
)?;
}
for (place, weight) in map {
let new_place = place2new_place
.get(&place)
.ok_or(anyhow!("Non-existing place referenced."))?;
result.add_arc(
ArcType::transition_to_place(new_transition, *new_place),
Some(weight),
);
}
}
}
let mut new_initial_marking = petri_net::Marking::new();
for (place, cardinality) in initial_marking.get_place2token().into_iter().enumerate() {
if cardinality > &0u64 {
let new_place = place2new_place
.get(&place)
.ok_or(anyhow!("Non-existing place referenced."))?;
new_initial_marking.insert(*new_place, *cardinality);
}
}
result.initial_marking = Some(new_initial_marking);
Ok(result)
} else {
let mut result = PetriNet::new();
result.add_transition(None, None);
Ok(result)
}
}
}
macro_rules! via_lpn {
($t:ident) => {
impl TryFrom<$t> for process_mining::PetriNet {
type Error = Error;
fn try_from(value: $t) -> Result<Self, Self::Error> {
let lpn: LabelledPetriNet = value.into();
(&lpn).try_into()
}
}
impl TryFrom<$t> for PetriNetMarkupLanguage {
type Error = Error;
fn try_from(value: $t) -> Result<Self, Self::Error> {
let lpn: LabelledPetriNet = value.into();
Ok(Self(lpn))
}
}
};
}
via_lpn!(DeterministicFiniteAutomaton);
via_lpn!(DirectlyFollowsGraph);
via_lpn!(DirectlyFollowsModel);
via_lpn!(ProcessTree);
via_lpn!(StochasticDeterministicFiniteAutomaton);
via_lpn!(StochasticDirectlyFollowsModel);
via_lpn!(StochasticLabelledPetriNet);
via_lpn!(StochasticProcessTree);