ebi_objects/ebi_objects/
process_tree.rs

1use std::{
2    fmt::Display,
3    io::{self},
4    str::FromStr,
5};
6
7use anyhow::{Context, Error, Result, anyhow};
8use ebi_derive::ActivityKey;
9use layout::{adt::dag::NodeHandle, topo::layout::VisualGraph};
10use strum::IntoEnumIterator;
11use strum_macros::EnumIter;
12
13use crate::{
14    Activity, ActivityKey, ActivityKeyTranslator, EbiObject, Exportable, Graphable, HasActivityKey,
15    Importable, Infoable, TranslateActivityKey, ebi_objects::labelled_petri_net::TransitionIndex,
16    line_reader::LineReader, traits::graphable,
17};
18
19use super::stochastic_process_tree::StochasticProcessTree;
20
21pub const HEADER: &str = "process tree";
22
23pub const FORMAT_SPECIFICATION: &str = "A process tree is a line-based structure. Lines starting with a \\# are ignored.
24    This first line is exactly `process tree'.
25    The subsequent lines contain the nodes:
26    Each node is either:
27    \\begin{itemize}
28        \\item A line with the word `activity' followed on the same line by a space and the label of the activity leaf;
29        \\item The word `tau';
30        \\item The name of an operator (`sequence', `xor', `concurrent', `loop', `interleaved', or `or') on its own line.
31        The line thereafter contains the number of children of the node, after which the nodes are given.
32        An operator node must have at least one child.
33    \\end{itemize}
34    Indentation of nodes is allowed, but not mandatory.
35    
36    For instance:
37    \\lstinputlisting[language=ebilines, style=boxed]{../testfiles/all_operators.ptree}";
38
39#[derive(Debug, ActivityKey, Clone)]
40pub struct ProcessTree {
41    pub activity_key: ActivityKey,
42    pub tree: Vec<Node>,
43    pub transition2node: Vec<usize>,
44}
45
46impl ProcessTree {
47    fn node_to_string(
48        &self,
49        indent: usize,
50        node: usize,
51        f: &mut std::fmt::Formatter<'_>,
52    ) -> Result<usize> {
53        let id = "\t".repeat(indent);
54        match &self.tree[node] {
55            Node::Tau => {
56                writeln!(f, "{}tau", id)?;
57                Ok(node + 1)
58            }
59            Node::Activity(activity) => {
60                writeln!(
61                    f,
62                    "{}activity {}",
63                    id,
64                    self.activity_key.get_activity_label(&activity)
65                )?;
66                Ok(node + 1)
67            }
68            Node::Operator(operator, number_of_children) => {
69                writeln!(f, "{}{}", id, operator.to_string())?;
70                writeln!(
71                    f,
72                    "{}# number of children\n{}{}",
73                    id, id, number_of_children
74                )?;
75                let mut child = node + 1;
76                for _ in 0..*number_of_children {
77                    child = self.node_to_string(indent + 1, child, f)?;
78                }
79                Ok(child)
80            }
81        }
82    }
83
84    fn node_to_dot(
85        &self,
86        graph: &mut VisualGraph,
87        node: usize,
88        entry: &NodeHandle,
89        exit: &NodeHandle,
90    ) -> usize {
91        match self.tree[node] {
92            Node::Tau => {
93                graphable::create_edge(graph, entry, exit, "");
94                node + 1
95            }
96            Node::Activity(activity) => {
97                let transition = graphable::create_transition(
98                    graph,
99                    self.activity_key.get_activity_label(&activity),
100                    "",
101                );
102                graphable::create_edge(graph, entry, &transition, "");
103                graphable::create_edge(graph, &transition, exit, "");
104                node + 1
105            }
106            Node::Operator(Operator::Xor, number_of_children) => {
107                let mut child = node + 1;
108                for _ in 0..number_of_children {
109                    child = ProcessTree::node_to_dot(&self, graph, child, entry, exit);
110                }
111                child
112            }
113            Node::Operator(Operator::Sequence, number_of_children) => {
114                let intermediate_nodes = (0..(number_of_children - 1))
115                    .map(|_| graphable::create_dot(graph))
116                    .collect::<Vec<_>>();
117
118                let mut child = node + 1;
119                for i in 0..number_of_children {
120                    let child_entry = if i == 0 {
121                        entry
122                    } else {
123                        &intermediate_nodes[i - 1]
124                    };
125                    let child_exit = if i == number_of_children - 1 {
126                        exit
127                    } else {
128                        &intermediate_nodes[i]
129                    };
130
131                    child = ProcessTree::node_to_dot(&self, graph, child, child_entry, child_exit);
132                }
133                child
134            }
135            Node::Operator(Operator::Concurrent, number_of_children) => {
136                let split = graphable::create_gateway(graph, "+");
137                graphable::create_edge(graph, entry, &split, "");
138                let join = graphable::create_gateway(graph, "+");
139                graphable::create_edge(graph, &join, exit, "");
140
141                let mut child = node + 1;
142                for _ in 0..number_of_children {
143                    child = ProcessTree::node_to_dot(&self, graph, child, &split, &join);
144                }
145                child
146            }
147            Node::Operator(Operator::Or, number_of_children) => {
148                let split = graphable::create_gateway(graph, "o");
149                graphable::create_edge(graph, entry, &split, "");
150                let join = graphable::create_gateway(graph, "o");
151                graphable::create_edge(graph, &join, exit, "");
152
153                let mut child = node + 1;
154                for _ in 0..number_of_children {
155                    child = ProcessTree::node_to_dot(&self, graph, child, &split, &join);
156                }
157                child
158            }
159            Node::Operator(Operator::Interleaved, number_of_children) => {
160                let split = graphable::create_gateway(graph, "↔");
161                graphable::create_edge(graph, entry, &split, "");
162                let join = graphable::create_gateway(graph, "↔");
163                graphable::create_edge(graph, &join, exit, "");
164
165                let mut child = node + 1;
166                for _ in 0..number_of_children {
167                    child = ProcessTree::node_to_dot(&self, graph, child, &split, &join);
168                }
169                child
170            }
171            Node::Operator(Operator::Loop, number_of_children) => {
172                let split = graphable::create_dot(graph);
173                graphable::create_edge(graph, entry, &split, "");
174                let join = graphable::create_dot(graph);
175                graphable::create_edge(graph, &join, exit, "");
176
177                let mut child = node + 1;
178
179                child = ProcessTree::node_to_dot(&self, graph, child, &split, &join);
180
181                if number_of_children == 1 {
182                    graphable::create_edge(graph, &join, &split, "");
183                } else {
184                    for _ in 1..number_of_children {
185                        child = ProcessTree::node_to_dot(&self, graph, child, &join, &split);
186                    }
187                }
188                child
189            }
190        }
191    }
192
193    ///read one node, recursively
194    fn string_to_tree(
195        lreader: &mut LineReader<'_>,
196        tree: &mut Vec<Node>,
197        activity_key: &mut ActivityKey,
198        root: bool,
199    ) -> Result<()> {
200        let node_type_line = match lreader.next_line_string().with_context(|| {
201            format!(
202                "Failed to read node {} at line {}",
203                tree.len(),
204                lreader.get_last_line_number()
205            )
206        }) {
207            Ok(x) => x,
208            Err(e) => {
209                if root {
210                    //The root may be missing: then, we have an empty tree.
211                    return Ok(());
212                } else {
213                    return Err(e);
214                }
215            }
216        };
217
218        if node_type_line.trim_start().starts_with("tau") {
219            tree.push(Node::Tau);
220        } else if node_type_line.trim_start().starts_with("activity ") {
221            let label = node_type_line.trim_start()[9..].to_string();
222            let activity = activity_key.process_activity(&label);
223            tree.push(Node::Activity(activity));
224        } else if let Ok(operator) = node_type_line.trim_start().trim_end().parse::<Operator>() {
225            let number_of_children = lreader.next_line_index().with_context(|| {
226                format!(
227                    "failed to read number of children for node {} at line {}",
228                    tree.len(),
229                    lreader.get_last_line_number()
230                )
231            })?;
232            if number_of_children < 1 {
233                return Err(anyhow!(
234                    "loop node ending at node {} at line {} has no children",
235                    tree.len(),
236                    lreader.get_last_line_number()
237                ));
238            }
239            tree.push(Node::Operator(operator, number_of_children));
240            for _ in 0..number_of_children {
241                Self::string_to_tree(lreader, tree, activity_key, false)?;
242            }
243        } else if root && node_type_line.trim_start().is_empty() {
244            //empty tree
245            return Ok(());
246        } else {
247            return Err(anyhow!(
248                "could not parse type of node {} at line {}. Expected `tau`, `activity`, `concurrent`, `interleaved`, `or`, `sequence` or `xor`",
249                tree.len(),
250                lreader.get_last_line_number()
251            ));
252        }
253
254        Ok(())
255    }
256}
257
258macro_rules! tree {
259    ($t:ident, $u:ident, $v:ident) => {
260        impl $t {
261            pub fn get_number_of_nodes(&self) -> usize {
262                return self.tree.len();
263            }
264
265            pub fn get_node(&self, node: usize) -> Option<&Node> {
266                self.tree.get(node)
267            }
268
269            pub fn root(&self) -> usize {
270                0
271            }
272
273            pub fn get_node_of_transition(&self, transition: TransitionIndex) -> Result<&Node> {
274                self.tree
275                    .get(
276                        *self
277                            .transition2node
278                            .get(transition)
279                            .ok_or_else(|| anyhow!("Transition does not exist."))?,
280                    )
281                    .ok_or_else(|| anyhow!("Node does not exist."))
282            }
283
284            /**
285             * Returns the parent of node. Notice that
286             * this is an expensive operation; avoid if possible.
287             *
288             * @param node
289             * @return The parent of node, and the rank of the child
290             */
291            pub fn get_parent(&self, node: usize) -> Option<(usize, usize)> {
292                if node == 0 {
293                    return None;
294                }
295
296                let mut potential_parent = node - 1;
297                while self.traverse(potential_parent) <= node {
298                    potential_parent -= 1;
299                }
300
301                let child_rank = self.get_child_rank_with(potential_parent, node)?;
302
303                Some((potential_parent, child_rank))
304            }
305
306            /**
307             *
308             * @param parent
309             * @param grandChild
310             * @return The number of the child within parent that contains grandChild.
311             *         If grandChild is not a child of parent, will return -1.
312             */
313            pub fn get_child_rank_with(&self, parent: usize, grand_child: usize) -> Option<usize> {
314                let mut child_rank = 0;
315                for child in self.get_children(parent) {
316                    if self.is_parent_of(child, grand_child) {
317                        return Some(child_rank);
318                    }
319                    child_rank += 1;
320                }
321                None
322            }
323
324            pub fn get_children(&self, node: usize) -> $u<'_> {
325                $u::new(self, node)
326            }
327
328            pub fn get_parents(&self, node: usize) -> $v<'_> {
329                $v::new(self, node)
330            }
331
332            pub fn get_descendants(&self, node: usize) -> &[Node] {
333                let next = self.traverse(node);
334                &self.tree[node..next]
335            }
336
337            /**
338             *
339             * @param parent
340             * @param child
341             * @return Whether the child is a direct or indirect child of parent.
342             */
343            pub fn is_parent_of(&self, parent: usize, child: usize) -> bool {
344                if parent > child {
345                    return false;
346                }
347                return self.traverse(parent) > child;
348            }
349
350            /**
351             * Find the next node of this node: the next sibling, and if that is not available, the next sibling up the tree.
352             * May return a non-existing node if there is no sibling.
353             */
354            pub fn traverse(&self, node: usize) -> usize {
355                match self.tree[node] {
356                    Node::Tau => node + 1,
357                    Node::Activity(_) => node + 1,
358                    Node::Operator(_, number_of_children) => {
359                        let mut n = node + 1;
360                        for _ in 0..number_of_children {
361                            n = self.traverse(n);
362                        }
363                        n
364                    }
365                }
366            }
367
368            pub fn get_child(&self, parent: usize, child_rank: usize) -> usize {
369                let mut i = parent + 1;
370                for _ in 0..child_rank {
371                    i = self.traverse(i);
372                }
373                return i;
374            }
375
376            pub fn get_number_of_children(&self, parent: usize) -> Option<usize> {
377                match self.tree.get(parent)? {
378                    Node::Tau => Some(0),
379                    Node::Activity(_) => Some(0),
380                    Node::Operator(_, number_of_children) => Some(*number_of_children),
381                }
382            }
383
384            pub fn node_to_transition(&self, node: usize) -> Option<usize> {
385                let mut transitions = 0;
386                let mut last = false;
387                for node in self.tree.iter().take(node + 1) {
388                    match node {
389                        Node::Activity(_) | Node::Tau => {
390                            transitions += 1;
391                            last = true
392                        }
393                        _ => last = false,
394                    }
395                }
396
397                if last { Some(transitions - 1) } else { None }
398            }
399        }
400
401        impl TranslateActivityKey for $t {
402            fn translate_using_activity_key(&mut self, to_activity_key: &mut ActivityKey) {
403                let translator = ActivityKeyTranslator::new(&self.activity_key, to_activity_key);
404                self.tree.iter_mut().for_each(|node| {
405                    if let Node::Activity(a) = node {
406                        *a = translator.translate_activity(&a)
407                    }
408                });
409                self.activity_key = to_activity_key.clone();
410            }
411        }
412
413        impl Infoable for $t {
414            fn info(&self, f: &mut impl std::io::Write) -> Result<()> {
415                writeln!(f, "Number of nodes\t\t{}", self.get_number_of_nodes())?;
416                writeln!(
417                    f,
418                    "Number of activities\t\t{}",
419                    $t::activity_key(self).get_number_of_activities()
420                )?;
421
422                writeln!(f, "")?;
423                self.activity_key().info(f)?;
424
425                Ok(write!(f, "")?)
426            }
427        }
428
429        impl Graphable for $t {
430            fn to_dot(&self) -> Result<layout::topo::layout::VisualGraph> {
431                let mut graph = VisualGraph::new(layout::core::base::Orientation::LeftToRight);
432                let source = graphable::create_place(&mut graph, "");
433                let sink = graphable::create_place(&mut graph, "");
434                if !self.tree.is_empty() {
435                    $t::node_to_dot(&self, &mut graph, 0, &source, &sink);
436                }
437                Ok(graph)
438            }
439        }
440
441        impl FromStr for $t {
442            type Err = Error;
443
444            fn from_str(s: &str) -> std::prelude::v1::Result<Self, Self::Err> {
445                let mut reader = io::Cursor::new(s);
446                Self::import(&mut reader)
447            }
448        }
449
450        pub struct $u<'a> {
451            //children iterator
452            tree: &'a $t,
453            node: usize,
454            now: Option<usize>,
455            next: usize,
456            count: usize,
457        }
458
459        impl<'a> $u<'a> {
460            fn new(tree: &'a $t, node: usize) -> Self {
461                Self {
462                    tree: tree,
463                    node: node,
464                    now: None,
465                    next: node + 1,
466                    count: 0,
467                }
468            }
469        }
470
471        impl<'a> Iterator for $u<'a> {
472            type Item = usize;
473
474            fn next(&mut self) -> Option<Self::Item> {
475                if self.count >= self.tree.get_number_of_children(self.node)? {
476                    return None;
477                }
478                self.count += 1;
479                self.now = Some(self.next);
480                self.next = self.tree.traverse(self.now.unwrap());
481                Some(self.now.unwrap())
482            }
483        }
484
485        pub struct $v<'a> {
486            //parents iterator
487            tree: &'a $t,
488            node: Option<(usize, usize)>,
489        }
490
491        impl<'a> $v<'a> {
492            fn new(tree: &'a $t, node: usize) -> Self {
493                Self {
494                    tree: tree,
495                    node: tree.get_parent(node),
496                }
497            }
498        }
499
500        impl<'a> Iterator for $v<'a> {
501            type Item = (usize, usize);
502
503            fn next(&mut self) -> Option<Self::Item> {
504                if let Some((node, child_rank)) = self.node {
505                    self.node = self.tree.get_parent(node);
506
507                    Some((node, child_rank))
508                } else {
509                    None
510                }
511            }
512        }
513    };
514}
515
516tree!(ProcessTree, ChildrenIterator, ParentsIterator);
517tree!(
518    StochasticProcessTree,
519    StochasticChildrenIterator,
520    StochasticParentsIterator
521);
522
523impl From<(ActivityKey, Vec<Node>)> for ProcessTree {
524    fn from(value: (ActivityKey, Vec<Node>)) -> Self {
525        let mut transition2node = vec![];
526        for (node_index, node) in value.1.iter().enumerate() {
527            match node {
528                Node::Tau | Node::Activity(_) => {
529                    transition2node.push(node_index);
530                }
531                Node::Operator(_, _) => {}
532            }
533        }
534
535        Self {
536            activity_key: value.0,
537            tree: value.1,
538            transition2node: transition2node,
539        }
540    }
541}
542
543impl Display for ProcessTree {
544    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
545        writeln!(f, "{}", HEADER)?;
546        if !self.tree.is_empty() {
547            let _ = self.node_to_string(0, 0, f);
548        };
549        write!(f, "")
550    }
551}
552
553impl Importable for ProcessTree {
554    fn import_as_object(reader: &mut dyn std::io::BufRead) -> Result<EbiObject> {
555        Ok(EbiObject::ProcessTree(Self::import(reader)?))
556    }
557
558    fn import(reader: &mut dyn std::io::BufRead) -> Result<Self>
559    where
560        Self: Sized,
561    {
562        let mut lreader = LineReader::new(reader);
563
564        let head = lreader
565            .next_line_string()
566            .with_context(|| format!("failed to read header, which should be {}", HEADER))?;
567        if head != HEADER {
568            return Err(anyhow!(
569                "first line should be exactly `{}`, but found `{}` on line `{}`",
570                HEADER,
571                lreader.get_last_line(),
572                lreader.get_last_line_number()
573            ));
574        }
575
576        let mut activity_key = ActivityKey::new();
577        let mut tree = vec![];
578        Self::string_to_tree(&mut lreader, &mut tree, &mut activity_key, true)?;
579
580        Ok((activity_key, tree).into())
581    }
582}
583
584impl Exportable for ProcessTree {
585    fn export_from_object(object: EbiObject, f: &mut dyn std::io::Write) -> Result<()> {
586        match object {
587            EbiObject::ProcessTree(lpn) => lpn.export(f),
588            _ => Err(anyhow!(
589                "cannot export {} {} as a process tree",
590                object.get_type().get_article(),
591                object.get_type()
592            )),
593        }
594    }
595
596    fn export(&self, f: &mut dyn std::io::Write) -> Result<()> {
597        Ok(write!(f, "{}", self)?)
598    }
599}
600
601#[derive(Debug, Clone)]
602pub enum Node {
603    Tau,
604    Activity(Activity),
605    Operator(Operator, usize), //type, number of children
606}
607
608impl Node {
609    pub fn is_leaf(&self) -> bool {
610        match self {
611            Self::Tau | Self::Activity(_) => true,
612            Self::Operator(_, _) => false,
613        }
614    }
615
616    pub fn set_number_of_children(&mut self, number_of_children: usize) -> Result<()> {
617        if let Self::Operator(_, old_number_of_children) = self {
618            *old_number_of_children = number_of_children;
619            Ok(())
620        } else {
621            Err(anyhow!(
622                "attempted to alter the number of children of an activity or a tau"
623            ))
624        }
625    }
626}
627
628#[derive(EnumIter, Debug, Clone, Copy)]
629pub enum Operator {
630    Xor,
631    Sequence,
632    Interleaved,
633    Concurrent,
634    Or,
635    Loop,
636}
637
638impl Operator {
639    pub fn to_string(&self) -> &str {
640        match self {
641            Operator::Xor => "xor",
642            Operator::Sequence => "sequence",
643            Operator::Interleaved => "interleaved",
644            Operator::Concurrent => "concurrent",
645            Operator::Or => "or",
646            Operator::Loop => "loop",
647        }
648    }
649}
650
651impl FromStr for Operator {
652    type Err = Error;
653
654    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
655        for op in Operator::iter() {
656            if s == op.to_string() {
657                return Ok(op);
658            }
659        }
660        return Err(anyhow!("operator not recognised"));
661    }
662}