ebi_objects/conversions/
to_petri_net_markup_language.rs

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