1
use std::fmt;
2

            
3
use merc_data::DataExpression;
4
use merc_data::DataSpecification;
5
use merc_data::DataVariable;
6
use merc_ldd::Ldd;
7
use merc_ldd::Storage;
8
use merc_ldd::Value;
9
use merc_ldd::compute_meta;
10
use merc_lts::LtsAction;
11
use merc_lts::LtsMultiAction;
12
use merc_utilities::MercError;
13

            
14
use crate::SymbolicLTS;
15
use crate::TransitionGroup;
16

            
17
/// Represents a symbolic LTS encoded by a disjunctive transition relation and a set of states.
18
pub struct SymbolicLts {
19
    data_specification: DataSpecification,
20
    states: Ldd,
21

            
22
    /// A singleton LDD representing the initial state.
23
    initial_state: Ldd,
24
    summand_groups: Vec<SummandGroup>,
25

            
26
    /// The action labels of the LTS, stored as their string representation,
27
    /// their position corresponds to the LDD values.
28
    action_labels: Vec<String>,
29

            
30
    /// The possible values for each process parameter, their position
31
    /// corresponds to the LDD values.
32
    parameter_values: Vec<Vec<DataExpression>>,
33
}
34

            
35
impl SymbolicLts {
36
    /// Creates a new symbolic LTS.
37
    ///
38
    /// `parameter_values` contains, for each process parameter, the list of
39
    /// possible values it can take. Their indices correspond to the values stored
40
    /// in the LDDs.
41
305
    pub fn new(
42
305
        data_specification: DataSpecification,
43
305
        states: Ldd,
44
305
        initial_state: Ldd,
45
305
        summand_groups: Vec<SummandGroup>,
46
305
        action_labels: Vec<LtsMultiAction<LtsAction>>,
47
305
        parameter_values: Vec<Vec<DataExpression>>,
48
305
    ) -> Self {
49
305
        let action_labels = action_labels
50
305
            .into_iter()
51
1779
            .map(|aterm| format!("{}", aterm))
52
305
            .collect::<Vec<String>>();
53

            
54
305
        Self {
55
305
            data_specification,
56
305
            states,
57
305
            initial_state,
58
305
            summand_groups,
59
305
            action_labels,
60
305
            parameter_values,
61
305
        }
62
305
    }
63

            
64
    /// Returns the data specification of the LTS.
65
    pub fn data_specification(&self) -> &DataSpecification {
66
        &self.data_specification
67
    }
68

            
69
    /// Returns the parameter values of the LTS.
70
    pub fn parameter_values(&self) -> &Vec<Vec<DataExpression>> {
71
        &self.parameter_values
72
    }
73

            
74
    /// Replaces the set of states of the LTS, for example after running reachability.
75
300
    pub fn set_states(&mut self, states: Ldd) {
76
300
        self.states = states;
77
300
    }
78
}
79

            
80
impl SymbolicLTS for SymbolicLts {
81
1410
    fn states(&self) -> &Ldd {
82
1410
        &self.states
83
1410
    }
84

            
85
1304
    fn initial_state(&self) -> &Ldd {
86
1304
        &self.initial_state
87
1304
    }
88

            
89
36139
    fn transition_groups(&self) -> &[impl TransitionGroup] {
90
36139
        &self.summand_groups
91
36139
    }
92

            
93
1317
    fn transition_groups_mut(&mut self) -> &mut [impl TransitionGroup] {
94
1317
        &mut self.summand_groups
95
1317
    }
96

            
97
627003
    fn action_labels(&self) -> &[String] {
98
627003
        &self.action_labels
99
627003
    }
100

            
101
303
    fn parameter_values(&self) -> &[Vec<DataExpression>] {
102
303
        &self.parameter_values
103
303
    }
104
}
105

            
106
/// Represents a short vector transition relation for a group of summands.
107
///
108
/// # Details
109
///
110
/// A short transition vector is part of a transition relation T -> U, where we
111
/// store T' -> U' with T' being the projection of T on the read parameters and
112
/// U' the projection of U on the write parameters, as a LDD. Formally,
113
///
114
/// (t, u) in (T -> U)  iff  (t', u') in (T' -> U') where t' and u' are the projections
115
///     of t and u on the read and write parameters respectively.
116
pub struct SummandGroup {
117
    /// The read parameters for this summand group.
118
    read_parameters: Vec<DataVariable>,
119
    read_parameter_indices: Vec<Value>,
120

            
121
    /// The write parameters for this summand group.
122
    write_parameters: Vec<DataVariable>,
123
    write_parameter_indices: Vec<Value>,
124

            
125
    /// The transition relation T' -> U' for this summand group.
126
    relation: Ldd,
127

            
128
    /// The meta information for this summand group.
129
    meta: Ldd,
130

            
131
    /// The action label index for this summand group.
132
    action_label_index: usize,
133
}
134

            
135
impl TransitionGroup for SummandGroup {
136
185670
    fn relation(&self) -> &Ldd {
137
185670
        &self.relation
138
185670
    }
139

            
140
6585
    fn meta(&self) -> &Ldd {
141
6585
        &self.meta
142
6585
    }
143

            
144
1756396
    fn read_indices(&self) -> &[u32] {
145
1756396
        &self.read_parameter_indices
146
1756396
    }
147

            
148
661291
    fn write_indices(&self) -> &[u32] {
149
661291
        &self.write_parameter_indices
150
661291
    }
151

            
152
629760
    fn action_label_index(&self) -> Option<usize> {
153
629760
        Some(self.action_label_index)
154
629760
    }
155

            
156
6585
    fn learn_successors(&mut self, _storage: &mut Storage, _todo: &Ldd) -> Result<(), MercError> {
157
        // All states are already explored.
158
6585
        Ok(())
159
6585
    }
160
}
161

            
162
impl SummandGroup {
163
    /// Creates a new summand group.
164
    ///
165
    /// This can fail if one of the read or write parameters is not in the list of all parameters.
166
1641
    pub fn new(
167
1641
        storage: &mut Storage,
168
1641
        parameters: &[DataVariable],
169
1641
        read_parameters: Vec<DataVariable>,
170
1641
        write_parameters: Vec<DataVariable>,
171
1641
        relation: Ldd,
172
1641
    ) -> Result<Self, MercError> {
173
        // Find the position of every variable in the parameter list.
174
1641
        let mut read_parameter_indices: Vec<Value> = read_parameters
175
1641
            .iter()
176
7050
            .map(|var| {
177
7050
                parameters
178
7050
                    .iter()
179
41344
                    .position(|p| p == var)
180
7050
                    .ok_or(format!("Cannot find read parameter {var:?}"))
181
7050
                    .map(|pos| pos as Value)
182
7050
            })
183
1641
            .collect::<Result<Vec<Value>, _>>()?;
184

            
185
1641
        let mut write_parameter_indices: Vec<Value> = write_parameters
186
1641
            .iter()
187
7105
            .map(|var| {
188
7105
                parameters
189
7105
                    .iter()
190
42362
                    .position(|p| p == var)
191
7105
                    .ok_or(format!("Cannot find write parameter {var:?}"))
192
7105
                    .map(|pos| pos as Value)
193
7105
            })
194
1641
            .collect::<Result<Vec<Value>, _>>()?;
195

            
196
        // For later processing it is convenient if these indices are sorted.
197
1641
        write_parameter_indices.sort();
198
1641
        read_parameter_indices.sort();
199

            
200
1641
        let meta = compute_meta(storage, &read_parameter_indices, &write_parameter_indices).0;
201
1641
        let action_label_index = read_parameters.len() + write_parameters.len(); // The action label is the last index
202

            
203
1641
        Ok(Self {
204
1641
            read_parameters,
205
1641
            read_parameter_indices,
206
1641
            write_parameters,
207
1641
            write_parameter_indices,
208
1641
            relation,
209
1641
            meta,
210
1641
            action_label_index,
211
1641
        })
212
1641
    }
213

            
214
    /// Returns the transition relation LDD for this summand group.
215
    pub fn relation(&self) -> &Ldd {
216
        &self.relation
217
    }
218

            
219
    /// Returns the read parameters for this summand group.
220
    pub fn read_parameters(&self) -> &[DataVariable] {
221
        &self.read_parameters
222
    }
223

            
224
    /// Returns the write parameters for this summand group.
225
    pub fn write_parameters(&self) -> &[DataVariable] {
226
        &self.write_parameters
227
    }
228
}
229

            
230
impl fmt::Debug for SummandGroup {
231
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232
        write!(
233
            f,
234
            "{:?} -> {:?}",
235
            self.read_parameter_indices, self.write_parameter_indices
236
        )
237
    }
238
}