mCRL2
Loading...
Searching...
No Matches
Graph.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
10#include "mcrl2/pg/SCC.h"
11#include "mcrl2/pg/shuffle.h"
13
14
16 : successors_(NULL), predecessors_(NULL),
17 successor_index_(NULL), predecessor_index_(NULL)
18{
19 reset(0, 0, EDGE_NONE);
20}
21
23{
24 delete[] successors_;
25 delete[] predecessors_;
26 delete[] successor_index_;
27 delete[] predecessor_index_;
28}
29
31{
32 reset(0, 0, EDGE_NONE);
33}
34
36{
37 V_ = V;
38 E_ = E;
40
41 delete[] successors_;
42 delete[] predecessors_;
43 delete[] successor_index_;
44 delete[] predecessor_index_;
45
47 {
48 successors_ = new verti[E];
49 successor_index_ = new edgei[V + 1];
50 for (verti v = 0; v <= V; ++v) successor_index_[v] = 0;
51 }
52 else
53 {
54 successors_ = NULL;
55 successor_index_ = NULL;
56 }
57
59 {
60 predecessors_ = new verti[E];
61 predecessor_index_ = new edgei[V + 1];
62 for (verti v = 0; v <= V; ++v) predecessor_index_[v] = 0;
63 }
64 else
65 {
66 predecessors_ = NULL;
67 predecessor_index_ = NULL;
68 }
69}
70
71static bool edge_cmp_forward ( const std::pair<verti, verti> &a,
72 const std::pair<verti, verti> &b )
73{
74 return a.first < b.first || (a.first == b.first && a.second < b.second);
75}
76
77static bool edge_cmp_backward( const std::pair<verti, verti> &a,
78 const std::pair<verti, verti> &b )
79{
80 return a.second < b.second || (a.second == b.second && a.first < b.first);
81}
82
84{
85 SCCs sccs;
86 decompose_graph(*this, sccs);
87
88 /* If we happen to have a single SCC by luck, we are done too: */
89 if (sccs.size() <= 1) return;
90
91 /* Otherwise, identify `top` and `bottom` components: */
92 std::vector<verti> index(V_, NO_VERTEX);
93 for (verti i = 0; i < sccs.size(); ++i)
94 {
95 const std::vector<verti> scc;
96 for (verti j = 0; j < scc.size(); ++j)
97 {
98 index[scc[j]] = i;
99 }
100 }
101 std::vector<char> is_top(sccs.size(), 1),
102 is_bot(sccs.size(), 1);
103 for (verti v = 0; v < V_; ++v)
104 {
105 for (const_iterator it = succ_begin(v); it != succ_end(v); ++it)
106 {
107 verti w = *it;
108 if (index[v] != index[w])
109 {
110 is_bot[index[v]] = 0;
111 is_top[index[w]] = 0;
112 }
113 }
114 }
115
116 /* Pick one vertex per SCC at random (excluding SCCs that are neither on top
117 nor at the bottom of the hierarchy) and connect them in a cycle. */
118 // FIXME: this creates more edges than strictly necessary!
119 std::vector<verti> vertis;
120 for (verti i = 0; i < sccs.size(); ++i)
121 {
122 if (is_top[i] || is_bot[i])
123 {
124 vertis.push_back(sccs[i][rand()%sccs[i].size()]);
125 }
126 }
127 mCRL2log(mcrl2::log::debug) << "Connecting " << vertis.size()
128 << " of " << V_ << " vertices to create an SCC." << std::endl;
129 shuffle_vector(vertis);
130 for (verti i = 0; i < sccs.size(); ++i)
131 {
132 const verti v = vertis[i],
133 w = vertis[(i + 1)%sccs.size()];
134 edges.push_back(std::make_pair(v, w));
135 }
136}
137
138void StaticGraph::make_random(verti V, unsigned outdeg, EdgeDirection edge_dir,
139 bool scc)
140{
141 if (V < 2)
142 {
143 edge_list edges;
144 assign(edges, edge_dir);
145 return;
146 }
147
148 /* Some assumptions on the RNG output range: */
149 assert(RAND_MAX >= 2*outdeg);
150 assert(RAND_MAX >= V);
151
152 /* Create a random edge set, with at least one outgoing edge per node,
153 and an average outdegree `outdeg`, without any duplicate edges (but
154 possibly with self-edges). */
155 edge_list edges;
156 std::vector<verti> neighbours(V);
157 for (verti i = 0; i < V; ++i) neighbours[i] = i;
158 for (verti i = 0; i < V; ++i)
159 {
160 unsigned N = 1 + rand()%(2*outdeg - 1);
161 if (N >= V - 1) N = V - 1;
162 for (unsigned n = 0; n < N; ++n)
163 {
164 std::swap(neighbours[n], neighbours[n + rand()%(V - n)]);
165 if (neighbours[n] == i) // don't generate loops
166 {
167 std::swap( neighbours[n],
168 neighbours[n + 1 + rand()%(V - n - 1)] );
169 }
170 edges.push_back(std::make_pair(i, neighbours[n]));
171 }
172 }
173
174 /* Create graph from edge set */
175 assign(edges, edge_dir);
176
177 if (scc)
178 {
179 /* Turn graph into a single strongly connected component: */
180 make_random_scc(edges);
181 assign(edges, edge_dir);
182#ifdef DEBUG
183 /* Check the resulting graph: */
184 SCCs new_sccs;
185 decompose_graph(*this, new_sccs);
186 assert(new_sccs.size() == 1);
187#endif
188 }
189}
190
192 unsigned outdeg, EdgeDirection edge_dir)
193{
194 assert(cluster_size > 1);
195 std::size_t clusters = V/cluster_size;
196 if (clusters <= 1)
197 {
198 make_random(V, outdeg, edge_dir, true);
199 return;
200 }
201
202 // Build `clusters` initial random graphs of cluster_size each:
203 StaticGraph *subgraphs = new StaticGraph[clusters];
204 for (std::size_t i = 0; i < clusters; ++i)
205 {
206 subgraphs[i].make_random( cluster_size + (i < V%cluster_size),
207 outdeg, edge_dir, true );
208 }
209
210 // Iteratively merge clusters:
211 for (int i = 0; clusters > 1; ++i)
212 {
213 mCRL2log(mcrl2::log::verbose) << "Generating clustered random game level "
214 << i << "..." << std::endl;
215 std::size_t next_clusters = (clusters + cluster_size - 1)/cluster_size;
216 StaticGraph *next_subgraphs = new StaticGraph[next_clusters];
217 std::vector<verti> offset(clusters, 0);
218 for (std::size_t c = 0; c < next_clusters; ++c)
219 {
220 /* Combine clusters [i:j) into one: */
221 std::size_t i = c*clusters/next_clusters,
222 j = (c + 1)*clusters/next_clusters;
223 mCRL2log(mcrl2::log::debug) << "combining " << j-i << " subgraphs ("
224 << i << " through " << j << " of "
225 << clusters << ")" << std::endl;
226
227 /* Calculate offsets to apply to vertex indices: */
228 for (std::size_t k = i + 1; k < j; ++k)
229 {
230 offset[k] = offset[k - 1] + subgraphs[k - 1].V();
231 }
232
233 /* Build edge list of combined subgraphs: */
234 edge_list edges;
235 for (std::size_t k = i; k < j; ++k)
236 {
237 edge_list subedges = subgraphs[k].get_edges();
238 for ( edge_list::const_iterator it = subedges.begin();
239 it != subedges.end(); ++it )
240 {
241 edges.push_back(std::make_pair( it->first + offset[k],
242 it->second + offset[k] ));
243 }
244 }
245
246 /* Create parent graph and use its edges to connect subgraphs: */
247 StaticGraph parent;
248 parent.make_random(j - i, outdeg, edge_dir, true);
249 edge_list paredges = parent.get_edges();
250 for (std::size_t e = 0; e < paredges.size(); ++e)
251 {
252 verti v = paredges[e].first,
253 w = paredges[e].second;
254 edges.push_back(std::make_pair(
255 offset[i + v] + rand()%subgraphs[i + v].V(),
256 offset[i + w] + rand()%subgraphs[i + w].V() ));
257 }
258 next_subgraphs[c].assign(edges, edge_dir);
259 }
260 delete[] subgraphs;
261 subgraphs = next_subgraphs;
262 clusters = next_clusters;
263 }
264 assert(clusters == 1);
265 swap(subgraphs[0]);
266 delete[] subgraphs;
267}
268
270{
271 std::vector<verti> perm(V_);
272 for (verti i = 0; i < V_; ++i) perm[i] = i;
273 shuffle_vector(perm);
274 shuffle_vertices(perm);
275}
276
277void StaticGraph::shuffle_vertices(const std::vector<verti> &perm)
278{
279 edge_list edges = get_edges();
280 for (edge_list::iterator it = edges.begin(); it != edges.end(); ++it)
281 {
282 it->first = perm[it->first];
283 it->second = perm[it->second];
284 }
285 assign(edges, edge_dir_);
286}
287
289{
290 if (&graph == this) return;
291
292 reset(graph.V_, graph.E_, graph.edge_dir_);
293
295 {
296 std::copy(graph.successors_, graph.successors_ + E_, successors_);
297 std::copy(graph.successor_index_, graph.successor_index_ + V_ + 1,
299 }
301 {
302 std::copy(graph.predecessors_, graph.predecessors_ + E_, predecessors_);
303 std::copy(graph.predecessor_index_, graph.predecessor_index_ + V_ + 1,
305 }
306}
307
309{
310 // Find number of vertices
311 verti V = 0;
312 for (edge_list::iterator it = edges.begin(); it != edges.end(); ++it)
313 {
314 if (it->first >= V) V = it->first + 1;
315 if (it->second >= V) V = it->second + 1;
316 }
317
318 // Count number of vertices
319 edgei E = (edgei)edges.size();
320 assert(E == edges.size()); /* detect integer overflow */
321
322 /* Reallocate memory */
323 reset(V, E, edge_dir);
324
326 {
327 /* Sort edges by predecessor first, successor second */
328 if (!std::is_sorted(edges.begin(), edges.end(), edge_cmp_forward))
329 {
330 std::sort(edges.begin(), edges.end(), edge_cmp_forward);
331 }
332
333 /* Create successor index */
334 edgei pos = 0;
335 for (verti v = 0; v < V; ++v)
336 {
337 while (pos < E && edges[pos].first < v) ++pos;
338 successor_index_[v] = pos;
339 }
341
342 /* Create successor list */
343 for (edgei e = 0; e < E; ++e) successors_[e] = edges[e].second;
344 }
345
347 {
348 /* Sort edges by successor first, predecessor second */
349 std::sort(edges.begin(), edges.end(), edge_cmp_backward);
350
351 /* Create predecessor index */
352 edgei pos = 0;
353 for (verti v = 0; v < V; ++v)
354 {
355 while (pos < E && edges[pos].second < v) ++pos;
356 predecessor_index_[v] = pos;
357 }
359
360 /* Create predecessor list */
361 for (edgei e = 0; e < E; ++e) predecessors_[e] = edges[e].first;
362 }
363}
364
366{
367 // Add end-of-list marker:
368 edges.push_back(std::make_pair(V_, V_));
369
371 {
372 // Sort edges by predecessor first, successor second
373 if (!std::is_sorted(edges.begin(), edges.end(), edge_cmp_forward))
374 {
375 std::sort(edges.begin(), edges.end(), edge_cmp_forward);
376 }
377
378 // Loop over existing edges and remove those listed in `edges`:
379 StaticGraph::edge_list::const_iterator it = edges.begin();
380 const verti *p = successors_;
381 verti v = 0;
382 edgei e = 0;
383 while (v < V_)
384 {
385 if (p == successors_ + successor_index_[v + 1])
386 {
387 successor_index_[++v] = e;
388 continue;
389 }
390 std::pair<verti, verti> edge(v, *p++);
391 while (edge_cmp_forward(*it, edge)) ++it;
392 if (*it == edge) ++it; else successors_[e++] = edge.second;
393 }
394 }
395
397 {
398 // Sort edges by successor first, predecessor second
399 std::sort(edges.begin(), edges.end(), edge_cmp_backward);
400
401 // Loop over existing edges and remove those listed in `edges`:
402 StaticGraph::edge_list::const_iterator it = edges.begin();
403 const verti *p = predecessors_;
404 verti v = 0;
405 edgei e = 0;
406 while (v < V_)
407 {
408 if (p == predecessors_ + predecessor_index_[v + 1])
409 {
410 predecessor_index_[++v] = e;
411 continue;
412 }
413 std::pair<verti, verti> edge(*p++, v);
414 while (edge_cmp_backward(*it, edge)) ++it;
415 if (*it == edge) ++it; else predecessors_[e++] = edge.first;
416 }
417 }
418
419 // Remove end-of-list marker:
420 edges.pop_back();
421
422 // Update edge count
424 {
426 {
428 }
430 }
431 else
432 {
433 assert(edge_dir_ & EDGE_PREDECESSOR);
435 }
436}
437
439{
440 assert(edge_dir_ & EDGE_SUCCESSOR); // successor info required for now!
441
442 edge_list result;
443 result.reserve(E_);
444 for (verti v = 0; v < V_; ++v)
445 {
446 edgei begin = successor_index_[v], end = successor_index_[v + 1];
447 for (edgei i = begin; i < end; ++i)
448 {
449 verti w = successors_[i];
450 result.push_back(std::make_pair(v, w));
451 }
452 }
453 assert(result.size() == E_);
454 return result;
455}
456
457void StaticGraph::write_raw(std::ostream &os) const
458{
459 os.write((const char*)&V_, sizeof(V_));
460 os.write((const char*)&E_, sizeof(E_));
461 os.write((const char*)&edge_dir_, sizeof(edge_dir_));
463 {
464 os.write((const char*)successors_, sizeof(verti)*E_);
465 os.write((const char*)successor_index_, sizeof(edgei)*(V_ + 1));
466 }
468 {
469 os.write((const char*)predecessors_, sizeof(verti)*E_);
470 os.write((const char*)predecessor_index_, sizeof(edgei)*(V_ + 1));
471 }
472}
473
474void StaticGraph::read_raw(std::istream &is)
475{
476 verti V;
477 edgei E;
479
480 is.read((char*)&V, sizeof(V));
481 is.read((char*)&E, sizeof(E));
482 is.read((char*)&edge_dir, sizeof(edge_dir));
483
484 reset(V, E, edge_dir);
485
487 {
488 is.read((char*)successors_, sizeof(verti)*E_);
489 is.read((char*)successor_index_, sizeof(edgei)*(V_ + 1));
490 }
492 {
493 is.read((char*)predecessors_, sizeof(verti)*E_);
494 is.read((char*)predecessor_index_, sizeof(edgei)*(V_ + 1));
495 }
496}
497
499{
500 if (this == &g) return;
501 std::swap(V_, g.V_);
502 std::swap(E_, g.E_);
508}
509
510#ifdef WITH_THREADS
512 const verti *verts,
513 const verti num_vertices,
514 bool proper,
515 EdgeDirection edge_dir )
516{
517 assert(this != &graph);
518
519 edgei num_edges = 0;
520
521 // Create a map of old->new vertex indices:
522 std::vector<verti> map(graph.V(), NO_VERTEX);
523 #pragma omp parallel
524 {
525 #pragma omp for
526 for (verti i = 0; i < num_vertices; ++i)
527 {
528 map[verts[i]] = i;
529 }
530
531 // Count number of new edges:
532 #pragma omp for reduction(+:num_edges)
533 for (verti i = 0; i < num_vertices; ++i)
534 {
535 const_iterator a = graph.succ_begin(verts[i]),
536 b = graph.succ_end(verts[i]);
537 while (a != b) if (map[*a++] != NO_VERTEX) ++num_edges;
538 }
539 }
540
541 // Allocate memory:
542 reset(num_vertices, num_edges, edge_dir ? edge_dir : graph.edge_dir());
543
544 //
545 // TODO: parallellize rest of function!
546 //
547
549 {
550 // Assign new successors:
551 verti v = 0;
552 edgei e = 0;
553 for (verti i = 0; i < num_vertices; ++i)
554 {
555 const verti u = verts[i];
556 successor_index_[v++] = e;
557 verti *begin = &successors_[e];
558 for (const_iterator succ_it = graph.succ_begin(u),
559 succ_end = graph.succ_end(u);
560 succ_it != succ_end; ++succ_it)
561 {
562 verti w = map[*succ_it];
563 if (w != NO_VERTEX) successors_[e++] = w;
564 }
565 verti *end = &successors_[e];
566 if (!std::is_sorted(begin, end, std::less<verti>()))
567 {
568 std::sort(begin, end);
569 }
570 if (proper) assert(begin != end); /* proper parity game graph */
571 }
572 assert(v == V_ && e == E_);
573 successor_index_[v] = e;
574 }
575
577 {
578 // Assign new predecessors:
579 verti v = 0;
580 edgei e = 0;
581 for (verti i = 0; i < num_vertices; ++i)
582 {
583 const verti u = verts[i];
584 predecessor_index_[v++] = e;
585 verti *begin = &predecessors_[e];
586 for (const_iterator pred_it = graph.pred_begin(u),
587 pred_end = graph.pred_end(u);
588 pred_it != pred_end; ++pred_it)
589 {
590 verti w = map[*pred_it];
591 if (w != NO_VERTEX) predecessors_[e++] = w;
592 }
593 verti *end = &predecessors_[e];
594 if (!std::is_sorted(begin, end, std::less<verti>()))
595 {
596 std::sort(begin, end);
597 }
598 }
599 assert(v == V_ && e == E_);
600 predecessor_index_[v] = e;
601 }
602}
603#endif
static bool edge_cmp_backward(const std::pair< verti, verti > &a, const std::pair< verti, verti > &b)
Definition Graph.cpp:77
static bool edge_cmp_forward(const std::pair< verti, verti > &a, const std::pair< verti, verti > &b)
Definition Graph.cpp:71
std::size_t edgei
type used to number edges
Definition Graph.h:25
std::size_t verti
type used to number vertices
Definition Graph.h:24
#define NO_VERTEX
Definition Graph.h:27
Definition SCC.h:54
std::size_t size() const
Definition SCC.h:62
std::vector< std::pair< verti, verti > > edge_list
Definition Graph.h:74
void make_random(verti V, unsigned outdeg, EdgeDirection edge_dir, bool scc)
Definition Graph.cpp:138
verti * successors_
Definition Graph.h:278
const_iterator succ_end(verti v) const
Definition Graph.h:193
~StaticGraph()
Definition Graph.cpp:22
void reset(verti V, edgei E, EdgeDirection edge_dir)
Definition Graph.cpp:35
EdgeDirection edge_dir() const
Definition Graph.h:185
edgei * predecessor_index_
Definition Graph.h:283
verti V_
Definition Graph.h:271
void make_random_clustered(verti cluster_size, verti V, unsigned outdeg, EdgeDirection edge_dir)
Definition Graph.cpp:191
void read_raw(std::istream &is)
Definition Graph.cpp:474
void swap(StaticGraph &g)
Definition Graph.cpp:498
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)
void make_random_scc(edge_list &edges)
Definition Graph.cpp:83
edgei * successor_index_
Definition Graph.h:283
void write_raw(std::ostream &os) const
Definition Graph.cpp:457
verti V() const
Definition Graph.h:179
edge_list get_edges() const
Definition Graph.cpp:438
void assign(const StaticGraph &graph)
Definition Graph.cpp:288
verti * predecessors_
Definition Graph.h:278
void remove_edges(edge_list &edges)
Definition Graph.cpp:365
const_iterator pred_begin(verti v) const
Definition Graph.h:198
void shuffle_vertices()
Definition Graph.cpp:269
EdgeDirection
Definition Graph.h:84
@ EDGE_SUCCESSOR
Definition Graph.h:86
@ EDGE_NONE
Definition Graph.h:85
@ EDGE_PREDECESSOR
Definition Graph.h:87
void clear()
Definition Graph.cpp:30
const_iterator pred_end(verti v) const
Definition Graph.h:203
EdgeDirection edge_dir_
Definition Graph.h:286
const verti * const_iterator
Definition Graph.h:66
edgei E_
Definition Graph.h:272
StaticGraph()
Definition Graph.cpp:15
edgei E() const
Definition Graph.h:182
int decompose_graph(const StaticGraph &graph, Callback &callback)
Definition SCC.h:32
#define mCRL2log(LEVEL)
mCRL2log(LEVEL) provides the stream used to log.
Definition logger.h:391
@ verbose
Definition logger.h:37
void swap(atermpp::unprotected_aterm_core &t1, atermpp::unprotected_aterm_core &t2) noexcept
Swaps two aterms.
Definition aterm.h:462
static void shuffle_vector(std::vector< T > &v)
Definition shuffle.h:21