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