7 #ifndef DOUBLE_SHIFT_QR_H
8 #define DOUBLE_SHIFT_QR_H
17 template <
typename Scalar =
double>
21 typedef arma::Mat<Scalar> Matrix;
22 typedef arma::Col<Scalar> Vector;
33 void compute_reflector(
const Scalar &x1,
const Scalar &x2,
const Scalar &x3,
int ind)
35 Scalar *u = ref_u.memptr() + 3 * ind;
37 if(std::abs(x1) + std::abs(x2) + std::abs(x3) <= 3 * prec)
39 u[0] = u[1] = u[2] = 0;
44 Scalar tmp = x2 * x2 + x3 * x3;
45 Scalar x1_new = x1 - ((x1 < 0) - (x1 > 0)) * std::sqrt(x1 * x1 + tmp);
46 Scalar x_norm = std::sqrt(x1_new * x1_new + tmp);
47 u[0] = x1_new / x_norm;
52 void compute_reflector(
const Scalar *x,
int ind)
54 compute_reflector(x[0], x[1], x[2], ind);
57 void compute_reflectors_from_block(Matrix &X,
int oi,
int block_size,
int start_ind)
60 const int mat_size = X.n_rows;
64 compute_reflector(0, 0, 0, start_ind);
70 Scalar *x00 = X.colptr(oi) + oi, *x01 = x00 + mat_size;
73 Scalar x = x00[0] * (x00[0] - shift_s) + x01[0] * x00[1] + shift_t;
74 Scalar y = x00[1] * (x00[0] + x01[1] - shift_s);
75 compute_reflector(x, y, 0, start_ind);
76 apply_PX(X, oi, oi, 2, mat_size - oi, start_ind);
77 apply_XP(X, 0, oi, oi + 2, 2, start_ind);
78 compute_reflector(0, 0, 0, start_ind + 1);
86 Scalar x = x00[0] * (x00[0] - shift_s) + x01[0] * x00[1] + shift_t;
87 Scalar y = x00[1] * (x00[0] + x01[1] - shift_s);
88 Scalar z = x01[2] * x00[1];
89 compute_reflector(x, y, z, start_ind);
91 apply_PX(X, oi, oi, 3, mat_size - oi, start_ind);
92 apply_XP(X, 0, oi, oi + std::min(block_size, 4), 3, start_ind);
96 for(
int i = 1; i < block_size - 2; i++)
98 compute_reflector(&X(oi + i, oi + i - 1), start_ind + i);
100 apply_PX(X, oi + i, oi + i - 1, 3, mat_size - oi - i + 1, start_ind + i);
101 apply_XP(X, 0, oi + i, oi + std::min(block_size, i + 4), 3, start_ind + i);
105 compute_reflector(X(oi + block_size - 2, oi + block_size - 3), X(oi + block_size - 1, oi + block_size - 3), 0, start_ind + block_size - 2);
107 apply_PX(X, oi + block_size - 2, oi + block_size - 3, 2, mat_size - oi - block_size + 3, start_ind + block_size - 2);
108 apply_XP(X, 0, oi + block_size - 2, oi + block_size, 2, start_ind + block_size - 2);
110 compute_reflector(0, 0, 0, start_ind + block_size - 1);
115 void apply_PX(Matrix &X,
int oi,
int oj,
int nrow,
int ncol,
int u_ind)
117 Scalar *u = ref_u.memptr() + 3 * u_ind;
119 if(std::abs(u[0]) + std::abs(u[1]) + std::abs(u[2]) <= 3 * prec)
122 const int stride = X.n_rows;
123 const Scalar u0_2 = 2 * u[0];
124 const Scalar u1_2 = 2 * u[1];
126 Scalar *xptr = X.colptr(oj) + oi;
129 for(
int i = 0; i < ncol; i++, xptr += stride)
131 Scalar tmp = u0_2 * xptr[0] + u1_2 * xptr[1];
132 xptr[0] -= tmp * u[0];
133 xptr[1] -= tmp * u[1];
136 const Scalar u2_2 = 2 * u[2];
137 for(
int i = 0; i < ncol; i++, xptr += stride)
139 Scalar tmp = u0_2 * xptr[0] + u1_2 * xptr[1] + u2_2 * xptr[2];
140 xptr[0] -= tmp * u[0];
141 xptr[1] -= tmp * u[1];
142 xptr[2] -= tmp * u[2];
149 void apply_PX(Scalar *x,
int u_ind)
151 Scalar u0 = ref_u(0, u_ind),
152 u1 = ref_u(1, u_ind),
153 u2 = ref_u(2, u_ind);
155 if(std::abs(u0) + std::abs(u1) + std::abs(u2) <= 3 * prec)
159 bool u2_is_zero = (std::abs(u2) <= prec);
160 Scalar dot2 = x[0] * u0 + x[1] * u1 + (u2_is_zero ? 0 : (x[2] * u2));
169 void apply_XP(Matrix &X,
int oi,
int oj,
int nrow,
int ncol,
int u_ind)
171 Scalar *u = ref_u.memptr() + 3 * u_ind;
173 if(std::abs(u[0]) + std::abs(u[1]) + std::abs(u[2]) <= 3 * prec)
176 int stride = X.n_rows;
177 const Scalar u0_2 = 2 * u[0];
178 const Scalar u1_2 = 2 * u[1];
179 Scalar *X0 = X.colptr(oj) + oi, *X1 = X0 + stride;
186 for(
int i = 0; i < nrow; i++)
188 Scalar tmp = u0_2 * X0[i] + u1_2 * X1[i];
193 Scalar *X2 = X1 + stride;
194 const Scalar u2_2 = 2 * u[2];
195 for(
int i = 0; i < nrow; i++)
197 Scalar tmp = u0_2 * X0[i] + u1_2 * X1[i] + u2_2 * X2[i];
208 prec(std::numeric_limits<Scalar>::epsilon()),
209 prec2(std::min(std::pow(prec, Scalar(2.0) / 3), n * prec)),
219 prec(std::numeric_limits<Scalar>::epsilon()),
220 prec2(std::min(std::pow(prec, Scalar(2.0) / 3), n * prec)),
226 void compute(
const Matrix &mat, Scalar s, Scalar t)
229 throw std::invalid_argument(
"DoubleShiftQR: matrix must be square");
232 mat_H.set_size(n, n);
235 ref_u.set_size(3, n);
242 std::vector<int> zero_ind;
243 zero_ind.reserve(n / 2);
244 zero_ind.push_back(0);
245 Scalar *Hii = mat_H.memptr();
246 for(
int i = 0; i < n - 2; i++, Hii += (n + 1))
249 if(std::abs(Hii[1]) <= prec2)
252 zero_ind.push_back(i + 1);
256 std::fill(Hii + 2, Hii + n - i, Scalar(0));
258 zero_ind.push_back(n);
260 for(std::vector<int>::size_type i = 0; i < zero_ind.size() - 1; i++)
262 int start = zero_ind[i];
263 int end = zero_ind[i + 1] - 1;
264 int block_size = end - start + 1;
266 compute_reflectors_from_block(mat_H, start, block_size, start);
275 throw std::logic_error(
"DoubleShiftQR: need to call compute() first");
282 void apply_QtY(Vector &y)
285 throw std::logic_error(
"DoubleShiftQR: need to call compute() first");
287 Scalar *y_ptr = y.memptr();
288 for(
int i = 0; i < n - 1; i++, y_ptr++)
296 void apply_YQ(Matrix &Y)
299 throw std::logic_error(
"DoubleShiftQR: need to call compute() first");
302 for(
int i = 0; i < n - 2; i++)
304 apply_XP(Y, 0, i, nrow, 3, i);
306 apply_XP(Y, 0, n - 2, nrow, 2, n - 2);
311 #endif // DOUBLE_SHIFT_QR_H