Blame linalg/hh.c

Packit 67cb25
/* linalg/hh.c
Packit 67cb25
 * 
Packit 67cb25
 * Copyright (C) 1996, 1997, 1998, 1999, 2000, 2007 Gerard Jungman, Brian Gough
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
/* Author:  G. Jungman */
Packit 67cb25
Packit 67cb25
#include <config.h>
Packit 67cb25
#include <stdlib.h>
Packit 67cb25
#include <gsl/gsl_math.h>
Packit 67cb25
#include <gsl/gsl_vector.h>
Packit 67cb25
#include <gsl/gsl_matrix.h>
Packit 67cb25
#include <gsl/gsl_linalg.h>
Packit 67cb25
Packit 67cb25
#define REAL double
Packit 67cb25
Packit 67cb25
/* [Engeln-Mullges + Uhlig, Alg. 4.42]
Packit 67cb25
 */
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_linalg_HH_solve (gsl_matrix * A, const gsl_vector * b, gsl_vector * x)
Packit 67cb25
{
Packit 67cb25
  if (A->size1 > A->size2)
Packit 67cb25
    {
Packit 67cb25
      /* System is underdetermined. */
Packit 67cb25
Packit 67cb25
      GSL_ERROR ("System is underdetermined", GSL_EINVAL);
Packit 67cb25
    }
Packit 67cb25
  else if (A->size2 != x->size)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR ("matrix and vector sizes must be equal", GSL_EBADLEN);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      int status ;
Packit 67cb25
Packit 67cb25
      gsl_vector_memcpy (x, b);
Packit 67cb25
Packit 67cb25
      status = gsl_linalg_HH_svx (A, x);
Packit 67cb25
      
Packit 67cb25
      return status ;
Packit 67cb25
    }
Packit 67cb25
}
Packit 67cb25
Packit 67cb25
int
Packit 67cb25
gsl_linalg_HH_svx (gsl_matrix * A, gsl_vector * x)
Packit 67cb25
{
Packit 67cb25
  if (A->size1 > A->size2)
Packit 67cb25
    {
Packit 67cb25
      /* System is underdetermined. */
Packit 67cb25
Packit 67cb25
      GSL_ERROR ("System is underdetermined", GSL_EINVAL);
Packit 67cb25
    }
Packit 67cb25
  else if (A->size2 != x->size)
Packit 67cb25
    {
Packit 67cb25
      GSL_ERROR ("matrix and vector sizes must be equal", GSL_EBADLEN);
Packit 67cb25
    }
Packit 67cb25
  else
Packit 67cb25
    {
Packit 67cb25
      const size_t N = A->size1;
Packit 67cb25
      const size_t M = A->size2;
Packit 67cb25
      size_t i, j, k;
Packit 67cb25
      REAL *d = (REAL *) malloc (N * sizeof (REAL));
Packit 67cb25
Packit 67cb25
      if (d == 0)
Packit 67cb25
        {
Packit 67cb25
          GSL_ERROR ("could not allocate memory for workspace", GSL_ENOMEM);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      /* Perform Householder transformation. */
Packit 67cb25
Packit 67cb25
      for (i = 0; i < N; i++)
Packit 67cb25
        {
Packit 67cb25
          const REAL aii = gsl_matrix_get (A, i, i);
Packit 67cb25
          REAL alpha;
Packit 67cb25
          REAL f;
Packit 67cb25
          REAL ak;
Packit 67cb25
          REAL max_norm = 0.0;
Packit 67cb25
          REAL r = 0.0;
Packit 67cb25
Packit 67cb25
          for (k = i; k < M; k++)
Packit 67cb25
            {
Packit 67cb25
              REAL aki = gsl_matrix_get (A, k, i);
Packit 67cb25
              r += aki * aki;
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          if (r == 0.0)
Packit 67cb25
            {
Packit 67cb25
              /* Rank of matrix is less than size1. */
Packit 67cb25
              free (d);
Packit 67cb25
              GSL_ERROR ("matrix is rank deficient", GSL_ESING);
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          alpha = sqrt (r) * GSL_SIGN (aii);
Packit 67cb25
Packit 67cb25
          ak = 1.0 / (r + alpha * aii);
Packit 67cb25
          gsl_matrix_set (A, i, i, aii + alpha);
Packit 67cb25
Packit 67cb25
          d[i] = -alpha;
Packit 67cb25
Packit 67cb25
          for (k = i + 1; k < N; k++)
Packit 67cb25
            {
Packit 67cb25
              REAL norm = 0.0;
Packit 67cb25
              f = 0.0;
Packit 67cb25
              for (j = i; j < M; j++)
Packit 67cb25
                {
Packit 67cb25
                  REAL ajk = gsl_matrix_get (A, j, k);
Packit 67cb25
                  REAL aji = gsl_matrix_get (A, j, i);
Packit 67cb25
                  norm += ajk * ajk;
Packit 67cb25
                  f += ajk * aji;
Packit 67cb25
                }
Packit 67cb25
              max_norm = GSL_MAX (max_norm, norm);
Packit 67cb25
Packit 67cb25
              f *= ak;
Packit 67cb25
Packit 67cb25
              for (j = i; j < M; j++)
Packit 67cb25
                {
Packit 67cb25
                  REAL ajk = gsl_matrix_get (A, j, k);
Packit 67cb25
                  REAL aji = gsl_matrix_get (A, j, i);
Packit 67cb25
                  gsl_matrix_set (A, j, k, ajk - f * aji);
Packit 67cb25
                }
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          if (fabs (alpha) < 2.0 * GSL_DBL_EPSILON * sqrt (max_norm))
Packit 67cb25
            {
Packit 67cb25
              /* Apparent singularity. */
Packit 67cb25
              free (d);
Packit 67cb25
              GSL_ERROR("apparent singularity detected", GSL_ESING);
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          /* Perform update of RHS. */
Packit 67cb25
Packit 67cb25
          f = 0.0;
Packit 67cb25
          for (j = i; j < M; j++)
Packit 67cb25
            {
Packit 67cb25
              f += gsl_vector_get (x, j) * gsl_matrix_get (A, j, i);
Packit 67cb25
            }
Packit 67cb25
          f *= ak;
Packit 67cb25
          for (j = i; j < M; j++)
Packit 67cb25
            {
Packit 67cb25
              REAL xj = gsl_vector_get (x, j);
Packit 67cb25
              REAL aji = gsl_matrix_get (A, j, i);
Packit 67cb25
              gsl_vector_set (x, j, xj - f * aji);
Packit 67cb25
            }
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      /* Perform back-substitution. */
Packit 67cb25
Packit 67cb25
      for (i = N; i-- > 0;)
Packit 67cb25
        {
Packit 67cb25
          REAL xi = gsl_vector_get (x, i);
Packit 67cb25
          REAL sum = 0.0;
Packit 67cb25
          for (k = i + 1; k < N; k++)
Packit 67cb25
            {
Packit 67cb25
              sum += gsl_matrix_get (A, i, k) * gsl_vector_get (x, k);
Packit 67cb25
            }
Packit 67cb25
Packit 67cb25
          gsl_vector_set (x, i, (xi - sum) / d[i]);
Packit 67cb25
        }
Packit 67cb25
Packit 67cb25
      free (d);
Packit 67cb25
      return GSL_SUCCESS;
Packit 67cb25
    }
Packit 67cb25
}
Packit 67cb25