dtrexc function

void dtrexc(
  1. String COMPQ,
  2. int N,
  3. Matrix<double> T_,
  4. int LDT,
  5. Matrix<double> Q_,
  6. int LDQ,
  7. Box<int> IFST,
  8. Box<int> ILST,
  9. Array<double> WORK_,
  10. Box<int> INFO,
)

Implementation

void dtrexc(
  final String COMPQ,
  final int N,
  final Matrix<double> T_,
  final int LDT,
  final Matrix<double> Q_,
  final int LDQ,
  final Box<int> IFST,
  final Box<int> ILST,
  final Array<double> WORK_,
  final Box<int> INFO,
) {
  final T = T_.having(ld: LDT);
  final Q = Q_.having(ld: LDQ);
  final WORK = WORK_.having();
  const ZERO = 0.0;
  bool WANTQ;
  int HERE = 0, NBF, NBL, NBNEXT;

  // Decode and test the input arguments.

  INFO.value = 0;
  WANTQ = lsame(COMPQ, 'V');
  if (!WANTQ && !lsame(COMPQ, 'N')) {
    INFO.value = -1;
  } else if (N < 0) {
    INFO.value = -2;
  } else if (LDT < max(1, N)) {
    INFO.value = -4;
  } else if (LDQ < 1 || (WANTQ && LDQ < max(1, N))) {
    INFO.value = -6;
  } else if ((IFST.value < 1 || IFST.value > N) && (N > 0)) {
    INFO.value = -7;
  } else if ((ILST.value < 1 || ILST.value > N) && (N > 0)) {
    INFO.value = -8;
  }
  if (INFO.value != 0) {
    xerbla('DTREXC', -INFO.value);
    return;
  }

  // Quick return if possible

  if (N <= 1) return;

  // Determine the first row of specified block
  // and find out it is 1 by 1 or 2 by 2.

  if (IFST.value > 1) {
    if (T[IFST.value][IFST.value - 1] != ZERO) IFST.value--;
  }
  NBF = 1;
  if (IFST.value < N) {
    if (T[IFST.value + 1][IFST.value] != ZERO) NBF = 2;
  }

  // Determine the first row of the final block
  // and find out it is 1 by 1 or 2 by 2.

  if (ILST.value > 1) {
    if (T[ILST.value][ILST.value - 1] != ZERO) ILST.value--;
  }
  NBL = 1;
  if (ILST.value < N) {
    if (T[ILST.value + 1][ILST.value] != ZERO) NBL = 2;
  }

  if (IFST.value == ILST.value) return;

  if (IFST.value < ILST.value) {
    // Update ILST

    if (NBF == 2 && NBL == 1) ILST.value--;
    if (NBF == 1 && NBL == 2) ILST.value++;

    HERE = IFST.value;

    do {
      // Swap block with next one below

      if (NBF == 1 || NBF == 2) {
        // Current block either 1 by 1 or 2 by 2

        NBNEXT = 1;
        if (HERE + NBF + 1 <= N) {
          if (T[HERE + NBF + 1][HERE + NBF] != ZERO) NBNEXT = 2;
        }
        dlaexc(WANTQ, N, T, LDT, Q, LDQ, HERE, NBF, NBNEXT, WORK, INFO);
        if (INFO.value != 0) {
          ILST.value = HERE;
          return;
        }
        HERE += NBNEXT;

        // Test if 2 by 2 block breaks into two 1 by 1 blocks

        if (NBF == 2) {
          if (T[HERE + 1][HERE] == ZERO) NBF = 3;
        }
      } else {
        // Current block consists of two 1 by 1 blocks each of which
        // must be swapped individually

        NBNEXT = 1;
        if (HERE + 3 <= N) {
          if (T[HERE + 3][HERE + 2] != ZERO) NBNEXT = 2;
        }
        dlaexc(WANTQ, N, T, LDT, Q, LDQ, HERE + 1, 1, NBNEXT, WORK, INFO);
        if (INFO.value != 0) {
          ILST.value = HERE;
          return;
        }
        if (NBNEXT == 1) {
          // Swap two 1 by 1 blocks, no problems possible

          dlaexc(WANTQ, N, T, LDT, Q, LDQ, HERE, 1, NBNEXT, WORK, INFO);
          HERE++;
        } else {
          // Recompute NBNEXT in case 2 by 2 split

          if (T[HERE + 2][HERE + 1] == ZERO) NBNEXT = 1;
          if (NBNEXT == 2) {
            // 2 by 2 Block did not split

            dlaexc(WANTQ, N, T, LDT, Q, LDQ, HERE, 1, NBNEXT, WORK, INFO);
            if (INFO.value != 0) {
              ILST.value = HERE;
              return;
            }
            HERE += 2;
          } else {
            // 2 by 2 Block did split

            dlaexc(WANTQ, N, T, LDT, Q, LDQ, HERE, 1, 1, WORK, INFO);
            dlaexc(WANTQ, N, T, LDT, Q, LDQ, HERE + 1, 1, 1, WORK, INFO);
            HERE += 2;
          }
        }
      }
    } while (HERE < ILST.value);
  } else {
    HERE = IFST.value;
    do {
      // Swap block with next one above

      if (NBF == 1 || NBF == 2) {
        // Current block either 1 by 1 or 2 by 2

        NBNEXT = 1;
        if (HERE >= 3) {
          if (T[HERE - 1][HERE - 2] != ZERO) NBNEXT = 2;
        }
        dlaexc(
            WANTQ, N, T, LDT, Q, LDQ, HERE - NBNEXT, NBNEXT, NBF, WORK, INFO);
        if (INFO.value != 0) {
          ILST.value = HERE;
          return;
        }
        HERE -= NBNEXT;

        // Test if 2 by 2 block breaks into two 1 by 1 blocks

        if (NBF == 2) {
          if (T[HERE + 1][HERE] == ZERO) NBF = 3;
        }
      } else {
        // Current block consists of two 1 by 1 blocks each of which
        // must be swapped individually

        NBNEXT = 1;
        if (HERE >= 3) {
          if (T[HERE - 1][HERE - 2] != ZERO) NBNEXT = 2;
        }
        dlaexc(WANTQ, N, T, LDT, Q, LDQ, HERE - NBNEXT, NBNEXT, 1, WORK, INFO);
        if (INFO.value != 0) {
          ILST.value = HERE;
          return;
        }
        if (NBNEXT == 1) {
          // Swap two 1 by 1 blocks, no problems possible

          dlaexc(WANTQ, N, T, LDT, Q, LDQ, HERE, NBNEXT, 1, WORK, INFO);
          HERE--;
        } else {
          // Recompute NBNEXT in case 2 by 2 split

          if (T[HERE][HERE - 1] == ZERO) NBNEXT = 1;
          if (NBNEXT == 2) {
            // 2 by 2 Block did not split

            dlaexc(WANTQ, N, T, LDT, Q, LDQ, HERE - 1, 2, 1, WORK, INFO);
            if (INFO.value != 0) {
              ILST.value = HERE;
              return;
            }
            HERE -= 2;
          } else {
            // 2 by 2 Block did split

            dlaexc(WANTQ, N, T, LDT, Q, LDQ, HERE, 1, 1, WORK, INFO);
            dlaexc(WANTQ, N, T, LDT, Q, LDQ, HERE - 1, 1, 1, WORK, INFO);
            HERE -= 2;
          }
        }
      }
    } while (HERE > ILST.value);
  }
  ILST.value = HERE;
}