ztrevc3 function

void ztrevc3(
  1. String SIDE,
  2. String HOWMNY,
  3. Array<bool> SELECT_,
  4. int N,
  5. Matrix<Complex> T_,
  6. int LDT,
  7. Matrix<Complex> VL_,
  8. int LDVL,
  9. Matrix<Complex> VR_,
  10. int LDVR,
  11. int MM,
  12. Box<int> M,
  13. Array<Complex> WORK_,
  14. int LWORK,
  15. Array<double> RWORK_,
  16. int LRWORK,
  17. Box<int> INFO,
)

Implementation

void ztrevc3(
  final String SIDE,
  final String HOWMNY,
  final Array<bool> SELECT_,
  final int N,
  final Matrix<Complex> T_,
  final int LDT,
  final Matrix<Complex> VL_,
  final int LDVL,
  final Matrix<Complex> VR_,
  final int LDVR,
  final int MM,
  final Box<int> M,
  final Array<Complex> WORK_,
  final int LWORK,
  final Array<double> RWORK_,
  final int LRWORK,
  final Box<int> INFO,
) {
  final SELECT = SELECT_.having();
  final T = T_.having(ld: LDT);
  final VL = VL_.having(ld: LDVL);
  final VR = VR_.having(ld: LDVR);
  final WORK = WORK_.having();
  final RWORK = RWORK_.having();
  const ZERO = 0.0, ONE = 1.0;
  const NBMIN = 8, NBMAX = 128;
  bool ALLV, BOTHV, LEFTV, LQUERY, OVER, RIGHTV, SOMEV;
  int I, II, IS, J, K, KI, IV, MAXWRK = 0, NB;
  double REMAX, SMIN = 0, SMLNUM, ULP, UNFL;
  final SCALE = Box(0.0);

  // Decode and test the input parameters
  BOTHV = lsame(SIDE, 'B');
  RIGHTV = lsame(SIDE, 'R') || BOTHV;
  LEFTV = lsame(SIDE, 'L') || BOTHV;

  ALLV = lsame(HOWMNY, 'A');
  OVER = lsame(HOWMNY, 'B');
  SOMEV = lsame(HOWMNY, 'S');

  // Set M to the number of columns required to store the selected
  // eigenvectors.
  if (SOMEV) {
    M.value = 0;
    for (J = 1; J <= N; J++) {
      if (SELECT[J]) M.value++;
    }
  } else {
    M.value = N;
  }

  INFO.value = 0;
  NB = ilaenv(1, 'ZTREVC', SIDE + HOWMNY, N, -1, -1, -1);
  MAXWRK = max(1, N + 2 * N * NB);
  WORK[1] = MAXWRK.toComplex();
  RWORK[1] = max(1, N).toDouble();
  LQUERY = LWORK == -1 || LRWORK == -1;
  if (!RIGHTV && !LEFTV) {
    INFO.value = -1;
  } else if (!ALLV && !OVER && !SOMEV) {
    INFO.value = -2;
  } else if (N < 0) {
    INFO.value = -4;
  } else if (LDT < max(1, N)) {
    INFO.value = -6;
  } else if (LDVL < 1 || (LEFTV && LDVL < N)) {
    INFO.value = -8;
  } else if (LDVR < 1 || (RIGHTV && LDVR < N)) {
    INFO.value = -10;
  } else if (MM < M.value) {
    INFO.value = -11;
  } else if (LWORK < max(1, 2 * N) && !LQUERY) {
    INFO.value = -14;
  } else if (LRWORK < max(1, N) && !LQUERY) {
    INFO.value = -16;
  }
  if (INFO.value != 0) {
    xerbla('ZTREVC3', -INFO.value);
    return;
  } else if (LQUERY) {
    return;
  }

  // Quick return if possible.
  if (N == 0) return;

  // Use blocked version of back-transformation if sufficient workspace.
  // Zero-out the workspace to avoid potential NaN propagation.
  if (OVER && LWORK >= N + 2 * N * NBMIN) {
    NB = (LWORK - N) ~/ (2 * N);
    NB = min(NB, NBMAX);
    zlaset('F', N, 1 + 2 * NB, Complex.zero, Complex.zero, WORK.asMatrix(N), N);
  } else {
    NB = 1;
  }

  // Set the constants to control overflow.
  UNFL = dlamch('Safe minimum');
  ULP = dlamch('Precision');
  SMLNUM = UNFL * (N / ULP);

  // Store the diagonal elements of T in working array WORK.
  for (I = 1; I <= N; I++) {
    WORK[I] = T[I][I];
  }

  // Compute 1-norm of each column of strictly upper triangular
  // part of T to control overflow in triangular solver.
  RWORK[1] = ZERO;
  for (J = 2; J <= N; J++) {
    RWORK[J] = dzasum(J - 1, T(1, J).asArray(), 1);
  }

  if (RIGHTV) {
    // Compute right eigenvectors.

    // IV is index of column in current block.
    // Non-blocked version always uses IV=NB=1;
    // blocked     version starts with IV=NB, goes down to 1.
    // (Note the "0-th" column is used to store the original diagonal.)
    IV = NB;
    IS = M.value;
    for (KI = N; KI >= 1; KI--) {
      if (SOMEV) {
        if (!SELECT[KI]) continue;
      }
      SMIN = max(ULP * T[KI][KI].cabs1(), SMLNUM);

      // Complex right eigenvector
      WORK[KI + IV * N] = Complex.one;

      // Form right-hand side.
      for (K = 1; K <= KI - 1; K++) {
        WORK[K + IV * N] = -T[K][KI];
      }

      // Solve upper triangular system:
      // [ T(1:KI-1,1:KI-1) - T(KI,KI) ]*X = SCALE*WORK.
      for (K = 1; K <= KI - 1; K++) {
        T[K][K] -= T[KI][KI];
        if (T[K][K].cabs1() < SMIN) T[K][K] = SMIN.toComplex();
      }

      if (KI > 1) {
        zlatrs('Upper', 'No transpose', 'Non-unit', 'Y', KI - 1, T, LDT,
            WORK(1 + IV * N), SCALE, RWORK, INFO);
        WORK[KI + IV * N] = SCALE.value.toComplex();
      }

      // Copy the vector x or Q*x to VR and normalize.
      if (!OVER) {
        // no back-transform: copy x to VR and normalize.
        zcopy(KI, WORK(1 + IV * N), 1, VR(1, IS).asArray(), 1);

        II = izamax(KI, VR(1, IS).asArray(), 1);
        REMAX = ONE / VR[II][IS].cabs1();
        zdscal(KI, REMAX, VR(1, IS).asArray(), 1);

        for (K = KI + 1; K <= N; K++) {
          VR[K][IS] = Complex.zero;
        }
      } else if (NB == 1) {
        // version 1: back-transform each vector with GEMV, Q*x.
        if (KI > 1) {
          zgemv('N', N, KI - 1, Complex.one, VR, LDVR, WORK(1 + IV * N), 1,
              SCALE.value.toComplex(), VR(1, KI).asArray(), 1);
        }

        II = izamax(N, VR(1, KI).asArray(), 1);
        REMAX = ONE / VR[II][KI].cabs1();
        zdscal(N, REMAX, VR(1, KI).asArray(), 1);
      } else {
        // version 2: back-transform block of vectors with GEMM
        // zero out below vector
        for (K = KI + 1; K <= N; K++) {
          WORK[K + IV * N] = Complex.zero;
        }

        // Columns IV:NB of work are valid vectors.
        // When the number of vectors stored reaches NB,
        // or if this was last vector, do the GEMM
        if ((IV == 1) || (KI == 1)) {
          zgemm(
              'N',
              'N',
              N,
              NB - IV + 1,
              KI + NB - IV,
              Complex.one,
              VR,
              LDVR,
              WORK(1 + IV * N).asMatrix(N),
              N,
              Complex.zero,
              WORK(1 + (NB + IV) * N).asMatrix(N),
              N);
          // normalize vectors
          for (K = IV; K <= NB; K++) {
            II = izamax(N, WORK(1 + (NB + K) * N), 1);
            REMAX = ONE / WORK[II + (NB + K) * N].cabs1();
            zdscal(N, REMAX, WORK(1 + (NB + K) * N), 1);
          }
          zlacpy('F', N, NB - IV + 1, WORK(1 + (NB + IV) * N).asMatrix(N), N,
              VR(1, KI), LDVR);
          IV = NB;
        } else {
          IV--;
        }
      }

      // Restore the original diagonal elements of T.
      for (K = 1; K <= KI - 1; K++) {
        T[K][K] = WORK[K];
      }

      IS--;
    }
  }

  if (LEFTV) {
    // Compute left eigenvectors.

    // IV is index of column in current block.
    // Non-blocked version always uses IV=1;
    // blocked     version starts with IV=1, goes up to NB.
    // (Note the "0-th" column is used to store the original diagonal.)
    IV = 1;
    IS = 1;
    for (KI = 1; KI <= N; KI++) {
      if (SOMEV) {
        if (!SELECT[KI]) continue;
      }
      SMIN = max(ULP * T[KI][KI].cabs1(), SMLNUM);

      // Complex left eigenvector
      WORK[KI + IV * N] = Complex.one;

      // Form right-hand side.
      for (K = KI + 1; K <= N; K++) {
        WORK[K + IV * N] = -T[KI][K].conjugate();
      }

      // Solve conjugate-transposed triangular system:
      // [ T(KI+1:N,KI+1:N) - T(KI,KI) ]**H * X = SCALE*WORK.
      for (K = KI + 1; K <= N; K++) {
        T[K][K] -= T[KI][KI];
        if (T[K][K].cabs1() < SMIN) T[K][K] = SMIN.toComplex();
      }

      if (KI < N) {
        zlatrs('Upper', 'Conjugate transpose', 'Non-unit', 'Y', N - KI,
            T(KI + 1, KI + 1), LDT, WORK(KI + 1 + IV * N), SCALE, RWORK, INFO);
        WORK[KI + IV * N] = SCALE.value.toComplex();
      }

      // Copy the vector x or Q*x to VL and normalize.
      if (!OVER) {
        // no back-transform: copy x to VL and normalize.
        zcopy(N - KI + 1, WORK(KI + IV * N), 1, VL(KI, IS).asArray(), 1);

        II = izamax(N - KI + 1, VL(KI, IS).asArray(), 1) + KI - 1;
        REMAX = ONE / VL[II][IS].cabs1();
        zdscal(N - KI + 1, REMAX, VL(KI, IS).asArray(), 1);

        for (K = 1; K <= KI - 1; K++) {
          VL[K][IS] = Complex.zero;
        }
      } else if (NB == 1) {
        // version 1: back-transform each vector with GEMV, Q*x.
        if (KI < N) {
          zgemv(
              'N',
              N,
              N - KI,
              Complex.one,
              VL(1, KI + 1),
              LDVL,
              WORK(KI + 1 + IV * N),
              1,
              SCALE.value.toComplex(),
              VL(1, KI).asArray(),
              1);
        }

        II = izamax(N, VL(1, KI).asArray(), 1);
        REMAX = ONE / VL[II][KI].cabs1();
        zdscal(N, REMAX, VL(1, KI).asArray(), 1);
      } else {
        // version 2: back-transform block of vectors with GEMM
        // zero out above vector
        // could go from KI-NV+1 to KI-1
        for (K = 1; K <= KI - 1; K++) {
          WORK[K + IV * N] = Complex.zero;
        }

        // Columns 1:IV of work are valid vectors.
        // When the number of vectors stored reaches NB,
        // or if this was last vector, do the GEMM
        if ((IV == NB) || (KI == N)) {
          zgemm(
              'N',
              'N',
              N,
              IV,
              N - KI + IV,
              Complex.one,
              VL(1, KI - IV + 1),
              LDVL,
              WORK(KI - IV + 1 + 1 * N).asMatrix(N),
              N,
              Complex.zero,
              WORK(1 + (NB + 1) * N).asMatrix(N),
              N);
          // normalize vectors
          for (K = 1; K <= IV; K++) {
            II = izamax(N, WORK(1 + (NB + K) * N), 1);
            REMAX = ONE / WORK[II + (NB + K) * N].cabs1();
            zdscal(N, REMAX, WORK(1 + (NB + K) * N), 1);
          }
          zlacpy('F', N, IV, WORK(1 + (NB + 1) * N).asMatrix(N), N,
              VL(1, KI - IV + 1), LDVL);
          IV = 1;
        } else {
          IV++;
        }
      }

      // Restore the original diagonal elements of T.
      for (K = KI + 1; K <= N; K++) {
        T[K][K] = WORK[K];
      }

      IS++;
    }
  }
}