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 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 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 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 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 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 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 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 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 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), }
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#[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 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 tree.get_children(node).all(|child| {
724 state[child] == NodeState::Closed || can_terminate(tree, state, child)
725 })
726 }
727 Node::Operator(Operator::Or, _) => {
728 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 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 return true;
746 }
747 if state[body_child] == NodeState::Enabled {
748 return false;
750 }
751
752 for child_rank in 1..number_of_children {
753 let redo_child = tree.get_child(node, child_rank);
754 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 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 tree.get_children(node).all(|child| {
774 state[child] == NodeState::Closed || can_terminate(tree, state, child)
775 })
776 }
777 }
778 }
779
780 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 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 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 } else if started_children == 1 {
818 if state[previous_parent] != NodeState::Started {
820 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 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_node(tree, state, tree.get_child(node, 0));
852 }
853 }
854 }
855
856 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 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 enable_next_sequential_nodes(tree, state, parent);
872 } else {
873 }
875 }
876 Node::Operator(Operator::Loop, number_of_children) => {
877 if child_rank == 0 {
878 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 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 enable_next_sequential_nodes(tree, state, parent);
892 } else {
893 enable_node(tree, state, tree.get_child(parent, child_rank + 1));
895 }
896 }
897 }
898 }
899 }
900
901 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 withdraw_enablement(
915 tree,
916 state,
917 tree.get_child(parent, child_rank + 1),
918 );
919 } else {
920 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 withdraw_enablement_next_sequential_nodes(tree, state, parent);
930 }
931 Node::Operator(Operator::Loop, number_of_children) => {
932 if child_rank == 0 {
933 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 withdraw_enablement(tree, state, tree.get_child(parent, 0));
944
945 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 for grandchild in node..tree.traverse(node) {
956 state[grandchild] = NodeState::Closed;
957 }
958
959 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 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 close_node(tree, state, parent);
973 }
974 }
975 Node::Operator(Operator::Concurrent, _)
976 | Node::Operator(Operator::Interleaved, _) => {
977 if tree
979 .get_children(parent)
980 .all(|child| state[child] == NodeState::Closed)
981 {
982 close_node(tree, state, parent);
984 }
985 }
986 Node::Operator(Operator::Or, _) => {
987 if tree
989 .get_children(parent)
990 .all(|child| state[child] == NodeState::Closed)
991 {
992 close_node(tree, state, parent);
994 }
995
996 enable_next_sequential_nodes(tree, state, parent);
998 }
999 Node::Operator(Operator::Xor, _) => {
1000 close_node(tree, state, parent);
1002 }
1003 Node::Operator(Operator::Loop, number_of_children) => {
1004 if child_rank == 0 {
1006 for child_rank in 1..number_of_children {
1008 enable_node(tree, state, tree.get_child(parent, child_rank));
1009 }
1010 enable_next_sequential_nodes(tree, state, parent);
1012 } else {
1013 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 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 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 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 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 if let Some((parent, _)) = tree.get_parent(node) {
1070 start_node(tree, state, parent, Some(node));
1071 }
1072 } else {
1073 if let Some(child) = child
1076 && child > node + 1
1077 {
1078 withdraw_enablement_next_sequential_nodes(tree, state, node);
1080 withdraw_enablement(tree, state, tree.get_child(node, 0));
1081 } else {
1082 for child_rank in 1..number_of_children {
1084 withdraw_enablement(tree, state, tree.get_child(node, child_rank));
1085 }
1086 }
1087
1088 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 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 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 }
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 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}