Heidelberg Educational Numerics Library Version 0.27 (from 15 March 2021)
qr.hh
Go to the documentation of this file.
1// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2/*
3 * File: qr.hh
4 * Author: Raphael Vogt <cx238@stud.uni-heidelberg.de>
5 *
6 * Created on August 30, 2020
7 */
8
9#ifndef HDNUM_QR_HH
10#define HDNUM_QR_HH
11
12#include <cmath>
13#include <utility>
14
15#include "densematrix.hh"
16#include "vector.hh"
17
22namespace hdnum {
23
52template <class T>
55
56 // for all columns except the first
57 for (int k = 1; k < Q.colsize(); k++) {
58 // orthogonalize column k against all previous
59 for (int j = 0; j < k; j++) {
60 // compute factor
61 T sum_nom(0.0);
62 T sum_denom(0.0);
63 for (int i = 0; i < Q.rowsize(); i++) {
64 sum_nom += A[i][k] * Q[i][j];
65 sum_denom += Q[i][j] * Q[i][j];
66 }
67 // modify
68 T alpha = sum_nom / sum_denom;
69 for (int i = 0; i < Q.rowsize(); i++) Q[i][k] -= alpha * Q[i][j];
70 }
71 }
72 for (int j = 0; j < Q.colsize(); j++) {
73 // compute norm of column j
74 T sum(0.0);
75 for (int i = 0; i < Q.rowsize(); i++) sum += Q[i][j] * Q[i][j];
76 sum = sqrt(sum);
77 // scale
78 for (int i = 0; i < Q.rowsize(); i++) Q[i][j] = Q[i][j] / sum;
79 }
80 return Q;
81}
82
111template <class T>
113 DenseMatrix<T> Q(A);
114
115 for (int k = 0; k < Q.colsize(); k++) {
116 // modify all later columns with column k
117 for (int j = k + 1; j < Q.colsize(); j++) {
118 // compute factor
119 T sum_nom(0.0);
120 T sum_denom(0.0);
121 for (int i = 0; i < Q.rowsize(); i++) {
122 sum_nom += Q[i][j] * Q[i][k];
123 sum_denom += Q[i][k] * Q[i][k];
124 }
125 // modify
126 T alpha = sum_nom / sum_denom;
127 for (int i = 0; i < Q.rowsize(); i++) Q[i][j] -= alpha * Q[i][k];
128 }
129 }
130 for (int j = 0; j < Q.colsize(); j++) {
131 // compute norm of column j
132 T sum(0.0);
133 for (int i = 0; i < Q.rowsize(); i++) sum += Q[i][j] * Q[i][j];
134 sum = sqrt(sum);
135 // scale
136 for (int i = 0; i < Q.rowsize(); i++) Q[i][j] = Q[i][j] / sum;
137 }
138 return Q;
139}
140
182template <class T>
184 // save matrix A, before it's replaced with Q
185 DenseMatrix<T> A(Q);
186
187 // create matrix R
189
190 // start orthogonalizing
191 for (int k = 0; k < Q.colsize(); k++) {
192 // modify all later columns with column k
193 for (int j = k + 1; j < Q.colsize(); j++) {
194 // compute factor
195 T sum_nom(0.0);
196 T sum_denom(0.0);
197 for (int i = 0; i < Q.rowsize(); i++) {
198 sum_nom += Q(i, j) * Q(i, k);
199 sum_denom += Q(i, k) * Q(i, k);
200 }
201
202 T alpha = sum_nom / sum_denom;
203 for (int i = 0; i < Q.rowsize(); i++) Q(i, j) -= alpha * Q(i, k);
204 }
205 }
206
207 // add values to R, except main diagonal
208 for (int i = 1; i < R.colsize(); i++) {
209 for (int j = 0; j < i; j++) {
210 T sum_nom(0.0);
211 T sum_l2nom(0.0);
212 for (int k = 0; k < Q.rowsize(); k++) {
213 sum_nom += A(k, i) * Q(k, j);
214 sum_l2nom += Q(k, j) * Q(k, j);
215 }
216 sum_l2nom = sqrt(sum_l2nom);
217 // add element
218 R(j, i) = sum_nom / sum_l2nom;
219 }
220 }
221
222 // add missing values and scale
223 for (int j = 0; j < Q.colsize(); j++) {
224 // compute norm of column j
225 T sum(0.0);
226 for (int i = 0; i < Q.rowsize(); i++) sum += Q(i, j) * Q(i, j);
227 sum = sqrt(sum);
228 // add main diagonal to R
229 R(j, j) = sum;
230 // scale Q
231 for (int i = 0; i < Q.rowsize(); i++) Q(i, j) = Q(i, j) / sum;
232 }
233 return R;
234}
235
277template <class T>
279 // create matrix R
281
282 // start orthogonalizing
283 for (int k = 0; k < Q.colsize(); k++) {
284 // compute norm of column k
285 T sum_denom(0.0);
286 for (int i = 0; i < Q.rowsize(); i++) {
287 sum_denom += Q(i, k) * Q(i, k);
288 }
289
290 // fill the main diagonal of R with elements
291 sum_denom = sqrt(sum_denom);
292 R(k, k) = sum_denom;
293
294 // scale column k to the main diagonal
295 for (int i = 0; i < Q.rowsize(); i++) {
296 Q(i, k) /= R(k, k);
297 }
298
299 // modify all later columns with column k
300 for (int j = k + 1; j < Q.colsize(); j++) {
301 // compute norm of column j
302 T sum_nom(0.0);
303 for (int i = 0; i < Q.rowsize(); i++) {
304 sum_nom += Q(i, k) * Q(i, j);
305 }
306 // insert missing elements to R
307 R(k, j) = sum_nom;
308
309 // orthogonalize column j
310 for (int i = 0; i < Q.rowsize(); i++) {
311 Q(i, j) -= Q(i, k) * R(k, j);
312 }
313 }
314 }
315 return R;
316}
317
381template <class T>
383 // check if permutation vector has the right size
384 if (p.size() != Q.colsize()) {
385 HDNUM_ERROR("Permutation Vector incompatible with Matrix!");
386 }
387
388 // initialize permutation vector
389 for (int i = 0; i < p.size(); i++) {
390 p[i] = i;
391 }
392
393 // initialize rank
394 rank = 0;
395
396 // save matrix A, before it's replaced with Q
397 DenseMatrix<T> A(Q);
398
399 // create Matrix R
401
402 // start orthogonalizing
403 for (int k = 0; k < Q.colsize(); k++) {
404 // find column with highest norm
405 // compute norm of column k
406 T norm_k(0.0);
407 for (int r = 0; r < Q.rowsize(); r++) {
408 norm_k += Q(r, k) * Q(r, k);
409 }
410 norm_k = sqrt(norm_k);
411
412 // compare norm of column k to the following column norms
413 for (int c = k+1; c < Q.colsize(); c++) {
414 T norm(0.0);
415 for (int r = 0; r < Q.rowsize(); r++) {
416 norm += Q(r, c) * Q(r, c);
417 }
418 norm = sqrt(norm);
419 // store permutation
420 if (norm > norm_k) {
421 p[k] = c;
422 }
423 }
424
425 // swap columns if necessary
426 if (p[k] > k) {
427 for (int r = 0; r < Q.rowsize(); r++) {
428 T temp_Q = Q(r, k);
429 Q(r, k) = Q(r, p[k]);
430 Q(r, p[k]) = temp_Q;
431 }
432 p[p[k]] = k;
433
434 // compute norm of the new column k
435 norm_k = 0;
436 for (int i = 0; i < Q.rowsize(); i++) {
437 norm_k += Q(i, k) * Q(i, k);
438 }
439 norm_k = sqrt(norm_k);
440 }
441
442 // if norm of column k > threshold -> column k is linear independent
443 if (norm_k > threshold) {
444 rank++;
445 } else {
446 break;
447 }
448
449 // modify all later columns with column k
450 for (int j = k + 1; j < Q.colsize(); j++) {
451 // compute factor
452 T sum_nom(0.0);
453 T sum_denom(0.0);
454 for (int i = 0; i < Q.rowsize(); i++) {
455 sum_nom += Q(i, j) * Q(i, k);
456 sum_denom += Q(i, k) * Q(i, k);
457 }
458
459 T alpha = sum_nom / sum_denom;
460 for (int i = 0; i < Q.rowsize(); i++) Q(i, j) -= alpha * Q(i, k);
461 }
462 }
463
464 // add values to R, except main diagonal
465 for (int i = 1; i < R.colsize(); i++) {
466 for (int j = 0; j < i; j++) {
467 T sum_nom(0.0);
468 T sum_l2nom(0.0);
469 for (int k = 0; k < Q.rowsize(); k++) {
470 sum_nom += A(k, p[i]) * Q(k, j);
471 sum_l2nom += Q(k, j) * Q(k, j);
472 }
473 sum_l2nom = sqrt(sum_l2nom);
474 // add element
475 R(j, i) = sum_nom / sum_l2nom;
476 }
477 }
478
479 // add missing values and scale
480 for (int j = 0; j < Q.colsize(); j++) {
481 // compute norm of column j
482 T sum(0.0);
483 for (int i = 0; i < Q.rowsize(); i++) sum += Q(i, j) * Q(i, j);
484 sum = sqrt(sum);
485 // add main diagonal to R
486 R(j, j) = sum;
487 // scale Q
488 for (int i = 0; i < Q.rowsize(); i++) Q(i, j) = Q(i, j) / sum;
489 }
490
491 return R;
492}
493
524template<typename T>
526 // check if permutation vector has the right size
527 if (p.size() != A.colsize()) {
528 HDNUM_ERROR("Permutation Vector incompatible with Matrix!");
529 }
530
531 // permutate the columns
532 for (int k = 0; k < p.size(); k++) {
533 if (p[k] != k) {
534 // swap column
535 for (int j=0; j < A.rowsize(); j++) {
536 T temp_A = A(j, k);
537 A(j, k) = A(j, p[k]);
538 A(j, p[k]) = temp_A;
539 }
540 // swap inside permutation vector
541 int temp_p = p[k];
542 p[k] = p[temp_p];
543 p[temp_p] = temp_p;
544 }
545 }
546}
547
548} // namespace hdnum
549
550#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
DenseMatrix< T > qr_gram_schmidt_pivoting(DenseMatrix< T > &Q, Vector< int > &p, int &rank, T threshold=0.00000000001)
computes qr decomposition using modified Gram-Schmidt and pivoting - works with all types of matrices
Definition qr.hh:382
DenseMatrix< T > modified_gram_schmidt(const DenseMatrix< T > &A)
computes orthonormal basis of Im(A) using modified Gram-Schmidt
Definition qr.hh:112
DenseMatrix< T > qr_gram_schmidt(DenseMatrix< T > &Q)
computes qr decomposition using modified Gram-Schmidt - works only with small (m>n) and square matric...
Definition qr.hh:278
DenseMatrix< T > qr_gram_schmidt_simple(DenseMatrix< T > &Q)
computes qr decomposition using modified Gram-Schmidt - works only with small (m>n) and square matric...
Definition qr.hh:183
DenseMatrix< T > gram_schmidt(const DenseMatrix< T > &A)
computes orthonormal basis of Im(A) using classical Gram-Schmidt
Definition qr.hh:53