Back to home page

EIC code displayed by LXR

 
 

    


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

0001 // Copyright Daniel Wallin 2007. Use, modification and distribution is
0002 // subject to the Boost Software License, Version 1.0. (See accompanying
0003 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0004 
0005 #ifndef BOOST_GRAPH_DISTRIBUTED_ADJLIST_SERIALIZATION_070925_HPP
0006 #define BOOST_GRAPH_DISTRIBUTED_ADJLIST_SERIALIZATION_070925_HPP
0007 
0008 #ifndef BOOST_GRAPH_USE_MPI
0009 #error "Parallel BGL files should not be included unless <boost/graph/use_mpi.hpp> has been included"
0010 #endif
0011 
0012 # include <boost/assert.hpp>
0013 # include <boost/lexical_cast.hpp>
0014 # include <boost/foreach.hpp>
0015 # include <boost/filesystem/path.hpp>
0016 # include <boost/filesystem/operations.hpp>
0017 # include <cctype>
0018 # include <fstream>
0019 
0020 namespace boost {
0021 
0022 namespace detail { namespace parallel
0023 {
0024 
0025   // Wraps a local descriptor, making it serializable.
0026   template <class Local>
0027   struct serializable_local_descriptor
0028   {
0029       serializable_local_descriptor()
0030       {}
0031 
0032       serializable_local_descriptor(Local local)
0033         : local(local)
0034       {}
0035 
0036       operator Local const&() const
0037       {
0038           return local;
0039       }
0040 
0041       bool operator==(serializable_local_descriptor const& other) const
0042       {
0043           return local == other.local;
0044       }
0045 
0046       bool operator<(serializable_local_descriptor const& other) const
0047       {
0048           return local < other.local;
0049       }
0050 
0051       template <class Archive>
0052       void serialize(Archive& ar, const unsigned int /*version*/)
0053       {
0054           ar & unsafe_serialize(local);
0055       }
0056 
0057       Local local;
0058   };
0059 
0060   template <class Vertex, class Properties>
0061   struct pending_edge
0062   {
0063       pending_edge(
0064           Vertex source, Vertex target
0065         , Properties properties, void* property_ptr
0066       )
0067         : source(source)
0068         , target(target)
0069         , properties(properties)
0070         , property_ptr(property_ptr)
0071       {}
0072 
0073       Vertex source;
0074       Vertex target;
0075       Properties properties;
0076       void* property_ptr;
0077   };
0078 
0079   inline bool is_digit(char c)
0080   {
0081       return std::isdigit(c) != 0;
0082   }
0083 
0084   inline std::vector<int> 
0085       available_process_files(std::string const& filename)
0086       {
0087           if (!filesystem::exists(filename))
0088               return std::vector<int>();
0089 
0090           std::vector<int> result;
0091 
0092           for (filesystem::directory_iterator i(filename), end; i != end; ++i)
0093           {
0094               if (!filesystem::is_regular(*i))
0095                   boost::throw_exception(std::runtime_error("directory contains non-regular entries"));
0096 
0097               std::string process_name = i->path().filename().string();
0098               for (std::string::size_type i = 0; i < process_name.size(); ++i)
0099                 if (!is_digit(process_name[i]))
0100                   boost::throw_exception(std::runtime_error("directory contains files with invalid names"));
0101 
0102               result.push_back(boost::lexical_cast<int>(process_name));
0103           }
0104 
0105           return result;
0106       }
0107 
0108   template <class Archive, class Tag, class T, class Base>
0109   void maybe_load_properties(
0110       Archive& ar, char const* name, property<Tag, T, Base>& properties)
0111   {
0112       ar >> serialization::make_nvp(name, get_property_value(properties, Tag()));
0113       maybe_load_properties(ar, name, static_cast<Base&>(properties));
0114   }
0115 
0116   template <class Archive>
0117   void maybe_load_properties(
0118       Archive&, char const*, no_property&)
0119   {}
0120 
0121   template <class Archive, typename Bundle>
0122   void maybe_load_properties(
0123       Archive& ar, char const* name, Bundle& bundle)
0124   {
0125     ar >> serialization::make_nvp(name, bundle);
0126     no_property prop;
0127     maybe_load_properties(ar, name, prop);
0128   }
0129 
0130 
0131 
0132 
0133 
0134 
0135   template <class Graph, class Archive, class VertexListS>
0136   struct graph_loader
0137   {
0138       typedef typename Graph::vertex_descriptor vertex_descriptor;
0139       typedef typename Graph::local_vertex_descriptor local_vertex_descriptor;
0140       typedef typename Graph::vertex_property_type vertex_property_type;
0141       typedef typename Graph::edge_descriptor edge_descriptor;
0142       typedef typename Graph::local_edge_descriptor local_edge_descriptor;
0143       typedef typename Graph::edge_property_type edge_property_type;
0144       typedef typename Graph::process_group_type process_group_type;
0145       typedef typename process_group_type::process_id_type process_id_type;
0146       typedef typename Graph::directed_selector directed_selector;
0147       typedef typename mpl::if_<
0148           is_same<VertexListS, defaultS>, vecS, VertexListS
0149       >::type vertex_list_selector;
0150       typedef pending_edge<vertex_descriptor, edge_property_type> 
0151           pending_edge_type; 
0152       typedef serializable_local_descriptor<local_vertex_descriptor>
0153           serializable_vertex_descriptor;
0154 
0155       graph_loader(Graph& g, Archive& ar)
0156         : m_g(g)
0157         , m_ar(ar)
0158         , m_pg(g.process_group())
0159         , m_requested_vertices(num_processes(m_pg))
0160         , m_remote_vertices(num_processes(m_pg))
0161         , m_property_ptrs(num_processes(m_pg))
0162       {
0163           g.clear();
0164           load_prefix();
0165           load_vertices();
0166           load_edges();
0167           ar >> make_nvp("distribution", m_g.distribution());
0168       }
0169 
0170   private:
0171       struct pending_in_edge
0172       {
0173           pending_in_edge(
0174               vertex_descriptor u, vertex_descriptor v, void* property_ptr
0175           )
0176             : u(u)
0177             , v(v)
0178             , property_ptr(property_ptr)
0179           {}
0180 
0181           vertex_descriptor u;
0182           vertex_descriptor v;
0183           void* property_ptr;
0184       };
0185 
0186       bool is_root() const
0187       {
0188           return process_id(m_pg) == 0;
0189       }
0190 
0191       template <class T>
0192       serialization::nvp<T> const make_nvp(char const* name, T& value) const
0193       {
0194           return serialization::nvp<T>(name, value);
0195       }
0196 
0197       void load_prefix();
0198       void load_vertices();
0199 
0200       template <class Anything>
0201       void maybe_load_and_store_local_vertex(Anything);
0202       void maybe_load_and_store_local_vertex(vecS);
0203 
0204       void load_edges();
0205       void load_in_edges(bidirectionalS);
0206       void load_in_edges(directedS);
0207       void add_pending_in_edge(
0208           vertex_descriptor u, vertex_descriptor v, void* property_ptr, vecS);
0209       template <class Anything>
0210       void add_pending_in_edge(
0211           vertex_descriptor u, vertex_descriptor v, void* property_ptr, Anything);
0212       template <class Anything>
0213       void add_edge(
0214           vertex_descriptor u, vertex_descriptor v
0215         , edge_property_type const& property, void* property_ptr, Anything);
0216       void add_edge(
0217           vertex_descriptor u, vertex_descriptor v
0218         , edge_property_type const& property, void* property_ptr, vecS);
0219       void add_remote_vertex_request(
0220           vertex_descriptor u, vertex_descriptor v, directedS);
0221       void add_remote_vertex_request(
0222           vertex_descriptor u, vertex_descriptor v, bidirectionalS);
0223       void add_in_edge(
0224           edge_descriptor const&, void*, directedS);
0225       void add_in_edge(
0226           edge_descriptor const& edge, void* old_property_ptr, bidirectionalS);
0227 
0228       void resolve_remote_vertices(directedS);
0229       void resolve_remote_vertices(bidirectionalS);
0230       vertex_descriptor resolve_remote_vertex(vertex_descriptor u) const;
0231       vertex_descriptor resolve_remote_vertex(vertex_descriptor u, vecS) const;
0232       template <class Anything>
0233       vertex_descriptor resolve_remote_vertex(vertex_descriptor u, Anything) const;
0234 
0235       void resolve_property_ptrs();
0236 
0237       void commit_pending_edges(vecS);
0238       template <class Anything>
0239       void commit_pending_edges(Anything);
0240       void commit_pending_in_edges(directedS);
0241       void commit_pending_in_edges(bidirectionalS);
0242 
0243       void* maybe_load_property_ptr(directedS) { return 0; }
0244       void* maybe_load_property_ptr(bidirectionalS);
0245 
0246       Graph& m_g;
0247       Archive& m_ar;
0248       process_group_type m_pg;
0249 
0250       std::vector<process_id_type> m_id_mapping;
0251 
0252       // Maps local vertices as loaded from the archive to
0253       // the ones actually added to the graph. Only used 
0254       // when !vecS.
0255       std::map<local_vertex_descriptor, local_vertex_descriptor> m_local_vertices;
0256 
0257       // This is the list of remote vertex descriptors that we
0258       // are going to receive from other processes. This is
0259       // kept sorted so that we can determine the position of
0260       // the matching vertex descriptor in m_remote_vertices.
0261       std::vector<std::vector<serializable_vertex_descriptor> > m_requested_vertices;
0262 
0263       // This is the list of remote vertex descriptors that
0264       // we send and receive from other processes.
0265       std::vector<std::vector<serializable_vertex_descriptor> > m_remote_vertices;
0266 
0267       // ...
0268       std::vector<pending_edge_type> m_pending_edges;
0269 
0270       // The pending in-edges that will be added in the commit step, after
0271       // the remote vertex descriptors has been resolved. Only used
0272       // when bidirectionalS and !vecS.
0273       std::vector<pending_in_edge> m_pending_in_edges;
0274 
0275       std::vector<std::vector<unsafe_pair<void*,void*> > > m_property_ptrs;
0276   };
0277 
0278   template <class Graph, class Archive, class VertexListS>
0279   void graph_loader<Graph, Archive, VertexListS>::load_prefix()
0280   {
0281       typename process_group_type::process_size_type num_processes_;
0282       m_ar >> make_nvp("num_processes", num_processes_);
0283 
0284       if (num_processes_ != num_processes(m_pg))
0285           boost::throw_exception(std::runtime_error("number of processes mismatch"));
0286 
0287       process_id_type old_id;
0288       m_ar >> make_nvp("id", old_id);
0289 
0290       std::vector<typename Graph::distribution_type::size_type> mapping;
0291       m_ar >> make_nvp("mapping", mapping);
0292 
0293       // Fetch all the old id's from the other processes.
0294       std::vector<process_id_type> old_ids;
0295       all_gather(m_pg, &old_id, &old_id+1, old_ids);
0296 
0297       m_id_mapping.resize(num_processes(m_pg), -1);
0298 
0299       for (process_id_type i = 0; i < num_processes(m_pg); ++i)
0300       {
0301 # ifdef PBGL_SERIALIZE_DEBUG
0302           if (is_root())
0303               std::cout << i << " used to be " << old_ids[i] << "\n"; 
0304 # endif
0305           BOOST_ASSERT(m_id_mapping[old_ids[i]] == -1);
0306           m_id_mapping[old_ids[i]] = i;
0307       }
0308 
0309       std::vector<typename Graph::distribution_type::size_type> new_mapping(
0310           mapping.size());
0311 
0312       for (int i = 0; i < num_processes(m_pg); ++i)
0313       {
0314           new_mapping[mapping[old_ids[i]]] = i;
0315       }
0316 
0317       m_g.distribution().assign_mapping(
0318           new_mapping.begin(), new_mapping.end());
0319   }
0320 
0321   template <class Graph, class Archive, class VertexListS>
0322   void graph_loader<Graph, Archive, VertexListS>::load_vertices()
0323   {
0324       int V;
0325       m_ar >> BOOST_SERIALIZATION_NVP(V); 
0326 
0327 # ifdef PBGL_SERIALIZE_DEBUG
0328       if (is_root())
0329           std::cout << "Loading vertices\n";
0330 # endif
0331 
0332       for (int i = 0; i < V; ++i)
0333       {
0334           maybe_load_and_store_local_vertex(vertex_list_selector());
0335       }
0336   }
0337 
0338   template <class Graph, class Archive, class VertexListS>
0339   template <class Anything>
0340   void graph_loader<Graph, Archive, VertexListS>::maybe_load_and_store_local_vertex(Anything)
0341   {
0342       // Load the original vertex descriptor
0343       local_vertex_descriptor local;
0344       m_ar >> make_nvp("local", unsafe_serialize(local)); 
0345 
0346       // Load the properties
0347       vertex_property_type property;
0348       detail::parallel::maybe_load_properties(m_ar, "vertex_property",
0349                           property);
0350 
0351       // Add the vertex
0352       vertex_descriptor v(process_id(m_pg), add_vertex(property, m_g.base()));
0353 
0354       if (m_g.on_add_vertex)
0355         m_g.on_add_vertex(v, m_g);
0356 
0357       // Create the mapping from the "old" local descriptor to the new
0358       // local descriptor.
0359       m_local_vertices[local] = v.local;
0360   }
0361 
0362   template <class Graph, class Archive, class VertexListS>
0363   void graph_loader<Graph, Archive, VertexListS>::maybe_load_and_store_local_vertex(vecS)
0364   {
0365       // Load the properties
0366       vertex_property_type property;
0367       detail::parallel::maybe_load_properties(m_ar, "vertex_property",
0368                           property);
0369 
0370       // Add the vertex
0371       vertex_descriptor v(process_id(m_pg), 
0372                           add_vertex(m_g.build_vertex_property(property), 
0373                                      m_g.base()));
0374 
0375       if (m_g.on_add_vertex)
0376         m_g.on_add_vertex(v, m_g);
0377   }
0378 
0379   template <class Graph, class Archive, class VertexListS>
0380   void graph_loader<Graph, Archive, VertexListS>::load_edges()
0381   {
0382       int E;
0383       m_ar >> BOOST_SERIALIZATION_NVP(E);
0384 
0385 # ifdef PBGL_SERIALIZE_DEBUG
0386       if (is_root())
0387           std::cout << "Loading edges\n";
0388 # endif
0389 
0390       for (int i = 0; i < E; ++i)
0391       {
0392           local_vertex_descriptor local_src;
0393           process_id_type target_owner;
0394           local_vertex_descriptor local_tgt;
0395 
0396           m_ar >> make_nvp("source", unsafe_serialize(local_src)); 
0397           m_ar >> make_nvp("target_owner", target_owner); 
0398           m_ar >> make_nvp("target", unsafe_serialize(local_tgt)); 
0399 
0400           process_id_type new_src_owner = process_id(m_pg);
0401           process_id_type new_tgt_owner = m_id_mapping[target_owner];
0402 
0403           vertex_descriptor source(new_src_owner, local_src);
0404           vertex_descriptor target(new_tgt_owner, local_tgt);
0405 
0406           edge_property_type properties;
0407           detail::parallel::maybe_load_properties(m_ar, "edge_property", properties);
0408 
0409           void* property_ptr = maybe_load_property_ptr(directed_selector());
0410           add_edge(source, target, properties, property_ptr, vertex_list_selector());
0411       }
0412 
0413       load_in_edges(directed_selector());
0414       commit_pending_edges(vertex_list_selector());
0415   }
0416 
0417   template <class Graph, class Archive, class VertexListS>
0418   void graph_loader<Graph, Archive, VertexListS>::load_in_edges(bidirectionalS)
0419   {
0420       std::size_t I;
0421       m_ar >> BOOST_SERIALIZATION_NVP(I);
0422 
0423 # ifdef PBGL_SERIALIZE_DEBUG
0424       if (is_root())
0425           std::cout << "Loading in-edges\n";
0426 # endif
0427 
0428       for (int i = 0; i < I; ++i)
0429       {
0430           process_id_type src_owner;
0431           local_vertex_descriptor local_src;
0432           local_vertex_descriptor local_target;
0433           void* property_ptr;
0434 
0435           m_ar >> make_nvp("src_owner", src_owner);
0436           m_ar >> make_nvp("source", unsafe_serialize(local_src));
0437           m_ar >> make_nvp("target", unsafe_serialize(local_target));
0438           m_ar >> make_nvp("property_ptr", unsafe_serialize(property_ptr));
0439 
0440           src_owner = m_id_mapping[src_owner];
0441 
0442           vertex_descriptor u(src_owner, local_src);
0443           vertex_descriptor v(process_id(m_pg), local_target);
0444 
0445           add_pending_in_edge(u, v, property_ptr, vertex_list_selector());
0446       }
0447   }
0448 
0449   template <class Graph, class Archive, class VertexListS>
0450   void graph_loader<Graph, Archive, VertexListS>::load_in_edges(directedS)
0451   {}
0452 
0453   template <class Graph, class Archive, class VertexListS>
0454   void graph_loader<Graph, Archive, VertexListS>::add_pending_in_edge(
0455       vertex_descriptor u, vertex_descriptor v, void* property_ptr, vecS)
0456   {
0457       m_pending_in_edges.push_back(pending_in_edge(u,v,property_ptr));
0458   }
0459 
0460   template <class Graph, class Archive, class VertexListS>
0461   template <class Anything>
0462   void graph_loader<Graph, Archive, VertexListS>::add_pending_in_edge(
0463       vertex_descriptor u, vertex_descriptor v, void* property_ptr, Anything)
0464   {
0465       // u and v represent the out-edge here, meaning v is local
0466       // to us, and u is always remote.
0467       m_pending_in_edges.push_back(pending_in_edge(u,v,property_ptr));
0468       add_remote_vertex_request(v, u, bidirectionalS());
0469   }
0470 
0471   template <class Graph, class Archive, class VertexListS> 
0472   template <class Anything>
0473   void graph_loader<Graph, Archive, VertexListS>::add_edge(
0474       vertex_descriptor u, vertex_descriptor v
0475     , edge_property_type const& property, void* property_ptr, Anything)
0476   {
0477       m_pending_edges.push_back(pending_edge_type(u, v, property, property_ptr));
0478       add_remote_vertex_request(u, v, directed_selector());
0479   }
0480 
0481   template <class Graph, class Archive, class VertexListS> 
0482   void graph_loader<Graph, Archive, VertexListS>::add_remote_vertex_request(
0483       vertex_descriptor u, vertex_descriptor v, directedS)
0484   {
0485       // We have to request the remote vertex.
0486       m_requested_vertices[owner(v)].push_back(local(v));
0487   }
0488 
0489   template <class Graph, class Archive, class VertexListS>
0490   void graph_loader<Graph, Archive, VertexListS>::add_remote_vertex_request(
0491       vertex_descriptor u, vertex_descriptor v, bidirectionalS)
0492   {
0493       // If the edge spans to another process, we know
0494       // that that process has a matching in-edge, so
0495       // we can just send our vertex. No requests
0496       // necessary.
0497       if (owner(v) != m_g.processor())
0498       {
0499           m_remote_vertices[owner(v)].push_back(local(u));
0500           m_requested_vertices[owner(v)].push_back(local(v));
0501       }
0502   }
0503 
0504   template <class Graph, class Archive, class VertexListS>
0505   void graph_loader<Graph, Archive, VertexListS>::add_edge(
0506       vertex_descriptor u, vertex_descriptor v
0507     , edge_property_type const& property, void* property_ptr, vecS)
0508   {
0509       std::pair<local_edge_descriptor, bool> inserted = 
0510           detail::parallel::add_local_edge(
0511               local(u), local(v)
0512             , m_g.build_edge_property(property), m_g.base());
0513       BOOST_ASSERT(inserted.second);
0514       put(edge_target_processor_id, m_g.base(), inserted.first, owner(v));
0515 
0516       edge_descriptor e(owner(u), owner(v), true, inserted.first);
0517 
0518       if (inserted.second && m_g.on_add_edge)
0519         m_g.on_add_edge(e, m_g);
0520 
0521       add_in_edge(e, property_ptr, directed_selector());
0522   }
0523 
0524   template <class Graph, class Archive, class VertexListS>
0525   void graph_loader<Graph, Archive, VertexListS>::add_in_edge(
0526       edge_descriptor const&, void*, directedS)
0527   {}
0528 
0529   template <class Graph, class Archive, class VertexListS>
0530   void graph_loader<Graph, Archive, VertexListS>::add_in_edge(
0531       edge_descriptor const& edge, void* old_property_ptr, bidirectionalS)
0532   {
0533       if (owner(target(edge, m_g)) == m_g.processor())
0534       {
0535           detail::parallel::stored_in_edge<local_edge_descriptor>
0536               e(m_g.processor(), local(edge));
0537           boost::graph_detail::push(get(
0538               vertex_in_edges, m_g.base())[local(target(edge, m_g))], e);
0539       }
0540       else
0541       {
0542           // We send the (old,new) property pointer pair to
0543           // the remote process. This could be optimized to
0544           // only send the new one -- the ordering can be
0545           // made implicit because the old pointer value is
0546           // stored on the remote process.
0547           //
0548           // Doing that is a little bit more complicated, but
0549           // in case it turns out it's important we can do it.
0550           void* property_ptr = local(edge).get_property();
0551           m_property_ptrs[owner(target(edge, m_g))].push_back(
0552               unsafe_pair<void*,void*>(old_property_ptr, property_ptr));
0553       }
0554   }
0555 
0556   template <class Graph, class Archive, class VertexListS>
0557   void graph_loader<Graph, Archive, VertexListS>::resolve_property_ptrs()
0558   {
0559 # ifdef PBGL_SERIALIZE_DEBUG
0560       if (is_root())
0561           std::cout << "Resolving property pointers\n";
0562 # endif
0563 
0564       for (int i = 0; i < num_processes(m_pg); ++i)
0565       {
0566           std::sort(
0567               m_property_ptrs[i].begin(), m_property_ptrs[i].end());
0568       }
0569 
0570       boost::parallel::inplace_all_to_all(m_pg, m_property_ptrs);
0571   }
0572 
0573   template <class Graph, class Archive, class VertexListS>
0574   void graph_loader<Graph, Archive, VertexListS>::resolve_remote_vertices(directedS)
0575   {
0576       for (int i = 0; i < num_processes(m_pg); ++i)
0577       {
0578           std::sort(m_requested_vertices[i].begin(), m_requested_vertices[i].end());
0579       }
0580 
0581       boost::parallel::inplace_all_to_all(
0582           m_pg, m_requested_vertices, m_remote_vertices);
0583 
0584       for (int i = 0; i < num_processes(m_pg); ++i)
0585       {
0586           BOOST_FOREACH(serializable_vertex_descriptor& u, m_remote_vertices[i])
0587           {
0588               u = m_local_vertices[u];
0589           }
0590       }
0591 
0592       boost::parallel::inplace_all_to_all(m_pg, m_remote_vertices);
0593   }
0594 
0595   template <class Graph, class Archive, class VertexListS>
0596   void graph_loader<Graph, Archive, VertexListS>::resolve_remote_vertices(bidirectionalS)
0597   {
0598 # ifdef PBGL_SERIALIZE_DEBUG
0599       if (is_root())
0600           std::cout << "Resolving remote vertices\n";
0601 # endif
0602 
0603       for (int i = 0; i < num_processes(m_pg); ++i)
0604       {
0605           std::sort(m_requested_vertices[i].begin(), m_requested_vertices[i].end());
0606           std::sort(m_remote_vertices[i].begin(), m_remote_vertices[i].end());
0607 
0608           BOOST_FOREACH(serializable_vertex_descriptor& u, m_remote_vertices[i])
0609           {
0610               u = m_local_vertices[u];
0611           }
0612       }
0613 
0614       boost::parallel::inplace_all_to_all(m_pg, m_remote_vertices);
0615 
0616       for (int i = 0; i < num_processes(m_pg); ++i)
0617           BOOST_ASSERT(m_remote_vertices[i].size() == m_requested_vertices[i].size());
0618   }
0619 
0620   template <class Graph, class Archive, class VertexListS>
0621   void graph_loader<Graph, Archive, VertexListS>::commit_pending_edges(vecS)
0622   {
0623       commit_pending_in_edges(directed_selector());
0624   }
0625 
0626   template <class Graph, class Archive, class VertexListS>
0627   template <class Anything>
0628   void graph_loader<Graph, Archive, VertexListS>::commit_pending_edges(Anything)
0629   {
0630       resolve_remote_vertices(directed_selector());
0631 
0632       BOOST_FOREACH(pending_edge_type const& e, m_pending_edges)
0633       {
0634           vertex_descriptor u = resolve_remote_vertex(e.source);
0635           vertex_descriptor v = resolve_remote_vertex(e.target);
0636           add_edge(u, v, e.properties, e.property_ptr, vecS());
0637       }
0638 
0639       commit_pending_in_edges(directed_selector());
0640   }
0641 
0642   template <class Graph, class Archive, class VertexListS>
0643   void graph_loader<Graph, Archive, VertexListS>::commit_pending_in_edges(directedS)
0644   {}
0645 
0646   template <class Graph, class Archive, class VertexListS>
0647   void graph_loader<Graph, Archive, VertexListS>::commit_pending_in_edges(bidirectionalS)
0648   {
0649       resolve_property_ptrs();
0650 
0651       BOOST_FOREACH(pending_in_edge const& e, m_pending_in_edges)
0652       {
0653           vertex_descriptor u = resolve_remote_vertex(e.u, vertex_list_selector());
0654           vertex_descriptor v = resolve_remote_vertex(e.v, vertex_list_selector());
0655 
0656           typedef detail::parallel::stored_in_edge<local_edge_descriptor> stored_edge;
0657 
0658           std::vector<unsafe_pair<void*,void*> >::iterator i = std::lower_bound(
0659               m_property_ptrs[owner(u)].begin()
0660             , m_property_ptrs[owner(u)].end()
0661             , unsafe_pair<void*,void*>(e.property_ptr, 0)
0662           );
0663 
0664           if (i == m_property_ptrs[owner(u)].end()
0665               || i->first != e.property_ptr)
0666           {
0667               BOOST_ASSERT(false);
0668           }
0669 
0670           local_edge_descriptor local_edge(local(u), local(v), i->second);
0671           stored_edge edge(owner(u), local_edge);
0672           boost::graph_detail::push(
0673               get(vertex_in_edges, m_g.base())[local(v)], edge);
0674       }
0675   }
0676 
0677   template <class Graph, class Archive, class VertexListS>
0678   typename graph_loader<Graph, Archive, VertexListS>::vertex_descriptor 
0679   graph_loader<Graph, Archive, VertexListS>::resolve_remote_vertex(
0680       vertex_descriptor u) const
0681   {
0682       if (owner(u) == process_id(m_pg))
0683       { 
0684           return vertex_descriptor(
0685               process_id(m_pg), m_local_vertices.find(local(u))->second);
0686       }
0687 
0688       typename std::vector<serializable_vertex_descriptor>::const_iterator 
0689           i = std::lower_bound(
0690               m_requested_vertices[owner(u)].begin()
0691             , m_requested_vertices[owner(u)].end()
0692             , serializable_vertex_descriptor(local(u))
0693           );
0694 
0695       if (i == m_requested_vertices[owner(u)].end()
0696           || *i != local(u))
0697       {
0698           BOOST_ASSERT(false);
0699       }
0700 
0701       local_vertex_descriptor local =
0702           m_remote_vertices[owner(u)][m_requested_vertices[owner(u)].end() - i];
0703       return vertex_descriptor(owner(u), local);
0704   }
0705 
0706   template <class Graph, class Archive, class VertexListS>
0707   typename graph_loader<Graph, Archive, VertexListS>::vertex_descriptor 
0708   graph_loader<Graph, Archive, VertexListS>::resolve_remote_vertex(
0709       vertex_descriptor u, vecS) const
0710   {
0711       return u;
0712   }
0713 
0714   template <class Graph, class Archive, class VertexListS>
0715   template <class Anything>
0716   typename graph_loader<Graph, Archive, VertexListS>::vertex_descriptor 
0717   graph_loader<Graph, Archive, VertexListS>::resolve_remote_vertex(
0718       vertex_descriptor u, Anything) const
0719   {
0720       return resolve_remote_vertex(u);
0721   }
0722 
0723   template <class Graph, class Archive, class VertexListS>
0724   void* 
0725   graph_loader<Graph, Archive, VertexListS>::maybe_load_property_ptr(bidirectionalS)
0726   {
0727       void* ptr;
0728       m_ar >> make_nvp("property_ptr", unsafe_serialize(ptr));
0729       return ptr;
0730   }
0731 
0732 template <class Archive, class D>
0733 void maybe_save_local_descriptor(Archive& ar, D const&, vecS)
0734 {}
0735 
0736 template <class Archive, class D, class NotVecS>
0737 void maybe_save_local_descriptor(Archive& ar, D const& d, NotVecS)
0738 {
0739     ar << serialization::make_nvp(
0740         "local", unsafe_serialize(const_cast<D&>(d)));
0741 }
0742 
0743 template <class Archive>
0744 void maybe_save_properties(
0745     Archive&, char const*, no_property const&)
0746 {}
0747 
0748 template <class Archive, class Tag, class T, class Base>
0749 void maybe_save_properties(
0750     Archive& ar, char const* name, property<Tag, T, Base> const& properties)
0751 {
0752     ar & serialization::make_nvp(name, get_property_value(properties, Tag()));
0753     maybe_save_properties(ar, name, static_cast<Base const&>(properties));
0754 }
0755 
0756 template <class Archive, class Graph>
0757 void save_in_edges(Archive& ar, Graph const& g, directedS)
0758 {}
0759 
0760 // We need to save the edges in the base edge
0761 // list, and the in_edges that are stored in the
0762 // vertex_in_edges vertex property.
0763 template <class Archive, class Graph>
0764 void save_in_edges(Archive& ar, Graph const& g, bidirectionalS)
0765 {
0766     typedef typename Graph::process_group_type
0767         process_group_type;
0768     typedef typename process_group_type::process_id_type
0769         process_id_type;
0770     typedef typename graph_traits<
0771         Graph>::vertex_descriptor vertex_descriptor;
0772     typedef typename vertex_descriptor::local_descriptor_type 
0773         local_vertex_descriptor;
0774     typedef typename graph_traits<
0775         Graph>::edge_descriptor edge_descriptor;
0776 
0777     process_id_type id = g.processor();
0778 
0779     std::vector<edge_descriptor> saved_in_edges;
0780 
0781     BGL_FORALL_VERTICES_T(v, g, Graph) 
0782     {
0783         BOOST_FOREACH(edge_descriptor const& e, in_edges(v, g))
0784         {
0785             // Only save the in_edges that isn't owned by this process.
0786             if (owner(e) == id)
0787                 continue;
0788 
0789             saved_in_edges.push_back(e);
0790         }
0791     }
0792 
0793     std::size_t I = saved_in_edges.size();
0794     ar << BOOST_SERIALIZATION_NVP(I);
0795 
0796     BOOST_FOREACH(edge_descriptor const& e, saved_in_edges)
0797     {
0798         process_id_type src_owner = owner(source(e,g));
0799         local_vertex_descriptor local_src = local(source(e,g));
0800         local_vertex_descriptor local_target = local(target(e,g));
0801         void* property_ptr = local(e).get_property();
0802 
0803         using serialization::make_nvp;
0804 
0805         ar << make_nvp("src_owner", src_owner);
0806         ar << make_nvp("source", unsafe_serialize(local_src));
0807         ar << make_nvp("target", unsafe_serialize(local_target));
0808         ar << make_nvp("property_ptr", unsafe_serialize(property_ptr));
0809     }
0810 }
0811 
0812 template <class Archive, class Edge>
0813 void maybe_save_property_ptr(Archive&, Edge const&, directedS)
0814 {}
0815 
0816 template <class Archive, class Edge>
0817 void maybe_save_property_ptr(Archive& ar, Edge const& e, bidirectionalS)
0818 {
0819     void* ptr = local(e).get_property();
0820     ar << serialization::make_nvp("property_ptr", unsafe_serialize(ptr));
0821 }
0822 
0823 template <class Archive, class Graph, class DirectedS>
0824 void save_edges(Archive& ar, Graph const& g, DirectedS)
0825 {
0826     typedef typename Graph::process_group_type
0827         process_group_type;
0828     typedef typename process_group_type::process_id_type
0829         process_id_type;
0830     typedef typename graph_traits<
0831         Graph>::vertex_descriptor vertex_descriptor;
0832 
0833     typedef typename Graph::edge_property_type edge_property_type;
0834 
0835     int E = num_edges(g);
0836     ar << BOOST_SERIALIZATION_NVP(E);
0837 
0838     // For *directed* graphs, we can just save
0839     // the edge list and be done.
0840     //
0841     // For *bidirectional* graphs, we need to also
0842     // save the "vertex_in_edges" property map,
0843     // because it might contain in-edges that
0844     // are not locally owned.
0845     BGL_FORALL_EDGES_T(e, g, Graph) 
0846     {
0847         vertex_descriptor src(source(e, g));
0848         vertex_descriptor tgt(target(e, g));
0849 
0850         typename vertex_descriptor::local_descriptor_type
0851             local_u(local(src));
0852         typename vertex_descriptor::local_descriptor_type
0853             local_v(local(tgt));
0854 
0855         process_id_type target_owner = owner(tgt);
0856 
0857         using serialization::make_nvp;
0858 
0859         ar << make_nvp("source", unsafe_serialize(local_u)); 
0860         ar << make_nvp("target_owner", target_owner); 
0861         ar << make_nvp("target", unsafe_serialize(local_v)); 
0862 
0863         maybe_save_properties(
0864             ar, "edge_property"
0865           , static_cast<edge_property_type const&>(get(edge_all_t(), g, e))
0866         );
0867 
0868         maybe_save_property_ptr(ar, e, DirectedS());
0869     }
0870 
0871     save_in_edges(ar, g, DirectedS());
0872 }
0873 
0874 }} // namespace detail::parallel
0875 
0876 template <PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
0877 template <class IStreamConstructibleArchive>
0878 void PBGL_DISTRIB_ADJLIST_TYPE::load(std::string const& filename)
0879 {
0880     process_group_type pg = process_group();
0881     process_id_type id = process_id(pg);
0882 
0883     synchronize(pg);
0884 
0885     std::vector<int> disk_files = detail::parallel::available_process_files(filename);
0886     std::sort(disk_files.begin(), disk_files.end());
0887 
0888     // Negotiate which process gets which file. Serialized.
0889     std::vector<int> consumed_files;
0890     int picked_file = -1;
0891 
0892     if (id > 0)
0893         receive_oob(pg, id-1, 0, consumed_files);
0894 
0895     std::sort(consumed_files.begin(), consumed_files.end());
0896     std::vector<int> available_files;
0897     std::set_difference(
0898         disk_files.begin(), disk_files.end()
0899       , consumed_files.begin(), consumed_files.end()
0900       , std::back_inserter(available_files)
0901     );
0902 
0903     if (available_files.empty())
0904         boost::throw_exception(std::runtime_error("no file available"));
0905 
0906     // back() used for debug purposes. Making sure the
0907     // ranks are shuffled.
0908     picked_file = available_files.back();
0909 
0910 # ifdef PBGL_SERIALIZE_DEBUG
0911     std::cout << id << " picked " << picked_file << "\n";
0912 # endif
0913 
0914     consumed_files.push_back(picked_file);
0915 
0916     if (id < num_processes(pg) - 1)
0917         send_oob(pg, id+1, 0, consumed_files);
0918 
0919     std::string local_filename = filename + "/" + 
0920         lexical_cast<std::string>(picked_file);
0921 
0922     std::ifstream in(local_filename.c_str(), std::ios_base::binary);
0923     IStreamConstructibleArchive ar(in);
0924 
0925     detail::parallel::graph_loader<
0926         graph_type, IStreamConstructibleArchive, InVertexListS
0927     > loader(*this, ar);
0928 
0929 # ifdef PBGL_SERIALIZE_DEBUG
0930     std::cout << "Process " << id << " done loading.\n";
0931 # endif
0932 
0933     synchronize(pg);
0934 }
0935 
0936 template <PBGL_DISTRIB_ADJLIST_TEMPLATE_PARMS>
0937 template <class OStreamConstructibleArchive>
0938 void PBGL_DISTRIB_ADJLIST_TYPE::save(std::string const& filename) const
0939 {
0940     typedef typename config_type::VertexListS vertex_list_selector;
0941 
0942     process_group_type pg = process_group();
0943     process_id_type id = process_id(pg);
0944 
0945     if (filesystem::exists(filename) && !filesystem::is_directory(filename))
0946         boost::throw_exception(std::runtime_error("entry exists, but is not a directory"));
0947 
0948     filesystem::remove_all(filename);
0949     filesystem::create_directory(filename);
0950 
0951     synchronize(pg);
0952 
0953     std::string local_filename = filename + "/" + 
0954         lexical_cast<std::string>(id);
0955 
0956     std::ofstream out(local_filename.c_str(), std::ios_base::binary);
0957     OStreamConstructibleArchive ar(out);
0958 
0959     using serialization::make_nvp;
0960 
0961     typename process_group_type::process_size_type num_processes_ = num_processes(pg);
0962     ar << make_nvp("num_processes", num_processes_);
0963     ar << BOOST_SERIALIZATION_NVP(id);
0964     ar << make_nvp("mapping", this->distribution().mapping());
0965 
0966     int V = num_vertices(*this);
0967     ar << BOOST_SERIALIZATION_NVP(V);
0968 
0969     BGL_FORALL_VERTICES_T(v, *this, graph_type)
0970     {
0971         local_vertex_descriptor local_descriptor(local(v));
0972         detail::parallel::maybe_save_local_descriptor(
0973             ar, local_descriptor, vertex_list_selector());
0974         detail::parallel::maybe_save_properties(
0975             ar, "vertex_property"
0976           , static_cast<vertex_property_type const&>(get(vertex_all_t(), *this, v))
0977         );
0978     }
0979 
0980     detail::parallel::save_edges(ar, *this, directed_selector());
0981 
0982     ar << make_nvp("distribution", this->distribution());
0983 }
0984 
0985 } // namespace boost
0986 
0987 #endif // BOOST_GRAPH_DISTRIBUTED_ADJLIST_SERIALIZATION_070925_HPP
0988