Skip to main content

ebi_bpmn/
semantics.rs

1use std::fmt::Display;
2
3use crate::{
4    BusinessProcessModelAndNotation,
5    element::BPMNElement,
6    stochastic_business_process_model_and_notation::StochasticBusinessProcessModelAndNotation,
7    traits::{
8        processable::Processable,
9        startable::{InitiationMode, Startable},
10        transitionable::Transitionable,
11    },
12};
13use anyhow::{Result, anyhow};
14use bitvec::bitvec;
15use ebi_activity_key::Activity;
16use ebi_arithmetic::Fraction;
17
18pub type TransitionIndex = usize;
19
20#[derive(Debug, PartialEq, Eq, Clone, Hash)]
21pub struct BPMNMarking {
22    pub(crate) element_index_2_sub_markings: Vec<BPMNSubMarking>,
23    pub(crate) root_marking: BPMNRootMarking,
24}
25
26#[derive(Debug, PartialEq, Eq, Clone, Hash)]
27pub struct BPMNRootMarking {
28    pub(crate) root_initial_choice_token: bool,
29    pub(crate) message_flow_2_tokens: Vec<u64>,
30}
31
32#[derive(Debug, PartialEq, Eq, Hash, Clone)]
33pub struct BPMNSubMarking {
34    pub(crate) sequence_flow_2_tokens: Vec<u64>,
35    pub(crate) initial_choice_token: bool,
36    pub(crate) element_index_2_tokens: Vec<u64>,
37    pub(crate) element_index_2_sub_markings: Vec<Vec<BPMNSubMarking>>,
38}
39
40impl Display for BPMNMarking {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        writeln!(f, "{}", stringify!(self))
43    }
44}
45
46impl BPMNSubMarking {
47    pub(crate) fn new_empty() -> Self {
48        Self {
49            sequence_flow_2_tokens: vec![],
50            initial_choice_token: false,
51            element_index_2_tokens: vec![],
52            element_index_2_sub_markings: vec![],
53        }
54    }
55}
56
57impl BusinessProcessModelAndNotation {
58    /// BPMN 2.0.2 standard page 238
59    pub fn get_initial_marking(&self) -> Result<BPMNMarking> {
60        //gather the initiation mode
61        let mut initiation_mode = InitiationMode::ParallelElements(vec![]);
62        for element in &self.elements {
63            if let BPMNElement::Process(process) = element {
64                initiation_mode = initiation_mode + process.initiation_mode(self)?;
65            }
66        }
67
68        if initiation_mode.is_choice_between_start_events() {
69            let root_marking = BPMNRootMarking {
70                message_flow_2_tokens: vec![0; self.message_flows.len()],
71                root_initial_choice_token: true,
72            };
73
74            let mut element_index_2_sub_markings = Vec::with_capacity(self.elements.len());
75            for element in self.elements.iter() {
76                if let BPMNElement::Process(process) = element {
77                    element_index_2_sub_markings.push(process.to_sub_marking(&initiation_mode)?);
78                } else {
79                    element_index_2_sub_markings.push(BPMNSubMarking::new_empty());
80                }
81            }
82
83            Ok(BPMNMarking {
84                element_index_2_sub_markings,
85                root_marking,
86            })
87        } else {
88            todo!()
89        }
90    }
91
92    pub fn execute_transition(
93        &self,
94        marking: &mut BPMNMarking,
95        mut transition_index: TransitionIndex,
96    ) -> Result<()> {
97        let transition_index_debug = transition_index;
98        let BPMNMarking {
99            element_index_2_sub_markings,
100            root_marking,
101        } = marking;
102        for (element, sub_marking) in self
103            .elements
104            .iter()
105            .zip(element_index_2_sub_markings.iter_mut())
106        {
107            let number_of_transitions = element.number_of_transitions(sub_marking);
108            if transition_index < number_of_transitions {
109                return element.execute_transition(
110                    transition_index,
111                    root_marking,
112                    sub_marking,
113                    self,
114                    self,
115                );
116            }
117            transition_index -= number_of_transitions;
118        }
119        Err(anyhow!(
120            "transition {} is not enabled, as it is unknown",
121            transition_index_debug
122        ))
123    }
124
125    pub fn is_final_marking(&self, marking: &BPMNMarking) -> Result<bool> {
126        Ok(self.get_enabled_transitions(marking)?.is_empty())
127    }
128
129    pub fn is_transition_silent(
130        &self,
131        transition_index: TransitionIndex,
132        marking: &BPMNMarking,
133    ) -> bool {
134        self.get_transition_activity(transition_index, marking)
135            .is_none()
136    }
137
138    pub fn get_transition_activity(
139        &self,
140        mut transition_index: TransitionIndex,
141        marking: &BPMNMarking,
142    ) -> Option<Activity> {
143        for (element, sub_marking) in self
144            .elements
145            .iter()
146            .zip(marking.element_index_2_sub_markings.iter())
147        {
148            let number_of_transitions = element.number_of_transitions(sub_marking);
149            if transition_index < number_of_transitions {
150                return element.transition_activity(transition_index, sub_marking);
151            }
152            transition_index -= number_of_transitions;
153        }
154        None
155    }
156
157    pub fn get_enabled_transitions(&self, marking: &BPMNMarking) -> Result<Vec<TransitionIndex>> {
158        let mut result = bitvec![0;0];
159        for (element, sub_marking) in self
160            .elements
161            .iter()
162            .zip(marking.element_index_2_sub_markings.iter())
163        {
164            result.extend(element.enabled_transitions(
165                &marking.root_marking,
166                sub_marking,
167                self,
168                self,
169            )?);
170        }
171
172        //transform to list of indices
173        let mut result2 = Vec::new();
174        for index in result.iter_ones() {
175            result2.push(index);
176        }
177        Ok(result2)
178    }
179
180    pub fn number_of_transitions(&self, marking: &BPMNMarking) -> usize {
181        let mut result = 0;
182        for (element, sub_marking) in self
183            .elements
184            .iter()
185            .zip(marking.element_index_2_sub_markings.iter())
186        {
187            result += element.number_of_transitions(sub_marking);
188        }
189        result
190    }
191}
192
193impl StochasticBusinessProcessModelAndNotation {
194    /// BPMN 2.0.2 standard page 238
195    pub fn get_initial_marking(&self) -> Result<BPMNMarking> {
196        self.bpmn.get_initial_marking()
197    }
198
199    pub fn execute_transition(
200        &self,
201        marking: &mut BPMNMarking,
202        transition_index: TransitionIndex,
203    ) -> Result<()> {
204        self.bpmn.execute_transition(marking, transition_index)
205    }
206
207    pub fn is_final_marking(&self, marking: &BPMNMarking) -> Result<bool> {
208        self.bpmn.is_final_marking(marking)
209    }
210
211    pub fn is_transition_silent(
212        &self,
213        transition_index: TransitionIndex,
214        marking: &BPMNMarking,
215    ) -> bool {
216        self.bpmn.is_transition_silent(transition_index, marking)
217    }
218
219    pub fn get_transition_activity(
220        &self,
221        transition_index: TransitionIndex,
222        marking: &BPMNMarking,
223    ) -> Option<Activity> {
224        self.bpmn.get_transition_activity(transition_index, marking)
225    }
226
227    pub fn get_enabled_transitions(&self, marking: &BPMNMarking) -> Result<Vec<TransitionIndex>> {
228        self.bpmn.get_enabled_transitions(marking)
229    }
230
231    pub fn number_of_transitions(&self, marking: &BPMNMarking) -> usize {
232        self.bpmn.number_of_transitions(marking)
233    }
234
235    pub fn get_transition_weight(
236        &self,
237        mut transition_index: TransitionIndex,
238        marking: &BPMNMarking,
239    ) -> Option<Fraction> {
240        for (element, sub_marking) in self
241            .bpmn
242            .elements
243            .iter()
244            .zip(marking.element_index_2_sub_markings.iter())
245        {
246            let number_of_transitions = element.number_of_transitions(sub_marking);
247            if transition_index < number_of_transitions {
248                return element.transition_weight(transition_index, sub_marking, &self.bpmn);
249            }
250            transition_index -= number_of_transitions;
251        }
252        None
253    }
254}
255
256#[cfg(test)]
257mod tests {
258    use ebi_arithmetic::{Fraction, One, f};
259
260    use crate::{
261        BusinessProcessModelAndNotation,
262        semantics::{BPMNMarking, BPMNRootMarking, BPMNSubMarking},
263        stochastic_business_process_model_and_notation::StochasticBusinessProcessModelAndNotation,
264    };
265    use std::fs::{self};
266
267    pub fn debug_transitions(bpmn: &BusinessProcessModelAndNotation, marking: &BPMNMarking) {
268        println!("transitions");
269        for transition_index in 0..bpmn.number_of_transitions(&marking) {
270            println!(
271                "\ttransition {} \t {}",
272                transition_index,
273                bpmn.transition_debug(transition_index, marking)
274                    .unwrap_or("None".to_string())
275            );
276        }
277    }
278
279    #[test]
280    fn bpmn_semantics() {
281        let fin = fs::read_to_string("testfiles/model.bpmn").unwrap();
282        let bpmn = fin.parse::<BusinessProcessModelAndNotation>().unwrap();
283
284        let mut marking = bpmn.get_initial_marking().unwrap();
285        assert_eq!(bpmn.number_of_transitions(&marking), 13);
286        debug_transitions(&bpmn, &marking);
287
288        assert_eq!(
289            marking,
290            BPMNMarking {
291                root_marking: BPMNRootMarking {
292                    root_initial_choice_token: true,
293                    message_flow_2_tokens: vec![]
294                },
295                element_index_2_sub_markings: vec![BPMNSubMarking {
296                    sequence_flow_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
297                    initial_choice_token: false,
298                    element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0, 0],
299                    element_index_2_sub_markings: vec![vec![]; 9],
300                }],
301            }
302        );
303        let enabled = bpmn.get_enabled_transitions(&marking).unwrap();
304        assert_eq!(enabled, [0]);
305
306        //execute start event
307        bpmn.execute_transition(&mut marking, 0).unwrap();
308        assert_eq!(
309            marking,
310            BPMNMarking {
311                root_marking: BPMNRootMarking {
312                    root_initial_choice_token: false,
313                    message_flow_2_tokens: vec![]
314                },
315                element_index_2_sub_markings: vec![BPMNSubMarking {
316                    sequence_flow_2_tokens: vec![0, 0, 0, 0, 0, 1, 0, 0, 0, 0],
317                    initial_choice_token: false,
318                    element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0, 0],
319                    element_index_2_sub_markings: vec![vec![]; 9],
320                }],
321            }
322        );
323        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [1]);
324
325        //execute task
326        assert_eq!(
327            bpmn.activity_key
328                .deprocess_activity(&bpmn.get_transition_activity(1, &marking).unwrap()),
329            "Register claim\n(2min)"
330        );
331        bpmn.execute_transition(&mut marking, 1).unwrap();
332        assert_eq!(
333            marking,
334            BPMNMarking {
335                root_marking: BPMNRootMarking {
336                    root_initial_choice_token: false,
337                    message_flow_2_tokens: vec![]
338                },
339                element_index_2_sub_markings: vec![BPMNSubMarking {
340                    sequence_flow_2_tokens: vec![1, 0, 0, 0, 0, 0, 0, 0, 0, 0],
341                    initial_choice_token: false,
342                    element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0, 0],
343                    element_index_2_sub_markings: vec![vec![]; 9],
344                }],
345            }
346        );
347        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [2, 3]);
348
349        //execute XOR split
350        bpmn.is_transition_silent(3, &marking);
351        bpmn.execute_transition(&mut marking, 3).unwrap();
352        assert_eq!(
353            marking,
354            BPMNMarking {
355                root_marking: BPMNRootMarking {
356                    root_initial_choice_token: false,
357                    message_flow_2_tokens: vec![]
358                },
359                element_index_2_sub_markings: vec![BPMNSubMarking {
360                    sequence_flow_2_tokens: vec![0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
361                    initial_choice_token: false,
362                    element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0, 0],
363                    element_index_2_sub_markings: vec![vec![]; 9],
364                }],
365            }
366        );
367        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [5]);
368
369        //execute task
370        assert_eq!(
371            bpmn.activity_key
372                .deprocess_activity(&bpmn.get_transition_activity(5, &marking).unwrap()),
373            "Check easy claim\n(5 min)"
374        );
375        bpmn.execute_transition(&mut marking, 5).unwrap();
376        assert_eq!(
377            marking,
378            BPMNMarking {
379                root_marking: BPMNRootMarking {
380                    root_initial_choice_token: false,
381                    message_flow_2_tokens: vec![]
382                },
383                element_index_2_sub_markings: vec![BPMNSubMarking {
384                    sequence_flow_2_tokens: vec![0, 0, 0, 1, 0, 0, 0, 0, 0, 0],
385                    initial_choice_token: false,
386                    element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0, 0],
387                    element_index_2_sub_markings: vec![vec![]; 9],
388                }],
389            }
390        );
391        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [9, 10]);
392
393        //execute XOR split
394        bpmn.is_transition_silent(9, &marking);
395        bpmn.execute_transition(&mut marking, 9).unwrap();
396        assert_eq!(
397            marking,
398            BPMNMarking {
399                root_marking: BPMNRootMarking {
400                    root_initial_choice_token: false,
401                    message_flow_2_tokens: vec![]
402                },
403                element_index_2_sub_markings: vec![BPMNSubMarking {
404                    sequence_flow_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
405                    initial_choice_token: false,
406                    element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0, 0],
407                    element_index_2_sub_markings: vec![vec![]; 9],
408                }],
409            }
410        );
411        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [7]);
412
413        //execute XOR join
414        bpmn.is_transition_silent(7, &marking);
415        bpmn.execute_transition(&mut marking, 7).unwrap();
416        assert_eq!(
417            marking,
418            BPMNMarking {
419                root_marking: BPMNRootMarking {
420                    root_initial_choice_token: false,
421                    message_flow_2_tokens: vec![]
422                },
423                element_index_2_sub_markings: vec![BPMNSubMarking {
424                    sequence_flow_2_tokens: vec![0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
425                    initial_choice_token: false,
426                    element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0, 0],
427                    element_index_2_sub_markings: vec![vec![]; 9],
428                }],
429            }
430        );
431        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [8]);
432        assert!(!bpmn.is_final_marking(&marking).unwrap());
433
434        //execute end event
435        bpmn.is_transition_silent(8, &marking);
436        bpmn.execute_transition(&mut marking, 8).unwrap();
437        assert_eq!(
438            marking,
439            BPMNMarking {
440                root_marking: BPMNRootMarking {
441                    root_initial_choice_token: false,
442                    message_flow_2_tokens: vec![]
443                },
444                element_index_2_sub_markings: vec![BPMNSubMarking {
445                    sequence_flow_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
446                    initial_choice_token: false,
447                    element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0, 0],
448                    element_index_2_sub_markings: vec![vec![]; 9],
449                }],
450            }
451        );
452        assert_eq!(
453            bpmn.get_enabled_transitions(&marking).unwrap(),
454            Vec::<usize>::new()
455        );
456        assert!(bpmn.is_final_marking(&marking).unwrap());
457    }
458
459    #[test]
460    fn bpmn_lanes_semantics() {
461        let fin = fs::read_to_string("testfiles/model-lanes.bpmn").unwrap();
462        let bpmn = fin.parse::<BusinessProcessModelAndNotation>().unwrap();
463
464        let mut marking = bpmn.get_initial_marking().unwrap();
465        debug_transitions(&bpmn, &marking);
466
467        assert_eq!(
468            marking,
469            BPMNMarking {
470                root_marking: BPMNRootMarking {
471                    root_initial_choice_token: true,
472                    message_flow_2_tokens: vec![0]
473                },
474                element_index_2_sub_markings: vec![
475                    BPMNSubMarking::new_empty(),
476                    BPMNSubMarking {
477                        sequence_flow_2_tokens: vec![0, 0, 0, 0, 0, 0, 0],
478                        initial_choice_token: false,
479                        element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0],
480                        element_index_2_sub_markings: vec![vec![]; 8],
481                    }
482                ],
483            }
484        );
485        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [1, 6]);
486
487        //execute start event
488        bpmn.is_transition_silent(1, &marking);
489        bpmn.execute_transition(&mut marking, 1).unwrap();
490        assert_eq!(
491            marking,
492            BPMNMarking {
493                root_marking: BPMNRootMarking {
494                    root_initial_choice_token: false,
495                    message_flow_2_tokens: vec![0]
496                },
497                element_index_2_sub_markings: vec![
498                    BPMNSubMarking::new_empty(),
499                    BPMNSubMarking {
500                        sequence_flow_2_tokens: vec![1, 0, 0, 0, 0, 0, 0],
501                        initial_choice_token: false,
502                        element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0],
503                        element_index_2_sub_markings: vec![vec![]; 8],
504                    }
505                ],
506            }
507        );
508        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [0]);
509
510        //start expanded sub-process
511        bpmn.is_transition_silent(0, &marking);
512        bpmn.execute_transition(&mut marking, 0).unwrap();
513        assert_eq!(
514            marking,
515            BPMNMarking {
516                root_marking: BPMNRootMarking {
517                    root_initial_choice_token: false,
518                    message_flow_2_tokens: vec![0]
519                },
520                element_index_2_sub_markings: vec![
521                    BPMNSubMarking::new_empty(),
522                    BPMNSubMarking {
523                        sequence_flow_2_tokens: vec![0, 0, 0, 0, 0, 0, 0],
524                        initial_choice_token: false,
525                        element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0],
526                        element_index_2_sub_markings: vec![
527                            vec![BPMNSubMarking {
528                                sequence_flow_2_tokens: vec![0, 0],
529                                initial_choice_token: true,
530                                element_index_2_tokens: vec![0, 0, 0],
531                                element_index_2_sub_markings: vec![vec![]; 3]
532                            }],
533                            vec![],
534                            vec![],
535                            vec![],
536                            vec![],
537                            vec![],
538                            vec![],
539                            vec![],
540                        ],
541                    }
542                ],
543            }
544        );
545        debug_transitions(&bpmn, &marking);
546        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [2]);
547
548        //execute start event
549        bpmn.is_transition_silent(2, &marking);
550        bpmn.execute_transition(&mut marking, 2).unwrap();
551        assert_eq!(
552            marking,
553            BPMNMarking {
554                root_marking: BPMNRootMarking {
555                    root_initial_choice_token: false,
556                    message_flow_2_tokens: vec![0]
557                },
558                element_index_2_sub_markings: vec![
559                    BPMNSubMarking::new_empty(),
560                    BPMNSubMarking {
561                        sequence_flow_2_tokens: vec![0, 0, 0, 0, 0, 0, 0],
562                        initial_choice_token: false,
563                        element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0],
564                        element_index_2_sub_markings: vec![
565                            vec![BPMNSubMarking {
566                                sequence_flow_2_tokens: vec![1, 0],
567                                initial_choice_token: false,
568                                element_index_2_tokens: vec![0, 0, 0],
569                                element_index_2_sub_markings: vec![vec![]; 3]
570                            }],
571                            vec![],
572                            vec![],
573                            vec![],
574                            vec![],
575                            vec![],
576                            vec![],
577                            vec![],
578                        ],
579                    }
580                ],
581            }
582        );
583        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [3]);
584
585        // execute task
586        assert_eq!(
587            bpmn.activity_key
588                .deprocess_activity(&bpmn.get_transition_activity(3, &marking).unwrap()),
589            ""
590        );
591        assert!(!bpmn.is_transition_silent(3, &marking));
592        bpmn.execute_transition(&mut marking, 3).unwrap();
593        assert_eq!(
594            marking,
595            BPMNMarking {
596                root_marking: BPMNRootMarking {
597                    root_initial_choice_token: false,
598                    message_flow_2_tokens: vec![0]
599                },
600                element_index_2_sub_markings: vec![
601                    BPMNSubMarking::new_empty(),
602                    BPMNSubMarking {
603                        sequence_flow_2_tokens: vec![0, 0, 0, 0, 0, 0, 0],
604                        initial_choice_token: false,
605                        element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0],
606                        element_index_2_sub_markings: vec![
607                            vec![BPMNSubMarking {
608                                sequence_flow_2_tokens: vec![0, 1],
609                                initial_choice_token: false,
610                                element_index_2_tokens: vec![0, 0, 0],
611                                element_index_2_sub_markings: vec![vec![]; 3]
612                            }],
613                            vec![],
614                            vec![],
615                            vec![],
616                            vec![],
617                            vec![],
618                            vec![],
619                            vec![],
620                        ],
621                    }
622                ],
623            }
624        );
625        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [4]);
626
627        //execute end event
628        assert!(bpmn.is_transition_silent(4, &marking));
629        bpmn.execute_transition(&mut marking, 4).unwrap();
630        assert_eq!(
631            marking,
632            BPMNMarking {
633                root_marking: BPMNRootMarking {
634                    root_initial_choice_token: false,
635                    message_flow_2_tokens: vec![0]
636                },
637                element_index_2_sub_markings: vec![
638                    BPMNSubMarking::new_empty(),
639                    BPMNSubMarking {
640                        sequence_flow_2_tokens: vec![0, 0, 0, 0, 0, 0, 0],
641                        initial_choice_token: false,
642                        element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0],
643                        element_index_2_sub_markings: vec![
644                            vec![BPMNSubMarking {
645                                sequence_flow_2_tokens: vec![0, 0],
646                                initial_choice_token: false,
647                                element_index_2_tokens: vec![0, 0, 0],
648                                element_index_2_sub_markings: vec![vec![]; 3]
649                            }],
650                            vec![],
651                            vec![],
652                            vec![],
653                            vec![],
654                            vec![],
655                            vec![],
656                            vec![],
657                        ],
658                    }
659                ],
660            }
661        );
662        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [1]);
663
664        //execute termination of sub-process
665        assert!(bpmn.is_transition_silent(1, &marking));
666        bpmn.execute_transition(&mut marking, 1).unwrap();
667        assert_eq!(
668            marking,
669            BPMNMarking {
670                root_marking: BPMNRootMarking {
671                    root_initial_choice_token: false,
672                    message_flow_2_tokens: vec![0]
673                },
674                element_index_2_sub_markings: vec![
675                    BPMNSubMarking::new_empty(),
676                    BPMNSubMarking {
677                        sequence_flow_2_tokens: vec![0, 0, 1, 1, 0, 0, 0],
678                        initial_choice_token: false,
679                        element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0],
680                        element_index_2_sub_markings: vec![
681                            vec![],
682                            vec![],
683                            vec![],
684                            vec![],
685                            vec![],
686                            vec![],
687                            vec![],
688                            vec![],
689                        ],
690                    }
691                ],
692            }
693        );
694        debug_transitions(&bpmn, &marking);
695        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [2, 5]);
696
697        //execute collapsed sub-process
698        assert_eq!(
699            bpmn.activity_key
700                .deprocess_activity(&bpmn.get_transition_activity(5, &marking).unwrap()),
701            ""
702        );
703        bpmn.execute_transition(&mut marking, 5).unwrap();
704        assert_eq!(
705            marking,
706            BPMNMarking {
707                root_marking: BPMNRootMarking {
708                    root_initial_choice_token: false,
709                    message_flow_2_tokens: vec![0]
710                },
711                element_index_2_sub_markings: vec![
712                    BPMNSubMarking::new_empty(),
713                    BPMNSubMarking {
714                        sequence_flow_2_tokens: vec![0, 0, 1, 0, 0, 0, 1],
715                        initial_choice_token: false,
716                        element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0],
717                        element_index_2_sub_markings: vec![
718                            vec![],
719                            vec![],
720                            vec![],
721                            vec![],
722                            vec![],
723                            vec![],
724                            vec![],
725                            vec![],
726                        ],
727                    }
728                ],
729            }
730        );
731        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [2, 8]);
732
733        //execute message end event
734        assert!(bpmn.is_transition_silent(8, &marking));
735        bpmn.execute_transition(&mut marking, 8).unwrap();
736        assert_eq!(
737            marking,
738            BPMNMarking {
739                root_marking: BPMNRootMarking {
740                    root_initial_choice_token: false,
741                    message_flow_2_tokens: vec![0]
742                },
743                element_index_2_sub_markings: vec![
744                    BPMNSubMarking::new_empty(),
745                    BPMNSubMarking {
746                        sequence_flow_2_tokens: vec![0, 0, 1, 0, 0, 0, 0],
747                        initial_choice_token: false,
748                        element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0],
749                        element_index_2_sub_markings: vec![
750                            vec![],
751                            vec![],
752                            vec![],
753                            vec![],
754                            vec![],
755                            vec![],
756                            vec![],
757                            vec![],
758                        ],
759                    }
760                ],
761            }
762        );
763        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [2]);
764
765        // execute collapsed sub-process
766        assert_eq!(
767            bpmn.activity_key
768                .deprocess_activity(&bpmn.get_transition_activity(2, &marking).unwrap()),
769            "collapsed subprocess"
770        );
771        bpmn.execute_transition(&mut marking, 2).unwrap();
772        assert_eq!(
773            marking,
774            BPMNMarking {
775                root_marking: BPMNRootMarking {
776                    root_initial_choice_token: false,
777                    message_flow_2_tokens: vec![0]
778                },
779                element_index_2_sub_markings: vec![
780                    BPMNSubMarking::new_empty(),
781                    BPMNSubMarking {
782                        sequence_flow_2_tokens: vec![0, 1, 0, 0, 0, 0, 0],
783                        initial_choice_token: false,
784                        element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0],
785                        element_index_2_sub_markings: vec![
786                            vec![],
787                            vec![],
788                            vec![],
789                            vec![],
790                            vec![],
791                            vec![],
792                            vec![],
793                            vec![],
794                        ],
795                    }
796                ],
797            }
798        );
799        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [4]);
800
801        //execute end event
802        assert!(bpmn.is_transition_silent(4, &marking));
803        bpmn.execute_transition(&mut marking, 4).unwrap();
804        assert_eq!(
805            marking,
806            BPMNMarking {
807                root_marking: BPMNRootMarking {
808                    root_initial_choice_token: false,
809                    message_flow_2_tokens: vec![0]
810                },
811                element_index_2_sub_markings: vec![
812                    BPMNSubMarking::new_empty(),
813                    BPMNSubMarking {
814                        sequence_flow_2_tokens: vec![0, 0, 0, 0, 0, 0, 0],
815                        initial_choice_token: false,
816                        element_index_2_tokens: vec![0, 0, 0, 0, 0, 0, 0, 0],
817                        element_index_2_sub_markings: vec![
818                            vec![],
819                            vec![],
820                            vec![],
821                            vec![],
822                            vec![],
823                            vec![],
824                            vec![],
825                            vec![],
826                        ],
827                    }
828                ],
829            }
830        );
831
832        assert!(bpmn.is_final_marking(&marking).unwrap());
833    }
834
835    #[test]
836    fn bpmn_or_import() {
837        let fin = fs::read_to_string("testfiles/and-a-b-xor-c-or.sbpmn").unwrap();
838        let bpmn = fin
839            .parse::<StochasticBusinessProcessModelAndNotation>()
840            .unwrap();
841
842        let mut marking = bpmn.get_initial_marking().unwrap();
843        debug_transitions(&bpmn.bpmn, &marking);
844        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [0]);
845        assert_eq!(
846            bpmn.get_transition_weight(0, &marking).unwrap(),
847            Fraction::one()
848        );
849
850        bpmn.execute_transition(&mut marking, 0).unwrap();
851        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [1]);
852        assert_eq!(
853            bpmn.get_transition_weight(1, &marking).unwrap(),
854            Fraction::one()
855        );
856
857        bpmn.execute_transition(&mut marking, 1).unwrap();
858        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [2, 3]);
859        assert_eq!(
860            bpmn.get_transition_weight(3, &marking).unwrap(),
861            Fraction::one()
862        );
863        assert_eq!(
864            bpmn.get_transition_weight(2, &marking).unwrap(),
865            Fraction::one()
866        );
867
868        bpmn.execute_transition(&mut marking, 2).unwrap();
869        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [3]);
870        assert_eq!(
871            bpmn.get_transition_weight(3, &marking).unwrap(),
872            Fraction::one()
873        );
874
875        bpmn.execute_transition(&mut marking, 3).unwrap();
876        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [4, 5]);
877        assert_eq!(bpmn.get_transition_weight(4, &marking).unwrap(), f!(1, 3));
878        assert_eq!(bpmn.get_transition_weight(5, &marking).unwrap(), f!(2, 3));
879
880        bpmn.execute_transition(&mut marking, 4).unwrap();
881        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [6, 7]);
882        assert_eq!(
883            bpmn.get_transition_weight(6, &marking).unwrap(),
884            Fraction::one()
885        );
886        assert_eq!(
887            bpmn.get_transition_weight(7, &marking).unwrap(),
888            Fraction::one()
889        );
890
891        bpmn.execute_transition(&mut marking, 6).unwrap();
892        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [7, 9]);
893        assert_eq!(
894            bpmn.get_transition_weight(7, &marking).unwrap(),
895            Fraction::one()
896        );
897        assert_eq!(
898            bpmn.get_transition_weight(9, &marking).unwrap(),
899            Fraction::one()
900        );
901
902        bpmn.execute_transition(&mut marking, 7).unwrap();
903        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [8, 9]);
904        assert_eq!(
905            bpmn.get_transition_weight(8, &marking).unwrap(),
906            Fraction::one()
907        );
908        assert_eq!(
909            bpmn.get_transition_weight(9, &marking).unwrap(),
910            Fraction::one()
911        );
912
913        bpmn.execute_transition(&mut marking, 8).unwrap();
914        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [9]);
915        assert_eq!(
916            bpmn.get_transition_weight(9, &marking).unwrap(),
917            Fraction::one()
918        );
919
920        bpmn.execute_transition(&mut marking, 9).unwrap();
921        assert_eq!(bpmn.get_enabled_transitions(&marking).unwrap(), [0; 0]);
922        assert!(bpmn.is_final_marking(&marking).unwrap());
923    }
924}