dgeev function

void dgeev(
  1. String JOBVL,
  2. String JOBVR,
  3. int N,
  4. Matrix<double> A_,
  5. int LDA,
  6. Array<double> WR_,
  7. Array<double> WI_,
  8. Matrix<double> VL_,
  9. int LDVL,
  10. Matrix<double> VR_,
  11. int LDVR,
  12. Array<double> WORK_,
  13. int LWORK,
  14. Box<int> INFO,
)

Implementation

void dgeev(
  final String JOBVL,
  final String JOBVR,
  final int N,
  final Matrix<double> A_,
  final int LDA,
  final Array<double> WR_,
  final Array<double> WI_,
  final Matrix<double> VL_,
  final int LDVL,
  final Matrix<double> VR_,
  final int LDVR,
  final Array<double> WORK_,
  final int LWORK,
  final Box<int> INFO,
) {
  final A = A_.having(ld: LDA);
  final WR = WR_.having();
  final WI = WI_.having();
  final VL = VL_.having(ld: LDVL);
  final VR = VR_.having(ld: LDVR);
  final WORK = WORK_.having();
  const ZERO = 0.0, ONE = 1.0;
  bool LQUERY, SCALEA, WANTVL, WANTVR;
  String SIDE = '';
  int HSWORK, I, IBAL, ITAU, IWRK, K, LWORK_TREVC, MAXWRK = 0, MINWRK;
  double ANRM, BIGNUM, CSCALE = 0, EPS, SCL, SMLNUM;
  final SELECT = Array<bool>(1);
  final DUM = Array<double>(1);
  final NOUT = Box(0), IERR = Box(0), IHI = Box(0), ILO = Box(0);
  final CS = Box(0.0), R = Box(0.0), SN = Box(0.0);

  // Test the input arguments

  INFO.value = 0;
  LQUERY = (LWORK == -1);
  WANTVL = lsame(JOBVL, 'V');
  WANTVR = lsame(JOBVR, 'V');
  if (!WANTVL && !lsame(JOBVL, 'N')) {
    INFO.value = -1;
  } else if (!WANTVR && !lsame(JOBVR, 'N')) {
    INFO.value = -2;
  } else if (N < 0) {
    INFO.value = -3;
  } else if (LDA < max(1, N)) {
    INFO.value = -5;
  } else if (LDVL < 1 || (WANTVL && LDVL < N)) {
    INFO.value = -9;
  } else if (LDVR < 1 || (WANTVR && LDVR < N)) {
    INFO.value = -11;
  }

  // Compute workspace
  // (Note: Comments in the code beginning "Workspace:" describe the
  // minimal amount of workspace needed at that point in the code,
  // as well as the preferred amount for good performance.
  // NB refers to the optimal block size for the immediately
  // following subroutine, as returned by ILAENV.
  // HSWORK refers to the workspace preferred by DHSEQR, as
  // calculated below. HSWORK is computed assuming ILO=1 and IHI=N,
  // the worst case.)

  if (INFO.value == 0) {
    if (N == 0) {
      MINWRK = 1;
      MAXWRK = 1;
    } else {
      MAXWRK = 2 * N + N * ilaenv(1, 'DGEHRD', ' ', N, 1, N, 0);
      if (WANTVL) {
        MINWRK = 4 * N;
        MAXWRK = max(
            MAXWRK, 2 * N + (N - 1) * ilaenv(1, 'DORGHR', ' ', N, 1, N, -1));
        dhseqr('S', 'V', N, 1, N, A, LDA, WR, WI, VL, LDVL, WORK, -1, INFO);
        HSWORK = WORK[1].toInt();
        MAXWRK = max(MAXWRK, max(N + 1, N + HSWORK));
        dtrevc3('L', 'B', SELECT, N, A, LDA, VL, LDVL, VR, LDVR, N, NOUT, WORK,
            -1, IERR);
        LWORK_TREVC = WORK[1].toInt();
        MAXWRK = max(MAXWRK, N + LWORK_TREVC);
        MAXWRK = max(MAXWRK, 4 * N);
      } else if (WANTVR) {
        MINWRK = 4 * N;
        MAXWRK = max(
            MAXWRK, 2 * N + (N - 1) * ilaenv(1, 'DORGHR', ' ', N, 1, N, -1));
        dhseqr('S', 'V', N, 1, N, A, LDA, WR, WI, VR, LDVR, WORK, -1, INFO);
        HSWORK = WORK[1].toInt();
        MAXWRK = max(MAXWRK, max(N + 1, N + HSWORK));
        dtrevc3('R', 'B', SELECT, N, A, LDA, VL, LDVL, VR, LDVR, N, NOUT, WORK,
            -1, IERR);
        LWORK_TREVC = WORK[1].toInt();
        MAXWRK = max(MAXWRK, N + LWORK_TREVC);
        MAXWRK = max(MAXWRK, 4 * N);
      } else {
        MINWRK = 3 * N;
        dhseqr('E', 'N', N, 1, N, A, LDA, WR, WI, VR, LDVR, WORK, -1, INFO);
        HSWORK = WORK[1].toInt();
        MAXWRK = max(MAXWRK, max(N + 1, N + HSWORK));
      }
      MAXWRK = max(MAXWRK, MINWRK);
    }
    WORK[1] = MAXWRK.toDouble();

    if (LWORK < MINWRK && !LQUERY) {
      INFO.value = -13;
    }
  }

  if (INFO.value != 0) {
    xerbla('DGEEV', -INFO.value);
    return;
  } else if (LQUERY) {
    return;
  }

  // Quick return if possible

  if (N == 0) return;

  // Get machine constants

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

  // Scale A if max element outside range [SMLNUM,BIGNUM]

  ANRM = dlange('M', N, N, A, LDA, DUM);
  SCALEA = false;
  if (ANRM > ZERO && ANRM < SMLNUM) {
    SCALEA = true;
    CSCALE = SMLNUM;
  } else if (ANRM > BIGNUM) {
    SCALEA = true;
    CSCALE = BIGNUM;
  }
  if (SCALEA) dlascl('G', 0, 0, ANRM, CSCALE, N, N, A, LDA, IERR);

  // Balance the matrix
  // (Workspace: need N)

  IBAL = 1;
  dgebal('B', N, A, LDA, ILO, IHI, WORK(IBAL), IERR);

  // Reduce to upper Hessenberg form
  // (Workspace: need 3*N, prefer 2*N+N*NB)

  ITAU = IBAL + N;
  IWRK = ITAU + N;
  dgehrd(N, ILO.value, IHI.value, A, LDA, WORK(ITAU), WORK(IWRK),
      LWORK - IWRK + 1, IERR);

  if (WANTVL) {
    // Want left eigenvectors
    // Copy Householder vectors to VL

    SIDE = 'L';
    dlacpy('L', N, N, A, LDA, VL, LDVL);

    // Generate orthogonal matrix in VL
    // (Workspace: need 3*N-1, prefer 2*N+(N-1)*NB)

    dorghr(N, ILO.value, IHI.value, VL, LDVL, WORK(ITAU), WORK(IWRK),
        LWORK - IWRK + 1, IERR);

    // Perform QR iteration, accumulating Schur vectors in VL
    // (Workspace: need N+1, prefer N+HSWORK (see comments) )

    IWRK = ITAU;
    dhseqr('S', 'V', N, ILO.value, IHI.value, A, LDA, WR, WI, VL, LDVL,
        WORK(IWRK), LWORK - IWRK + 1, INFO);

    if (WANTVR) {
      // Want left and right eigenvectors
      // Copy Schur vectors to VR

      SIDE = 'B';
      dlacpy('F', N, N, VL, LDVL, VR, LDVR);
    }
  } else if (WANTVR) {
    // Want right eigenvectors
    // Copy Householder vectors to VR

    SIDE = 'R';
    dlacpy('L', N, N, A, LDA, VR, LDVR);

    // Generate orthogonal matrix in VR
    // (Workspace: need 3*N-1, prefer 2*N+(N-1)*NB)

    dorghr(N, ILO.value, IHI.value, VR, LDVR, WORK(ITAU), WORK(IWRK),
        LWORK - IWRK + 1, IERR);

    // Perform QR iteration, accumulating Schur vectors in VR
    // (Workspace: need N+1, prefer N+HSWORK (see comments) )

    IWRK = ITAU;
    dhseqr('S', 'V', N, ILO.value, IHI.value, A, LDA, WR, WI, VR, LDVR,
        WORK(IWRK), LWORK - IWRK + 1, INFO);
  } else {
    // Compute eigenvalues only
    // (Workspace: need N+1, prefer N+HSWORK (see comments) )

    IWRK = ITAU;
    dhseqr('E', 'N', N, ILO.value, IHI.value, A, LDA, WR, WI, VR, LDVR,
        WORK(IWRK), LWORK - IWRK + 1, INFO);
  }

  // If INFO != 0 from DHSEQR, then quit

  if (INFO.value == 0) {
    if (WANTVL || WANTVR) {
      // Compute left and/or right eigenvectors
      // (Workspace: need 4*N, prefer N + N + 2*N*NB)

      dtrevc3(SIDE, 'B', SELECT, N, A, LDA, VL, LDVL, VR, LDVR, N, NOUT,
          WORK(IWRK), LWORK - IWRK + 1, IERR);
    }

    if (WANTVL) {
      // Undo balancing of left eigenvectors
      // (Workspace: need N)

      dgebak('B', 'L', N, ILO.value, IHI.value, WORK(IBAL), N, VL, LDVL, IERR);

      // Normalize left eigenvectors and make largest component real

      for (I = 1; I <= N; I++) {
        if (WI[I] == ZERO) {
          SCL = ONE / dnrm2(N, VL(1, I).asArray(), 1);
          dscal(N, SCL, VL(1, I).asArray(), 1);
        } else if (WI[I] > ZERO) {
          SCL = ONE /
              dlapy2(dnrm2(N, VL(1, I).asArray(), 1),
                  dnrm2(N, VL(1, I + 1).asArray(), 1));
          dscal(N, SCL, VL(1, I).asArray(), 1);
          dscal(N, SCL, VL(1, I + 1).asArray(), 1);
          for (K = 1; K <= N; K++) {
            WORK[IWRK + K - 1] =
                pow(VL[K][I], 2).toDouble() + pow(VL[K][I + 1], 2);
          }
          K = idamax(N, WORK(IWRK), 1);
          dlartg(VL[K][I], VL[K][I + 1], CS, SN, R);
          drot(N, VL(1, I).asArray(), 1, VL(1, I + 1).asArray(), 1, CS.value,
              SN.value);
          VL[K][I + 1] = ZERO;
        }
      }
    }

    if (WANTVR) {
      // Undo balancing of right eigenvectors
      // (Workspace: need N)

      dgebak('B', 'R', N, ILO.value, IHI.value, WORK(IBAL), N, VR, LDVR, IERR);

      // Normalize right eigenvectors and make largest component real

      for (I = 1; I <= N; I++) {
        if (WI[I] == ZERO) {
          SCL = ONE / dnrm2(N, VR(1, I).asArray(), 1);
          dscal(N, SCL, VR(1, I).asArray(), 1);
        } else if (WI[I] > ZERO) {
          SCL = ONE /
              dlapy2(dnrm2(N, VR(1, I).asArray(), 1),
                  dnrm2(N, VR(1, I + 1).asArray(), 1));
          dscal(N, SCL, VR(1, I).asArray(), 1);
          dscal(N, SCL, VR(1, I + 1).asArray(), 1);
          for (K = 1; K <= N; K++) {
            WORK[IWRK + K - 1] =
                pow(VR[K][I], 2).toDouble() + pow(VR[K][I + 1], 2);
          }
          K = idamax(N, WORK(IWRK), 1);
          dlartg(VR[K][I], VR[K][I + 1], CS, SN, R);
          drot(N, VR(1, I).asArray(), 1, VR(1, I + 1).asArray(), 1, CS.value,
              SN.value);
          VR[K][I + 1] = ZERO;
        }
      }
    }
  }

  // Undo scaling if necessary

  if (SCALEA) {
    var ld = max(N - INFO.value, 1);
    dlascl('G', 0, 0, CSCALE, ANRM, N - INFO.value, 1,
        WR(INFO.value + 1).asMatrix(ld), ld, IERR);
    dlascl('G', 0, 0, CSCALE, ANRM, N - INFO.value, 1,
        WI(INFO.value + 1).asMatrix(ld), ld, IERR);
    if (INFO.value > 0) {
      dlascl(
          'G', 0, 0, CSCALE, ANRM, ILO.value - 1, 1, WR.asMatrix(N), N, IERR);
      dlascl(
          'G', 0, 0, CSCALE, ANRM, ILO.value - 1, 1, WI.asMatrix(N), N, IERR);
    }
  }

  WORK[1] = MAXWRK.toDouble();
}