COMBINATORIAL_BLAS  1.6
WriteMCLClusters.h
Go to the documentation of this file.
1 /****************************************************************/
2 /* Parallel Combinatorial BLAS Library (for Graph Computations) */
3 /* version 1.6 -------------------------------------------------*/
4 /* date: 6/15/2017 ---------------------------------------------*/
5 /* authors: Ariful Azad, Aydin Buluc --------------------------*/
6 /****************************************************************/
7 
8 
9 
10 #include <mpi.h>
11 #include <stdint.h>
12 #include <sys/time.h>
13 #include <iostream>
14 #include <fstream>
15 #include <string>
16 #include <sstream> // Required for stringstreams
17 #include <ctime>
18 #include <cmath>
19 #include "CombBLAS/CombBLAS.h"
20 
21 namespace combblas {
22 
24 {
25 public:
26  // no reader
27  template <typename c, typename t, typename VT>
28  void save(std::basic_ostream<c,t>& os, std::vector<VT> & strvec, int64_t index)
29  {
30  for (auto it = strvec.begin() ; it != strvec.end(); ++it)
31  os << *it << " ";
32  }
33 };
34 
35 
44 template <class IT>
45 void WriteMCLClusters(std::string ofName, FullyDistVec<IT, IT> clustIdForVtx, FullyDistVec<IT, std::array<char, MAXVERTNAME> > vtxLabels)
46 {
47  auto commGrid = clustIdForVtx.getcommgrid();
48  MPI_Comm World = commGrid->GetWorld();
49  int nprocs = commGrid->GetSize();
50 
51  // find the number of clusters
52  IT nclusters = clustIdForVtx.Reduce(maximum<IT>(), (IT) 0 ) ;
53  nclusters ++; // because of zero based indexing for clusters
54 
55  std::vector<int> rdispls(nprocs+1);
56  std::vector<int> recvcnt(nprocs);
57  std::vector<int> sendcnt(nprocs,0);
58  std::vector<int> sdispls(nprocs+1);
59  IT ploclen = clustIdForVtx.LocArrSize();
60 
61 
62  const IT* larr = clustIdForVtx.GetLocArr(); // local part of cluster ids for vertices
63  //just to get the destination processor
64  FullyDistVec<IT,IT> temp(commGrid, nclusters,0);
65  for(IT i=0; i < ploclen; ++i)
66  {
67  IT locind;
68  int owner = temp.Owner(larr[i], locind);
69  sendcnt[owner]++;
70  }
71  MPI_Alltoall(sendcnt.data(), 1, MPI_INT, recvcnt.data(), 1, MPI_INT, World);
72 
73  sdispls[0] = 0;
74  rdispls[0] = 0;
75  for(int i=0; i<nprocs; ++i)
76  {
77  sdispls[i+1] = sdispls[i] + sendcnt[i];
78  rdispls[i+1] = rdispls[i] + recvcnt[i];
79  }
80 
81 
82  typedef std::array<char, MAXVERTNAME> STRASARRAY;
83  typedef std::pair< IT, STRASARRAY> TYPE2SEND;
84  const STRASARRAY* lVtxLabels = vtxLabels.GetLocArr();
85  std::vector<TYPE2SEND> senddata(ploclen);
86 
87 
88  // Pack cluster and vertex information to send
89  std::vector<int> count(nprocs, 0);
90  for(IT i=0; i < ploclen; ++i)
91  {
92  IT locind;
93  int owner = temp.Owner(larr[i], locind);
94  int idx = sdispls[owner] + count[owner];
95  count[owner]++;
96  senddata[idx] = TYPE2SEND(locind, lVtxLabels[i]); // sending local cluster ids for the destination processor
97  }
98 
99  MPI_Datatype MPI_CLUST;
100  MPI_Type_contiguous(sizeof(TYPE2SEND), MPI_CHAR, &MPI_CLUST);
101  MPI_Type_commit(&MPI_CLUST);
102 
103  IT totrecv = rdispls[nprocs];
104  std::vector<TYPE2SEND> recvdata(totrecv);
105 
106  MPI_Alltoallv(senddata.data(), sendcnt.data(), sdispls.data(), MPI_CLUST, recvdata.data(), recvcnt.data(), rdispls.data(), MPI_CLUST, World);
107 
108 
109  // Receiver groups vertices by cluster ids
110  std::vector< std::vector<std::string> > vtxGroupbyCC(temp.LocArrSize());
111  for(int i=0; i<totrecv; ++i)
112  {
113  IT clusterID = recvdata[i].first;
114  auto locnull = std::find(recvdata[i].second.begin(), recvdata[i].second.end(), '\0'); // find the null character (or string::end)
115  std::string vtxstr(recvdata[i].second.begin(), locnull);
116  vtxGroupbyCC[clusterID].push_back(vtxstr);
117  }
118 
119  // in each cluster sort vertex labels
120 #ifdef THREADED
121 #pragma omp parallel for
122 #endif
123  for(unsigned int i=0; i<vtxGroupbyCC.size(); ++i)
124  {
125  std::sort(vtxGroupbyCC[i].begin(), vtxGroupbyCC[i].end());
126  }
127 
128  // Create a vector locally populate it
129  FullyDistVec<IT,std::vector<std::string> > clusters(commGrid, nclusters, std::vector<std::string>{});
130  for(int i=0; i<clusters.LocArrSize(); i++)
131  {
132  clusters.SetLocalElement(i, vtxGroupbyCC[i]);
133  }
134  // do not write header and 1-based
135  clusters.ParallelWrite(ofName, 1, HipMCLClusterSaveHandler(), false);
136 
137 }
138 
139 
140 
148 template <class IT>
149 void WriteMCLClusters(std::string ofName, FullyDistVec<IT, IT> clustIdForVtx, int base)
150 {
151  auto commGrid = clustIdForVtx.getcommgrid();
152  MPI_Comm World = commGrid->GetWorld();
153  int nprocs = commGrid->GetSize();
154  IT lenuntil = clustIdForVtx.LengthUntil();
155 
156  // find the number of clusters
157  IT nclusters = clustIdForVtx.Reduce(maximum<IT>(), (IT) 0 ) ;
158  nclusters ++; // because of zero based indexing for clusters
159 
160  std::vector<int> rdispls(nprocs+1);
161  std::vector<int> recvcnt(nprocs);
162  std::vector<int> sendcnt(nprocs,0);
163  std::vector<int> sdispls(nprocs+1);
164  IT ploclen = clustIdForVtx.LocArrSize();
165 
166 
167  const IT* larr = clustIdForVtx.GetLocArr(); // local part of cluster ids for vertices
168  //just to get the destination processor
169  FullyDistVec<IT,IT> temp(commGrid, nclusters,0);
170  for(IT i=0; i < ploclen; ++i)
171  {
172  IT locind;
173  int owner = temp.Owner(larr[i], locind);
174  sendcnt[owner]++;
175  }
176  MPI_Alltoall(sendcnt.data(), 1, MPI_INT, recvcnt.data(), 1, MPI_INT, World);
177 
178  sdispls[0] = 0;
179  rdispls[0] = 0;
180  for(int i=0; i<nprocs; ++i)
181  {
182  sdispls[i+1] = sdispls[i] + sendcnt[i];
183  rdispls[i+1] = rdispls[i] + recvcnt[i];
184  }
185 
186 
187 
188  std::vector<std::pair<IT, IT>> senddata(ploclen);
189  // Pack cluster and vertex information to send
190  std::vector<int> count(nprocs, 0);
191  for(IT i=0; i < ploclen; ++i)
192  {
193  IT locind;
194  int owner = temp.Owner(larr[i], locind);
195  int idx = sdispls[owner] + count[owner];
196  count[owner]++;
197  senddata[idx] = std::make_pair(locind, i+lenuntil+base); // sending local cluster ids for the destination processor
198  }
199 
200  MPI_Datatype MPI_CLUST;
201  MPI_Type_contiguous(sizeof(std::pair<IT, IT>), MPI_CHAR, &MPI_CLUST);
202  MPI_Type_commit(&MPI_CLUST);
203 
204  IT totrecv = rdispls[nprocs];
205  std::vector<std::pair<IT, IT>> recvdata(totrecv);
206 
207  MPI_Alltoallv(senddata.data(), sendcnt.data(), sdispls.data(), MPI_CLUST, recvdata.data(), recvcnt.data(), rdispls.data(), MPI_CLUST, World);
208 
209 
210  // Receiver groups vertices by cluster ids
211  std::vector< std::vector<IT> > vtxGroupbyCC(temp.LocArrSize());
212  for(int i=0; i<totrecv; ++i)
213  {
214  IT clusterID = recvdata[i].first;
215  vtxGroupbyCC[clusterID].push_back(recvdata[i].second);
216  }
217 
218  // Create a vector locally populate it
219  FullyDistVec<IT,std::vector<IT> > clusters(commGrid, nclusters, std::vector<IT>{});
220  for(int i=0; i<clusters.LocArrSize(); i++)
221  {
222  clusters.SetLocalElement(i, vtxGroupbyCC[i]);
223  }
224  // do not write header and 1-based
225  clusters.ParallelWrite(ofName, 1, HipMCLClusterSaveHandler(), false);
226 
227 }
228 
229 }
230 
void save(std::basic_ostream< c, t > &os, std::vector< VT > &strvec, int64_t index)
Compute the maximum of two values.
Definition: Operations.h:154
std::shared_ptr< CommGrid > getcommgrid() const
Definition: FullyDistVec.h:257
void SetLocalElement(IT index, NT value)
Definition: FullyDistVec.h:144
long int64_t
Definition: compat.h:21
Definition: CCGrid.h:4
NT Reduce(_BinaryOperation __binary_op, NT identity) const
void WriteMCLClusters(std::string ofName, FullyDistVec< IT, IT > clustIdForVtx, FullyDistVec< IT, std::array< char, MAXVERTNAME > > vtxLabels)
const NT * GetLocArr() const
Definition: FullyDistVec.h:167