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