Blame linalg/hesstri.c

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