1 // Copyright (C) 2004-2006 The Trustees of Indiana University.
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)
7 // Authors: Douglas Gregor
10 #include <boost/graph/use_mpi.hpp>
11 #include <boost/config.hpp>
12 #include <boost/throw_exception.hpp>
13 #include <boost/serialization/vector.hpp>
14 #include <boost/graph/distributed/adjacency_list.hpp>
15 #include <boost/graph/connected_components.hpp>
16 #include <boost/graph/distributed/connected_components_parallel_search.hpp>
17 #include <boost/graph/random.hpp>
18 #include <boost/property_map/parallel/distributed_property_map.hpp>
19 #include <boost/graph/distributed/mpi_process_group.hpp>
20 #include <boost/graph/parallel/distribution.hpp>
21 #include <boost/graph/erdos_renyi_generator.hpp>
22 #include <boost/graph/distributed/graphviz.hpp>
26 #include <boost/random.hpp>
27 #include <boost/test/minimal.hpp>
29 #include <boost/graph/distributed/compressed_sparse_row_graph.hpp>
30 #include <boost/graph/rmat_graph_generator.hpp>
32 #ifdef BOOST_NO_EXCEPTIONS
34 boost::throw_exception(std::exception
const& ex
)
36 std::cout
<< ex
.what() << std::endl
;
41 using namespace boost
;
42 using boost::graph::distributed::mpi_process_group
;
44 typedef double time_type
;
46 inline time_type
get_time()
51 std::string
print_time(time_type t
)
53 std::ostringstream out
;
54 out
<< std::setiosflags(std::ios::fixed
) << std::setprecision(2) << t
;
62 bool operator()() const { return false; }
63 bool operator()(T x
, T y
) const { return (owner(x
) < owner(y
) || (owner(x
) == owner(y
) && local(x
) < local(y
))); }
67 test_distributed_connected_components(int n
, double _p
, bool verify
, bool emit_dot_file
, int seed
, bool parallel_search
)
69 // typedef adjacency_list<listS,
70 // distributedS<mpi_process_group, vecS>,
71 // undirectedS> Graph;
73 typedef compressed_sparse_row_graph
<directedS
, no_property
, no_property
, no_property
,
74 distributedS
<mpi_process_group
> > Graph
;
81 parallel::variant_distribution
<mpi_process_group
> distrib
82 = parallel::block(pg
, n
);
87 distrib
= parallel::random_distribution(pg
, dist_gen
, n
);
89 distrib
= parallel::oned_block_cyclic(pg
, 13);
93 // Graph g(erdos_renyi_iterator<minstd_rand, Graph>(gen, n, _p/2),
94 // erdos_renyi_iterator<minstd_rand, Graph>(),
97 int m
= int(n
* n
* _p
/2);
98 double a
= 0.57, b
= 0.19, c
= 0.19, d
= 0.05;
100 // Last boolean parameter makes R-MAT bidirectional
101 Graph
g(sorted_unique_rmat_iterator
<minstd_rand
, Graph
>(gen
, n
, m
, a
, b
, c
, d
, true),
102 sorted_unique_rmat_iterator
<minstd_rand
, Graph
>(),
107 std::vector
<int> local_components_vec(num_vertices(g
));
108 typedef iterator_property_map
<std::vector
<int>::iterator
, property_map
<Graph
, vertex_index_t
>::type
> ComponentMap
;
109 ComponentMap
component(local_components_vec
.begin(), get(vertex_index
, g
));
111 int num_components
= 0;
113 time_type start
= get_time();
114 if (parallel_search
) {
115 num_components
= connected_components_ps(g
, component
);
117 num_components
= connected_components(g
, component
);
119 time_type end
= get_time();
120 if (process_id(g
.process_group()) == 0)
121 std::cerr
<< "Connected Components time = " << print_time(end
- start
) << " seconds.\n"
122 << num_components
<< " components identified\n";
126 if ( process_id(g
.process_group()) == 0 )
128 component
.set_max_ghost_cells(0);
129 for (int i
= 0; i
< n
; ++i
)
130 get(component
, vertex(i
, g
));
131 synchronize(component
);
133 // Check against the sequential version
134 typedef adjacency_list
<listS
,
140 no_property
> Graph2
;
144 // Graph2 g2(erdos_renyi_iterator<minstd_rand, Graph>(gen, n, _p/2),
145 // erdos_renyi_iterator<minstd_rand, Graph>(),
148 Graph2
g2( sorted_unique_rmat_iterator
<minstd_rand
, Graph
>(gen
, n
, m
, a
, b
, c
, d
, true),
149 sorted_unique_rmat_iterator
<minstd_rand
, Graph
>(),
152 std::vector
<int> component2 (n
);
154 tmp
= connected_components(g2
, make_iterator_property_map(component2
.begin(), get(vertex_index
, g2
)));
155 std::cerr
<< "Verifier found " << tmp
<< " components" << std::endl
;
157 // Make sure components and component2 match
158 std::map
<int, int> c2c
;
160 // This fails if there are more components in 'component' than
161 // 'component2' because multiple components in 'component' may
162 // legitimately map to the same component number in 'component2'.
163 // We can either test the mapping in the opposite direction or
164 // just assert that the numbers of components found by both
165 // algorithms is the same
166 for ( i
= 0; i
< n
; i
++ )
167 if ( c2c
.find( get(component
, vertex(i
, g
)) ) == c2c
.end() )
168 c2c
[get(component
, vertex(i
, g
))] = component2
[i
];
170 if ( c2c
[get(component
, vertex(i
, g
))] != component2
[i
] )
173 if ( i
< n
|| num_components
!= tmp
) {
174 printf("Unable to verify CC result...\n");
176 printf("Passed verification... %i connected components\n",
181 synchronize(component
);
184 write_graphviz("cc.dot", g
, paint_by_number(component
));
188 int test_main(int argc
, char* argv
[])
190 mpi::environment
env(argc
, argv
);
193 test_distributed_connected_components(10000, 0.001, true, false, 1, false);
194 test_distributed_connected_components(10000, 0.001, true, false, 1, true);
197 test_distributed_connected_components
198 (atoi(argv
[1]), atof(argv
[2]),
199 argv
[3]==std::string("true"), argv
[4]==std::string("true"),
200 argc
== 6? 1 : atoi(argv
[6]),
201 argv
[5]==std::string("true"));