1
#![forbid(unsafe_code)]
2

            
3
use delegate::delegate;
4

            
5
use merc_lts::LTS;
6
use merc_lts::LabelIndex;
7
use merc_lts::LabelledTransitionSystem;
8
use merc_lts::StateIndex;
9
use merc_lts::Transition;
10

            
11
/// For divergence-preserving branching bisimulation, we only need to treat
12
/// tau-self-loops as non-inert transitions. This can be achieved by temporarily
13
/// renaming the tau-self-loops to self-loops with a special label.
14
pub struct DivergencePreservingLts<'a, L: LTS> {
15
    /// The special label used to mark tau-self-loops, this should not be used in the original LTS.
16
    tau_self_loops_label: LabelIndex,
17

            
18
    /// We copy the labels and add the special label at the end.
19
    labels: Vec<L::Label>,
20

            
21
    lts: &'a L,
22
}
23

            
24
impl<'a, L: LTS> DivergencePreservingLts<'a, L> {
25
2000
    pub fn new(lts: &'a L) -> Self {
26
        // We add a new label for the tau-self-loops.
27
2000
        let tau_self_loops = lts.num_of_labels();
28
2000
        let labels = lts
29
2000
            .labels()
30
2000
            .iter()
31
2000
            .cloned()
32
2000
            .chain(std::iter::once(lts.labels()[0].clone()))
33
2000
            .collect();
34

            
35
2000
        DivergencePreservingLts {
36
2000
            tau_self_loops_label: LabelIndex::new(tau_self_loops),
37
2000
            labels,
38
2000
            lts,
39
2000
        }
40
2000
    }
41
}
42

            
43
impl<L: LTS> LTS for DivergencePreservingLts<'_, L> {
44
    type Label = L::Label;
45

            
46
31265441
    fn outgoing_transitions(&self, state_index: StateIndex) -> impl Iterator<Item = Transition> + '_ {
47
32798022
        self.lts.outgoing_transitions(state_index).map(move |transition| {
48
            // A self-loop with tau should be renamed to the special label.
49
32798022
            if self.lts.is_hidden_label(transition.label) && state_index == transition.to {
50
131017
                Transition {
51
131017
                    label: self.tau_self_loops_label,
52
131017
                    to: transition.to,
53
131017
                }
54
            } else {
55
32667005
                transition
56
            }
57
32798022
        })
58
31265441
    }
59

            
60
793440
    fn num_of_labels(&self) -> usize {
61
793440
        self.lts.num_of_labels() + 1
62
793440
    }
63

            
64
61020
    fn labels(&self) -> &[Self::Label] {
65
61020
        &self.labels
66
61020
    }
67

            
68
    fn merge_disjoint<U: LTS<Label = Self::Label>>(
69
        self,
70
        _other: &U,
71
    ) -> (LabelledTransitionSystem<Self::Label>, StateIndex) {
72
        unimplemented!(
73
            "merge_disjoint is not implemented for DivergencePreservingLts, because this should only be used as a view on the original LTS."
74
        );
75
    }
76

            
77
    delegate! {
78
        to self.lts {
79
            fn initial_state_index(&self) -> StateIndex;
80
119508
            fn num_of_states(&self) -> usize;
81
2200
            fn num_of_transitions(&self) -> usize;
82
475135
            fn iter_states(&self) -> impl Iterator<Item = StateIndex> + '_;
83
60850117
            fn is_hidden_label(&self, label_index: LabelIndex) -> bool;
84
        }
85
    }
86
}