COMBINATORIAL_BLAS  1.6
SpCCols.cpp
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  Copyright (c) 2010-2017, The Regents of the University of California
9 
10  Permission is hereby granted, free of charge, to any person obtaining a copy
11  of this software and associated documentation files (the "Software"), to deal
12  in the Software without restriction, including without limitation the rights
13  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14  copies of the Software, and to permit persons to whom the Software is
15  furnished to do so, subject to the following conditions:
16 
17  The above copyright notice and this permission notice shall be included in
18  all copies or substantial portions of the Software.
19 
20  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26  THE SOFTWARE.
27  */
28 
29 
30 #include "SpCCols.h"
31 #include "Deleter.h"
32 #include <algorithm>
33 #include <functional>
34 #include <vector>
35 #include <climits>
36 #include <iomanip>
37 #include <cassert>
38 
39 namespace combblas {
40 
41 /****************************************************************************/
42 /********************* PUBLIC CONSTRUCTORS/DESTRUCTORS **********************/
43 /****************************************************************************/
44 
45 template <class IT, class NT>
46 const IT SpCCols<IT,NT>::esscount = static_cast<IT>(3);
47 
48 
49 template <class IT, class NT>
50 SpCCols<IT,NT>::SpCCols():csc(NULL), m(0), n(0), nnz(0), splits(0){
51 }
52 
53 // Allocate all the space necessary
54 template <class IT, class NT>
55 SpCCols<IT,NT>::SpCCols(IT size, IT nRow, IT nCol)
56 :m(nRow), n(nCol), nnz(size), splits(0)
57 {
58  if(nnz > 0)
59  csc = new Csc<IT,NT>(nnz, n);
60  else
61  csc = NULL;
62 }
63 
64 template <class IT, class NT>
66 {
67  if(nnz > 0)
68  {
69  if(csc != NULL)
70  {
71  if(splits > 0)
72  {
73  for(int i=0; i<splits; ++i)
74  delete cscarr[i];
75  delete [] cscarr;
76  }
77  else
78  {
79  delete csc;
80  }
81  }
82  }
83 }
84 
85 // Copy constructor (constructs a new object. i.e. this is NEVER called on an existing object)
86 // Derived's copy constructor can safely call Base's default constructor as base has no data members
87 template <class IT, class NT>
89 : m(rhs.m), n(rhs.n), nnz(rhs.nnz), splits(rhs.splits)
90 {
91  if(splits > 0)
92  {
93  for(int i=0; i<splits; ++i)
94  CopyCsc(rhs.cscarr[i]);
95  }
96  else
97  {
98  CopyCsc(rhs.csc);
99  }
100 }
101 
108 template <class IT, class NT>
109 SpCCols<IT,NT>::SpCCols(const SpTuples<IT, NT> & rhs, bool transpose)
110 : m(rhs.m), n(rhs.n), nnz(rhs.nnz), splits(0)
111 {
112 
113  if(nnz == 0) // m by n matrix of complete zeros
114  {
115  if(transpose) std::swap(m,n);
116  csc = NULL;
117  }
118  else
119  {
120  if(transpose)
121  {
122  std::swap(m,n);
123  csc = new Csc<IT,NT>(nnz,n); // the swap is already done here
124  std::vector< std::pair<IT,NT> > tosort (nnz);
125  std::vector<IT> work(n+1, (IT) 0 ); // workspace, zero initialized, first entry stays zero
126  for (IT k = 0 ; k < nnz ; ++k)
127  {
128  IT tmp = rhs.rowindex(k);
129  work [ tmp+1 ]++ ; // column counts (i.e, w holds the "col difference array")
130  }
131  if(nnz > 0)
132  {
133  std::partial_sum(work.begin(), work.end(), work.begin());
134  std::copy(work.begin(), work.end(), csc->jc);
135  IT last;
136  for (IT k = 0 ; k < nnz ; ++k)
137  {
138  tosort[ work[ rhs.rowindex(k) ]++] = std::make_pair( rhs.colindex(k), rhs.numvalue(k));
139  }
140  #ifdef _OPENMP
141  #pragma omp parallel for
142  #endif
143  for(int i=0; i< n; ++i)
144  {
145  sort(tosort.begin() + csc->jc[i], tosort.begin() + csc->jc[i+1]);
146 
147  IT ind;
148  typename std::vector<std::pair<IT,NT> >::iterator itr; // iterator is a dependent name
149  for(itr = tosort.begin() + csc->jc[i], ind = csc->jc[i]; itr != tosort.begin() + csc->jc[i+1]; ++itr, ++ind)
150  {
151  csc->ir[ind] = itr->first;
152  csc->num[ind] = itr->second;
153  }
154  }
155  }
156  }
157  else
158  {
159  csc = new Csc<IT,NT>(nnz,n); // the swap is already done here
160  std::vector< std::pair<IT,NT> > tosort (nnz);
161  std::vector<IT> work(n+1, (IT) 0 ); // workspace, zero initialized, first entry stays zero
162  for (IT k = 0 ; k < nnz ; ++k)
163  {
164  IT tmp = rhs.colindex(k);
165  work [ tmp+1 ]++ ; // column counts (i.e, w holds the "col difference array")
166  }
167  if(nnz > 0)
168  {
169  std::partial_sum(work.begin(), work.end(), work.begin());
170  std::copy(work.begin(), work.end(), csc->jc);
171  IT last;
172  for (IT k = 0 ; k < nnz ; ++k)
173  {
174  tosort[ work[ rhs.colindex(k) ]++] = std::make_pair( rhs.rowindex(k), rhs.numvalue(k));
175  }
176  #ifdef _OPENMP
177  #pragma omp parallel for
178  #endif
179  for(int i=0; i< n; ++i)
180  {
181  sort(tosort.begin() + csc->jc[i], tosort.begin() + csc->jc[i+1]);
182 
183  IT ind;
184  typename std::vector<std::pair<IT,NT> >::iterator itr; // iterator is a dependent name
185  for(itr = tosort.begin() + csc->jc[i], ind = csc->jc[i]; itr != tosort.begin() + csc->jc[i+1]; ++itr, ++ind)
186  {
187  csc->ir[ind] = itr->first;
188  csc->num[ind] = itr->second;
189  }
190  }
191  }
192  }
193  }
194 }
195 
196 /****************************************************************************/
197 /************************** PUBLIC OPERATORS ********************************/
198 /****************************************************************************/
199 
205 template <class IT, class NT>
207 {
208  // this pointer stores the address of the class instance
209  // check for self assignment using address comparison
210  if(this != &rhs)
211  {
212  if(csc != NULL && nnz > 0)
213  {
214  delete csc;
215  }
216  if(rhs.csc != NULL)
217  {
218  csc = new Csc<IT,NT>(*(rhs.csc));
219  nnz = rhs.nnz;
220  }
221  else
222  {
223  csc = NULL;
224  nnz = 0;
225  }
226 
227  m = rhs.m;
228  n = rhs.n;
229  splits = rhs.splits;
230  }
231  return *this;
232 }
233 
234 
235 template <class IT, class NT>
236 void SpCCols<IT,NT>::RowSplit(int numsplits)
237 {
238  splits = numsplits;
239  IT perpiece = m / splits;
240  std::vector<IT> nnzs(splits, 0);
241  std::vector < std::vector < std::tuple<IT,IT,NT> > > colrowpairs(splits);
242  std::vector< std::vector<IT> > colcnts(splits);
243  for(int i=0; i< splits; ++i)
244  colcnts[i].resize(n, 0);
245 
246  if(nnz > 0 && csc != NULL)
247  {
248  for(IT i=0; i< csc->n; ++i)
249  {
250  for(IT j = csc->jc[i]; j< csc->jc[i+1]; ++j)
251  {
252  IT rowid = csc->ir[j]; // colid=i
253  IT owner = std::min(rowid / perpiece, static_cast<IT>(splits-1));
254  colrowpairs[owner].push_back(std::make_tuple(i, rowid - owner*perpiece, csc->num[i]));
255 
256  ++(colcnts[owner][i]);
257  ++(nnzs[owner]);
258  }
259  }
260  }
261  delete csc; // claim memory
262  cscarr = new Csc<IT,NT>*[splits];
263 
264  #ifdef _OPENMP
265  #pragma omp parallel for
266  #endif
267  for(int i=0; i< splits; ++i) // i iterates over splits
268  {
269  cscarr[i] = new Csc<IT,NT>(nnzs[i],n);
270  sort(colrowpairs[i].begin(), colrowpairs[i].end()); // sort w.r.t. columns first and rows second
271  cscarr[i]->jc[0] = 0;
272  std::partial_sum(colcnts[i].begin(), colcnts[i].end(), cscarr[i]->jc+1);
273  std::copy(cscarr[i]->jc, cscarr[i]->jc+n, colcnts[i].begin()); // reuse the colcnts as "current column pointers"
274 
275 
276  for(IT k=0; k<nnzs[i]; ++k) // k iterates over all nonzeros
277  {
278  IT cindex = std::get<0>(colrowpairs[i][k]);
279  IT rindex = std::get<1>(colrowpairs[i][k]);
280  NT value = std::get<2>(colrowpairs[i][k]);
281 
282  IT curcptr = (colcnts[i][cindex])++; // fetch the pointer and post increment
283  cscarr[i]->ir[curcptr] = rindex;
284  cscarr[i]->num[curcptr] = value;
285  }
286  }
287 }
288 
289 
290 template<class IT, class NT>
292 {
293  std::cout << "m: " << m ;
294  std::cout << ", n: " << n ;
295  std::cout << ", nnz: "<< nnz ;
296 
297  if(splits > 0)
298  {
299  std::cout << ", local splits: " << splits << std::endl;
300 #ifdef _OPENMP
301  if(omp_get_thread_num() == 0)
302  {
303  SubPrintInfo(cscarr[0]);
304  }
305 #endif
306  }
307  else
308  {
309  std::cout << std::endl;
310  SubPrintInfo(csc);
311  }
312 }
313 
314 
315 
316 
317 /****************************************************************************/
318 /************************* PRIVATE MEMBER FUNCTIONS *************************/
319 /****************************************************************************/
320 
321 
322 template <class IT, class NT>
323 void SpCCols<IT,NT>::SubPrintInfo(Csc<IT,NT> * mycsc) const
324 {
325 #ifdef _OPENMP
326  std::cout << "Printing for thread " << omp_get_thread_num() << std::endl;
327 #endif
328  if(m < PRINT_LIMIT && n < PRINT_LIMIT) // small enough to print
329  {
330  NT ** A = SpHelper::allocate2D<NT>(m,n);
331  for(IT i=0; i< m; ++i)
332  for(IT j=0; j<n; ++j)
333  A[i][j] = NT();
334  if(mycsc != NULL)
335  {
336  for(IT i=0; i< n; ++i)
337  {
338  for(IT j = mycsc->jc[i]; j< mycsc->jc[i+1]; ++j)
339  {
340  IT rowid = mycsc->ir[j];
341  A[rowid][i] = mycsc->num[j];
342  }
343  }
344  }
345  for(IT i=0; i< m; ++i)
346  {
347  for(IT j=0; j<n; ++j)
348  {
349  std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(2) << A[i][j];
350  std::cout << " ";
351  }
352  std::cout << std::endl;
353  }
355  }
356 }
357 
358 
359 template <class IT, class NT>
360 inline void SpCCols<IT,NT>::CopyCsc(Csc<IT,NT> * source)
361 {
362  // source csc will be NULL if number of nonzeros is zero
363  if(source != NULL)
364  csc = new Csc<IT,NT>(*source);
365  else
366  csc = NULL;
367 }
368 
369 }
int size
void PrintInfo() const
Definition: SpCCols.cpp:291
IT & colindex(IT i)
Definition: SpTuples.h:75
NT & numvalue(IT i)
Definition: SpTuples.h:76
SpCCols< IT, NT > & operator=(const SpCCols< IT, NT > &rhs)
Definition: SpCCols.cpp:206
IT * jc
Definition: csc.h:57
IT * ir
Definition: csc.h:58
double A
static const IT esscount
Definition: SpCCols.h:73
IT & rowindex(IT i)
Definition: SpTuples.h:74
Csc< IT, NT > ** cscarr
Definition: SpCCols.h:222
NT * num
Definition: csc.h:59
Definition: CCGrid.h:4
#define PRINT_LIMIT
Definition: SpDefs.h:63
Csc< IT, NT > * csc
Definition: SpCCols.h:221
void RowSplit(int numsplits)
Definition: SpCCols.cpp:236
static void deallocate2D(T **array, I m)
Definition: SpHelper.h:249