// Copyright (C) 2006 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 // A test of the distributed compressed sparse row graph type #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if 0 // Contains internal AdjList types not present in CSR graph # include #endif #include // Needed for MST #include #include #include #include #ifdef BOOST_NO_EXCEPTIONS void boost::throw_exception(std::exception const& ex) { std::cout << ex.what() << std::endl; abort(); } #endif /**************************************************************************** * Edge weight generator iterator * ****************************************************************************/ template 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 inline generator_iterator make_generator_iterator( RandomGenerator& gen, const F& f) { return generator_iterator(gen, f); } /**************************************************************************** * Printing DFS Visitor * ****************************************************************************/ struct printing_dfs_visitor { template void initialize_vertex(Vertex v, const Graph& g) { vertex_event("initialize_vertex", v, g); } template void start_vertex(Vertex v, const Graph& g) { vertex_event("start_vertex", v, g); } template void discover_vertex(Vertex v, const Graph& g) { vertex_event("discover_vertex", v, g); } template void examine_edge(Edge e, const Graph& g) { edge_event("examine_edge", e, g); } template void tree_edge(Edge e, const Graph& g) { edge_event("tree_edge", e, g); } template void back_edge(Edge e, const Graph& g) { edge_event("back_edge", e, g); } template void forward_or_cross_edge(Edge e, const Graph& g) { edge_event("forward_or_cross_edge", e, g); } template void finish_vertex(Vertex v, const Graph& g) { vertex_event("finish_vertex", v, g); } private: template void vertex_event(const char* name, Vertex v, const Graph& g) { std::cerr << "#" << process_id(g.process_group()) << ": " << name << "(" << get_vertex_name(v, g) << ": " << local(v) << "@" << owner(v) << ")\n"; } template void edge_event(const char* name, Edge e, const Graph& g) { std::cerr << "#" << process_id(g.process_group()) << ": " << name << "(" << get_vertex_name(source(e, g), g) << ": " << local(source(e, g)) << "@" << owner(source(e, g)) << ", " << get_vertex_name(target(e, g), g) << ": " << local(target(e, g)) << "@" << owner(target(e, g)) << ")\n"; } }; using namespace boost; using boost::graph::distributed::mpi_process_group; typedef int weight_type; struct WeightedEdge { WeightedEdge(weight_type weight = 0) : weight(weight) { } weight_type weight; template void serialize(Archiver& ar, const unsigned int /*version*/) { ar & weight; } }; struct VertexProperties { VertexProperties(int d = 0) : distance(d) { } int distance; template void serialize(Archiver& ar, const unsigned int /*version*/) { ar & distance; } }; int test_main(int argc, char* argv[]) { mpi::environment env(argc, argv); typedef compressed_sparse_row_graph > Digraph; // Make sure we can build graphs using common graph generators typedef sorted_erdos_renyi_iterator ERIter; typedef small_world_iterator SWIter; typedef sorted_rmat_iterator RMATIter; typedef graph_traits::edge_descriptor edge_descriptor; int n = 40; int k = 3; double prob = 0.1; int C = 10; double a = 0.5, b = 0.1, c = 0.25, d = 0.15; int iterations = 50; int num_colors = n / 10; int lookahead = C / 10; minstd_rand gen; // Directed Graphs Digraph g(ERIter(gen, n, prob), ERIter(), make_generator_iterator(gen, uniform_int(0, C)), n); Digraph g2(SWIter(gen, n, k, prob), SWIter(), n); Digraph g3(RMATIter(gen, n, size_t(n*n*prob), a, b, c, d), RMATIter(), n); // Test BFS breadth_first_search(g, vertex(0, g), visitor(bfs_visitor<>())); // Test SSSP Algorithms graph::distributed::delta_stepping_shortest_paths(g, vertex(0, g), dummy_property_map(), get(&VertexProperties::distance, g), get(&WeightedEdge::weight, g)); dijkstra_shortest_paths(g, vertex(0, g), distance_map(get(&VertexProperties::distance, g)). weight_map(get(&WeightedEdge::weight, g))); dijkstra_shortest_paths(g, vertex(0, g), distance_map(get(&VertexProperties::distance, g)). weight_map(get(&WeightedEdge::weight, g)). lookahead(lookahead)); // Test PageRank using boost::graph::n_iterations; std::vector ranks(num_vertices(g)); page_rank(g, make_iterator_property_map(ranks.begin(), get(boost::vertex_index, g)), n_iterations(iterations), 0.85, vertex(0, g)); // Test Graph Coloring typedef property_map::type vertex_index_map; std::vector colors_vec(num_vertices(g)); iterator_property_map color(&colors_vec[0], get(vertex_index, g)); graph::boman_et_al_graph_coloring(g, color, num_colors); // Test DFS // // DFS requires an undirected graph, currently CSR graphs must be directed #if 0 std::vector parent(num_vertices(g)); std::vector explore(num_vertices(g)); boost::graph::tsin_depth_first_visit (g, vertex(0, g), printing_dfs_visitor(), color, make_iterator_property_map(parent.begin(), get(vertex_index, g)), make_iterator_property_map(explore.begin(), get(vertex_index, g)), get(vertex_index, g)); #endif // Test S-T Connected st_connected(g, vertex(0, g), vertex(1, g), color, get(vertex_owner, g)); // Test Connected Components // // CC requires an undirected graph, currently CSR graphs must be directed #if 0 std::vector local_components_vec(num_vertices(g)); typedef iterator_property_map::iterator, vertex_index_map> ComponentMap; ComponentMap component(local_components_vec.begin(), get(vertex_index, g)); assert(connected_components(g, component) == connected_components_ps(g, component)); #endif // Test Betweenness Centrality // // Betweenness Centrality is broken at the moment typedef iterator_property_map::iterator, vertex_index_map> CentralityMap; std::vector centralityS(num_vertices(g), 0); CentralityMap centrality(centralityS.begin(), get(vertex_index, g)); brandes_betweenness_centrality(g, centrality); // // Test MST // std::vector mst_edges; dense_boruvka_minimum_spanning_tree(make_vertex_list_adaptor(g), get(&WeightedEdge::weight, g), std::back_inserter(mst_edges)); mst_edges.clear(); merge_local_minimum_spanning_trees(make_vertex_list_adaptor(g), get(&WeightedEdge::weight, g), std::back_inserter(mst_edges)); mst_edges.clear(); boruvka_then_merge(make_vertex_list_adaptor(g), get(&WeightedEdge::weight, g), std::back_inserter(mst_edges)); mst_edges.clear(); boruvka_mixed_merge(make_vertex_list_adaptor(g), get(&WeightedEdge::weight, g), std::back_inserter(mst_edges)); // Test Strong Components // // Can't build reverse graph of a CSR graph #if 0 std::vector local_components_vec(num_vertices(g)); typedef iterator_property_map::iterator, vertex_index_map> ComponentMap; ComponentMap component(local_components_vec.begin(), get(vertex_index, g)); int num_components = strong_components(g, component); #endif std::ofstream out("dcsr.dot"); write_graphviz(out, g); return 0; }