nonsymmv.c

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

C
970
字号
         ii;  gsl_complex lambda; /* current eigenvalue */  double lambda_re,   /* Re(lambda) */         lambda_im;   /* Im(lambda) */  gsl_matrix_view Tv, /* temporary views */                  Zv;  gsl_vector_view y,  /* temporary views */                  y2,                  ev,                  ev2;  double dat[4],      /* scratch arrays */         dat_X[4];  double scale;       /* scale factor */  double xnorm;       /* |X| */  gsl_vector_complex_view ecol, /* column of evec */                          ecol2;  int complex_pair;   /* complex eigenvalue pair? */  double smin;  /*   * Compute 1-norm of each column of upper triangular part of T   * to control overflow in triangular solver   */  gsl_vector_set(w->work3, 0, 0.0);  for (ju = 1; ju < N; ++ju)    {      gsl_vector_set(w->work3, ju, 0.0);      for (iu = 0; iu < ju; ++iu)        {          gsl_vector_set(w->work3, ju,                         gsl_vector_get(w->work3, ju) +                         fabs(gsl_matrix_get(T, iu, ju)));        }    }  for (i = (int) N - 1; i >= 0; --i)    {      iu = (size_t) i;      /* get current eigenvalue and store it in lambda */      lambda_re = gsl_matrix_get(T, iu, iu);      if (iu != 0 && gsl_matrix_get(T, iu, iu - 1) != 0.0)        {          lambda_im = sqrt(fabs(gsl_matrix_get(T, iu, iu - 1))) *                      sqrt(fabs(gsl_matrix_get(T, iu - 1, iu)));        }      else        {          lambda_im = 0.0;        }      GSL_SET_COMPLEX(&lambda, lambda_re, lambda_im);      smin = GSL_MAX(GSL_DBL_EPSILON * (fabs(lambda_re) + fabs(lambda_im)),                     smlnum);      smin = GSL_MAX(smin, GSL_NONSYMMV_SMLNUM);      if (lambda_im == 0.0)        {          int k, l;          gsl_vector_view bv, xv;          /* real eigenvector */          /*           * The ordering of eigenvalues in 'eval' is arbitrary and           * does not necessarily follow the Schur form T, so store           * lambda in the right slot in eval to ensure it corresponds           * to the eigenvector we are about to compute           */          gsl_vector_complex_set(eval, iu, lambda);          /*           * We need to solve the system:           *           * (T(1:iu-1, 1:iu-1) - lambda*I)*X = -T(1:iu-1,iu)           */          /* construct right hand side */          for (k = 0; k < i; ++k)            {              gsl_vector_set(w->work,                             (size_t) k,                             -gsl_matrix_get(T, (size_t) k, iu));            }          gsl_vector_set(w->work, iu, 1.0);          for (l = i - 1; l >= 0; --l)            {              size_t lu = (size_t) l;              if (lu == 0)                complex_pair = 0;              else                complex_pair = gsl_matrix_get(T, lu, lu - 1) != 0.0;              if (!complex_pair)                {                  double x;                  /*                   * 1-by-1 diagonal block - solve the system:                   *                   * (T_{ll} - lambda)*x = -T_{l(iu)}                   */                  Tv = gsl_matrix_submatrix(T, lu, lu, 1, 1);                  bv = gsl_vector_view_array(dat, 1);                  gsl_vector_set(&bv.vector, 0,                                 gsl_vector_get(w->work, lu));                  xv = gsl_vector_view_array(dat_X, 1);                  gsl_schur_solve_equation(1.0,                                           &Tv.matrix,                                           lambda_re,                                           1.0,                                           1.0,                                           &bv.vector,                                           &xv.vector,                                           &scale,                                           &xnorm,                                           smin);                  /* scale x to avoid overflow */                  x = gsl_vector_get(&xv.vector, 0);                  if (xnorm > 1.0)                    {                      if (gsl_vector_get(w->work3, lu) > bignum / xnorm)                        {                          x /= xnorm;                          scale /= xnorm;                        }                    }                  if (scale != 1.0)                    {                      gsl_vector_view wv;                      wv = gsl_vector_subvector(w->work, 0, iu + 1);                      gsl_blas_dscal(scale, &wv.vector);                    }                  gsl_vector_set(w->work, lu, x);                  if (lu > 0)                    {                      gsl_vector_view v1, v2;                      /* update right hand side */                      v1 = gsl_matrix_subcolumn(T, lu, 0, lu);                      v2 = gsl_vector_subvector(w->work, 0, lu);                      gsl_blas_daxpy(-x, &v1.vector, &v2.vector);                    } /* if (l > 0) */                } /* if (!complex_pair) */              else                {                  double x11, x21;                  /*                   * 2-by-2 diagonal block                   */                  Tv = gsl_matrix_submatrix(T, lu - 1, lu - 1, 2, 2);                  bv = gsl_vector_view_array(dat, 2);                  gsl_vector_set(&bv.vector, 0,                                 gsl_vector_get(w->work, lu - 1));                  gsl_vector_set(&bv.vector, 1,                                 gsl_vector_get(w->work, lu));                  xv = gsl_vector_view_array(dat_X, 2);                  gsl_schur_solve_equation(1.0,                                           &Tv.matrix,                                           lambda_re,                                           1.0,                                           1.0,                                           &bv.vector,                                           &xv.vector,                                           &scale,                                           &xnorm,                                           smin);                  /* scale X(1,1) and X(2,1) to avoid overflow */                  x11 = gsl_vector_get(&xv.vector, 0);                  x21 = gsl_vector_get(&xv.vector, 1);                  if (xnorm > 1.0)                    {                      double beta;                      beta = GSL_MAX(gsl_vector_get(w->work3, lu - 1),                                     gsl_vector_get(w->work3, lu));                      if (beta > bignum / xnorm)                        {                          x11 /= xnorm;                          x21 /= xnorm;                          scale /= xnorm;                        }                    }                  /* scale if necessary */                  if (scale != 1.0)                    {                      gsl_vector_view wv;                      wv = gsl_vector_subvector(w->work, 0, iu + 1);                      gsl_blas_dscal(scale, &wv.vector);                    }                  gsl_vector_set(w->work, lu - 1, x11);                  gsl_vector_set(w->work, lu, x21);                  /* update right hand side */                  if (lu > 1)                    {                      gsl_vector_view v1, v2;                      v1 = gsl_matrix_subcolumn(T, lu - 1, 0, lu - 1);                      v2 = gsl_vector_subvector(w->work, 0, lu - 1);                      gsl_blas_daxpy(-x11, &v1.vector, &v2.vector);                      v1 = gsl_matrix_subcolumn(T, lu, 0, lu - 1);                      gsl_blas_daxpy(-x21, &v1.vector, &v2.vector);                    }                  --l;                } /* if (complex_pair) */            } /* for (l = i - 1; l >= 0; --l) */          /*           * At this point, w->work is an eigenvector of the           * Schur form T. To get an eigenvector of the original           * matrix, we multiply on the left by Z, the matrix of           * Schur vectors           */          ecol = gsl_matrix_complex_column(evec, iu);          y = gsl_matrix_column(Z, iu);          if (iu > 0)            {              gsl_vector_view x;              Zv = gsl_matrix_submatrix(Z, 0, 0, N, iu);              x = gsl_vector_subvector(w->work, 0, iu);              /* compute Z * w->work and store it in Z(:,iu) */              gsl_blas_dgemv(CblasNoTrans,                             1.0,                             &Zv.matrix,                             &x.vector,                             gsl_vector_get(w->work, iu),                             &y.vector);            } /* if (iu > 0) */          /* store eigenvector into evec */          ev = gsl_vector_complex_real(&ecol.vector);          ev2 = gsl_vector_complex_imag(&ecol.vector);          scale = 0.0;          for (ii = 0; ii < N; ++ii)            {              double a = gsl_vector_get(&y.vector, ii);              /* store real part of eigenvector */              gsl_vector_set(&ev.vector, ii, a);              /* set imaginary part to 0 */              gsl_vector_set(&ev2.vector, ii, 0.0);              if (fabs(a) > scale)                scale = fabs(a);            }          if (scale != 0.0)            scale = 1.0 / scale;          /* scale by magnitude of largest element */          gsl_blas_dscal(scale, &ev.vector);        } /* if (GSL_IMAG(lambda) == 0.0) */      else        {          gsl_vector_complex_view bv, xv;          size_t k;          int l;          gsl_complex lambda2;          /* complex eigenvector */          /*           * Store the complex conjugate eigenvalues in the right           * slots in eval           */          GSL_SET_REAL(&lambda2, GSL_REAL(lambda));          GSL_SET_IMAG(&lambda2, -GSL_IMAG(lambda));          gsl_vector_complex_set(eval, iu - 1, lambda);          gsl_vector_complex_set(eval, iu, lambda2);          /*           * First solve:           *           * [ T(i:i+1,i:i+1) - lambda*I ] * X = 0           */          if (fabs(gsl_matrix_get(T, iu - 1, iu)) >=              fabs(gsl_matrix_get(T, iu, iu - 1)))            {              gsl_vector_set(w->work, iu - 1, 1.0);              gsl_vector_set(w->work2, iu,                             lambda_im / gsl_matrix_get(T, iu - 1, iu));            }          else            {              gsl_vector_set(w->work, iu - 1,                             -lambda_im / gsl_matrix_get(T, iu, iu - 1));              gsl_vector_set(w->work2, iu, 1.0);            }          gsl_vector_set(w->work, iu, 0.0);          gsl_vector_set(w->work2, iu - 1, 0.0);

⌨️ 快捷键说明

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