3 * Copyright (C) 2006 Patrick Alken
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or (at
8 * your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include <gsl/gsl_linalg.h>
22 #include <gsl/gsl_matrix.h>
23 #include <gsl/gsl_vector.h>
26 gsl_linalg_hessenberg_decomp()
27 Compute the Householder reduction to Hessenberg form of a
28 square N-by-N matrix A.
32 See Golub & Van Loan, "Matrix Computations" (3rd ed), algorithm
35 Inputs: A - matrix to reduce
36 tau - where to store scalar factors in Householder
37 matrices; this vector must be of length N,
38 where N is the order of A
40 Return: GSL_SUCCESS unless error occurs
42 Notes: on output, the upper triangular portion of A (including
43 the diagaonal and subdiagonal) contains the Hessenberg matrix.
44 The lower triangular portion (below the subdiagonal) contains
45 the Householder vectors which can be used to construct
46 the similarity transform matrix U.
50 U = U(1) U(2) ... U(n - 2)
54 U(i) = I - tau(i) * v(i) * v(i)^t
56 and the vector v(i) is stored in column i of the matrix A
57 underneath the subdiagonal. So the first element of v(i)
58 is stored in row i + 2, column i, the second element at
59 row i + 3, column i, and so on.
61 Also note that for the purposes of computing U(i),
62 v(1:i) = 0, v(i + 1) = 1, and v(i+2:n) is what is stored in
63 column i of A beneath the subdiagonal.
67 gsl_linalg_hessenberg_decomp(gsl_matrix *A, gsl_vector *tau)
69 const size_t N = A->size1;
73 GSL_ERROR ("Hessenberg reduction requires square matrix",
76 else if (N != tau->size)
78 GSL_ERROR ("tau vector must match matrix size", GSL_EBADLEN);
87 size_t i; /* looping */
88 gsl_vector_view c, /* matrix column */
89 hv; /* householder vector */
91 double tau_i; /* beta in algorithm 7.4.2 */
93 for (i = 0; i < N - 2; ++i)
96 * make a copy of A(i + 1:n, i) and store it in the section
97 * of 'tau' that we haven't stored coefficients in yet
100 c = gsl_matrix_subcolumn(A, i, i + 1, N - i - 1);
102 hv = gsl_vector_subvector(tau, i + 1, N - (i + 1));
103 gsl_vector_memcpy(&hv.vector, &c.vector);
105 /* compute householder transformation of A(i+1:n,i) */
106 tau_i = gsl_linalg_householder_transform(&hv.vector);
108 /* apply left householder matrix (I - tau_i v v') to A */
109 m = gsl_matrix_submatrix(A, i + 1, i, N - (i + 1), N - i);
110 gsl_linalg_householder_hm(tau_i, &hv.vector, &m.matrix);
112 /* apply right householder matrix (I - tau_i v v') to A */
113 m = gsl_matrix_submatrix(A, 0, i + 1, N, N - (i + 1));
114 gsl_linalg_householder_mh(tau_i, &hv.vector, &m.matrix);
116 /* save Householder coefficient */
117 gsl_vector_set(tau, i, tau_i);
120 * store Householder vector below the subdiagonal in column
121 * i of the matrix. hv(1) does not need to be stored since
124 c = gsl_vector_subvector(&c.vector, 1, c.vector.size - 1);
125 hv = gsl_vector_subvector(&hv.vector, 1, hv.vector.size - 1);
126 gsl_vector_memcpy(&c.vector, &hv.vector);
131 } /* gsl_linalg_hessenberg_decomp() */
134 gsl_linalg_hessenberg_unpack()
135 Construct the matrix U which transforms a matrix A into
136 its upper Hessenberg form:
140 by unpacking the information stored in H from gsl_linalg_hessenberg().
142 U is a product of Householder matrices:
144 U = U(1) U(2) ... U(n - 2)
148 U(i) = I - tau(i) * v(i) * v(i)^t
150 The v(i) are stored in the lower triangular part of H by
151 gsl_linalg_hessenberg(). The tau(i) are stored in the vector tau.
153 Inputs: H - Hessenberg matrix computed from
154 gsl_linalg_hessenberg()
155 tau - tau vector computed from gsl_linalg_hessenberg()
156 U - (output) where to store similarity matrix
158 Return: success or error
162 gsl_linalg_hessenberg_unpack(gsl_matrix * H, gsl_vector * tau,
167 gsl_matrix_set_identity(U);
169 s = gsl_linalg_hessenberg_unpack_accum(H, tau, U);
172 } /* gsl_linalg_hessenberg_unpack() */
175 gsl_linalg_hessenberg_unpack_accum()
176 This routine is the same as gsl_linalg_hessenberg_unpack(), except
177 instead of storing the similarity matrix in U, it accumulates it,
180 U -> U * [ U(1) U(2) ... U(n - 2) ]
184 U -> U(1) U(2) ... U(n - 2)
186 Inputs: H - Hessenberg matrix computed from
187 gsl_linalg_hessenberg()
188 tau - tau vector computed from gsl_linalg_hessenberg()
189 V - (input/output) where to accumulate similarity matrix
191 Return: success or error
193 Notes: 1) On input, V needs to be initialized. The Householder matrices
194 are accumulated into V, so on output,
196 V_out = V_in * U(1) * U(2) * ... * U(n - 2)
198 so if you just want the product of the Householder matrices,
199 initialize V to the identity matrix before calling this
202 2) V does not have to be square, but must have the same
203 number of columns as the order of H
207 gsl_linalg_hessenberg_unpack_accum(gsl_matrix * H, gsl_vector * tau,
210 const size_t N = H->size1;
214 GSL_ERROR ("Hessenberg reduction requires square matrix",
217 else if (N != tau->size)
219 GSL_ERROR ("tau vector must match matrix size", GSL_EBADLEN);
221 else if (N != V->size2)
223 GSL_ERROR ("V matrix has wrong dimension", GSL_EBADLEN);
227 size_t j; /* looping */
228 double tau_j; /* householder coefficient */
229 gsl_vector_view c, /* matrix column */
230 hv; /* householder vector */
239 for (j = 0; j < (N - 2); ++j)
241 c = gsl_matrix_column(H, j);
243 tau_j = gsl_vector_get(tau, j);
246 * get a view to the householder vector in column j, but
247 * make sure hv(2) starts at the element below the
248 * subdiagonal, since hv(1) was never stored and is always
251 hv = gsl_vector_subvector(&c.vector, j + 1, N - (j + 1));
254 * Only operate on part of the matrix since the first
255 * j + 1 entries of the real householder vector are 0
259 * Note here that V->size1 is not necessarily equal to N
261 m = gsl_matrix_submatrix(V, 0, j + 1, V->size1, N - (j + 1));
263 /* apply right Householder matrix to V */
264 gsl_linalg_householder_mh(tau_j, &hv.vector, &m.matrix);
269 } /* gsl_linalg_hessenberg_unpack_accum() */
272 gsl_linalg_hessenberg_set_zero()
273 Zero out the lower triangular portion of the Hessenberg matrix H.
274 This is useful when Householder vectors may be stored in the lower
275 part of H, but eigenvalue solvers need some scratch space with zeros.
279 gsl_linalg_hessenberg_set_zero(gsl_matrix * H)
281 const size_t N = H->size1;
287 for (j = 0; j < N - 2; ++j)
289 for (i = j + 2; i < N; ++i)
291 gsl_matrix_set(H, i, j, 0.0);
296 } /* gsl_linalg_hessenberg_set_zero() */
299 gsl_linalg_hessenberg_submatrix()
301 This routine does the same thing as gsl_linalg_hessenberg(),
302 except that it operates on a submatrix of a larger matrix, but
303 updates the larger matrix with the Householder transformations.
307 M = [ M_{11} | M_{12} | M_{13} ]
311 where M_{11} and M_{33} are already in Hessenberg form, and we
312 just want to reduce A to Hessenberg form. Applying the transformations
313 to A alone will cause the larger matrix M to lose its similarity
314 information. So this routine updates M_{12} and M_{23} as A gets
317 Inputs: M - total matrix
318 A - (sub)matrix to reduce
319 top - row index of top of A in M
320 tau - where to store scalar factors in Householder
321 matrices; this vector must be of length N,
322 where N is the order of A
324 Return: GSL_SUCCESS unless error occurs
326 Notes: on output, the upper triangular portion of A (including
327 the diagaonal and subdiagonal) contains the Hessenberg matrix.
328 The lower triangular portion (below the subdiagonal) contains
329 the Householder vectors which can be used to construct
330 the similarity transform matrix U.
334 U = U(1) U(2) ... U(n - 2)
338 U(i) = I - tau(i) * v(i) * v(i)^t
340 and the vector v(i) is stored in column i of the matrix A
341 underneath the subdiagonal. So the first element of v(i)
342 is stored in row i + 2, column i, the second element at
343 row i + 3, column i, and so on.
345 Also note that for the purposes of computing U(i),
346 v(1:i) = 0, v(i + 1) = 1, and v(i+2:n) is what is stored in
347 column i of A beneath the subdiagonal.
351 gsl_linalg_hessenberg_submatrix(gsl_matrix *M, gsl_matrix *A, size_t top,
354 const size_t N = A->size1;
355 const size_t N_M = M->size1;
359 GSL_ERROR ("Hessenberg reduction requires square matrix",
362 else if (N != tau->size)
364 GSL_ERROR ("tau vector must match matrix size", GSL_EBADLEN);
373 size_t i; /* looping */
374 gsl_vector_view c, /* matrix column */
375 hv; /* householder vector */
377 double tau_i; /* beta in algorithm 7.4.2 */
379 for (i = 0; i < N - 2; ++i)
382 * make a copy of A(i + 1:n, i) and store it in the section
383 * of 'tau' that we haven't stored coefficients in yet
386 c = gsl_matrix_subcolumn(A, i, i + 1, N - i - 1);
388 hv = gsl_vector_subvector(tau, i + 1, N - (i + 1));
389 gsl_vector_memcpy(&hv.vector, &c.vector);
391 /* compute householder transformation of A(i+1:n,i) */
392 tau_i = gsl_linalg_householder_transform(&hv.vector);
395 * apply left householder matrix (I - tau_i v v') to
398 m = gsl_matrix_submatrix(M,
403 gsl_linalg_householder_hm(tau_i, &hv.vector, &m.matrix);
406 * apply right householder matrix (I - tau_i v v') to
411 m = gsl_matrix_submatrix(M,
416 gsl_linalg_householder_mh(tau_i, &hv.vector, &m.matrix);
418 /* save Householder coefficient */
419 gsl_vector_set(tau, i, tau_i);
422 * store Householder vector below the subdiagonal in column
423 * i of the matrix. hv(1) does not need to be stored since
426 c = gsl_vector_subvector(&c.vector, 1, c.vector.size - 1);
427 hv = gsl_vector_subvector(&hv.vector, 1, hv.vector.size - 1);
428 gsl_vector_memcpy(&c.vector, &hv.vector);
433 } /* gsl_linalg_hessenberg_submatrix() */
435 /* To support gsl-1.9 interface: DEPRECATED */
437 gsl_linalg_hessenberg(gsl_matrix *A, gsl_vector *tau)
439 return gsl_linalg_hessenberg_decomp(A, tau);