Matrix.h
Go to the documentation of this file.
1 /*
2  This file is part of the Ristra wonton project.
3  Please see the license file at the root of this repository, or at:
4  https://github.com/laristra/wonton/blob/master/LICENSE
5 */
6 
7 #ifndef WONTON_MATRIX_H_
8 #define WONTON_MATRIX_H_
9 
10 #include <cassert>
11 #include <vector>
12 #include <array>
13 #include <iostream>
14 #include <type_traits>
15 
16 #include "wonton/support/Vector.h" // Wonton::Vector
17 #include "wonton/support/wonton.h" // Wonton::pow2
18 
24 namespace Wonton {
25 
26 static std::string ignore_msg="ignore";
27 static std::string &ignore_msg_ref(ignore_msg);
28 
29 class Matrix {
30  public:
31  Matrix() : Rows_(0), Columns_(0) {}
32 
33  Matrix(int const Rows, int const Columns) :
34  Rows_(Rows), Columns_(Columns) {
35  A_.resize(Rows_*Columns_); // uninitialized
36  }
37 
38  // Initialize to some constant value
39  explicit Matrix(int const Rows, int const Columns,
40  double initval) :
41  Rows_(Rows), Columns_(Columns) {
42  A_.resize(Rows_*Columns_);
43  for (int i = 0; i < Rows_; ++i)
44  for (int j = 0; j < Columns_; ++j)
45  A_[i*Columns_+j] = initval;
46  }
47 
48  // Initialize from vector of vectors - assume that each row vector
49  // is of the same size - if its not, then some values will be
50  // uninitialized
51 
52  explicit Matrix(std::vector<std::vector<double>> const& invals) {
53  Rows_ = invals.size();
54  Columns_ = invals[0].size();
55  A_.resize(Rows_*Columns_);
56  for (int i = 0; i < Rows_; ++i)
57  for (int j = 0; j < Columns_; ++j)
58  A_[i*Columns_+j] = invals[i][j];
59  }
60 
61  Matrix(Matrix const& M) : Rows_(M.rows()), Columns_(M.columns()) {
62  A_ = M.data();
63  }
64 
65  Matrix& operator=(Matrix const& M) {
66  Rows_ = M.rows();
67  Columns_ = M.columns();
68  A_.resize(Rows_*Columns_);
69  for (int i = 0; i < Rows_; ++i)
70  for (int j = 0; j < Columns_; ++j)
71  A_[i*Columns_+j] = M[i][j];
72 
73  is_singular_ = 0;
74 
75  return *this;
76  }
77 
79  Matrix& operator+=(const Matrix& rhs) {
80  assert((Rows_ == rhs.rows()) && (Columns_ == rhs.columns()));
81 
82  for (int i = 0; i < Rows_; ++i)
83  for (int j = 0; j < Columns_; ++j)
84  A_[i*Columns_+j] += rhs[i][j];
85 
86  is_singular_ = 0;
87 
88  return *this;
89  }
90 
92  Matrix& operator-=(const Matrix& rhs) {
93  assert((Rows_ == rhs.rows()) && (Columns_ == rhs.columns()));
94 
95  for (int i = 0; i < Rows_; ++i)
96  for (int j = 0; j < Columns_; ++j)
97  A_[i*Columns_+j] -= rhs[i][j];
98 
99  is_singular_ = 0;
100 
101  return *this;
102  }
103 
105  Matrix& operator*=(const double rhs) {
106  for (auto& a : A_) {
107  a *= rhs;
108  }
109 
110  is_singular_ = 0;
111 
112  return *this;
113  }
114 
115  // Destructor
116  ~Matrix() {}
117 
119  int rows() const {return Rows_;}
120 
122  int columns() const {return Columns_;}
123 
125  //
126  // The main utility of this operator is to facilitate the use
127  // of the [][] notation to refer to elements of the matrix
128  // Since we don't know what the host code will do with the pointer,
129  // (i.e. change values) we invalidate the singularity indicator.
130 
131  double * operator[](int const RowIndex) {
132  is_singular_ = 0;
133  return &(A_[RowIndex*Columns_]);
134  }
135 
137  //
138  // The main utility of this operator is to facilitate the use
139  // of the [][] notation to refer to elements of a const matrix
140 
141  double const * operator[](int const RowIndex) const {
142  return &(A_[RowIndex*Columns_]);
143  }
144 
146  Matrix transpose() const {
147  Matrix AT(Columns_, Rows_);
148  for (int i = 0; i < Rows_; ++i)
149  for (int j = 0; j < Columns_; ++j)
150  AT[j][i] = A_[i*Columns_+j];
151  return AT;
152  }
153 
155 
156  Matrix inverse() {
157  if (Rows_ != Columns_) {
158  std::cerr << "Matrix is not rectangular" << std::endl;
159  throw std::exception();
160  }
161 
162  Matrix Ainv(Rows_, Rows_, 0.0);
163 
164  // Create a temporary matrix with twice as many columns
165  Matrix D(Rows_, 2*Rows_);
166 
167  // Initialize the reduction matrix
168  int Rows2 = 2*Rows_;
169  for (int i = 0; i < Rows_; i++) {
170  for (int j = 0; j < Rows_; j++) {
171  D[i][j] = A_[i*Columns_+j];
172  D[i][Rows_+j] = 0.0;
173  }
174  D[i][Rows_+i] = 1.0;
175  }
176 
177  // Do the reduction
178  for (int i = 0; i < Rows_; i++) {
179  double alpha = D[i][i];
180  if (alpha == 0.0) {
181  is_singular_ = 2;
182  return Ainv;
183  }
184 
185  for (int j = 0; j < Rows2; j++)
186  D[i][j] = D[i][j]/alpha;
187 
188  for (int k = 0; k < Rows_; k++) {
189  if ((k - i) == 0)
190  continue;
191 
192  double beta = D[k][i];
193  for (int j = 0; j < Rows2; j++)
194  D[k][j] = D[k][j] - beta*D[i][j];
195  }
196  }
197  is_singular_ = 1;
198 
199  // Copy result into output matrix
200  for (int i = 0; i < Rows_; i++)
201  for (int j = 0; j < Rows_; j++)
202  Ainv[i][j] = D[i][j + Rows_];
203 
204  return Ainv;
205  }
206 
213  std::vector<double> operator*(std::vector<double> const& X) const {
214  assert(unsigned(Columns_) == X.size());
215 
216  std::vector<double> AX(Rows_);
217  for (int i = 0; i < Rows_; ++i) {
218  AX[i] = 0.0;
219  for (int j = 0; j < Columns_; ++j)
220  AX[i] += A_[i*Columns_+j]*X[j];
221  }
222  return AX;
223  }
224 
231  template<int D>
232  Vector<D> operator*(Vector<D> const& X) const {
233  assert(Rows_ == D && Columns_ == D);
234 
235  Vector<D> AX;
236  for (int i = 0; i < Rows_; ++i) {
237  AX[i] = 0.0;
238  for (int j = 0; j < Columns_; ++j)
239  AX[i] += A_[i*Columns_+j]*X[j];
240  }
241  return AX;
242  }
243 
249  Matrix operator*(Matrix const& B) const {
250  assert(Columns_ == B.rows());
251 
252  Matrix AB(Rows_, B.columns(), 0.0);
253 
254  for (int i = 0; i < Rows_; ++i)
255  for (int j = 0; j < B.columns(); ++j)
256  for (int k = 0; k < Columns_; ++k)
257  AB[i][j] += A_[i*Columns_+k]*B[k][j];
258 
259  return AB;
260  }
261 
266  const std::vector<double>& data() const { return A_; }
267 
288  Matrix solve(Matrix const& B,
289  std::string method="inverse",
290  std::string &error=ignore_msg_ref);
291 
299  int is_singular(){
300  return is_singular_;
301  }
302 
303  private:
304  int Rows_, Columns_;
305  std::vector<double> A_;
306  std::string method_;
307  int is_singular_ = 0;
308 }; // class Matrix
309 
310 // Add two matrices.
311 inline Matrix operator+(const Matrix& A, const Matrix& B) {
312  assert((A.rows() == B.rows()) && (A.columns() == B.columns()));
313 
314  Matrix Sum(A);
315  for (int i = 0; i < A.rows(); ++i)
316  for (int j = 0; j < A.columns(); ++j)
317  Sum[i][j] += B[i][j];
318 
319  return Sum;
320 }
321 
323 inline Matrix operator-(const Matrix& A, const Matrix& B) {
324  assert((A.rows() == B.rows()) && (A.columns() == B.columns()));
325 
326  Matrix Diff(A);
327  for (int i = 0; i < A.rows(); ++i)
328  for (int j = 0; j < A.columns(); ++j)
329  Diff[i][j] -= B[i][j];
330 
331  return Diff;
332 }
333 
338 inline Matrix operator*(const Matrix& A, const double& s) {
339  Matrix As(A);
340 
341  for (int i = 0; i < A.rows(); ++i)
342  for (int j = 0; j < A.columns(); ++j)
343  As[i][j] *= s;
344 
345  return As;
346 }
347 
352 inline Matrix operator*(const double& s, const Matrix& A) {
353  Matrix sA(A);
354 
355  for (int i = 0; i < A.rows(); ++i)
356  for (int j = 0; j < A.columns(); ++j)
357  sA[i][j] *= s;
358 
359  return sA;
360 }
361 
362 // Multiply the first vector by the transpose of the second vector
363 template<int D>
364 inline Matrix operator*(const Vector<D>& a, const Vector<D>& b) {
365  Matrix prod(D, D);
366  for (int i = 0; i < D; i++)
367  for (int j = 0; j < D; j++)
368  prod[i][j] = a[i]*b[j];
369  return prod;
370 }
371 
384 template<int D>
385 void solve(const Matrix& A, const Vector<D>& b, Vector<D>& x) {
386  int n = A.rows();
387  assert(n == A.columns());
388  assert(D == n);
389 
390  const std::vector<double>& a_ = A.data();
391  double s, norm;
392 
393  Matrix R(A);
394  Matrix Q(n, n, 0.0);
395  Matrix U(n, n);
396 
397  std::vector<double> y(n);
398 
399  int i, j, k, l;
400  for (i = 0; i < n; i++)
401  Q[i][i] = 1.0;
402 
403  // Find A = QR using the reflection method
404  for (i = 0; i < n - 1; i++) {
405  y[i] = R[i][i];
406  for (j = i + 1, s = 0.0; j < n; j++) {
407  y[j] = R[j][i];
408  s += pow2(R[j][i]);
409  }
410  norm = sqrt(s + pow2(y[i]));
411  assert(std::fabs(norm > std::numeric_limits<double>::epsilon()));
412  if (s == 0)
413  continue;
414 
415  y[i] -= norm;
416  norm = sqrt(s + pow2(y[i]));
417 
418  for (j = i; j < n; j++)
419  y[j] /= norm;
420 
421  // Generate U matrix
422  for (k = 0; k < n; k++)
423  for (l = 0; l < n; l++)
424  if (k < i || l < i)
425  U[k][l] = (k == l) ? 1.0 : 0.0;
426  else
427  U[k][l] = (k == l) ? 1.0 - 2.0*y[k]*y[l] : -2.0*y[k]*y[l];
428 
429  // Modify Q matrix
430  Q = Q*U;
431  // Modify R matrix
432  R = U*R;
433  }
434  // We need to confirm that the last element is nonzero
435  assert(std::fabs(R[n - 1][n - 1]) > std::numeric_limits<double>::epsilon());
436 
437  Vector<D> QTb = Q.transpose()*b;
438 
439  // Now, use the back substitution to find x
440  for (i = n - 1; i >= 0; i--) {
441  for (k = i + 1; k < n; k++)
442  QTb[i] -= R[i][k]*x[k];
443 
444  x[i] = QTb[i]/R[i][i];
445  }
446 }
447 
454 template<>
455 inline
456 void solve<1>(const Matrix& A, const Vector<1>& b, Vector<1>& x) {
457  assert(std::fabs(A[0][0]) > std::numeric_limits<double>::epsilon());
458  x[0] = b[0]/A[0][0];
459 }
460 
467 template<>
468 inline
469 void solve<2>(const Matrix& A, const Vector<2>& b, Vector<2>& x) {
470  double detA = A[0][0]*A[1][1] - A[0][1]*A[1][0];
471  assert(std::fabs(detA) > std::numeric_limits<double>::epsilon());
472 
473  x[0] = (A[1][1]*b[0] - A[0][1]*b[1])/detA;
474  x[1] = (A[0][0]*b[1] - A[1][0]*b[0])/detA;
475 }
476 
477 } // namespace Wonton
478 
479 #endif // WONTON_MATRIX_H_
Factorize a number N into D equal (or nearly equal) factors.
Definition: adaptive_refinement_mesh.h:31
std::vector< T > vector
Definition: wonton.h:285
WONTON_INLINE Point< D > operator*(const Point< D > &p, double s)
Definition: Point.h:247
const int X
Definition: Point.h:39
double pow2(double x)
Definition: wonton.h:329
WONTON_INLINE Vector< D > operator-(const Point< D > &p1, const Point< D > &p2)
Definition: Point.h:239
WONTON_INLINE Point< D > operator+(const Point< D > &p, const Vector< D > &v)
Definition: Point.h:227