1
#![forbid(unsafe_code)]
2

            
3
//! The labelled transition system (LTS) trait and associated types.
4

            
5
use std::fmt;
6
use std::hash::Hash;
7

            
8
use merc_collections::Graph;
9
use merc_utilities::TagIndex;
10

            
11
use crate::LabelledTransitionSystem;
12

            
13
/// A unique type for the labels.
14
pub struct LabelTag;
15

            
16
/// A unique type for the states.
17
pub struct StateTag;
18

            
19
/// The index type for a label.
20
pub type LabelIndex = TagIndex<usize, LabelTag>;
21

            
22
/// The index for a state.
23
pub type StateIndex = TagIndex<usize, StateTag>;
24

            
25
/// The trait for labelled transition systems.
26
///
27
/// Uses (strong) indices to refer to states and labels. The state indices are
28
/// represented as `StateIndex`, and the label indices as `LabelIndex`. The
29
/// labels themselves are given by type `Label`.
30
pub trait LTS
31
where
32
    Self: Sized,
33
{
34
    /// The associated type for transition labels.
35
    type Label: TransitionLabel;
36

            
37
    /// Returns the index of the initial state
38
    fn initial_state_index(&self) -> StateIndex;
39

            
40
    /// Returns the set of outgoing transitions for the given state.
41
    fn outgoing_transitions(&self, state_index: StateIndex) -> impl Iterator<Item = Transition> + '_;
42

            
43
    /// Iterate over all state_index in the labelled transition system
44
    fn iter_states(&self) -> impl Iterator<Item = StateIndex> + '_;
45

            
46
    /// Returns the number of states.
47
    fn num_of_states(&self) -> usize;
48

            
49
    /// Returns the number of labels.
50
    fn num_of_labels(&self) -> usize;
51

            
52
    /// Returns the number of transitions.
53
    fn num_of_transitions(&self) -> usize;
54

            
55
    /// Returns the list of labels.
56
    fn labels(&self) -> &[Self::Label];
57

            
58
    /// Returns true iff the given label index is a hidden label.
59
    fn is_hidden_label(&self, label_index: LabelIndex) -> bool;
60

            
61
    /// Consumes the current LTS and merges it with another one, returning the
62
    /// disjoint merged LTS and the initial state of the other LTS in the merged
63
    /// LTS.
64
    ///
65
    /// TODO: Can this be generalised to returning `Self`?
66
    fn merge_disjoint<L: LTS<Label = Self::Label>>(
67
        self,
68
        other: &L,
69
    ) -> (LabelledTransitionSystem<Self::Label>, StateIndex);
70
}
71

            
72
/// A wrapper struct to treat an LTS as a graph.
73
pub struct AsGraph<'a, L: LTS>(pub &'a L);
74

            
75
/// A labelled transition system is also a graph.
76
impl<L: LTS> Graph for AsGraph<'_, L> {
77
    type VertexIndex = StateIndex;
78
    type LabelIndex = LabelIndex;
79

            
80
2202
    fn num_of_vertices(&self) -> usize {
81
2202
        self.0.num_of_states()
82
2202
    }
83

            
84
1101
    fn iter_vertices(&self) -> impl Iterator<Item = Self::VertexIndex> {
85
1101
        self.0.iter_states()
86
1101
    }
87

            
88
10012
    fn outgoing_edges(&self, vertex: Self::VertexIndex) -> impl Iterator<Item = (Self::LabelIndex, Self::VertexIndex)> {
89
19675
        self.0.outgoing_transitions(vertex).map(|t| (t.label, t.to))
90
10012
    }
91
}
92

            
93
/// A common trait for all transition labels. For various algorithms on LTSs we
94
/// require that  they are orderable, comparable, and hashable. So we require that here
95
/// instead of specifying these bounds on usage.
96
pub trait TransitionLabel: Ord + Hash + Eq + Clone + fmt::Display + fmt::Debug {
97
    /// Returns the tau label for this transition label type.
98
    fn tau_label() -> Self;
99

            
100
    /// Returns true iff this label is the tau label.
101
    fn is_tau_label(&self) -> bool {
102
        self == &Self::tau_label()
103
    }
104

            
105
    /// Returns true iff this label matches the given string label.
106
    fn matches_label(&self, label: &str) -> bool;
107

            
108
    /// Used for generating labels for the random LTSs
109
    fn from_index(i: usize) -> Self;
110
}
111

            
112
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
113
pub struct Transition {
114
    pub label: LabelIndex,
115
    pub to: StateIndex,
116
}
117

            
118
impl Transition {
119
    /// Constructs a new transition.
120
58789
    pub fn new(label: LabelIndex, to: StateIndex) -> Self {
121
58789
        Self { label, to }
122
58789
    }
123
}