⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 francis.c

📁 math library from gnu
💻 C
📖 第 1 页 / 共 2 页
字号:
   */  dat[0] = (h_tmp1*h_tmp2 - h_cross) / gsl_matrix_get(H, 1, 0) +           gsl_matrix_get(H, 0, 1);  dat[1] = gsl_matrix_get(H, 1, 1) - gsl_matrix_get(H, 0, 0) - h_tmp1 -           h_tmp2;  dat[2] = gsl_matrix_get(H, 2, 1);  scale = fabs(dat[0]) + fabs(dat[1]) + fabs(dat[2]);  if (scale != 0.0)    {      /* scale to prevent overflow or underflow */      dat[0] /= scale;      dat[1] /= scale;      dat[2] /= scale;    }  if (w->Z || w->compute_t)    {      /*       * get absolute indices of this (sub)matrix relative to the       * original Hessenberg matrix       */      top = francis_get_submatrix(w->H, H);    }  for (i = 0; i < N - 2; ++i)    {      tau_i = gsl_linalg_householder_transform(&v3.vector);      if (tau_i != 0.0)        {          /* q = max(1, i - 1) */          q = (1 > ((int)i - 1)) ? 0 : (i - 1);          /* r = min(i + 3, N - 1) */          r = ((i + 3) < (N - 1)) ? (i + 3) : (N - 1);          if (w->compute_t)            {              /*               * We are computing the Schur form T, so we               * need to transform the whole matrix H               *               * H -> P_k^t H P_k               *               * where P_k is the current Householder matrix               */              /* apply left householder matrix (I - tau_i v v') to H */              m = gsl_matrix_submatrix(w->H,                                       top + i,                                       top + q,                                       3,                                       w->size - top - q);              gsl_linalg_householder_hm(tau_i, &v3.vector, &m.matrix);              /* apply right householder matrix (I - tau_i v v') to H */              m = gsl_matrix_submatrix(w->H,                                       0,                                       top + i,                                       top + r + 1,                                       3);              gsl_linalg_householder_mh(tau_i, &v3.vector, &m.matrix);            }          else            {              /*               * We are not computing the Schur form T, so we               * only need to transform the active block               */              /* apply left householder matrix (I - tau_i v v') to H */              m = gsl_matrix_submatrix(H, i, q, 3, N - q);              gsl_linalg_householder_hm(tau_i, &v3.vector, &m.matrix);              /* apply right householder matrix (I - tau_i v v') to H */              m = gsl_matrix_submatrix(H, 0, i, r + 1, 3);              gsl_linalg_householder_mh(tau_i, &v3.vector, &m.matrix);            }          if (w->Z)            {              /* accumulate the similarity transformation into Z */              m = gsl_matrix_submatrix(w->Z, 0, top + i, w->size, 3);              gsl_linalg_householder_mh(tau_i, &v3.vector, &m.matrix);            }        } /* if (tau_i != 0.0) */      dat[0] = gsl_matrix_get(H, i + 1, i);      dat[1] = gsl_matrix_get(H, i + 2, i);      if (i < (N - 3))        {          dat[2] = gsl_matrix_get(H, i + 3, i);        }      scale = fabs(dat[0]) + fabs(dat[1]) + fabs(dat[2]);      if (scale != 0.0)        {          /* scale to prevent overflow or underflow */          dat[0] /= scale;          dat[1] /= scale;          dat[2] /= scale;        }    } /* for (i = 0; i < N - 2; ++i) */  scale = fabs(dat[0]) + fabs(dat[1]);  if (scale != 0.0)    {      /* scale to prevent overflow or underflow */      dat[0] /= scale;      dat[1] /= scale;    }  tau_i = gsl_linalg_householder_transform(&v2.vector);  if (w->compute_t)    {      m = gsl_matrix_submatrix(w->H,                               top + N - 2,                               top + N - 3,                               2,                               w->size - top - N + 3);      gsl_linalg_householder_hm(tau_i, &v2.vector, &m.matrix);      m = gsl_matrix_submatrix(w->H,                               0,                               top + N - 2,                               top + N,                               2);      gsl_linalg_householder_mh(tau_i, &v2.vector, &m.matrix);    }  else    {      m = gsl_matrix_submatrix(H, N - 2, N - 3, 2, 3);      gsl_linalg_householder_hm(tau_i, &v2.vector, &m.matrix);      m = gsl_matrix_submatrix(H, 0, N - 2, N, 2);      gsl_linalg_householder_mh(tau_i, &v2.vector, &m.matrix);    }  if (w->Z)    {      /* accumulate transformation into Z */      m = gsl_matrix_submatrix(w->Z, 0, top + N - 2, w->size, 2);      gsl_linalg_householder_mh(tau_i, &v2.vector, &m.matrix);    }  return GSL_SUCCESS;} /* francis_qrstep() *//*francis_search_subdiag_small_elements()  Search for a small subdiagonal element starting from the bottomof a matrix A. A small element is one that satisfies:|A_{i,i-1}| <= eps * (|A_{i,i}| + |A_{i-1,i-1}|)Inputs: A - matrix (must be at least 3-by-3)Return: row index of small subdiagonal element or 0 if not foundNotes: the first small element that is found (starting from bottom)       is set to zero*/static inline size_tfrancis_search_subdiag_small_elements(gsl_matrix * A){  const size_t N = A->size1;  size_t i;  double dpel = gsl_matrix_get(A, N - 2, N - 2);  for (i = N - 1; i > 0; --i)    {      double sel = gsl_matrix_get(A, i, i - 1);      double del = gsl_matrix_get(A, i, i);      if ((sel == 0.0) ||          (fabs(sel) < GSL_DBL_EPSILON * (fabs(del) + fabs(dpel))))        {          gsl_matrix_set(A, i, i - 1, 0.0);          return (i);        }      dpel = del;    }  return (0);} /* francis_search_subdiag_small_elements() *//*francis_schur_standardize()  Convert a 2-by-2 diagonal block in the Schur form to standard formand update the rest of T and Z matrices if required.Inputs: A     - 2-by-2 matrix        eval1 - where to store eigenvalue 1        eval2 - where to store eigenvalue 2        w     - francis workspace*/static inline voidfrancis_schur_standardize(gsl_matrix *A, gsl_complex *eval1,                          gsl_complex *eval2,                          gsl_eigen_francis_workspace *w){  const size_t N = w->size;  double cs, sn;  size_t top;  /*   * figure out where the submatrix A resides in the   * original matrix H   */  top = francis_get_submatrix(w->H, A);  /* convert 2-by-2 block to standard form */  francis_standard_form(A, &cs, &sn);  /* set eigenvalues */  GSL_SET_REAL(eval1, gsl_matrix_get(A, 0, 0));  GSL_SET_REAL(eval2, gsl_matrix_get(A, 1, 1));  if (gsl_matrix_get(A, 1, 0) == 0.0)    {      GSL_SET_IMAG(eval1, 0.0);      GSL_SET_IMAG(eval2, 0.0);    }  else    {      double tmp = sqrt(fabs(gsl_matrix_get(A, 0, 1)) *                        fabs(gsl_matrix_get(A, 1, 0)));      GSL_SET_IMAG(eval1, tmp);      GSL_SET_IMAG(eval2, -tmp);    }  if (w->compute_t)    {      gsl_vector_view xv, yv;      /*       * The above call to francis_standard_form transformed a 2-by-2 block       * of T into upper triangular form via the transformation       *       * U = [ CS -SN ]       *     [ SN  CS ]       *       * The original matrix T was       *       * T = [ T_{11} | T_{12} | T_{13} ]       *     [   0*   |   A    | T_{23} ]       *     [   0    |   0*   | T_{33} ]       *       * where 0* indicates all zeros except for possibly       * one subdiagonal element next to A.       *       * After francis_standard_form, T looks like this:       *       * T = [ T_{11} | T_{12}  | T_{13} ]       *     [   0*   | U^t A U | T_{23} ]       *     [   0    |    0*   | T_{33} ]       *       * since only the 2-by-2 block of A was changed. However,       * in order to be able to back transform T at the end,       * we need to apply the U transformation to the rest       * of the matrix T since there is no way to apply a       * similarity transformation to T and change only the       * middle 2-by-2 block. In other words, let       *       * M = [ I 0 0 ]       *     [ 0 U 0 ]       *     [ 0 0 I ]       *       * and compute       *       * M^t T M = [ T_{11} | T_{12} U |   T_{13}   ]       *           [ U^t 0* | U^t A U  | U^t T_{23} ]       *           [   0    |   0* U   |   T_{33}   ]       *       * So basically we need to apply the transformation U       * to the i x 2 matrix T_{12} and the 2 x (n - i + 2)       * matrix T_{23}, where i is the index of the top of A       * in T.       *       * The BLAS routine drot() is suited for this.       */      if (top < (N - 2))        {          /* transform the 2 rows of T_{23} */          xv = gsl_matrix_subrow(w->H, top, top + 2, N - top - 2);          yv = gsl_matrix_subrow(w->H, top + 1, top + 2, N - top - 2);          gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);        }      if (top > 0)        {          /* transform the 2 columns of T_{12} */          xv = gsl_matrix_subcolumn(w->H, top, 0, top);          yv = gsl_matrix_subcolumn(w->H, top + 1, 0, top);          gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);        }    } /* if (w->compute_t) */  if (w->Z)    {      gsl_vector_view xv, yv;      /*       * Accumulate the transformation in Z. Here, Z -> Z * M       *       * So:       *       * Z -> [ Z_{11} | Z_{12} U | Z_{13} ]       *      [ Z_{21} | Z_{22} U | Z_{23} ]       *      [ Z_{31} | Z_{32} U | Z_{33} ]       *       * So we just need to apply drot() to the 2 columns       * starting at index 'top'       */      xv = gsl_matrix_column(w->Z, top);      yv = gsl_matrix_column(w->Z, top + 1);      gsl_blas_drot(&xv.vector, &yv.vector, cs, sn);    } /* if (w->Z) */} /* francis_schur_standardize() *//*francis_get_submatrix()  B is a submatrix of A. The goal of this function is tocompute the indices in A of where the matrix B resides*/static inline size_tfrancis_get_submatrix(gsl_matrix *A, gsl_matrix *B){  size_t diff;  double ratio;  size_t top;  diff = (size_t) (B->data - A->data);  ratio = (double)diff / ((double) (A->tda + 1));  top = (size_t) floor(ratio);  return top;} /* francis_get_submatrix() *//*francis_standard_form()  Compute the Schur factorization of a real 2-by-2 matrix instandard form:[ A B ] = [ CS -SN ] [ T11 T12 ] [ CS SN ][ C D ]   [ SN  CS ] [ T21 T22 ] [-SN CS ]where either:1) T21 = 0 so that T11 and T22 are real eigenvalues of the matrix, or2) T11 = T22 and T21*T12 < 0, so that T11 +/- sqrt(|T21*T12|) are   complex conjugate eigenvaluesInputs: A  - 2-by-2 matrix        cs - where to store cosine parameter of rotation matrix        sn - where to store sine parameter of rotation matrixNotes: 1) based on LAPACK routine DLANV2       2) On output, A is modified to contain the matrix in standard form*/static voidfrancis_standard_form(gsl_matrix *A, double *cs, double *sn){  double a, b, c, d; /* input matrix values */  double tmp;  double p, z;  double bcmax, bcmis, scale;  double tau, sigma;  double cs1, sn1;  double aa, bb, cc, dd;  double sab, sac;  a = gsl_matrix_get(A, 0, 0);  b = gsl_matrix_get(A, 0, 1);  c = gsl_matrix_get(A, 1, 0);  d = gsl_matrix_get(A, 1, 1);  if (c == 0.0)    {      /*       * matrix is already upper triangular - set rotation matrix       * to the identity       */      *cs = 1.0;      *sn = 0.0;    }  else if (b == 0.0)    {      /* swap rows and columns to make it upper triangular */      *cs = 0.0;      *sn = 1.0;      tmp = d;      d = a;      a = tmp;      b = -c;      c = 0.0;    }  else if (((a - d) == 0.0) && (GSL_SIGN(b) != GSL_SIGN(c)))    {      /* the matrix has complex eigenvalues with a == d */      *cs = 1.0;      *sn = 0.0;    }  else    {      tmp = a - d;      p = 0.5 * tmp;      bcmax = GSL_MAX(fabs(b), fabs(c));      bcmis = GSL_MIN(fabs(b), fabs(c)) * GSL_SIGN(b) * GSL_SIGN(c);      scale = GSL_MAX(fabs(p), bcmax);      z = (p / scale) * p + (bcmax / scale) * bcmis;      if (z >= 4.0 * GSL_DBL_EPSILON)        {          /* real eigenvalues, compute a and d */          z = p + GSL_SIGN(p) * fabs(sqrt(scale) * sqrt(z));          a = d + z;          d -= (bcmax / z) * bcmis;          /* compute b and the rotation matrix */          tau = gsl_hypot(c, z);          *cs = z / tau;          *sn = c / tau;          b -= c;          c = 0.0;        }      else        {          /*           * complex eigenvalues, or real (almost) equal eigenvalues -           * make diagonal elements equal           */          sigma = b + c;          tau = gsl_hypot(sigma, tmp);          *cs = sqrt(0.5 * (1.0 + fabs(sigma) / tau));          *sn = -(p / (tau * (*cs))) * GSL_SIGN(sigma);          /*           * Compute [ AA BB ] = [ A B ] [ CS -SN ]           *         [ CC DD ]   [ C D ] [ SN  CS ]           */          aa = a * (*cs) + b * (*sn);          bb = -a * (*sn) + b * (*cs);          cc = c * (*cs) + d * (*sn);          dd = -c * (*sn) + d * (*cs);          /*           * Compute [ A B ] = [ CS SN ] [ AA BB ]           *         [ C D ]   [-SN CS ] [ CC DD ]           */          a = aa * (*cs) + cc * (*sn);          b = bb * (*cs) + dd * (*sn);          c = -aa * (*sn) + cc * (*cs);          d = -bb * (*sn) + dd * (*cs);          tmp = 0.5 * (a + d);          a = d = tmp;          if (c != 0.0)            {              if (b != 0.0)                {                  if (GSL_SIGN(b) == GSL_SIGN(c))                    {                      /*                       * real eigenvalues: reduce to upper triangular                       * form                       */                      sab = sqrt(fabs(b));                      sac = sqrt(fabs(c));                      p = GSL_SIGN(c) * fabs(sab * sac);                      tau = 1.0 / sqrt(fabs(b + c));                      a = tmp + p;                      d = tmp - p;                      b -= c;                      c = 0.0;                      cs1 = sab * tau;                      sn1 = sac * tau;                      tmp = (*cs) * cs1 - (*sn) * sn1;                      *sn = (*cs) * sn1 + (*sn) * cs1;                      *cs = tmp;                    }                }              else                {                  b = -c;                  c = 0.0;                  tmp = *cs;                  *cs = -(*sn);                  *sn = tmp;                }            }        }    }  /* set new matrix elements */  gsl_matrix_set(A, 0, 0, a);  gsl_matrix_set(A, 0, 1, b);  gsl_matrix_set(A, 1, 0, c);  gsl_matrix_set(A, 1, 1, d);} /* francis_standard_form() */

⌨️ 快捷键说明

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