genv.c

来自「math library from gnu」· C语言 代码 · 共 924 行 · 第 1/2 页

C
924
字号
/* eigen/genv.c *  * Copyright (C) 2007 Patrick Alken *  * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or (at * your option) any later version. *  * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * General Public License for more details. *  * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */#include <stdlib.h>#include <math.h>#include <config.h>#include <gsl/gsl_eigen.h>#include <gsl/gsl_linalg.h>#include <gsl/gsl_math.h>#include <gsl/gsl_blas.h>#include <gsl/gsl_vector.h>#include <gsl/gsl_vector_complex.h>#include <gsl/gsl_matrix.h>#include <gsl/gsl_errno.h>/* * This module computes the eigenvalues and eigenvectors of a * real generalized eigensystem A x = \lambda B x. Left and right * Schur vectors are optionally computed as well. * * This file contains routines based on original code from LAPACK * which is distributed under the modified BSD license. */static int genv_get_right_eigenvectors(const gsl_matrix *S,                                       const gsl_matrix *T,                                       gsl_matrix *Z,                                       gsl_matrix_complex *evec,                                       gsl_eigen_genv_workspace *w);static void genv_normalize_eigenvectors(gsl_vector_complex *alpha,                                        gsl_matrix_complex *evec);/*gsl_eigen_genv_alloc()  Allocate a workspace for solving the generalized eigenvalue problem.The size of this workspace is O(7n).Inputs: n - size of matricesReturn: pointer to workspace*/gsl_eigen_genv_workspace *gsl_eigen_genv_alloc(const size_t n){  gsl_eigen_genv_workspace *w;  if (n == 0)    {      GSL_ERROR_NULL ("matrix dimension must be positive integer",                      GSL_EINVAL);    }  w = (gsl_eigen_genv_workspace *) calloc (1, sizeof (gsl_eigen_genv_workspace));  if (w == 0)    {      GSL_ERROR_NULL ("failed to allocate space for workspace", GSL_ENOMEM);    }  w->size = n;  w->Q = NULL;  w->Z = NULL;  w->gen_workspace_p = gsl_eigen_gen_alloc(n);  if (w->gen_workspace_p == 0)    {      gsl_eigen_genv_free(w);      GSL_ERROR_NULL ("failed to allocate space for gen workspace", GSL_ENOMEM);    }  /* compute the full Schur forms */  gsl_eigen_gen_params(1, 1, 1, w->gen_workspace_p);  w->work1 = gsl_vector_alloc(n);  w->work2 = gsl_vector_alloc(n);  w->work3 = gsl_vector_alloc(n);  w->work4 = gsl_vector_alloc(n);  w->work5 = gsl_vector_alloc(n);  w->work6 = gsl_vector_alloc(n);  if (w->work1 == 0 || w->work2 == 0 || w->work3 == 0 ||      w->work4 == 0 || w->work5 == 0 || w->work6 == 0)    {      gsl_eigen_genv_free(w);      GSL_ERROR_NULL ("failed to allocate space for additional workspace", GSL_ENOMEM);    }  return (w);} /* gsl_eigen_genv_alloc() *//*gsl_eigen_genv_free()  Free workspace w*/voidgsl_eigen_genv_free(gsl_eigen_genv_workspace *w){  if (w->gen_workspace_p)    gsl_eigen_gen_free(w->gen_workspace_p);  if (w->work1)    gsl_vector_free(w->work1);  if (w->work2)    gsl_vector_free(w->work2);  if (w->work3)    gsl_vector_free(w->work3);  if (w->work4)    gsl_vector_free(w->work4);  if (w->work5)    gsl_vector_free(w->work5);  if (w->work6)    gsl_vector_free(w->work6);  free(w);} /* gsl_eigen_genv_free() *//*gsl_eigen_genv()Solve the generalized eigenvalue problemA x = \lambda B xfor the eigenvalues \lambda and right eigenvectors x.Inputs: A     - general real matrix        B     - general real matrix        alpha - (output) where to store eigenvalue numerators        beta  - (output) where to store eigenvalue denominators        evec  - (output) where to store eigenvectors        w     - workspaceReturn: success or error*/intgsl_eigen_genv (gsl_matrix * A, gsl_matrix * B, gsl_vector_complex * alpha,                gsl_vector * beta, gsl_matrix_complex *evec,                gsl_eigen_genv_workspace * w){  const size_t N = A->size1;  /* check matrix and vector sizes */  if (N != A->size2)    {      GSL_ERROR ("matrix must be square to compute eigenvalues", GSL_ENOTSQR);    }  else if ((N != B->size1) || (N != B->size2))    {      GSL_ERROR ("B matrix dimensions must match A", GSL_EBADLEN);    }  else if (alpha->size != N || beta->size != N)    {      GSL_ERROR ("eigenvalue vector must match matrix size", GSL_EBADLEN);    }  else if (w->size != N)    {      GSL_ERROR ("matrix size does not match workspace", GSL_EBADLEN);    }  else if (evec->size1 != N)    {      GSL_ERROR ("eigenvector matrix has wrong size", GSL_EBADLEN);    }  else    {      int s;      gsl_matrix Z;      /*       * We need a place to store the right Schur vectors, so we will       * treat evec as a real matrix and store them in the left       * half - the factor of 2 in the tda corresponds to the       * complex multiplicity       */      Z.size1 = N;      Z.size2 = N;      Z.tda = 2 * N;      Z.data = evec->data;      Z.block = 0;      Z.owner = 0;      s = gsl_eigen_gen_QZ(A, B, alpha, beta, w->Q, &Z, w->gen_workspace_p);      if (w->Z)        {          /* save right Schur vectors */          gsl_matrix_memcpy(w->Z, &Z);        }      /* only compute eigenvectors if we found all eigenvalues */      if (s == GSL_SUCCESS)        {          /* compute eigenvectors */          s = genv_get_right_eigenvectors(A, B, &Z, evec, w);          if (s == GSL_SUCCESS)            genv_normalize_eigenvectors(alpha, evec);        }      return s;    }} /* gsl_eigen_genv() *//*gsl_eigen_genv_QZ()Solve the generalized eigenvalue problemA x = \lambda B xfor the eigenvalues \lambda and right eigenvectors x. Optionallycompute left and/or right Schur vectors Q and Z which satisfy:A = Q S Z^tB = Q T Z^twhere (S, T) is the generalized Schur form of (A, B)Inputs: A     - general real matrix        B     - general real matrix        alpha - (output) where to store eigenvalue numerators        beta  - (output) where to store eigenvalue denominators        evec  - (output) where to store eigenvectors        Q     - (output) if non-null, where to store left Schur vectors        Z     - (output) if non-null, where to store right Schur vectors        w     - workspaceReturn: success or error*/intgsl_eigen_genv_QZ (gsl_matrix * A, gsl_matrix * B,                   gsl_vector_complex * alpha, gsl_vector * beta,                   gsl_matrix_complex * evec,                   gsl_matrix * Q, gsl_matrix * Z,                   gsl_eigen_genv_workspace * w){  if (Q && (A->size1 != Q->size1 || A->size1 != Q->size2))    {      GSL_ERROR("Q matrix has wrong dimensions", GSL_EBADLEN);    }  else if (Z && (A->size1 != Z->size1 || A->size1 != Z->size2))    {      GSL_ERROR("Z matrix has wrong dimensions", GSL_EBADLEN);    }  else    {      int s;      w->Q = Q;      w->Z = Z;      s = gsl_eigen_genv(A, B, alpha, beta, evec, w);      w->Q = NULL;      w->Z = NULL;      return s;    }} /* gsl_eigen_genv_QZ() *//******************************************** *           INTERNAL ROUTINES              * ********************************************//*genv_get_right_eigenvectors()  Compute right eigenvectors of the Schur form (S, T) and thenbacktransform them using the right Schur vectors to get righteigenvectors of the original system.Inputs: S     - upper quasi-triangular Schur form of A        T     - upper triangular Schur form of B        Z     - right Schur vectors        evec  - (output) where to store eigenvectors        w     - workspaceReturn: success or errorNotes: 1) based on LAPACK routine DTGEVC       2) eigenvectors are stored in the order that their          eigenvalues appear in the Schur form*/static intgenv_get_right_eigenvectors(const gsl_matrix *S, const gsl_matrix *T,                            gsl_matrix *Z,                            gsl_matrix_complex *evec,                            gsl_eigen_genv_workspace *w){  const size_t N = w->size;  const double small = GSL_DBL_MIN * N / GSL_DBL_EPSILON;  const double big = 1.0 / small;  const double bignum = 1.0 / (GSL_DBL_MIN * N);  size_t i, j, k, end;  int is;  double anorm, bnorm;  double temp, temp2, temp2r, temp2i;  double ascale, bscale;  double salfar, sbeta;  double acoef, bcoefr, bcoefi, acoefa, bcoefa;  double creala, cimaga, crealb, cimagb, cre2a, cim2a, cre2b, cim2b;  double dmin, xmax;  double scale;  size_t nw, na;  int lsa, lsb;  int complex_pair;  gsl_complex z_zero, z_one;  double bdiag[2] = { 0.0, 0.0 };  double sum[4];  int il2by2;  size_t jr, jc, ja;  double xscale;  gsl_vector_complex_view ecol;  gsl_vector_view re, im, re2, im2;  GSL_SET_COMPLEX(&z_zero, 0.0, 0.0);  GSL_SET_COMPLEX(&z_one, 1.0, 0.0);  /*   * Compute the 1-norm of each column of (S, T) excluding elements   * belonging to the diagonal blocks to check for possible overflow   * in the triangular solver   */  anorm = fabs(gsl_matrix_get(S, 0, 0));  if (N > 1)    anorm += fabs(gsl_matrix_get(S, 1, 0));  bnorm = fabs(gsl_matrix_get(T, 0, 0));  gsl_vector_set(w->work1, 0, 0.0);  gsl_vector_set(w->work2, 0, 0.0);  for (j = 1; j < N; ++j)    {      temp = temp2 = 0.0;      if (gsl_matrix_get(S, j, j - 1) == 0.0)        end = j;      else        end = j - 1;      for (i = 0; i < end; ++i)        {          temp += fabs(gsl_matrix_get(S, i, j));          temp2 += fabs(gsl_matrix_get(T, i, j));        }      gsl_vector_set(w->work1, j, temp);      gsl_vector_set(w->work2, j, temp2);      for (i = end; i < GSL_MIN(j + 2, N); ++i)        {          temp += fabs(gsl_matrix_get(S, i, j));          temp2 += fabs(gsl_matrix_get(T, i, j));        }      anorm = GSL_MAX(anorm, temp);      bnorm = GSL_MAX(bnorm, temp2);    }  ascale = 1.0 / GSL_MAX(anorm, GSL_DBL_MIN);  bscale = 1.0 / GSL_MAX(bnorm, GSL_DBL_MIN);  complex_pair = 0;  for (k = 0; k < N; ++k)    {      size_t je = N - 1 - k;      if (complex_pair)        {          complex_pair = 0;          continue;        }      nw = 1;      if (je > 0)        {          if (gsl_matrix_get(S, je, je - 1) != 0.0)            {              complex_pair = 1;              nw = 2;            }        }      if (!complex_pair)        {          if (fabs(gsl_matrix_get(S, je, je)) <= GSL_DBL_MIN &&              fabs(gsl_matrix_get(T, je, je)) <= GSL_DBL_MIN)            {              /* singular matrix pencil - unit eigenvector */              for (i = 0; i < N; ++i)                gsl_matrix_complex_set(evec, i, je, z_zero);              gsl_matrix_complex_set(evec, je, je, z_one);              continue;            }          /* clear vector */          for (i = 0; i < N; ++i)            gsl_vector_set(w->work3, i, 0.0);        }      else        {          /* clear vectors */          for (i = 0; i < N; ++i)            {              gsl_vector_set(w->work3, i, 0.0);              gsl_vector_set(w->work4, i, 0.0);            }        }      if (!complex_pair)        {          /* real eigenvalue */          temp = 1.0 / GSL_MAX(GSL_DBL_MIN,                               GSL_MAX(fabs(gsl_matrix_get(S, je, je)) * ascale,                                       fabs(gsl_matrix_get(T, je, je)) * bscale));          salfar = (temp * gsl_matrix_get(S, je, je)) * ascale;          sbeta = (temp * gsl_matrix_get(T, je, je)) * bscale;          acoef = sbeta * ascale;          bcoefr = salfar * bscale;          bcoefi = 0.0;          /* scale to avoid underflow */          scale = 1.0;          lsa = fabs(sbeta) >= GSL_DBL_MIN && fabs(acoef) < small;          lsb = fabs(salfar) >= GSL_DBL_MIN && fabs(bcoefr) < small;          if (lsa)            scale = (small / fabs(sbeta)) * GSL_MIN(anorm, big);          if (lsb)            scale = GSL_MAX(scale, (small / fabs(salfar)) * GSL_MIN(bnorm, big));          if (lsa || lsb)            {

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?