Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/signals/test/random_signal_system.cpp @ 29

Last change on this file since 29 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 12.6 KB
Line 
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.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}
Note: See TracBrowser for help on using the repository browser.