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.
24 #include <gsl/gsl_eigen.h>
25 #include <gsl/gsl_linalg.h>
26 #include <gsl/gsl_math.h>
27 #include <gsl/gsl_blas.h>
28 #include <gsl/gsl_vector.h>
29 #include <gsl/gsl_vector_complex.h>
30 #include <gsl/gsl_matrix.h>
31 #include <gsl/gsl_errno.h>
34 * This module computes the eigenvalues and eigenvectors of a
35 * real generalized eigensystem A x = \lambda B x. Left and right
36 * Schur vectors are optionally computed as well.
38 * This file contains routines based on original code from LAPACK
39 * which is distributed under the modified BSD license.
42 static int genv_get_right_eigenvectors(const gsl_matrix *S,
45 gsl_matrix_complex *evec,
46 gsl_eigen_genv_workspace *w);
47 static void genv_normalize_eigenvectors(gsl_vector_complex *alpha,
48 gsl_matrix_complex *evec);
51 gsl_eigen_genv_alloc()
52 Allocate a workspace for solving the generalized eigenvalue problem.
53 The size of this workspace is O(7n).
55 Inputs: n - size of matrices
57 Return: pointer to workspace
60 gsl_eigen_genv_workspace *
61 gsl_eigen_genv_alloc(const size_t n)
63 gsl_eigen_genv_workspace *w;
67 GSL_ERROR_NULL ("matrix dimension must be positive integer",
71 w = calloc (1, sizeof (gsl_eigen_genv_workspace));
75 GSL_ERROR_NULL ("failed to allocate space for workspace", GSL_ENOMEM);
82 w->gen_workspace_p = gsl_eigen_gen_alloc(n);
84 if (w->gen_workspace_p == 0)
86 gsl_eigen_genv_free(w);
87 GSL_ERROR_NULL ("failed to allocate space for gen workspace", GSL_ENOMEM);
90 /* compute the full Schur forms */
91 gsl_eigen_gen_params(1, 1, 1, w->gen_workspace_p);
93 w->work1 = gsl_vector_alloc(n);
94 w->work2 = gsl_vector_alloc(n);
95 w->work3 = gsl_vector_alloc(n);
96 w->work4 = gsl_vector_alloc(n);
97 w->work5 = gsl_vector_alloc(n);
98 w->work6 = gsl_vector_alloc(n);
100 if (w->work1 == 0 || w->work2 == 0 || w->work3 == 0 ||
101 w->work4 == 0 || w->work5 == 0 || w->work6 == 0)
103 gsl_eigen_genv_free(w);
104 GSL_ERROR_NULL ("failed to allocate space for additional workspace", GSL_ENOMEM);
108 } /* gsl_eigen_genv_alloc() */
111 gsl_eigen_genv_free()
116 gsl_eigen_genv_free(gsl_eigen_genv_workspace *w)
118 if (w->gen_workspace_p)
119 gsl_eigen_gen_free(w->gen_workspace_p);
122 gsl_vector_free(w->work1);
125 gsl_vector_free(w->work2);
128 gsl_vector_free(w->work3);
131 gsl_vector_free(w->work4);
134 gsl_vector_free(w->work5);
137 gsl_vector_free(w->work6);
140 } /* gsl_eigen_genv_free() */
145 Solve the generalized eigenvalue problem
149 for the eigenvalues \lambda and right eigenvectors x.
151 Inputs: A - general real matrix
152 B - general real matrix
153 alpha - (output) where to store eigenvalue numerators
154 beta - (output) where to store eigenvalue denominators
155 evec - (output) where to store eigenvectors
158 Return: success or error
162 gsl_eigen_genv (gsl_matrix * A, gsl_matrix * B, gsl_vector_complex * alpha,
163 gsl_vector * beta, gsl_matrix_complex *evec,
164 gsl_eigen_genv_workspace * w)
166 const size_t N = A->size1;
168 /* check matrix and vector sizes */
172 GSL_ERROR ("matrix must be square to compute eigenvalues", GSL_ENOTSQR);
174 else if ((N != B->size1) || (N != B->size2))
176 GSL_ERROR ("B matrix dimensions must match A", GSL_EBADLEN);
178 else if (alpha->size != N || beta->size != N)
180 GSL_ERROR ("eigenvalue vector must match matrix size", GSL_EBADLEN);
182 else if (w->size != N)
184 GSL_ERROR ("matrix size does not match workspace", GSL_EBADLEN);
186 else if (evec->size1 != N)
188 GSL_ERROR ("eigenvector matrix has wrong size", GSL_EBADLEN);
196 * We need a place to store the right Schur vectors, so we will
197 * treat evec as a real matrix and store them in the left
198 * half - the factor of 2 in the tda corresponds to the
199 * complex multiplicity
208 s = gsl_eigen_gen_QZ(A, B, alpha, beta, w->Q, &Z, w->gen_workspace_p);
212 /* save right Schur vectors */
213 gsl_matrix_memcpy(w->Z, &Z);
216 /* only compute eigenvectors if we found all eigenvalues */
217 if (s == GSL_SUCCESS)
219 /* compute eigenvectors */
220 s = genv_get_right_eigenvectors(A, B, &Z, evec, w);
222 if (s == GSL_SUCCESS)
223 genv_normalize_eigenvectors(alpha, evec);
228 } /* gsl_eigen_genv() */
233 Solve the generalized eigenvalue problem
237 for the eigenvalues \lambda and right eigenvectors x. Optionally
238 compute left and/or right Schur vectors Q and Z which satisfy:
243 where (S, T) is the generalized Schur form of (A, B)
245 Inputs: A - general real matrix
246 B - general real matrix
247 alpha - (output) where to store eigenvalue numerators
248 beta - (output) where to store eigenvalue denominators
249 evec - (output) where to store eigenvectors
250 Q - (output) if non-null, where to store left Schur vectors
251 Z - (output) if non-null, where to store right Schur vectors
254 Return: success or error
258 gsl_eigen_genv_QZ (gsl_matrix * A, gsl_matrix * B,
259 gsl_vector_complex * alpha, gsl_vector * beta,
260 gsl_matrix_complex * evec,
261 gsl_matrix * Q, gsl_matrix * Z,
262 gsl_eigen_genv_workspace * w)
264 if (Q && (A->size1 != Q->size1 || A->size1 != Q->size2))
266 GSL_ERROR("Q matrix has wrong dimensions", GSL_EBADLEN);
268 else if (Z && (A->size1 != Z->size1 || A->size1 != Z->size2))
270 GSL_ERROR("Z matrix has wrong dimensions", GSL_EBADLEN);
279 s = gsl_eigen_genv(A, B, alpha, beta, evec, w);
286 } /* gsl_eigen_genv_QZ() */
288 /********************************************
289 * INTERNAL ROUTINES *
290 ********************************************/
293 genv_get_right_eigenvectors()
294 Compute right eigenvectors of the Schur form (S, T) and then
295 backtransform them using the right Schur vectors to get right
296 eigenvectors of the original system.
298 Inputs: S - upper quasi-triangular Schur form of A
299 T - upper triangular Schur form of B
300 Z - right Schur vectors
301 evec - (output) where to store eigenvectors
304 Return: success or error
306 Notes: 1) based on LAPACK routine DTGEVC
307 2) eigenvectors are stored in the order that their
308 eigenvalues appear in the Schur form
312 genv_get_right_eigenvectors(const gsl_matrix *S, const gsl_matrix *T,
314 gsl_matrix_complex *evec,
315 gsl_eigen_genv_workspace *w)
317 const size_t N = w->size;
318 const double small = GSL_DBL_MIN * N / GSL_DBL_EPSILON;
319 const double big = 1.0 / small;
320 const double bignum = 1.0 / (GSL_DBL_MIN * N);
324 double temp, temp2, temp2r, temp2i;
325 double ascale, bscale;
326 double salfar, sbeta;
327 double acoef, bcoefr, bcoefi, acoefa, bcoefa;
328 double creala, cimaga, crealb, cimagb, cre2a, cim2a, cre2b, cim2b;
334 gsl_complex z_zero, z_one;
335 double bdiag[2] = { 0.0, 0.0 };
340 gsl_vector_complex_view ecol;
341 gsl_vector_view re, im, re2, im2;
343 GSL_SET_COMPLEX(&z_zero, 0.0, 0.0);
344 GSL_SET_COMPLEX(&z_one, 1.0, 0.0);
347 * Compute the 1-norm of each column of (S, T) excluding elements
348 * belonging to the diagonal blocks to check for possible overflow
349 * in the triangular solver
352 anorm = fabs(gsl_matrix_get(S, 0, 0));
354 anorm += fabs(gsl_matrix_get(S, 1, 0));
355 bnorm = fabs(gsl_matrix_get(T, 0, 0));
357 gsl_vector_set(w->work1, 0, 0.0);
358 gsl_vector_set(w->work2, 0, 0.0);
360 for (j = 1; j < N; ++j)
363 if (gsl_matrix_get(S, j, j - 1) == 0.0)
368 for (i = 0; i < end; ++i)
370 temp += fabs(gsl_matrix_get(S, i, j));
371 temp2 += fabs(gsl_matrix_get(T, i, j));
374 gsl_vector_set(w->work1, j, temp);
375 gsl_vector_set(w->work2, j, temp2);
377 for (i = end; i < GSL_MIN(j + 2, N); ++i)
379 temp += fabs(gsl_matrix_get(S, i, j));
380 temp2 += fabs(gsl_matrix_get(T, i, j));
383 anorm = GSL_MAX(anorm, temp);
384 bnorm = GSL_MAX(bnorm, temp2);
387 ascale = 1.0 / GSL_MAX(anorm, GSL_DBL_MIN);
388 bscale = 1.0 / GSL_MAX(bnorm, GSL_DBL_MIN);
391 for (k = 0; k < N; ++k)
393 size_t je = N - 1 - k;
404 if (gsl_matrix_get(S, je, je - 1) != 0.0)
413 if (fabs(gsl_matrix_get(S, je, je)) <= GSL_DBL_MIN &&
414 fabs(gsl_matrix_get(T, je, je)) <= GSL_DBL_MIN)
416 /* singular matrix pencil - unit eigenvector */
417 for (i = 0; i < N; ++i)
418 gsl_matrix_complex_set(evec, i, je, z_zero);
420 gsl_matrix_complex_set(evec, je, je, z_one);
426 for (i = 0; i < N; ++i)
427 gsl_vector_set(w->work3, i, 0.0);
432 for (i = 0; i < N; ++i)
434 gsl_vector_set(w->work3, i, 0.0);
435 gsl_vector_set(w->work4, i, 0.0);
441 /* real eigenvalue */
443 temp = 1.0 / GSL_MAX(GSL_DBL_MIN,
444 GSL_MAX(fabs(gsl_matrix_get(S, je, je)) * ascale,
445 fabs(gsl_matrix_get(T, je, je)) * bscale));
446 salfar = (temp * gsl_matrix_get(S, je, je)) * ascale;
447 sbeta = (temp * gsl_matrix_get(T, je, je)) * bscale;
448 acoef = sbeta * ascale;
449 bcoefr = salfar * bscale;
452 /* scale to avoid underflow */
454 lsa = fabs(sbeta) >= GSL_DBL_MIN && fabs(acoef) < small;
455 lsb = fabs(salfar) >= GSL_DBL_MIN && fabs(bcoefr) < small;
457 scale = (small / fabs(sbeta)) * GSL_MIN(anorm, big);
459 scale = GSL_MAX(scale, (small / fabs(salfar)) * GSL_MIN(bnorm, big));
463 scale = GSL_MIN(scale,
466 GSL_MAX(fabs(acoef), fabs(bcoefr)))));
468 acoef = ascale * (scale * sbeta);
473 bcoefr = bscale * (scale * salfar);
478 acoefa = fabs(acoef);
479 bcoefa = fabs(bcoefr);
481 /* first component is 1 */
482 gsl_vector_set(w->work3, je, 1.0);
485 /* compute contribution from column je of A and B to sum */
487 for (i = 0; i < je; ++i)
489 gsl_vector_set(w->work3, i,
490 bcoefr*gsl_matrix_get(T, i, je) -
491 acoef * gsl_matrix_get(S, i, je));
496 gsl_matrix_const_view vs =
497 gsl_matrix_const_submatrix(S, je - 1, je - 1, 2, 2);
498 gsl_matrix_const_view vt =
499 gsl_matrix_const_submatrix(T, je - 1, je - 1, 2, 2);
501 /* complex eigenvalue */
503 gsl_schur_gen_eigvals(&vs.matrix,
512 GSL_ERROR("gsl_schur_gen_eigvals failed on complex block", GSL_FAILURE);
515 /* scale to avoid over/underflow */
516 acoefa = fabs(acoef);
517 bcoefa = fabs(bcoefr) + fabs(bcoefi);
520 if (acoefa*GSL_DBL_EPSILON < GSL_DBL_MIN && acoefa >= GSL_DBL_MIN)
521 scale = (GSL_DBL_MIN / GSL_DBL_EPSILON) / acoefa;
522 if (bcoefa*GSL_DBL_EPSILON < GSL_DBL_MIN && bcoefa >= GSL_DBL_MIN)
523 scale = GSL_MAX(scale, (GSL_DBL_MIN/GSL_DBL_EPSILON) / bcoefa);
524 if (GSL_DBL_MIN*acoefa > ascale)
525 scale = ascale / (GSL_DBL_MIN * acoefa);
526 if (GSL_DBL_MIN*bcoefa > bscale)
527 scale = GSL_MIN(scale, bscale / (GSL_DBL_MIN*bcoefa));
531 acoefa = fabs(acoef);
534 bcoefa = fabs(bcoefr) + fabs(bcoefi);
537 /* compute first two components of eigenvector */
539 temp = acoef * gsl_matrix_get(S, je, je - 1);
540 temp2r = acoef * gsl_matrix_get(S, je, je) -
541 bcoefr * gsl_matrix_get(T, je, je);
542 temp2i = -bcoefi * gsl_matrix_get(T, je, je);
544 if (fabs(temp) >= fabs(temp2r) + fabs(temp2i))
546 gsl_vector_set(w->work3, je, 1.0);
547 gsl_vector_set(w->work4, je, 0.0);
548 gsl_vector_set(w->work3, je - 1, -temp2r / temp);
549 gsl_vector_set(w->work4, je - 1, -temp2i / temp);
553 gsl_vector_set(w->work3, je - 1, 1.0);
554 gsl_vector_set(w->work4, je - 1, 0.0);
555 temp = acoef * gsl_matrix_get(S, je - 1, je);
556 gsl_vector_set(w->work3, je,
557 (bcoefr*gsl_matrix_get(T, je - 1, je - 1) -
558 acoef*gsl_matrix_get(S, je - 1, je - 1)) / temp);
559 gsl_vector_set(w->work4, je,
560 bcoefi*gsl_matrix_get(T, je - 1, je - 1) / temp);
563 xmax = GSL_MAX(fabs(gsl_vector_get(w->work3, je)) +
564 fabs(gsl_vector_get(w->work4, je)),
565 fabs(gsl_vector_get(w->work3, je - 1)) +
566 fabs(gsl_vector_get(w->work4, je - 1)));
568 /* compute contribution from column je and je - 1 */
570 creala = acoef * gsl_vector_get(w->work3, je - 1);
571 cimaga = acoef * gsl_vector_get(w->work4, je - 1);
572 crealb = bcoefr * gsl_vector_get(w->work3, je - 1) -
573 bcoefi * gsl_vector_get(w->work4, je - 1);
574 cimagb = bcoefi * gsl_vector_get(w->work3, je - 1) +
575 bcoefr * gsl_vector_get(w->work4, je - 1);
576 cre2a = acoef * gsl_vector_get(w->work3, je);
577 cim2a = acoef * gsl_vector_get(w->work4, je);
578 cre2b = bcoefr * gsl_vector_get(w->work3, je) -
579 bcoefi * gsl_vector_get(w->work4, je);
580 cim2b = bcoefi * gsl_vector_get(w->work3, je) +
581 bcoefr * gsl_vector_get(w->work4, je);
583 for (i = 0; i < je - 1; ++i)
585 gsl_vector_set(w->work3, i,
586 -creala * gsl_matrix_get(S, i, je - 1) +
587 crealb * gsl_matrix_get(T, i, je - 1) -
588 cre2a * gsl_matrix_get(S, i, je) +
589 cre2b * gsl_matrix_get(T, i, je));
590 gsl_vector_set(w->work4, i,
591 -cimaga * gsl_matrix_get(S, i, je - 1) +
592 cimagb * gsl_matrix_get(T, i, je - 1) -
593 cim2a * gsl_matrix_get(S, i, je) +
594 cim2b * gsl_matrix_get(T, i, je));
598 dmin = GSL_MAX(GSL_DBL_MIN,
599 GSL_MAX(GSL_DBL_EPSILON*acoefa*anorm,
600 GSL_DBL_EPSILON*bcoefa*bnorm));
602 /* triangular solve of (a A - b B) x = 0 */
605 for (is = (int) je - (int) nw; is >= 0; --is)
609 if (!il2by2 && j > 0)
611 if (gsl_matrix_get(S, j, j - 1) != 0.0)
618 bdiag[0] = gsl_matrix_get(T, j, j);
622 bdiag[1] = gsl_matrix_get(T, j + 1, j + 1);
630 gsl_matrix_const_view sv =
631 gsl_matrix_const_submatrix(S, j, j, na, na);
632 gsl_vector_view xv, bv;
634 bv = gsl_vector_subvector(w->work3, j, na);
637 * the loop below expects the solution in the first column
638 * of sum, so set stride to 2
640 xv = gsl_vector_view_array_with_stride(sum, 2, na);
642 gsl_schur_solve_equation(acoef,
656 gsl_matrix_const_view sv =
657 gsl_matrix_const_submatrix(S, j, j, na, na);
658 gsl_vector_complex_view xv =
659 gsl_vector_complex_view_array(sum, na);
660 gsl_vector_complex_view bv =
661 gsl_vector_complex_view_array(bdat, na);
664 bdat[0] = gsl_vector_get(w->work3, j);
665 bdat[1] = gsl_vector_get(w->work4, j);
668 bdat[2] = gsl_vector_get(w->work3, j + 1);
669 bdat[3] = gsl_vector_get(w->work4, j + 1);
672 GSL_SET_COMPLEX(&z, bcoefr, bcoefi);
674 gsl_schur_solve_equation_z(acoef,
688 for (jr = 0; jr <= je; ++jr)
690 gsl_vector_set(w->work3, jr,
691 scale * gsl_vector_get(w->work3, jr));
694 gsl_vector_set(w->work4, jr,
695 scale * gsl_vector_get(w->work4, jr));
700 xmax = GSL_MAX(scale * xmax, temp);
702 for (jr = 0; jr < na; ++jr)
704 gsl_vector_set(w->work3, j + jr, sum[jr*na]);
706 gsl_vector_set(w->work4, j + jr, sum[jr*na + 1]);
711 xscale = 1.0 / GSL_MAX(1.0, xmax);
712 temp = acoefa * gsl_vector_get(w->work1, j) +
713 bcoefa * gsl_vector_get(w->work2, j);
717 acoefa * gsl_vector_get(w->work1, j + 1) +
718 bcoefa * gsl_vector_get(w->work2, j + 1));
721 temp = GSL_MAX(temp, GSL_MAX(acoefa, bcoefa));
722 if (temp > bignum * xscale)
724 for (jr = 0; jr <= je; ++jr)
726 gsl_vector_set(w->work3, jr,
727 xscale * gsl_vector_get(w->work3, jr));
730 gsl_vector_set(w->work4, jr,
731 xscale * gsl_vector_get(w->work4, jr));
737 for (ja = 0; ja < na; ++ja)
741 creala = acoef * gsl_vector_get(w->work3, j + ja);
742 cimaga = acoef * gsl_vector_get(w->work4, j + ja);
743 crealb = bcoefr * gsl_vector_get(w->work3, j + ja) -
744 bcoefi * gsl_vector_get(w->work4, j + ja);
745 cimagb = bcoefi * gsl_vector_get(w->work3, j + ja) +
746 bcoefr * gsl_vector_get(w->work4, j + ja);
747 for (jr = 0; jr <= j - 1; ++jr)
749 gsl_vector_set(w->work3, jr,
750 gsl_vector_get(w->work3, jr) -
751 creala * gsl_matrix_get(S, jr, j + ja) +
752 crealb * gsl_matrix_get(T, jr, j + ja));
753 gsl_vector_set(w->work4, jr,
754 gsl_vector_get(w->work4, jr) -
755 cimaga * gsl_matrix_get(S, jr, j + ja) +
756 cimagb * gsl_matrix_get(T, jr, j + ja));
761 creala = acoef * gsl_vector_get(w->work3, j + ja);
762 crealb = bcoefr * gsl_vector_get(w->work3, j + ja);
763 for (jr = 0; jr <= j - 1; ++jr)
765 gsl_vector_set(w->work3, jr,
766 gsl_vector_get(w->work3, jr) -
767 creala * gsl_matrix_get(S, jr, j + ja) +
768 crealb * gsl_matrix_get(T, jr, j + ja));
770 } /* if (!complex_pair) */
771 } /* for (ja = 0; ja < na; ++ja) */
775 } /* for (i = 0; i < je - nw; ++i) */
777 for (jr = 0; jr < N; ++jr)
779 gsl_vector_set(w->work5, jr,
780 gsl_vector_get(w->work3, 0) * gsl_matrix_get(Z, jr, 0));
783 gsl_vector_set(w->work6, jr,
784 gsl_vector_get(w->work4, 0) * gsl_matrix_get(Z, jr, 0));
788 for (jc = 1; jc <= je; ++jc)
790 for (jr = 0; jr < N; ++jr)
792 gsl_vector_set(w->work5, jr,
793 gsl_vector_get(w->work5, jr) +
794 gsl_vector_get(w->work3, jc) * gsl_matrix_get(Z, jr, jc));
797 gsl_vector_set(w->work6, jr,
798 gsl_vector_get(w->work6, jr) +
799 gsl_vector_get(w->work4, jc) * gsl_matrix_get(Z, jr, jc));
804 /* store the eigenvector */
808 ecol = gsl_matrix_complex_column(evec, je - 1);
809 re = gsl_vector_complex_real(&ecol.vector);
810 im = gsl_vector_complex_imag(&ecol.vector);
812 ecol = gsl_matrix_complex_column(evec, je);
813 re2 = gsl_vector_complex_real(&ecol.vector);
814 im2 = gsl_vector_complex_imag(&ecol.vector);
818 ecol = gsl_matrix_complex_column(evec, je);
819 re = gsl_vector_complex_real(&ecol.vector);
820 im = gsl_vector_complex_imag(&ecol.vector);
823 for (jr = 0; jr < N; ++jr)
825 gsl_vector_set(&re.vector, jr, gsl_vector_get(w->work5, jr));
828 gsl_vector_set(&im.vector, jr, gsl_vector_get(w->work6, jr));
829 gsl_vector_set(&re2.vector, jr, gsl_vector_get(w->work5, jr));
830 gsl_vector_set(&im2.vector, jr, -gsl_vector_get(w->work6, jr));
834 gsl_vector_set(&im.vector, jr, 0.0);
838 /* scale eigenvector */
842 for (j = 0; j < N; ++j)
845 fabs(gsl_vector_get(&re.vector, j)) +
846 fabs(gsl_vector_get(&im.vector, j)));
851 for (j = 0; j < N; ++j)
853 xmax = GSL_MAX(xmax, fabs(gsl_vector_get(&re.vector, j)));
857 if (xmax > GSL_DBL_MIN)
860 for (j = 0; j < N; ++j)
862 gsl_vector_set(&re.vector, j,
863 gsl_vector_get(&re.vector, j) * xscale);
866 gsl_vector_set(&im.vector, j,
867 gsl_vector_get(&im.vector, j) * xscale);
868 gsl_vector_set(&re2.vector, j,
869 gsl_vector_get(&re2.vector, j) * xscale);
870 gsl_vector_set(&im2.vector, j,
871 gsl_vector_get(&im2.vector, j) * xscale);
875 } /* for (k = 0; k < N; ++k) */
878 } /* genv_get_right_eigenvectors() */
881 genv_normalize_eigenvectors()
882 Normalize eigenvectors so that their Euclidean norm is 1
884 Inputs: alpha - eigenvalue numerators
889 genv_normalize_eigenvectors(gsl_vector_complex *alpha,
890 gsl_matrix_complex *evec)
892 const size_t N = evec->size1;
893 size_t i; /* looping */
895 gsl_vector_complex_view vi;
896 gsl_vector_view re, im;
897 double scale; /* scaling factor */
899 for (i = 0; i < N; ++i)
901 ai = gsl_vector_complex_get(alpha, i);
902 vi = gsl_matrix_complex_column(evec, i);
904 re = gsl_vector_complex_real(&vi.vector);
906 if (GSL_IMAG(ai) == 0.0)
908 scale = 1.0 / gsl_blas_dnrm2(&re.vector);
909 gsl_blas_dscal(scale, &re.vector);
911 else if (GSL_IMAG(ai) > 0.0)
913 im = gsl_vector_complex_imag(&vi.vector);
915 scale = 1.0 / gsl_hypot(gsl_blas_dnrm2(&re.vector),
916 gsl_blas_dnrm2(&im.vector));
917 gsl_blas_zdscal(scale, &vi.vector);
919 vi = gsl_matrix_complex_column(evec, i + 1);
920 gsl_blas_zdscal(scale, &vi.vector);
923 } /* genv_normalize_eigenvectors() */