1
//! Authors: Maurice Laveaux and Sjef van Loo
2
#[cfg(debug_assertions)]
3
use std::collections::HashSet;
4
use std::fmt;
5

            
6
use itertools::Itertools;
7

            
8
use merc_collections::Graph;
9
use merc_utilities::TagIndex;
10

            
11
use crate::Player;
12

            
13
/// A strong type for the vertices.
14
pub struct VertexTag;
15

            
16
/// A strong type for the priorities.
17
pub struct PriorityTag;
18

            
19
/// The index for a vertex.
20
pub type VertexIndex = TagIndex<usize, VertexTag>;
21

            
22
/// The strong type for a priority.
23
pub type Priority = TagIndex<usize, PriorityTag>;
24

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

            
31
    /// Stores the priority of every vertex.
32
    priority: Vec<Priority>,
33

            
34
    /// Offsets into the transition array for every vertex.
35
    vertices: Vec<usize>,
36
    edges_to: Vec<VertexIndex>,
37

            
38
    initial_vertex: VertexIndex,
39
}
40

            
41
impl ParityGame {
42
    /// Constructs a new parity game from an iterator over edges.
43
    ///
44
    /// The vertices are given by their owner and priority. The `edges` iterator
45
    /// should yield tuples of the form (from, to). If `make_total` is true,
46
    /// self-loops are added on-the-fly to vertices with no outgoing edges.
47
2134
    pub fn from_edges<F, I>(
48
2134
        initial_vertex: VertexIndex,
49
2134
        owner: Vec<Player>,
50
2134
        mut priority: Vec<Priority>,
51
2134
        make_total: bool,
52
2134
        mut edges: F,
53
2134
    ) -> Self
54
2134
    where
55
2134
        F: FnMut() -> I,
56
2134
        I: Iterator<Item = (VertexIndex, VertexIndex)>,
57
    {
58
2134
        let num_of_vertices = owner.len();
59
2134
        debug_assert_eq!(
60
2134
            priority.len(),
61
            num_of_vertices,
62
            "Owner and priority vectors should have the same length"
63
        );
64

            
65
2134
        let mut vertices = Vec::new();
66
2134
        vertices.resize_with(num_of_vertices, Default::default);
67
2134
        debug_assert!(
68
2134
            initial_vertex.value() < num_of_vertices,
69
            "Initial vertex index {} out of bounds {num_of_vertices}",
70
            initial_vertex.value()
71
        );
72

            
73
        // Count the number of transitions for every state
74
2134
        let mut num_of_edges = 0;
75
107405
        for (from, to) in edges() {
76
            // Ensure that the states vector is large enough.
77
107405
            if vertices.len() <= *from.max(to) {
78
                vertices.resize_with(*from.max(to) + 1, || 0);
79
107405
            }
80

            
81
107405
            vertices[*from] += 1;
82
107405
            num_of_edges += 1;
83

            
84
107405
            debug_assert!(
85
107405
                *from < num_of_vertices && *to < num_of_vertices,
86
                "Vertex index out of bounds: from {:?}, to {:?}, num_of_vertices {}",
87
                from,
88
                to,
89
                num_of_vertices
90
            );
91
        }
92

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

            
98
        // If make_total is true, reserve space for self-loops on vertices with no outgoing edges
99
2134
        if make_total {
100
77306
            for count in vertices.iter_mut() {
101
77306
                if *count == 0 {
102
17087
                    *count = 1;
103
17087
                    num_of_edges += 1;
104
60219
                }
105
            }
106
200
        }
107

            
108
        // Sets the offset for every state into the edge arrays.
109
79306
        vertices.iter_mut().fold(0, |count, start| {
110
79306
            let result = count + *start;
111
79306
            *start = count;
112
79306
            result
113
79306
        });
114

            
115
        // Place the transitions, and increment the end for every state.
116
2134
        let mut edges_to = vec![VertexIndex::new(0); num_of_edges];
117
107405
        for (from, to) in edges() {
118
107405
            let start = &mut vertices[*from];
119
107405
            edges_to[*start] = to;
120
107405
            *start += 1;
121
107405
        }
122

            
123
        // If make_total is true, add self-loops for vertices that had no outgoing edges
124
2134
        if make_total {
125
77306
            for vertex_idx in 0..num_of_vertices {
126
77306
                let start = vertices[vertex_idx];
127
77306
                let previous = if vertex_idx > 0 { vertices[vertex_idx - 1] } else { 0 };
128
77306
                if start == previous {
129
17087
                    // No outgoing edges, add self-loop
130
17087
                    edges_to[start] = VertexIndex::new(vertex_idx);
131
17087
                    vertices[vertex_idx] += 1; // Increment end offset
132
17087

            
133
17087
                    // Change the priority of the vertex such that the self-loop is winning for the opponent.
134
17087
                    priority[vertex_idx] = Priority::new(owner[vertex_idx].opponent().to_index());
135
60219
                }
136
            }
137
200
        }
138

            
139
        // Reset the offset to the start.
140
79306
        vertices.iter_mut().fold(0, |previous, start| {
141
79306
            let result = *start;
142
79306
            *start = previous;
143
79306
            result
144
79306
        });
145

            
146
2134
        vertices.push(num_of_edges); // Sentinel vertex
147
2134
        Self::new(initial_vertex, owner, priority, vertices, edges_to)
148
2134
    }
149

            
150
    /// Constructs a parity game directly from the given arrays.
151
3273
    pub(crate) fn new(
152
3273
        initial_vertex: VertexIndex,
153
3273
        owner: Vec<Player>,
154
3273
        priority: Vec<Priority>,
155
3273
        vertices: Vec<usize>,
156
3273
        edges_to: Vec<VertexIndex>,
157
3273
    ) -> Self {
158
3273
        let result = Self {
159
3273
            owner,
160
3273
            priority,
161
3273
            vertices,
162
3273
            edges_to,
163
3273
            initial_vertex,
164
3273
        };
165
3273
        result.assert_consistent();
166
3273
        result
167
3273
    }
168

            
169
    /// Returns the vertices array.
170
125908
    pub(crate) fn vertices(&self) -> &Vec<usize> {
171
125908
        &self.vertices
172
125908
    }
173

            
174
    /// Returns the edges_to array.
175
62954
    pub(crate) fn edges_to(&self) -> &Vec<VertexIndex> {
176
62954
        &self.edges_to
177
62954
    }
178

            
179
    /// Returns the owners array.
180
318
    pub(crate) fn owners(&self) -> &Vec<Player> {
181
318
        &self.owner
182
318
    }
183

            
184
    /// Returns the priorities array.
185
1021
    pub(crate) fn priorities(&self) -> &Vec<Priority> {
186
1021
        &self.priority
187
1021
    }
188

            
189
    /// Asserts that the internal data structures are consistent with each other.
190
3273
    fn assert_consistent(&self) {
191
        // Check that the sizes are consistent
192
3273
        debug_assert_eq!(
193
3273
            self.owner.len(),
194
3273
            self.priority.len(),
195
            "There should an owner and priority for every vertex"
196
        );
197
3273
        debug_assert_eq!(
198
3273
            self.vertices.len(),
199
3273
            self.owner.len() + 1,
200
            "There should be an offset for every vertex, and the sentinel state"
201
        );
202
3273
        debug_assert_eq!(self.initial_vertex, 0, "The initial vertex should be vertex 0");
203

            
204
        // Check that there are no duplicate edges
205
        #[cfg(debug_assertions)]
206
        {
207
3273
            let mut seen = HashSet::new();
208
105220
            for vertex in self.iter_vertices() {
209
105220
                seen.clear();
210
162487
                for edge in self.outgoing_edges(vertex) {
211
162487
                    if !seen.insert(edge.to()) {
212
                        panic!("Duplicate edge from vertex {:?} to vertex {:?}", vertex, edge.to());
213
162487
                    }
214
                }
215
            }
216
        }
217
3273
    }
218
}
219

            
220
impl PG for ParityGame {
221
    type Label = ();
222

            
223
2972
    fn initial_vertex(&self) -> VertexIndex {
224
2972
        self.initial_vertex
225
2972
    }
226

            
227
89791
    fn num_of_vertices(&self) -> usize {
228
89791
        self.owner.len()
229
89791
    }
230

            
231
4838
    fn num_of_edges(&self) -> usize {
232
4838
        self.edges_to.len()
233
4838
    }
234

            
235
18461
    fn iter_vertices(&self) -> impl Iterator<Item = VertexIndex> + '_ {
236
18461
        (0..self.num_of_vertices()).map(VertexIndex::new)
237
18461
    }
238

            
239
862796
    fn outgoing_edges<'a>(&'a self, state_index: VertexIndex) -> impl Iterator<Item = Edge<'a, ()>> + 'a {
240
862796
        let start = self.vertices[*state_index];
241
862796
        let end = self.vertices[*state_index + 1];
242

            
243
1353265
        (start..end).map(move |i| Edge::new(&(), self.edges_to[i]))
244
862796
    }
245

            
246
413348
    fn owner(&self, vertex: VertexIndex) -> Player {
247
413348
        self.owner[*vertex]
248
413348
    }
249

            
250
302303
    fn priority(&self, vertex: VertexIndex) -> Priority {
251
302303
        self.priority[*vertex]
252
302303
    }
253

            
254
300
    fn highest_priority(&self) -> Priority {
255
30000
        self.priority.iter().fold(Priority::new(0), |max, p| max.max(*p))
256
300
    }
257

            
258
1333
    fn is_total(&self) -> bool {
259
        // The parity game is total if every vertex has at least one outgoing edge.
260
53210
        self.iter_vertices().all(|v| self.outgoing_edges(v).next().is_some())
261
1333
    }
262
}
263

            
264
impl fmt::Debug for ParityGame {
265
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
266
        writeln!(f, "ParityGame {{")?;
267
        writeln!(f, "  num_vertices: {},", self.num_of_vertices())?;
268
        writeln!(f, "  num_edges: {},", self.num_of_edges())?;
269
        writeln!(f, "  initial_vertex: v{},", *self.initial_vertex)?;
270
        writeln!(f, "  vertices: [")?;
271
        for v in self.iter_vertices() {
272
            let owner = self.owner(v);
273
            let prio = self.priority(v);
274
            write!(
275
                f,
276
                "    {}: ({:?}, priority: {}, outgoing: [",
277
                *v,
278
                owner.to_index(),
279
                *prio
280
            )?;
281

            
282
            write!(f, "{}", self.outgoing_edges(v).map(|edge| edge.to()).format(", "))?;
283
            writeln!(f, "]),")?;
284
        }
285
        writeln!(f, "  ]")?;
286
        writeln!(f, "}}")
287
    }
288
}
289

            
290
/// A trait for parity games.
291
pub trait PG {
292
    type Label;
293

            
294
    /// Returns the initial vertex of the parity game.
295
    fn initial_vertex(&self) -> VertexIndex;
296

            
297
    /// Returns the number of vertices in the parity game.
298
    fn num_of_vertices(&self) -> usize;
299

            
300
    /// Returns the number of edges in the parity game.
301
    fn num_of_edges(&self) -> usize;
302

            
303
    /// Returns the highest priority in the parity game.
304
    fn highest_priority(&self) -> Priority;
305

            
306
    /// Returns an iterator over all vertices in the parity game.
307
    ///
308
    /// Assumes that the returned vertices are in the range 0 to
309
    /// num_of_vertices() - 1.
310
    fn iter_vertices(&self) -> impl Iterator<Item = VertexIndex> + '_;
311

            
312
    /// Returns an iterator over the outgoing edges for the given vertex.
313
    fn outgoing_edges<'a>(&'a self, vertex: VertexIndex) -> impl Iterator<Item = Edge<'a, Self::Label>> + 'a;
314

            
315
    /// Returns the owner of the given vertex.
316
    fn owner(&self, vertex: VertexIndex) -> Player;
317

            
318
    /// Returns the priority of the given vertex.
319
    fn priority(&self, vertex: VertexIndex) -> Priority;
320

            
321
    /// Returns true iff the parity game is total, checks all vertices have at least one outgoing edge.
322
    fn is_total(&self) -> bool;
323
}
324

            
325
/// Represents an edge in a parity game.
326
pub struct Edge<'a, L> {
327
    label: &'a L,
328
    to: VertexIndex,
329
}
330

            
331
impl<'a, L> Edge<'a, L> {
332
    /// Creates a new edge.
333
1477929
    pub fn new(label: &'a L, to: VertexIndex) -> Self {
334
1477929
        Self { label, to }
335
1477929
    }
336

            
337
    /// Returns the label of the edge.
338
150258
    pub fn label(&self) -> &'a L {
339
150258
        self.label
340
150258
    }
341

            
342
1820066
    pub fn to(&self) -> VertexIndex {
343
1820066
        self.to
344
1820066
    }
345
}
346

            
347
/// A wrapper to view a parity game as a graph.
348
pub struct AsGraph<'a, G: PG>(pub &'a G);
349

            
350
/// Every parity game is also a graph.
351
impl<G: PG> Graph for AsGraph<'_, G> {
352
    type VertexIndex = VertexIndex;
353
    type LabelIndex = ();
354

            
355
50310
    fn num_of_vertices(&self) -> usize {
356
50310
        self.0.num_of_vertices()
357
50310
    }
358

            
359
1400
    fn iter_vertices(&self) -> impl Iterator<Item = Self::VertexIndex> {
360
1400
        self.0.iter_vertices()
361
1400
    }
362

            
363
48910
    fn outgoing_edges(
364
48910
        &self,
365
48910
        vertex: <Self as Graph>::VertexIndex,
366
48910
    ) -> impl Iterator<Item = (Self::LabelIndex, Self::VertexIndex)> {
367
48910
        self.0.outgoing_edges(vertex).map(|edge| ((), edge.to()))
368
48910
    }
369
}
370

            
371
#[cfg(test)]
372
mod tests {
373
    use merc_utilities::random_test;
374

            
375
    use crate::PG;
376
    use crate::random_parity_game;
377

            
378
    #[test]
379
1
    fn test_random_parity_game_make_total() {
380
100
        random_test(100, |rng| {
381
100
            let game = random_parity_game(rng, true, 50, 10, 5);
382
100
            assert!(game.is_total());
383
100
        });
384
1
    }
385
}