COMBINATORIAL_BLAS 1.6
 
Loading...
Searching...
No Matches
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
39namespace combblas {
40
41/****************************************************************************/
42/********************* PUBLIC CONSTRUCTORS/DESTRUCTORS **********************/
43/****************************************************************************/
44
45template <class IT, class NT>
46const IT SpCCols<IT,NT>::esscount = static_cast<IT>(3);
47
48
49template <class IT, class NT>
50SpCCols<IT,NT>::SpCCols():csc(NULL), m(0), n(0), nnz(0), splits(0){
51}
52
53// Allocate all the space necessary
54template <class IT, class NT>
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
64template <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
87template <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
108template <class IT, class NT>
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
205template <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
235template <class IT, class NT>
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
290template<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
315template <class IT, class NT>
316template <typename UnaryOperation, typename GlobalIT>
319 bool inPlace,
320 GlobalIT rowOffset,
321 GlobalIT colOffset
322 )
323{
325
326 if (nnz > 0)
327 {
329 if (inPlace)
330 {
331 nnz = csc->nz;
332 if (nnz == 0)
333 {
334 delete csc;
335 csc = NULL;
336 }
337 retcols = NULL;
338 }
339 else
340 {
341 // wrap the pruned csc into a new SpCCols
342 retcols = new SpCCols<IT, NT>();
343 retcols->csc = ret;
344 retcols->nnz = retcols->csc->nz;
345 retcols->n = n;
346 retcols->m = m;
347 }
348 }
349 else
350 {
351 if (inPlace)
352 retcols = NULL;
353 else
354 {
355 retcols = new SpCCols<IT, NT>();
356 retcols->csc = NULL;
357 retcols->nnz = 0;
358 retcols->n = 0;
359 retcols->m = 0;
360 }
361 }
362
363 return retcols;
364}
365
366
367
368template <class IT, class NT>
369std::vector<IT>
371{
372 std::vector<IT> essentials(esscount);
373 essentials[0] = nnz;
374 essentials[1] = m;
375 essentials[2] = n;
376 return essentials;
377}
378
379
380
381template <class IT, class NT>
382void
384{
385 assert(essentials.size() == esscount);
386
387 nnz = essentials[0];
388 m = essentials[1];
389 n = essentials[2];
390
391 if (nnz > 0)
392 csc = new Csc<IT, NT>(nnz, n);
393 else
394 csc = NULL;
395}
396
397
398
399template <class IT, class NT>
400void
402 IT nRow,
403 IT nCol,
404 std::tuple<IT, IT, NT> *mytuples)
405{
407 tuples.SortColBased();
408 SpCCols<IT, NT> tmp(tuples, false);
409 *this = tmp;
410}
411
412
413
414template <class IT, class NT>
417{
418 Arr<IT, NT> arr(2, 1);
419
420 if (nnz > 0)
421 {
422 arr.indarrs[0] = LocArr<IT, IT>(csc->jc, csc->n + 1);
423 arr.indarrs[1] = LocArr<IT, IT>(csc->ir, csc->nz);
424 arr.numarrs[0] = LocArr<NT, IT>(csc->num, csc->nz);
425 }
426 else
427 {
428 arr.indarrs[0] = LocArr<IT, IT>(NULL, 0);
429 arr.indarrs[1] = LocArr<IT, IT>(NULL, 0);
430 arr.numarrs[0] = LocArr<NT, IT>(NULL, 0);
431 }
432
433 return arr;
434}
435
436
437
438template <class IT, class NT>
439void
441{
442 if (nnz > 0)
443 {
444 SpTuples<IT, NT> tuples(*this);
445 tuples.SortRowBased();
446 *this = SpCCols<IT, NT>(tuples, true);
447 }
448 else
449 *this = SpCCols<IT, NT>(0, n, m);
450}
451
452
453
454template <class IT, class NT>
457{
458 SpTuples<IT, NT> tuples(*this);
459 tuples.SortRowBased();
460
461 return SpCCols<IT, NT>(tuples, true);
462}
463
464
465
466template <class IT, class NT>
469{
470 SpTuples<IT, NT> tuples(*this);
471 tuples.SortRowBased();
472
473 return new SpCCols<IT, NT>(tuples, true);
474}
475
476
477
478template <class IT, class NT>
479void
482 )
483{
484 IT cut = n/2;
485 if (cut == 0)
486 {
487 std::cout<< "Matrix is too small to be splitted" << std::endl;
488 return;
489 }
490
493
494 if (nnz != 0)
495 csc->Split(Acsc, Bcsc, cut);
496
498 partB = SpCCols<IT, NT>(m, n - cut, Bcsc);
499
500 *this = SpCCols<IT, NT>();
501}
502
503
504
505template <class IT, class NT>
506void
509 )
510{
511 assert (partA.m == partB.m);
512
514 if (partA.nnz == 0 && partB.nnz == 0)
515 Ccsc = NULL;
516 else if (partA.nnz == 0)
517 {
518 Ccsc = new Csc<IT, NT>(partB.nnz, partA.n + partB.n);
519 std::fill(Ccsc->jc, Ccsc->jc + partA.n, 0);
520 std::copy(partB.csc->jc, partB.csc->jc + partB.n + 1,
521 Ccsc->jc + partA.n);
522 std::copy(partB.csc->ir, partB.csc->ir + partB.nnz, Ccsc->ir);
523 std::copy(partB.csc->num, partB.csc->num + partB.nnz, Ccsc->num);
524 // Ccsc = new Csc<IT,NT>(*(partB.csc));
525 }
526 else if (partB.nnz == 0)
527 {
528 Ccsc = new Csc<IT, NT>(partA.nnz, partA.n + partB.n);
529 std::copy(partA.csc->jc, partA.csc->jc + partA.n + 1, Ccsc->jc);
530 std::fill(Ccsc->jc + partA.n + 1, Ccsc->jc + partA.n + partB.n + 1,
531 partA.csc->jc[partA.n]);
532 std::copy(partA.csc->ir, partA.csc->ir + partA.nnz, Ccsc->ir);
533 std::copy(partA.csc->num, partA.csc->num + partA.nnz, Ccsc->num);
534 // Ccsc = new Csc<IT,NT>(*(partA.csc));
535 }
536 else
537 Ccsc->Merge(partA.csc, partB.csc, partA.n); // 3rd param not used
538
539 *this = SpCCols<IT, NT>(partA.m, partA.n + partB.n, Ccsc);
540
543}
544
545
546
547template <class IT, class NT>
548std::ofstream &
549SpCCols<IT, NT>::put (std::ofstream &outfile) const
550{
551 if (nnz == 0)
552 {
553 outfile << "Matrix doesn't have any nonzeros" << std::endl;
554 return outfile;
555 }
556
557 SpTuples<IT, NT> tuples(*this);
558 outfile << tuples << std::endl;
559 return outfile;
560}
561
562
563
564
565/****************************************************************************/
566/************************* PRIVATE MEMBER FUNCTIONS *************************/
567/****************************************************************************/
568
569
570template <class IT, class NT>
572 IT nCol,
574 ) :
575 csc(mycsc), m(nRow), n(nCol), splits(0)
576{
577 if (mycsc == NULL)
578 nnz = 0;
579 else
580 nnz = mycsc->nz;
581}
582
583
584
585template <class IT, class NT>
586void SpCCols<IT,NT>::SubPrintInfo(Csc<IT,NT> * mycsc) const
587{
588#ifdef _OPENMP
589 std::cout << "Printing for thread " << omp_get_thread_num() << std::endl;
590#endif
591 if(m < PRINT_LIMIT && n < PRINT_LIMIT) // small enough to print
592 {
593 NT ** A = SpHelper::allocate2D<NT>(m,n);
594 for(IT i=0; i< m; ++i)
595 for(IT j=0; j<n; ++j)
596 A[i][j] = NT();
597 if(mycsc != NULL)
598 {
599 for(IT i=0; i< n; ++i)
600 {
601 for(IT j = mycsc->jc[i]; j< mycsc->jc[i+1]; ++j)
602 {
603 IT rowid = mycsc->ir[j];
604 A[rowid][i] = mycsc->num[j];
605 }
606 }
607 }
608 for(IT i=0; i< m; ++i)
609 {
610 for(IT j=0; j<n; ++j)
611 {
612 std::cout << std::setiosflags(std::ios::fixed) << std::setprecision(2) << A[i][j];
613 std::cout << " ";
614 }
615 std::cout << std::endl;
616 }
618 }
619}
620
621
622template <class IT, class NT>
623inline void SpCCols<IT,NT>::CopyCsc(Csc<IT,NT> * source)
624{
625 // source csc will be NULL if number of nonzeros is zero
626 if(source != NULL)
627 csc = new Csc<IT,NT>(*source);
628 else
629 csc = NULL;
630}
631
632}
int64_t IT
double NT
void CreateImpl(const std::vector< IT > &essentials)
Definition SpCCols.cpp:383
void RowSplit(int numsplits)
Definition SpCCols.cpp:236
void Split(SpCCols< IT, NT > &partA, SpCCols< IT, NT > &partB)
Definition SpCCols.cpp:480
SpCCols< IT, NT > TransposeConst() const
Definition SpCCols.cpp:456
SpCCols< IT, NT > * TransposeConstPtr() const
Definition SpCCols.cpp:468
SpCCols< IT, NT > * PruneI(UnaryOperation unary_op, bool inPlace, GlobalIT rowOffset, GlobalIT colOffset)
Definition SpCCols.cpp:318
static const IT esscount
Definition SpCCols.h:73
Arr< IT, NT > GetArrays() const
Definition SpCCols.cpp:416
void PrintInfo() const
Definition SpCCols.cpp:291
std::ofstream & put(std::ofstream &outfile) const
Definition SpCCols.cpp:549
SpCCols< IT, NT > & operator=(const SpCCols< IT, NT > &rhs)
Definition SpCCols.cpp:206
void Merge(SpCCols< IT, NT > &partA, SpCCols< IT, NT > &partB)
Definition SpCCols.cpp:507
std::vector< IT > GetEssentials() const
Definition SpCCols.cpp:370
Csc< IT, NT > * csc
Definition SpCCols.h:268
static void deallocate2D(T **array, I m)
Definition SpHelper.h:249
int size
Definition common.h:20
#define PRINT_LIMIT
Definition SpDefs.h:63
double A