Blame eigen/nonsymmv.c

Packit 67cb25
/* eigen/nonsymmv.c
Packit 67cb25
 * 
Packit 67cb25
 * Copyright (C) 2006 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 <config.h>
Packit 67cb25
#include <stdlib.h>
Packit 67cb25
#include <math.h>
Packit 67cb25
Packit 67cb25
#include <gsl/gsl_complex.h>
Packit 67cb25
#include <gsl/gsl_complex_math.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
Packit 67cb25
/*
Packit 67cb25
 * This module computes the eigenvalues and eigenvectors of a real
Packit 67cb25
 * nonsymmetric matrix.
Packit 67cb25
 * 
Packit 67cb25
 * This file contains routines based on original code from LAPACK
Packit 67cb25
 * which is distributed under the modified BSD license. The LAPACK
Packit 67cb25
 * routines used are DTREVC and DLALN2.
Packit 67cb25
 */
Packit 67cb25
Packit 67cb25
#define GSL_NONSYMMV_SMLNUM (2.0 * GSL_DBL_MIN)
Packit 67cb25
#define GSL_NONSYMMV_BIGNUM ((1.0 - GSL_DBL_EPSILON) / GSL_NONSYMMV_SMLNUM)
Packit 67cb25
Packit 67cb25
static void nonsymmv_get_right_eigenvectors(gsl_matrix *T, gsl_matrix *Z,
Packit 67cb25
                                            gsl_vector_complex *eval,
Packit 67cb25
                                            gsl_matrix_complex *evec,
Packit 67cb25
                                            gsl_eigen_nonsymmv_workspace *w);
Packit 67cb25
static void nonsymmv_normalize_eigenvectors(gsl_vector_complex *eval,
Packit 67cb25
                                            gsl_matrix_complex *evec);
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
gsl_eigen_nonsymmv_alloc()
Packit 67cb25
Packit 67cb25
Allocate a workspace for solving the nonsymmetric eigenvalue problem.
Packit 67cb25
The size of this workspace is O(5n).
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_nonsymmv_workspace *
Packit 67cb25
gsl_eigen_nonsymmv_alloc(const size_t n)
Packit 67cb25
{
Packit 67cb25
  gsl_eigen_nonsymmv_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_nonsymmv_workspace *)
Packit 67cb25
      calloc (1, sizeof (gsl_eigen_nonsymmv_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->Z = NULL;
Packit 67cb25
  w->nonsymm_workspace_p = gsl_eigen_nonsymm_alloc(n);
Packit 67cb25
Packit 67cb25
  if (w->nonsymm_workspace_p == 0)
Packit 67cb25
    {
Packit 67cb25
      gsl_eigen_nonsymmv_free(w);
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for nonsymm workspace", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  /*
Packit 67cb25
   * set parameters to compute the full Schur form T and balance
Packit 67cb25
   * the matrices
Packit 67cb25
   */
Packit 67cb25
  gsl_eigen_nonsymm_params(1, 0, w->nonsymm_workspace_p);
Packit 67cb25
Packit 67cb25
  w->work = gsl_vector_alloc(n);
Packit 67cb25
  w->work2 = gsl_vector_alloc(n);
Packit 67cb25
  w->work3 = gsl_vector_alloc(n);
Packit 67cb25
  if (w->work == 0 || w->work2 == 0 || w->work3 == 0)
Packit 67cb25
    {
Packit 67cb25
      gsl_eigen_nonsymmv_free(w);
Packit 67cb25
      GSL_ERROR_NULL ("failed to allocate space for nonsymmv additional workspace", GSL_ENOMEM);
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  return (w);
Packit 67cb25
} /* gsl_eigen_nonsymmv_alloc() */
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
gsl_eigen_nonsymmv_free()
Packit 67cb25
  Free workspace w
Packit 67cb25
*/
Packit 67cb25
Packit 67cb25
void
Packit 67cb25
gsl_eigen_nonsymmv_free (gsl_eigen_nonsymmv_workspace * w)
Packit 67cb25
{
Packit 67cb25
  RETURN_IF_NULL (w);
Packit 67cb25
Packit 67cb25
  if (w->nonsymm_workspace_p)
Packit 67cb25
    gsl_eigen_nonsymm_free(w->nonsymm_workspace_p);
Packit 67cb25
Packit 67cb25
  if (w->work)
Packit 67cb25
    gsl_vector_free(w->work);
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
  free(w);
Packit 67cb25
} /* gsl_eigen_nonsymmv_free() */
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
gsl_eigen_nonsymmv_params()
Packit 67cb25
  Set some parameters which define how we solve the eigenvalue
Packit 67cb25
problem.
Packit 67cb25
Packit 67cb25
Inputs: balance   - 1 if we want to balance the matrix, 0 if not
Packit 67cb25
        w         - nonsymmv workspace
Packit 67cb25
*/
Packit 67cb25
Packit 67cb25
void
Packit 67cb25
gsl_eigen_nonsymmv_params (const int balance,
Packit 67cb25
                           gsl_eigen_nonsymmv_workspace *w)
Packit 67cb25
{
Packit 67cb25
  gsl_eigen_nonsymm_params(1, balance, w->nonsymm_workspace_p);
Packit 67cb25
} /* gsl_eigen_nonsymm_params() */
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
gsl_eigen_nonsymmv()
Packit 67cb25
Packit 67cb25
Solve the nonsymmetric eigensystem problem
Packit 67cb25
Packit 67cb25
A x = \lambda x
Packit 67cb25
Packit 67cb25
for the eigenvalues \lambda and right eigenvectors x
Packit 67cb25
Packit 67cb25
Inputs: A    - general real matrix
Packit 67cb25
        eval - where to store eigenvalues
Packit 67cb25
        evec - 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_nonsymmv (gsl_matrix * A, gsl_vector_complex * eval,
Packit 67cb25
                    gsl_matrix_complex * evec,
Packit 67cb25
                    gsl_eigen_nonsymmv_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 (eval->size != N)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR ("eigenvalue vector must match matrix size", GSL_EBADLEN);
Packit 67cb25
    }
Packit 67cb25
  else if (evec->size1 != evec->size2)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR ("eigenvector matrix must be square", GSL_ENOTSQR);
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 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
      /* compute eigenvalues, Schur form, and Schur vectors */
Packit 67cb25
      s = gsl_eigen_nonsymm_Z(A, eval, &Z, w->nonsymm_workspace_p);
Packit 67cb25
Packit 67cb25
      if (w->Z)
Packit 67cb25
        {
Packit 67cb25
          /*
Packit 67cb25
           * save the Schur vectors in user supplied matrix, since
Packit 67cb25
           * they will be destroyed when computing eigenvectors
Packit 67cb25
           */
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
          nonsymmv_get_right_eigenvectors(A, &Z, eval, evec, w);
Packit 67cb25
Packit 67cb25
          /* normalize so that Euclidean norm is 1 */
Packit 67cb25
          nonsymmv_normalize_eigenvectors(eval, evec);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      return s;
Packit 67cb25
    }
Packit 67cb25
} /* gsl_eigen_nonsymmv() */
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
gsl_eigen_nonsymmv_Z()
Packit 67cb25
  Compute eigenvalues and eigenvectors of a real nonsymmetric matrix
Packit 67cb25
and also save the Schur vectors. See comments in gsl_eigen_nonsymm_Z
Packit 67cb25
for more information.
Packit 67cb25
Packit 67cb25
Inputs: A    - real nonsymmetric matrix
Packit 67cb25
        eval - where to store eigenvalues
Packit 67cb25
        evec - where to store eigenvectors
Packit 67cb25
        Z    - where to store Schur vectors
Packit 67cb25
        w    - nonsymmv workspace
Packit 67cb25
Packit 67cb25
Return: success or error
Packit 67cb25
*/
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_eigen_nonsymmv_Z (gsl_matrix * A, gsl_vector_complex * eval,
Packit 67cb25
                      gsl_matrix_complex * evec, gsl_matrix * Z,
Packit 67cb25
                      gsl_eigen_nonsymmv_workspace * w)
Packit 67cb25
{
Packit 67cb25
  /* check matrix and vector sizes */
Packit 67cb25
Packit 67cb25
  if (A->size1 != A->size2)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR ("matrix must be square to compute eigenvalues/eigenvectors", GSL_ENOTSQR);
Packit 67cb25
    }
Packit 67cb25
  else if (eval->size != A->size1)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR ("eigenvalue vector must match matrix size", GSL_EBADLEN);
Packit 67cb25
    }
Packit 67cb25
  else if (evec->size1 != evec->size2)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR ("eigenvector matrix must be square", GSL_ENOTSQR);
Packit 67cb25
    }
Packit 67cb25
  else if (evec->size1 != A->size1)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR ("eigenvector matrix has wrong size", GSL_EBADLEN);
Packit 67cb25
    }
Packit 67cb25
  else if ((Z->size1 != Z->size2) || (Z->size1 != A->size1))
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->Z = Z;
Packit 67cb25
Packit 67cb25
      s = gsl_eigen_nonsymmv(A, eval, evec, w);
Packit 67cb25
Packit 67cb25
      w->Z = NULL;
Packit 67cb25
Packit 67cb25
      return s;
Packit 67cb25
    }
Packit 67cb25
} /* gsl_eigen_nonsymmv_Z() */
Packit 67cb25
Packit 67cb25
/********************************************
Packit 67cb25
 *           INTERNAL ROUTINES              *
Packit 67cb25
 ********************************************/
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
nonsymmv_get_right_eigenvectors()
Packit 67cb25
  Compute the right eigenvectors of the Schur form T and then
Packit 67cb25
backtransform them using the Schur vectors to get right eigenvectors of
Packit 67cb25
the original matrix.
Packit 67cb25
Packit 67cb25
Inputs: T    - Schur form
Packit 67cb25
        Z    - Schur vectors
Packit 67cb25
        eval - where to store eigenvalues (to ensure that the
Packit 67cb25
               correct eigenvalue is stored in the same position
Packit 67cb25
               as the eigenvectors)
Packit 67cb25
        evec - where to store eigenvectors
Packit 67cb25
        w    - nonsymmv workspace
Packit 67cb25
Packit 67cb25
Return: none
Packit 67cb25
Packit 67cb25
Notes: 1) based on LAPACK routine DTREVC - the algorithm used is
Packit 67cb25
          backsubstitution on the upper quasi triangular system T
Packit 67cb25
          followed by backtransformation by Z to get vectors of the
Packit 67cb25
          original matrix.
Packit 67cb25
Packit 67cb25
       2) The Schur vectors in Z are destroyed and replaced with
Packit 67cb25
          eigenvectors stored with the same storage scheme as DTREVC.
Packit 67cb25
          The eigenvectors are also stored in 'evec'
Packit 67cb25
Packit 67cb25
       3) The matrix T is unchanged on output
Packit 67cb25
Packit 67cb25
       4) Each eigenvector is normalized so that the element of
Packit 67cb25
          largest magnitude has magnitude 1; here the magnitude of
Packit 67cb25
          a complex number (x,y) is taken to be |x| + |y|
Packit 67cb25
*/
Packit 67cb25
Packit 67cb25
static void
Packit 67cb25
nonsymmv_get_right_eigenvectors(gsl_matrix *T, gsl_matrix *Z,
Packit 67cb25
                                gsl_vector_complex *eval,
Packit 67cb25
                                gsl_matrix_complex *evec,
Packit 67cb25
                                gsl_eigen_nonsymmv_workspace *w)
Packit 67cb25
{
Packit 67cb25
  const size_t N = T->size1;
Packit 67cb25
  const double smlnum = GSL_DBL_MIN * N / GSL_DBL_EPSILON;
Packit 67cb25
  const double bignum = (1.0 - GSL_DBL_EPSILON) / smlnum;
Packit 67cb25
  int i;              /* looping */
Packit 67cb25
  size_t iu,          /* looping */
Packit 67cb25
         ju,
Packit 67cb25
         ii;
Packit 67cb25
  gsl_complex lambda; /* current eigenvalue */
Packit 67cb25
  double lambda_re,   /* Re(lambda) */
Packit 67cb25
         lambda_im;   /* Im(lambda) */
Packit 67cb25
  gsl_matrix_view Tv, /* temporary views */
Packit 67cb25
                  Zv;
Packit 67cb25
  gsl_vector_view y,  /* temporary views */
Packit 67cb25
                  y2,
Packit 67cb25
                  ev,
Packit 67cb25
                  ev2;
Packit 67cb25
  double dat[4],      /* scratch arrays */
Packit 67cb25
         dat_X[4];
Packit 67cb25
  double scale;       /* scale factor */
Packit 67cb25
  double xnorm;       /* |X| */
Packit 67cb25
  gsl_vector_complex_view ecol, /* column of evec */
Packit 67cb25
                          ecol2;
Packit 67cb25
  int complex_pair;   /* complex eigenvalue pair? */
Packit 67cb25
  double smin;
Packit 67cb25
Packit 67cb25
  /*
Packit 67cb25
   * Compute 1-norm of each column of upper triangular part of T
Packit 67cb25
   * to control overflow in triangular solver
Packit 67cb25
   */
Packit 67cb25
Packit 67cb25
  gsl_vector_set(w->work3, 0, 0.0);
Packit 67cb25
  for (ju = 1; ju < N; ++ju)
Packit 67cb25
    {
Packit 67cb25
      gsl_vector_set(w->work3, ju, 0.0);
Packit 67cb25
      for (iu = 0; iu < ju; ++iu)
Packit 67cb25
        {
Packit 67cb25
          gsl_vector_set(w->work3, ju,
Packit 67cb25
                         gsl_vector_get(w->work3, ju) +
Packit 67cb25
                         fabs(gsl_matrix_get(T, iu, ju)));
Packit 67cb25
        }
Packit 67cb25
    }
Packit 67cb25
Packit 67cb25
  for (i = (int) N - 1; i >= 0; --i)
Packit 67cb25
    {
Packit 67cb25
      iu = (size_t) i;
Packit 67cb25
Packit 67cb25
      /* get current eigenvalue and store it in lambda */
Packit 67cb25
      lambda_re = gsl_matrix_get(T, iu, iu);
Packit 67cb25
Packit 67cb25
      if (iu != 0 && gsl_matrix_get(T, iu, iu - 1) != 0.0)
Packit 67cb25
        {
Packit 67cb25
          lambda_im = sqrt(fabs(gsl_matrix_get(T, iu, iu - 1))) *
Packit 67cb25
                      sqrt(fabs(gsl_matrix_get(T, iu - 1, iu)));
Packit 67cb25
        }
Packit 67cb25
      else
Packit 67cb25
        {
Packit 67cb25
          lambda_im = 0.0;
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      GSL_SET_COMPLEX(&lambda, lambda_re, lambda_im);
Packit 67cb25
Packit 67cb25
      smin = GSL_MAX(GSL_DBL_EPSILON * (fabs(lambda_re) + fabs(lambda_im)),
Packit 67cb25
                     smlnum);
Packit 67cb25
      smin = GSL_MAX(smin, GSL_NONSYMMV_SMLNUM);
Packit 67cb25
Packit 67cb25
      if (lambda_im == 0.0)
Packit 67cb25
        {
Packit 67cb25
          int k, l;
Packit 67cb25
          gsl_vector_view bv, xv;
Packit 67cb25
Packit 67cb25
          /* real eigenvector */
Packit 67cb25
Packit 67cb25
          /*
Packit 67cb25
           * The ordering of eigenvalues in 'eval' is arbitrary and
Packit 67cb25
           * does not necessarily follow the Schur form T, so store
Packit 67cb25
           * lambda in the right slot in eval to ensure it corresponds
Packit 67cb25
           * to the eigenvector we are about to compute
Packit 67cb25
           */
Packit 67cb25
          gsl_vector_complex_set(eval, iu, lambda);
Packit 67cb25
Packit 67cb25
          /*
Packit 67cb25
           * We need to solve the system:
Packit 67cb25
           *
Packit 67cb25
           * (T(1:iu-1, 1:iu-1) - lambda*I)*X = -T(1:iu-1,iu)
Packit 67cb25
           */
Packit 67cb25
Packit 67cb25
          /* construct right hand side */
Packit 67cb25
          for (k = 0; k < i; ++k)
Packit 67cb25
            {
Packit 67cb25
              gsl_vector_set(w->work,
Packit 67cb25
                             (size_t) k,
Packit 67cb25
                             -gsl_matrix_get(T, (size_t) k, iu));
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          gsl_vector_set(w->work, iu, 1.0);
Packit 67cb25
Packit 67cb25
          for (l = i - 1; l >= 0; --l)
Packit 67cb25
            {
Packit 67cb25
              size_t lu = (size_t) l;
Packit 67cb25
Packit 67cb25
              if (lu == 0)
Packit 67cb25
                complex_pair = 0;
Packit 67cb25
              else
Packit 67cb25
                complex_pair = gsl_matrix_get(T, lu, lu - 1) != 0.0;
Packit 67cb25
Packit 67cb25
              if (!complex_pair)
Packit 67cb25
                {
Packit 67cb25
                  double x;
Packit 67cb25
Packit 67cb25
                  /*
Packit 67cb25
                   * 1-by-1 diagonal block - solve the system:
Packit 67cb25
                   *
Packit 67cb25
                   * (T_{ll} - lambda)*x = -T_{l(iu)}
Packit 67cb25
                   */
Packit 67cb25
Packit 67cb25
                  Tv = gsl_matrix_submatrix(T, lu, lu, 1, 1);
Packit 67cb25
                  bv = gsl_vector_view_array(dat, 1);
Packit 67cb25
                  gsl_vector_set(&bv.vector, 0,
Packit 67cb25
                                 gsl_vector_get(w->work, lu));
Packit 67cb25
                  xv = gsl_vector_view_array(dat_X, 1);
Packit 67cb25
Packit 67cb25
                  gsl_schur_solve_equation(1.0,
Packit 67cb25
                                           &Tv.matrix,
Packit 67cb25
                                           lambda_re,
Packit 67cb25
                                           1.0,
Packit 67cb25
                                           1.0,
Packit 67cb25
                                           &bv.vector,
Packit 67cb25
                                           &xv.vector,
Packit 67cb25
                                           &scale,
Packit 67cb25
                                           &xnorm,
Packit 67cb25
                                           smin);
Packit 67cb25
Packit 67cb25
                  /* scale x to avoid overflow */
Packit 67cb25
                  x = gsl_vector_get(&xv.vector, 0);
Packit 67cb25
                  if (xnorm > 1.0)
Packit 67cb25
                    {
Packit 67cb25
                      if (gsl_vector_get(w->work3, lu) > bignum / xnorm)
Packit 67cb25
                        {
Packit 67cb25
                          x /= xnorm;
Packit 67cb25
                          scale /= xnorm;
Packit 67cb25
                        }
Packit 67cb25
                    }
Packit 67cb25
Packit 67cb25
                  if (scale != 1.0)
Packit 67cb25
                    {
Packit 67cb25
                      gsl_vector_view wv;
Packit 67cb25
Packit 67cb25
                      wv = gsl_vector_subvector(w->work, 0, iu + 1);
Packit 67cb25
                      gsl_blas_dscal(scale, &wv.vector);
Packit 67cb25
                    }
Packit 67cb25
Packit 67cb25
                  gsl_vector_set(w->work, lu, x);
Packit 67cb25
Packit 67cb25
                  if (lu > 0)
Packit 67cb25
                    {
Packit 67cb25
                      gsl_vector_view v1, v2;
Packit 67cb25
Packit 67cb25
                      /* update right hand side */
Packit 67cb25
Packit 67cb25
                      v1 = gsl_matrix_subcolumn(T, lu, 0, lu);
Packit 67cb25
                      v2 = gsl_vector_subvector(w->work, 0, lu);
Packit 67cb25
                      gsl_blas_daxpy(-x, &v1.vector, &v2.vector);
Packit 67cb25
                    } /* if (l > 0) */
Packit 67cb25
                } /* if (!complex_pair) */
Packit 67cb25
              else
Packit 67cb25
                {
Packit 67cb25
                  double x11, x21;
Packit 67cb25
Packit 67cb25
                  /*
Packit 67cb25
                   * 2-by-2 diagonal block
Packit 67cb25
                   */
Packit 67cb25
Packit 67cb25
                  Tv = gsl_matrix_submatrix(T, lu - 1, lu - 1, 2, 2);
Packit 67cb25
                  bv = gsl_vector_view_array(dat, 2);
Packit 67cb25
                  gsl_vector_set(&bv.vector, 0,
Packit 67cb25
                                 gsl_vector_get(w->work, lu - 1));
Packit 67cb25
                  gsl_vector_set(&bv.vector, 1,
Packit 67cb25
                                 gsl_vector_get(w->work, lu));
Packit 67cb25
                  xv = gsl_vector_view_array(dat_X, 2);
Packit 67cb25
Packit 67cb25
                  gsl_schur_solve_equation(1.0,
Packit 67cb25
                                           &Tv.matrix,
Packit 67cb25
                                           lambda_re,
Packit 67cb25
                                           1.0,
Packit 67cb25
                                           1.0,
Packit 67cb25
                                           &bv.vector,
Packit 67cb25
                                           &xv.vector,
Packit 67cb25
                                           &scale,
Packit 67cb25
                                           &xnorm,
Packit 67cb25
                                           smin);
Packit 67cb25
Packit 67cb25
                  /* scale X(1,1) and X(2,1) to avoid overflow */
Packit 67cb25
                  x11 = gsl_vector_get(&xv.vector, 0);
Packit 67cb25
                  x21 = gsl_vector_get(&xv.vector, 1);
Packit 67cb25
Packit 67cb25
                  if (xnorm > 1.0)
Packit 67cb25
                    {
Packit 67cb25
                      double beta;
Packit 67cb25
Packit 67cb25
                      beta = GSL_MAX(gsl_vector_get(w->work3, lu - 1),
Packit 67cb25
                                     gsl_vector_get(w->work3, lu));
Packit 67cb25
                      if (beta > bignum / xnorm)
Packit 67cb25
                        {
Packit 67cb25
                          x11 /= xnorm;
Packit 67cb25
                          x21 /= xnorm;
Packit 67cb25
                          scale /= xnorm;
Packit 67cb25
                        }
Packit 67cb25
                    }
Packit 67cb25
Packit 67cb25
                  /* scale if necessary */
Packit 67cb25
                  if (scale != 1.0)
Packit 67cb25
                    {
Packit 67cb25
                      gsl_vector_view wv;
Packit 67cb25
Packit 67cb25
                      wv = gsl_vector_subvector(w->work, 0, iu + 1);
Packit 67cb25
                      gsl_blas_dscal(scale, &wv.vector);
Packit 67cb25
                    }
Packit 67cb25
Packit 67cb25
                  gsl_vector_set(w->work, lu - 1, x11);
Packit 67cb25
                  gsl_vector_set(w->work, lu, x21);
Packit 67cb25
Packit 67cb25
                  /* update right hand side */
Packit 67cb25
                  if (lu > 1)
Packit 67cb25
                    {
Packit 67cb25
                      gsl_vector_view v1, v2;
Packit 67cb25
Packit 67cb25
                      v1 = gsl_matrix_subcolumn(T, lu - 1, 0, lu - 1);
Packit 67cb25
                      v2 = gsl_vector_subvector(w->work, 0, lu - 1);
Packit 67cb25
                      gsl_blas_daxpy(-x11, &v1.vector, &v2.vector);
Packit 67cb25
Packit 67cb25
                      v1 = gsl_matrix_subcolumn(T, lu, 0, lu - 1);
Packit 67cb25
                      gsl_blas_daxpy(-x21, &v1.vector, &v2.vector);
Packit 67cb25
                    }
Packit 67cb25
Packit 67cb25
                  --l;
Packit 67cb25
                } /* if (complex_pair) */
Packit 67cb25
            } /* for (l = i - 1; l >= 0; --l) */
Packit 67cb25
Packit 67cb25
          /*
Packit 67cb25
           * At this point, w->work is an eigenvector of the
Packit 67cb25
           * Schur form T. To get an eigenvector of the original
Packit 67cb25
           * matrix, we multiply on the left by Z, the matrix of
Packit 67cb25
           * Schur vectors
Packit 67cb25
           */
Packit 67cb25
Packit 67cb25
          ecol = gsl_matrix_complex_column(evec, iu);
Packit 67cb25
          y = gsl_matrix_column(Z, iu);
Packit 67cb25
Packit 67cb25
          if (iu > 0)
Packit 67cb25
            {
Packit 67cb25
              gsl_vector_view x;
Packit 67cb25
Packit 67cb25
              Zv = gsl_matrix_submatrix(Z, 0, 0, N, iu);
Packit 67cb25
Packit 67cb25
              x = gsl_vector_subvector(w->work, 0, iu);
Packit 67cb25
Packit 67cb25
              /* compute Z * w->work and store it in Z(:,iu) */
Packit 67cb25
              gsl_blas_dgemv(CblasNoTrans,
Packit 67cb25
                             1.0,
Packit 67cb25
                             &Zv.matrix,
Packit 67cb25
                             &x.vector,
Packit 67cb25
                             gsl_vector_get(w->work, iu),
Packit 67cb25
                             &y.vector);
Packit 67cb25
            } /* if (iu > 0) */
Packit 67cb25
Packit 67cb25
          /* store eigenvector into evec */
Packit 67cb25
Packit 67cb25
          ev = gsl_vector_complex_real(&ecol.vector);
Packit 67cb25
          ev2 = gsl_vector_complex_imag(&ecol.vector);
Packit 67cb25
Packit 67cb25
          scale = 0.0;
Packit 67cb25
          for (ii = 0; ii < N; ++ii)
Packit 67cb25
            {
Packit 67cb25
              double a = gsl_vector_get(&y.vector, ii);
Packit 67cb25
Packit 67cb25
              /* store real part of eigenvector */
Packit 67cb25
              gsl_vector_set(&ev.vector, ii, a);
Packit 67cb25
Packit 67cb25
              /* set imaginary part to 0 */
Packit 67cb25
              gsl_vector_set(&ev2.vector, ii, 0.0);
Packit 67cb25
Packit 67cb25
              if (fabs(a) > scale)
Packit 67cb25
                scale = fabs(a);
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          if (scale != 0.0)
Packit 67cb25
            scale = 1.0 / scale;
Packit 67cb25
Packit 67cb25
          /* scale by magnitude of largest element */
Packit 67cb25
          gsl_blas_dscal(scale, &ev.vector);
Packit 67cb25
        } /* if (GSL_IMAG(lambda) == 0.0) */
Packit 67cb25
      else
Packit 67cb25
        {
Packit 67cb25
          gsl_vector_complex_view bv, xv;
Packit 67cb25
          size_t k;
Packit 67cb25
          int l;
Packit 67cb25
          gsl_complex lambda2;
Packit 67cb25
Packit 67cb25
          /* complex eigenvector */
Packit 67cb25
Packit 67cb25
          /*
Packit 67cb25
           * Store the complex conjugate eigenvalues in the right
Packit 67cb25
           * slots in eval
Packit 67cb25
           */
Packit 67cb25
          GSL_SET_REAL(&lambda2, GSL_REAL(lambda));
Packit 67cb25
          GSL_SET_IMAG(&lambda2, -GSL_IMAG(lambda));
Packit 67cb25
          gsl_vector_complex_set(eval, iu - 1, lambda);
Packit 67cb25
          gsl_vector_complex_set(eval, iu, lambda2);
Packit 67cb25
Packit 67cb25
          /*
Packit 67cb25
           * First solve:
Packit 67cb25
           *
Packit 67cb25
           * [ T(i:i+1,i:i+1) - lambda*I ] * X = 0
Packit 67cb25
           */
Packit 67cb25
Packit 67cb25
          if (fabs(gsl_matrix_get(T, iu - 1, iu)) >=
Packit 67cb25
              fabs(gsl_matrix_get(T, iu, iu - 1)))
Packit 67cb25
            {
Packit 67cb25
              gsl_vector_set(w->work, iu - 1, 1.0);
Packit 67cb25
              gsl_vector_set(w->work2, iu,
Packit 67cb25
                             lambda_im / gsl_matrix_get(T, iu - 1, iu));
Packit 67cb25
            }
Packit 67cb25
          else
Packit 67cb25
            {
Packit 67cb25
              gsl_vector_set(w->work, iu - 1,
Packit 67cb25
                             -lambda_im / gsl_matrix_get(T, iu, iu - 1));
Packit 67cb25
              gsl_vector_set(w->work2, iu, 1.0);
Packit 67cb25
            }
Packit 67cb25
          gsl_vector_set(w->work, iu, 0.0);
Packit 67cb25
          gsl_vector_set(w->work2, iu - 1, 0.0);
Packit 67cb25
Packit 67cb25
          /* construct right hand side */
Packit 67cb25
          for (k = 0; k < iu - 1; ++k)
Packit 67cb25
            {
Packit 67cb25
              gsl_vector_set(w->work, k,
Packit 67cb25
                             -gsl_vector_get(w->work, iu - 1) *
Packit 67cb25
                             gsl_matrix_get(T, k, iu - 1));
Packit 67cb25
              gsl_vector_set(w->work2, k,
Packit 67cb25
                             -gsl_vector_get(w->work2, iu) *
Packit 67cb25
                             gsl_matrix_get(T, k, iu));
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          /*
Packit 67cb25
           * We must solve the upper quasi-triangular system:
Packit 67cb25
           *
Packit 67cb25
           * [ T(1:i-2,1:i-2) - lambda*I ] * X = s*(work + i*work2)
Packit 67cb25
           */
Packit 67cb25
Packit 67cb25
          for (l = i - 2; l >= 0; --l)
Packit 67cb25
            {
Packit 67cb25
              size_t lu = (size_t) l;
Packit 67cb25
Packit 67cb25
              if (lu == 0)
Packit 67cb25
                complex_pair = 0;
Packit 67cb25
              else
Packit 67cb25
                complex_pair = gsl_matrix_get(T, lu, lu - 1) != 0.0;
Packit 67cb25
Packit 67cb25
              if (!complex_pair)
Packit 67cb25
                {
Packit 67cb25
                  gsl_complex bval;
Packit 67cb25
                  gsl_complex x;
Packit 67cb25
Packit 67cb25
                  /*
Packit 67cb25
                   * 1-by-1 diagonal block - solve the system:
Packit 67cb25
                   *
Packit 67cb25
                   * (T_{ll} - lambda)*x = work + i*work2
Packit 67cb25
                   */
Packit 67cb25
Packit 67cb25
                  Tv = gsl_matrix_submatrix(T, lu, lu, 1, 1);
Packit 67cb25
                  bv = gsl_vector_complex_view_array(dat, 1);
Packit 67cb25
                  xv = gsl_vector_complex_view_array(dat_X, 1);
Packit 67cb25
Packit 67cb25
                  GSL_SET_COMPLEX(&bval,
Packit 67cb25
                                  gsl_vector_get(w->work, lu),
Packit 67cb25
                                  gsl_vector_get(w->work2, lu));
Packit 67cb25
                  gsl_vector_complex_set(&bv.vector, 0, bval);
Packit 67cb25
Packit 67cb25
                  gsl_schur_solve_equation_z(1.0,
Packit 67cb25
                                             &Tv.matrix,
Packit 67cb25
                                             &lambda,
Packit 67cb25
                                             1.0,
Packit 67cb25
                                             1.0,
Packit 67cb25
                                             &bv.vector,
Packit 67cb25
                                             &xv.vector,
Packit 67cb25
                                             &scale,
Packit 67cb25
                                             &xnorm,
Packit 67cb25
                                             smin);
Packit 67cb25
Packit 67cb25
                  if (xnorm > 1.0)
Packit 67cb25
                    {
Packit 67cb25
                      if (gsl_vector_get(w->work3, lu) > bignum / xnorm)
Packit 67cb25
                        {
Packit 67cb25
                          gsl_blas_zdscal(1.0/xnorm, &xv.vector);
Packit 67cb25
                          scale /= xnorm;
Packit 67cb25
                        }
Packit 67cb25
                    }
Packit 67cb25
Packit 67cb25
                  /* scale if necessary */
Packit 67cb25
                  if (scale != 1.0)
Packit 67cb25
                    {
Packit 67cb25
                      gsl_vector_view wv;
Packit 67cb25
Packit 67cb25
                      wv = gsl_vector_subvector(w->work, 0, iu + 1);
Packit 67cb25
                      gsl_blas_dscal(scale, &wv.vector);
Packit 67cb25
                      wv = gsl_vector_subvector(w->work2, 0, iu + 1);
Packit 67cb25
                      gsl_blas_dscal(scale, &wv.vector);
Packit 67cb25
                    }
Packit 67cb25
Packit 67cb25
                  x = gsl_vector_complex_get(&xv.vector, 0);
Packit 67cb25
                  gsl_vector_set(w->work, lu, GSL_REAL(x));
Packit 67cb25
                  gsl_vector_set(w->work2, lu, GSL_IMAG(x));
Packit 67cb25
Packit 67cb25
                  /* update the right hand side */
Packit 67cb25
                  if (lu > 0)
Packit 67cb25
                    {
Packit 67cb25
                      gsl_vector_view v1, v2;
Packit 67cb25
Packit 67cb25
                      v1 = gsl_matrix_subcolumn(T, lu, 0, lu);
Packit 67cb25
                      v2 = gsl_vector_subvector(w->work, 0, lu);
Packit 67cb25
                      gsl_blas_daxpy(-GSL_REAL(x), &v1.vector, &v2.vector);
Packit 67cb25
Packit 67cb25
                      v2 = gsl_vector_subvector(w->work2, 0, lu);
Packit 67cb25
                      gsl_blas_daxpy(-GSL_IMAG(x), &v1.vector, &v2.vector);
Packit 67cb25
                    } /* if (lu > 0) */
Packit 67cb25
                } /* if (!complex_pair) */
Packit 67cb25
              else
Packit 67cb25
                {
Packit 67cb25
                  gsl_complex b1, b2, x1, x2;
Packit 67cb25
Packit 67cb25
                  /*
Packit 67cb25
                   * 2-by-2 diagonal block - solve the system
Packit 67cb25
                   */
Packit 67cb25
Packit 67cb25
                  Tv = gsl_matrix_submatrix(T, lu - 1, lu - 1, 2, 2);
Packit 67cb25
                  bv = gsl_vector_complex_view_array(dat, 2);
Packit 67cb25
                  xv = gsl_vector_complex_view_array(dat_X, 2);
Packit 67cb25
Packit 67cb25
                  GSL_SET_COMPLEX(&b1,
Packit 67cb25
                                  gsl_vector_get(w->work, lu - 1),
Packit 67cb25
                                  gsl_vector_get(w->work2, lu - 1));
Packit 67cb25
                  GSL_SET_COMPLEX(&b2,
Packit 67cb25
                                  gsl_vector_get(w->work, lu),
Packit 67cb25
                                  gsl_vector_get(w->work2, lu));
Packit 67cb25
                  gsl_vector_complex_set(&bv.vector, 0, b1);
Packit 67cb25
                  gsl_vector_complex_set(&bv.vector, 1, b2);
Packit 67cb25
Packit 67cb25
                  gsl_schur_solve_equation_z(1.0,
Packit 67cb25
                                             &Tv.matrix,
Packit 67cb25
                                             &lambda,
Packit 67cb25
                                             1.0,
Packit 67cb25
                                             1.0,
Packit 67cb25
                                             &bv.vector,
Packit 67cb25
                                             &xv.vector,
Packit 67cb25
                                             &scale,
Packit 67cb25
                                             &xnorm,
Packit 67cb25
                                             smin);
Packit 67cb25
Packit 67cb25
                  x1 = gsl_vector_complex_get(&xv.vector, 0);
Packit 67cb25
                  x2 = gsl_vector_complex_get(&xv.vector, 1);
Packit 67cb25
Packit 67cb25
                  if (xnorm > 1.0)
Packit 67cb25
                    {
Packit 67cb25
                      double beta;
Packit 67cb25
Packit 67cb25
                      beta = GSL_MAX(gsl_vector_get(w->work3, lu - 1),
Packit 67cb25
                                     gsl_vector_get(w->work3, lu));
Packit 67cb25
                      if (beta > bignum / xnorm)
Packit 67cb25
                        {
Packit 67cb25
                          gsl_blas_zdscal(1.0/xnorm, &xv.vector);
Packit 67cb25
                          scale /= xnorm;
Packit 67cb25
                        }
Packit 67cb25
                    }
Packit 67cb25
Packit 67cb25
                  /* scale if necessary */
Packit 67cb25
                  if (scale != 1.0)
Packit 67cb25
                    {
Packit 67cb25
                      gsl_vector_view wv;
Packit 67cb25
Packit 67cb25
                      wv = gsl_vector_subvector(w->work, 0, iu + 1);
Packit 67cb25
                      gsl_blas_dscal(scale, &wv.vector);
Packit 67cb25
                      wv = gsl_vector_subvector(w->work2, 0, iu + 1);
Packit 67cb25
                      gsl_blas_dscal(scale, &wv.vector);
Packit 67cb25
                    }
Packit 67cb25
                  gsl_vector_set(w->work, lu - 1, GSL_REAL(x1));
Packit 67cb25
                  gsl_vector_set(w->work, lu, GSL_REAL(x2));
Packit 67cb25
                  gsl_vector_set(w->work2, lu - 1, GSL_IMAG(x1));
Packit 67cb25
                  gsl_vector_set(w->work2, lu, GSL_IMAG(x2));
Packit 67cb25
Packit 67cb25
                  /* update right hand side */
Packit 67cb25
                  if (lu > 1)
Packit 67cb25
                    {
Packit 67cb25
                      gsl_vector_view v1, v2, v3, v4;
Packit 67cb25
Packit 67cb25
                      v1 = gsl_matrix_subcolumn(T, lu - 1, 0, lu - 1);
Packit 67cb25
                      v4 = gsl_matrix_subcolumn(T, lu, 0, lu - 1);
Packit 67cb25
                      v2 = gsl_vector_subvector(w->work, 0, lu - 1);
Packit 67cb25
                      v3 = gsl_vector_subvector(w->work2, 0, lu - 1);
Packit 67cb25
Packit 67cb25
                      gsl_blas_daxpy(-GSL_REAL(x1), &v1.vector, &v2.vector);
Packit 67cb25
                      gsl_blas_daxpy(-GSL_REAL(x2), &v4.vector, &v2.vector);
Packit 67cb25
                      gsl_blas_daxpy(-GSL_IMAG(x1), &v1.vector, &v3.vector);
Packit 67cb25
                      gsl_blas_daxpy(-GSL_IMAG(x2), &v4.vector, &v3.vector);
Packit 67cb25
                    } /* if (lu > 1) */
Packit 67cb25
Packit 67cb25
                  --l;
Packit 67cb25
                } /* if (complex_pair) */
Packit 67cb25
            } /* for (l = i - 2; l >= 0; --l) */
Packit 67cb25
Packit 67cb25
          /*
Packit 67cb25
           * At this point, work + i*work2 is an eigenvector
Packit 67cb25
           * of T - backtransform to get an eigenvector of the
Packit 67cb25
           * original matrix
Packit 67cb25
           */
Packit 67cb25
Packit 67cb25
          y = gsl_matrix_column(Z, iu - 1);
Packit 67cb25
          y2 = gsl_matrix_column(Z, iu);
Packit 67cb25
Packit 67cb25
          if (iu > 1)
Packit 67cb25
            {
Packit 67cb25
              gsl_vector_view x;
Packit 67cb25
Packit 67cb25
              /* compute real part of eigenvectors */
Packit 67cb25
Packit 67cb25
              Zv = gsl_matrix_submatrix(Z, 0, 0, N, iu - 1);
Packit 67cb25
              x = gsl_vector_subvector(w->work, 0, iu - 1);
Packit 67cb25
Packit 67cb25
              gsl_blas_dgemv(CblasNoTrans,
Packit 67cb25
                             1.0,
Packit 67cb25
                             &Zv.matrix,
Packit 67cb25
                             &x.vector,
Packit 67cb25
                             gsl_vector_get(w->work, iu - 1),
Packit 67cb25
                             &y.vector);
Packit 67cb25
Packit 67cb25
Packit 67cb25
              /* now compute the imaginary part */
Packit 67cb25
              x = gsl_vector_subvector(w->work2, 0, iu - 1);
Packit 67cb25
Packit 67cb25
              gsl_blas_dgemv(CblasNoTrans,
Packit 67cb25
                             1.0,
Packit 67cb25
                             &Zv.matrix,
Packit 67cb25
                             &x.vector,
Packit 67cb25
                             gsl_vector_get(w->work2, iu),
Packit 67cb25
                             &y2.vector);
Packit 67cb25
            }
Packit 67cb25
          else
Packit 67cb25
            {
Packit 67cb25
              gsl_blas_dscal(gsl_vector_get(w->work, iu - 1), &y.vector);
Packit 67cb25
              gsl_blas_dscal(gsl_vector_get(w->work2, iu), &y2.vector);
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          /*
Packit 67cb25
           * Now store the eigenvectors into evec - the real parts
Packit 67cb25
           * are Z(:,iu - 1) and the imaginary parts are
Packit 67cb25
           * +/- Z(:,iu)
Packit 67cb25
           */
Packit 67cb25
Packit 67cb25
          /* get views of the two eigenvector slots */
Packit 67cb25
          ecol = gsl_matrix_complex_column(evec, iu - 1);
Packit 67cb25
          ecol2 = gsl_matrix_complex_column(evec, iu);
Packit 67cb25
Packit 67cb25
          /*
Packit 67cb25
           * save imaginary part first as it may get overwritten
Packit 67cb25
           * when copying the real part due to our storage scheme
Packit 67cb25
           * in Z/evec
Packit 67cb25
           */
Packit 67cb25
          ev = gsl_vector_complex_imag(&ecol.vector);
Packit 67cb25
          ev2 = gsl_vector_complex_imag(&ecol2.vector);
Packit 67cb25
          scale = 0.0;
Packit 67cb25
          for (ii = 0; ii < N; ++ii)
Packit 67cb25
            {
Packit 67cb25
              double a = gsl_vector_get(&y2.vector, ii);
Packit 67cb25
Packit 67cb25
              scale = GSL_MAX(scale,
Packit 67cb25
                              fabs(a) + fabs(gsl_vector_get(&y.vector, ii)));
Packit 67cb25
Packit 67cb25
              gsl_vector_set(&ev.vector, ii, a);
Packit 67cb25
              gsl_vector_set(&ev2.vector, ii, -a);
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          /* now save the real part */
Packit 67cb25
          ev = gsl_vector_complex_real(&ecol.vector);
Packit 67cb25
          ev2 = gsl_vector_complex_real(&ecol2.vector);
Packit 67cb25
          for (ii = 0; ii < N; ++ii)
Packit 67cb25
            {
Packit 67cb25
              double a = gsl_vector_get(&y.vector, ii);
Packit 67cb25
Packit 67cb25
              gsl_vector_set(&ev.vector, ii, a);
Packit 67cb25
              gsl_vector_set(&ev2.vector, ii, a);
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          if (scale != 0.0)
Packit 67cb25
            scale = 1.0 / scale;
Packit 67cb25
Packit 67cb25
          /* scale by largest element magnitude */
Packit 67cb25
Packit 67cb25
          gsl_blas_zdscal(scale, &ecol.vector);
Packit 67cb25
          gsl_blas_zdscal(scale, &ecol2.vector);
Packit 67cb25
Packit 67cb25
          /*
Packit 67cb25
           * decrement i since we took care of two eigenvalues at
Packit 67cb25
           * the same time
Packit 67cb25
           */
Packit 67cb25
          --i;
Packit 67cb25
        } /* if (GSL_IMAG(lambda) != 0.0) */
Packit 67cb25
    } /* for (i = (int) N - 1; i >= 0; --i) */
Packit 67cb25
} /* nonsymmv_get_right_eigenvectors() */
Packit 67cb25
Packit 67cb25
/*
Packit 67cb25
nonsymmv_normalize_eigenvectors()
Packit 67cb25
  Normalize eigenvectors so that their Euclidean norm is 1
Packit 67cb25
Packit 67cb25
Inputs: eval - eigenvalues
Packit 67cb25
        evec - eigenvectors
Packit 67cb25
*/
Packit 67cb25
Packit 67cb25
static void
Packit 67cb25
nonsymmv_normalize_eigenvectors(gsl_vector_complex *eval,
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 ei;
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
      ei = gsl_vector_complex_get(eval, 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(ei) == 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(ei) > 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
} /* nonsymmv_normalize_eigenvectors() */