Flow123d  jenkins-Flow123d-windows-release-multijob-285
matrix_coo.hpp
Go to the documentation of this file.
1 #ifndef la_matrix_coo_h
2 #define la_matrix_coo_h
3 
4 #define ALLOWED_MEM_OVERHEAD 2.e+6 // entries, this corresponds to 32 MB of
5  // overhead in <int, int, double> matrixCoo
6 //------------------------------------------------------------------------------
7 #include <vector>
8 #include <cassert>
9 #include <cmath>
10 #include <algorithm>
11 #include <iomanip>
12 #include <numeric>
13 
14 //------------------------------------------------------------------------------
15 namespace la{
16  template< typename INDT, typename VALT >
17  class MatrixCoo;
18 }
19 
20 //------------------------------------------------------------------------------
21 /** \brief Temporary storage for a sparse matrix
22  * \details This object stores and handles matrix in coordinate format, i.e.,
23  * <row_index,col_index,value>-combinations for each matrix entry of a sparse matrix.
24  * Functionalities are:
25  * - preparing assembly of elements - allocating proper space to all elements
26  * in unassembled form
27  * - inserting an element - it is user's responsibility not to insert zeros
28  * - finishing assembly of elements - this is the core routine which
29  * - sorts triples, merges entries with the same pair of indices,
30  * truncates the array to assembled size
31  * - 'zeroing' a row and setting its diagonal entry to a given value
32  * - query of number of entries - this counts also zeros if they were inserted
33  * - get inside/outide-a-range counts of elements - for PETSc preallocation
34  * - filling the arrays for a row-compressed data storage for external
35  * solver libraries
36  * - computing inf norm
37  * - cleanup and writing
38  */
39 template< typename INDT, typename VALT >
40 class la::MatrixCoo
41 {
42 public:
43  typedef INDT IndexType;
44  typedef VALT ValueType;
45 
46 public:
47  MatrixCoo( unsigned nRows = 0, unsigned nCols = 0 )
48  : nRows_( nRows ),
49  nCols_( nCols ),
50  sorted_ ( false )
51  {
52  sortedSize_ = 0;
53  }
54 
55  ~MatrixCoo( ) {
56  matrixCooVec_.clear();
57  }
58 
59  //! Return number of non-zeros
60  IndexType nnz() const { return matrixCooVec_.size(); }
61 
62  //! Prepare matrix for assembly - allocate buffer for UNASSEMBLED entries
63  //! serial copies of element matrices to memory
64  //! length = numElements * size( elementMatrix )
65  void prepareAssembly( const IndexType length )
66  {
67  matrixCooVec_.reserve( length );
68 
69  return;
70  }
71 
72  //! Insert a value to unassembled vector
73  void insert( const IndexType i, const IndexType j, const ValueType value )
74  {
75  // combine index pair
76  IndexPair_ ip( i, j );
77 
78  // combine triples
79  Triple_ trip( ip, value );
80 
81  // insert it to buffer in any case
82  matrixCooVec_.push_back( trip );
83 
84  sorted_ = false;
85 
86  // resort if number of new unsorted entries excess a critical value
87  if ( (matrixCooVec_.size() - sortedSize_) > ALLOWED_MEM_OVERHEAD ) {
88  this -> finishAssembly();
89  }
90 
91  return;
92  }
93  //! Finalize matrix assembly - build the assembled input and truncate matrix
95  {
96  // sort entries to make sure
97  std::sort( matrixCooVec_.begin( ), matrixCooVec_.end( ), TripleLessThan_( ) );
98 
99  // combine the sorted matrix into one vector
100  typename MatrixCooVec_::const_iterator itGlobale = matrixCooVec_.end();
101 
102  typename MatrixCooVec_::const_iterator itSelectb = matrixCooVec_.begin();
103  typename MatrixCooVec_::const_iterator itSelecte = itSelectb;
104 
105  Triple_ tmpTriple;
106 
107  typename MatrixCooVec_::iterator itStore = matrixCooVec_.begin();
108 
109  // for each pair of indices
110  while (itSelectb != itGlobale) {
111 
112  // find any change in indices
113  itSelecte = std::upper_bound( itSelectb, itGlobale, *itSelectb, TripleLessThan_( ) );
114 
115  // sum values in the range
116  tmpTriple = combineTriples_ ( itSelectb, itSelecte );
117 
118  // store new
119  *itStore = tmpTriple;
120  itStore++;
121 
122  // shift ranges
123  itSelectb = itSelecte;
124  }
125 
126  // determine number of nonzeros in assembled matrix
127  unsigned nnz = std::distance( matrixCooVec_.begin( ), itStore);
128 
129  // truncate the vector from the end
130  matrixCooVec_.resize( nnz );
131 
132  // mark the amount of sorted entries
133  sortedSize_ = nnz;
134 
135  sorted_ = true;
136 
137  return;
138  }
139 
140  //! Determine number of nonzeros within a block [low,high) - used for PETSc preallocation
141  void getIntervalCounts( IndexType low, IndexType high,
142  std::vector<IndexType> & nnzRowsIn, std::vector<IndexType> & nnzRowsOut)
143  {
144  // sort entries to make sure
145  if ( not sorted_ ) {
146  this -> finishAssembly( );
147  }
148 
149  // run through all entries
150  typename MatrixCooVec_::const_iterator iter = matrixCooVec_.begin();
151  typename MatrixCooVec_::const_iterator itere = matrixCooVec_.end();
152 
153  for ( ; iter != itere; ++iter ) {
154 
155  IndexType row = (*iter).first.first;
156  IndexType col = (*iter).first.second;
157 
158  // check that it belongs to the interval
159  if ( row >= low and row < high ) {
160 
161  IndexType rowLoc = row - low;
162  // it is on my row, now where to put it
163 
164  if ( col >= low and col < high ) {
165  // it is inside the diagonal block
166  nnzRowsIn[rowLoc]++;
167  }
168  else {
169  // it is outside the diagonal block
170  nnzRowsOut[rowLoc]++;
171  }
172  }
173  }
174  }
175 
176  //! Get specific entry
177  void getEntry( IndexType index, IndexType & row, IndexType & col, ValueType & val )
178  {
179  row = matrixCooVec_[ index ].first.first;
180  col = matrixCooVec_[ index ].first.second;
181  val = matrixCooVec_[ index ].second;
182  }
183 
184  //! Zero a row and set diagonal to scalar
185  void zeroRow( const IndexType row, const ValueType factor )
186  {
187 
188  // sort entries to make sure
189  if ( not sorted_ ) {
190  this -> finishAssembly( );
191  }
192 
193  // erasing iterator
194  typename MatrixCooVec_::iterator tripEraseIter;
195  typename MatrixCooVec_::iterator tripEraseIterE;
196 
197  // find constrained row in matrix and set iterator there
198  tripEraseIter = std::lower_bound ( matrixCooVec_.begin(), matrixCooVec_.end(),
199  row, TripleRowIndexLessThan_( ) );
200 
201  // find last entry at the row
202  tripEraseIterE = std::upper_bound( tripEraseIter, matrixCooVec_.end(),
203  *tripEraseIter, TripleRowLessThan_( ) );
204 
205  // find diagonal
206  typename MatrixCooVec_::iterator tripEraseIterDiag;
207  tripEraseIterDiag = std::find_if( tripEraseIter, tripEraseIterE, TripleDiagEntry_( ) );
208 
209  // set row entries to zero
210  for ( ; tripEraseIter != tripEraseIterE; ++tripEraseIter ) {
211  (*tripEraseIter).second = static_cast< ValueType >( 0.0 );
212  }
213 
214  // put value from constraint on diagonal
215  Triple_ tmpTrip = std::make_pair( std::make_pair ( row, row ), factor );
216 
217  if ( tripEraseIterDiag != tripEraseIterE ) {
218  // diagonal entry already present
219  *tripEraseIterDiag = tmpTrip;
220  }
221  else {
222  // nothing on diagonal, add it
223  matrixCooVec_.push_back( tmpTrip );
224  sorted_ = false;
225  }
226  }
227 
228  //! Fill arrays with column indices, row pointers and values for
229  //! row-compressed data storage
231  std::vector<IndexType> & rowPtrs,
232  std::vector<ValueType> & values )
233  {
234 
235  // sort entries to make sure
236  if ( not sorted_ ) {
237  this -> finishAssembly( );
238  }
239 
240  // iterate over all elements and fill the nonzero,
241  // column index, and row pointer arrys
242  typename MatrixCooVec_::const_iterator tvIter = matrixCooVec_.begin();
243  typename MatrixCooVec_::const_iterator tvEnd = matrixCooVec_.end();
244 
245  // reserve space
246  colIndices.reserve(matrixCooVec_.size());
247  values.reserve(matrixCooVec_.size());
248 
249  unsigned nr = this -> deduceNumRows_( );
250  rowPtrs.reserve( nr + 1 );
251 
252  int previousRow = -1;
253  IndexType index = 0;
254 
255  for ( ; tvIter != tvEnd; ++tvIter ) {
256  const IndexType row = (*tvIter).first.first;
257  const IndexType col = (*tvIter).first.second;
258 
259  values.push_back( tvIter -> second );
260  colIndices.push_back( col );
261  if ( row == previousRow ) index++;
262  else rowPtrs.push_back( index++ );
263 
264  previousRow = row;
265  }
266 
267  rowPtrs.push_back( values.size() );
268 
269  return;
270  }
271 
272  //! Fill independent arrays with column indices, row pointers and values
274  std::vector<IndexType> & colIndices,
275  std::vector<ValueType> & values,
276  bool onlyUpperTriangle = false )
277  {
278 
279  // sort entries to make sure
280  if ( not sorted_ ) {
281  this -> finishAssembly( );
282  }
283 
284  // iterate over all elements and fill the nonzero,
285  // column index, and row index arrys
286  typename MatrixCooVec_::const_iterator tvIter = matrixCooVec_.begin();
287  typename MatrixCooVec_::const_iterator tvEnd = matrixCooVec_.end();
288 
289  // reserve space
290  colIndices.reserve(matrixCooVec_.size());
291  rowIndices.reserve(matrixCooVec_.size());
292  values.reserve(matrixCooVec_.size());
293 
294  for ( ; tvIter != tvEnd; ++tvIter ) {
295  const IndexType row = (*tvIter).first.first ;
296  const IndexType col = (*tvIter).first.second ;
297 
298  if ( not onlyUpperTriangle or col >= row ) {
299  values.push_back( (*tvIter).second );
300  rowIndices.push_back( row );
301  colIndices.push_back( col );
302  }
303  }
304  return;
305  }
306 
307  //! destroy all contents
308  void clear()
309  {
310  matrixCooVec_.clear();
311  // force deallocation of the vector
312  MatrixCooVec_().swap( matrixCooVec_ );
313  return;
314  }
315 
316  //! erase all contents
317  void erase()
318  {
319  // erasing iterator
320  typename MatrixCooVec_::iterator tripEraseIter = matrixCooVec_.begin( );
321  typename MatrixCooVec_::iterator tripEraseIterE = matrixCooVec_.end( );
322 
323  // loop to erase values
324  for ( ; tripEraseIter != tripEraseIterE; ++tripEraseIter ) {
325  (*tripEraseIter).second = static_cast< ValueType >(0.0);
326  }
327 
328  return;
329  }
330 
331  //! debug-output
332  std::ostream & write( std::ostream & out )
333  {
334  // sort entries to make sure
335  if ( not sorted_ ) {
336  this -> finishAssembly( );
337  }
338  typename MatrixCooVec_::const_iterator tvIter = matrixCooVec_.begin();
339  typename MatrixCooVec_::const_iterator tvEnd = matrixCooVec_.end();
340  for ( ; tvIter != tvEnd; ++tvIter ) {
341  const IndexType row = (*tvIter).first.first;
342  const IndexType col = (*tvIter).first.second;
343 
344  out << row << " " << col << " "
345  << std::setprecision(12)
346  << (*tvIter).second << std::endl;
347 
348  }
349  return out;
350  }
351 
352  //----------------------------------------------------------------------------
353  //! Compute maximal row sum (infinity-norm) of a matrix in coordinate format.
354  double infNorm()
355  {
356  // sort entries to make sure
357  if ( not sorted_ ) {
358  this -> finishAssembly( );
359  }
360  unsigned nr = this -> deduceNumRows_( );
361  std::vector<double> rowSums( nr, 0.0 );
362  typename MatrixCooVec_::const_iterator iter = matrixCooVec_.begin();
363  typename MatrixCooVec_::const_iterator last = matrixCooVec_.end();
364  for ( ; iter != last; ++iter ) {
365  const IndexType iRow = (*iter).first.first;
366  rowSums[ iRow ] += std::fabs( (*iter).second );
367  }
368 
369  return *std::max_element( rowSums.begin(), rowSums.end() );
370  }
371 
372  //--------------------------------------------------------------------------
373  //! Return Frobenius norm of matrix \f$||a_{ij}||_F=\sqrt{\sum_i\sum_j |a_{ij}|^2}\f$
374  ValueType frobeniusNorm()
375  {
376  // sort entries to make sure
377  if ( not sorted_ ) {
378  this -> finishAssembly( );
379  }
380 
381  ValueType sumOfSquares = 0.0;
382 
383  typename MatrixCooVec_::const_iterator iter = matrixCooVec_.begin();
384  typename MatrixCooVec_::const_iterator last = matrixCooVec_.end();
385  for ( ; iter != last; ++iter ) {
386 
387  ValueType val = (*iter).second;
388  sumOfSquares += val * val;
389  }
390 
391  return std::sqrt( sumOfSquares );
392  }
393 
394  //--------------------------------------------------------------------------
395  //! Get scalar suitable to be put on diagonal while fixing BC
396  //! This is the mean value of extremal entries on diagonal - the aim of this guess is to
397  //! be within the spectra of the original matrix - this value immediately corresponds to an
398  //! eigenvalue
399  double getDiagScalar( )
400  {
401 
402  ValueType val;
403  // initialize maximum and minimum
404  if ( matrixCooVec_.size() > 0 ) {
405  val = std::fabs( matrixCooVec_[0].second );
406  }
407  else {
408  val = 0.0;
409  }
410  ValueType maxVal = val;
411  ValueType minVal = val;
412  IndexType row, col;
413  for ( IndexType i = 1; i < static_cast<IndexType>( matrixCooVec_.size() ); i++ ) {
414 
415  row = matrixCooVec_[i].first.first;
416  col = matrixCooVec_[i].first.second;
417 
418  if ( row == col ) {
419  val = std::fabs( matrixCooVec_[i].second );
420 
421  // update maximum
422  if ( val > maxVal ) {
423  maxVal = val;
424  }
425 
426  // update minimum
427  if ( val < minVal ) {
428  minVal = val;
429  }
430  }
431  }
432 
433  // recommend value in between extremal absolute values along diagonal
434  ValueType scalar = ( minVal + maxVal ) / 2.0;
435 
436  return scalar;
437 
438  }
439 
440 private:
441  typedef std::pair<IndexType, IndexType> IndexPair_; //!< pair of indices
442  typedef std::pair<IndexPair_,ValueType> Triple_; //!< triple
443  typedef std::vector<Triple_> MatrixCooVec_;//!< vector of triples
444  MatrixCooVec_ matrixCooVec_;//!< matrix in coordinate format <i,j, values>
445 
446  IndexType nRows_; //!< number of rows of matrix
447  IndexType nCols_; //!< number of columns of matrix
448 
449  unsigned sortedSize_; //!< number of sorted entries
450 
451  bool sorted_; //!< state variable - is matrix sorted?
452 
453  //--------------------------------------------------------------------------
454  // private functions
455 
456  //! deduce number of rows - if it was given by user, use it, otherwise,
457  //! deduce it from the index of the last entry
458  IndexType deduceNumRows_( )
459  {
460  IndexType nr;
461 
462  if ( nRows_ > 0 ) {
463  // number of rows was given by user
464  nr = nRows_;
465  }
466  else {
467  // deduce number of rows from sorted matrix
468  nr = (*matrixCooVec_.rbegin()).first.first + 1;
469  }
470 
471  return nr;
472  }
473 
474 
475  //! returns true if the index pair of the first entry is smaller than of the second entry
476  struct TripleLessThan_ : std::binary_function< Triple_, Triple_, bool >
477  {
478  bool operator() ( Triple_ firstTriple, Triple_ secondTriple) {
479 
480  IndexPair_ firstTripleIndxPair = firstTriple.first;
481  IndexPair_ secondTripleIndxPair = secondTriple.first;
482 
483  return (firstTripleIndxPair < secondTripleIndxPair);
484  }
485  };
486 
487  //! returns true if the first entry has smaller ROW index than the second one
488  struct TripleRowLessThan_ : std::binary_function< Triple_, Triple_, bool >
489  {
490  bool operator() ( Triple_ firstTriple, Triple_ secondTriple) {
491 
492  IndexType firstRowIndex = firstTriple.first.first;
493  IndexType secondRowIndex = secondTriple.first.first;
494 
495  return (firstRowIndex < secondRowIndex);
496  }
497  };
498 
499  //! returns true if the row of an entry is smaller than a prescribed index
501  {
502  bool operator() ( Triple_ triple, IndexType row ) {
503 
504  IndexType tripleRowIndex = triple.first.first;
505 
506  return (tripleRowIndex < row);
507  }
508  };
509 
510  //! returns true if the entry is on diagonal, i.e. row == column
512  {
513  bool operator() ( Triple_ triple ) {
514 
515  IndexType tripleRowIndex = triple.first.first;
516  IndexType tripleColIndex = triple.first.second;
517 
518  return (tripleRowIndex == tripleColIndex);
519  }
520  };
521 
522  //! merge range of triples by addition
523  Triple_ combineTriples_ ( typename MatrixCooVec_::const_iterator itb, typename MatrixCooVec_::const_iterator ite ) {
524 
525  IndexPair_ tmpPair = (*itb).first;
526  ValueType val = 0.0;
527 
528  for ( ; itb != ite; ++itb) {
529  val += (*itb).second;
530  }
531 
532  Triple_ combinedTriple = std::make_pair(tmpPair, val);
533 
534  return combinedTriple;
535 
536  }
537 };
538 
539 #endif
void prepareAssembly(const IndexType length)
Definition: matrix_coo.hpp:65
void finishAssembly()
Finalize matrix assembly - build the assembled input and truncate matrix.
Definition: matrix_coo.hpp:94
double getDiagScalar()
Definition: matrix_coo.hpp:399
std::ostream & write(std::ostream &out)
debug-output
Definition: matrix_coo.hpp:332
void zeroRow(const IndexType row, const ValueType factor)
Zero a row and set diagonal to scalar.
Definition: matrix_coo.hpp:185
std::pair< IndexType, IndexType > IndexPair_
pair of indices
Definition: matrix_coo.hpp:441
Triple_ combineTriples_(typename MatrixCooVec_::const_iterator itb, typename MatrixCooVec_::const_iterator ite)
merge range of triples by addition
Definition: matrix_coo.hpp:523
void getEntry(IndexType index, IndexType &row, IndexType &col, ValueType &val)
Get specific entry.
Definition: matrix_coo.hpp:177
MatrixCoo(unsigned nRows=0, unsigned nCols=0)
Definition: matrix_coo.hpp:47
returns true if the index pair of the first entry is smaller than of the second entry ...
Definition: matrix_coo.hpp:476
void erase()
erase all contents
Definition: matrix_coo.hpp:317
IndexType nnz() const
Return number of non-zeros.
Definition: matrix_coo.hpp:60
MatrixCooVec_ matrixCooVec_
matrix in coordinate format
Definition: matrix_coo.hpp:444
bool operator()(Triple_ triple)
Definition: matrix_coo.hpp:513
bool operator()(Triple_ firstTriple, Triple_ secondTriple)
Definition: matrix_coo.hpp:490
returns true if the entry is on diagonal, i.e. row == column
Definition: matrix_coo.hpp:511
ValueType frobeniusNorm()
Return Frobenius norm of matrix .
Definition: matrix_coo.hpp:374
unsigned sortedSize_
number of sorted entries
Definition: matrix_coo.hpp:449
bool operator()(Triple_ firstTriple, Triple_ secondTriple)
Definition: matrix_coo.hpp:478
returns true if the first entry has smaller ROW index than the second one
Definition: matrix_coo.hpp:488
IndexType nRows_
number of rows of matrix
Definition: matrix_coo.hpp:446
bool sorted_
state variable - is matrix sorted?
Definition: matrix_coo.hpp:451
void insert(const IndexType i, const IndexType j, const ValueType value)
Insert a value to unassembled vector.
Definition: matrix_coo.hpp:73
std::pair< IndexPair_, ValueType > Triple_
triple
Definition: matrix_coo.hpp:442
returns true if the row of an entry is smaller than a prescribed index
Definition: matrix_coo.hpp:500
void extractArrays(std::vector< IndexType > &rowIndices, std::vector< IndexType > &colIndices, std::vector< ValueType > &values, bool onlyUpperTriangle=false)
Fill independent arrays with column indices, row pointers and values.
Definition: matrix_coo.hpp:273
void getIntervalCounts(IndexType low, IndexType high, std::vector< IndexType > &nnzRowsIn, std::vector< IndexType > &nnzRowsOut)
Determine number of nonzeros within a block [low,high) - used for PETSc preallocation.
Definition: matrix_coo.hpp:141
Temporary storage for a sparse matrix.
Definition: matrix_coo.hpp:17
double infNorm()
Compute maximal row sum (infinity-norm) of a matrix in coordinate format.
Definition: matrix_coo.hpp:354
void clear()
destroy all contents
Definition: matrix_coo.hpp:308
IndexType nCols_
number of columns of matrix
Definition: matrix_coo.hpp:447
void setCompressedRowArrays(std::vector< IndexType > &colIndices, std::vector< IndexType > &rowPtrs, std::vector< ValueType > &values)
Definition: matrix_coo.hpp:230
std::vector< Triple_ > MatrixCooVec_
vector of triples
Definition: matrix_coo.hpp:443
bool operator()(Triple_ triple, IndexType row)
Definition: matrix_coo.hpp:502
IndexType deduceNumRows_()
Definition: matrix_coo.hpp:458
#define ALLOWED_MEM_OVERHEAD
Definition: matrix_coo.hpp:4