Heidelberg Educational Numerics Library Version 0.27 (from 15 March 2021)
lr.hh
Go to the documentation of this file.
1// -*- tab-width: 4; indent-tabs-mode: nil -*-
2#ifndef HDNUM_LR_HH
3#define HDNUM_LR_HH
4
5#include "vector.hh"
6#include "densematrix.hh"
7
12namespace hdnum {
13
15 template<class T>
17 {
18 if (A.rowsize()!=A.colsize() || A.rowsize()==0)
19 HDNUM_ERROR("need square and nonempty matrix");
20 if (A.rowsize()!=p.size())
21 HDNUM_ERROR("permutation vector incompatible with matrix");
22
23 // transformation to upper triangular
24 for (std::size_t k=0; k<A.rowsize()-1; ++k)
25 {
26 // find pivot element and exchange rows
27 for (std::size_t r=k; r<A.rowsize(); ++r)
28 if (A[r][k]!=0)
29 {
30 p[k] = r; // store permutation in step k
31 if (r>k) // exchange complete row if r!=k
32 for (std::size_t j=0; j<A.colsize(); ++j)
33 {
34 T temp(A[k][j]);
35 A[k][j] = A[r][j];
36 A[r][j] = temp;
37 }
38 break;
39 }
40 if (A[k][k]==0) HDNUM_ERROR("matrix is singular");
41
42 // modification
43 for (std::size_t i=k+1; i<A.rowsize(); ++i)
44 {
45 T qik(A[i][k]/A[k][k]);
46 A[i][k] = qik;
47 for (std::size_t j=k+1; j<A.colsize(); ++j)
48 A[i][j] -= qik * A[k][j];
49 }
50 }
51 }
52
54 template<class T>
55 T abs (const T& t)
56 {
57 if (t<0.0)
58 return -t;
59 else
60 return t;
61 }
62
64 template<class T>
66 {
67 if (A.rowsize()!=A.colsize() || A.rowsize()==0)
68 HDNUM_ERROR("need square and nonempty matrix");
69 if (A.rowsize()!=p.size())
70 HDNUM_ERROR("permutation vector incompatible with matrix");
71
72 // initialize permutation
73 for (std::size_t k=0; k<A.rowsize(); ++k)
74 p[k] = k;
75
76 // transformation to upper triangular
77 for (std::size_t k=0; k<A.rowsize()-1; ++k)
78 {
79 // find pivot element
80 for (std::size_t r=k+1; r<A.rowsize(); ++r)
81 if (abs(A[r][k])>abs(A[k][k]))
82 p[k] = r; // store permutation in step k
83
84 if (p[k]>k) // exchange complete row if r!=k
85 for (std::size_t j=0; j<A.colsize(); ++j)
86 {
87 T temp(A[k][j]);
88 A[k][j] = A[p[k]][j];
89 A[p[k]][j] = temp;
90 }
91
92 if (A[k][k]==0) HDNUM_ERROR("matrix is singular");
93
94 // modification
95 for (std::size_t i=k+1; i<A.rowsize(); ++i)
96 {
97 T qik(A[i][k]/A[k][k]);
98 A[i][k] = qik;
99 for (std::size_t j=k+1; j<A.colsize(); ++j)
100 A[i][j] -= qik * A[k][j];
101 }
102 }
103 }
104
106 template<class T>
108 {
109 if (A.rowsize()!=A.colsize() || A.rowsize()==0)
110 HDNUM_ERROR("need square and nonempty matrix");
111 if (A.rowsize()!=p.size())
112 HDNUM_ERROR("permutation vector incompatible with matrix");
113
114 // initialize permutation
115 for (std::size_t k=0; k<A.rowsize(); ++k)
116 p[k] = q[k] = k;
117
118 // transformation to upper triangular
119 for (std::size_t k=0; k<A.rowsize()-1; ++k)
120 {
121 // find pivot element
122 for (std::size_t r=k; r<A.rowsize(); ++r)
123 for (std::size_t s=k; s<A.colsize(); ++s)
124 if (abs(A[r][s])>abs(A[k][k]))
125 {
126 p[k] = r; // store permutation in step k
127 q[k] = s;
128 }
129
130 if (p[k]>k) // exchange complete row if r!=k
131 for (std::size_t j=0; j<A.colsize(); ++j)
132 {
133 T temp(A[k][j]);
134 A[k][j] = A[p[k]][j];
135 A[p[k]][j] = temp;
136 }
137 if (q[k]>k) // exchange complete column if s!=k
138 for (std::size_t i=0; i<A.rowsize(); ++i)
139 {
140 T temp(A[i][k]);
141 A[i][k] = A[i][q[k]];
142 A[i][q[k]] = temp;
143 }
144
145 if (std::abs(A[k][k])==0) HDNUM_ERROR("matrix is singular");
146
147 // modification
148 for (std::size_t i=k+1; i<A.rowsize(); ++i)
149 {
150 T qik(A[i][k]/A[k][k]);
151 A[i][k] = qik;
152 for (std::size_t j=k+1; j<A.colsize(); ++j)
153 A[i][j] -= qik * A[k][j];
154 }
155 }
156 }
157
159 template<class T>
161 {
162 if (b.size()!=p.size())
163 HDNUM_ERROR("permutation vector incompatible with rhs");
164
165 for (std::size_t k=0; k<b.size()-1; ++k)
166 if (p[k]!=k) std::swap(b[k],b[p[k]]);
167 }
168
170 template<class T>
172 {
173 if (z.size()!=q.size())
174 HDNUM_ERROR("permutation vector incompatible with z");
175
176 for (int k=z.size()-2; k>=0; --k)
177 if (q[k]!=std::size_t(k)) std::swap(z[k],z[q[k]]);
178 }
179
181 template<class T>
183 {
184 if (A.rowsize()*A.colsize()==0)
185 HDNUM_ERROR("need nonempty matrix");
186 if (A.rowsize()!=s.size())
187 HDNUM_ERROR("scaling vector incompatible with matrix");
188
189 // equilibrate row sums
190 for (std::size_t k=0; k<A.rowsize(); ++k)
191 {
192 s[k] = T(0.0);
193 for (std::size_t j=0; j<A.colsize(); ++j)
194 s[k] += abs(A[k][j]);
195 if (std::abs(s[k])==0) HDNUM_ERROR("row sum is zero");
196 for (std::size_t j=0; j<A.colsize(); ++j)
197 A[k][j] /= s[k];
198 }
199 }
200
202 template<class T>
204 {
205 if (s.size()!=b.size())
206 HDNUM_ERROR("s and b incompatible");
207
208 // equilibrate row sums
209 for (std::size_t k=0; k<b.size(); ++k)
210 b[k] /= s[k];
211 }
212
214 template<class T>
215 void solveL (const DenseMatrix<T>& A, Vector<T>& x, const Vector<T>& b)
216 {
217 if (A.rowsize()!=A.colsize() || A.rowsize()==0)
218 HDNUM_ERROR("need square and nonempty matrix");
219 if (A.rowsize()!=b.size())
220 HDNUM_ERROR("right hand side incompatible with matrix");
221
222 for (std::size_t i=0; i<A.rowsize(); ++i)
223 {
224 T rhs(b[i]);
225 for (std::size_t j=0; j<i; j++)
226 rhs -= A[i][j] * x[j];
227 x[i] = rhs;
228 }
229 }
230
232 template<class T>
233 void solveR (const DenseMatrix<T>& A, Vector<T>& x, const Vector<T>& b)
234 {
235 if (A.rowsize()!=A.colsize() || A.rowsize()==0)
236 HDNUM_ERROR("need square and nonempty matrix");
237 if (A.rowsize()!=b.size())
238 HDNUM_ERROR("right hand side incompatible with matrix");
239
240 for (int i=A.rowsize()-1; i>=0; --i)
241 {
242 T rhs(b[i]);
243 for (std::size_t j=i+1; j<A.colsize(); j++)
244 rhs -= A[i][j] * x[j];
245 x[i] = rhs/A[i][i];
246 }
247 }
248
250 template<class T>
252 {
253 if (A.rowsize()!=A.colsize() || A.rowsize()==0)
254 HDNUM_ERROR("need square and nonempty matrix");
255 if (A.rowsize()!=b.size())
256 HDNUM_ERROR("right hand side incompatible with matrix");
257
258 Vector<T> s(x.size());
259 Vector<std::size_t> p(x.size());
260 Vector<std::size_t> q(x.size());
261 row_equilibrate(A,s);
262 lr_fullpivot(A,p,q);
265 solveL(A,b,b);
266 solveR(A,x,b);
268 }
269
270}
271#endif
Class with mathematical matrix operations.
Definition densematrix.hh:33
size_t rowsize() const
get number of rows of the matrix
Definition densematrix.hh:136
size_t colsize() const
get number of columns of the matrix
Definition densematrix.hh:153
void permute_forward(const Vector< std::size_t > &p, Vector< T > &b)
apply permutations to a right hand side vector
Definition lr.hh:160
T abs(const T &t)
our own abs class that works also for multiprecision types
Definition lr.hh:55
void linsolve(DenseMatrix< T > &A, Vector< T > &x, Vector< T > &b)
a complete solver; Note A, x and b are modified!
Definition lr.hh:251
void lr_fullpivot(DenseMatrix< T > &A, Vector< std::size_t > &p, Vector< std::size_t > &q)
lr decomposition of A with full pivoting
Definition lr.hh:107
void permute_backward(const Vector< std::size_t > &q, Vector< T > &z)
apply permutations to a solution vector
Definition lr.hh:171
void apply_equilibrate(Vector< T > &s, Vector< T > &b)
apply row equilibration to right hand side vector
Definition lr.hh:203
void lr(DenseMatrix< T > &A, Vector< std::size_t > &p)
compute lr decomposition of A with first nonzero pivoting
Definition lr.hh:16
void solveR(const DenseMatrix< T > &A, Vector< T > &x, const Vector< T > &b)
Assume R = upper triangle of A and solve R x = b.
Definition lr.hh:233
void lr_partialpivot(DenseMatrix< T > &A, Vector< std::size_t > &p)
lr decomposition of A with column pivoting
Definition lr.hh:65
void solveL(const DenseMatrix< T > &A, Vector< T > &x, const Vector< T > &b)
Assume L = lower triangle of A with l_ii=1, solve L x = b.
Definition lr.hh:215
void row_equilibrate(DenseMatrix< T > &A, Vector< T > &s)
perform a row equilibration of a matrix; return scaling for later use
Definition lr.hh:182