OPAL (Object Oriented Parallel Accelerator Library) 2022.1
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
43template <class T>
44class LUMatrix {
45
46public:
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
72private:
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
88template <class T>
90 decomp(), index()
91{}
92
93
94template <class T>
96 decomp(rhs.decomp), index(rhs.index)
97{}
98
99
100template <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
171template <class T>
173{}
174
175
176template <class T>
178 decomp = rhs.decomp;
179 index = rhs.index;
180 return *this;
181}
182
183
184template <class T> template <class I> inline
185void 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
228template <class T>
230 if(B.size() != decomp.nrows()) {
231 throw SizeError("LUMatrix::backSubstitute()", "Inconsistent dimensions.");
232 }
233
234 backSubstitute(B.begin());
235}
236
237
238template <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
250template <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
const int nr
Definition: ClassicRandom.h:24
T::PETE_Expr_t::PETE_Return_t sum(const PETE_Expr< T > &expr)
Definition: PETE.h:1111
PETE_TUTree< FnAbs, typename T::PETE_Expr_t > abs(const PETE_Expr< T > &l)
iterator begin()
Get beginning of data.
Definition: Array1D.h:204
int size() const
Get array size.
Definition: Array1D.h:228
int nrows() const
Get number of rows.
Definition: Array2D.h:301
col_iterator col_begin(int c)
Get column iterator.
Definition: Array2D.h:391
int ncols() const
Get number of columns.
Definition: Array2D.h:307
Triangle decomposition of a matrix.
Definition: LUMatrix.h:44
Matrix< T > decomp
Definition: LUMatrix.h:78
void backSubstitute(Iterator) const
Array1D< int > index
Definition: LUMatrix.h:81
LUMatrix()
Definition: LUMatrix.h:89
void backSubstitute(Vector< T > &B) const
Back substitution.
Definition: LUMatrix.h:229
~LUMatrix()
Definition: LUMatrix.h:172
Matrix< T > inverse() const
Get inverse.
Definition: LUMatrix.h:251
LUMatrix< T > & operator=(const LUMatrix< T > &)
Definition: LUMatrix.h:177
Matrix.
Definition: Matrix.h:39
Vector.
Definition: Vector.h:37
Singular matrix exception.
Size error exception.
Definition: SizeError.h:33