COMBINATORIAL_BLAS 1.6
 
Loading...
Searching...
No Matches
dcsc.cpp
Go to the documentation of this file.
1/****************************************************************/
2/* Parallel Combinatorial BLAS Library (for Graph Computations) */
3/* version 1.6 -------------------------------------------------*/
4/* date: 05/15/2016 --------------------------------------------*/
5/* authors: Ariful Azad, Aydin Buluc, Adam Lugowski ------------*/
6/****************************************************************/
7/*
8 Copyright (c) 2010-2016, 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 "dcsc.h"
31#include <algorithm>
32#include <functional>
33#include <iostream>
34#include "Friends.h"
35#include "SpHelper.h"
36
37
38namespace combblas {
39
40template <class IT, class NT>
41Dcsc<IT,NT>::Dcsc ():cp(NULL), jc(NULL), ir(NULL), numx(NULL),nz(0), nzc(0), memowned(true){}
42
43template <class IT, class NT>
44Dcsc<IT,NT>::Dcsc (IT nnz, IT nzcol): nz(nnz),nzc(nzcol),memowned(true)
45{
46 assert (nz != 0);
47 assert (nzc != 0);
48 cp = new IT[nzc+1];
49 jc = new IT[nzc];
50 ir = new IT[nz];
51 numx = new NT[nz];
52}
53
55template <class IT, class NT>
56inline void Dcsc<IT,NT>::getindices (StackEntry<NT, std::pair<IT,IT> > * multstack, IT & rindex, IT & cindex, IT & j, IT nnz)
57{
58 if(j<nnz)
59 {
60 cindex = multstack[j].key.first;
61 rindex = multstack[j].key.second;
62 }
63 else
64 {
65 rindex = std::numeric_limits<IT>::max();
66 cindex = std::numeric_limits<IT>::max();
67 }
68 ++j;
69}
70
71template <class IT, class NT>
73{
74 if(nnz == 0) return *this;
75
76 IT estnzc = nzc + nnz;
77 IT estnz = nz + nnz;
79
80 IT curnzc = 0; // number of nonzero columns constructed so far
81 IT curnz = 0;
82 IT i = 0;
83 IT j = 0;
85 getindices(multstack, rindex, cindex,j,nnz);
86
87 temp.cp[0] = 0;
88 while(i< nzc && cindex < std::numeric_limits<IT>::max()) // i runs over columns of "this", j runs over all the nonzeros of "multstack"
89 {
90 if(jc[i] > cindex)
91 {
92 IT columncount = 0;
93 temp.jc[curnzc++] = cindex;
94 do
95 {
96 temp.ir[curnz] = rindex;
97 temp.numx[curnz++] = multstack[j-1].value;
98
99 getindices(multstack, rindex, cindex,j,nnz);
100 ++columncount;
101 }
102 while(temp.jc[curnzc-1] == cindex); // loop until cindex changes
103
104 temp.cp[curnzc] = temp.cp[curnzc-1] + columncount;
105 }
106 else if(jc[i] < cindex)
107 {
108 temp.jc[curnzc++] = jc[i++];
109 for(IT k = cp[i-1]; k< cp[i]; ++k)
110 {
111 temp.ir[curnz] = ir[k];
112 temp.numx[curnz++] = numx[k];
113 }
114 temp.cp[curnzc] = temp.cp[curnzc-1] + (cp[i] - cp[i-1]);
115 }
116 else // they are equal, merge the column
117 {
118 temp.jc[curnzc++] = jc[i];
119 IT ii = cp[i];
120 IT prevnz = curnz;
121 while (ii < cp[i+1] && cindex == jc[i]) // cindex would be MAX if multstack is deplated
122 {
123 if (ir[ii] < rindex)
124 {
125 temp.ir[curnz] = ir[ii];
126 temp.numx[curnz++] = numx[ii++];
127 }
128 else if (ir[ii] > rindex)
129 {
130 temp.ir[curnz] = rindex;
131 temp.numx[curnz++] = multstack[j-1].value;
132
133 getindices(multstack, rindex, cindex,j,nnz);
134 }
135 else
136 {
137 temp.ir[curnz] = ir[ii];
138 temp.numx[curnz++] = numx[ii++] + multstack[j-1].value;
139
140 getindices(multstack, rindex, cindex,j,nnz);
141 }
142 }
143 while (ii < cp[i+1])
144 {
145 temp.ir[curnz] = ir[ii];
146 temp.numx[curnz++] = numx[ii++];
147 }
148 while (cindex == jc[i])
149 {
150 temp.ir[curnz] = rindex;
151 temp.numx[curnz++] = multstack[j-1].value;
152
153 getindices(multstack, rindex, cindex,j,nnz);
154 }
155 temp.cp[curnzc] = temp.cp[curnzc-1] + curnz-prevnz;
156 ++i;
157 }
158 }
159 while(i< nzc)
160 {
161 temp.jc[curnzc++] = jc[i++];
162 for(IT k = cp[i-1]; k< cp[i]; ++k)
163 {
164 temp.ir[curnz] = ir[k];
165 temp.numx[curnz++] = numx[k];
166 }
167 temp.cp[curnzc] = temp.cp[curnzc-1] + (cp[i] - cp[i-1]);
168 }
169 while(cindex < std::numeric_limits<IT>::max())
170 {
171 IT columncount = 0;
172 temp.jc[curnzc++] = cindex;
173 do
174 {
175 temp.ir[curnz] = rindex;
176 temp.numx[curnz++] = multstack[j-1].value;
177
178 getindices(multstack, rindex, cindex,j,nnz);
179 ++columncount;
180 }
181 while(temp.jc[curnzc-1] == cindex); // loop until cindex changes
182
183 temp.cp[curnzc] = temp.cp[curnzc-1] + columncount;
184 }
185 temp.Resize(curnzc, curnz);
186 *this = temp;
187 return *this;
188}
189
190
195template <class IT, class NT>
196Dcsc<IT,NT>::Dcsc (StackEntry<NT, std::pair<IT,IT> > * multstack, IT mdim, IT ndim, IT nnz): nz(nnz),memowned(true)
197{
198 nzc = std::min(ndim, nnz); // nzc can't exceed any of those
199
200 assert(nz != 0 );
201 cp = new IT[nzc+1]; // to be shrinked
202 jc = new IT[nzc]; // to be shrinked
203 ir = new IT[nz];
204 numx = new NT[nz];
205
206 IT curnzc = 0; // number of nonzero columns constructed so far
207 IT cindex = multstack[0].key.first;
208 IT rindex = multstack[0].key.second;
209
210 ir[0] = rindex;
211 numx[0] = multstack[0].value;
212 jc[curnzc] = cindex;
213 cp[curnzc] = 0;
214 ++curnzc;
215
216 for(IT i=1; i<nz; ++i)
217 {
218 cindex = multstack[i].key.first;
219 rindex = multstack[i].key.second;
220
221 ir[i] = rindex;
222 numx[i] = multstack[i].value;
223 if(cindex != jc[curnzc-1])
224 {
225 jc[curnzc] = cindex;
226 cp[curnzc++] = i;
227 }
228 }
229 cp[curnzc] = nz;
230 Resize(curnzc, nz); // only shrink cp & jc arrays
231}
232
238template <class IT, class NT>
239Dcsc<IT,NT>::Dcsc (IT nnz, const std::vector<IT> & indices, bool isRow): nz(nnz),nzc(nnz),memowned(true)
240{
241 assert((nnz != 0) && (indices.size() == nnz));
242 cp = new IT[nnz+1];
243 jc = new IT[nnz];
244 ir = new IT[nnz];
245 numx = new NT[nnz];
246
247 SpHelper::iota(cp, cp+nnz+1, 0); // insert sequential values {0,1,2,..}
248 std::fill_n(numx, nnz, static_cast<NT>(1));
249
250 if(isRow)
251 {
252 SpHelper::iota(ir, ir+nnz, 0);
253 std::copy (indices.begin(), indices.end(), jc);
254 }
255 else
256 {
257 SpHelper::iota(jc, jc+nnz, 0);
258 std::copy (indices.begin(), indices.end(), ir);
259 }
260}
261
262
263template <class IT, class NT>
264template <typename NNT>
266{
267 Dcsc<IT,NNT> convert(nz, nzc);
268
269 for(IT i=0; i< nz; ++i)
270 {
271 convert.numx[i] = static_cast<NNT>(numx[i]);
272 }
273 std::copy(ir, ir+nz, convert.ir); // copy(first, last, result)
274 std::copy(jc, jc+nzc, convert.jc);
275 std::copy(cp, cp+nzc+1, convert.cp);
276 return convert;
277}
278
279template <class IT, class NT>
280template <typename NIT, typename NNT>
282{
283 Dcsc<NIT,NNT> convert(nz, nzc);
284
285 for(IT i=0; i< nz; ++i)
286 convert.numx[i] = static_cast<NNT>(numx[i]);
287 for(IT i=0; i< nz; ++i)
288 convert.ir[i] = static_cast<NIT>(ir[i]);
289 for(IT i=0; i< nzc; ++i)
290 convert.jc[i] = static_cast<NIT>(jc[i]);
291 for(IT i=0; i<= nzc; ++i)
292 convert.cp[i] = static_cast<NIT>(cp[i]);
293 return convert;
294}
295
296template <class IT, class NT>
297Dcsc<IT,NT>::Dcsc (const Dcsc<IT,NT> & rhs): nz(rhs.nz), nzc(rhs.nzc),memowned(true)
298{
299 if(nz > 0)
300 {
301 numx = new NT[nz];
302 ir = new IT[nz];
303 std::copy(rhs.numx, rhs.numx + nz, numx); // numx can be a non-POD type
304 std::copy(rhs.ir, rhs.ir + nz, ir);
305 }
306 else
307 {
308 numx = NULL;
309 ir = NULL;
310 }
311 if(nzc > 0)
312 {
313 jc = new IT[nzc];
314 cp = new IT[nzc+1];
315 std::copy(rhs.jc, rhs.jc + nzc, jc);
316 std::copy(rhs.cp, rhs.cp + nzc + 1, cp);
317 }
318 else
319 {
320 jc = NULL;
321 cp = NULL;
322 }
323}
324
328template <class IT, class NT>
330{
331 if(this != &rhs)
332 {
333 // make empty first !
334 if(nz > 0)
335 {
336 delete[] numx;
337 delete[] ir;
338 }
339 if(nzc > 0)
340 {
341 delete[] jc;
342 delete[] cp;
343 }
344 nz = rhs.nz;
345 nzc = rhs.nzc;
346 if(nz > 0)
347 {
348 numx = new NT[nz];
349 ir = new IT[nz];
350 std::copy(rhs.numx, rhs.numx + nz, numx); // numx can be a non-POD type
351 std::copy(rhs.ir, rhs.ir + nz, ir);
352 }
353 else
354 {
355 numx = NULL;
356 ir = NULL;
357 }
358 if(nzc > 0)
359 {
360 jc = new IT[nzc];
361 cp = new IT[nzc+1];
362 std::copy(rhs.jc, rhs.jc + nzc, jc);
363 std::copy(rhs.cp, rhs.cp + nzc + 1, cp);
364 }
365 else
366 {
367 jc = NULL;
368 cp = NULL;
369 }
370 }
371 return *this;
372}
373
374template <class IT, class NT>
375Dcsc<IT, NT> & Dcsc<IT,NT>::operator+=(const Dcsc<IT,NT> & rhs) // add and assign operator
376{
377 IT estnzc = nzc + rhs.nzc;
378 IT estnz = nz + rhs.nz;
380
381 IT curnzc = 0;
382 IT curnz = 0;
383 IT i = 0;
384 IT j = 0;
385 temp.cp[0] = 0;
386 while(i< nzc && j<rhs.nzc)
387 {
388 if(jc[i] > rhs.jc[j])
389 {
390 temp.jc[curnzc++] = rhs.jc[j++];
391 for(IT k = rhs.cp[j-1]; k< rhs.cp[j]; ++k)
392 {
393 temp.ir[curnz] = rhs.ir[k];
394 temp.numx[curnz++] = rhs.numx[k];
395 }
396 temp.cp[curnzc] = temp.cp[curnzc-1] + (rhs.cp[j] - rhs.cp[j-1]);
397 }
398 else if(jc[i] < rhs.jc[j])
399 {
400 temp.jc[curnzc++] = jc[i++];
401 for(IT k = cp[i-1]; k< cp[i]; k++)
402 {
403 temp.ir[curnz] = ir[k];
404 temp.numx[curnz++] = numx[k];
405 }
406 temp.cp[curnzc] = temp.cp[curnzc-1] + (cp[i] - cp[i-1]);
407 }
408 else
409 {
410 temp.jc[curnzc++] = jc[i];
411 IT ii = cp[i];
412 IT jj = rhs.cp[j];
413 IT prevnz = curnz;
414 while (ii < cp[i+1] && jj < rhs.cp[j+1])
415 {
416 if (ir[ii] < rhs.ir[jj])
417 {
418 temp.ir[curnz] = ir[ii];
419 temp.numx[curnz++] = numx[ii++];
420 }
421 else if (ir[ii] > rhs.ir[jj])
422 {
423 temp.ir[curnz] = rhs.ir[jj];
424 temp.numx[curnz++] = rhs.numx[jj++];
425 }
426 else
427 {
428 temp.ir[curnz] = ir[ii];
429 temp.numx[curnz++] = numx[ii++] + rhs.numx[jj++]; // might include zeros
430 }
431 }
432 while (ii < cp[i+1])
433 {
434 temp.ir[curnz] = ir[ii];
435 temp.numx[curnz++] = numx[ii++];
436 }
437 while (jj < rhs.cp[j+1])
438 {
439 temp.ir[curnz] = rhs.ir[jj];
440 temp.numx[curnz++] = rhs.numx[jj++];
441 }
442 temp.cp[curnzc] = temp.cp[curnzc-1] + curnz-prevnz;
443 ++i;
444 ++j;
445 }
446 }
447 while(i< nzc)
448 {
449 temp.jc[curnzc++] = jc[i++];
450 for(IT k = cp[i-1]; k< cp[i]; ++k)
451 {
452 temp.ir[curnz] = ir[k];
453 temp.numx[curnz++] = numx[k];
454 }
455 temp.cp[curnzc] = temp.cp[curnzc-1] + (cp[i] - cp[i-1]);
456 }
457 while(j < rhs.nzc)
458 {
459 temp.jc[curnzc++] = rhs.jc[j++];
460 for(IT k = rhs.cp[j-1]; k< rhs.cp[j]; ++k)
461 {
462 temp.ir[curnz] = rhs.ir[k];
463 temp.numx[curnz++] = rhs.numx[k];
464 }
465 temp.cp[curnzc] = temp.cp[curnzc-1] + (rhs.cp[j] - rhs.cp[j-1]);
466 }
467 temp.Resize(curnzc, curnz);
468 *this = temp;
469 return *this;
470}
471
472template <class IT, class NT>
474{
475 if(nzc != rhs.nzc) return false;
476 bool same = std::equal(cp, cp+nzc+1, rhs.cp);
477 same = same && std::equal(jc, jc+nzc, rhs.jc);
478 same = same && std::equal(ir, ir+nz, rhs.ir);
479
480#ifdef DEBUG
481 std::vector<NT> error(nz);
482 std::transform(numx, numx+nz, rhs.numx, error.begin(), absdiff<NT>());
483 std::vector< std::pair<NT, NT> > error_original_pair(nz);
484 for(IT i=0; i < nz; ++i)
485 error_original_pair[i] = std::make_pair(error[i], numx[i]);
486 if(error_original_pair.size() > 10) // otherwise would crush for small data
487 {
488 partial_sort(error_original_pair.begin(), error_original_pair.begin()+10, error_original_pair.end(), std::greater< std::pair<NT,NT> >());
489 std::cout << "Highest 10 different entries are: " << std::endl;
490 for(IT i=0; i < 10; ++i)
491 std::cout << "Diff: " << error_original_pair[i].first << " on " << error_original_pair[i].second << std::endl;
492 }
493 else
494 {
495 sort(error_original_pair.begin(), error_original_pair.end(), std::greater< std::pair<NT,NT> >());
496 std::cout << "Highest different entries are: " << std::endl;
497 for(typename std::vector< std::pair<NT, NT> >::iterator it=error_original_pair.begin(); it != error_original_pair.end(); ++it)
498 std::cout << "Diff: " << it->first << " on " << it->second << std::endl;
499 }
500 std::cout << "Same before num: " << same << std::endl;
501#endif
502
504 same = same && std::equal(numx, numx+nz, rhs.numx, epsilonequal );
505 return same;
506}
507
513template <class IT, class NT>
515{
516 // We have a class with a friend function and a member function with the same name. Calling the friend function from the member function
517 // might (if the signature is the same) give compilation errors if not preceded by :: that denotes the global scope.
518 *this = combblas::EWiseMult((*this), &rhs, exclude); // call the binary version
519}
520
521
525template <class IT, class NT>
527{
528 // We have a class with a friend function and a member function with the same name. Calling the friend function from the member function
529 // might (if the signature is the same) give compilation errors if not preceded by :: that denotes the global scope.
530 *this = combblas::SetDifference((*this), &rhs); // call the binary version
531}
532
533
534template <class IT, class NT>
535template <typename _UnaryOperation, typename GlobalIT>
537{
538 // Two-pass algorithm
539 IT prunednnz = 0;
540 IT prunednzc = 0;
541 for(IT i=0; i<nzc; ++i)
542 {
543 bool colexists = false;
544 for(IT j=cp[i]; j < cp[i+1]; ++j)
545 {
546 if(!(__unary_op(std::make_tuple(rowOffset+ir[j], colOffset+jc[i], numx[j])))) // keep this nonzero
547 {
548 ++prunednnz;
549 colexists = true;
550 }
551 }
552 if(colexists) ++prunednzc;
553 }
554 IT * oldcp = cp;
555 IT * oldjc = jc;
556 IT * oldir = ir;
557 NT * oldnumx = numx;
558
559 cp = new IT[prunednzc+1];
560 jc = new IT[prunednzc];
561 ir = new IT[prunednnz];
562 numx = new NT[prunednnz];
563
564 IT cnzc = 0;
565 IT cnnz = 0;
566 cp[cnzc] = 0;
567 for(IT i=0; i<nzc; ++i)
568 {
569 for(IT j = oldcp[i]; j < oldcp[i+1]; ++j)
570 {
571 if(!(__unary_op(std::make_tuple(rowOffset+oldir[j], colOffset+oldjc[i], oldnumx[j])))) // keep this nonzero
572 {
573 ir[cnnz] = oldir[j];
574 numx[cnnz++] = oldnumx[j];
575 }
576 }
577 if(cnnz > cp[cnzc])
578 {
579 jc[cnzc] = oldjc[i];
580 cp[cnzc+1] = cnnz;
581 ++cnzc;
582 }
583 }
586 if (inPlace)
587 {
588 // delete the memory pointed by previous pointers
590 nz = cnnz;
591 nzc = cnzc;
592 return NULL;
593 }
594 else
595 {
596 // create a new object to store the data
597 Dcsc<IT,NT>* ret = new Dcsc<IT,NT>();
598 ret->cp = cp;
599 ret->jc = jc;
600 ret->ir = ir;
601 ret->numx = numx;
602 ret->nz = cnnz;
603 ret->nzc = cnzc;
604
605 // put the previous pointers back
606 cp = oldcp;
607 jc = oldjc;
608 ir = oldir;
609 numx = oldnumx;
610
611 return ret;
612 }
613}
614
615template <class IT, class NT>
616template <typename _UnaryOperation>
618{
619 // Two-pass algorithm
620 IT prunednnz = 0;
621 IT prunednzc = 0;
622 for(IT i=0; i<nzc; ++i)
623 {
624 bool colexists = false;
625 for(IT j=cp[i]; j < cp[i+1]; ++j)
626 {
627 if(!(__unary_op(numx[j]))) // keep this nonzero
628 {
629 ++prunednnz;
630 colexists = true;
631 }
632 }
633 if(colexists) ++prunednzc;
634 }
635 IT * oldcp = cp;
636 IT * oldjc = jc;
637 IT * oldir = ir;
638 NT * oldnumx = numx;
639
640 cp = new IT[prunednzc+1];
641 jc = new IT[prunednzc];
642 ir = new IT[prunednnz];
643 numx = new NT[prunednnz];
644
645 IT cnzc = 0;
646 IT cnnz = 0;
647 cp[cnzc] = 0;
648 for(IT i=0; i<nzc; ++i)
649 {
650 for(IT j = oldcp[i]; j < oldcp[i+1]; ++j)
651 {
652 if(!(__unary_op(oldnumx[j]))) // keep this nonzero
653 {
654 ir[cnnz] = oldir[j];
655 numx[cnnz++] = oldnumx[j];
656 }
657 }
658 if(cnnz > cp[cnzc])
659 {
660 jc[cnzc] = oldjc[i];
661 cp[cnzc+1] = cnnz;
662 ++cnzc;
663 }
664 }
667 if (inPlace)
668 {
669 // delete the memory pointed by previous pointers
671 nz = cnnz;
672 nzc = cnzc;
673 return NULL;
674 }
675 else
676 {
677 // create a new object to store the data
678 Dcsc<IT,NT>* ret = new Dcsc<IT,NT>();
679 ret->cp = cp;
680 ret->jc = jc;
681 ret->ir = ir;
682 ret->numx = numx;
683 ret->nz = cnnz;
684 ret->nzc = cnzc;
685
686 // put the previous pointers back
687 cp = oldcp;
688 jc = oldjc;
689 ir = oldir;
690 numx = oldnumx;
691
692 return ret;
693 }
694}
695
696
697template <class IT, class NT>
698template <typename _BinaryOperation>
700{
701 // Two-pass algorithm
702 IT prunednnz = 0;
703 IT prunednzc = 0;
704 for(IT i=0; i<nzc; ++i)
705 {
706 bool colexists = false;
707 for(IT j=cp[i]; j < cp[i+1]; ++j)
708 {
709 IT colid = jc[i];
710 if(!(__binary_op(numx[j], pvals[colid]))) // keep this nonzero
711 {
712 ++prunednnz;
713 colexists = true;
714 }
715 }
716 if(colexists) ++prunednzc;
717 }
718 IT * oldcp = cp;
719 IT * oldjc = jc;
720 IT * oldir = ir;
721 NT * oldnumx = numx;
722
723 cp = new IT[prunednzc+1];
724 jc = new IT[prunednzc];
725 ir = new IT[prunednnz];
726 numx = new NT[prunednnz];
727
728 IT cnzc = 0;
729 IT cnnz = 0;
730 cp[cnzc] = 0;
731 for(IT i=0; i<nzc; ++i)
732 {
733 for(IT j = oldcp[i]; j < oldcp[i+1]; ++j)
734 {
735 IT colid = oldjc[i];
736 if(!(__binary_op(oldnumx[j], pvals[colid])))
737 {
738 ir[cnnz] = oldir[j];
739 numx[cnnz++] = oldnumx[j];
740 }
741 }
742 if(cnnz > cp[cnzc])
743 {
744 jc[cnzc] = oldjc[i];
745 cp[cnzc+1] = cnnz;
746 ++cnzc;
747 }
748 }
750 if (inPlace)
751 {
752 // delete the memory pointed by previous pointers
754 nz = cnnz;
755 nzc = cnzc;
756 return NULL;
757 }
758 else
759 {
760 // create a new object to store the data
761 Dcsc<IT,NT>* ret = new Dcsc<IT,NT>();
762 ret->cp = cp;
763 ret->jc = jc;
764 ret->ir = ir;
765 ret->numx = numx;
766 ret->nz = cnnz;
767 ret->nzc = cnzc;
768
769 // put the previous pointers back
770 cp = oldcp;
771 jc = oldjc;
772 ir = oldir;
773 numx = oldnumx;
774
775 return ret;
776 }
777}
778
779template <class IT, class NT>
780void Dcsc<IT,NT>::PruneColumnByIndex(const std::vector<IT>& ci)
781{
782 if (ci.size() == 0)
783 return;
784
785 /* ci is assumed to be pre-sorted */
786
787 IT c = 0;
788 IT j = 0;
789
790 std::vector<IT> vjc, vir, nzpercol;
791 std::vector<NT> vnumx;
792
793 while (j < nzc)
794 {
795 if (c >= ci.size() || ci[c] > jc[j]) /* this means column jc[j] shouldn't be pruned, and instead should be copied */
796 {
797 vjc.push_back(jc[j]);
798 nzpercol.push_back(cp[j+1] - cp[j]);
799
800 for (IT p = cp[j]; p < cp[j+1]; ++p)
801 {
802 vir.push_back(ir[p]);
803 vnumx.push_back(numx[p]);
804 }
805
806 ++j;
807 }
808 else if (ci[c] < jc[j]) ++c; /* this means the column we want to prune has no nonzeros already */
809 else /* this means column j should be pruned */
810 {
811 ++j, ++c;
812 }
813 }
814
815 nzc = vjc.size();
816 nz = vir.size();
817
818 delete [] cp;
819 delete [] jc;
820 delete [] ir;
821 delete [] numx;
822
823 cp = new IT[nzc+1];
824 jc = new IT[nzc];
825 ir = new IT[nz];
826 numx = new NT[nz];
827
828 cp[0] = 0;
829
830 std::partial_sum(nzpercol.begin(), nzpercol.end(), cp + 1);
831 std::copy(vjc.begin(), vjc.end(), jc);
832 std::copy(vir.begin(), vir.end(), ir);
833 std::copy(vnumx.begin(), vnumx.end(), numx);
834}
835
836
837// prune selected columns indexed by pinds
838template <class IT, class NT>
839template <typename _BinaryOperation>
841{
842
843 // Two-pass algorithm
844 IT prunednnz = 0;
845 IT prunednzc = 0;
846 IT k = 0;
847 for(IT i=0; i<nzc; ++i)
848 {
849 bool colexists = false;
850 IT colid = jc[i];
851 if(colid==pinds[k]) // pinds is sorted
852 {
853 for(IT j=cp[i]; j < cp[i+1]; ++j)
854 {
855 if(!(__binary_op(numx[j], pvals[k]))) // keep this nonzero
856 {
857 ++prunednnz;
858 colexists = true;
859 }
860 }
861 k++;
862 }
863 else // untouched columns
864 {
865 colexists = true;
866 prunednnz += (cp[i+1] - cp[i]);
867 }
868 if(colexists) ++prunednzc;
869 }
870 IT * oldcp = cp;
871 IT * oldjc = jc;
872 IT * oldir = ir;
873 NT * oldnumx = numx;
874
875 cp = new IT[prunednzc+1];
876 jc = new IT[prunednzc];
877 ir = new IT[prunednnz];
878 numx = new NT[prunednnz];
879
880 IT cnzc = 0;
881 IT cnnz = 0;
882 cp[cnzc] = 0;
883 k = 0;
884 for(IT i=0; i<nzc; ++i)
885 {
886 IT colid = oldjc[i];
887 if(colid==pinds[k]) // prunned columns
888 {
889 for(IT j = oldcp[i]; j < oldcp[i+1]; ++j)
890 {
891 if(!(__binary_op(oldnumx[j], pvals[k])))
892 {
893 ir[cnnz] = oldir[j];
894 numx[cnnz++] = oldnumx[j];
895 }
896 }
897 k++;
898 }
899 else // copy other columns
900 {
901 for(IT j = oldcp[i]; j < oldcp[i+1]; ++j)
902 {
903 ir[cnnz] = oldir[j];
904 numx[cnnz++] = oldnumx[j];
905 }
906 }
907 if(cnnz > cp[cnzc])
908 {
909 jc[cnzc] = oldjc[i];
910 cp[cnzc+1] = cnnz;
911 ++cnzc;
912 }
913 }
915 if (inPlace)
916 {
917 // delete the memory pointed by previous pointers
919 nz = cnnz;
920 nzc = cnzc;
921 return NULL;
922 }
923 else
924 {
925 // create a new object to store the data
926 Dcsc<IT,NT>* ret = new Dcsc<IT,NT>();
927 ret->cp = cp;
928 ret->jc = jc;
929 ret->ir = ir;
930 ret->numx = numx;
931 ret->nz = cnnz;
932 ret->nzc = cnzc;
933
934 // put the previous pointers back
935 cp = oldcp;
936 jc = oldjc;
937 ir = oldir;
938 numx = oldnumx;
939
940 return ret;
941 }
942}
943
944template <class IT, class NT>
946{
947 for(IT i=0; i<nzc; ++i)
948 {
949 IT colid = jc[i];
950 for(IT j=cp[i]; j < cp[i+1]; ++j)
951 {
952 IT rowid = ir[j];
953 numx[j] *= scaler[rowid][colid];
954 }
955 }
956}
957
962template <class IT, class NT>
963template <typename _BinaryOperation>
965{
966 for(IT i=0; i<nzc; ++i)
967 {
968 IT colid = jc[i];
969 for(IT j=cp[i]; j < cp[i+1]; ++j)
970 {
971 IT rowid = ir[j];
972 array[rowid][colid] = __binary_op(array[rowid][colid], numx[j]);
973 }
974 }
975}
976
982template <class IT, class NT>
984{
985 float cf = static_cast<float>(ndim+1) / static_cast<float>(nzc);
986 IT colchunks = static_cast<IT> ( ceil( static_cast<float>(ndim+1) / ceil(cf)) );
987
988 aux = new IT[colchunks+1];
989
990 IT chunksize = static_cast<IT>(ceil(cf));
991 IT reg = 0;
992 IT curchunk = 0;
993 aux[curchunk++] = 0;
994 for(IT i = 0; i< nzc; ++i)
995 {
996 if(jc[i] >= curchunk * chunksize) // beginning of the next chunk
997 {
998 while(jc[i] >= curchunk * chunksize) // consider any empty chunks
999 {
1000 aux[curchunk++] = reg;
1001 }
1002 }
1003 reg = i+1;
1004 }
1005 while(curchunk <= colchunks)
1006 {
1007 aux[curchunk++] = reg;
1008 }
1009 return colchunks;
1010}
1011
1016template <class IT, class NT>
1018{
1019 if(nzcnew == 0)
1020 {
1021 delete[] jc;
1022 delete[] cp;
1023 nzc = 0;
1024 }
1025 if(nznew == 0)
1026 {
1027 delete[] ir;
1028 delete[] numx;
1029 nz = 0;
1030 }
1031 if ( nzcnew == 0 && nznew == 0)
1032 {
1033 return;
1034 }
1035 if (nzcnew != nzc)
1036 {
1037 IT * tmpcp = cp;
1038 IT * tmpjc = jc;
1039 cp = new IT[nzcnew+1];
1040 jc = new IT[nzcnew];
1041 if(nzcnew > nzc) // Grow it (copy all of the old elements)
1042 {
1043 std::copy(tmpcp, tmpcp+nzc+1, cp); // copy(first, end, result)
1044 std::copy(tmpjc, tmpjc+nzc, jc);
1045 }
1046 else // Shrink it (copy only a portion of the old elements)
1047 {
1048 std::copy(tmpcp, tmpcp+nzcnew+1, cp);
1049 std::copy(tmpjc, tmpjc+nzcnew, jc);
1050 }
1051 delete[] tmpcp; // delete the memory pointed by previous pointers
1052 delete[] tmpjc;
1053 nzc = nzcnew;
1054 }
1055 if (nznew != nz)
1056 {
1057 NT * tmpnumx = numx;
1058 IT * tmpir = ir;
1059 numx = new NT[nznew];
1060 ir = new IT[nznew];
1061 if(nznew > nz) // Grow it (copy all of the old elements)
1062 {
1063 std::copy(tmpnumx, tmpnumx+nz, numx); // numx can be non-POD
1064 std::copy(tmpir, tmpir+nz, ir);
1065 }
1066 else // Shrink it (copy only a portion of the old elements)
1067 {
1068 std::copy(tmpnumx, tmpnumx+nznew, numx);
1069 std::copy(tmpir, tmpir+nznew, ir);
1070 }
1071 delete[] tmpnumx; // delete the memory pointed by previous pointers
1072 delete[] tmpir;
1073 nz = nznew;
1074 }
1075}
1076
1083template<class IT, class NT>
1085{
1086 IT base = static_cast<IT>(floor((float) (colind/csize)));
1087 IT start = aux[base];
1088 IT end = aux[base+1];
1089
1090 IT * itr = std::find(jc + start, jc + end, colind);
1091
1092 found = (itr != jc + end);
1093 return (itr-jc);
1094}
1095
1100template<class IT, class NT>
1102{
1103 IT * itr = std::lower_bound(jc, jc+nzc, cut);
1104 IT pos = itr - jc;
1105
1106 if(cp[pos] == 0)
1107 {
1108 A = NULL;
1109 }
1110 else
1111 {
1112 A = new Dcsc<IT,NT>(cp[pos], pos);
1113 std::copy(jc, jc+pos, A->jc);
1114 std::copy(cp, cp+pos+1, A->cp);
1115 std::copy(ir, ir+cp[pos], A->ir);
1116 std::copy(numx, numx + cp[pos], A->numx); // copy(first, last, result)
1117 }
1118 if(nz-cp[pos] == 0)
1119 {
1120 B = NULL;
1121 }
1122 else
1123 {
1124 B = new Dcsc<IT,NT>(nz-cp[pos], nzc-pos);
1125 std::copy(jc+pos, jc+ nzc, B->jc);
1126 transform(B->jc, B->jc + (nzc-pos), B->jc, bind2nd(std::minus<IT>(), cut));
1127 std::copy(cp+pos, cp+nzc+1, B->cp);
1128 transform(B->cp, B->cp + (nzc-pos+1), B->cp, bind2nd(std::minus<IT>(), cp[pos]));
1129 std::copy(ir+cp[pos], ir+nz, B->ir);
1130 std::copy(numx+cp[pos], numx+nz, B->numx); // copy(first, last, result)
1131 }
1132}
1133
1140template<class IT, class NT>
1141void Dcsc<IT,NT>::ColSplit(std::vector< Dcsc<IT,NT>* > & parts, std::vector<IT> & cuts)
1142{
1143 IT * jcbegin = jc;
1144 std::vector<IT> pos; // pos has "parts-1" entries
1145 for(auto cutpoint = cuts.begin(); cutpoint != cuts.end(); ++cutpoint)
1146 {
1147 IT * itr = std::lower_bound(jcbegin, jc+nzc, *cutpoint);
1148 pos.push_back(itr - jc);
1149 jcbegin = itr; // so that lower_bound searches a smaller vector
1150 }
1151
1152 if(cp[pos[0]] == 0) // first piece
1153 {
1154 parts[0] = NULL;
1155 }
1156 else
1157 {
1158 parts[0] = new Dcsc<IT,NT>(cp[pos[0]], pos[0]); // Dcsc(nnz, nzc)
1159 std::copy(jc, jc+pos[0], parts[0]->jc); // std::copy
1160 std::copy(cp, cp+pos[0]+1, parts[0]->cp);
1161 std::copy(ir, ir+cp[pos[0]], parts[0]->ir);
1162 std::copy(numx, numx + cp[pos[0]], parts[0]->numx); // copy(first, last, result)
1163 }
1164 int ncuts = cuts.size(); // all except last piece
1165 for(int i=1; i< ncuts; ++i) // treat the first piece differently
1166 {
1167 if(cp[pos[i]] - cp[pos[i-1]] == 0)
1168 {
1169 parts[i] = NULL;
1170 }
1171 else
1172 {
1173 parts[i] = new Dcsc<IT,NT>(cp[pos[i]] - cp[pos[i-1]], pos[i] - pos[i-1]); // Dcsc(nnz, nzc)
1174 std::copy(jc+pos[i-1], jc+pos[i], parts[i]->jc); // std::copy
1175 transform(parts[i]->jc, parts[i]->jc + (pos[i]-pos[i-1]), parts[i]->jc, bind2nd(std::minus<IT>(), cuts[i-1])); // cuts[i-1] is well defined as i>=1
1176
1177 std::copy(cp+pos[i-1], cp+pos[i]+1, parts[i]->cp);
1178 transform(parts[i]->cp, parts[i]->cp + (pos[i]-pos[i-1]+1), parts[i]->cp, bind2nd(std::minus<IT>(), cp[pos[i-1]]));
1179
1180 std::copy(ir+cp[pos[i-1]], ir+cp[pos[i]], parts[i]->ir);
1181 std::copy(numx+cp[pos[i-1]], numx + cp[pos[i]], parts[i]->numx); // copy(first, last, result)
1182 }
1183 }
1184 if(nz - cp[pos[ncuts-1]] == 0)
1185 {
1186 parts[ncuts] = NULL;
1187 }
1188 else
1189 {
1190 parts[ncuts] = new Dcsc<IT,NT>(nz-cp[pos[ncuts-1]], nzc-pos[ncuts-1]); // ncuts = npieces -1
1191 std::copy(jc+pos[ncuts-1], jc+ nzc, parts[ncuts]->jc);
1192 transform(parts[ncuts]->jc, parts[ncuts]->jc + (nzc-pos[ncuts-1]), parts[ncuts]->jc, bind2nd(std::minus<IT>(), cuts[ncuts-1]));
1193
1194 std::copy(cp+pos[ncuts-1], cp+nzc+1, parts[ncuts]->cp);
1195 transform(parts[ncuts]->cp, parts[ncuts]->cp + (nzc-pos[ncuts-1]+1), parts[ncuts]->cp, bind2nd(std::minus<IT>(), cp[pos[ncuts-1]]));
1196 std::copy(ir+cp[pos[ncuts-1]], ir+nz, parts[ncuts]->ir);
1197 std::copy(numx+cp[pos[ncuts-1]], numx+nz, parts[ncuts]->numx);
1198 }
1199}
1200
1201
1202// Assumes A and B are not NULL
1203// When any is NULL, this function is not called anyway
1204template<class IT, class NT>
1206{
1207 assert((A != NULL) && (B != NULL)); // handled at higher level
1208 IT cnz = A->nz + B->nz;
1209 IT cnzc = A->nzc + B->nzc;
1210 if(cnz > 0)
1211 {
1212 *this = Dcsc<IT,NT>(cnz, cnzc); // safe, because "this" can not be NULL inside a member function
1213
1214 std::copy(A->jc, A->jc + A->nzc, jc); // copy(first, last, result)
1215 std::copy(B->jc, B->jc + B->nzc, jc + A->nzc);
1216 transform(jc + A->nzc, jc + cnzc, jc + A->nzc, bind2nd(std::plus<IT>(), cut));
1217
1218 std::copy(A->cp, A->cp + A->nzc, cp);
1219 std::copy(B->cp, B->cp + B->nzc +1, cp + A->nzc);
1220 transform(cp + A->nzc, cp+cnzc+1, cp + A->nzc, bind2nd(std::plus<IT>(), A->cp[A->nzc]));
1221
1222 std::copy(A->ir, A->ir + A->nz, ir);
1223 std::copy(B->ir, B->ir + B->nz, ir + A->nz);
1224
1225 // since numx is potentially non-POD, we use std::copy
1226 std::copy(A->numx, A->numx + A->nz, numx);
1227 std::copy(B->numx, B->numx + B->nz, numx + A->nz);
1228 }
1229}
1230
1231
1238template<class IT, class NT>
1239void Dcsc<IT,NT>::ColConcatenate(std::vector< Dcsc<IT,NT>* > & parts, std::vector<IT> & offsets)
1240{
1241 IT cnz = 0;
1242 IT cnzc = 0;
1243 size_t nmembers = parts.size();
1244 for(size_t i=0; i< nmembers; ++i)
1245 {
1246 cnz += parts[i]->nz;
1247 cnzc += parts[i]->nzc;
1248 }
1249 if(cnz > 0)
1250 {
1251 *this = Dcsc<IT,NT>(cnz, cnzc); // safe, because "this" can not be NULL inside a member function
1252
1253 IT run_nz = 0;
1254 IT run_nzc = 0;
1255 for(size_t i=0; i< nmembers; ++i)
1256 {
1257 std::copy(parts[i]->jc, parts[i]->jc + parts[i]->nzc, jc + run_nzc);
1258 transform(jc + run_nzc, jc + run_nzc + parts[i]->nzc, jc + run_nzc, bind2nd(std::plus<IT>(), offsets[i]));
1259
1260 // remember: cp[nzc] = nnz
1261 std::copy(parts[i]->cp, parts[i]->cp + parts[i]->nzc, cp + run_nzc);
1262 transform(cp + run_nzc, cp + run_nzc + parts[i]->nzc, cp + run_nzc, bind2nd(std::plus<IT>(),run_nz));
1263
1264 std::copy(parts[i]->ir, parts[i]->ir + parts[i]->nz, ir + run_nz);
1265 std::copy(parts[i]->numx, parts[i]->numx + parts[i]->nz, numx + run_nz);
1266
1267 run_nzc += parts[i]->nzc;
1268 run_nz += parts[i]->nz;
1269 }
1270 // adjust the last pointer
1271 cp[run_nzc] = run_nz;
1272 }
1273}
1274
1280template<class IT, class NT>
1281template<class VT>
1282void Dcsc<IT,NT>::FillColInds(const VT * colnums, IT nind, std::vector< std::pair<IT,IT> > & colinds, IT * aux, IT csize) const
1283{
1284 if ( aux == NULL || (nzc / nind) < THRESHOLD) // use scanning indexing
1285 {
1286 IT mink = std::min(nzc, nind);
1287 std::pair<IT,IT> * isect = new std::pair<IT,IT>[mink];
1288 std::pair<IT,IT> * range1 = new std::pair<IT,IT>[nzc];
1289 std::pair<IT,IT> * range2 = new std::pair<IT,IT>[nind];
1290
1291 for(IT i=0; i < nzc; ++i)
1292 {
1293 range1[i] = std::make_pair(jc[i], i); // get the actual nonzero value and the index to the ith nonzero
1294 }
1295 for(IT i=0; i < nind; ++i)
1296 {
1297 range2[i] = std::make_pair(static_cast<IT>(colnums[i]), 0); // second is dummy as all the intersecting elements are copied from the first range
1298 }
1299
1300 std::pair<IT,IT> * itr = set_intersection(range1, range1 + nzc, range2, range2+nind, isect, SpHelper::first_compare<IT> );
1301 // isect now can iterate on a subset of the elements of range1
1302 // meaning that the intersection can be accessed directly by isect[i] instead of range1[isect[i]]
1303 // this is because the intersecting elements are COPIED to the output range "isect"
1304
1305 IT kisect = static_cast<IT>(itr-isect); // size of the intersection
1306 for(IT j=0, i =0; j< nind; ++j)
1307 {
1308 // the elements represented by jc[isect[i]] are a subset of the elements represented by colnums[j]
1309 if( i == kisect || isect[i].first != static_cast<IT>(colnums[j]))
1310 {
1311 // not found, signal by setting first = second
1312 colinds[j].first = 0;
1313 colinds[j].second = 0;
1314 }
1315 else // i < kisect && dcsc->jc[isect[i]] == colnums[j]
1316 {
1317 IT p = isect[i++].second;
1318 colinds[j].first = cp[p];
1319 colinds[j].second = cp[p+1];
1320 }
1321 }
1323 }
1324 else // use aux based indexing
1325 {
1326 bool found;
1327 for(IT j =0; j< nind; ++j)
1328 {
1329 IT pos = AuxIndex(static_cast<IT>(colnums[j]), found, aux, csize);
1330 if(found)
1331 {
1332 colinds[j].first = cp[pos];
1333 colinds[j].second = cp[pos+1];
1334 }
1335 else // not found, signal by setting first = second
1336 {
1337 colinds[j].first = 0;
1338 colinds[j].second = 0;
1339 }
1340 }
1341 }
1342}
1343
1344
1345template <class IT, class NT>
1347{
1348 if(nz > 0) // dcsc may be empty
1349 {
1350 delete[] numx;
1351 delete[] ir;
1352 }
1353 if(nzc > 0)
1354 {
1355 delete[] jc;
1356 delete[] cp;
1357 }
1358}
1359
1360}
int64_t IT
double NT
void convert(string ifname, string ofname, string sort="revsize")
Definition test.cpp:53
void EWiseScale(NT **scaler)
Definition dcsc.cpp:945
Dcsc< IT, NT > * PruneI(_UnaryOperation __unary_op, bool inPlace, GlobalIT rowOffset, GlobalIT colOffset)
Definition dcsc.cpp:536
void ColConcatenate(std::vector< Dcsc< IT, NT > * > &parts, std::vector< IT > &offsets)
Definition dcsc.cpp:1239
void ColSplit(std::vector< Dcsc< IT, NT > * > &parts, std::vector< IT > &cuts)
Definition dcsc.cpp:1141
Dcsc< IT, NT > * PruneColumn(NT *pvals, _BinaryOperation __binary_op, bool inPlace)
Definition dcsc.cpp:699
Dcsc< IT, NT > & operator=(const Dcsc< IT, NT > &rhs)
Definition dcsc.cpp:329
IT AuxIndex(const IT colind, bool &found, IT *aux, IT csize) const
Definition dcsc.cpp:1084
IT * ir
row indices, size nz
Definition dcsc.h:126
bool operator==(const Dcsc< IT, NT > &rhs)
Definition dcsc.cpp:473
void PruneColumnByIndex(const std::vector< IT > &ci)
Definition dcsc.cpp:780
void Merge(const Dcsc< IT, NT > *Adcsc, const Dcsc< IT, NT > *B, IT cut)
Definition dcsc.cpp:1205
Dcsc< IT, NT > * Prune(_UnaryOperation __unary_op, bool inPlace)
Definition dcsc.cpp:617
Dcsc< IT, NT > & AddAndAssign(StackEntry< NT, std::pair< IT, IT > > *multstack, IT mdim, IT ndim, IT nnz)
Definition dcsc.cpp:72
friend Dcsc< IU, typename promote_trait< NU1, NU2 >::T_promote > SetDifference(const Dcsc< IU, NU1 > &A, const Dcsc< IU, NU2 > *B)
Definition Friends.h:748
IT * cp
The master array, size nzc+1 (keeps column pointers)
Definition dcsc.h:124
void Resize(IT nzcnew, IT nznew)
Definition dcsc.cpp:1017
IT nzc
number of columns with at least one non-zero in them
Definition dcsc.h:130
void Split(Dcsc< IT, NT > *&A, Dcsc< IT, NT > *&B, IT cut)
Definition dcsc.cpp:1101
IT ConstructAux(IT ndim, IT *&aux) const
Definition dcsc.cpp:983
NT * numx
generic values, size nz
Definition dcsc.h:127
Dcsc< IT, NT > & operator+=(const Dcsc< IT, NT > &rhs)
Definition dcsc.cpp:375
void FillColInds(const VT *colnums, IT nind, std::vector< std::pair< IT, IT > > &colinds, IT *aux, IT csize) const
Definition dcsc.cpp:1282
void UpdateDense(NT **array, _BinaryOperation __binary_op) const
Definition dcsc.cpp:964
IT * jc
col indices, size nzc
Definition dcsc.h:125
friend Dcsc< IU, typename promote_trait< NU1, NU2 >::T_promote > EWiseMult(const Dcsc< IU, NU1 > &A, const Dcsc< IU, NU2 > *B, bool exclude)
Definition Friends.h:834
static void iota(_ForwardIter __first, _ForwardIter __last, T __val)
Definition SpHelper.h:226
#define THRESHOLD
Definition SpDefs.h:126
Dcsc< IU, typename promote_trait< NU1, NU2 >::T_promote > SetDifference(const Dcsc< IU, NU1 > &A, const Dcsc< IU, NU2 > *B)
Definition Friends.h:748
void DeleteAll(A arr1)
Definition Deleter.h:48
Dcsc< IU, typename promote_trait< NU1, NU2 >::T_promote > EWiseMult(const Dcsc< IU, NU1 > &A, const Dcsc< IU, NU2 > *B, bool exclude)
Definition Friends.h:834
double A