Skip to main content

ebi_objects/conversions/
to_petri_net_markup_language.rs

1use 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        //create places
27        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        //create transitions
36        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            //incoming
48            {
49                //transform to a map of places and arc weights
50                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                //add
57                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            //outgoing
69            {
70                //transform to a map of places and arc weights
71                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                //add
78                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.to_u32().ok_or(anyhow!("value out of bounds"))?),
85                        Some(weight),
86                    );
87                }
88            }
89        }
90
91        //initial marking
92        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);