// TRANSPOSE
 // Transpose of a Phasor matrix
 public PhasorMatrix transpose() {
   PhasorMatrix tmat = new PhasorMatrix(this.ncol, this.nrow);
   Phasor[][] tarray = tmat.getArrayReference();
   for (int i = 0; i < this.ncol; i++) {
     for (int j = 0; j < this.nrow; j++) {
       tarray[i][j] = Phasor.copy(this.matrix[j][i]);
     }
   }
   return tmat;
 }
  // Multiply this Phasor matrix by a Phasor constant
  // This matrix remains unaltered
  public PhasorMatrix times(Phasor constant) {
    PhasorMatrix cmat = new PhasorMatrix(this.nrow, this.ncol);
    Phasor[][] carray = cmat.getArrayReference();

    for (int i = 0; i < this.nrow; i++) {
      for (int j = 0; j < this.ncol; j++) {
        carray[i][j] = this.matrix[i][j].times(constant);
      }
    }
    return cmat;
  }
 // COPY
 // Copy a PhasorMatrix [static method]
 public static PhasorMatrix copy(PhasorMatrix a) {
   if (a == null) {
     return null;
   } else {
     int nr = a.getNrow();
     int nc = a.getNcol();
     Phasor[][] aarray = a.getArrayReference();
     PhasorMatrix b = new PhasorMatrix(nr, nc);
     b.nrow = nr;
     b.ncol = nc;
     Phasor[][] barray = b.getArrayReference();
     for (int i = 0; i < nr; i++) {
       for (int j = 0; j < nc; j++) {
         barray[i][j] = Phasor.copy(aarray[i][j]);
       }
     }
     for (int i = 0; i < nr; i++) b.index[i] = a.index[i];
     return b;
   }
 }
 // Return a sub-matrix
 // row = array of row indices
 // col = array of column indices
 public PhasorMatrix getSubMatrix(int[] row, int[] col) {
   int n = row.length;
   int m = col.length;
   PhasorMatrix subMatrix = new PhasorMatrix(n, m);
   Phasor[][] sarray = subMatrix.getArrayReference();
   for (int i = 0; i < n; i++) {
     for (int j = 0; j < m; j++) {
       sarray[i][j] = Phasor.copy(this.matrix[row[i]][col[j]]);
     }
   }
   return subMatrix;
 }
 // Construct a Phasor scalar matrix
 public static PhasorMatrix scalarMatrix(int nrow, Phasor diagconst) {
   PhasorMatrix u = new PhasorMatrix(nrow, nrow);
   Phasor[][] uarray = u.getArrayReference();
   for (int i = 0; i < nrow; i++) {
     for (int j = i; j < nrow; j++) {
       if (i == j) {
         uarray[i][j] = Phasor.copy(diagconst);
       }
     }
   }
   return u;
 }
 // Construct a Phasor diagonal matrix
 public static PhasorMatrix diagonalMatrix(int nrow, Phasor[] diag) {
   if (diag.length != nrow)
     throw new IllegalArgumentException("matrix dimension differs from diagonal array length");
   PhasorMatrix u = new PhasorMatrix(nrow, nrow);
   Phasor[][] uarray = u.getArrayReference();
   for (int i = 0; i < nrow; i++) {
     for (int j = i; j < nrow; j++) {
       if (i == j) {
         uarray[i][j] = Phasor.copy(diag[i]);
       }
     }
   }
   return u;
 }
 // Subtract  Phasor 2-D array from this matrix.  [instance method]
 public PhasorMatrix minus(Phasor[][] bmat) {
   int nr = bmat.length;
   int nc = bmat[0].length;
   if ((this.nrow != nr) || (this.ncol != nc)) {
     throw new IllegalArgumentException("Array dimensions do not agree");
   }
   PhasorMatrix cmat = new PhasorMatrix(nr, nc);
   Phasor[][] carray = cmat.getArrayReference();
   for (int i = 0; i < nr; i++) {
     for (int j = 0; j < nc; j++) {
       carray[i][j] = this.matrix[i][j].minus(bmat[i][j]);
     }
   }
   return cmat;
 }
  // MULTIPLICATION
  // Multiply this Phasor matrix by a Phasor matrix.
  // This matrix remains unaltered.
  public PhasorMatrix times(PhasorMatrix bmat) {
    if (this.ncol != bmat.nrow) throw new IllegalArgumentException("Nonconformable matrices");

    PhasorMatrix cmat = new PhasorMatrix(this.nrow, bmat.ncol);
    Phasor[][] carray = cmat.getArrayReference();
    Phasor sum = new Phasor();

    for (int i = 0; i < this.nrow; i++) {
      for (int j = 0; j < bmat.ncol; j++) {
        sum = Phasor.zero();
        for (int k = 0; k < this.ncol; k++) {
          sum.plusEquals(this.matrix[i][k].times(bmat.matrix[k][j]));
        }
        carray[i][j] = Phasor.copy(sum);
      }
    }
    return cmat;
  }
  // Return a sub-matrix starting with row index i, column index j
  // and ending with column index k, row index l
  public PhasorMatrix getSubMatrix(int i, int j, int k, int l) {
    if (i + k - 1 >= this.nrow)
      throw new IllegalArgumentException(
          "Sub-matrix position is outside the row bounds of this Matrix");
    if (j + l - 1 >= this.ncol)
      throw new IllegalArgumentException(
          "Sub-matrix position is outside the column bounds of this Matrix");

    int n = k - i + 1, m = l - j + 1;
    PhasorMatrix subMatrix = new PhasorMatrix(n, m);
    Phasor[][] sarray = subMatrix.getArrayReference();
    for (int p = 0; p < n; p++) {
      for (int q = 0; q < m; q++) {
        sarray[p][q] = Phasor.copy(this.matrix[i + p][j + q]);
      }
    }
    return subMatrix;
  }
  // INVERSE
  // Inverse of a square Phasor matrix
  public PhasorMatrix inverse() {
    int n = this.nrow;
    if (n != this.ncol) throw new IllegalArgumentException("Matrix is not square");
    Phasor[] col = new Phasor[n];
    Phasor[] xvec = new Phasor[n];
    PhasorMatrix invmat = new PhasorMatrix(n, n);
    Phasor[][] invarray = invmat.getArrayReference();
    PhasorMatrix ludmat;

    ludmat = this.luDecomp();
    for (int j = 0; j < n; j++) {
      for (int i = 0; i < n; i++) col[i] = Phasor.zero();
      col[j] = Phasor.plusOne();
      xvec = ludmat.luBackSub(col);
      for (int i = 0; i < n; i++) invarray[i][j] = Phasor.copy(xvec[i]);
    }
    return invmat;
  }
 // Clone a PhasorMatrix
 public Object clone() {
   if (this == null) {
     return null;
   } else {
     int nr = this.nrow;
     int nc = this.ncol;
     PhasorMatrix b = new PhasorMatrix(nr, nc);
     Phasor[][] barray = b.getArrayReference();
     b.nrow = nr;
     b.ncol = nc;
     for (int i = 0; i < nr; i++) {
       for (int j = 0; j < nc; j++) {
         barray[i][j] = Phasor.copy(this.matrix[i][j]);
       }
     }
     for (int i = 0; i < nr; i++) b.index[i] = this.index[i];
     return (Object) b;
   }
 }
  // LU DECOMPOSITION OF COMPLEX MATRIX A
  // For details of LU decomposition
  // See Numerical Recipes, The Art of Scientific Computing
  // by W H Press, S A Teukolsky, W T Vetterling & B P Flannery
  // Cambridge University Press,   http://www.nr.com/
  // PhasorMatrix ludmat is the returned LU decompostion
  // int[] index is the vector of row permutations
  // dswap returns +1.0 for even number of row interchanges
  //       returns -1.0 for odd number of row interchanges
  public PhasorMatrix luDecomp() {
    if (this.nrow != this.ncol) throw new IllegalArgumentException("A matrix is not square");
    int n = this.nrow;
    int imax = 0;
    double dum = 0.0D, temp = 0.0D, big = 0.0D;
    double[] vv = new double[n];
    Phasor sum = new Phasor();
    Phasor dumm = new Phasor();

    PhasorMatrix ludmat = PhasorMatrix.copy(this);
    Phasor[][] ludarray = ludmat.getArrayReference();

    ludmat.dswap = 1.0;
    for (int i = 0; i < n; i++) {
      big = 0.0;
      for (int j = 0; j < n; j++) {
        if ((temp = ludarray[i][j].abs()) > big) big = temp;
      }
      if (big == 0.0) throw new ArithmeticException("Singular matrix");
      vv[i] = 1.0 / big;
    }
    for (int j = 0; j < n; j++) {
      for (int i = 0; i < j; i++) {
        sum = Phasor.copy(ludarray[i][j]);
        for (int k = 0; k < i; k++) sum.minusEquals(ludarray[i][k].times(ludarray[k][j]));
        ludarray[i][j] = Phasor.copy(sum);
      }
      big = 0.0;
      for (int i = j; i < n; i++) {
        sum = Phasor.copy(ludarray[i][j]);
        for (int k = 0; k < j; k++) {
          sum.minusEquals(ludarray[i][k].times(ludarray[k][j]));
        }
        ludarray[i][j] = Phasor.copy(sum);
        if ((dum = vv[i] * sum.abs()) >= big) {
          big = dum;
          imax = i;
        }
      }
      if (j != imax) {
        for (int k = 0; k < n; k++) {
          dumm = Phasor.copy(ludarray[imax][k]);
          ludarray[imax][k] = Phasor.copy(ludarray[j][k]);
          ludarray[j][k] = Phasor.copy(dumm);
        }
        ludmat.dswap = -ludmat.dswap;
        vv[imax] = vv[j];
      }
      ludmat.index[j] = imax;

      if (ludarray[j][j].isZero()) {
        ludarray[j][j].reset(TINY, 0.0D);
      }
      if (j != n - 1) {
        dumm = ludarray[j][j].inverse();
        for (int i = j + 1; i < n; i++) {
          ludarray[i][j].timesEquals(dumm);
        }
      }
    }
    return ludmat;
  }