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
5418
    pub fn new() -> Self {
46
5418
        Self {
47
5418
            mapping: HashMap::new(),
48
5418
        }
49
5418
    }
50

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

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

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

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

            
77
2459
        self
78
2459
    }
79

            
80
    /// Extends the strategy with an arbitrary strategy for the given `player` on the given `vertices`.
81
897
    pub fn extend_arbitrary<G: PG>(mut self, pg: &G, vertices: &Set, subgame: &Set, player: Player) -> Strategy {
82
11812
        for vertex in vertices.iter_ones().map(VertexIndex::new) {
83
11812
            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
2497
                if let Some(edge) = pg.outgoing_edges(vertex).find(|edge| subgame[*edge.to()]) {
86
2071
                    self.set(vertex, edge.to());
87
2071
                }
88
9741
            }
89
        }
90

            
91
897
        self
92
897
    }
93

            
94
    /// Returns an iterator over all (from, to) pairs in the strategy.
95
2459
    pub fn iter(&self) -> impl Iterator<Item = (&VertexIndex, &VertexIndex)> {
96
2459
        self.mapping.iter()
97
2459
    }
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
5418
    fn new() -> Self {
126
5418
        Self::new()
127
5418
    }
128

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

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

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

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

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

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

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

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

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

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

            
163
5224
    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
}