OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
dist_map_graph.hpp
1 /*
2  * dist_map_graph.hpp
3  *
4  * Created on: Dec 10, 2015
5  * Author: Antonio Leo
6  *
7  *
8  * The distributed graph, is a graph distributed across processors, each processor store part of the graph
9  *
10  * ## Dictionary
11  *
12  * * local vertex id, is the index of the vertex in the local graph
13  * * vertex id is the "unique" index in the distribution vector (vtxdist)
14  * * global id is the "unique" topological id of the vertex, it never change
15  *
16  *
17  *
18  * Graph structure that store a CSR graph format
19  *
20  * This Graph format is suppose to have a list of vertex that store an index x that indicate where
21  * in the adjacency list we have the list of all the neighborhood vertex, plus an adjacency list
22  * that store all the neighborhood for each vertex:
23  *
24  * In reality inside DistGraph_CSR
25  *
26  * VertexList store the Vertex index that indicate the end of the neighborhood list,
27  * the start is indicated by i * v_slot (id of the vertex, v_slot maximum number of
28  * neighborhood for a vertex)
29  *
30  * EdgeList store for each vertex at position i * v_slot (id of the vertex, v_slot maximum
31  * number of neighborhood for a vertex) the list of all the neighborhood of the vertex i
32  *
33  * Example
34  *
35  * Suppose an undirected graph of 4 vertex
36  *
37  * 1 -> 2 3 4
38  * 2 -> 1
39  * 3 -> 4 1
40  * 4 -> 1 3
41  *
42  * suppose that v_slot is 4 ( each vertex has less tha 4 neighborhood )
43  *
44  * we will have
45  *
46  * Vertex list 3 5 10 14
47  * Edge list 2 3 4 0 1 0 0 0 4 1 0 0 1 3 0 0
48  *
49  * Vertex properties and edge properties are stored in a separate structure
50  *
51  * ## Dictionary
52  *
53  * The distributed
54  *
55  * * local vertex id is the index of the vertex in
56  *
57  */
58 
59 #ifndef DIST_MAP_GRAPH_HPP_
60 #define DIST_MAP_GRAPH_HPP_
61 
62 #include "Vector/map_vector.hpp"
63 #include "Graph/map_graph.hpp"
64 #include <unordered_map>
65 #include "Packer_Unpacker/Packer.hpp"
66 #include "Packer_Unpacker/Unpacker.hpp"
67 #include "VCluster/VCluster.hpp"
68 
69 #define NO_EDGE -1
70 #define DIST_GRAPH_ERROR 7001
71 
72 template<typename V, typename E,
73  typename Memory,
74  typename layout_v,
75  typename layout_e,
76  template<typename> class layout_v_base,
77  template<typename> class layout_e_base,
78  typename grow_p>
80 
81 class v_info
82 {
83 public:
84  typedef boost::fusion::vector<size_t, size_t> type;
85 
86  type data;
87 
88  static const unsigned int id = 0;
89  static const unsigned int gid = 1;
90  static const unsigned int max_prop = 2;
91 
92  v_info()
93  {
94  }
95 
96  inline void setid(size_t id_)
97  {
98  boost::fusion::at_c<0>(data) = id_;
99  }
100 
101  inline void setgid(size_t gid_)
102  {
103  boost::fusion::at_c<1>(data) = gid_;
104  }
105 
106  template<unsigned int id> inline auto get() -> decltype(boost::fusion::at_c < id > (data))
107  {
108  return boost::fusion::at_c<id>(data);
109  }
110 
111  template<unsigned int id> inline auto get() const -> const decltype(boost::fusion::at_c < id > (data))
112  {
113  return boost::fusion::at_c<id>(data);
114  }
115 
116  template<unsigned int dim, typename Mem> inline v_info(const encapc<dim, v_info, Mem> & p)
117  {
118  this->operator=(p);
119  }
120 
121  template<unsigned int dim, typename Mem> inline v_info & operator=(const encapc<dim, v_info, Mem> & p)
122  {
123  boost::fusion::at_c<0>(data) = p.template get<0>();
124  boost::fusion::at_c<1>(data) = p.template get<1>();
125 
126  return *this;
127  }
128 
129  static bool noPointers()
130  {
131  return true;
132  }
133 };
134 
135 class e_info
136 {
137 public:
138  typedef boost::fusion::vector<size_t, size_t> type;
139 
140  type data;
141 
142  static const unsigned int sgid = 0;
143  static const unsigned int dgid = 1;
144  static const unsigned int max_prop = 2;
145 
146  e_info()
147  {
148  }
149 
150  template<unsigned int id> inline auto get() -> decltype(boost::fusion::at_c < id > (data))
151  {
152  return boost::fusion::at_c<id>(data);
153  }
154 
155  template<unsigned int id> inline auto get() const -> const decltype(boost::fusion::at_c < id > (data))
156  {
157  return boost::fusion::at_c<id>(data);
158  }
159 
160  template<unsigned int dim, typename Mem> inline e_info(const encapc<dim, e_info, Mem> & p)
161  {
162  this->operator=(p);
163  }
164 
165  template<unsigned int dim, typename Mem> inline e_info & operator=(const encapc<dim, e_info, Mem> & p)
166  {
167  boost::fusion::at_c<0>(data) = p.template get<0>();
168  boost::fusion::at_c<1>(data) = p.template get<1>();
169 
170  return *this;
171  }
172 
173  static bool noPointers()
174  {
175  return true;
176  }
177 };
178 
202 template<typename V, typename E = no_edge,
203  typename Memory = HeapMemory,
204  typename layout_v = typename memory_traits_lin<V>::type,
205  typename layout_e = typename memory_traits_lin<E>::type,
206  template <typename> class layout_v_base = memory_traits_lin,
207  template <typename> class layout_e_base = memory_traits_lin,
208  typename grow_p = openfpm::grow_policy_double>
209 class DistGraph_CSR
210 {
213 
216 
219 
221  size_t v_slot;
222 
225 
228 
231 
234 
237 
240 
243 
245  std::unordered_map<size_t, size_t> id2glb;
246 
248  std::unordered_map<size_t, size_t> glb2id;
249 
251  std::unordered_map<size_t, size_t> glb2loc;
252 
255  {
269  bool isEmpty = true;
270  };
271 
274 
277 
279  typedef struct
280  {
282  size_t id;
283  // processor containing the vertex
284  size_t pid;
285  } GlobalVInfo;
286 
288  // Map of GlobalVInfo containing informations of vertices of the INITIAL distribution contained in this processor
289  // ex. if this will contain the first 4 vertices of the distribution (0,1,2,3) it will maintain informations only about these vertices
290  // The key is the vertex global id
291  std::unordered_map<size_t, GlobalVInfo> glbi_map;
292 
295 
297  std::unordered_map<size_t, bool> ghs_map;
298 
300  typedef struct
301  {
303  size_t v1;
305  size_t v2;
307  size_t v1n;
309  size_t v2n;
310  } EdgeReq;
311 
314 
325  template<typename CheckPolicy = NoCheck> inline size_t addEdge_(size_t v1, size_t v2)
326  {
327  // If v1 and v2 does not satisfy some criteria return
328  if (CheckPolicy::valid(v1, v.size()) == false)
329  {return (size_t)NO_EDGE;}
330  if (CheckPolicy::valid(v2, v.size()) == false)
331  {return (size_t)NO_EDGE;}
332 
333  // get the number of adjacent vertex
334  size_t id_x_end = v_l.template get<0>(v1);
335 
336 #ifdef DEBUG
337 
338  // Check that the edge does not already exist
339 
340  for (size_t s = 0; s < id_x_end; s++)
341  {
342  if (e_l.template get<e_map::vid>(v1 * v_slot + s) == v2)
343  {
344  std::cerr << "Error graph: the edge already exist\n";
345  }
346  }
347 #endif
348 
349  // Check if there is space for another edge
350 
351  if (id_x_end >= v_slot)
352  {
353  // Unfortunately there is not space we need to reallocate memory
354  // Reallocate with double slot
355 
356  // Create an new Graph
357  DistGraph_CSR<V, E> g_new(2 * v_slot, v.size());
358 
359  // Copy the graph
360  for (size_t i = 0; i < v.size(); i++)
361  {
362  // copy the property from the old graph
363  g_new.v.set(i, v, 2 * i);
364  }
365 
366  // swap the new graph with the old one
367  swap(g_new);
368  }
369 
370  // Here we are sure than v and e has enough slots to store a new edge
371  // Check that e_l has enough space to store new edge
372  // should be always e.size == e_l.size
373 
374  if (id_x_end >= e_l.size())
375  {
376  // Resize the basic structure
377  e_l.resize(v.size() * v_slot);
378  }
379 
380  // add in e_l the adjacent vertex for v1 and fill the edge id
381  e_l.template get<e_map::vid>(v1 * v_slot + id_x_end) = v2;
382  e_l.template get<e_map::eid>(v1 * v_slot + id_x_end) = e.size();
383 
384  // add an empty edge
385  e.resize(e.size() + 1);
386  e_m.resize(e_m.size() + 1);
387 
388  // Increment the ending point
389  ++v_l.template get<0>(v1);
390 
391  // return the created edge
392  return e.size() - 1;
393  }
394 
404  static void * gr_receive(size_t msg_i, size_t total_msg, size_t total_p, size_t i, size_t ri, size_t tag, void * ptr)
405  {
407 
408  v->get(i).allocate(msg_i);
409 
410  return v->get(i).getPointer();
411 
412  }
413 
423  static void * on_receive(size_t msg_i, size_t total_msg, size_t total_p, size_t i, size_t ri, size_t tag, void * ptr)
424  {
426 
427  v->get(i).resize(msg_i / sizeof(size_t));
428 
429  return &(v->get(i).get(0));
430  }
431 
436  {
437  if (sgp.size() == vcl.getProcessingUnits())
438  {
439  for (size_t p = 0; p < vcl.getProcessingUnits(); ++p)
440  {
441  sgp.get(p).send_v.clear();
442  sgp.get(p).send_v_m.clear();
443  sgp.get(p).send_e.clear();
444  sgp.get(p).send_e_m.clear();
445  sgp.get(p).send_es.clear();
446  sgp.get(p).send_el.clear();
447  sgp.get(p).isEmpty = true;
448  }
449  }
450  else
451  {
452  sgp.resize(vcl.getProcessingUnits());
453 
454  for (size_t p = 0; p < vcl.getProcessingUnits(); ++p)
455  {
456  openfpm::vector<V> s_v;
458  openfpm::vector<E> s_e;
462 
463  sgp.get(p).send_v = s_v;
464  sgp.get(p).send_v_m = s_v_m;
465  sgp.get(p).send_e = s_e;
466  sgp.get(p).send_e_m = s_e_m;
467  sgp.get(p).send_es = s_es;
468  sgp.get(p).send_el = s_el;
469  sgp.get(p).isEmpty = true;
470  }
471  }
472  }
473 
478  {
479  // Prepare new graph
480  DistGraph_CSR recv_g;
481 
482  // Reset maps
483  glb2loc.clear();
484  glb2id.clear();
485  id2glb.clear();
486 
487  size_t local_i = 0;
488 
489  // Add previous vertices without the sent ones
490  for (size_t i = 0; i < this->getNVertex(); ++i)
491  {
492  if (!isToDelete(i))
493  {
494  recv_g.add_vertex(this->vertex(i), this->getVertexId(i), this->getVertexGlobalId(i));
495 
496  for (size_t j = 0; j < this->getNChilds(i); j++)
497  {
498  recv_g.addEdge(local_i, this->getChild(i, j), this->getChildEdge(i, j), this->getChildInfo(i, j));
499  }
500  ++local_i;
501  }
502  }
503 
504  recv_g.fvtxdist = fvtxdist;
505 
506  // Swap temporary graph with the main one
507  swap(recv_g);
508 
509  // Clear vertex to delete array
510  v_td.clear();
511  }
512 
518  bool isToDelete(size_t i)
519  {
520 
521  for (size_t j = 0; j < v_td.size(); ++j)
522  {
523  if (i == v_td.get(j))
524  return true;
525  }
526  return false;
527  }
528 
534  size_t getVProcessor(size_t v)
535  {
536  for (size_t i = 1; i < vtxdist.size() - 1; ++i)
537  {
538  if (v < vtxdist.get(i))
539  {
540  return i - 1;
541  }
542  }
543  return vcl.getProcessingUnits() - 1;
544  }
545 
551  template<bool addAsGhosts>
553  {
554  // If the exchange is not to retrieve ghost vertices delete the vertices this processor is sending
555  if (!addAsGhosts)
557 
563  openfpm::vector<ExtPreAlloc<HeapMemory> *> to_release_ext;
564 
565  // Total number of vertex to send
566  size_t nvts = 0;
567  for (size_t i = 0; i < vcl.getProcessingUnits(); i++)
568  {
569  nvts += sgp.get(i).send_v.size();
570  }
571 
572  // For each processor
573  for (size_t i = 0; i < vcl.getProcessingUnits(); i++)
574  {
575  // if nothing to send continue
576  if (sgp.get(i).isEmpty)
577  continue;
578 
579  // process to communicate with TODO remove pc
580  size_t pc = i;
581 
582  size_t vp_size = sgp.get(pc).send_v.size();
583 
584  size_t req = 0;
585 
586  // prepare slot for number of vertices
588 
589  for (size_t j = 0; j < vp_size; j++)
590  {
591  // prepare slot for vertex
593 
594  // prepare slot info for vertex
596 
597  // prepare slot for the number of children
599 
600  // prepare slots for the children
601  for (size_t k = 0; k < sgp.get(pc).send_es.get(j); k++)
602  {
603  // prepare slot for edge
605 
606  // prepare slot for edge info
608 
609  // prepare slot for edge target id
611  }
612  }
613 
614  // allocate the memory
615  HeapMemory & pmem = *(new HeapMemory());
616 // pmem.allocate(req);
617  ExtPreAlloc<HeapMemory> & mem = *(new ExtPreAlloc<HeapMemory>(req, pmem));
618  mem.incRef();
619 
620  to_release.add(&pmem);
621  to_release_ext.add(&mem);
622 
623  Pack_stat sts;
624  size_t e_it = 0;
625 
626  // Pack total size
627  Packer<size_t, HeapMemory>::pack(mem, vp_size, sts);
628 
629  for (size_t j = 0; j < vp_size; j++)
630  {
631  // Pack the vertex
632  Packer<decltype(sgp.get(pc).send_v.get(0)), HeapMemory>::pack(mem, sgp.get(pc).send_v.get(j), sts);
633 
634  // Pack the vertex info
635  Packer<decltype(sgp.get(pc).send_v_m.get(0)), HeapMemory>::pack(mem, sgp.get(pc).send_v_m.get(j), sts);
636 
637  // Pack size of the children
638  Packer<size_t, HeapMemory>::pack(mem, sgp.get(pc).send_es.get(j), sts);
639 
640  // Pack children
641  for (size_t k = 0; k < sgp.get(pc).send_es.get(j); k++)
642  {
643  // Pack the edge
644  Packer<decltype(sgp.get(pc).send_e.get(0)), HeapMemory>::pack(mem, sgp.get(pc).send_e.get(e_it), sts);
645 
646  // Pack the edge info
647  Packer<decltype(sgp.get(pc).send_e_m.get(0)), HeapMemory>::pack(mem, sgp.get(pc).send_e_m.get(e_it), sts);
648 
649  // Pack the edge target id
650  Packer<size_t, HeapMemory>::pack(mem, sgp.get(pc).send_el.get(e_it), sts);
651 
652  ++e_it;
653  }
654  }
655 
656  prc.add(i);
657  size.add(pmem.size());
658  ptr.add(mem.getPointerBase());
659  }
660 
661  // Exchange informations through processors
662  vcl.sendrecvMultipleMessagesNBX(prc.size(), (size_t *)size.getPointer(), (size_t *)prc.getPointer(), (void **)ptr.getPointer(), gr_receive, &packs, NONE);
663 
664  for (int i = 0 ; i < to_release_ext.size(); i++)
665  {
666  to_release_ext.get(i)->decRef();
667  delete to_release_ext.get(i);
668 
669  delete to_release.get(i);
670  }
671 
672  for (size_t i = 0; i < vcl.getProcessingUnits(); i++)
673  {
674 
675  if (i != vcl.getProcessUnitID() && packs.get(i).size() > 0)
676  {
677  Unpack_stat ps;
678 
679  ExtPreAlloc<HeapMemory> mem(packs.get(i).size(), packs.get(i));
680 
681  // unpack total number of vertex
682  size_t r_size;
683  Unpacker<size_t, HeapMemory>::unpack(mem, r_size, ps);
684 
685  // take previous last item
686  size_t prev = getNVertex();
687 
688  for (size_t j = prev; j < prev + r_size; j++)
689  {
690  // unpack the vertex
691  V v_n;
692  Unpacker<V, HeapMemory>::unpack(mem, v_n, ps);
693 
694  v_info vm;
696 
697  add_vertex(v_n, vm.template get<v_info::id>(), vm.template get<v_info::gid>());
698 
699  if (addAsGhosts)
700  ghs_map.insert( { vm.template get<v_info::gid>(), false });
701 
702  // unpack size of children
703  size_t s;
705 
706  // prepare slots for the children
707  for (size_t k = 0; k < s; k++)
708  {
709  // unpack edge
710  E e_n;
711  Unpacker<E, HeapMemory>::unpack(mem, e_n, ps);
712 
713  // unpack edge
714  e_info e_i;
716 
717  // unpack vertex id of the edge target
718  size_t el_n;
720 
721  // add the edge //HERE ERROR modify to add globals
722  addEdge(j, el_n, e_n, e_i);
723  }
724  }
725  }
726  }
727 
728  // After the exchange reset all the structures needed for it
729  resetExchange();
730  }
731 
736  {
737  // Prepare vtxdist
738  vtxdist.resize(vcl.getProcessingUnits() + 1);
739 
740  // Set first element to 0, always the same
741  vtxdist.get(0) = 0;
742 
743  // Prepare array that will contain the sizes of all the graphs
745 
746  // Set the local size
747  size_t tv = getNVertex();
748 
749  // Sent and receive the size of each subgraph
750  vcl.allGather(tv, recv);
751  vcl.execute();
752 
753  // Set the value for this processor
754  recv.get(vcl.getProcessUnitID()) = getNVertex();
755 
756  // Update vtxdist
757  for (size_t i = 1; i <= recv.size(); ++i)
758  {
759  vtxdist.get(i) = recv.get(i - 1) + vtxdist.get(i - 1);
760  }
761  }
762 
766  void remap()
767  {
768  size_t p_id = vcl.getProcessUnitID();
769 
770  typedef struct
771  {
772  // new vertex id
773  size_t id;
774  // processor rank that contain the vertex
775  size_t pid;
776  } IdnProc;
777 
778  // Map that will contain the couples to update the global info map in this processor
779  // The key is the (old vertex id)
780  std::unordered_map<size_t, IdnProc> on_toup;
781 
782  // For each processor old, new couples
784 
785  std::map<size_t, size_t> old_glob2loc(glb2loc.begin(), glb2loc.end());
786  size_t j = vtxdist.get(p_id);
787  size_t i = 0, k = 0;
788 
789  // Reset maps of vertices ids
790  id2glb.clear();
791  glb2id.clear();
792  glb2loc.clear();
793 
794  // Fix sending couples gid, newid and remove on_toup updating glbi_map here and after receive
795  for (auto it : old_glob2loc)
796  {
797  // The couple to the final map, needed to update the vertices in this sub-graph
798  IdnProc nidpid = { j, p_id };
799  on_toup.insert( { v_m.get(it.second).template get<v_info::id>(), nidpid });
800 
801  // fill the re-mapping information for each processors that need it
802  on_info.get(getInfoProc(it.first)).add(v_m.get(it.second).template get<v_info::id>());
803  on_info.get(getInfoProc(it.first)).add(j);
804 
805  // Re-map the vertex
806  map_v(j, v_m.get(it.second).template get<v_info::gid>(), it.second);
807 
808  j++;
809  i++;
810  k += 2;
811  }
812 
813  // Prepare structures to send the old-new couples
817 
818  // Array that will contain the couples, divided per processor
820 
821  fillSendRecvStructs<size_t>(on_info, prc, size, ptr);
822 
823  // Send on_info
824  vcl.sendrecvMultipleMessagesNBX(prc.size(), (size_t *)size.getPointer(), (size_t *)prc.getPointer(), (void **)ptr.getPointer(), on_receive, &on_vs, NONE);
825 
826  // Insert in the on_toup map the received couples
827  for (size_t i = 0; i < vcl.getProcessingUnits(); i++)
828  {
829  if (i != vcl.getProcessUnitID() && on_vs.get(i).size() > 0) // redundant check 2nd arg in if
830  {
831  for (size_t j = 0; j < on_vs.get(i).size() - 1; j += 2) // -1 is useless
832  {
833  IdnProc nidpid = { on_vs.get(i).get(j + 1), i };
834  on_toup.insert( { on_vs.get(i).get(j), nidpid });
835  }
836  }
837  }
838 
839  // Update the glbi_map with the new ids and the processor info
840  for (auto k : glbi_map)
841  {
842  auto search = on_toup.find(glbi_map.at(k.first).id); // fix with (k.second).id
843  if (search != on_toup.end())
844  {
845  GlobalVInfo t = { (search->second).id, (search->second).pid };
846  glbi_map.at(k.first) = t;
847  }
848  }
849 
850  // Vector of vertices global id I need info
852 
853  // Map of re-mapping info
854  std::unordered_map<size_t, size_t> rmi_m(vcl.getProcessingUnits()); // TODO elimin
855 
856  // Check which vertices I need to ask info about
857  for (size_t i = 0; i < getNVertex(); ++i)
858  {
859  for (size_t j = 0; j < getNChilds(i); ++j)
860  {
861  // Here we get the global vertex id of all the children
862  size_t vid = getChildDstGid(i, j);
863  // We check which processor has the information about this vertex
864  size_t pid = getInfoProc(vid);
865 
866  // if the vertex info is not in this processor I have to make a request to the right processor
867  if (!vertexIsInThisGraph(vid) && pid != vcl.getProcessUnitID())
868  {
869  // add to requests
870  vni.get(pid).add(vid);
871  }
872  else if (pid == vcl.getProcessUnitID())
873  {
874  // if info is in this processor add it in the map
875  rmi_m.insert( { vid, glbi_map.at(vid).id });
876  }
877  else if (vertexIsInThisGraph(vid)) // check if it is needed, probably not because the glbi_map is update
878  {
879  // if the vertex is in this graph, add the new id in the map
880  rmi_m.insert( { vid, glb2id.at(vid) });
881  }
882  }
883  }
884 
885  // Array that will contain the requests from the other processors
887 
888  // Fill the structures for sendrecvMultipleMessagesNBX function
889  fillSendRecvStructs<size_t>(vni, prc, size, ptr);
890 
891  // Send and receive requests
892  vcl.sendrecvMultipleMessagesNBX(prc.size(), (size_t *)size.getPointer(), (size_t *)prc.getPointer(), (void **)ptr.getPointer(), on_receive, &req_rmi, NONE);
893 
894  // Re-mapping info map
896 
897  // Array that will contain the response to previous requests
899 
900  // Prepare re-mapping info response
901  for (size_t i = 0; i < req_rmi.size(); ++i)
902  {
903  for (size_t j = 0; j < req_rmi.get(i).size(); ++j)
904  {
905  resp_rmi.get(i).add(glbi_map.at(req_rmi.get(i).get(j)).id);
906  }
907  }
908 
909  // Fill the structures for sendrecvMultipleMessagesNBX function
910  fillSendRecvStructs<size_t>(resp_rmi, prc, size, ptr);
911 
912  // Send responses
913  vcl.sendrecvMultipleMessagesNBX(prc.size(), (size_t *)size.getPointer(), (size_t *)prc.getPointer(), (void **)ptr.getPointer(), on_receive, &rmi, NONE);
914 
915  // Add received info into re-mapping info map
916  for (size_t i = 0; i < rmi.size(); ++i)
917  {
918  for (size_t j = 0; j < rmi.get(i).size(); ++j)
919  {
920  rmi_m.insert( { vni.get(i).get(j), rmi.get(i).get(j) });
921  }
922  }
923 
924  // Finally re-map the edges
925  for (size_t i = 0; i < getNVertex(); ++i)
926  {
927  for (size_t s = 0; s < getNChilds(i); s++)
928  {
929  e_l.template get<e_map::vid>(i * v_slot + s) = rmi_m.at(getChildDstGid(i, s));
930  }
931  }
932  }
933 
937  void initGlbimap()
938  {
939  size_t pid = vcl.getProcessUnitID();
940 
941  for (size_t i = 0; i < getNVertex(); ++i)
942  {
943  GlobalVInfo info;
944  info.id = v_m.get(i).template get<v_info::id>();
945  info.pid = pid;
946  glbi_map.insert( { v_m.get(i).template get<v_info::gid>(), info });
947  }
948  }
949 
955  size_t getInfoProc(size_t vid)
956  {
957  for (size_t i = 0; i < fvtxdist.size() - 1; ++i)
958  {
959  if (vid >= (size_t)fvtxdist.get(i) && vid < (size_t)fvtxdist.get(i + 1))
960  {
961  return i;
962  }
963  }
964  return vcl.getProcessingUnits() - 1;
965  }
966 
976  template<typename T>
978  {
979  // Reset sendrecv structures
980  prc.clear();
981  size.clear();
982  ptr.clear();
983 
984  for (size_t i = 0; i < vec.size(); ++i)
985  {
986  if (vec.get(i).size() > 0 && i != vcl.getProcessUnitID())
987  {
988  prc.add(i);
989  size.add(vec.get(i).size() * sizeof(T));
990  ptr.add(vec.get(i).getPointer());
991  }
992  }
993  }
994 
995 public:
996 
998  typedef V V_type;
999 
1001  typedef E E_type;
1002 
1005 
1008 
1016  {
1018 
1019  dup.v_slot = v_slot;
1020 
1021  // duplicate all the structures
1022 
1023  dup.v.swap(v.duplicate());
1024  dup.v_m.swap(v_m.duplicate());
1025  dup.v_l.swap(v_l.duplicate());
1026  dup.glb2id = glb2id;
1027  dup.id2glb = id2glb;
1028  dup.glb2loc = glb2loc;
1029  dup.e.swap(e.duplicate());
1030  dup.e_m.swap(e_m.duplicate());
1031  dup.e_l.swap(e_l.duplicate());
1032  dup.e_invalid.swap(e_invalid.duplicate());
1033  dup.vtxdist.swap(vtxdist.duplicate());
1034  dup.fvtxdist.swap(fvtxdist.duplicate());
1035  return dup;
1036  }
1037 
1044  vcl(create_vcluster())
1045  {
1046  this->operator=(dg);
1047  }
1048 
1055  :vcl(create_vcluster())
1056  {
1057  this->operator=(dg);
1058  }
1059 
1066  DistGraph_CSR(0, 16)
1067  {
1068  }
1069 
1075  DistGraph_CSR(size_t n_vertex) :
1076  DistGraph_CSR(n_vertex, 16)
1077  {
1078  }
1079 
1085  DistGraph_CSR(size_t n_vertex, size_t n_slot) :
1086  vcl(create_vcluster()), v_slot(n_slot)
1087  {
1088  // Creating n_vertex into the graph
1089  v.resize(n_vertex);
1090  // Creating n_vertex info objects into the graph
1091  v_m.resize(n_vertex);
1092  // Creating n_vertex adjacency list counters
1093  v_l.resize(n_vertex);
1094  // no edge set the counter to zero
1095  v_l.fill(0);
1096  // create one invalid edge
1097  e_invalid.resize(1);
1098  // init communication structures
1099  resetExchange();
1100  }
1101 
1107  {
1108  v.resize(vtxdist.size());
1109 
1110  for (size_t i = 0; i < vtxdist.size(); ++i)
1111  {
1112  v.get(i) = vtxdist.get(i);
1113  }
1114  }
1115 
1121  {
1122  return &vtxdist;
1123  }
1124 
1130  {
1131  vtxdist.resize(vcl.getProcessingUnits() + 1);
1132  fvtxdist.resize(vcl.getProcessingUnits() + 1);
1133 
1134  for (size_t i = 0; i < vtxdist.size(); ++i)
1135  {
1136  vtxdist.get(i) = v.get(i);
1137  fvtxdist.get(i) = v.get(i);
1138  }
1139  }
1140 
1145  {
1146  updateVtxdist();
1147 
1148  fvtxdist.resize(vcl.getProcessingUnits() + 1);
1149 
1150  for (size_t i = 0; i < vtxdist.size(); ++i)
1151  {
1152  fvtxdist.get(i) = vtxdist.get(i);
1153  }
1154  }
1155 
1163  vcl(vcl)
1164  {
1165  swap(g);
1166  }
1167 
1176  {
1177  swap(g);
1178 
1179  return *this;
1180  }
1181 
1190  {
1191  swap(g.duplicate());
1192 
1193  return *this;
1194  }
1195 
1206  template<unsigned int i> auto vertex_p(size_t id) -> decltype( v.template get<i>(id) )
1207  {
1208  return v.template get<i>(id);
1209  }
1210 
1219  template<unsigned int i> auto vertex_p(grid_key_dx<1> id) -> decltype( v.template get<i>(id) )
1220  {
1221  return v.template get<i>(id);
1222  }
1223 
1231  auto vertex(size_t id) -> decltype( v.get(id) )
1232  {
1233  return v.get(id);
1234  }
1235 
1245  auto vertex(grid_key_dx<1> id) -> decltype( v.get(id.get(0)) )
1246  {
1247  return v.get(id.get(0));
1248  }
1249 
1259  auto vertex(openfpm::vector_key_iterator id) -> decltype( v.get(0) )
1260  {
1261  return v.get(id.get());
1262  }
1263 
1271  auto vertex(size_t id) const -> const decltype( v.get(id) )
1272  {
1273  return v.get(id);
1274  }
1275 
1285  auto vertex(grid_key_dx<1> id) const -> const decltype( v.get(id.get(0)) )
1286  {
1287  return v.get(id.get(0));
1288  }
1289 
1299  auto vertex(openfpm::vector_key_iterator id) const -> const decltype( v.get(0) )
1300  {
1301  return v.get(id.get());
1302  }
1303 
1313  auto vertex_info(openfpm::vector_key_iterator id) const -> const decltype( v_m.get(0) )
1314  {
1315  return v_m.get(id.get());
1316  }
1317 
1325  auto getVertex(size_t id) -> decltype( v.get(id) )
1326  {
1327 
1328 #ifdef SE_CLASS1
1329 
1330  if (glb2loc.find(id) == glb2loc.end())
1331  {
1332  std::cerr << __FILE__ << ":" << __LINE__ << " The vertex with global id " << id << " is not in this sub-graph. Try to call reqVertex(" << id << ") and sync() first.\n";
1333  ACTION_ON_ERROR(DIST_GRAPH_ERROR);
1334  }
1335 
1336 #endif
1337 
1338  return v.get(glb2loc.find(id)->second);
1339  }
1340 
1348  auto getVertex(size_t id) const -> const decltype( v.get(0) )
1349  {
1350  try
1351  {
1352  return v.get(glb2loc.at(id));
1353  } catch (const std::out_of_range& oor)
1354  {
1355  std::cerr << "The vertex with global id " << id << " is not in this sub-graph. Try to call reqVertex(" << id << ") and sync() first.\n";
1356  }
1357 
1358  return v.get(0);
1359  }
1360 
1370  size_t nodeById(size_t id) const
1371  {
1372  try
1373  {
1374  return glb2loc.at(id2glb.at(id));
1375  } catch (const std::out_of_range& oor)
1376  {
1377  std::cout << "Node not found by glb: " << id << std::endl;
1378  }
1379 
1380  return 0;
1381  }
1382 
1387  size_t firstId() const
1388  {
1389  return vtxdist.get(vcl.getProcessUnitID());
1390  }
1391 
1396  size_t lastId() const
1397  {
1398  return vtxdist.get(vcl.getProcessUnitID() + 1) - 1;
1399  }
1400 
1406  size_t getVertexId(size_t i) const
1407  {
1408  return v_m.get(i).template get<v_info::id>();
1409  }
1410 
1416  size_t getVertexGlobalId(size_t i) const
1417  {
1418  return v_m.get(i).template get<v_info::gid>();
1419  }
1420 
1426  bool vertexIsInThisGraph(size_t id)
1427  {
1428  auto search = glb2id.find(id);
1429 
1430  if (search != glb2id.end())
1431  {
1432  return true;
1433  }
1434  else
1435  {
1436  return false;
1437  }
1438  }
1439 
1449  void map_v(size_t n, size_t g, size_t l)
1450  {
1451  id2glb.insert( { n, g });
1452  glb2id.insert( { g, n });
1453  glb2loc.insert( { g, l });
1454  v_m.get(l).template get<v_info::id>() = n;
1455  }
1456 
1462  void clear()
1463  {
1464  v.clear();
1465  v_m.clear();
1466  e.clear();
1467  id2glb.clear();
1468  glb2id.clear();
1469  glb2loc.clear();
1470  v_l.clear();
1471  e_l.clear();
1472  e_invalid.clear();
1473  }
1474 
1483  template<unsigned int i> auto edge_p(grid_key_dx<1> id) -> decltype ( e.template get<i>(id) )
1484  {
1485  return e.template get<i>(id);
1486  }
1487 
1496  template<unsigned int i> auto edge_p(size_t id) -> decltype ( e.template get<i>(id) )
1497  {
1498  return e.template get<i>(id);
1499  }
1500 
1508  auto edge(grid_key_dx<1> id) const -> const decltype ( e.get(id.get(0)) )
1509  {
1510  return e.get(id.get(0));
1511  }
1512 
1520  auto edge(edge_key ek) const -> const decltype ( e.get(0) )
1521  {
1522  return e.get(e_l.template get<e_map::eid>(ek.pos * v_slot + ek.pos_e));
1523  }
1524 
1532  auto getEdge(edge_key ek) const -> const decltype ( e.get(0) )
1533  {
1534  size_t v;
1535 
1536  try
1537  {
1538  v = glb2loc.at(ek.pos);
1539  } catch (const std::out_of_range& oor)
1540  {
1541  std::cout << "The source vertex of this edge is not in this graph.\n";
1542  }
1543 
1544  return e.get(e_l.template get<e_map::eid>(v * v_slot + ek.pos_e));
1545  }
1546 
1556  auto edge(size_t id) const -> const decltype ( e.get(id) )
1557  {
1558  return e.get(id);
1559  }
1560 
1568  inline size_t getNChilds(size_t c) const
1569  {
1570  return v_l.template get<0>(c);
1571  }
1572 
1580  inline size_t getNChilds(typename openfpm::vector<V, Memory, layout_v_base, grow_p, openfpm::vect_isel<V>::value>::iterator_key & c)
1581  {
1582  return v_l.template get<0>(c.get());
1583  }
1584 
1592  inline size_t getNEdge(size_t v) const
1593  {
1594  try
1595  {
1596  v = glb2loc.at(v);
1597  } catch (const std::out_of_range& oor)
1598  {
1599  std::cout << "The source vertex of this edge is not in this graph.\n";
1600  }
1601 
1602  return v_l.template get<0>(v);
1603  }
1604 
1613  inline auto getChildEdge(size_t v, size_t v_e) -> decltype(e.get(0))
1614  {
1615  return e.get(e_l.template get<e_map::eid>(v * v_slot + v_e));
1616  }
1617 
1626  inline auto getChildInfo(size_t v, size_t v_e) -> decltype(e_m.get(0))
1627  {
1628  return e_m.get(e_l.template get<e_map::eid>(v * v_slot + v_e));
1629  }
1630 
1639  inline auto getEdge(size_t v, size_t v_e) -> decltype(e.get(0))
1640  {
1641  try
1642  {
1643  v = glb2loc.at(v);
1644  } catch (const std::out_of_range& oor)
1645  {
1646  std::cout << "The source vertex of this edge is not in this graph.\n";
1647  }
1648 
1649  return e.get(e_l.template get<e_map::eid>(v * v_slot + v_e));
1650  }
1651 
1660  inline size_t getChild(size_t v, size_t i) const
1661  {
1662 #ifdef SE_CLASS1
1663  if (i >= v_l.template get<0>(v))
1664  {
1665  std::cerr << "Error " << __FILE__ << " line: " << __LINE__ << " vertex " << v << " does not have edge " << i << " on processor " << vcl.getProcessUnitID() << "\n";
1666  }
1667 
1668  if (e.size() <= e_l.template get<e_map::eid>(v * v_slot + i))
1669  {
1670  std::cerr << "Error " << __FILE__ << " " << __LINE__ << " vertex " << v << " does not have edge " << i << " on processor " << vcl.getProcessUnitID() << " (" << e.size() << "<=" << e_l.template get<e_map::eid>(v * v_slot + i) << ")\n";
1671  }
1672 #endif
1673  // Get the edge id
1674  return e_l.template get<e_map::vid>(v * v_slot + i);
1675  }
1676 
1684  inline size_t getChild(size_t i) const
1685  {
1686  // Get the edge id
1687  return e_l.template get<e_map::vid>(i);
1688  }
1689 
1698  inline size_t getChild(typename openfpm::vector<V, Memory, layout_v_base, grow_p, openfpm::vect_isel<V>::value>::iterator_key & v, size_t i)
1699  {
1700 #ifdef DEBUG
1701  if (i >= v_l.template get<0>(v.get()))
1702  {
1703  std::cerr << "Error " << __FILE__ << " line: " << __LINE__ << " vertex " << v.get() << " does not have edge " << i << "\n";
1704  }
1705 
1706  if (e.size() <= e_l.template get<e_map::eid>(v.get() * v_slot + i))
1707  {
1708  std::cerr << "Error " << __FILE__ << " " << __LINE__ << " vertex " << v.get() << " does not have edge " << i << "\n";
1709  }
1710 #endif
1711 
1712  // Get the edge id
1713  return e_l.template get<e_map::vid>(v.get() * v_slot + i);
1714  }
1715 
1722  inline void add_vertex(const V & vrt, size_t id, size_t gid)
1723  {
1724  // Create vertex info object
1725  v_info vm;
1726  vm.template get<v_info::id>() = id;
1727  vm.template get<v_info::gid>() = gid;
1728 
1729  // Add the vertex info
1730  v_m.add(vm);
1731 
1732  // Add the vertex
1733  v.add(vrt);
1734 
1735  // Update id to global map
1736  id2glb.insert( { id, gid });
1737 
1738  // Update global id to local index
1739  glb2loc.insert( { gid, v.size() - 1 });
1740 
1741  // Update global id to id
1742  glb2id.insert( { gid, id });
1743 
1744  // Set the number of adjacent vertex for this vertex to 0
1745  v_l.add(0ul);
1746 
1747  // Add a slot for the vertex adjacency list
1748  e_l.resize(e_l.size() + v_slot);
1749  }
1750 
1757  template<unsigned int dim, typename Mem> inline void add_vertex(const encapc<dim, V, Mem> & vrt, size_t id, size_t gid)
1758  {
1759  // Create vertex info object
1760  v_info vm;
1761  vm.template get<v_info::id>() = id;
1762  vm.template get<v_info::gid>() = gid;
1763 
1764  // Add the vertex info
1765  v_m.add(vm);
1766 
1767  // Add the vertex
1768  v.add(vrt);
1769 
1770  // Update id to global map
1771  id2glb.insert( { id, gid });
1772 
1773  // Update global id to local index
1774  glb2loc.insert( { gid, v.size() - 1 });
1775 
1776  // Update global id to id
1777  glb2id.insert( { gid, id });
1778 
1779  // Set the number of adjacent vertex for this vertex to 0
1780  v_l.add(0ul);
1781 
1782  // Add a slot for the vertex adjacency list
1783  e_l.resize(e_l.size() + v_slot);
1784  }
1785 
1791  inline void add_vertex(const V & vrt, size_t gid)
1792  {
1793  add_vertex(vrt, gid, gid);
1794  }
1795 
1802  void setGlobalMap(size_t g, size_t l, size_t i)
1803  {
1804  v_m.template get<v_info::id>(l) = i;
1805 
1806  v_m.template get<v_info::gid>(l) = g;
1807 
1808  // Set global id to local index
1809  glb2loc.insert( { g, l });
1810 
1811  // Set global id to id
1812  glb2id.insert( { g, i });
1813 
1814  // Set id to global map
1815  id2glb.insert( { i, g });
1816  }
1817 
1818  inline auto addEdge(size_t v1, size_t v2, size_t srcgid, size_t dstgid) -> decltype(e.get(0))
1819  {
1820  // add an edge
1821  long int id_x_end = addEdge_<NoCheck>(v1, v2);
1822  // If there is not edge return an invalid edge, is a kind of stub object
1823  if (id_x_end == NO_EDGE)
1824  return e_invalid.get(0);
1825 
1826  // set source and destination global ids of the edge
1827  e_m.template get<e_info::sgid>(id_x_end) = srcgid;
1828  e_m.template get<e_info::dgid>(id_x_end) = dstgid;
1829 
1830  // return the edge to change the properties
1831  return e.get(id_x_end);
1832  }
1833 
1834  inline auto addEdge(size_t v1, size_t v2, size_t srcgid, size_t dstgid, const E & ed) -> decltype(e.get(0))
1835  {
1836  // add an edge
1837  long int id_x_end = addEdge_<NoCheck>(v1, v2);
1838  // If there is not edge return an invalid edge, is a kind of stub object
1839  if (id_x_end == NO_EDGE)
1840  return e_invalid.get(0);
1841 
1842  // add in e_l the edge properties
1843  e.set(id_x_end, ed);
1844 
1845  // set source and destination global ids of the edge
1846  e_m.template get<e_info::sgid>(id_x_end) = srcgid;
1847  e_m.template get<e_info::dgid>(id_x_end) = dstgid;
1848 
1849  // return the edge to change the properties
1850  return e.get(id_x_end);
1851  }
1852 
1853  template<unsigned int dim, typename Mem, typename Mem1> inline auto addEdge(size_t v1, size_t v2, const encapc<dim, E, Mem> & ed, const encapc<dim, e_info, Mem1> & ei) -> decltype(e.get(0))
1854  {
1855  // add an edge
1856  long int id_x_end = addEdge_<NoCheck>(v1, v2);
1857  // If there is not edge return an invalid edge, is a kind of stub object
1858  if (id_x_end == NO_EDGE)
1859  return e_invalid.get(0);
1860 
1861  // set the edge object and the edge info object
1862  e.set(id_x_end, ed);
1863  e_m.set(id_x_end, ei);
1864 
1865  // return the edge to change the properties
1866  return e.get(id_x_end);
1867  }
1868 
1869  inline auto addEdge(size_t v1, size_t v2, const E & ed, const e_info & ei) -> decltype(e.get(0))
1870  {
1871  // add an edge
1872  long int id_x_end = addEdge_<NoCheck>(v1, v2);
1873  // If there is not edge return an invalid edge, is a kind of stub object
1874  if (id_x_end == NO_EDGE)
1875  return e_invalid.get(0);
1876 
1877  // set the edge object and the edge info object
1878  e.set(id_x_end, ed);
1879  e_m.set(id_x_end, ei);
1880 
1881  // return the edge to change the properties
1882  return e.get(id_x_end);
1883  }
1884 
1891  size_t getChildSrcGid(size_t v1, size_t s)
1892  {
1893  size_t eid = e_l.template get<e_map::eid>(v1 * v_slot + s);
1894  return e_m.template get<e_info::sgid>(eid);
1895  }
1896 
1903  size_t getChildDstGid(size_t v1, size_t s)
1904  {
1905  size_t eid = e_l.template get<e_map::eid>(v1 * v_slot + s);
1906  return e_m.template get<e_info::dgid>(eid);
1907  }
1908 
1914  template<typename CheckPolicy = NoCheck> inline void add_edge(size_t v1, size_t v2)
1915  {
1916  //if the source vertex is not in this graph, this processor doesn't need to do anything
1917  if (!vertexIsInThisGraph(v1))
1918  {
1919  return;
1920  }
1921 
1922  //if the destination vertex is not in this graph, this processor has to request it and add the edge to a queue
1923  if (!vertexIsInThisGraph(v2))
1924  {
1925  reqVertex(v2);
1926  EdgeReq er = { v1, v2, 0, 0 };
1927  e_queue.add(er);
1928 
1929  return;
1930  }
1931 
1932  // add an edge
1933  long int id_x_end = addEdge_<CheckPolicy>(glb2loc.at(v1), glb2id.at(v2));
1934 
1935  // If there is not edge return an invalid edge, is a kind of stub object
1936  if (id_x_end == NO_EDGE)
1937  return;
1938 
1939  // set source and destination ids of the edge
1940  e_m.get(id_x_end).template get<e_info::sgid>() = v1;
1941  e_m.get(id_x_end).template get<e_info::dgid>() = v2;
1942  }
1943 
1947  void syncEdge()
1948  {
1949  // retrieve ghosts necessary for edge adding
1950  sync();
1951 
1952  // update with real values of edges, we don't add the edge here because it will modify edge's array length
1953  for (size_t i = 0; i < e_queue.size(); ++i)
1954  {
1955  e_queue.get(i).v1n = glb2loc.at(e_queue.get(i).v1);
1956  e_queue.get(i).v2n = glb2id.at(e_queue.get(i).v2);
1957  }
1958 
1959  deleteGhosts();
1960 
1961  for (auto req : e_queue)
1962  {
1963  // add an edge
1964  long int id_x_end = addEdge_<>(req.v1n, req.v2n);
1965 
1966  // If there is not edge return an invalid edge, is a kind of stub object
1967  if (id_x_end == NO_EDGE)
1968  return;
1969 
1970  // set source and destination ids of the edge
1971  e_m.get(id_x_end).template get<e_info::sgid>() = req.v1;
1972  e_m.get(id_x_end).template get<e_info::dgid>() = req.v2;
1973  }
1974 
1975  e_queue.clear();
1976 
1977  }
1978 
1986  inline void swap(DistGraph_CSR<V, E> & g)
1987  {
1988  // switch the memory
1989  v.swap(g.v);
1990  v_m.swap(g.v_m);
1991  e.swap(g.e);
1992  e_m.swap(g.e_m);
1993  v_l.swap(g.v_l);
1994  glb2id.swap(g.glb2id);
1995  id2glb.swap(g.id2glb);
1996  glb2loc.swap(g.glb2loc);
1997  e_l.swap(g.e_l);
1998  e_invalid.swap(g.e_invalid);
1999  vtxdist.swap(g.vtxdist);
2000  fvtxdist.swap(g.fvtxdist);
2001 
2002  size_t v_slot_tmp = v_slot;
2003  v_slot = g.v_slot;
2004  g.v_slot = v_slot_tmp;
2005  }
2006 
2014  inline void swap(DistGraph_CSR<V, E> && g)
2015  {
2016  // switch the memory
2017  v.swap(g.v);
2018  v_m.swap(g.v_m);
2019  e.swap(g.e);
2020  e_m.swap(g.e_m);
2021  v_l.swap(g.v_l);
2022  glb2id.swap(g.glb2id);
2023  id2glb.swap(g.id2glb);
2024  glb2loc.swap(g.glb2loc);
2025  e_l.swap(g.e_l);
2026  e_invalid.swap(g.e_invalid);
2027  vtxdist.swap(g.vtxdist);
2028  fvtxdist.swap(g.fvtxdist);
2029 
2030  size_t v_slot_tmp = v_slot;
2031  v_slot = g.v_slot;
2032  g.v_slot = v_slot_tmp;
2033  }
2034 
2042  inline auto getVertexIterator() const -> decltype(v.getIterator())
2043  {
2044  return v.getIterator();
2045  }
2046 
2055  {
2057  }
2058 
2064  inline size_t getNVertex() const
2065  {
2066  return v.size();
2067  }
2068 
2074  inline size_t getTotNVertex() const
2075  {
2076  return vtxdist.get(vcl.getProcessingUnits());
2077  }
2078 
2084  inline size_t getNEdge() const
2085  {
2086  return e.size();
2087  }
2088 
2092  void init()
2093  {
2095 
2096  initGlbimap();
2097 
2098  remap();
2099  }
2100 
2106  bool isGhost(size_t id)
2107  {
2108  auto search = ghs_map.find(id);
2109 
2110  if (search != ghs_map.end())
2111  {
2112  return true;
2113  }
2114  else
2115  {
2116  return false;
2117  }
2118  }
2119 
2124  {
2125  if (ghs_map.size() == 0)
2126  return;
2127 
2128  // Prepare new graph
2129  DistGraph_CSR recv_g;
2130 
2131  size_t fpos = getNVertex() - ghs_map.size();
2132  size_t epos = 0;
2133 
2134  // Reset global to local map
2135  for (auto gh : ghs_map)
2136  {
2137  epos += getNChilds(glb2loc.at(gh.first));
2138  id2glb.erase(glb2id.at(gh.first));
2139  glb2loc.erase(gh.first);
2140  glb2id.erase(gh.first);
2141 
2142  }
2143 
2144  //resize all structures to delete the ghosts
2145  v.resize(fpos);
2146  v_m.resize(fpos);
2147  v_l.resize(fpos);
2148  e.resize(e.size() - epos);
2149  e_m.resize(e_m.size() - epos);
2150  e_l.resize(fpos * v_slot);
2151 
2152  // Clear ghosts map
2153  ghs_map.clear();
2154  }
2155 
2163  template<bool toRemove = true> //TODO make it private and create wrapper in public
2164  void q_move(size_t i, size_t t)
2165  {
2166  // Check if a 'useless' move has been requested
2167  if (t == vcl.getProcessUnitID())
2168  {
2169  std::cerr << "Warning: " << __FILE__ << ":" << __LINE__ << " target processor is equal the local processor\n";
2170  return;
2171  }
2172 
2173  // If the array for t processor is empty, set it to not empty
2174  if (sgp.get(t).isEmpty)
2175  sgp.get(t).isEmpty = false;
2176 
2177  // Add the vertex to the vertex send buffer
2178  sgp.get(t).send_v.add(vertex(i));
2179 
2180  // Add the vertex to the vertex send buffer
2181  sgp.get(t).send_v_m.add(v_m.get(i));
2182 
2183  // Add the info about the number of children
2184  sgp.get(t).send_es.add(getNChilds(i));
2185 
2186  for (size_t s = 0; s < getNChilds(i); s++)
2187  {
2188  // Add edge value and object to the respective arrays
2189  sgp.get(t).send_e.add(getChildEdge(i, s));
2190  sgp.get(t).send_e_m.add(getChildInfo(i, s));
2191  sgp.get(t).send_el.add(getChild(i, s));
2192  }
2193 
2194  // If the vertex has to be removed after the send add its index id to the v_td array
2195  if (toRemove)
2196  v_td.add(i);
2197  }
2198 
2204  {
2205  size_t exs = 0;
2206  for (size_t i = 0; i < vcl.getProcessingUnits(); ++i)
2207  if (sgp.get(i).isEmpty)
2208  exs++;
2209 
2210  if (exs == 0)
2211  return true;
2212 
2213  return false;
2214  }
2215 
2220  {
2221  if (glbi_map.size() == 0)
2222  initGlbimap();
2223 
2224  deleteGhosts();
2225 
2226  exchangeVertices<false>();
2227 
2228  updateVtxdist();
2229 
2230  remap();
2231  }
2232 
2237  void reqVertex(size_t gid)
2238  {
2239  // if not initialized, prepare vr_queue
2240  if (vr_queue.size() == 0)
2241  vr_queue.resize(vcl.getProcessingUnits());
2242 
2243  if (!vertexIsInThisGraph(gid))
2244  {
2245  vr_queue.get(getInfoProc(gid)).add(gid);
2246  }
2247 
2248  }
2249 
2253  void sync()
2254  {
2255  // If not initialized, prepare global informations map
2256  if (glbi_map.size() == 0)
2257  initGlbimap();
2258 
2259  // if not initialized, prepare vr_queue
2260  if (vr_queue.size() == 0) // TODO remove check on size
2261  vr_queue.resize(vcl.getProcessingUnits());
2262 
2263  // Arrays that will contain temporary requests and responses during communications TODO move to global private and reset method
2266 
2267  // Prepare structures for communication
2271 
2272  // Fill the structures for sendrecvMultipleMessagesNBX function
2273  fillSendRecvStructs<size_t>(vr_queue, prc, size, ptr);
2274 
2275  // Send/receive requests for info about needed vertices
2276  vcl.sendrecvMultipleMessagesNBX(prc.size(), (size_t *)size.getPointer(), (size_t *)prc.getPointer(), (void **)ptr.getPointer(), on_receive, &resp, NONE);
2277 
2278  // Prepare responses with the containing processors of requested vertices
2279  for (size_t i = 0; i < resp.size(); ++i)
2280  {
2281  reqs.get(i).clear();
2282 
2283  for (size_t j = 0; j < resp.get(i).size(); ++j)
2284  {
2285  try
2286  {
2287  reqs.get(i).add(glbi_map.at(resp.get(i).get(j)).pid);
2288  } catch (const std::out_of_range& oor)
2289  {
2290  std::cout << resp.get(i).get(j) << " not found in global info map (proc: " << vcl.getProcessUnitID() << ")\n";
2291  }
2292  }
2293  }
2294 
2295  // Fill the structures for sendrecvMultipleMessagesNBX function
2296  fillSendRecvStructs<size_t>(reqs, prc, size, ptr);
2297 
2298  // Reset response array TODO clear and resize not needed
2299  resp.clear();
2300  resp.resize(vcl.getProcessingUnits());
2301 
2302  // Send/receive responses with the containing processors of requested vertices
2303  vcl.sendrecvMultipleMessagesNBX(prc.size(), (size_t *)size.getPointer(), (size_t *)prc.getPointer(), (void **)ptr.getPointer(), on_receive, &resp, NONE);
2304 
2305  // Clear requests array
2306  reqs.clear();
2307  reqs.resize(vcl.getProcessingUnits());
2308 
2309  // Prepare vertices requests
2310  for (size_t i = 0; i < vcl.getProcessingUnits(); ++i)
2311  {
2312  // If the info has been retrieved from other processors take it from resp
2313  if (i != vcl.getProcessUnitID())
2314  {
2315  for (size_t j = 0; j < vr_queue.get(i).size(); ++j)
2316  {
2317  reqs.get(resp.get(i).get(j)).add(vr_queue.get(i).get(j));
2318  }
2319  }
2320  // Otherwise take it from the global info map of this processor
2321  else
2322  {
2323  for (size_t j = 0; j < vr_queue.get(i).size(); ++j)
2324  {
2325  reqs.get(glbi_map.at(vr_queue.get(i).get(j)).pid).add(vr_queue.get(i).get(j));
2326  }
2327  }
2328  }
2329 
2330  // Fill the structures for sendrecvMultipleMessagesNBX function
2331  fillSendRecvStructs<size_t>(reqs, prc, size, ptr);
2332 
2333  // Reset response array
2334  resp.clear();
2335  resp.resize(vcl.getProcessingUnits());
2336 
2337  // Send/receive vertices requests
2338  vcl.sendrecvMultipleMessagesNBX(prc.size(), (size_t *)size.getPointer(), (size_t *)prc.getPointer(), (void **)ptr.getPointer(), on_receive, &resp, NONE);
2339 
2340  for (size_t i = 0; i < resp.size(); ++i)
2341  {
2342  for (size_t j = 0; j < resp.get(i).size(); ++j)
2343  {
2344  try
2345  {
2346  q_move<false>(glb2loc.at(resp.get(i).get(j)), i);
2347  } catch (const std::out_of_range& oor)
2348  {
2349  std::cout << resp.get(i).get(j) << " not found in global to local map (proc: " << vcl.getProcessUnitID() << ")\n";
2350  }
2351  }
2352  }
2353 
2354  // Send and receive vertices, the received ones will be added to the graph as ghosts
2355  exchangeVertices<true>();
2356 
2357  // Empty the requests list
2358  vr_queue.clear();
2359  }
2360 };
2361 
2386 template<typename V, typename E>
2387 class DistGraph_CSR_s: public DistGraph_CSR<V, E>
2388 {
2389 
2390 };
2391 
2392 #endif /* DIST_MAP_GRAPH_HPP_ */
void exchangeVertices()
Send and receive vertices and update current graph.
void clear()
operator to clear the whole graph
void syncEdge()
Execute a synchronization through processor to finalize the add of the edges requested in the e_queue...
auto vertex_p(size_t id) -> decltype(v.template get< i >(id))
operator to access the vertex
openfpm::vector< e_map, Memory, layout_e_base, grow_p, openfpm::vect_isel< e_map >::value > e_l
Structure that store for each vertex the adjacent the vertex id and edge id (for property into e)
DistGraph_CSR()
Constructor.
void add_vertex(const V &vrt, size_t id, size_t gid)
Add vertex vrt with global id and id properties.
size_t getNChilds(size_t c) const
Return the number of children of a vertex.
openfpm::vector< V > send_v
vertex send buffer
void q_move(size_t i, size_t t)
Prepare to send vertex i from the local processor to the target processor.
Transform the boost::fusion::vector into memory specification (memory_traits)
size_t getProcessUnitID()
Get the process unit id.
void deleteMovedVertices()
Remove from this graph the vertices that have been sent.
auto edge(size_t id) const -> const decltype(e.get(id))
operator to access the edge
size_t getNEdge(size_t v) const
Return the number of children of a vertex given its global id.
size_t getNVertex() const
Return the number of the vertices in this subgraph.
openfpm::vector< size_t > send_es
For each vertex contain the number of children.
static void * on_receive(size_t msg_i, size_t total_msg, size_t total_p, size_t i, size_t ri, size_t tag, void *ptr)
Callback of the sendrecv to set the size of the array received.
V V_type
Vertex typedef.
auto edge_p(grid_key_dx< 1 > id) -> decltype(e.template get< i >(id))
Access the edge.
Grow policy define how the vector should grow every time we exceed the size.
openfpm::vector< e_info > send_e_m
edge info send buffer
void sendrecvMultipleMessagesNBX(openfpm::vector< size_t > &prc, openfpm::vector< T > &data, openfpm::vector< size_t > &prc_recv, openfpm::vector< size_t > &recv_sz, void *(*msg_alloc)(size_t, size_t, size_t, size_t, size_t, size_t, void *), void *ptr_arg, long int opt=NONE)
Send and receive multiple messages.
openfpm::vector< V, Memory, layout_v_base, grow_p, openfpm::vect_isel< V >::value > v
Structure that store the vertex properties.
grid_key_dx is the key to access any element in the grid
Definition: grid_key.hpp:18
openfpm::vector< idx_t > fvtxdist
Fixed distribution vector, it never changes, it maintains always the first decomposition and topology...
openfpm::vector< E, Memory, layout_e_base, grow_p, openfpm::vect_isel< E >::value >::container E_container
Object container for the edge, for example can be encap<...> (map_grid or openfpm::vector)
auto vertex(grid_key_dx< 1 > id) -> decltype(v.get(id.get(0)))
operator to access the vertex
Structure needed to get vertex position by global id.
openfpm::vector< idx_t > vtxdist
Distribution vector.
DistGraph_CSR(Vcluster<> &vcl, DistGraph_CSR< V, E, Memory > &&g)
Copy constructor.
bool isEmpty
Indicates if the pack is empty or not.
void getDecompositionVector(openfpm::vector< idx_t > &v)
Operator to access the decomposition vector.
void map_v(size_t n, size_t g, size_t l)
operator to update all the hashmap
std::unordered_map< size_t, bool > ghs_map
Map containing the ghost vertices of this graph, if bool is false the ghost will be deleted in the ne...
auto edge_p(size_t id) -> decltype(e.template get< i >(id))
Access the edge.
void swap(DistGraph_CSR< V, E > &g)
Swap the memory of g with this graph.
bool allGather(T &send, openfpm::vector< T, Mem, gr > &v)
Gather the data from all processors.
size_t getChildDstGid(size_t v1, size_t s)
Get the global id of edge's destination vertex.
DistGraph_CSR< V, E, Memory, layout_v, layout_e, layout_v_base, layout_e_base, grow_p > duplicate() const
It duplicate the graph.
size_t getChild(size_t i) const
Get the child edge.
openfpm::vector< size_t > v_td
Array containing the sent vertices and that will be deleted from the graph.
openfpm::vector< SendGraphPack > sgp
Pack storing that data to send to other processors.
Structure to store a add request of an edge.
std::unordered_map< size_t, size_t > id2glb
Map to access to the global vertex id given the vertex id.
Vcluster & vcl
Vcluster communication object.
bool isToDelete(size_t i)
Check it the vertex i must be deleted or not.
void reqVertex(size_t gid)
Put a vertex request in queue.
size_t getChild(size_t v, size_t i) const
Get the child edge.
Simplified implementation of DistGraph_CSR.
void deleteGhosts()
Remove all the ghosts from this graph.
bool moveQueueIsEmpty()
Check if the move queue is empty.
size_t firstId() const
openfpm::vector< v_info, Memory, memory_traits_lin, grow_p, openfpm::vect_isel< v_info >::value > v_m
Structure that store the vertex id and global id.
Graph edge iterator.
Definition: map_graph.hpp:167
auto getChildEdge(size_t v, size_t v_e) -> decltype(e.get(0))
Get the vertex edge.
openfpm::vector< size_t, Memory, layout_v_base, grow_p, openfpm::vect_isel< size_t >::value > v_l
Structure that store the number of adjacent vertex in e_l for each vertex.
size_t size()
Stub size.
Definition: map_vector.hpp:211
DistGraph_CSR(const DistGraph_CSR &dg)
Constructor.
size_t getVertexId(size_t i) const
Get the id of a vertex given its index position.
void updateVtxdist()
Update the distribution vector vtxdist.
This class allocate, and destroy CPU memory.
Definition: HeapMemory.hpp:39
void sync()
Execute all vertex requests and add them as ghosts inside this graph, they will be available until a ...
Implementation of VCluster class.
Definition: VCluster.hpp:58
void execute()
Execute all the requests.
bool isGhost(size_t id)
Check if a vertex is a ghost vertex (not belonging to this processor)
size_t getVertexGlobalId(size_t i) const
Get the id of a vertex given its index position.
size_t getNChilds(typename openfpm::vector< V, Memory, layout_v_base, grow_p, openfpm::vect_isel< V >::value >::iterator_key &c)
Return the number of childs of a vertex.
std::unordered_map< size_t, size_t > glb2id
Map to access the vertex id given the global vertex id.
std::unordered_map< size_t, GlobalVInfo > glbi_map
TODO update description from pdf.
void fillSendRecvStructs(openfpm::vector< openfpm::vector< T >> &vec, openfpm::vector< size_t > &prc, openfpm::vector< size_t > &size, openfpm::vector< void * > &ptr)
Fill the prc, size and ptr structures with the data of vec.
auto vertex(size_t id) const -> const decltype(v.get(id))
Function to access the vertexes.
void remap()
Re-map received vertices in order to have ordered vertex ids.
E E_type
Edge typedef.
DistGraph_CSR< V, E, Memory > & operator=(DistGraph_CSR< V, E, Memory > &&g)
Copy the graph.
void add_vertex(const encapc< dim, V, Mem > &vrt, size_t id, size_t gid)
Add vertex vrt with global id and id properties.
size_t getChild(typename openfpm::vector< V, Memory, layout_v_base, grow_p, openfpm::vect_isel< V >::value >::iterator_key &v, size_t i)
Get the child edge.
static size_t packRequest(const T &obj, size_t &req)
Error, no implementation.
Definition: Packer.hpp:66
DistGraph_CSR< V, E, Memory > & operator=(const DistGraph_CSR< V, E, Memory > &g)
Copy the graph.
virtual size_t size() const
the the size of the allocated memory
Definition: HeapMemory.cpp:153
It analyze the type given and it select correctly the implementation for vector.
Definition: vect_isel.hpp:36
void resetExchange()
Init communication structures.
auto edge(grid_key_dx< 1 > id) const -> const decltype(e.get(id.get(0)))
Access the edge.
size_t getVProcessor(size_t v)
Get the processor of the the given vertex id, CAN be used BEFORE re-mapping starts.
openfpm::vector< e_info, Memory, layout_e_base, grow_p, openfpm::vect_isel< e_info >::value > e_m
Structure that store the edge properties.
size_t v1
source vertex
auto vertex(openfpm::vector_key_iterator id) -> decltype(v.get(0))
operator to access the vertex
Packing class.
Definition: Packer.hpp:49
DistGraph_CSR(size_t n_vertex, size_t n_slot)
Constructor.
openfpm::vector< size_t > send_el
For each edge contain the child vertex id.
class with no edge
Definition: map_graph.hpp:57
size_t nodeById(size_t id) const
operator to access the vertex position index by id property
size_t getNEdge() const
Return the number of edges.
size_t getInfoProc(size_t vid)
Get the processor id of the processor containing the vertex with global id vid.
auto vertex(openfpm::vector_key_iterator id) const -> const decltype(v.get(0))
operator to access the vertex
size_t getProcessingUnits()
Get the total number of processors.
virtual void incRef()
Increment the reference counter.
Definition: ExtPreAlloc.hpp:98
Structure that store a graph in CSR format or basically in compressed adjacency matrix format.
Unpacking status object.
Definition: Pack_stat.hpp:15
void initDistributionVector()
Initialize the vtxdist and the fvtxdist.
Struct containing the (sub)graph to send.
void redistribute()
Redistribute function that wraps different stages of the redistribution.
auto vertex_info(openfpm::vector_key_iterator id) const -> const decltype(v_m.get(0))
operator to access the vertex info
auto vertex_p(grid_key_dx< 1 > id) -> decltype(v.template get< i >(id))
Access the vertex.
openfpm::vector< V, Memory, layout_v_base, grow_p, openfpm::vect_isel< V >::value >::container V_container
Object container for the vertex, for example can be encap<...> (map_grid or openfpm::vector)
void * getPointerBase()
The the base pointer of the preallocate memory.
static void unpack(ExtPreAlloc< Mem >, T &obj)
Error, no implementation.
Definition: Unpacker.hpp:40
void initGlbimap()
Initialize the fixed structure for global mapping. See glbiv for details.
size_t lastId() const
void swap(DistGraph_CSR< V, E > &&g)
Swap the memory of g with this graph.
void setGlobalMap(size_t g, size_t l, size_t i)
map global id to local id
openfpm::vector< idx_t > * getVtxdist()
Operator to access the decomposition vector.
auto getChildInfo(size_t v, size_t v_e) -> decltype(e_m.get(0))
Get the vertex edge info.
size_t v1n
source vertex global index
auto getEdge(size_t v, size_t v_e) -> decltype(e.get(0))
Get the vertex edge given the vertex global id as source.
auto edge(edge_key ek) const -> const decltype(e.get(0))
operator to access the edge
auto getVertex(size_t id) const -> const decltype(v.get(0))
Function to access the vertexes.
static void * gr_receive(size_t msg_i, size_t total_msg, size_t total_p, size_t i, size_t ri, size_t tag, void *ptr)
Callback to set the size of the receiving vector.
void add_edge(size_t v1, size_t v2)
Add an edge between vertices v1 end v2, needs syncEdge() to complete the action.
void add_vertex(const V &vrt, size_t gid)
Add vertex vrt with global id and id properties.
size_t v_slot
number of slot per vertex
openfpm::vector< EdgeReq > e_queue
Queue of requests to add edges.
auto getVertex(size_t id) -> decltype(v.get(id))
Function to access the vertexes.
openfpm::vector< E > send_e
edge send buffer
DistGraph_CSR(DistGraph_CSR &&dg)
Constructor.
size_t addEdge_(size_t v1, size_t v2)
add edge on the graph
size_t getTotNVertex() const
Return the total number of the vertices.
auto vertex(grid_key_dx< 1 > id) const -> const decltype(v.get(id.get(0)))
operator to access the vertex
bool vertexIsInThisGraph(size_t id)
Check if the vertex with GLOBAL id is in this graph.
openfpm::vector< E, Memory, layout_e_base, grow_p, openfpm::vect_isel< E >::value > e
Structure that store the edge properties.
auto getEdge(edge_key ek) const -> const decltype(e.get(0))
operator to access the edge
std::unordered_map< size_t, size_t > glb2loc
Map to access the local vertex id given the global one.
openfpm::vector< v_info > send_v_m
vertex info send buffer
Packing status object.
Definition: Pack_stat.hpp:60
Definition: ids.hpp:148
static void pack(ExtPreAlloc< Mem >, const T &obj)
Error, no implementation.
Definition: Packer.hpp:56
auto getVertexIterator() const -> decltype(v.getIterator())
Get the vertex iterator.
edge_iterator< DistGraph_CSR< V, E, Memory > > getEdgeIterator() const
Get the vertex iterator.
DistGraph_CSR(size_t n_vertex)
Constructor.
size_t getChildSrcGid(size_t v1, size_t s)
Get the global id of edge's source vertex.
size_t v2
target vertex
auto vertex(size_t id) -> decltype(v.get(id))
Function to access the vertexes.
void init()
Once added all the vertices this function must be called to initialize all the properties,...
openfpm::vector< E, Memory, layout_e_base, grow_p, openfpm::vect_isel< E >::value > e_invalid
invalid edge element, when a function try to create an in valid edge this object is returned
size_t v2n
destination vertex global index
void initDistributionVector(openfpm::vector< idx_t > &v)
Operator to access the decomposition vector.
openfpm::vector< openfpm::vector< size_t > > vr_queue
Queue of vertex requests.