Blame eigen/genv.c

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