MOOSE - Multiscale Object Oriented Simulation Environment
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
SparseMatrix.h
Go to the documentation of this file.
1 /**********************************************************************
2 ** This program is part of 'MOOSE', the
3 ** Messaging Object Oriented Simulation Environment,
4 ** also known as GENESIS 3 base code.
5 ** copyright (C) 2003-2006 Upinder S. Bhalla. and NCBS
6 ** It is made available under the terms of the
7 ** GNU Lesser General Public License version 2.1
8 ** See the file COPYING.LIB for the full notice.
9 **********************************************************************/
10 
11 #ifndef _SPARSE_MATRIX_H
12 #define _SPARSE_MATRIX_H
13 
14 #include <vector>
15 using namespace std;
16 
26 extern const unsigned int SM_MAX_ROWS;
27 extern const unsigned int SM_MAX_COLUMNS;
28 extern const unsigned int SM_RESERVE;
29 
30 template< class T > class Triplet
31 {
32 public:
34  {
35  ;
36  }
37 
38  Triplet( T a, unsigned int b, unsigned int c )
39  : a_( a ), b_( b ), c_( c )
40  {
41  ;
42  }
43  bool operator< ( const Triplet< T >& other ) const
44  {
45  return ( c_ < other.c_ );
46  }
47  static bool cmp( const Triplet< T >& p, const Triplet< T >& q )
48  {
49  if ( p.b_ == q.b_ )
50  return ( p.c_ < q.c_ );
51  else if ( p.b_ < q.b_ )
52  return true;
53  return false;
54  }
55 
56  T a_;
57  unsigned int b_; // row
58  unsigned int c_; // col
59 };
60 
61 
62 typedef std::vector< class T >::const_iterator constTypeIter;
63 template < class T > class SparseMatrix
64 {
65 public:
67  // Constructors
70  : nrows_( 0 ), ncolumns_( 0 ), rowStart_( 1, 0 )
71  {
72  N_.resize( 0 );
73  N_.reserve( SM_RESERVE );
74  colIndex_.resize( 0 );
75  colIndex_.reserve( SM_RESERVE );
76  }
77 
78  SparseMatrix( unsigned int nrows, unsigned int ncolumns )
79  {
80  setSize( nrows, ncolumns );
81  }
82 
84  // Information operations.
86 
87  unsigned int nRows() const
88  {
89  return nrows_;
90  }
91 
92  unsigned int nColumns() const
93  {
94  return ncolumns_;
95  }
96 
97  unsigned int nEntries() const
98  {
99  return N_.size();
100  }
101 
102  /*
103  bool operator==()( const SparseMatrix& other ) {
104  if (
105  nrows_ == other.nrows_ &&
106  ncolumns_ == other.ncolumns_ &&
107  && N_.size() == other.N_.size() &&
108  rowStart_ == other.rowStart_ &&
109  colIndex_ == other.colIndex_ ) {
110  for ( unsigned int i = 0; i < N_.size(); ++i )
111  if ( !doubleEq( N_[i], other.N_[i] ) )
112  return false;
113  return true;
114  }
115  return false;
116  }
117  */
118 
120  // Individual entry Access operations.
122 
126  void setSize( unsigned int nrows, unsigned int ncolumns )
127  {
128  if ( nrows == 0 || ncolumns == 0 )
129  {
130  N_.clear();
131  rowStart_.resize( 1 );
132  rowStart_[0] = 0;
133  colIndex_.clear();
134  nrows_ = 0;
135  ncolumns_ = 0;
136  return;
137  }
138  if ( nrows < SM_MAX_ROWS && ncolumns < SM_MAX_COLUMNS )
139  {
140  N_.clear();
141  N_.reserve( 2 * nrows );
142  nrows_ = nrows;
143  ncolumns_ = ncolumns;
144  rowStart_.clear();
145  rowStart_.resize( nrows + 1, 0 );
146  colIndex_.clear();
147  colIndex_.reserve( 2 * nrows );
148  }
149  else
150  {
151  cerr << "Error: SparseMatrix::setSize( " <<
152  nrows << ", " << ncolumns << ") out of range: ( " <<
153  SM_MAX_ROWS << ", " << SM_MAX_COLUMNS << ")\n";
154  }
155  }
156 
161  void set( unsigned int row, unsigned int column, T value )
162  {
163  if ( nrows_ == 0 || ncolumns_ == 0 )
164  return;
165  vector< unsigned int >::iterator i;
166  vector< unsigned int >::iterator begin =
167  colIndex_.begin() + rowStart_[ row ];
168  vector< unsigned int >::iterator end =
169  colIndex_.begin() + rowStart_[ row + 1 ];
170 
171  if ( begin == end ) // Entire row was empty.
172  {
173  unsigned long offset = begin - colIndex_.begin();
174  colIndex_.insert( colIndex_.begin() + offset, column );
175  N_.insert( N_.begin() + offset, value );
176  for ( unsigned int j = row + 1; j <= nrows_; j++ )
177  rowStart_[ j ]++;
178  return;
179  }
180 
181  if ( column > *( end - 1 ) ) // add entry at end of row.
182  {
183  unsigned long offset = end - colIndex_.begin();
184  colIndex_.insert( colIndex_.begin() + offset, column );
185  N_.insert( N_.begin() + offset, value );
186  for ( unsigned int j = row + 1; j <= nrows_; j++ )
187  rowStart_[ j ]++;
188  return;
189  }
190  for ( i = begin; i != end; i++ )
191  {
192  if ( *i == column ) // Found desired entry. By defn it is nonzero.
193  {
194  N_[ i - colIndex_.begin()] = value;
195  return;
196  }
197  else if ( *i > column ) // Desired entry is blank.
198  {
199  unsigned long offset = i - colIndex_.begin();
200  colIndex_.insert( colIndex_.begin() + offset, column );
201  N_.insert( N_.begin() + offset, value );
202  for ( unsigned int j = row + 1; j <= nrows_; j++ )
203  rowStart_[ j ]++;
204  return;
205  }
206  }
207  }
208 
212  void unset( unsigned int row, unsigned int column )
213  {
214  if ( nrows_ == 0 || ncolumns_ == 0 )
215  return;
216  vector< unsigned int >::iterator i;
217  vector< unsigned int >::iterator begin =
218  colIndex_.begin() + rowStart_[ row ];
219  vector< unsigned int >::iterator end =
220  colIndex_.begin() + rowStart_[ row + 1 ];
221 
222  if ( begin == end ) // Entire row was empty. Ignore
223  {
224  return;
225  }
226 
227  if ( column > *( end - 1 ) ) // End of row. Ignore
228  {
229  return;
230  }
231  for ( i = begin; i != end; i++ )
232  {
233  if ( *i == column ) // Found desired entry. Zap it.
234  {
235  unsigned long offset = i - colIndex_.begin();
236  colIndex_.erase( i );
237  N_.erase( N_.begin() + offset );
238  for ( unsigned int j = row + 1; j <= nrows_; j++ )
239  rowStart_[ j ]--;
240  return;
241  }
242  else if ( *i > column ) //Desired entry is blank. Ignore
243  {
244  return;
245  }
246  }
247  }
248 
253  T get( unsigned int row, unsigned int column ) const
254  {
255  if ( nrows_ == 0 || ncolumns_ == 0 )
256  return 0;
257  assert( row < nrows_ && column < ncolumns_ );
258  vector< unsigned int >::const_iterator i;
259  vector< unsigned int >::const_iterator begin =
260  colIndex_.begin() + rowStart_[ row ];
261  vector< unsigned int >::const_iterator end =
262  colIndex_.begin() + rowStart_[ row + 1 ];
263 
264  i = find( begin, end, column );
265  if ( i == end ) // most common situation for a sparse Stoich matrix.
266  {
267  return 0;
268  }
269  else
270  {
271  return N_[ rowStart_[row] + (i - begin) ];
272  }
273  }
275  // Row/Column Access operations.
277 
288  unsigned int getRow( unsigned int row,
289  const T** entry, const unsigned int** colIndex ) const
290  {
291  if ( row >= nrows_ || ncolumns_ == 0 )
292  {
293  entry = 0;
294  colIndex = 0;
295  return 0;
296  }
297  unsigned int rs = rowStart_[row];
298  if ( rs >= N_.size() )
299  {
300  entry = 0;
301  colIndex = 0;
302  return 0;
303  }
304  *entry = &( N_[ rs ] );
305  *colIndex = &( colIndex_[rs] );
306  return rowStart_[row + 1] - rs;
307  }
308 
314  unsigned int getRow( unsigned int row,
315  vector< T >& e, vector< unsigned int >& c ) const
316  {
317  e.clear();
318  c.clear();
319  if ( row >= nrows_ || ncolumns_ == 0 )
320  {
321  return 0;
322  }
323  unsigned int rs = rowStart_[row];
324  if ( rs >= N_.size() )
325  {
326  return 0;
327  }
328  unsigned int ret = rowStart_[row + 1] - rs;
329  e.insert( e.begin(),
330  N_.begin() + rs, N_.begin() + rs + ret );
331  c.insert( c.begin(),
332  colIndex_.begin() + rs, colIndex_.begin() + rs + ret );
333  return ret;
334  }
335 
336 
342  unsigned int getColumn( unsigned int col,
343  vector< T >& entry,
344  vector< unsigned int >& rowIndex ) const
345  {
346  entry.resize( 0 );
347  rowIndex.resize( 0 );
348 
349  unsigned int row = 0;
350  for ( unsigned int i = 0; i < N_.size(); ++i )
351  {
352  if ( col == colIndex_[i] )
353  {
354  entry.push_back( N_[i] );
355  while ( rowStart_[ row + 1 ] <= i )
356  row++;
357  rowIndex.push_back( row );
358  }
359  }
360  return entry.size();
361  }
362 
363 #if 0
364  void rowOperation( unsigned int row, unary_function< T, void>& f )
365  {
366  assert( row < nrows_ );
367 
368  constTypeIter i;
369  // vector< T >::const_iterator i;
370  unsigned int rs = rowStart_[row];
371  vector< unsigned int >::const_iterator j = colIndex_.begin() + rs;
372  // vector< T >::const_iterator end =
373  constTypeIter end =
374  N_.begin() + rowStart_[ row + 1 ];
375 
376  // for_each
377  for ( i = N_.begin() + rs; i != end; ++i )
378  f( *i );
379  }
380 #endif
381 
387  void addRow( unsigned int rowNum, const vector< T >& row )
388  {
389  assert( rowNum < nrows_ );
390  assert( rowStart_.size() == (nrows_ + 1 ) );
391  assert( N_.size() == colIndex_.size() );
392  if ( ncolumns_ == 0 )
393  return;
394  for ( unsigned int i = 0; i < ncolumns_; ++i )
395  {
396  if ( row[i] != T( ~0 ) )
397  {
398  N_.push_back( row[i] );
399  colIndex_.push_back( i );
400  }
401  }
402  rowStart_[rowNum + 1] = N_.size();
403  }
404 
410  void addRow( unsigned int rowNum,
411  const vector < T >& entry,
412  const vector< unsigned int >& colIndexArg )
413  {
414  assert( rowNum < nrows_ );
415  assert( rowStart_.size() == (nrows_ + 1 ) );
416  assert( rowStart_[ rowNum ] == N_.size() );
417  assert( entry.size() == colIndexArg.size() );
418  assert( N_.size() == colIndex_.size() );
419  if ( ncolumns_ == 0 )
420  return;
421  N_.insert( N_.end(), entry.begin(), entry.end() );
422  colIndex_.insert( colIndex_.end(),
423  colIndexArg.begin(), colIndexArg.end() );
424  rowStart_[rowNum + 1] = N_.size();
425  }
427  const vector< T >& matrixEntry() const
428  {
429  return N_;
430  }
431  const vector< unsigned int >& colIndex() const
432  {
433  return colIndex_;
434  }
435  const vector< unsigned int >& rowStart() const
436  {
437  return rowStart_;
438  }
440  // Operations on entire matrix.
442 
443  void clear()
444  {
445  N_.resize( 0 );
446  colIndex_.resize( 0 );
447  assert( rowStart_.size() == (nrows_ + 1) );
448  rowStart_.assign( nrows_ + 1, 0 );
449  }
450 
451 
456  void transpose()
457  {
458  vector< Triplet< T > > t;
459 
460  unsigned int rowIndex = 0;
461  if ( rowStart_.size() < 2 )
462  return;
463  /*
464  for ( unsigned int i = 0; i < rowStart_.size(); ++i )
465  cout << rowStart_[i] << " ";
466  cout << endl;
467  */
468  // cout << "rowNum = ";
469  unsigned int rs = rowStart_[0];
470  for ( unsigned int i = 0; i < N_.size(); ++i )
471  {
472  while( rs == rowStart_[ rowIndex + 1 ] )
473  {
474  rowIndex++;
475  }
476  rs++;
477 
478  /*
479  if ( i == rowStart_[j] ) {
480  rowNum++;
481  j++;
482  }
483  */
484  // cout << rowNum << " ";
485  // The rowNum is going to be the new colIndex.
486  Triplet< T > x( N_[i], rowIndex, colIndex_[i] );
487  t.push_back( x );
488  }
489  // cout << endl;
490  // cout << "before sort\n"; printTriplet( t );
491  stable_sort( t.begin(), t.end() );
492  // cout << "after sort\n"; printTriplet( t );
493 
494  unsigned int j = ~0;
495  rowStart_.resize( 0 );
496  rowStart_.push_back( 0 );
497  unsigned int ci = 0;
498  for ( unsigned int i = 0; i < N_.size(); ++i )
499  {
500  N_[i] = t[i].a_;
501  colIndex_[i] = t[i].b_;
502 
503  while ( ci != t[i].c_ )
504  {
505  rowStart_.push_back( i );
506  ci++;
507  }
508 
509  /*
510  if ( t[i].c_ != j ) {
511  j = t[i].c_;
512  rowStart_.push_back( i );
513  }
514  */
515  }
516  for ( j = ci; j < ncolumns_; ++j )
517  rowStart_.push_back( N_.size() );
518  // rowStart_.push_back( N_.size() );
519  j = nrows_;
520  nrows_ = ncolumns_;
521  ncolumns_ = j;
522  assert( rowStart_.size() == nrows_ + 1 );
523  }
524 
533  void reorderColumns( const vector< unsigned int >& colMap )
534  {
535  unsigned int numNewColumns = colMap.size();;
536  SparseMatrix< T > old = *this;
537  setSize( nrows_, numNewColumns );
538  if ( numNewColumns == 0 )
539  return;
540  for ( unsigned int i = 0; i < old.nrows_; ++i )
541  {
542  const T* entry;
543  const unsigned int* colIndex;
544  unsigned int n = old.getRow( i, &entry, &colIndex );
545  // Make the full-length vectors of the new row.
546  vector< T > newEntry( numNewColumns );
547  vector< bool > isNewEntry( numNewColumns, false );
548  unsigned int numOccupiedEntries = 0;
549  for ( unsigned int j = 0; j < n; ++j )
550  {
551  assert( colIndex[j] < old.ncolumns_ );
552  for ( unsigned int q = 0; q < colMap.size(); ++q )
553  {
554  if ( colMap[q] == colIndex[j] )
555  {
556  isNewEntry[q] = true;
557  newEntry[q] = entry[j];
558  ++numOccupiedEntries;
559  }
560  }
561  }
562  // Compress the full-length vector into the sparse form
563  vector< T > sparseEntry;
564  vector< unsigned int > sparseCols;
565  sparseEntry.reserve( numOccupiedEntries );
566  sparseCols.reserve( numOccupiedEntries );
567  for ( unsigned int q = 0; q < numNewColumns; ++q )
568  {
569  if ( isNewEntry[q] )
570  {
571  sparseEntry.push_back( newEntry[q] );
572  sparseCols.push_back( q );
573  }
574  }
575  addRow( i, sparseEntry, sparseCols );
576  }
577  }
578 
580  // Utility operations.
582 
583  void tripletFill( const vector< unsigned int >& row,
584  const vector< unsigned int >& col,
585  const vector< T >& z, bool retainSize = false )
586  {
587  unsigned int len = row.size();
588  if ( len > col.size() ) len = col.size();
589  if ( len > z.size() ) len = z.size();
590  vector< Triplet< T > > trip( len );
591  for ( unsigned int i = 0; i < len; ++i )
592  trip[i]= Triplet< T >(z[i], row[i], col[i] );
593  sort( trip.begin(), trip.end(), Triplet< T >::cmp );
594  unsigned int nr = nrows_;
595  unsigned int nc = ncolumns_;
596  if ( !retainSize ) {
597  nr = trip.back().b_ + 1;
598  nc = 0;
599  for ( typename vector< Triplet< T > >::iterator i =
600  trip.begin(); i != trip.end(); ++i )
601  {
602  if ( nc < i->c_ )
603  nc = i->c_;
604  }
605  nc++;
606  }
607  setSize( nr, nc );
608 
609  vector< unsigned int > colIndex( nc );
610  vector< T > entry( nc );
611 
612  typename vector< Triplet< T > >::iterator j = trip.begin();
613  for ( unsigned int i = 0; i < nr; ++i )
614  {
615  colIndex.clear();
616  entry.clear();
617  while( j != trip.end() && j->b_ == i )
618  {
619  colIndex.push_back( j->c_ );
620  entry.push_back( j->a_ );
621  j++;
622  }
623  addRow( i, entry, colIndex );
624  }
625  }
626 
627  void pairFill( const vector< unsigned int >& row,
628  const vector< unsigned int >& col, T value )
629  {
630  vector< T > z( row.size(), value );
631  tripletFill( row, col, z );
632  }
633 
635  // Printing operations.
637 
638  void printTriplet( const vector< Triplet< T > >& t )
639  {
640  for ( unsigned int i = 0; i < t.size(); ++i )
641  {
642  cout << i << " " << t[i].a_ << " " << t[i].b_ <<
643  " " << t[i].c_ << endl;
644  }
645  }
646 
650  void print() const
651  {
652  for ( unsigned int i = 0; i < nrows_; ++i )
653  {
654  unsigned int k = rowStart_[i];
655  unsigned int end = rowStart_[i + 1];
656  unsigned int nextColIndex = colIndex_[k];
657  for ( unsigned int j = 0; j < ncolumns_; ++j )
658  {
659  if ( j < nextColIndex )
660  {
661  cout << "0 ";
662  }
663  else if ( k < end )
664  {
665  cout << N_[k] << " ";
666  ++k;
667  nextColIndex = colIndex_[k];
668  }
669  else
670  {
671  cout << "0 ";
672  }
673  }
674  cout << endl;
675  }
676  }
677 
681  void printInternal() const
682  {
683  unsigned int max = (nrows_ < N_.size() ) ? N_.size() : nrows_+1;
684  cout << "# ";
685  for ( unsigned int i = 0; i < max; ++i )
686  cout << i << " ";
687  cout << "\nrs ";
688  for ( unsigned int i = 0; i < rowStart_.size(); ++i )
689  cout << rowStart_[i] << " ";
690  cout << "\ncol ";
691  for ( unsigned int i = 0; i < N_.size(); ++i )
692  cout << colIndex_[i] << " ";
693  cout << "\nN ";
694  for ( unsigned int i = 0; i < N_.size(); ++i )
695  cout << N_[i] << " ";
696  cout << endl;
697  }
698 
699 
700 protected:
701  unsigned int nrows_;
702  unsigned int ncolumns_;
703  vector< T > N_;
704 
705  /*
706  * Column index of each non-zero entry.
707  * This matches up entry-by entry with the N_ vector.
708  */
709  vector< unsigned int > colIndex_;
710 
712  vector< unsigned int > rowStart_;
713 };
714 
715 #endif // _SPARSE_MATRIX_H
unsigned int nEntries() const
Definition: SparseMatrix.h:97
unsigned int b_
Definition: SparseMatrix.h:57
void tripletFill(const vector< unsigned int > &row, const vector< unsigned int > &col, const vector< T > &z, bool retainSize=false)
Definition: SparseMatrix.h:583
uint32_t value
Definition: moosemodule.h:42
const vector< T > & matrixEntry() const
Here we expose the sparse matrix for MOOSE use.
Definition: SparseMatrix.h:427
void addRow(unsigned int rowNum, const vector< T > &entry, const vector< unsigned int > &colIndexArg)
Definition: SparseMatrix.h:410
unsigned int ncolumns_
Definition: SparseMatrix.h:702
unsigned int nColumns() const
Definition: SparseMatrix.h:92
void printInternal() const
Definition: SparseMatrix.h:681
void set(unsigned int row, unsigned int column, T value)
Definition: SparseMatrix.h:161
unsigned int getRow(unsigned int row, const T **entry, const unsigned int **colIndex) const
Definition: SparseMatrix.h:288
unsigned int c_
Definition: SparseMatrix.h:58
unsigned int nRows() const
Definition: SparseMatrix.h:87
void transpose()
Definition: SparseMatrix.h:456
void printTriplet(const vector< Triplet< T > > &t)
Definition: SparseMatrix.h:638
SparseMatrix(unsigned int nrows, unsigned int ncolumns)
Definition: SparseMatrix.h:78
vector< T > N_
Definition: SparseMatrix.h:703
unsigned int rowIndex(const Element *e, const DataId &d)
Definition: SparseMsg.cpp:425
void addRow(unsigned int rowNum, const vector< T > &row)
Definition: SparseMatrix.h:387
void pairFill(const vector< unsigned int > &row, const vector< unsigned int > &col, T value)
Definition: SparseMatrix.h:627
unsigned int nrows_
Definition: SparseMatrix.h:701
const vector< unsigned int > & colIndex() const
Definition: SparseMatrix.h:431
const unsigned int SM_MAX_COLUMNS
void setSize(unsigned int nrows, unsigned int ncolumns)
Definition: SparseMatrix.h:126
void print() const
Definition: SparseMatrix.h:650
unsigned int getRow(unsigned int row, vector< T > &e, vector< unsigned int > &c) const
Definition: SparseMatrix.h:314
std::vector< class T >::const_iterator constTypeIter
Definition: SparseMatrix.h:62
void unset(unsigned int row, unsigned int column)
Definition: SparseMatrix.h:212
const vector< unsigned int > & rowStart() const
Definition: SparseMatrix.h:435
vector< unsigned int > colIndex_
Non-zero entries in the SparseMatrix.
Definition: SparseMatrix.h:709
void reorderColumns(const vector< unsigned int > &colMap)
Definition: SparseMatrix.h:533
const unsigned int SM_RESERVE
Triplet(T a, unsigned int b, unsigned int c)
Definition: SparseMatrix.h:38
unsigned int getColumn(unsigned int col, vector< T > &entry, vector< unsigned int > &rowIndex) const
Definition: SparseMatrix.h:342
static bool cmp(const Triplet< T > &p, const Triplet< T > &q)
Definition: SparseMatrix.h:47
const unsigned int SM_MAX_ROWS
vector< unsigned int > rowStart_
Start index in the N_ and colIndex_ vectors, of each row.
Definition: SparseMatrix.h:712