]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/signals/test/random_signal_system.cpp
Add patch for failing prerm scripts
[ceph.git] / ceph / src / boost / libs / signals / test / random_signal_system.cpp
CommitLineData
7c673cae
FG
1// Boost.Signals library
2
3// Copyright Douglas Gregor 2001-2004. Use, modification and
4// distribution is subject to the Boost Software License, Version
5// 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6// http://www.boost.org/LICENSE_1_0.txt)
7
8// For more information, see http://www.boost.org
9
10#include <boost/signal.hpp>
11#include <boost/graph/adjacency_list.hpp>
12#include <boost/graph/breadth_first_search.hpp>
13#include <boost/graph/dijkstra_shortest_paths.hpp>
14#include <boost/property_map/property_map.hpp>
15#include <boost/random.hpp>
16#include <map>
17#include <set>
18#include <stdlib.h>
19#include <time.h>
20#include <boost/test/minimal.hpp>
21
22using namespace boost;
23using namespace boost::signals;
24
25struct signal_tag {
26 typedef vertex_property_tag kind;
27};
28
29struct connection_tag {
30 typedef edge_property_tag kind;
31};
32
33typedef signal4<void, int, int, double, int&> signal_type;
34typedef adjacency_list<listS, listS, directedS,
35 // Vertex properties
36 property<signal_tag, signal_type*,
37 // property<vertex_color_t, default_color_type,
38 property<vertex_index_t, int> >,
39 // Edge properties
40 property<connection_tag, connection,
41 property<edge_weight_t, int> > >
42 signal_graph_type;
43typedef signal_graph_type::vertex_descriptor vertex_descriptor;
44typedef signal_graph_type::edge_descriptor edge_descriptor;
45
46// The signal graph
47static signal_graph_type signal_graph;
48
49// Mapping from a signal to its associated vertex descriptor
50static std::map<signal_type*, vertex_descriptor> signal_to_descriptor;
51
52// Mapping from a connection to its associated edge descriptor
53static std::map<connection, edge_descriptor> connection_to_descriptor;
54
55std::map<signal_type*, int> min_signal_propagate_distance;
56
57void remove_disconnected_connections()
58{
59 // remove disconnected connections
60 std::map<connection, edge_descriptor>::iterator i =
61 connection_to_descriptor.begin();
62 while (i != connection_to_descriptor.end()) {
63 if (!i->first.connected()) {
64 connection_to_descriptor.erase(i++);
65 }
66 else {
67 ++i;
68 }
69 }
70}
71
72void remove_signal(signal_type* sig)
73{
74 clear_vertex(signal_to_descriptor[sig], signal_graph);
75 remove_vertex(signal_to_descriptor[sig], signal_graph);
76 delete sig;
77 signal_to_descriptor.erase(sig);
78 remove_disconnected_connections();
79}
80
81void random_remove_signal(minstd_rand& rand_gen);
82
83struct tracking_bridge {
84 tracking_bridge(const tracking_bridge& other)
85 : sig(other.sig), rand_gen(other.rand_gen)
86 { ++bridge_count; }
87
88 tracking_bridge(signal_type* s, minstd_rand& rg) : sig(s), rand_gen(rg)
89 { ++bridge_count; }
90
91 ~tracking_bridge()
92 { --bridge_count; }
93
94 void operator()(int cur_dist, int max_dist, double deletion_prob,
95 int& deletions_left) const
96 {
97 if (signal_to_descriptor.find(sig) == signal_to_descriptor.end())
98 return;
99
100 ++cur_dist;
101
102 // Update the directed Bacon distance
103 if (min_signal_propagate_distance.find(sig) ==
104 min_signal_propagate_distance.end()) {
105 min_signal_propagate_distance[sig] = cur_dist;
106 }
107 else if (cur_dist < min_signal_propagate_distance[sig]) {
108 min_signal_propagate_distance[sig] = cur_dist;
109 }
110 else if (deletion_prob == 0.0) {
111 // don't bother calling because we've already found a better route here
112 return;
113 }
114
115 // Maybe delete the signal
116 if (uniform_01<minstd_rand>(rand_gen)() < deletion_prob &&
117 deletions_left-- && signal_to_descriptor.size() > 1) {
118 random_remove_signal(rand_gen);
119 }
120 // propagate the signal
121 else if (cur_dist < max_dist) {
122 (*sig)(cur_dist, max_dist, deletion_prob, deletions_left);
123 }
124 }
125
126 signal_type* sig;
127 minstd_rand& rand_gen;
128 static int bridge_count;
129};
130
131int tracking_bridge::bridge_count = 0;
132
133namespace boost {
134 template<typename V>
135 void visit_each(V& v, const tracking_bridge& t, int)
136 {
137 v(t);
138 v(t.sig);
139 }
140}
141
142signal_type* add_signal()
143{
144 signal_type* sig = new signal_type();
145 vertex_descriptor v = add_vertex(signal_graph);
146 signal_to_descriptor[sig] = v;
147 put(signal_tag(), signal_graph, v, sig);
148
149 return sig;
150}
151
152connection add_connection(signal_type* sig1, signal_type* sig2,
153 minstd_rand& rand_gen)
154{
155 std::cout << " Adding connection: " << sig1 << " -> " << sig2 << std::endl;
156
157 connection c = sig1->connect(tracking_bridge(sig2, rand_gen));
158 edge_descriptor e =
159 add_edge(signal_to_descriptor[sig1], signal_to_descriptor[sig2],
160 signal_graph).first;
161 connection_to_descriptor[c] = e;
162 put(connection_tag(), signal_graph, e, c);
163 put(edge_weight, signal_graph, e, 1);
164 return c;
165}
166
167void remove_connection(connection c)
168{
169 signal_type* sig1 = get(signal_tag(), signal_graph,
170 source(connection_to_descriptor[c], signal_graph));
171 signal_type* sig2 = get(signal_tag(), signal_graph,
172 target(connection_to_descriptor[c], signal_graph));
173 std::cout << " Removing connection: " << sig1 << " -> " << sig2
174 << std::endl;
175 c.disconnect();
176 remove_edge(connection_to_descriptor[c], signal_graph);
177 connection_to_descriptor.erase(c);
178}
179
180bool signal_connection_exists(signal_type* sig1, signal_type* sig2,
181 edge_descriptor& edge_desc)
182{
183 vertex_descriptor source_sig = signal_to_descriptor[sig1];
184 vertex_descriptor target_sig = signal_to_descriptor[sig2];
185 signal_graph_type::out_edge_iterator e;
186 for (e = out_edges(source_sig, signal_graph).first;
187 e != out_edges(source_sig, signal_graph).second; ++e) {
188 if (target(*e, signal_graph) == target_sig) {
189 edge_desc = *e;
190 return true;
191 }
192 }
193 return false;
194}
195
196bool signal_connection_exists(signal_type* sig1, signal_type* sig2)
197{
198 edge_descriptor e;
199 return signal_connection_exists(sig1, sig2, e);
200}
201
202std::map<signal_type*, vertex_descriptor>::iterator
203choose_random_signal(minstd_rand& rand_gen)
204{
205 int signal_idx
206 = uniform_int<>(0, signal_to_descriptor.size() - 1)(rand_gen);
207 std::map<signal_type*, vertex_descriptor>::iterator result =
208 signal_to_descriptor.begin();
209 for(; signal_idx; --signal_idx)
210 ++result;
211
212 return result;
213}
214
215void random_remove_signal(minstd_rand& rand_gen)
216{
217 std::map<signal_type*, vertex_descriptor>::iterator victim =
218 choose_random_signal(rand_gen);
219 std::cout << " Removing signal " << victim->first << std::endl;
220 remove_signal(victim->first);
221}
222
223void random_add_connection(minstd_rand& rand_gen)
224{
225 std::map<signal_type*, vertex_descriptor>::iterator source;
226 std::map<signal_type*, vertex_descriptor>::iterator target;
227 do {
228 source = choose_random_signal(rand_gen);
229 target = choose_random_signal(rand_gen);
230 } while (signal_connection_exists(source->first, target->first));
231
232 add_connection(source->first, target->first, rand_gen);
233}
234
235void random_remove_connection(minstd_rand& rand_gen)
236{
237 int victim_idx =
238 uniform_int<>(0, num_edges(signal_graph)-1)(rand_gen);
239 signal_graph_type::edge_iterator e = edges(signal_graph).first;
240 while (victim_idx--) {
241 ++e;
242 }
243
244 remove_connection(get(connection_tag(), signal_graph, *e));
245}
246
247void random_bacon_test(minstd_rand& rand_gen)
248{
249 signal_type* kevin = choose_random_signal(rand_gen)->first;
250 min_signal_propagate_distance.clear();
251 min_signal_propagate_distance[kevin] = 0;
252
253 const int horizon = 10; // only go to depth 10 at most
254
255 std::cout << " Bacon test: kevin is " << kevin
256 << "\n Propagating signal...";
257
258 // Propagate the signal out to the horizon
259 int deletions_left = 0;
260 (*kevin)(0, horizon, 0.0, deletions_left);
261
262 std::cout << "OK\n Finding shortest paths...";
263
264 // Initialize all colors to white
265 {
266 unsigned int num = 0;
267 for (signal_graph_type::vertex_iterator v = vertices(signal_graph).first;
268 v != vertices(signal_graph).second;
269 ++v) {
270 // put(vertex_color, signal_graph, *v, white_color);
271 put(vertex_index, signal_graph, *v, num++);
272 }
273
274 BOOST_CHECK(num == num_vertices(signal_graph));
275 }
276
277 // Perform a breadth-first search starting at kevin, and record the
278 // distances from kevin to each reachable node.
279 std::map<vertex_descriptor, int> bacon_distance_map;
280
281#if 0
282 bacon_distance_map[signal_to_descriptor[kevin]] = 0;
283 breadth_first_visit(signal_graph, signal_to_descriptor[kevin],
284 visitor(
285 make_bfs_visitor(
286 record_distances(
287 make_assoc_property_map(bacon_distance_map),
288 on_examine_edge()))).
289 color_map(get(vertex_color, signal_graph)));
290#endif
291
292 dijkstra_shortest_paths(signal_graph, signal_to_descriptor[kevin],
293 distance_map(make_assoc_property_map(bacon_distance_map)));
294 std::cout << "OK\n";
295 // Make sure the bacon distances agree (prior to the horizon)
296 {
297 std::map<signal_type*, int>::iterator i;
298 for (i = min_signal_propagate_distance.begin();
299 i != min_signal_propagate_distance.end();
300 ++i) {
301 if (i->second != bacon_distance_map[signal_to_descriptor[i->first]]) {
302 std::cout << "Signal distance to " << i->first << " was "
303 << i->second << std::endl;
304 std::cout << "Graph distance was "
305 << bacon_distance_map[signal_to_descriptor[i->first]]
306 << std::endl;
307 }
308 BOOST_CHECK(i->second == bacon_distance_map[signal_to_descriptor[i->first]]);
309 }
310 }
311}
312
313void randomly_create_connections(minstd_rand& rand_gen, double edge_probability)
314{
315 // Randomly create connections
316 uniform_01<minstd_rand> random(rand_gen);
317 for (signal_graph_type::vertex_iterator v1 = vertices(signal_graph).first;
318 v1 != vertices(signal_graph).second; ++v1) {
319 for (signal_graph_type::vertex_iterator v2 = vertices(signal_graph).first;
320 v2 != vertices(signal_graph).second; ++v2) {
321 if (random() < edge_probability) {
322 add_connection(get(signal_tag(), signal_graph, *v1),
323 get(signal_tag(), signal_graph, *v2),
324 rand_gen);
325 }
326 }
327 }
328}
329
330void random_recursive_deletion(minstd_rand& rand_gen)
331{
332 signal_type* kevin = choose_random_signal(rand_gen)->first;
333 min_signal_propagate_distance.clear();
334 min_signal_propagate_distance[kevin] = 0;
335
336 const int horizon = 4; // only go to depth "horizon" at most
337
338 std::cout << " Recursive deletion test: start is " << kevin << std::endl;
339
340 // Propagate the signal out to the horizon
341 int deletions_left = (int)(0.05*num_vertices(signal_graph));
342 (*kevin)(0, horizon, 0.05, deletions_left);
343}
344
345int test_main(int argc, char* argv[])
346{
347 if (argc < 4) {
348 std::cerr << "Usage: random_signal_system <# of initial signals> "
349 << "<edge probability> <iterations>" << std::endl;
350 return 1;
351 }
352
353 int number_of_initial_signals = atoi(argv[1]);
354 double edge_probability = atof(argv[2]);
355 int iterations = atoi(argv[3]);
356
357 int seed;
358 if (argc == 5)
359 seed = atoi(argv[4]);
360 else
361 seed = time(0);
362
363 std::cout << "Number of initial signals: " << number_of_initial_signals
364 << std::endl;
365 std::cout << "Edge probability: " << edge_probability << std::endl;
366 std::cout << "Iterations: " << iterations << std::endl;
367 std::cout << "Seed: " << seed << std::endl;
368
369 // Initialize random number generator
370 minstd_rand rand_gen;
371 rand_gen.seed(seed);
372
373 for (int iter = 0; iter < iterations; ++iter) {
374 if (num_vertices(signal_graph) < 2) {
375 for (int i = 0; i < number_of_initial_signals; ++i)
376 add_signal();
377 }
378
379 while (num_edges(signal_graph) < 2) {
380 randomly_create_connections(rand_gen, edge_probability);
381 }
382
383 std::cerr << "Iteration #" << (iter+1) << std::endl;
384
385 uniform_int<> random_action(0, 7);
386 switch (random_action(rand_gen)) {
387 case 0:
388 std::cout << " Adding new signal: " << add_signal() << std::endl;
389 break;
390
391 case 1:
392 random_remove_signal(rand_gen);
393 break;
394
395 case 2:
396 if (num_edges(signal_graph) <
397 num_vertices(signal_graph)*num_vertices(signal_graph)) {
398 random_add_connection(rand_gen);
399 }
400 break;
401
402 case 3:
403 random_remove_connection(rand_gen);
404 break;
405
406 case 4:
407 case 5:
408 case 6:
409 random_bacon_test(rand_gen);
410 break;
411
412 case 7:
413 random_recursive_deletion(rand_gen);
414 break;
415 }
416 }
417
418 for (signal_graph_type::vertex_iterator v = vertices(signal_graph).first;
419 v != vertices(signal_graph).second;
420 ++v) {
421 delete get(signal_tag(), signal_graph, *v);
422 }
423
424 BOOST_CHECK(tracking_bridge::bridge_count == 0);
425 if (tracking_bridge::bridge_count != 0) {
426 std::cerr << tracking_bridge::bridge_count << " connections remain.\n";
427 }
428 return 0;
429}