mCRL2
Loading...
Searching...
No Matches
ParityGame.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2013 University of Twente
2// Copyright (c) 2009-2013 Michael Weber <michaelw@cs.utwente.nl>
3// Copyright (c) 2009-2013 Maks Verver <maksverver@geocities.com>
4// Copyright (c) 2009-2013 Eindhoven University of Technology
5//
6// Distributed under the Boost Software License, Version 1.0.
7// (See accompanying file LICENSE_1_0.txt or copy at
8// http://www.boost.org/LICENSE_1_0.txt)
9
11
12#include <deque>
13#include <map>
14#include <cstdlib>
15
17 : d_(0), vertex_(NULL), cardinality_(NULL)
18{
19}
20
22{
23 delete[] vertex_;
24 delete[] cardinality_;
25}
26
28{
29 delete[] vertex_;
30 delete[] cardinality_;
31
32 d_ = 0;
33 graph_.clear();
34 vertex_ = NULL;
35 cardinality_ = NULL;
36}
37
39{
40 if (&game == this) return;
41
42 graph_.assign(game.graph_);
43 verti V = graph_.V();
44 reset(V, game.d_);
45 std::copy(game.vertex_, game.vertex_ + V, vertex_);
47}
48
50{
51 delete[] vertex_;
52 delete[] cardinality_;
53
54 vertex_ = v;
55 graph_.assign(g);
56 d_ = 0;
57 for(verti i = 0; i < g.V(); i++)
58 {
59 d_ = std::max(d_, static_cast<int>(v[i].priority + 1));
60 }
61 cardinality_ = new verti[d_];
63}
64
66{
67 delete[] vertex_;
68 delete[] cardinality_;
69
70 d_ = d;
72 cardinality_ = new verti[d_];
73}
74
76{
77 std::fill(cardinality_, cardinality_ + d_, 0);
78 for (verti v = 0; v < num_vertices; ++v)
79 {
81 }
82}
83
84void ParityGame::make_random( verti V, unsigned clustersize, unsigned outdeg,
85 StaticGraph::EdgeDirection edge_dir, int d )
86{
87 graph_.make_random_clustered(clustersize > 0 ? clustersize : V,
88 V, outdeg, edge_dir);
89 if (clustersize > 0) graph_.shuffle_vertices();
90 reset(V, d);
91 for (verti v = 0; v < V; ++v)
92 {
93 vertex_[v].player = (rand()%2 == 0) ? PLAYER_EVEN : PLAYER_ODD;
94 vertex_[v].priority = rand()%d;
95 }
97}
98
100{
101 // For each vertex, invert player and increase priority by one
102 for (verti v = 0; v < graph_.V(); ++v)
103 {
105 vertex_[v].priority = vertex_[v].priority + 1;
106 }
107
108 // Update priority counts (move each on space to the right)
109 verti *new_cardinality = new verti[d_ + 1];
110 new_cardinality[0] = 0;
111 std::copy(cardinality_, cardinality_ + d_, new_cardinality + 1);
112 delete[] cardinality_;
113 cardinality_ = new_cardinality;
114 d_ = d_ + 1;
115
116 // Try to compress priorities
118}
119
120void ParityGame::shuffle(const std::vector<verti> &perm)
121{
122 // N.B. maximum priority and priorities cardinalities remain unchanged.
123
124 /* NOTE: shuffling could probably be done more efficiently (in-place?)
125 if performance becomes an issue. */
127
128 // Create new vertex info
129 ParityGameVertex *new_vertex = new ParityGameVertex[graph_.V()];
130 for (verti v = 0; v < graph_.V(); ++v) new_vertex[perm[v]] = vertex_[v];
131 delete[] vertex_;
132 vertex_ = new_vertex;
133}
134
135void ParityGame::compress_priorities( const verti cardinality[],
136 bool preserve_parity )
137{
139
140 // Quickly check if we have anything to compress first:
141 if ( empty() || std::find( cardinality + preserve_parity,
142 cardinality + d_, 0 ) == cardinality + d_ )
143 {
144 return;
145 }
146
147 // Find out how to map old priorities to new priorities
148 std::vector<int> prio_map(d_, -1);
149 int first_prio = 0, last_prio = 0;
150 if (!preserve_parity)
151 {
152 // Find lowest priority in use:
153 while (cardinality[first_prio] == 0) ++first_prio;
154 assert(first_prio < d_); // fails only if cardinality count is invalid!
155 }
156 int swap_players = first_prio%2;
157 prio_map[first_prio] = last_prio;
158 for (int p = first_prio + 1; p < d_; ++p)
159 {
160 if (cardinality[p] == 0) continue; // remove priority p
161 if ((last_prio ^ p)%2 != swap_players) ++last_prio;
162 prio_map[p] = last_prio;
163 }
164
165 // Update priority limit and cardinality counts
166 int new_d = last_prio + 1;
167 verti *new_cardinality = new verti[new_d];
168 std::fill(new_cardinality, new_cardinality + new_d, 0);
169 for (int p = 0; p < d_; ++p)
170 {
171 if (prio_map[p] >= 0)
172 {
173 new_cardinality[prio_map[p]] += cardinality_[p];
174 }
175 }
176 delete[] cardinality_;
177 cardinality_ = new_cardinality;
178 d_ = new_d;
179
180 // Remap priorities and players of all vertices
181 for (verti v = 0; v < graph_.V(); ++v)
182 {
183 assert(prio_map[vertex_[v].priority] >= 0);
184 vertex_[v].priority = prio_map[vertex_[v].priority];
185 if (0 != swap_players) vertex_[v].player = opponent(vertex_[v].player);
186 }
187
188 return;
189}
190
193{
194 int p = priority(v), q = 0;
195 for ( ; it != end; ++it)
196 {
197 verti w = *it;
198 int r = priority(w);
199 if (r >= p) return 0;
200 if (r > q) q = r;
201 }
202 vertex_[v].priority = q;
203 --cardinality_[p];
204 ++cardinality_[q];
205 return p - q;
206}
207
208/* N.B. this method is designed to be reasonably fast and use little memory
209 in the common case that few priorities can be propagated, which is why the
210 algorithm starts with a first pass looking for vertices which can be
211 updated, rather than putting them all in the initial queue, which would be
212 simpler but require more memory up-front. */
214{
215 long long res = 0;
216 std::deque<verti> todo;
217
218 // Make an initial pass to look for updatable vertices:
219 for (verti v = 0; v < graph_.V(); ++v)
220 {
221 if (priority(v) > 0)
222 {
223 int change = propagate_priority(v, graph_.succ_begin(v),
224 graph_.succ_end(v) )
226 graph_.pred_end(v) );
227 if (change > 0) {
228 res += change;
229 todo.push_back(v);
230 }
231 }
232 }
233
234 // Check neighbours of updated vertices again:
235 while (!todo.empty())
236 {
237 verti w = todo.front();
238 priority_t p = priority(w);
239 todo.pop_front();
240
241 // Perform backwards propagation on predecessors:
243 it != graph_.pred_end(w); ++it )
244 {
245 verti v = *it;
246 if (priority(v) > p)
247 {
248 int change = propagate_priority(v, graph_.succ_begin(v),
249 graph_.succ_end(v) );
250 if (change > 0) {
251 res += change;
252 todo.push_back(v);
253 }
254 }
255 }
256
257 // Perform forwards propagation on successors:
259 it != graph_.succ_end(w); ++it )
260 {
261 verti v = *it;
262 if (priority(v) > p)
263 {
264 int change = propagate_priority(v, graph_.pred_begin(v),
265 graph_.pred_end(v) );
266 if (change > 0) {
267 res += change;
268 todo.push_back(v);
269 }
270 }
271 }
272 }
273
274 return res;
275}
276
278{
279 for (verti v = 0; v < graph_.V(); ++v)
280 {
281 if (graph_.succ_begin(v) == graph_.succ_end(v)) return false;
282 }
283 return true;
284}
285
287{
288 using std::swap;
289 swap(d_, pg.d_);
290 swap(graph_, pg.graph_);
291 swap(vertex_, pg.vertex_);
293}
294
295#ifdef WITH_THREADS
296void ParityGame::make_subgame_threads( const ParityGame &game,
297 const verti *verts,
298 const verti nvert,
299 bool proper,
301{
302 assert(this != &game);
303 reset(nvert, game.d());
304
305 //#pragma omp parallel for
306 for (verti v = 0; v < nvert; ++v)
307 {
308 vertex_[v] = game.vertex_[verts[v]];
309 }
310
311 graph_.make_subgraph_threads(game.graph_, verts, nvert, proper, edge_dir);
312
313 // FIXME: parallellize this?
315}
316#endif
std::size_t verti
type used to number vertices
Definition Graph.h:24
std::size_t priority_t
Definition ParityGame.h:32
@ PLAYER_ODD
Odd (1)
Definition ParityGame.h:36
@ PLAYER_EVEN
Even (0)
Definition ParityGame.h:35
player_t opponent(const player_t p)
Definition ParityGame.h:40
priority_t priority(verti v) const
Definition ParityGame.h:259
verti cardinality(int p) const
Definition ParityGame.h:266
priority_t d() const
Definition ParityGame.h:253
void clear()
Player player(verti v) const
Definition ParityGame.h:262
bool empty() const
Definition ParityGame.h:115
void swap(ParityGame &pg)
void reset(verti V, int d)
long long propagate_priorities()
StaticGraph graph_
Definition ParityGame.h:318
void assign(const ParityGame &game)
verti * cardinality_
Definition ParityGame.h:325
bool proper() const
void shuffle(const std::vector< verti > &perm)
void recalculate_cardinalities(verti num_vertices)
int propagate_priority(verti v, StaticGraph::const_iterator it, StaticGraph::const_iterator end)
void compress_priorities(const verti cardinality[]=0, bool preserve_parity=true)
void make_dual()
ParityGameVertex * vertex_
Definition ParityGame.h:321
void make_random(verti V, unsigned clustersize, unsigned outdeg, StaticGraph::EdgeDirection edge_dir, int d)
const_iterator succ_end(verti v) const
Definition Graph.h:193
void make_random_clustered(verti cluster_size, verti V, unsigned outdeg, EdgeDirection edge_dir)
Definition Graph.cpp:191
const_iterator succ_begin(verti v) const
Definition Graph.h:188
void make_subgraph_threads(const StaticGraph &graph, const verti *verts, const verti nvert, bool proper, EdgeDirection edge_dir=EDGE_NONE)
verti V() const
Definition Graph.h:179
void assign(const StaticGraph &graph)
Definition Graph.cpp:288
const_iterator pred_begin(verti v) const
Definition Graph.h:198
void shuffle_vertices()
Definition Graph.cpp:269
EdgeDirection
Definition Graph.h:84
void clear()
Definition Graph.cpp:30
const_iterator pred_end(verti v) const
Definition Graph.h:203
const verti * const_iterator
Definition Graph.h:66
void swap(atermpp::unprotected_aterm_core &t1, atermpp::unprotected_aterm_core &t2) noexcept
Swaps two aterms.
Definition aterm.h:462
player_t player
the vertex owner (i.e. next player to move)
Definition ParityGame.h:62
priority_t priority
the priority of the vertex between 0 and d (exclusive).
Definition ParityGame.h:65