|
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() */
|