dsterf function

void dsterf(
  1. int N,
  2. Array<double> D_,
  3. Array<double> E_,
  4. Box<int> INFO,
)

Implementation

void dsterf(
  final int N,
  final Array<double> D_,
  final Array<double> E_,
  final Box<int> INFO,
) {
  final D = D_.having();
  final E = E_.having();
  const ZERO = 0.0, ONE = 1.0, TWO = 2.0, THREE = 3.0;
  const MAXIT = 30;
  int I, ISCALE, JTOT, L, L1, LEND, LENDSV, LSV, M, NMAXIT;
  double ALPHA,
      ANORM,
      BB,
      C,
      EPS,
      EPS2,
      GAMMA,
      OLDC,
      OLDGAM,
      P,
      R,
      RTE,
      S,
      SAFMAX,
      SAFMIN,
      SIGMA,
      SSFMAX,
      SSFMIN;
  // RMAX;
  final RT1 = Box(0.0), RT2 = Box(0.0);

  // Test the input parameters.

  INFO.value = 0;

  // Quick return if possible

  if (N < 0) {
    INFO.value = -1;
    xerbla('DSTERF', -INFO.value);
    return;
  }
  if (N <= 1) return;

  // Determine the unit roundoff for this environment.

  EPS = dlamch('E');
  EPS2 = pow(EPS, 2).toDouble();
  SAFMIN = dlamch('S');
  SAFMAX = ONE / SAFMIN;
  SSFMAX = sqrt(SAFMAX) / THREE;
  SSFMIN = sqrt(SAFMIN) / EPS2;
  // RMAX = dlamch('O');

  // Compute the eigenvalues of the tridiagonal matrix.

  NMAXIT = N * MAXIT;
  SIGMA = ZERO;
  JTOT = 0;

  // Determine where the matrix splits and choose QL or QR iteration
  // for each block, according to whether top or bottom diagonal
  // element is smaller.

  L1 = 1;

  while (true) {
    if (L1 > N) break;
    if (L1 > 1) E[L1 - 1] = ZERO;
    bool isLoopExhausted = true;
    for (M = L1; M <= N - 1; M++) {
      if (E[M].abs() <= (sqrt(D[M].abs()) * sqrt(D[M + 1].abs())) * EPS) {
        E[M] = ZERO;
        isLoopExhausted = false;
        break;
      }
    }
    if (isLoopExhausted) {
      M = N;
    }

    L = L1;
    LSV = L;
    LEND = M;
    LENDSV = LEND;
    L1 = M + 1;
    if (LEND == L) continue;

    // Scale submatrix in rows and columns L to LEND

    ANORM = dlanst('M', LEND - L + 1, D(L), E(L));
    ISCALE = 0;
    if (ANORM == ZERO) continue;
    if ((ANORM > SSFMAX)) {
      ISCALE = 1;
      dlascl(
          'G', 0, 0, ANORM, SSFMAX, LEND - L + 1, 1, D(L).asMatrix(N), N, INFO);
      dlascl('G', 0, 0, ANORM, SSFMAX, LEND - L, 1, E(L).asMatrix(N), N, INFO);
    } else if (ANORM < SSFMIN) {
      ISCALE = 2;
      dlascl(
          'G', 0, 0, ANORM, SSFMIN, LEND - L + 1, 1, D(L).asMatrix(N), N, INFO);
      dlascl('G', 0, 0, ANORM, SSFMIN, LEND - L, 1, E(L).asMatrix(N), N, INFO);
    }

    for (I = L; I <= LEND - 1; I++) {
      E[I] = pow(E[I], 2).toDouble();
    }

    // Choose between QL and QR iteration

    if (D[LEND].abs() < D[L].abs()) {
      LEND = LSV;
      L = LENDSV;
    }

    if (LEND >= L) {
      // QL Iteration

      // Look for small subdiagonal element.

      while (LEND >= L) {
        var hasSubdiagonalElement = false;
        if (L != LEND) {
          for (M = L; M <= LEND - 1; M++) {
            if (E[M].abs() <= EPS2 * (D[M] * D[M + 1]).abs()) {
              hasSubdiagonalElement = true;
              break;
            }
          }
        }
        if (!hasSubdiagonalElement) {
          M = LEND;
        }

        if (M < LEND) E[M] = ZERO;
        P = D[L];
        if (M != L) {
          // If remaining matrix is 2 by 2, use DLAE2 to compute its
          // eigenvalues.

          if (M == L + 1) {
            RTE = sqrt(E[L]);
            dlae2(D[L], RTE, D[L + 1], RT1, RT2);
            D[L] = RT1.value;
            D[L + 1] = RT2.value;
            E[L] = ZERO;
            L += 2;
            continue;
          }

          if (JTOT == NMAXIT) break;
          JTOT++;

          // Form shift.

          RTE = sqrt(E[L]);
          SIGMA = (D[L + 1] - P) / (TWO * RTE);
          R = dlapy2(SIGMA, ONE);
          SIGMA = P - (RTE / (SIGMA + sign(R, SIGMA)));

          C = ONE;
          S = ZERO;
          GAMMA = D[M] - SIGMA;
          P = GAMMA * GAMMA;

          // Inner loop

          for (I = M - 1; I >= L; I--) {
            BB = E[I];
            R = P + BB;
            if (I != M - 1) E[I + 1] = S * R;
            OLDC = C;
            C = P / R;
            S = BB / R;
            OLDGAM = GAMMA;
            ALPHA = D[I];
            GAMMA = C * (ALPHA - SIGMA) - S * OLDGAM;
            D[I + 1] = OLDGAM + (ALPHA - GAMMA);
            if (C != ZERO) {
              P = (GAMMA * GAMMA) / C;
            } else {
              P = OLDC * BB;
            }
          }

          E[L] = S * P;
          D[L] = SIGMA + GAMMA;
          continue;
        }

        // Eigenvalue found.

        D[L] = P;
        L++;
      }
    } else {
      // QR Iteration

      // Look for small superdiagonal element.

      while (L >= LEND) {
        var hasSuperdiagonalElement = false;
        for (M = L; M >= LEND + 1; M--) {
          if (E[M - 1].abs() <= EPS2 * (D[M] * D[M - 1]).abs()) {
            hasSuperdiagonalElement = true;
            break;
          }
        }
        if (!hasSuperdiagonalElement) {
          M = LEND;
        }

        if (M > LEND) E[M - 1] = ZERO;
        P = D[L];
        if (M != L) {
          // If remaining matrix is 2 by 2, use DLAE2 to compute its
          // eigenvalues.

          if (M == L - 1) {
            RTE = sqrt(E[L - 1]);
            dlae2(D[L], RTE, D[L - 1], RT1, RT2);
            D[L] = RT1.value;
            D[L - 1] = RT2.value;
            E[L - 1] = ZERO;
            L -= 2;
            continue;
          }

          if (JTOT == NMAXIT) break;
          JTOT++;

          // Form shift.

          RTE = sqrt(E[L - 1]);
          SIGMA = (D[L - 1] - P) / (TWO * RTE);
          R = dlapy2(SIGMA, ONE);
          SIGMA = P - (RTE / (SIGMA + sign(R, SIGMA)));

          C = ONE;
          S = ZERO;
          GAMMA = D[M] - SIGMA;
          P = GAMMA * GAMMA;

          // Inner loop

          for (I = M; I <= L - 1; I++) {
            BB = E[I];
            R = P + BB;
            if (I != M) E[I - 1] = S * R;
            OLDC = C;
            C = P / R;
            S = BB / R;
            OLDGAM = GAMMA;
            ALPHA = D[I + 1];
            GAMMA = C * (ALPHA - SIGMA) - S * OLDGAM;
            D[I] = OLDGAM + (ALPHA - GAMMA);
            if (C != ZERO) {
              P = (GAMMA * GAMMA) / C;
            } else {
              P = OLDC * BB;
            }
          }

          E[L - 1] = S * P;
          D[L] = SIGMA + GAMMA;
          continue;
        }

        // Eigenvalue found.
        D[L] = P;
        L--;
      }
    }

    // Undo scaling if necessary
    if (ISCALE == 1) {
      dlascl('G', 0, 0, SSFMAX, ANORM, LENDSV - LSV + 1, 1, D(LSV).asMatrix(N),
          N, INFO);
    }
    if (ISCALE == 2) {
      dlascl('G', 0, 0, SSFMIN, ANORM, LENDSV - LSV + 1, 1, D(LSV).asMatrix(N),
          N, INFO);
    }

    // Check for no convergence to an eigenvalue after a total
    // of N*MAXIT iterations.

    if (JTOT >= NMAXIT) {
      for (I = 1; I <= N - 1; I++) {
        if (E[I] != ZERO) INFO.value++;
      }
      return;
    }
  }

  // Sort eigenvalues in increasing order.

  dlasrt('I', N, D, INFO);
}