COMBINATORIAL_BLAS  1.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
SpDCCols.cpp
Go to the documentation of this file.
1 /****************************************************************/
2 /* Parallel Combinatorial BLAS Library (for Graph Computations) */
3 /* version 1.2 -------------------------------------------------*/
4 /* date: 10/06/2011 --------------------------------------------*/
5 /* authors: Aydin Buluc (abuluc@lbl.gov), Adam Lugowski --------*/
6 /****************************************************************/
7 /*
8  Copyright (c) 2011, Aydin Buluc
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 #include "SpDCCols.h"
30 #include "Deleter.h"
31 #include <algorithm>
32 #include <functional>
33 #include <vector>
34 #include <climits>
35 #include <iomanip>
36 #include <cassert>
37 
38 using namespace std;
39 
40 /****************************************************************************/
41 /********************* PUBLIC CONSTRUCTORS/DESTRUCTORS **********************/
42 /****************************************************************************/
43 
44 template <class IT, class NT>
45 const IT SpDCCols<IT,NT>::esscount = static_cast<IT>(4);
46 
47 
48 template <class IT, class NT>
49 SpDCCols<IT,NT>::SpDCCols():dcsc(NULL), m(0), n(0), nnz(0), splits(0){
50 }
51 
52 // Allocate all the space necessary
53 template <class IT, class NT>
54 SpDCCols<IT,NT>::SpDCCols(IT size, IT nRow, IT nCol, IT nzc)
55 :m(nRow), n(nCol), nnz(size), splits(0)
56 {
57  if(nnz > 0)
58  dcsc = new Dcsc<IT,NT>(nnz, nzc);
59  else
60  dcsc = NULL;
61 }
62 
63 template <class IT, class NT>
65 {
66  if(nnz > 0)
67  {
68  if(dcsc != NULL)
69  {
70  if(splits > 0)
71  {
72  for(int i=0; i<splits; ++i)
73  delete dcscarr[i];
74  delete [] dcscarr;
75  }
76  else
77  {
78  delete dcsc;
79  }
80  }
81  }
82 }
83 
84 // Copy constructor (constructs a new object. i.e. this is NEVER called on an existing object)
85 // Derived's copy constructor can safely call Base's default constructor as base has no data members
86 template <class IT, class NT>
88 : m(rhs.m), n(rhs.n), nnz(rhs.nnz), splits(rhs.splits)
89 {
90  if(splits > 0)
91  {
92  for(int i=0; i<splits; ++i)
93  CopyDcsc(rhs.dcscarr[i]);
94  }
95  else
96  {
97  CopyDcsc(rhs.dcsc);
98  }
99 }
100 
107 template <class IT, class NT>
108 SpDCCols<IT,NT>::SpDCCols(const SpTuples<IT,NT> & rhs, bool transpose)
109 : m(rhs.m), n(rhs.n), nnz(rhs.nnz), splits(0)
110 {
111 
112  if(nnz == 0) // m by n matrix of complete zeros
113  {
114  if(transpose) swap(m,n);
115  dcsc = NULL;
116  }
117  else
118  {
119  if(transpose)
120  {
121  swap(m,n);
122  IT localnzc = 1;
123  for(IT i=1; i< rhs.nnz; ++i)
124  {
125  if(rhs.rowindex(i) != rhs.rowindex(i-1))
126  {
127  ++localnzc;
128  }
129  }
130  dcsc = new Dcsc<IT,NT>(rhs.nnz,localnzc);
131  dcsc->jc[0] = rhs.rowindex(0);
132  dcsc->cp[0] = 0;
133 
134  for(IT i=0; i<rhs.nnz; ++i)
135  {
136  dcsc->ir[i] = rhs.colindex(i); // copy rhs.jc to ir since this transpose=true
137  dcsc->numx[i] = rhs.numvalue(i);
138  }
139 
140  IT jspos = 1;
141  for(IT i=1; i<rhs.nnz; ++i)
142  {
143  if(rhs.rowindex(i) != dcsc->jc[jspos-1])
144  {
145  dcsc->jc[jspos] = rhs.rowindex(i); // copy rhs.ir to jc since this transpose=true
146  dcsc->cp[jspos++] = i;
147  }
148  }
149  dcsc->cp[jspos] = rhs.nnz;
150  }
151  else
152  {
153  IT localnzc = 1;
154  for(IT i=1; i<rhs.nnz; ++i)
155  {
156  if(rhs.colindex(i) != rhs.colindex(i-1))
157  {
158  ++localnzc;
159  }
160  }
161  dcsc = new Dcsc<IT,NT>(rhs.nnz,localnzc);
162  dcsc->jc[0] = rhs.colindex(0);
163  dcsc->cp[0] = 0;
164 
165  for(IT i=0; i<rhs.nnz; ++i)
166  {
167  dcsc->ir[i] = rhs.rowindex(i); // copy rhs.ir to ir since this transpose=false
168  dcsc->numx[i] = rhs.numvalue(i);
169  }
170 
171  IT jspos = 1;
172  for(IT i=1; i<rhs.nnz; ++i)
173  {
174  if(rhs.colindex(i) != dcsc->jc[jspos-1])
175  {
176  dcsc->jc[jspos] = rhs.colindex(i); // copy rhs.jc to jc since this transpose=true
177  dcsc->cp[jspos++] = i;
178  }
179  }
180  dcsc->cp[jspos] = rhs.nnz;
181  }
182  }
183 }
184 
185 
186 /****************************************************************************/
187 /************************** PUBLIC OPERATORS ********************************/
188 /****************************************************************************/
189 
195 template <class IT, class NT>
197 {
198  // this pointer stores the address of the class instance
199  // check for self assignment using address comparison
200  if(this != &rhs)
201  {
202  if(dcsc != NULL && nnz > 0)
203  {
204  delete dcsc;
205  }
206  if(rhs.dcsc != NULL)
207  {
208  dcsc = new Dcsc<IT,NT>(*(rhs.dcsc));
209  nnz = rhs.nnz;
210  }
211  else
212  {
213  dcsc = NULL;
214  nnz = 0;
215  }
216 
217  m = rhs.m;
218  n = rhs.n;
219  splits = rhs.splits;
220  }
221  return *this;
222 }
223 
224 template <class IT, class NT>
226 {
227  // this pointer stores the address of the class instance
228  // check for self assignment using address comparison
229  if(this != &rhs)
230  {
231  if(m == rhs.m && n == rhs.n)
232  {
233  if(rhs.nnz == 0)
234  {
235  return *this;
236  }
237  else if(nnz == 0)
238  {
239  dcsc = new Dcsc<IT,NT>(*(rhs.dcsc));
240  nnz = dcsc->nz;
241  }
242  else
243  {
244  (*dcsc) += (*(rhs.dcsc));
245  nnz = dcsc->nz;
246  }
247  }
248  else
249  {
250  cout<< "Not addable: " << m << "!=" << rhs.m << " or " << n << "!=" << rhs.n <<endl;
251  }
252  }
253  else
254  {
255  cout<< "Missing feature (A+A): Use multiply with 2 instead !"<<endl;
256  }
257  return *this;
258 }
259 
260 template <class IT, class NT>
261 template <typename _UnaryOperation>
262 SpDCCols<IT,NT>* SpDCCols<IT,NT>::Prune(_UnaryOperation __unary_op, bool inPlace)
263 {
264  if(nnz > 0)
265  {
266  Dcsc<IT,NT>* ret = dcsc->Prune (__unary_op, inPlace);
267  if (inPlace)
268  {
269  nnz = dcsc->nz;
270 
271  if(nnz == 0)
272  {
273  delete dcsc;
274  dcsc = NULL;
275  }
276  return NULL;
277  }
278  else
279  {
280  // wrap the new pruned Dcsc into a new SpDCCols
281  SpDCCols<IT,NT>* retcols = new SpDCCols<IT, NT>();
282  retcols->dcsc = ret;
283  retcols->nnz = retcols->dcsc->nz;
284  retcols->n = n;
285  retcols->m = m;
286  return retcols;
287  }
288  }
289  else
290  {
291  if (inPlace)
292  {
293  return NULL;
294  }
295  else
296  {
297  SpDCCols<IT,NT>* retcols = new SpDCCols<IT, NT>();
298  retcols->dcsc = NULL;
299  retcols->nnz = 0;
300  retcols->n = n;
301  retcols->m = m;
302  return retcols;
303  }
304  }
305 }
306 
307 template <class IT, class NT>
308 void SpDCCols<IT,NT>::EWiseMult (const SpDCCols<IT,NT> & rhs, bool exclude)
309 {
310  if(this != &rhs)
311  {
312  if(m == rhs.m && n == rhs.n)
313  {
314  if(rhs.nnz == 0)
315  {
316  if(exclude) // then we don't exclude anything
317  {
318  return;
319  }
320  else // A .* zeros() is zeros()
321  {
322  *this = SpDCCols<IT,NT>(0,m,n,0); // completely reset the matrix
323  }
324  }
325  else if (rhs.nnz != 0 && nnz != 0)
326  {
327  dcsc->EWiseMult (*(rhs.dcsc), exclude);
328  nnz = dcsc->nz;
329  if(nnz == 0 )
330  dcsc = NULL;
331  }
332  }
333  else
334  {
335  cout<< "Matrices do not conform for A .* op(B) !"<<endl;
336  }
337  }
338  else
339  {
340  cout<< "Missing feature (A .* A): Use Square_EWise() instead !"<<endl;
341  }
342 }
343 
347 template <class IT, class NT>
348 void SpDCCols<IT,NT>::EWiseScale(NT ** scaler, IT m_scaler, IT n_scaler)
349 {
350  if(m == m_scaler && n == n_scaler)
351  {
352  if(nnz > 0)
353  dcsc->EWiseScale (scaler);
354  }
355  else
356  {
357  cout<< "Matrices do not conform for EWiseScale !"<<endl;
358  }
359 }
360 
361 
362 /****************************************************************************/
363 /********************* PUBLIC MEMBER FUNCTIONS ******************************/
364 /****************************************************************************/
365 
366 template <class IT, class NT>
367 void SpDCCols<IT,NT>::CreateImpl(const vector<IT> & essentials)
368 {
369  assert(essentials.size() == esscount);
370  nnz = essentials[0];
371  m = essentials[1];
372  n = essentials[2];
373 
374  if(nnz > 0)
375  dcsc = new Dcsc<IT,NT>(nnz,essentials[3]);
376  else
377  dcsc = NULL;
378 }
379 
380 template <class IT, class NT>
381 void SpDCCols<IT,NT>::CreateImpl(IT size, IT nRow, IT nCol, tuple<IT, IT, NT> * mytuples)
382 {
383  SpTuples<IT,NT> tuples(size, nRow, nCol, mytuples);
384  tuples.SortColBased();
385 
386 #ifdef DEBUG
387  pair<IT,IT> rlim = tuples.RowLimits();
388  pair<IT,IT> clim = tuples.ColLimits();
389 
390  ofstream oput;
391  stringstream ss;
392  string rank;
393  int myrank;
394  MPI_Comm_rank(MPI_COMM_WORLD, &myrank);
395  ss << myrank;
396  ss >> rank;
397  string ofilename = "Read";
398  ofilename += rank;
399  oput.open(ofilename.c_str(), ios_base::app );
400  oput << "Creating of dimensions " << nRow << "-by-" << nCol << " of size: " << size <<
401  " with row range (" << rlim.first << "," << rlim.second << ") and column range (" << clim.first << "," << clim.second << ")" << endl;
402  if(tuples.getnnz() > 0)
403  {
404  IT minfr = joker::get<0>(tuples.front());
405  IT minto = joker::get<1>(tuples.front());
406  IT maxfr = joker::get<0>(tuples.back());
407  IT maxto = joker::get<1>(tuples.back());
408 
409  oput << "Min: " << minfr << ", " << minto << "; Max: " << maxfr << ", " << maxto << endl;
410  }
411  oput.close();
412 #endif
413 
414  SpDCCols<IT,NT> object(tuples, false);
415  *this = object;
416 }
417 
418 
419 template <class IT, class NT>
421 {
422  vector<IT> essentials(esscount);
423  essentials[0] = nnz;
424  essentials[1] = m;
425  essentials[2] = n;
426  essentials[3] = (nnz > 0) ? dcsc->nzc : 0;
427  return essentials;
428 }
429 
430 template <class IT, class NT>
431 template <typename NNT>
433 {
434  Dcsc<IT,NNT> * convert;
435  if(nnz > 0)
436  convert = new Dcsc<IT,NNT>(*dcsc);
437  else
438  convert = NULL;
439 
440  return SpDCCols<IT,NNT>(m, n, convert);
441 }
442 
443 
444 template <class IT, class NT>
445 template <typename NIT, typename NNT>
447 {
448  Dcsc<NIT,NNT> * convert;
449  if(nnz > 0)
450  convert = new Dcsc<NIT,NNT>(*dcsc);
451  else
452  convert = NULL;
453 
454  return SpDCCols<NIT,NNT>(m, n, convert);
455 }
456 
457 
458 template <class IT, class NT>
460 {
461  Arr<IT,NT> arr(3,1);
462 
463  if(nnz > 0)
464  {
465  arr.indarrs[0] = LocArr<IT,IT>(dcsc->cp, dcsc->nzc+1);
466  arr.indarrs[1] = LocArr<IT,IT>(dcsc->jc, dcsc->nzc);
467  arr.indarrs[2] = LocArr<IT,IT>(dcsc->ir, dcsc->nz);
468  arr.numarrs[0] = LocArr<NT,IT>(dcsc->numx, dcsc->nz);
469  }
470  else
471  {
472  arr.indarrs[0] = LocArr<IT,IT>(NULL, 0);
473  arr.indarrs[1] = LocArr<IT,IT>(NULL, 0);
474  arr.indarrs[2] = LocArr<IT,IT>(NULL, 0);
475  arr.numarrs[0] = LocArr<NT,IT>(NULL, 0);
476 
477  }
478  return arr;
479 }
480 
486 template <class IT, class NT>
488 {
489  if(nnz > 0)
490  {
491  SpTuples<IT,NT> Atuples(*this);
492  Atuples.SortRowBased();
493 
494  // destruction of (*this) is handled by the assignment operator
495  *this = SpDCCols<IT,NT>(Atuples,true);
496  }
497  else
498  {
499  *this = SpDCCols<IT,NT>(0, n, m, 0);
500  }
501 }
502 
503 
509 template <class IT, class NT>
511 {
512  SpTuples<IT,NT> Atuples(*this);
513  Atuples.SortRowBased();
514 
515  return SpDCCols<IT,NT>(Atuples,true);
516 }
517 
523 template <class IT, class NT>
525 {
526  IT cut = n/2;
527  if(cut == 0)
528  {
529  cout<< "Matrix is too small to be splitted" << endl;
530  return;
531  }
532 
533  Dcsc<IT,NT> *Adcsc = NULL;
534  Dcsc<IT,NT> *Bdcsc = NULL;
535 
536  if(nnz != 0)
537  {
538  dcsc->Split(Adcsc, Bdcsc, cut);
539  }
540 
541  partA = SpDCCols<IT,NT> (m, cut, Adcsc);
542  partB = SpDCCols<IT,NT> (m, n-cut, Bdcsc);
543 
544  // handle destruction through assignment operator
545  *this = SpDCCols<IT, NT>();
546 }
547 
552 template <class IT, class NT>
554 {
555  assert( partA.m == partB.m );
556 
557  Dcsc<IT,NT> * Cdcsc = new Dcsc<IT,NT>();
558 
559  if(partA.nnz == 0 && partB.nnz == 0)
560  {
561  Cdcsc = NULL;
562  }
563  else if(partA.nnz == 0)
564  {
565  Cdcsc = new Dcsc<IT,NT>(*(partB.dcsc));
566  transform(Cdcsc->jc, Cdcsc->jc + Cdcsc->nzc, Cdcsc->jc, bind2nd(plus<IT>(), partA.n));
567  }
568  else if(partB.nnz == 0)
569  {
570  Cdcsc = new Dcsc<IT,NT>(*(partA.dcsc));
571  }
572  else
573  {
574  Cdcsc->Merge(partA.dcsc, partB.dcsc, partA.n);
575  }
576  *this = SpDCCols<IT,NT> (partA.m, partA.n + partB.n, Cdcsc);
577 
578  partA = SpDCCols<IT, NT>();
579  partB = SpDCCols<IT, NT>();
580 }
581 
588 template <class IT, class NT>
589 template <class SR>
591 {
592  if(A.isZero() || B.isZero())
593  {
594  return -1; // no need to do anything
595  }
596  Isect<IT> *isect1, *isect2, *itr1, *itr2, *cols, *rows;
597  SpHelper::SpIntersect(*(A.dcsc), *(B.dcsc), cols, rows, isect1, isect2, itr1, itr2);
598 
599  IT kisect = static_cast<IT>(itr1-isect1); // size of the intersection ((itr1-isect1) == (itr2-isect2))
600  if(kisect == 0)
601  {
602  DeleteAll(isect1, isect2, cols, rows);
603  return -1;
604  }
605 
606  StackEntry< NT, pair<IT,IT> > * multstack;
607  IT cnz = SpHelper::SpCartesian< SR > (*(A.dcsc), *(B.dcsc), kisect, isect1, isect2, multstack);
608  DeleteAll(isect1, isect2, cols, rows);
609 
610  IT mdim = A.m;
611  IT ndim = B.m; // since B has already been transposed
612  if(isZero())
613  {
614  dcsc = new Dcsc<IT,NT>(multstack, mdim, ndim, cnz);
615  }
616  else
617  {
618  dcsc->AddAndAssign(multstack, mdim, ndim, cnz);
619  }
620  nnz = dcsc->nz;
621 
622  delete [] multstack;
623  return 1;
624 }
625 
632 template <class IT, class NT>
633 template <typename SR>
635 {
636  if(A.isZero() || B.isZero())
637  {
638  return -1; // no need to do anything
639  }
640  StackEntry< NT, pair<IT,IT> > * multstack;
641  int cnz = SpHelper::SpColByCol< SR > (*(A.dcsc), *(B.dcsc), A.n, multstack);
642 
643  IT mdim = A.m;
644  IT ndim = B.n;
645  if(isZero())
646  {
647  dcsc = new Dcsc<IT,NT>(multstack, mdim, ndim, cnz);
648  }
649  else
650  {
651  dcsc->AddAndAssign(multstack, mdim, ndim, cnz);
652  }
653  nnz = dcsc->nz;
654 
655  delete [] multstack;
656  return 1;
657 }
658 
659 
660 template <class IT, class NT>
661 template <typename SR>
663 {
664  cout << "PlusEq_AtXBn function has not been implemented yet !" << endl;
665  return 0;
666 }
667 
668 template <class IT, class NT>
669 template <typename SR>
671 {
672  cout << "PlusEq_AtXBt function has not been implemented yet !" << endl;
673  return 0;
674 }
675 
676 
677 template <class IT, class NT>
679 {
680  IT * itr = find(dcsc->jc, dcsc->jc + dcsc->nzc, ci);
681  if(itr != dcsc->jc + dcsc->nzc)
682  {
683  IT irbeg = dcsc->cp[itr - dcsc->jc];
684  IT irend = dcsc->cp[itr - dcsc->jc + 1];
685 
686  IT * ele = find(dcsc->ir + irbeg, dcsc->ir + irend, ri);
687  if(ele != dcsc->ir + irend)
688  {
689  SpDCCols<IT,NT> SingEleMat(1, 1, 1, 1); // 1-by-1 matrix with 1 nonzero
690  *(SingEleMat.dcsc->numx) = dcsc->numx[ele - dcsc->ir];
691  *(SingEleMat.dcsc->ir) = *ele;
692  *(SingEleMat.dcsc->jc) = *itr;
693  (SingEleMat.dcsc->cp)[0] = 0;
694  (SingEleMat.dcsc->cp)[1] = 1;
695  }
696  else
697  {
698  return SpDCCols<IT,NT>(); // 0-by-0 empty matrix
699  }
700  }
701  else
702  {
703  return SpDCCols<IT,NT>(); // 0-by-0 empty matrix
704  }
705 }
706 
711 template <class IT, class NT>
712 SpDCCols<IT,NT> SpDCCols<IT,NT>::operator() (const vector<IT> & ri, const vector<IT> & ci) const
713 {
714  typedef PlusTimesSRing<NT,NT> PT;
715 
716  IT rsize = ri.size();
717  IT csize = ci.size();
718 
719  if(rsize == 0 && csize == 0)
720  {
721  // return an m x n matrix of complete zeros
722  // since we don't know whether columns or rows are indexed
723  return SpDCCols<IT,NT> (0, m, n, 0);
724  }
725  else if(rsize == 0)
726  {
727  return ColIndex(ci);
728  }
729  else if(csize == 0)
730  {
731  SpDCCols<IT,NT> LeftMatrix(rsize, rsize, this->m, ri, true);
732  return LeftMatrix.OrdColByCol< PT >(*this);
733  }
734  else // this handles the (rsize=1 && csize=1) case as well
735  {
736  SpDCCols<IT,NT> LeftMatrix(rsize, rsize, this->m, ri, true);
737  SpDCCols<IT,NT> RightMatrix(csize, this->n, csize, ci, false);
738  return LeftMatrix.OrdColByCol< PT >( OrdColByCol< PT >(RightMatrix) );
739  }
740 }
741 
742 template <class IT, class NT>
743 ofstream & SpDCCols<IT,NT>::put(ofstream & outfile) const
744 {
745  if(nnz == 0)
746  {
747  outfile << "Matrix doesn't have any nonzeros" <<endl;
748  return outfile;
749  }
750  SpTuples<IT,NT> tuples(*this);
751  outfile << tuples << endl;
752  return outfile;
753 }
754 
755 
756 template <class IT, class NT>
757 ifstream & SpDCCols<IT,NT>::get(ifstream & infile)
758 {
759  cout << "Getting... SpDCCols" << endl;
760  IT m, n, nnz;
761  infile >> m >> n >> nnz;
762  SpTuples<IT,NT> tuples(nnz, m, n);
763  infile >> tuples;
764  tuples.SortColBased();
765 
766  SpDCCols<IT,NT> object(tuples, false, NULL);
767  *this = object;
768  return infile;
769 }
770 
771 
772 template<class IT, class NT>
773 void SpDCCols<IT,NT>::PrintInfo(ofstream & out) const
774 {
775  out << "m: " << m ;
776  out << ", n: " << n ;
777  out << ", nnz: "<< nnz ;
778 
779  if(splits > 0)
780  {
781  out << ", local splits: " << splits << endl;
782  }
783  else
784  {
785  if(dcsc != NULL)
786  {
787  out << ", nzc: "<< dcsc->nzc << endl;
788  }
789  else
790  {
791  out <<", nzc: "<< 0 << endl;
792  }
793  }
794 }
795 
796 template<class IT, class NT>
798 {
799  cout << "m: " << m ;
800  cout << ", n: " << n ;
801  cout << ", nnz: "<< nnz ;
802 
803  if(splits > 0)
804  {
805  cout << ", local splits: " << splits << endl;
806  }
807  else
808  {
809  if(dcsc != NULL)
810  {
811  cout << ", nzc: "<< dcsc->nzc << endl;
812  }
813  else
814  {
815  cout <<", nzc: "<< 0 << endl;
816  }
817 
818  if(m < PRINT_LIMIT && n < PRINT_LIMIT) // small enough to print
819  {
820  NT ** A = SpHelper::allocate2D<NT>(m,n);
821  for(IT i=0; i< m; ++i)
822  for(IT j=0; j<n; ++j)
823  A[i][j] = NT();
824  if(dcsc != NULL)
825  {
826  for(IT i=0; i< dcsc->nzc; ++i)
827  {
828  for(IT j = dcsc->cp[i]; j<dcsc->cp[i+1]; ++j)
829  {
830  IT colid = dcsc->jc[i];
831  IT rowid = dcsc->ir[j];
832  A[rowid][colid] = dcsc->numx[j];
833  }
834  }
835  }
836  for(IT i=0; i< m; ++i)
837  {
838  for(IT j=0; j<n; ++j)
839  {
840  cout << setiosflags(ios::fixed) << setprecision(2) << A[i][j];
841  cout << " ";
842  }
843  cout << endl;
844  }
846  }
847  }
848 }
849 
850 
851 /****************************************************************************/
852 /********************* PRIVATE CONSTRUCTORS/DESTRUCTORS *********************/
853 /****************************************************************************/
854 
856 template <class IT, class NT>
857 SpDCCols<IT,NT>::SpDCCols(IT nRow, IT nCol, Dcsc<IT,NT> * mydcsc)
858 :dcsc(mydcsc), m(nRow), n(nCol), splits(0)
859 {
860  if (mydcsc == NULL)
861  nnz = 0;
862  else
863  nnz = mydcsc->nz;
864 }
865 
867 template <class IT, class NT>
868 SpDCCols<IT,NT>::SpDCCols (IT size, IT nRow, IT nCol, const vector<IT> & indices, bool isRow)
869 :m(nRow), n(nCol), nnz(size), splits(0)
870 {
871  if(size > 0)
872  dcsc = new Dcsc<IT,NT>(size,indices,isRow);
873  else
874  dcsc = NULL;
875 }
876 
877 
878 /****************************************************************************/
879 /************************* PRIVATE MEMBER FUNCTIONS *************************/
880 /****************************************************************************/
881 
882 template <class IT, class NT>
883 inline void SpDCCols<IT,NT>::CopyDcsc(Dcsc<IT,NT> * source)
884 {
885  // source dcsc will be NULL if number of nonzeros is zero
886  if(source != NULL)
887  dcsc = new Dcsc<IT,NT>(*source);
888  else
889  dcsc = NULL;
890 }
891 
898 template <class IT, class NT>
899 SpDCCols<IT,NT> SpDCCols<IT,NT>::ColIndex(const vector<IT> & ci) const
900 {
901  IT csize = ci.size();
902  if(nnz == 0) // nothing to index
903  {
904  return SpDCCols<IT,NT>(0, m, csize, 0);
905  }
906  else if(ci.empty())
907  {
908  return SpDCCols<IT,NT>(0, m,0, 0);
909  }
910 
911  // First pass for estimation
912  IT estsize = 0;
913  IT estnzc = 0;
914  for(IT i=0, j=0; i< dcsc->nzc && j < csize;)
915  {
916  if((dcsc->jc)[i] < ci[j])
917  {
918  ++i;
919  }
920  else if ((dcsc->jc)[i] > ci[j])
921  {
922  ++j;
923  }
924  else
925  {
926  estsize += (dcsc->cp)[i+1] - (dcsc->cp)[i];
927  ++estnzc;
928  ++i;
929  ++j;
930  }
931  }
932 
933  SpDCCols<IT,NT> SubA(estsize, m, csize, estnzc);
934  if(estnzc == 0)
935  {
936  return SubA; // no need to run the second pass
937  }
938  SubA.dcsc->cp[0] = 0;
939  IT cnzc = 0;
940  IT cnz = 0;
941  for(IT i=0, j=0; i < dcsc->nzc && j < csize;)
942  {
943  if((dcsc->jc)[i] < ci[j])
944  {
945  ++i;
946  }
947  else if ((dcsc->jc)[i] > ci[j]) // an empty column for the output
948  {
949  ++j;
950  }
951  else
952  {
953  IT columncount = (dcsc->cp)[i+1] - (dcsc->cp)[i];
954  SubA.dcsc->jc[cnzc++] = j;
955  SubA.dcsc->cp[cnzc] = SubA.dcsc->cp[cnzc-1] + columncount;
956  copy(dcsc->ir + dcsc->cp[i], dcsc->ir + dcsc->cp[i+1], SubA.dcsc->ir + cnz);
957  copy(dcsc->numx + dcsc->cp[i], dcsc->numx + dcsc->cp[i+1], SubA.dcsc->numx + cnz);
958  cnz += columncount;
959  ++i;
960  ++j;
961  }
962  }
963  return SubA;
964 }
965 
966 template <class IT, class NT>
967 template <typename SR, typename NTR>
969 {
970  typedef typename promote_trait<NT,NTR>::T_promote T_promote;
971 
972  if(isZero() || rhs.isZero())
973  {
974  return SpDCCols< IT, T_promote > (0, m, rhs.n, 0); // return an empty matrix
975  }
976  SpDCCols<IT,NTR> Btrans = rhs.TransposeConst();
977 
978  Isect<IT> *isect1, *isect2, *itr1, *itr2, *cols, *rows;
979  SpHelper::SpIntersect(*dcsc, *(Btrans.dcsc), cols, rows, isect1, isect2, itr1, itr2);
980 
981  IT kisect = static_cast<IT>(itr1-isect1); // size of the intersection ((itr1-isect1) == (itr2-isect2))
982  if(kisect == 0)
983  {
984  DeleteAll(isect1, isect2, cols, rows);
985  return SpDCCols< IT, T_promote > (0, m, rhs.n, 0);
986  }
988  IT cnz = SpHelper::SpCartesian< SR > (*dcsc, *(Btrans.dcsc), kisect, isect1, isect2, multstack);
989  DeleteAll(isect1, isect2, cols, rows);
990 
991  Dcsc<IT, T_promote> * mydcsc = NULL;
992  if(cnz > 0)
993  {
994  mydcsc = new Dcsc< IT,T_promote > (multstack, m, rhs.n, cnz);
995  delete [] multstack;
996  }
997  return SpDCCols< IT,T_promote > (m, rhs.n, mydcsc);
998 }
999 
1000 
1001 template <class IT, class NT>
1002 template <typename SR, typename NTR>
1004 {
1005  typedef typename promote_trait<NT,NTR>::T_promote T_promote;
1006 
1007  if(isZero() || rhs.isZero())
1008  {
1009  return SpDCCols<IT, T_promote> (0, m, rhs.n, 0); // return an empty matrix
1010  }
1011  StackEntry< T_promote, pair<IT,IT> > * multstack;
1012  IT cnz = SpHelper::SpColByCol< SR > (*dcsc, *(rhs.dcsc), n, multstack);
1013 
1014  Dcsc<IT,T_promote > * mydcsc = NULL;
1015  if(cnz > 0)
1016  {
1017  mydcsc = new Dcsc< IT,T_promote > (multstack, m, rhs.n, cnz);
1018  delete [] multstack;
1019  }
1020  return SpDCCols< IT,T_promote > (m, rhs.n, mydcsc);
1021 }
1022