123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924 |
- /* eigen/genv.c
- *
- * Copyright (C) 2007 Patrick Alken
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3 of the License, or (at
- * your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
- #include <stdlib.h>
- #include <math.h>
- #include "gsl__config.h"
- #include "gsl_eigen.h"
- #include "gsl_linalg.h"
- #include "gsl_math.h"
- #include "gsl_blas.h"
- #include "gsl_vector.h"
- #include "gsl_vector_complex.h"
- #include "gsl_matrix.h"
- #include "gsl_errno.h"
- /*
- * This module computes the eigenvalues and eigenvectors of a
- * real generalized eigensystem A x = \lambda B x. Left and right
- * Schur vectors are optionally computed as well.
- *
- * This file contains routines based on original code from LAPACK
- * which is distributed under the modified BSD license.
- */
- static int genv_get_right_eigenvectors(const gsl_matrix *S,
- const gsl_matrix *T,
- gsl_matrix *Z,
- gsl_matrix_complex *evec,
- gsl_eigen_genv_workspace *w);
- static void genv_normalize_eigenvectors(gsl_vector_complex *alpha,
- gsl_matrix_complex *evec);
- /*
- gsl_eigen_genv_alloc()
- Allocate a workspace for solving the generalized eigenvalue problem.
- The size of this workspace is O(7n).
- Inputs: n - size of matrices
- Return: pointer to workspace
- */
- gsl_eigen_genv_workspace *
- gsl_eigen_genv_alloc(const size_t n)
- {
- gsl_eigen_genv_workspace *w;
- if (n == 0)
- {
- GSL_ERROR_NULL ("matrix dimension must be positive integer",
- GSL_EINVAL);
- }
- w = (gsl_eigen_genv_workspace *) calloc (1, sizeof (gsl_eigen_genv_workspace));
- if (w == 0)
- {
- GSL_ERROR_NULL ("failed to allocate space for workspace", GSL_ENOMEM);
- }
- w->size = n;
- w->Q = NULL;
- w->Z = NULL;
- w->gen_workspace_p = gsl_eigen_gen_alloc(n);
- if (w->gen_workspace_p == 0)
- {
- gsl_eigen_genv_free(w);
- GSL_ERROR_NULL ("failed to allocate space for gen workspace", GSL_ENOMEM);
- }
- /* compute the full Schur forms */
- gsl_eigen_gen_params(1, 1, 1, w->gen_workspace_p);
- w->work1 = gsl_vector_alloc(n);
- w->work2 = gsl_vector_alloc(n);
- w->work3 = gsl_vector_alloc(n);
- w->work4 = gsl_vector_alloc(n);
- w->work5 = gsl_vector_alloc(n);
- w->work6 = gsl_vector_alloc(n);
- if (w->work1 == 0 || w->work2 == 0 || w->work3 == 0 ||
- w->work4 == 0 || w->work5 == 0 || w->work6 == 0)
- {
- gsl_eigen_genv_free(w);
- GSL_ERROR_NULL ("failed to allocate space for additional workspace", GSL_ENOMEM);
- }
- return (w);
- } /* gsl_eigen_genv_alloc() */
- /*
- gsl_eigen_genv_free()
- Free workspace w
- */
- void
- gsl_eigen_genv_free(gsl_eigen_genv_workspace *w)
- {
- if (w->gen_workspace_p)
- gsl_eigen_gen_free(w->gen_workspace_p);
- if (w->work1)
- gsl_vector_free(w->work1);
- if (w->work2)
- gsl_vector_free(w->work2);
- if (w->work3)
- gsl_vector_free(w->work3);
- if (w->work4)
- gsl_vector_free(w->work4);
- if (w->work5)
- gsl_vector_free(w->work5);
- if (w->work6)
- gsl_vector_free(w->work6);
- free(w);
- } /* gsl_eigen_genv_free() */
- /*
- gsl_eigen_genv()
- Solve the generalized eigenvalue problem
- A x = \lambda B x
- for the eigenvalues \lambda and right eigenvectors x.
- Inputs: A - general real matrix
- B - general real matrix
- alpha - (output) where to store eigenvalue numerators
- beta - (output) where to store eigenvalue denominators
- evec - (output) where to store eigenvectors
- w - workspace
- Return: success or error
- */
- int
- gsl_eigen_genv (gsl_matrix * A, gsl_matrix * B, gsl_vector_complex * alpha,
- gsl_vector * beta, gsl_matrix_complex *evec,
- gsl_eigen_genv_workspace * w)
- {
- const size_t N = A->size1;
- /* check matrix and vector sizes */
- if (N != A->size2)
- {
- GSL_ERROR ("matrix must be square to compute eigenvalues", GSL_ENOTSQR);
- }
- else if ((N != B->size1) || (N != B->size2))
- {
- GSL_ERROR ("B matrix dimensions must match A", GSL_EBADLEN);
- }
- else if (alpha->size != N || beta->size != N)
- {
- GSL_ERROR ("eigenvalue vector must match matrix size", GSL_EBADLEN);
- }
- else if (w->size != N)
- {
- GSL_ERROR ("matrix size does not match workspace", GSL_EBADLEN);
- }
- else if (evec->size1 != N)
- {
- GSL_ERROR ("eigenvector matrix has wrong size", GSL_EBADLEN);
- }
- else
- {
- int s;
- gsl_matrix Z;
- /*
- * We need a place to store the right Schur vectors, so we will
- * treat evec as a real matrix and store them in the left
- * half - the factor of 2 in the tda corresponds to the
- * complex multiplicity
- */
- Z.size1 = N;
- Z.size2 = N;
- Z.tda = 2 * N;
- Z.data = evec->data;
- Z.block = 0;
- Z.owner = 0;
- s = gsl_eigen_gen_QZ(A, B, alpha, beta, w->Q, &Z, w->gen_workspace_p);
- if (w->Z)
- {
- /* save right Schur vectors */
- gsl_matrix_memcpy(w->Z, &Z);
- }
- /* only compute eigenvectors if we found all eigenvalues */
- if (s == GSL_SUCCESS)
- {
- /* compute eigenvectors */
- s = genv_get_right_eigenvectors(A, B, &Z, evec, w);
- if (s == GSL_SUCCESS)
- genv_normalize_eigenvectors(alpha, evec);
- }
- return s;
- }
- } /* gsl_eigen_genv() */
- /*
- gsl_eigen_genv_QZ()
- Solve the generalized eigenvalue problem
- A x = \lambda B x
- for the eigenvalues \lambda and right eigenvectors x. Optionally
- compute left and/or right Schur vectors Q and Z which satisfy:
- A = Q S Z^t
- B = Q T Z^t
- where (S, T) is the generalized Schur form of (A, B)
- Inputs: A - general real matrix
- B - general real matrix
- alpha - (output) where to store eigenvalue numerators
- beta - (output) where to store eigenvalue denominators
- evec - (output) where to store eigenvectors
- Q - (output) if non-null, where to store left Schur vectors
- Z - (output) if non-null, where to store right Schur vectors
- w - workspace
- Return: success or error
- */
- int
- gsl_eigen_genv_QZ (gsl_matrix * A, gsl_matrix * B,
- gsl_vector_complex * alpha, gsl_vector * beta,
- gsl_matrix_complex * evec,
- gsl_matrix * Q, gsl_matrix * Z,
- gsl_eigen_genv_workspace * w)
- {
- if (Q && (A->size1 != Q->size1 || A->size1 != Q->size2))
- {
- GSL_ERROR("Q matrix has wrong dimensions", GSL_EBADLEN);
- }
- else if (Z && (A->size1 != Z->size1 || A->size1 != Z->size2))
- {
- GSL_ERROR("Z matrix has wrong dimensions", GSL_EBADLEN);
- }
- else
- {
- int s;
- w->Q = Q;
- w->Z = Z;
- s = gsl_eigen_genv(A, B, alpha, beta, evec, w);
- w->Q = NULL;
- w->Z = NULL;
- return s;
- }
- } /* gsl_eigen_genv_QZ() */
- /********************************************
- * INTERNAL ROUTINES *
- ********************************************/
- /*
- genv_get_right_eigenvectors()
- Compute right eigenvectors of the Schur form (S, T) and then
- backtransform them using the right Schur vectors to get right
- eigenvectors of the original system.
- Inputs: S - upper quasi-triangular Schur form of A
- T - upper triangular Schur form of B
- Z - right Schur vectors
- evec - (output) where to store eigenvectors
- w - workspace
- Return: success or error
- Notes: 1) based on LAPACK routine DTGEVC
- 2) eigenvectors are stored in the order that their
- eigenvalues appear in the Schur form
- */
- static int
- genv_get_right_eigenvectors(const gsl_matrix *S, const gsl_matrix *T,
- gsl_matrix *Z,
- gsl_matrix_complex *evec,
- gsl_eigen_genv_workspace *w)
- {
- const size_t N = w->size;
- const double small = GSL_DBL_MIN * N / GSL_DBL_EPSILON;
- const double big = 1.0 / small;
- const double bignum = 1.0 / (GSL_DBL_MIN * N);
- size_t i, j, k, end;
- int is;
- double anorm, bnorm;
- double temp, temp2, temp2r, temp2i;
- double ascale, bscale;
- double salfar, sbeta;
- double acoef, bcoefr, bcoefi, acoefa, bcoefa;
- double creala, cimaga, crealb, cimagb, cre2a, cim2a, cre2b, cim2b;
- double dmin, xmax;
- double scale;
- size_t nw, na;
- int lsa, lsb;
- int complex_pair;
- gsl_complex z_zero, z_one;
- double bdiag[2] = { 0.0, 0.0 };
- double sum[4];
- int il2by2;
- size_t jr, jc, ja;
- double xscale;
- gsl_vector_complex_view ecol;
- gsl_vector_view re, im, re2, im2;
- GSL_SET_COMPLEX(&z_zero, 0.0, 0.0);
- GSL_SET_COMPLEX(&z_one, 1.0, 0.0);
- /*
- * Compute the 1-norm of each column of (S, T) excluding elements
- * belonging to the diagonal blocks to check for possible overflow
- * in the triangular solver
- */
- anorm = fabs(gsl_matrix_get(S, 0, 0));
- if (N > 1)
- anorm += fabs(gsl_matrix_get(S, 1, 0));
- bnorm = fabs(gsl_matrix_get(T, 0, 0));
- gsl_vector_set(w->work1, 0, 0.0);
- gsl_vector_set(w->work2, 0, 0.0);
- for (j = 1; j < N; ++j)
- {
- temp = temp2 = 0.0;
- if (gsl_matrix_get(S, j, j - 1) == 0.0)
- end = j;
- else
- end = j - 1;
- for (i = 0; i < end; ++i)
- {
- temp += fabs(gsl_matrix_get(S, i, j));
- temp2 += fabs(gsl_matrix_get(T, i, j));
- }
- gsl_vector_set(w->work1, j, temp);
- gsl_vector_set(w->work2, j, temp2);
- for (i = end; i < GSL_MIN(j + 2, N); ++i)
- {
- temp += fabs(gsl_matrix_get(S, i, j));
- temp2 += fabs(gsl_matrix_get(T, i, j));
- }
- anorm = GSL_MAX(anorm, temp);
- bnorm = GSL_MAX(bnorm, temp2);
- }
- ascale = 1.0 / GSL_MAX(anorm, GSL_DBL_MIN);
- bscale = 1.0 / GSL_MAX(bnorm, GSL_DBL_MIN);
- complex_pair = 0;
- for (k = 0; k < N; ++k)
- {
- size_t je = N - 1 - k;
- if (complex_pair)
- {
- complex_pair = 0;
- continue;
- }
- nw = 1;
- if (je > 0)
- {
- if (gsl_matrix_get(S, je, je - 1) != 0.0)
- {
- complex_pair = 1;
- nw = 2;
- }
- }
- if (!complex_pair)
- {
- if (fabs(gsl_matrix_get(S, je, je)) <= GSL_DBL_MIN &&
- fabs(gsl_matrix_get(T, je, je)) <= GSL_DBL_MIN)
- {
- /* singular matrix pencil - unit eigenvector */
- for (i = 0; i < N; ++i)
- gsl_matrix_complex_set(evec, i, je, z_zero);
- gsl_matrix_complex_set(evec, je, je, z_one);
- continue;
- }
- /* clear vector */
- for (i = 0; i < N; ++i)
- gsl_vector_set(w->work3, i, 0.0);
- }
- else
- {
- /* clear vectors */
- for (i = 0; i < N; ++i)
- {
- gsl_vector_set(w->work3, i, 0.0);
- gsl_vector_set(w->work4, i, 0.0);
- }
- }
- if (!complex_pair)
- {
- /* real eigenvalue */
- temp = 1.0 / GSL_MAX(GSL_DBL_MIN,
- GSL_MAX(fabs(gsl_matrix_get(S, je, je)) * ascale,
- fabs(gsl_matrix_get(T, je, je)) * bscale));
- salfar = (temp * gsl_matrix_get(S, je, je)) * ascale;
- sbeta = (temp * gsl_matrix_get(T, je, je)) * bscale;
- acoef = sbeta * ascale;
- bcoefr = salfar * bscale;
- bcoefi = 0.0;
- /* scale to avoid underflow */
- scale = 1.0;
- lsa = fabs(sbeta) >= GSL_DBL_MIN && fabs(acoef) < small;
- lsb = fabs(salfar) >= GSL_DBL_MIN && fabs(bcoefr) < small;
- if (lsa)
- scale = (small / fabs(sbeta)) * GSL_MIN(anorm, big);
- if (lsb)
- scale = GSL_MAX(scale, (small / fabs(salfar)) * GSL_MIN(bnorm, big));
- if (lsa || lsb)
- {
- scale = GSL_MIN(scale,
- 1.0 / (GSL_DBL_MIN *
- GSL_MAX(1.0,
- GSL_MAX(fabs(acoef), fabs(bcoefr)))));
- if (lsa)
- acoef = ascale * (scale * sbeta);
- else
- acoef *= scale;
- if (lsb)
- bcoefr = bscale * (scale * salfar);
- else
- bcoefr *= scale;
- }
- acoefa = fabs(acoef);
- bcoefa = fabs(bcoefr);
- /* first component is 1 */
- gsl_vector_set(w->work3, je, 1.0);
- xmax = 1.0;
- /* compute contribution from column je of A and B to sum */
- for (i = 0; i < je; ++i)
- {
- gsl_vector_set(w->work3, i,
- bcoefr*gsl_matrix_get(T, i, je) -
- acoef * gsl_matrix_get(S, i, je));
- }
- }
- else
- {
- gsl_matrix_const_view vs =
- gsl_matrix_const_submatrix(S, je - 1, je - 1, 2, 2);
- gsl_matrix_const_view vt =
- gsl_matrix_const_submatrix(T, je - 1, je - 1, 2, 2);
- /* complex eigenvalue */
- gsl_schur_gen_eigvals(&vs.matrix,
- &vt.matrix,
- &bcoefr,
- &temp2,
- &bcoefi,
- &acoef,
- &temp);
- if (bcoefi == 0.0)
- {
- GSL_ERROR("gsl_schur_gen_eigvals failed on complex block", GSL_FAILURE);
- }
- /* scale to avoid over/underflow */
- acoefa = fabs(acoef);
- bcoefa = fabs(bcoefr) + fabs(bcoefi);
- scale = 1.0;
- if (acoefa*GSL_DBL_EPSILON < GSL_DBL_MIN && acoefa >= GSL_DBL_MIN)
- scale = (GSL_DBL_MIN / GSL_DBL_EPSILON) / acoefa;
- if (bcoefa*GSL_DBL_EPSILON < GSL_DBL_MIN && bcoefa >= GSL_DBL_MIN)
- scale = GSL_MAX(scale, (GSL_DBL_MIN/GSL_DBL_EPSILON) / bcoefa);
- if (GSL_DBL_MIN*acoefa > ascale)
- scale = ascale / (GSL_DBL_MIN * acoefa);
- if (GSL_DBL_MIN*bcoefa > bscale)
- scale = GSL_MIN(scale, bscale / (GSL_DBL_MIN*bcoefa));
- if (scale != 1.0)
- {
- acoef *= scale;
- acoefa = fabs(acoef);
- bcoefr *= scale;
- bcoefi *= scale;
- bcoefa = fabs(bcoefr) + fabs(bcoefi);
- }
- /* compute first two components of eigenvector */
- temp = acoef * gsl_matrix_get(S, je, je - 1);
- temp2r = acoef * gsl_matrix_get(S, je, je) -
- bcoefr * gsl_matrix_get(T, je, je);
- temp2i = -bcoefi * gsl_matrix_get(T, je, je);
- if (fabs(temp) >= fabs(temp2r) + fabs(temp2i))
- {
- gsl_vector_set(w->work3, je, 1.0);
- gsl_vector_set(w->work4, je, 0.0);
- gsl_vector_set(w->work3, je - 1, -temp2r / temp);
- gsl_vector_set(w->work4, je - 1, -temp2i / temp);
- }
- else
- {
- gsl_vector_set(w->work3, je - 1, 1.0);
- gsl_vector_set(w->work4, je - 1, 0.0);
- temp = acoef * gsl_matrix_get(S, je - 1, je);
- gsl_vector_set(w->work3, je,
- (bcoefr*gsl_matrix_get(T, je - 1, je - 1) -
- acoef*gsl_matrix_get(S, je - 1, je - 1)) / temp);
- gsl_vector_set(w->work4, je,
- bcoefi*gsl_matrix_get(T, je - 1, je - 1) / temp);
- }
- xmax = GSL_MAX(fabs(gsl_vector_get(w->work3, je)) +
- fabs(gsl_vector_get(w->work4, je)),
- fabs(gsl_vector_get(w->work3, je - 1)) +
- fabs(gsl_vector_get(w->work4, je - 1)));
- /* compute contribution from column je and je - 1 */
- creala = acoef * gsl_vector_get(w->work3, je - 1);
- cimaga = acoef * gsl_vector_get(w->work4, je - 1);
- crealb = bcoefr * gsl_vector_get(w->work3, je - 1) -
- bcoefi * gsl_vector_get(w->work4, je - 1);
- cimagb = bcoefi * gsl_vector_get(w->work3, je - 1) +
- bcoefr * gsl_vector_get(w->work4, je - 1);
- cre2a = acoef * gsl_vector_get(w->work3, je);
- cim2a = acoef * gsl_vector_get(w->work4, je);
- cre2b = bcoefr * gsl_vector_get(w->work3, je) -
- bcoefi * gsl_vector_get(w->work4, je);
- cim2b = bcoefi * gsl_vector_get(w->work3, je) +
- bcoefr * gsl_vector_get(w->work4, je);
- for (i = 0; i < je - 1; ++i)
- {
- gsl_vector_set(w->work3, i,
- -creala * gsl_matrix_get(S, i, je - 1) +
- crealb * gsl_matrix_get(T, i, je - 1) -
- cre2a * gsl_matrix_get(S, i, je) +
- cre2b * gsl_matrix_get(T, i, je));
- gsl_vector_set(w->work4, i,
- -cimaga * gsl_matrix_get(S, i, je - 1) +
- cimagb * gsl_matrix_get(T, i, je - 1) -
- cim2a * gsl_matrix_get(S, i, je) +
- cim2b * gsl_matrix_get(T, i, je));
- }
- }
- dmin = GSL_MAX(GSL_DBL_MIN,
- GSL_MAX(GSL_DBL_EPSILON*acoefa*anorm,
- GSL_DBL_EPSILON*bcoefa*bnorm));
- /* triangular solve of (a A - b B) x = 0 */
- il2by2 = 0;
- for (is = (int) je - (int) nw; is >= 0; --is)
- {
- j = (size_t) is;
- if (!il2by2 && j > 0)
- {
- if (gsl_matrix_get(S, j, j - 1) != 0.0)
- {
- il2by2 = 1;
- continue;
- }
- }
- bdiag[0] = gsl_matrix_get(T, j, j);
- if (il2by2)
- {
- na = 2;
- bdiag[1] = gsl_matrix_get(T, j + 1, j + 1);
- }
- else
- na = 1;
- if (nw == 1)
- {
- gsl_matrix_const_view sv =
- gsl_matrix_const_submatrix(S, j, j, na, na);
- gsl_vector_view xv, bv;
- bv = gsl_vector_subvector(w->work3, j, na);
- /*
- * the loop below expects the solution in the first column
- * of sum, so set stride to 2
- */
- xv = gsl_vector_view_array_with_stride(sum, 2, na);
- gsl_schur_solve_equation(acoef,
- &sv.matrix,
- bcoefr,
- bdiag[0],
- bdiag[1],
- &bv.vector,
- &xv.vector,
- &scale,
- &temp,
- dmin);
- }
- else
- {
- double bdat[4];
- gsl_matrix_const_view sv =
- gsl_matrix_const_submatrix(S, j, j, na, na);
- gsl_vector_complex_view xv =
- gsl_vector_complex_view_array(sum, na);
- gsl_vector_complex_view bv =
- gsl_vector_complex_view_array(bdat, na);
- gsl_complex z;
- bdat[0] = gsl_vector_get(w->work3, j);
- bdat[1] = gsl_vector_get(w->work4, j);
- if (na == 2)
- {
- bdat[2] = gsl_vector_get(w->work3, j + 1);
- bdat[3] = gsl_vector_get(w->work4, j + 1);
- }
- GSL_SET_COMPLEX(&z, bcoefr, bcoefi);
- gsl_schur_solve_equation_z(acoef,
- &sv.matrix,
- &z,
- bdiag[0],
- bdiag[1],
- &bv.vector,
- &xv.vector,
- &scale,
- &temp,
- dmin);
- }
- if (scale < 1.0)
- {
- for (jr = 0; jr <= je; ++jr)
- {
- gsl_vector_set(w->work3, jr,
- scale * gsl_vector_get(w->work3, jr));
- if (nw == 2)
- {
- gsl_vector_set(w->work4, jr,
- scale * gsl_vector_get(w->work4, jr));
- }
- }
- }
- xmax = GSL_MAX(scale * xmax, temp);
- for (jr = 0; jr < na; ++jr)
- {
- gsl_vector_set(w->work3, j + jr, sum[jr*na]);
- if (nw == 2)
- gsl_vector_set(w->work4, j + jr, sum[jr*na + 1]);
- }
- if (j > 0)
- {
- xscale = 1.0 / GSL_MAX(1.0, xmax);
- temp = acoefa * gsl_vector_get(w->work1, j) +
- bcoefa * gsl_vector_get(w->work2, j);
- if (il2by2)
- {
- temp = GSL_MAX(temp,
- acoefa * gsl_vector_get(w->work1, j + 1) +
- bcoefa * gsl_vector_get(w->work2, j + 1));
- }
- temp = GSL_MAX(temp, GSL_MAX(acoefa, bcoefa));
- if (temp > bignum * xscale)
- {
- for (jr = 0; jr <= je; ++jr)
- {
- gsl_vector_set(w->work3, jr,
- xscale * gsl_vector_get(w->work3, jr));
- if (nw == 2)
- {
- gsl_vector_set(w->work4, jr,
- xscale * gsl_vector_get(w->work4, jr));
- }
- }
- xmax *= xscale;
- }
- for (ja = 0; ja < na; ++ja)
- {
- if (complex_pair)
- {
- creala = acoef * gsl_vector_get(w->work3, j + ja);
- cimaga = acoef * gsl_vector_get(w->work4, j + ja);
- crealb = bcoefr * gsl_vector_get(w->work3, j + ja) -
- bcoefi * gsl_vector_get(w->work4, j + ja);
- cimagb = bcoefi * gsl_vector_get(w->work3, j + ja) +
- bcoefr * gsl_vector_get(w->work4, j + ja);
- for (jr = 0; jr <= j - 1; ++jr)
- {
- gsl_vector_set(w->work3, jr,
- gsl_vector_get(w->work3, jr) -
- creala * gsl_matrix_get(S, jr, j + ja) +
- crealb * gsl_matrix_get(T, jr, j + ja));
- gsl_vector_set(w->work4, jr,
- gsl_vector_get(w->work4, jr) -
- cimaga * gsl_matrix_get(S, jr, j + ja) +
- cimagb * gsl_matrix_get(T, jr, j + ja));
- }
- }
- else
- {
- creala = acoef * gsl_vector_get(w->work3, j + ja);
- crealb = bcoefr * gsl_vector_get(w->work3, j + ja);
- for (jr = 0; jr <= j - 1; ++jr)
- {
- gsl_vector_set(w->work3, jr,
- gsl_vector_get(w->work3, jr) -
- creala * gsl_matrix_get(S, jr, j + ja) +
- crealb * gsl_matrix_get(T, jr, j + ja));
- }
- } /* if (!complex_pair) */
- } /* for (ja = 0; ja < na; ++ja) */
- } /* if (j > 0) */
- il2by2 = 0;
- } /* for (i = 0; i < je - nw; ++i) */
- for (jr = 0; jr < N; ++jr)
- {
- gsl_vector_set(w->work5, jr,
- gsl_vector_get(w->work3, 0) * gsl_matrix_get(Z, jr, 0));
- if (nw == 2)
- {
- gsl_vector_set(w->work6, jr,
- gsl_vector_get(w->work4, 0) * gsl_matrix_get(Z, jr, 0));
- }
- }
- for (jc = 1; jc <= je; ++jc)
- {
- for (jr = 0; jr < N; ++jr)
- {
- gsl_vector_set(w->work5, jr,
- gsl_vector_get(w->work5, jr) +
- gsl_vector_get(w->work3, jc) * gsl_matrix_get(Z, jr, jc));
- if (nw == 2)
- {
- gsl_vector_set(w->work6, jr,
- gsl_vector_get(w->work6, jr) +
- gsl_vector_get(w->work4, jc) * gsl_matrix_get(Z, jr, jc));
- }
- }
- }
- /* store the eigenvector */
- if (complex_pair)
- {
- ecol = gsl_matrix_complex_column(evec, je - 1);
- re = gsl_vector_complex_real(&ecol.vector);
- im = gsl_vector_complex_imag(&ecol.vector);
- ecol = gsl_matrix_complex_column(evec, je);
- re2 = gsl_vector_complex_real(&ecol.vector);
- im2 = gsl_vector_complex_imag(&ecol.vector);
- }
- else
- {
- ecol = gsl_matrix_complex_column(evec, je);
- re = gsl_vector_complex_real(&ecol.vector);
- im = gsl_vector_complex_imag(&ecol.vector);
- }
- for (jr = 0; jr < N; ++jr)
- {
- gsl_vector_set(&re.vector, jr, gsl_vector_get(w->work5, jr));
- if (complex_pair)
- {
- gsl_vector_set(&im.vector, jr, gsl_vector_get(w->work6, jr));
- gsl_vector_set(&re2.vector, jr, gsl_vector_get(w->work5, jr));
- gsl_vector_set(&im2.vector, jr, -gsl_vector_get(w->work6, jr));
- }
- else
- {
- gsl_vector_set(&im.vector, jr, 0.0);
- }
- }
- /* scale eigenvector */
- xmax = 0.0;
- if (complex_pair)
- {
- for (j = 0; j < N; ++j)
- {
- xmax = GSL_MAX(xmax,
- fabs(gsl_vector_get(&re.vector, j)) +
- fabs(gsl_vector_get(&im.vector, j)));
- }
- }
- else
- {
- for (j = 0; j < N; ++j)
- {
- xmax = GSL_MAX(xmax, fabs(gsl_vector_get(&re.vector, j)));
- }
- }
- if (xmax > GSL_DBL_MIN)
- {
- xscale = 1.0 / xmax;
- for (j = 0; j < N; ++j)
- {
- gsl_vector_set(&re.vector, j,
- gsl_vector_get(&re.vector, j) * xscale);
- if (complex_pair)
- {
- gsl_vector_set(&im.vector, j,
- gsl_vector_get(&im.vector, j) * xscale);
- gsl_vector_set(&re2.vector, j,
- gsl_vector_get(&re2.vector, j) * xscale);
- gsl_vector_set(&im2.vector, j,
- gsl_vector_get(&im2.vector, j) * xscale);
- }
- }
- }
- } /* for (k = 0; k < N; ++k) */
- return GSL_SUCCESS;
- } /* genv_get_right_eigenvectors() */
- /*
- genv_normalize_eigenvectors()
- Normalize eigenvectors so that their Euclidean norm is 1
- Inputs: alpha - eigenvalue numerators
- evec - eigenvectors
- */
- static void
- genv_normalize_eigenvectors(gsl_vector_complex *alpha,
- gsl_matrix_complex *evec)
- {
- const size_t N = evec->size1;
- size_t i; /* looping */
- gsl_complex ai;
- gsl_vector_complex_view vi;
- gsl_vector_view re, im;
- double scale; /* scaling factor */
- for (i = 0; i < N; ++i)
- {
- ai = gsl_vector_complex_get(alpha, i);
- vi = gsl_matrix_complex_column(evec, i);
- re = gsl_vector_complex_real(&vi.vector);
- if (GSL_IMAG(ai) == 0.0)
- {
- scale = 1.0 / gsl_blas_dnrm2(&re.vector);
- gsl_blas_dscal(scale, &re.vector);
- }
- else if (GSL_IMAG(ai) > 0.0)
- {
- im = gsl_vector_complex_imag(&vi.vector);
- scale = 1.0 / gsl_hypot(gsl_blas_dnrm2(&re.vector),
- gsl_blas_dnrm2(&im.vector));
- gsl_blas_zdscal(scale, &vi.vector);
- vi = gsl_matrix_complex_column(evec, i + 1);
- gsl_blas_zdscal(scale, &vi.vector);
- }
- }
- } /* genv_normalize_eigenvectors() */
|