dtrsna function

void dtrsna(
  1. String JOB,
  2. String HOWMNY,
  3. Array<bool> SELECT_,
  4. int N,
  5. Matrix<double> T_,
  6. int LDT,
  7. Matrix<double> VL_,
  8. int LDVL,
  9. Matrix<double> VR_,
  10. int LDVR,
  11. Array<double> S_,
  12. Array<double> SEP_,
  13. int MM,
  14. Box<int> M,
  15. Matrix<double> WORK_,
  16. int LDWORK,
  17. Array<int> IWORK_,
  18. Box<int> INFO,
)

Implementation

void dtrsna(
  final String JOB,
  final String HOWMNY,
  final Array<bool> SELECT_,
  final int N,
  final Matrix<double> T_,
  final int LDT,
  final Matrix<double> VL_,
  final int LDVL,
  final Matrix<double> VR_,
  final int LDVR,
  final Array<double> S_,
  final Array<double> SEP_,
  final int MM,
  final Box<int> M,
  final Matrix<double> WORK_,
  final int LDWORK,
  final Array<int> IWORK_,
  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 S = S_.having();
  final SEP = SEP_.having();
  final WORK = WORK_.having(ld: LDWORK);
  final IWORK = IWORK_.having();
  const ZERO = 0.0, ONE = 1.0, TWO = 2.0;
  bool PAIR, SOMCON, WANTBH, WANTS, WANTSP;
  int I, J, K, KS, N2 = 0, NN = 0;
  double BIGNUM,
      COND,
      CS,
      DELTA,
      DUMM = 0,
      EPS,
      LNRM,
      MU = 0,
      PROD,
      PROD1,
      PROD2,
      RNRM,
      SMLNUM,
      SN;
  final ISAVE = Array<int>(3);
  final DUMMY = Array<double>(1);
  final IERR = Box(0), KASE = Box(0), IFST = Box(0), ILST = Box(0);
  final SCALE = Box(0.0), EST = Box(0.0);

  // Decode and test the input parameters

  WANTBH = lsame(JOB, 'B');
  WANTS = lsame(JOB, 'E') || WANTBH;
  WANTSP = lsame(JOB, 'V') || WANTBH;

  SOMCON = lsame(HOWMNY, 'S');

  INFO.value = 0;
  if (!WANTS && !WANTSP) {
    INFO.value = -1;
  } else if (!lsame(HOWMNY, 'A') && !SOMCON) {
    INFO.value = -2;
  } else if (N < 0) {
    INFO.value = -4;
  } else if (LDT < max(1, N)) {
    INFO.value = -6;
  } else if (LDVL < 1 || (WANTS && LDVL < N)) {
    INFO.value = -8;
  } else if (LDVR < 1 || (WANTS && LDVR < N)) {
    INFO.value = -10;
  } else {
    // Set M to the number of eigenpairs for which condition numbers
    // are required, and test MM.

    if (SOMCON) {
      M.value = 0;
      PAIR = false;
      for (K = 1; K <= N; K++) {
        if (PAIR) {
          PAIR = false;
        } else {
          if (K < N) {
            if (T[K + 1][K] == ZERO) {
              if (SELECT[K]) M.value++;
            } else {
              PAIR = true;
              if (SELECT[K] || SELECT[K + 1]) M.value += 2;
            }
          } else {
            if (SELECT[N]) M.value++;
          }
        }
      }
    } else {
      M.value = N;
    }

    if (MM < M.value) {
      INFO.value = -13;
    } else if (LDWORK < 1 || (WANTSP && LDWORK < N)) {
      INFO.value = -16;
    }
  }
  if (INFO.value != 0) {
    xerbla('DTRSNA', -INFO.value);
    return;
  }

  // Quick return if possible

  if (N == 0) return;

  if (N == 1) {
    if (SOMCON) {
      if (!SELECT[1]) return;
    }
    if (WANTS) S[1] = ONE;
    if (WANTSP) SEP[1] = T[1][1].abs();
    return;
  }

  // Get machine constants

  EPS = dlamch('P');
  SMLNUM = dlamch('S') / EPS;
  BIGNUM = ONE / SMLNUM;

  KS = 0;
  PAIR = false;
  for (K = 1; K <= N; K++) {
    // Determine whether T[k][k] begins a 1-by-1 or 2-by-2 block.

    if (PAIR) {
      PAIR = false;
      continue;
    }

    if (K < N) PAIR = T[K + 1][K] != ZERO;

    // Determine whether condition numbers are required for the k-th
    // eigenpair.

    if (SOMCON) {
      if (PAIR) {
        if (!SELECT[K] && !SELECT[K + 1]) continue;
      } else {
        if (!SELECT[K]) continue;
      }
    }

    KS++;

    if (WANTS) {
      // Compute the reciprocal condition number of the k-th
      // eigenvalue.

      if (!PAIR) {
        // Real eigenvalue.

        PROD = ddot(N, VR(1, KS).asArray(), 1, VL(1, KS).asArray(), 1);
        RNRM = dnrm2(N, VR(1, KS).asArray(), 1);
        LNRM = dnrm2(N, VL(1, KS).asArray(), 1);
        S[KS] = PROD.abs() / (RNRM * LNRM);
      } else {
        // Complex eigenvalue.

        PROD1 = ddot(N, VR(1, KS).asArray(), 1, VL(1, KS).asArray(), 1);
        PROD1 +=
            ddot(N, VR(1, KS + 1).asArray(), 1, VL(1, KS + 1).asArray(), 1);
        PROD2 = ddot(N, VL(1, KS).asArray(), 1, VR(1, KS + 1).asArray(), 1);
        PROD2 -= ddot(N, VL(1, KS + 1).asArray(), 1, VR(1, KS).asArray(), 1);
        RNRM = dlapy2(dnrm2(N, VR(1, KS).asArray(), 1),
            dnrm2(N, VR(1, KS + 1).asArray(), 1));
        LNRM = dlapy2(dnrm2(N, VL(1, KS).asArray(), 1),
            dnrm2(N, VL(1, KS + 1).asArray(), 1));
        COND = dlapy2(PROD1, PROD2) / (RNRM * LNRM);
        S[KS] = COND;
        S[KS + 1] = COND;
      }
    }

    if (WANTSP) {
      // Estimate the reciprocal condition number of the k-th
      // eigenvector.

      // Copy the matrix T to the array WORK and swap the diagonal
      // block beginning at T[k][k] to the (1,1) position.

      dlacpy('Full', N, N, T, LDT, WORK, LDWORK);
      IFST.value = K;
      ILST.value = 1;
      dtrexc('No Q', N, WORK, LDWORK, DUMMY.asMatrix(1), 1, IFST, ILST,
          WORK(1, N + 1).asArray(), IERR);

      if (IERR.value == 1 || IERR.value == 2) {
        // Could not swap because blocks not well separated

        SCALE.value = ONE;
        EST.value = BIGNUM;
      } else {
        // Reordering successful

        if (WORK[2][1] == ZERO) {
          // Form C = T22 - lambda*I in WORK[2:N][2:N].

          for (I = 2; I <= N; I++) {
            WORK[I][I] -= WORK[1][1];
          }
          N2 = 1;
          NN = N - 1;
        } else {
          // Triangularize the 2 by 2 block by unitary
          // transformation U = [  cs   i*ss ]
          // [ i*ss   cs  ].
          // such that the (1,1) position of WORK is complex
          // eigenvalue lambda with positive imaginary part. (2,2)
          // position of WORK is the complex eigenvalue lambda
          // with negative imaginary  part.

          MU = sqrt(WORK[1][2].abs()) * sqrt(WORK[2][1].abs());
          DELTA = dlapy2(MU, WORK[2][1]);
          CS = MU / DELTA;
          SN = -WORK[2][1] / DELTA;

          // Form

          // C**T = WORK[2:N][2:N] + i*[rwork(1) ..... rwork(n-1) ]
          // [   mu                     ]
          // [         ..               ]
          // [             ..           ]
          // [                  mu      ]
          // where C**T is transpose of matrix C,
          // and RWORK is stored starting in the N+1-st column of
          // WORK.

          for (J = 3; J <= N; J++) {
            WORK[2][J] = CS * WORK[2][J];
            WORK[J][J] -= WORK[1][1];
          }
          WORK[2][2] = ZERO;

          WORK[1][N + 1] = TWO * MU;
          for (I = 2; I <= N - 1; I++) {
            WORK[I][N + 1] = SN * WORK[1][I + 1];
          }
          N2 = 2;
          NN = 2 * (N - 1);
        }

        // Estimate norm(inv(C**T))

        EST.value = ZERO;
        KASE.value = 0;
        while (true) {
          dlacn2(NN, WORK(1, N + 2).asArray(), WORK(1, N + 4).asArray(), IWORK,
              EST, KASE, ISAVE);
          if (KASE.value == 0) break;
          if (KASE.value == 1) {
            if (N2 == 1) {
              // Real eigenvalue: solve C**T*x = scale*c.

              dlaqtr(true, true, N - 1, WORK(2, 2), LDWORK, DUMMY, DUMM, SCALE,
                  WORK(1, N + 4).asArray(), WORK(1, N + 6).asArray(), IERR);
            } else {
              // Complex eigenvalue: solve
              // C**T*(p+iq) = scale*(c+id) in real arithmetic.

              dlaqtr(
                  true,
                  false,
                  N - 1,
                  WORK(2, 2),
                  LDWORK,
                  WORK(1, N + 1).asArray(),
                  MU,
                  SCALE,
                  WORK(1, N + 4).asArray(),
                  WORK(1, N + 6).asArray(),
                  IERR);
            }
          } else {
            if (N2 == 1) {
              // Real eigenvalue: solve C*x = scale*c.

              dlaqtr(false, true, N - 1, WORK(2, 2), LDWORK, DUMMY, DUMM, SCALE,
                  WORK(1, N + 4).asArray(), WORK(1, N + 6).asArray(), IERR);
            } else {
              // Complex eigenvalue: solve
              // C*(p+iq) = scale*(c+id) in real arithmetic.

              dlaqtr(
                  false,
                  false,
                  N - 1,
                  WORK(2, 2),
                  LDWORK,
                  WORK(1, N + 1).asArray(),
                  MU,
                  SCALE,
                  WORK(1, N + 4).asArray(),
                  WORK(1, N + 6).asArray(),
                  IERR);
            }
          }
        }
      }

      SEP[KS] = SCALE.value / max(EST.value, SMLNUM);
      if (PAIR) SEP[KS + 1] = SEP[KS];
    }

    if (PAIR) KS++;
  }
}