|
Packit |
67cb25 |
/* eigen/gen.c
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Copyright (C) 2006, 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 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* This module computes the eigenvalues of a real generalized
|
|
Packit |
67cb25 |
* eigensystem A x = \lambda B x. Left and right Schur vectors
|
|
Packit |
67cb25 |
* are optionally computed as well.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Based on the algorithm from Moler and Stewart
|
|
Packit |
67cb25 |
* [1] C. Moler, G. Stewart, "An Algorithm for Generalized Matrix
|
|
Packit |
67cb25 |
* Eigenvalue Problems", SIAM J. Numer. Anal., Vol 10, No 2, 1973.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This algorithm is also described in the book
|
|
Packit |
67cb25 |
* [2] Golub & Van Loan, "Matrix Computations" (3rd ed), algorithm 7.7.3
|
|
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 |
#define GEN_ESHIFT_COEFF (1.736)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void gen_schur_decomp(gsl_matrix *H, gsl_matrix *R,
|
|
Packit |
67cb25 |
gsl_vector_complex *alpha, gsl_vector *beta,
|
|
Packit |
67cb25 |
gsl_eigen_gen_workspace *w);
|
|
Packit |
67cb25 |
static inline int gen_qzstep(gsl_matrix *H, gsl_matrix *R,
|
|
Packit |
67cb25 |
gsl_eigen_gen_workspace *w);
|
|
Packit |
67cb25 |
static inline void gen_qzstep_d(gsl_matrix *H, gsl_matrix *R,
|
|
Packit |
67cb25 |
gsl_eigen_gen_workspace *w);
|
|
Packit |
67cb25 |
static void gen_tri_split_top(gsl_matrix *H, gsl_matrix *R,
|
|
Packit |
67cb25 |
gsl_eigen_gen_workspace *w);
|
|
Packit |
67cb25 |
static inline void gen_tri_chase_zero(gsl_matrix *H, gsl_matrix *R,
|
|
Packit |
67cb25 |
size_t q,
|
|
Packit |
67cb25 |
gsl_eigen_gen_workspace *w);
|
|
Packit |
67cb25 |
static inline void gen_tri_zero_H(gsl_matrix *H, gsl_matrix *R,
|
|
Packit |
67cb25 |
gsl_eigen_gen_workspace *w);
|
|
Packit |
67cb25 |
static inline size_t gen_search_small_elements(gsl_matrix *H,
|
|
Packit |
67cb25 |
gsl_matrix *R,
|
|
Packit |
67cb25 |
int *flag,
|
|
Packit |
67cb25 |
gsl_eigen_gen_workspace *w);
|
|
Packit |
67cb25 |
static int gen_schur_standardize1(gsl_matrix *A, gsl_matrix *B,
|
|
Packit |
67cb25 |
double *alphar, double *beta,
|
|
Packit |
67cb25 |
gsl_eigen_gen_workspace *w);
|
|
Packit |
67cb25 |
static int gen_schur_standardize2(gsl_matrix *A, gsl_matrix *B,
|
|
Packit |
67cb25 |
gsl_complex *alpha1,
|
|
Packit |
67cb25 |
gsl_complex *alpha2,
|
|
Packit |
67cb25 |
double *beta1, double *beta2,
|
|
Packit |
67cb25 |
gsl_eigen_gen_workspace *w);
|
|
Packit |
67cb25 |
static int gen_compute_eigenvals(gsl_matrix *A, gsl_matrix *B,
|
|
Packit |
67cb25 |
gsl_complex *alpha1,
|
|
Packit |
67cb25 |
gsl_complex *alpha2, double *beta1,
|
|
Packit |
67cb25 |
double *beta2);
|
|
Packit |
67cb25 |
static void gen_store_eigval1(const gsl_matrix *H, const double a,
|
|
Packit |
67cb25 |
const double b, gsl_vector_complex *alpha,
|
|
Packit |
67cb25 |
gsl_vector *beta,
|
|
Packit |
67cb25 |
gsl_eigen_gen_workspace *w);
|
|
Packit |
67cb25 |
static void gen_store_eigval2(const gsl_matrix *H,
|
|
Packit |
67cb25 |
const gsl_complex *alpha1,
|
|
Packit |
67cb25 |
const double beta1,
|
|
Packit |
67cb25 |
const gsl_complex *alpha2,
|
|
Packit |
67cb25 |
const double beta2,
|
|
Packit |
67cb25 |
gsl_vector_complex *alpha,
|
|
Packit |
67cb25 |
gsl_vector *beta,
|
|
Packit |
67cb25 |
gsl_eigen_gen_workspace *w);
|
|
Packit |
67cb25 |
static inline size_t gen_get_submatrix(const gsl_matrix *A,
|
|
Packit |
67cb25 |
const gsl_matrix *B);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*FIX**/
|
|
Packit |
67cb25 |
inline static double normF (gsl_matrix * A);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_eigen_gen_alloc()
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Allocate a workspace for solving the generalized eigenvalue problem.
|
|
Packit |
67cb25 |
The size of this workspace is O(n)
|
|
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_gen_workspace *
|
|
Packit |
67cb25 |
gsl_eigen_gen_alloc(const size_t n)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_eigen_gen_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_gen_workspace *) calloc (1, sizeof (gsl_eigen_gen_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->max_iterations = 30 * n;
|
|
Packit |
67cb25 |
w->n_evals = 0;
|
|
Packit |
67cb25 |
w->n_iter = 0;
|
|
Packit |
67cb25 |
w->needtop = 0;
|
|
Packit |
67cb25 |
w->atol = 0.0;
|
|
Packit |
67cb25 |
w->btol = 0.0;
|
|
Packit |
67cb25 |
w->ascale = 0.0;
|
|
Packit |
67cb25 |
w->bscale = 0.0;
|
|
Packit |
67cb25 |
w->eshift = 0.0;
|
|
Packit |
67cb25 |
w->H = NULL;
|
|
Packit |
67cb25 |
w->R = NULL;
|
|
Packit |
67cb25 |
w->compute_s = 0;
|
|
Packit |
67cb25 |
w->compute_t = 0;
|
|
Packit |
67cb25 |
w->Q = NULL;
|
|
Packit |
67cb25 |
w->Z = NULL;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->work = gsl_vector_alloc(n);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->work == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_eigen_gen_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_gen_alloc() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_eigen_gen_free()
|
|
Packit |
67cb25 |
Free workspace w
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
void
|
|
Packit |
67cb25 |
gsl_eigen_gen_free (gsl_eigen_gen_workspace * w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
RETURN_IF_NULL (w);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->work)
|
|
Packit |
67cb25 |
gsl_vector_free(w->work);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
free(w);
|
|
Packit |
67cb25 |
} /* gsl_eigen_gen_free() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_eigen_gen_params()
|
|
Packit |
67cb25 |
Set parameters which define how we solve the eigenvalue problem
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: compute_s - 1 if we want to compute S, 0 if not
|
|
Packit |
67cb25 |
compute_t - 1 if we want to compute T, 0 if not
|
|
Packit |
67cb25 |
balance - 1 if we want to balance matrices, 0 if not
|
|
Packit |
67cb25 |
w - gen workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: none
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
void
|
|
Packit |
67cb25 |
gsl_eigen_gen_params (const int compute_s, const int compute_t,
|
|
Packit |
67cb25 |
const int balance, gsl_eigen_gen_workspace *w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
w->compute_s = compute_s;
|
|
Packit |
67cb25 |
w->compute_t = compute_t;
|
|
Packit |
67cb25 |
} /* gsl_eigen_gen_params() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_eigen_gen()
|
|
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.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: A - general real matrix
|
|
Packit |
67cb25 |
B - general real matrix
|
|
Packit |
67cb25 |
alpha - where to store eigenvalue numerators
|
|
Packit |
67cb25 |
beta - where to store eigenvalue denominators
|
|
Packit |
67cb25 |
w - workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success or error
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_eigen_gen (gsl_matrix * A, gsl_matrix * B, gsl_vector_complex * alpha,
|
|
Packit |
67cb25 |
gsl_vector * beta, gsl_eigen_gen_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
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double anorm, bnorm;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute the Hessenberg-Triangular reduction of (A, B) */
|
|
Packit |
67cb25 |
gsl_linalg_hesstri_decomp(A, B, w->Q, w->Z, w->work);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* save pointers to original matrices */
|
|
Packit |
67cb25 |
w->H = A;
|
|
Packit |
67cb25 |
w->R = B;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->n_evals = 0;
|
|
Packit |
67cb25 |
w->n_iter = 0;
|
|
Packit |
67cb25 |
w->eshift = 0.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* determine if we need to compute top indices in QZ step */
|
|
Packit |
67cb25 |
w->needtop = w->Q != 0 || w->Z != 0 || w->compute_t || w->compute_s;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute matrix norms */
|
|
Packit |
67cb25 |
anorm = normF(A);
|
|
Packit |
67cb25 |
bnorm = normF(B);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute tolerances and scaling factors */
|
|
Packit |
67cb25 |
w->atol = GSL_MAX(GSL_DBL_MIN, GSL_DBL_EPSILON * anorm);
|
|
Packit |
67cb25 |
w->btol = GSL_MAX(GSL_DBL_MIN, GSL_DBL_EPSILON * bnorm);
|
|
Packit |
67cb25 |
w->ascale = 1.0 / GSL_MAX(GSL_DBL_MIN, anorm);
|
|
Packit |
67cb25 |
w->bscale = 1.0 / GSL_MAX(GSL_DBL_MIN, bnorm);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute the generalized Schur decomposition and eigenvalues */
|
|
Packit |
67cb25 |
gen_schur_decomp(A, B, alpha, beta, w);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->n_evals != N)
|
|
Packit |
67cb25 |
return GSL_EMAXITER;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gsl_eigen_gen() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_eigen_gen_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. Optionally compute left and/or right
|
|
Packit |
67cb25 |
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 - where to store eigenvalue numerators
|
|
Packit |
67cb25 |
beta - where to store eigenvalue denominators
|
|
Packit |
67cb25 |
Q - if non-null, where to store left Schur vectors
|
|
Packit |
67cb25 |
Z - 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_gen_QZ (gsl_matrix * A, gsl_matrix * B,
|
|
Packit |
67cb25 |
gsl_vector_complex * alpha, gsl_vector * beta,
|
|
Packit |
67cb25 |
gsl_matrix * Q, gsl_matrix * Z,
|
|
Packit |
67cb25 |
gsl_eigen_gen_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_gen(A, B, alpha, beta, 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_gen_QZ() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/********************************************
|
|
Packit |
67cb25 |
* INTERNAL ROUTINES *
|
|
Packit |
67cb25 |
********************************************/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gen_schur_decomp()
|
|
Packit |
67cb25 |
Compute the generalized Schur decomposition of the matrix pencil
|
|
Packit |
67cb25 |
(H, R) which is in Hessenberg-Triangular form
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: H - upper hessenberg matrix
|
|
Packit |
67cb25 |
R - upper triangular matrix
|
|
Packit |
67cb25 |
alpha - (output) where to store eigenvalue numerators
|
|
Packit |
67cb25 |
beta - (output) where to store eigenvalue denominators
|
|
Packit |
67cb25 |
w - workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: none
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Notes: 1) w->n_evals is updated to keep track of how many eigenvalues
|
|
Packit |
67cb25 |
are found
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
gen_schur_decomp(gsl_matrix *H, gsl_matrix *R, gsl_vector_complex *alpha,
|
|
Packit |
67cb25 |
gsl_vector *beta, gsl_eigen_gen_workspace *w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t N;
|
|
Packit |
67cb25 |
gsl_matrix_view h, r;
|
|
Packit |
67cb25 |
gsl_matrix_view vh, vr;
|
|
Packit |
67cb25 |
size_t q; /* index of small subdiagonal element */
|
|
Packit |
67cb25 |
gsl_complex z1, z2; /* complex values */
|
|
Packit |
67cb25 |
double a, b;
|
|
Packit |
67cb25 |
int s;
|
|
Packit |
67cb25 |
int flag;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
N = H->size1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
h = gsl_matrix_submatrix(H, 0, 0, N, N);
|
|
Packit |
67cb25 |
r = gsl_matrix_submatrix(R, 0, 0, N, N);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
while ((N > 1) && (w->n_iter)++ < w->max_iterations)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
q = gen_search_small_elements(&h.matrix, &r.matrix, &flag, w);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (flag == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* no small elements found - do a QZ sweep */
|
|
Packit |
67cb25 |
s = gen_qzstep(&h.matrix, &r.matrix, w);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (s == GSL_CONTINUE)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* (h, r) is a 2-by-2 block with complex eigenvalues -
|
|
Packit |
67cb25 |
* standardize and read off eigenvalues
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
s = gen_schur_standardize2(&h.matrix,
|
|
Packit |
67cb25 |
&r.matrix,
|
|
Packit |
67cb25 |
&z1,
|
|
Packit |
67cb25 |
&z2,
|
|
Packit |
67cb25 |
&a,
|
|
Packit |
67cb25 |
&b,
|
|
Packit |
67cb25 |
w);
|
|
Packit |
67cb25 |
if (s != GSL_SUCCESS)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* if we get here, then the standardization process
|
|
Packit |
67cb25 |
* perturbed the eigenvalues onto the real line -
|
|
Packit |
67cb25 |
* continue QZ iteration to break them into 1-by-1
|
|
Packit |
67cb25 |
* blocks
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
continue;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gen_store_eigval2(&h.matrix, &z1, a, &z2, b, alpha, beta, w);
|
|
Packit |
67cb25 |
N = 0;
|
|
Packit |
67cb25 |
} /* if (s) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
continue;
|
|
Packit |
67cb25 |
} /* if (flag == 0) */
|
|
Packit |
67cb25 |
else if (flag == 2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (q == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* the leading element of R is zero, split off a block
|
|
Packit |
67cb25 |
* at the top
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
gen_tri_split_top(&h.matrix, &r.matrix, w);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* we found a small element on the diagonal of R - chase the
|
|
Packit |
67cb25 |
* zero to the bottom of the active block and then zero
|
|
Packit |
67cb25 |
* H(n, n - 1) to split off a 1-by-1 block
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (q != N - 1)
|
|
Packit |
67cb25 |
gen_tri_chase_zero(&h.matrix, &r.matrix, q, w);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* now zero H(n, n - 1) */
|
|
Packit |
67cb25 |
gen_tri_zero_H(&h.matrix, &r.matrix, w);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* continue so the next iteration detects the zero in H */
|
|
Packit |
67cb25 |
continue;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* a small subdiagonal element of H was found - one or two
|
|
Packit |
67cb25 |
* eigenvalues have converged or the matrix has split into
|
|
Packit |
67cb25 |
* two smaller matrices
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (q == (N - 1))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* the last subdiagonal element of the hessenberg matrix is 0 -
|
|
Packit |
67cb25 |
* H_{NN} / R_{NN} is a real eigenvalue - standardize so
|
|
Packit |
67cb25 |
* R_{NN} > 0
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
vh = gsl_matrix_submatrix(&h.matrix, q, q, 1, 1);
|
|
Packit |
67cb25 |
vr = gsl_matrix_submatrix(&r.matrix, q, q, 1, 1);
|
|
Packit |
67cb25 |
gen_schur_standardize1(&vh.matrix, &vr.matrix, &a, &b, w);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gen_store_eigval1(&vh.matrix, a, b, alpha, beta, w);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
--N;
|
|
Packit |
67cb25 |
h = gsl_matrix_submatrix(&h.matrix, 0, 0, N, N);
|
|
Packit |
67cb25 |
r = gsl_matrix_submatrix(&r.matrix, 0, 0, N, N);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (q == (N - 2))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* bottom right 2-by-2 block may have converged */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
vh = gsl_matrix_submatrix(&h.matrix, q, q, 2, 2);
|
|
Packit |
67cb25 |
vr = gsl_matrix_submatrix(&r.matrix, q, q, 2, 2);
|
|
Packit |
67cb25 |
s = gen_schur_standardize2(&vh.matrix,
|
|
Packit |
67cb25 |
&vr.matrix,
|
|
Packit |
67cb25 |
&z1,
|
|
Packit |
67cb25 |
&z2,
|
|
Packit |
67cb25 |
&a,
|
|
Packit |
67cb25 |
&b,
|
|
Packit |
67cb25 |
w);
|
|
Packit |
67cb25 |
if (s != GSL_SUCCESS)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* this 2-by-2 block contains real eigenvalues that
|
|
Packit |
67cb25 |
* have not yet separated into 1-by-1 blocks -
|
|
Packit |
67cb25 |
* recursively call gen_schur_decomp() to finish off
|
|
Packit |
67cb25 |
* this block
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
gen_schur_decomp(&vh.matrix, &vr.matrix, alpha, beta, w);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* we got 2 complex eigenvalues */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gen_store_eigval2(&vh.matrix, &z1, a, &z2, b, alpha, beta, w);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
N -= 2;
|
|
Packit |
67cb25 |
h = gsl_matrix_submatrix(&h.matrix, 0, 0, N, N);
|
|
Packit |
67cb25 |
r = gsl_matrix_submatrix(&r.matrix, 0, 0, N, N);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (q == 1)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* H_{11} / R_{11} is an eigenvalue */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
vh = gsl_matrix_submatrix(&h.matrix, 0, 0, 1, 1);
|
|
Packit |
67cb25 |
vr = gsl_matrix_submatrix(&r.matrix, 0, 0, 1, 1);
|
|
Packit |
67cb25 |
gen_schur_standardize1(&vh.matrix, &vr.matrix, &a, &b, w);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gen_store_eigval1(&vh.matrix, a, b, alpha, beta, w);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
--N;
|
|
Packit |
67cb25 |
h = gsl_matrix_submatrix(&h.matrix, 1, 1, N, N);
|
|
Packit |
67cb25 |
r = gsl_matrix_submatrix(&r.matrix, 1, 1, N, N);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (q == 2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* upper left 2-by-2 block may have converged */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
vh = gsl_matrix_submatrix(&h.matrix, 0, 0, 2, 2);
|
|
Packit |
67cb25 |
vr = gsl_matrix_submatrix(&r.matrix, 0, 0, 2, 2);
|
|
Packit |
67cb25 |
s = gen_schur_standardize2(&vh.matrix,
|
|
Packit |
67cb25 |
&vr.matrix,
|
|
Packit |
67cb25 |
&z1,
|
|
Packit |
67cb25 |
&z2,
|
|
Packit |
67cb25 |
&a,
|
|
Packit |
67cb25 |
&b,
|
|
Packit |
67cb25 |
w);
|
|
Packit |
67cb25 |
if (s != GSL_SUCCESS)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* this 2-by-2 block contains real eigenvalues that
|
|
Packit |
67cb25 |
* have not yet separated into 1-by-1 blocks -
|
|
Packit |
67cb25 |
* recursively call gen_schur_decomp() to finish off
|
|
Packit |
67cb25 |
* this block
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
gen_schur_decomp(&vh.matrix, &vr.matrix, alpha, beta, w);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* we got 2 complex eigenvalues */
|
|
Packit |
67cb25 |
gen_store_eigval2(&vh.matrix, &z1, a, &z2, b, alpha, beta, w);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
N -= 2;
|
|
Packit |
67cb25 |
h = gsl_matrix_submatrix(&h.matrix, 2, 2, N, N);
|
|
Packit |
67cb25 |
r = gsl_matrix_submatrix(&r.matrix, 2, 2, N, N);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* There is a zero element on the subdiagonal somewhere
|
|
Packit |
67cb25 |
* in the middle of the matrix - we can now operate
|
|
Packit |
67cb25 |
* separately on the two submatrices split by this
|
|
Packit |
67cb25 |
* element. q is the row index of the zero element.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* operate on lower right (N - q)-by-(N - q) block first */
|
|
Packit |
67cb25 |
vh = gsl_matrix_submatrix(&h.matrix, q, q, N - q, N - q);
|
|
Packit |
67cb25 |
vr = gsl_matrix_submatrix(&r.matrix, q, q, N - q, N - q);
|
|
Packit |
67cb25 |
gen_schur_decomp(&vh.matrix, &vr.matrix, alpha, beta, w);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* operate on upper left q-by-q block */
|
|
Packit |
67cb25 |
vh = gsl_matrix_submatrix(&h.matrix, 0, 0, q, q);
|
|
Packit |
67cb25 |
vr = gsl_matrix_submatrix(&r.matrix, 0, 0, q, q);
|
|
Packit |
67cb25 |
gen_schur_decomp(&vh.matrix, &vr.matrix, alpha, beta, w);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
N = 0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* while ((N > 1) && (w->n_iter)++ < w->max_iterations) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* handle special case of N = 1 */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (N == 1)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gen_schur_standardize1(&h.matrix, &r.matrix, &a, &b, w);
|
|
Packit |
67cb25 |
gen_store_eigval1(&h.matrix, a, b, alpha, beta, w);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gen_schur_decomp() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gen_qzstep()
|
|
Packit |
67cb25 |
This routine determines what type of QZ step to perform on
|
|
Packit |
67cb25 |
the generalized matrix pair (H, R). If the pair is 3-by-3 or bigger,
|
|
Packit |
67cb25 |
we look at the bottom right 2-by-2 block. If this block has complex
|
|
Packit |
67cb25 |
eigenvalues, we perform a Francis double shift QZ sweep. If it
|
|
Packit |
67cb25 |
has real eigenvalues, we perform an implicit single shift QZ sweep.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
If the pair is 2-by-2 with real eigenvalues, we perform a single
|
|
Packit |
67cb25 |
shift sweep. If it has complex eigenvalues, we return GSL_CONTINUE
|
|
Packit |
67cb25 |
to notify the calling function that a 2-by-2 block with complex
|
|
Packit |
67cb25 |
eigenvalues has converged, so that it may then call
|
|
Packit |
67cb25 |
gen_schur_standardize2(). In the real eigenvalue case, we want to
|
|
Packit |
67cb25 |
continue doing QZ sweeps to break it up into two 1-by-1 blocks.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
See LAPACK routine DHGEQZ and [1] for more information.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: H - upper Hessenberg matrix (at least 2-by-2)
|
|
Packit |
67cb25 |
R - upper triangular matrix (at least 2-by-2)
|
|
Packit |
67cb25 |
w - workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: GSL_SUCCESS on normal completion
|
|
Packit |
67cb25 |
GSL_CONTINUE if we detect a 2-by-2 block with complex eigenvalues
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static inline int
|
|
Packit |
67cb25 |
gen_qzstep(gsl_matrix *H, gsl_matrix *R, gsl_eigen_gen_workspace *w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t N = H->size1;
|
|
Packit |
67cb25 |
gsl_matrix_view vh, vr; /* views of bottom right 2-by-2 block */
|
|
Packit |
67cb25 |
double wr1, wr2, wi;
|
|
Packit |
67cb25 |
double scale1, scale2, scale;
|
|
Packit |
67cb25 |
double cs, sn; /* givens rotation */
|
|
Packit |
67cb25 |
double temp, /* temporary variables */
|
|
Packit |
67cb25 |
temp2;
|
|
Packit |
67cb25 |
size_t j; /* looping */
|
|
Packit |
67cb25 |
gsl_vector_view xv, yv; /* temporary views */
|
|
Packit |
67cb25 |
size_t top = 0;
|
|
Packit |
67cb25 |
size_t rows;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->n_iter % 10 == 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* Exceptional shift - we have gone 10 iterations without finding
|
|
Packit |
67cb25 |
* a new eigenvalue, do a single shift sweep with an
|
|
Packit |
67cb25 |
* exceptional shift
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if ((GSL_DBL_MIN * w->max_iterations) *
|
|
Packit |
67cb25 |
fabs(gsl_matrix_get(H, N - 2, N - 1)) <
|
|
Packit |
67cb25 |
fabs(gsl_matrix_get(R, N - 2, N - 2)))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
w->eshift += gsl_matrix_get(H, N - 2, N - 1) /
|
|
Packit |
67cb25 |
gsl_matrix_get(R, N - 2, N - 2);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
w->eshift += 1.0 / (GSL_DBL_MIN * w->max_iterations);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if ((w->eshift < GSL_DBL_EPSILON) &&
|
|
Packit |
67cb25 |
(GSL_DBL_MIN * w->max_iterations) *
|
|
Packit |
67cb25 |
fabs(gsl_matrix_get(H, N - 1, N - 2)) <
|
|
Packit |
67cb25 |
fabs(gsl_matrix_get(R, N - 2, N - 2)))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
w->eshift = GEN_ESHIFT_COEFF *
|
|
Packit |
67cb25 |
(w->ascale * gsl_matrix_get(H, N - 1, N - 2)) /
|
|
Packit |
67cb25 |
(w->bscale * gsl_matrix_get(R, N - 2, N - 2));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
scale1 = 1.0;
|
|
Packit |
67cb25 |
wr1 = w->eshift;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* Compute generalized eigenvalues of bottom right 2-by-2 block
|
|
Packit |
67cb25 |
* to be used as shifts - wr1 is the Wilkinson shift
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
vh = gsl_matrix_submatrix(H, N - 2, N - 2, 2, 2);
|
|
Packit |
67cb25 |
vr = gsl_matrix_submatrix(R, N - 2, N - 2, 2, 2);
|
|
Packit |
67cb25 |
gsl_schur_gen_eigvals(&vh.matrix,
|
|
Packit |
67cb25 |
&vr.matrix,
|
|
Packit |
67cb25 |
&wr1,
|
|
Packit |
67cb25 |
&wr2,
|
|
Packit |
67cb25 |
&wi,
|
|
Packit |
67cb25 |
&scale1,
|
|
Packit |
67cb25 |
&scale2);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (wi != 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* complex eigenvalues */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (N == 2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* its a 2-by-2 block with complex eigenvalues - notify
|
|
Packit |
67cb25 |
* the calling function to deflate
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
return (GSL_CONTINUE);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* do a francis double shift sweep */
|
|
Packit |
67cb25 |
gen_qzstep_d(H, R, w);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* real eigenvalues - perform single shift QZ step */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
temp = GSL_MIN(w->ascale, 1.0) * (0.5 / GSL_DBL_MIN);
|
|
Packit |
67cb25 |
if (scale1 > temp)
|
|
Packit |
67cb25 |
scale = temp / scale1;
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
scale = 1.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
temp = GSL_MIN(w->bscale, 1.0) * (0.5 / GSL_DBL_MIN);
|
|
Packit |
67cb25 |
if (fabs(wr1) > temp)
|
|
Packit |
67cb25 |
scale = GSL_MIN(scale, temp / fabs(wr1));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
scale1 *= scale;
|
|
Packit |
67cb25 |
wr1 *= scale;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->needtop)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* get absolute index of this matrix relative to original matrix */
|
|
Packit |
67cb25 |
top = gen_get_submatrix(w->H, H);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
temp = scale1*gsl_matrix_get(H, 0, 0) - wr1*gsl_matrix_get(R, 0, 0);
|
|
Packit |
67cb25 |
temp2 = scale1*gsl_matrix_get(H, 1, 0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_linalg_givens(temp, temp2, &cs, &sn;;
|
|
Packit |
67cb25 |
sn = -sn;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (j = 0; j < N - 1; ++j)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (j > 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
temp = gsl_matrix_get(H, j, j - 1);
|
|
Packit |
67cb25 |
temp2 = gsl_matrix_get(H, j + 1, j - 1);
|
|
Packit |
67cb25 |
gsl_linalg_givens(temp, temp2, &cs, &sn;;
|
|
Packit |
67cb25 |
sn = -sn;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* apply to column (j - 1) */
|
|
Packit |
67cb25 |
temp = cs * gsl_matrix_get(H, j, j - 1) +
|
|
Packit |
67cb25 |
sn * gsl_matrix_get(H, j + 1, j - 1);
|
|
Packit |
67cb25 |
gsl_matrix_set(H, j, j - 1, temp);
|
|
Packit |
67cb25 |
gsl_matrix_set(H, j + 1, j - 1, 0.0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* apply G to H(j:j+1,:) and T(j:j+1,:) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_s)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subrow(w->H, top + j, top + j, w->size - top - j);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subrow(w->H, top + j + 1, top + j, w->size - top - j);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subrow(H, j, j, N - j);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subrow(H, j + 1, j, N - j);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_t)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subrow(w->R, top + j, top + j, w->size - top - j);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subrow(w->R, top + j + 1, top + j, w->size - top - j);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subrow(R, j, j, N - j);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subrow(R, j + 1, j, N - j);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->Q)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* accumulate Q: Q -> QG */
|
|
Packit |
67cb25 |
xv = gsl_matrix_column(w->Q, top + j);
|
|
Packit |
67cb25 |
yv = gsl_matrix_column(w->Q, top + j + 1);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
temp = gsl_matrix_get(R, j + 1, j + 1);
|
|
Packit |
67cb25 |
temp2 = gsl_matrix_get(R, j + 1, j);
|
|
Packit |
67cb25 |
gsl_linalg_givens(temp, temp2, &cs, &sn;;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
rows = GSL_MIN(j + 3, N);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_s)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subcolumn(w->H, top + j, 0, top + rows);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subcolumn(w->H, top + j + 1, 0, top + rows);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subcolumn(H, j, 0, rows);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subcolumn(H, j + 1, 0, rows);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
rows = GSL_MIN(j + 2, N);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_t)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subcolumn(w->R, top + j, 0, top + rows);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subcolumn(w->R, top + j + 1, 0, top + rows);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subcolumn(R, j, 0, rows);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subcolumn(R, j + 1, 0, rows);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->Z)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* accumulate Z: Z -> ZG */
|
|
Packit |
67cb25 |
xv = gsl_matrix_column(w->Z, top + j);
|
|
Packit |
67cb25 |
yv = gsl_matrix_column(w->Z, top + j + 1);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* for (j = 0; j < N - 1; ++j) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
} /* gen_qzstep() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gen_qzstep_d()
|
|
Packit |
67cb25 |
Perform an implicit double shift QZ step.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
See Golub & Van Loan, "Matrix Computations" (3rd ed), algorithm 7.7.2
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: H - upper Hessenberg matrix (at least 3-by-3)
|
|
Packit |
67cb25 |
R - upper triangular matrix (at least 3-by-3)
|
|
Packit |
67cb25 |
w - workspace
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static inline void
|
|
Packit |
67cb25 |
gen_qzstep_d(gsl_matrix *H, gsl_matrix *R, gsl_eigen_gen_workspace *w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t N = H->size1;
|
|
Packit |
67cb25 |
size_t j; /* looping */
|
|
Packit |
67cb25 |
double dat[3]; /* householder vector */
|
|
Packit |
67cb25 |
double tau; /* householder coefficient */
|
|
Packit |
67cb25 |
gsl_vector_view v2, v3; /* views into 'dat' */
|
|
Packit |
67cb25 |
gsl_matrix_view m; /* temporary view */
|
|
Packit |
67cb25 |
double tmp;
|
|
Packit |
67cb25 |
size_t q, r;
|
|
Packit |
67cb25 |
size_t top = 0; /* location of H in original matrix */
|
|
Packit |
67cb25 |
double scale;
|
|
Packit |
67cb25 |
double AB11, /* various matrix element ratios */
|
|
Packit |
67cb25 |
AB22,
|
|
Packit |
67cb25 |
ABNN,
|
|
Packit |
67cb25 |
ABMM,
|
|
Packit |
67cb25 |
AMNBNN,
|
|
Packit |
67cb25 |
ANMBMM,
|
|
Packit |
67cb25 |
A21B11,
|
|
Packit |
67cb25 |
A12B22,
|
|
Packit |
67cb25 |
A32B22,
|
|
Packit |
67cb25 |
B12B22,
|
|
Packit |
67cb25 |
BMNBNN;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
v2 = gsl_vector_view_array(dat, 2);
|
|
Packit |
67cb25 |
v3 = gsl_vector_view_array(dat, 3);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->needtop)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* get absolute index of this matrix relative to original matrix */
|
|
Packit |
67cb25 |
top = gen_get_submatrix(w->H, H);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* Similar to the QR method, we take the shifts to be the two
|
|
Packit |
67cb25 |
* zeros of the problem
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* det[H(n-1:n,n-1:n) - s*R(n-1:n,n-1:n)] = 0
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* The initial householder vector elements are then given by
|
|
Packit |
67cb25 |
* Eq. 4.1 of [1], which are designed to reduce errors when
|
|
Packit |
67cb25 |
* off diagonal elements are small.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
ABMM = (w->ascale * gsl_matrix_get(H, N - 2, N - 2)) /
|
|
Packit |
67cb25 |
(w->bscale * gsl_matrix_get(R, N - 2, N - 2));
|
|
Packit |
67cb25 |
ABNN = (w->ascale * gsl_matrix_get(H, N - 1, N - 1)) /
|
|
Packit |
67cb25 |
(w->bscale * gsl_matrix_get(R, N - 1, N - 1));
|
|
Packit |
67cb25 |
AB11 = (w->ascale * gsl_matrix_get(H, 0, 0)) /
|
|
Packit |
67cb25 |
(w->bscale * gsl_matrix_get(R, 0, 0));
|
|
Packit |
67cb25 |
AB22 = (w->ascale * gsl_matrix_get(H, 1, 1)) /
|
|
Packit |
67cb25 |
(w->bscale * gsl_matrix_get(R, 1, 1));
|
|
Packit |
67cb25 |
AMNBNN = (w->ascale * gsl_matrix_get(H, N - 2, N - 1)) /
|
|
Packit |
67cb25 |
(w->bscale * gsl_matrix_get(R, N - 1, N - 1));
|
|
Packit |
67cb25 |
ANMBMM = (w->ascale * gsl_matrix_get(H, N - 1, N - 2)) /
|
|
Packit |
67cb25 |
(w->bscale * gsl_matrix_get(R, N - 2, N - 2));
|
|
Packit |
67cb25 |
BMNBNN = gsl_matrix_get(R, N - 2, N - 1) /
|
|
Packit |
67cb25 |
gsl_matrix_get(R, N - 1, N - 1);
|
|
Packit |
67cb25 |
A21B11 = (w->ascale * gsl_matrix_get(H, 1, 0)) /
|
|
Packit |
67cb25 |
(w->bscale * gsl_matrix_get(R, 0, 0));
|
|
Packit |
67cb25 |
A12B22 = (w->ascale * gsl_matrix_get(H, 0, 1)) /
|
|
Packit |
67cb25 |
(w->bscale * gsl_matrix_get(R, 1, 1));
|
|
Packit |
67cb25 |
A32B22 = (w->ascale * gsl_matrix_get(H, 2, 1)) /
|
|
Packit |
67cb25 |
(w->bscale * gsl_matrix_get(R, 1, 1));
|
|
Packit |
67cb25 |
B12B22 = gsl_matrix_get(R, 0, 1) / gsl_matrix_get(R, 1, 1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* These are the Eqs (4.1) of [1], just multiplied by the factor
|
|
Packit |
67cb25 |
* (A_{21} / B_{11})
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
dat[0] = (ABMM - AB11) * (ABNN - AB11) - (AMNBNN * ANMBMM) +
|
|
Packit |
67cb25 |
(ANMBMM * BMNBNN * AB11) + (A12B22 - (AB11 * B12B22)) * A21B11;
|
|
Packit |
67cb25 |
dat[1] = ((AB22 - AB11) - (A21B11 * B12B22) - (ABMM - AB11) -
|
|
Packit |
67cb25 |
(ABNN - AB11) + (ANMBMM * BMNBNN)) * A21B11;
|
|
Packit |
67cb25 |
dat[2] = A32B22 * A21B11;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
scale = fabs(dat[0]) + fabs(dat[1]) + fabs(dat[2]);
|
|
Packit |
67cb25 |
if (scale != 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
dat[0] /= scale;
|
|
Packit |
67cb25 |
dat[1] /= scale;
|
|
Packit |
67cb25 |
dat[2] /= scale;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (j = 0; j < N - 2; ++j)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
r = GSL_MIN(j + 4, N);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* Find householder Q so that
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Q [x y z]^t = [ * 0 0 ]^t
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
tau = gsl_linalg_householder_transform(&v3.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (tau != 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* q is the initial column to start applying the householder
|
|
Packit |
67cb25 |
* transformation. The GSL_MAX() simply ensures we don't
|
|
Packit |
67cb25 |
* try to apply it to column (-1), since we are zeroing out
|
|
Packit |
67cb25 |
* column (j - 1) except for the first iteration which
|
|
Packit |
67cb25 |
* introduces the bulge.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
q = (size_t) GSL_MAX(0, (int)j - 1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* H -> QH, R -> QR */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_s)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* We are computing the Schur form S, so we need to
|
|
Packit |
67cb25 |
* transform the whole matrix H
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(w->H,
|
|
Packit |
67cb25 |
top + j,
|
|
Packit |
67cb25 |
top + q,
|
|
Packit |
67cb25 |
3,
|
|
Packit |
67cb25 |
w->size - top - q);
|
|
Packit |
67cb25 |
gsl_linalg_householder_hm(tau, &v3.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* just transform the active block */
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(H, j, q, 3, N - q);
|
|
Packit |
67cb25 |
gsl_linalg_householder_hm(tau, &v3.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_t)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* We are computing the Schur form T, so we need to
|
|
Packit |
67cb25 |
* transform the whole matrix R
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(w->R,
|
|
Packit |
67cb25 |
top + j,
|
|
Packit |
67cb25 |
top + j,
|
|
Packit |
67cb25 |
3,
|
|
Packit |
67cb25 |
w->size - top - j);
|
|
Packit |
67cb25 |
gsl_linalg_householder_hm(tau, &v3.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* just transform the active block */
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(R, j, j, 3, N - j);
|
|
Packit |
67cb25 |
gsl_linalg_householder_hm(tau, &v3.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->Q)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* accumulate the transformation into Q */
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(w->Q, 0, top + j, w->size, 3);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v3.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* if (tau != 0.0) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* Find householder Z so that
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* [ r_{j+2,j} r_{j+2, j+1}, r_{j+2, j+2} ] Z = [ 0 0 * ]
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* This isn't exactly what gsl_linalg_householder_transform
|
|
Packit |
67cb25 |
* does, so we need to rotate the input vector so it preserves
|
|
Packit |
67cb25 |
* the last element, and then rotate it back afterwards.
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* So instead of transforming [x y z], we transform [z x y],
|
|
Packit |
67cb25 |
* and the resulting HH vector [1 v2 v3] -> [v2 v3 1] but
|
|
Packit |
67cb25 |
* then needs to be scaled to have the first element = 1, so
|
|
Packit |
67cb25 |
* it becomes [1 v3/v2 1/v2] (tau must also be scaled accordingly).
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
dat[0] = gsl_matrix_get(R, j + 2, j + 2);
|
|
Packit |
67cb25 |
dat[1] = gsl_matrix_get(R, j + 2, j);
|
|
Packit |
67cb25 |
dat[2] = gsl_matrix_get(R, j + 2, j + 1);
|
|
Packit |
67cb25 |
scale = fabs(dat[0]) + fabs(dat[1]) + fabs(dat[2]);
|
|
Packit |
67cb25 |
if (scale != 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
dat[0] /= scale;
|
|
Packit |
67cb25 |
dat[1] /= scale;
|
|
Packit |
67cb25 |
dat[2] /= scale;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
tau = gsl_linalg_householder_transform(&v3.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (tau != 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* rotate back */
|
|
Packit |
67cb25 |
tmp = gsl_vector_get(&v3.vector, 1);
|
|
Packit |
67cb25 |
gsl_vector_set(&v3.vector, 1, gsl_vector_get(&v3.vector, 2)/tmp);
|
|
Packit |
67cb25 |
gsl_vector_set(&v3.vector, 2, 1.0 / tmp);
|
|
Packit |
67cb25 |
tau *= tmp * tmp;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* H -> HZ, R -> RZ */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_s)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(w->H, 0, top + j, top + r, 3);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v3.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(H, 0, j, r, 3);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v3.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_t)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(w->R, 0, top + j, top + j + 3, 3);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v3.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(R, 0, j, j + 3, 3);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v3.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->Z)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* accumulate transformation into Z */
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(w->Z, 0, top + j, w->size, 3);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v3.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* if (tau != 0.0) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* Find householder Z so that
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* [ r_{j+1,j} r_{j+1, j+1} ] Z = [ 0 * ]
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
dat[0] = gsl_matrix_get(R, j + 1, j + 1);
|
|
Packit |
67cb25 |
dat[1] = gsl_matrix_get(R, j + 1, j);
|
|
Packit |
67cb25 |
scale = fabs(dat[0]) + fabs(dat[1]);
|
|
Packit |
67cb25 |
if (scale != 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
dat[0] /= scale;
|
|
Packit |
67cb25 |
dat[1] /= scale;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
tau = gsl_linalg_householder_transform(&v2.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (tau != 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* rotate back */
|
|
Packit |
67cb25 |
tmp = gsl_vector_get(&v2.vector, 1);
|
|
Packit |
67cb25 |
gsl_vector_set(&v2.vector, 1, 1.0 / tmp);
|
|
Packit |
67cb25 |
tau *= tmp * tmp;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* H -> HZ, R -> RZ */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_s)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(w->H, 0, top + j, top + r, 2);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(H, 0, j, r, 2);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_t)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(w->R, 0, top + j, top + j + 3, 2);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(R, 0, j, j + 3, 2);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->Z)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* accumulate transformation into Z */
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(w->Z, 0, top + j, w->size, 2);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* if (tau != 0.0) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
dat[0] = gsl_matrix_get(H, j + 1, j);
|
|
Packit |
67cb25 |
dat[1] = gsl_matrix_get(H, j + 2, j);
|
|
Packit |
67cb25 |
if (j < N - 3)
|
|
Packit |
67cb25 |
dat[2] = gsl_matrix_get(H, j + 3, j);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
scale = fabs(dat[0]) + fabs(dat[1]) + fabs(dat[2]);
|
|
Packit |
67cb25 |
if (scale != 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
dat[0] /= scale;
|
|
Packit |
67cb25 |
dat[1] /= scale;
|
|
Packit |
67cb25 |
dat[2] /= scale;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* for (j = 0; j < N - 2; ++j) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* Find Householder Q so that
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* Q [ x y ]^t = [ * 0 ]^t
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
scale = fabs(dat[0]) + fabs(dat[1]);
|
|
Packit |
67cb25 |
if (scale != 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
dat[0] /= scale;
|
|
Packit |
67cb25 |
dat[1] /= scale;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
tau = gsl_linalg_householder_transform(&v2.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_s)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(w->H,
|
|
Packit |
67cb25 |
top + N - 2,
|
|
Packit |
67cb25 |
top + N - 3,
|
|
Packit |
67cb25 |
2,
|
|
Packit |
67cb25 |
w->size - top - N + 3);
|
|
Packit |
67cb25 |
gsl_linalg_householder_hm(tau, &v2.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(H, N - 2, N - 3, 2, 3);
|
|
Packit |
67cb25 |
gsl_linalg_householder_hm(tau, &v2.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_t)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(w->R,
|
|
Packit |
67cb25 |
top + N - 2,
|
|
Packit |
67cb25 |
top + N - 2,
|
|
Packit |
67cb25 |
2,
|
|
Packit |
67cb25 |
w->size - top - N + 2);
|
|
Packit |
67cb25 |
gsl_linalg_householder_hm(tau, &v2.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(R, N - 2, N - 2, 2, 2);
|
|
Packit |
67cb25 |
gsl_linalg_householder_hm(tau, &v2.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->Q)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* accumulate the transformation into Q */
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(w->Q, 0, top + N - 2, w->size, 2);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* Find Householder Z so that
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* [ b_{n,n-1} b_{nn} ] Z = [ 0 * ]
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
dat[0] = gsl_matrix_get(R, N - 1, N - 1);
|
|
Packit |
67cb25 |
dat[1] = gsl_matrix_get(R, N - 1, N - 2);
|
|
Packit |
67cb25 |
scale = fabs(dat[0]) + fabs(dat[1]);
|
|
Packit |
67cb25 |
if (scale != 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
dat[0] /= scale;
|
|
Packit |
67cb25 |
dat[1] /= scale;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
tau = gsl_linalg_householder_transform(&v2.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* rotate back */
|
|
Packit |
67cb25 |
tmp = gsl_vector_get(&v2.vector, 1);
|
|
Packit |
67cb25 |
gsl_vector_set(&v2.vector, 1, 1.0 / tmp);
|
|
Packit |
67cb25 |
tau *= tmp * tmp;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_s)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(w->H, 0, top + N - 2, top + N, 2);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(H, 0, N - 2, N, 2);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_t)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(w->R, 0, top + N - 2, top + N, 2);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(R, 0, N - 2, N, 2);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->Z)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* accumulate the transformation into Z */
|
|
Packit |
67cb25 |
m = gsl_matrix_submatrix(w->Z, 0, top + N - 2, w->size, 2);
|
|
Packit |
67cb25 |
gsl_linalg_householder_mh(tau, &v2.vector, &m.matrix);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gen_qzstep_d() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gen_tri_split_top()
|
|
Packit |
67cb25 |
This routine is called when the leading element on the diagonal of R
|
|
Packit |
67cb25 |
has become negligible. Split off a 1-by-1 block at the top.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: H - upper hessenberg matrix
|
|
Packit |
67cb25 |
R - upper triangular matrix
|
|
Packit |
67cb25 |
w - workspace
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
gen_tri_split_top(gsl_matrix *H, gsl_matrix *R, gsl_eigen_gen_workspace *w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t N = H->size1;
|
|
Packit |
67cb25 |
size_t j, top = 0;
|
|
Packit |
67cb25 |
double cs, sn;
|
|
Packit |
67cb25 |
gsl_vector_view xv, yv;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->needtop)
|
|
Packit |
67cb25 |
top = gen_get_submatrix(w->H, H);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
j = 0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_linalg_givens(gsl_matrix_get(H, j, j),
|
|
Packit |
67cb25 |
gsl_matrix_get(H, j + 1, j),
|
|
Packit |
67cb25 |
&cs,
|
|
Packit |
67cb25 |
&sn;;
|
|
Packit |
67cb25 |
sn = -sn;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_s)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subrow(w->H, top + j, top, w->size - top);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subrow(w->H, top + j + 1, top, w->size - top);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_row(H, j);
|
|
Packit |
67cb25 |
yv = gsl_matrix_row(H, j + 1);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
gsl_matrix_set(H, j + 1, j, 0.0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_t)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subrow(w->R, top + j, top + 1, w->size - top - 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subrow(w->R, top + j + 1, top + 1, w->size - top - 1);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subrow(R, j, 1, N - 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subrow(R, j + 1, 1, N - 1);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->Q)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_column(w->Q, top + j);
|
|
Packit |
67cb25 |
yv = gsl_matrix_column(w->Q, top + j + 1);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gen_tri_split_top() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gen_tri_chase_zero()
|
|
Packit |
67cb25 |
This routine is called when an element on the diagonal of R
|
|
Packit |
67cb25 |
has become negligible. Chase the zero to the bottom of the active
|
|
Packit |
67cb25 |
block so we can split off a 1-by-1 block.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: H - upper hessenberg matrix
|
|
Packit |
67cb25 |
R - upper triangular matrix
|
|
Packit |
67cb25 |
q - index such that R(q,q) = 0 (q must be > 0)
|
|
Packit |
67cb25 |
w - workspace
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static inline void
|
|
Packit |
67cb25 |
gen_tri_chase_zero(gsl_matrix *H, gsl_matrix *R, size_t q,
|
|
Packit |
67cb25 |
gsl_eigen_gen_workspace *w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t N = H->size1;
|
|
Packit |
67cb25 |
size_t j, top = 0;
|
|
Packit |
67cb25 |
double cs, sn;
|
|
Packit |
67cb25 |
gsl_vector_view xv, yv;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->needtop)
|
|
Packit |
67cb25 |
top = gen_get_submatrix(w->H, H);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (j = q; j < N - 1; ++j)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_linalg_givens(gsl_matrix_get(R, j, j + 1),
|
|
Packit |
67cb25 |
gsl_matrix_get(R, j + 1, j + 1),
|
|
Packit |
67cb25 |
&cs,
|
|
Packit |
67cb25 |
&sn;;
|
|
Packit |
67cb25 |
sn = -sn;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_t)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subrow(w->R, top + j, top + j + 1, w->size - top - j - 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subrow(w->R, top + j + 1, top + j + 1, w->size - top - j - 1);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subrow(R, j, j + 1, N - j - 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subrow(R, j + 1, j + 1, N - j - 1);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
gsl_matrix_set(R, j + 1, j + 1, 0.0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_s)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subrow(w->H, top + j, top + j - 1, w->size - top - j + 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subrow(w->H, top + j + 1, top + j - 1, w->size - top - j + 1);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subrow(H, j, j - 1, N - j + 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subrow(H, j + 1, j - 1, N - j + 1);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->Q)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* accumulate Q */
|
|
Packit |
67cb25 |
xv = gsl_matrix_column(w->Q, top + j);
|
|
Packit |
67cb25 |
yv = gsl_matrix_column(w->Q, top + j + 1);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_linalg_givens(gsl_matrix_get(H, j + 1, j),
|
|
Packit |
67cb25 |
gsl_matrix_get(H, j + 1, j - 1),
|
|
Packit |
67cb25 |
&cs,
|
|
Packit |
67cb25 |
&sn;;
|
|
Packit |
67cb25 |
sn = -sn;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_s)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subcolumn(w->H, top + j, 0, top + j + 2);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subcolumn(w->H, top + j - 1, 0, top + j + 2);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subcolumn(H, j, 0, j + 2);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subcolumn(H, j - 1, 0, j + 2);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
gsl_matrix_set(H, j + 1, j - 1, 0.0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_t)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subcolumn(w->R, top + j, 0, top + j + 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subcolumn(w->R, top + j - 1, 0, top + j + 1);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subcolumn(R, j, 0, j + 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subcolumn(R, j - 1, 0, j + 1);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->Z)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* accumulate Z */
|
|
Packit |
67cb25 |
xv = gsl_matrix_column(w->Z, top + j);
|
|
Packit |
67cb25 |
yv = gsl_matrix_column(w->Z, top + j - 1);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gen_tri_chase_zero() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gen_tri_zero_H()
|
|
Packit |
67cb25 |
Companion function to get_tri_chase_zero(). After the zero on
|
|
Packit |
67cb25 |
the diagonal of R has been chased to the bottom, we zero the element
|
|
Packit |
67cb25 |
H(n, n - 1) in order to split off a 1-by-1 block.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static inline void
|
|
Packit |
67cb25 |
gen_tri_zero_H(gsl_matrix *H, gsl_matrix *R, gsl_eigen_gen_workspace *w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t N = H->size1;
|
|
Packit |
67cb25 |
size_t top = 0;
|
|
Packit |
67cb25 |
double cs, sn;
|
|
Packit |
67cb25 |
gsl_vector_view xv, yv;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->needtop)
|
|
Packit |
67cb25 |
top = gen_get_submatrix(w->H, H);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_linalg_givens(gsl_matrix_get(H, N - 1, N - 1),
|
|
Packit |
67cb25 |
gsl_matrix_get(H, N - 1, N - 2),
|
|
Packit |
67cb25 |
&cs,
|
|
Packit |
67cb25 |
&sn;;
|
|
Packit |
67cb25 |
sn = -sn;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_s)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subcolumn(w->H, top + N - 1, 0, top + N);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subcolumn(w->H, top + N - 2, 0, top + N);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_column(H, N - 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_column(H, N - 2);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_matrix_set(H, N - 1, N - 2, 0.0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_t)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subcolumn(w->R, top + N - 1, 0, top + N - 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subcolumn(w->R, top + N - 2, 0, top + N - 1);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subcolumn(R, N - 1, 0, N - 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subcolumn(R, N - 2, 0, N - 1);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->Z)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* accumulate Z */
|
|
Packit |
67cb25 |
xv = gsl_matrix_column(w->Z, top + N - 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_column(w->Z, top + N - 2);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gen_tri_zero_H() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gen_search_small_elements()
|
|
Packit |
67cb25 |
This routine searches for small elements in the matrix pencil
|
|
Packit |
67cb25 |
(H, R) to determine if any eigenvalues have converged.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Tests:
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
1. Test if the Hessenberg matrix has a small subdiagonal element:
|
|
Packit |
67cb25 |
H(i, i - 1) < tolerance
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
2. Test if the Triangular matrix has a small diagonal element:
|
|
Packit |
67cb25 |
R(i, i) < tolerance
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Possible outcomes:
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
(A) Neither test passed: in this case 'flag' is set to 0 and the
|
|
Packit |
67cb25 |
function returns 0
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
(B) Test 1 passes and 2 does not: in this case 'flag' is set to 1
|
|
Packit |
67cb25 |
and we return the row index i such that H(i, i - 1) < tol
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
(C) Test 2 passes and 1 does not: in this case 'flag' is set to 2
|
|
Packit |
67cb25 |
and we return the index i such that R(i, i) < tol
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
(D) Tests 1 and 2 both pass: in this case 'flag' is set to 3 and
|
|
Packit |
67cb25 |
we return the index i such that H(i, i - 1) < tol and R(i, i) < tol
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: H - upper Hessenberg matrix
|
|
Packit |
67cb25 |
R - upper Triangular matrix
|
|
Packit |
67cb25 |
flag - (output) flag set on output (see above)
|
|
Packit |
67cb25 |
w - workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: see above
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static inline size_t
|
|
Packit |
67cb25 |
gen_search_small_elements(gsl_matrix *H, gsl_matrix *R,
|
|
Packit |
67cb25 |
int *flag, gsl_eigen_gen_workspace *w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t N = H->size1;
|
|
Packit |
67cb25 |
int k;
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
int pass1 = 0;
|
|
Packit |
67cb25 |
int pass2 = 0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (k = (int) N - 1; k >= 0; --k)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
i = (size_t) k;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (i != 0 && fabs(gsl_matrix_get(H, i, i - 1)) <= w->atol)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_matrix_set(H, i, i - 1, 0.0);
|
|
Packit |
67cb25 |
pass1 = 1;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (fabs(gsl_matrix_get(R, i, i)) < w->btol)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_matrix_set(R, i, i, 0.0);
|
|
Packit |
67cb25 |
pass2 = 1;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (pass1 && !pass2) /* case B */
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
*flag = 1;
|
|
Packit |
67cb25 |
return (i);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (!pass1 && pass2) /* case C */
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
*flag = 2;
|
|
Packit |
67cb25 |
return (i);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (pass1 && pass2) /* case D */
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
*flag = 3;
|
|
Packit |
67cb25 |
return (i);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* neither test passed: case A */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*flag = 0;
|
|
Packit |
67cb25 |
return (0);
|
|
Packit |
67cb25 |
} /* gen_search_subdiag_small_elements() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gen_schur_standardize1()
|
|
Packit |
67cb25 |
This function is called when a 1-by-1 block has converged -
|
|
Packit |
67cb25 |
convert the block to standard form and update the Schur forms and
|
|
Packit |
67cb25 |
vectors if required. Standard form here means that the diagonal
|
|
Packit |
67cb25 |
element of B is positive.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: A - 1-by-1 matrix in Schur form S
|
|
Packit |
67cb25 |
B - 1-by-1 matrix in Schur form T
|
|
Packit |
67cb25 |
alphar - where to store real part of eigenvalue numerator
|
|
Packit |
67cb25 |
beta - where to store eigenvalue denominator
|
|
Packit |
67cb25 |
w - workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
gen_schur_standardize1(gsl_matrix *A, gsl_matrix *B, double *alphar,
|
|
Packit |
67cb25 |
double *beta, gsl_eigen_gen_workspace *w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
size_t top = 0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* it is a 1-by-1 block - the only requirement is that
|
|
Packit |
67cb25 |
* B_{00} is > 0, so if it isn't apply a -I transformation
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
if (gsl_matrix_get(B, 0, 0) < 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (w->needtop)
|
|
Packit |
67cb25 |
top = gen_get_submatrix(w->H, A);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_t)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (i = 0; i <= top; ++i)
|
|
Packit |
67cb25 |
gsl_matrix_set(w->R, i, top, -gsl_matrix_get(w->R, i, top));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
gsl_matrix_set(B, 0, 0, -gsl_matrix_get(B, 0, 0));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_s)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (i = 0; i <= top; ++i)
|
|
Packit |
67cb25 |
gsl_matrix_set(w->H, i, top, -gsl_matrix_get(w->H, i, top));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
gsl_matrix_set(A, 0, 0, -gsl_matrix_get(A, 0, 0));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->Z)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (i = 0; i < w->size; ++i)
|
|
Packit |
67cb25 |
gsl_matrix_set(w->Z, i, top, -gsl_matrix_get(w->Z, i, top));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*alphar = gsl_matrix_get(A, 0, 0);
|
|
Packit |
67cb25 |
*beta = gsl_matrix_get(B, 0, 0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
} /* gen_schur_standardize1() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gen_schur_standardize2()
|
|
Packit |
67cb25 |
This function is called when a 2-by-2 generalized block has
|
|
Packit |
67cb25 |
converged. Convert the block to standard form, which means B
|
|
Packit |
67cb25 |
is rotated so that
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
B = [ B11 0 ] with B11, B22 non-negative
|
|
Packit |
67cb25 |
[ 0 B22 ]
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
If the resulting block (A, B) has complex eigenvalues, they are
|
|
Packit |
67cb25 |
computed. Otherwise, the function will return GSL_CONTINUE to
|
|
Packit |
67cb25 |
notify caller that we need to do more single shift sweeps to
|
|
Packit |
67cb25 |
convert the 2-by-2 block into two 1-by-1 blocks.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: A - 2-by-2 submatrix of schur form S
|
|
Packit |
67cb25 |
B - 2-by-2 submatrix of schur form T
|
|
Packit |
67cb25 |
alpha1 - (output) where to store eigenvalue 1 numerator
|
|
Packit |
67cb25 |
alpha2 - (output) where to store eigenvalue 2 numerator
|
|
Packit |
67cb25 |
beta1 - (output) where to store eigenvalue 1 denominator
|
|
Packit |
67cb25 |
beta2 - (output) where to store eigenvalue 2 denominator
|
|
Packit |
67cb25 |
w - workspace
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: GSL_SUCCESS if block has complex eigenvalues (they are computed)
|
|
Packit |
67cb25 |
GSL_CONTINUE if block has real eigenvalues (they are not computed)
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
gen_schur_standardize2(gsl_matrix *A, gsl_matrix *B, gsl_complex *alpha1,
|
|
Packit |
67cb25 |
gsl_complex *alpha2, double *beta1, double *beta2,
|
|
Packit |
67cb25 |
gsl_eigen_gen_workspace *w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double datB[4],
|
|
Packit |
67cb25 |
datV[4],
|
|
Packit |
67cb25 |
datS[2],
|
|
Packit |
67cb25 |
work[2];
|
|
Packit |
67cb25 |
gsl_matrix_view uv = gsl_matrix_view_array(datB, 2, 2);
|
|
Packit |
67cb25 |
gsl_matrix_view vv = gsl_matrix_view_array(datV, 2, 2);
|
|
Packit |
67cb25 |
gsl_vector_view sv = gsl_vector_view_array(datS, 2);
|
|
Packit |
67cb25 |
gsl_vector_view wv = gsl_vector_view_array(work, 2);
|
|
Packit |
67cb25 |
double B11, B22;
|
|
Packit |
67cb25 |
size_t top = 0;
|
|
Packit |
67cb25 |
double det;
|
|
Packit |
67cb25 |
double cr, sr, cl, sl;
|
|
Packit |
67cb25 |
gsl_vector_view xv, yv;
|
|
Packit |
67cb25 |
int s;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->needtop)
|
|
Packit |
67cb25 |
top = gen_get_submatrix(w->H, A);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* Rotate B so that
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* B = [ B11 0 ]
|
|
Packit |
67cb25 |
* [ 0 B22 ]
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* with B11 non-negative
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_matrix_memcpy(&uv.matrix, B);
|
|
Packit |
67cb25 |
gsl_linalg_SV_decomp(&uv.matrix, &vv.matrix, &sv.vector, &wv.vector);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* Right now, B = U S V^t, where S = diag(s)
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* The SVD routine may have computed reflection matrices U and V,
|
|
Packit |
67cb25 |
* but it would be much nicer to have rotations since we won't have
|
|
Packit |
67cb25 |
* to use BLAS mat-mat multiplications to update our matrices,
|
|
Packit |
67cb25 |
* and can instead use drot. So convert them to rotations if
|
|
Packit |
67cb25 |
* necessary
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
det = gsl_matrix_get(&vv.matrix, 0, 0) * gsl_matrix_get(&vv.matrix, 1, 1) -
|
|
Packit |
67cb25 |
gsl_matrix_get(&vv.matrix, 0, 1) * gsl_matrix_get(&vv.matrix, 1, 0);
|
|
Packit |
67cb25 |
if (det < 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* V is a reflection, convert it to a rotation by inserting
|
|
Packit |
67cb25 |
* F = [1 0; 0 -1] so that:
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* B = U S [1 0] [1 0] V^t
|
|
Packit |
67cb25 |
* [0 -1] [0 -1]
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* so S -> S F and V -> V F where F is the reflection matrix
|
|
Packit |
67cb25 |
* We just need to invert S22 since the first column of V
|
|
Packit |
67cb25 |
* will remain unchanged and we can just read off the CS and SN
|
|
Packit |
67cb25 |
* parameters.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
datS[1] = -datS[1];
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
cr = gsl_matrix_get(&vv.matrix, 0, 0);
|
|
Packit |
67cb25 |
sr = gsl_matrix_get(&vv.matrix, 1, 0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* same for U */
|
|
Packit |
67cb25 |
det = gsl_matrix_get(&uv.matrix, 0, 0) * gsl_matrix_get(&uv.matrix, 1, 1) -
|
|
Packit |
67cb25 |
gsl_matrix_get(&uv.matrix, 0, 1) * gsl_matrix_get(&uv.matrix, 1, 0);
|
|
Packit |
67cb25 |
if (det < 0.0)
|
|
Packit |
67cb25 |
datS[1] = -datS[1];
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
cl = gsl_matrix_get(&uv.matrix, 0, 0);
|
|
Packit |
67cb25 |
sl = gsl_matrix_get(&uv.matrix, 1, 0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
B11 = gsl_vector_get(&sv.vector, 0);
|
|
Packit |
67cb25 |
B22 = gsl_vector_get(&sv.vector, 1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* make sure B11 is positive */
|
|
Packit |
67cb25 |
if (B11 < 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
B11 = -B11;
|
|
Packit |
67cb25 |
B22 = -B22;
|
|
Packit |
67cb25 |
cr = -cr;
|
|
Packit |
67cb25 |
sr = -sr;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* At this point,
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* [ S11 0 ] = [ CSL SNL ] B [ CSR -SNR ]
|
|
Packit |
67cb25 |
* [ 0 S22 ] [-SNL CSL ] [ SNR CSR ]
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* apply rotations to H and rest of R
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_s)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subrow(w->H, top, top, w->size - top);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subrow(w->H, top + 1, top, w->size - top);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cl, sl);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
xv = gsl_matrix_subcolumn(w->H, top, 0, top + 2);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subcolumn(w->H, top + 1, 0, top + 2);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cr, sr);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_row(A, 0);
|
|
Packit |
67cb25 |
yv = gsl_matrix_row(A, 1);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cl, sl);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
xv = gsl_matrix_column(A, 0);
|
|
Packit |
67cb25 |
yv = gsl_matrix_column(A, 1);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cr, sr);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_t)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
if (top != (w->size - 2))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subrow(w->R, top, top + 2, w->size - top - 2);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subrow(w->R, top + 1, top + 2, w->size - top - 2);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cl, sl);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (top != 0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_subcolumn(w->R, top, 0, top);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subcolumn(w->R, top + 1, 0, top);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cr, sr);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->Q)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_column(w->Q, top);
|
|
Packit |
67cb25 |
yv = gsl_matrix_column(w->Q, top + 1);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cl, sl);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->Z)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_column(w->Z, top);
|
|
Packit |
67cb25 |
yv = gsl_matrix_column(w->Z, top + 1);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cr, sr);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_matrix_set(B, 0, 0, B11);
|
|
Packit |
67cb25 |
gsl_matrix_set(B, 0, 1, 0.0);
|
|
Packit |
67cb25 |
gsl_matrix_set(B, 1, 0, 0.0);
|
|
Packit |
67cb25 |
gsl_matrix_set(B, 1, 1, B22);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* if B22 is < 0, make it positive by negating its column */
|
|
Packit |
67cb25 |
if (B22 < 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t i;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_s)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (i = 0; i < top + 2; ++i)
|
|
Packit |
67cb25 |
gsl_matrix_set(w->H, i, top + 1, -gsl_matrix_get(w->H, i, top + 1));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_matrix_set(A, 0, 1, -gsl_matrix_get(A, 0, 1));
|
|
Packit |
67cb25 |
gsl_matrix_set(A, 1, 1, -gsl_matrix_get(A, 1, 1));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->compute_t)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (i = 0; i < top + 2; ++i)
|
|
Packit |
67cb25 |
gsl_matrix_set(w->R, i, top + 1, -gsl_matrix_get(w->R, i, top + 1));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_matrix_set(B, 0, 1, -gsl_matrix_get(B, 0, 1));
|
|
Packit |
67cb25 |
gsl_matrix_set(B, 1, 1, -gsl_matrix_get(B, 1, 1));
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (w->Z)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
xv = gsl_matrix_column(w->Z, top + 1);
|
|
Packit |
67cb25 |
gsl_vector_scale(&xv.vector, -1.0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* our block is now in standard form - compute eigenvalues */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
s = gen_compute_eigenvals(A, B, alpha1, alpha2, beta1, beta2);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return s;
|
|
Packit |
67cb25 |
} /* gen_schur_standardize2() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gen_compute_eigenvals()
|
|
Packit |
67cb25 |
Compute the complex eigenvalues of a 2-by-2 block
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: GSL_CONTINUE if block contains real eigenvalues (they are not
|
|
Packit |
67cb25 |
computed)
|
|
Packit |
67cb25 |
GSL_SUCCESS on normal completion
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static int
|
|
Packit |
67cb25 |
gen_compute_eigenvals(gsl_matrix *A, gsl_matrix *B, gsl_complex *alpha1,
|
|
Packit |
67cb25 |
gsl_complex *alpha2, double *beta1, double *beta2)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double wr1, wr2, wi, scale1, scale2;
|
|
Packit |
67cb25 |
double s1inv;
|
|
Packit |
67cb25 |
double A11, A12, A21, A22;
|
|
Packit |
67cb25 |
double B11, B22;
|
|
Packit |
67cb25 |
double c11r, c11i, c12, c21, c22r, c22i;
|
|
Packit |
67cb25 |
double cz, cq;
|
|
Packit |
67cb25 |
double szr, szi, sqr, sqi;
|
|
Packit |
67cb25 |
double a1r, a1i, a2r, a2i, b1r, b1i, b1a, b2r, b2i, b2a;
|
|
Packit |
67cb25 |
double alphar, alphai;
|
|
Packit |
67cb25 |
double t1, an, bn, tempr, tempi, wabs;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* This function is called from gen_schur_standardize2() and
|
|
Packit |
67cb25 |
* its possible the standardization has perturbed the eigenvalues
|
|
Packit |
67cb25 |
* onto the real line - so check for this before computing them
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_schur_gen_eigvals(A, B, &wr1, &wr2, &wi, &scale1, &scale2);
|
|
Packit |
67cb25 |
if (wi == 0.0)
|
|
Packit |
67cb25 |
return GSL_CONTINUE; /* real eigenvalues - continue QZ iteration */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* complex eigenvalues - compute alpha and beta */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
s1inv = 1.0 / scale1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
A11 = gsl_matrix_get(A, 0, 0);
|
|
Packit |
67cb25 |
A12 = gsl_matrix_get(A, 0, 1);
|
|
Packit |
67cb25 |
A21 = gsl_matrix_get(A, 1, 0);
|
|
Packit |
67cb25 |
A22 = gsl_matrix_get(A, 1, 1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
B11 = gsl_matrix_get(B, 0, 0);
|
|
Packit |
67cb25 |
B22 = gsl_matrix_get(B, 1, 1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
c11r = scale1 * A11 - wr1 * B11;
|
|
Packit |
67cb25 |
c11i = -wi * B11;
|
|
Packit |
67cb25 |
c12 = scale1 * A12;
|
|
Packit |
67cb25 |
c21 = scale1 * A21;
|
|
Packit |
67cb25 |
c22r = scale1 * A22 - wr1 * B22;
|
|
Packit |
67cb25 |
c22i = -wi * B22;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (fabs(c11r) + fabs(c11i) + fabs(c12) >
|
|
Packit |
67cb25 |
fabs(c21) + fabs(c22r) + fabs(c22i))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
t1 = gsl_hypot3(c12, c11r, c11i);
|
|
Packit |
67cb25 |
if (t1 != 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
cz = c12 / t1;
|
|
Packit |
67cb25 |
szr = -c11r / t1;
|
|
Packit |
67cb25 |
szi = -c11i / t1;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
cz = 0.0;
|
|
Packit |
67cb25 |
szr = 1.0;
|
|
Packit |
67cb25 |
szi = 0.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
cz = hypot(c22r, c22i);
|
|
Packit |
67cb25 |
if (cz <= GSL_DBL_MIN)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
cz = 0.0;
|
|
Packit |
67cb25 |
szr = 1.0;
|
|
Packit |
67cb25 |
szi = 0.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
tempr = c22r / cz;
|
|
Packit |
67cb25 |
tempi = c22i / cz;
|
|
Packit |
67cb25 |
t1 = hypot(cz, c21);
|
|
Packit |
67cb25 |
cz /= t1;
|
|
Packit |
67cb25 |
szr = -c21*tempr / t1;
|
|
Packit |
67cb25 |
szi = c21*tempi / t1;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
an = fabs(A11) + fabs(A12) + fabs(A21) + fabs(A22);
|
|
Packit |
67cb25 |
bn = fabs(B11) + fabs(B22);
|
|
Packit |
67cb25 |
wabs = fabs(wr1) + fabs(wi);
|
|
Packit |
67cb25 |
if (scale1*an > wabs*bn)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
cq = cz * B11;
|
|
Packit |
67cb25 |
if (cq <= GSL_DBL_MIN)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
cq = 0.0;
|
|
Packit |
67cb25 |
sqr = 1.0;
|
|
Packit |
67cb25 |
sqi = 0.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
sqr = szr * B22;
|
|
Packit |
67cb25 |
sqi = -szi * B22;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
a1r = cz * A11 + szr * A12;
|
|
Packit |
67cb25 |
a1i = szi * A12;
|
|
Packit |
67cb25 |
a2r = cz * A21 + szr * A22;
|
|
Packit |
67cb25 |
a2i = szi * A22;
|
|
Packit |
67cb25 |
cq = hypot(a1r, a1i);
|
|
Packit |
67cb25 |
if (cq <= GSL_DBL_MIN)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
cq = 0.0;
|
|
Packit |
67cb25 |
sqr = 1.0;
|
|
Packit |
67cb25 |
sqi = 0.0;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
tempr = a1r / cq;
|
|
Packit |
67cb25 |
tempi = a1i / cq;
|
|
Packit |
67cb25 |
sqr = tempr * a2r + tempi * a2i;
|
|
Packit |
67cb25 |
sqi = tempi * a2r - tempr * a2i;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
t1 = gsl_hypot3(cq, sqr, sqi);
|
|
Packit |
67cb25 |
cq /= t1;
|
|
Packit |
67cb25 |
sqr /= t1;
|
|
Packit |
67cb25 |
sqi /= t1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
tempr = sqr*szr - sqi*szi;
|
|
Packit |
67cb25 |
tempi = sqr*szi + sqi*szr;
|
|
Packit |
67cb25 |
b1r = cq*cz*B11 + tempr*B22;
|
|
Packit |
67cb25 |
b1i = tempi*B22;
|
|
Packit |
67cb25 |
b1a = hypot(b1r, b1i);
|
|
Packit |
67cb25 |
b2r = cq*cz*B22 + tempr*B11;
|
|
Packit |
67cb25 |
b2i = -tempi*B11;
|
|
Packit |
67cb25 |
b2a = hypot(b2r, b2i);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
*beta1 = b1a;
|
|
Packit |
67cb25 |
*beta2 = b2a;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
alphar = (wr1 * b1a) * s1inv;
|
|
Packit |
67cb25 |
alphai = (wi * b1a) * s1inv;
|
|
Packit |
67cb25 |
GSL_SET_COMPLEX(alpha1, alphar, alphai);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
alphar = (wr1 * b2a) * s1inv;
|
|
Packit |
67cb25 |
alphai = -(wi * b2a) * s1inv;
|
|
Packit |
67cb25 |
GSL_SET_COMPLEX(alpha2, alphar, alphai);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
} /* gen_compute_eigenvals() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gen_store_eigval1()
|
|
Packit |
67cb25 |
Store eigenvalue of a 1-by-1 block into the alpha and beta
|
|
Packit |
67cb25 |
output vectors. This routine ensures that eigenvalues are stored
|
|
Packit |
67cb25 |
in the same order as they appear in the Schur form and updates
|
|
Packit |
67cb25 |
various internal workspace quantities.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
gen_store_eigval1(const gsl_matrix *H, const double a, const double b,
|
|
Packit |
67cb25 |
gsl_vector_complex *alpha,
|
|
Packit |
67cb25 |
gsl_vector *beta, gsl_eigen_gen_workspace *w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t top = gen_get_submatrix(w->H, H);
|
|
Packit |
67cb25 |
gsl_complex z;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
GSL_SET_COMPLEX(&z, a, 0.0);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_complex_set(alpha, top, z);
|
|
Packit |
67cb25 |
gsl_vector_set(beta, top, b);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->n_evals += 1;
|
|
Packit |
67cb25 |
w->n_iter = 0;
|
|
Packit |
67cb25 |
w->eshift = 0.0;
|
|
Packit |
67cb25 |
} /* gen_store_eigval1() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gen_store_eigval2()
|
|
Packit |
67cb25 |
Store eigenvalues of a 2-by-2 block into the alpha and beta
|
|
Packit |
67cb25 |
output vectors. This routine ensures that eigenvalues are stored
|
|
Packit |
67cb25 |
in the same order as they appear in the Schur form and updates
|
|
Packit |
67cb25 |
various internal workspace quantities.
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static void
|
|
Packit |
67cb25 |
gen_store_eigval2(const gsl_matrix *H, const gsl_complex *alpha1,
|
|
Packit |
67cb25 |
const double beta1, const gsl_complex *alpha2,
|
|
Packit |
67cb25 |
const double beta2, gsl_vector_complex *alpha,
|
|
Packit |
67cb25 |
gsl_vector *beta, gsl_eigen_gen_workspace *w)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t top = gen_get_submatrix(w->H, H);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_complex_set(alpha, top, *alpha1);
|
|
Packit |
67cb25 |
gsl_vector_set(beta, top, beta1);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_vector_complex_set(alpha, top + 1, *alpha2);
|
|
Packit |
67cb25 |
gsl_vector_set(beta, top + 1, beta2);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
w->n_evals += 2;
|
|
Packit |
67cb25 |
w->n_iter = 0;
|
|
Packit |
67cb25 |
w->eshift = 0.0;
|
|
Packit |
67cb25 |
} /* gen_store_eigval2() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gen_get_submatrix()
|
|
Packit |
67cb25 |
B is a submatrix of A. The goal of this function is to
|
|
Packit |
67cb25 |
compute the indices in A of where the matrix B resides
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
static inline size_t
|
|
Packit |
67cb25 |
gen_get_submatrix(const gsl_matrix *A, const gsl_matrix *B)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t diff;
|
|
Packit |
67cb25 |
double ratio;
|
|
Packit |
67cb25 |
size_t top;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
diff = (size_t) (B->data - A->data);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* B is on the diagonal of A, so measure distance in units of
|
|
Packit |
67cb25 |
tda+1 */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
ratio = (double)diff / ((double) (A->tda + 1));
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
top = (size_t) floor(ratio);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return top;
|
|
Packit |
67cb25 |
} /* gen_get_submatrix() */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* Frobenius norm */
|
|
Packit |
67cb25 |
inline static double
|
|
Packit |
67cb25 |
normF (gsl_matrix * A)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
size_t i, j, M = A->size1, N = A->size2;
|
|
Packit |
67cb25 |
double sum = 0.0, scale = 0.0, ssq = 1.0;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
for (i = 0; i < M; i++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (j = 0; j < N; j++)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double Aij = gsl_matrix_get (A, i, j);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (Aij != 0.0)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double ax = fabs (Aij);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (scale < ax)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
ssq = 1.0 + ssq * (scale / ax) * (scale / ax);
|
|
Packit |
67cb25 |
scale = ax;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
ssq += (ax / scale) * (ax / scale);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
sum = scale * sqrt (ssq);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return sum;
|
|
Packit |
67cb25 |
}
|