OPAL (Object Oriented Parallel Accelerator Library)  2.2.0
OPAL
LUMatrix.h
Go to the documentation of this file.
1 #ifndef CLASSIC_LUMatrix_HH
2 #define CLASSIC_LUMatrix_HH
3 
4 // ------------------------------------------------------------------------
5 // $RCSfile: LUMatrix.h,v $
6 // ------------------------------------------------------------------------
7 // $Revision: 1.1.1.1 $
8 // ------------------------------------------------------------------------
9 // Copyright: see Copyright.readme
10 // ------------------------------------------------------------------------
11 //
12 // Template class: LUMatrix
13 //
14 // ------------------------------------------------------------------------
15 // Class category: Algebra
16 // ------------------------------------------------------------------------
17 //
18 // $Date: 2000/03/27 09:32:32 $
19 // $Author: fci $
20 //
21 // ------------------------------------------------------------------------
22 
23 #include "Algebra/Array1D.h"
24 #include "Algebra/Matrix.h"
26 #include "Utilities/SizeError.h"
27 #include <cmath>
28 
29 
30 // Template class LUMatrix<T>
31 // ------------------------------------------------------------------------
33 // A templated representation of a LU-decomposition.
34 // Constructed from a Matrix<T>, this class remembers the triangular
35 // decomposition and can return the back-substitution or the inverse.
36 // When LUMatrix is used on a complex matrix, then the statement
37 // [pre]
38 // include std::abs;
39 // [/pre]
40 // is required in the calling file, so as to inject the [tt]abs()[/tt]
41 // function to the global namespace.
42 
43 template <class T>
44 class LUMatrix {
45 
46 public:
47 
49  // Construct triangular decomposition of [b]m[/b].
50  // Throw [b]SingularMatrixError[/b] if the [b]m[/b] is singular.
51  explicit LUMatrix(const Matrix<T> &m);
52 
53  LUMatrix();
54  LUMatrix(const LUMatrix<T> &);
55  ~LUMatrix();
57 
59  // Perform back substitution on the vector [b]B[/b].
60  // The new [b]B[/b] is the old [b]B[/b], pre-multiplied by the inverse.
61  void backSubstitute(Vector<T> &B) const;
62 
64  // Perform back substitution on the matrix [b]M[/b].
65  // The new [b]M[/b] is the old [b]M[/b], pre-multiplied by the inverse.
66  void backSubstitute(Matrix<T> &M) const;
67 
69  // Construct and return the inverse.
70  Matrix<T> inverse() const;
71 
72 private:
73 
74  // Back substitution on iterator.
75  template <class Iterator> void backSubstitute(Iterator) const;
76 
77  // The LU-decomposed matrix.
79 
80  // The [b]index[/b] array used for LU decomposition and back substitution.
82 };
83 
84 
85 // Template function implementation.
86 // ------------------------------------------------------------------------
87 
88 template <class T>
90  decomp(), index()
91 {}
92 
93 
94 template <class T>
96  decomp(rhs.decomp), index(rhs.index)
97 {}
98 
99 
100 template <class T>
102  decomp(rhs), index(rhs.nrows()) {
103  if(rhs.nrows() != rhs.ncols()) {
104  throw SizeError("LUMatrix::LUMatrix()", "Matrix is not square.");
105  }
106 
107  // Builds the L-U decomp of a square matrix.
108  // This constructor is used in combination with backSubstitute
109  // to solve linear equations or invert a matrix.
110  int nr = rhs.nrows();
111 
112  // Scale the matrix (find largest element of each row).
113  Array1D<double> scaleVector(nr);
114  for(int i = 0; i < nr; i++) {
115  double maximum = 0.0;
116 
117  for(int j = 0; j < nr; j++) {
118  double temp = std::abs(decomp[i][j]);
119  if(temp > maximum) maximum = temp;
120  }
121 
122  if(maximum == 0.0) throw SingularMatrixError("LUMatrix::LUMatrix()");
123  scaleVector[i] = 1.0 / maximum;
124  }
125 
126  // The loop over columns of Crout's method.
127  for(int j = 0; j < nr; j++) {
128  // Eqn 2.3.12 except for j = i:
129  for(int i = 0; i < j; i++) {
130  for(int k = 0; k < i; k++) {
131  decomp[i][j] -= decomp[i][k] * decomp[k][j];
132  }
133  }
134 
135  // Initialize the search for the largest pivot element.
136  double maximum = 0.0;
137  int col_max = 0;
138 
139  // i = j of eq 2.3.12 & i = j + 1 .. N of 2.3.13.
140  for(int i = j; i < nr; i++) {
141  for(int k = 0; k < j; k++) {
142  decomp[i][j] -= decomp[i][k] * decomp[k][j];
143  }
144 
145  // Figure of merit for pivot.
146  double dum = std::abs(scaleVector[i] * decomp[i][j]);
147 
148  // Is it better than the best so far ?
149  if(dum >= maximum) {
150  col_max = i;
151  maximum = dum;
152  }
153  }
154 
155  // Do we need to interchange rows and the scale factor ?
156  if(j != col_max) {
157  decomp.swapRows(col_max, j);
158  std::swap(scaleVector[col_max], scaleVector[j]);
159  }
160 
161  index[j] = col_max;
162 
163  // Now, finally, divide by the pivot element.
164  if(j != nr - 1) {
165  T dum = T(1) / decomp[j][j];
166  for(int i = j + 1; i < nr; i++) decomp[i][j] *= dum;
167  }
168  }
169 }
170 
171 template <class T>
173 {}
174 
175 
176 template <class T>
178  decomp = rhs.decomp;
179  index = rhs.index;
180  return *this;
181 }
182 
183 
184 template <class T> template <class I> inline
185 void LUMatrix<T>::backSubstitute(I iter) const {
186  // Solves the set of linear equations A*X = B.
187  // Here "this" is the LU-decomp of the matrix A, determined by the
188  // routine LUDecompose().
189  // B is input as an iterator iter pointing the the first element of the
190  // vector B; the solution is returned in the same vector. This routine
191  // takes into account the possibility that B will begin with many zero
192  // elements, so it is efficient for use in matrix inversion.
193  // See pp 36-37 in Press & Flannery.
194 
195  int nr = decomp.nrows();
196  int ii = - 1;
197 
198  for(int i = 0; i < nr; i++) {
199  int ip = index[i];
200  T sum = iter[ip];
201  iter[ip] = iter[i];
202 
203  if(ii >= 0) {
204  for(int j = ii; j < i; j++) {
205  sum -= decomp[i][j] * iter[j];
206  }
207  } else if(sum != 0) {
208  ii = i;
209  }
210 
211  iter[i] = sum;
212  }
213 
214  for(int i = nr; i > 0;) {
215  i--;
216  T sum = iter[i];
217 
218  for(int j = i + 1; j < nr; j++) {
219  sum -= decomp[i][j] * iter[j];
220  }
221 
222  // store a component of the solution vector X.
223  iter[i] = sum / decomp[i][i];
224  }
225 }
226 
227 
228 template <class T>
230  if(B.size() != decomp.nrows()) {
231  throw SizeError("LUMatrix::backSubstitute()", "Inconsistent dimensions.");
232  }
233 
234  backSubstitute(B.begin());
235 }
236 
237 
238 template <class T>
240  if(M.nrows() != decomp.nrows()) {
241  throw SizeError("LUMatrix::backSubstitute()", "Inconsistent dimensions.");
242  }
243 
244  for(int column = 0; column < M.ncols(); column++) {
245  backSubstitute(M.col_begin(column));
246  }
247 }
248 
249 
250 template <class T>
252  int nr = decomp.nrows();
253  Matrix<T> R(nr, nr, 1.0);
254  backSubstitute(R);
255  return R;
256 }
257 
258 #endif // CLASSIC_LUMatrix_HH
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
Triangle decomposition of a matrix.
Definition: LUMatrix.h:44
Definition: rbendmap.h:8
col_iterator col_begin(int c)
Get column iterator.
Definition: Array2D.h:391
Size error exception.
Definition: SizeError.h:33
const int nr
Definition: ClassicRandom.h:24
int ncols() const
Get number of columns.
Definition: Array2D.h:307
T::PETE_Expr_t::PETE_Return_t sum(const PETE_Expr< T > &expr)
Definition: PETE.h:1213
LUMatrix< T > & operator=(const LUMatrix< T > &)
Definition: LUMatrix.h:177
Singular matrix exception.
int size() const
Get array size.
Definition: Array1D.h:228
Matrix< T > decomp
Definition: LUMatrix.h:78
LUMatrix()
Definition: LUMatrix.h:89
~LUMatrix()
Definition: LUMatrix.h:172
iterator begin()
Get beginning of data.
Definition: Array1D.h:204
Matrix< T > inverse() const
Get inverse.
Definition: LUMatrix.h:251
Matrix.
Definition: Matrix.h:38
void backSubstitute(Vector< T > &B) const
Back substitution.
Definition: LUMatrix.h:229
Vector.
int nrows() const
Get number of rows.
Definition: Array2D.h:301
Array1D< int > index
Definition: LUMatrix.h:81