123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239 |
- // 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
|