ebi_objects/conversions/
to_business_process_model_and_notation.rs1use crate::{
2 DeterministicFiniteAutomaton, DirectlyFollowsGraph, DirectlyFollowsModel, LabelledPetriNet, PetriNetMarkupLanguage, ProcessTree, ProcessTreeMarkupLanguage, StochasticDeterministicFiniteAutomaton, StochasticDirectlyFollowsModel, StochasticLabelledPetriNet, StochasticNondeterministicFiniteAutomaton, StochasticProcessTree
3};
4use ebi_bpmn::{
5 BusinessProcessModelAndNotation,
6 creator::{BPMNCreator, GatewayType},
7};
8
9impl From<LabelledPetriNet> for BusinessProcessModelAndNotation {
10 fn from(value: LabelledPetriNet) -> Self {
11 let mut c = BPMNCreator::new();
12 let process = c.add_process();
13
14 let mut place_2_xor_gateway = vec![];
16 for _ in 0..value.get_number_of_places() {
17 place_2_xor_gateway.push(c.add_gateway_unchecked(process, GatewayType::Exclusive));
18 }
19
20 for transition in 0..value.get_number_of_transitions() {
22 let out_1 = value.transition2output_places[transition].len() == 1
24 && value.transition2output_places_cardinality[transition][0] == 1;
25 let in_1 = value.transition2input_places[transition].len() == 1
26 && value.transition2input_places_cardinality[transition][0] == 1;
27
28 if let Some(activity) = value.get_transition_label(transition) {
29 let task = c.add_task_unchecked(process, activity);
31
32 if in_1 {
34 let pre_place =
36 place_2_xor_gateway[value.transition2input_places[transition][0]];
37 c.add_sequence_flow_unchecked(process, pre_place, task);
38 } else {
39 let gateway = c.add_gateway_unchecked(process, GatewayType::Parallel);
41 for (output_place, cardinality) in value.transition2output_places[transition]
42 .iter()
43 .zip(value.transition2output_places_cardinality[transition].iter())
44 {
45 let output_gateway = place_2_xor_gateway[*output_place];
46 for _ in 0..*cardinality {
47 c.add_sequence_flow_unchecked(process, gateway, output_gateway);
48 }
49 }
50 }
51
52 for (output_place, cardinality) in value.transition2output_places[transition]
54 .iter()
55 .zip(value.transition2output_places_cardinality[transition].iter())
56 {
57 let output_gateway = place_2_xor_gateway[*output_place];
58 for _ in 0..*cardinality {
59 c.add_sequence_flow_unchecked(process, task, output_gateway);
60 }
61 }
62 } else {
63 match (in_1, out_1) {
65 (true, true) => {
66 let pre_place =
70 place_2_xor_gateway[value.transition2input_places[transition][0]];
71 let post_place =
72 place_2_xor_gateway[value.transition2output_places[transition][0]];
73 c.add_sequence_flow_unchecked(process, pre_place, post_place);
74 }
75 (true, false) => {
76 let gateway = c.add_gateway_unchecked(process, GatewayType::Parallel);
77
78 for (input_place, cardinality) in value.transition2input_places[transition]
80 .iter()
81 .zip(value.transition2input_places_cardinality[transition].iter())
82 {
83 let input_gateway = place_2_xor_gateway[*input_place];
84 for _ in 0..*cardinality {
85 c.add_sequence_flow_unchecked(process, input_gateway, gateway);
86 }
87 }
88
89 for (output_place, cardinality) in value.transition2output_places
91 [transition]
92 .iter()
93 .zip(value.transition2output_places_cardinality[transition].iter())
94 {
95 let output_gateway = place_2_xor_gateway[*output_place];
96 for _ in 0..*cardinality {
97 c.add_sequence_flow_unchecked(process, gateway, output_gateway);
98 }
99 }
100 }
101 (false, true) => {
102 let gateway = c.add_gateway_unchecked(process, GatewayType::Exclusive);
103
104 for (input_place, cardinality) in value.transition2input_places[transition]
106 .iter()
107 .zip(value.transition2input_places_cardinality[transition].iter())
108 {
109 let input_gateway = place_2_xor_gateway[*input_place];
110 for _ in 0..*cardinality {
111 c.add_sequence_flow_unchecked(process, input_gateway, gateway);
112 }
113 }
114
115 for (output_place, cardinality) in value.transition2output_places
117 [transition]
118 .iter()
119 .zip(value.transition2output_places_cardinality[transition].iter())
120 {
121 let output_gateway = place_2_xor_gateway[*output_place];
122 for _ in 0..*cardinality {
123 c.add_sequence_flow_unchecked(process, gateway, output_gateway);
124 }
125 }
126 }
127 (false, false) => {
128 let input = c.add_gateway_unchecked(process, GatewayType::Exclusive);
130 let output = c.add_gateway_unchecked(process, GatewayType::Parallel);
131 c.add_sequence_flow_unchecked(process, input, output);
132
133 for (input_place, cardinality) in value.transition2input_places[transition]
135 .iter()
136 .zip(value.transition2input_places_cardinality[transition].iter())
137 {
138 let input_gateway = place_2_xor_gateway[*input_place];
139 for _ in 0..*cardinality {
140 c.add_sequence_flow_unchecked(process, input_gateway, input);
141 }
142 }
143
144 for (output_place, cardinality) in value.transition2output_places
146 [transition]
147 .iter()
148 .zip(value.transition2output_places_cardinality[transition].iter())
149 {
150 let output_gateway = place_2_xor_gateway[*output_place];
151 for _ in 0..*cardinality {
152 c.add_sequence_flow_unchecked(process, output, output_gateway);
153 }
154 }
155 }
156 }
157 }
158 }
159
160 c.to_bpmn().unwrap()
162 }
163}
164
165macro_rules! via_lpn {
166 ($t:ident) => {
167 impl From<$t> for BusinessProcessModelAndNotation {
168 fn from(value: $t) -> Self {
169 LabelledPetriNet::from(value).into()
170 }
171 }
172 };
173}
174
175via_lpn!(DeterministicFiniteAutomaton);
176via_lpn!(DirectlyFollowsGraph);
177via_lpn!(DirectlyFollowsModel);
178via_lpn!(StochasticDirectlyFollowsModel);
179via_lpn!(ProcessTree);
180via_lpn!(PetriNetMarkupLanguage);
181via_lpn!(ProcessTreeMarkupLanguage);
182via_lpn!(StochasticProcessTree);
183via_lpn!(StochasticLabelledPetriNet);
184via_lpn!(StochasticDeterministicFiniteAutomaton);
185via_lpn!(StochasticNondeterministicFiniteAutomaton);
186
187#[cfg(test)]
188mod tests {
189 use crate::StochasticLabelledPetriNet;
190 use ebi_bpmn::BusinessProcessModelAndNotation;
191 use std::fs;
192
193 #[test]
194 fn slpn_2_bpmn() {
195 let fin = fs::read_to_string("testfiles/a-aa-bb.slpn").unwrap();
196 let slpn = fin.parse::<StochasticLabelledPetriNet>().unwrap();
197
198 let _bpmn = BusinessProcessModelAndNotation::from(slpn);
199 }
200}