Nektar++
MatrixVectorMultiplication.cpp
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 // File: MatrixVectorMultiplication.hpp
4 //
5 // For more information, please see: http://www.nektar.info
6 //
7 // The MIT License
8 //
9 // Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
10 // Department of Aeronautics, Imperial College London (UK), and Scientific
11 // Computing and Imaging Institute, University of Utah (USA).
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a
14 // copy of this software and associated documentation files (the "Software"),
15 // to deal in the Software without restriction, including without limitation
16 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 // and/or sell copies of the Software, and to permit persons to whom the
18 // Software is furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included
21 // in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 // DEALINGS IN THE SOFTWARE.
30 //
31 // Description:
32 //
33 ///////////////////////////////////////////////////////////////////////////////
34 
35 #include <type_traits>
36 
37 #include <boost/core/ignore_unused.hpp>
38 
41 
43 
46 
53 
54 namespace Nektar
55 {
56 
57  template<typename DataType, typename LhsDataType, typename MatrixType>
58  void NekMultiplyUnspecializedMatrixType(DataType* result,
60  const DataType* rhs)
61  {
62  for(unsigned int i = 0; i < lhs.GetRows(); ++i)
63  {
64  DataType accum = DataType(0);
65  for(unsigned int j = 0; j < lhs.GetColumns(); ++j)
66  {
67  accum += lhs(i,j)*rhs[j];
68  }
69  result[i] = accum;
70  }
71  }
72 
73  template<typename DataType, typename LhsDataType, typename MatrixType>
74  void NekMultiplyDiagonalMatrix(DataType* result,
76  const DataType* rhs)
77  {
78  int n = lhs.GetRows();
79  for(unsigned int i = 0; i < n; ++i)
80  {
81  result[i] = lhs(i,i)*rhs[i];
82  }
83  }
84 
85  template<typename DataType, typename LhsDataType>
86  void NekMultiplyDiagonalMatrix(DataType* result,
88  const DataType* rhs)
89  {
90  int n = lhs.GetRows();
91  const DataType* mat_ptr = lhs.GetRawPtr();
92  Vmath::Vmul(n, mat_ptr, 1, rhs, 1, result, 1);
93  }
94 
95  template<typename LhsDataType, typename MatrixType>
98  const NekDouble* rhs,
99  typename std::enable_if<
101  {
102  boost::ignore_unused(p);
103 
104  int m = lhs.GetRows();
105  int n = lhs.GetColumns();
106  int kl = lhs.GetNumberOfSubDiagonals();
107  int ku = lhs.GetNumberOfSuperDiagonals();
108  double alpha = lhs.Scale();
109  const double* a = lhs.GetRawPtr();
110  int lda = kl + ku + 1;
111  const double* x = rhs;
112  int incx = 1;
113  double beta = 0.0;
114  double* y = result;
115  int incy = 1;
116  Blas::Dgbmv('N', m, n, kl, ku, alpha, a, lda, x, incx, beta, y, incy);
117 
118  }
119 
120  template<typename DataType, typename LhsDataType>
121  void NekMultiplyBandedMatrix(DataType* result,
123  const DataType* rhs,
124  typename std::enable_if<
126  {
127  boost::ignore_unused(result, lhs, rhs, p);
128 
129  NEKERROR(ErrorUtil::efatal, "Banded block matrix multiplication not yet implemented");
130  }
131 
132  template<typename DataType, typename LhsInnerMatrixType>
135  const NekVector<DataType>& rhs)
136  {
137  unsigned int numberOfBlockRows = lhs.GetNumberOfBlockRows();
138  unsigned int numberOfBlockColumns = lhs.GetNumberOfBlockColumns();
139  DataType* result_ptr = result.GetRawPtr();
140  const DataType* rhs_ptr = rhs.GetRawPtr();
141 
142  for(unsigned int i = 0; i < result.GetDimension(); ++i)
143  {
144  result_ptr[i] = DataType(0);
145  }
146  Array<OneD, DataType> temp(result.GetDimension());
147  DataType* temp_ptr = temp.get();
148 
149  unsigned int curResultRow = 0;
150  for(unsigned int blockRow = 0; blockRow < numberOfBlockRows; ++blockRow)
151  {
152  unsigned int rowsInBlock = lhs.GetNumberOfRowsInBlockRow(blockRow);
153 
154  if( blockRow != 0 )
155  {
156  curResultRow += lhs.GetNumberOfRowsInBlockRow(blockRow-1);
157  }
158 
159  if( rowsInBlock == 0 )
160  {
161  continue;
162  }
163 
164  DataType* resultWrapper = result_ptr + curResultRow;
165 
166  unsigned int curWrapperRow = 0;
167  for(unsigned int blockColumn = 0; blockColumn < numberOfBlockColumns; ++blockColumn)
168  {
169  if( blockColumn != 0 )
170  {
171  curWrapperRow += lhs.GetNumberOfColumnsInBlockColumn(blockColumn-1);
172  }
173 
174  //const std::shared_ptr<const LhsInnerMatrixType>& block = lhs.GetBlock(blockRow, blockColumn);
175  const LhsInnerMatrixType* block = lhs.GetBlockPtr(blockRow, blockColumn);
176  if( !block )
177  {
178  continue;
179  }
180 
181  unsigned int columnsInBlock = lhs.GetNumberOfColumnsInBlockColumn(blockColumn);
182  if( columnsInBlock == 0 )
183  {
184  continue;
185  }
186 
187  const DataType* rhsWrapper = rhs_ptr + curWrapperRow;
188  Multiply(temp_ptr, *block, rhsWrapper);
189  for(unsigned int i = 0; i < rowsInBlock; ++i)
190  {
191  resultWrapper[i] += temp_ptr[i];
192  }
193  }
194  }
195  }
196 
197  template<typename LhsInnerMatrixType>
200  const NekVector<double>& rhs)
201  {
202  unsigned int numberOfBlockRows = lhs.GetNumberOfBlockRows();
203  double* result_ptr = result.GetRawPtr();
204  const double* rhs_ptr = rhs.GetRawPtr();
205 
206  Array<OneD, unsigned int> rowSizes;
207  Array<OneD, unsigned int> colSizes;
208  lhs.GetBlockSizes(rowSizes, colSizes);
209 
210  unsigned int curResultRow = 0;
211  unsigned int curWrapperRow = 0;
212  unsigned int rowsInBlock = 0;
213  unsigned int columnsInBlock = 0;
214  for(unsigned int blockRow = 0; blockRow < numberOfBlockRows; ++blockRow)
215  {
216  curResultRow += rowsInBlock;
217  curWrapperRow += columnsInBlock;
218  if ( blockRow == 0)
219  {
220  rowsInBlock = rowSizes[blockRow] + 1;
221  columnsInBlock = colSizes[blockRow] + 1;
222  }
223  else
224  {
225  rowsInBlock = rowSizes[blockRow] - rowSizes[blockRow-1];
226  columnsInBlock = colSizes[blockRow] - colSizes[blockRow-1];
227  }
228 
229  if( rowsInBlock == 0)
230  {
231  continue;
232  }
233  if( columnsInBlock == 0)
234  {
235  std::fill(result.begin()+curResultRow,
236  result.begin()+curResultRow + rowsInBlock, 0.0);
237  continue;
238  }
239 
240  const LhsInnerMatrixType* block = lhs.GetBlockPtr(blockRow, blockRow);
241  if( !block )
242  {
243  continue;
244  }
245 
246  double* resultWrapper = result_ptr + curResultRow;
247  const double* rhsWrapper = rhs_ptr + curWrapperRow;
248  Multiply(resultWrapper, *block, rhsWrapper);
249  //resultWrapper = (*block)*rhsWrapper;
250  }
251  curResultRow += rowsInBlock;
252  if (curResultRow < result.GetRows())
253  {
254  std::fill(result.begin()+curResultRow, result.end(), 0.0);
255  }
256  }
257 
259  const NekMatrix<NekMatrix<NekMatrix<NekDouble, StandardMatrixTag>, ScaledMatrixTag>, BlockMatrixTag>& lhs,
260  const NekVector<double>& rhs)
261  {
262  unsigned int numberOfBlockRows = lhs.GetNumberOfBlockRows();
263  double* result_ptr = result.GetRawPtr();
264  const double* rhs_ptr = rhs.GetRawPtr();
265 
266  Array<OneD, unsigned int> rowSizes;
267  Array<OneD, unsigned int> colSizes;
268  lhs.GetBlockSizes(rowSizes, colSizes);
269 
270  unsigned int curResultRow = 0;
271  unsigned int curWrapperRow = 0;
272  unsigned int rowsInBlock = 0;
273  unsigned int columnsInBlock = 0;
274  for(unsigned int blockRow = 0; blockRow < numberOfBlockRows; ++blockRow)
275  {
276  curResultRow += rowsInBlock;
277  curWrapperRow += columnsInBlock;
278  if ( blockRow == 0)
279  {
280  rowsInBlock = rowSizes[blockRow] + 1;
281  columnsInBlock = colSizes[blockRow] + 1;
282  }
283  else
284  {
285  rowsInBlock = rowSizes[blockRow] - rowSizes[blockRow-1];
286  columnsInBlock = colSizes[blockRow] - colSizes[blockRow-1];
287  }
288 
289  if( rowsInBlock == 0)
290  {
291  continue;
292  }
293  if( columnsInBlock == 0)
294  {
295  std::fill(result.begin()+curResultRow,
296  result.begin()+curResultRow + rowsInBlock, 0.0);
297  continue;
298  }
299 
300  const DNekScalMat* block = lhs.GetBlockPtr(blockRow, blockRow);
301  if( !block )
302  {
303  continue;
304  }
305 
306  double* resultWrapper = result_ptr + curResultRow;
307  const double* rhsWrapper = rhs_ptr + curWrapperRow;
308 
309  // Multiply
310  const unsigned int* size = block->GetSize();
311  Blas::Dgemv('N', size[0], size[1], block->Scale(),
312  block->GetRawPtr(), size[0], rhsWrapper, 1,
313  0.0, resultWrapper, 1);
314  }
315  curResultRow += rowsInBlock;
316  if (curResultRow < result.GetRows())
317  {
318  std::fill(result.begin()+curResultRow, result.end(), 0.0);
319  }
320  }
321 
324  const NekDouble* rhs)
325  {
326  int vectorSize = lhs.GetColumns();
327  std::copy(rhs, rhs+vectorSize, result);
328  int n = lhs.GetRows();
329  const double* a = lhs.GetRawPtr();
330  double* x = result;
331  int incx = 1;
332 
333  Blas::Dtpmv('L', lhs.GetTransposeFlag(), 'N', n, a, x, incx);
334  }
335 
337  const NekMatrix<NekMatrix<NekDouble, StandardMatrixTag>, ScaledMatrixTag>& lhs,
338  const NekDouble* rhs)
339  {
340  NekMultiplyLowerTriangularMatrix(result, *lhs.GetOwnedMatrix(), rhs);
341 
342  for(unsigned int i = 0; i < lhs.GetColumns(); ++i)
343  {
344  result[i] *= lhs.Scale();
345  }
346  }
347 
348  template<typename DataType, typename LhsDataType, typename MatrixType>
349  void NekMultiplyLowerTriangularMatrix(DataType* result,
351  const DataType* rhs)
352  {
353  for(unsigned int i = 0; i < lhs.GetRows(); ++i)
354  {
355  DataType accum = DataType(0);
356  for(unsigned int j = 0; j <= i; ++j)
357  {
358  accum += lhs(i,j)*rhs[j];
359  }
360  result[i] = accum;
361  }
362  }
363 
366  const NekDouble* rhs)
367  {
368  int vectorSize = lhs.GetColumns();
369  std::copy(rhs, rhs+vectorSize, result);
370  int n = lhs.GetRows();
371  const double* a = lhs.GetRawPtr();
372  double* x = result;
373  int incx = 1;
374 
375  Blas::Dtpmv('U', lhs.GetTransposeFlag(), 'N', n, a, x, incx);
376  }
377 
379  const NekMatrix<NekMatrix<NekDouble, StandardMatrixTag>, ScaledMatrixTag>& lhs,
380  const NekDouble* rhs)
381  {
382  NekMultiplyUpperTriangularMatrix(result, *lhs.GetOwnedMatrix(), rhs);
383 
384  for(unsigned int i = 0; i < lhs.GetColumns(); ++i)
385  {
386  result[i] *= lhs.Scale();
387  }
388  }
389 
390  template<typename DataType, typename LhsDataType, typename MatrixType>
391  void NekMultiplyUpperTriangularMatrix(DataType* result,
393  const DataType* rhs)
394  {
395  for(unsigned int i = 0; i < lhs.GetRows(); ++i)
396  {
397  DataType accum = DataType(0);
398  for(unsigned int j = i; j < lhs.GetColumns(); ++j)
399  {
400  accum += lhs(i,j)*rhs[j];
401  }
402  result[i] = accum;
403  }
404  }
405 
406  template<typename InnerMatrixType, typename MatrixTag>
408  typename std::enable_if<CanGetRawPtr<NekMatrix<InnerMatrixType, MatrixTag> >::value >::type* p=0)
409  {
410  boost::ignore_unused(p);
411 
412  const unsigned int* size = lhs.GetSize();
413 
414  double alpha = lhs.Scale();
415  const double* a = lhs.GetRawPtr();
416  const double* x = rhs;
417  int incx = 1;
418  double beta = 0.0;
419  double* y = result;
420  int incy = 1;
421 
422  Blas::Dspmv('U', size[0], alpha, a, x, incx, beta, y, incy);
423  }
424 
425  template<typename InnerMatrixType, typename MatrixTag>
427  typename std::enable_if<!CanGetRawPtr<NekMatrix<InnerMatrixType, MatrixTag> >::value >::type* p = 0)
428  {
429  boost::ignore_unused(p);
430 
431  NekMultiplyUnspecializedMatrixType(result, lhs, rhs);
432  }
433 
434  template<typename InnerMatrixType, typename MatrixTag>
436  typename std::enable_if<CanGetRawPtr<NekMatrix<InnerMatrixType, MatrixTag> >::value >::type* p=0)
437  {
438  boost::ignore_unused(p);
439 
440  const unsigned int* size = lhs.GetSize();
441 
442  char t = lhs.GetTransposeFlag();
443 
444  double alpha = lhs.Scale();
445  const double* a = lhs.GetRawPtr();
446  int lda = size[0];
447  const double* x = rhs;
448  int incx = 1;
449  double beta = 0.0;
450  double* y = result;
451  int incy = 1;
452 
453  Blas::Dgemv(t, size[0], size[1], alpha, a, lda, x, incx, beta, y, incy);
454  }
455 
456  template<typename InnerMatrixType, typename MatrixTag>
458  typename std::enable_if<!CanGetRawPtr<NekMatrix<InnerMatrixType, MatrixTag> >::value>::type* p = 0)
459  {
460  boost::ignore_unused(p);
461 
462  NekMultiplyUnspecializedMatrixType(result, lhs, rhs);
463  }
464 
465  template<typename DataType, typename LhsDataType, typename MatrixType>
466  void Multiply(DataType* result,
468  const DataType* rhs)
469  {
470  switch(lhs.GetType())
471  {
472  case eFULL:
473  NekMultiplyFullMatrix(result, lhs, rhs);
474  break;
475  case eDIAGONAL:
476  NekMultiplyDiagonalMatrix(result, lhs, rhs);
477  break;
478  case eUPPER_TRIANGULAR:
479  NekMultiplyUpperTriangularMatrix(result, lhs, rhs);
480  break;
481  case eLOWER_TRIANGULAR:
482  NekMultiplyLowerTriangularMatrix(result, lhs, rhs);
483  break;
484  case eSYMMETRIC:
485  NekMultiplySymmetricMatrix(result, lhs, rhs);
486  break;
487  case eBANDED:
488  NekMultiplyBandedMatrix(result, lhs, rhs);
489  break;
490  case eSYMMETRIC_BANDED:
493  default:
494  NekMultiplyUnspecializedMatrixType(result, lhs, rhs);
495  }
496  }
497 
498  template<typename DataType, typename LhsDataType, typename MatrixType>
501  const NekVector<DataType>& rhs)
502  {
503 
504  ASSERTL1(lhs.GetColumns() == rhs.GetRows(), std::string("A left side matrix with column count ") +
505  std::to_string(lhs.GetColumns()) +
506  std::string(" and a right side vector with row count ") +
507  std::to_string(rhs.GetRows()) + std::string(" can't be multiplied."));
508  Multiply(result.GetRawPtr(), lhs, rhs.GetRawPtr());
509  }
510 
512 
513  template<typename DataType, typename LhsInnerMatrixType>
516  const NekVector<DataType>& rhs)
517  {
518  if( lhs.GetStorageType() == eDIAGONAL )
519  {
520  DiagonalBlockMatrixMultiply(result, lhs, rhs);
521  }
522  else
523  {
524  FullBlockMatrixMultiply(result, lhs, rhs);
525  }
526  }
527 
529 
530  template<typename DataType, typename LhsDataType, typename MatrixType>
533  const NekVector<DataType>& rhs)
534  {
535  NekVector<DataType> result(lhs.GetRows(), DataType(0));
536  Multiply(result, lhs, rhs);
537  return result;
538  }
539 
541 
542 
543 }
void NekMultiplyUpperTriangularMatrix(NekDouble *result, const NekMatrix< NekDouble, StandardMatrixTag > &lhs, const NekDouble *rhs)
void NekMultiplyBandedMatrix(NekDouble *result, const NekMatrix< LhsDataType, MatrixType > &lhs, const NekDouble *rhs, typename std::enable_if< CanGetRawPtr< NekMatrix< LhsDataType, MatrixType > >::value >::type *p=0)
void FullBlockMatrixMultiply(NekVector< DataType > &result, const NekMatrix< LhsInnerMatrixType, BlockMatrixTag > &lhs, const NekVector< DataType > &rhs)
iterator begin()
Definition: NekVector.cpp:239
#define NEKERROR(type, msg)
Assert Level 0 – Fundamental assert which is used whether in FULLDEBUG, DEBUG or OPT compilation mod...
Definition: ErrorUtil.hpp:209
void DiagonalBlockFullScalMatrixMultiply(NekVector< double > &result, const NekMatrix< NekMatrix< NekMatrix< NekDouble, StandardMatrixTag >, ScaledMatrixTag >, BlockMatrixTag > &lhs, const NekVector< double > &rhs)
#define NEKTAR_STANDARD_AND_SCALED_MATRICES
void NekMultiplyUnspecializedMatrixType(DataType *result, const NekMatrix< LhsDataType, MatrixType > &lhs, const DataType *rhs)
def copy(self)
Definition: pycml.py:2663
StandardMatrixTag & lhs
static void Dspmv(const char &uplo, const int &n, const double &alpha, const double *a, const double *x, const int &incx, const double &beta, double *y, const int &incy)
BLAS level 2: Matrix vector multiply y = A x where A is symmetric packed.
Definition: Blas.hpp:195
void Multiply(NekMatrix< ResultDataType, StandardMatrixTag > &result, const NekMatrix< LhsDataType, LhsMatrixType > &lhs, const ResultDataType &rhs)
DataType * GetRawPtr()
Definition: NekVector.cpp:221
static void Dgbmv(const char &trans, const int &m, const int &n, const int &kl, const int &ku, const double &alpha, const double *a, const int &lda, const double *x, const int &incx, const double &beta, double *y, const int &incy)
Definition: Blas.hpp:176
void NekMultiplyFullMatrix(NekDouble *result, const NekMatrix< InnerMatrixType, MatrixTag > &lhs, const NekDouble *rhs, typename std::enable_if< CanGetRawPtr< NekMatrix< InnerMatrixType, MatrixTag > >::value >::type *p=0)
double NekDouble
static void Dgemv(const char &trans, const int &m, const int &n, const double &alpha, const double *a, const int &lda, const double *x, const int &incx, const double &beta, double *y, const int &incy)
BLAS level 2: Matrix vector multiply y = A x where A[m x n].
Definition: Blas.hpp:168
void NekMultiplySymmetricMatrix(NekDouble *result, const NekMatrix< InnerMatrixType, MatrixTag > &lhs, const NekDouble *rhs, typename std::enable_if< CanGetRawPtr< NekMatrix< InnerMatrixType, MatrixTag > >::value >::type *p=0)
void NekMultiplyLowerTriangularMatrix(NekDouble *result, const NekMatrix< NekDouble, StandardMatrixTag > &lhs, const NekDouble *rhs)
static void Dtpmv(const char &uplo, const char &trans, const char &diag, const int &n, const double *ap, double *x, const int &incx)
Definition: Blas.hpp:187
iterator end()
Definition: NekVector.cpp:242
NEKTAR_GENERATE_EXPLICIT_FUNCTION_INSTANTIATION_SINGLE_MATRIX(Multiply, NEKTAR_ALL_MATRIX_TYPES,(1,(void)),(1,(DNekMat &)),(1,(const NekDouble &))) template< typename DataType
unsigned int GetDimension() const
Returns the number of dimensions for the point.
Definition: NekVector.cpp:209
StandardMatrixTag boost::call_traits< LhsDataType >::const_reference rhs
unsigned int GetRows() const
Definition: NekVector.cpp:215
void NekMultiplyDiagonalMatrix(DataType *result, const NekMatrix< LhsDataType, MatrixType > &lhs, const DataType *rhs)
#define ASSERTL1(condition, msg)
Assert Level 1 – Debugging which is used whether in FULLDEBUG or DEBUG compilation mode...
Definition: ErrorUtil.hpp:250
void DiagonalBlockMatrixMultiply(NekVector< double > &result, const NekMatrix< LhsInnerMatrixType, BlockMatrixTag > &lhs, const NekVector< double > &rhs)
#define NEKTAR_BLOCK_MATRIX_TYPES
void Vmul(int n, const T *x, const int incx, const T *y, const int incy, T *z, const int incz)
Multiply vector z = x*y.
Definition: Vmath.cpp:186