/**
  * Matrix transpose.
  *
  * @return A'
  */
 public Matrix transpose() {
   Matrix X = new Matrix(n, m);
   double[][] C = X.getArray();
   for (int i = 0; i < m; i++) {
     for (int j = 0; j < n; j++) {
       C[j][i] = A[i][j];
     }
   }
   return X;
 }
 /**
  * Unary minus
  *
  * @return -A
  */
 public Matrix uminus() {
   Matrix X = new Matrix(m, n);
   double[][] C = X.getArray();
   for (int i = 0; i < m; i++) {
     for (int j = 0; j < n; j++) {
       C[i][j] = -A[i][j];
     }
   }
   return X;
 }
 /**
  * Generate identity matrix
  *
  * @param m Number of rows.
  * @param n Number of colums.
  * @return An m-by-n matrix with ones on the diagonal and zeros elsewhere.
  */
 public static Matrix identity(int m, int n) {
   Matrix A = new Matrix(m, n);
   double[][] X = A.getArray();
   for (int i = 0; i < m; i++) {
     for (int j = 0; j < n; j++) {
       X[i][j] = (i == j ? 1.0 : 0.0);
     }
   }
   return A;
 }
 /**
  * Generate matrix with random elements
  *
  * @param m Number of rows.
  * @param n Number of colums.
  * @return An m-by-n matrix with uniformly distributed random elements.
  */
 public static Matrix random(int m, int n) {
   Matrix A = new Matrix(m, n);
   double[][] X = A.getArray();
   for (int i = 0; i < m; i++) {
     for (int j = 0; j < n; j++) {
       X[i][j] = Math.random();
     }
   }
   return A;
 }
 /**
  * Multiply a matrix by a scalar, C = s*A
  *
  * @param s scalar
  * @return s*A
  */
 public Matrix times(double s) {
   Matrix X = new Matrix(m, n);
   double[][] C = X.getArray();
   for (int i = 0; i < m; i++) {
     for (int j = 0; j < n; j++) {
       C[i][j] = s * A[i][j];
     }
   }
   return X;
 }
 /**
  * Element-by-element left division, C = A.\B
  *
  * @param B another matrix
  * @return A.\B
  */
 public Matrix arrayLeftDivide(Matrix B) {
   checkMatrixDimensions(B);
   Matrix X = new Matrix(m, n);
   double[][] C = X.getArray();
   for (int i = 0; i < m; i++) {
     for (int j = 0; j < n; j++) {
       C[i][j] = B.A[i][j] / A[i][j];
     }
   }
   return X;
 }
 /**
  * Return the Householder vectors
  *
  * @return Lower trapezoidal matrix whose columns define the reflections
  */
 public Matrix getH() {
   Matrix X = new Matrix(m, n);
   double[][] H = X.getArray();
   for (int i = 0; i < m; i++) {
     for (int j = 0; j < n; j++) {
       if (i >= j) {
         H[i][j] = QR[i][j];
       } else {
         H[i][j] = 0.0;
       }
     }
   }
   return X;
 }
 /**
  * Get a submatrix.
  *
  * @param r Array of row indices.
  * @param j0 Initial column index
  * @param j1 Final column index
  * @return A(r(:),j0:j1)
  * @exception ArrayIndexOutOfBoundsException Submatrix indices
  */
 public Matrix getMatrix(int[] r, int j0, int j1) {
   Matrix X = new Matrix(r.length, j1 - j0 + 1);
   double[][] B = X.getArray();
   try {
     for (int i = 0; i < r.length; i++) {
       for (int j = j0; j <= j1; j++) {
         B[i][j - j0] = A[r[i]][j];
       }
     }
   } catch (ArrayIndexOutOfBoundsException e) {
     throw new ArrayIndexOutOfBoundsException("Submatrix indices");
   }
   return X;
 }
 /**
  * Get a submatrix.
  *
  * @param i0 Initial row index
  * @param i1 Final row index
  * @param c Array of column indices.
  * @return A(i0:i1,c(:))
  * @exception ArrayIndexOutOfBoundsException Submatrix indices
  */
 public Matrix getMatrix(int i0, int i1, int[] c) {
   Matrix X = new Matrix(i1 - i0 + 1, c.length);
   double[][] B = X.getArray();
   try {
     for (int i = i0; i <= i1; i++) {
       for (int j = 0; j < c.length; j++) {
         B[i - i0][j] = A[i][c[j]];
       }
     }
   } catch (ArrayIndexOutOfBoundsException e) {
     throw new ArrayIndexOutOfBoundsException("Submatrix indices");
   }
   return X;
 }
 /**
  * Get a submatrix.
  *
  * @param i0 Initial row index
  * @param i1 Final row index
  * @param j0 Initial column index
  * @param j1 Final column index
  * @return A(i0:i1,j0:j1)
  * @exception ArrayIndexOutOfBoundsException Submatrix indices
  */
 public Matrix getMatrix(int i0, int i1, int j0, int j1) {
   Matrix X = new Matrix(i1 - i0 + 1, j1 - j0 + 1);
   double[][] B = X.getArray();
   try {
     for (int i = i0; i <= i1; i++) {
       for (int j = j0; j <= j1; j++) {
         B[i - i0][j - j0] = A[i][j];
       }
     }
   } catch (ArrayIndexOutOfBoundsException e) {
     throw new ArrayIndexOutOfBoundsException("Submatrix indices");
   }
   return X;
 }
 /**
  * Construct a matrix from a copy of a 2-D array.
  *
  * @param A Two-dimensional array of doubles.
  * @exception IllegalArgumentException All rows must have the same length
  */
 public static Matrix constructWithCopy(double[][] A) {
   int m = A.length;
   int n = A[0].length;
   Matrix X = new Matrix(m, n);
   double[][] C = X.getArray();
   for (int i = 0; i < m; i++) {
     if (A[i].length != n) {
       throw new IllegalArgumentException("All rows must have the same length.");
     }
     for (int j = 0; j < n; j++) {
       C[i][j] = A[i][j];
     }
   }
   return X;
 }
 /**
  * Return the upper triangular factor
  *
  * @return R
  */
 public Matrix getR() {
   Matrix X = new Matrix(n, n);
   double[][] R = X.getArray();
   for (int i = 0; i < n; i++) {
     for (int j = 0; j < n; j++) {
       if (i < j) {
         R[i][j] = QR[i][j];
       } else if (i == j) {
         R[i][j] = Rdiag[i];
       } else {
         R[i][j] = 0.0;
       }
     }
   }
   return X;
 }
 /**
  * Set a submatrix.
  *
  * @param i0 Initial row index
  * @param i1 Final row index
  * @param j0 Initial column index
  * @param j1 Final column index
  * @param X A(i0:i1,j0:j1)
  * @exception ArrayIndexOutOfBoundsException Submatrix indices
  */
 public void setMatrix(int i0, int i1, int j0, int j1, Matrix X) {
   try {
     for (int i = i0; i <= i1; i++) {
       for (int j = j0; j <= j1; j++) {
         A[i][j] = X.get(i - i0, j - j0);
       }
     }
   } catch (ArrayIndexOutOfBoundsException e) {
     throw new ArrayIndexOutOfBoundsException("Submatrix indices");
   }
 }
 /**
  * Set a submatrix.
  *
  * @param r Array of row indices.
  * @param j0 Initial column index
  * @param j1 Final column index
  * @param X A(r(:),j0:j1)
  * @exception ArrayIndexOutOfBoundsException Submatrix indices
  */
 public void setMatrix(int[] r, int j0, int j1, Matrix X) {
   try {
     for (int i = 0; i < r.length; i++) {
       for (int j = j0; j <= j1; j++) {
         A[r[i]][j] = X.get(i, j - j0);
       }
     }
   } catch (ArrayIndexOutOfBoundsException e) {
     throw new ArrayIndexOutOfBoundsException("Submatrix indices");
   }
 }
 /**
  * Set a submatrix.
  *
  * @param i0 Initial row index
  * @param i1 Final row index
  * @param c Array of column indices.
  * @param X A(i0:i1,c(:))
  * @exception ArrayIndexOutOfBoundsException Submatrix indices
  */
 public void setMatrix(int i0, int i1, int[] c, Matrix X) {
   try {
     for (int i = i0; i <= i1; i++) {
       for (int j = 0; j < c.length; j++) {
         A[i][c[j]] = X.get(i - i0, j);
       }
     }
   } catch (ArrayIndexOutOfBoundsException e) {
     throw new ArrayIndexOutOfBoundsException("Submatrix indices");
   }
 }
  /**
   * QR Decomposition, computed by Householder reflections.
   *
   * @param A Rectangular matrix
   * @return Structure to access R and the Householder vectors and compute Q.
   */
  public QRDecomposition(Matrix A) {
    // Initialize.
    QR = A.getArrayCopy();
    m = A.getRowDimension();
    n = A.getColumnDimension();
    Rdiag = new double[n];

    // Main loop.
    for (int k = 0; k < n; k++) {
      // Compute 2-norm of k-th column without under/overflow.
      double nrm = 0;
      for (int i = k; i < m; i++) {
        nrm = Maths.hypot(nrm, QR[i][k]);
      }

      if (nrm != 0.0) {
        // Form k-th Householder vector.
        if (QR[k][k] < 0) {
          nrm = -nrm;
        }
        for (int i = k; i < m; i++) {
          QR[i][k] /= nrm;
        }
        QR[k][k] += 1.0;

        // Apply transformation to remaining columns.
        for (int j = k + 1; j < n; j++) {
          double s = 0.0;
          for (int i = k; i < m; i++) {
            s += QR[i][k] * QR[i][j];
          }
          s = -s / QR[k][k];
          for (int i = k; i < m; i++) {
            QR[i][j] += s * QR[i][k];
          }
        }
      }
      Rdiag[k] = -nrm;
    }
  }
 /**
  * Linear algebraic matrix multiplication, A * B
  *
  * @param B another matrix
  * @return Matrix product, A * B
  * @exception IllegalArgumentException Matrix inner dimensions must agree.
  */
 public Matrix times(Matrix B) {
   if (B.m != n) {
     throw new IllegalArgumentException("Matrix inner dimensions must agree.");
   }
   Matrix X = new Matrix(m, B.n);
   double[][] C = X.getArray();
   double[] Bcolj = new double[n];
   for (int j = 0; j < B.n; j++) {
     for (int k = 0; k < n; k++) {
       Bcolj[k] = B.A[k][j];
     }
     for (int i = 0; i < m; i++) {
       double[] Arowi = A[i];
       double s = 0;
       for (int k = 0; k < n; k++) {
         s += Arowi[k] * Bcolj[k];
       }
       C[i][j] = s;
     }
   }
   return X;
 }
  /**
   * Least squares solution of A*X = B
   *
   * @param B A Matrix with as many rows as A and any number of columns.
   * @return X that minimizes the two norm of Q*R*X-B.
   * @exception IllegalArgumentException Matrix row dimensions must agree.
   * @exception RuntimeException Matrix is rank deficient.
   */
  public Matrix solve(Matrix B) {
    if (B.getRowDimension() != m) {
      throw new IllegalArgumentException("Matrix row dimensions must agree.");
    }
    if (!this.isFullRank()) {
      throw new RuntimeException("Matrix is rank deficient.");
    }

    // Copy right hand side
    int nx = B.getColumnDimension();
    double[][] X = B.getArrayCopy();

    // Compute Y = transpose(Q)*B
    for (int k = 0; k < n; k++) {
      for (int j = 0; j < nx; j++) {
        double s = 0.0;
        for (int i = k; i < m; i++) {
          s += QR[i][k] * X[i][j];
        }
        s = -s / QR[k][k];
        for (int i = k; i < m; i++) {
          X[i][j] += s * QR[i][k];
        }
      }
    }
    // Solve R*X = Y;
    for (int k = n - 1; k >= 0; k--) {
      for (int j = 0; j < nx; j++) {
        X[k][j] /= Rdiag[k];
      }
      for (int i = 0; i < k; i++) {
        for (int j = 0; j < nx; j++) {
          X[i][j] -= X[k][j] * QR[i][k];
        }
      }
    }
    return (new Matrix(X, n, nx).getMatrix(0, n - 1, 0, nx - 1));
  }
 /**
  * Generate and return the (economy-sized) orthogonal factor
  *
  * @return Q
  */
 public Matrix getQ() {
   Matrix X = new Matrix(m, n);
   double[][] Q = X.getArray();
   for (int k = n - 1; k >= 0; k--) {
     for (int i = 0; i < m; i++) {
       Q[i][k] = 0.0;
     }
     Q[k][k] = 1.0;
     for (int j = k; j < n; j++) {
       if (QR[k][k] != 0) {
         double s = 0.0;
         for (int i = k; i < m; i++) {
           s += QR[i][k] * Q[i][j];
         }
         s = -s / QR[k][k];
         for (int i = k; i < m; i++) {
           Q[i][j] += s * QR[i][k];
         }
       }
     }
   }
   return X;
 }
 /**
  * Solve X*A = B, which is also A'*X' = B'
  *
  * @param B right hand side
  * @return solution if A is square, least squares solution otherwise.
  */
 public Matrix solveTranspose(Matrix B) {
   return transpose().solve(B.transpose());
 }