3 * Copyright (C) 2007 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.
23 #include <gsl/gsl_eigen.h>
24 #include <gsl/gsl_linalg.h>
25 #include <gsl/gsl_math.h>
26 #include <gsl/gsl_blas.h>
27 #include <gsl/gsl_vector.h>
28 #include <gsl/gsl_matrix.h>
31 * This module computes the eigenvalues and eigenvectors of a real
32 * generalized symmetric-definite eigensystem A x = \lambda B x, where
33 * A and B are symmetric, and B is positive-definite.
36 static void gensymmv_normalize_eigenvectors(gsl_matrix *evec);
39 gsl_eigen_gensymmv_alloc()
41 Allocate a workspace for solving the generalized symmetric-definite
42 eigenvalue problem. The size of this workspace is O(4n).
44 Inputs: n - size of matrices
46 Return: pointer to workspace
49 gsl_eigen_gensymmv_workspace *
50 gsl_eigen_gensymmv_alloc(const size_t n)
52 gsl_eigen_gensymmv_workspace *w;
56 GSL_ERROR_NULL ("matrix dimension must be positive integer",
60 w = calloc (1, sizeof (gsl_eigen_gensymmv_workspace));
64 GSL_ERROR_NULL ("failed to allocate space for workspace", GSL_ENOMEM);
69 w->symmv_workspace_p = gsl_eigen_symmv_alloc(n);
70 if (!w->symmv_workspace_p)
72 gsl_eigen_gensymmv_free(w);
73 GSL_ERROR_NULL("failed to allocate space for symmv workspace", GSL_ENOMEM);
77 } /* gsl_eigen_gensymmv_alloc() */
80 gsl_eigen_gensymmv_free()
85 gsl_eigen_gensymmv_free (gsl_eigen_gensymmv_workspace * w)
87 if (w->symmv_workspace_p)
88 gsl_eigen_symmv_free(w->symmv_workspace_p);
91 } /* gsl_eigen_gensymmv_free() */
96 Solve the generalized symmetric-definite eigenvalue problem
100 for the eigenvalues \lambda and eigenvectors x.
102 Inputs: A - real symmetric matrix
103 B - real symmetric and positive definite matrix
104 eval - where to store eigenvalues
105 evec - where to store eigenvectors
108 Return: success or error
112 gsl_eigen_gensymmv (gsl_matrix * A, gsl_matrix * B, gsl_vector * eval,
113 gsl_matrix * evec, gsl_eigen_gensymmv_workspace * w)
115 const size_t N = A->size1;
117 /* check matrix and vector sizes */
121 GSL_ERROR ("matrix must be square to compute eigenvalues", GSL_ENOTSQR);
123 else if ((N != B->size1) || (N != B->size2))
125 GSL_ERROR ("B matrix dimensions must match A", GSL_EBADLEN);
127 else if (eval->size != N)
129 GSL_ERROR ("eigenvalue vector must match matrix size", GSL_EBADLEN);
131 else if (evec->size1 != evec->size2)
133 GSL_ERROR ("eigenvector matrix must be square", GSL_ENOTSQR);
135 else if (evec->size1 != N)
137 GSL_ERROR ("eigenvector matrix has wrong size", GSL_EBADLEN);
139 else if (w->size != N)
141 GSL_ERROR ("matrix size does not match workspace", GSL_EBADLEN);
147 /* compute Cholesky factorization of B */
148 s = gsl_linalg_cholesky_decomp(B);
149 if (s != GSL_SUCCESS)
150 return s; /* B is not positive definite */
152 /* transform to standard symmetric eigenvalue problem */
153 gsl_eigen_gensymm_standardize(A, B);
155 /* compute eigenvalues and eigenvectors */
156 s = gsl_eigen_symmv(A, eval, evec, w->symmv_workspace_p);
157 if (s != GSL_SUCCESS)
160 /* backtransform eigenvectors: evec -> L^{-T} evec */
161 gsl_blas_dtrsm(CblasLeft,
169 /* the blas call destroyed the normalization - renormalize */
170 gensymmv_normalize_eigenvectors(evec);
174 } /* gsl_eigen_gensymmv() */
176 /********************************************
177 * INTERNAL ROUTINES *
178 ********************************************/
181 gensymmv_normalize_eigenvectors()
182 Normalize eigenvectors so that their Euclidean norm is 1
184 Inputs: evec - eigenvectors
188 gensymmv_normalize_eigenvectors(gsl_matrix *evec)
190 const size_t N = evec->size1;
191 size_t i; /* looping */
193 for (i = 0; i < N; ++i)
195 gsl_vector_view vi = gsl_matrix_column(evec, i);
196 double scale = 1.0 / gsl_blas_dnrm2(&vi.vector);
198 gsl_blas_dscal(scale, &vi.vector);
200 } /* gensymmv_normalize_eigenvectors() */