|
Packit |
67cb25 |
/* linalg/hesstri.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_linalg.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_matrix.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_vector.h>
|
|
Packit |
67cb25 |
#include <gsl/gsl_blas.h>
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* This module contains routines related to the Hessenberg-Triangular
|
|
Packit |
67cb25 |
* reduction of two general real matrices
|
|
Packit |
67cb25 |
*
|
|
Packit |
67cb25 |
* See Golub & Van Loan, "Matrix Computations", 3rd ed, sec 7.7.4
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
gsl_linalg_hesstri_decomp()
|
|
Packit |
67cb25 |
Perform a reduction to generalized upper Hessenberg form.
|
|
Packit |
67cb25 |
Given A and B, this function overwrites A with an upper Hessenberg
|
|
Packit |
67cb25 |
matrix H = U^T A V and B with an upper triangular matrix R = U^T B V
|
|
Packit |
67cb25 |
with U and V orthogonal.
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
See Golub & Van Loan, "Matrix Computations" (3rd ed) algorithm 7.7.1
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Inputs: A - real square matrix
|
|
Packit |
67cb25 |
B - real square matrix
|
|
Packit |
67cb25 |
U - (output) if non-null, U is stored here on output
|
|
Packit |
67cb25 |
V - (output) if non-null, V is stored here on output
|
|
Packit |
67cb25 |
work - workspace (length n)
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
Return: success or error
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
int
|
|
Packit |
67cb25 |
gsl_linalg_hesstri_decomp(gsl_matrix * A, gsl_matrix * B, gsl_matrix * U,
|
|
Packit |
67cb25 |
gsl_matrix * V, gsl_vector * work)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
const size_t N = A->size1;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if ((N != A->size2) || (N != B->size1) || (N != B->size2))
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("Hessenberg-triangular reduction requires square matrices",
|
|
Packit |
67cb25 |
GSL_ENOTSQR);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else if (N != work->size)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
GSL_ERROR ("length of workspace must match matrix dimension",
|
|
Packit |
67cb25 |
GSL_EBADLEN);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
double cs, sn; /* rotation parameters */
|
|
Packit |
67cb25 |
size_t i, j; /* looping */
|
|
Packit |
67cb25 |
gsl_vector_view xv, yv; /* temporary views */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* B -> Q^T B = R (upper triangular) */
|
|
Packit |
67cb25 |
gsl_linalg_QR_decomp(B, work);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* A -> Q^T A */
|
|
Packit |
67cb25 |
gsl_linalg_QR_QTmat(B, work, A);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* initialize U and V if desired */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (U)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
gsl_linalg_QR_unpack(B, work, U, B);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
else
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* zero out lower triangle of B */
|
|
Packit |
67cb25 |
for (j = 0; j < N - 1; ++j)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (i = j + 1; i < N; ++i)
|
|
Packit |
67cb25 |
gsl_matrix_set(B, i, j, 0.0);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (V)
|
|
Packit |
67cb25 |
gsl_matrix_set_identity(V);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (N < 3)
|
|
Packit |
67cb25 |
return GSL_SUCCESS; /* nothing more to do */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* reduce A and B */
|
|
Packit |
67cb25 |
for (j = 0; j < N - 2; ++j)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
for (i = N - 1; i >= (j + 2); --i)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* step 1: rotate rows i - 1, i to kill A(i,j) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/*
|
|
Packit |
67cb25 |
* compute G = [ CS SN ] so that G^t [ A(i-1,j) ] = [ * ]
|
|
Packit |
67cb25 |
* [-SN CS ] [ A(i, j) ] [ 0 ]
|
|
Packit |
67cb25 |
*/
|
|
Packit |
67cb25 |
gsl_linalg_givens(gsl_matrix_get(A, i - 1, j),
|
|
Packit |
67cb25 |
gsl_matrix_get(A, i, j),
|
|
Packit |
67cb25 |
&cs,
|
|
Packit |
67cb25 |
&sn;;
|
|
Packit |
67cb25 |
/* invert so drot() works correctly (G -> G^t) */
|
|
Packit |
67cb25 |
sn = -sn;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute G^t A(i-1:i, j:n) */
|
|
Packit |
67cb25 |
xv = gsl_matrix_subrow(A, i - 1, j, N - j);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subrow(A, i, j, N - j);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute G^t B(i-1:i, i-1:n) */
|
|
Packit |
67cb25 |
xv = gsl_matrix_subrow(B, i - 1, i - 1, N - i + 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subrow(B, i, i - 1, N - i + 1);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (U)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* accumulate U: U -> U G */
|
|
Packit |
67cb25 |
xv = gsl_matrix_column(U, i - 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_column(U, i);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* step 2: rotate columns i, i - 1 to kill B(i, i - 1) */
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
gsl_linalg_givens(-gsl_matrix_get(B, i, i),
|
|
Packit |
67cb25 |
gsl_matrix_get(B, i, i - 1),
|
|
Packit |
67cb25 |
&cs,
|
|
Packit |
67cb25 |
&sn;;
|
|
Packit |
67cb25 |
/* invert so drot() works correctly (G -> G^t) */
|
|
Packit |
67cb25 |
sn = -sn;
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* compute B(1:i, i-1:i) G */
|
|
Packit |
67cb25 |
xv = gsl_matrix_subcolumn(B, i - 1, 0, i + 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_subcolumn(B, i, 0, i + 1);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
/* apply to A(1:n, i-1:i) */
|
|
Packit |
67cb25 |
xv = gsl_matrix_column(A, i - 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_column(A, i);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
if (V)
|
|
Packit |
67cb25 |
{
|
|
Packit |
67cb25 |
/* accumulate V: V -> V G */
|
|
Packit |
67cb25 |
xv = gsl_matrix_column(V, i - 1);
|
|
Packit |
67cb25 |
yv = gsl_matrix_column(V, i);
|
|
Packit |
67cb25 |
gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
|
|
Packit |
67cb25 |
return GSL_SUCCESS;
|
|
Packit |
67cb25 |
}
|
|
Packit |
67cb25 |
} /* gsl_linalg_hesstri_decomp() */
|