zunbdb6 function

void zunbdb6(
  1. int M1,
  2. int M2,
  3. int N,
  4. Array<Complex> X1_,
  5. int INCX1,
  6. Array<Complex> X2_,
  7. int INCX2,
  8. Matrix<Complex> Q1_,
  9. int LDQ1,
  10. Matrix<Complex> Q2_,
  11. int LDQ2,
  12. Array<Complex> WORK_,
  13. int LWORK,
  14. Box<int> INFO,
)

Implementation

void zunbdb6(
  final int M1,
  final int M2,
  final int N,
  final Array<Complex> X1_,
  final int INCX1,
  final Array<Complex> X2_,
  final int INCX2,
  final Matrix<Complex> Q1_,
  final int LDQ1,
  final Matrix<Complex> Q2_,
  final int LDQ2,
  final Array<Complex> WORK_,
  final int LWORK,
  final Box<int> INFO,
) {
  final Q1 = Q1_.having(ld: LDQ1);
  final Q2 = Q2_.having(ld: LDQ2);
  final WORK = WORK_.having();
  final X1 = X1_.having();
  final X2 = X2_.having();
  const ALPHA = 0.83, REALZERO = 0.0;
  int I, IX;
  double EPS, NORM, NORM_NEW;
  final SCL = Box(0.0), SSQ = Box(0.0);

  // Test input arguments

  INFO.value = 0;
  if (M1 < 0) {
    INFO.value = -1;
  } else if (M2 < 0) {
    INFO.value = -2;
  } else if (N < 0) {
    INFO.value = -3;
  } else if (INCX1 < 1) {
    INFO.value = -5;
  } else if (INCX2 < 1) {
    INFO.value = -7;
  } else if (LDQ1 < max(1, M1)) {
    INFO.value = -9;
  } else if (LDQ2 < max(1, M2)) {
    INFO.value = -11;
  } else if (LWORK < N) {
    INFO.value = -13;
  }

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

  EPS = dlamch('Precision');

  // Compute the Euclidean norm of X

  SCL.value = REALZERO;
  SSQ.value = REALZERO;
  zlassq(M1, X1, INCX1, SCL, SSQ);
  zlassq(M2, X2, INCX2, SCL, SSQ);
  NORM = SCL.value * sqrt(SSQ.value);

  // First, project X onto the orthogonal complement of Q's column
  // space

  if (M1 == 0) {
    for (I = 1; I <= N; I++) {
      WORK[I] = Complex.zero;
    }
  } else {
    zgemv('C', M1, N, Complex.one, Q1, LDQ1, X1, INCX1, Complex.zero, WORK, 1);
  }

  zgemv('C', M2, N, Complex.one, Q2, LDQ2, X2, INCX2, Complex.one, WORK, 1);
  zgemv('N', M1, N, -Complex.one, Q1, LDQ1, WORK, 1, Complex.one, X1, INCX1);
  zgemv('N', M2, N, -Complex.one, Q2, LDQ2, WORK, 1, Complex.one, X2, INCX2);

  SCL.value = REALZERO;
  SSQ.value = REALZERO;
  zlassq(M1, X1, INCX1, SCL, SSQ);
  zlassq(M2, X2, INCX2, SCL, SSQ);
  NORM_NEW = SCL.value * sqrt(SSQ.value);

  // If projection is sufficiently large in norm, then stop.
  // If projection is zero, then stop.
  // Otherwise, project again.

  if (NORM_NEW >= ALPHA * NORM) {
    return;
  }

  if (NORM_NEW <= N * EPS * NORM) {
    for (IX = 1; IX <= 1 + (M1 - 1) * INCX1; IX += INCX1) {
      X1[IX] = Complex.zero;
    }
    for (IX = 1; IX <= 1 + (M2 - 1) * INCX2; IX += INCX2) {
      X2[IX] = Complex.zero;
    }
    return;
  }

  NORM = NORM_NEW;

  for (I = 1; I <= N; I++) {
    WORK[I] = Complex.zero;
  }

  if (M1 == 0) {
    for (I = 1; I <= N; I++) {
      WORK[I] = Complex.zero;
    }
  } else {
    zgemv('C', M1, N, Complex.one, Q1, LDQ1, X1, INCX1, Complex.zero, WORK, 1);
  }

  zgemv('C', M2, N, Complex.one, Q2, LDQ2, X2, INCX2, Complex.one, WORK, 1);
  zgemv('N', M1, N, -Complex.one, Q1, LDQ1, WORK, 1, Complex.one, X1, INCX1);
  zgemv('N', M2, N, -Complex.one, Q2, LDQ2, WORK, 1, Complex.one, X2, INCX2);

  SCL.value = REALZERO;
  SSQ.value = REALZERO;
  zlassq(M1, X1, INCX1, SCL, SSQ);
  zlassq(M2, X2, INCX2, SCL, SSQ);
  NORM_NEW = SCL.value * sqrt(SSQ.value);

  // If second projection is sufficiently large in norm, then do
  // nothing more. Alternatively, if it shrunk significantly, then
  // truncate it to zero.

  if (NORM_NEW < ALPHA * NORM) {
    for (IX = 1; IX <= 1 + (M1 - 1) * INCX1; IX += INCX1) {
      X1[IX] = Complex.zero;
    }
    for (IX = 1; IX <= 1 + (M2 - 1) * INCX2; IX += INCX2) {
      X2[IX] = Complex.zero;
    }
  }
}