1
use std::collections::HashMap;
2
use std::fmt;
3

            
4
use crate::PG;
5
use crate::Player;
6
use crate::Set;
7
use crate::VertexIndex;
8

            
9
/// A strategy abstraction used by Zielonka.
10
///
11
/// This allows running the solver with either full strategy construction
12
/// (`Strategy`) or with a zero-cost no-op strategy (`()`).
13
pub trait Strat: Sized {
14
    /// Creates a new empty strategy value.
15
    fn new() -> Self;
16

            
17
    /// Records a strategy move from `from` to `to`.
18
    fn set(&mut self, from: VertexIndex, to: VertexIndex);
19

            
20
    /// Gets the strategy move for `from`, if one is defined.
21
    fn get(&self, from: VertexIndex) -> Option<VertexIndex>;
22

            
23
    /// Removes any strategy move for `from`.
24
    fn remove(&mut self, from: VertexIndex);
25

            
26
    /// Combines two strategy values.
27
    fn union(self, other: Self) -> Self;
28

            
29
    /// Extends with arbitrary choices on unresolved owned vertices.
30
    fn extend_arbitrary<G: PG>(self, pg: &G, vertices: &Set, subgame: &Set, player: Player) -> Self;
31
}
32

            
33
/// Keeps track of a strategy for a player in a parity game.
34
///
35
/// # Details
36
///
37
/// A strategy is a partial function from vertices owned by a player to one of
38
/// their successors.
39
pub struct Strategy {
40
    mapping: HashMap<VertexIndex, VertexIndex>,
41
}
42

            
43
impl Strategy {
44
    /// Creates a new, empty strategy.
45
5550
    pub fn new() -> Self {
46
5550
        Self {
47
5550
            mapping: HashMap::new(),
48
5550
        }
49
5550
    }
50

            
51
    /// Adds a mapping from `from` to `to` in the strategy.
52
28475
    pub fn set(&mut self, from: VertexIndex, to: VertexIndex) {
53
28475
        self.mapping.insert(from, to);
54
28475
    }
55

            
56
    /// Gets the target vertex for the given source vertex, if it is defined.
57
212720
    pub fn get(&self, from: VertexIndex) -> Option<&VertexIndex> {
58
212720
        self.mapping.get(&from)
59
212720
    }
60

            
61
    /// Removes the strategy entry for the given vertex, if it exists.
62
7942
    pub fn remove(&mut self, from: VertexIndex) {
63
7942
        self.mapping.remove(&from);
64
7942
    }
65

            
66
    /// Computes the union of two strategies, assumes that they do not overlap.
67
2525
    pub fn union(mut self, other: Strategy) -> Strategy {
68
        // Add all mappings from the extension strategy to the base strategy
69
8157
        for (&from, &to) in other.iter() {
70
8157
            debug_assert!(
71
8157
                !self.mapping.contains_key(&from),
72
                "Cannot combine strategies with overlapping domains"
73
            );
74
8157
            self.set(from, to);
75
        }
76

            
77
2525
        self
78
2525
    }
79

            
80
    /// Extends the strategy with an arbitrary strategy for the given `player` on the given `vertices`.
81
915
    pub fn extend_arbitrary<G: PG>(mut self, pg: &G, vertices: &Set, subgame: &Set, player: Player) -> Strategy {
82
12121
        for vertex in vertices.iter_ones().map(VertexIndex::new) {
83
12121
            if pg.owner(vertex) == player && self.get(vertex).is_none() {
84
                // Add an arbitrary mapping for this vertex, we can just take the first outgoing edge.
85
2629
                if let Some(edge) = pg.outgoing_edges(vertex).find(|edge| subgame[*edge.to()]) {
86
2161
                    self.set(vertex, edge.to());
87
2161
                }
88
9960
            }
89
        }
90

            
91
915
        self
92
915
    }
93

            
94
    /// Returns an iterator over all (from, to) pairs in the strategy.
95
2525
    pub fn iter(&self) -> impl Iterator<Item = (&VertexIndex, &VertexIndex)> {
96
2525
        self.mapping.iter()
97
2525
    }
98

            
99
    /// Checks that the strategy is only defined for the vertices owned by the
100
    /// given player. Furthermore, ensure that the strategy is defined for all
101
    /// vertices won in the solution for the given player
102
400
    pub fn check_consistent<G: PG>(&self, pg: &G, solution: &Set, player: Player) {
103
40000
        for vertex in pg.iter_vertices() {
104
40000
            if solution[*vertex] && pg.owner(vertex) == player && self.get(vertex).is_none() {
105
                panic!(
106
                    "Strategy is not defined for vertex {:?} owned by {:?}, but is in the winning set.",
107
                    vertex,
108
                    pg.owner(vertex),
109
                );
110
40000
            }
111

            
112
40000
            if self.get(vertex).is_some() && pg.owner(vertex) != player {
113
                panic!(
114
                    "Strategy is defined for vertex {:?} owned by {:?}, but it should be owned by {:?}.",
115
                    vertex,
116
                    pg.owner(vertex),
117
                    player
118
                );
119
40000
            }
120
        }
121
400
    }
122
}
123

            
124
impl Strat for Strategy {
125
5550
    fn new() -> Self {
126
5550
        Self::new()
127
5550
    }
128

            
129
18157
    fn set(&mut self, from: VertexIndex, to: VertexIndex) {
130
18157
        Strategy::set(self, from, to);
131
18157
    }
132

            
133
16208
    fn get(&self, from: VertexIndex) -> Option<VertexIndex> {
134
16208
        Strategy::get(self, from).copied()
135
16208
    }
136

            
137
7942
    fn remove(&mut self, from: VertexIndex) {
138
7942
        Strategy::remove(self, from);
139
7942
    }
140

            
141
2525
    fn union(self, other: Self) -> Self {
142
2525
        Strategy::union(self, other)
143
2525
    }
144

            
145
915
    fn extend_arbitrary<G: PG>(self, pg: &G, vertices: &Set, subgame: &Set, player: Player) -> Self {
146
915
        Strategy::extend_arbitrary(self, pg, vertices, subgame, player)
147
915
    }
148
}
149

            
150
impl Strat for () {
151
17896
    fn new() -> Self {}
152

            
153
31240
    fn set(&mut self, _from: VertexIndex, _to: VertexIndex) {}
154

            
155
7821
    fn get(&self, _from: VertexIndex) -> Option<VertexIndex> {
156
7821
        None
157
7821
    }
158

            
159
3549
    fn remove(&mut self, _from: VertexIndex) {}
160

            
161
7052
    fn union(self, _other: Self) -> Self {}
162

            
163
3484
    fn extend_arbitrary<G: PG>(self, _pg: &G, _vertices: &Set, _subgame: &Set, _player: Player) -> Self {}
164
}
165

            
166
impl Default for Strategy {
167
    fn default() -> Self {
168
        Self::new()
169
    }
170
}
171

            
172
impl fmt::Debug for Strategy {
173
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
174
        writeln!(f, "Strategy {{")?;
175
        for (from, to) in &self.mapping {
176
            writeln!(f, "  v{} -> v{}", from, to)?;
177
        }
178
        writeln!(f, "}}")
179
    }
180
}