1 // Copyright (C) 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: Nick Edmonds
10 #include <boost/graph/use_mpi.hpp>
15 # include <boost/graph/distributed/compressed_sparse_row_graph.hpp>
17 # include <boost/graph/distributed/adjacency_list.hpp>
20 #include <boost/config.hpp>
21 #include <boost/throw_exception.hpp>
22 #include <boost/graph/distributed/mpi_process_group.hpp>
23 #include <boost/graph/distributed/concepts.hpp>
24 #include <boost/graph/erdos_renyi_generator.hpp>
25 #include <boost/graph/distributed/betweenness_centrality.hpp>
26 #include <boost/random/linear_congruential.hpp>
27 #include <boost/graph/graphviz.hpp>
28 #include <boost/property_map/vector_property_map.hpp>
29 #include <boost/test/minimal.hpp>
31 #ifdef BOOST_NO_EXCEPTIONS
33 boost::throw_exception(std::exception const& ex)
35 std::cout << ex.what() << std::endl;
40 /****************************************************************************
41 * Edge weight generator iterator *
42 ****************************************************************************/
43 template<typename F, typename RandomGenerator>
44 class generator_iterator
47 typedef std::input_iterator_tag iterator_category;
48 typedef typename F::result_type value_type;
49 typedef const value_type& reference;
50 typedef const value_type* pointer;
51 typedef void difference_type;
54 generator_iterator(RandomGenerator& gen, const F& f = F())
60 reference operator*() const { return value; }
61 pointer operator->() const { return &value; }
63 generator_iterator& operator++()
69 generator_iterator operator++(int)
71 generator_iterator temp(*this);
76 bool operator==(const generator_iterator& other) const
77 { return f == other.f; }
79 bool operator!=(const generator_iterator& other) const
80 { return !(*this == other); }
88 template<typename F, typename RandomGenerator>
89 inline generator_iterator<F, RandomGenerator>
90 make_generator_iterator( RandomGenerator& gen, const F& f)
91 { return generator_iterator<F, RandomGenerator>(gen, f); }
93 using namespace boost;
94 using boost::graph::distributed::mpi_process_group;
96 typedef int weight_type;
99 WeightedEdge(weight_type weight = 0) : weight(weight) { }
103 template<typename Archiver>
104 void serialize(Archiver& ar, const unsigned int /*version*/)
110 int test_main(int argc, char* argv[])
112 mpi::environment env(argc, argv);
115 typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge,
116 no_property, distributedS<mpi_process_group> >
118 typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge>
121 typedef adjacency_list<vecS,
122 distributedS<mpi_process_group, vecS>,
125 property<edge_weight_t, int> > Graph;
127 typedef adjacency_list<vecS, vecS, directedS, no_property,
128 property<edge_weight_t, int> > seqGraph;
132 typedef sorted_erdos_renyi_iterator<minstd_rand, Graph> ERIter;
142 // NOTE: Weighted betweenness centrality only works with non-zero edge weights
145 Graph g(edges_are_sorted, ERIter(gen, n, prob), ERIter(),
146 make_generator_iterator(gen, uniform_int<int>(1, C)),
149 gen.seed(1); // Re-seed PRNG so we get the same graph
155 ERIter(gen, n, prob), ERIter(),
156 make_generator_iterator(gen, uniform_int<int>(1, C)),
159 // Test Betweenness Centrality
160 typedef property_map<Graph, vertex_index_t>::const_type IndexMap;
161 typedef iterator_property_map<std::vector<int>::iterator, IndexMap>
164 std::vector<int> centralityS(num_vertices(g), 0);
165 CentralityMap centrality(centralityS.begin(), get(vertex_index, g));
167 brandes_betweenness_centrality(g, centrality);
169 std::vector<int> weightedCentralityS(num_vertices(g), 0);
170 CentralityMap weightedCentrality(weightedCentralityS.begin(), get(vertex_index, g));
172 brandes_betweenness_centrality(g, centrality_map(weightedCentrality).
174 weight_map(get(&WeightedEdge::weight, g)));
176 weight_map(get(edge_weight, g)));
179 int g_cpd = central_point_dominance(g, centrality);
182 // Non-distributed (embarassingly parallel) Betweenness Centrality
184 typedef boost::graph::parallel::process_group_type<Graph>::type
187 process_group_type pg = process_group(g);
189 process_group_type::process_id_type id = process_id(pg);
190 process_group_type::process_size_type p = num_processes(pg);
192 typedef property_map<seqGraph, vertex_index_t>::const_type seqIndexMap;
193 typedef iterator_property_map<std::vector<int>::iterator, seqIndexMap> seqCentralityMap;
195 std::vector<int> nonDistributedCentralityS(num_vertices(sg), 0);
196 seqCentralityMap nonDistributedCentrality(nonDistributedCentralityS.begin(), get(vertex_index, sg));
198 std::vector<int> nonDistributedWeightedCentralityS(num_vertices(sg), 0);
199 seqCentralityMap nonDistributedWeightedCentrality(nonDistributedWeightedCentralityS.begin(),
200 get(vertex_index, sg));
202 non_distributed_brandes_betweenness_centrality(pg, sg, nonDistributedCentrality);
204 non_distributed_brandes_betweenness_centrality(pg, sg,
205 centrality_map(nonDistributedWeightedCentrality).
207 weight_map(get(&WeightedEdge::weight, sg)));
209 weight_map(get(edge_weight, sg)));
215 std::vector<int> seqCentralityS(num_vertices(sg), 0);
216 seqCentralityMap seqCentrality(seqCentralityS.begin(), get(vertex_index, sg));
218 std::vector<int> seqWeightedCentralityS(num_vertices(sg), 0);
219 seqCentralityMap seqWeightedCentrality(seqWeightedCentralityS.begin(), get(vertex_index, sg));
221 brandes_betweenness_centrality(sg, seqCentrality);
223 brandes_betweenness_centrality(sg, centrality_map(seqWeightedCentrality).
225 weight_map(get(&WeightedEdge::weight, sg)));
227 weight_map(get(edge_weight, sg)));
230 int sg_cpd = central_point_dominance(sg, seqCentrality);
232 // Verify exact betweenness centrality
234 // We're cheating when we map vertices in g to vertices in sg
235 // since we know that g is using the block distribution here
236 typedef property_map<Graph, vertex_owner_t>::const_type OwnerMap;
237 typedef property_map<Graph, vertex_local_t>::const_type LocalMap;
239 OwnerMap owner = get(vertex_owner, g);
240 LocalMap local = get(vertex_local, g);
245 typedef graph_traits<Graph>::vertex_iterator vertex_iterator;
246 vertex_iterator v, v_end;
248 for (boost::tie(v, v_end) = vertices(g); v != v_end; ++v) {
249 if (get(centrality, *v) != seqCentralityS[(n/p) * get(owner, *v) + get(local, *v)]) {
250 std::cerr << " " << id << ": Error - centrality of " << get(local, *v) << "@" << get(owner, *v)
251 << " does not match the sequential result (" << get(centrality, *v) << " vs. "
252 << seqCentralityS[(n/p) * get(owner, *v) + get(local, *v)] << ")\n";
256 if (get(weightedCentrality, *v) != seqWeightedCentralityS[(n/p) * get(owner, *v) + get(local, *v)]) {
257 std::cerr << " " << id << ": Error - weighted centrality of " << get(local, *v) << "@" << get(owner, *v)
258 << " does not match the sequential result (" << get(weightedCentrality, *v) << " vs. "
259 << seqWeightedCentralityS[(n/p) * get(owner, *v) + get(local, *v)] << ")\n";
266 typedef graph_traits<seqGraph>::vertex_iterator vertex_iterator;
267 vertex_iterator v, v_end;
269 for (boost::tie(v, v_end) = vertices(sg); v != v_end; ++v) {
270 if (get(seqCentrality, *v) != get(nonDistributedCentrality, *v)) {
271 std::cerr << " " << id << ": Error - non-distributed centrality of " << *v
272 << " does not match the sequential result (" << get(nonDistributedCentrality, *v)
273 << " vs. " << get(seqCentrality, *v) << ")\n";
277 if (get(seqWeightedCentrality, *v) != get(nonDistributedWeightedCentrality, *v)) {
278 std::cerr << " " << id << ": Error - non-distributed weighted centrality of " << *v
279 << " does not match the sequential result (" << get(nonDistributedWeightedCentrality, *v)
280 << " vs. " << get(seqCentrality, *v) << ")\n";
286 if (g_cpd != sg_cpd) {
288 std::cerr << "Central point dominance did not match the sequential result\n";
292 MPI_Abort(MPI_COMM_WORLD, -1);