1
//! Authors: Maurice Laveaux and Sjef van Loo
2

            
3
use std::marker::PhantomData;
4

            
5
use merc_collections::ByteCompressedVec;
6
use merc_collections::bytevec;
7

            
8
use crate::PG;
9
use crate::VertexIndex;
10

            
11
/// Stores the predecessors for a given parity game.
12
pub struct Predecessors<'a> {
13
    /// A flat list of all predecessors in the game.
14
    edges_from: ByteCompressedVec<VertexIndex>,
15

            
16
    /// A mapping from the vertex to the `edges_from` that stores its
17
    /// predecessors.
18
    vertex_to_predecessors: ByteCompressedVec<usize>,
19

            
20
    /// Marker to tie the lifetime of the predecessors to the game.
21
    _marker: PhantomData<&'a ()>,
22
}
23

            
24
impl<'a> Predecessors<'a> {
25
    /// Creates the predecessors structure for the given parity game.
26
2232
    pub fn new<G: PG>(game: &'a G) -> Self {
27
2232
        let mut edges_from = bytevec![VertexIndex::new(0); game.num_of_edges()];
28
2232
        let mut vertex_to_predecessors = bytevec![0; game.num_of_vertices()];
29

            
30
        // Count the number of incoming transitions for each vertex
31
122015
        for vertex_index in game.iter_vertices() {
32
130275
            for edge in game.outgoing_edges(vertex_index) {
33
130275
                vertex_to_predecessors.update(edge.to().value(), |start| *start += 1);
34
            }
35
        }
36

            
37
        // Compute the start offsets (prefix sum)
38
147202
        vertex_to_predecessors.fold(0, |offset, start| {
39
147202
            let new_offset = offset + *start;
40
147202
            *start = offset;
41
147202
            new_offset
42
147202
        });
43

            
44
        // Place the transitions
45
122015
        for vertex_index in game.iter_vertices() {
46
130275
            for edge in game.outgoing_edges(vertex_index) {
47
130275
                vertex_to_predecessors.update(edge.to().value(), |start| {
48
130275
                    edges_from.set(*start, vertex_index);
49
130275
                    *start += 1;
50
130275
                });
51
            }
52
        }
53

            
54
2232
        let mut offset = 0usize;
55
147202
        vertex_to_predecessors.fold(0, |previous, start| {
56
147202
            let result = *start;
57
147202
            *start = previous;
58
147202
            offset = result;
59
147202
            result
60
147202
        });
61

            
62
2232
        vertex_to_predecessors.push(offset);
63

            
64
2232
        Self {
65
2232
            edges_from,
66
2232
            vertex_to_predecessors,
67
2232
            _marker: PhantomData,
68
2232
        }
69
2232
    }
70

            
71
    /// Returns an iterator over the predecessors the given vertex.
72
124244
    pub fn predecessors(&self, vertex_index: VertexIndex) -> impl Iterator<Item = VertexIndex> + use<'_> {
73
124244
        let start = self.vertex_to_predecessors.index(vertex_index.value());
74
124244
        let end = self.vertex_to_predecessors.index(vertex_index.value() + 1);
75
174226
        (start..end).map(move |i| self.edges_from.index(i))
76
124244
    }
77
}
78

            
79
#[cfg(test)]
80
mod tests {
81
    use itertools::Itertools;
82
    use merc_utilities::random_test;
83

            
84
    use crate::PG;
85
    use crate::Predecessors;
86
    use crate::PrioSubgame;
87
    use crate::Priority;
88
    use crate::random_parity_game;
89

            
90
    #[test]
91
    #[cfg_attr(miri, ignore)] // Test is too slow under miri
92
1
    fn test_random_predecessors() {
93
100
        random_test(100, |rng| {
94
100
            let game = random_parity_game(rng, true, 50, 10, 5);
95
100
            check_predecessors(game);
96
100
        })
97
1
    }
98

            
99
    #[test]
100
    #[cfg_attr(miri, ignore)] // Test is too slow under miri
101
1
    fn test_random_predecessors_subgame() {
102
100
        random_test(100, |rng| {
103
100
            let pg = random_parity_game(rng, true, 50, 10, 5);
104
100
            let game = PrioSubgame::new(&pg, Priority::new(0));
105

            
106
100
            check_predecessors(game);
107
100
        })
108
1
    }
109

            
110
    /// Checks that the predecessors computed by the `Predecessors` structure
111
    /// match the expected predecessors computed by iterating over all vertices
112
    /// and their outgoing edges.
113
200
    fn check_predecessors<G: PG>(game: G) {
114
200
        let predecessors = Predecessors::new(&game);
115
5903
        for vertex in game.iter_vertices() {
116
            // Compute the expected predecessors by iterating over all vertices and their outgoing edges.
117
5903
            let expected_predecessors: Vec<_> = game
118
5903
                .iter_vertices()
119
534597
                .filter(|&v| game.outgoing_edges(v).any(|e| e.to() == vertex))
120
5903
                .collect();
121
5903
            let actual_predecessors: Vec<_> = predecessors.predecessors(vertex).collect();
122
    
123
5903
            assert_eq!(
124
5903
                expected_predecessors.into_iter().sorted().collect::<Vec<_>>(),
125
5903
                actual_predecessors.into_iter().sorted().collect::<Vec<_>>(),
126
                "Predecessors of vertex {} do not match",
127
                vertex.value()
128
            );
129
        }
130
200
    }
131
}