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