1
//! Authors: Maurice Laveaux and Sjef van Loo
2
use std::fmt;
3

            
4
use itertools::Itertools;
5

            
6
use merc_utilities::TagIndex;
7

            
8
use crate::Player;
9

            
10
/// A strong type for the vertices.
11
pub struct VertexTag;
12

            
13
/// A strong type for the priorities.
14
pub struct PriorityTag;
15

            
16
/// The index for a vertex.
17
pub type VertexIndex = TagIndex<usize, VertexTag>;
18

            
19
/// The strong type for a priority.
20
pub type Priority = TagIndex<usize, PriorityTag>;
21

            
22
/// Represents an explicit max-priority parity game. This
23
/// means that higher priority values are more significant.
24
pub struct ParityGame {
25
    /// Stores the owner of every vertex.
26
    owner: Vec<Player>,
27

            
28
    /// Stores the priority of every vertex.
29
    priority: Vec<Priority>,
30

            
31
    /// Offsets into the transition array for every vertex.
32
    vertices: Vec<usize>,
33
    edges_to: Vec<VertexIndex>,
34

            
35
    initial_vertex: VertexIndex,
36
}
37

            
38
impl ParityGame {
39
    /// Construct a new parity game from an iterator over transitions.
40
958
    pub fn new(
41
958
        initial_vertex: VertexIndex,
42
958
        owner: Vec<Player>,
43
958
        priority: Vec<Priority>,
44
958
        vertices: Vec<usize>,
45
958
        edges_to: Vec<VertexIndex>,
46
958
    ) -> Self {
47
        // Check that the sizes are consistent
48
958
        debug_assert_eq!(
49
958
            owner.len(),
50
958
            priority.len(),
51
            "There should an owner and priority for every vertex"
52
        );
53
958
        debug_assert_eq!(
54
958
            vertices.len(),
55
958
            owner.len() + 1,
56
            "There should be an offset for every vertex, and the sentinel state"
57
        );
58
958
        debug_assert_eq!(initial_vertex, 0, "The initial vertex should be vertex 0");
59

            
60
958
        Self {
61
958
            owner,
62
958
            priority,
63
958
            vertices,
64
958
            edges_to,
65
958
            initial_vertex,
66
958
        }
67
958
    }
68

            
69
    /// Constructs a new parity game from an iterator over edges.
70
    ///
71
    /// The vertices are given by their owner and priority. The `edges` iterator
72
    /// should yield tuples of the form (from, to). If `make_total` is true,
73
    /// self-loops are added on-the-fly to vertices with no outgoing edges.
74
1353
    pub fn from_edges<F, I>(
75
1353
        initial_vertex: VertexIndex,
76
1353
        owner: Vec<Player>,
77
1353
        mut priority: Vec<Priority>,
78
1353
        make_total: bool,
79
1353
        mut edges: F,
80
1353
    ) -> Self
81
1353
    where
82
1353
        F: FnMut() -> I,
83
1353
        I: Iterator<Item = (VertexIndex, VertexIndex)>,
84
    {
85
1353
        let num_of_vertices = owner.len();
86
1353
        debug_assert_eq!(
87
1353
            priority.len(),
88
            num_of_vertices,
89
            "Owner and priority vectors should have the same length"
90
        );
91

            
92
1353
        let mut vertices = Vec::new();
93
1353
        vertices.resize_with(num_of_vertices, Default::default);
94
1353
        debug_assert!(
95
1353
            initial_vertex.value() < num_of_vertices,
96
            "Initial vertex index {} out of bounds {num_of_vertices}",
97
            initial_vertex.value()
98
        );
99

            
100
        // Count the number of transitions for every state
101
1353
        let mut num_of_edges = 0;
102
48579
        for (from, to) in edges() {
103
            // Ensure that the states vector is large enough.
104
48579
            if vertices.len() <= *from.max(to) {
105
                vertices.resize_with(*from.max(to) + 1, || 0);
106
48579
            }
107

            
108
48579
            vertices[*from] += 1;
109
48579
            num_of_edges += 1;
110

            
111
48579
            debug_assert!(
112
48579
                *from < num_of_vertices && *to < num_of_vertices,
113
                "Vertex index out of bounds: from {:?}, to {:?}, num_of_vertices {}",
114
                from,
115
                to,
116
                num_of_vertices
117
            );
118
        }
119

            
120
1353
        if initial_vertex.value() >= vertices.len() {
121
            // Ensure that the initial state is a valid state (and all states before it exist).
122
            vertices.resize_with(initial_vertex.value() + 1, Default::default);
123
1353
        }
124

            
125
        // If make_total is true, reserve space for self-loops on vertices with no outgoing edges
126
1353
        if make_total {
127
35566
            for count in vertices.iter_mut() {
128
35566
                if *count == 0 {
129
5683
                    *count = 1;
130
5683
                    num_of_edges += 1;
131
29883
                }
132
            }
133
200
        }
134

            
135
        // Sets the offset for every state into the edge arrays.
136
37566
        vertices.iter_mut().fold(0, |count, start| {
137
37566
            let result = count + *start;
138
37566
            *start = count;
139
37566
            result
140
37566
        });
141

            
142
        // Place the transitions, and increment the end for every state.
143
1353
        let mut edges_to = vec![VertexIndex::new(0); num_of_edges];
144
48579
        for (from, to) in edges() {
145
48579
            let start = &mut vertices[*from];
146
48579
            edges_to[*start] = to;
147
48579
            *start += 1;
148
48579
        }
149

            
150
        // If make_total is true, add self-loops for vertices that had no outgoing edges
151
1353
        if make_total {
152
35566
            for vertex_idx in 0..num_of_vertices {
153
35566
                let start = vertices[vertex_idx];
154
35566
                let previous = if vertex_idx > 0 { vertices[vertex_idx - 1] } else { 0 };
155
35566
                if start == previous {
156
5683
                    // No outgoing edges, add self-loop
157
5683
                    edges_to[start] = VertexIndex::new(vertex_idx);
158
5683
                    vertices[vertex_idx] += 1; // Increment end offset
159
5683

            
160
5683
                    // Change the priority of the vertex such that the self-loop is winning for the opponent.
161
5683
                    priority[vertex_idx] = Priority::new(owner[vertex_idx].opponent().to_index());
162
29883
                }
163
            }
164
200
        }
165

            
166
        // Reset the offset to the start.
167
37566
        vertices.iter_mut().fold(0, |previous, start| {
168
37566
            let result = *start;
169
37566
            *start = previous;
170
37566
            result
171
37566
        });
172

            
173
1353
        vertices.push(num_of_edges); // Sentinel vertex
174

            
175
1353
        Self {
176
1353
            initial_vertex,
177
1353
            owner,
178
1353
            priority,
179
1353
            vertices,
180
1353
            edges_to,
181
1353
        }
182
1353
    }
183

            
184
    /// Returns true iff the parity game is total, checks all vertices have at least one outgoing edge.
185
953
    pub fn is_total(&self) -> bool {
186
18691
        for v in self.iter_vertices() {
187
18691
            if self.outgoing_edges(v).next().is_none() {
188
                return false;
189
18691
            }
190
        }
191

            
192
953
        true
193
953
    }
194

            
195
    /// Returns the vertices array.
196
106698
    pub(crate) fn vertices(&self) -> &Vec<usize> {
197
106698
        &self.vertices
198
106698
    }
199

            
200
    /// Returns the edges_to array.
201
53349
    pub(crate) fn edges_to(&self) -> &Vec<VertexIndex> {
202
53349
        &self.edges_to
203
53349
    }
204

            
205
    /// Returns the owners array.
206
954
    pub(crate) fn owners(&self) -> &Vec<Player> {
207
954
        &self.owner
208
954
    }
209

            
210
    /// Returns the priorities array.
211
954
    pub(crate) fn priorities(&self) -> &Vec<Priority> {
212
954
        &self.priority
213
954
    }
214
}
215

            
216
impl PG for ParityGame {
217
1708
    fn initial_vertex(&self) -> VertexIndex {
218
1708
        self.initial_vertex
219
1708
    }
220

            
221
18478
    fn num_of_vertices(&self) -> usize {
222
18478
        self.owner.len()
223
18478
    }
224

            
225
2454
    fn num_of_edges(&self) -> usize {
226
2454
        self.edges_to.len()
227
2454
    }
228

            
229
7573
    fn iter_vertices(&self) -> impl Iterator<Item = VertexIndex> + '_ {
230
7573
        (0..self.num_of_vertices()).map(VertexIndex::new)
231
7573
    }
232

            
233
106532
    fn outgoing_edges(&self, state_index: VertexIndex) -> impl Iterator<Item = VertexIndex> + '_ {
234
106532
        let start = self.vertices[*state_index];
235
106532
        let end = self.vertices[*state_index + 1];
236

            
237
127751
        (start..end).map(move |i| self.edges_to[i])
238
106532
    }
239

            
240
96196
    fn owner(&self, vertex: VertexIndex) -> Player {
241
96196
        self.owner[*vertex]
242
96196
    }
243

            
244
127145
    fn priority(&self, vertex: VertexIndex) -> Priority {
245
127145
        self.priority[*vertex]
246
127145
    }
247
}
248

            
249
impl fmt::Debug for ParityGame {
250
100
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251
100
        writeln!(f, "ParityGame {{")?;
252
100
        writeln!(f, "  num_vertices: {},", self.num_of_vertices())?;
253
100
        writeln!(f, "  num_edges: {},", self.num_of_edges())?;
254
100
        writeln!(f, "  initial_vertex: v{},", *self.initial_vertex)?;
255
100
        writeln!(f, "  vertices: [")?;
256
10000
        for v in self.iter_vertices() {
257
10000
            let owner = self.owner(v);
258
10000
            let prio = self.priority(v);
259
10000
            write!(
260
10000
                f,
261
                "    {}: ({:?}, priority: {}, outgoing: [",
262
10000
                *v,
263
10000
                owner.to_index(),
264
10000
                *prio
265
            )?;
266

            
267
10000
            write!(f, "{}", self.outgoing_edges(v).format(", "))?;
268
10000
            writeln!(f, "]),")?;
269
        }
270
100
        writeln!(f, "  ]")?;
271
100
        writeln!(f, "}}")
272
100
    }
273
}
274

            
275
/// A trait for parity games.
276
pub trait PG {
277
    /// Returns the initial vertex of the parity game.
278
    fn initial_vertex(&self) -> VertexIndex;
279

            
280
    /// Returns the number of vertices in the parity game.
281
    fn num_of_vertices(&self) -> usize;
282

            
283
    /// Returns the number of edges in the parity game.
284
    fn num_of_edges(&self) -> usize;
285

            
286
    /// Returns an iterator over all vertices in the parity game.
287
    fn iter_vertices(&self) -> impl Iterator<Item = VertexIndex> + '_;
288

            
289
    /// Returns an iterator over the outgoing edges for the given vertex.
290
    fn outgoing_edges(&self, state_index: VertexIndex) -> impl Iterator<Item = VertexIndex> + '_;
291

            
292
    /// Returns the owner of the given vertex.
293
    fn owner(&self, vertex: VertexIndex) -> Player;
294

            
295
    /// Returns the priority of the given vertex.
296
    fn priority(&self, vertex: VertexIndex) -> Priority;
297
}
298

            
299
#[cfg(test)]
300
mod tests {
301
    use merc_utilities::random_test;
302

            
303
    use crate::random_parity_game;
304

            
305
    #[test]
306
1
    fn test_random_parity_game_make_total() {
307
100
        random_test(100, |rng| {
308
100
            let game = random_parity_game(rng, true, 50, 10, 5);
309
100
            assert!(game.is_total());
310
100
        });
311
1
    }
312
}