IFEM  90A354
matrixnd.h
Go to the documentation of this file.
1 // $Id$
2 //==============================================================================
12 //==============================================================================
13 
14 #ifndef UTL_MATRIX_ND_H
15 #define UTL_MATRIX_ND_H
16 
17 #include "matrix.h"
18 
19 
20 namespace utl
21 {
29  template<class T> class matrix3d : public matrixBase<T>
30  {
31  public:
33  matrix3d() {}
35  explicit matrix3d(vector<T>& vec) : matrixBase<T>(vec) {}
38  matrix3d(size_t n_1, size_t n_2, size_t n_3) : matrixBase<T>(n_1,n_2,n_3) {}
40  matrix3d(const matrix3d<T>& mat) : matrixBase<T>(mat) {}
42  explicit matrix3d(std::istream& is, std::streamsize max = 10)
43  {
44  // Read size
45  size_t n0 = 0, n1 = 0, n2 = 0;
46  is.ignore(10, ':');
47  is.ignore(1);
48  is >> n0 >> n1 >> n2;
49  is.ignore(1, '\n');
50 
51  // Read contents
52  this->resize(n0,n1,n2,1);
53  for (size_t k = 0; k < n2; k++) {
54  is.ignore(max, '\n');
55  for (size_t i = 0; i < n0; i++) {
56  is.ignore(max, ':');
57  for (size_t j = 0; j < n1; j++)
58  is >> this->elem[n0*(n1*k + j) + i];
59  is.ignore(1, '\n');
60  }
61  }
62  }
63 
65  virtual ~matrix3d() {}
66 
74  void resize(size_t n_1, size_t n_2, size_t n_3, bool forceClear = false)
75  {
76  this->redim(n_1,n_2,n_3,1,forceClear);
77  }
78 
81  {
82  if (&A == this)
83  return *this;
84 
85  memcpy(this->n,A.n,sizeof(A.n));
86  this->elem = A.elem;
87  return *this;
88  }
89 
92  T& operator()(size_t i1, size_t i2, size_t i3)
93  {
94  CHECK_INDEX("matrix3d::operator(): First index " ,i1,this->n[0]);
95  CHECK_INDEX("matrix3d::operator(): Second index ",i2,this->n[1]);
96  CHECK_INDEX("matrix3d::operator(): Third index " ,i3,this->n[2]);
97  return this->elem[i1-1 + this->n[0]*((i2-1) + this->n[1]*(i3-1))];
98  }
99 
102  const T& operator()(size_t i1, size_t i2, size_t i3) const
103  {
104  CHECK_INDEX("matrix3d::operator(): First index " ,i1,this->n[0]);
105  CHECK_INDEX("matrix3d::operator(): Second index ",i2,this->n[1]);
106  CHECK_INDEX("matrix3d::operator(): Third index " ,i3,this->n[2]);
107  return this->elem[i1-1 + this->n[0]*((i2-1) + this->n[1]*(i3-1))];
108  }
109 
111  vector<T> getColumn(size_t i2, size_t i3) const
112  {
113  CHECK_INDEX("matrix3d::getColumn: Second index ",i2,this->n[1]);
114  CHECK_INDEX("matrix3d::getColumn: Third index " ,i3,this->n[2]);
115  if (this->n[1] < 2 && this->n[2] < 2) return this->elem;
116  vector<T> col(this->n[0]);
117  memcpy(col.ptr(),this->ptr(i2-1+this->n[1]*(i3-1)),col.size()*sizeof(T));
118  return col;
119  }
120 
122  void fillColumn(size_t i2, size_t i3, const std::vector<T>& data)
123  {
124  CHECK_INDEX("matrix3d::fillColumn: Second index ",i2,this->n[1]);
125  CHECK_INDEX("matrix3d::fillColumn: Third index " ,i3,this->n[2]);
126  size_t ndata = this->n[0] > data.size() ? data.size() : this->n[0];
127  memcpy(this->ptr(i2-1+this->n[1]*(i3-1)),data.data(),ndata*sizeof(T));
128  }
129 
131  T trace(size_t i1) const
132  {
133  CHECK_INDEX("matrix3d::trace(): Index ",i1,this->n[0]);
134  return this->elem.sum(i1-1,this->n[0]*(this->n[1]+1));
135  }
136 
138  matrix3d<T>& operator+=(const matrix3d<T>& X) { return this->add(X); }
140  matrix3d<T>& operator-=(const matrix3d<T>& X) { return this->add(X,T(-1)); }
142  matrix3d<T>& add(const matrix3d<T>& X, T alfa = T(1))
143  {
144  return static_cast<matrix3d<T>&>(this->matrixBase<T>::add(X,alfa));
145  }
146 
149  {
150  return static_cast<matrix3d<T>&>(this->matrixBase<T>::multiply(c));
151  }
152 
160  bool multiply(const matrix<T>& A, const matrix3d<T>& B,
161  bool transA = false, bool addTo = false);
162 
173  bool multiplyMat(const std::vector<T>& A, const matrix3d<T>& B,
174  bool addTo = false);
175 
176  private:
178  bool compatible(const matrix<T>& A, const matrix3d<T>& B,
179  bool transA, size_t& M, size_t& N, size_t& K)
180  {
181  M = transA ? A.cols() : A.rows();
182  N = B.n[1]*B.n[2];
183  K = transA ? A.rows() : A.cols();
184  if (K == B.n[0]) return true;
185 
186  std::cerr <<"matrix3d::multiply: Incompatible matrices: A("
187  << A.rows() <<','<< A.cols() <<"), B("
188  << B.n[0] <<','<< B.n[1] <<','<< B.n[2] <<")\n"
189  <<" when computing C = "
190  << (transA ? "A^t":"A") <<" * B"<< std::endl;
191  ABORT_ON_INDEX_CHECK;
192  return false;
193  }
194 
197  bool compatible(const std::vector<T>& A, const matrix3d<T>& B,
198  size_t& M, size_t& N, size_t& K)
199  {
200  N = B.n[1]*B.n[2];
201  K = B.n[0];
202  M = K > 0 ? A.size() / K : 0;
203  if (M*K == A.size() && !A.empty()) return true;
204 
205  std::cerr <<"matrix3d::multiply: Incompatible matrices: A(r*c="<< A.size()
206  <<"), B("<< B.n[0] <<","<< B.n[1] <<","<< B.n[2] <<")\n"
207  <<" when computing C = A * B"<< std::endl;
208  ABORT_ON_INDEX_CHECK;
209  return false;
210  }
211 
212  protected:
214  virtual void clearIfNrowChanged(size_t n1, size_t n2, size_t)
215  {
216  if (n1 != this->n[0] || n2 != this->n[1]) this->elem.clear();
217  }
218  };
219 
220 
225  template<class T> class matrix4d : public matrixBase<T>
226  {
227  public:
229  matrix4d() {}
231  explicit matrix4d(vector<T>& vec) : matrixBase<T>(vec) {}
234  matrix4d(size_t n_1, size_t n_2, size_t n_3, size_t n_4)
235  : matrixBase<T>(n_1,n_2,n_3,n_4) {}
237  matrix4d(const matrix4d<T>& mat) : matrixBase<T>(mat) {}
238 
240  virtual ~matrix4d() {}
241 
250  void resize(size_t n_1, size_t n_2, size_t n_3, size_t n_4,
251  bool forceClear = false)
252  {
253  this->redim(n_1,n_2,n_3,n_4,forceClear);
254  }
255 
258  {
259  if (&A == this)
260  return *this;
261 
262  memcpy(this->n,A.n,sizeof(A.n));
263  this->elem = A.elem;
264  return *this;
265  }
266 
269  T& operator()(size_t i1, size_t i2, size_t i3, size_t i4)
270  {
271  CHECK_INDEX("matrix4d::operator(): First index " ,i1,this->n[0]);
272  CHECK_INDEX("matrix4d::operator(): Second index ",i2,this->n[1]);
273  CHECK_INDEX("matrix4d::operator(): Third index " ,i3,this->n[2]);
274  CHECK_INDEX("matrix4d::operator(): Fourth index ",i4,this->n[3]);
275  return this->elem[i1-1 + this->n[0]*((i2-1) + this->n[1]*((i3-1) + this->n[2]*(i4-1)))];
276  }
277 
280  const T& operator()(size_t i1, size_t i2, size_t i3, size_t i4) const
281  {
282  CHECK_INDEX("matrix4d::operator(): First index " ,i1,this->n[0]);
283  CHECK_INDEX("matrix4d::operator(): Second index ",i2,this->n[1]);
284  CHECK_INDEX("matrix4d::operator(): Third index " ,i3,this->n[2]);
285  CHECK_INDEX("matrix4d::operator(): Fourth index ",i4,this->n[3]);
286  return this->elem[i1-1 + this->n[0]*((i2-1) + this->n[1]*((i3-1) + this->n[2]*(i4-1)))];
287  }
288 
290  matrix4d<T>& operator+=(const matrix4d<T>& X) { return this->add(X); }
292  matrix4d<T>& operator-=(const matrix4d<T>& X) { return this->add(X,T(-1)); }
294  matrix4d<T>& add(const matrix4d<T>& X, T alfa = T(1))
295  {
296  return static_cast<matrix4d<T>&>(this->matrixBase<T>::add(X,alfa));
297  }
298 
301  {
302  return static_cast<matrix4d<T>&>(this->matrixBase<T>::multiply(c));
303  }
304 
306  vector<T> getColumn(size_t i2, size_t i3, size_t i4) const
307  {
308  CHECK_INDEX("matrix4d::getColumn: Second index ",i2,this->n[1]);
309  CHECK_INDEX("matrix4d::getColumn: Third index " ,i3,this->n[2]);
310  CHECK_INDEX("matrix4d::getColumn: Fourth index ",i4,this->n[3]);
311  if (this->n[1] < 2 && this->n[2] < 2 && this->n[3] < 2) return this->elem;
312  vector<T> col(this->n[0]);
313  memcpy(col.ptr(),
314  this->ptr(i2-1 + this->n[1]*((i3-1) + this->n[2]*(i4-1))),
315  col.size()*sizeof(T));
316  return col;
317  }
318 
320  void fillColumn(size_t i2, size_t i3, size_t i4, const std::vector<T>& data)
321  {
322  CHECK_INDEX("matrix4d::fillColumn: Second index ",i2,this->n[1]);
323  CHECK_INDEX("matrix4d::fillColumn: Third index " ,i3,this->n[2]);
324  CHECK_INDEX("matrix4d::fillColumn: Fourth index ",i4,this->n[3]);
325  size_t ndata = this->n[0] > data.size() ? data.size() : this->n[0];
326  memcpy(this->ptr(i2-1 + this->n[1]*((i3-1)) + this->n[2]*(i4-1)),
327  data.data(),ndata*sizeof(T));
328  }
329 
330  protected:
332  virtual void clearIfNrowChanged(size_t n1, size_t n2, size_t n3)
333  {
334  if (n1 != this->n[0] || n2 != this->n[1] || n3 != this->n[2])
335  this->elem.clear();
336  }
337  };
338 
339 
340 #ifdef HAS_BLAS
341  //============================================================================
342  //=== BLAS-implementation of the matrix/vector multiplication methods ====
343  //============================================================================
344 
345  template<> inline
346  bool matrix3d<float>::multiply(const matrix<float>& A,
347  const matrix3d<float>& B,
348  bool transA, bool addTo)
349  {
350  size_t M, N, K;
351  if (!this->compatible(A,B,transA,M,N,K)) return false;
352  if (!addTo) this->resize(M,B.n[1],B.n[2]);
353 
354  cblas_sgemm(CblasColMajor,
355  transA ? CblasTrans : CblasNoTrans, CblasNoTrans,
356  M, N, K, 1.0f,
357  A.ptr(), A.rows(),
358  B.ptr(), B.n[0],
359  addTo ? 1.0f : 0.0f,
360  this->ptr(), n[0]);
361 
362  return true;
363  }
364 
365  template<> inline
366  bool matrix3d<double>::multiply(const matrix<double>& A,
367  const matrix3d<double>& B,
368  bool transA, bool addTo)
369  {
370  size_t M, N, K;
371  if (!this->compatible(A,B,transA,M,N,K)) return false;
372  if (!addTo) this->resize(M,B.n[1],B.n[2]);
373 
374  cblas_dgemm(CblasColMajor,
375  transA ? CblasTrans : CblasNoTrans, CblasNoTrans,
376  M, N, K, 1.0,
377  A.ptr(), A.rows(),
378  B.ptr(), B.n[0],
379  addTo ? 1.0 : 0.0,
380  this->ptr(), n[0]);
381 
382  return true;
383  }
384 
385  template<> inline
386  bool matrix3d<float>::multiplyMat(const std::vector<float>& A,
387  const matrix3d<float>& B, bool addTo)
388  {
389  size_t M, N, K;
390  if (!this->compatible(A,B,M,N,K)) return false;
391  if (!addTo) this->resize(M,B.n[1],B.n[2]);
392 
393  cblas_sgemm(CblasColMajor, CblasNoTrans, CblasNoTrans,
394  M, N, K, 1.0f,
395  A.data(), M,
396  B.ptr(), B.n[0],
397  addTo ? 1.0f : 0.0f,
398  this->ptr(), n[0]);
399 
400  return true;
401  }
402 
403  template<> inline
404  bool matrix3d<double>::multiplyMat(const std::vector<double>& A,
405  const matrix3d<double>& B, bool addTo)
406  {
407  size_t M, N, K;
408  if (!this->compatible(A,B,M,N,K)) return false;
409  if (!addTo) this->resize(M,B.n[1],B.n[2]);
410 
411  cblas_dgemm(CblasColMajor, CblasNoTrans, CblasNoTrans,
412  M, N, K, 1.0,
413  A.data(), M,
414  B.ptr(), B.n[0],
415  addTo ? 1.0 : 0.0,
416  this->ptr(), n[0]);
417 
418  return true;
419  }
420 
421 #else
422  //============================================================================
423  //=== Non-BLAS inlined implementations (slow...) =========================
424  //============================================================================
425 
426  template<class T> inline
427  bool matrix3d<T>::multiply(const matrix<T>& A, const matrix3d<T>& B,
428  bool transA, bool addTo)
429  {
430  size_t M, N, K;
431  if (!this->compatible(A,B,transA,M,N,K)) return false;
432  if (!addTo) this->resize(M,B.n[1],B.n[2],true);
433 
434  for (size_t i = 1; i <= this->n[0]; i++)
435  for (size_t j = 1; j <= this->n[1]; j++)
436  for (size_t k = 1; k <= K; k++)
437  for (size_t l = 1; l <= this->n[2]; l++)
438  if (transA)
439  this->operator()(i,j,l) += A(k,i)*B(k,j,l);
440  else
441  this->operator()(i,j,l) += A(i,k)*B(k,j,l);
442 
443  return true;
444  }
445 
446  template<class T> inline
447  bool matrix3d<T>::multiplyMat(const std::vector<T>& A, const matrix3d<T>& B,
448  bool addTo)
449  {
450  size_t M, N, K;
451  if (!this->compatible(A,B,M,N,K)) return false;
452  if (!addTo) this->resize(M,B.n[1],B.n[2],true);
453 
454  for (size_t i = 1; i <= this->n[0]; i++)
455  for (size_t j = 1; j <= this->n[1]; j++)
456  for (size_t k = 1; k <= K; k++)
457  for (size_t l = 1; l <= this->n[2]; l++)
458  this->operator()(i,j,l) += A[i-1+M*(k-1)]*B(k,j,l);
459 
460  return true;
461  }
462 #endif
463 
467  template<class T> std::ostream& operator<<(std::ostream& s,
468  const matrix3d<T>& A)
469  {
470  if (A.empty())
471  return s <<" (empty)"<< std::endl;
472 
473  s <<" Dimension: "<< A.dim(1) <<" "<< A.dim(2) <<" "<< A.dim(3);
474  matrix<T> B(A.dim(1),A.dim(2));
475  const T* Aptr = A.ptr();
476  for (size_t k = 0; k < A.dim(3); k++, Aptr += B.size())
477  {
478  B.fill(Aptr);
479  if (k == 0) s <<"\n";
480  s <<"i3="<< k+1 <<":"<< B;
481  }
482 
483  return s;
484  }
485 
489  template<class T> std::ostream& operator<<(std::ostream& s,
490  const matrix4d<T>& A)
491  {
492  if (A.empty())
493  return s <<" (empty)"<< std::endl;
494 
495  s <<" Dimension: "<< A.dim(1) <<" "<< A.dim(2)
496  <<" "<< A.dim(3) <<" "<< A.dim(4);
497  matrix<T> B(A.dim(1),A.dim(2));
498  const T* Aptr = A.ptr();
499  for (size_t k = 0; k < A.dim(3); k++)
500  for (size_t l = 0; l < A.dim(4); l++, Aptr += B.size())
501  {
502  B.fill(Aptr);
503  if (k == 0 && l == 0) s <<"\n";
504  s <<"i3="<< k+1 <<", i4="<< l+1 <<":"<< B;
505  }
506 
507  return s;
508  }
509 }
510 
511 #endif
static SystemMatrix * K
Pointer to coefficient matrix A.
Definition: EigSolver.C:91
static SystemMatrix * M
Pointer to coefficient matrix B.
Definition: EigSolver.C:92
virtual bool empty() const
Checks if the matrix is empty.
Definition: SystemMatrix.h:249
Three-dimensional rectangular matrix with some algebraic operations.
Definition: matrixnd.h:30
matrix3d(size_t n_1, size_t n_2, size_t n_3)
Constructor creating a matrix of dimension .
Definition: matrixnd.h:38
matrix3d(vector< T > &vec)
Constructor using an external vector for matrix element storage.
Definition: matrixnd.h:35
matrix3d< T > & operator=(const matrix3d< T > &A)
Assignment operator.
Definition: matrixnd.h:80
const T & operator()(size_t i1, size_t i2, size_t i3) const
Index-1 based element access.
Definition: matrixnd.h:102
bool compatible(const std::vector< T > &A, const matrix3d< T > &B, size_t &M, size_t &N, size_t &K)
Check dimension compatibility for matrix-matrix multiplication, when the matrix A is represented by a...
Definition: matrixnd.h:197
void resize(size_t n_1, size_t n_2, size_t n_3, bool forceClear=false)
Resize the matrix to dimension .
Definition: matrixnd.h:74
T trace(size_t i1) const
Return the trace of the i1'th sub-matrix.
Definition: matrixnd.h:131
matrix3d< T > & operator-=(const matrix3d< T > &X)
Subtract the given matrix X from *this.
Definition: matrixnd.h:140
virtual void clearIfNrowChanged(size_t n1, size_t n2, size_t)
Clears the content if any of the first two dimensions changed.
Definition: matrixnd.h:214
matrix3d< T > & multiply(T c)
Multiplication of this matrix by a scalar c.
Definition: matrixnd.h:148
void fillColumn(size_t i2, size_t i3, const std::vector< T > &data)
Fill a column of the matrix.
Definition: matrixnd.h:122
virtual ~matrix3d()
Empty destructor.
Definition: matrixnd.h:65
matrix3d()
Constructor creating an empty matrix.
Definition: matrixnd.h:33
matrix3d(std::istream &is, std::streamsize max=10)
Constructor to read a matrix from a stream.
Definition: matrixnd.h:42
matrix3d< T > & add(const matrix3d< T > &X, T alfa=T(1))
Add the given matrix X scaled by alfa to *this.
Definition: matrixnd.h:142
matrix3d< T > & operator+=(const matrix3d< T > &X)
Add the given matrix X to *this.
Definition: matrixnd.h:138
T & operator()(size_t i1, size_t i2, size_t i3)
Index-1 based element access.
Definition: matrixnd.h:92
bool compatible(const matrix< T > &A, const matrix3d< T > &B, bool transA, size_t &M, size_t &N, size_t &K)
Check dimension compatibility for matrix-matrix multiplication.
Definition: matrixnd.h:178
bool multiplyMat(const std::vector< T > &A, const matrix3d< T > &B, bool addTo=false)
Matrix-matrix multiplication.
Definition: matrixnd.h:447
matrix3d(const matrix3d< T > &mat)
Copy constructor.
Definition: matrixnd.h:40
bool multiply(const matrix< T > &A, const matrix3d< T > &B, bool transA=false, bool addTo=false)
Matrix-matrix multiplication.
Definition: matrixnd.h:427
vector< T > getColumn(size_t i2, size_t i3) const
Extract a column from the matrix.
Definition: matrixnd.h:111
Four-dimensional rectangular matrix with some algebraic operations.
Definition: matrixnd.h:226
virtual void clearIfNrowChanged(size_t n1, size_t n2, size_t n3)
Clears the content if any of the first three dimensions changed.
Definition: matrixnd.h:332
matrix4d(size_t n_1, size_t n_2, size_t n_3, size_t n_4)
Constructor creating a matrix of dimension .
Definition: matrixnd.h:234
matrix4d< T > & operator+=(const matrix4d< T > &X)
Add the given matrix X to *this.
Definition: matrixnd.h:290
matrix4d< T > & multiply(T c)
Multiplication of this matrix by a scalar c.
Definition: matrixnd.h:300
matrix4d< T > & operator=(const matrix4d< T > &A)
Assignment operator.
Definition: matrixnd.h:257
T & operator()(size_t i1, size_t i2, size_t i3, size_t i4)
Index-1 based element access.
Definition: matrixnd.h:269
void fillColumn(size_t i2, size_t i3, size_t i4, const std::vector< T > &data)
Fill a column of the matrix.
Definition: matrixnd.h:320
void resize(size_t n_1, size_t n_2, size_t n_3, size_t n_4, bool forceClear=false)
Resize the matrix to dimension .
Definition: matrixnd.h:250
matrix4d()
Constructor creating an empty matrix.
Definition: matrixnd.h:229
virtual ~matrix4d()
Empty destructor.
Definition: matrixnd.h:240
vector< T > getColumn(size_t i2, size_t i3, size_t i4) const
Extract a column from the matrix.
Definition: matrixnd.h:306
matrix4d(vector< T > &vec)
Constructor using an external vector for matrix element storage.
Definition: matrixnd.h:231
matrix4d(const matrix4d< T > &mat)
Copy constructor.
Definition: matrixnd.h:237
matrix4d< T > & add(const matrix4d< T > &X, T alfa=T(1))
Add the given matrix X scaled by alfa to *this.
Definition: matrixnd.h:294
const T & operator()(size_t i1, size_t i2, size_t i3, size_t i4) const
Index-1 based element access.
Definition: matrixnd.h:280
matrix4d< T > & operator-=(const matrix4d< T > &X)
Subtract the given matrix X from *this.
Definition: matrixnd.h:292
Common base class for multi-dimensional (2D and 3D) matrices.
Definition: matrix.h:308
size_t n[4]
Dimension of the matrix.
Definition: matrix.h:440
size_t dim(short int d=1) const
Query dimensions.
Definition: matrix.h:376
matrixBase< T > & add(const matrixBase< T > &A, const T &alfa)
Add the given matrix A scaled by alfa to *this.
Definition: matrix.h:1584
vector< T > & elem
Actual matrix elements, stored column by column.
Definition: matrix.h:441
size_t size() const
Query total matrix size.
Definition: matrix.h:378
T * ptr(size_t c=0)
Access through pointer.
Definition: matrix.h:392
bool empty() const
Check if the matrix is empty.
Definition: matrix.h:380
void redim(size_t n_1, size_t n_2, size_t n_3, size_t n_4, bool forceClear)
Resize the matrix to dimension .
Definition: matrix.h:338
matrixBase< T > & multiply(const T &c)
Multiplication of this matrix by a scalar c.
Definition: matrix.h:1595
Two-dimensional rectangular matrix with some algebraic operations.
Definition: matrix.h:456
size_t cols() const
Query number of matrix columns.
Definition: matrix.h:560
size_t rows() const
Query number of matrix rows.
Definition: matrix.h:558
void fill(const std::vector< T > &v, size_t n, size_t m=0)
Fill the matrix with vector data.
Definition: matrix.h:628
A vector class with some added algebraic operations.
Definition: matrix.h:64
size_t size() const
Size of the vector.
Definition: matrix.h:88
T * ptr()
Access through pointer.
Definition: matrix.h:83
Simple template classes for dense rectangular matrices and vectors.
General utility classes and functions.
Definition: SIMoptions.h:22
std::ostream & operator<<(std::ostream &s, const vector< T > &X)
Print the vector X to the stream s.
Definition: matrix.h:1783