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 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 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 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 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 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 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 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 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 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), }
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}