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
538239
    fn num_of_vertices(&self) -> usize {
81
538239
        self.0.num_of_states()
82
538239
    }
83

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

            
88
532637
    fn outgoing_edges(&self, vertex: Self::VertexIndex) -> impl Iterator<Item = (Self::LabelIndex, Self::VertexIndex)> {
89
567488
        self.0.outgoing_transitions(vertex).map(|t| (t.label, t.to))
90
532637
    }
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
    ///
102
    /// This default implementation compares with the tau label returned by [Self::tau_label].
103
    fn is_tau_label(&self) -> bool {
104
        self == &Self::tau_label()
105
    }
106

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

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

            
114
/// Represents a transition in the LTS originating from some known state.
115
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
116
pub struct Transition {
117
    pub label: LabelIndex,
118
    pub to: StateIndex,
119
}
120

            
121
impl Transition {
122
    /// Constructs a new transition.
123
    pub fn new(label: LabelIndex, to: StateIndex) -> Self {
124
        Self { label, to }
125
    }
126
}