1 // Copyright (C) 2005-2008 The Trustees of Indiana University.
2 
3 // Use, modification and distribution is subject to the Boost Software
4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6 
7 //  Authors: Douglas Gregor
8 //           Andrew Lumsdaine
9 //
10 // Test of Hohberg's distributed biconnected components algorithm.
11 #include <boost/graph/use_mpi.hpp>
12 #include <boost/config.hpp>
13 #include <boost/throw_exception.hpp>
14 #include <boost/graph/distributed/hohberg_biconnected_components.hpp>
15 #include <boost/graph/distributed/mpi_process_group.hpp>
16 #include <boost/graph/distributed/adjacency_list.hpp>
17 #include <boost/test/minimal.hpp>
18 
19 #ifdef BOOST_NO_EXCEPTIONS
20 void
throw_exception(std::exception const & ex)21 boost::throw_exception(std::exception const& ex)
22 {
23     std::cout << ex.what() << std::endl;
24     abort();
25 }
26 #endif
27 
28 using boost::graph::distributed::mpi_process_group;
29 
30 using namespace boost;
31 
32 template<typename Graph>
check_components(const Graph & g,std::size_t num_comps)33 void check_components(const Graph& g, std::size_t num_comps)
34 {
35   std::size_t not_mapped = (std::numeric_limits<std::size_t>::max)();
36   std::vector<std::size_t> color_to_name(num_comps, not_mapped);
37   BGL_FORALL_EDGES_T(e, g, Graph) {
38     BOOST_CHECK(get(edge_color, g, e) < num_comps);
39     if (color_to_name[get(edge_color, g, e)] == not_mapped)
40       color_to_name[get(edge_color, g, e)] = get(edge_name, g, e);
41     BOOST_CHECK(color_to_name[get(edge_color,g,e)] == get(edge_name,g,e));
42 
43     if (color_to_name[get(edge_color,g,e)] != get(edge_name,g,e)) {
44       for (std::size_t i = 0; i < color_to_name.size(); ++i)
45         std::cerr << color_to_name[i] << ' ';
46 
47       std::cerr << std::endl;
48 
49       std::cerr << color_to_name[get(edge_color,g,e)] << " != "
50                 << get(edge_name,g,e) << " on edge "
51                 << local(source(e, g)) << " -> " << local(target(e, g))
52                 << std::endl;
53     }
54   }
55 }
56 
57 template<typename Graph>
58 void
test_small_hohberg_biconnected_components(Graph & g,int n,int comps_expected,bool single_component=true)59 test_small_hohberg_biconnected_components(Graph& g, int n, int comps_expected,
60                                           bool single_component = true)
61 {
62   using boost::graph::distributed::hohberg_biconnected_components;
63 
64   bool is_root = (process_id(process_group(g)) == 0);
65 
66   if (single_component) {
67     for (int i = 0; i < n; ++i) {
68       if (is_root) std::cerr << "Testing with leader = " << i << std::endl;
69 
70       // Scramble edge_color_map
71       BGL_FORALL_EDGES_T(e, g, Graph)
72         put(edge_color, g, e, 17);
73 
74       typename graph_traits<Graph>::vertex_descriptor leader = vertex(i, g);
75       int num_comps =
76         hohberg_biconnected_components(g, get(edge_color, g), &leader,
77                                        &leader + 1);
78 
79       BOOST_CHECK(num_comps == comps_expected);
80       check_components(g, num_comps);
81     }
82   }
83 
84   if (is_root) std::cerr << "Testing simple interface." << std::endl;
85   synchronize(g);
86 
87   // Scramble edge_color_map
88   int i = 0;
89   BGL_FORALL_EDGES_T(e, g, Graph) {
90     ++i;
91     put(edge_color, g, e, 17);
92   }
93   std::cerr << process_id(process_group(g)) << " has "
94             << i << " edges.\n";
95 
96   int num_comps = hohberg_biconnected_components(g, get(edge_color, g));
97 
98   BOOST_CHECK(num_comps == comps_expected);
99   check_components(g, num_comps);
100 }
101 
test_main(int argc,char * argv[])102 int test_main(int argc, char* argv[])
103 {
104   mpi::environment env(argc, argv);
105 
106   typedef adjacency_list<listS,
107                          distributedS<mpi_process_group, vecS>,
108                          undirectedS,
109                          // Vertex properties
110                          no_property,
111                          // Edge properties
112                          property<edge_name_t, std::size_t,
113                          property<edge_color_t, std::size_t> > > Graph;
114 
115   typedef std::pair<int, int> E;
116 
117   {
118     // Example 1: A single component with 2 bicomponents
119     E edges_init[] = { E(0, 1), E(0, 2), E(1, 3), E(2, 4), E(3, 4), E(4, 5),
120                        E(4, 6), E(5, 6) };
121     const int m = sizeof(edges_init) / sizeof(E);
122     std::size_t expected_components[m] = { 0, 0, 0, 0, 0, 1, 1, 1 };
123     const int n = 7;
124     Graph g(&edges_init[0], &edges_init[0] + m, &expected_components[0], n);
125 
126     int num_comps_expected =
127       *std::max_element(&expected_components[0], &expected_components[0] + m)
128       + 1;
129 
130     test_small_hohberg_biconnected_components(g, n, num_comps_expected);
131   }
132 
133   {
134     // Example 2: A single component with 4 bicomponents
135     E edges_init[] = { E(0, 1), E(1, 2), E(2, 0), E(2, 3), E(3, 4), E(4, 5),
136                        E(5, 2), E(3, 6), E(6, 7), E(7, 8), E(8, 6) };
137     const int m = sizeof(edges_init) / sizeof(E);
138     std::size_t expected_components[m] = { 0, 0, 0, 1, 1, 1, 1, 2, 3, 3, 3 };
139     const int n = 9;
140     Graph g(&edges_init[0], &edges_init[0] + m, &expected_components[0], n);
141 
142     int num_comps_expected =
143       *std::max_element(&expected_components[0], &expected_components[0] + m)
144       + 1;
145 
146     test_small_hohberg_biconnected_components(g, n, num_comps_expected);
147   }
148 
149   {
150     // Example 3: Two components, 6 bicomponents
151     // This is just the concatenation of the two previous graphs.
152     E edges_init[] = { /* Example 1 graph */
153                        E(0, 1), E(0, 2), E(1, 3), E(2, 4), E(3, 4), E(4, 5),
154                        E(4, 6), E(5, 6),
155                        /* Example 2 graph */
156                        E(7, 8), E(8, 9), E(9, 7), E(9, 10), E(10, 11),
157                        E(11, 12), E(12, 9), E(10, 13), E(13, 14), E(14, 15),
158                        E(15, 13) };
159     const int m = sizeof(edges_init) / sizeof(E);
160     std::size_t expected_components[m] =
161       { /* Example 1 */0, 0, 0, 0, 0, 1, 1, 1,
162         /* Example 2 */2, 2, 2, 3, 3, 3, 3, 4, 5, 5, 5 };
163     const int n = 16;
164     Graph g(&edges_init[0], &edges_init[0] + m, &expected_components[0], n);
165 
166     int num_comps_expected =
167       *std::max_element(&expected_components[0], &expected_components[0] + m)
168       + 1;
169 
170     test_small_hohberg_biconnected_components(g, n, num_comps_expected,
171                                               false);
172   }
173 
174   return 0;
175 }
176