]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/graph/distributed/named_graph.hpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / boost / graph / distributed / named_graph.hpp
1 // Copyright (C) 2007 Douglas Gregor
2 // Copyright (C) 2007 Hartmut Kaiser
3
4 // Use, modification and distribution is subject to the Boost Software
5 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt)
7
8 // TODO:
9 // - Cache (some) remote vertex names?
10 #ifndef BOOST_GRAPH_DISTRIBUTED_NAMED_GRAPH_HPP
11 #define BOOST_GRAPH_DISTRIBUTED_NAMED_GRAPH_HPP
12
13 #ifndef BOOST_GRAPH_USE_MPI
14 #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
15 #endif
16
17 #include <boost/assert.hpp>
18 #include <boost/graph/named_graph.hpp>
19 #include <boost/functional/hash.hpp>
20 #include <boost/variant.hpp>
21 #include <boost/graph/parallel/simple_trigger.hpp>
22 #include <boost/graph/parallel/process_group.hpp>
23 #include <boost/graph/parallel/detail/property_holders.hpp>
24
25 namespace boost { namespace graph { namespace distributed {
26
27 using boost::parallel::trigger_receive_context;
28 using boost::detail::parallel::pair_with_property;
29
30 /*******************************************************************
31 * Hashed distribution of named entities *
32 *******************************************************************/
33
34 template<typename T>
35 struct hashed_distribution
36 {
37 template<typename ProcessGroup>
38 hashed_distribution(const ProcessGroup& pg, std::size_t /*num_vertices*/ = 0)
39 : n(num_processes(pg)) { }
40
41 int operator()(const T& value) const
42 {
43 return hasher(value) % n;
44 }
45
46 std::size_t n;
47 hash<T> hasher;
48 };
49
50 /// Specialization for named graphs
51 template <typename InDistribution, typename VertexProperty, typename VertexSize,
52 typename ProcessGroup,
53 typename ExtractName
54 = typename internal_vertex_name<VertexProperty>::type>
55 struct select_distribution
56 {
57 private:
58 /// The type used to name vertices in the graph
59 typedef typename remove_cv<
60 typename remove_reference<
61 typename ExtractName::result_type>::type>::type
62 vertex_name_type;
63
64 public:
65 /**
66 * The @c type field provides a distribution object that maps
67 * vertex names to processors. The distribution object will be
68 * constructed with the process group over which communication will
69 * occur. The distribution object shall also be a function
70 * object mapping from the type of the name to a processor number
71 * in @c [0, @c p) (for @c p processors). By default, the mapping
72 * function uses the @c boost::hash value of the name, modulo @c p.
73 */
74 typedef typename mpl::if_<is_same<InDistribution, defaultS>,
75 hashed_distribution<vertex_name_type>,
76 InDistribution>::type
77 type;
78
79 /// for named graphs the default type is the same as the stored distribution
80 /// type
81 typedef type default_type;
82 };
83
84 /// Specialization for non-named graphs
85 template <typename InDistribution, typename VertexProperty, typename VertexSize,
86 typename ProcessGroup>
87 struct select_distribution<InDistribution, VertexProperty, VertexSize,
88 ProcessGroup, void>
89 {
90 /// the distribution type stored in the graph for non-named graphs should be
91 /// the variant_distribution type
92 typedef typename mpl::if_<is_same<InDistribution, defaultS>,
93 boost::parallel::variant_distribution<ProcessGroup,
94 VertexSize>,
95 InDistribution>::type type;
96
97 /// default_type is used as the distribution functor for the
98 /// adjacency_list, it should be parallel::block by default
99 typedef typename mpl::if_<is_same<InDistribution, defaultS>,
100 boost::parallel::block, type>::type
101 default_type;
102 };
103
104
105 /*******************************************************************
106 * Named graph mixin *
107 *******************************************************************/
108
109 /**
110 * named_graph is a mixin that provides names for the vertices of a
111 * graph, including a mapping from names to vertices. Graph types that
112 * may or may not be have vertex names (depending on the properties
113 * supplied by the user) should use maybe_named_graph.
114 *
115 * Template parameters:
116 *
117 * Graph: the graph type that derives from named_graph
118 *
119 * Vertex: the type of a vertex descriptor in Graph. Note: we cannot
120 * use graph_traits here, because the Graph is not yet defined.
121 *
122 * VertexProperty: the type of the property stored along with the
123 * vertex.
124 *
125 * ProcessGroup: the process group over which the distributed name
126 * graph mixin will communicate.
127 */
128 template<typename Graph, typename Vertex, typename Edge, typename Config>
129 class named_graph
130 {
131 public:
132 /// Messages passed within the distributed named graph
133 enum message_kind {
134 /**
135 * Requests the addition of a vertex on a remote processor. The
136 * message data is a @c vertex_name_type.
137 */
138 msg_add_vertex_name,
139
140 /**
141 * Requests the addition of a vertex on a remote processor. The
142 * message data is a @c vertex_name_type. The remote processor
143 * will send back a @c msg_add_vertex_name_reply message
144 * containing the vertex descriptor.
145 */
146 msg_add_vertex_name_with_reply,
147
148 /**
149 * Requests the vertex descriptor corresponding to the given
150 * vertex name. The remote process will reply with a
151 * @c msg_find_vertex_reply message containing the answer.
152 */
153 msg_find_vertex,
154
155 /**
156 * Requests the addition of an edge on a remote processor. The
157 * data stored in these messages is a @c pair<source, target>@,
158 * where @c source and @c target may be either names (of type @c
159 * vertex_name_type) or vertex descriptors, depending on what
160 * information we have locally.
161 */
162 msg_add_edge_name_name,
163 msg_add_edge_vertex_name,
164 msg_add_edge_name_vertex,
165
166 /**
167 * These messages are identical to msg_add_edge_*_*, except that
168 * the process actually adding the edge will send back a @c
169 * pair<edge_descriptor,bool>
170 */
171 msg_add_edge_name_name_with_reply,
172 msg_add_edge_vertex_name_with_reply,
173 msg_add_edge_name_vertex_with_reply,
174
175 /**
176 * Requests the addition of an edge with a property on a remote
177 * processor. The data stored in these messages is a @c
178 * pair<vertex_property_type, pair<source, target>>@, where @c
179 * source and @c target may be either names (of type @c
180 * vertex_name_type) or vertex descriptors, depending on what
181 * information we have locally.
182 */
183 msg_add_edge_name_name_with_property,
184 msg_add_edge_vertex_name_with_property,
185 msg_add_edge_name_vertex_with_property,
186
187 /**
188 * These messages are identical to msg_add_edge_*_*_with_property,
189 * except that the process actually adding the edge will send back
190 * a @c pair<edge_descriptor,bool>.
191 */
192 msg_add_edge_name_name_with_reply_and_property,
193 msg_add_edge_vertex_name_with_reply_and_property,
194 msg_add_edge_name_vertex_with_reply_and_property
195 };
196
197 /// The vertex descriptor type
198 typedef Vertex vertex_descriptor;
199
200 /// The edge descriptor type
201 typedef Edge edge_descriptor;
202
203 /// The vertex property type
204 typedef typename Config::vertex_property_type vertex_property_type;
205
206 /// The vertex property type
207 typedef typename Config::edge_property_type edge_property_type;
208
209 /// The type used to extract names from the property structure
210 typedef typename internal_vertex_name<vertex_property_type>::type
211 extract_name_type;
212
213 /// The type used to name vertices in the graph
214 typedef typename remove_cv<
215 typename remove_reference<
216 typename extract_name_type::result_type>::type>::type
217 vertex_name_type;
218
219 /// The type used to distribute named vertices in the graph
220 typedef typename Config::distribution_type distribution_type;
221 typedef typename Config::base_distribution_type base_distribution_type;
222
223 /// The type used for communication in the distributed structure
224 typedef typename Config::process_group_type process_group_type;
225
226 /// Type used to identify processes
227 typedef typename process_group_type::process_id_type process_id_type;
228
229 /// a reference to this class, which is used for disambiguation of the
230 // add_vertex function
231 typedef named_graph named_graph_type;
232
233 /// Structure returned when adding a vertex by vertex name
234 struct lazy_add_vertex;
235 friend struct lazy_add_vertex;
236
237 /// Structure returned when adding an edge by vertex name
238 struct lazy_add_edge;
239 friend struct lazy_add_edge;
240
241 /// Structure returned when adding an edge by vertex name with a property
242 struct lazy_add_edge_with_property;
243 friend struct lazy_add_edge_with_property;
244
245 explicit named_graph(const process_group_type& pg);
246
247 named_graph(const process_group_type& pg, const base_distribution_type& distribution);
248
249 /// Set up triggers, but only for the BSP process group
250 void setup_triggers();
251
252 /// Retrieve the derived instance
253 Graph& derived() { return static_cast<Graph&>(*this); }
254 const Graph& derived() const { return static_cast<const Graph&>(*this); }
255
256 /// Retrieve the process group
257 process_group_type& process_group() { return process_group_; }
258 const process_group_type& process_group() const { return process_group_; }
259
260 // Retrieve the named distribution
261 distribution_type& named_distribution() { return distribution_; }
262 const distribution_type& named_distribution() const { return distribution_; }
263
264 /// Notify the named_graph that we have added the given vertex. This
265 /// is a no-op.
266 void added_vertex(Vertex) { }
267
268 /// Notify the named_graph that we are removing the given
269 /// vertex. This is a no-op.
270 template <typename VertexIterStability>
271 void removing_vertex(Vertex, VertexIterStability) { }
272
273 /// Notify the named_graph that we are clearing the graph
274 void clearing_graph() { }
275
276 /// Retrieve the owner of a given vertex based on the properties
277 /// associated with that vertex. This operation just returns the
278 /// number of the local processor, adding all vertices locally.
279 process_id_type owner_by_property(const vertex_property_type&);
280
281 protected:
282 void
283 handle_add_vertex_name(int source, int tag, const vertex_name_type& msg,
284 trigger_receive_context);
285
286 vertex_descriptor
287 handle_add_vertex_name_with_reply(int source, int tag,
288 const vertex_name_type& msg,
289 trigger_receive_context);
290
291 boost::parallel::detail::untracked_pair<vertex_descriptor, bool>
292 handle_find_vertex(int source, int tag, const vertex_name_type& msg,
293 trigger_receive_context);
294
295 template<typename U, typename V>
296 void handle_add_edge(int source, int tag, const boost::parallel::detail::untracked_pair<U, V>& msg,
297 trigger_receive_context);
298
299 template<typename U, typename V>
300 boost::parallel::detail::untracked_pair<edge_descriptor, bool>
301 handle_add_edge_with_reply(int source, int tag, const boost::parallel::detail::untracked_pair<U, V>& msg,
302 trigger_receive_context);
303
304 template<typename U, typename V>
305 void
306 handle_add_edge_with_property
307 (int source, int tag,
308 const pair_with_property<U, V, edge_property_type>& msg,
309 trigger_receive_context);
310
311 template<typename U, typename V>
312 boost::parallel::detail::untracked_pair<edge_descriptor, bool>
313 handle_add_edge_with_reply_and_property
314 (int source, int tag,
315 const pair_with_property<U, V, edge_property_type>& msg,
316 trigger_receive_context);
317
318 /// The process group for this distributed data structure
319 process_group_type process_group_;
320
321 /// The distribution we will use to map names to processors
322 distribution_type distribution_;
323 };
324
325 /// Helper macro containing the template parameters of named_graph
326 #define BGL_NAMED_GRAPH_PARAMS \
327 typename Graph, typename Vertex, typename Edge, typename Config
328 /// Helper macro containing the named_graph<...> instantiation
329 #define BGL_NAMED_GRAPH \
330 named_graph<Graph, Vertex, Edge, Config>
331
332 /**
333 * Data structure returned from add_vertex that will "lazily" add the
334 * vertex, either when it is converted to a @c vertex_descriptor or
335 * when the most recent copy has been destroyed.
336 */
337 template<BGL_NAMED_GRAPH_PARAMS>
338 struct BGL_NAMED_GRAPH::lazy_add_vertex
339 {
340 /// Construct a new lazyily-added vertex
341 lazy_add_vertex(named_graph& self, const vertex_name_type& name)
342 : self(self), name(name), committed(false) { }
343
344 /// Transfer responsibility for adding the vertex from the source of
345 /// the copy to the newly-constructed opbject.
346 lazy_add_vertex(const lazy_add_vertex& other)
347 : self(other.self), name(other.name), committed(other.committed)
348 {
349 other.committed = true;
350 }
351
352 /// If the vertex has not been added yet, add it
353 ~lazy_add_vertex();
354
355 /// Add the vertex and return its descriptor. This conversion can
356 /// only occur once, and only when this object is responsible for
357 /// creating the vertex.
358 operator vertex_descriptor() const { return commit(); }
359
360 /// Add the vertex and return its descriptor. This can only be
361 /// called once, and only when this object is responsible for
362 /// creating the vertex.
363 vertex_descriptor commit() const;
364
365 protected:
366 named_graph& self;
367 vertex_name_type name;
368 mutable bool committed;
369 };
370
371 template<BGL_NAMED_GRAPH_PARAMS>
372 BGL_NAMED_GRAPH::lazy_add_vertex::~lazy_add_vertex()
373 {
374 typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
375
376 /// If this vertex has already been created or will be created by
377 /// someone else, or if someone threw an exception, we will not
378 /// create the vertex now.
379 if (committed || std::uncaught_exception())
380 return;
381
382 committed = true;
383
384 process_id_type owner = self.named_distribution()(name);
385 if (owner == process_id(self.process_group()))
386 /// Add the vertex locally
387 add_vertex(self.derived().base().vertex_constructor(name), self.derived());
388 else
389 /// Ask the owner of the vertex to add a vertex with this name
390 send(self.process_group(), owner, msg_add_vertex_name, name);
391 }
392
393 template<BGL_NAMED_GRAPH_PARAMS>
394 typename BGL_NAMED_GRAPH::vertex_descriptor
395 BGL_NAMED_GRAPH::lazy_add_vertex::commit() const
396 {
397 typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
398 BOOST_ASSERT (!committed);
399 committed = true;
400
401 process_id_type owner = self.named_distribution()(name);
402 if (owner == process_id(self.process_group()))
403 /// Add the vertex locally
404 return add_vertex(self.derived().base().vertex_constructor(name),
405 self.derived());
406 else {
407 /// Ask the owner of the vertex to add a vertex with this name
408 vertex_descriptor result;
409 send_oob_with_reply(self.process_group(), owner,
410 msg_add_vertex_name_with_reply, name, result);
411 return result;
412 }
413 }
414
415 /**
416 * Data structure returned from add_edge that will "lazily" add the
417 * edge, either when it is converted to a @c
418 * pair<edge_descriptor,bool> or when the most recent copy has been
419 * destroyed.
420 */
421 template<BGL_NAMED_GRAPH_PARAMS>
422 struct BGL_NAMED_GRAPH::lazy_add_edge
423 {
424 /// The graph's edge descriptor
425 typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
426
427 /// Add an edge for the edge (u, v) based on vertex names
428 lazy_add_edge(BGL_NAMED_GRAPH& self,
429 const vertex_name_type& u_name,
430 const vertex_name_type& v_name)
431 : self(self), u(u_name), v(v_name), committed(false) { }
432
433 /// Add an edge for the edge (u, v) based on a vertex descriptor and name
434 lazy_add_edge(BGL_NAMED_GRAPH& self,
435 vertex_descriptor u,
436 const vertex_name_type& v_name)
437 : self(self), u(u), v(v_name), committed(false) { }
438
439 /// Add an edge for the edge (u, v) based on a vertex name and descriptor
440 lazy_add_edge(BGL_NAMED_GRAPH& self,
441 const vertex_name_type& u_name,
442 vertex_descriptor v)
443 : self(self), u(u_name), v(v), committed(false) { }
444
445 /// Add an edge for the edge (u, v) based on vertex descriptors
446 lazy_add_edge(BGL_NAMED_GRAPH& self,
447 vertex_descriptor u,
448 vertex_descriptor v)
449 : self(self), u(u), v(v), committed(false) { }
450
451 /// Copy a lazy_add_edge structure, which transfers responsibility
452 /// for adding the edge to the newly-constructed object.
453 lazy_add_edge(const lazy_add_edge& other)
454 : self(other.self), u(other.u), v(other.v), committed(other.committed)
455 {
456 other.committed = true;
457 }
458
459 /// If the edge has not yet been added, add the edge but don't wait
460 /// for a reply.
461 ~lazy_add_edge();
462
463 /// Returns commit().
464 operator std::pair<edge_descriptor, bool>() const { return commit(); }
465
466 // Add the edge. This operation will block if a remote edge is
467 // being added.
468 std::pair<edge_descriptor, bool> commit() const;
469
470 protected:
471 BGL_NAMED_GRAPH& self;
472 mutable variant<vertex_descriptor, vertex_name_type> u;
473 mutable variant<vertex_descriptor, vertex_name_type> v;
474 mutable bool committed;
475
476 private:
477 // No copy-assignment semantics
478 void operator=(lazy_add_edge&);
479 };
480
481 template<BGL_NAMED_GRAPH_PARAMS>
482 BGL_NAMED_GRAPH::lazy_add_edge::~lazy_add_edge()
483 {
484 using boost::parallel::detail::make_untracked_pair;
485
486 /// If this edge has already been created or will be created by
487 /// someone else, or if someone threw an exception, we will not
488 /// create the edge now.
489 if (committed || std::uncaught_exception())
490 return;
491
492 committed = true;
493
494 if (vertex_name_type* v_name = boost::get<vertex_name_type>(&v)) {
495 // We haven't resolved the target vertex to a descriptor yet, so
496 // it must not be local. Send a message to the owner of the target
497 // of the edge. If the owner of the target does not happen to own
498 // the source, it will resolve the target to a vertex descriptor
499 // and pass the message along to the owner of the source.
500 if (vertex_name_type* u_name = boost::get<vertex_name_type>(&u))
501 send(self.process_group(), self.distribution_(*v_name),
502 BGL_NAMED_GRAPH::msg_add_edge_name_name,
503 make_untracked_pair(*u_name, *v_name));
504 else
505 send(self.process_group(), self.distribution_(*v_name),
506 BGL_NAMED_GRAPH::msg_add_edge_vertex_name,
507 make_untracked_pair(boost::get<vertex_descriptor>(u), *v_name));
508 } else {
509 if (vertex_name_type* u_name = boost::get<vertex_name_type>(&u))
510 // We haven't resolved the source vertex to a descriptor yet, so
511 // it must not be local. Send a message to the owner of the
512 // source vertex requesting the edge addition.
513 send(self.process_group(), self.distribution_(*u_name),
514 BGL_NAMED_GRAPH::msg_add_edge_name_vertex,
515 make_untracked_pair(*u_name, boost::get<vertex_descriptor>(v)));
516 else
517 // We have descriptors for both of the vertices, either of which
518 // may be remote or local. Tell the owner of the source vertex
519 // to add the edge (it may be us!).
520 add_edge(boost::get<vertex_descriptor>(u),
521 boost::get<vertex_descriptor>(v),
522 self.derived());
523 }
524 }
525
526 template<BGL_NAMED_GRAPH_PARAMS>
527 std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
528 BGL_NAMED_GRAPH::lazy_add_edge::commit() const
529 {
530 typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
531 using boost::parallel::detail::make_untracked_pair;
532
533 BOOST_ASSERT(!committed);
534 committed = true;
535
536 /// The result we will return, if we are sending a message to
537 /// request that someone else add the edge.
538 boost::parallel::detail::untracked_pair<edge_descriptor, bool> result;
539
540 /// The owner of the vertex "u"
541 process_id_type u_owner;
542
543 process_id_type rank = process_id(self.process_group());
544 if (const vertex_name_type* u_name = boost::get<vertex_name_type>(&u)) {
545 /// We haven't resolved the source vertex to a descriptor yet, so
546 /// it must not be local.
547 u_owner = self.named_distribution()(*u_name);
548
549 /// Send a message to the remote vertex requesting that it add the
550 /// edge. The message differs depending on whether we have a
551 /// vertex name or a vertex descriptor for the target.
552 if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
553 send_oob_with_reply(self.process_group(), u_owner,
554 BGL_NAMED_GRAPH::msg_add_edge_name_name_with_reply,
555 make_untracked_pair(*u_name, *v_name), result);
556 else
557 send_oob_with_reply(self.process_group(), u_owner,
558 BGL_NAMED_GRAPH::msg_add_edge_name_vertex_with_reply,
559 make_untracked_pair(*u_name,
560 boost::get<vertex_descriptor>(v)),
561 result);
562 } else {
563 /// We have resolved the source vertex to a descriptor, which may
564 /// either be local or remote.
565 u_owner
566 = get(vertex_owner, self.derived(),
567 boost::get<vertex_descriptor>(u));
568 if (u_owner == rank) {
569 /// The source is local. If we need to, resolve the target vertex.
570 if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
571 v = add_vertex(*v_name, self.derived());
572
573 /// Add the edge using vertex descriptors
574 return add_edge(boost::get<vertex_descriptor>(u),
575 boost::get<vertex_descriptor>(v),
576 self.derived());
577 } else {
578 /// The source is remote. Just send a message to its owner
579 /// requesting that the owner add the new edge, either directly
580 /// or via the derived class's add_edge function.
581 if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
582 send_oob_with_reply
583 (self.process_group(), u_owner,
584 BGL_NAMED_GRAPH::msg_add_edge_vertex_name_with_reply,
585 make_untracked_pair(boost::get<vertex_descriptor>(u), *v_name),
586 result);
587 else
588 return add_edge(boost::get<vertex_descriptor>(u),
589 boost::get<vertex_descriptor>(v),
590 self.derived());
591 }
592 }
593
594 // If we get here, the edge has been added remotely and "result"
595 // contains the result of that edge addition.
596 return result;
597 }
598
599 /**
600 * Data structure returned from add_edge that will "lazily" add the
601 * edge with a property, either when it is converted to a @c
602 * pair<edge_descriptor,bool> or when the most recent copy has been
603 * destroyed.
604 */
605 template<BGL_NAMED_GRAPH_PARAMS>
606 struct BGL_NAMED_GRAPH::lazy_add_edge_with_property
607 {
608 /// The graph's edge descriptor
609 typedef typename graph_traits<Graph>::edge_descriptor edge_descriptor;
610
611 /// The Edge property type for our graph
612 typedef typename Config::edge_property_type edge_property_type;
613
614 /// Add an edge for the edge (u, v) based on vertex names
615 lazy_add_edge_with_property(BGL_NAMED_GRAPH& self,
616 const vertex_name_type& u_name,
617 const vertex_name_type& v_name,
618 const edge_property_type& property)
619 : self(self), u(u_name), v(v_name), property(property), committed(false)
620 {
621 }
622
623 /// Add an edge for the edge (u, v) based on a vertex descriptor and name
624 lazy_add_edge_with_property(BGL_NAMED_GRAPH& self,
625 vertex_descriptor u,
626 const vertex_name_type& v_name,
627 const edge_property_type& property)
628 : self(self), u(u), v(v_name), property(property), committed(false) { }
629
630 /// Add an edge for the edge (u, v) based on a vertex name and descriptor
631 lazy_add_edge_with_property(BGL_NAMED_GRAPH& self,
632 const vertex_name_type& u_name,
633 vertex_descriptor v,
634 const edge_property_type& property)
635 : self(self), u(u_name), v(v), property(property), committed(false) { }
636
637 /// Add an edge for the edge (u, v) based on vertex descriptors
638 lazy_add_edge_with_property(BGL_NAMED_GRAPH& self,
639 vertex_descriptor u,
640 vertex_descriptor v,
641 const edge_property_type& property)
642 : self(self), u(u), v(v), property(property), committed(false) { }
643
644 /// Copy a lazy_add_edge_with_property structure, which transfers
645 /// responsibility for adding the edge to the newly-constructed
646 /// object.
647 lazy_add_edge_with_property(const lazy_add_edge_with_property& other)
648 : self(other.self), u(other.u), v(other.v), property(other.property),
649 committed(other.committed)
650 {
651 other.committed = true;
652 }
653
654 /// If the edge has not yet been added, add the edge but don't wait
655 /// for a reply.
656 ~lazy_add_edge_with_property();
657
658 /// Returns commit().
659 operator std::pair<edge_descriptor, bool>() const { return commit(); }
660
661 // Add the edge. This operation will block if a remote edge is
662 // being added.
663 std::pair<edge_descriptor, bool> commit() const;
664
665 protected:
666 BGL_NAMED_GRAPH& self;
667 mutable variant<vertex_descriptor, vertex_name_type> u;
668 mutable variant<vertex_descriptor, vertex_name_type> v;
669 edge_property_type property;
670 mutable bool committed;
671
672 private:
673 // No copy-assignment semantics
674 void operator=(lazy_add_edge_with_property&);
675 };
676
677 template<BGL_NAMED_GRAPH_PARAMS>
678 BGL_NAMED_GRAPH::lazy_add_edge_with_property::~lazy_add_edge_with_property()
679 {
680 using boost::detail::parallel::make_pair_with_property;
681
682 /// If this edge has already been created or will be created by
683 /// someone else, or if someone threw an exception, we will not
684 /// create the edge now.
685 if (committed || std::uncaught_exception())
686 return;
687
688 committed = true;
689
690 if (vertex_name_type* v_name = boost::get<vertex_name_type>(&v)) {
691 // We haven't resolved the target vertex to a descriptor yet, so
692 // it must not be local. Send a message to the owner of the target
693 // of the edge. If the owner of the target does not happen to own
694 // the source, it will resolve the target to a vertex descriptor
695 // and pass the message along to the owner of the source.
696 if (vertex_name_type* u_name = boost::get<vertex_name_type>(&u))
697 send(self.process_group(), self.distribution_(*v_name),
698 BGL_NAMED_GRAPH::msg_add_edge_name_name_with_property,
699 make_pair_with_property(*u_name, *v_name, property));
700 else
701 send(self.process_group(), self.distribution_(*v_name),
702 BGL_NAMED_GRAPH::msg_add_edge_vertex_name_with_property,
703 make_pair_with_property(boost::get<vertex_descriptor>(u), *v_name,
704 property));
705 } else {
706 if (vertex_name_type* u_name = boost::get<vertex_name_type>(&u))
707 // We haven't resolved the source vertex to a descriptor yet, so
708 // it must not be local. Send a message to the owner of the
709 // source vertex requesting the edge addition.
710 send(self.process_group(), self.distribution_(*u_name),
711 BGL_NAMED_GRAPH::msg_add_edge_name_vertex_with_property,
712 make_pair_with_property(*u_name, boost::get<vertex_descriptor>(v),
713 property));
714 else
715 // We have descriptors for both of the vertices, either of which
716 // may be remote or local. Tell the owner of the source vertex
717 // to add the edge (it may be us!).
718 add_edge(boost::get<vertex_descriptor>(u),
719 boost::get<vertex_descriptor>(v),
720 property,
721 self.derived());
722 }
723 }
724
725 template<BGL_NAMED_GRAPH_PARAMS>
726 std::pair<typename graph_traits<Graph>::edge_descriptor, bool>
727 BGL_NAMED_GRAPH::lazy_add_edge_with_property::commit() const
728 {
729 using boost::detail::parallel::make_pair_with_property;
730 typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
731 BOOST_ASSERT(!committed);
732 committed = true;
733
734 /// The result we will return, if we are sending a message to
735 /// request that someone else add the edge.
736 boost::parallel::detail::untracked_pair<edge_descriptor, bool> result;
737
738 /// The owner of the vertex "u"
739 process_id_type u_owner;
740
741 process_id_type rank = process_id(self.process_group());
742 if (const vertex_name_type* u_name = boost::get<vertex_name_type>(&u)) {
743 /// We haven't resolved the source vertex to a descriptor yet, so
744 /// it must not be local.
745 u_owner = self.named_distribution()(*u_name);
746
747 /// Send a message to the remote vertex requesting that it add the
748 /// edge. The message differs depending on whether we have a
749 /// vertex name or a vertex descriptor for the target.
750 if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
751 send_oob_with_reply
752 (self.process_group(), u_owner,
753 BGL_NAMED_GRAPH::msg_add_edge_name_name_with_reply_and_property,
754 make_pair_with_property(*u_name, *v_name, property),
755 result);
756 else
757 send_oob_with_reply
758 (self.process_group(), u_owner,
759 BGL_NAMED_GRAPH::msg_add_edge_name_vertex_with_reply_and_property,
760 make_pair_with_property(*u_name,
761 boost::get<vertex_descriptor>(v),
762 property),
763 result);
764 } else {
765 /// We have resolved the source vertex to a descriptor, which may
766 /// either be local or remote.
767 u_owner
768 = get(vertex_owner, self.derived(),
769 boost::get<vertex_descriptor>(u));
770 if (u_owner == rank) {
771 /// The source is local. If we need to, resolve the target vertex.
772 if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
773 v = add_vertex(*v_name, self.derived());
774
775 /// Add the edge using vertex descriptors
776 return add_edge(boost::get<vertex_descriptor>(u),
777 boost::get<vertex_descriptor>(v),
778 property,
779 self.derived());
780 } else {
781 /// The source is remote. Just send a message to its owner
782 /// requesting that the owner add the new edge, either directly
783 /// or via the derived class's add_edge function.
784 if (const vertex_name_type* v_name = boost::get<vertex_name_type>(&v))
785 send_oob_with_reply
786 (self.process_group(), u_owner,
787 BGL_NAMED_GRAPH::msg_add_edge_vertex_name_with_reply_and_property,
788 make_pair_with_property(boost::get<vertex_descriptor>(u), *v_name,
789 property),
790 result);
791 else
792 return add_edge(boost::get<vertex_descriptor>(u),
793 boost::get<vertex_descriptor>(v),
794 property,
795 self.derived());
796 }
797 }
798
799 // If we get here, the edge has been added remotely and "result"
800 // contains the result of that edge addition.
801 return result;
802 }
803
804 /// Construct the named_graph with a particular process group
805 template<BGL_NAMED_GRAPH_PARAMS>
806 BGL_NAMED_GRAPH::named_graph(const process_group_type& pg)
807 : process_group_(pg, boost::parallel::attach_distributed_object()),
808 distribution_(pg)
809 {
810 setup_triggers();
811 }
812
813 /// Construct the named_graph mixin with a particular process group
814 /// and distribution function
815 template<BGL_NAMED_GRAPH_PARAMS>
816 BGL_NAMED_GRAPH::named_graph(const process_group_type& pg,
817 const base_distribution_type& distribution)
818 : process_group_(pg, boost::parallel::attach_distributed_object()),
819 distribution_(pg, distribution)
820 {
821 setup_triggers();
822 }
823
824 template<BGL_NAMED_GRAPH_PARAMS>
825 void
826 BGL_NAMED_GRAPH::setup_triggers()
827 {
828 using boost::graph::parallel::simple_trigger;
829
830 simple_trigger(process_group_, msg_add_vertex_name, this,
831 &named_graph::handle_add_vertex_name);
832 simple_trigger(process_group_, msg_add_vertex_name_with_reply, this,
833 &named_graph::handle_add_vertex_name_with_reply);
834 simple_trigger(process_group_, msg_find_vertex, this,
835 &named_graph::handle_find_vertex);
836 simple_trigger(process_group_, msg_add_edge_name_name, this,
837 &named_graph::template handle_add_edge<vertex_name_type,
838 vertex_name_type>);
839 simple_trigger(process_group_, msg_add_edge_name_name_with_reply, this,
840 &named_graph::template handle_add_edge_with_reply
841 <vertex_name_type, vertex_name_type>);
842 simple_trigger(process_group_, msg_add_edge_name_vertex, this,
843 &named_graph::template handle_add_edge<vertex_name_type,
844 vertex_descriptor>);
845 simple_trigger(process_group_, msg_add_edge_name_vertex_with_reply, this,
846 &named_graph::template handle_add_edge_with_reply
847 <vertex_name_type, vertex_descriptor>);
848 simple_trigger(process_group_, msg_add_edge_vertex_name, this,
849 &named_graph::template handle_add_edge<vertex_descriptor,
850 vertex_name_type>);
851 simple_trigger(process_group_, msg_add_edge_vertex_name_with_reply, this,
852 &named_graph::template handle_add_edge_with_reply
853 <vertex_descriptor, vertex_name_type>);
854 simple_trigger(process_group_, msg_add_edge_name_name_with_property, this,
855 &named_graph::
856 template handle_add_edge_with_property<vertex_name_type,
857 vertex_name_type>);
858 simple_trigger(process_group_,
859 msg_add_edge_name_name_with_reply_and_property, this,
860 &named_graph::template handle_add_edge_with_reply_and_property
861 <vertex_name_type, vertex_name_type>);
862 simple_trigger(process_group_, msg_add_edge_name_vertex_with_property, this,
863 &named_graph::
864 template handle_add_edge_with_property<vertex_name_type,
865 vertex_descriptor>);
866 simple_trigger(process_group_,
867 msg_add_edge_name_vertex_with_reply_and_property, this,
868 &named_graph::template handle_add_edge_with_reply_and_property
869 <vertex_name_type, vertex_descriptor>);
870 simple_trigger(process_group_, msg_add_edge_vertex_name_with_property, this,
871 &named_graph::
872 template handle_add_edge_with_property<vertex_descriptor,
873 vertex_name_type>);
874 simple_trigger(process_group_,
875 msg_add_edge_vertex_name_with_reply_and_property, this,
876 &named_graph::template handle_add_edge_with_reply_and_property
877 <vertex_descriptor, vertex_name_type>);
878 }
879
880 /// Retrieve the vertex associated with the given name
881 template<BGL_NAMED_GRAPH_PARAMS>
882 optional<Vertex>
883 find_vertex(typename BGL_NAMED_GRAPH::vertex_name_type const& name,
884 const BGL_NAMED_GRAPH& g)
885 {
886 typedef typename Graph::local_vertex_descriptor local_vertex_descriptor;
887 typedef typename graph_traits<Graph>::vertex_descriptor vertex_descriptor;
888
889 // Determine the owner of this name
890 typename BGL_NAMED_GRAPH::process_id_type owner
891 = g.named_distribution()(name);
892
893 if (owner == process_id(g.process_group())) {
894 // The vertex is local, so search for a mapping here
895 optional<local_vertex_descriptor> result
896 = find_vertex(name, g.derived().base());
897 if (result)
898 return Vertex(owner, *result);
899 else
900 return optional<Vertex>();
901 }
902 else {
903 // Ask the ownering process for the name of this vertex
904 boost::parallel::detail::untracked_pair<vertex_descriptor, bool> result;
905 send_oob_with_reply(g.process_group(), owner,
906 BGL_NAMED_GRAPH::msg_find_vertex, name, result);
907 if (result.second)
908 return result.first;
909 else
910 return optional<Vertex>();
911 }
912 }
913
914 /// meta-function helping in figuring out if the given VertextProerty belongs to
915 /// a named graph
916 template<typename VertexProperty>
917 struct not_is_named_graph
918 : is_same<typename internal_vertex_name<VertexProperty>::type, void>
919 {};
920
921 /// Retrieve the vertex associated with the given name
922 template<typename Graph>
923 typename Graph::named_graph_type::lazy_add_vertex
924 add_vertex(typename Graph::vertex_name_type const& name,
925 Graph& g,
926 typename disable_if<
927 not_is_named_graph<typename Graph::vertex_property_type>,
928 void*>::type = 0)
929 {
930 return typename Graph::named_graph_type::lazy_add_vertex(g, name);
931 }
932
933 /// Add an edge using vertex names to refer to the vertices
934 template<BGL_NAMED_GRAPH_PARAMS>
935 typename BGL_NAMED_GRAPH::lazy_add_edge
936 add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
937 typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
938 BGL_NAMED_GRAPH& g)
939 {
940 typedef typename BGL_NAMED_GRAPH::lazy_add_edge lazy_add_edge;
941 typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
942
943 process_id_type rank = process_id(g.process_group());
944 process_id_type u_owner = g.named_distribution()(u_name);
945 process_id_type v_owner = g.named_distribution()(v_name);
946
947 // Resolve local vertex names before building the "lazy" edge
948 // addition structure.
949 if (u_owner == rank && v_owner == rank)
950 return lazy_add_edge(g, add_vertex(u_name, g), add_vertex(v_name, g));
951 else if (u_owner == rank && v_owner != rank)
952 return lazy_add_edge(g, add_vertex(u_name, g), v_name);
953 else if (u_owner != rank && v_owner == rank)
954 return lazy_add_edge(g, u_name, add_vertex(v_name, g));
955 else
956 return lazy_add_edge(g, u_name, v_name);
957 }
958
959 template<BGL_NAMED_GRAPH_PARAMS>
960 typename BGL_NAMED_GRAPH::lazy_add_edge
961 add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
962 typename BGL_NAMED_GRAPH::vertex_descriptor const& v,
963 BGL_NAMED_GRAPH& g)
964 {
965 // Resolve local vertex names before building the "lazy" edge
966 // addition structure.
967 typedef typename BGL_NAMED_GRAPH::lazy_add_edge lazy_add_edge;
968 if (g.named_distribution()(u_name) == process_id(g.process_group()))
969 return lazy_add_edge(g, add_vertex(u_name, g), v);
970 else
971 return lazy_add_edge(g, u_name, v);
972 }
973
974 template<BGL_NAMED_GRAPH_PARAMS>
975 typename BGL_NAMED_GRAPH::lazy_add_edge
976 add_edge(typename BGL_NAMED_GRAPH::vertex_descriptor const& u,
977 typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
978 BGL_NAMED_GRAPH& g)
979 {
980 // Resolve local vertex names before building the "lazy" edge
981 // addition structure.
982 typedef typename BGL_NAMED_GRAPH::lazy_add_edge lazy_add_edge;
983 if (g.named_distribution()(v_name) == process_id(g.process_group()))
984 return lazy_add_edge(g, u, add_vertex(v_name, g));
985 else
986 return lazy_add_edge(g, u, v_name);
987 }
988
989 /// Add an edge using vertex names to refer to the vertices
990 template<BGL_NAMED_GRAPH_PARAMS>
991 typename BGL_NAMED_GRAPH::lazy_add_edge_with_property
992 add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
993 typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
994 typename Graph::edge_property_type const& property,
995 BGL_NAMED_GRAPH& g)
996 {
997 typedef typename BGL_NAMED_GRAPH::lazy_add_edge_with_property lazy_add_edge;
998 typedef typename BGL_NAMED_GRAPH::process_id_type process_id_type;
999
1000 process_id_type rank = process_id(g.process_group());
1001 process_id_type u_owner = g.named_distribution()(u_name);
1002 process_id_type v_owner = g.named_distribution()(v_name);
1003
1004 // Resolve local vertex names before building the "lazy" edge
1005 // addition structure.
1006 if (u_owner == rank && v_owner == rank)
1007 return lazy_add_edge(g, add_vertex(u_name, g), add_vertex(v_name, g),
1008 property);
1009 else if (u_owner == rank && v_owner != rank)
1010 return lazy_add_edge(g, add_vertex(u_name, g), v_name, property);
1011 else if (u_owner != rank && v_owner == rank)
1012 return lazy_add_edge(g, u_name, add_vertex(v_name, g), property);
1013 else
1014 return lazy_add_edge(g, u_name, v_name, property);
1015 }
1016
1017 template<BGL_NAMED_GRAPH_PARAMS>
1018 typename BGL_NAMED_GRAPH::lazy_add_edge_with_property
1019 add_edge(typename BGL_NAMED_GRAPH::vertex_name_type const& u_name,
1020 typename BGL_NAMED_GRAPH::vertex_descriptor const& v,
1021 typename Graph::edge_property_type const& property,
1022 BGL_NAMED_GRAPH& g)
1023 {
1024 // Resolve local vertex names before building the "lazy" edge
1025 // addition structure.
1026 typedef typename BGL_NAMED_GRAPH::lazy_add_edge_with_property lazy_add_edge;
1027 if (g.named_distribution()(u_name) == process_id(g.process_group()))
1028 return lazy_add_edge(g, add_vertex(u_name, g), v, property);
1029 else
1030 return lazy_add_edge(g, u_name, v, property);
1031 }
1032
1033 template<BGL_NAMED_GRAPH_PARAMS>
1034 typename BGL_NAMED_GRAPH::lazy_add_edge_with_property
1035 add_edge(typename BGL_NAMED_GRAPH::vertex_descriptor const& u,
1036 typename BGL_NAMED_GRAPH::vertex_name_type const& v_name,
1037 typename Graph::edge_property_type const& property,
1038 BGL_NAMED_GRAPH& g)
1039 {
1040 // Resolve local vertex names before building the "lazy" edge
1041 // addition structure.
1042 typedef typename BGL_NAMED_GRAPH::lazy_add_edge_with_property lazy_add_edge;
1043 if (g.named_distribution()(v_name) == process_id(g.process_group()))
1044 return lazy_add_edge(g, u, add_vertex(v_name, g), property);
1045 else
1046 return lazy_add_edge(g, u, v_name, property);
1047 }
1048
1049 template<BGL_NAMED_GRAPH_PARAMS>
1050 typename BGL_NAMED_GRAPH::process_id_type
1051 BGL_NAMED_GRAPH::owner_by_property(const vertex_property_type& property)
1052 {
1053 return distribution_(derived().base().extract_name(property));
1054 }
1055
1056
1057 /*******************************************************************
1058 * Message handlers *
1059 *******************************************************************/
1060
1061 template<BGL_NAMED_GRAPH_PARAMS>
1062 void
1063 BGL_NAMED_GRAPH::
1064 handle_add_vertex_name(int /*source*/, int /*tag*/,
1065 const vertex_name_type& msg, trigger_receive_context)
1066 {
1067 add_vertex(msg, derived());
1068 }
1069
1070 template<BGL_NAMED_GRAPH_PARAMS>
1071 typename BGL_NAMED_GRAPH::vertex_descriptor
1072 BGL_NAMED_GRAPH::
1073 handle_add_vertex_name_with_reply(int source, int /*tag*/,
1074 const vertex_name_type& msg,
1075 trigger_receive_context)
1076 {
1077 return add_vertex(msg, derived());
1078 }
1079
1080 template<BGL_NAMED_GRAPH_PARAMS>
1081 boost::parallel::detail::untracked_pair<typename BGL_NAMED_GRAPH::vertex_descriptor, bool>
1082 BGL_NAMED_GRAPH::
1083 handle_find_vertex(int source, int /*tag*/, const vertex_name_type& msg,
1084 trigger_receive_context)
1085 {
1086 using boost::parallel::detail::make_untracked_pair;
1087
1088 optional<vertex_descriptor> v = find_vertex(msg, derived());
1089 if (v)
1090 return make_untracked_pair(*v, true);
1091 else
1092 return make_untracked_pair(graph_traits<Graph>::null_vertex(), false);
1093 }
1094
1095 template<BGL_NAMED_GRAPH_PARAMS>
1096 template<typename U, typename V>
1097 void
1098 BGL_NAMED_GRAPH::
1099 handle_add_edge(int source, int /*tag*/, const boost::parallel::detail::untracked_pair<U, V>& msg,
1100 trigger_receive_context)
1101 {
1102 add_edge(msg.first, msg.second, derived());
1103 }
1104
1105 template<BGL_NAMED_GRAPH_PARAMS>
1106 template<typename U, typename V>
1107 boost::parallel::detail::untracked_pair<typename BGL_NAMED_GRAPH::edge_descriptor, bool>
1108 BGL_NAMED_GRAPH::
1109 handle_add_edge_with_reply(int source, int /*tag*/, const boost::parallel::detail::untracked_pair<U, V>& msg,
1110 trigger_receive_context)
1111 {
1112 std::pair<typename BGL_NAMED_GRAPH::edge_descriptor, bool> p =
1113 add_edge(msg.first, msg.second, derived());
1114 return p;
1115 }
1116
1117 template<BGL_NAMED_GRAPH_PARAMS>
1118 template<typename U, typename V>
1119 void
1120 BGL_NAMED_GRAPH::
1121 handle_add_edge_with_property
1122 (int source, int tag,
1123 const pair_with_property<U, V, edge_property_type>& msg,
1124 trigger_receive_context)
1125 {
1126 add_edge(msg.first, msg.second, msg.get_property(), derived());
1127 }
1128
1129 template<BGL_NAMED_GRAPH_PARAMS>
1130 template<typename U, typename V>
1131 boost::parallel::detail::untracked_pair<typename BGL_NAMED_GRAPH::edge_descriptor, bool>
1132 BGL_NAMED_GRAPH::
1133 handle_add_edge_with_reply_and_property
1134 (int source, int tag,
1135 const pair_with_property<U, V, edge_property_type>& msg,
1136 trigger_receive_context)
1137 {
1138 std:: pair<typename BGL_NAMED_GRAPH::edge_descriptor, bool> p =
1139 add_edge(msg.first, msg.second, msg.get_property(), derived());
1140 return p;
1141 }
1142
1143 #undef BGL_NAMED_GRAPH
1144 #undef BGL_NAMED_GRAPH_PARAMS
1145
1146 /*******************************************************************
1147 * Maybe named graph mixin *
1148 *******************************************************************/
1149
1150 /**
1151 * A graph mixin that can provide a mapping from names to vertices,
1152 * and use that mapping to simplify creation and manipulation of
1153 * graphs.
1154 */
1155 template<typename Graph, typename Vertex, typename Edge, typename Config,
1156 typename ExtractName
1157 = typename internal_vertex_name<typename Config::vertex_property_type>::type>
1158 struct maybe_named_graph
1159 : public named_graph<Graph, Vertex, Edge, Config>
1160 {
1161 private:
1162 typedef named_graph<Graph, Vertex, Edge, Config> inherited;
1163 typedef typename Config::process_group_type process_group_type;
1164
1165 public:
1166 /// The type used to distribute named vertices in the graph
1167 typedef typename Config::distribution_type distribution_type;
1168 typedef typename Config::base_distribution_type base_distribution_type;
1169
1170 explicit maybe_named_graph(const process_group_type& pg) : inherited(pg) { }
1171
1172 maybe_named_graph(const process_group_type& pg,
1173 const base_distribution_type& distribution)
1174 : inherited(pg, distribution) { }
1175
1176 distribution_type& distribution() { return this->distribution_; }
1177 const distribution_type& distribution() const { return this->distribution_; }
1178 };
1179
1180 /**
1181 * A graph mixin that can provide a mapping from names to vertices,
1182 * and use that mapping to simplify creation and manipulation of
1183 * graphs. This partial specialization turns off this functionality
1184 * when the @c VertexProperty does not have an internal vertex name.
1185 */
1186 template<typename Graph, typename Vertex, typename Edge, typename Config>
1187 struct maybe_named_graph<Graph, Vertex, Edge, Config, void>
1188 {
1189 private:
1190 typedef typename Config::process_group_type process_group_type;
1191 typedef typename Config::vertex_property_type vertex_property_type;
1192
1193 public:
1194 typedef typename process_group_type::process_id_type process_id_type;
1195
1196 /// The type used to distribute named vertices in the graph
1197 typedef typename Config::distribution_type distribution_type;
1198 typedef typename Config::base_distribution_type base_distribution_type;
1199
1200 explicit maybe_named_graph(const process_group_type&) { }
1201
1202 maybe_named_graph(const process_group_type& pg,
1203 const base_distribution_type& distribution)
1204 : distribution_(pg, distribution) { }
1205
1206 /// Notify the named_graph that we have added the given vertex. This
1207 /// is a no-op.
1208 void added_vertex(Vertex) { }
1209
1210 /// Notify the named_graph that we are removing the given
1211 /// vertex. This is a no-op.
1212 template <typename VertexIterStability>
1213 void removing_vertex(Vertex, VertexIterStability) { }
1214
1215 /// Notify the named_graph that we are clearing the graph
1216 void clearing_graph() { }
1217
1218 /// Retrieve the owner of a given vertex based on the properties
1219 /// associated with that vertex. This operation just returns the
1220 /// number of the local processor, adding all vertices locally.
1221 process_id_type owner_by_property(const vertex_property_type&)
1222 {
1223 return process_id(pg);
1224 }
1225
1226 distribution_type& distribution() { return distribution_; }
1227 const distribution_type& distribution() const { return distribution_; }
1228
1229 protected:
1230 /// The process group of the graph
1231 process_group_type pg;
1232
1233 /// The distribution used for the graph
1234 distribution_type distribution_;
1235 };
1236
1237 } } } // end namespace boost::graph::distributed
1238
1239 #endif // BOOST_GRAPH_DISTRIBUTED_NAMED_GRAPH_HPP