Skip to main content

ebi_objects/ebi_objects/
process_tree.rs

1use super::stochastic_process_tree::StochasticProcessTree;
2#[cfg(any(test, feature = "testactivities"))]
3use crate::activity_key::has_activity_key::TestActivityKey;
4use crate::{
5    Activity, ActivityKey, ActivityKeyTranslator, EbiObject, Exportable, Graphable, HasActivityKey,
6    Importable, Infoable, TranslateActivityKey,
7    ebi_objects::labelled_petri_net::TransitionIndex,
8    line_reader::LineReader,
9    traits::{
10        graphable,
11        importable::{ImporterParameter, ImporterParameterValues, from_string},
12    },
13};
14use anyhow::{Context, Error, Result, anyhow};
15use ebi_derive::ActivityKey;
16use layout::{adt::dag::NodeHandle, topo::layout::VisualGraph};
17use std::{
18    fmt::Display,
19    ops::{Index, IndexMut},
20    str::FromStr,
21};
22use strum::IntoEnumIterator;
23use strum_macros::EnumIter;
24
25pub const HEADER: &str = "process tree";
26
27#[derive(Debug, ActivityKey, Clone)]
28pub struct ProcessTree {
29    pub activity_key: ActivityKey,
30    pub tree: Vec<Node>,
31    pub transition2node: Vec<usize>,
32}
33
34impl ProcessTree {
35    pub fn number_of_leaves(&self) -> usize {
36        self.tree.iter().filter(|node| node.is_leaf()).count()
37    }
38
39    fn node_to_string(
40        &self,
41        indent: usize,
42        node: usize,
43        f: &mut std::fmt::Formatter<'_>,
44    ) -> Result<usize> {
45        let id = "\t".repeat(indent);
46        match &self.tree[node] {
47            Node::Tau => {
48                writeln!(f, "{}tau", id)?;
49                Ok(node + 1)
50            }
51            Node::Activity(activity) => {
52                writeln!(
53                    f,
54                    "{}activity {}",
55                    id,
56                    self.activity_key.get_activity_label(&activity)
57                )?;
58                Ok(node + 1)
59            }
60            Node::Operator(operator, number_of_children) => {
61                writeln!(f, "{}{}", id, operator.to_string())?;
62                writeln!(
63                    f,
64                    "{}# number of children\n{}{}",
65                    id, id, number_of_children
66                )?;
67                let mut child = node + 1;
68                for _ in 0..*number_of_children {
69                    child = self.node_to_string(indent + 1, child, f)?;
70                }
71                Ok(child)
72            }
73        }
74    }
75
76    fn node_to_dot(
77        &self,
78        graph: &mut VisualGraph,
79        node: usize,
80        entry: &NodeHandle,
81        exit: &NodeHandle,
82    ) -> usize {
83        match self.tree[node] {
84            Node::Tau => {
85                graphable::create_edge(graph, entry, exit, "");
86                node + 1
87            }
88            Node::Activity(activity) => {
89                let transition = graphable::create_transition(
90                    graph,
91                    self.activity_key.get_activity_label(&activity),
92                    "",
93                );
94                graphable::create_edge(graph, entry, &transition, "");
95                graphable::create_edge(graph, &transition, exit, "");
96                node + 1
97            }
98            Node::Operator(Operator::Xor, number_of_children) => {
99                let mut child = node + 1;
100                for _ in 0..number_of_children {
101                    child = ProcessTree::node_to_dot(&self, graph, child, entry, exit);
102                }
103                child
104            }
105            Node::Operator(Operator::Sequence, number_of_children) => {
106                let intermediate_nodes = (0..(number_of_children - 1))
107                    .map(|_| graphable::create_dot(graph))
108                    .collect::<Vec<_>>();
109
110                let mut child = node + 1;
111                for i in 0..number_of_children {
112                    let child_entry = if i == 0 {
113                        entry
114                    } else {
115                        &intermediate_nodes[i - 1]
116                    };
117                    let child_exit = if i == number_of_children - 1 {
118                        exit
119                    } else {
120                        &intermediate_nodes[i]
121                    };
122
123                    child = ProcessTree::node_to_dot(&self, graph, child, child_entry, child_exit);
124                }
125                child
126            }
127            Node::Operator(Operator::Concurrent, number_of_children) => {
128                let split = graphable::create_gateway(graph, "+");
129                graphable::create_edge(graph, entry, &split, "");
130                let join = graphable::create_gateway(graph, "+");
131                graphable::create_edge(graph, &join, exit, "");
132
133                let mut child = node + 1;
134                for _ in 0..number_of_children {
135                    child = ProcessTree::node_to_dot(&self, graph, child, &split, &join);
136                }
137                child
138            }
139            Node::Operator(Operator::Or, number_of_children) => {
140                let split = graphable::create_gateway(graph, "o");
141                graphable::create_edge(graph, entry, &split, "");
142                let join = graphable::create_gateway(graph, "o");
143                graphable::create_edge(graph, &join, exit, "");
144
145                let mut child = node + 1;
146                for _ in 0..number_of_children {
147                    child = ProcessTree::node_to_dot(&self, graph, child, &split, &join);
148                }
149                child
150            }
151            Node::Operator(Operator::Interleaved, number_of_children) => {
152                let split = graphable::create_gateway(graph, "↔");
153                graphable::create_edge(graph, entry, &split, "");
154                let join = graphable::create_gateway(graph, "↔");
155                graphable::create_edge(graph, &join, exit, "");
156
157                let mut child = node + 1;
158                for _ in 0..number_of_children {
159                    child = ProcessTree::node_to_dot(&self, graph, child, &split, &join);
160                }
161                child
162            }
163            Node::Operator(Operator::Loop, number_of_children) => {
164                let split = graphable::create_dot(graph);
165                graphable::create_edge(graph, entry, &split, "");
166                let join = graphable::create_dot(graph);
167                graphable::create_edge(graph, &join, exit, "");
168
169                let mut child = node + 1;
170
171                child = ProcessTree::node_to_dot(&self, graph, child, &split, &join);
172
173                if number_of_children == 1 {
174                    graphable::create_edge(graph, &join, &split, "");
175                } else {
176                    for _ in 1..number_of_children {
177                        child = ProcessTree::node_to_dot(&self, graph, child, &join, &split);
178                    }
179                }
180                child
181            }
182        }
183    }
184
185    ///read one node, recursively
186    fn string_to_tree(
187        lreader: &mut LineReader<'_>,
188        tree: &mut Vec<Node>,
189        activity_key: &mut ActivityKey,
190        root: bool,
191    ) -> Result<()> {
192        let node_type_line = match lreader.next_line_string().with_context(|| {
193            format!(
194                "Failed to read node {} at line {}",
195                tree.len(),
196                lreader.get_last_line_number()
197            )
198        }) {
199            Ok(x) => x,
200            Err(e) => {
201                if root {
202                    //The root may be missing: then, we have an empty tree.
203                    return Ok(());
204                } else {
205                    return Err(e);
206                }
207            }
208        };
209
210        if node_type_line.trim_start().starts_with("tau") {
211            tree.push(Node::Tau);
212        } else if node_type_line.trim_start().starts_with("activity ") {
213            let label = node_type_line.trim_start()[9..].to_string();
214            let activity = activity_key.process_activity(&label);
215            tree.push(Node::Activity(activity));
216        } else if let Ok(operator) = node_type_line.trim_start().trim_end().parse::<Operator>() {
217            let number_of_children = lreader.next_line_index().with_context(|| {
218                format!(
219                    "failed to read number of children for node {} at line {}",
220                    tree.len(),
221                    lreader.get_last_line_number()
222                )
223            })?;
224            if number_of_children < 1 {
225                return Err(anyhow!(
226                    "loop node ending at node {} at line {} has no children",
227                    tree.len(),
228                    lreader.get_last_line_number()
229                ));
230            }
231            tree.push(Node::Operator(operator, number_of_children));
232            for _ in 0..number_of_children {
233                Self::string_to_tree(lreader, tree, activity_key, false)?;
234            }
235        } else if root && node_type_line.trim_start().is_empty() {
236            //empty tree
237            return Ok(());
238        } else {
239            return Err(anyhow!(
240                "could not parse type of node {} at line {}. Expected `tau`, `activity`, `concurrent`, `interleaved`, `or`, `sequence` or `xor`",
241                tree.len(),
242                lreader.get_last_line_number()
243            ));
244        }
245
246        Ok(())
247    }
248}
249
250macro_rules! tree {
251    ($t:ident, $u:ident, $v:ident) => {
252        impl $t {
253            pub fn get_number_of_nodes(&self) -> usize {
254                return self.tree.len();
255            }
256
257            pub fn get_node(&self, node: usize) -> Option<&Node> {
258                self.tree.get(node)
259            }
260
261            pub fn root(&self) -> usize {
262                0
263            }
264
265            pub fn get_node_of_transition(&self, transition: TransitionIndex) -> Result<&Node> {
266                self.tree
267                    .get(
268                        *self
269                            .transition2node
270                            .get(transition)
271                            .ok_or_else(|| anyhow!("Transition does not exist."))?,
272                    )
273                    .ok_or_else(|| anyhow!("Node does not exist."))
274            }
275
276            /**
277             * Returns the parent of node. Notice that
278             * this is an expensive operation; avoid if possible.
279             *
280             * @param node
281             * @return The parent of node, and the rank of the child
282             */
283            pub fn get_parent(&self, node: usize) -> Option<(usize, usize)> {
284                if node == 0 {
285                    return None;
286                }
287
288                let mut potential_parent = node - 1;
289                while self.traverse(potential_parent) <= node {
290                    potential_parent -= 1;
291                }
292
293                let child_rank = self.get_child_rank_with(potential_parent, node)?;
294
295                Some((potential_parent, child_rank))
296            }
297
298            /**
299             *
300             * @param parent
301             * @param grandChild
302             * @return The number of the child within parent that contains grandChild.
303             *         If grandChild is not a child of parent, will return -1.
304             */
305            pub fn get_child_rank_with(&self, parent: usize, grand_child: usize) -> Option<usize> {
306                let mut child_rank = 0;
307                for child in self.get_children(parent) {
308                    if self.is_parent_of(child, grand_child) {
309                        return Some(child_rank);
310                    }
311                    child_rank += 1;
312                }
313                None
314            }
315
316            pub fn get_children(&self, node: usize) -> $u<'_> {
317                $u::new(self, node)
318            }
319
320            pub fn get_parents(&self, node: usize) -> $v<'_> {
321                $v::new(self, node)
322            }
323
324            pub fn get_descendants(&self, node: usize) -> &[Node] {
325                let next = self.traverse(node);
326                &self.tree[node..next]
327            }
328
329            /**
330             *
331             * @param parent
332             * @param child
333             * @return Whether the child is a direct or indirect child of parent.
334             */
335            pub fn is_parent_of(&self, parent: usize, child: usize) -> bool {
336                if parent > child {
337                    return false;
338                }
339                return self.traverse(parent) > child;
340            }
341
342            /**
343             * Find the next node of this node: the next sibling, and if that is not available, the next sibling up the tree.
344             * May return a non-existing node if there is no sibling.
345             */
346            pub fn traverse(&self, node: usize) -> usize {
347                match self.tree[node] {
348                    Node::Tau => node + 1,
349                    Node::Activity(_) => node + 1,
350                    Node::Operator(_, number_of_children) => {
351                        let mut n = node + 1;
352                        for _ in 0..number_of_children {
353                            n = self.traverse(n);
354                        }
355                        n
356                    }
357                }
358            }
359
360            pub fn get_child(&self, parent: usize, child_rank: usize) -> usize {
361                let mut i = parent + 1;
362                for _ in 0..child_rank {
363                    i = self.traverse(i);
364                }
365                return i;
366            }
367
368            pub fn get_number_of_children(&self, parent: usize) -> Option<usize> {
369                match self.tree.get(parent)? {
370                    Node::Tau => Some(0),
371                    Node::Activity(_) => Some(0),
372                    Node::Operator(_, number_of_children) => Some(*number_of_children),
373                }
374            }
375
376            pub fn node_to_transition(&self, node: usize) -> Option<usize> {
377                let mut transitions = 0;
378                let mut last = false;
379                for node in self.tree.iter().take(node + 1) {
380                    match node {
381                        Node::Activity(_) | Node::Tau => {
382                            transitions += 1;
383                            last = true
384                        }
385                        _ => last = false,
386                    }
387                }
388
389                if last { Some(transitions - 1) } else { None }
390            }
391        }
392
393        impl TranslateActivityKey for $t {
394            fn translate_using_activity_key(&mut self, to_activity_key: &mut ActivityKey) {
395                let translator = ActivityKeyTranslator::new(&self.activity_key, to_activity_key);
396                self.tree.iter_mut().for_each(|node| {
397                    if let Node::Activity(a) = node {
398                        *a = translator.translate_activity(&a)
399                    }
400                });
401                self.activity_key = to_activity_key.clone();
402            }
403        }
404
405        impl Infoable for $t {
406            fn info(&self, f: &mut impl std::io::Write) -> Result<()> {
407                writeln!(f, "Number of nodes\t\t{}", self.get_number_of_nodes())?;
408                writeln!(
409                    f,
410                    "Number of activities\t\t{}",
411                    $t::activity_key(self).get_number_of_activities()
412                )?;
413
414                writeln!(f, "")?;
415                self.activity_key().info(f)?;
416
417                Ok(writeln!(f, "")?)
418            }
419        }
420
421        impl Graphable for $t {
422            fn to_dot(&self) -> Result<layout::topo::layout::VisualGraph> {
423                let mut graph = VisualGraph::new(layout::core::base::Orientation::LeftToRight);
424                let source = graphable::create_place(&mut graph, "");
425                let sink = graphable::create_place(&mut graph, "");
426                if !self.tree.is_empty() {
427                    $t::node_to_dot(&self, &mut graph, 0, &source, &sink);
428                }
429                Ok(graph)
430            }
431        }
432
433        pub struct $u<'a> {
434            //children iterator
435            tree: &'a $t,
436            node: usize,
437            now: Option<usize>,
438            next: usize,
439            count: usize,
440        }
441
442        impl<'a> $u<'a> {
443            fn new(tree: &'a $t, node: usize) -> Self {
444                Self {
445                    tree: tree,
446                    node: node,
447                    now: None,
448                    next: node + 1,
449                    count: 0,
450                }
451            }
452        }
453
454        impl<'a> Iterator for $u<'a> {
455            type Item = usize;
456
457            fn next(&mut self) -> Option<Self::Item> {
458                if self.count >= self.tree.get_number_of_children(self.node)? {
459                    return None;
460                }
461                self.count += 1;
462                self.now = Some(self.next);
463                self.next = self.tree.traverse(self.now.unwrap());
464                Some(self.now.unwrap())
465            }
466        }
467
468        pub struct $v<'a> {
469            //parents iterator
470            tree: &'a $t,
471            node: Option<(usize, usize)>,
472        }
473
474        impl<'a> $v<'a> {
475            fn new(tree: &'a $t, node: usize) -> Self {
476                Self {
477                    tree: tree,
478                    node: tree.get_parent(node),
479                }
480            }
481        }
482
483        impl<'a> Iterator for $v<'a> {
484            type Item = (usize, usize);
485
486            fn next(&mut self) -> Option<Self::Item> {
487                if let Some((node, child_rank)) = self.node {
488                    self.node = self.tree.get_parent(node);
489
490                    Some((node, child_rank))
491                } else {
492                    None
493                }
494            }
495        }
496    };
497}
498
499tree!(ProcessTree, ChildrenIterator, ParentsIterator);
500tree!(
501    StochasticProcessTree,
502    StochasticChildrenIterator,
503    StochasticParentsIterator
504);
505
506impl Display for ProcessTree {
507    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
508        writeln!(f, "{}", HEADER)?;
509        if !self.tree.is_empty() {
510            let _ = self.node_to_string(0, 0, f);
511        };
512        write!(f, "")
513    }
514}
515
516impl Importable for ProcessTree {
517    const FILE_FORMAT_SPECIFICATION_LATEX: &str = "A process tree is a line-based structure. Lines starting with a \\# are ignored.
518    This first line is exactly `process tree'.
519    The subsequent lines contain the nodes:
520    Each node is either:
521    \\begin{itemize}
522        \\item A line with the word `activity' followed on the same line by a space and the label of the activity leaf;
523        \\item The word `tau';
524        \\item The name of an operator (`sequence', `xor', `concurrent', `loop', `interleaved', or `or') on its own line.
525        The line thereafter contains the number of children of the node, after which the nodes are given.
526        An operator node must have at least one child.
527    \\end{itemize}
528    Indentation of nodes is allowed, but not mandatory.
529    
530    For instance:
531    \\lstinputlisting[language=ebilines, style=boxed]{../testfiles/all_operators.ptree}";
532
533    const IMPORTER_PARAMETERS: &[ImporterParameter] = &[];
534
535    fn import_as_object(
536        reader: &mut dyn std::io::BufRead,
537        parameter_values: &ImporterParameterValues,
538    ) -> Result<EbiObject> {
539        Ok(EbiObject::ProcessTree(Self::import(
540            reader,
541            parameter_values,
542        )?))
543    }
544
545    fn import(reader: &mut dyn std::io::BufRead, _: &ImporterParameterValues) -> Result<Self>
546    where
547        Self: Sized,
548    {
549        let mut lreader = LineReader::new(reader);
550
551        let head = lreader
552            .next_line_string()
553            .with_context(|| format!("failed to read header, which should be {}", HEADER))?;
554        if head != HEADER {
555            return Err(anyhow!(
556                "first line should be exactly `{}`, but found `{}` on line `{}`",
557                HEADER,
558                lreader.get_last_line(),
559                lreader.get_last_line_number()
560            ));
561        }
562
563        let mut activity_key = ActivityKey::new();
564        let mut tree = vec![];
565        Self::string_to_tree(&mut lreader, &mut tree, &mut activity_key, true)?;
566
567        Ok((activity_key, tree).into())
568    }
569}
570from_string!(ProcessTree);
571
572impl Exportable for ProcessTree {
573    fn export_from_object(object: EbiObject, f: &mut dyn std::io::Write) -> Result<()> {
574        match object {
575            EbiObject::ProcessTree(lpn) => lpn.export(f),
576            EbiObject::StochasticProcessTree(lpn) => {
577                <StochasticProcessTree as Into<ProcessTree>>::into(lpn).export(f)
578            }
579            _ => Err(anyhow!(
580                "cannot export {} {} as a process tree",
581                object.get_type().get_article(),
582                object.get_type()
583            )),
584        }
585    }
586
587    fn export(&self, f: &mut dyn std::io::Write) -> Result<()> {
588        Ok(write!(f, "{}", self)?)
589    }
590}
591
592#[derive(Debug, Clone)]
593pub enum Node {
594    Tau,
595    Activity(Activity),
596    Operator(Operator, usize), //type, number of children
597}
598
599impl Node {
600    pub fn is_leaf(&self) -> bool {
601        match self {
602            Self::Tau | Self::Activity(_) => true,
603            Self::Operator(_, _) => false,
604        }
605    }
606
607    pub fn set_number_of_children(&mut self, number_of_children: usize) -> Result<()> {
608        if let Self::Operator(_, old_number_of_children) = self {
609            *old_number_of_children = number_of_children;
610            Ok(())
611        } else {
612            Err(anyhow!(
613                "attempted to alter the number of children of an activity or a tau"
614            ))
615        }
616    }
617}
618
619#[derive(EnumIter, Debug, Clone, Copy)]
620pub enum Operator {
621    Xor,
622    Sequence,
623    Interleaved,
624    Concurrent,
625    Or,
626    Loop,
627}
628
629impl Operator {
630    pub fn to_string(&self) -> &str {
631        match self {
632            Operator::Xor => "xor",
633            Operator::Sequence => "sequence",
634            Operator::Interleaved => "interleaved",
635            Operator::Concurrent => "concurrent",
636            Operator::Or => "or",
637            Operator::Loop => "loop",
638        }
639    }
640}
641
642impl FromStr for Operator {
643    type Err = Error;
644
645    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
646        for op in Operator::iter() {
647            if s == op.to_string() {
648                return Ok(op);
649            }
650        }
651        return Err(anyhow!("operator not recognised"));
652    }
653}
654
655// ======= semantics functions =======
656// Semantics belongs in the Ebi crate, not here in Ebi_objects,
657// however we use them to create a state space in several conversions.
658// As such, its bases functions are here.
659
660#[derive(Clone, strum_macros::Display, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
661pub enum NodeState {
662    Enabled,
663    Started,
664    Closed,
665}
666
667#[derive(Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
668pub struct TreeMarking {
669    pub(crate) terminated: bool,
670    pub(crate) states: Vec<NodeState>,
671}
672
673impl TreeMarking {
674    pub fn get(&self, index: usize) -> Option<&NodeState> {
675        self.states.get(index)
676    }
677}
678
679impl Display for TreeMarking {
680    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
681        write!(f, "{:?}, terminated: {}", self.states, self.terminated)
682    }
683}
684
685impl Index<usize> for TreeMarking {
686    type Output = NodeState;
687
688    fn index(&self, index: usize) -> &Self::Output {
689        self.states.index(index)
690    }
691}
692
693impl IndexMut<usize> for TreeMarking {
694    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
695        self.states.index_mut(index)
696    }
697}
698
699#[macro_export]
700macro_rules! tree_semantics {
701    ($t:ident) => {
702        pub fn get_initial_state(tree: &$t) -> Option<TreeMarking> {
703            if tree.tree.is_empty() {
704                None
705            } else {
706                let mut state = TreeMarking {
707                    states: vec![NodeState::Closed; tree.get_number_of_nodes()],
708                    terminated: false,
709                };
710                enable_node(tree, &mut state, tree.root());
711                Some(state)
712            }
713        }
714
715        /// Returns whether it is possible that this node now terminates (true), or that a leaf has to be executed first (false).
716        pub(crate) fn can_terminate(tree: &$t, state: &TreeMarking, node: usize) -> bool {
717            match tree.tree[node] {
718                Node::Tau => state[node] == NodeState::Closed,
719                Node::Activity(_) => state[node] == NodeState::Closed,
720                Node::Operator(Operator::Concurrent, _)
721                | Node::Operator(Operator::Interleaved, _) => {
722                    //these nodes can terminate if all of their children are either closed or can terminate
723                    tree.get_children(node).all(|child| {
724                        state[child] == NodeState::Closed || can_terminate(tree, state, child)
725                    })
726                }
727                Node::Operator(Operator::Or, _) => {
728                    //an or can terminate if at least one child can terminate, and the others can be withdrawn
729                    let mut one_child_closed = false;
730                    for child in tree.get_children(node) {
731                        if can_terminate(tree, state, child) {
732                            one_child_closed = true;
733                        } else if !can_withdraw_enablement(tree, state, child) {
734                            //if there is one child that is not closed and not withdrawn, we cannot terminate the or
735                            return false;
736                        }
737                    }
738
739                    one_child_closed
740                }
741                Node::Operator(Operator::Loop, number_of_children) => {
742                    let body_child = tree.get_child(node, 0);
743                    if state[node] == NodeState::Closed {
744                        //if the loop is closed, it can terminate
745                        return true;
746                    }
747                    if state[body_child] == NodeState::Enabled {
748                        //the first child is enabled, which means that the loop cannot terminate in this state
749                        return false;
750                    }
751
752                    for child_rank in 1..number_of_children {
753                        let redo_child = tree.get_child(node, child_rank);
754                        //all the redo children must be able to withdraw enablement
755                        if !can_withdraw_enablement(tree, state, redo_child) {
756                            return false;
757                        }
758                    }
759
760                    return true;
761                }
762                Node::Operator(Operator::Sequence, number_of_children) => {
763                    //a sequence node can terminate if all its non-last children are closed and the last child can terminate
764                    for child_rank in 0..number_of_children - 1 {
765                        if state[tree.get_child(node, child_rank)] != NodeState::Closed {
766                            return false;
767                        }
768                    }
769                    can_terminate(tree, state, tree.get_child(node, number_of_children - 1))
770                }
771                Node::Operator(Operator::Xor, _) => {
772                    //an xor can terminate if all of its children are closed or can terminate
773                    tree.get_children(node).all(|child| {
774                        state[child] == NodeState::Closed || can_terminate(tree, state, child)
775                    })
776                }
777            }
778        }
779
780        /**
781         * Returns whether it is possible to withdraw the enablement.
782         */
783        fn can_withdraw_enablement(_tree: &$t, state: &TreeMarking, node: usize) -> bool {
784            state[node] == NodeState::Enabled
785        }
786
787        pub(crate) fn can_execute(tree: &$t, state: &TreeMarking, node: usize) -> bool {
788            match tree.tree.get(node) {
789                Some(Node::Activity(_)) => {}
790                Some(Node::Tau) => {}
791                _ => return false,
792            }
793
794            if let Some(NodeState::Closed) = state.get(node) {
795                return false;
796            }
797            if let Some(NodeState::Started) = state.get(node) {
798                return false;
799            }
800
801            //for every interleaved parent, check whether we're not executing two nodes concurrently
802            let mut previous_parent = node;
803            for (parent, _) in tree.get_parents(node) {
804                if let Some(Node::Operator(Operator::Interleaved, _)) = tree.tree.get(parent) {
805                    //count the number of started children
806                    let started_children = tree.get_children(parent).fold(0, |count, child| {
807                        if state[child] == NodeState::Started && !can_terminate(tree, state, child)
808                        {
809                            count + 1
810                        } else {
811                            count
812                        }
813                    });
814
815                    if started_children == 0 {
816                        //this is the first starting child; no problem
817                    } else if started_children == 1 {
818                        //there is already a child of this interleaved parent started
819                        if state[previous_parent] != NodeState::Started {
820                            //another child already started; this node cannot fire now
821                            return false;
822                        }
823                    } else {
824                        unreachable!()
825                    }
826                }
827
828                previous_parent = parent;
829            }
830
831            true
832        }
833
834        fn enable_node(tree: &$t, state: &mut TreeMarking, node: usize) {
835            state[node] = NodeState::Enabled;
836
837            match tree.tree[node] {
838                Node::Tau => {}
839                Node::Activity(_) => {}
840                Node::Operator(Operator::Concurrent, _)
841                | Node::Operator(Operator::Interleaved, _)
842                | Node::Operator(Operator::Or, _)
843                | Node::Operator(Operator::Xor, _) => {
844                    //enable all children
845                    for child in tree.get_children(node) {
846                        enable_node(tree, state, child);
847                    }
848                }
849                Node::Operator(Operator::Sequence, _) | Node::Operator(Operator::Loop, _) => {
850                    //enable the first child
851                    enable_node(tree, state, tree.get_child(node, 0));
852                }
853            }
854        }
855
856        /// enable the nodes that are sequentially next from this node
857        fn enable_next_sequential_nodes(tree: &$t, state: &mut TreeMarking, node: usize) {
858            if let Some((parent, child_rank)) = tree.get_parent(node) {
859                match tree.tree[parent] {
860                    Node::Tau => unreachable!(),
861                    Node::Activity(_) => unreachable!(),
862                    Node::Operator(Operator::Xor, _) => {
863                        //propagate to parent
864                        enable_next_sequential_nodes(tree, state, parent);
865                    }
866                    Node::Operator(Operator::Concurrent, _)
867                    | Node::Operator(Operator::Or, _)
868                    | Node::Operator(Operator::Interleaved, _) => {
869                        if can_terminate(tree, state, parent) {
870                            //this parent can terminate, so we propagate to parent
871                            enable_next_sequential_nodes(tree, state, parent);
872                        } else {
873                            //this parent cannot yet terminate, so there is nothing to enable
874                        }
875                    }
876                    Node::Operator(Operator::Loop, number_of_children) => {
877                        if child_rank == 0 {
878                            //enable the redo children and the next sequential node
879                            for child_rank in 1..number_of_children {
880                                enable_node(tree, state, tree.get_child(parent, child_rank));
881                            }
882                            enable_next_sequential_nodes(tree, state, parent);
883                        } else {
884                            //we were a redo child, enable the body child
885                            enable_node(tree, state, tree.get_child(parent, 0));
886                        }
887                    }
888                    Node::Operator(Operator::Sequence, number_of_children) => {
889                        if child_rank == number_of_children - 1 {
890                            //this was the last child, the sequence would end here; propagate to parent
891                            enable_next_sequential_nodes(tree, state, parent);
892                        } else {
893                            //enable the next child
894                            enable_node(tree, state, tree.get_child(parent, child_rank + 1));
895                        }
896                    }
897                }
898            }
899        }
900
901        /// withdraws the enablement of the next sequential nodes
902        fn withdraw_enablement_next_sequential_nodes(
903            tree: &$t,
904            state: &mut TreeMarking,
905            node: usize,
906        ) {
907            if let Some((parent, child_rank)) = tree.get_parent(node) {
908                match tree.tree[parent] {
909                    Node::Tau => unreachable!(),
910                    Node::Activity(_) => unreachable!(),
911                    Node::Operator(Operator::Sequence, number_of_children) => {
912                        if child_rank < number_of_children - 1 {
913                            //we were a non-last child; withdraw the enablement of our next sibling
914                            withdraw_enablement(
915                                tree,
916                                state,
917                                tree.get_child(parent, child_rank + 1),
918                            );
919                        } else {
920                            //we are the last child; recurse upwards
921                            withdraw_enablement_next_sequential_nodes(tree, state, parent);
922                        }
923                    }
924                    Node::Operator(Operator::Concurrent, _)
925                    | Node::Operator(Operator::Or, _)
926                    | Node::Operator(Operator::Interleaved, _)
927                    | Node::Operator(Operator::Xor, _) => {
928                        //propagate to parent
929                        withdraw_enablement_next_sequential_nodes(tree, state, parent);
930                    }
931                    Node::Operator(Operator::Loop, number_of_children) => {
932                        if child_rank == 0 {
933                            //we were the body child, withdraw redo children
934                            for child_rank in 1..number_of_children {
935                                withdraw_enablement(
936                                    tree,
937                                    state,
938                                    tree.get_child(parent, child_rank),
939                                );
940                            }
941                        } else {
942                            //we were a redo child, withdraw the body child
943                            withdraw_enablement(tree, state, tree.get_child(parent, 0));
944
945                            //propagate to parent
946                            withdraw_enablement_next_sequential_nodes(tree, state, parent);
947                        }
948                    }
949                }
950            }
951        }
952
953        fn close_node(tree: &$t, state: &mut TreeMarking, node: usize) {
954            //close this node and all of its children
955            for grandchild in node..tree.traverse(node) {
956                state[grandchild] = NodeState::Closed;
957            }
958
959            //this may open another node, based on the operator of the parent
960            if let Some((parent, child_rank)) = tree.get_parent(node) {
961                match tree.tree[parent] {
962                    Node::Tau => unreachable!(),
963                    Node::Activity(_) => unreachable!(),
964                    Node::Operator(Operator::Sequence, number_of_children) => {
965                        //for a sequence parent, we enable the next child
966                        // log::debug!("close node {}, parent is sequence node {}", node, parent);
967                        if child_rank < number_of_children - 1 {
968                            let next_child = tree.get_child(parent, child_rank + 1);
969                            enable_node(tree, state, next_child);
970                        } else {
971                            //if there is no next child, we recurse on the parent
972                            close_node(tree, state, parent);
973                        }
974                    }
975                    Node::Operator(Operator::Concurrent, _)
976                    | Node::Operator(Operator::Interleaved, _) => {
977                        //for a concurrent or interleaved parent, the parent can be closed if all of its children have been closed
978                        if tree
979                            .get_children(parent)
980                            .all(|child| state[child] == NodeState::Closed)
981                        {
982                            //close the parent
983                            close_node(tree, state, parent);
984                        }
985                    }
986                    Node::Operator(Operator::Or, _) => {
987                        //for an or parent, the parent can be closed if all of its children have been closed
988                        if tree
989                            .get_children(parent)
990                            .all(|child| state[child] == NodeState::Closed)
991                        {
992                            //close the parent
993                            close_node(tree, state, parent);
994                        }
995
996                        //furthermore, we may continue with the next sequential sibling of the parent
997                        enable_next_sequential_nodes(tree, state, parent);
998                    }
999                    Node::Operator(Operator::Xor, _) => {
1000                        //for a xor parent, the parent can be closed as we executed one of its children
1001                        close_node(tree, state, parent);
1002                    }
1003                    Node::Operator(Operator::Loop, number_of_children) => {
1004                        //for a loop parent, we open the next child(ren)
1005                        if child_rank == 0 {
1006                            //enable the siblings
1007                            for child_rank in 1..number_of_children {
1008                                enable_node(tree, state, tree.get_child(parent, child_rank));
1009                            }
1010                            //enable the exit
1011                            enable_next_sequential_nodes(tree, state, parent);
1012                        } else {
1013                            //enable the first child
1014                            enable_node(tree, state, tree.get_child(parent, 0));
1015                        }
1016                    }
1017                }
1018            }
1019        }
1020
1021        fn withdraw_enablement(tree: &$t, state: &mut TreeMarking, node: usize) {
1022            for grandchild in node..tree.traverse(node) {
1023                state[grandchild] = NodeState::Closed;
1024            }
1025        }
1026
1027        /// Starts executing a node.
1028        /// Recurses upwards to adjust enablement.
1029        fn start_node(tree: &$t, state: &mut TreeMarking, node: usize, child: Option<usize>) {
1030            match tree.tree[node] {
1031                Node::Tau
1032                | Node::Activity(_)
1033                | Node::Operator(Operator::Concurrent, _)
1034                | Node::Operator(Operator::Or, _)
1035                | Node::Operator(Operator::Sequence, _) => {
1036                    if state[node] != NodeState::Started {
1037                        state[node] = NodeState::Started;
1038
1039                        //recurse to parent
1040                        if let Some((parent, _)) = tree.get_parent(node) {
1041                            start_node(tree, state, parent, Some(node));
1042                        }
1043                    }
1044                }
1045                Node::Operator(Operator::Interleaved, _) => {
1046                    if state[node] != NodeState::Started {
1047                        state[node] = NodeState::Started;
1048
1049                        //recurse to parent
1050                        if let Some((parent, _)) = tree.get_parent(node) {
1051                            start_node(tree, state, parent, Some(node));
1052                        }
1053                    } else if let Some(from_child) = child {
1054                        //we are starting a non-first child of an interleaved node: withdraw enablement in all grand children
1055                        for child in tree.get_children(node) {
1056                            if child != from_child {
1057                                withdraw_enablement(tree, state, child);
1058                            }
1059                        }
1060                    } else {
1061                        unreachable!()
1062                    }
1063                }
1064                Node::Operator(Operator::Loop, number_of_children) => {
1065                    if state[node] != NodeState::Started {
1066                        state[node] = NodeState::Started;
1067
1068                        //recurse to parent
1069                        if let Some((parent, _)) = tree.get_parent(node) {
1070                            start_node(tree, state, parent, Some(node));
1071                        }
1072                    } else {
1073                        //for a loop, even though it started before, we may need to withdraw enablement of next sequential nodes
1074
1075                        if let Some(child) = child
1076                            && child > node + 1
1077                        {
1078                            //we are in a redo child: withdraw the next sequential node, which cannot fire now
1079                            withdraw_enablement_next_sequential_nodes(tree, state, node);
1080                            withdraw_enablement(tree, state, tree.get_child(node, 0));
1081                        } else {
1082                            //we are in a body child; withdraw the enablement of the redo children
1083                            for child_rank in 1..number_of_children {
1084                                withdraw_enablement(tree, state, tree.get_child(node, child_rank));
1085                            }
1086                        }
1087
1088                        //recurse to parent
1089                        if let Some((parent, _)) = tree.get_parent(node) {
1090                            start_node(tree, state, parent, Some(node));
1091                        }
1092                    }
1093                }
1094
1095                Node::Operator(Operator::Xor, _) => {
1096                    if state[node] != NodeState::Started {
1097                        state[node] = NodeState::Started;
1098
1099                        //for an xor, the siblings of the child must be withdrawn
1100                        for child2 in tree.get_children(node) {
1101                            if let Some(child) = child {
1102                                if child2 != child {
1103                                    withdraw_enablement(tree, state, child2);
1104                                }
1105                            }
1106                        }
1107                        //recurse to parent
1108                        if let Some((parent, _)) = tree.get_parent(node) {
1109                            start_node(tree, state, parent, Some(node));
1110                        }
1111                    }
1112                }
1113            }
1114        }
1115
1116        pub fn get_number_of_transitions(tree: &$t) -> usize {
1117            tree.tree.iter().filter(|node| node.is_leaf()).count() + 1 //the last transition is explicit termination, which is required by the semantics of Ebi
1118        }
1119
1120        pub fn get_enabled_transitions(tree: &$t, state: &TreeMarking) -> Vec<TransitionIndex> {
1121            let mut result = vec![];
1122
1123            for (transition_index, node) in tree.transition2node.iter().enumerate() {
1124                if can_execute(tree, state, *node) {
1125                    result.push(transition_index);
1126                }
1127            }
1128
1129            if !state.terminated && can_terminate(tree, state, tree.root()) {
1130                result.push(tree.transition2node.len());
1131            }
1132
1133            result
1134        }
1135
1136        pub fn is_final_state(_tree: &$t, state: &TreeMarking) -> bool {
1137            state.terminated
1138        }
1139
1140        pub fn get_transition_activity(tree: &$t, transition: TransitionIndex) -> Option<Activity> {
1141            let node = tree.transition2node.get(transition)?;
1142            match tree.tree[*node] {
1143                Node::Tau => None,
1144                Node::Activity(activity) => Some(activity),
1145                Node::Operator(_, _) => None,
1146            }
1147        }
1148
1149        pub fn execute_transition(
1150            tree: &$t,
1151            state: &mut TreeMarking,
1152            transition: TransitionIndex,
1153        ) -> Result<()> {
1154            if transition >= tree.transition2node.len() {
1155                state.terminated = true;
1156                state.states.fill(NodeState::Closed);
1157            } else {
1158                let node = tree
1159                    .transition2node
1160                    .get(transition)
1161                    .ok_or_else(|| anyhow!("transition does not exist"))?;
1162                start_node(tree, state, *node, None);
1163                close_node(tree, state, *node);
1164            }
1165            // log::debug!("state after execution {}", state);
1166            Ok(())
1167        }
1168    };
1169}
1170
1171tree_semantics!(ProcessTree);
1172
1173#[cfg(any(test, feature = "testactivities"))]
1174impl TestActivityKey for ProcessTree {
1175    fn test_activity_key(&self) {
1176        self.tree.iter().for_each(|node| {
1177            if let Node::Activity(a) = node {
1178                self.activity_key().assert_activity_is_of_key(a);
1179            }
1180        });
1181    }
1182}
1183
1184#[cfg(test)]
1185mod tests {
1186    use crate::{
1187        HasActivityKey, ProcessTree, StochasticProcessTree,
1188        ebi_objects::process_tree::{
1189            execute_transition, get_enabled_transitions, get_initial_state, get_transition_activity,
1190        },
1191    };
1192    use std::fs;
1193
1194    #[test]
1195    fn ptree_semantics_loop() {
1196        let fin1 =
1197            fs::read_to_string("testfiles/seq(a,xor(seq(f,and(c,b)),seq(f,loop(d,e))).sptree")
1198                .unwrap();
1199        let tree: ProcessTree = fin1.parse::<StochasticProcessTree>().unwrap().into();
1200
1201        let ta = 0;
1202        let tf1 = 1;
1203        let tf2 = 4;
1204        let td = 5;
1205        let te = 6;
1206        let ttau = 7;
1207        let tfin = 8;
1208
1209        assert_eq!(
1210            tree.activity_key()
1211                .deprocess_activity(&get_transition_activity(&tree, td).unwrap()),
1212            "d"
1213        );
1214        assert_eq!(
1215            tree.activity_key()
1216                .deprocess_activity(&get_transition_activity(&tree, te).unwrap()),
1217            "e"
1218        );
1219        assert!(get_transition_activity(&tree, ttau).is_none());
1220
1221        let mut state = get_initial_state(&tree).unwrap();
1222        println!("{}\n", state);
1223        assert_eq!(get_enabled_transitions(&tree, &state), [ta]);
1224
1225        println!("execute a {}", ta);
1226        execute_transition(&tree, &mut state, ta).unwrap();
1227        println!("{}\n", state);
1228        assert_eq!(get_enabled_transitions(&tree, &state), [tf1, tf2]);
1229
1230        println!("execute f2 {}", tf2);
1231        execute_transition(&tree, &mut state, tf2).unwrap();
1232        println!("{}\n", state);
1233        assert_eq!(get_enabled_transitions(&tree, &state), [td]);
1234
1235        println!("execute d {}", td);
1236        execute_transition(&tree, &mut state, td).unwrap();
1237        println!("{}\n", state);
1238        assert_eq!(get_enabled_transitions(&tree, &state), [te, ttau]);
1239
1240        println!("execute e {}", te);
1241        execute_transition(&tree, &mut state, te).unwrap();
1242        println!("{}\n", state);
1243        assert_eq!(get_enabled_transitions(&tree, &state), [td]);
1244
1245        println!("execute d {}", td);
1246        execute_transition(&tree, &mut state, td).unwrap();
1247        println!("{}\n", state);
1248        assert_eq!(get_enabled_transitions(&tree, &state), [te, ttau]);
1249
1250        println!("execute tau {}", ttau);
1251        execute_transition(&tree, &mut state, ttau).unwrap();
1252        println!("{}\n", state);
1253        assert_eq!(get_enabled_transitions(&tree, &state), [tfin]);
1254
1255        println!("terminate {}", tfin);
1256        execute_transition(&tree, &mut state, tfin).unwrap();
1257        println!("{}\n", state);
1258        assert_eq!(get_enabled_transitions(&tree, &state).len(), 0);
1259    }
1260}