annotate DEPENDENCIES/generic/include/boost/graph/distributed/adjlist/redistribute.hpp @ 118:770eb830ec19 emscripten

Typo fix
author Chris Cannam
date Wed, 18 May 2016 16:14:08 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1 // Copyright (C) 2005-2006 The Trustees of Indiana University.
Chris@16 2
Chris@16 3 // Use, modification and distribution is subject to the Boost Software
Chris@16 4 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
Chris@16 5 // http://www.boost.org/LICENSE_1_0.txt)
Chris@16 6
Chris@16 7 // Authors: Douglas Gregor
Chris@16 8 // Andrew Lumsdaine
Chris@16 9
Chris@16 10 //
Chris@16 11 // Implements redistribution of vertices for a distributed adjacency
Chris@16 12 // list. This file should not be included by users. It will be
Chris@16 13 // included by the distributed adjacency list header.
Chris@16 14 //
Chris@16 15
Chris@16 16 #ifndef BOOST_GRAPH_USE_MPI
Chris@16 17 #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
Chris@16 18 #endif
Chris@16 19
Chris@16 20 #include <boost/pending/container_traits.hpp>
Chris@16 21
Chris@16 22 namespace boost { namespace detail { namespace parallel {
Chris@16 23
Chris@16 24 /* This structure contains a (vertex or edge) descriptor that is being
Chris@16 25 moved from one processor to another. It contains the properties for
Chris@16 26 that descriptor (if any).
Chris@16 27 */
Chris@16 28 template<typename Descriptor, typename DescriptorProperty>
Chris@16 29 struct redistributed_descriptor : maybe_store_property<DescriptorProperty>
Chris@16 30 {
Chris@16 31 typedef maybe_store_property<DescriptorProperty> inherited;
Chris@16 32
Chris@16 33 redistributed_descriptor() { }
Chris@16 34
Chris@16 35 redistributed_descriptor(const Descriptor& v, const DescriptorProperty& p)
Chris@16 36 : inherited(p), descriptor(v) { }
Chris@16 37
Chris@16 38 Descriptor descriptor;
Chris@16 39
Chris@16 40 private:
Chris@16 41 friend class boost::serialization::access;
Chris@16 42
Chris@16 43 template<typename Archiver>
Chris@16 44 void serialize(Archiver& ar, unsigned int /*version*/)
Chris@16 45 {
Chris@16 46 ar & boost::serialization::base_object<inherited>(*this)
Chris@16 47 & unsafe_serialize(descriptor);
Chris@16 48 }
Chris@16 49 };
Chris@16 50
Chris@16 51 /* Predicate that returns true if the target has migrated. */
Chris@16 52 template<typename VertexProcessorMap, typename Graph>
Chris@16 53 struct target_migrated_t
Chris@16 54 {
Chris@16 55 typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
Chris@16 56 typedef typename graph_traits<Graph>::edge_descriptor Edge;
Chris@16 57
Chris@16 58 target_migrated_t(VertexProcessorMap vertex_to_processor, const Graph& g)
Chris@16 59 : vertex_to_processor(vertex_to_processor), g(g) { }
Chris@16 60
Chris@16 61 bool operator()(Edge e) const
Chris@16 62 {
Chris@16 63 typedef global_descriptor<Vertex> DVertex;
Chris@16 64 processor_id_type owner = get(edge_target_processor_id, g, e);
Chris@16 65 return get(vertex_to_processor, DVertex(owner, target(e, g))) != owner;
Chris@16 66 }
Chris@16 67
Chris@16 68 private:
Chris@16 69 VertexProcessorMap vertex_to_processor;
Chris@16 70 const Graph& g;
Chris@16 71 };
Chris@16 72
Chris@16 73 template<typename VertexProcessorMap, typename Graph>
Chris@16 74 inline target_migrated_t<VertexProcessorMap, Graph>
Chris@16 75 target_migrated(VertexProcessorMap vertex_to_processor, const Graph& g)
Chris@16 76 { return target_migrated_t<VertexProcessorMap, Graph>(vertex_to_processor, g); }
Chris@16 77
Chris@16 78 /* Predicate that returns true if the source of an in-edge has migrated. */
Chris@16 79 template<typename VertexProcessorMap, typename Graph>
Chris@16 80 struct source_migrated_t
Chris@16 81 {
Chris@16 82 typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
Chris@16 83 typedef typename graph_traits<Graph>::edge_descriptor Edge;
Chris@16 84
Chris@16 85 source_migrated_t(VertexProcessorMap vertex_to_processor, const Graph& g)
Chris@16 86 : vertex_to_processor(vertex_to_processor), g(g) { }
Chris@16 87
Chris@16 88 bool operator()(stored_in_edge<Edge> e) const
Chris@16 89 {
Chris@16 90 return get(vertex_to_processor, DVertex(e.source_processor, source(e.e, g)))
Chris@16 91 != e.source_processor;
Chris@16 92 }
Chris@16 93
Chris@16 94 private:
Chris@16 95 VertexProcessorMap vertex_to_processor;
Chris@16 96 const Graph& g;
Chris@16 97 };
Chris@16 98
Chris@16 99 template<typename VertexProcessorMap, typename Graph>
Chris@16 100 inline source_migrated_t<VertexProcessorMap, Graph>
Chris@16 101 source_migrated(VertexProcessorMap vertex_to_processor, const Graph& g)
Chris@16 102 { return source_migrated_t<VertexProcessorMap, Graph>(vertex_to_processor, g); }
Chris@16 103
Chris@16 104 /* Predicate that returns true if the target has migrated. */
Chris@16 105 template<typename VertexProcessorMap, typename Graph>
Chris@16 106 struct source_or_target_migrated_t
Chris@16 107 {
Chris@16 108 typedef typename graph_traits<Graph>::edge_descriptor Edge;
Chris@16 109
Chris@16 110 source_or_target_migrated_t(VertexProcessorMap vertex_to_processor,
Chris@16 111 const Graph& g)
Chris@16 112 : vertex_to_processor(vertex_to_processor), g(g) { }
Chris@16 113
Chris@16 114 bool operator()(Edge e) const
Chris@16 115 {
Chris@16 116 return get(vertex_to_processor, source(e, g)) != source(e, g).owner
Chris@16 117 || get(vertex_to_processor, target(e, g)) != target(e, g).owner;
Chris@16 118 }
Chris@16 119
Chris@16 120 private:
Chris@16 121 VertexProcessorMap vertex_to_processor;
Chris@16 122 const Graph& g;
Chris@16 123 };
Chris@16 124
Chris@16 125 template<typename VertexProcessorMap, typename Graph>
Chris@16 126 inline source_or_target_migrated_t<VertexProcessorMap, Graph>
Chris@16 127 source_or_target_migrated(VertexProcessorMap vertex_to_processor,
Chris@16 128 const Graph& g)
Chris@16 129 {
Chris@16 130 typedef source_or_target_migrated_t<VertexProcessorMap, Graph> result_type;
Chris@16 131 return result_type(vertex_to_processor, g);
Chris@16 132 }
Chris@16 133
Chris@16 134 } } // end of namespace detail::parallel
Chris@16 135
Chris@16 136 template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
Chris@16 137 template<typename VertexProcessorMap>
Chris@16 138 void
Chris@16 139 PBGL_DISTRIB_ADJLIST_TYPE
Chris@16 140 ::request_in_neighbors(vertex_descriptor v,
Chris@16 141 VertexProcessorMap vertex_to_processor,
Chris@16 142 bidirectionalS)
Chris@16 143 {
Chris@16 144 BGL_FORALL_INEDGES_T(v, e, *this, graph_type)
Chris@16 145 request(vertex_to_processor, source(e, *this));
Chris@16 146 }
Chris@16 147
Chris@16 148 template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
Chris@16 149 template<typename VertexProcessorMap>
Chris@16 150 void
Chris@16 151 PBGL_DISTRIB_ADJLIST_TYPE
Chris@16 152 ::remove_migrated_in_edges(vertex_descriptor v,
Chris@16 153 VertexProcessorMap vertex_to_processor,
Chris@16 154 bidirectionalS)
Chris@16 155 {
Chris@16 156 graph_detail::erase_if(get(vertex_in_edges, base())[v.local],
Chris@16 157 source_migrated(vertex_to_processor, base()));
Chris@16 158 }
Chris@16 159
Chris@16 160 template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
Chris@16 161 template<typename VertexProcessorMap>
Chris@16 162 void
Chris@16 163 PBGL_DISTRIB_ADJLIST_TYPE
Chris@16 164 ::redistribute(VertexProcessorMap vertex_to_processor)
Chris@16 165 {
Chris@16 166 using boost::parallel::inplace_all_to_all;
Chris@16 167
Chris@16 168 // When we have stable descriptors, we only move those descriptors
Chris@16 169 // that actually need to be moved. Otherwise, we essentially have to
Chris@16 170 // regenerate the entire graph.
Chris@16 171 const bool has_stable_descriptors =
Chris@16 172 is_same<typename config_type::vertex_list_selector, listS>::value
Chris@16 173 || is_same<typename config_type::vertex_list_selector, setS>::value
Chris@16 174 || is_same<typename config_type::vertex_list_selector, multisetS>::value;
Chris@16 175
Chris@16 176 typedef detail::parallel::redistributed_descriptor<vertex_descriptor,
Chris@16 177 vertex_property_type>
Chris@16 178 redistributed_vertex;
Chris@16 179 typedef detail::parallel::redistributed_descriptor<edge_descriptor,
Chris@16 180 edge_property_type>
Chris@16 181 redistributed_edge;
Chris@16 182
Chris@16 183 vertex_iterator vi, vi_end;
Chris@16 184 edge_iterator ei, ei_end;
Chris@16 185
Chris@16 186 process_group_type pg = process_group();
Chris@16 187
Chris@16 188 // Initial synchronization makes sure that we have all of our ducks
Chris@16 189 // in a row. We don't want any outstanding add/remove messages
Chris@16 190 // coming in mid-redistribution!
Chris@16 191 synchronize(process_group_);
Chris@16 192
Chris@16 193 // We cannot cope with eviction of ghost cells
Chris@16 194 vertex_to_processor.set_max_ghost_cells(0);
Chris@16 195
Chris@16 196 process_id_type p = num_processes(pg);
Chris@16 197
Chris@16 198 // Send vertices and edges to the processor where they will
Chris@16 199 // actually reside. This requires O(|V| + |E|) communication
Chris@16 200 std::vector<std::vector<redistributed_vertex> > redistributed_vertices(p);
Chris@16 201 std::vector<std::vector<redistributed_edge> > redistributed_edges(p);
Chris@16 202
Chris@16 203 // Build the sets of relocated vertices for each process and then do
Chris@16 204 // an all-to-all transfer.
Chris@16 205 for (boost::tie(vi, vi_end) = vertices(*this); vi != vi_end; ++vi) {
Chris@16 206 if (!has_stable_descriptors
Chris@16 207 || get(vertex_to_processor, *vi) != vi->owner) {
Chris@16 208 redistributed_vertices[get(vertex_to_processor, *vi)]
Chris@16 209 .push_back(redistributed_vertex(*vi, get(vertex_all_t(), base(),
Chris@16 210 vi->local)));
Chris@16 211 }
Chris@16 212
Chris@16 213 // When our descriptors are stable, we need to determine which
Chris@16 214 // adjacent descriptors are stable to determine which edges will
Chris@16 215 // be removed.
Chris@16 216 if (has_stable_descriptors) {
Chris@16 217 BGL_FORALL_OUTEDGES_T(*vi, e, *this, graph_type)
Chris@16 218 request(vertex_to_processor, target(e, *this));
Chris@16 219 request_in_neighbors(*vi, vertex_to_processor, directed_selector());
Chris@16 220 }
Chris@16 221 }
Chris@16 222
Chris@16 223 inplace_all_to_all(pg, redistributed_vertices);
Chris@16 224
Chris@16 225 // If we have stable descriptors, we need to know where our neighbor
Chris@16 226 // vertices are moving.
Chris@16 227 if (has_stable_descriptors)
Chris@16 228 synchronize(vertex_to_processor);
Chris@16 229
Chris@16 230 // Build the sets of relocated edges for each process and then do
Chris@16 231 // an all-to-all transfer.
Chris@16 232 for (boost::tie(ei, ei_end) = edges(*this); ei != ei_end; ++ei) {
Chris@16 233 vertex_descriptor src = source(*ei, *this);
Chris@16 234 vertex_descriptor tgt = target(*ei, *this);
Chris@16 235 if (!has_stable_descriptors
Chris@16 236 || get(vertex_to_processor, src) != src.owner
Chris@16 237 || get(vertex_to_processor, tgt) != tgt.owner)
Chris@16 238 redistributed_edges[get(vertex_to_processor, source(*ei, *this))]
Chris@16 239 .push_back(redistributed_edge(*ei, split_edge_property(get(edge_all_t(), base(),
Chris@16 240 ei->local))));
Chris@16 241 }
Chris@16 242 inplace_all_to_all(pg, redistributed_edges);
Chris@16 243
Chris@16 244 // A mapping from old vertex descriptors to new vertex
Chris@16 245 // descriptors. This is an STL map partly because I'm too lazy to
Chris@16 246 // build a real property map (which is hard in the general case) but
Chris@16 247 // also because it won't try to look in the graph itself, because
Chris@16 248 // the keys are all vertex descriptors that have been invalidated.
Chris@16 249 std::map<vertex_descriptor, vertex_descriptor> old_to_new_vertex_map;
Chris@16 250
Chris@16 251 if (has_stable_descriptors) {
Chris@16 252 // Clear out all vertices and edges that will have moved. There
Chris@16 253 // are several stages to this.
Chris@16 254
Chris@16 255 // First, eliminate all outgoing edges from the (local) vertices
Chris@16 256 // that have been moved or whose targets have been moved.
Chris@16 257 BGL_FORALL_VERTICES_T(v, *this, graph_type) {
Chris@16 258 if (get(vertex_to_processor, v) != v.owner) {
Chris@16 259 clear_out_edges(v.local, base());
Chris@16 260 clear_in_edges_local(v, directed_selector());
Chris@16 261 } else {
Chris@16 262 remove_out_edge_if(v.local,
Chris@16 263 target_migrated(vertex_to_processor, base()),
Chris@16 264 base());
Chris@16 265 remove_migrated_in_edges(v, vertex_to_processor, directed_selector());
Chris@16 266 }
Chris@16 267 }
Chris@16 268
Chris@16 269 // Next, eliminate locally-stored edges that have migrated (for
Chris@16 270 // undirected graphs).
Chris@16 271 graph_detail::erase_if(local_edges_,
Chris@16 272 source_or_target_migrated(vertex_to_processor, *this));
Chris@16 273
Chris@16 274 // Eliminate vertices that have migrated
Chris@16 275 for (boost::tie(vi, vi_end) = vertices(*this); vi != vi_end; /* in loop */) {
Chris@16 276 if (get(vertex_to_processor, *vi) != vi->owner)
Chris@16 277 remove_vertex((*vi++).local, base());
Chris@16 278 else {
Chris@16 279 // Add the identity relation for vertices that have not migrated
Chris@16 280 old_to_new_vertex_map[*vi] = *vi;
Chris@16 281 ++vi;
Chris@16 282 }
Chris@16 283 }
Chris@16 284 } else {
Chris@16 285 // Clear out the local graph: the entire graph is in transit
Chris@16 286 clear();
Chris@16 287 }
Chris@16 288
Chris@16 289 // Add the new vertices to the graph. When we do so, update the old
Chris@16 290 // -> new vertex mapping both locally and for the owner of the "old"
Chris@16 291 // vertex.
Chris@16 292 {
Chris@16 293 typedef std::pair<vertex_descriptor, vertex_descriptor> mapping_pair;
Chris@16 294 std::vector<std::vector<mapping_pair> > mappings(p);
Chris@16 295
Chris@16 296 for (process_id_type src = 0; src < p; ++src) {
Chris@16 297 for (typename std::vector<redistributed_vertex>::iterator vi =
Chris@16 298 redistributed_vertices[src].begin();
Chris@16 299 vi != redistributed_vertices[src].end(); ++vi) {
Chris@16 300 vertex_descriptor new_vertex =
Chris@16 301 add_vertex(vi->get_property(), *this);
Chris@16 302 old_to_new_vertex_map[vi->descriptor] = new_vertex;
Chris@16 303 mappings[vi->descriptor.owner].push_back(mapping_pair(vi->descriptor,
Chris@16 304 new_vertex));
Chris@16 305 }
Chris@16 306
Chris@16 307 redistributed_vertices[src].clear();
Chris@16 308 }
Chris@16 309
Chris@16 310 inplace_all_to_all(pg, mappings);
Chris@16 311
Chris@16 312 // Add the mappings we were sent into the old->new map.
Chris@16 313 for (process_id_type src = 0; src < p; ++src)
Chris@16 314 old_to_new_vertex_map.insert(mappings[src].begin(), mappings[src].end());
Chris@16 315 }
Chris@16 316
Chris@16 317 // Get old->new vertex mappings for all of the vertices we need to
Chris@16 318 // know about.
Chris@16 319
Chris@16 320 // TBD: An optimization here might involve sending the
Chris@16 321 // request-response pairs without an explicit request step (for
Chris@16 322 // bidirectional and undirected graphs). However, it may not matter
Chris@16 323 // all that much given the cost of redistribution.
Chris@16 324 {
Chris@16 325 std::vector<std::vector<vertex_descriptor> > vertex_map_requests(p);
Chris@16 326 std::vector<std::vector<vertex_descriptor> > vertex_map_responses(p);
Chris@16 327
Chris@16 328 // We need to know about all of the vertices incident on edges
Chris@16 329 // that have been relocated to this processor. Tell each processor
Chris@16 330 // what each other processor needs to know.
Chris@16 331 for (process_id_type src = 0; src < p; ++src)
Chris@16 332 for (typename std::vector<redistributed_edge>::iterator ei =
Chris@16 333 redistributed_edges[src].begin();
Chris@16 334 ei != redistributed_edges[src].end(); ++ei) {
Chris@16 335 vertex_descriptor need_vertex = target(ei->descriptor, *this);
Chris@16 336 if (old_to_new_vertex_map.find(need_vertex)
Chris@16 337 == old_to_new_vertex_map.end())
Chris@16 338 {
Chris@16 339 old_to_new_vertex_map[need_vertex] = need_vertex;
Chris@16 340 vertex_map_requests[need_vertex.owner].push_back(need_vertex);
Chris@16 341 }
Chris@16 342 }
Chris@16 343 inplace_all_to_all(pg,
Chris@16 344 vertex_map_requests,
Chris@16 345 vertex_map_responses);
Chris@16 346
Chris@16 347 // Process the requests made for vertices we own. Then perform yet
Chris@16 348 // another all-to-all swap. This one matches the requests we've
Chris@16 349 // made to the responses we were given.
Chris@16 350 for (process_id_type src = 0; src < p; ++src)
Chris@16 351 for (typename std::vector<vertex_descriptor>::iterator vi =
Chris@16 352 vertex_map_responses[src].begin();
Chris@16 353 vi != vertex_map_responses[src].end(); ++vi)
Chris@16 354 *vi = old_to_new_vertex_map[*vi];
Chris@16 355 inplace_all_to_all(pg, vertex_map_responses);
Chris@16 356
Chris@16 357 // Matching the requests to the responses, update the old->new
Chris@16 358 // vertex map for all of the vertices we will need to know.
Chris@16 359 for (process_id_type src = 0; src < p; ++src) {
Chris@16 360 typedef typename std::vector<vertex_descriptor>::size_type size_type;
Chris@16 361 for (size_type i = 0; i < vertex_map_requests[src].size(); ++i) {
Chris@16 362 old_to_new_vertex_map[vertex_map_requests[src][i]] =
Chris@16 363 vertex_map_responses[src][i];
Chris@16 364 }
Chris@16 365 }
Chris@16 366 }
Chris@16 367
Chris@16 368 // Add edges to the graph by mapping the source and target.
Chris@16 369 for (process_id_type src = 0; src < p; ++src) {
Chris@16 370 for (typename std::vector<redistributed_edge>::iterator ei =
Chris@16 371 redistributed_edges[src].begin();
Chris@16 372 ei != redistributed_edges[src].end(); ++ei) {
Chris@16 373 add_edge(old_to_new_vertex_map[source(ei->descriptor, *this)],
Chris@16 374 old_to_new_vertex_map[target(ei->descriptor, *this)],
Chris@16 375 ei->get_property(),
Chris@16 376 *this);
Chris@16 377 }
Chris@16 378
Chris@16 379 redistributed_edges[src].clear();
Chris@16 380 }
Chris@16 381
Chris@16 382 // Be sure that edge-addition messages are received now, completing
Chris@16 383 // the graph.
Chris@16 384 synchronize(process_group_);
Chris@16 385
Chris@16 386 this->distribution().clear();
Chris@16 387
Chris@16 388 detail::parallel::maybe_initialize_vertex_indices(vertices(base()),
Chris@16 389 get(vertex_index, base()));
Chris@16 390 }
Chris@16 391
Chris@16 392 } // end namespace boost