/**
   * Returns a matrix which is the result of an element by element multiplication of 'this' and 'b':
   * c<sub>i,j</sub> = a<sub>i,j</sub>*b<sub>i,j</sub> .
   *
   * @param b A simple matrix.
   * @return The element by element multiplication of 'this' and 'b'.
   */
  public T elementMult(T b) {
    T c = createMatrix(mat.numRows, mat.numCols);

    CommonOps.elementMult(mat, b.getMatrix(), c.getMatrix());

    return c;
  }
  /**
   * Returns the result of matrix subtraction:<br>
   * <br>
   * c = a - b <br>
   * <br>
   * where c is the returned matrix, a is this matrix, and b is the passed in matrix.
   *
   * @param b m by n matrix. Not modified.
   * @return The results of this operation.
   * @see CommonOps#sub(org.ejml.data.D1Matrix64F , org.ejml.data.D1Matrix64F ,
   *     org.ejml.data.D1Matrix64F)
   */
  public T minus(T b) {
    T ret = copy();

    CommonOps.subEquals(ret.getMatrix(), b.getMatrix());

    return ret;
  }
  /**
   * Performs a matrix addition and scale operation.<br>
   * <br>
   * c = a + &beta;*b <br>
   * <br>
   * where c is the returned matrix, a is this matrix, and b is the passed in matrix.
   *
   * @param beta the beta
   * @param b m by n matrix. Not modified.
   * @return A matrix that contains the results.
   * @see CommonOps#add(org.ejml.data.D1Matrix64F , double , org.ejml.data.D1Matrix64F ,
   *     org.ejml.data.D1Matrix64F)
   */
  public T plus(double beta, T b) {
    T ret = copy();

    CommonOps.addEquals(ret.getMatrix(), beta, b.getMatrix());

    return ret;
  }
  /**
   * Returns a matrix which is the result of matrix multiplication:<br>
   * <br>
   * c = a * b <br>
   * <br>
   * where c is the returned matrix, a is this matrix, and b is the passed in matrix.
   *
   * @param b A matrix that is n by bn. Not modified.
   * @return The results of this operation.
   * @see CommonOps#mult(org.ejml.data.RowD1Matrix64F , org.ejml.data.RowD1Matrix64F ,
   *     org.ejml.data.RowD1Matrix64F)
   */
  public T mult(T b) {
    T ret = createMatrix(mat.numRows, b.getMatrix().numCols);

    CommonOps.mult(mat, b.getMatrix(), ret.getMatrix());

    return ret;
  }
  /**
   * Solves for X in the following equation:<br>
   * <br>
   * x = a<sup>-1</sup>b<br>
   * <br>
   * where 'a' is this matrix and 'b' is an n by p matrix.
   *
   * <p>If the system could not be solved then SingularMatrixException is thrown. Even if no
   * exception is thrown 'a' could still be singular or nearly singular.
   *
   * @param b n by p matrix. Not modified.
   * @return The solution for 'x' that is n by p.
   * @see CommonOps#solve(DenseMatrix64F, DenseMatrix64F, DenseMatrix64F)
   */
  public T solve(T b) {
    T x = createMatrix(mat.numCols, b.getMatrix().numCols);

    if (!CommonOps.solve(mat, b.getMatrix(), x.getMatrix())) {
      throw new SingularMatrixException();
    }

    return x;
  }
  /**
   * Extracts a row or column from this matrix. The returned vector will either be a row or column
   * vector depending on the input type.
   *
   * @param extractRow If true a row will be extracted.
   * @param element The row or column the vector is contained in.
   * @return Extracted vector.
   */
  public T extractVector(boolean extractRow, int element) {
    int length = extractRow ? mat.numCols : mat.numRows;

    T ret = extractRow ? createMatrix(1, length) : createMatrix(length, 1);

    if (extractRow) {
      SpecializedOps.subvector(mat, element, 0, length, true, 0, ret.getMatrix());
    } else {
      SpecializedOps.subvector(mat, 0, element, length, false, 0, ret.getMatrix());
    }

    return ret;
  }
  /**
   * Returns the transpose of this matrix.<br>
   * a<sup>T</sup>
   *
   * @return A matrix that is n by m.
   * @see org.ejml.ops.CommonOps#transpose(DenseMatrix64F,DenseMatrix64F)
   */
  public T transpose() {
    T ret = createMatrix(mat.numCols, mat.numRows);

    CommonOps.transpose(mat, ret.getMatrix());

    return ret;
  }
 /**
  * Returns the inverse of this matrix.<br>
  * <br>
  * b = a<sup>-1<sup><br>
  *
  * <p>If the matrix could not be inverted then SingularMatrixException is thrown. Even if no
  * exception is thrown the matrix could still be singular or nearly singular.
  *
  * @return The inverse of this matrix.
  * @see CommonOps#invert(DenseMatrix64F, DenseMatrix64F)
  */
 public T invert() {
   T ret = createMatrix(mat.numRows, mat.numCols);
   if (!CommonOps.invert(mat, ret.getMatrix())) {
     throw new SingularMatrixException();
   }
   return ret;
 }
  /**
   * Returns the result of dividing each element by 'val': b<sub>i,j</sub> = a<sub>i,j</sub>/val .
   *
   * @param val Divisor.
   * @return Matrix with its elements divided by the specified value.
   * @see CommonOps#divide(double, org.ejml.data.D1Matrix64F)
   */
  public T divide(double val) {
    T ret = copy();

    CommonOps.divide(val, ret.getMatrix());

    return ret;
  }
  /**
   * Returns the result of scaling each element by 'val':<br>
   * b<sub>i,j</sub> = val*a<sub>i,j</sub> .
   *
   * @param val The multiplication factor.
   * @return The scaled matrix.
   * @see CommonOps#scale(double, org.ejml.data.D1Matrix64F)
   */
  public T scale(double val) {
    T ret = copy();

    CommonOps.scale(val, ret.getMatrix());

    return ret;
  }
  /**
   * Extracts the diagonal from this matrix and returns them inside a column vector.
   *
   * @return Diagonal elements inside a column vector.
   * @see org.ejml.ops.CommonOps#extractDiag(DenseMatrix64F, DenseMatrix64F)
   */
  public T extractDiag() {
    int N = Math.min(mat.numCols, mat.numRows);

    T diag = createMatrix(N, 1);

    CommonOps.extractDiag(mat, diag.getMatrix());

    return diag;
  }
  /**
   * Computes the dot product (a.k.a. inner product) between this vector and vector 'v'.
   *
   * @param v The second vector in the dot product. Not modified.
   * @return dot product
   */
  public double dot(T v) {
    if (!isVector()) {
      throw new IllegalArgumentException("'this' matrix is not a vector.");
    } else if (!v.isVector()) {
      throw new IllegalArgumentException("'v' matrix is not a vector.");
    }

    return VectorVectorMult.innerProd(mat, v.getMatrix());
  }
 /**
  * Creates and returns a matrix which is idential to this one.
  *
  * @return A new identical matrix.
  */
 public T copy() {
   // logger.info("copy matrix base");
   if (mat == null) {
     return null;
   }
   T ret = createMatrix(mat.numRows, mat.numCols);
   ret.getMatrix().set(this.getMatrix());
   // ret.determinant = determinant;
   // ret.logDeterminant = logDeterminant;
   return ret;
 }
  /**
   * Creates a new SimpleMatrix which is a submatrix of this matrix.
   *
   * <p>s<sub>i-y0 , j-x0</sub> = o<sub>ij</sub> for all y0 &le; i < y1 and x0 &le; j < x1<br>
   * <br>
   * where 's<sub>ij</sub>' is an element in the submatrix and 'o<sub>ij</sub>' is an element in the
   * original matrix.
   *
   * <p>If any of the inputs are set to T.END then it will be set to the last row or column in the
   * matrix.
   *
   * @param y0 Start row.
   * @param y1 Stop row.
   * @param x0 Start column.
   * @param x1 Stop column.
   * @return The submatrix.
   */
  public T extractMatrix(int y0, int y1, int x0, int x1) {
    if (y0 == END) {
      y0 = mat.numRows;
    }
    if (y1 == END) {
      y1 = mat.numRows;
    }
    if (x0 == END) {
      x0 = mat.numCols;
    }
    if (x1 == END) {
      x1 = mat.numCols;
    }

    T ret = createMatrix(y1 - y0, x1 - x0);

    CommonOps.extract(mat, y0, y1, x0, x1, ret.getMatrix(), 0, 0);

    return ret;
  }
  /**
   * Computes the Kronecker product between this matrix and the provided B matrix:<br>
   * <br>
   * C = kron(A,B) .
   *
   * @param B The right matrix in the operation. Not modified.
   * @return Kronecker product between this matrix and B.
   * @see CommonOps#kron(DenseMatrix64F, DenseMatrix64F, DenseMatrix64F)
   */
  public T kron(T B) {
    T ret = createMatrix(mat.numRows * B.numRows(), mat.numCols * B.numCols());
    CommonOps.kron(mat, B.getMatrix(), ret.getMatrix());

    return ret;
  }
 /**
  * Computes the Moore-Penrose pseudo-inverse .
  *
  * @return inverse computed using the pseudo inverse.
  */
 public T pseudoInverse() {
   T ret = createMatrix(mat.numCols, mat.numRows);
   CommonOps.pinv(mat, ret.getMatrix());
   return ret;
 }
 /**
  * Returns a new matrix whose elements are the negative of 'this' matrix's elements.<br>
  * <br>
  * b<sub>ij</sub> = -a<sub>ij</sub>
  *
  * @return A matrix that is the negative of the original.
  */
 public T negative() {
   T A = copy();
   CommonOps.changeSign(A.getMatrix());
   return A;
 }
 /**
  * Sets the elements in this matrix to be equal to the elements in the passed in matrix. Both
  * matrix must have the same dimension.
  *
  * @param a The matrix whose value this matrix is being set to.
  */
 public void setInternalMatrix(T a) {
   mat.set(a.getMatrix());
 }
 /**
  * Copy matrix B into this matrix at location (insertRow, insertCol).
  *
  * @param insertRow First row the matrix is to be inserted into.
  * @param insertCol First column the matrix is to be inserted into.
  * @param B The matrix that is being inserted.
  */
 public void insertIntoThis(int insertRow, int insertCol, T B) {
   CommonOps.insert(B.getMatrix(), mat, insertRow, insertCol);
 }
 /**
  * Checks to see if matrix 'a' is the same as this matrix within the specified tolerance.
  *
  * @param a The matrix it is being compared against.
  * @param tol How similar they must be to be equals.
  * @return If they are equal within tolerance of each other.
  */
 public boolean isIdentical(T a, double tol) {
   return MatrixFeatures.isIdentical(mat, a.getMatrix(), tol);
 }