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
4294
    pub fn from_edges<F, I>(
48
4294
        initial_vertex: VertexIndex,
49
4294
        owner: Vec<Player>,
50
4294
        mut priority: Vec<Priority>,
51
4294
        make_total: bool,
52
4294
        mut edges: F,
53
4294
    ) -> Self
54
4294
    where
55
4294
        F: FnMut() -> I,
56
4294
        I: Iterator<Item = (VertexIndex, VertexIndex)>,
57
    {
58
4294
        let num_of_vertices = owner.len();
59
4294
        debug_assert_eq!(
60
4294
            priority.len(),
61
            num_of_vertices,
62
            "Owner and priority vectors should have the same length"
63
        );
64

            
65
4294
        let mut vertices = Vec::new();
66
4294
        vertices.resize_with(num_of_vertices, Default::default);
67
4294
        debug_assert!(
68
4294
            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
4294
        let mut num_of_edges = 0;
75
172197
        for (from, to) in edges() {
76
            // Ensure that the states vector is large enough.
77
172197
            if vertices.len() <= *from.max(to) {
78
                vertices.resize_with(*from.max(to) + 1, || 0);
79
172197
            }
80

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

            
84
172197
            debug_assert!(
85
172197
                *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
4294
        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
4294
        }
97

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

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

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

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

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

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

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

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

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

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

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

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

            
189
    /// Asserts that the internal data structures are consistent with each other.
190
7293
    fn assert_consistent(&self) {
191
        // Check that the sizes are consistent
192
7293
        debug_assert_eq!(
193
7293
            self.owner.len(),
194
7293
            self.priority.len(),
195
            "There should an owner and priority for every vertex"
196
        );
197
7293
        debug_assert_eq!(
198
7293
            self.vertices.len(),
199
7293
            self.owner.len() + 1,
200
            "There should be an offset for every vertex, and the sentinel state"
201
        );
202
7293
        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
7293
            let mut seen = HashSet::new();
208
206209
            for vertex in self.iter_vertices() {
209
206209
                seen.clear();
210
295839
                for edge in self.outgoing_edges(vertex) {
211
295839
                    if !seen.insert(edge.to()) {
212
                        panic!("Duplicate edge from vertex {:?} to vertex {:?}", vertex, edge.to());
213
295839
                    }
214
                }
215
            }
216
        }
217
7293
    }
218
}
219

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

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

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

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

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

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

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

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

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

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

            
258
3593
    fn is_total(&self) -> bool {
259
        // The parity game is total if every vertex has at least one outgoing edge.
260
123389
        self.iter_vertices().all(|v| self.outgoing_edges(v).next().is_some())
261
3593
    }
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
2304255
    pub fn new(label: &'a L, to: VertexIndex) -> Self {
334
2304255
        Self { label, to }
335
2304255
    }
336

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

            
342
2651966
    pub fn to(&self) -> VertexIndex {
343
2651966
        self.to
344
2651966
    }
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
86411
    fn num_of_vertices(&self) -> usize {
356
86411
        self.0.num_of_vertices()
357
86411
    }
358

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

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