OpenFPM_pdata  4.1.0
Project that contain the implementation of distributed structures
 
Loading...
Searching...
No Matches
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
72template<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>
79class DistGraph_CSR;
80
81class v_info
82{
83public:
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
136{
137public:
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
202template<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>
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 {
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
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;
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;
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;
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
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
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
995public:
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
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)
2242
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
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
2386template<typename V, typename E>
2388{
2389
2390};
2391
2392#endif /* DIST_MAP_GRAPH_HPP_ */
Simplified implementation of DistGraph_CSR.
Structure that store a graph in CSR format or basically in compressed adjacency matrix format.
openfpm::vector< idx_t > fvtxdist
Fixed distribution vector, it never changes, it maintains always the first decomposition and topology...
void setGlobalMap(size_t g, size_t l, size_t i)
map global id to local id
void initGlbimap()
Initialize the fixed structure for global mapping. See glbiv for details.
size_t getNVertex() const
Return the number of the vertices in this subgraph.
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 getVertex(size_t id) const -> const decltype(v.get(0))
Function to access the vertexes.
V V_type
Vertex typedef.
void swap(DistGraph_CSR< V, E > &g)
Swap the memory of g with this graph.
void add_vertex(const V &vrt, size_t gid)
Add vertex vrt with global id and id properties.
DistGraph_CSR()
Constructor.
auto getVertex(size_t id) -> decltype(v.get(id))
Function to access the vertexes.
size_t getTotNVertex() const
Return the total number of the vertices.
void deleteGhosts()
Remove all the ghosts from this graph.
void q_move(size_t i, size_t t)
Prepare to send vertex i from the local processor to the target processor.
void init()
Once added all the vertices this function must be called to initialize all the properties,...
void swap(DistGraph_CSR< V, E > &&g)
Swap the memory of g with this graph.
auto vertex_p(size_t id) -> decltype(v.template get< i >(id))
operator to access the vertex
void initDistributionVector()
Initialize the vtxdist and the fvtxdist.
auto edge(grid_key_dx< 1 > id) const -> const decltype(e.get(id.get(0)))
Access the edge.
size_t addEdge_(size_t v1, size_t v2)
add edge on the graph
void remap()
Re-map received vertices in order to have ordered vertex ids.
void sync()
Execute all vertex requests and add them as ghosts inside this graph, they will be available until a ...
void initDistributionVector(openfpm::vector< idx_t > &v)
Operator to access the decomposition vector.
size_t getVertexId(size_t i) const
Get the id of a vertex given its index position.
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.
std::unordered_map< size_t, size_t > glb2loc
Map to access the local vertex id given the global one.
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 getChildDstGid(size_t v1, size_t s)
Get the global id of edge's destination vertex.
auto edge_p(size_t id) -> decltype(e.template get< i >(id))
Access the edge.
size_t v_slot
number of slot per vertex
auto edge(edge_key ek) const -> const decltype(e.get(0))
operator to access the edge
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
auto vertex(grid_key_dx< 1 > id) const -> const decltype(v.get(id.get(0)))
operator to access the vertex
size_t getChildSrcGid(size_t v1, size_t s)
Get the global id of edge's source vertex.
void exchangeVertices()
Send and receive vertices and update current graph.
void clear()
operator to clear the whole graph
size_t getInfoProc(size_t vid)
Get the processor id of the processor containing the vertex with global id vid.
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.
edge_iterator< DistGraph_CSR< V, E, Memory > > getEdgeIterator() const
Get the vertex iterator.
auto getEdge(edge_key ek) const -> const decltype(e.get(0))
operator to access the edge
std::unordered_map< size_t, GlobalVInfo > glbi_map
TODO update description from pdf.
auto getVertexIterator() const -> decltype(v.getIterator())
Get the vertex iterator.
openfpm::vector< EdgeReq > e_queue
Queue of requests to add edges.
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)
size_t getNEdge() const
Return the number of edges.
bool vertexIsInThisGraph(size_t id)
Check if the vertex with GLOBAL id is in this graph.
void deleteMovedVertices()
Remove from this graph the vertices that have been sent.
size_t nodeById(size_t id) const
operator to access the vertex position index by id property
auto vertex_p(grid_key_dx< 1 > id) -> decltype(v.template get< i >(id))
Access the vertex.
void resetExchange()
Init communication structures.
void redistribute()
Redistribute function that wraps different stages of the redistribution.
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)
Vcluster & vcl
Vcluster communication object.
std::unordered_map< size_t, size_t > glb2id
Map to access the vertex id given the global vertex id.
bool isGhost(size_t id)
Check if a vertex is a ghost vertex (not belonging to this processor)
E E_type
Edge typedef.
std::unordered_map< size_t, size_t > id2glb
Map to access to the global vertex id given the vertex id.
openfpm::vector< V, Memory, layout_v_base, grow_p, openfpm::vect_isel< V >::value > v
Structure that store the vertex properties.
DistGraph_CSR(Vcluster<> &vcl, DistGraph_CSR< V, E, Memory > &&g)
Copy constructor.
DistGraph_CSR(size_t n_vertex, size_t n_slot)
Constructor.
DistGraph_CSR< V, E, Memory > & operator=(const DistGraph_CSR< V, E, Memory > &g)
Copy the graph.
auto vertex(openfpm::vector_key_iterator id) -> decltype(v.get(0))
operator to access the vertex
bool isToDelete(size_t i)
Check it the vertex i must be deleted or not.
auto edge_p(grid_key_dx< 1 > id) -> decltype(e.template get< i >(id))
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.
void getDecompositionVector(openfpm::vector< idx_t > &v)
Operator to access the decomposition vector.
DistGraph_CSR< V, E, Memory, layout_v, layout_e, layout_v_base, layout_e_base, grow_p > duplicate() const
It duplicate the graph.
openfpm::vector< SendGraphPack > sgp
Pack storing that data to send to other processors.
size_t getNChilds(size_t c) const
Return the number of children of a vertex.
DistGraph_CSR(DistGraph_CSR &&dg)
Constructor.
bool moveQueueIsEmpty()
Check if the move queue is empty.
auto vertex(grid_key_dx< 1 > id) -> decltype(v.get(id.get(0)))
operator to access the vertex
void add_vertex(const V &vrt, size_t id, size_t gid)
Add vertex vrt with global id and id properties.
openfpm::vector< idx_t > vtxdist
Distribution vector.
size_t getChild(size_t v, size_t i) const
Get the child edge.
DistGraph_CSR(size_t n_vertex)
Constructor.
auto vertex(openfpm::vector_key_iterator id) const -> const decltype(v.get(0))
operator to access the vertex
void updateVtxdist()
Update the distribution vector vtxdist.
size_t getNEdge(size_t v) const
Return the number of children of a vertex given its global id.
auto edge(size_t id) const -> const decltype(e.get(id))
operator to access the edge
void reqVertex(size_t gid)
Put a vertex request in queue.
openfpm::vector< idx_t > * getVtxdist()
Operator to access the decomposition vector.
size_t firstId() const
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...
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)
DistGraph_CSR(const DistGraph_CSR &dg)
Constructor.
size_t lastId() const
openfpm::vector< size_t > v_td
Array containing the sent vertices and that will be deleted from the graph.
openfpm::vector< e_info, Memory, layout_e_base, grow_p, openfpm::vect_isel< e_info >::value > e_m
Structure that store the edge properties.
void add_vertex(const encapc< dim, V, Mem > &vrt, size_t id, size_t gid)
Add vertex vrt with global id and id properties.
DistGraph_CSR< V, E, Memory > & operator=(DistGraph_CSR< V, E, Memory > &&g)
Copy the graph.
auto vertex(size_t id) -> decltype(v.get(id))
Function to access the vertexes.
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.
auto vertex(size_t id) const -> const decltype(v.get(id))
Function to access the vertexes.
auto vertex_info(openfpm::vector_key_iterator id) const -> const decltype(v_m.get(0))
operator to access the vertex info
auto getChildInfo(size_t v, size_t v_e) -> decltype(e_m.get(0))
Get the vertex edge info.
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.
void map_v(size_t n, size_t g, size_t l)
operator to update all the hashmap
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.
openfpm::vector< openfpm::vector< size_t > > vr_queue
Queue of vertex requests.
openfpm::vector< E, Memory, layout_e_base, grow_p, openfpm::vect_isel< E >::value > e
Structure that store the edge properties.
void syncEdge()
Execute a synchronization through processor to finalize the add of the edges requested in the e_queue...
size_t getChild(size_t i) const
Get the child edge.
auto getChildEdge(size_t v, size_t v_e) -> decltype(e.get(0))
Get the vertex edge.
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.
size_t getVertexGlobalId(size_t i) const
Get the id of a vertex given its index position.
virtual void incRef()
Increment the reference counter.
void * getPointerBase()
The the base pointer of the preallocate memory.
This class allocate, and destroy CPU memory.
virtual size_t size() const
the the size of the allocated memory
Packing status object.
Definition Pack_stat.hpp:61
Packing class.
Definition Packer.hpp:50
static void pack(ExtPreAlloc< Mem >, const T &obj)
Error, no implementation.
Definition Packer.hpp:56
static size_t packRequest(const T &obj, size_t &req)
Error, no implementation.
Definition Packer.hpp:66
Unpacking status object.
Definition Pack_stat.hpp:16
static void unpack(ExtPreAlloc< Mem >, T &obj)
Error, no implementation.
Definition Unpacker.hpp:40
void execute()
Execute all the requests.
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.
size_t getProcessUnitID()
Get the process unit id.
size_t getProcessingUnits()
Get the total number of processors.
bool allGather(T &send, openfpm::vector< T, Mem, gr > &v)
Gather the data from all processors.
Implementation of VCluster class.
Definition VCluster.hpp:59
Graph edge iterator.
grid_key_dx is the key to access any element in the grid
Definition grid_key.hpp:19
class with no edge
Definition map_graph.hpp:58
Grow policy define how the vector should grow every time we exceed the size.
Implementation of 1-D std::vector like structure.
size_t size()
Stub size.
Structure to store a add request of an edge.
size_t v2n
destination vertex global index
size_t v1n
source vertex global index
size_t v1
source vertex
size_t v2
target vertex
Structure needed to get vertex position by global id.
Struct containing the (sub)graph to send.
bool isEmpty
Indicates if the pack is empty or not.
openfpm::vector< v_info > send_v_m
vertex info send buffer
openfpm::vector< size_t > send_es
For each vertex contain the number of children.
openfpm::vector< size_t > send_el
For each edge contain the child vertex id.
openfpm::vector< e_info > send_e_m
edge info send buffer
openfpm::vector< E > send_e
edge send buffer
openfpm::vector< V > send_v
vertex send buffer
Definition ids.hpp:149
Transform the boost::fusion::vector into memory specification (memory_traits)
It analyze the type given and it select correctly the implementation for vector.
Definition vect_isel.hpp:37
Sub-domain vertex graph node.