File: roget_components.cpp

package info (click to toggle)
boost 1.33.1-10
  • links: PTS
  • area: main
  • in suites: etch, etch-m68k
  • size: 100,948 kB
  • ctags: 145,103
  • sloc: cpp: 573,492; xml: 49,055; python: 15,626; ansic: 13,588; sh: 2,099; yacc: 858; makefile: 660; perl: 427; lex: 111; csh: 6
file content (132 lines) | stat: -rw-r--r-- 4,862 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//=======================================================================
// Copyright 2001 University of Notre Dame.
// Authors: Jeremy G. Siek, Andrew Lumsdaine, Lie-Quan Lee
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//=======================================================================

#include <stdio.h>
#include <iostream>
#include <boost/graph/stanford_graph.hpp>
#include <boost/graph/strong_components.hpp>

#define specs(v) \
 (filename ? index_map[v] : v->cat_no) << " " << v->name

int main(int argc, char* argv[])
{
  using namespace boost;
  Graph* g;
  typedef graph_traits<Graph*>::vertex_descriptor vertex_t;
  unsigned long n = 0;
  unsigned long d = 0;
  unsigned long p = 0;
  long s = 0;
  char* filename = NULL;
  int c, i;

  while (--argc) {
    if (sscanf(argv[argc], "-n%lu", &n) == 1);
    else if (sscanf(argv[argc], "-d%lu", &d) == 1);
    else if (sscanf(argv[argc], "-p%lu", &p) == 1);
    else if (sscanf(argv[argc], "-s%ld", &s) == 1);
    else if (strncmp(argv[argc], "-g", 2) == 0)
      filename = argv[argc] + 2;
    else {
      fprintf(stderr, "Usage: %s [-nN][-dN][-pN][-sN][-gfoo]\n", argv[0]);
      return -2;
    }
  }

  g = (filename ? restore_graph(filename) : roget(n, d, p, s));
  if (g == NULL) {
    fprintf(stderr, "Sorry, can't create the graph! (error code %ld)\n",
            panic_code);
    return -1;
  }
  printf("Reachability analysis of %s\n\n", g->id);

  // - The root map corresponds to what Knuth calls the "min" field.
  // - The discover time map is the "rank" field
  // - Knuth uses the rank field for double duty, to record the
  //   discover time, and to keep track of which vertices have
  //   been visited. The BGL strong_components() function needs
  //   a separate field for marking colors, so we use the w field.

  std::vector<int> comp(num_vertices(g));
  property_map<Graph*, vertex_index_t>::type 
    index_map = get(vertex_index, g);

  property_map<Graph*, v_property<vertex_t> >::type 
    root = get(v_property<vertex_t>(), g);

  int num_comp = strong_components
    (g, make_iterator_property_map(comp.begin(), index_map),
     root_map(root).
     discover_time_map(get(z_property<long>(), g)).
     color_map(get(w_property<long>(), g)));

  std::vector< std::vector<vertex_t> > strong_comp(num_comp);

  // First add representative vertices to each component's list
  graph_traits<Graph*>::vertex_iterator vi, vi_end;
  for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
    if (root[*vi] == *vi)
      strong_comp[comp[index_map[*vi]]].push_back(*vi);

  // Then add the other vertices of the component
  for (tie(vi, vi_end) = vertices(g); vi != vi_end; ++vi)
    if (root[*vi] != *vi)
      strong_comp[comp[index_map[*vi]]].push_back(*vi);

  // We do not print out the "from" and "to" information as Knuth
  // does because we no longer have easy access to that information
  // from outside the algorithm.

  for (c = 0; c < num_comp; ++c) {
    vertex_t v = strong_comp[c].front();
    std::cout << "Strong component `" << specs(v) << "'";
    if (strong_comp[c].size() > 1) {
      std::cout << " also includes:\n";
      for (i = 1; i < strong_comp[c].size(); ++i)
        std::cout << " " << specs(strong_comp[c][i]) << std::endl;
    } else
      std::cout << std::endl;
  }

  // Next we print out the "component graph" or "condensation", that
  // is, we consider each component to be a vertex in a new graph
  // where there is an edge connecting one component to another if there
  // is one or more edges connecting any of the vertices from the
  // first component to any of the vertices in the second. We use the
  // name of the representative vertex as the name of the component.

  printf("\nLinks between components:\n");

  // This array provides an efficient way to check if we've already
  // created a link from the current component to the component
  // of the target vertex.
  std::vector<int> mark(num_comp, (std::numeric_limits<int>::max)());

  // We go in reverse order just to mimic the output ordering in
  // Knuth's version.
  for (c = num_comp - 1; c >= 0; --c) {
    vertex_t u = strong_comp[c][0];
    for (i = 0; i < strong_comp[c].size(); ++i) {
      vertex_t v = strong_comp[c][i];
      graph_traits<Graph*>::out_edge_iterator ei, ei_end;
      for (tie(ei, ei_end) = out_edges(v, g); ei != ei_end; ++ei) {
        vertex_t x = target(*ei, g);
        int comp_x = comp[index_map[x]];
        if (comp_x != c && mark[comp_x] != c) {
          mark[comp_x] = c;
          vertex_t w = strong_comp[comp_x][0];
          std::cout << specs(u) << " -> " << specs(w)
                    << " (e.g., " << specs(v) << " -> " << specs(x) << ")\n";
        } // if
      } // for
    } // for
  } // for
}