3 * Copyright (C) 2004, 2007 Brian Gough, Gerard Jungman
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.
22 #include <gsl/gsl_math.h>
23 #include <gsl/gsl_vector.h>
24 #include <gsl/gsl_matrix.h>
25 #include <gsl/gsl_eigen.h>
27 /* Algorithm 8.4.3 - Cyclic Jacobi. Golub & Van Loan, Matrix Computations */
30 symschur2 (gsl_matrix * A, size_t p, size_t q, double *c, double *s)
32 double Apq = gsl_matrix_get (A, p, q);
36 double App = gsl_matrix_get (A, p, p);
37 double Aqq = gsl_matrix_get (A, q, q);
38 double tau = (Aqq - App) / (2.0 * Apq);
43 t = 1.0 / (tau + hypot (1.0, tau));
47 t = -1.0 / (-tau + hypot (1.0, tau));
50 c1 = 1.0 / hypot (1.0, t);
61 /* reduction in off(A) is 2*(A_pq)^2 */
67 apply_jacobi_L (gsl_matrix * A, size_t p, size_t q, double c, double s)
70 const size_t N = A->size2;
72 /* Apply rotation to matrix A, A' = J^T A */
74 for (j = 0; j < N; j++)
76 double Apj = gsl_matrix_get (A, p, j);
77 double Aqj = gsl_matrix_get (A, q, j);
78 gsl_matrix_set (A, p, j, Apj * c - Aqj * s);
79 gsl_matrix_set (A, q, j, Apj * s + Aqj * c);
84 apply_jacobi_R (gsl_matrix * A, size_t p, size_t q, double c, double s)
87 const size_t M = A->size1;
89 /* Apply rotation to matrix A, A' = A J */
91 for (i = 0; i < M; i++)
93 double Aip = gsl_matrix_get (A, i, p);
94 double Aiq = gsl_matrix_get (A, i, q);
95 gsl_matrix_set (A, i, p, Aip * c - Aiq * s);
96 gsl_matrix_set (A, i, q, Aip * s + Aiq * c);
101 norm (gsl_matrix * A)
103 size_t i, j, M = A->size1, N = A->size2;
104 double sum = 0.0, scale = 0.0, ssq = 1.0;
106 for (i = 0; i < M; i++)
108 for (j = 0; j < N; j++)
110 double Aij = gsl_matrix_get (A, i, j);
114 double ax = fabs (Aij);
118 ssq = 1.0 + ssq * (scale / ax) * (scale / ax);
123 ssq += (ax / scale) * (ax / scale);
130 sum = scale * sqrt (ssq);
136 gsl_eigen_jacobi (gsl_matrix * a,
138 gsl_matrix * evec, unsigned int max_rot, unsigned int *nrot)
141 const size_t M = a->size1, N = a->size2;
142 double red, redsum = 0.0;
146 GSL_ERROR ("eigenproblem requires square matrix", GSL_ENOTSQR);
148 else if (M != evec->size1 || M != evec->size2)
150 GSL_ERROR ("eigenvector matrix must match input matrix", GSL_EBADLEN);
152 else if (M != eval->size)
154 GSL_ERROR ("eigenvalue vector must match input matrix", GSL_EBADLEN);
157 gsl_vector_set_zero (eval);
158 gsl_matrix_set_identity (evec);
160 for (i = 0; i < max_rot; i++)
162 double nrm = norm (a);
167 for (p = 0; p < N; p++)
169 for (q = p + 1; q < N; q++)
173 red = symschur2 (a, p, q, &c, &s);
176 /* Compute A <- J^T A J */
177 apply_jacobi_L (a, p, q, c, s);
178 apply_jacobi_R (a, p, q, c, s);
180 /* Compute V <- V J */
181 apply_jacobi_R (evec, p, q, c, s);
188 for (p = 0; p < N; p++)
190 double ep = gsl_matrix_get (a, p, p);
191 gsl_vector_set (eval, p, ep);
203 gsl_eigen_invert_jacobi (const gsl_matrix * a,
204 gsl_matrix * ainv, unsigned int max_rot)
206 if (a->size1 != a->size2 || ainv->size1 != ainv->size2)
208 GSL_ERROR("jacobi method requires square matrix", GSL_ENOTSQR);
210 else if (a->size1 != ainv->size2)
212 GSL_ERROR ("inverse matrix must match input matrix", GSL_EBADLEN);
216 const size_t n = a->size2;
218 unsigned int nrot = 0;
221 gsl_vector * eval = gsl_vector_alloc(n);
222 gsl_matrix * evec = gsl_matrix_alloc(n, n);
223 gsl_matrix * tmp = gsl_matrix_alloc(n, n);
225 gsl_matrix_memcpy (tmp, a);
227 status = gsl_eigen_jacobi(tmp, eval, evec, max_rot, &nrot);
233 double ainv_ij = 0.0;
237 double f = 1.0 / gsl_vector_get(eval, k);
238 double vik = gsl_matrix_get (evec, i, k);
239 double vjk = gsl_matrix_get (evec, j, k);
240 ainv_ij += vik * vjk * f;
242 gsl_matrix_set (ainv, i, j, ainv_ij);
246 gsl_vector_free(eval);
247 gsl_matrix_free(evec);
248 gsl_matrix_free(tmp);