| // Copyright 2004 The Trustees of Indiana University. |
| |
| // Use, modification and distribution is subject to 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) |
| |
| // Authors: Nick Edmonds |
| // Andrew Lumsdaine |
| |
| // #define PBGL_ACCOUNTING |
| |
| #include <boost/graph/use_mpi.hpp> |
| |
| #include <boost/graph/distributed/compressed_sparse_row_graph.hpp> |
| #include <boost/graph/distributed/adjacency_list.hpp> |
| |
| #include <boost/graph/distributed/mpi_process_group.hpp> |
| |
| #include <boost/test/minimal.hpp> |
| #include <boost/random.hpp> |
| #include <boost/property_map/parallel/distributed_property_map.hpp> |
| #include <boost/graph/distributed/graphviz.hpp> |
| #include <boost/graph/iteration_macros.hpp> |
| #include <boost/graph/properties.hpp> |
| |
| #include <boost/graph/rmat_graph_generator.hpp> |
| #include <boost/graph/small_world_generator.hpp> |
| #include <boost/graph/erdos_renyi_generator.hpp> |
| |
| #include <boost/graph/distributed/connected_components.hpp> |
| #include <boost/graph/distributed/connected_components_parallel_search.hpp> |
| #include <boost/graph/distributed/betweenness_centrality.hpp> |
| #include <boost/graph/distributed/delta_stepping_shortest_paths.hpp> |
| |
| #include <time.h> |
| #include <sys/time.h> |
| |
| #include <iostream> |
| #include <iomanip> |
| #include <vector> |
| #include <stdint.h> |
| |
| // Edge distribution tags select a generator |
| struct rmat_edge_distribution_tag { }; |
| struct rmat_unique_edge_distribution_tag { }; |
| |
| using namespace boost; |
| using boost::graph::distributed::mpi_process_group; |
| |
| /**************************************************************************** |
| * Timing |
| ****************************************************************************/ |
| #ifndef PBGL_ACCOUNTING |
| |
| typedef double time_type; |
| |
| inline time_type get_time() |
| { |
| timeval tp; |
| gettimeofday(&tp, 0); |
| return tp.tv_sec + tp.tv_usec / 1000000.0; |
| } |
| |
| std::string print_time(time_type t) |
| { |
| std::ostringstream out; |
| out << std::setiosflags(std::ios::fixed) << std::setprecision(2) << t; |
| return out.str(); |
| } |
| |
| #endif // PBGL_ACCOUNTING |
| |
| /**************************************************************************** |
| * Edge weight generator iterator * |
| ****************************************************************************/ |
| template<typename F, typename RandomGenerator> |
| class generator_iterator |
| { |
| public: |
| typedef std::input_iterator_tag iterator_category; |
| typedef typename F::result_type value_type; |
| typedef const value_type& reference; |
| typedef const value_type* pointer; |
| typedef void difference_type; |
| |
| explicit |
| generator_iterator(RandomGenerator& gen, const F& f = F()) |
| : f(f), gen(&gen) |
| { |
| value = this->f(gen); |
| } |
| |
| reference operator*() const { return value; } |
| pointer operator->() const { return &value; } |
| |
| generator_iterator& operator++() |
| { |
| value = f(*gen); |
| return *this; |
| } |
| |
| generator_iterator operator++(int) |
| { |
| generator_iterator temp(*this); |
| ++(*this); |
| return temp; |
| } |
| |
| bool operator==(const generator_iterator& other) const |
| { return f == other.f; } |
| |
| bool operator!=(const generator_iterator& other) const |
| { return !(*this == other); } |
| |
| private: |
| F f; |
| RandomGenerator* gen; |
| value_type value; |
| }; |
| |
| template<typename F, typename RandomGenerator> |
| inline generator_iterator<F, RandomGenerator> |
| make_generator_iterator( RandomGenerator& gen, const F& f) |
| { return generator_iterator<F, RandomGenerator>(gen, f); } |
| |
| /**************************************************************************** |
| * Edge Property * |
| ****************************************************************************/ |
| typedef int weight_type; |
| |
| struct WeightedEdge { |
| WeightedEdge(weight_type weight = 0) : weight(weight) { } |
| |
| weight_type weight; |
| |
| template<typename Archiver> |
| void serialize(Archiver& ar, const unsigned int /*version*/) |
| { |
| ar & weight; |
| } |
| }; |
| |
| /**************************************************************************** |
| * Algorithm Tests * |
| ****************************************************************************/ |
| template <typename Graph> |
| void test_directed_sequential_algorithms(const Graph& g) |
| { } |
| |
| template <typename Graph> |
| void test_undirected_sequential_algorithms(const Graph& g) |
| { |
| std::vector<unsigned int> componentS(num_vertices(g)); |
| typedef iterator_property_map< |
| std::vector<unsigned int>::iterator, |
| typename property_map<Graph, vertex_index_t>::type> |
| ComponentMap; |
| ComponentMap component(componentS.begin(), get(vertex_index, g)); |
| |
| time_type start = get_time(); |
| unsigned int num_components = connected_components(g, component); |
| time_type end = get_time(); |
| |
| std::cerr << " Sequential connected Components time = " |
| << print_time(end - start) << " seconds.\n" |
| << " " << num_components << " components identified\n"; |
| } |
| |
| template <typename Graph, typename EdgeWeightMap> |
| void test_directed_csr_only_algorithms(const Graph& g, EdgeWeightMap weight, |
| typename graph_traits<Graph>::vertices_size_type num_sources, |
| typename property_traits<EdgeWeightMap>::value_type C) |
| { |
| typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor; |
| typedef typename graph_traits<Graph>::vertex_iterator vertex_iterator; |
| typedef typename graph_traits<Graph>::vertices_size_type vertices_size_type; |
| typedef typename graph_traits<Graph>::edges_size_type edges_size_type; |
| |
| typedef typename boost::graph::parallel::process_group_type<Graph>::type |
| process_group_type; |
| |
| process_group_type pg = process_group(g); |
| typename process_group_type::process_id_type id = process_id(pg); |
| typename process_group_type::process_size_type p = num_processes(pg); |
| |
| vertices_size_type n = num_vertices(g); |
| n = boost::parallel::all_reduce(pg, n, std::plus<vertices_size_type>()); |
| |
| edges_size_type m = num_edges(g); |
| m = boost::parallel::all_reduce(pg, m, std::plus<edges_size_type>()); |
| |
| // |
| // Betweenness Centrality (Approximate) |
| // |
| queue<vertex_descriptor> delta_stepping_vertices; |
| |
| { |
| // Distributed Centrality Map |
| typedef typename property_map<Graph, vertex_index_t>::const_type IndexMap; |
| typedef iterator_property_map<std::vector<int>::iterator, IndexMap> CentralityMap; |
| |
| std::vector<int> centralityS(num_vertices(g), 0); |
| CentralityMap centrality(centralityS.begin(), get(vertex_index, g)); |
| |
| // Calculate number of vertices of degree 0 |
| vertices_size_type n0 = 0; |
| BGL_FORALL_VERTICES_T(v, g, Graph) { |
| if (out_degree(v, g) == 0) n0++; |
| } |
| n0 = boost::parallel::all_reduce(pg, n0, std::plus<vertices_size_type>()); |
| |
| queue<vertex_descriptor> sources; |
| |
| { |
| assert(num_sources >= p); // Don't feel like adding a special case for num_sources < p |
| |
| minstd_rand gen; |
| uniform_int<vertices_size_type> rand_vertex(0, num_vertices(g) - 1); |
| std::vector<vertex_descriptor> all_sources, local_sources; |
| vertices_size_type local_vertices = vertices_size_type(floor((double)num_sources / p)); |
| local_vertices += (id < (num_sources - (p * local_vertices)) ? 1 : 0); |
| |
| while (local_vertices > 0) { |
| vertex_iterator iter = vertices(g).first; |
| std::advance(iter, rand_vertex(gen)); |
| |
| if (out_degree(*iter, g) != 0 |
| && std::find(local_sources.begin(), local_sources.end(), *iter) == local_sources.end()) { |
| local_sources.push_back(*iter); |
| --local_vertices; |
| } |
| } |
| all_gather(pg, local_sources.begin(), local_sources.end(), all_sources); |
| std::sort(all_sources.begin(), all_sources.end()); |
| for (typename std::vector<vertex_descriptor>::iterator iter = all_sources.begin(); |
| iter != all_sources.end(); ++iter) { |
| sources.push(*iter); |
| delta_stepping_vertices.push(*iter); |
| } |
| } |
| |
| // NOTE: The delta below assumes uniform edge weight distribution |
| time_type start = get_time(); |
| brandes_betweenness_centrality(g, buffer(sources).weight_map(weight). |
| centrality_map(centrality).lookahead((m / n) * (C / 2))); |
| time_type end = get_time(); |
| |
| edges_size_type exactTEPs = edges_size_type(floor(7 * n* (n - n0) / (end - start))); |
| |
| if (id == 0) |
| std::cerr << " Betweenness Centrality Approximate (" << num_sources << " sources) = " |
| << print_time(end - start) << " (" << exactTEPs << " TEPs)\n"; |
| } |
| |
| // |
| // Delta stepping performance (to compare to SSSP inside BC |
| // |
| if (false) { |
| typedef typename property_map<Graph, vertex_index_t>::const_type IndexMap; |
| typedef iterator_property_map<std::vector<int>::iterator, IndexMap> DistanceMap; |
| |
| std::vector<int> distanceS(num_vertices(g), 0); |
| DistanceMap distance(distanceS.begin(), get(vertex_index, g)); |
| |
| while(!delta_stepping_vertices.empty()) { |
| |
| time_type start = get_time(); |
| delta_stepping_shortest_paths(g, delta_stepping_vertices.top(), dummy_property_map(), |
| distance, weight); |
| time_type end = get_time(); |
| |
| delta_stepping_vertices.pop(); |
| distance.reset(); |
| |
| if (id == 0) |
| std::cerr << " Delta-stepping shortest paths = " << print_time(end - start) |
| << std::endl; |
| } |
| } |
| |
| } |
| |
| template <typename Graph> |
| void test_directed_algorithms(const Graph& g) |
| { |
| } |
| |
| template <typename Graph> |
| void test_undirected_algorithms(const Graph& g) |
| { |
| typedef typename boost::graph::parallel::process_group_type<Graph>::type |
| process_group_type; |
| |
| process_group_type pg = process_group(g); |
| typename process_group_type::process_id_type id = process_id(pg); |
| typename process_group_type::process_size_type p = num_processes(pg); |
| |
| |
| // Connected Components |
| std::vector<unsigned int> local_components_vec(num_vertices(g)); |
| typedef iterator_property_map< |
| std::vector<unsigned int>::iterator, |
| typename property_map<Graph, vertex_index_t>::type> |
| ComponentMap; |
| ComponentMap component(local_components_vec.begin(), get(vertex_index, g)); |
| |
| int num_components; |
| |
| time_type start = get_time(); |
| num_components = connected_components(g, component); |
| time_type end = get_time(); |
| if (id == 0) |
| std::cerr << " Connected Components time = " << print_time(end - start) |
| << " seconds.\n" |
| << " " << num_components << " components identified\n"; |
| |
| start = get_time(); |
| num_components = boost::graph::distributed::connected_components_ps(g, component); |
| end = get_time(); |
| if (id == 0) |
| std::cerr << " Connected Components (parallel search) time = " |
| << print_time(end - start) << " seconds.\n" |
| << " " << num_components << " components identified\n"; |
| } |
| |
| /**************************************************************************** |
| * Graph Type Tests * |
| ****************************************************************************/ |
| |
| // TODO: Re-seed PRNG before sequential tests to get the same graph as the |
| // distributed case? |
| |
| // |
| // Compressed Sparse Row |
| // |
| |
| // R-MAT |
| template <typename ProcessGroup, typename RandomGenerator, typename Distribution> |
| void test_csr(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib, |
| bool sequential_tests, size_t N, size_t M, size_t C, |
| double a, double b, double c, double d, size_t num_sources, |
| rmat_edge_distribution_tag) |
| { |
| if (process_id(pg) == 0) |
| std::cerr << " R-MAT\n"; |
| |
| typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge, no_property, |
| distributedS<mpi_process_group> > Graph; |
| |
| Graph g(sorted_rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d), |
| sorted_rmat_iterator<RandomGenerator, Graph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N, pg, distrib); |
| |
| test_directed_algorithms(g); |
| test_directed_csr_only_algorithms(g, get(&WeightedEdge::weight, g), num_sources, C); |
| |
| if (sequential_tests && process_id(pg) == 0) { |
| typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge> |
| seqGraph; |
| |
| seqGraph sg(edges_are_sorted, |
| sorted_rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d), |
| sorted_rmat_iterator<RandomGenerator, seqGraph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N); |
| |
| test_directed_sequential_algorithms(sg); |
| } |
| } |
| |
| // R-MAT with unique edges |
| template <typename ProcessGroup, typename RandomGenerator, typename Distribution> |
| void test_csr(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib, |
| bool sequential_tests, size_t N, size_t M, size_t C, |
| double a, double b, double c, double d, size_t num_sources, |
| rmat_unique_edge_distribution_tag) |
| { |
| if (process_id(pg) == 0) |
| std::cerr << " R-MAT - unique\n"; |
| |
| typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge, no_property, |
| distributedS<mpi_process_group> > Graph; |
| |
| // Last boolean parameter makes R-MAT bidirectional |
| Graph g(sorted_unique_rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d), |
| sorted_unique_rmat_iterator<RandomGenerator, Graph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N, pg, distrib); |
| |
| test_directed_algorithms(g); |
| test_directed_csr_only_algorithms(g, get(&WeightedEdge::weight, g), num_sources, C); |
| |
| if (sequential_tests && process_id(pg) == 0) { |
| typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge> |
| seqGraph; |
| |
| seqGraph sg(edges_are_sorted, |
| sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d), |
| sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N); |
| |
| test_directed_sequential_algorithms(sg); |
| } |
| } |
| |
| // Erdos-Renyi |
| template <typename ProcessGroup, typename RandomGenerator, typename Distribution> |
| void test_csr(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib, |
| bool sequential_tests, size_t N, size_t M, size_t C, size_t num_sources) |
| { |
| if (process_id(pg) == 0) |
| std::cerr << " Erdos-Renyi\n"; |
| |
| double _p = static_cast<double>(M) / (N*N); |
| |
| typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge, no_property, |
| distributedS<mpi_process_group> > Graph; |
| |
| Graph g(sorted_erdos_renyi_iterator<RandomGenerator, Graph>(gen, N, _p/2), |
| sorted_erdos_renyi_iterator<RandomGenerator, Graph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N, pg, distrib); |
| |
| test_directed_algorithms(g); |
| test_directed_csr_only_algorithms(g, get(&WeightedEdge::weight, g), num_sources, C); |
| |
| if (sequential_tests && process_id(pg) == 0) { |
| typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge> |
| seqGraph; |
| |
| seqGraph sg(edges_are_sorted, |
| sorted_erdos_renyi_iterator<RandomGenerator, seqGraph>(gen, N, _p/2), |
| sorted_erdos_renyi_iterator<RandomGenerator, seqGraph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N); |
| |
| test_directed_sequential_algorithms(sg); |
| } |
| } |
| |
| // Small World |
| template <typename ProcessGroup, typename RandomGenerator, typename Distribution> |
| void test_csr(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib, |
| bool sequential_tests, size_t N, size_t M, size_t C, double p, |
| size_t num_sources) |
| { |
| if (process_id(pg) == 0) |
| std::cerr << " Small-World\n"; |
| |
| int k = M / N; |
| |
| typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge, no_property, |
| distributedS<mpi_process_group> > Graph; |
| |
| Graph g(small_world_iterator<RandomGenerator, Graph>(gen, N, k, p), |
| small_world_iterator<RandomGenerator, Graph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N, pg, distrib); |
| |
| test_directed_algorithms(g); |
| test_directed_csr_only_algorithms(g, get(&WeightedEdge::weight, g), num_sources, C); |
| |
| if (sequential_tests && process_id(pg) == 0) { |
| typedef compressed_sparse_row_graph<directedS, no_property, WeightedEdge> |
| seqGraph; |
| |
| seqGraph sg(edges_are_sorted, |
| small_world_iterator<RandomGenerator, seqGraph>(gen, N, k, p), |
| small_world_iterator<RandomGenerator, seqGraph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N); |
| |
| test_directed_sequential_algorithms(sg); |
| } |
| } |
| |
| // |
| // Adjacency List |
| // |
| |
| // R-MAT |
| template <typename ProcessGroup, typename RandomGenerator, typename Distribution> |
| void test_adjacency_list(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib, |
| bool sequential_tests, size_t N, size_t M, size_t C, |
| double a, double b, double c, double d, |
| rmat_edge_distribution_tag) |
| { |
| if (process_id(pg) == 0) |
| std::cerr << "R-MAT\n"; |
| |
| { |
| typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>, |
| directedS, no_property, WeightedEdge> Graph; |
| |
| Graph g(rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d), |
| rmat_iterator<RandomGenerator, Graph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N, pg, distrib); |
| |
| test_directed_algorithms(g); |
| } |
| |
| { |
| typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>, |
| undirectedS, no_property, WeightedEdge> Graph; |
| |
| Graph g(rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d), |
| rmat_iterator<RandomGenerator, Graph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N, pg, distrib); |
| |
| test_undirected_algorithms(g); |
| } |
| |
| if (sequential_tests && process_id(pg) == 0) { |
| { |
| typedef adjacency_list<vecS, vecS, directedS, no_property, property<edge_weight_t, int> > |
| seqGraph; |
| |
| seqGraph sg(rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d), |
| rmat_iterator<RandomGenerator, seqGraph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N); |
| |
| test_directed_sequential_algorithms(sg); |
| } |
| |
| { |
| typedef adjacency_list<vecS, vecS, undirectedS, no_property, property<edge_weight_t, int> > |
| seqGraph; |
| |
| seqGraph sg(rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d), |
| rmat_iterator<RandomGenerator, seqGraph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N); |
| |
| test_undirected_sequential_algorithms(sg); |
| } |
| } |
| } |
| |
| // R-MAT with unique edges |
| template <typename ProcessGroup, typename RandomGenerator, typename Distribution> |
| void test_adjacency_list(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib, |
| bool sequential_tests, size_t N, size_t M, size_t C, |
| double a, double b, double c, double d, |
| rmat_unique_edge_distribution_tag) |
| { |
| if (process_id(pg) == 0) |
| std::cerr << " R-MAT - unique\n"; |
| |
| { |
| typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>, |
| directedS, no_property, WeightedEdge> Graph; |
| |
| Graph g(sorted_unique_rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d), |
| sorted_unique_rmat_iterator<RandomGenerator, Graph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N, pg, distrib); |
| |
| test_directed_algorithms(g); |
| } |
| |
| { |
| typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>, |
| undirectedS, no_property, WeightedEdge> Graph; |
| |
| Graph g(sorted_unique_rmat_iterator<RandomGenerator, Graph>(gen, N, M, a, b, c, d), |
| sorted_unique_rmat_iterator<RandomGenerator, Graph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N, pg, distrib); |
| |
| test_undirected_algorithms(g); |
| } |
| |
| if (sequential_tests && process_id(pg) == 0) { |
| { |
| typedef adjacency_list<vecS, vecS, directedS, no_property, property<edge_weight_t, int> > |
| seqGraph; |
| |
| seqGraph sg(sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d), |
| sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N); |
| |
| test_directed_sequential_algorithms(sg); |
| } |
| |
| { |
| typedef adjacency_list<vecS, vecS, undirectedS, no_property, property<edge_weight_t, int> > |
| seqGraph; |
| |
| seqGraph sg(sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(gen, N, M, a, b, c, d), |
| sorted_unique_rmat_iterator<RandomGenerator, seqGraph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N); |
| |
| test_undirected_sequential_algorithms(sg); |
| } |
| } |
| } |
| |
| // Erdos-Renyi |
| template <typename ProcessGroup, typename RandomGenerator, typename Distribution> |
| void test_adjacency_list(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib, |
| bool sequential_tests, size_t N, size_t M, size_t C) |
| { |
| if (process_id(pg) == 0) |
| std::cerr << " Erdos-Renyi\n"; |
| |
| double _p = static_cast<double>(M) / N*N; |
| |
| { |
| typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>, |
| directedS, no_property, WeightedEdge> Graph; |
| |
| Graph g(erdos_renyi_iterator<RandomGenerator, Graph>(gen, N, _p/2), |
| erdos_renyi_iterator<RandomGenerator, Graph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N, pg, distrib); |
| |
| test_directed_algorithms(g); |
| } |
| |
| { |
| typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>, |
| undirectedS, no_property, WeightedEdge> Graph; |
| |
| Graph g(erdos_renyi_iterator<RandomGenerator, Graph>(gen, N, _p/2), |
| erdos_renyi_iterator<RandomGenerator, Graph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N, pg, distrib); |
| |
| test_undirected_algorithms(g); |
| } |
| |
| if (sequential_tests && process_id(pg) == 0) { |
| { |
| typedef adjacency_list<vecS, vecS, directedS, no_property, property<edge_weight_t, int> > |
| seqGraph; |
| |
| seqGraph sg(erdos_renyi_iterator<RandomGenerator, seqGraph>(gen, N, _p/2), |
| erdos_renyi_iterator<RandomGenerator, seqGraph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N); |
| |
| test_directed_sequential_algorithms(sg); |
| } |
| |
| { |
| typedef adjacency_list<vecS, vecS, undirectedS, no_property, property<edge_weight_t, int> > |
| seqGraph; |
| |
| seqGraph sg(erdos_renyi_iterator<RandomGenerator, seqGraph>(gen, N, _p/2), |
| erdos_renyi_iterator<RandomGenerator, seqGraph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N); |
| |
| test_undirected_sequential_algorithms(sg); |
| } |
| } |
| } |
| |
| // Small World |
| template <typename ProcessGroup, typename RandomGenerator, typename Distribution> |
| void test_adjacency_list(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distrib, |
| bool sequential_tests, size_t N, size_t M, size_t C, double p) |
| { |
| if (process_id(pg) == 0) |
| std::cerr << " Small-World\n"; |
| |
| int k = M / N; |
| |
| { |
| typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>, |
| directedS, no_property, WeightedEdge> Graph; |
| |
| Graph g(small_world_iterator<RandomGenerator, Graph>(gen, N, k, p), |
| small_world_iterator<RandomGenerator, Graph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N, pg, distrib); |
| |
| test_directed_algorithms(g); |
| } |
| |
| { |
| typedef adjacency_list<vecS, distributedS<mpi_process_group, vecS>, |
| undirectedS, no_property, WeightedEdge> Graph; |
| |
| Graph g(small_world_iterator<RandomGenerator, Graph>(gen, N, k, p), |
| small_world_iterator<RandomGenerator, Graph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N, pg, distrib); |
| |
| test_undirected_algorithms(g); |
| } |
| |
| if (sequential_tests && process_id(pg) == 0) { |
| { |
| typedef adjacency_list<vecS, vecS, directedS, no_property, property<edge_weight_t, int> > |
| seqGraph; |
| |
| seqGraph sg(small_world_iterator<RandomGenerator, seqGraph>(gen, N, k, p), |
| small_world_iterator<RandomGenerator, seqGraph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N); |
| |
| test_directed_sequential_algorithms(sg); |
| } |
| |
| { |
| typedef adjacency_list<vecS, vecS, undirectedS, no_property, property<edge_weight_t, int> > |
| seqGraph; |
| |
| seqGraph sg(small_world_iterator<RandomGenerator, seqGraph>(gen, N, k, p), |
| small_world_iterator<RandomGenerator, seqGraph>(), |
| make_generator_iterator(gen, uniform_int<int>(1, C)), |
| N); |
| |
| test_undirected_sequential_algorithms(sg); |
| } |
| } |
| } |
| |
| void usage() |
| { |
| std::cerr << "Algorithm Performance Test\n" |
| << "Usage : algorithm_performance [options]\n\n" |
| << "Options are:\n" |
| << "\t--vertices v\t\t\tNumber of vertices in the graph\n" |
| << "\t--edges v\t\t\tNumber of edges in the graph\n" |
| << "\t--seed s\t\t\tSeed for synchronized random number generator\n" |
| << "\t--max-weight miw\t\tMaximum integer edge weight\n" |
| << "\t--rewire-probability\t\tRewire-probabitility (p) for small-world graphs\n" |
| << "\t--dot\t\t\t\tEmit a dot file containing the graph\n" |
| << "\t--verify\t\t\tVerify result\n" |
| << "\t--degree-dist\t\t\tOutput degree distribution of graph\n" |
| << "\t--sequential-graph\t\tRun sequential graph tests\n" |
| << "\t--erdos-renyi\t\t\tRun tests on Erdos-Renyi graphs\n" |
| << "\t--small-world\t\t\tRun tests on Small World graphs\n" |
| << "\t--rmat\t\t\t\tRun tests on R-MAT graphs\n" |
| << "\t--rmat-unique\t\t\tRun tests on R-MAT graphs with no duplicate edges\n" |
| << "\t--csr <bool>\t\t\tRun tests using CSR graphs\n" |
| << "\t--adjacency-list <bool>\t\tRun tests using Adjacency List graphs\n"; |
| } |
| |
| |
| int test_main(int argc, char* argv[]) |
| { |
| mpi::environment env(argc, argv); |
| |
| rand48 gen; |
| |
| // Default args |
| size_t n = 100, |
| m = 8*n, |
| c = 100, |
| num_sources = 32, |
| num_headers = 16 * 1024, |
| batch_buffer_size = 1024 * 1024; |
| uint64_t seed = 1; |
| bool emit_dot_file = false, |
| verify = false, |
| sequential_graph = false, |
| show_degree_dist = false, |
| erdos_renyi = false, |
| small_world = false, |
| rmat = false, |
| rmat_unique = false, |
| csr = false, |
| adj_list = false; |
| double p = 0.1, |
| rmat_a = 0.5, |
| rmat_b = 0.25, |
| rmat_c = 0.1, |
| rmat_d = 0.15; |
| |
| // Parse args |
| for (int i = 1; i < argc; ++i) { |
| std::string arg = argv[i]; |
| |
| if (arg == "--vertices") |
| n = boost::lexical_cast<size_t>( argv[i+1] ); |
| |
| if (arg == "--seed") |
| seed = boost::lexical_cast<uint64_t>( argv[i+1] ); |
| |
| if (arg == "--edges") |
| m = boost::lexical_cast<size_t>( argv[i+1] ); |
| |
| if (arg == "--max-weight") |
| c = boost::lexical_cast<int>( argv[i+1] ); |
| |
| if (arg == "--batch-buffer-size") { |
| batch_buffer_size = boost::lexical_cast<size_t>( argv[i+1] ); |
| num_headers = batch_buffer_size / 16; |
| num_headers = num_headers > 0 ? num_headers : 1; |
| } |
| |
| if (arg == "--rewire-probability") |
| p = boost::lexical_cast<double>( argv[i+1] ); |
| |
| if (arg == "--num-sources") |
| num_sources = boost::lexical_cast<size_t>( argv[i + 1] ); |
| |
| if (arg == "--erdos-renyi") |
| erdos_renyi = true; |
| |
| if (arg == "--small-world") |
| small_world = true; |
| |
| if (arg == "--rmat") |
| rmat = true; |
| |
| if (arg == "--rmat-unique") |
| rmat_unique = true; |
| |
| if (arg == "--dot") |
| emit_dot_file = true; |
| |
| if (arg == "--verify") |
| verify = true; |
| |
| if (arg == "--degree-dist") |
| show_degree_dist = true; |
| |
| if (arg == "--sequential-graph") |
| sequential_graph = true; |
| |
| if (arg == "--csr") |
| csr = std::string(argv[i+1]) == "true"; |
| |
| if (arg == "--adjacency-list") |
| adj_list = std::string(argv[i+1]) == "true"; |
| } |
| |
| mpi_process_group pg(num_headers, batch_buffer_size); |
| |
| if (argc == 1) { |
| if (process_id(pg) == 0) |
| usage(); |
| exit(-1); |
| } |
| |
| gen.seed(seed); |
| |
| parallel::variant_distribution<mpi_process_group> distrib |
| = parallel::block(pg, n); |
| |
| if (csr) { |
| if (process_id(pg) == 0) |
| std::cerr << "CSR Graph Tests\n"; |
| |
| if (erdos_renyi) |
| test_csr(pg, gen, distrib, sequential_graph, n, m, c, num_sources); |
| if (small_world) |
| test_csr(pg, gen, distrib, sequential_graph, n, m, c, p, num_sources); |
| if (rmat) |
| test_csr(pg, gen, distrib, sequential_graph, n, m, c, |
| rmat_a, rmat_b, rmat_c, rmat_d, num_sources, rmat_edge_distribution_tag()); |
| if (rmat_unique) |
| test_csr(pg, gen, distrib, sequential_graph, n, m, c, |
| rmat_a, rmat_b, rmat_c, rmat_d, num_sources, rmat_unique_edge_distribution_tag()); |
| } |
| |
| gen.seed(seed); // DEBUG |
| |
| if (adj_list) { |
| if (process_id(pg) == 0) |
| std::cerr << "Adjacency List Graph Tests\n"; |
| |
| if (erdos_renyi) |
| test_adjacency_list(pg, gen, distrib, sequential_graph, n, m, c); |
| if (small_world) |
| test_adjacency_list(pg, gen, distrib, sequential_graph, n, m, c, p); |
| if (rmat) |
| test_adjacency_list(pg, gen, distrib, sequential_graph, n, m, c, |
| rmat_a, rmat_b, rmat_c, rmat_d, rmat_edge_distribution_tag()); |
| if (rmat_unique) |
| test_adjacency_list(pg, gen, distrib, sequential_graph, n, m, c, |
| rmat_a, rmat_b, rmat_c, rmat_d, rmat_unique_edge_distribution_tag()); |
| } |
| |
| return 0; |
| } |