Dlatrd.java

package org.mklab.sdpj.gpack.lapackwrap;

import org.mklab.nfc.matrix.ComplexNumericalMatrix;
import org.mklab.nfc.matrix.RealNumericalMatrix;
import org.mklab.nfc.scalar.ComplexNumericalScalar;
import org.mklab.nfc.scalar.RealNumericalScalar;
import org.mklab.sdpj.gpack.blaswrap.BLAS;


/**
 * @author koga
 * @version $Revision$, 2009/04/25
   * @param <RS> type of real scalar
   * @param <RM> type of real matrix
   * @param <CS> type of complex scalar
   * @param <CM> type of complex Matrix
 */
public class Dlatrd<RS extends RealNumericalScalar<RS, RM, CS, CM>, RM extends RealNumericalMatrix<RS, RM, CS, CM>, CS extends ComplexNumericalScalar<RS, RM, CS, CM>, CM extends ComplexNumericalMatrix<RS, RM, CS, CM>> {

  /** */
  private RS[] a;
  /** */
  private RS[] w;

  /*  -- LAPACK auxiliary routine (version 3.0) --   
  Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd.,   
  Courant Institute, Argonne National Lab, and Rice University   
  October 31, 1992   


  Purpose   
  =======   

  DLATRD reduces NB rows and columns of a real symmetric matrix A to   
  symmetric tridiagonal form by an orthogonal similarity   
  transformation Q' * A * Q, and returns the matrices V and W which are   
  needed to apply the transformation to the unreduced part of A.   

  If UPLO = 'U', DLATRD reduces the last NB rows and columns of a   
  matrix, of which the upper triangle is supplied;   
  if UPLO = 'L', DLATRD reduces the first NB rows and columns of a   
  matrix, of which the lower triangle is supplied.   

  This is an auxiliary routine called by DSYTRD.   

  Arguments   
  =========   

  UPLO    (input) CHARACTER   
       Specifies whether the upper or lower triangular part of the   
       symmetric matrix A is stored:   
       = 'U': Upper triangular   
       = 'L': Lower triangular   

  N       (input) INTEGER   
       The order of the matrix A.   

  NB      (input) INTEGER   
       The number of rows and columns to be reduced.   

  A       (input/output) DOUBLE PRECISION array, dimension (LDA,N)   
       On entry, the symmetric matrix A.  If UPLO = 'U', the leading   
       n-by-n upper triangular part of A contains the upper   
       triangular part of the matrix A, and the strictly lower   
       triangular part of A is not referenced.  If UPLO = 'L', the   
       leading n-by-n lower triangular part of A contains the lower   
       triangular part of the matrix A, and the strictly upper   
       triangular part of A is not referenced.   
       On exit:   
       if UPLO = 'U', the last NB columns have been reduced to   
         tridiagonal form, with the diagonal elements overwriting   
         the diagonal elements of A; the elements above the diagonal   
         with the array TAU, represent the orthogonal matrix Q as a   
         product of elementary reflectors;   
       if UPLO = 'L', the first NB columns have been reduced to   
         tridiagonal form, with the diagonal elements overwriting   
         the diagonal elements of A; the elements below the diagonal   
         with the array TAU, represent the  orthogonal matrix Q as a   
         product of elementary reflectors.   
       See Further Details.   

  LDA     (input) INTEGER   
       The leading dimension of the array A.  LDA >= (1,N).   

  RS       (output) DOUBLE PRECISION array, dimension (N-1)   
       If UPLO = 'U', E(n-nb:n-1) contains the superdiagonal   
       elements of the last NB columns of the reduced matrix;   
       if UPLO = 'L', E(1:nb) contains the subdiagonal elements of   
       the first NB columns of the reduced matrix.   

  TAU     (output) DOUBLE PRECISION array, dimension (N-1)   
       The scalar factors of the elementary reflectors, stored in   
       TAU(n-nb:n-1) if UPLO = 'U', and in TAU(1:nb) if UPLO = 'L'.   
       See Further Details.   

  W       (output) DOUBLE PRECISION array, dimension (LDW,NB)   
       The n-by-nb matrix W required to update the unreduced part   
       of A.   

  LDW     (input) INTEGER   
       The leading dimension of the array W. LDW >= max(1,N).   

  Further Details   
  ===============   

  If UPLO = 'U', the matrix Q is represented as a product of elementary   
  reflectors   

  Q = H(n) H(n-1) . . . H(n-nb+1).   

  Each H(i) has the form   

  H(i) = I - tau * v * v'   

  where tau is a real scalar, and v is a real vector with   
  v(i:n) = 0 and v(i-1) = 1; v(1:i-1) is stored on exit in A(1:i-1,i),   
  and tau in TAU(i-1).   

  If UPLO = 'L', the matrix Q is represented as a product of elementary   
  reflectors   

  Q = H(1) H(2) . . . H(nb).   

  Each H(i) has the form   

  H(i) = I - tau * v * v'   

  where tau is a real scalar, and v is a real vector with   
  v(1:i) = 0 and v(i+1) = 1; v(i+1:n) is stored on exit in A(i+1:n,i),   
  and tau in TAU(i).   

  The elements of the vectors v together form the n-by-nb matrix V   
  which is needed, with W, to apply the transformation to the unreduced   
  part of the matrix, using a symmetric rank-2k update of the form:   
  A := A - V*W' - W*V'.   

  The contents of A on exit are illustrated by the following examples   
  with n = 5 and nb = 2:   

  if UPLO = 'U':                       if UPLO = 'L':   

  (  a   a   a   v4  v5 )              (  d                  )   
  (      a   a   v4  v5 )              (  1   d              )   
  (          a   1   v5 )              (  v1  1   a          )   
  (              d   1  )              (  v1  v2  a   a      )   
  (                  d  )              (  v1  v2  a   a   a  )   

  where d denotes a diagonal element of the reduced matrix, a denotes   
  an element of the original matrix that is unchanged, and vi denotes   
  an element of the vector defining H(i).   

  =====================================================================   
  */
  /**
   * @param uplo uplo
   * @param n n
   * @param nb nb
   * @param ai ai
   * @param lda lda
   * @param e e
   * @param tau tau
   * @param wi wi
   * @param ldw ldw
   * @return result
   */
  int execute(String uplo, int n, int nb, RS[] ai, int lda, RS[] e, RS[] tau, RS[] wi, int ldw) {
    final RS unit = ai[0].createUnit();

    this.a = ai;
    this.w = wi;

    RS c_b5 = unit.create(-1);
    RS c_b6 = unit.create(1);
    RS c_b16 = unit.create(0);

    int a_dim1 = lda;
    int a_offset = 1 + a_dim1 * 1;
    int pointer_a = -a_offset;
    int pointer_e = -1;
    int pointer_tau = -1;
    int w_dim1 = ldw;
    int w_offset = 1 + w_dim1 * 1;
    int pointer_w = -w_offset;

    if (n <= 0) {
      return 0;
    }

    if (BLAS.lsame(uplo, "U")) { //$NON-NLS-1$
      /* Reduce last NB columns of upper triangle */
      for (int i = n; i >= n - nb + 1; --i) {
        int iw = i - n + nb;
        if (i < n) {
          /* Update A(1:i,i) */
          dgemv_awa("No transpose", i, n - i, c_b5, (i + 1) * a_dim1 + 1 + pointer_a, lda, (iw + 1) * w_dim1 + i + pointer_w, ldw, c_b6, i * a_dim1 + 1 + pointer_a, 1); //$NON-NLS-1$
          dgemv_waa("No transpose", i, n - i, c_b5, (iw + 1) * w_dim1 + 1 + pointer_w, ldw, (i + 1) * a_dim1 + i + pointer_a, lda, c_b6, i * a_dim1 + 1 + pointer_a, 1); //$NON-NLS-1$
        }

        if (i > 1) {
          /* Generate elementary reflector H(i) to annihilate A(1:i-2,i) */
          RS alpha1 = this.a[i * a_dim1 + i - 1 + pointer_a];
          RS[] ans = dlarfg(i - 1, alpha1, i * a_dim1 + 1 + pointer_a, 1, tau[pointer_tau + i - 1]);
          this.a[i * a_dim1 + i - 1 + pointer_a] = ans[0];
          tau[pointer_tau + i - 1] = ans[1];

          e[pointer_e + i - 1] = this.a[i * a_dim1 + i - 1 + pointer_a];
          this.a[i * a_dim1 + i - 1 + pointer_a] = unit.createUnit();

          /* Compute W(1:i-1,i) */
          dsymv("Upper", i - 1, c_b6, a_offset + pointer_a, lda, i * a_dim1 + 1 + pointer_a, 1, c_b16, (iw) * w_dim1 + 1 + pointer_w, 1); //$NON-NLS-1$

          if (i < n) {
            dgemv_waa("Transpose", i - 1, n - i, c_b6, (iw + 1) * w_dim1 + 1 + pointer_w, ldw, i * a_dim1 + 1 + pointer_a, 1, c_b16, (iw) * w_dim1 + i + 1 + pointer_w, 1); //$NON-NLS-1$
            dgemv_aww("No transpose", i - 1, n - i, c_b5, (i + 1) * a_dim1 + 1 + pointer_a, lda, (iw) * w_dim1 + i + 1 + pointer_w, 1, c_b6, (iw) * w_dim1 + 1 + pointer_w, 1); //$NON-NLS-1$
            dgemv_aaw("Transpose", i - 1, n - i, c_b6, (i + 1) * a_dim1 + 1 + pointer_a, lda, i * a_dim1 + 1 + pointer_a, 1, c_b16, iw * w_dim1 + i + 1 + pointer_w, 1); //$NON-NLS-1$
            dgemv_www("No transpose", i - 1, n - i, c_b5, (iw + 1) * w_dim1 + 1 + pointer_w, ldw, (iw) * w_dim1 + i + 1 + pointer_w, 1, c_b6, (iw) * w_dim1 + 1 + pointer_w, 1); //$NON-NLS-1$
          }

          dscal(i - 1, tau[pointer_tau + i - 1], (iw) * w_dim1 + 1 + pointer_w, 1);
          RS alpha = tau[pointer_tau + i - 1].divide(2).unaryMinus().multiply(ddot(i - 1, (iw) * w_dim1 + 1 + pointer_w, 1, (i) * a_dim1 + 1 + pointer_a, 1));
          daxpy(i - 1, alpha, i * a_dim1 + 1 + pointer_a, 1, iw * w_dim1 + 1 + pointer_w, 1);
        }
        /* L10: */
      }
    } else {
      /* Reduce first NB columns of lower triangle */
      for (int i = 1; i <= nb; ++i) {
        /* Update A(i:n,i) */
        dgemv_awa("No transpose", n - i + 1, i - 1, c_b5, a_dim1 + i + pointer_a, lda, w_dim1 + i + pointer_w, ldw, c_b6, i * a_dim1 + i + pointer_a, 1); //$NON-NLS-1$
        dgemv_waa("No transpose", n - i + 1, i - 1, c_b5, w_dim1 + i + pointer_w, ldw, a_dim1 + i + pointer_a, lda, c_b6, i * a_dim1 + i + pointer_a, 1); //$NON-NLS-1$

        if (i < n) {
          /* Generate elementary reflector H(i) to annihilate   
              A(i+2:n,i)   
             Computing MIN */

          RS alpha1 = this.a[i * a_dim1 + i + 1 + pointer_a];
          RS[] ans = dlarfg(n - i, alpha1, i * a_dim1 + Math.min(i + 2, n) + pointer_a, 1, tau[pointer_tau + i]);
          this.a[i * a_dim1 + i + 1 + pointer_a] = ans[0];
          tau[pointer_tau + i] = ans[1];

          e[pointer_e + i] = this.a[i * a_dim1 + i + 1 + pointer_a];
          this.a[i * a_dim1 + i + 1 + pointer_a] = unit.createUnit(); // Tools.toNumericalScalar(1);

          /*              Compute W(i+1:n,i) */
          dsymv("Lower", n - i, c_b6, (i + 1) * a_dim1 + i + 1 + pointer_a, lda, i * a_dim1 + i + 1 + pointer_a, 1, c_b16, (i) * w_dim1 + i + 1 + pointer_w, 1); //$NON-NLS-1$
          dgemv_waw("Transpose", n - i, i - 1, c_b6, w_dim1 + i + 1 + pointer_w, ldw, i * a_dim1 + i + 1 + pointer_a, 1, c_b16, (i) * w_dim1 + 1 + pointer_w, 1); //$NON-NLS-1$
          dgemv_aww("No transpose", n - i, i - 1, c_b5, a_dim1 + i + 1 + pointer_a, lda, (i) * w_dim1 + 1 + pointer_w, 1, c_b6, i * w_dim1 + i + 1 + pointer_w, 1); //$NON-NLS-1$
          dgemv_aaw("Transpose", n - i, i - 1, c_b6, a_dim1 + i + 1 + pointer_a, lda, i * a_dim1 + i + 1 + pointer_a, 1, c_b16, (i) * w_dim1 + 1 + pointer_w, 1); //$NON-NLS-1$
          dgemv_www("No transpose", n - i, i - 1, c_b5, w_dim1 + i + 1 + pointer_w, ldw, i * w_dim1 + 1 + pointer_w, 1, c_b6, (i) * w_dim1 + i + 1 + pointer_w, 1); //$NON-NLS-1$
          dscal(n - i, tau[pointer_tau + i], (i) * w_dim1 + i + 1 + pointer_w, 1);
          RS alpha = tau[pointer_tau + i].divide(2).unaryMinus().multiply(ddot(n - i, (i) * w_dim1 + i + 1 + pointer_w, 1, i * a_dim1 + i + 1 + pointer_a, 1));
          daxpy(n - i, alpha, i * a_dim1 + i + 1 + pointer_a, 1, (i) * w_dim1 + i + 1 + pointer_w, 1);
        }
        /* L20: */
      }
    }

    return 0;
  }

  /**
   * 引数で与えたパラメータ(配列等)は変更されません
   * 
   * @param n n
   * @param dxIndex dxIndex
   * @param incx incx
   * @param dyIndex dyIndex
   * @param incy incy
   * @return result
   */
  private RS ddot(int n, int dxIndex, int incx, int dyIndex, int incy) {
    final RS unit = this.a[0].createUnit();
    RS[] dx = unit.createArray(this.w.length - dxIndex);
    RS[] dy = unit.createArray(this.a.length - dyIndex);
    System.arraycopy(this.w, dxIndex, dx, 0, dx.length);
    System.arraycopy(this.a, dyIndex, dy, 0, dy.length);
    return BLAS.ddot(n, dx, incx, dy, incy);
  }

  /**
   * dy= dy+da.*dx 引数dyの値は変更されます。
   * 
   * @param n n
   * @param alpha alpha
   * @param dxIndex dxIndex
   * @param incx indx
   * @param dyIndex dyIndex
   * @param incy incy
   */
  private void daxpy(int n, RS alpha, int dxIndex, int incx, int dyIndex, int incy) {
    final RS unit = alpha.createUnit();
    RS[] dx = unit.createArray(this.a.length - dxIndex);
    RS[] dy = unit.createArray(this.w.length - dyIndex);
    System.arraycopy(this.a, dxIndex, dx, 0, dx.length);
    System.arraycopy(this.w, dyIndex, dy, 0, dy.length);
    BLAS.daxpy(n, alpha, dx, incx, dy, incy);
    System.arraycopy(dy, 0, this.w, dyIndex, dy.length);
  }

  /**
   * @param n n
   * @param da tau[?]
   * @param dxIndex w
   * @param incx indx
   */
  private void dscal(int n, RS da, int dxIndex, int incx) {
    final RS unit = da.createUnit();
    RS[] dx = unit.createArray(this.w.length - dxIndex);
    System.arraycopy(this.w, dxIndex, dx, 0, dx.length);
    BLAS.dscal(n, da, dx, incx);
    System.arraycopy(dx, 0, this.w, dxIndex, dx.length);
  }

  /**
   * @param uplo uplo
   * @param n n
   * @param alpha alpha
   * @param aIndex aIndex
   * @param lda lda
   * @param xIndex xIndex
   * @param incx incx
   * @param beta beta
   * @param yIndex w overwritten
   * @param incy incy
   * @return result
   */
  private int dsymv(String uplo, int n, RS alpha, int aIndex, int lda, int xIndex, int incx, RS beta, int yIndex, int incy) {
    final RS unit = alpha.createUnit();
    RS[] aTemp = unit.createArray(this.a.length - aIndex);
    RS[] x = unit.createArray(this.a.length - xIndex);
    RS[] y = unit.createArray(this.w.length - yIndex);
    System.arraycopy(this.a, aIndex, aTemp, 0, aTemp.length);
    System.arraycopy(this.a, xIndex, x, 0, x.length);
    System.arraycopy(this.w, yIndex, y, 0, y.length);
    int retValue = BLAS.dsymv(uplo, n, alpha, aTemp, lda, x, incx, beta, y, incy);
    System.arraycopy(y, 0, this.w, yIndex, y.length);

    return retValue;
  }

  /**
   * @param n n
   * @param alpha a[?]
   * @param xIndex a
   * @param incx indx
   * @param tau tau
   * @return result
   */
  private RS[] dlarfg(int n, RS alpha, int xIndex, int incx, RS tau) {
    final RS unit = alpha.createUnit();
    RS[] x = unit.createArray(this.a.length - xIndex);
    System.arraycopy(this.a, xIndex, x, 0, x.length);
    RS[] ans = Clapack.dlarfg(n, alpha, x, incx, tau);
    System.arraycopy(x, 0, this.a, xIndex, x.length);
    return ans;
  }

  /**
   * @param trans unchanged
   * @param m unchanged
   * @param n unchanged
   * @param alpha unchanged
   * @param aIndex unchanged
   * @param lda unchanged
   * @param xIndex unchanged
   * @param incx unchanged
   * @param beta unchanged
   * @param yIndex is overwritten by the update vector y
   * @param incy unchanged
   */
  private void dgemv_aww(String trans, int m, int n, RS alpha, int aIndex, int lda, int xIndex, int incx, RS beta, int yIndex, int incy) {
    final RS unit = alpha.createUnit();
    RS[] aTemp = unit.createArray(this.a.length - aIndex);
    RS[] x = unit.createArray(this.w.length - xIndex);
    RS[] y = unit.createArray(this.w.length - yIndex);
    System.arraycopy(this.a, aIndex, aTemp, 0, aTemp.length);
    System.arraycopy(this.w, xIndex, x, 0, x.length);
    System.arraycopy(this.w, yIndex, y, 0, y.length);
    BLAS.dgemv(trans, m, n, alpha, aTemp, lda, x, incx, beta, y, incy);
    System.arraycopy(y, 0, this.w, yIndex, y.length);
  }

  /**
   * @param trans unchanged
   * @param m unchanged
   * @param n unchanged
   * @param alpha unchanged
   * @param aIndex unchanged
   * @param lda unchanged
   * @param xIndex xIndex
   * @param incx unchanged
   * @param beta unchanged
   * @param yIndex is overwritten by the update vector y
   * @param incy unchanged
   */
  private void dgemv_awa(String trans, int m, int n, RS alpha, int aIndex, int lda, int xIndex, int incx, RS beta, int yIndex, int incy) {
    final RS unit = alpha.createUnit();
    RS[] aTemp = unit.createArray(this.a.length - aIndex);
    RS[] x = unit.createArray(this.w.length - xIndex);
    RS[] y = unit.createArray(this.a.length - yIndex);
    System.arraycopy(this.a, aIndex, aTemp, 0, aTemp.length);
    System.arraycopy(this.w, xIndex, x, 0, x.length);
    System.arraycopy(this.a, yIndex, y, 0, y.length);
    BLAS.dgemv(trans, m, n, alpha, aTemp, lda, x, incx, beta, y, incy);
    System.arraycopy(y, 0, this.a, yIndex, y.length);
  }

  /**
   * @param trans unchanged
   * @param m unchanged
   * @param n unchanged
   * @param alpha unchanged
   * @param aIndex aIndex
   * @param lda unchanged
   * @param xIndex xIndex
   * @param incx unchanged
   * @param beta unchanged
   * @param yIndex is overwritten by the update vector y
   * @param incy unchanged
   */
  private void dgemv_waa(String trans, int m, int n, RS alpha, int aIndex, int lda, int xIndex, int incx, RS beta, int yIndex, int incy) {
    final RS unit = alpha.createUnit();
    RS[] aTemp = unit.createArray(this.w.length - aIndex);
    RS[] x = unit.createArray(this.a.length - xIndex);
    RS[] y = unit.createArray(this.a.length - yIndex);
    System.arraycopy(this.w, aIndex, aTemp, 0, aTemp.length);
    System.arraycopy(this.a, xIndex, x, 0, x.length);
    System.arraycopy(this.a, yIndex, y, 0, y.length);
    BLAS.dgemv(trans, m, n, alpha, aTemp, lda, x, incx, beta, y, incy);
    System.arraycopy(y, 0, this.a, yIndex, y.length);
  }

  /**
   * @param trans unchanged
   * @param m unchanged
   * @param n unchanged
   * @param alpha unchanged
   * @param aIndex unchanged
   * @param lda unchanged
   * @param xIndex unchanged
   * @param incx unchanged
   * @param beta unchanged
   * @param yIndex is overwritten by the update vector y
   * @param incy unchanged
   */
  private void dgemv_aaw(String trans, int m, int n, RS alpha, int aIndex, int lda, int xIndex, int incx, RS beta, int yIndex, int incy) {
    final RS unit = alpha.createUnit();
    RS[] aTemp = unit.createArray(this.a.length - aIndex);
    RS[] x = unit.createArray(this.a.length - xIndex);
    RS[] y = unit.createArray(this.w.length - yIndex);
    System.arraycopy(this.a, aIndex, aTemp, 0, aTemp.length);
    System.arraycopy(this.a, xIndex, x, 0, x.length);
    System.arraycopy(this.w, yIndex, y, 0, y.length);
    BLAS.dgemv(trans, m, n, alpha, aTemp, lda, x, incx, beta, y, incy);
    System.arraycopy(y, 0, this.w, yIndex, y.length);
  }

  /**
   * @param trans unchanged
   * @param m unchanged
   * @param n unchanged
   * @param alpha unchanged
   * @param aIndex unchanged
   * @param lda unchanged
   * @param xIndex unchanged
   * @param incx unchanged
   * @param beta unchanged
   * @param yIndex is overwritten by the update vector y
   * @param incy unchanged
   */
  private void dgemv_www(String trans, int m, int n, RS alpha, int aIndex, int lda, int xIndex, int incx, RS beta, int yIndex, int incy) {
    final RS unit = alpha.createUnit();
    RS[] aTemp = unit.createArray(this.w.length - aIndex);
    RS[] x = unit.createArray(this.w.length - xIndex);
    RS[] y = unit.createArray(this.w.length - yIndex);
    System.arraycopy(this.w, aIndex, aTemp, 0, aTemp.length);
    System.arraycopy(this.w, xIndex, x, 0, x.length);
    System.arraycopy(this.w, yIndex, y, 0, y.length);
    BLAS.dgemv(trans, m, n, alpha, aTemp, lda, x, incx, beta, y, incy);
    System.arraycopy(y, 0, this.w, yIndex, y.length);
  }

  /**
   * @param trans unchanged
   * @param m unchanged
   * @param n unchanged
   * @param alpha unchanged
   * @param aIndex unchanged
   * @param lda unchanged
   * @param xIndex unchanged
   * @param incx unchanged
   * @param beta unchanged
   * @param yIndex is overwritten by the update vector y
   * @param incy unchanged
   */
  private void dgemv_waw(String trans, int m, int n, RS alpha, int aIndex, int lda, int xIndex, int incx, RS beta, int yIndex, int incy) {
    final RS unit = alpha.createUnit();
    RS[] aTemp = unit.createArray(this.w.length - aIndex);
    RS[] x = unit.createArray(this.a.length - xIndex);
    RS[] y = unit.createArray(this.w.length - yIndex);
    System.arraycopy(this.w, aIndex, aTemp, 0, aTemp.length);
    System.arraycopy(this.a, xIndex, x, 0, x.length);
    System.arraycopy(this.w, yIndex, y, 0, y.length);
    BLAS.dgemv(trans, m, n, alpha, aTemp, lda, x, incx, beta, y, incy);
    System.arraycopy(y, 0, this.w, yIndex, y.length);
  }
}