dlaed6 function

void dlaed6(
  1. int KNITER,
  2. bool ORGATI,
  3. double RHO,
  4. Array<double> D_,
  5. Array<double> Z_,
  6. double FINIT,
  7. Box<double> TAU,
  8. Box<int> INFO,
)

Implementation

void dlaed6(
  final int KNITER,
  final bool ORGATI,
  final double RHO,
  final Array<double> D_,
  final Array<double> Z_,
  final double FINIT,
  final Box<double> TAU,
  final Box<int> INFO,
) {
  final D = D_.having();
  final Z = Z_.having();
  const MAXIT = 40;
  const ZERO = 0.0, ONE = 1.0, TWO = 2.0, THREE = 3.0, FOUR = 4.0, EIGHT = 8.0;
  final DSCALE = Array<double>(3), ZSCALE = Array<double>(3);
  bool SCALE;
  int I, ITER, NITER;
  double A,
      B,
      BASE,
      C,
      DDF,
      DF,
      EPS,
      ERRETM,
      ETA,
      F,
      FC,
      SCLFAC,
      SCLINV = 0,
      SMALL1,
      SMALL2,
      SMINV1,
      SMINV2,
      TEMP,
      TEMP1,
      TEMP2,
      TEMP3,
      TEMP4,
      LBD,
      UBD;

  INFO.value = 0;

  if (ORGATI) {
    LBD = D[2];
    UBD = D[3];
  } else {
    LBD = D[1];
    UBD = D[2];
  }
  if (FINIT < ZERO) {
    LBD = ZERO;
  } else {
    UBD = ZERO;
  }

  NITER = 1;
  TAU.value = ZERO;
  if (KNITER == 2) {
    if (ORGATI) {
      TEMP = (D[3] - D[2]) / TWO;
      C = RHO + Z[1] / ((D[1] - D[2]) - TEMP);
      A = C * (D[2] + D[3]) + Z[2] + Z[3];
      B = C * D[2] * D[3] + Z[2] * D[3] + Z[3] * D[2];
    } else {
      TEMP = (D[1] - D[2]) / TWO;
      C = RHO + Z[3] / ((D[3] - D[2]) - TEMP);
      A = C * (D[1] + D[2]) + Z[1] + Z[2];
      B = C * D[1] * D[2] + Z[1] * D[2] + Z[2] * D[1];
    }
    TEMP = max(A.abs(), max(B.abs(), C.abs()));
    A /= TEMP;
    B /= TEMP;
    C /= TEMP;
    if (C == ZERO) {
      TAU.value = B / A;
    } else if (A <= ZERO) {
      TAU.value = (A - sqrt((A * A - FOUR * B * C).abs())) / (TWO * C);
    } else {
      TAU.value = TWO * B / (A + sqrt((A * A - FOUR * B * C).abs()));
    }
    if (TAU.value < LBD || TAU.value > UBD) TAU.value = (LBD + UBD) / TWO;
    if (D[1] == TAU.value || D[2] == TAU.value || D[3] == TAU.value) {
      TAU.value = ZERO;
    } else {
      TEMP = FINIT +
          TAU.value * Z[1] / (D[1] * (D[1] - TAU.value)) +
          TAU.value * Z[2] / (D[2] * (D[2] - TAU.value)) +
          TAU.value * Z[3] / (D[3] * (D[3] - TAU.value));
      if (TEMP <= ZERO) {
        LBD = TAU.value;
      } else {
        UBD = TAU.value;
      }
      if (FINIT.abs() <= TEMP.abs()) TAU.value = ZERO;
    }
  }

  // get machine parameters for possible scaling to avoid overflow

  // modified by Sven: parameters SMALL1, SMINV1, SMALL2,
  // SMINV2, EPS are not SAVEd anymore between one call to the
  // others but recomputed at each call

  EPS = dlamch('Epsilon');
  BASE = dlamch('Base');
  SMALL1 = pow(BASE, log(dlamch('SafMin')) / log(BASE) ~/ THREE).toDouble();
  SMINV1 = ONE / SMALL1;
  SMALL2 = SMALL1 * SMALL1;
  SMINV2 = SMINV1 * SMINV1;

  // Determine if scaling of inputs necessary to avoid overflow
  // when computing 1/TEMP**3

  if (ORGATI) {
    TEMP = min((D[2] - TAU.value).abs(), (D[3] - TAU.value).abs());
  } else {
    TEMP = min((D[1] - TAU.value).abs(), (D[2] - TAU.value).abs());
  }
  SCALE = false;
  if (TEMP <= SMALL1) {
    SCALE = true;
    if (TEMP <= SMALL2) {
      // Scale up by power of radix nearest 1/SAFMIN**(2/3)

      SCLFAC = SMINV2;
      SCLINV = SMALL2;
    } else {
      // Scale up by power of radix nearest 1/SAFMIN**(1/3)

      SCLFAC = SMINV1;
      SCLINV = SMALL1;
    }

    // Scaling up safe because D, Z, TAU scaled elsewhere to be O(1)

    for (I = 1; I <= 3; I++) {
      DSCALE[I] = D[I] * SCLFAC;
      ZSCALE[I] = Z[I] * SCLFAC;
    }
    TAU.value *= SCLFAC;
    LBD *= SCLFAC;
    UBD *= SCLFAC;
  } else {
    // Copy D and Z to DSCALE and ZSCALE

    for (I = 1; I <= 3; I++) {
      DSCALE[I] = D[I];
      ZSCALE[I] = Z[I];
    }
  }

  FC = ZERO;
  DF = ZERO;
  DDF = ZERO;
  for (I = 1; I <= 3; I++) {
    TEMP = ONE / (DSCALE[I] - TAU.value);
    TEMP1 = ZSCALE[I] * TEMP;
    TEMP2 = TEMP1 * TEMP;
    TEMP3 = TEMP2 * TEMP;
    FC += TEMP1 / DSCALE[I];
    DF += TEMP2;
    DDF += TEMP3;
  }
  F = FINIT + TAU.value * FC;

  done:
  while (true) {
    if (F.abs() <= ZERO) break done;
    if (F <= ZERO) {
      LBD = TAU.value;
    } else {
      UBD = TAU.value;
    }

    // Iteration begins -- Use Gragg-Thornton-Warner cubic convergent
    // scheme

    // It is not hard to see that

    // 1) Iterations will go up monotonically
    // if FINIT < 0;

    // 2) Iterations will go down monotonically
    // if FINIT > 0.

    ITER = NITER + 1;

    for (NITER = ITER; NITER <= MAXIT; NITER++) {
      if (ORGATI) {
        TEMP1 = DSCALE[2] - TAU.value;
        TEMP2 = DSCALE[3] - TAU.value;
      } else {
        TEMP1 = DSCALE[1] - TAU.value;
        TEMP2 = DSCALE[2] - TAU.value;
      }
      A = (TEMP1 + TEMP2) * F - TEMP1 * TEMP2 * DF;
      B = TEMP1 * TEMP2 * F;
      C = F - (TEMP1 + TEMP2) * DF + TEMP1 * TEMP2 * DDF;
      TEMP = max(A.abs(), max(B.abs(), C.abs()));
      A /= TEMP;
      B /= TEMP;
      C /= TEMP;
      if (C == ZERO) {
        ETA = B / A;
      } else if (A <= ZERO) {
        ETA = (A - sqrt((A * A - FOUR * B * C).abs())) / (TWO * C);
      } else {
        ETA = TWO * B / (A + sqrt((A * A - FOUR * B * C).abs()));
      }
      if (F * ETA >= ZERO) {
        ETA = -F / DF;
      }

      TAU.value += ETA;
      if (TAU.value < LBD || TAU.value > UBD) TAU.value = (LBD + UBD) / TWO;

      FC = ZERO;
      ERRETM = ZERO;
      DF = ZERO;
      DDF = ZERO;
      for (I = 1; I <= 3; I++) {
        if ((DSCALE[I] - TAU.value) != ZERO) {
          TEMP = ONE / (DSCALE[I] - TAU.value);
          TEMP1 = ZSCALE[I] * TEMP;
          TEMP2 = TEMP1 * TEMP;
          TEMP3 = TEMP2 * TEMP;
          TEMP4 = TEMP1 / DSCALE[I];
          FC += TEMP4;
          ERRETM += TEMP4.abs();
          DF += TEMP2;
          DDF += TEMP3;
        } else {
          break done;
        }
      }
      F = FINIT + TAU.value * FC;
      ERRETM = EIGHT * (FINIT.abs() + TAU.value.abs() * ERRETM) +
          TAU.value.abs() * DF;
      if ((F.abs() <= FOUR * EPS * ERRETM) ||
          ((UBD - LBD) <= FOUR * EPS * TAU.value.abs())) break done;
      if (F <= ZERO) {
        LBD = TAU.value;
      } else {
        UBD = TAU.value;
      }
    }
    INFO.value = 1;
    break;
  }

  // Undo scaling
  if (SCALE) TAU.value *= SCLINV;
}