dlasd8 function

void dlasd8(
  1. int ICOMPQ,
  2. int K,
  3. Array<double> D_,
  4. Array<double> Z_,
  5. Array<double> VF_,
  6. Array<double> VL_,
  7. Array<double> DIFL_,
  8. Matrix<double> DIFR_,
  9. int LDDIFR,
  10. Array<double> DSIGMA_,
  11. Array<double> WORK_,
  12. Box<int> INFO,
)

Implementation

void dlasd8(
  final int ICOMPQ,
  final int K,
  final Array<double> D_,
  final Array<double> Z_,
  final Array<double> VF_,
  final Array<double> VL_,
  final Array<double> DIFL_,
  final Matrix<double> DIFR_,
  final int LDDIFR,
  final Array<double> DSIGMA_,
  final Array<double> WORK_,
  final Box<int> INFO,
) {
  final D = D_.having();
  final Z = Z_.having();
  final VF = VF_.having();
  final VL = VL_.having();
  final DIFL = DIFL_.having();
  final DIFR = DIFR_.having(ld: LDDIFR);
  final DSIGMA = DSIGMA_.having();
  final WORK = WORK_.having();
  const ONE = 1.0;
  int I, IWK1, IWK2, IWK2I, IWK3, IWK3I, J;
  double DIFLJ, DIFRJ = 0, DJ, DSIGJ, DSIGJP = 0, RHO, TEMP;

  // Test the input parameters.

  INFO.value = 0;

  if ((ICOMPQ < 0) || (ICOMPQ > 1)) {
    INFO.value = -1;
  } else if (K < 1) {
    INFO.value = -2;
  } else if (LDDIFR < K) {
    INFO.value = -9;
  }
  if (INFO.value != 0) {
    xerbla('DLASD8', -INFO.value);
    return;
  }

  // Quick return if possible

  if (K == 1) {
    D[1] = Z[1].abs();
    DIFL[1] = D[1];
    if (ICOMPQ == 1) {
      DIFL[2] = ONE;
      DIFR[1][2] = ONE;
    }
    return;
  }

  // Book keeping.

  IWK1 = 1;
  IWK2 = IWK1 + K;
  IWK3 = IWK2 + K;
  IWK2I = IWK2 - 1;
  IWK3I = IWK3 - 1;

  // Normalize Z.

  RHO = dnrm2(K, Z, 1);
  dlascl('G', 0, 0, RHO, ONE, K, 1, Z.asMatrix(K), K, INFO);
  RHO *= RHO;

  // Initialize WORK(IWK3).

  dlaset('A', K, 1, ONE, ONE, WORK(IWK3).asMatrix(K), K);

  // Compute the updated singular values, the arrays DIFL, DIFR,
  // and the updated Z.

  for (J = 1; J <= K; J++) {
    dlasd4(K, J, DSIGMA, Z, WORK(IWK1), RHO, D.box(J), WORK(IWK2), INFO);

    // If the root finder fails, report the convergence failure.

    if (INFO.value != 0) {
      return;
    }
    WORK[IWK3I + J] *= WORK[J] * WORK[IWK2I + J];
    DIFL[J] = -WORK[J];
    DIFR[J][1] = -WORK[J + 1];
    for (I = 1; I <= J - 1; I++) {
      WORK[IWK3I + I] *= WORK[I] *
          WORK[IWK2I + I] /
          (DSIGMA[I] - DSIGMA[J]) /
          (DSIGMA[I] + DSIGMA[J]);
    }
    for (I = J + 1; I <= K; I++) {
      WORK[IWK3I + I] *= WORK[I] *
          WORK[IWK2I + I] /
          (DSIGMA[I] - DSIGMA[J]) /
          (DSIGMA[I] + DSIGMA[J]);
    }
  }

  // Compute updated Z.

  for (I = 1; I <= K; I++) {
    Z[I] = sign(sqrt(WORK[IWK3I + I].abs()), Z[I]);
  }

  // Update VF and VL.

  for (J = 1; J <= K; J++) {
    DIFLJ = DIFL[J];
    DJ = D[J];
    DSIGJ = -DSIGMA[J];
    if (J < K) {
      DIFRJ = -DIFR[J][1];
      DSIGJP = -DSIGMA[J + 1];
    }
    WORK[J] = -Z[J] / DIFLJ / (DSIGMA[J] + DJ);

    // Use calls to the subroutine DLAMC3 to enforce the parentheses
    // (x+y)+z. The goal is to prevent optimizing compilers
    // from doing x+(y+z).

    for (I = 1; I <= J - 1; I++) {
      WORK[I] = Z[I] / (dlamc3(DSIGMA[I], DSIGJ) - DIFLJ) / (DSIGMA[I] + DJ);
    }
    for (I = J + 1; I <= K; I++) {
      WORK[I] = Z[I] / (dlamc3(DSIGMA[I], DSIGJP) + DIFRJ) / (DSIGMA[I] + DJ);
    }
    TEMP = dnrm2(K, WORK, 1);
    WORK[IWK2I + J] = ddot(K, WORK, 1, VF, 1) / TEMP;
    WORK[IWK3I + J] = ddot(K, WORK, 1, VL, 1) / TEMP;
    if (ICOMPQ == 1) {
      DIFR[J][2] = TEMP;
    }
  }

  dcopy(K, WORK(IWK2), 1, VF, 1);
  dcopy(K, WORK(IWK3), 1, VL, 1);
}