Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:37:12

0001 // Copyright (C) 2005-2006 The Trustees of Indiana University.
0002 
0003 // Use, modification and distribution is subject to the Boost Software
0004 // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0005 // http://www.boost.org/LICENSE_1_0.txt)
0006 
0007 //  Authors: Douglas Gregor
0008 //           Andrew Lumsdaine
0009 
0010 //
0011 // Implements redistribution of vertices for a distributed adjacency
0012 // list. This file should not be included by users. It will be
0013 // included by the distributed adjacency list header.
0014 //
0015 
0016 #ifndef BOOST_GRAPH_USE_MPI
0017 #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
0018 #endif
0019 
0020 #include <boost/pending/container_traits.hpp>
0021 
0022 namespace boost { namespace detail { namespace parallel {
0023 
0024 /* This structure contains a (vertex or edge) descriptor that is being
0025    moved from one processor to another. It contains the properties for
0026    that descriptor (if any).
0027  */
0028 template<typename Descriptor, typename DescriptorProperty>
0029 struct redistributed_descriptor : maybe_store_property<DescriptorProperty>
0030 {
0031   typedef maybe_store_property<DescriptorProperty> inherited;
0032 
0033   redistributed_descriptor() { }
0034 
0035   redistributed_descriptor(const Descriptor& v, const DescriptorProperty& p)
0036     : inherited(p), descriptor(v) { }
0037 
0038   Descriptor descriptor;
0039 
0040 private:
0041   friend class boost::serialization::access;
0042 
0043   template<typename Archiver>
0044   void serialize(Archiver& ar, unsigned int /*version*/)
0045   {
0046     ar & boost::serialization::base_object<inherited>(*this) 
0047        & unsafe_serialize(descriptor);
0048   }
0049 };
0050 
0051 /* Predicate that returns true if the target has migrated. */
0052 template<typename VertexProcessorMap, typename Graph>
0053 struct target_migrated_t
0054 {
0055   typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
0056   typedef typename graph_traits<Graph>::edge_descriptor Edge;
0057 
0058   target_migrated_t(VertexProcessorMap vertex_to_processor, const Graph& g)
0059     : vertex_to_processor(vertex_to_processor), g(g) { }
0060 
0061   bool operator()(Edge e) const
0062   {
0063     typedef global_descriptor<Vertex> DVertex;
0064     processor_id_type owner = get(edge_target_processor_id, g, e);
0065     return get(vertex_to_processor, DVertex(owner, target(e, g))) != owner;
0066   }
0067 
0068 private:
0069   VertexProcessorMap vertex_to_processor;
0070   const Graph& g;
0071 };
0072 
0073 template<typename VertexProcessorMap, typename Graph>
0074 inline target_migrated_t<VertexProcessorMap, Graph>
0075 target_migrated(VertexProcessorMap vertex_to_processor, const Graph& g)
0076 { return target_migrated_t<VertexProcessorMap, Graph>(vertex_to_processor, g); }
0077 
0078 /* Predicate that returns true if the source of an in-edge has migrated. */
0079 template<typename VertexProcessorMap, typename Graph>
0080 struct source_migrated_t
0081 {
0082   typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
0083   typedef typename graph_traits<Graph>::edge_descriptor Edge;
0084 
0085   source_migrated_t(VertexProcessorMap vertex_to_processor, const Graph& g)
0086     : vertex_to_processor(vertex_to_processor), g(g) { }
0087 
0088   bool operator()(stored_in_edge<Edge> e) const
0089   {
0090     return get(vertex_to_processor, DVertex(e.source_processor, source(e.e, g)))
0091       != e.source_processor;
0092   }
0093 
0094 private:
0095   VertexProcessorMap vertex_to_processor;
0096   const Graph& g;
0097 };
0098 
0099 template<typename VertexProcessorMap, typename Graph>
0100 inline source_migrated_t<VertexProcessorMap, Graph>
0101 source_migrated(VertexProcessorMap vertex_to_processor, const Graph& g)
0102 { return source_migrated_t<VertexProcessorMap, Graph>(vertex_to_processor, g); }
0103 
0104 /* Predicate that returns true if the target has migrated. */
0105 template<typename VertexProcessorMap, typename Graph>
0106 struct source_or_target_migrated_t
0107 {
0108   typedef typename graph_traits<Graph>::edge_descriptor Edge;
0109 
0110   source_or_target_migrated_t(VertexProcessorMap vertex_to_processor,
0111                               const Graph& g)
0112     : vertex_to_processor(vertex_to_processor), g(g) { }
0113 
0114   bool operator()(Edge e) const
0115   {
0116     return get(vertex_to_processor, source(e, g)) != source(e, g).owner
0117       || get(vertex_to_processor, target(e, g)) != target(e, g).owner;
0118   }
0119 
0120 private:
0121   VertexProcessorMap vertex_to_processor;
0122   const Graph& g;
0123 };
0124 
0125 template<typename VertexProcessorMap, typename Graph>
0126 inline source_or_target_migrated_t<VertexProcessorMap, Graph>
0127 source_or_target_migrated(VertexProcessorMap vertex_to_processor,
0128 const Graph& g)
0129 {
0130   typedef source_or_target_migrated_t<VertexProcessorMap, Graph> result_type;
0131   return result_type(vertex_to_processor, g);
0132 }
0133 
0134 } } // end of namespace detail::parallel
0135 
0136 template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
0137 template<typename VertexProcessorMap>
0138 void
0139 PBGL_DISTRIB_ADJLIST_TYPE
0140 ::request_in_neighbors(vertex_descriptor v,
0141                        VertexProcessorMap vertex_to_processor,
0142                        bidirectionalS)
0143 {
0144   BGL_FORALL_INEDGES_T(v, e, *this, graph_type)
0145     request(vertex_to_processor, source(e, *this));
0146 }
0147 
0148 template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
0149 template<typename VertexProcessorMap>
0150 void
0151 PBGL_DISTRIB_ADJLIST_TYPE
0152 ::remove_migrated_in_edges(vertex_descriptor v,
0153                            VertexProcessorMap vertex_to_processor,
0154                            bidirectionalS)
0155 {
0156   graph_detail::erase_if(get(vertex_in_edges, base())[v.local],
0157                          source_migrated(vertex_to_processor, base()));
0158 }
0159 
0160 template<PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
0161 template<typename VertexProcessorMap>
0162 void
0163 PBGL_DISTRIB_ADJLIST_TYPE
0164 ::redistribute(VertexProcessorMap vertex_to_processor)
0165 {
0166   using boost::parallel::inplace_all_to_all;
0167 
0168   // When we have stable descriptors, we only move those descriptors
0169   // that actually need to be moved. Otherwise, we essentially have to
0170   // regenerate the entire graph.
0171   const bool has_stable_descriptors =
0172     is_same<typename config_type::vertex_list_selector, listS>::value
0173     || is_same<typename config_type::vertex_list_selector, setS>::value
0174     || is_same<typename config_type::vertex_list_selector, multisetS>::value;
0175 
0176   typedef detail::parallel::redistributed_descriptor<vertex_descriptor, 
0177                                                      vertex_property_type>
0178     redistributed_vertex;
0179   typedef detail::parallel::redistributed_descriptor<edge_descriptor, 
0180                                                      edge_property_type>
0181     redistributed_edge;
0182 
0183   vertex_iterator vi, vi_end;
0184   edge_iterator ei, ei_end;
0185 
0186   process_group_type pg = process_group();
0187 
0188   // Initial synchronization makes sure that we have all of our ducks
0189   // in a row. We don't want any outstanding add/remove messages
0190   // coming in mid-redistribution!
0191   synchronize(process_group_);
0192 
0193   // We cannot cope with eviction of ghost cells
0194   vertex_to_processor.set_max_ghost_cells(0);
0195 
0196   process_id_type p = num_processes(pg);
0197 
0198   // Send vertices and edges to the processor where they will
0199   // actually reside.  This requires O(|V| + |E|) communication
0200   std::vector<std::vector<redistributed_vertex> > redistributed_vertices(p);
0201   std::vector<std::vector<redistributed_edge> > redistributed_edges(p);
0202 
0203   // Build the sets of relocated vertices for each process and then do
0204   // an all-to-all transfer.
0205   for (boost::tie(vi, vi_end) = vertices(*this); vi != vi_end; ++vi) {
0206     if (!has_stable_descriptors
0207         || get(vertex_to_processor, *vi) != vi->owner) {
0208       redistributed_vertices[get(vertex_to_processor, *vi)]
0209         .push_back(redistributed_vertex(*vi, get(vertex_all_t(), base(),
0210                                                  vi->local)));
0211     }
0212 
0213     // When our descriptors are stable, we need to determine which
0214     // adjacent descriptors are stable to determine which edges will
0215     // be removed.
0216     if (has_stable_descriptors) {
0217       BGL_FORALL_OUTEDGES_T(*vi, e, *this, graph_type)
0218         request(vertex_to_processor, target(e, *this));
0219       request_in_neighbors(*vi, vertex_to_processor, directed_selector());
0220     }
0221   }
0222 
0223   inplace_all_to_all(pg, redistributed_vertices);
0224 
0225   // If we have stable descriptors, we need to know where our neighbor
0226   // vertices are moving.
0227   if (has_stable_descriptors)
0228     synchronize(vertex_to_processor);
0229 
0230   // Build the sets of relocated edges for each process and then do
0231   // an all-to-all transfer.
0232   for (boost::tie(ei, ei_end) = edges(*this); ei != ei_end; ++ei) {
0233     vertex_descriptor src = source(*ei, *this);
0234     vertex_descriptor tgt = target(*ei, *this);
0235     if (!has_stable_descriptors
0236         || get(vertex_to_processor, src) != src.owner
0237         || get(vertex_to_processor, tgt) != tgt.owner)
0238       redistributed_edges[get(vertex_to_processor, source(*ei, *this))]
0239         .push_back(redistributed_edge(*ei, split_edge_property(get(edge_all_t(), base(),
0240                                                                    ei->local))));
0241   }
0242   inplace_all_to_all(pg, redistributed_edges);
0243 
0244   // A mapping from old vertex descriptors to new vertex
0245   // descriptors. This is an STL map partly because I'm too lazy to
0246   // build a real property map (which is hard in the general case) but
0247   // also because it won't try to look in the graph itself, because
0248   // the keys are all vertex descriptors that have been invalidated.
0249   std::map<vertex_descriptor, vertex_descriptor> old_to_new_vertex_map;
0250 
0251   if (has_stable_descriptors) {
0252     // Clear out all vertices and edges that will have moved. There
0253     // are several stages to this.
0254 
0255     // First, eliminate all outgoing edges from the (local) vertices
0256     // that have been moved or whose targets have been moved.
0257     BGL_FORALL_VERTICES_T(v, *this, graph_type) {
0258       if (get(vertex_to_processor, v) != v.owner) {
0259         clear_out_edges(v.local, base());
0260         clear_in_edges_local(v, directed_selector());
0261       } else {
0262         remove_out_edge_if(v.local,
0263                            target_migrated(vertex_to_processor, base()),
0264                            base());
0265         remove_migrated_in_edges(v, vertex_to_processor, directed_selector());
0266       }
0267     }
0268 
0269     // Next, eliminate locally-stored edges that have migrated (for
0270     // undirected graphs).
0271     graph_detail::erase_if(local_edges_,
0272                            source_or_target_migrated(vertex_to_processor, *this));
0273 
0274     // Eliminate vertices that have migrated
0275     for (boost::tie(vi, vi_end) = vertices(*this); vi != vi_end; /* in loop */) {
0276       if (get(vertex_to_processor, *vi) != vi->owner)
0277         remove_vertex((*vi++).local, base());
0278       else {
0279         // Add the identity relation for vertices that have not migrated
0280         old_to_new_vertex_map[*vi] = *vi;
0281         ++vi;
0282       }
0283     }
0284   } else {
0285     // Clear out the local graph: the entire graph is in transit
0286     clear();
0287   }
0288 
0289   // Add the new vertices to the graph. When we do so, update the old
0290   // -> new vertex mapping both locally and for the owner of the "old"
0291   // vertex.
0292   {
0293     typedef std::pair<vertex_descriptor, vertex_descriptor> mapping_pair;
0294     std::vector<std::vector<mapping_pair> > mappings(p);
0295 
0296     for (process_id_type src = 0; src < p; ++src) {
0297       for (typename std::vector<redistributed_vertex>::iterator vi =
0298              redistributed_vertices[src].begin();
0299            vi != redistributed_vertices[src].end(); ++vi) {
0300         vertex_descriptor new_vertex =
0301             add_vertex(vi->get_property(), *this);
0302         old_to_new_vertex_map[vi->descriptor] = new_vertex;
0303         mappings[vi->descriptor.owner].push_back(mapping_pair(vi->descriptor,
0304                                                               new_vertex));
0305       }
0306 
0307       redistributed_vertices[src].clear();
0308     }
0309 
0310     inplace_all_to_all(pg, mappings);
0311 
0312     // Add the mappings we were sent into the old->new map.
0313     for (process_id_type src = 0; src < p; ++src)
0314       old_to_new_vertex_map.insert(mappings[src].begin(), mappings[src].end());
0315   }
0316 
0317   // Get old->new vertex mappings for all of the vertices we need to
0318   // know about.
0319 
0320   // TBD: An optimization here might involve sending the
0321   // request-response pairs without an explicit request step (for
0322   // bidirectional and undirected graphs). However, it may not matter
0323   // all that much given the cost of redistribution.
0324   {
0325     std::vector<std::vector<vertex_descriptor> > vertex_map_requests(p);
0326     std::vector<std::vector<vertex_descriptor> > vertex_map_responses(p);
0327 
0328     // We need to know about all of the vertices incident on edges
0329     // that have been relocated to this processor. Tell each processor
0330     // what each other processor needs to know.
0331     for (process_id_type src = 0; src < p; ++src)
0332       for (typename std::vector<redistributed_edge>::iterator ei =
0333              redistributed_edges[src].begin();
0334            ei != redistributed_edges[src].end(); ++ei) {
0335         vertex_descriptor need_vertex = target(ei->descriptor, *this);
0336         if (old_to_new_vertex_map.find(need_vertex)
0337             == old_to_new_vertex_map.end())
0338           {
0339             old_to_new_vertex_map[need_vertex] = need_vertex;
0340             vertex_map_requests[need_vertex.owner].push_back(need_vertex);
0341           }
0342       }
0343     inplace_all_to_all(pg,
0344                        vertex_map_requests,
0345                        vertex_map_responses);
0346 
0347     // Process the requests made for vertices we own. Then perform yet
0348     // another all-to-all swap. This one matches the requests we've
0349     // made to the responses we were given.
0350     for (process_id_type src = 0; src < p; ++src)
0351       for (typename std::vector<vertex_descriptor>::iterator vi =
0352              vertex_map_responses[src].begin();
0353            vi != vertex_map_responses[src].end(); ++vi)
0354         *vi = old_to_new_vertex_map[*vi];
0355     inplace_all_to_all(pg, vertex_map_responses);
0356 
0357     // Matching the requests to the responses, update the old->new
0358     // vertex map for all of the vertices we will need to know.
0359     for (process_id_type src = 0; src < p; ++src) {
0360       typedef typename std::vector<vertex_descriptor>::size_type size_type;
0361       for (size_type i = 0; i < vertex_map_requests[src].size(); ++i) {
0362         old_to_new_vertex_map[vertex_map_requests[src][i]] =
0363           vertex_map_responses[src][i];
0364       }
0365     }
0366   }
0367 
0368   // Add edges to the graph by mapping the source and target.
0369   for (process_id_type src = 0; src < p; ++src) {
0370     for (typename std::vector<redistributed_edge>::iterator ei =
0371            redistributed_edges[src].begin();
0372          ei != redistributed_edges[src].end(); ++ei) {
0373       add_edge(old_to_new_vertex_map[source(ei->descriptor, *this)],
0374                old_to_new_vertex_map[target(ei->descriptor, *this)],
0375                ei->get_property(),
0376                *this);
0377     }
0378 
0379     redistributed_edges[src].clear();
0380   }
0381 
0382   // Be sure that edge-addition messages are received now, completing
0383   // the graph.
0384   synchronize(process_group_);
0385 
0386   this->distribution().clear();
0387 
0388   detail::parallel::maybe_initialize_vertex_indices(vertices(base()), 
0389                                                     get(vertex_index, base()));
0390 }
0391 
0392 } // end namespace boost