1
#![forbid(unsafe_code)]
2

            
3
use std::collections::HashMap;
4
use std::fmt;
5

            
6
use merc_collections::ByteCompressedVec;
7
use merc_collections::CompressedEntry;
8
use merc_collections::CompressedVecMetrics;
9
use merc_collections::bytevec;
10
use merc_io::LargeFormatter;
11
use merc_utilities::TagIndex;
12

            
13
use crate::LTS;
14
use crate::LabelIndex;
15
use crate::LabelTag;
16
use crate::StateIndex;
17
use crate::Transition;
18
use crate::TransitionLabel;
19

            
20
/// Represents a labelled transition system consisting of states with directed
21
/// labelled transitions between them.
22
///
23
/// # Details
24
///
25
/// Uses byte compressed vectors to store the states and their outgoing
26
/// transitions efficiently in memory.
27
#[derive(PartialEq, Eq, Clone)]
28
pub struct LabelledTransitionSystem<Label> {
29
    /// Encodes the states and their outgoing transitions.
30
    states: ByteCompressedVec<usize>,
31
    transition_labels: ByteCompressedVec<LabelIndex>,
32
    transition_to: ByteCompressedVec<StateIndex>,
33

            
34
    /// Keeps track of the labels for every index, and which of them are hidden.
35
    labels: Vec<Label>,
36

            
37
    /// The index of the initial state.
38
    initial_state: StateIndex,
39
}
40

            
41
impl<Label: TransitionLabel> LabelledTransitionSystem<Label> {
42
    /// Creates a new a labelled transition system with the given transitions,
43
    /// labels, and hidden labels.
44
    ///
45
    /// The initial state is the state with the given index. `num_of_states`` is
46
    /// the number of states in the LTS, if known. If it is not known, pass
47
    /// `None`. However, in that case the number of states will be determined
48
    /// based on the maximum state index in the transitions. And all states that
49
    /// do not have any outgoing transitions will simply be created as deadlock
50
    /// states.
51
10522
    pub fn new<I, F>(
52
10522
        initial_state: StateIndex,
53
10522
        num_of_states: Option<usize>,
54
10522
        mut transition_iter: F,
55
10522
        labels: Vec<Label>,
56
10522
    ) -> LabelledTransitionSystem<Label>
57
10522
    where
58
10522
        F: FnMut() -> I,
59
10522
        I: Iterator<Item = (StateIndex, LabelIndex, StateIndex)>,
60
    {
61
10522
        let mut states = ByteCompressedVec::new();
62
10522
        if let Some(num_of_states) = num_of_states {
63
10521
            states.resize_with(num_of_states, Default::default);
64
10521
            debug_assert!(
65
10521
                initial_state.value() < num_of_states,
66
                "Initial vertex index {} out of bounds {num_of_states}",
67
                initial_state.value()
68
            );
69
1
        }
70

            
71
        // Count the number of transitions for every state
72
10522
        let mut num_of_transitions = 0;
73
892503
        for (from, _, to) in transition_iter() {
74
            // Ensure that the states vector is large enough.
75
892503
            if states.len() <= *from.max(to) {
76
2
                states.resize_with(*from.max(to) + 1, || 0);
77
892501
            }
78

            
79
892503
            states.update(*from, |start| *start += 1);
80
892503
            num_of_transitions += 1;
81

            
82
892503
            if let Some(num_of_states) = num_of_states {
83
892498
                debug_assert!(
84
892498
                    *from < num_of_states && *to < num_of_states,
85
                    "State index out of bounds: from {:?}, to {:?}, num_of_states {}",
86
                    from,
87
                    to,
88
                    num_of_states
89
                );
90
5
            }
91
        }
92

            
93
10522
        if initial_state.value() >= states.len() {
94
            // Ensure that the initial state is a valid state (and all states before it exist).
95
            states.resize_with(initial_state.value() + 1, Default::default);
96
10522
        }
97

            
98
        // Track the number of transitions before every state.
99
170898
        states.fold(0, |count, start| {
100
170898
            let result = count + *start;
101
170898
            *start = count;
102
170898
            result
103
170898
        });
104

            
105
        // Place the transitions, and increment the end for every state.
106
10522
        let mut transition_labels = bytevec![LabelIndex::new(labels.len()); num_of_transitions];
107
10522
        let mut transition_to = bytevec![StateIndex::new(states.len()); num_of_transitions];
108
892503
        for (from, label, to) in transition_iter() {
109
892503
            states.update(*from, |start| {
110
892503
                transition_labels.set(*start, label);
111
892503
                transition_to.set(*start, to);
112
892503
                *start += 1
113
892503
            });
114
        }
115

            
116
        // Reset the offset.
117
170898
        states.fold(0, |previous, start| {
118
170898
            let result = *start;
119
170898
            *start = previous;
120
170898
            result
121
170898
        });
122

            
123
        // The minus one is because we added one extra state for the sentinel.
124
10522
        debug_assert!(
125
10522
            initial_state.value() < states.len(),
126
            "Initial state {:?} out of bounds (num states: {})",
127
            initial_state,
128
            states.len() - 1
129
        );
130

            
131
        // Add the sentinel state.
132
10522
        states.push(transition_labels.len());
133

            
134
10522
        LabelledTransitionSystem {
135
10522
            initial_state,
136
10522
            labels,
137
10522
            states,
138
10522
            transition_labels,
139
10522
            transition_to,
140
10522
        }
141
10522
    }
142

            
143
    /// Constructs a LTS by the the a successor function for every state.
144
    pub fn with_successors<F, I>(
145
        initial_state: StateIndex,
146
        num_of_states: usize,
147
        labels: Vec<Label>,
148
        mut successors: F,
149
    ) -> Self
150
    where
151
        F: FnMut(StateIndex) -> I,
152
        I: Iterator<Item = (LabelIndex, StateIndex)>,
153
    {
154
        assert!(
155
            *labels
156
                .first()
157
                .expect("At least one label (the hidden label) must be provided")
158
                == Label::tau_label(),
159
            "The first label must be the hidden label."
160
        );
161

            
162
        let mut states = ByteCompressedVec::new();
163
        states.resize_with(num_of_states, Default::default);
164

            
165
        let mut transition_labels = ByteCompressedVec::with_capacity(num_of_states, 16usize.bytes_required());
166
        let mut transition_to = ByteCompressedVec::with_capacity(num_of_states, num_of_states.bytes_required());
167

            
168
        for state_index in 0..num_of_states {
169
            let state_index = StateIndex::new(state_index);
170
            states.update(*state_index, |entry| {
171
                *entry = transition_labels.len();
172
            });
173

            
174
            for (label, to) in successors(state_index) {
175
                transition_labels.push(label);
176
                transition_to.push(to);
177
            }
178
        }
179

            
180
        // Add the sentinel state.
181
        states.push(transition_labels.len());
182

            
183
        LabelledTransitionSystem {
184
            initial_state,
185
            labels,
186
            states,
187
            transition_labels,
188
            transition_to,
189
        }
190
    }
191

            
192
    /// Consumes the current LTS and merges it with another one, returning the merged LTS.
193
    ///
194
    /// # Details
195
    ///
196
    /// Internally this works by offsetting the state indices of the other LTS by the number of states
197
    /// in the current LTS, and combining the action labels. The offset is returned such that
198
    /// can find the states of the other LTS in the merged LTS as the initial state of the other LTS.
199
400
    fn merge_disjoint_impl(mut self, other: &impl LTS<Label = Label>) -> (Self, StateIndex) {
200
        // Determine the combination of action labels
201
400
        let mut all_labels = self.labels().to_vec();
202
3600
        for label in other.labels() {
203
3600
            if !all_labels.contains(label) {
204
400
                all_labels.push(label.clone());
205
3200
            }
206
        }
207

            
208
400
        let label_indices: HashMap<Label, TagIndex<usize, LabelTag>> = HashMap::from_iter(
209
400
            all_labels
210
400
                .iter()
211
400
                .enumerate()
212
3600
                .map(|(i, label)| (label.clone(), LabelIndex::new(i))),
213
        );
214

            
215
400
        let total_number_of_states = self.num_of_states() + other.num_of_states();
216

            
217
        // Reserve space for the right LTS.
218
400
        self.states
219
400
            .reserve(other.num_of_states(), total_number_of_states.bytes_required());
220
400
        self.transition_labels
221
400
            .reserve(other.num_of_transitions(), all_labels.len().bytes_required());
222
400
        self.transition_to
223
400
            .reserve(other.num_of_transitions(), total_number_of_states.bytes_required());
224

            
225
400
        let offset = self.num_of_states();
226

            
227
        // Remove the sentinel state temporarily. This breaks the state invariant, but we will add it back later.
228
400
        self.states.pop();
229

            
230
        // Add vertices for the other LTS that are offset by the number of states in self
231
11357
        for state_index in other.iter_states() {
232
            // Add a new state for every state in the other LTS
233
11357
            self.states.push(self.num_of_transitions());
234
91621
            for transition in other.outgoing_transitions(state_index) {
235
91621
                // Add the transitions of the other LTS, offsetting the state indices
236
91621
                self.transition_to.push(StateIndex::new(transition.to.value() + offset));
237
91621

            
238
91621
                // Map the label to the new index in all_labels
239
91621
                let label_name = &other.labels()[transition.label.value()];
240
91621
                self.transition_labels
241
91621
                    .push(*label_indices.get(label_name).expect("Label should exist in all_labels"));
242
91621
            }
243
        }
244

            
245
        // Add back the sentinel state
246
400
        self.states.push(self.num_of_transitions());
247
400
        debug_assert_eq!(self.num_of_states(), total_number_of_states);
248

            
249
400
        (
250
400
            Self {
251
400
                initial_state: self.initial_state,
252
400
                labels: all_labels,
253
400
                states: self.states,
254
400
                transition_labels: self.transition_labels,
255
400
                transition_to: self.transition_to,
256
400
            },
257
400
            StateIndex::new(offset + other.initial_state_index().value()),
258
400
        )
259
400
    }
260

            
261
    /// Creates a labelled transition system from another one, given the permutation of state indices
262
    ///
263
1000
    pub fn new_from_permutation<P>(lts: Self, permutation: P) -> Self
264
1000
    where
265
1000
        P: Fn(StateIndex) -> StateIndex + Copy,
266
    {
267
1000
        let mut states = bytevec![0; lts.num_of_states()];
268

            
269
8304
        for state_index in lts.iter_states() {
270
            // Keep the transitions the same move the state indices around
271
8304
            let new_state_index = permutation(state_index);
272
8304
            let state = lts.states.index(*state_index);
273
8304
            states.update(*new_state_index, |entry| {
274
8304
                *entry = state;
275
8304
            });
276
        }
277

            
278
        // Add the sentinel state.
279
1000
        states.push(lts.num_of_transitions());
280

            
281
1000
        LabelledTransitionSystem {
282
1000
            initial_state: permutation(lts.initial_state),
283
1000
            labels: lts.labels,
284
1000
            states,
285
1000
            transition_labels: lts.transition_labels,
286
1000
            transition_to: lts.transition_to,
287
1000
        }
288
1000
    }
289

            
290
    /// Consumes the LTS and relabels its transition labels according to the given mapping.
291
    pub fn relabel<L: TransitionLabel>(self, labelling: impl Fn(Label) -> L) -> LabelledTransitionSystem<L> {
292
        let new_labels: Vec<L> = self.labels.iter().cloned().map(labelling).collect();
293

            
294
        LabelledTransitionSystem {
295
            initial_state: self.initial_state,
296
            labels: new_labels,
297
            states: self.states,
298
            transition_labels: self.transition_labels,
299
            transition_to: self.transition_to,
300
        }
301
    }
302

            
303
    /// Returns metrics about the LTS.
304
    pub fn metrics(&self) -> LtsMetrics {
305
        LtsMetrics {
306
            num_of_states: self.num_of_states(),
307
            num_of_labels: self.num_of_labels(),
308
            num_of_transitions: self.num_of_transitions(),
309
            state_metrics: self.states.metrics(),
310
            transition_labels_metrics: self.transition_labels.metrics(),
311
            transition_to_metrics: self.transition_to.metrics(),
312
        }
313
    }
314
}
315

            
316
impl<L: TransitionLabel> LTS for LabelledTransitionSystem<L> {
317
    type Label = L;
318

            
319
16662
    fn initial_state_index(&self) -> StateIndex {
320
16662
        self.initial_state
321
16662
    }
322

            
323
424974
    fn outgoing_transitions(&self, state_index: StateIndex) -> impl Iterator<Item = Transition> + '_ {
324
424974
        let start = self.states.index(*state_index);
325
424974
        let end = self.states.index(*state_index + 1);
326

            
327
424974
        (start..end).map(move |i| Transition {
328
1712806
            label: self.transition_labels.index(i),
329
1712806
            to: self.transition_to.index(i),
330
1712806
        })
331
424974
    }
332

            
333
19663
    fn iter_states(&self) -> impl Iterator<Item = StateIndex> + '_ {
334
19663
        (0..self.num_of_states()).map(StateIndex::new)
335
19663
    }
336

            
337
160185
    fn num_of_states(&self) -> usize {
338
        // Remove the sentinel state.
339
160185
        self.states.len() - 1
340
160185
    }
341

            
342
24957
    fn num_of_labels(&self) -> usize {
343
24957
        self.labels.len()
344
24957
    }
345

            
346
35922
    fn num_of_transitions(&self) -> usize {
347
35922
        self.transition_labels.len()
348
35922
    }
349

            
350
1099794
    fn labels(&self) -> &[Self::Label] {
351
1099794
        &self.labels[0..]
352
1099794
    }
353

            
354
319624
    fn is_hidden_label(&self, label_index: LabelIndex) -> bool {
355
319624
        label_index.value() == 0
356
319624
    }
357

            
358
300
    fn merge_disjoint<T: LTS<Label = Self::Label>>(self, other: &T) -> (Self, StateIndex) {
359
300
        self.merge_disjoint_impl(other)
360
300
    }
361
}
362

            
363
/// Metrics for a labelled transition system.
364
#[derive(Debug, Clone)]
365
pub struct LtsMetrics {
366
    /// The number of states in the LTS.
367
    pub num_of_states: usize,
368
    pub state_metrics: CompressedVecMetrics,
369
    /// The number of transitions in the LTS.
370
    pub num_of_transitions: usize,
371
    pub transition_labels_metrics: CompressedVecMetrics,
372
    pub transition_to_metrics: CompressedVecMetrics,
373
    /// The number of action labels in the LTS.
374
    pub num_of_labels: usize,
375
}
376

            
377
impl fmt::Display for LtsMetrics {
378
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
379
        // Print some information about the LTS.
380
        writeln!(f, "Number of states: {}", LargeFormatter(self.num_of_states))?;
381
        writeln!(f, "Number of action labels: {}", LargeFormatter(self.num_of_labels))?;
382
        writeln!(
383
            f,
384
            "Number of transitions: {}\n",
385
            LargeFormatter(self.num_of_transitions)
386
        )?;
387
        writeln!(f, "Memory usage:")?;
388
        writeln!(f, "States {}", self.state_metrics)?;
389
        writeln!(f, "Transition labels {}", self.transition_labels_metrics)?;
390
        write!(f, "Transition to {}", self.transition_to_metrics)
391
    }
392
}
393

            
394
/// Checks that two LTSs are equivalent, for testing purposes.
395
#[cfg(test)]
396
300
pub fn check_equivalent<L: LTS>(lts: &L, lts_read: &L) {
397
300
    println!("LTS labels: {:?}", lts.labels());
398
300
    println!("Read LTS labels: {:?}", lts_read.labels());
399

            
400
    // If labels are not used, the number of labels may be less. So find a remapping of old labels to new labels.
401
300
    let mapping = lts
402
300
        .labels()
403
300
        .iter()
404
300
        .enumerate()
405
1800
        .map(|(_i, label)| lts_read.labels().iter().position(|l| l == label))
406
300
        .collect::<Vec<_>>();
407

            
408
    // Print the mapping
409
900
    for (i, m) in mapping.iter().enumerate() {
410
900
        println!("Label {} mapped to {:?}", i, m);
411
900
    }
412

            
413
300
    assert_eq!(lts.num_of_states(), lts_read.num_of_states());
414
300
    assert_eq!(lts.num_of_transitions(), lts_read.num_of_transitions());
415

            
416
    // Check that all the outgoing transitions are the same.
417
30000
    for state_index in lts.iter_states() {
418
30000
        let transitions: Vec<_> = lts.outgoing_transitions(state_index).collect();
419
30000
        let transitions_read: Vec<_> = lts_read.outgoing_transitions(state_index).collect();
420

            
421
        // Check that transitions are the same, modulo label remapping.
422
278484
        transitions.iter().for_each(|t| {
423
278484
            let mapped_label = mapping[t.label.value()].expect(&format!("Label {} should be found", t.label));
424
278484
            assert!(
425
278484
                transitions_read
426
278484
                    .iter()
427
1903338
                    .any(|tr| tr.to == t.to && tr.label.value() == mapped_label)
428
            );
429
278484
        });
430
    }
431
300
}
432

            
433
#[cfg(test)]
434
mod tests {
435
    use merc_io::DumpFiles;
436
    use merc_utilities::random_test;
437

            
438
    use crate::random_lts;
439
    use crate::write_aut;
440

            
441
    #[test]
442
    #[cfg_attr(miri, ignore)] // Miri is too slow
443
1
    fn test_labelled_transition_system_merge() {
444
100
        random_test(100, |rng| {
445
100
            let mut files = DumpFiles::new("test_labelled_transition_system_merge");
446

            
447
100
            let left = random_lts(rng, 5, 5, 10);
448
100
            let right = random_lts(rng, 5, 10, 10);
449

            
450
100
            files.dump("left.aut", |f| write_aut(f, &left)).unwrap();
451
100
            files.dump("right.aut", |f| write_aut(f, &right)).unwrap();
452

            
453
100
            let (merged, _offset) = left.clone().merge_disjoint_impl(&right);
454

            
455
100
            files.dump("merged.aut", |f| write_aut(f, &merged)).unwrap();
456
100
        })
457
1
    }
458
}