ebi_objects/conversions/
to_petri_net_markup_language.rs1use crate::ebi_objects::{
2 deterministic_finite_automaton::DeterministicFiniteAutomaton,
3 directly_follows_graph::DirectlyFollowsGraph, directly_follows_model::DirectlyFollowsModel,
4 labelled_petri_net::LabelledPetriNet, petri_net_markup_language::PetriNetMarkupLanguage,
5 process_tree::ProcessTree,
6 stochastic_deterministic_finite_automaton::StochasticDeterministicFiniteAutomaton,
7 stochastic_directly_follows_model::StochasticDirectlyFollowsModel,
8 stochastic_labelled_petri_net::StochasticLabelledPetriNet,
9 stochastic_process_tree::StochasticProcessTree,
10};
11use anyhow::{Error, anyhow};
12use process_mining::{
13 PetriNet,
14 core::process_models::petri_net::{self, ArcType},
15};
16use std::collections::HashMap;
17
18impl TryFrom<&LabelledPetriNet> for process_mining::PetriNet {
19 type Error = anyhow::Error;
20
21 fn try_from(lpn: &LabelledPetriNet) -> std::result::Result<Self, Self::Error> {
22 log::info!("Convert LPN into PNML.");
23
24 let mut result = PetriNet::new();
25
26 let mut place2new_place = HashMap::new();
28 {
29 for place in 0..lpn.get_number_of_places() {
30 let new_place = result.add_place(None);
31 place2new_place.insert(place, new_place);
32 }
33 }
34
35 for transition in 0..lpn.transition2input_places.len() {
37 let new_transition = result.add_transition(
38 match lpn.get_transition_label(transition) {
39 Some(activity) => {
40 Some(lpn.activity_key.get_activity_label(&activity).to_string())
41 }
42 None => None,
43 },
44 None,
45 );
46
47 {
49 let mut map = HashMap::new();
51 for (pos, place) in lpn.transition2input_places[transition].iter().enumerate() {
52 *map.entry(*place).or_insert(0) +=
53 u32::try_from(lpn.transition2input_places_cardinality[transition][pos])?;
54 }
55
56 for (place, weight) in map {
58 let new_place = place2new_place
59 .get(&place)
60 .ok_or(anyhow!("Non-existing place referenced."))?;
61 result.add_arc(
62 ArcType::place_to_transition(*new_place, new_transition),
63 Some(weight),
64 );
65 }
66 }
67
68 {
70 let mut map = HashMap::new();
72 for (pos, place) in lpn.transition2output_places[transition].iter().enumerate() {
73 *map.entry(*place).or_insert(0) +=
74 u32::try_from(lpn.transition2output_places_cardinality[transition][pos])?;
75 }
76
77 for (place, weight) in map {
79 let new_place = place2new_place
80 .get(&place)
81 .ok_or(anyhow!("Non-existing place referenced."))?;
82 result.add_arc(
83 ArcType::transition_to_place(new_transition, *new_place),
84 Some(weight),
86 );
87 }
88 }
89 }
90
91 let mut new_initial_marking = petri_net::Marking::new();
93 for (place, cardinality) in lpn
94 .initial_marking
95 .get_place2token()
96 .into_iter()
97 .enumerate()
98 {
99 if cardinality > &0u64 {
100 let new_place = place2new_place
101 .get(&place)
102 .ok_or(anyhow!("Non-existing place referenced."))?;
103 new_initial_marking.insert(*new_place, *cardinality);
104 }
105 }
106 result.initial_marking = Some(new_initial_marking);
107
108 Ok(result)
109 }
110}
111
112macro_rules! from {
113 ($t:ident) => {
114 impl TryFrom<$t> for process_mining::PetriNet {
115 type Error = Error;
116
117 fn try_from(value: $t) -> Result<Self, Self::Error> {
118 let lpn: LabelledPetriNet = value.into();
119 (&lpn).try_into()
120 }
121 }
122
123 impl TryFrom<$t> for PetriNetMarkupLanguage {
124 type Error = Error;
125
126 fn try_from(value: $t) -> Result<Self, Self::Error> {
127 let lpn: LabelledPetriNet = value.into();
128 Ok(Self(lpn))
129 }
130 }
131 };
132}
133
134from!(StochasticLabelledPetriNet);
135from!(DeterministicFiniteAutomaton);
136from!(DirectlyFollowsModel);
137from!(DirectlyFollowsGraph);
138from!(StochasticDirectlyFollowsModel);
139from!(ProcessTree);
140from!(StochasticProcessTree);
141from!(StochasticDeterministicFiniteAutomaton);