OpenFPM_pdata  1.1.0
Project that contain the implementation of distributed structures
 All Data Structures Namespaces Functions Variables Typedefs Enumerations Friends Pages
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 
254  typedef struct
255  {
269  bool isEmpty = true;
270  } SendGraphPack;
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 NO_EDGE;
330  if (CheckPolicy::valid(v2, v.size()) == false)
331  return 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, 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, 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 
562 
563  // Total number of vertex to send
564  size_t nvts = 0;
565  for (size_t i = 0; i < vcl.getProcessingUnits(); i++)
566  {
567  nvts += sgp.get(i).send_v.size();
568  }
569 
570  // For each processor
571  for (size_t i = 0; i < vcl.getProcessingUnits(); i++)
572  {
573  // if nothing to send continue
574  if (sgp.get(i).isEmpty)
575  continue;
576 
577  // process to communicate with TODO remove pc
578  size_t pc = i;
579 
580  size_t vp_size = sgp.get(pc).send_v.size();
581 
582  size_t req = 0;
583 
584  // prepare slot for number of vertices
586 
587  for (size_t j = 0; j < vp_size; j++)
588  {
589  // prepare slot for vertex
591 
592  // prepare slot info for vertex
594 
595  // prepare slot for the number of children
597 
598  // prepare slots for the children
599  for (size_t k = 0; k < sgp.get(pc).send_es.get(j); k++)
600  {
601  // prepare slot for edge
603 
604  // prepare slot for edge info
606 
607  // prepare slot for edge target id
609  }
610  }
611 
612  // allocate the memory
613  HeapMemory & pmem = *(new HeapMemory());
614 // pmem.allocate(req);
615  ExtPreAlloc<HeapMemory> & mem = *(new ExtPreAlloc<HeapMemory>(req, pmem));
616 
617  mem.incRef();
618 
619  Pack_stat sts;
620  size_t e_it = 0;
621 
622  // Pack total size
623  Packer<size_t, HeapMemory>::pack(mem, vp_size, sts);
624 
625  for (size_t j = 0; j < vp_size; j++)
626  {
627  // Pack the vertex
628  Packer<decltype(sgp.get(pc).send_v.get(0)), HeapMemory>::pack(mem, sgp.get(pc).send_v.get(j), sts);
629 
630  // Pack the vertex info
631  Packer<decltype(sgp.get(pc).send_v_m.get(0)), HeapMemory>::pack(mem, sgp.get(pc).send_v_m.get(j), sts);
632 
633  // Pack size of the children
634  Packer<size_t, HeapMemory>::pack(mem, sgp.get(pc).send_es.get(j), sts);
635 
636  // Pack children
637  for (size_t k = 0; k < sgp.get(pc).send_es.get(j); k++)
638  {
639  // Pack the edge
640  Packer<decltype(sgp.get(pc).send_e.get(0)), HeapMemory>::pack(mem, sgp.get(pc).send_e.get(e_it), sts);
641 
642  // Pack the edge info
643  Packer<decltype(sgp.get(pc).send_e_m.get(0)), HeapMemory>::pack(mem, sgp.get(pc).send_e_m.get(e_it), sts);
644 
645  // Pack the edge target id
646  Packer<size_t, HeapMemory>::pack(mem, sgp.get(pc).send_el.get(e_it), sts);
647 
648  ++e_it;
649  }
650  }
651 
652  prc.add(i);
653  size.add(pmem.size());
654  ptr.add(mem.getPointerBase());
655  }
656 
657  // Exchange informations through processors
658  vcl.sendrecvMultipleMessagesNBX(prc.size(), (size_t *)size.getPointer(), (size_t *)prc.getPointer(), (void **)ptr.getPointer(), gr_receive, &packs, NONE);
659 
660  for (size_t i = 0; i < vcl.getProcessingUnits(); i++)
661  {
662 
663  if (i != vcl.getProcessUnitID() && packs.get(i).size() > 0)
664  {
665  Unpack_stat ps;
666 
667  ExtPreAlloc<HeapMemory> mem(packs.get(i).size(), packs.get(i));
668 
669  // unpack total number of vertex
670  size_t r_size;
671  Unpacker<size_t, HeapMemory>::unpack(mem, r_size, ps);
672 
673  // take previous last item
674  size_t prev = getNVertex();
675 
676  for (size_t j = prev; j < prev + r_size; j++)
677  {
678  // unpack the vertex
679  V v_n;
680  Unpacker<V, HeapMemory>::unpack(mem, v_n, ps);
681 
682  v_info vm;
684 
685  add_vertex(v_n, vm.template get<v_info::id>(), vm.template get<v_info::gid>());
686 
687  if (addAsGhosts)
688  ghs_map.insert( { vm.template get<v_info::gid>(), false });
689 
690  // unpack size of children
691  size_t s;
693 
694  // prepare slots for the children
695  for (size_t k = 0; k < s; k++)
696  {
697  // unpack edge
698  E e_n;
699  Unpacker<E, HeapMemory>::unpack(mem, e_n, ps);
700 
701  // unpack edge
702  e_info e_i;
704 
705  // unpack vertex id of the edge target
706  size_t el_n;
708 
709  // add the edge //HERE ERROR modify to add globals
710  addEdge(j, el_n, e_n, e_i);
711  }
712  }
713  }
714  }
715 
716  // After the exchange reset all the structures needed for it
717  resetExchange();
718  }
719 
724  {
725  // Prepare vtxdist
726  vtxdist.resize(vcl.getProcessingUnits() + 1);
727 
728  // Set first element to 0, always the same
729  vtxdist.get(0) = 0;
730 
731  // Prepare array that will contain the sizes of all the graphs
733 
734  // Set the local size
735  size_t tv = getNVertex();
736 
737  // Sent and receive the size of each subgraph
738  vcl.allGather(tv, recv);
739  vcl.execute();
740 
741  // Set the value for this processor
742  recv.get(vcl.getProcessUnitID()) = getNVertex();
743 
744  // Update vtxdist
745  for (size_t i = 1; i <= recv.size(); ++i)
746  {
747  vtxdist.get(i) = recv.get(i - 1) + vtxdist.get(i - 1);
748  }
749  }
750 
754  void remap()
755  {
756  size_t p_id = vcl.getProcessUnitID();
757 
758  typedef struct
759  {
760  // new vertex id
761  size_t id;
762  // processor rank that contain the vertex
763  size_t pid;
764  } IdnProc;
765 
766  // Map that will contain the couples to update the global info map in this processor
767  // The key is the (old vertex id)
768  std::unordered_map<size_t, IdnProc> on_toup;
769 
770  // For each processor old, new couples
772 
773  std::map<size_t, size_t> old_glob2loc(glb2loc.begin(), glb2loc.end());
774  size_t j = vtxdist.get(p_id);
775  size_t i = 0, k = 0;
776 
777  // Reset maps of vertices ids
778  id2glb.clear();
779  glb2id.clear();
780  glb2loc.clear();
781 
782  // Fix sending couples gid, newid and remove on_toup updating glbi_map here and after receive
783  for (auto it : old_glob2loc)
784  {
785  // The couple to the final map, needed to update the vertices in this sub-graph
786  IdnProc nidpid = { j, p_id };
787  on_toup.insert( { v_m.get(it.second).template get<v_info::id>(), nidpid });
788 
789  // fill the re-mapping information for each processors that need it
790  on_info.get(getInfoProc(it.first)).add(v_m.get(it.second).template get<v_info::id>());
791  on_info.get(getInfoProc(it.first)).add(j);
792 
793  // Re-map the vertex
794  map_v(j, v_m.get(it.second).template get<v_info::gid>(), it.second);
795 
796  j++;
797  i++;
798  k += 2;
799  }
800 
801  // Prepare structures to send the old-new couples
805 
806  // Array that will contain the couples, divided per processor
808 
809  fillSendRecvStructs<size_t>(on_info, prc, size, ptr);
810 
811  // Send on_info
812  vcl.sendrecvMultipleMessagesNBX(prc.size(), (size_t *)size.getPointer(), (size_t *)prc.getPointer(), (void **)ptr.getPointer(), on_receive, &on_vs, NONE);
813 
814  // Insert in the on_toup map the received couples
815  for (size_t i = 0; i < vcl.getProcessingUnits(); i++)
816  {
817  if (i != vcl.getProcessUnitID() && on_vs.get(i).size() > 0) // redundant check 2nd arg in if
818  {
819  for (size_t j = 0; j < on_vs.get(i).size() - 1; j += 2) // -1 is useless
820  {
821  IdnProc nidpid = { on_vs.get(i).get(j + 1), i };
822  on_toup.insert( { on_vs.get(i).get(j), nidpid });
823  }
824  }
825  }
826 
827  // Update the glbi_map with the new ids and the processor info
828  for (auto k : glbi_map)
829  {
830  auto search = on_toup.find(glbi_map.at(k.first).id); // fix with (k.second).id
831  if (search != on_toup.end())
832  {
833  GlobalVInfo t = { (search->second).id, (search->second).pid };
834  glbi_map.at(k.first) = t;
835  }
836  }
837 
838  // Vector of vertices global id I need info
840 
841  // Map of re-mapping info
842  std::unordered_map<size_t, size_t> rmi_m(vcl.getProcessingUnits()); // TODO elimin
843 
844  // Check which vertices I need to ask info about
845  for (size_t i = 0; i < getNVertex(); ++i)
846  {
847  for (size_t j = 0; j < getNChilds(i); ++j)
848  {
849  // Here we get the global vertex id of all the children
850  size_t vid = getChildDstGid(i, j);
851  // We check which processor has the information about this vertex
852  size_t pid = getInfoProc(vid);
853 
854  // if the vertex info is not in this processor I have to make a request to the right processor
855  if (!vertexIsInThisGraph(vid) && pid != vcl.getProcessUnitID())
856  {
857  // add to requests
858  vni.get(pid).add(vid);
859  }
860  else if (pid == vcl.getProcessUnitID())
861  {
862  // if info is in this processor add it in the map
863  rmi_m.insert( { vid, glbi_map.at(vid).id });
864  }
865  else if (vertexIsInThisGraph(vid)) // check if it is needed, probably not because the glbi_map is update
866  {
867  // if the vertex is in this graph, add the new id in the map
868  rmi_m.insert( { vid, glb2id.at(vid) });
869  }
870  }
871  }
872 
873  // Array that will contain the requests from the other processors
875 
876  // Fill the structures for sendrecvMultipleMessagesNBX function
877  fillSendRecvStructs<size_t>(vni, prc, size, ptr);
878 
879  // Send and receive requests
880  vcl.sendrecvMultipleMessagesNBX(prc.size(), (size_t *)size.getPointer(), (size_t *)prc.getPointer(), (void **)ptr.getPointer(), on_receive, &req_rmi, NONE);
881 
882  // Re-mapping info map
884 
885  // Array that will contain the response to previous requests
887 
888  // Prepare re-mapping info response
889  for (size_t i = 0; i < req_rmi.size(); ++i)
890  {
891  for (size_t j = 0; j < req_rmi.get(i).size(); ++j)
892  {
893  resp_rmi.get(i).add(glbi_map.at(req_rmi.get(i).get(j)).id);
894  }
895  }
896 
897  // Fill the structures for sendrecvMultipleMessagesNBX function
898  fillSendRecvStructs<size_t>(resp_rmi, prc, size, ptr);
899 
900  // Send responses
901  vcl.sendrecvMultipleMessagesNBX(prc.size(), (size_t *)size.getPointer(), (size_t *)prc.getPointer(), (void **)ptr.getPointer(), on_receive, &rmi, NONE);
902 
903  // Add received info into re-mapping info map
904  for (size_t i = 0; i < rmi.size(); ++i)
905  {
906  for (size_t j = 0; j < rmi.get(i).size(); ++j)
907  {
908  rmi_m.insert( { vni.get(i).get(j), rmi.get(i).get(j) });
909  }
910  }
911 
912  // Finally re-map the edges
913  for (size_t i = 0; i < getNVertex(); ++i)
914  {
915  for (size_t s = 0; s < getNChilds(i); s++)
916  {
917  e_l.template get<e_map::vid>(i * v_slot + s) = rmi_m.at(getChildDstGid(i, s));
918  }
919  }
920  }
921 
925  void initGlbimap()
926  {
927  size_t pid = vcl.getProcessUnitID();
928 
929  for (size_t i = 0; i < getNVertex(); ++i)
930  {
931  GlobalVInfo info;
932  info.id = v_m.get(i).template get<v_info::id>();
933  info.pid = pid;
934  glbi_map.insert( { v_m.get(i).template get<v_info::gid>(), info });
935  }
936  }
937 
943  size_t getInfoProc(size_t vid)
944  {
945  for (size_t i = 0; i < fvtxdist.size() - 1; ++i)
946  {
947  if (vid >= (size_t)fvtxdist.get(i) && vid < (size_t)fvtxdist.get(i + 1))
948  {
949  return i;
950  }
951  }
952  return vcl.getProcessingUnits() - 1;
953  }
954 
964  template<typename T>
966  {
967  // Reset sendrecv structures
968  prc.clear();
969  size.clear();
970  ptr.clear();
971 
972  for (size_t i = 0; i < vec.size(); ++i)
973  {
974  if (vec.get(i).size() > 0 && i != vcl.getProcessUnitID())
975  {
976  prc.add(i);
977  size.add(vec.get(i).size() * sizeof(T));
978  ptr.add(vec.get(i).getPointer());
979  }
980  }
981  }
982 
983 public:
984 
986  typedef V V_type;
987 
989  typedef E E_type;
990 
993 
996 
1004  {
1006 
1007  dup.v_slot = v_slot;
1008 
1009  // duplicate all the structures
1010 
1011  dup.v.swap(v.duplicate());
1012  dup.v_m.swap(v_m.duplicate());
1013  dup.v_l.swap(v_l.duplicate());
1014  dup.glb2id = glb2id;
1015  dup.id2glb = id2glb;
1016  dup.glb2loc = glb2loc;
1017  dup.e.swap(e.duplicate());
1018  dup.e_m.swap(e_m.duplicate());
1019  dup.e_l.swap(e_l.duplicate());
1020  dup.e_invalid.swap(e_invalid.duplicate());
1021  dup.vtxdist.swap(vtxdist.duplicate());
1022  dup.fvtxdist.swap(fvtxdist.duplicate());
1023  return dup;
1024  }
1025 
1032  vcl(create_vcluster())
1033  {
1034  this->operator=(dg);
1035  }
1036 
1043  :vcl(create_vcluster())
1044  {
1045  this->operator=(dg);
1046  }
1047 
1054  DistGraph_CSR(0, 16)
1055  {
1056  }
1057 
1063  DistGraph_CSR(size_t n_vertex) :
1064  DistGraph_CSR(n_vertex, 16)
1065  {
1066  }
1067 
1073  DistGraph_CSR(size_t n_vertex, size_t n_slot) :
1074  vcl(create_vcluster()), v_slot(n_slot)
1075  {
1076  // Creating n_vertex into the graph
1077  v.resize(n_vertex);
1078  // Creating n_vertex info objects into the graph
1079  v_m.resize(n_vertex);
1080  // Creating n_vertex adjacency list counters
1081  v_l.resize(n_vertex);
1082  // no edge set the counter to zero
1083  v_l.fill(0);
1084  // create one invalid edge
1085  e_invalid.resize(1);
1086  // init communication structures
1087  resetExchange();
1088  }
1089 
1095  {
1096  v.resize(vtxdist.size());
1097 
1098  for (size_t i = 0; i < vtxdist.size(); ++i)
1099  {
1100  v.get(i) = vtxdist.get(i);
1101  }
1102  }
1103 
1109  {
1110  return &vtxdist;
1111  }
1112 
1118  {
1119  vtxdist.resize(vcl.getProcessingUnits() + 1);
1120  fvtxdist.resize(vcl.getProcessingUnits() + 1);
1121 
1122  for (size_t i = 0; i < vtxdist.size(); ++i)
1123  {
1124  vtxdist.get(i) = v.get(i);
1125  fvtxdist.get(i) = v.get(i);
1126  }
1127  }
1128 
1133  {
1134  updateVtxdist();
1135 
1136  fvtxdist.resize(vcl.getProcessingUnits() + 1);
1137 
1138  for (size_t i = 0; i < vtxdist.size(); ++i)
1139  {
1140  fvtxdist.get(i) = vtxdist.get(i);
1141  }
1142  }
1143 
1151  vcl(vcl)
1152  {
1153  swap(g);
1154  }
1155 
1164  {
1165  swap(g);
1166 
1167  return *this;
1168  }
1169 
1178  {
1179  swap(g.duplicate());
1180 
1181  return *this;
1182  }
1183 
1194  template<unsigned int i> auto vertex_p(size_t id) -> decltype( v.template get<i>(id) )
1195  {
1196  return v.template get<i>(id);
1197  }
1198 
1207  template<unsigned int i> auto vertex_p(grid_key_dx<1> id) -> decltype( v.template get<i>(id) )
1208  {
1209  return v.template get<i>(id);
1210  }
1211 
1219  auto vertex(size_t id) -> decltype( v.get(id) )
1220  {
1221  return v.get(id);
1222  }
1223 
1233  auto vertex(grid_key_dx<1> id) -> decltype( v.get(id.get(0)) )
1234  {
1235  return v.get(id.get(0));
1236  }
1237 
1247  auto vertex(openfpm::vector_key_iterator id) -> decltype( v.get(0) )
1248  {
1249  return v.get(id.get());
1250  }
1251 
1259  auto vertex(size_t id) const -> const decltype( v.get(id) )
1260  {
1261  return v.get(id);
1262  }
1263 
1273  auto vertex(grid_key_dx<1> id) const -> const decltype( v.get(id.get(0)) )
1274  {
1275  return v.get(id.get(0));
1276  }
1277 
1287  auto vertex(openfpm::vector_key_iterator id) const -> const decltype( v.get(0) )
1288  {
1289  return v.get(id.get());
1290  }
1291 
1301  auto vertex_info(openfpm::vector_key_iterator id) const -> const decltype( v_m.get(0) )
1302  {
1303  return v_m.get(id.get());
1304  }
1305 
1313  auto getVertex(size_t id) -> decltype( v.get(id) )
1314  {
1315 
1316 #ifdef SE_CLASS1
1317 
1318  if (glb2loc.find(id) == glb2loc.end())
1319  {
1320  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";
1321  ACTION_ON_ERROR(DIST_GRAPH_ERROR);
1322  }
1323 
1324 #endif
1325 
1326  return v.get(glb2loc.find(id)->second);
1327  }
1328 
1336  auto getVertex(size_t id) const -> const decltype( v.get(0) )
1337  {
1338  try
1339  {
1340  return v.get(glb2loc.at(id));
1341  } catch (const std::out_of_range& oor)
1342  {
1343  std::cerr << "The vertex with global id " << id << " is not in this sub-graph. Try to call reqVertex(" << id << ") and sync() first.\n";
1344  }
1345 
1346  return v.get(0);
1347  }
1348 
1358  size_t nodeById(size_t id) const
1359  {
1360  try
1361  {
1362  return glb2loc.at(id2glb.at(id));
1363  } catch (const std::out_of_range& oor)
1364  {
1365  std::cout << "Node not found by glb: " << id << std::endl;
1366  }
1367 
1368  return 0;
1369  }
1370 
1375  size_t firstId() const
1376  {
1377  return vtxdist.get(vcl.getProcessUnitID());
1378  }
1379 
1384  size_t lastId() const
1385  {
1386  return vtxdist.get(vcl.getProcessUnitID() + 1) - 1;
1387  }
1388 
1394  size_t getVertexId(size_t i) const
1395  {
1396  return v_m.get(i).template get<v_info::id>();
1397  }
1398 
1404  size_t getVertexGlobalId(size_t i) const
1405  {
1406  return v_m.get(i).template get<v_info::gid>();
1407  }
1408 
1414  bool vertexIsInThisGraph(size_t id)
1415  {
1416  auto search = glb2id.find(id);
1417 
1418  if (search != glb2id.end())
1419  {
1420  return true;
1421  }
1422  else
1423  {
1424  return false;
1425  }
1426  }
1427 
1437  void map_v(size_t n, size_t g, size_t l)
1438  {
1439  id2glb.insert( { n, g });
1440  glb2id.insert( { g, n });
1441  glb2loc.insert( { g, l });
1442  v_m.get(l).template get<v_info::id>() = n;
1443  }
1444 
1450  void clear()
1451  {
1452  v.clear();
1453  v_m.clear();
1454  e.clear();
1455  id2glb.clear();
1456  glb2id.clear();
1457  glb2loc.clear();
1458  v_l.clear();
1459  e_l.clear();
1460  e_invalid.clear();
1461  }
1462 
1471  template<unsigned int i> auto edge_p(grid_key_dx<1> id) -> decltype ( e.template get<i>(id) )
1472  {
1473  return e.template get<i>(id);
1474  }
1475 
1484  template<unsigned int i> auto edge_p(size_t id) -> decltype ( e.template get<i>(id) )
1485  {
1486  return e.template get<i>(id);
1487  }
1488 
1496  auto edge(grid_key_dx<1> id) const -> const decltype ( e.get(id.get(0)) )
1497  {
1498  return e.get(id.get(0));
1499  }
1500 
1508  auto edge(edge_key ek) const -> const decltype ( e.get(0) )
1509  {
1510  return e.get(e_l.template get<e_map::eid>(ek.pos * v_slot + ek.pos_e));
1511  }
1512 
1520  auto getEdge(edge_key ek) const -> const decltype ( e.get(0) )
1521  {
1522  size_t v;
1523 
1524  try
1525  {
1526  v = glb2loc.at(ek.pos);
1527  } catch (const std::out_of_range& oor)
1528  {
1529  std::cout << "The source vertex of this edge is not in this graph.\n";
1530  }
1531 
1532  return e.get(e_l.template get<e_map::eid>(v * v_slot + ek.pos_e));
1533  }
1534 
1544  auto edge(size_t id) const -> const decltype ( e.get(id) )
1545  {
1546  return e.get(id);
1547  }
1548 
1556  inline size_t getNChilds(size_t c) const
1557  {
1558  return v_l.template get<0>(c);
1559  }
1560 
1568  inline size_t getNChilds(typename openfpm::vector<V, Memory, layout_v, layout_v_base, grow_p, openfpm::vect_isel<V>::value>::iterator_key & c)
1569  {
1570  return v_l.template get<0>(c.get());
1571  }
1572 
1580  inline size_t getNEdge(size_t v) const
1581  {
1582  try
1583  {
1584  v = glb2loc.at(v);
1585  } catch (const std::out_of_range& oor)
1586  {
1587  std::cout << "The source vertex of this edge is not in this graph.\n";
1588  }
1589 
1590  return v_l.template get<0>(v);
1591  }
1592 
1601  inline auto getChildEdge(size_t v, size_t v_e) -> decltype(e.get(0))
1602  {
1603  return e.get(e_l.template get<e_map::eid>(v * v_slot + v_e));
1604  }
1605 
1614  inline auto getChildInfo(size_t v, size_t v_e) -> decltype(e_m.get(0))
1615  {
1616  return e_m.get(e_l.template get<e_map::eid>(v * v_slot + v_e));
1617  }
1618 
1627  inline auto getEdge(size_t v, size_t v_e) -> decltype(e.get(0))
1628  {
1629  try
1630  {
1631  v = glb2loc.at(v);
1632  } catch (const std::out_of_range& oor)
1633  {
1634  std::cout << "The source vertex of this edge is not in this graph.\n";
1635  }
1636 
1637  return e.get(e_l.template get<e_map::eid>(v * v_slot + v_e));
1638  }
1639 
1648  inline size_t getChild(size_t v, size_t i) const
1649  {
1650 #ifdef SE_CLASS1
1651  if (i >= v_l.template get<0>(v))
1652  {
1653  std::cerr << "Error " << __FILE__ << " line: " << __LINE__ << " vertex " << v << " does not have edge " << i << " on processor " << vcl.getProcessUnitID() << "\n";
1654  }
1655 
1656  if (e.size() <= e_l.template get<e_map::eid>(v * v_slot + i))
1657  {
1658  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";
1659  }
1660 #endif
1661  // Get the edge id
1662  return e_l.template get<e_map::vid>(v * v_slot + i);
1663  }
1664 
1672  inline size_t getChild(size_t i) const
1673  {
1674  // Get the edge id
1675  return e_l.template get<e_map::vid>(i);
1676  }
1677 
1686  inline size_t getChild(typename openfpm::vector<V, Memory, layout_v, layout_v_base, grow_p, openfpm::vect_isel<V>::value>::iterator_key & v, size_t i)
1687  {
1688 #ifdef DEBUG
1689  if (i >= v_l.template get<0>(v.get()))
1690  {
1691  std::cerr << "Error " << __FILE__ << " line: " << __LINE__ << " vertex " << v.get() << " does not have edge " << i << "\n";
1692  }
1693 
1694  if (e.size() <= e_l.template get<e_map::eid>(v.get() * v_slot + i))
1695  {
1696  std::cerr << "Error " << __FILE__ << " " << __LINE__ << " vertex " << v.get() << " does not have edge " << i << "\n";
1697  }
1698 #endif
1699 
1700  // Get the edge id
1701  return e_l.template get<e_map::vid>(v.get() * v_slot + i);
1702  }
1703 
1710  inline void add_vertex(const V & vrt, size_t id, size_t gid)
1711  {
1712  // Create vertex info object
1713  v_info vm;
1714  vm.template get<v_info::id>() = id;
1715  vm.template get<v_info::gid>() = gid;
1716 
1717  // Add the vertex info
1718  v_m.add(vm);
1719 
1720  // Add the vertex
1721  v.add(vrt);
1722 
1723  // Update id to global map
1724  id2glb.insert( { id, gid });
1725 
1726  // Update global id to local index
1727  glb2loc.insert( { gid, v.size() - 1 });
1728 
1729  // Update global id to id
1730  glb2id.insert( { gid, id });
1731 
1732  // Set the number of adjacent vertex for this vertex to 0
1733  v_l.add(0ul);
1734 
1735  // Add a slot for the vertex adjacency list
1736  e_l.resize(e_l.size() + v_slot);
1737  }
1738 
1745  template<unsigned int dim, typename Mem> inline void add_vertex(const encapc<dim, V, Mem> & vrt, size_t id, size_t gid)
1746  {
1747  // Create vertex info object
1748  v_info vm;
1749  vm.template get<v_info::id>() = id;
1750  vm.template get<v_info::gid>() = gid;
1751 
1752  // Add the vertex info
1753  v_m.add(vm);
1754 
1755  // Add the vertex
1756  v.add(vrt);
1757 
1758  // Update id to global map
1759  id2glb.insert( { id, gid });
1760 
1761  // Update global id to local index
1762  glb2loc.insert( { gid, v.size() - 1 });
1763 
1764  // Update global id to id
1765  glb2id.insert( { gid, id });
1766 
1767  // Set the number of adjacent vertex for this vertex to 0
1768  v_l.add(0ul);
1769 
1770  // Add a slot for the vertex adjacency list
1771  e_l.resize(e_l.size() + v_slot);
1772  }
1773 
1779  inline void add_vertex(const V & vrt, size_t gid)
1780  {
1781  add_vertex(vrt, gid, gid);
1782  }
1783 
1790  void setGlobalMap(size_t g, size_t l, size_t i)
1791  {
1792  v_m.template get<v_info::id>(l) = i;
1793 
1794  v_m.template get<v_info::gid>(l) = g;
1795 
1796  // Set global id to local index
1797  glb2loc.insert( { g, l });
1798 
1799  // Set global id to id
1800  glb2id.insert( { g, i });
1801 
1802  // Set id to global map
1803  id2glb.insert( { i, g });
1804  }
1805 
1806  inline auto addEdge(size_t v1, size_t v2, size_t srcgid, size_t dstgid) -> decltype(e.get(0))
1807  {
1808  // add an edge
1809  long int id_x_end = addEdge_<NoCheck>(v1, v2);
1810  // If there is not edge return an invalid edge, is a kind of stub object
1811  if (id_x_end == NO_EDGE)
1812  return e_invalid.get(0);
1813 
1814  // set source and destination global ids of the edge
1815  e_m.template get<e_info::sgid>(id_x_end) = srcgid;
1816  e_m.template get<e_info::dgid>(id_x_end) = dstgid;
1817 
1818  // return the edge to change the properties
1819  return e.get(id_x_end);
1820  }
1821 
1822  inline auto addEdge(size_t v1, size_t v2, size_t srcgid, size_t dstgid, const E & ed) -> decltype(e.get(0))
1823  {
1824  // add an edge
1825  long int id_x_end = addEdge_<NoCheck>(v1, v2);
1826  // If there is not edge return an invalid edge, is a kind of stub object
1827  if (id_x_end == NO_EDGE)
1828  return e_invalid.get(0);
1829 
1830  // add in e_l the edge properties
1831  e.set(id_x_end, ed);
1832 
1833  // set source and destination global ids of the edge
1834  e_m.template get<e_info::sgid>(id_x_end) = srcgid;
1835  e_m.template get<e_info::dgid>(id_x_end) = dstgid;
1836 
1837  // return the edge to change the properties
1838  return e.get(id_x_end);
1839  }
1840 
1841  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))
1842  {
1843  // add an edge
1844  long int id_x_end = addEdge_<NoCheck>(v1, v2);
1845  // If there is not edge return an invalid edge, is a kind of stub object
1846  if (id_x_end == NO_EDGE)
1847  return e_invalid.get(0);
1848 
1849  // set the edge object and the edge info object
1850  e.set(id_x_end, ed);
1851  e_m.set(id_x_end, ei);
1852 
1853  // return the edge to change the properties
1854  return e.get(id_x_end);
1855  }
1856 
1857  inline auto addEdge(size_t v1, size_t v2, const E & ed, const e_info & ei) -> decltype(e.get(0))
1858  {
1859  // add an edge
1860  long int id_x_end = addEdge_<NoCheck>(v1, v2);
1861  // If there is not edge return an invalid edge, is a kind of stub object
1862  if (id_x_end == NO_EDGE)
1863  return e_invalid.get(0);
1864 
1865  // set the edge object and the edge info object
1866  e.set(id_x_end, ed);
1867  e_m.set(id_x_end, ei);
1868 
1869  // return the edge to change the properties
1870  return e.get(id_x_end);
1871  }
1872 
1879  size_t getChildSrcGid(size_t v1, size_t s)
1880  {
1881  size_t eid = e_l.template get<e_map::eid>(v1 * v_slot + s);
1882  return e_m.template get<e_info::sgid>(eid);
1883  }
1884 
1891  size_t getChildDstGid(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::dgid>(eid);
1895  }
1896 
1902  template<typename CheckPolicy = NoCheck> inline void add_edge(size_t v1, size_t v2)
1903  {
1904  //if the source vertex is not in this graph, this processor doesn't need to do anything
1905  if (!vertexIsInThisGraph(v1))
1906  {
1907  return;
1908  }
1909 
1910  //if the destination vertex is not in this graph, this processor has to request it and add the edge to a queue
1911  if (!vertexIsInThisGraph(v2))
1912  {
1913  reqVertex(v2);
1914  EdgeReq er = { v1, v2, 0, 0 };
1915  e_queue.add(er);
1916 
1917  return;
1918  }
1919 
1920  // add an edge
1921  long int id_x_end = addEdge_<CheckPolicy>(glb2loc.at(v1), glb2id.at(v2));
1922 
1923  // If there is not edge return an invalid edge, is a kind of stub object
1924  if (id_x_end == NO_EDGE)
1925  return;
1926 
1927  // set source and destination ids of the edge
1928  e_m.get(id_x_end).template get<e_info::sgid>() = v1;
1929  e_m.get(id_x_end).template get<e_info::dgid>() = v2;
1930  }
1931 
1935  void syncEdge()
1936  {
1937  // retrieve ghosts necessary for edge adding
1938  sync();
1939 
1940  // update with real values of edges, we don't add the edge here because it will modify edge's array length
1941  for (size_t i = 0; i < e_queue.size(); ++i)
1942  {
1943  e_queue.get(i).v1n = glb2loc.at(e_queue.get(i).v1);
1944  e_queue.get(i).v2n = glb2id.at(e_queue.get(i).v2);
1945  }
1946 
1947  deleteGhosts();
1948 
1949  for (auto req : e_queue)
1950  {
1951  // add an edge
1952  long int id_x_end = addEdge_<>(req.v1n, req.v2n);
1953 
1954  // If there is not edge return an invalid edge, is a kind of stub object
1955  if (id_x_end == NO_EDGE)
1956  return;
1957 
1958  // set source and destination ids of the edge
1959  e_m.get(id_x_end).template get<e_info::sgid>() = req.v1;
1960  e_m.get(id_x_end).template get<e_info::dgid>() = req.v2;
1961  }
1962 
1963  e_queue.clear();
1964 
1965  }
1966 
1974  inline void swap(DistGraph_CSR<V, E> & g)
1975  {
1976  // switch the memory
1977  v.swap(g.v);
1978  v_m.swap(g.v_m);
1979  e.swap(g.e);
1980  e_m.swap(g.e_m);
1981  v_l.swap(g.v_l);
1982  glb2id.swap(g.glb2id);
1983  id2glb.swap(g.id2glb);
1984  glb2loc.swap(g.glb2loc);
1985  e_l.swap(g.e_l);
1986  e_invalid.swap(g.e_invalid);
1987  vtxdist.swap(g.vtxdist);
1988  fvtxdist.swap(g.fvtxdist);
1989 
1990  size_t v_slot_tmp = v_slot;
1991  v_slot = g.v_slot;
1992  g.v_slot = v_slot_tmp;
1993  }
1994 
2002  inline void swap(DistGraph_CSR<V, E> && g)
2003  {
2004  // switch the memory
2005  v.swap(g.v);
2006  v_m.swap(g.v_m);
2007  e.swap(g.e);
2008  e_m.swap(g.e_m);
2009  v_l.swap(g.v_l);
2010  glb2id.swap(g.glb2id);
2011  id2glb.swap(g.id2glb);
2012  glb2loc.swap(g.glb2loc);
2013  e_l.swap(g.e_l);
2014  e_invalid.swap(g.e_invalid);
2015  vtxdist.swap(g.vtxdist);
2016  fvtxdist.swap(g.fvtxdist);
2017 
2018  size_t v_slot_tmp = v_slot;
2019  v_slot = g.v_slot;
2020  g.v_slot = v_slot_tmp;
2021  }
2022 
2030  inline auto getVertexIterator() const -> decltype(v.getIterator())
2031  {
2032  return v.getIterator();
2033  }
2034 
2043  {
2045  }
2046 
2052  inline size_t getNVertex() const
2053  {
2054  return v.size();
2055  }
2056 
2062  inline size_t getTotNVertex() const
2063  {
2064  return vtxdist.get(vcl.getProcessingUnits());
2065  }
2066 
2072  inline size_t getNEdge() const
2073  {
2074  return e.size();
2075  }
2076 
2080  void init()
2081  {
2083 
2084  initGlbimap();
2085 
2086  remap();
2087  }
2088 
2094  bool isGhost(size_t id)
2095  {
2096  auto search = ghs_map.find(id);
2097 
2098  if (search != ghs_map.end())
2099  {
2100  return true;
2101  }
2102  else
2103  {
2104  return false;
2105  }
2106  }
2107 
2112  {
2113  if (ghs_map.size() == 0)
2114  return;
2115 
2116  // Prepare new graph
2117  DistGraph_CSR recv_g;
2118 
2119  size_t fpos = getNVertex() - ghs_map.size();
2120  size_t epos = 0;
2121 
2122  // Reset global to local map
2123  for (auto gh : ghs_map)
2124  {
2125  epos += getNChilds(glb2loc.at(gh.first));
2126  id2glb.erase(glb2id.at(gh.first));
2127  glb2loc.erase(gh.first);
2128  glb2id.erase(gh.first);
2129 
2130  }
2131 
2132  //resize all structures to delete the ghosts
2133  v.resize(fpos);
2134  v_m.resize(fpos);
2135  v_l.resize(fpos);
2136  e.resize(e.size() - epos);
2137  e_m.resize(e_m.size() - epos);
2138  e_l.resize(fpos * v_slot);
2139 
2140  // Clear ghosts map
2141  ghs_map.clear();
2142  }
2143 
2151  template<bool toRemove = true> //TODO make it private and create wrapper in public
2152  void q_move(size_t i, size_t t)
2153  {
2154  // Check if a 'useless' move has been requested
2155  if (t == vcl.getProcessUnitID())
2156  {
2157  std::cerr << "Warning: " << __FILE__ << ":" << __LINE__ << " target processor is equal the local processor\n";
2158  return;
2159  }
2160 
2161  // If the array for t processor is empty, set it to not empty
2162  if (sgp.get(t).isEmpty)
2163  sgp.get(t).isEmpty = false;
2164 
2165  // Add the vertex to the vertex send buffer
2166  sgp.get(t).send_v.add(vertex(i));
2167 
2168  // Add the vertex to the vertex send buffer
2169  sgp.get(t).send_v_m.add(v_m.get(i));
2170 
2171  // Add the info about the number of children
2172  sgp.get(t).send_es.add(getNChilds(i));
2173 
2174  for (size_t s = 0; s < getNChilds(i); s++)
2175  {
2176  // Add edge value and object to the respective arrays
2177  sgp.get(t).send_e.add(getChildEdge(i, s));
2178  sgp.get(t).send_e_m.add(getChildInfo(i, s));
2179  sgp.get(t).send_el.add(getChild(i, s));
2180  }
2181 
2182  // If the vertex has to be removed after the send add its index id to the v_td array
2183  if (toRemove)
2184  v_td.add(i);
2185  }
2186 
2192  {
2193  size_t exs = 0;
2194  for (size_t i = 0; i < vcl.getProcessingUnits(); ++i)
2195  if (sgp.get(i).isEmpty)
2196  exs++;
2197 
2198  if (exs == 0)
2199  return true;
2200 
2201  return false;
2202  }
2203 
2208  {
2209  if (glbi_map.size() == 0)
2210  initGlbimap();
2211 
2212  deleteGhosts();
2213 
2214  exchangeVertices<false>();
2215 
2216  updateVtxdist();
2217 
2218  remap();
2219  }
2220 
2225  void reqVertex(size_t gid)
2226  {
2227  // if not initialized, prepare vr_queue
2228  if (vr_queue.size() == 0)
2229  vr_queue.resize(vcl.getProcessingUnits());
2230 
2231  if (!vertexIsInThisGraph(gid))
2232  {
2233  vr_queue.get(getInfoProc(gid)).add(gid);
2234  }
2235 
2236  }
2237 
2241  void sync()
2242  {
2243  // If not initialized, prepare global informations map
2244  if (glbi_map.size() == 0)
2245  initGlbimap();
2246 
2247  // if not initialized, prepare vr_queue
2248  if (vr_queue.size() == 0) // TODO remove check on size
2249  vr_queue.resize(vcl.getProcessingUnits());
2250 
2251  // Arrays that will contain temporary requests and responses during communications TODO move to global private and reset method
2254 
2255  // Prepare structures for communication
2259 
2260  // Fill the structures for sendrecvMultipleMessagesNBX function
2261  fillSendRecvStructs<size_t>(vr_queue, prc, size, ptr);
2262 
2263  // Send/receive requests for info about needed vertices
2264  vcl.sendrecvMultipleMessagesNBX(prc.size(), (size_t *)size.getPointer(), (size_t *)prc.getPointer(), (void **)ptr.getPointer(), on_receive, &resp, NONE);
2265 
2266  // Prepare responses with the containing processors of requested vertices
2267  for (size_t i = 0; i < resp.size(); ++i)
2268  {
2269  reqs.get(i).clear();
2270 
2271  for (size_t j = 0; j < resp.get(i).size(); ++j)
2272  {
2273  try
2274  {
2275  reqs.get(i).add(glbi_map.at(resp.get(i).get(j)).pid);
2276  } catch (const std::out_of_range& oor)
2277  {
2278  std::cout << resp.get(i).get(j) << " not found in global info map (proc: " << vcl.getProcessUnitID() << ")\n";
2279  }
2280  }
2281  }
2282 
2283  // Fill the structures for sendrecvMultipleMessagesNBX function
2284  fillSendRecvStructs<size_t>(reqs, prc, size, ptr);
2285 
2286  // Reset response array TODO clear and resize not needed
2287  resp.clear();
2288  resp.resize(vcl.getProcessingUnits());
2289 
2290  // Send/receive responses with the containing processors of requested vertices
2291  vcl.sendrecvMultipleMessagesNBX(prc.size(), (size_t *)size.getPointer(), (size_t *)prc.getPointer(), (void **)ptr.getPointer(), on_receive, &resp, NONE);
2292 
2293  // Clear requests array
2294  reqs.clear();
2295  reqs.resize(vcl.getProcessingUnits());
2296 
2297  // Prepare vertices requests
2298  for (size_t i = 0; i < vcl.getProcessingUnits(); ++i)
2299  {
2300  // If the info has been retrieved from other processors take it from resp
2301  if (i != vcl.getProcessUnitID())
2302  {
2303  for (size_t j = 0; j < vr_queue.get(i).size(); ++j)
2304  {
2305  reqs.get(resp.get(i).get(j)).add(vr_queue.get(i).get(j));
2306  }
2307  }
2308  // Otherwise take it from the global info map of this processor
2309  else
2310  {
2311  for (size_t j = 0; j < vr_queue.get(i).size(); ++j)
2312  {
2313  reqs.get(glbi_map.at(vr_queue.get(i).get(j)).pid).add(vr_queue.get(i).get(j));
2314  }
2315  }
2316  }
2317 
2318  // Fill the structures for sendrecvMultipleMessagesNBX function
2319  fillSendRecvStructs<size_t>(reqs, prc, size, ptr);
2320 
2321  // Reset response array
2322  resp.clear();
2323  resp.resize(vcl.getProcessingUnits());
2324 
2325  // Send/receive vertices requests
2326  vcl.sendrecvMultipleMessagesNBX(prc.size(), (size_t *)size.getPointer(), (size_t *)prc.getPointer(), (void **)ptr.getPointer(), on_receive, &resp, NONE);
2327 
2328  for (size_t i = 0; i < resp.size(); ++i)
2329  {
2330  for (size_t j = 0; j < resp.get(i).size(); ++j)
2331  {
2332  try
2333  {
2334  q_move<false>(glb2loc.at(resp.get(i).get(j)), i);
2335  } catch (const std::out_of_range& oor)
2336  {
2337  std::cout << resp.get(i).get(j) << " not found in global to local map (proc: " << vcl.getProcessUnitID() << ")\n";
2338  }
2339  }
2340  }
2341 
2342  // Send and receive vertices, the received ones will be added to the graph as ghosts
2343  exchangeVertices<true>();
2344 
2345  // Empty the requests list
2346  vr_queue.clear();
2347  }
2348 };
2349 
2374 template<typename V, typename E>
2375 class DistGraph_CSR_s: public DistGraph_CSR<V, E>
2376 {
2377 
2378 };
2379 
2380 #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
DistGraph_CSR()
Constructor.
void add_vertex(const V &vrt, size_t id, size_t gid)
Add vertex vrt with global id and id properties.
openfpm::vector< V > send_v
vertex send buffer
size_t getTotNVertex() const
Return the total number of the vertices.
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)
Definition: memory_conf.hpp:93
size_t getChild(size_t v, size_t i) const
Get the child edge.
DistGraph_CSR(Vcluster &vcl, DistGraph_CSR< V, E, Memory > &&g)
Copy constructor.
void deleteMovedVertices()
Remove from this graph the vertices that have been sent.
static void * gr_receive(size_t msg_i, size_t total_msg, size_t total_p, size_t i, size_t ri, void *ptr)
Callback to set the size of the receiving vector.
auto edge(size_t id) const -> const decltype(e.get(id))
operator to access the edge
openfpm::vector< size_t > send_es
For each vertex contain the number of children.
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
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...
size_t getProcessUnitID()
Get the process unit id.
size_t nodeById(size_t id) const
operator to access the vertex position index by id property
size_t getVertexGlobalId(size_t i) const
Get the id of a vertex given its index position.
void execute()
Execute all the requests.
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.
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.
size_t getChildDstGid(size_t v1, size_t s)
Get the global id of edge's destination vertex.
size_t getNEdge(size_t v) const
Return the number of children of a vertex given its global id.
openfpm::vector< size_t > v_td
Array containing the sent vertices and that will be deleted from the graph.
size_t getNEdge() const
Return the number of edges.
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.
openfpm::vector< e_map, Memory, typename memory_traits_lin< e_map >::type, 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) ...
openfpm::vector< E, Memory, layout_e, 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) ...
Simplified implementation of DistGraph_CSR.
size_t size()
Stub size.
Definition: map_vector.hpp:70
void deleteGhosts()
Remove all the ghosts from this graph.
openfpm::vector< E, Memory, layout_e, layout_e_base, grow_p, openfpm::vect_isel< E >::value > e
Structure that store the edge properties.
bool moveQueueIsEmpty()
Check if the move queue is empty.
Graph edge iterator.
Definition: map_graph.hpp:169
auto getChildEdge(size_t v, size_t v_e) -> decltype(e.get(0))
Get the vertex edge.
DistGraph_CSR(const DistGraph_CSR &dg)
Constructor.
size_t firstId() const
edge_iterator< DistGraph_CSR< V, E, Memory > > getEdgeIterator() const
Get the vertex iterator.
virtual size_t size() const
the the size of the allocated memory
Definition: HeapMemory.cpp:157
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, void *), void *ptr_arg, long int opt=NONE)
Send and receive multiple messages.
void updateVtxdist()
Update the distribution vector vtxdist.
openfpm::vector< e_info, Memory, typename layout_e_base< e_info >::type, layout_e_base, grow_p, openfpm::vect_isel< e_info >::value > e_m
Structure that store the edge properties.
This class allocate, and destroy CPU memory.
Definition: HeapMemory.hpp:39
size_t getNVertex() const
Return the number of the vertices in this subgraph.
size_t getChild(size_t i) const
Get the child edge.
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:36
size_t lastId() const
openfpm::vector< V, Memory, layout_v, layout_v_base, grow_p, openfpm::vect_isel< V >::value > v
Structure that store the vertex properties.
bool isGhost(size_t id)
Check if a vertex is a ghost vertex (not belonging to this processor)
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 getNChilds(typename openfpm::vector< V, Memory, layout_v, layout_v_base, grow_p, openfpm::vect_isel< V >::value >::iterator_key &c)
Return the number of childs of a vertex.
static size_t packRequest(const T &obj, size_t &req)
Error, no implementation.
Definition: Packer.hpp:59
DistGraph_CSR< V, E, Memory > & operator=(const DistGraph_CSR< V, E, Memory > &g)
Copy the graph.
It analyze the type given and it select correctly the implementation for vector.
Definition: vect_isel.hpp:36
void resetExchange()
Init communication structures.
size_t getVertexId(size_t i) const
Get the id of a vertex given its index position.
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.
size_t v1
source vertex
size_t getChild(typename openfpm::vector< V, Memory, layout_v, layout_v_base, grow_p, openfpm::vect_isel< V >::value >::iterator_key &v, size_t i)
Get the child edge.
auto vertex(openfpm::vector_key_iterator id) -> decltype(v.get(0))
operator to access the vertex
Packing class.
Definition: Packer.hpp:44
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 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
openfpm::vector< v_info, Memory, typename memory_traits_lin< v_info >::type, memory_traits_lin, grow_p, openfpm::vect_isel< v_info >::value > v_m
Structure that store the vertex id and global id.
virtual void incRef()
Increment the reference counter.
Definition: ExtPreAlloc.hpp:69
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.
static void * on_receive(size_t msg_i, size_t total_msg, size_t total_p, size_t i, size_t ri, void *ptr)
Callback of the sendrecv to set the size of the array received.
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
openfpm::vector< size_t, Memory, typename layout_v_base< size_t >::type, 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.
auto vertex_p(grid_key_dx< 1 > id) -> decltype(v.template get< i >(id))
Access the vertex.
void * getPointerBase()
The the base pointer of the preallocate memory.
openfpm::vector< E, Memory, layout_e, 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 ...
static void unpack(ExtPreAlloc< Mem >, T &obj)
Error, no implementation.
Definition: Unpacker.hpp:36
void initGlbimap()
Initialize the fixed structure for global mapping. See glbiv for details.
void swap(DistGraph_CSR< V, E > &&g)
Swap the memory of g with this graph.
openfpm::vector< V, Memory, layout_v, 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 setGlobalMap(size_t g, size_t l, size_t i)
map global id to local id
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 getNChilds(size_t c) const
Return the number of children of a vertex.
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.
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
This class is a container for the memory interface like HeapMemory CudaMemory.
Definition: memory_c.hpp:31
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
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.
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:51
Definition: ids.hpp:148
static void pack(ExtPreAlloc< Mem >, const T &obj)
Error, no implementation.
Definition: Packer.hpp:51
auto getVertexIterator() const -> decltype(v.getIterator())
Get the vertex iterator.
size_t getProcessingUnits()
Get the total number of processors.
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.
bool allGather(T &send, openfpm::vector< T, Mem, gr > &v)
Gather the data from all processors.
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, useless if a graph factory is used.
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.