omega_h
Reliable mesh adaptation
Omega_h_qr.hpp
1 #ifndef OMEGA_H_QR_HPP
2 #define OMEGA_H_QR_HPP
3 
4 #include <Omega_h_matrix.hpp>
5 
6 namespace Omega_h {
7 
8 /* Trefethen, Lloyd N., and David Bau III.
9  Numerical linear algebra. Vol. 50. SIAM, 1997.
10  Algorithm 10.1. Householder QR Factorization
11 
12  for k=1 to n
13  x = A_{k:m,k}
14  v_k = sign(x_1)\|x\|_2 e_1 + x
15  v_k = v_k / \|v_k\|_2 <- note this can divide by zero if x={0}
16  A_{k:m,k:n} = A_{k:m,k:n} - 2 v_k (v_k^* A_{k:m,k:n}) */
17 
18 template <Int max_m, Int max_n>
19 OMEGA_H_INLINE Vector<max_m> householder_vector(
20  Int m, Matrix<max_m, max_n> a, Int k) {
21  Real norm_x = 0.0;
22  for (Int i = k; i < m; ++i) norm_x += square(a[k][i]);
23  norm_x = std::sqrt(norm_x);
24  /* technically, every matrix has a QR decomposition.
25  * if norm_x is close to zero here, the matrix is rank-deficient
26  * and we could just skip this reflection and carry forward
27  * the rank information.
28  * however, all current uses of this code require the matrix
29  * to be full-rank, so we can save a bunch of bookkeeping up
30  * the stack if we simply assert this here.
31  */
32  OMEGA_H_CHECK(norm_x > 0.0);
33  Vector<max_m> v_k;
34  for (Int i = k; i < m; ++i) v_k[i] = a[k][i];
35  v_k[k] += sign(a[k][k]) * norm_x;
36  Real norm_v_k = 0.0;
37  for (Int i = k; i < m; ++i) norm_v_k += square(v_k[i]);
38  norm_v_k = std::sqrt(norm_v_k);
39  for (Int i = k; i < m; ++i) v_k[i] /= norm_v_k;
40  return v_k;
41 }
42 
43 template <Int max_m, Int max_n>
44 OMEGA_H_INLINE void reflect_columns(
45  Int m, Int n, Matrix<max_m, max_n>& a, Vector<max_m> v_k, Int k) {
46  for (Int j = k; j < n; ++j) {
47  Real dot = 0.0;
48  for (Int i = k; i < m; ++i) dot += a[j][i] * v_k[i];
49  for (Int i = k; i < m; ++i) a[j][i] -= 2.0 * dot * v_k[i];
50  }
51 }
52 
53 template <Int max_m, Int max_n>
55  Few<Vector<max_m>, max_n> v; // the householder vectors
56  Tensor<max_n> r;
57 };
58 
59 template <Int max_m, Int max_n>
60 OMEGA_H_INLINE QRFactorization<max_m, max_n> factorize_qr_householder(
61  Int m, Int n, Matrix<max_m, max_n> a) {
62  Few<Vector<max_m>, max_n> v;
63  for (Int k = 0; k < n; ++k) {
64  v[k] = householder_vector(m, a, k);
65  reflect_columns(m, n, a, v[k], k);
66  }
67  auto r = reduced_r_from_full(n, a);
68  return {v, r};
69 }
70 
71 /* Trefethen, Lloyd N., and David Bau III.
72  Numerical linear algebra. Vol. 50. SIAM, 1997.
73  Algorithm 10.2. Implicit Calculation of a Product $Q^*b$
74 
75  for k=1 to n
76  b_{k:m} = b_{k:m} - 2 v_k (v_k^* b_{k:m}) */
77 template <Int max_m, Int max_n>
78 OMEGA_H_INLINE Vector<max_n> implicit_q_trans_b(
79  Int m, Int n, Few<Vector<max_m>, max_n> v, Vector<max_m> b) {
80  for (Int k = 0; k < n; ++k) {
81  Real dot = 0.0;
82  for (Int i = k; i < m; ++i) dot += v[k][i] * b[i];
83  for (Int i = k; i < m; ++i) b[i] -= 2.0 * dot * v[k][i];
84  }
85  Vector<max_n> qtb = zero_vector<max_n>();
86  for (Int i = 0; i < n; ++i) qtb[i] = b[i];
87  return qtb;
88 }
89 
90 /* Trefethen, Lloyd N., and David Bau III.
91  Numerical linear algebra. Vol. 50. SIAM, 1997.
92  Algorithm 10.2. Implicit Calculation of a Product $Qx$
93 
94  for k=n downto 1
95  x_{k:m} = x_{k:m} - 2 v_k (v_k^* b_{k:m}) */
96 template <Int max_m, Int max_n>
97 OMEGA_H_INLINE void implicit_q_x(
98  Int m, Int n, Vector<max_m>& x, Few<Vector<max_m>, max_n> v) {
99  for (Int k2 = 0; k2 < n; ++k2) {
100  Int k = n - k2 - 1;
101  Real dot = 0;
102  for (Int i = k; i < m; ++i) dot += v[k][i] * x[i];
103  for (Int i = k; i < m; ++i) x[i] -= 2 * dot * v[k][i];
104  }
105 }
106 
107 template <Int max_m, Int max_n>
108 OMEGA_H_INLINE Tensor<max_n> reduced_r_from_full(
109  Int n, Matrix<max_m, max_n> fr) {
110  Tensor<max_n> rr;
111  for (Int j = 0; j < n; ++j)
112  for (Int i = 0; i < n; ++i) rr[j][i] = fr[j][i];
113  return rr;
114 }
115 
116 template <Int max_m>
117 OMEGA_H_INLINE Vector<max_m> solve_upper_triangular(
118  Int m, Tensor<max_m> a, Vector<max_m> b) {
119  Vector<max_m> x;
120  for (Int ii = 0; ii < m; ++ii) {
121  Int i = m - ii - 1;
122  x[i] = b[i];
123  for (Int j = i + 1; j < m; ++j) x[i] -= a[j][i] * x[j];
124  x[i] /= a[i][i];
125  }
126  return x;
127 }
128 
129 /* Trefethen, Lloyd N., and David Bau III.
130  Numerical linear algebra. Vol. 50. SIAM, 1997.
131  Algorithm 11.2 Least Squares via QR factorization
132 
133  1. Compute the reduced QR factorization A = \hat{Q}\hat{R}
134  2. Compute the vector \hat{Q}^* b
135  3. Solve the upper-triangular system \hat{R} x = \hat{Q}^* b for x */
136 template <Int max_m, Int max_n>
137 OMEGA_H_INLINE Vector<max_n> solve_using_qr(
138  Int m, Int n, Matrix<max_m, max_n> a, Vector<max_m> b) {
139  auto qr = factorize_qr_householder(m, n, a);
140  auto qtb = implicit_q_trans_b(m, n, qr.v, b);
141  auto x = solve_upper_triangular(n, qr.r, qtb);
142  return x;
143 }
144 template <Int max_m, Int max_n>
145 OMEGA_H_INLINE Vector<max_n> solve_using_qr(
146  Matrix<max_m, max_n> a, Vector<max_m> b) {
147  return solve_using_qr(max_m, max_n, a, b);
148 }
149 
150 } // end namespace Omega_h
151 
152 #endif
Definition: Omega_h_few.hpp:61
Definition: amr_mpi_test.cpp:6
Definition: Omega_h_qr.hpp:54