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
///
15
/// This relies on the fact that the original tau label is a specific label. The
16
/// special label is added to the end of the label list, and is not used in the
17
/// original LTS.
18
pub struct DivergencePreservingLts<'a, L: LTS> {
19
    /// The special label used to mark tau-self-loops, this should not be used in the original LTS.
20
    tau_self_loops_label: LabelIndex,
21

            
22
    /// We copy the labels and add the special label at the end.
23
    labels: Vec<L::Label>,
24

            
25
    lts: &'a L,
26
}
27

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

            
39
2003
        DivergencePreservingLts {
40
2003
            tau_self_loops_label: LabelIndex::new(tau_self_loops),
41
2003
            labels,
42
2003
            lts,
43
2003
        }
44
2003
    }
45
}
46

            
47
impl<L: LTS> LTS for DivergencePreservingLts<'_, L> {
48
    type Label = L::Label;
49

            
50
31490298
    fn outgoing_transitions(&self, state_index: StateIndex) -> impl Iterator<Item = Transition> + '_ {
51
33123121
        self.lts.outgoing_transitions(state_index).map(move |transition| {
52
            // A self-loop with tau should be renamed to the special label.
53
33123121
            if self.lts.is_hidden_label(transition.label) && state_index == transition.to {
54
138637
                Transition {
55
138637
                    label: self.tau_self_loops_label,
56
138637
                    to: transition.to,
57
138637
                }
58
            } else {
59
32984484
                transition
60
            }
61
33123121
        })
62
31490298
    }
63

            
64
796043
    fn num_of_labels(&self) -> usize {
65
796043
        self.lts.num_of_labels() + 1
66
796043
    }
67

            
68
61379
    fn labels(&self) -> &[Self::Label] {
69
61379
        &self.labels
70
61379
    }
71

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

            
81
    delegate! {
82
        to self.lts {
83
            fn initial_state_index(&self) -> StateIndex;
84
120093
            fn num_of_states(&self) -> usize;
85
2206
            fn num_of_transitions(&self) -> usize;
86
477947
            fn iter_states(&self) -> impl Iterator<Item = StateIndex> + '_;
87
61324365
            fn is_hidden_label(&self, label_index: LabelIndex) -> bool;
88
        }
89
    }
90
}