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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            
250
482823
    fn priority(&self, vertex: VertexIndex) -> Priority {
251
482823
        self.priority[*vertex]
252
482823
    }
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
2447
    fn is_total(&self) -> bool {
259
        // The parity game is total if every vertex has at least one outgoing edge.
260
99580
        self.iter_vertices().all(|v| self.outgoing_edges(v).next().is_some())
261
2447
    }
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
1976804
    pub fn new(label: &'a L, to: VertexIndex) -> Self {
334
1976804
        Self { label, to }
335
1976804
    }
336

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

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

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

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