roget_components.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. //=======================================================================
  2. // Copyright 2001 University of Notre Dame.
  3. // Authors: Jeremy G. Siek, Andrew Lumsdaine, Lie-Quan Lee
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See
  6. // accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //=======================================================================
  9. #include <cstdio>
  10. #include <cstring>
  11. #include <iostream>
  12. #include <boost/graph/stanford_graph.hpp>
  13. #include <boost/graph/strong_components.hpp>
  14. #define specs(v) \
  15. (filename ? index_map[v] : v->cat_no) << " " << v->name
  16. int main(int argc, char* argv[])
  17. {
  18. using namespace boost;
  19. Graph* g;
  20. typedef graph_traits<Graph*>::vertex_descriptor vertex_t;
  21. unsigned long n = 0;
  22. unsigned long d = 0;
  23. unsigned long p = 0;
  24. long s = 0;
  25. char* filename = NULL;
  26. int c, i;
  27. while (--argc) {
  28. if (sscanf(argv[argc], "-n%lu", &n) == 1);
  29. else if (sscanf(argv[argc], "-d%lu", &d) == 1);
  30. else if (sscanf(argv[argc], "-p%lu", &p) == 1);
  31. else if (sscanf(argv[argc], "-s%ld", &s) == 1);
  32. else if (strncmp(argv[argc], "-g", 2) == 0)
  33. filename = argv[argc] + 2;
  34. else {
  35. fprintf(stderr, "Usage: %s [-nN][-dN][-pN][-sN][-gfoo]\n", argv[0]);
  36. return -2;
  37. }
  38. }
  39. g = (filename ? restore_graph(filename) : roget(n, d, p, s));
  40. if (g == NULL) {
  41. fprintf(stderr, "Sorry, can't create the graph! (error code %ld)\n",
  42. panic_code);
  43. return -1;
  44. }
  45. printf("Reachability analysis of %s\n\n", g->id);
  46. // - The root map corresponds to what Knuth calls the "min" field.
  47. // - The discover time map is the "rank" field
  48. // - Knuth uses the rank field for double duty, to record the
  49. // discover time, and to keep track of which vertices have
  50. // been visited. The BGL strong_components() function needs
  51. // a separate field for marking colors, so we use the w field.
  52. std::vector<int> comp(num_vertices(g));
  53. property_map<Graph*, vertex_index_t>::type
  54. index_map = get(vertex_index, g);
  55. property_map<Graph*, v_property<vertex_t> >::type
  56. root = get(v_property<vertex_t>(), g);
  57. int num_comp = strong_components
  58. (g, make_iterator_property_map(comp.begin(), index_map),
  59. root_map(root).
  60. discover_time_map(get(z_property<long>(), g)).
  61. color_map(get(w_property<long>(), g)));
  62. std::vector< std::vector<vertex_t> > strong_comp(num_comp);
  63. // First add representative vertices to each component's list
  64. graph_traits<Graph*>::vertex_iterator vi, vi_end;
  65. for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
  66. if (root[*vi] == *vi)
  67. strong_comp[comp[index_map[*vi]]].push_back(*vi);
  68. // Then add the other vertices of the component
  69. for (boost::tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
  70. if (root[*vi] != *vi)
  71. strong_comp[comp[index_map[*vi]]].push_back(*vi);
  72. // We do not print out the "from" and "to" information as Knuth
  73. // does because we no longer have easy access to that information
  74. // from outside the algorithm.
  75. for (c = 0; c < num_comp; ++c) {
  76. vertex_t v = strong_comp[c].front();
  77. std::cout << "Strong component `" << specs(v) << "'";
  78. if (strong_comp[c].size() > 1) {
  79. std::cout << " also includes:\n";
  80. for (i = 1; i < strong_comp[c].size(); ++i)
  81. std::cout << " " << specs(strong_comp[c][i]) << std::endl;
  82. } else
  83. std::cout << std::endl;
  84. }
  85. // Next we print out the "component graph" or "condensation", that
  86. // is, we consider each component to be a vertex in a new graph
  87. // where there is an edge connecting one component to another if there
  88. // is one or more edges connecting any of the vertices from the
  89. // first component to any of the vertices in the second. We use the
  90. // name of the representative vertex as the name of the component.
  91. printf("\nLinks between components:\n");
  92. // This array provides an efficient way to check if we've already
  93. // created a link from the current component to the component
  94. // of the target vertex.
  95. std::vector<int> mark(num_comp, (std::numeric_limits<int>::max)());
  96. // We go in reverse order just to mimic the output ordering in
  97. // Knuth's version.
  98. for (c = num_comp - 1; c >= 0; --c) {
  99. vertex_t u = strong_comp[c][0];
  100. for (i = 0; i < strong_comp[c].size(); ++i) {
  101. vertex_t v = strong_comp[c][i];
  102. graph_traits<Graph*>::out_edge_iterator ei, ei_end;
  103. for (boost::tie(ei, ei_end) = out_edges(v, g); ei != ei_end; ++ei) {
  104. vertex_t x = target(*ei, g);
  105. int comp_x = comp[index_map[x]];
  106. if (comp_x != c && mark[comp_x] != c) {
  107. mark[comp_x] = c;
  108. vertex_t w = strong_comp[comp_x][0];
  109. std::cout << specs(u) << " -> " << specs(w)
  110. << " (e.g., " << specs(v) << " -> " << specs(x) << ")\n";
  111. } // if
  112. } // for
  113. } // for
  114. } // for
  115. }