diff --git a/include/boost/graph/distributed/betweenness_centrality.hpp b/include/boost/graph/distributed/betweenness_centrality.hpp index 24b5282..6de8b2e 100644 --- a/include/boost/graph/distributed/betweenness_centrality.hpp +++ b/include/boost/graph/distributed/betweenness_centrality.hpp @@ -79,30 +79,6 @@ namespace boost { } // serialization - namespace graph { namespace distributed { - - // HACKY: Overload get on a tuple to return the value at the key indicated - // by the first element of the tuple so that we can use tuples in a distributed queue - template - inline - typename PropertyMap::value_type - get(PropertyMap& pm, boost::tuple const& t) - { - return get(pm, boost::tuples::get<0>(t)); - } - - // HACKY: Same as above for std::pair - template - inline - typename PropertyMap::value_type - get(PropertyMap& pm, std::pair const& t) - { - return get(pm, t.first); - } - - } } // graph::distributed - - template class get_owner_of_first_tuple_element { diff --git a/include/boost/graph/distributed/compressed_sparse_row_graph.hpp b/include/boost/graph/distributed/compressed_sparse_row_graph.hpp index 70a6e10..c432b70 100644 --- a/include/boost/graph/distributed/compressed_sparse_row_graph.hpp +++ b/include/boost/graph/distributed/compressed_sparse_row_graph.hpp @@ -17,6 +17,8 @@ #error "Parallel BGL files should not be included unless has been included" #endif +#define BOOST_GRAPH_USE_NEW_CSR_INTERFACE + #include #include #include @@ -29,6 +31,11 @@ namespace boost { +// Distributed and sequential inplace ctors have the same signature so +// we need a separate tag for distributed inplace ctors +enum distributed_construct_inplace_from_sources_and_targets_t + {distributed_construct_inplace_from_sources_and_targets}; + // The number of bits we reserve for the processor ID. // DPG TBD: This is a hack. It will eventually be a run-time quantity. static const int processor_bits = 8; @@ -142,6 +149,181 @@ class compressed_sparse_row_graph< compressed_sparse_row_graph(const ProcessGroup& pg = ProcessGroup()) : m_process_group(pg), m_distribution(parallel::block(pg, 0)) {} + compressed_sparse_row_graph(const GraphProperty& prop, + const ProcessGroup& pg = ProcessGroup()) + : m_process_group(pg), m_distribution(parallel::block(pg, 0)) {} + + compressed_sparse_row_graph(vertices_size_type numverts, + const ProcessGroup& pg = ProcessGroup()) + : m_process_group(pg), m_distribution(parallel::block(pg, 0)), + m_base(numverts) + {} + + compressed_sparse_row_graph(vertices_size_type numverts, + const GraphProperty& prop, + const ProcessGroup& pg = ProcessGroup()) + : m_process_group(pg), m_distribution(parallel::block(pg, 0)), + m_base(numverts) + {} + + template + compressed_sparse_row_graph(vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist) + : m_process_group(pg), m_distribution(dist), m_base(numverts) {} + + template + compressed_sparse_row_graph(vertices_size_type numverts, + const GraphProperty& prop, + const ProcessGroup& pg, + const Distribution& dist) + : m_process_group(pg), m_distribution(dist), m_base(numverts) {} + +#ifdef BOOST_GRAPH_USE_NEW_CSR_INTERFACE + + template + compressed_sparse_row_graph(edges_are_unsorted_t, + InputIterator edge_begin, InputIterator edge_end, + vertices_size_type numverts, + const ProcessGroup& pg = ProcessGroup(), + const GraphProperty& prop = GraphProperty()); + + template + compressed_sparse_row_graph(edges_are_unsorted_t, + InputIterator edge_begin, InputIterator edge_end, + vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist, + const GraphProperty& prop = GraphProperty()); + + template + compressed_sparse_row_graph(edges_are_unsorted_t, + InputIterator edge_begin, InputIterator edge_end, + EdgePropertyIterator ep_iter, + vertices_size_type numverts, + const ProcessGroup& pg = ProcessGroup(), + const GraphProperty& prop = GraphProperty()); + + template + compressed_sparse_row_graph(edges_are_unsorted_t, + InputIterator edge_begin, InputIterator edge_end, + EdgePropertyIterator ep_iter, + vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist, + const GraphProperty& prop = GraphProperty()); + + template + compressed_sparse_row_graph(edges_are_sorted_t, + InputIterator edge_begin, InputIterator edge_end, + vertices_size_type numverts, + edges_size_type numedges = 0, + const ProcessGroup& pg = ProcessGroup(), + const GraphProperty& prop = GraphProperty()); + + template + compressed_sparse_row_graph(edges_are_sorted_t, + InputIterator edge_begin, InputIterator edge_end, + vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist, + const GraphProperty& prop = GraphProperty()); + + template + compressed_sparse_row_graph(edges_are_sorted_t, + InputIterator edge_begin, InputIterator edge_end, + EdgePropertyIterator ep_iter, + vertices_size_type numverts, + edges_size_type numedges = 0, + const ProcessGroup& pg = ProcessGroup(), + const GraphProperty& prop = GraphProperty()); + + template + compressed_sparse_row_graph(edges_are_sorted_t, + InputIterator edge_begin, InputIterator edge_end, + EdgePropertyIterator ep_iter, + vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist, + const GraphProperty& prop = GraphProperty()); + + template + compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, + MultiPassInputIterator edge_begin, + MultiPassInputIterator edge_end, + vertices_size_type numverts, + const ProcessGroup& pg = ProcessGroup(), + const GraphProperty& prop = GraphProperty()); + + template + compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, + MultiPassInputIterator edge_begin, + MultiPassInputIterator edge_end, + vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist, + const GraphProperty& prop = GraphProperty()); + + template + compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, + MultiPassInputIterator edge_begin, + MultiPassInputIterator edge_end, + EdgePropertyIterator ep_iter, + vertices_size_type numverts, + const ProcessGroup& pg = ProcessGroup(), + const GraphProperty& prop = GraphProperty()); + + template + compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, + MultiPassInputIterator edge_begin, + MultiPassInputIterator edge_end, + EdgePropertyIterator ep_iter, + vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist, + const GraphProperty& prop = GraphProperty()); + + template + compressed_sparse_row_graph(distributed_construct_inplace_from_sources_and_targets_t, + std::vector& sources, + std::vector& targets, + vertices_size_type numverts, + const ProcessGroup& pg = ProcessGroup(), + const GraphProperty& prop = GraphProperty()); + + template + compressed_sparse_row_graph(distributed_construct_inplace_from_sources_and_targets_t, + std::vector& sources, + std::vector& targets, + vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist, + const GraphProperty& prop = GraphProperty()); + + template + compressed_sparse_row_graph(distributed_construct_inplace_from_sources_and_targets_t, + std::vector& sources, + std::vector& targets, + std::vector& edge_props, + vertices_size_type numverts, + const ProcessGroup& pg = ProcessGroup(), + const GraphProperty& prop = GraphProperty()); + + template + compressed_sparse_row_graph(distributed_construct_inplace_from_sources_and_targets_t, + std::vector& sources, + std::vector& targets, + std::vector& edge_props, + vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist, + const GraphProperty& prop = GraphProperty()); + +#endif + template compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, vertices_size_type numverts, @@ -223,6 +405,57 @@ class compressed_sparse_row_graph< return make_vertex_descriptor(process_id(m_process_group), v); } + // Structural modification + vertex_descriptor add_vertex() + { + typename graph_traits::vertex_descriptor v + = boost::add_vertex(m_base); + + return make_vertex_descriptor(process_id(m_process_group), v); + } + + vertex_descriptor add_vertex(const vertex_bundled& p) + { + typename graph_traits::vertex_descriptor v + = boost::add_vertex(m_base, p); + + return make_vertex_descriptor(process_id(m_process_group), v); + } + + vertex_descriptor add_vertices(vertices_size_type count) + { + typename graph_traits::vertex_descriptor v + = boost::add_vertices(count, m_base); + + return make_vertex_descriptor(process_id(m_process_group), v); + } + + template + void + add_edges(InputIterator first, InputIterator last) + { boost::add_edges_global(first, last, get(vertex_local, *this), m_base); } + + template + void + add_edges(InputIterator first, InputIterator last, + EdgePropertyIterator ep_iter, + EdgePropertyIterator ep_iter_end) + { boost::add_edges_global(first, last, ep_iter, ep_iter_end, + get(vertex_local, *this), m_base); } + + template + void + add_edges_sorted(InputIterator first, InputIterator last) + { boost::add_edges_sorted_global(first, last, + get(vertex_local, *this), m_base); } + + template + void + add_edges_sorted(InputIterator first_sorted, InputIterator last_sorted, + EdgePropertyIterator ep_iter_sorted) + { boost::add_edges_sorted_global(first_sorted, last_sorted, ep_iter_sorted, + get(vertex_local, *this), m_base); } + protected: ProcessGroup m_process_group; distribution_type m_distribution; @@ -471,6 +704,501 @@ edges(const BOOST_DISTRIB_CSR_GRAPH_TYPE& g) // ----------------------------------------------------------------- // Graph constructors + +#ifdef BOOST_GRAPH_USE_NEW_CSR_INTERFACE +// Returns true if a vertex belongs to a process according to a distribution +template +struct local_edge { + + local_edge(OwnerMap owner, ProcessId id) + : owner(owner), id(id) {} + + template + bool operator()(std::pair& x) + { return get(owner, x.first) == id; } + + template + bool operator()(const std::pair& x) const + { return get(owner, x.first) == id; } + +private: + OwnerMap owner; + ProcessId id; +}; + +// Turns an index iterator into a vertex iterator +template +class index_to_vertex_iterator { + +public: + typedef std::input_iterator_tag iterator_category; + typedef typename graph_traits::vertex_descriptor Vertex; + typedef std::pair value_type; + typedef const value_type& reference; + typedef const value_type* pointer; + typedef void difference_type; + + index_to_vertex_iterator(IndexIterator index, + const Graph& g) + : index(index), g(g), current(to_edge(*index)) {} + + reference operator*() { current = to_edge(*index); return current; } + pointer operator->() { current = to_edge(*index); return ¤t; } + + index_to_vertex_iterator& operator++() + { + ++index; + return *this; + } + + index_to_vertex_iterator operator++(int) + { + index_to_vertex_iterator temp(*this); + ++(*this); + return temp; + } + + bool operator==(const index_to_vertex_iterator& other) const + { return index == other.index; } + + bool operator!=(const index_to_vertex_iterator& other) const + { return !(*this == other); } + +private: + value_type to_edge(const typename std::iterator_traits::value_type& x) + { return std::make_pair(vertex(x.first, g), vertex(x.second, g)); } + + IndexIterator index; + const Graph& g; + value_type current; +}; + +template +struct index_to_vertex_func { + + typedef typename boost::graph_traits::vertex_descriptor vertex_descriptor; + typedef typename boost::graph_traits::vertices_size_type vertices_size_type; + typedef std::pair result_type; + typedef std::pair base_iterator_type; + + index_to_vertex_func(const Distribution& dist, const Graph& g) + : dist(dist), g(g) {} + + + result_type operator()(const base_iterator_type& p) const + { + return std::make_pair(vertex(p.first, g), vertex(p.second, g)); + } + +private: + const Distribution& dist; + const Graph& g; +}; + +// NGE: This method only works with iterators that have a difference_type, +// the index_to_vertex_iterator class above is retained for compatibility +// with BGL generators which have no difference_type +template +boost::transform_iterator, IndexIterator> +make_index_to_vertex_iterator(IndexIterator it, const Distribution& dist, + const Graph& g) { + return boost::make_transform_iterator( + it, index_to_vertex_func(dist, g)); +} +#endif + +// Forward declaration of csr_vertex_owner_map +template class csr_vertex_owner_map; + +#ifdef BOOST_GRAPH_USE_NEW_CSR_INTERFACE + +template +template +BOOST_DISTRIB_CSR_GRAPH_TYPE:: +compressed_sparse_row_graph(edges_are_unsorted_t, + InputIterator edge_begin, InputIterator edge_end, + vertices_size_type numverts, + const ProcessGroup& pg, + const GraphProperty& prop) + : m_process_group(pg), + m_distribution(parallel::block(m_process_group, numverts)), + m_base(edges_are_unsorted_global, + index_to_vertex_iterator(edge_begin, *this), + index_to_vertex_iterator(edge_end, *this), + m_distribution.block_size(process_id(m_process_group), numverts), + get(vertex_local, *this), + local_edge, + process_id_type> (get(vertex_owner, *this), process_id(pg)), + prop) +{ } + +template +template +BOOST_DISTRIB_CSR_GRAPH_TYPE:: +compressed_sparse_row_graph(edges_are_unsorted_t, + InputIterator edge_begin, InputIterator edge_end, + vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist, + const GraphProperty& prop) + : m_process_group(pg), + m_distribution(dist), + m_base(edges_are_unsorted_global, + index_to_vertex_iterator(edge_begin, *this), + index_to_vertex_iterator(edge_end, *this), + m_distribution.block_size(process_id(m_process_group), numverts), + get(vertex_local, *this), + local_edge, + process_id_type> (get(vertex_owner, *this), process_id(pg)), + prop) +{ } + +template +template +BOOST_DISTRIB_CSR_GRAPH_TYPE:: +compressed_sparse_row_graph(edges_are_unsorted_t, + InputIterator edge_begin, InputIterator edge_end, + EdgePropertyIterator ep_iter, + vertices_size_type numverts, + const ProcessGroup& pg, + const GraphProperty& prop) + : m_process_group(pg), + m_distribution(parallel::block(m_process_group, numverts)), + m_base(edges_are_unsorted_global, + index_to_vertex_iterator(edge_begin, *this), + index_to_vertex_iterator(edge_end, *this), + ep_iter, + m_distribution.block_size(process_id(m_process_group), numverts), + get(vertex_local, *this), + local_edge, + process_id_type> (get(vertex_owner, *this), process_id(pg)), + prop) +{ } + +template +template +BOOST_DISTRIB_CSR_GRAPH_TYPE:: +compressed_sparse_row_graph(edges_are_unsorted_t, + InputIterator edge_begin, InputIterator edge_end, + EdgePropertyIterator ep_iter, + vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist, + const GraphProperty& prop) + : m_process_group(pg), + m_distribution(dist), + m_base(edges_are_unsorted_global, + index_to_vertex_iterator(edge_begin, *this), + index_to_vertex_iterator(edge_end, *this), + ep_iter, + m_distribution.block_size(process_id(m_process_group), numverts), + get(vertex_local, *this), + local_edge, + process_id_type> (get(vertex_owner, *this), process_id(pg)), + prop) +{ } + +template +template +BOOST_DISTRIB_CSR_GRAPH_TYPE:: +compressed_sparse_row_graph(edges_are_sorted_t, + InputIterator edge_begin, InputIterator edge_end, + vertices_size_type numverts, + edges_size_type numedges, // This is not used as there is no appropriate BGL ctor + const ProcessGroup& pg, + const GraphProperty& prop) + : m_process_group(pg), + m_distribution(parallel::block(m_process_group, numverts)), + m_base(edges_are_sorted_global, + index_to_vertex_iterator(edge_begin, *this), + index_to_vertex_iterator(edge_end, *this), + get(vertex_local, *this), + local_edge, + process_id_type> (get(vertex_owner, *this), process_id(pg)), + m_distribution.block_size(process_id(m_process_group), numverts), + prop) +{ } + +template +template +BOOST_DISTRIB_CSR_GRAPH_TYPE:: +compressed_sparse_row_graph(edges_are_sorted_t, + InputIterator edge_begin, InputIterator edge_end, + vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist, + const GraphProperty& prop) + : m_process_group(pg), + m_distribution(dist), + m_base(edges_are_sorted_global, + index_to_vertex_iterator(edge_begin, *this), + index_to_vertex_iterator(edge_end, *this), + get(vertex_local, *this), + local_edge, + process_id_type> (get(vertex_owner, *this), process_id(pg)), + m_distribution.block_size(process_id(m_process_group), numverts), + prop) +{ } + +template +template +BOOST_DISTRIB_CSR_GRAPH_TYPE:: +compressed_sparse_row_graph(edges_are_sorted_t, + InputIterator edge_begin, InputIterator edge_end, + EdgePropertyIterator ep_iter, + vertices_size_type numverts, + edges_size_type numedges, // This is not used as there is no appropriate BGL ctor + const ProcessGroup& pg, + const GraphProperty& prop) + : m_process_group(pg), + m_distribution(parallel::block(m_process_group, numverts)), + m_base(edges_are_sorted_global, + index_to_vertex_iterator(edge_begin, *this), + index_to_vertex_iterator(edge_end, *this), + ep_iter, + get(vertex_local, *this), + local_edge, + process_id_type> (get(vertex_owner, *this), process_id(pg)), + m_distribution.block_size(process_id(m_process_group), numverts), + prop) +{ } + +template +template +BOOST_DISTRIB_CSR_GRAPH_TYPE:: +compressed_sparse_row_graph(edges_are_sorted_t, + InputIterator edge_begin, InputIterator edge_end, + EdgePropertyIterator ep_iter, + vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist, + const GraphProperty& prop) + : m_process_group(pg), + m_distribution(dist), + m_base(edges_are_sorted_global, + index_to_vertex_iterator(edge_begin, *this), + index_to_vertex_iterator(edge_end, *this), + ep_iter, + get(vertex_local, *this), + local_edge, + process_id_type> (get(vertex_owner, *this), process_id(pg)), + m_distribution.block_size(process_id(m_process_group), numverts), + prop) +{ } + +template +template +BOOST_DISTRIB_CSR_GRAPH_TYPE:: +compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, + MultiPassInputIterator edge_begin, + MultiPassInputIterator edge_end, + vertices_size_type numverts, + const ProcessGroup& pg, + const GraphProperty& prop) + : m_process_group(pg), + m_distribution(parallel::block(m_process_group, numverts)), + m_base(edges_are_unsorted_multi_pass_global, + make_index_to_vertex_iterator(edge_begin, parallel::block(m_process_group, numverts), *this), + make_index_to_vertex_iterator(edge_end, parallel::block(m_process_group, numverts), *this), + m_distribution.block_size(process_id(m_process_group), numverts), + get(vertex_local, *this), + local_edge, + process_id_type> (get(vertex_owner, *this), process_id(pg)), + prop) +{ } + +template +template +BOOST_DISTRIB_CSR_GRAPH_TYPE:: +compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, + MultiPassInputIterator edge_begin, + MultiPassInputIterator edge_end, + vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist, + const GraphProperty& prop) + : m_process_group(pg), + m_distribution(dist), + m_base(edges_are_unsorted_multi_pass_global, + make_index_to_vertex_iterator(edge_begin, parallel::block(m_process_group, numverts), *this), + make_index_to_vertex_iterator(edge_end, parallel::block(m_process_group, numverts), *this), + m_distribution.block_size(process_id(m_process_group), numverts), + get(vertex_local, *this), + local_edge, + process_id_type> (get(vertex_owner, *this), process_id(pg)), + prop) +{ } + + +template +template +BOOST_DISTRIB_CSR_GRAPH_TYPE:: +compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, + MultiPassInputIterator edge_begin, + MultiPassInputIterator edge_end, + EdgePropertyIterator ep_iter, + vertices_size_type numverts, + const ProcessGroup& pg, + const GraphProperty& prop) + : m_process_group(pg), + m_distribution(parallel::block(m_process_group, numverts)), + m_base(edges_are_unsorted_multi_pass_global, + make_index_to_vertex_iterator(edge_begin, parallel::block(m_process_group, numverts), *this), + make_index_to_vertex_iterator(edge_end, parallel::block(m_process_group, numverts), *this), + ep_iter, + m_distribution.block_size(process_id(m_process_group), numverts), + get(vertex_local, *this), + local_edge, + process_id_type> (get(vertex_owner, *this), process_id(pg)), + prop) +{ } + +template +template +BOOST_DISTRIB_CSR_GRAPH_TYPE:: +compressed_sparse_row_graph(edges_are_unsorted_multi_pass_t, + MultiPassInputIterator edge_begin, + MultiPassInputIterator edge_end, + EdgePropertyIterator ep_iter, + vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist, + const GraphProperty& prop) + : m_process_group(pg), + m_distribution(dist), + m_base(edges_are_unsorted_multi_pass_global, + make_index_to_vertex_iterator(edge_begin, parallel::block(m_process_group, numverts), *this), + make_index_to_vertex_iterator(edge_end, parallel::block(m_process_group, numverts), *this), + ep_iter, + m_distribution.block_size(process_id(m_process_group), numverts), + get(vertex_local, *this), + local_edge, + process_id_type> (get(vertex_owner, *this), process_id(pg)), + prop) +{ } + +template +template +BOOST_DISTRIB_CSR_GRAPH_TYPE:: +compressed_sparse_row_graph(distributed_construct_inplace_from_sources_and_targets_t, + std::vector& sources, + std::vector& targets, + vertices_size_type numverts, + const ProcessGroup& pg, + const GraphProperty& prop) + : m_process_group(pg), + m_distribution(parallel::block(m_process_group, numverts)), + m_base(m_distribution.block_size(process_id(m_process_group), numverts)) +{ + // Convert linear indices to global indices + for (edges_size_type i = 0; i < sources.size(); ++i) { + sources[i] = m_distribution.local(sources[i]); + targets[i] = make_vertex_descriptor(m_distribution(targets[i]), + m_distribution.local(targets[i])); + } + + m_base.assign_sources_and_targets_global( + sources, targets, m_distribution.block_size(process_id(m_process_group), numverts), + identity_property_map()); + + // TODO: set property on m_base? +} + +template +template +BOOST_DISTRIB_CSR_GRAPH_TYPE:: +compressed_sparse_row_graph(distributed_construct_inplace_from_sources_and_targets_t, + std::vector& sources, + std::vector& targets, + vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist, + const GraphProperty& prop) + : m_process_group(pg), + m_distribution(dist), + m_base(m_distribution.block_size(process_id(m_process_group), numverts)) +{ + // Convert linear indices to global indices + for (edges_size_type i = 0; i < sources.size(); ++i) { + sources[i] = m_distribution.local(sources[i]); + targets[i] = make_vertex_descriptor(m_distribution(targets[i]), + m_distribution.local(targets[i])); + } + + m_base.assign_sources_and_targets_global( + sources, targets, m_distribution.block_size(process_id(m_process_group), numverts), + identity_property_map()); + + // TODO: set property on m_base? +} + +template +template +BOOST_DISTRIB_CSR_GRAPH_TYPE:: +compressed_sparse_row_graph(distributed_construct_inplace_from_sources_and_targets_t, + std::vector& sources, + std::vector& targets, + std::vector& edge_props, + vertices_size_type numverts, + const ProcessGroup& pg, + const GraphProperty& prop) + : m_process_group(pg), + m_distribution(parallel::block(m_process_group, numverts)), + m_base(m_distribution.block_size(process_id(m_process_group), numverts)) +{ + // Convert linear indices to global indices + for (edges_size_type i = 0; i < sources.size(); ++i) { + sources[i] = m_distribution.local(sources[i]); + targets[i] = make_vertex_descriptor(m_distribution(targets[i]), + m_distribution.local(targets[i])); + } + + m_base.assign_sources_and_targets_global( + sources, targets, edge_props, + m_distribution.block_size(process_id(m_process_group), numverts), + identity_property_map()); + + // TODO: set property on m_base? +} + +template +template +BOOST_DISTRIB_CSR_GRAPH_TYPE:: +compressed_sparse_row_graph(distributed_construct_inplace_from_sources_and_targets_t, + std::vector& sources, + std::vector& targets, + std::vector& edge_props, + vertices_size_type numverts, + const ProcessGroup& pg, + const Distribution& dist, + const GraphProperty& prop) + : m_process_group(pg), + m_distribution(dist), + m_base(m_distribution.block_size(process_id(m_process_group), numverts)) +{ + // Convert linear indices to global indices + for (edges_size_type i = 0; i < sources.size(); ++i) { + sources[i] = m_distribution.local(sources[i]); + targets[i] = make_vertex_descriptor(m_distribution(targets[i]), + m_distribution.local(targets[i])); + } + + m_base.assign_sources_and_targets_global( + sources, targets, edge_props, + m_distribution.block_size(process_id(m_process_group), numverts), + identity_property_map()); + + // TODO: set property on m_base? +} + +#endif + +// +// Old (untagged) ctors, these default to the unsorted sequential ctors +// template template BOOST_DISTRIB_CSR_GRAPH_TYPE:: @@ -480,8 +1208,21 @@ compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, const GraphProperty& prop) : m_process_group(pg), m_distribution(parallel::block(m_process_group, numverts)), +#ifndef BOOST_GRAPH_USE_NEW_CSR_INTERFACE m_base(m_distribution.block_size(process_id(m_process_group), numverts)) +#else + m_base(edges_are_unsorted_global, + index_to_vertex_iterator(edge_begin, *this), + index_to_vertex_iterator(edge_end, *this), + m_distribution.block_size(process_id(m_process_group), numverts), + get(vertex_local, *this), + local_edge, + process_id_type> (get(vertex_owner, *this), process_id(pg)), + prop) +#endif + { +#ifndef BOOST_GRAPH_USE_NEW_CSR_INTERFACE parallel::block dist(m_process_group, numverts); // Allows us to add edges @@ -499,6 +1240,7 @@ compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, } ++edge_begin; } +#endif } template @@ -510,9 +1252,23 @@ compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, const ProcessGroup& pg, const GraphProperty& prop) : m_process_group(pg), + m_distribution(parallel::block(m_process_group, numverts)), +#ifndef BOOST_GRAPH_USE_NEW_CSR_INTERFACE m_base(m_distribution.block_size(process_id(m_process_group), numverts)) +#else + m_base(edges_are_unsorted_global, + index_to_vertex_iterator(edge_begin, *this), + index_to_vertex_iterator(edge_end, *this), + ep_iter, + m_distribution.block_size(process_id(m_process_group), numverts), + get(vertex_local, *this), + local_edge, + process_id_type> (get(vertex_owner, *this), process_id(pg)), + prop) +#endif { +#ifndef BOOST_GRAPH_USE_NEW_CSR_INTERFACE parallel::block dist(m_process_group, numverts); // Allows us to add edges @@ -526,12 +1282,12 @@ compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, EdgeIndex tgt = make_vertex_descriptor(dist(edge_begin->second), dist.local(edge_begin->second)); - add_edge(dist.local(src), tgt, *ep_iter, m_base); } ++edge_begin; ++ep_iter; } +#endif } template @@ -544,8 +1300,20 @@ compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, const GraphProperty& prop) : m_process_group(pg), m_distribution(dist), +#ifndef BOOST_GRAPH_USE_NEW_CSR_INTERFACE m_base(dist.block_size(process_id(m_process_group), numverts)) +#else + m_base(edges_are_unsorted_global, + index_to_vertex_iterator(edge_begin, *this), + index_to_vertex_iterator(edge_end, *this), + m_distribution.block_size(process_id(m_process_group), numverts), + get(vertex_local, *this), + local_edge, + process_id_type> (get(vertex_owner, *this), process_id(pg)), + prop) +#endif { +#ifndef BOOST_GRAPH_USE_NEW_CSR_INTERFACE // Allows us to add edges m_base.m_last_source = 0; @@ -563,6 +1331,7 @@ compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, } ++edge_begin; } +#endif } template @@ -577,8 +1346,20 @@ compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, const GraphProperty& prop) : m_process_group(pg), m_distribution(dist), +#ifndef BOOST_GRAPH_USE_NEW_CSR_INTERFACE m_base(dist.block_size(process_id(m_process_group), numverts)) +#else + m_base(edges_are_unsorted_global, + index_to_vertex_iterator(edge_begin, *this), + index_to_vertex_iterator(edge_end, *this), + m_distribution.block_size(process_id(m_process_group), numverts), + get(vertex_local, *this), + local_edge, + process_id_type> (get(vertex_owner, *this), process_id(pg)), + prop) +#endif { +#ifndef BOOST_GRAPH_USE_NEW_CSR_INTERFACE // Allows us to add edges m_base.m_last_source = 0; @@ -595,6 +1376,7 @@ compressed_sparse_row_graph(InputIterator edge_begin, InputIterator edge_end, ++edge_begin; ++ep_iter; } +#endif } // ----------------------------------------------------------------- @@ -744,6 +1526,57 @@ class property_map typedef type const_type; }; +// ----------------------------------------------------------------- +// Structural modifiers + +#if 0 +template +typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor +add_vertex(BOOST_DISTRIB_CSR_GRAPH_TYPE& g) +{ return g.add_vertex(); } + +template +typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor +add_vertex(const typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_bundled& p, + BOOST_DISTRIB_CSR_GRAPH_TYPE& g) +{ return g.add_vertex(p); } + +template +typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertex_descriptor +add_vertices(typename BOOST_DISTRIB_CSR_GRAPH_TYPE::vertices_size_type count, + BOOST_DISTRIB_CSR_GRAPH_TYPE& g) +{ return g.add_vertices(count); } + +template +void +add_edges(InputIterator first, InputIterator last, + BOOST_DISTRIB_CSR_GRAPH_TYPE& g) +{ g.add_edges(first, last); } + +template +void +add_edges(InputIterator first, InputIterator last, + EdgePropertyIterator ep_iter, + EdgePropertyIterator ep_iter_end, + BOOST_DISTRIB_CSR_GRAPH_TYPE& g) +{ return g.add_edges(first, last, ep_iter, ep_iter_end); } + +template +void +add_edges_sorted(InputIterator first, InputIterator last, + BOOST_DISTRIB_CSR_GRAPH_TYPE& g) +{ return g.add_edges_sorted(first, last); } + +template +void +add_edges_sorted(InputIterator first_sorted, InputIterator last_sorted, + EdgePropertyIterator ep_iter_sorted, + BOOST_DISTRIB_CSR_GRAPH_TYPE& g) +{ g.add_edges_sorted(first_sorted, last_sorted, ep_iter_sorted); } +#endif + // ----------------------------------------------------------------- // Vertex Owner Property Map template diff --git a/include/boost/graph/distributed/eager_dijkstra_shortest_paths.hpp b/include/boost/graph/distributed/eager_dijkstra_shortest_paths.hpp index 3fc4176..8cee034 100644 --- a/include/boost/graph/distributed/eager_dijkstra_shortest_paths.hpp +++ b/include/boost/graph/distributed/eager_dijkstra_shortest_paths.hpp @@ -113,10 +113,20 @@ template c_pred(m_predecessor); boost::parallel::caching_property_map c_dist(m_distance); + distance_type old_distance = get(c_dist, target(e, g)); + bool m_decreased = relax(e, g, m_weight, c_pred, c_dist, m_combine, m_compare); - if (m_decreased) { + /* On x86 Linux with optimization, we sometimes get into a + horrible case where m_decreased is true but the distance hasn't + actually changed. This occurs when the comparison inside + relax() occurs with the 80-bit precision of the x87 floating + point unit, but the difference is lost when the resulting + values are written back to lower-precision memory (e.g., a + double). With the eager Dijkstra's implementation, this results + in looping. */ + if (m_decreased && old_distance != get(c_dist, target(e, g))) { m_Q.update(target(e, g)); m_vis.edge_relaxed(e, g); } else diff --git a/include/boost/graph/distributed/st_connected.hpp b/include/boost/graph/distributed/st_connected.hpp index 9400458..b007442 100644 --- a/include/boost/graph/distributed/st_connected.hpp +++ b/include/boost/graph/distributed/st_connected.hpp @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include #include @@ -46,8 +46,8 @@ st_connected(const DistributedGraph& g, typename graph_traits::vertex_descriptor t, ColorMap color, OwnerMap owner) { - using boost::parallel::process_group; - using boost::parallel::process_group_type; + using boost::graph::parallel::process_group; + using boost::graph::parallel::process_group_type; using boost::parallel::all_reduce; typedef typename property_traits::value_type Color; diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f425344..4e5a939 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -87,6 +87,7 @@ if (MPI_FOUND) boost_graph_parallel_test(distributed_rmat_cc_ps) boost_graph_parallel_test(distributed_rmat_cc) boost_graph_parallel_test(distributed_rmat_pagerank) + boost_graph_parallel_test(distributed_st_connected_test) boost_add_executable(ssca ssca.cpp diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 0950fee..61bf161 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -41,6 +41,7 @@ test-suite graph_parallel [ mpi-test distributed_rmat_cc_ps : : : 2 ] [ mpi-test distributed_rmat_cc : : : 2 ] [ mpi-test distributed_rmat_pagerank : : : 2 ] + [ mpi-test distributed_st_connected_test : : : 2 ] ; } diff --git a/test/algorithm_performance.cpp b/test/algorithm_performance.cpp index 83e7a9e..6772bfd 100644 --- a/test/algorithm_performance.cpp +++ b/test/algorithm_performance.cpp @@ -359,7 +359,8 @@ void test_csr(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distri typedef compressed_sparse_row_graph seqGraph; - seqGraph sg(sorted_rmat_iterator(gen, N, M, a, b, c, d), + seqGraph sg(edges_are_sorted, + sorted_rmat_iterator(gen, N, M, a, b, c, d), sorted_rmat_iterator(), make_generator_iterator(gen, uniform_int(1, C)), N); @@ -394,7 +395,8 @@ void test_csr(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distri typedef compressed_sparse_row_graph seqGraph; - seqGraph sg(sorted_unique_rmat_iterator(gen, N, M, a, b, c, d), + seqGraph sg(edges_are_sorted, + sorted_unique_rmat_iterator(gen, N, M, a, b, c, d), sorted_unique_rmat_iterator(), make_generator_iterator(gen, uniform_int(1, C)), N); @@ -428,7 +430,8 @@ void test_csr(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distri typedef compressed_sparse_row_graph seqGraph; - seqGraph sg(sorted_erdos_renyi_iterator(gen, N, _p/2), + seqGraph sg(edges_are_sorted, + sorted_erdos_renyi_iterator(gen, N, _p/2), sorted_erdos_renyi_iterator(), make_generator_iterator(gen, uniform_int(1, C)), N); @@ -463,7 +466,8 @@ void test_csr(const ProcessGroup& pg, RandomGenerator& gen, Distribution& distri typedef compressed_sparse_row_graph seqGraph; - seqGraph sg(small_world_iterator(gen, N, k, p), + seqGraph sg(edges_are_sorted, + small_world_iterator(gen, N, k, p), small_world_iterator(), make_generator_iterator(gen, uniform_int(1, C)), N); diff --git a/test/distributed_betweenness_centrality_test.cpp b/test/distributed_betweenness_centrality_test.cpp index 1acc2ac..fc5dad1 100644 --- a/test/distributed_betweenness_centrality_test.cpp +++ b/test/distributed_betweenness_centrality_test.cpp @@ -96,9 +96,7 @@ using boost::graph::distributed::mpi_process_group; typedef int weight_type; struct WeightedEdge { - WeightedEdge(weight_type weight = 1) : weight(weight) { } - - void operator=(weight_type x) { weight = x; } + WeightedEdge(weight_type weight = 0) : weight(weight) { } weight_type weight; @@ -130,6 +128,7 @@ int test_main(int argc, char* argv[]) property > seqGraph; #endif + typedef sorted_erdos_renyi_iterator ERIter; typedef graph_traits::vertex_descriptor vertex_descriptor; @@ -152,7 +151,11 @@ int test_main(int argc, char* argv[]) gen.seed(1); // Re-seed PRNG so we get the same graph - seqGraph sg(edges_are_sorted, ERIter(gen, n, prob), ERIter(), + seqGraph sg( +#ifdef CSR + edges_are_sorted, +#endif + ERIter(gen, n, prob), ERIter(), make_generator_iterator(gen, uniform_int(1, C)), n); diff --git a/test/distributed_csr_algorithm_test.cpp b/test/distributed_csr_algorithm_test.cpp index 508c88b..0fc770e 100644 --- a/test/distributed_csr_algorithm_test.cpp +++ b/test/distributed_csr_algorithm_test.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #if 0 // Contains internal AdjList types not present in CSR graph # include @@ -299,6 +300,9 @@ int test_main(int argc, char* argv[]) 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 diff --git a/test/distributed_dimacs_reader.cpp b/test/distributed_dimacs_reader.cpp index d0900b0..a2e3cb7 100644 --- a/test/distributed_dimacs_reader.cpp +++ b/test/distributed_dimacs_reader.cpp @@ -54,7 +54,6 @@ void test_dimacs_reader(const char *filename) { mpi_process_group pg; - mpi_process_group::process_id_type id = process_id(pg); typedef adjacency_list, diff --git a/test/distributed_st_connected_test.cpp b/test/distributed_st_connected_test.cpp new file mode 100644 index 0000000..2100794 --- /dev/null +++ b/test/distributed_st_connected_test.cpp @@ -0,0 +1,87 @@ +// Copyright (C) 2004-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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_NO_EXCEPTIONS +void +boost::throw_exception(std::exception const& ex) +{ + std::cout << ex.what() << std::endl; + abort(); +} +#endif + +using namespace boost; +using boost::graph::distributed::mpi_process_group; + +// Set up the vertex names +enum vertex_id_t { u, v, w, x, y, z, N }; +char vertex_names[] = { 'u', 'v', 'w', 'x', 'y', 'z' }; + +void +test_distributed_st_connected() { + + typedef adjacency_list, + undirectedS, + // Vertex properties + property > + Graph; + typedef graph_traits::vertices_size_type size_type; + typedef graph_traits::vertex_descriptor vertex_descriptor; + + // Specify the edges in the graph + { + typedef std::pair E; + E edge_array[] = { E(u, u), E(u, v), E(u, w), E(v, w), E(x, y), + E(x, z), E(z, y), E(z, z) }; + Graph g(edge_array, edge_array + sizeof(edge_array) / sizeof(E), N); + + bool connected = st_connected(g, vertex(u, g), vertex(z, g), + get(vertex_color, g), get(vertex_owner, g)); + + assert(!connected); + } + + { + typedef std::pair E; + E edge_array[] = { E(u, v), E(u, w), E(u, x), E(x, v), E(y, x), + E(v, y), E(w, y), E(w, z), E(z, z) }; + Graph g(edge_array, edge_array + sizeof(edge_array) / sizeof(E), N); + + bool connected = st_connected(g, vertex(u, g), vertex(z, g), + get(vertex_color, g), get(vertex_owner, g)); + + assert(connected); + } + + +} + +int test_main(int argc, char* argv[]) +{ + mpi::environment env(argc, argv); + test_distributed_st_connected(); + return 0; +} diff --git a/test/ssca.cpp b/test/ssca.cpp index 5938d07..6cc4a16 100644 --- a/test/ssca.cpp +++ b/test/ssca.cpp @@ -616,7 +616,8 @@ run_non_distributed_graph_tests(RandomGenerator& gen, const ProcessGroup& pg, time_type start = get_time(); #ifdef CSR - seqGraph sg(sorted_unique_rmat_iterator(gen, n, m, a, b, c, d), + seqGraph sg(edges_are_sorted, + sorted_unique_rmat_iterator(gen, n, m, a, b, c, d), sorted_unique_rmat_iterator(), make_generator_iterator(gen, uniform_int(0, maxEdgeWeight)), n);