1240 lines
48 KiB
C++
1240 lines
48 KiB
C++
|
// Copyright (C) 2007 Douglas Gregor
|
||
|
// Copyright (C) 2007 Hartmut Kaiser
|
||
|
|
||
|
// 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)
|
||
|
|
||
|
// TODO:
|
||
|
// - Cache (some) remote vertex names?
|
||
|
#ifndef BOOST_GRAPH_DISTRIBUTED_NAMED_GRAPH_HPP
|
||
|
#define BOOST_GRAPH_DISTRIBUTED_NAMED_GRAPH_HPP
|
||
|
|
||
|
#ifndef BOOST_GRAPH_USE_MPI
|
||
|
#error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
|
||
|
#endif
|
||
|
|
||
|
#include <boost/assert.hpp>
|
||
|
#include <boost/graph/named_graph.hpp>
|
||
|
#include <boost/functional/hash.hpp>
|
||
|
#include <boost/variant.hpp>
|
||
|
#include <boost/graph/parallel/simple_trigger.hpp>
|
||
|
#include <boost/graph/parallel/process_group.hpp>
|
||
|
#include <boost/graph/parallel/detail/property_holders.hpp>
|
||
|
|
||
|
namespace boost { namespace graph { namespace distributed {
|
||
|
|
||
|
using boost::parallel::trigger_receive_context;
|
||
|
using boost::detail::parallel::pair_with_property;
|
||
|
|
||
|
/*******************************************************************
|
||
|
* Hashed distribution of named entities *
|
||
|
*******************************************************************/
|
||
|
|
||
|
template<typename T>
|
||
|
struct hashed_distribution
|
||
|
{
|
||
|
template<typename ProcessGroup>
|
||
|
hashed_distribution(const ProcessGroup& pg, std::size_t /*num_vertices*/ = 0)
|
||
|
: n(num_processes(pg)) { }
|
||
|
|
||
|
int operator()(const T& value) const
|
||
|
{
|
||
|
return hasher(value) % n;
|
||
|
}
|
||
|
|
||
|
std::size_t n;
|
||
|
hash<T> hasher;
|
||
|
};
|
||
|
|
||
|
/// Specialization for named graphs
|
||
|
template <typename InDistribution, typename VertexProperty, typename VertexSize,
|
||
|
typename ProcessGroup,
|
||
|
typename ExtractName
|
||
|
= typename internal_vertex_name<VertexProperty>::type>
|
||
|
struct select_distribution
|
||
|
{
|
||
|
private:
|
||
|
/// The type used to name vertices in the graph
|
||
|
typedef typename remove_cv<
|
||
|
typename remove_reference<
|
||
|
typename ExtractName::result_type>::type>::type
|
||
|
vertex_name_type;
|
||
|
|
||
|
public:
|
||
|
/**
|
||
|
* The @c type field provides a distribution object that maps
|
||
|
* vertex names to processors. The distribution object will be
|
||
|
* constructed with the process group over which communication will
|
||
|
* occur. The distribution object shall also be a function
|
||
|
* object mapping from the type of the name to a processor number
|
||
|
* in @c [0, @c p) (for @c p processors). By default, the mapping
|
||
|
* function uses the @c boost::hash value of the name, modulo @c p.
|
||
|
*/
|
||
|
typedef typename mpl::if_<is_same<InDistribution, defaultS>,
|
||
|
hashed_distribution<vertex_name_type>,
|
||
|
InDistribution>::type
|
||
|
type;
|
||
|
|
||
|
/// for named graphs the default type is the same as the stored distribution
|
||
|
/// type
|
||
|
typedef type default_type;
|
||
|
};
|
||
|
|
||
|
/// Specialization for non-named graphs
|
||
|
template <typename InDistribution, typename VertexProperty, typename VertexSize,
|
||
|
typename ProcessGroup>
|
||
|
struct select_distribution<InDistribution, VertexProperty, VertexSize,
|
||
|
ProcessGroup, void>
|
||
|
{
|
||
|
/// the distribution type stored in the graph for non-named graphs should be
|
||
|
/// the variant_distribution type
|
||
|
typedef typename mpl::if_<is_same<InDistribution, defaultS>,
|
||
|
boost::parallel::variant_distribution<ProcessGroup,
|
||
|
VertexSize>,
|
||
|
InDistribution>::type type;
|
||
|
|
||
|
/// default_type is used as the distribution functor for the
|
||
|
/// adjacency_list, it should be parallel::block by default
|
||
|
typedef typename mpl::if_<is_same<InDistribution, defaultS>,
|
||
|
boost::parallel::block, type>::type
|
||
|
default_type;
|
||
|
};
|
||
|
|
||
|
|
||
|
/*******************************************************************
|
||
|
* Named graph mixin *
|
||
|
*******************************************************************/
|
||
|
|
||
|
/**
|
||
|
* named_graph is a mixin that provides names for the vertices of a
|
||
|
* graph, including a mapping from names to vertices. Graph types that
|
||
|
* may or may not be have vertex names (depending on the properties
|
||
|
* supplied by the user) should use maybe_named_graph.
|
||
|
*
|
||
|
* Template parameters:
|
||
|
*
|
||
|
* Graph: the graph type that derives from named_graph
|
||
|
*
|
||
|
* Vertex: the type of a vertex descriptor in Graph. Note: we cannot
|
||
|
* use graph_traits here, because the Graph is not yet defined.
|
||
|
*
|
||
|
* VertexProperty: the type of the property stored along with the
|
||
|
* vertex.
|
||
|
*
|
||
|
* ProcessGroup: the process group over which the distributed name
|
||
|
* graph mixin will communicate.
|
||
|
*/
|
||
|
template<typename Graph, typename Vertex, typename Edge, typename Config>
|
||
|
class named_graph
|
||
|
{
|
||
|
public:
|
||
|
/// Messages passed within the distributed named graph
|
||
|
enum message_kind {
|
||
|
/**
|
||
|
* Requests the addition of a vertex on a remote processor. The
|
||
|
* message data is a @c vertex_name_type.
|
||
|
*/
|
||
|
msg_add_vertex_name,
|
||
|
|
||
|
/**
|
||
|
* Requests the addition of a vertex on a remote processor. The
|
||
|
* message data is a @c vertex_name_type. The remote processor
|
||
|
* will send back a @c msg_add_vertex_name_reply message
|
||
|
* containing the vertex descriptor.
|
||
|
*/
|
||
|
msg_add_vertex_name_with_reply,
|
||
|
|
||
|
/**
|
||
|
* Requests the vertex descriptor corresponding to the given
|
||
|
* vertex name. The remote process will reply with a
|
||
|
* @c msg_find_vertex_reply message containing the answer.
|
||
|
*/
|
||
|
msg_find_vertex,
|
||
|
|
||
|
/**
|
||
|
* Requests the addition of an edge on a remote processor. The
|
||
|
* data stored in these messages is a @c pair<source, target>@,
|
||
|
* where @c source and @c target may be either names (of type @c
|
||
|
* vertex_name_type) or vertex descriptors, depending on what
|
||
|
* information we have locally.
|
||
|
*/
|
||
|
msg_add_edge_name_name,
|
||
|
msg_add_edge_vertex_name,
|
||
|
msg_add_edge_name_vertex,
|
||
|
|
||
|
/**
|
||
|
* These messages are identical to msg_add_edge_*_*, except that
|
||
|
* the process actually adding the edge will send back a @c
|
||
|
* pair<edge_descriptor,bool>
|
||
|
*/
|
||
|
msg_add_edge_name_name_with_reply,
|
||
|
msg_add_edge_vertex_name_with_reply,
|
||
|
msg_add_edge_name_vertex_with_reply,
|
||
|
|
||
|
/**
|
||
|
* Requests the addition of an edge with a property on a remote
|
||
|
* processor. The data stored in these messages is a @c
|
||
|
* pair<vertex_property_type, pair<source, target>>@, where @c
|
||
|
* source and @c target may be either names (of type @c
|
||
|
* vertex_name_type) or vertex descriptors, depending on what
|
||
|
* information we have locally.
|
||
|
*/
|
||
|
msg_add_edge_name_name_with_property,
|
||
|
msg_add_edge_vertex_name_with_property,
|
||
|
msg_add_edge_name_vertex_with_property,
|
||
|
|
||
|
/**
|
||
|
* These messages are identical to msg_add_edge_*_*_with_property,
|
||
|
* except that the process actually adding the edge will send back
|
||
|
* a @c pair<edge_descriptor,bool>.
|
||
|
*/
|
||
|
msg_add_edge_name_name_with_reply_and_property,
|
||
|
msg_add_edge_vertex_name_with_reply_and_property,
|
||
|
msg_add_edge_name_vertex_with_reply_and_property
|
||
|
};
|
||
|
|
||
|
/// The vertex descriptor type
|
||
|
typedef Vertex vertex_descriptor;
|
||
|
|
||
|
/// The edge descriptor type
|
||
|
typedef Edge edge_descriptor;
|
||
|
|
||
|
/// The vertex property type
|
||
|
typedef typename Config::vertex_property_type vertex_property_type;
|
||
|
|
||
|
/// The vertex property type
|
||
|
typedef typename Config::edge_property_type edge_property_type;
|
||
|
|
||
|
/// The type used to extract names from the property structure
|
||
|
typedef typename internal_vertex_name<vertex_property_type>::type
|
||
|
extract_name_type;
|
||
|
|
||
|
/// The type used to name vertices in the graph
|
||
|
typedef typename remove_cv<
|
||
|
typename remove_reference<
|
||
|
typename extract_name_type::result_type>::type>::type
|
||
|
vertex_name_type;
|
||
|
|
||
|
/// The type used to distribute named vertices in the graph
|
||
|
typedef typename Config::distribution_type distribution_type;
|
||
|
typedef typename Config::base_distribution_type base_distribution_type;
|
||
|
|
||
|
/// The type used for communication in the distributed structure
|
||
|
typedef typename Config::process_group_type process_group_type;
|
||
|
|
||
|
/// Type used to identify processes
|
||
|
typedef typename process_group_type::process_id_type process_id_type;
|
||
|
|
||
|
/// a reference to this class, which is used for disambiguation of the
|
||
|
// add_vertex function
|
||
|
typedef named_graph named_graph_type;
|
||
|
|
||
|
/// Structure returned when adding a vertex by vertex name
|
||
|
struct lazy_add_vertex;
|
||
|
friend struct lazy_add_vertex;
|
||
|
|
||
|
/// Structure returned when adding an edge by vertex name
|
||
|
struct lazy_add_edge;
|
||
|
friend struct lazy_add_edge;
|
||
|
|
||
|
/// Structure returned when adding an edge by vertex name with a property
|
||
|
struct lazy_add_edge_with_property;
|
||
|
friend struct lazy_add_edge_with_property;
|
||
|
|
||
|
explicit named_graph(const process_group_type& pg);
|
||
|
|
||
|
named_graph(const process_group_type& pg, const base_distribution_type& distribution);
|
||
|
|
||
|
/// Set up triggers, but only for the BSP process group
|
||
|
void setup_triggers();
|
||
|
|
||
|
/// Retrieve the derived instance
|
||
|
Graph& derived() { return static_cast<Graph&>(*this); }
|
||
|
const Graph& derived() const { return static_cast<const Graph&>(*this); }
|
||
|
|
||
|
/// Retrieve the process group
|
||
|
process_group_type& process_group() { return process_group_; }
|
||
|
const process_group_type& process_group() const { return process_group_; }
|
||
|
|
||
|
// Retrieve the named distribution
|
||
|
distribution_type& named_distribution() { return distribution_; }
|
||
|
const distribution_type& named_distribution() const { return distribution_; }
|
||
|
|
||
|
/// Notify the named_graph that we have added the given vertex. This
|
||
|
/// is a no-op.
|
||
|
void added_vertex(Vertex) { }
|
||
|
|
||
|
/// Notify the named_graph that we are removing the given
|
||
|
/// vertex. This is a no-op.
|
||
|
template <typename VertexIterStability>
|
||
|
void removing_vertex(Vertex, VertexIterStability) { }
|
||
|
|
||
|
/// Notify the named_graph that we are clearing the graph
|
||
|
void clearing_graph() { }
|
||
|
|
||
|
/// Retrieve the owner of a given vertex based on the properties
|
||
|
/// associated with that vertex. This operation just returns the
|
||
|
/// number of the local processor, adding all vertices locally.
|
||
|
process_id_type owner_by_property(const vertex_property_type&);
|
||
|
|
||
|
protected:
|
||
|
void
|
||
|
handle_add_vertex_name(int source, int tag, const vertex_name_type& msg,
|
||
|
trigger_receive_context);
|
||
|
|
||
|
vertex_descriptor
|
||
|
handle_add_vertex_name_with_reply(int source, int tag,
|
||
|
const vertex_name_type& msg,
|
||
|
trigger_receive_context);
|
||
|
|
||
|
boost::parallel::detail::untracked_pair<vertex_descriptor, bool>
|
||
|
handle_find_vertex(int source, int tag, const vertex_name_type& msg,
|
||
|
trigger_receive_context);
|
||
|
|
||
|
template<typename U, typename V>
|
||
|
void handle_add_edge(int source, int tag, const boost::parallel::detail::untracked_pair<U, V>& msg,
|
||
|
trigger_receive_context);
|
||
|
|
||
|
template<typename U, typename V>
|
||
|
boost::parallel::detail::untracked_pair<edge_descriptor, bool>
|
||
|
handle_add_edge_with_reply(int source, int tag, const boost::parallel::detail::untracked_pair<U, V>& msg,
|
||
|
trigger_receive_context);
|
||
|
|
||
|
template<typename U, typename V>
|
||
|
void
|
||
|
handle_add_edge_with_property
|
||
|
(int source, int tag,
|
||
|
const pair_with_property<U, V, edge_property_type>& msg,
|
||
|
trigger_receive_context);
|
||
|
|
||
|
template<typename U, typename V>
|
||
|
boost::parallel::detail::untracked_pair<edge_descriptor, bool>
|
||
|
handle_add_edge_with_reply_and_property
|
||
|
(int source, int tag,
|
||
|
const pair_with_property<U, V, edge_property_type>& msg,
|
||
|
trigger_receive_context);
|
||
|
|
||
|
/// The process group for this distributed data structure
|
||
|
process_group_type process_group_;
|
||
|
|
||
|
/// The distribution we will use to map names to processors
|
||
|
distribution_type distribution_;
|
||
|
};
|
||
|
|
||
|
/// Helper macro containing the template parameters of named_graph
|
||
|
#define BGL_NAMED_GRAPH_PARAMS \
|
||
|
typename Graph, typename Vertex, typename Edge, typename Config
|
||
|
/// Helper macro containing the named_graph<...> instantiation
|
||
|
#define BGL_NAMED_GRAPH \
|
||
|
named_graph<Graph, Vertex, Edge, Config>
|
||
|
|
||
|
/**
|
||
|
* Data structure returned from add_vertex that will "lazily" add the
|
||
|
* vertex, either when it is converted to a @c vertex_descriptor or
|
||
|
* when the most recent copy has been destroyed.
|
||
|
*/
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
struct BGL_NAMED_GRAPH::lazy_add_vertex
|
||
|
{
|
||
|
/// Construct a new lazyily-added vertex
|
||
|
lazy_add_vertex(named_graph& self, const vertex_name_type& name)
|
||
|
: self(self), name(name), committed(false) { }
|
||
|
|
||
|
/// Transfer responsibility for adding the vertex from the source of
|
||
|
/// the copy to the newly-constructed opbject.
|
||
|
lazy_add_vertex(const lazy_add_vertex& other)
|
||
|
: self(other.self), name(other.name), committed(other.committed)
|
||
|
{
|
||
|
other.committed = true;
|
||
|
}
|
||
|
|
||
|
/// If the vertex has not been added yet, add it
|
||
|
~lazy_add_vertex();
|
||
|
|
||
|
/// Add the vertex and return its descriptor. This conversion can
|
||
|
/// only occur once, and only when this object is responsible for
|
||
|
/// creating the vertex.
|
||
|
operator vertex_descriptor() const { return commit(); }
|
||
|
|
||
|
/// Add the vertex and return its descriptor. This can only be
|
||
|
/// called once, and only when this object is responsible for
|
||
|
/// creating the vertex.
|
||
|
vertex_descriptor commit() const;
|
||
|
|
||
|
protected:
|
||
|
named_graph& self;
|
||
|
vertex_name_type name;
|
||
|
mutable bool committed;
|
||
|
};
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
BGL_NAMED_GRAPH::lazy_add_vertex::~lazy_add_vertex()
|
||
|
{
|
||
|
typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
|
||
|
|
||
|
/// If this vertex has already been created or will be created by
|
||
|
/// someone else, or if someone threw an exception, we will not
|
||
|
/// create the vertex now.
|
||
|
if (committed || std::uncaught_exception())
|
||
|
return;
|
||
|
|
||
|
committed = true;
|
||
|
|
||
|
process_id_type owner = self.named_distribution()(name);
|
||
|
if (owner == process_id(self.process_group()))
|
||
|
/// Add the vertex locally
|
||
|
add_vertex(self.derived().base().vertex_constructor(name), self.derived());
|
||
|
else
|
||
|
/// Ask the owner of the vertex to add a vertex with this name
|
||
|
send(self.process_group(), owner, msg_add_vertex_name, name);
|
||
|
}
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
typename BGL_NAMED_GRAPH::vertex_descriptor
|
||
|
BGL_NAMED_GRAPH::lazy_add_vertex::commit() const
|
||
|
{
|
||
|
typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
|
||
|
BOOST_ASSERT (!committed);
|
||
|
committed = true;
|
||
|
|
||
|
process_id_type owner = self.named_distribution()(name);
|
||
|
if (owner == process_id(self.process_group()))
|
||
|
/// Add the vertex locally
|
||
|
return add_vertex(self.derived().base().vertex_constructor(name),
|
||
|
self.derived());
|
||
|
else {
|
||
|
/// Ask the owner of the vertex to add a vertex with this name
|
||
|
vertex_descriptor result;
|
||
|
send_oob_with_reply(self.process_group(), owner,
|
||
|
msg_add_vertex_name_with_reply, name, result);
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Data structure returned from add_edge that will "lazily" add the
|
||
|
* edge, either when it is converted to a @c
|
||
|
* pair<edge_descriptor,bool> or when the most recent copy has been
|
||
|
* destroyed.
|
||
|
*/
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
struct BGL_NAMED_GRAPH::lazy_add_edge
|
||
|
{
|
||
|
/// The graph's edge descriptor
|
||
|
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
|
||
|
|
||
|
/// Add an edge for the edge (u, v) based on vertex names
|
||
|
lazy_add_edge(BGL_NAMED_GRAPH& self,
|
||
|
const vertex_name_type& u_name,
|
||
|
const vertex_name_type& v_name)
|
||
|
: self(self), u(u_name), v(v_name), committed(false) { }
|
||
|
|
||
|
/// Add an edge for the edge (u, v) based on a vertex descriptor and name
|
||
|
lazy_add_edge(BGL_NAMED_GRAPH& self,
|
||
|
vertex_descriptor u,
|
||
|
const vertex_name_type& v_name)
|
||
|
: self(self), u(u), v(v_name), committed(false) { }
|
||
|
|
||
|
/// Add an edge for the edge (u, v) based on a vertex name and descriptor
|
||
|
lazy_add_edge(BGL_NAMED_GRAPH& self,
|
||
|
const vertex_name_type& u_name,
|
||
|
vertex_descriptor v)
|
||
|
: self(self), u(u_name), v(v), committed(false) { }
|
||
|
|
||
|
/// Add an edge for the edge (u, v) based on vertex descriptors
|
||
|
lazy_add_edge(BGL_NAMED_GRAPH& self,
|
||
|
vertex_descriptor u,
|
||
|
vertex_descriptor v)
|
||
|
: self(self), u(u), v(v), committed(false) { }
|
||
|
|
||
|
/// Copy a lazy_add_edge structure, which transfers responsibility
|
||
|
/// for adding the edge to the newly-constructed object.
|
||
|
lazy_add_edge(const lazy_add_edge& other)
|
||
|
: self(other.self), u(other.u), v(other.v), committed(other.committed)
|
||
|
{
|
||
|
other.committed = true;
|
||
|
}
|
||
|
|
||
|
/// If the edge has not yet been added, add the edge but don't wait
|
||
|
/// for a reply.
|
||
|
~lazy_add_edge();
|
||
|
|
||
|
/// Returns commit().
|
||
|
operator std::pair<edge_descriptor, bool>() const { return commit(); }
|
||
|
|
||
|
// Add the edge. This operation will block if a remote edge is
|
||
|
// being added.
|
||
|
std::pair<edge_descriptor, bool> commit() const;
|
||
|
|
||
|
protected:
|
||
|
BGL_NAMED_GRAPH& self;
|
||
|
mutable variant<vertex_descriptor, vertex_name_type> u;
|
||
|
mutable variant<vertex_descriptor, vertex_name_type> v;
|
||
|
mutable bool committed;
|
||
|
|
||
|
private:
|
||
|
// No copy-assignment semantics
|
||
|
void operator=(lazy_add_edge&);
|
||
|
};
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
BGL_NAMED_GRAPH::lazy_add_edge::~lazy_add_edge()
|
||
|
{
|
||
|
using boost::parallel::detail::make_untracked_pair;
|
||
|
|
||
|
/// If this edge has already been created or will be created by
|
||
|
/// someone else, or if someone threw an exception, we will not
|
||
|
/// create the edge now.
|
||
|
if (committed || std::uncaught_exception())
|
||
|
return;
|
||
|
|
||
|
committed = true;
|
||
|
|
||
|
if (vertex_name_type* v_name = boost::get<vertex_name_type>(&v)) {
|
||
|
// We haven't resolved the target vertex to a descriptor yet, so
|
||
|
// it must not be local. Send a message to the owner of the target
|
||
|
// of the edge. If the owner of the target does not happen to own
|
||
|
// the source, it will resolve the target to a vertex descriptor
|
||
|
// and pass the message along to the owner of the source.
|
||
|
if (vertex_name_type* u_name = boost::get<vertex_name_type>(&u))
|
||
|
send(self.process_group(), self.distribution_(*v_name),
|
||
|
BGL_NAMED_GRAPH::msg_add_edge_name_name,
|
||
|
make_untracked_pair(*u_name, *v_name));
|
||
|
else
|
||
|
send(self.process_group(), self.distribution_(*v_name),
|
||
|
BGL_NAMED_GRAPH::msg_add_edge_vertex_name,
|
||
|
make_untracked_pair(boost::get<vertex_descriptor>(u), *v_name));
|
||
|
} else {
|
||
|
if (vertex_name_type* u_name = boost::get<vertex_name_type>(&u))
|
||
|
// We haven't resolved the source vertex to a descriptor yet, so
|
||
|
// it must not be local. Send a message to the owner of the
|
||
|
// source vertex requesting the edge addition.
|
||
|
send(self.process_group(), self.distribution_(*u_name),
|
||
|
BGL_NAMED_GRAPH::msg_add_edge_name_vertex,
|
||
|
make_untracked_pair(*u_name, boost::get<vertex_descriptor>(v)));
|
||
|
else
|
||
|
// We have descriptors for both of the vertices, either of which
|
||
|
// may be remote or local. Tell the owner of the source vertex
|
||
|
// to add the edge (it may be us!).
|
||
|
add_edge(boost::get<vertex_descriptor>(u),
|
||
|
boost::get<vertex_descriptor>(v),
|
||
|
self.derived());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
|
||
|
BGL_NAMED_GRAPH::lazy_add_edge::commit() const
|
||
|
{
|
||
|
typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
|
||
|
using boost::parallel::detail::make_untracked_pair;
|
||
|
|
||
|
BOOST_ASSERT(!committed);
|
||
|
committed = true;
|
||
|
|
||
|
/// The result we will return, if we are sending a message to
|
||
|
/// request that someone else add the edge.
|
||
|
boost::parallel::detail::untracked_pair<edge_descriptor, bool> result;
|
||
|
|
||
|
/// The owner of the vertex "u"
|
||
|
process_id_type u_owner;
|
||
|
|
||
|
process_id_type rank = process_id(self.process_group());
|
||
|
if (const vertex_name_type* u_name = boost::get<vertex_name_type>(&u)) {
|
||
|
/// We haven't resolved the source vertex to a descriptor yet, so
|
||
|
/// it must not be local.
|
||
|
u_owner = self.named_distribution()(*u_name);
|
||
|
|
||
|
/// Send a message to the remote vertex requesting that it add the
|
||
|
/// edge. The message differs depending on whether we have a
|
||
|
/// vertex name or a vertex descriptor for the target.
|
||
|
if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
|
||
|
send_oob_with_reply(self.process_group(), u_owner,
|
||
|
BGL_NAMED_GRAPH::msg_add_edge_name_name_with_reply,
|
||
|
make_untracked_pair(*u_name, *v_name), result);
|
||
|
else
|
||
|
send_oob_with_reply(self.process_group(), u_owner,
|
||
|
BGL_NAMED_GRAPH::msg_add_edge_name_vertex_with_reply,
|
||
|
make_untracked_pair(*u_name,
|
||
|
boost::get<vertex_descriptor>(v)),
|
||
|
result);
|
||
|
} else {
|
||
|
/// We have resolved the source vertex to a descriptor, which may
|
||
|
/// either be local or remote.
|
||
|
u_owner
|
||
|
= get(vertex_owner, self.derived(),
|
||
|
boost::get<vertex_descriptor>(u));
|
||
|
if (u_owner == rank) {
|
||
|
/// The source is local. If we need to, resolve the target vertex.
|
||
|
if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
|
||
|
v = add_vertex(*v_name, self.derived());
|
||
|
|
||
|
/// Add the edge using vertex descriptors
|
||
|
return add_edge(boost::get<vertex_descriptor>(u),
|
||
|
boost::get<vertex_descriptor>(v),
|
||
|
self.derived());
|
||
|
} else {
|
||
|
/// The source is remote. Just send a message to its owner
|
||
|
/// requesting that the owner add the new edge, either directly
|
||
|
/// or via the derived class's add_edge function.
|
||
|
if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
|
||
|
send_oob_with_reply
|
||
|
(self.process_group(), u_owner,
|
||
|
BGL_NAMED_GRAPH::msg_add_edge_vertex_name_with_reply,
|
||
|
make_untracked_pair(boost::get<vertex_descriptor>(u), *v_name),
|
||
|
result);
|
||
|
else
|
||
|
return add_edge(boost::get<vertex_descriptor>(u),
|
||
|
boost::get<vertex_descriptor>(v),
|
||
|
self.derived());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we get here, the edge has been added remotely and "result"
|
||
|
// contains the result of that edge addition.
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Data structure returned from add_edge that will "lazily" add the
|
||
|
* edge with a property, either when it is converted to a @c
|
||
|
* pair<edge_descriptor,bool> or when the most recent copy has been
|
||
|
* destroyed.
|
||
|
*/
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
struct BGL_NAMED_GRAPH::lazy_add_edge_with_property
|
||
|
{
|
||
|
/// The graph's edge descriptor
|
||
|
typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
|
||
|
|
||
|
/// The Edge property type for our graph
|
||
|
typedef typename Config::edge_property_type edge_property_type;
|
||
|
|
||
|
/// Add an edge for the edge (u, v) based on vertex names
|
||
|
lazy_add_edge_with_property(BGL_NAMED_GRAPH& self,
|
||
|
const vertex_name_type& u_name,
|
||
|
const vertex_name_type& v_name,
|
||
|
const edge_property_type& property)
|
||
|
: self(self), u(u_name), v(v_name), property(property), committed(false)
|
||
|
{
|
||
|
}
|
||
|
|
||
|
/// Add an edge for the edge (u, v) based on a vertex descriptor and name
|
||
|
lazy_add_edge_with_property(BGL_NAMED_GRAPH& self,
|
||
|
vertex_descriptor u,
|
||
|
const vertex_name_type& v_name,
|
||
|
const edge_property_type& property)
|
||
|
: self(self), u(u), v(v_name), property(property), committed(false) { }
|
||
|
|
||
|
/// Add an edge for the edge (u, v) based on a vertex name and descriptor
|
||
|
lazy_add_edge_with_property(BGL_NAMED_GRAPH& self,
|
||
|
const vertex_name_type& u_name,
|
||
|
vertex_descriptor v,
|
||
|
const edge_property_type& property)
|
||
|
: self(self), u(u_name), v(v), property(property), committed(false) { }
|
||
|
|
||
|
/// Add an edge for the edge (u, v) based on vertex descriptors
|
||
|
lazy_add_edge_with_property(BGL_NAMED_GRAPH& self,
|
||
|
vertex_descriptor u,
|
||
|
vertex_descriptor v,
|
||
|
const edge_property_type& property)
|
||
|
: self(self), u(u), v(v), property(property), committed(false) { }
|
||
|
|
||
|
/// Copy a lazy_add_edge_with_property structure, which transfers
|
||
|
/// responsibility for adding the edge to the newly-constructed
|
||
|
/// object.
|
||
|
lazy_add_edge_with_property(const lazy_add_edge_with_property& other)
|
||
|
: self(other.self), u(other.u), v(other.v), property(other.property),
|
||
|
committed(other.committed)
|
||
|
{
|
||
|
other.committed = true;
|
||
|
}
|
||
|
|
||
|
/// If the edge has not yet been added, add the edge but don't wait
|
||
|
/// for a reply.
|
||
|
~lazy_add_edge_with_property();
|
||
|
|
||
|
/// Returns commit().
|
||
|
operator std::pair<edge_descriptor, bool>() const { return commit(); }
|
||
|
|
||
|
// Add the edge. This operation will block if a remote edge is
|
||
|
// being added.
|
||
|
std::pair<edge_descriptor, bool> commit() const;
|
||
|
|
||
|
protected:
|
||
|
BGL_NAMED_GRAPH& self;
|
||
|
mutable variant<vertex_descriptor, vertex_name_type> u;
|
||
|
mutable variant<vertex_descriptor, vertex_name_type> v;
|
||
|
edge_property_type property;
|
||
|
mutable bool committed;
|
||
|
|
||
|
private:
|
||
|
// No copy-assignment semantics
|
||
|
void operator=(lazy_add_edge_with_property&);
|
||
|
};
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
BGL_NAMED_GRAPH::lazy_add_edge_with_property::~lazy_add_edge_with_property()
|
||
|
{
|
||
|
using boost::detail::parallel::make_pair_with_property;
|
||
|
|
||
|
/// If this edge has already been created or will be created by
|
||
|
/// someone else, or if someone threw an exception, we will not
|
||
|
/// create the edge now.
|
||
|
if (committed || std::uncaught_exception())
|
||
|
return;
|
||
|
|
||
|
committed = true;
|
||
|
|
||
|
if (vertex_name_type* v_name = boost::get<vertex_name_type>(&v)) {
|
||
|
// We haven't resolved the target vertex to a descriptor yet, so
|
||
|
// it must not be local. Send a message to the owner of the target
|
||
|
// of the edge. If the owner of the target does not happen to own
|
||
|
// the source, it will resolve the target to a vertex descriptor
|
||
|
// and pass the message along to the owner of the source.
|
||
|
if (vertex_name_type* u_name = boost::get<vertex_name_type>(&u))
|
||
|
send(self.process_group(), self.distribution_(*v_name),
|
||
|
BGL_NAMED_GRAPH::msg_add_edge_name_name_with_property,
|
||
|
make_pair_with_property(*u_name, *v_name, property));
|
||
|
else
|
||
|
send(self.process_group(), self.distribution_(*v_name),
|
||
|
BGL_NAMED_GRAPH::msg_add_edge_vertex_name_with_property,
|
||
|
make_pair_with_property(boost::get<vertex_descriptor>(u), *v_name,
|
||
|
property));
|
||
|
} else {
|
||
|
if (vertex_name_type* u_name = boost::get<vertex_name_type>(&u))
|
||
|
// We haven't resolved the source vertex to a descriptor yet, so
|
||
|
// it must not be local. Send a message to the owner of the
|
||
|
// source vertex requesting the edge addition.
|
||
|
send(self.process_group(), self.distribution_(*u_name),
|
||
|
BGL_NAMED_GRAPH::msg_add_edge_name_vertex_with_property,
|
||
|
make_pair_with_property(*u_name, boost::get<vertex_descriptor>(v),
|
||
|
property));
|
||
|
else
|
||
|
// We have descriptors for both of the vertices, either of which
|
||
|
// may be remote or local. Tell the owner of the source vertex
|
||
|
// to add the edge (it may be us!).
|
||
|
add_edge(boost::get<vertex_descriptor>(u),
|
||
|
boost::get<vertex_descriptor>(v),
|
||
|
property,
|
||
|
self.derived());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
|
||
|
BGL_NAMED_GRAPH::lazy_add_edge_with_property::commit() const
|
||
|
{
|
||
|
using boost::detail::parallel::make_pair_with_property;
|
||
|
typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
|
||
|
BOOST_ASSERT(!committed);
|
||
|
committed = true;
|
||
|
|
||
|
/// The result we will return, if we are sending a message to
|
||
|
/// request that someone else add the edge.
|
||
|
boost::parallel::detail::untracked_pair<edge_descriptor, bool> result;
|
||
|
|
||
|
/// The owner of the vertex "u"
|
||
|
process_id_type u_owner;
|
||
|
|
||
|
process_id_type rank = process_id(self.process_group());
|
||
|
if (const vertex_name_type* u_name = boost::get<vertex_name_type>(&u)) {
|
||
|
/// We haven't resolved the source vertex to a descriptor yet, so
|
||
|
/// it must not be local.
|
||
|
u_owner = self.named_distribution()(*u_name);
|
||
|
|
||
|
/// Send a message to the remote vertex requesting that it add the
|
||
|
/// edge. The message differs depending on whether we have a
|
||
|
/// vertex name or a vertex descriptor for the target.
|
||
|
if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
|
||
|
send_oob_with_reply
|
||
|
(self.process_group(), u_owner,
|
||
|
BGL_NAMED_GRAPH::msg_add_edge_name_name_with_reply_and_property,
|
||
|
make_pair_with_property(*u_name, *v_name, property),
|
||
|
result);
|
||
|
else
|
||
|
send_oob_with_reply
|
||
|
(self.process_group(), u_owner,
|
||
|
BGL_NAMED_GRAPH::msg_add_edge_name_vertex_with_reply_and_property,
|
||
|
make_pair_with_property(*u_name,
|
||
|
boost::get<vertex_descriptor>(v),
|
||
|
property),
|
||
|
result);
|
||
|
} else {
|
||
|
/// We have resolved the source vertex to a descriptor, which may
|
||
|
/// either be local or remote.
|
||
|
u_owner
|
||
|
= get(vertex_owner, self.derived(),
|
||
|
boost::get<vertex_descriptor>(u));
|
||
|
if (u_owner == rank) {
|
||
|
/// The source is local. If we need to, resolve the target vertex.
|
||
|
if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
|
||
|
v = add_vertex(*v_name, self.derived());
|
||
|
|
||
|
/// Add the edge using vertex descriptors
|
||
|
return add_edge(boost::get<vertex_descriptor>(u),
|
||
|
boost::get<vertex_descriptor>(v),
|
||
|
property,
|
||
|
self.derived());
|
||
|
} else {
|
||
|
/// The source is remote. Just send a message to its owner
|
||
|
/// requesting that the owner add the new edge, either directly
|
||
|
/// or via the derived class's add_edge function.
|
||
|
if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
|
||
|
send_oob_with_reply
|
||
|
(self.process_group(), u_owner,
|
||
|
BGL_NAMED_GRAPH::msg_add_edge_vertex_name_with_reply_and_property,
|
||
|
make_pair_with_property(boost::get<vertex_descriptor>(u), *v_name,
|
||
|
property),
|
||
|
result);
|
||
|
else
|
||
|
return add_edge(boost::get<vertex_descriptor>(u),
|
||
|
boost::get<vertex_descriptor>(v),
|
||
|
property,
|
||
|
self.derived());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// If we get here, the edge has been added remotely and "result"
|
||
|
// contains the result of that edge addition.
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
/// Construct the named_graph with a particular process group
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
BGL_NAMED_GRAPH::named_graph(const process_group_type& pg)
|
||
|
: process_group_(pg, boost::parallel::attach_distributed_object()),
|
||
|
distribution_(pg)
|
||
|
{
|
||
|
setup_triggers();
|
||
|
}
|
||
|
|
||
|
/// Construct the named_graph mixin with a particular process group
|
||
|
/// and distribution function
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
BGL_NAMED_GRAPH::named_graph(const process_group_type& pg,
|
||
|
const base_distribution_type& distribution)
|
||
|
: process_group_(pg, boost::parallel::attach_distributed_object()),
|
||
|
distribution_(pg, distribution)
|
||
|
{
|
||
|
setup_triggers();
|
||
|
}
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
void
|
||
|
BGL_NAMED_GRAPH::setup_triggers()
|
||
|
{
|
||
|
using boost::graph::parallel::simple_trigger;
|
||
|
|
||
|
simple_trigger(process_group_, msg_add_vertex_name, this,
|
||
|
&named_graph::handle_add_vertex_name);
|
||
|
simple_trigger(process_group_, msg_add_vertex_name_with_reply, this,
|
||
|
&named_graph::handle_add_vertex_name_with_reply);
|
||
|
simple_trigger(process_group_, msg_find_vertex, this,
|
||
|
&named_graph::handle_find_vertex);
|
||
|
simple_trigger(process_group_, msg_add_edge_name_name, this,
|
||
|
&named_graph::template handle_add_edge<vertex_name_type,
|
||
|
vertex_name_type>);
|
||
|
simple_trigger(process_group_, msg_add_edge_name_name_with_reply, this,
|
||
|
&named_graph::template handle_add_edge_with_reply
|
||
|
<vertex_name_type, vertex_name_type>);
|
||
|
simple_trigger(process_group_, msg_add_edge_name_vertex, this,
|
||
|
&named_graph::template handle_add_edge<vertex_name_type,
|
||
|
vertex_descriptor>);
|
||
|
simple_trigger(process_group_, msg_add_edge_name_vertex_with_reply, this,
|
||
|
&named_graph::template handle_add_edge_with_reply
|
||
|
<vertex_name_type, vertex_descriptor>);
|
||
|
simple_trigger(process_group_, msg_add_edge_vertex_name, this,
|
||
|
&named_graph::template handle_add_edge<vertex_descriptor,
|
||
|
vertex_name_type>);
|
||
|
simple_trigger(process_group_, msg_add_edge_vertex_name_with_reply, this,
|
||
|
&named_graph::template handle_add_edge_with_reply
|
||
|
<vertex_descriptor, vertex_name_type>);
|
||
|
simple_trigger(process_group_, msg_add_edge_name_name_with_property, this,
|
||
|
&named_graph::
|
||
|
template handle_add_edge_with_property<vertex_name_type,
|
||
|
vertex_name_type>);
|
||
|
simple_trigger(process_group_,
|
||
|
msg_add_edge_name_name_with_reply_and_property, this,
|
||
|
&named_graph::template handle_add_edge_with_reply_and_property
|
||
|
<vertex_name_type, vertex_name_type>);
|
||
|
simple_trigger(process_group_, msg_add_edge_name_vertex_with_property, this,
|
||
|
&named_graph::
|
||
|
template handle_add_edge_with_property<vertex_name_type,
|
||
|
vertex_descriptor>);
|
||
|
simple_trigger(process_group_,
|
||
|
msg_add_edge_name_vertex_with_reply_and_property, this,
|
||
|
&named_graph::template handle_add_edge_with_reply_and_property
|
||
|
<vertex_name_type, vertex_descriptor>);
|
||
|
simple_trigger(process_group_, msg_add_edge_vertex_name_with_property, this,
|
||
|
&named_graph::
|
||
|
template handle_add_edge_with_property<vertex_descriptor,
|
||
|
vertex_name_type>);
|
||
|
simple_trigger(process_group_,
|
||
|
msg_add_edge_vertex_name_with_reply_and_property, this,
|
||
|
&named_graph::template handle_add_edge_with_reply_and_property
|
||
|
<vertex_descriptor, vertex_name_type>);
|
||
|
}
|
||
|
|
||
|
/// Retrieve the vertex associated with the given name
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
optional<Vertex>
|
||
|
find_vertex(typename BGL_NAMED_GRAPH::vertex_name_type const& name,
|
||
|
const BGL_NAMED_GRAPH& g)
|
||
|
{
|
||
|
typedef typename Graph::local_vertex_descriptor local_vertex_descriptor;
|
||
|
typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
|
||
|
|
||
|
// Determine the owner of this name
|
||
|
typename BGL_NAMED_GRAPH::process_id_type owner
|
||
|
= g.named_distribution()(name);
|
||
|
|
||
|
if (owner == process_id(g.process_group())) {
|
||
|
// The vertex is local, so search for a mapping here
|
||
|
optional<local_vertex_descriptor> result
|
||
|
= find_vertex(name, g.derived().base());
|
||
|
if (result)
|
||
|
return Vertex(owner, *result);
|
||
|
else
|
||
|
return optional<Vertex>();
|
||
|
}
|
||
|
else {
|
||
|
// Ask the ownering process for the name of this vertex
|
||
|
boost::parallel::detail::untracked_pair<vertex_descriptor, bool> result;
|
||
|
send_oob_with_reply(g.process_group(), owner,
|
||
|
BGL_NAMED_GRAPH::msg_find_vertex, name, result);
|
||
|
if (result.second)
|
||
|
return result.first;
|
||
|
else
|
||
|
return optional<Vertex>();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// meta-function helping in figuring out if the given VertextProerty belongs to
|
||
|
/// a named graph
|
||
|
template<typename VertexProperty>
|
||
|
struct not_is_named_graph
|
||
|
: is_same<typename internal_vertex_name<VertexProperty>::type, void>
|
||
|
{};
|
||
|
|
||
|
/// Retrieve the vertex associated with the given name
|
||
|
template<typename Graph>
|
||
|
typename Graph::named_graph_type::lazy_add_vertex
|
||
|
add_vertex(typename Graph::vertex_name_type const& name,
|
||
|
Graph& g,
|
||
|
typename disable_if<
|
||
|
not_is_named_graph<typename Graph::vertex_property_type>,
|
||
|
void*>::type = 0)
|
||
|
{
|
||
|
return typename Graph::named_graph_type::lazy_add_vertex(g, name);
|
||
|
}
|
||
|
|
||
|
/// Add an edge using vertex names to refer to the vertices
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
typename BGL_NAMED_GRAPH::lazy_add_edge
|
||
|
add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
|
||
|
typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
|
||
|
BGL_NAMED_GRAPH& g)
|
||
|
{
|
||
|
typedef typename BGL_NAMED_GRAPH::lazy_add_edge lazy_add_edge;
|
||
|
typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
|
||
|
|
||
|
process_id_type rank = process_id(g.process_group());
|
||
|
process_id_type u_owner = g.named_distribution()(u_name);
|
||
|
process_id_type v_owner = g.named_distribution()(v_name);
|
||
|
|
||
|
// Resolve local vertex names before building the "lazy" edge
|
||
|
// addition structure.
|
||
|
if (u_owner == rank && v_owner == rank)
|
||
|
return lazy_add_edge(g, add_vertex(u_name, g), add_vertex(v_name, g));
|
||
|
else if (u_owner == rank && v_owner != rank)
|
||
|
return lazy_add_edge(g, add_vertex(u_name, g), v_name);
|
||
|
else if (u_owner != rank && v_owner == rank)
|
||
|
return lazy_add_edge(g, u_name, add_vertex(v_name, g));
|
||
|
else
|
||
|
return lazy_add_edge(g, u_name, v_name);
|
||
|
}
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
typename BGL_NAMED_GRAPH::lazy_add_edge
|
||
|
add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
|
||
|
typename BGL_NAMED_GRAPH::vertex_descriptor const& v,
|
||
|
BGL_NAMED_GRAPH& g)
|
||
|
{
|
||
|
// Resolve local vertex names before building the "lazy" edge
|
||
|
// addition structure.
|
||
|
typedef typename BGL_NAMED_GRAPH::lazy_add_edge lazy_add_edge;
|
||
|
if (g.named_distribution()(u_name) == process_id(g.process_group()))
|
||
|
return lazy_add_edge(g, add_vertex(u_name, g), v);
|
||
|
else
|
||
|
return lazy_add_edge(g, u_name, v);
|
||
|
}
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
typename BGL_NAMED_GRAPH::lazy_add_edge
|
||
|
add_edge(typename BGL_NAMED_GRAPH::vertex_descriptor const& u,
|
||
|
typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
|
||
|
BGL_NAMED_GRAPH& g)
|
||
|
{
|
||
|
// Resolve local vertex names before building the "lazy" edge
|
||
|
// addition structure.
|
||
|
typedef typename BGL_NAMED_GRAPH::lazy_add_edge lazy_add_edge;
|
||
|
if (g.named_distribution()(v_name) == process_id(g.process_group()))
|
||
|
return lazy_add_edge(g, u, add_vertex(v_name, g));
|
||
|
else
|
||
|
return lazy_add_edge(g, u, v_name);
|
||
|
}
|
||
|
|
||
|
/// Add an edge using vertex names to refer to the vertices
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
typename BGL_NAMED_GRAPH::lazy_add_edge_with_property
|
||
|
add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
|
||
|
typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
|
||
|
typename Graph::edge_property_type const& property,
|
||
|
BGL_NAMED_GRAPH& g)
|
||
|
{
|
||
|
typedef typename BGL_NAMED_GRAPH::lazy_add_edge_with_property lazy_add_edge;
|
||
|
typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
|
||
|
|
||
|
process_id_type rank = process_id(g.process_group());
|
||
|
process_id_type u_owner = g.named_distribution()(u_name);
|
||
|
process_id_type v_owner = g.named_distribution()(v_name);
|
||
|
|
||
|
// Resolve local vertex names before building the "lazy" edge
|
||
|
// addition structure.
|
||
|
if (u_owner == rank && v_owner == rank)
|
||
|
return lazy_add_edge(g, add_vertex(u_name, g), add_vertex(v_name, g),
|
||
|
property);
|
||
|
else if (u_owner == rank && v_owner != rank)
|
||
|
return lazy_add_edge(g, add_vertex(u_name, g), v_name, property);
|
||
|
else if (u_owner != rank && v_owner == rank)
|
||
|
return lazy_add_edge(g, u_name, add_vertex(v_name, g), property);
|
||
|
else
|
||
|
return lazy_add_edge(g, u_name, v_name, property);
|
||
|
}
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
typename BGL_NAMED_GRAPH::lazy_add_edge_with_property
|
||
|
add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
|
||
|
typename BGL_NAMED_GRAPH::vertex_descriptor const& v,
|
||
|
typename Graph::edge_property_type const& property,
|
||
|
BGL_NAMED_GRAPH& g)
|
||
|
{
|
||
|
// Resolve local vertex names before building the "lazy" edge
|
||
|
// addition structure.
|
||
|
typedef typename BGL_NAMED_GRAPH::lazy_add_edge_with_property lazy_add_edge;
|
||
|
if (g.named_distribution()(u_name) == process_id(g.process_group()))
|
||
|
return lazy_add_edge(g, add_vertex(u_name, g), v, property);
|
||
|
else
|
||
|
return lazy_add_edge(g, u_name, v, property);
|
||
|
}
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
typename BGL_NAMED_GRAPH::lazy_add_edge_with_property
|
||
|
add_edge(typename BGL_NAMED_GRAPH::vertex_descriptor const& u,
|
||
|
typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
|
||
|
typename Graph::edge_property_type const& property,
|
||
|
BGL_NAMED_GRAPH& g)
|
||
|
{
|
||
|
// Resolve local vertex names before building the "lazy" edge
|
||
|
// addition structure.
|
||
|
typedef typename BGL_NAMED_GRAPH::lazy_add_edge_with_property lazy_add_edge;
|
||
|
if (g.named_distribution()(v_name) == process_id(g.process_group()))
|
||
|
return lazy_add_edge(g, u, add_vertex(v_name, g), property);
|
||
|
else
|
||
|
return lazy_add_edge(g, u, v_name, property);
|
||
|
}
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
typename BGL_NAMED_GRAPH::process_id_type
|
||
|
BGL_NAMED_GRAPH::owner_by_property(const vertex_property_type& property)
|
||
|
{
|
||
|
return distribution_(derived().base().extract_name(property));
|
||
|
}
|
||
|
|
||
|
|
||
|
/*******************************************************************
|
||
|
* Message handlers *
|
||
|
*******************************************************************/
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
void
|
||
|
BGL_NAMED_GRAPH::
|
||
|
handle_add_vertex_name(int /*source*/, int /*tag*/,
|
||
|
const vertex_name_type& msg, trigger_receive_context)
|
||
|
{
|
||
|
add_vertex(msg, derived());
|
||
|
}
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
typename BGL_NAMED_GRAPH::vertex_descriptor
|
||
|
BGL_NAMED_GRAPH::
|
||
|
handle_add_vertex_name_with_reply(int source, int /*tag*/,
|
||
|
const vertex_name_type& msg,
|
||
|
trigger_receive_context)
|
||
|
{
|
||
|
return add_vertex(msg, derived());
|
||
|
}
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
boost::parallel::detail::untracked_pair<typename BGL_NAMED_GRAPH::vertex_descriptor, bool>
|
||
|
BGL_NAMED_GRAPH::
|
||
|
handle_find_vertex(int source, int /*tag*/, const vertex_name_type& msg,
|
||
|
trigger_receive_context)
|
||
|
{
|
||
|
using boost::parallel::detail::make_untracked_pair;
|
||
|
|
||
|
optional<vertex_descriptor> v = find_vertex(msg, derived());
|
||
|
if (v)
|
||
|
return make_untracked_pair(*v, true);
|
||
|
else
|
||
|
return make_untracked_pair(graph_traits<Graph>::null_vertex(), false);
|
||
|
}
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
template<typename U, typename V>
|
||
|
void
|
||
|
BGL_NAMED_GRAPH::
|
||
|
handle_add_edge(int source, int /*tag*/, const boost::parallel::detail::untracked_pair<U, V>& msg,
|
||
|
trigger_receive_context)
|
||
|
{
|
||
|
add_edge(msg.first, msg.second, derived());
|
||
|
}
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
template<typename U, typename V>
|
||
|
boost::parallel::detail::untracked_pair<typename BGL_NAMED_GRAPH::edge_descriptor, bool>
|
||
|
BGL_NAMED_GRAPH::
|
||
|
handle_add_edge_with_reply(int source, int /*tag*/, const boost::parallel::detail::untracked_pair<U, V>& msg,
|
||
|
trigger_receive_context)
|
||
|
{
|
||
|
std::pair<typename BGL_NAMED_GRAPH::edge_descriptor, bool> p =
|
||
|
add_edge(msg.first, msg.second, derived());
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
template<typename U, typename V>
|
||
|
void
|
||
|
BGL_NAMED_GRAPH::
|
||
|
handle_add_edge_with_property
|
||
|
(int source, int tag,
|
||
|
const pair_with_property<U, V, edge_property_type>& msg,
|
||
|
trigger_receive_context)
|
||
|
{
|
||
|
add_edge(msg.first, msg.second, msg.get_property(), derived());
|
||
|
}
|
||
|
|
||
|
template<BGL_NAMED_GRAPH_PARAMS>
|
||
|
template<typename U, typename V>
|
||
|
boost::parallel::detail::untracked_pair<typename BGL_NAMED_GRAPH::edge_descriptor, bool>
|
||
|
BGL_NAMED_GRAPH::
|
||
|
handle_add_edge_with_reply_and_property
|
||
|
(int source, int tag,
|
||
|
const pair_with_property<U, V, edge_property_type>& msg,
|
||
|
trigger_receive_context)
|
||
|
{
|
||
|
std:: pair<typename BGL_NAMED_GRAPH::edge_descriptor, bool> p =
|
||
|
add_edge(msg.first, msg.second, msg.get_property(), derived());
|
||
|
return p;
|
||
|
}
|
||
|
|
||
|
#undef BGL_NAMED_GRAPH
|
||
|
#undef BGL_NAMED_GRAPH_PARAMS
|
||
|
|
||
|
/*******************************************************************
|
||
|
* Maybe named graph mixin *
|
||
|
*******************************************************************/
|
||
|
|
||
|
/**
|
||
|
* A graph mixin that can provide a mapping from names to vertices,
|
||
|
* and use that mapping to simplify creation and manipulation of
|
||
|
* graphs.
|
||
|
*/
|
||
|
template<typename Graph, typename Vertex, typename Edge, typename Config,
|
||
|
typename ExtractName
|
||
|
= typename internal_vertex_name<typename Config::vertex_property_type>::type>
|
||
|
struct maybe_named_graph
|
||
|
: public named_graph<Graph, Vertex, Edge, Config>
|
||
|
{
|
||
|
private:
|
||
|
typedef named_graph<Graph, Vertex, Edge, Config> inherited;
|
||
|
typedef typename Config::process_group_type process_group_type;
|
||
|
|
||
|
public:
|
||
|
/// The type used to distribute named vertices in the graph
|
||
|
typedef typename Config::distribution_type distribution_type;
|
||
|
typedef typename Config::base_distribution_type base_distribution_type;
|
||
|
|
||
|
explicit maybe_named_graph(const process_group_type& pg) : inherited(pg) { }
|
||
|
|
||
|
maybe_named_graph(const process_group_type& pg,
|
||
|
const base_distribution_type& distribution)
|
||
|
: inherited(pg, distribution) { }
|
||
|
|
||
|
distribution_type& distribution() { return this->distribution_; }
|
||
|
const distribution_type& distribution() const { return this->distribution_; }
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* A graph mixin that can provide a mapping from names to vertices,
|
||
|
* and use that mapping to simplify creation and manipulation of
|
||
|
* graphs. This partial specialization turns off this functionality
|
||
|
* when the @c VertexProperty does not have an internal vertex name.
|
||
|
*/
|
||
|
template<typename Graph, typename Vertex, typename Edge, typename Config>
|
||
|
struct maybe_named_graph<Graph, Vertex, Edge, Config, void>
|
||
|
{
|
||
|
private:
|
||
|
typedef typename Config::process_group_type process_group_type;
|
||
|
typedef typename Config::vertex_property_type vertex_property_type;
|
||
|
|
||
|
public:
|
||
|
typedef typename process_group_type::process_id_type process_id_type;
|
||
|
|
||
|
/// The type used to distribute named vertices in the graph
|
||
|
typedef typename Config::distribution_type distribution_type;
|
||
|
typedef typename Config::base_distribution_type base_distribution_type;
|
||
|
|
||
|
explicit maybe_named_graph(const process_group_type&) { }
|
||
|
|
||
|
maybe_named_graph(const process_group_type& pg,
|
||
|
const base_distribution_type& distribution)
|
||
|
: distribution_(pg, distribution) { }
|
||
|
|
||
|
/// Notify the named_graph that we have added the given vertex. This
|
||
|
/// is a no-op.
|
||
|
void added_vertex(Vertex) { }
|
||
|
|
||
|
/// Notify the named_graph that we are removing the given
|
||
|
/// vertex. This is a no-op.
|
||
|
template <typename VertexIterStability>
|
||
|
void removing_vertex(Vertex, VertexIterStability) { }
|
||
|
|
||
|
/// Notify the named_graph that we are clearing the graph
|
||
|
void clearing_graph() { }
|
||
|
|
||
|
/// Retrieve the owner of a given vertex based on the properties
|
||
|
/// associated with that vertex. This operation just returns the
|
||
|
/// number of the local processor, adding all vertices locally.
|
||
|
process_id_type owner_by_property(const vertex_property_type&)
|
||
|
{
|
||
|
return process_id(pg);
|
||
|
}
|
||
|
|
||
|
distribution_type& distribution() { return distribution_; }
|
||
|
const distribution_type& distribution() const { return distribution_; }
|
||
|
|
||
|
protected:
|
||
|
/// The process group of the graph
|
||
|
process_group_type pg;
|
||
|
|
||
|
/// The distribution used for the graph
|
||
|
distribution_type distribution_;
|
||
|
};
|
||
|
|
||
|
} } } // end namespace boost::graph::distributed
|
||
|
|
||
|
#endif // BOOST_GRAPH_DISTRIBUTED_NAMED_GRAPH_HPP
|