dlarrb function

void dlarrb(
  1. int N,
  2. Array<double> D_,
  3. Array<double> LLD_,
  4. int IFIRST,
  5. int ILAST,
  6. double RTOL1,
  7. double RTOL2,
  8. int OFFSET,
  9. Array<double> W_,
  10. Array<double> WGAP_,
  11. Array<double> WERR_,
  12. Array<double> WORK_,
  13. Array<int> IWORK_,
  14. double PIVMIN,
  15. double SPDIAM,
  16. int TWIST,
  17. Box<int> INFO,
)

Implementation

void dlarrb(
  final int N,
  final Array<double> D_,
  final Array<double> LLD_,
  final int IFIRST,
  final int ILAST,
  final double RTOL1,
  final double RTOL2,
  final int OFFSET,
  final Array<double> W_,
  final Array<double> WGAP_,
  final Array<double> WERR_,
  final Array<double> WORK_,
  final Array<int> IWORK_,
  final double PIVMIN,
  final double SPDIAM,
  final int TWIST,
  final Box<int> INFO,
) {
  final D = D_.having();
  final LLD = LLD_.having();
  final W = W_.having();
  final WGAP = WGAP_.having();
  final WERR = WERR_.having();
  final WORK = WORK_.having();
  final IWORK = IWORK_.having();
  const ZERO = 0.0, TWO = 2.0, HALF = 0.5;
  int MAXITR;
  int I, I1, II, IP, ITER, K, NEGCNT, NEXT, NINT, OLNINT, PREV, R;
  double BACK = 0,
      CVRGD,
      GAP,
      LEFT = 0,
      LGAP,
      MID,
      MNWDTH,
      RGAP,
      RIGHT,
      TMP,
      WIDTH;

  INFO.value = 0;

  // Quick return if possible

  if (N <= 0) {
    return;
  }

  MAXITR = (log(SPDIAM + PIVMIN) - log(PIVMIN)) ~/ log(TWO) + 2;
  MNWDTH = TWO * PIVMIN;

  R = TWIST;
  if ((R < 1) || (R > N)) R = N;

  // Initialize unconverged intervals in [ WORK[2*I-1], WORK[2*I] ].
  // The Sturm Count, Count( WORK[2*I-1] ) is arranged to be I-1, while
  // Count( WORK[2*I] ) is stored in IWORK[ 2*I ]. The integer IWORK[ 2*I-1 ]
  // for an unconverged interval is set to the index of the next unconverged
  // interval, and is -1 or 0 for a converged interval. Thus a linked
  // list of unconverged intervals is set up.

  I1 = IFIRST;
  // The number of unconverged intervals
  NINT = 0;
  // The last unconverged interval found
  PREV = 0;

  RGAP = WGAP[I1 - OFFSET];
  for (I = I1; I <= ILAST; I++) {
    K = 2 * I;
    II = I - OFFSET;
    LEFT = W[II] - WERR[II];
    RIGHT = W[II] + WERR[II];
    LGAP = RGAP;
    RGAP = WGAP[II];
    GAP = min(LGAP, RGAP);

    // Make sure that [LEFT,RIGHT] contains the desired eigenvalue
    // Compute negcount from dstqds facto L+D+L+^T = L D L^T - LEFT

    // Do while( NEGCNT(LEFT) > I-1 )

    BACK = WERR[II];
    while (true) {
      NEGCNT = dlaneg(N, D, LLD, LEFT, PIVMIN, R);
      if (NEGCNT <= I - 1) break;
      LEFT -= BACK;
      BACK = TWO * BACK;
    }

    // Do while( NEGCNT(RIGHT) < I )
    // Compute negcount from dstqds facto L+D+L+^T = L D L^T - RIGHT

    BACK = WERR[II];
    while (true) {
      NEGCNT = dlaneg(N, D, LLD, RIGHT, PIVMIN, R);
      if (NEGCNT >= I) break;
      RIGHT += BACK;
      BACK = TWO * BACK;
    }
    WIDTH = HALF * (LEFT - RIGHT).abs();
    TMP = max(LEFT.abs(), RIGHT.abs());
    CVRGD = max(RTOL1 * GAP, RTOL2 * TMP);
    if (WIDTH <= CVRGD || WIDTH <= MNWDTH) {
      // This interval has already converged and does not need refinement.
      // (Note that the gaps might change through refining the
      // eigenvalues, however, they can only get bigger.)
      // Remove it from the list.
      IWORK[K - 1] = -1;
      // Make sure that I1 always points to the first unconverged interval
      if ((I == I1) && (I < ILAST)) I1 = I + 1;
      if ((PREV >= I1) && (I <= ILAST)) IWORK[2 * PREV - 1] = I + 1;
    } else {
      // unconverged interval found
      PREV = I;
      NINT++;
      IWORK[K - 1] = I + 1;
      IWORK[K] = NEGCNT;
    }
    WORK[K - 1] = LEFT;
    WORK[K] = RIGHT;
  }

  // Do while( NINT > 0 ), i.e. there are still unconverged intervals
  // and while (ITER < MAXITR)

  ITER = 0;
  do {
    PREV = I1 - 1;
    I = I1;
    OLNINT = NINT;

    for (IP = 1; IP <= OLNINT; IP++) {
      K = 2 * I;
      II = I - OFFSET;
      RGAP = WGAP[II];
      LGAP = RGAP;
      if (II > 1) LGAP = WGAP[II - 1];
      GAP = min(LGAP, RGAP);
      NEXT = IWORK[K - 1];
      LEFT = WORK[K - 1];
      RIGHT = WORK[K];
      MID = HALF * (LEFT + RIGHT);

      // semiwidth of interval
      WIDTH = RIGHT - MID;
      TMP = max(LEFT.abs(), RIGHT.abs());
      CVRGD = max(RTOL1 * GAP, RTOL2 * TMP);
      if ((WIDTH <= CVRGD) || (WIDTH <= MNWDTH) || (ITER == MAXITR)) {
        // reduce number of unconverged intervals
        NINT--;
        // Mark interval as converged.
        IWORK[K - 1] = 0;
        if (I1 == I) {
          I1 = NEXT;
        } else {
          // Prev holds the last unconverged interval previously examined
          if (PREV >= I1) IWORK[2 * PREV - 1] = NEXT;
        }
        I = NEXT;
        continue;
      }
      PREV = I;

      // Perform one bisection step

      NEGCNT = dlaneg(N, D, LLD, MID, PIVMIN, R);
      if (NEGCNT <= I - 1) {
        WORK[K - 1] = MID;
      } else {
        WORK[K] = MID;
      }
      I = NEXT;
    }
    ITER++;
    // do another loop if there are still unconverged intervals
    // However, in the last iteration, all intervals are accepted
    // since this is the best we can do.
  } while ((NINT > 0) && (ITER <= MAXITR));

  // At this point, all the intervals have converged
  for (I = IFIRST; I <= ILAST; I++) {
    K = 2 * I;
    II = I - OFFSET;
    // All intervals marked by '0' have been refined.
    if (IWORK[K - 1] == 0) {
      W[II] = HALF * (WORK[K - 1] + WORK[K]);
      WERR[II] = WORK[K] - W[II];
    }
  }

  for (I = IFIRST + 1; I <= ILAST; I++) {
    K = 2 * I;
    II = I - OFFSET;
    WGAP[II - 1] = max(ZERO, W[II] - WERR[II] - W[II - 1] - WERR[II - 1]);
  }
}