org.ejml.dense.row.CommonOps_FDRM Maven / Gradle / Ivy
Show all versions of ejml-fdense Show documentation
/*
* Copyright (c) 2021, Peter Abeles. All Rights Reserved.
*
* This file is part of Efficient Java Matrix Library (EJML).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.ejml.dense.row;
import javax.annotation.Generated;
import org.ejml.EjmlParameters;
import org.ejml.LinearSolverSafe;
import org.ejml.MatrixDimensionException;
import org.ejml.UtilEjml;
import org.ejml.data.*;
import org.ejml.dense.row.decomposition.TriangularSolver_FDRM;
import org.ejml.dense.row.decomposition.lu.LUDecompositionAlt_FDRM;
import org.ejml.dense.row.factory.LinearSolverFactory_FDRM;
import org.ejml.dense.row.linsol.chol.LinearSolverChol_FDRM;
import org.ejml.dense.row.linsol.lu.LinearSolverLu_FDRM;
import org.ejml.dense.row.linsol.svd.SolvePseudoInverseSvd_FDRM;
import org.ejml.dense.row.misc.*;
import org.ejml.dense.row.mult.MatrixMatrixMult_FDRM;
import org.ejml.dense.row.mult.MatrixMultProduct_FDRM;
import org.ejml.dense.row.mult.MatrixVectorMult_FDRM;
import org.ejml.dense.row.mult.VectorVectorMult_FDRM;
import org.ejml.interfaces.linsol.LinearSolverDense;
import org.ejml.interfaces.linsol.ReducedRowEchelonForm_F32;
import org.ejml.ops.FOperatorUnary;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import static org.ejml.UtilEjml.*;
/**
*
* Common matrix operations are contained here. Which specific underlying algorithm is used
* is not specified just the out come of the operation. Nor should calls to these functions
* reply on the underlying implementation. Which algorithm is used can depend on the matrix
* being passed in.
*
*
* For more exotic and specialized generic operations see {@link SpecializedOps_FDRM}.
*
*
* @author Peter Abeles
* @see MatrixMatrixMult_FDRM
* @see MatrixVectorMult_FDRM
* @see SpecializedOps_FDRM
* @see MatrixFeatures_FDRM
*/
@SuppressWarnings({"ForLoopReplaceableByForEach"})
@Generated("org.ejml.dense.row.CommonOps_DDRM")
public class CommonOps_FDRM {
/**
* Performs the following operation:
*
* c = a * b
*
* cij = ∑k=1:n { aik * bkj}
*
*
* @param a The left matrix in the multiplication operation. Not modified.
* @param b The right matrix in the multiplication operation. Not modified.
* @param output Where the results of the operation are stored. Modified.
*/
public static T mult( T a, T b, @Nullable T output ) {
output = reshapeOrDeclare(output, a, a.numRows, b.numCols);
UtilEjml.checkSameInstance(a, output);
UtilEjml.checkSameInstance(b, output);
if (b.numCols == 1) {
MatrixVectorMult_FDRM.mult(a, b, output);
} else if (b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH) {
MatrixMatrixMult_FDRM.mult_reorder(a, b, output);
} else {
MatrixMatrixMult_FDRM.mult_small(a, b, output);
}
return output;
}
/**
* Performs the following operation:
*
* c = α * a * b
*
* cij = α ∑k=1:n { * aik * bkj}
*
*
* @param alpha Scaling factor.
* @param a The left matrix in the multiplication operation. Not modified.
* @param b The right matrix in the multiplication operation. Not modified.
* @param output Where the results of the operation are stored. Modified.
*/
public static T mult( float alpha, T a, T b, @Nullable T output ) {
output = reshapeOrDeclare(output, a, a.numRows, b.numCols);
UtilEjml.checkSameInstance(a, output);
UtilEjml.checkSameInstance(b, output);
// TODO add a matrix vectory multiply here
if (b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH) {
MatrixMatrixMult_FDRM.mult_reorder(alpha, a, b, output);
} else {
MatrixMatrixMult_FDRM.mult_small(alpha, a, b, output);
}
return output;
}
/**
* Performs the following operation:
*
* c = aT * b
*
* cij = ∑k=1:n { aki * bkj}
*
*
* @param a The left matrix in the multiplication operation. Not modified.
* @param b The right matrix in the multiplication operation. Not modified.
* @param output Where the results of the operation are stored. Modified.
*/
public static T multTransA( T a, T b, @Nullable T output ) {
output = reshapeOrDeclare(output, a, a.numCols, b.numCols);
UtilEjml.checkSameInstance(a, output);
UtilEjml.checkSameInstance(b, output);
if (b.numCols == 1) {
// todo check a.numCols == 1 and do inner product?
// there are significantly faster algorithms when dealing with vectors
if (a.numCols >= EjmlParameters.MULT_COLUMN_SWITCH) {
MatrixVectorMult_FDRM.multTransA_reorder(a, b, output);
} else {
MatrixVectorMult_FDRM.multTransA_small(a, b, output);
}
} else if (a.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ||
b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH) {
MatrixMatrixMult_FDRM.multTransA_reorder(a, b, output);
} else {
MatrixMatrixMult_FDRM.multTransA_small(a, b, output);
}
return output;
}
/**
* Performs the following operation:
*
* c = α * aT * b
*
* cij = α ∑k=1:n { aki * bkj}
*
*
* @param alpha Scaling factor.
* @param a The left matrix in the multiplication operation. Not modified.
* @param b The right matrix in the multiplication operation. Not modified.
* @param output Where the results of the operation are stored. Modified.
*/
public static T multTransA( float alpha, T a, T b, @Nullable T output ) {
output = reshapeOrDeclare(output, a, a.numCols, b.numCols);
UtilEjml.checkSameInstance(a, output);
UtilEjml.checkSameInstance(b, output);
// TODO add a matrix vectory multiply here
if (a.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ||
b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH) {
MatrixMatrixMult_FDRM.multTransA_reorder(alpha, a, b, output);
} else {
MatrixMatrixMult_FDRM.multTransA_small(alpha, a, b, output);
}
return output;
}
/**
*
* Performs the following operation:
*
* c = a * bT
* cij = ∑k=1:n { aik * bjk}
*
*
* @param a The left matrix in the multiplication operation. Not modified.
* @param b The right matrix in the multiplication operation. Not modified.
* @param output Where the results of the operation are stored. Modified.
*/
public static T multTransB( T a, T b, @Nullable T output ) {
output = reshapeOrDeclare(output, a, a.numRows, b.numRows);
UtilEjml.checkSameInstance(a, output);
UtilEjml.checkSameInstance(b, output);
if (b.numRows == 1) {
MatrixVectorMult_FDRM.mult(a, b, output);
} else {
MatrixMatrixMult_FDRM.multTransB(a, b, output);
}
return output;
}
/**
*
* Performs the following operation:
*
* c = α * a * bT
* cij = α ∑k=1:n { aik * bjk}
*
*
* @param alpha Scaling factor.
* @param a The left matrix in the multiplication operation. Not modified.
* @param b The right matrix in the multiplication operation. Not modified.
* @param output Where the results of the operation are stored. Modified.
*/
public static T multTransB( float alpha, T a, T b, @Nullable T output ) {
output = reshapeOrDeclare(output, a, a.numRows, b.numRows);
UtilEjml.checkSameInstance(a, output);
UtilEjml.checkSameInstance(b, output);
// TODO add a matrix vectory multiply here
MatrixMatrixMult_FDRM.multTransB(alpha, a, b, output);
return output;
}
/**
*
* Performs the following operation:
*
* c = aT * bT
* cij = ∑k=1:n { aki * bjk}
*
*
* @param a The left matrix in the multiplication operation. Not modified.
* @param b The right matrix in the multiplication operation. Not modified.
* @param output Where the results of the operation are stored. Modified.
*/
public static T multTransAB( T a, T b, @Nullable T output ) {
output = reshapeOrDeclare(output, a, a.numCols, b.numRows);
UtilEjml.checkSameInstance(a, output);
UtilEjml.checkSameInstance(b, output);
if (b.numRows == 1) {
// there are significantly faster algorithms when dealing with vectors
if (a.numCols >= EjmlParameters.MULT_COLUMN_SWITCH) {
MatrixVectorMult_FDRM.multTransA_reorder(a, b, output);
} else {
MatrixVectorMult_FDRM.multTransA_small(a, b, output);
}
} else if (a.numCols >= EjmlParameters.MULT_TRANAB_COLUMN_SWITCH) {
MatrixMatrixMult_FDRM.multTransAB_aux(a, b, output, null);
} else {
MatrixMatrixMult_FDRM.multTransAB(a, b, output);
}
return output;
}
/**
*
* Performs the following operation:
*
* c = α * aT * bT
* cij = α ∑k=1:n { aki * bjk}
*
*
* @param alpha Scaling factor.
* @param a The left matrix in the multiplication operation. Not modified.
* @param b The right matrix in the multiplication operation. Not modified.
* @param output Where the results of the operation are stored. Modified.
*/
public static T multTransAB( float alpha, T a, T b, @Nullable T output ) {
output = reshapeOrDeclare(output, a, a.numCols, b.numRows);
UtilEjml.checkSameInstance(a, output);
UtilEjml.checkSameInstance(b, output);
// TODO add a matrix vectory multiply here
if (a.numCols >= EjmlParameters.MULT_TRANAB_COLUMN_SWITCH) {
MatrixMatrixMult_FDRM.multTransAB_aux(alpha, a, b, output, null);
} else {
MatrixMatrixMult_FDRM.multTransAB(alpha, a, b, output);
}
return output;
}
/**
*
* Computes the dot product or inner product between two vectors. If the two vectors are columns vectors
* then it is defined as:
* {@code dot(a,b) = aT * b}
* If the vectors are column or row or both is ignored by this function.
*
*
* @param a Vector
* @param b Vector
* @return Dot product of the two vectors
*/
public static float dot( FMatrixD1 a, FMatrixD1 b ) {
if (!MatrixFeatures_FDRM.isVector(a) || !MatrixFeatures_FDRM.isVector(b))
throw new RuntimeException("Both inputs must be vectors");
return VectorVectorMult_FDRM.innerProd(a, b);
}
/**
* Computes the matrix multiplication inner product:
*
* c = aT * a
*
* cij = ∑k=1:n { aki * akj}
*
*
*
* Is faster than using a generic matrix multiplication by taking advantage of symmetry. For
* vectors there is an even faster option, see {@link VectorVectorMult_FDRM#innerProd(FMatrixD1, FMatrixD1)}
*
*
* @param a The matrix being multiplied. Not modified.
* @param output Where the results of the operation are stored. Modified.
*/
public static T multInner( T a, @Nullable T output ) {
output = reshapeOrDeclare(output, a, a.numCols, a.numCols);
if (a.numCols >= EjmlParameters.MULT_INNER_SWITCH) {
MatrixMultProduct_FDRM.inner_small(a, output);
} else {
MatrixMultProduct_FDRM.inner_reorder(a, output);
}
return output;
}
/**
* Computes the matrix multiplication outer product:
*
* c = a * aT
*
* cij = ∑k=1:m { aik * ajk}
*
*
*
* Is faster than using a generic matrix multiplication by taking advantage of symmetry.
*
*
* @param a The matrix being multiplied. Not modified.
* @param output Where the results of the operation are stored. Modified.
*/
public static T multOuter( T a, @Nullable T output ) {
output = reshapeOrDeclare(output, a, a.numRows, a.numRows);
MatrixMultProduct_FDRM.outer(a, output);
return output;
}
/**
*
* Performs the following operation:
*
* c = c + a * b
* cij = cij + ∑k=1:n { aik * bkj}
*
*
* @param a The left matrix in the multiplication operation. Not modified.
* @param b The right matrix in the multiplication operation. Not modified.
* @param c Where the results of the operation are stored. Modified.
*/
public static void multAdd( FMatrix1Row a, FMatrix1Row b, FMatrix1Row c ) {
if (b.numCols == 1) {
MatrixVectorMult_FDRM.multAdd(a, b, c);
} else {
if (b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH) {
MatrixMatrixMult_FDRM.multAdd_reorder(a, b, c);
} else {
MatrixMatrixMult_FDRM.multAdd_small(a, b, c);
}
}
}
/**
*
* Performs the following operation:
*
* c = c + α * a * b
* cij = cij + α * ∑k=1:n { aik * bkj}
*
*
* @param alpha scaling factor.
* @param a The left matrix in the multiplication operation. Not modified.
* @param b The right matrix in the multiplication operation. Not modified.
* @param c Where the results of the operation are stored. Modified.
*/
public static void multAdd( float alpha, FMatrix1Row a, FMatrix1Row b, FMatrix1Row c ) {
// TODO add a matrix vectory multiply here
if (b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH) {
MatrixMatrixMult_FDRM.multAdd_reorder(alpha, a, b, c);
} else {
MatrixMatrixMult_FDRM.multAdd_small(alpha, a, b, c);
}
}
/**
*
* Performs the following operation:
*
* c = c + aT * b
* cij = cij + ∑k=1:n { aki * bkj}
*
*
* @param a The left matrix in the multiplication operation. Not modified.
* @param b The right matrix in the multiplication operation. Not modified.
* @param c Where the results of the operation are stored. Modified.
*/
public static void multAddTransA( FMatrix1Row a, FMatrix1Row b, FMatrix1Row c ) {
if (b.numCols == 1) {
if (a.numCols >= EjmlParameters.MULT_COLUMN_SWITCH) {
MatrixVectorMult_FDRM.multAddTransA_reorder(a, b, c);
} else {
MatrixVectorMult_FDRM.multAddTransA_small(a, b, c);
}
} else {
if (a.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ||
b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH) {
MatrixMatrixMult_FDRM.multAddTransA_reorder(a, b, c);
} else {
MatrixMatrixMult_FDRM.multAddTransA_small(a, b, c);
}
}
}
/**
*
* Performs the following operation:
*
* c = c + α * aT * b
* cij =cij + α * ∑k=1:n { aki * bkj}
*
*
* @param alpha scaling factor
* @param a The left matrix in the multiplication operation. Not modified.
* @param b The right matrix in the multiplication operation. Not modified.
* @param c Where the results of the operation are stored. Modified.
*/
public static void multAddTransA( float alpha, FMatrix1Row a, FMatrix1Row b, FMatrix1Row c ) {
// TODO add a matrix vectory multiply here
if (a.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ||
b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH) {
MatrixMatrixMult_FDRM.multAddTransA_reorder(alpha, a, b, c);
} else {
MatrixMatrixMult_FDRM.multAddTransA_small(alpha, a, b, c);
}
}
/**
*
* Performs the following operation:
*
* c = c + a * bT
* cij = cij + ∑k=1:n { aik * bjk}
*
*
* @param a The left matrix in the multiplication operation. Not modified.
* @param b The right matrix in the multiplication operation. Not modified.
* @param c Where the results of the operation are stored. Modified.
*/
public static void multAddTransB( FMatrix1Row a, FMatrix1Row b, FMatrix1Row c ) {
MatrixMatrixMult_FDRM.multAddTransB(a, b, c);
}
/**
*
* Performs the following operation:
*
* c = c + α * a * bT
* cij = cij + α * ∑k=1:n { aik * bjk}
*
*
* @param alpha Scaling factor.
* @param a The left matrix in the multiplication operation. Not modified.
* @param b The right matrix in the multiplication operation. Not modified.
* @param c Where the results of the operation are stored. Modified.
*/
public static void multAddTransB( float alpha, FMatrix1Row a, FMatrix1Row b, FMatrix1Row c ) {
// TODO add a matrix vectory multiply here
MatrixMatrixMult_FDRM.multAddTransB(alpha, a, b, c);
}
/**
*
* Performs the following operation:
*
* c = c + aT * bT
* cij = cij + ∑k=1:n { aki * bjk}
*
*
* @param a The left matrix in the multiplication operation. Not Modified.
* @param b The right matrix in the multiplication operation. Not Modified.
* @param c Where the results of the operation are stored. Modified.
*/
public static void multAddTransAB( FMatrix1Row a, FMatrix1Row b, FMatrix1Row c ) {
if (a.numCols >= EjmlParameters.MULT_TRANAB_COLUMN_SWITCH) {
MatrixMatrixMult_FDRM.multAddTransAB_aux(a, b, c, null);
} else {
MatrixMatrixMult_FDRM.multAddTransAB(a, b, c);
}
}
/**
*
* Performs the following operation:
*
* c = c + α * aT * bT
* cij = cij + α * ∑k=1:n { aki * bjk}
*
*
* @param alpha Scaling factor.
* @param a The left matrix in the multiplication operation. Not Modified.
* @param b The right matrix in the multiplication operation. Not Modified.
* @param c Where the results of the operation are stored. Modified.
*/
public static void multAddTransAB( float alpha, FMatrix1Row a, FMatrix1Row b, FMatrix1Row c ) {
// TODO add a matrix vectory multiply here
if (a.numCols >= EjmlParameters.MULT_TRANAB_COLUMN_SWITCH) {
MatrixMatrixMult_FDRM.multAddTransAB_aux(alpha, a, b, c, null);
} else {
MatrixMatrixMult_FDRM.multAddTransAB(alpha, a, b, c);
}
}
/**
*
* Solves for x in the following equation:
*
* A*x = b
*
*
*
* If the system could not be solved then false is returned. If it returns true
* that just means the algorithm finished operating, but the results could still be bad
* because 'A' is singular or nearly singular.
*
*
*
* If repeat calls to solve are being made then one should consider using {@link LinearSolverFactory_FDRM}
* instead.
*
*
*
* It is ok for 'b' and 'x' to be the same matrix.
*
*
* @param a A matrix that is m by n. Not modified.
* @param b A matrix that is n by k. Not modified.
* @param x A matrix that is m by k. Modified.
* @return true if it could invert the matrix false if it could not.
*/
public static boolean solve( FMatrixRMaj a, FMatrixRMaj b, FMatrixRMaj x ) {
x.reshape(a.numCols, b.numCols);
LinearSolverDense solver = LinearSolverFactory_FDRM.general(a.numRows, a.numCols);
// make sure the inputs 'a' and 'b' are not modified
solver = new LinearSolverSafe<>(solver);
if (!solver.setA(a))
return false;
solver.solve(b, x);
return true;
}
/**
*
* Linear solver for systems which are symmetric positive definite.
* A*x = b
*
*
* @param A A matrix that is n by n and SPD. Not modified.
* @param b A matrix that is n by k. Not modified.
* @param x A matrix that is n by k. Modified.
* @return true if it could invert the matrix false if it could not.
* @see UnrolledCholesky_FDRM
* @see LinearSolverFactory_FDRM
*/
public static boolean solveSPD( FMatrixRMaj A, FMatrixRMaj b, FMatrixRMaj x ) {
if (A.numRows != A.numCols)
throw new IllegalArgumentException("Must be a square matrix");
x.reshape(A.numCols, b.numCols);
if (A.numRows <= UnrolledCholesky_FDRM.MAX) {
FMatrixRMaj L = A.createLike();
// L*L' = A
if (!UnrolledCholesky_FDRM.lower(A, L))
return false;
// if only one column then a faster method can be used
if (x.numCols == 1) {
x.setTo(b);
TriangularSolver_FDRM.solveL(L.data, x.data, L.numCols);
TriangularSolver_FDRM.solveTranL(L.data, x.data, L.numCols);
} else {
float[] vv = new float[A.numCols];
LinearSolverChol_FDRM.solveLower(L, b, x, vv);
}
} else {
LinearSolverDense solver = LinearSolverFactory_FDRM.chol(A.numCols);
solver = new LinearSolverSafe<>(solver);
if (!solver.setA(A))
return false;
solver.solve(b, x);
return true;
}
return true;
}
/**
* Performs an "in-place" transpose.
*
*
* For square matrices the transpose is truly in-place and does not require
* additional memory. For non-square matrices, internally a temporary matrix is declared and
* {@link #transpose(FMatrixRMaj, FMatrixRMaj)} is invoked.
*
*
* @param mat The matrix that is to be transposed. Modified.
*/
public static void transpose( FMatrixRMaj mat ) {
if (mat.numCols == mat.numRows) {
TransposeAlgs_FDRM.square(mat);
} else {
FMatrixRMaj b = new FMatrixRMaj(mat.numCols, mat.numRows);
transpose(mat, b);
mat.setTo(b);
}
}
/**
*
* Transposes matrix 'a' and stores the results in 'b':
*
* bij = aji
* where 'b' is the transpose of 'a'.
*
*
* @param A The original matrix. Not modified.
* @param A_tran Where the transpose is stored. If null a new matrix is created. Modified.
* @return The transposed matrix.
*/
public static FMatrixRMaj transpose( FMatrixRMaj A, @Nullable FMatrixRMaj A_tran ) {
A_tran = reshapeOrDeclare(A_tran, A.numCols, A.numRows);
if (A.numRows > EjmlParameters.TRANSPOSE_SWITCH &&
A.numCols > EjmlParameters.TRANSPOSE_SWITCH)
TransposeAlgs_FDRM.block(A, A_tran, EjmlParameters.BLOCK_WIDTH);
else
TransposeAlgs_FDRM.standard(A, A_tran);
return A_tran;
}
/**
*
* This computes the trace of the matrix:
*
* trace = ∑i=1:n { aii }
* where n = min(numRows,numCols)
*
*
* @param a A square matrix. Not modified.
*/
public static float trace( FMatrix1Row a ) {
int N = Math.min(a.numRows, a.numCols);
float sum = 0;
int index = 0;
for (int i = 0; i < N; i++) {
sum += a.get(index);
index += 1 + a.numCols;
}
return sum;
}
/**
* Returns the determinant of the matrix. If the inverse of the matrix is also
* needed, then using {@link org.ejml.interfaces.decomposition.LUDecomposition_F32} directly (or any
* similar algorithm) can be more efficient.
*
* @param mat The matrix whose determinant is to be computed. Not modified.
* @return The determinant.
*/
public static float det( FMatrixRMaj mat ) {
int numCol = mat.getNumCols();
int numRow = mat.getNumRows();
if (numCol != numRow) {
throw new MatrixDimensionException("Must be a square matrix.");
} else if (numCol <= UnrolledDeterminantFromMinor_FDRM.MAX) {
// slight performance boost overall by doing it this way
// when it was the case statement the VM did some strange optimization
// and made case 2 about 1/2 the speed
if (numCol >= 2) {
return UnrolledDeterminantFromMinor_FDRM.det(mat);
} else {
return mat.get(0);
}
} else {
LUDecompositionAlt_FDRM alg = new LUDecompositionAlt_FDRM();
if (alg.inputModified()) {
mat = mat.copy();
}
if (!alg.decompose(mat))
return 0.0f;
return alg.computeDeterminant().real;
}
}
/**
*
* Performs a matrix inversion operation on the specified matrix and stores the results
* in the same matrix.
*
* a = a-1
*
*
*
* If the algorithm could not invert the matrix then false is returned. If it returns true
* that just means the algorithm finished. The results could still be bad
* because the matrix is singular or nearly singular.
*
*
* @param mat The matrix that is to be inverted. Results are stored here. Modified.
* @return true if it could invert the matrix false if it could not.
*/
public static boolean invert( FMatrixRMaj mat ) {
if (mat.numCols <= UnrolledInverseFromMinor_FDRM.MAX) {
if (mat.numCols != mat.numRows) {
throw new MatrixDimensionException("Must be a square matrix.");
}
if (mat.numCols >= 2) {
UnrolledInverseFromMinor_FDRM.inv(mat, mat);
} else {
mat.set(0, 1.0f/mat.get(0));
}
} else {
LUDecompositionAlt_FDRM alg = new LUDecompositionAlt_FDRM();
LinearSolverLu_FDRM solver = new LinearSolverLu_FDRM(alg);
if (solver.setA(mat)) {
solver.invert(mat);
} else {
return false;
}
}
return true;
}
/**
*
* Performs a matrix inversion operation that does not modify the original
* and stores the results in another matrix. The two matrices must have the
* same dimension.
*
* b = a-1
*
*
*
* If the algorithm could not invert the matrix then false is returned. If it returns true
* that just means the algorithm finished. The results could still be bad
* because the matrix is singular or nearly singular.
*
*
*
* For medium to large matrices there might be a slight performance boost to using
* {@link LinearSolverFactory_FDRM} instead.
*
*
* @param mat The matrix that is to be inverted. Not modified.
* @param result Where the inverse matrix is stored. Modified.
* @return true if it could invert the matrix false if it could not.
*/
public static boolean invert( FMatrixRMaj mat, FMatrixRMaj result ) {
result.reshape(mat.numRows, mat.numCols);
if (mat.numCols <= UnrolledInverseFromMinor_FDRM.MAX) {
if (mat.numCols != mat.numRows) {
throw new MatrixDimensionException("Must be a square matrix.");
}
if (result.numCols >= 2) {
UnrolledInverseFromMinor_FDRM.inv(mat, result);
} else {
result.set(0, 1.0f/mat.get(0));
}
} else {
LUDecompositionAlt_FDRM alg = new LUDecompositionAlt_FDRM();
LinearSolverLu_FDRM solver = new LinearSolverLu_FDRM(alg);
if (solver.modifiesA())
mat = mat.copy();
if (!solver.setA(mat))
return false;
solver.invert(result);
}
return true;
}
/**
* Matrix inverse for symmetric positive definite matrices. For small matrices an unrolled
* cholesky is used. Otherwise a standard decomposition.
*
* @param mat (Input) SPD matrix
* @param result (Output) Inverted matrix.
* @return true if it could invert the matrix false if it could not.
* @see UnrolledCholesky_FDRM
* @see LinearSolverFactory_FDRM#chol(int)
*/
public static boolean invertSPD( FMatrixRMaj mat, FMatrixRMaj result ) {
if (mat.numRows != mat.numCols)
throw new IllegalArgumentException("Must be a square matrix");
result.reshape(mat.numRows, mat.numRows);
if (mat.numRows <= UnrolledCholesky_FDRM.MAX) {
// L*L' = A
if (!UnrolledCholesky_FDRM.lower(mat, result))
return false;
// L = inv(L)
TriangularSolver_FDRM.invertLower(result.data, result.numCols);
// inv(A) = inv(L')*inv(L)
SpecializedOps_FDRM.multLowerTranA(result);
} else {
LinearSolverDense solver = LinearSolverFactory_FDRM.chol(mat.numCols);
if (solver.modifiesA())
mat = mat.copy();
if (!solver.setA(mat))
return false;
solver.invert(result);
}
return true;
}
/**
*
* Computes the Moore-Penrose pseudo-inverse:
*
* pinv(A) = (ATA)-1 AT
* or
* pinv(A) = AT(AAT)-1
*
*
* Internally it uses {@link SolvePseudoInverseSvd_FDRM} to compute the inverse. For performance reasons, this should only
* be used when a matrix is singular or nearly singular.
*
*
* @param A A m by n Matrix. Not modified.
* @param invA Where the computed pseudo inverse is stored. n by m. Modified.
*/
public static void pinv( FMatrixRMaj A, FMatrixRMaj invA ) {
LinearSolverDense solver = LinearSolverFactory_FDRM.pseudoInverse(true);
if (solver.modifiesA())
A = A.copy();
if (!solver.setA(A))
throw new IllegalArgumentException("Invert failed, maybe a bug?");
solver.invert(invA);
}
/**
* Converts the columns in a matrix into a set of vectors.
*
* @param A Matrix. Not modified.
* @return An array of vectors.
*/
public static FMatrixRMaj[] columnsToVector( FMatrixRMaj A, @Nullable FMatrixRMaj[] v ) {
FMatrixRMaj[] ret;
if (v == null || v.length < A.numCols) {
ret = new FMatrixRMaj[A.numCols];
} else {
ret = v;
}
for (int i = 0; i < ret.length; i++) {
if (ret[i] == null) {
ret[i] = new FMatrixRMaj(A.numRows, 1);
} else {
ret[i].reshape(A.numRows, 1, false);
}
FMatrixRMaj u = ret[i];
for (int j = 0; j < A.numRows; j++) {
u.set(j, 0, A.get(j, i));
}
}
return ret;
}
/**
* Converts the rows in a matrix into a set of vectors.
*
* @param A Matrix. Not modified.
* @return An array of vectors.
*/
public static FMatrixRMaj[] rowsToVector( FMatrixRMaj A, @Nullable FMatrixRMaj[] v ) {
FMatrixRMaj[] ret;
if (v == null || v.length < A.numRows) {
ret = new FMatrixRMaj[A.numRows];
} else {
ret = v;
}
for (int i = 0; i < ret.length; i++) {
if (ret[i] == null) {
ret[i] = new FMatrixRMaj(A.numCols, 1);
} else {
ret[i].reshape(A.numCols, 1, false);
}
FMatrixRMaj u = ret[i];
for (int j = 0; j < A.numCols; j++) {
u.set(j, 0, A.get(i, j));
}
}
return ret;
}
/**
* Sets all the diagonal elements equal to one and everything else equal to zero.
* If this is a square matrix then it will be an identity matrix.
*
* @param mat A square matrix.
* @see #identity(int)
*/
public static void setIdentity( FMatrix1Row mat ) {
int width = mat.numRows < mat.numCols ? mat.numRows : mat.numCols;
Arrays.fill(mat.data, 0, mat.getNumElements(), 0);
int index = 0;
for (int i = 0; i < width; i++, index += mat.numCols + 1) {
mat.data[index] = 1;
}
}
/**
*
* Creates an identity matrix of the specified size.
*
* aij = 0 if i ≠ j
* aij = 1 if i = j
*
*
* @param width The width and height of the identity matrix.
* @return A new instance of an identity matrix.
*/
public static FMatrixRMaj identity( int width ) {
FMatrixRMaj ret = new FMatrixRMaj(width, width);
for (int i = 0; i < width; i++) {
ret.set(i, i, 1.0f);
}
return ret;
}
/**
* Creates a rectangular matrix which is zero except along the diagonals.
*
* @param numRows Number of rows in the matrix.
* @param numCols NUmber of columns in the matrix.
* @return A matrix with diagonal elements equal to one.
*/
public static FMatrixRMaj identity( int numRows, int numCols ) {
FMatrixRMaj ret = new FMatrixRMaj(numRows, numCols);
int small = numRows < numCols ? numRows : numCols;
for (int i = 0; i < small; i++) {
ret.set(i, i, 1.0f);
}
return ret;
}
/**
*
* Creates a new square matrix whose diagonal elements are specified by diagEl and all
* the other elements are zero.
*
* aij = 0 if i ≤ j
* aij = diag[i] if i = j
*
*
* @param diagEl Contains the values of the diagonal elements of the resulting matrix.
* @return A new matrix.
* @see #diagR
*/
public static FMatrixRMaj diag( float... diagEl ) {
return diag(null, diagEl.length, diagEl);
}
/**
* @see #diag(float...)
*/
public static FMatrixRMaj diag( @Nullable FMatrixRMaj ret, int width, float... diagEl ) {
if (ret == null) {
ret = new FMatrixRMaj(width, width);
} else {
if (ret.numRows != width || ret.numCols != width)
throw new IllegalArgumentException("Unexpected matrix size");
CommonOps_FDRM.fill(ret, 0);
}
for (int i = 0; i < width; i++) {
ret.unsafe_set(i, i, diagEl[i]);
}
return ret;
}
/**
*
* Creates a new rectangular matrix whose diagonal elements are specified by diagEl and all
* the other elements are zero.
*
* aij = 0 if i ≤ j
* aij = diag[i] if i = j
*
*
* @param numRows Number of rows in the matrix.
* @param numCols Number of columns in the matrix.
* @param diagEl Contains the values of the diagonal elements of the resulting matrix.
* @return A new matrix.
* @see #diag
*/
public static FMatrixRMaj diagR( int numRows, int numCols, float... diagEl ) {
FMatrixRMaj ret = new FMatrixRMaj(numRows, numCols);
int o = Math.min(numRows, numCols);
for (int i = 0; i < o; i++) {
ret.set(i, i, diagEl[i]);
}
return ret;
}
/**
*
* The Kronecker product of two matrices is defined as:
* Cij = aijB
* where Cij is a sub matrix inside of C ∈ ℜ m*k × n*l,
* A ∈ ℜ m × n, and B ∈ ℜ k × l.
*
*
* @param A The left matrix in the operation. Not modified.
* @param B The right matrix in the operation. Not modified.
* @param C Where the results of the operation are stored. Nullable. Modified.
*/
public static FMatrixRMaj kron( FMatrixRMaj A, FMatrixRMaj B, @Nullable FMatrixRMaj C ) {
int numColsC = A.numCols*B.numCols;
int numRowsC = A.numRows*B.numRows;
C = reshapeOrDeclare(C,numRowsC, numColsC);
// TODO see comment below
// this will work well for small matrices
// but an alternative version should be made for large matrices
for (int i = 0; i < A.numRows; i++) {
for (int j = 0; j < A.numCols; j++) {
float a = A.get(i, j);
for (int rowB = 0; rowB < B.numRows; rowB++) {
for (int colB = 0; colB < B.numCols; colB++) {
float val = a*B.get(rowB, colB);
C.unsafe_set(i*B.numRows + rowB, j*B.numCols + colB, val);
}
}
}
}
return C;
}
/**
*
* Extracts a submatrix from 'src' and inserts it in a submatrix in 'dst'.
*
*
* si-y0 , j-x0 = oij for all y0 ≤ i < y1 and x0 ≤ j < x1
*
* where 'sij' is an element in the submatrix and 'oij' is an element in the
* original matrix.
*
*
* @param src The original matrix which is to be copied. Not modified.
* @param srcX0 Start column.
* @param srcX1 Stop column+1.
* @param srcY0 Start row.
* @param srcY1 Stop row+1.
* @param dst Where the submatrix are stored. Modified.
* @param dstY0 Start row in dst.
* @param dstX0 start column in dst.
*/
public static void extract( FMatrix src,
int srcY0, int srcY1,
int srcX0, int srcX1,
FMatrix dst,
int dstY0, int dstX0 ) {
if (srcY1 < srcY0 || srcY0 < 0 || srcY1 > src.getNumRows())
throw new MatrixDimensionException("srcY1 < srcY0 || srcY0 < 0 || srcY1 > src.numRows. " + stringShapes(src, dst));
if (srcX1 < srcX0 || srcX0 < 0 || srcX1 > src.getNumCols())
throw new MatrixDimensionException("srcX1 < srcX0 || srcX0 < 0 || srcX1 > src.numCols. " + stringShapes(src, dst));
int w = srcX1 - srcX0;
int h = srcY1 - srcY0;
if (dstY0 + h > dst.getNumRows())
throw new MatrixDimensionException("dst is too small in rows. " + dst.getNumRows() + " < " + (dstY0 + h));
if (dstX0 + w > dst.getNumCols())
throw new MatrixDimensionException("dst is too small in columns. " + dst.getNumCols() + " < " + (dstX0 + w));
// interestingly, the performance is only different for small matrices but identical for larger ones
if (src instanceof FMatrixRMaj && dst instanceof FMatrixRMaj) {
ImplCommonOps_FDRM.extract((FMatrixRMaj)src, srcY0, srcX0, (FMatrixRMaj)dst, dstY0, dstX0, h, w);
} else {
ImplCommonOps_FDMA.extract(src, srcY0, srcX0, dst, dstY0, dstX0, h, w);
}
}
/**
* Extract where the destination is reshaped to match the extracted region
*
* @param src The original matrix which is to be copied. Not modified.
* @param srcX0 Start column.
* @param srcX1 Stop column+1.
* @param srcY0 Start row.
* @param srcY1 Stop row+1.
* @param dst Where the submatrix are stored. Modified.
*/
public static void extract( FMatrix src,
int srcY0, int srcY1,
int srcX0, int srcX1,
FMatrix dst ) {
((ReshapeMatrix)dst).reshape(srcY1 - srcY0, srcX1 - srcX0);
extract(src, srcY0, srcY1, srcX0, srcX1, dst, 0, 0);
}
/**
*
* Extracts a submatrix from 'src' and inserts it in a submatrix in 'dst'. Uses the shape of dst
* to determine the size of the matrix extracted.
*
*
* @param src The original matrix which is to be copied. Not modified.
* @param srcY0 Start row in src.
* @param srcX0 Start column in src.
* @param dst Where the matrix is extracted into.
*/
public static void extract( FMatrix src,
int srcY0, int srcX0,
FMatrix dst ) {
extract(src, srcY0, srcY0 + dst.getNumRows(), srcX0, srcX0 + dst.getNumCols(), dst, 0, 0);
}
/**
*
* Creates a new matrix which is the specified submatrix of 'src'
*
*
* si-y0 , j-x0 = oij for all y0 ≤ i < y1 and x0 ≤ j < x1
*
* where 'sij' is an element in the submatrix and 'oij' is an element in the
* original matrix.
*
*
* @param src The original matrix which is to be copied. Not modified.
* @param srcX0 Start column.
* @param srcX1 Stop column+1.
* @param srcY0 Start row.
* @param srcY1 Stop row+1.
* @return Extracted submatrix.
*/
public static FMatrixRMaj extract( FMatrixRMaj src,
int srcY0, int srcY1,
int srcX0, int srcX1 ) {
if (srcY1 <= srcY0 || srcY0 < 0 || srcY1 > src.numRows)
throw new MatrixDimensionException("srcY1 <= srcY0 || srcY0 < 0 || srcY1 > src.numRows");
if (srcX1 <= srcX0 || srcX0 < 0 || srcX1 > src.numCols)
throw new MatrixDimensionException("srcX1 <= srcX0 || srcX0 < 0 || srcX1 > src.numCols");
int w = srcX1 - srcX0;
int h = srcY1 - srcY0;
FMatrixRMaj dst = new FMatrixRMaj(h, w);
ImplCommonOps_FDRM.extract(src, srcY0, srcX0, dst, 0, 0, h, w);
return dst;
}
/**
* Extracts out a matrix from source given a sub matrix with arbitrary rows and columns specified in
* two array lists
*
* @param src Source matrix. Not modified.
* @param rows array of row indexes
* @param rowsSize maximum element in row array
* @param cols array of column indexes
* @param colsSize maximum element in column array
* @param dst output matrix. Must be correct shape.
*/
public static FMatrixRMaj extract( FMatrixRMaj src,
int[] rows, int rowsSize,
int[] cols, int colsSize, @Nullable FMatrixRMaj dst ) {
dst = reshapeOrDeclare(dst, rowsSize, colsSize);
int indexDst = 0;
for (int i = 0; i < rowsSize; i++) {
int indexSrcRow = src.numCols*rows[i];
for (int j = 0; j < colsSize; j++) {
dst.data[indexDst++] = src.data[indexSrcRow + cols[j]];
}
}
return dst;
}
/**
* Extracts the elements from the source matrix by their 1D index.
*
* @param src Source matrix. Not modified.
* @param indexes array of row indexes
* @param length maximum element in row array
* @param dst output matrix. Must be a vector of the correct length.
*/
public static FMatrixRMaj extract( FMatrixRMaj src, int[] indexes, int length, @Nullable FMatrixRMaj dst ) {
if (dst==null)
dst = new FMatrixRMaj(length,1);
else if (!(MatrixFeatures_FDRM.isVector(dst) && dst.getNumElements()==length) )
dst.reshape(length,1);
for (int i = 0; i < length; i++) {
dst.data[i] = src.data[indexes[i]];
}
return dst;
}
/**
* Inserts into the specified elements of dst the source matrix.
*
* for i in len(rows):
* for j in len(cols):
* dst(rows[i],cols[j]) = src(i,j)
*
*
* @param src Source matrix. Not modified.
* @param dst output matrix. Must be correct shape.
* @param rows array of row indexes.
* @param rowsSize maximum element in row array
* @param cols array of column indexes
* @param colsSize maximum element in column array
*/
public static void insert( FMatrixRMaj src,
FMatrixRMaj dst,
int[] rows, int rowsSize,
int[] cols, int colsSize ) {
UtilEjml.assertEq(rowsSize, src.numRows, "src's rows don't match rowsSize");
UtilEjml.assertEq(colsSize, src.numCols, "src's columns don't match colsSize");
int indexSrc = 0;
for (int i = 0; i < rowsSize; i++) {
int indexDstRow = dst.numCols*rows[i];
for (int j = 0; j < colsSize; j++) {
dst.data[indexDstRow + cols[j]] = src.data[indexSrc++];
}
}
}
/**
*
* Extracts the diagonal elements 'src' write it to the 'dst' vector. 'dst'
* can either be a row or column vector.
*
*
* @param src Matrix whose diagonal elements are being extracted. Not modified.
* @param dst A vector the results will be written into. Modified.
*/
public static FMatrixRMaj extractDiag( FMatrixRMaj src, @Nullable FMatrixRMaj dst ) {
int N = Math.min(src.numRows, src.numCols);
if( dst == null ) {
dst = new FMatrixRMaj(N,1);
} else {
if (!MatrixFeatures_FDRM.isVector(dst) || dst.numCols*dst.numCols != N) {
dst.reshape(N, 1);
}
}
for (int i = 0; i < N; i++) {
dst.set(i, src.unsafe_get(i, i));
}
return dst;
}
/**
* Extracts the row from a matrix.
*
* @param a Input matrix
* @param row Which row is to be extracted
* @param out output. Storage for the extracted row. If null then a new vector will be returned.
* @return The extracted row.
*/
public static FMatrixRMaj extractRow( FMatrixRMaj a, int row, @Nullable FMatrixRMaj out ) {
if (out == null)
out = new FMatrixRMaj(1, a.numCols);
else if (!MatrixFeatures_FDRM.isVector(out) || out.getNumElements() != a.numCols)
out.reshape(1, a.numCols);
System.arraycopy(a.data, a.getIndex(row, 0), out.data, 0, a.numCols);
return out;
}
/**
* Extracts the column from a matrix.
*
* @param a Input matrix
* @param column Which column is to be extracted
* @param out output. Storage for the extracted column. If null then a new vector will be returned.
* @return The extracted column.
*/
public static FMatrixRMaj extractColumn( FMatrixRMaj a, int column, @Nullable FMatrixRMaj out ) {
if (out == null)
out = new FMatrixRMaj(a.numRows, 1);
else if (!MatrixFeatures_FDRM.isVector(out) || out.getNumElements() != a.numRows)
out.reshape(a.numRows, 1);
int index = column;
for (int i = 0; i < a.numRows; i++, index += a.numCols) {
out.data[i] = a.data[index];
}
return out;
}
/**
* Removes columns from the matrix.
*
* @param A Matrix. Modified
* @param col0 First column
* @param col1 Last column, inclusive.
*/
public static void removeColumns( FMatrixRMaj A, int col0, int col1 ) {
UtilEjml.assertTrue(col0 < col1, "col1 must be >= col0");
UtilEjml.assertTrue(col0 >= 0 && col1 <= A.numCols,"Columns which are to be removed must be in bounds");
int step = col1 - col0 + 1;
int offset = 0;
for (int row = 0, idx = 0; row < A.numRows; row++) {
for (int i = 0; i < col0; i++, idx++) {
A.data[idx] = A.data[idx + offset];
}
offset += step;
for (int i = col1 + 1; i < A.numCols; i++, idx++) {
A.data[idx] = A.data[idx + offset];
}
}
A.numCols -= step;
}
/**
* Inserts matrix 'src' into matrix 'dest' with the (0,0) of src at (row,col) in dest.
* This is equivalent to calling extract(src,0,src.numRows,0,src.numCols,dest,destY0,destX0).
*
* @param src matrix that is being copied into dest. Not modified.
* @param dest Where src is being copied into. Modified.
* @param destY0 Start row for the copy into dest.
* @param destX0 Start column for the copy into dest.
*/
public static void insert( FMatrix src, FMatrix dest, int destY0, int destX0 ) {
extract(src, 0, src.getNumRows(), 0, src.getNumCols(), dest, destY0, destX0);
}
/**
*
* Returns the value of the element in the matrix that has the largest value.
*
* Max{ aij } for all i and j
*
*
* @param a A matrix. Not modified.
* @return The max element value of the matrix.
*/
public static float elementMax( FMatrixD1 a ) {
return ImplCommonOps_FDRM.elementMax(a, null);
}
/**
*
* Returns the value of the element in the matrix that has the largest value.
*
* Max{ aij } for all i and j
*
*
* @param a A matrix. Not modified.
* @param loc (Output) Location of selected element.
* @return The max element value of the matrix.
*/
public static float elementMax( FMatrixD1 a, ElementLocation loc ) {
return ImplCommonOps_FDRM.elementMax(a, loc);
}
/**
*
* Returns the absolute value of the element in the matrix that has the largest absolute value.
*
* Max{ |aij| } for all i and j
*
*
* @param a A matrix. Not modified.
* @return The max abs element value of the matrix.
*/
public static float elementMaxAbs( FMatrixD1 a ) {
return ImplCommonOps_FDRM.elementMaxAbs(a, null);
}
/**
*
* Returns the absolute value of the element in the matrix that has the largest absolute value.
*
* Max{ |aij| } for all i and j
*
*
* @param a A matrix. Not modified.
* @param loc (Output) Location of element element.
* @return The max abs element value of the matrix.
*/
public static float elementMaxAbs( FMatrixD1 a, ElementLocation loc ) {
return ImplCommonOps_FDRM.elementMaxAbs(a, loc);
}
/**
*
* Returns the value of the element in the matrix that has the minimum value.
*
* Min{ aij } for all i and j
*
*
* @param a A matrix. Not modified.
* @return The value of element in the matrix with the minimum value.
*/
public static float elementMin( FMatrixD1 a ) {
return ImplCommonOps_FDRM.elementMin(a, null);
}
/**
*
* Returns the value of the element in the matrix that has the minimum value.
*
* Min{ aij } for all i and j
*
*
* @param a A matrix. Not modified.
* @param loc (Output) Location of selected element.
* @return The value of element in the matrix with the minimum value.
*/
public static float elementMin( FMatrixD1 a, ElementLocation loc ) {
return ImplCommonOps_FDRM.elementMin(a, loc);
}
/**
*
* Returns the absolute value of the element in the matrix that has the smallest absolute value.
*
* Min{ |aij| } for all i and j
*
*
* @param a A matrix. Not modified.
* @return The max element value of the matrix.
*/
public static float elementMinAbs( FMatrixD1 a ) {
return ImplCommonOps_FDRM.elementMinAbs(a, null);
}
/**
*
* Returns the absolute value of the element in the matrix that has the smallest absolute value.
*
* Min{ |aij| } for all i and j
*
*
* @param a (Input) A matrix. Not modified.
* @param loc (Output) Location of selected element.
* @return The max element value of the matrix.
*/
public static float elementMinAbs( FMatrixD1 a, ElementLocation loc ) {
return ImplCommonOps_FDRM.elementMinAbs(a, loc);
}
/**
* Performs the an element by element multiplication operation:
*
* aij = aij * bij
*
*
* @param A The left matrix in the multiplication operation. Modified.
* @param B The right matrix in the multiplication operation. Not modified.
*/
public static void elementMult( FMatrixD1 A, FMatrixD1 B ) {
ImplCommonOps_FDRM.elementMult(A, B);
}
/**
* Performs the an element by element multiplication operation:
*
* cij = aij * bij
*
*
* @param A The left matrix in the multiplication operation. Not modified.
* @param B The right matrix in the multiplication operation. Not modified.
* @param output Where the results of the operation are stored. Modified.
*/
public static T elementMult( T A, T B, @Nullable T output ) {
return ImplCommonOps_FDRM.elementMult(A, B, output);
}
/**
* Performs the an element by element division operation:
*
* aij = aij / bij
*
*
* @param A The left matrix in the division operation. Modified.
* @param B The right matrix in the division operation. Not modified.
*/
public static void elementDiv( FMatrixD1 A, FMatrixD1 B ) {
ImplCommonOps_FDRM.elementDiv(A, B);
}
/**
* Performs the an element by element division operation:
*
* cij = aij / bij
*
*
* @param A The left matrix in the division operation. Not modified.
* @param B The right matrix in the division operation. Not modified.
* @param output Where the results of the operation are stored. Modified.
*/
public static T elementDiv( T A, T B, @Nullable T output ) {
return ImplCommonOps_FDRM.elementDiv(A, B, output);
}
/**
*
* Computes the sum of all the elements in the matrix:
*
* sum(i=1:m , j=1:n ; aij)
*
*
* @param mat An m by n matrix. Not modified.
* @return The sum of the elements.
*/
public static float elementSum( FMatrixD1 mat ) {
return ImplCommonOps_FDRM.elementSum(mat);
}
/**
*
* Computes the sum of the absolute value all the elements in the matrix:
*
* sum(i=1:m , j=1:n ; |aij|)
*
*
* @param mat An m by n matrix. Not modified.
* @return The sum of the absolute value of each element.
*/
public static float elementSumAbs( FMatrixD1 mat ) {
return ImplCommonOps_FDRM.elementSumAbs(mat);
}
/**
*
* Element-wise power operation
* cij = aij ^ bij
*
*
* @param A left side
* @param B right side
* @param output output (modified)
*/
public static T elementPower( T A, T B, @Nullable T output ) {
return ImplCommonOps_FDRM.elementPower(A, B, output);
}
/**
*
* Element-wise power operation
* cij = a ^ bij
*
*
* @param a left scalar
* @param B right side
* @param output output (modified)
*/
public static T elementPower( float a, T B, @Nullable T output ) {
return ImplCommonOps_FDRM.elementPower(a, B, output);
}
/**
*
* Element-wise power operation
* cij = aij ^ b
*
*
* @param A left side
* @param b right scalar
* @param output output (modified)
*/
public static T elementPower( T A, float b, @Nullable T output ) {
return ImplCommonOps_FDRM.elementPower(A, b, output);
}
/**
*
* Element-wise log operation
* cij = (float)Math.log(aij)
*
*
* @param A (input) A matrix
* @param output (input/output) Storage for results. can be null. (modified)
* @return The results
*/
public static T elementLog( T A, @Nullable T output ) {
return ImplCommonOps_FDRM.elementLog(A, output);
}
/**
*
* Element-wise exp operation
* cij = (float)Math.exp(aij)
*
*
* @param A (input) A matrix
* @param output (input/output) Storage for results. can be null. (modified)
* @return The results
*/
public static T elementExp( T A, @Nullable T output ) {
return ImplCommonOps_FDRM.elementExp(A, output);
}
/**
* Multiplies every element in row i by value[i].
*
* @param values array. Not modified.
* @param A Matrix. Modified.
*/
public static void multRows( float[] values, FMatrixRMaj A ) {
if (values.length < A.numRows) {
throw new IllegalArgumentException("Not enough elements in values.");
}
int index = 0;
for (int row = 0; row < A.numRows; row++) {
float v = values[row];
for (int col = 0; col < A.numCols; col++, index++) {
A.data[index] *= v;
}
}
}
/**
* Divides every element in row i by value[i].
*
* @param values array. Not modified.
* @param A Matrix. Modified.
*/
public static void divideRows( float[] values, FMatrixRMaj A ) {
if (values.length < A.numRows) {
throw new IllegalArgumentException("Not enough elements in values.");
}
int index = 0;
for (int row = 0; row < A.numRows; row++) {
float v = values[row];
for (int col = 0; col < A.numCols; col++, index++) {
A.data[index] /= v;
}
}
}
/**
* Multiplies every element in column i by value[i].
*
* @param A Matrix. Modified.
* @param values array. Not modified.
*/
public static void multCols( FMatrixRMaj A, float[] values ) {
if (values.length < A.numCols) {
throw new IllegalArgumentException("Not enough elements in values.");
}
int index = 0;
for (int row = 0; row < A.numRows; row++) {
for (int col = 0; col < A.numCols; col++, index++) {
A.data[index] *= values[col];
}
}
}
/**
* Divides every element in column i by value[i].
*
* @param A Matrix. Modified.
* @param values array. Not modified.
*/
public static void divideCols( FMatrixRMaj A, float[] values ) {
if (values.length < A.numCols) {
throw new IllegalArgumentException("Not enough elements in values.");
}
int index = 0;
for (int row = 0; row < A.numRows; row++) {
for (int col = 0; col < A.numCols; col++, index++) {
A.data[index] /= values[col];
}
}
}
/**
* Equivalent to multiplying a matrix B by the inverse of two diagonal matrices.
* B = inv(A)*B*inv(C), where A=diag(a) and C=diag(c).
*
* @param diagA Array of length offsteA + B.numRows
* @param offsetA First index in A
* @param B Rectangular matrix
* @param diagC Array of length indexC + B.numCols
* @param offsetC First index in C
*/
public static void divideRowsCols( float[] diagA, int offsetA,
FMatrixRMaj B,
float[] diagC, int offsetC ) {
if (diagA.length - offsetA < B.numRows) {
throw new IllegalArgumentException("Not enough elements in diagA.");
}
if (diagC.length - offsetC < B.numCols) {
throw new IllegalArgumentException("Not enough elements in diagC.");
}
final int rows = B.numRows;
final int cols = B.numCols;
int index = 0;
for (int row = 0; row < rows; row++) {
float va = diagA[offsetA + row];
for (int col = 0; col < cols; col++, index++) {
B.data[index] /= va*diagC[offsetC + col];
}
}
}
/**
*
* Computes the sum of each row in the input matrix and returns the results in a vector:
*
* bj = sum(i=1:n ; aji)
*
*
* @param input INput matrix whose rows are summed.
* @param output Optional storage for output. Reshaped into a column. Modified.
* @return Vector containing the sum of each row in the input.
*/
public static FMatrixRMaj sumRows( FMatrixRMaj input, @Nullable FMatrixRMaj output ) {
output = UtilEjml.reshapeOrDeclare(output, input.numRows, 1);
for (int row = 0; row < input.numRows; row++) {
float total = 0;
int end = (row + 1)*input.numCols;
for (int index = row*input.numCols; index < end; index++) {
total += input.data[index];
}
output.set(row, total);
}
return output;
}
/**
*
* Finds the element with the minimum value along each row in the input matrix and returns the results in a vector:
*
* bj = min(i=1:n ; aji)
*
*
* @param input Input matrix
* @param output Optional storage for output. Reshaped into a column. Modified.
* @return Vector containing the sum of each row in the input.
*/
public static FMatrixRMaj minRows( FMatrixRMaj input, @Nullable FMatrixRMaj output ) {
output = UtilEjml.reshapeOrDeclare(output, input.numRows, 1);
for (int row = 0; row < input.numRows; row++) {
float min = Float.MAX_VALUE;
int end = (row + 1)*input.numCols;
for (int index = row*input.numCols; index < end; index++) {
float v = input.data[index];
if (v < min)
min = v;
}
output.set(row, min);
}
return output;
}
/**
*
* Finds the element with the maximum value along each row in the input matrix and returns the results in a vector:
*
* bj = max(i=1:n ; aji)
*
*
* @param input Input matrix
* @param output Optional storage for output. Reshaped into a column. Modified.
* @return Vector containing the sum of each row in the input.
*/
public static FMatrixRMaj maxRows( FMatrixRMaj input, @Nullable FMatrixRMaj output ) {
output = UtilEjml.reshapeOrDeclare(output, input.numRows, 1);
for (int row = 0; row < input.numRows; row++) {
float max = -Float.MAX_VALUE;
int end = (row + 1)*input.numCols;
for (int index = row*input.numCols; index < end; index++) {
float v = input.data[index];
if (v > max)
max = v;
}
output.set(row, max);
}
return output;
}
/**
*
* Computes the sum of each column in the input matrix and returns the results in a vector:
*
* bj = sum(i=1:m ; aij)
*
*
* @param input Input matrix
* @param output Optional storage for output. Reshaped into a row vector. Modified.
* @return Vector containing the sum of each column
*/
public static FMatrixRMaj sumCols( FMatrixRMaj input, @Nullable FMatrixRMaj output ) {
output = UtilEjml.reshapeOrDeclare(output, 1, input.numCols);
for (int cols = 0; cols < input.numCols; cols++) {
float total = 0;
int index = cols;
int end = index + input.numCols*input.numRows;
for (; index < end; index += input.numCols) {
total += input.data[index];
}
output.set(cols, total);
}
return output;
}
/**
*
* Finds the element with the minimum value along column in the input matrix and returns the results in a vector:
*
* bj = min(i=1:m ; aij)
*
*
* @param input Input matrix
* @param output Optional storage for output. Reshaped into a row vector. Modified.
* @return Vector containing the minimum of each column
*/
public static FMatrixRMaj minCols( FMatrixRMaj input, @Nullable FMatrixRMaj output ) {
output = UtilEjml.reshapeOrDeclare(output, 1, input.numCols);
for (int cols = 0; cols < input.numCols; cols++) {
float minimum = Float.MAX_VALUE;
int index = cols;
int end = index + input.numCols*input.numRows;
for (; index < end; index += input.numCols) {
float v = input.data[index];
if (v < minimum)
minimum = v;
}
output.set(cols, minimum);
}
return output;
}
/**
*
* Finds the element with the minimum value along column in the input matrix and returns the results in a vector:
*
* bj = min(i=1:m ; aij)
*
*
* @param input Input matrix
* @param output Optional storage for output. Reshaped into a row vector. Modified.
* @return Vector containing the maximum of each column
*/
public static FMatrixRMaj maxCols( FMatrixRMaj input, @Nullable FMatrixRMaj output ) {
output = UtilEjml.reshapeOrDeclare(output, 1, input.numCols);
for (int cols = 0; cols < input.numCols; cols++) {
float maximum = -Float.MAX_VALUE;
int index = cols;
int end = index + input.numCols*input.numRows;
for (; index < end; index += input.numCols) {
float v = input.data[index];
if (v > maximum)
maximum = v;
}
output.set(cols, maximum);
}
return output;
}
/**
* Performs the following operation:
*
* a = a + b
* aij = aij + bij
*
*
* @param a (input/output) A Matrix. Modified.
* @param b (input) A Matrix. Not modified.
*/
public static void addEquals( FMatrixD1 a, FMatrixD1 b ) {
UtilEjml.checkSameShape(a, b, true);
final int length = a.getNumElements();
for (int i = 0; i < length; i++) {
a.plus(i, b.get(i));
}
}
/**
* Performs the following operation:
*
* a = a + β * b
* aij = aij + β * bij
*
*
* @param beta The number that matrix 'b' is multiplied by.
* @param a (input/output) A Matrix. Modified.
* @param b (input) A Matrix. Not modified.
*/
public static void addEquals( FMatrixD1 a, float beta, FMatrixD1 b ) {
UtilEjml.checkSameShape(a, b, true);
final int length = a.getNumElements();
for (int i = 0; i < length; i++) {
a.plus(i, beta*b.get(i));
}
}
/**
* Performs the following operation:
*
* c = a + b
* cij = aij + bij
*
*
*
* Matrix C can be the same instance as Matrix A and/or B.
*
*
* @param a A Matrix. Not modified.
* @param b A Matrix. Not modified.
* @param output (output) A Matrix where the results are stored. Can be null. Modified.
* @return The results.
*/
public static T add( final T a, final T b, @Nullable T output ) {
UtilEjml.checkSameShape(a, b, true);
output = UtilEjml.reshapeOrDeclare(output, a);
final int length = a.getNumElements();
for (int i = 0; i < length; i++) {
output.set(i, a.get(i) + b.get(i));
}
return output;
}
/**
* Performs the following operation:
*
* c = a + β * b
* cij = aij + β * bij
*
*
*
* Matrix C can be the same instance as Matrix A and/or B.
*
*
* @param a A Matrix. Not modified.
* @param beta Scaling factor for matrix b.
* @param b A Matrix. Not modified.
* @param output (output) A Matrix where the results are stored. Can be null. Modified.
* @return The results.
*/
public static T add( T a, float beta, T b, @Nullable T output ) {
UtilEjml.checkSameShape(a, b, true);
output = UtilEjml.reshapeOrDeclare(output, a);
final int length = a.getNumElements();
for (int i = 0; i < length; i++) {
output.set(i, a.get(i) + beta*b.get(i));
}
return output;
}
/**
* Performs the following operation:
*
* c = α * a + β * b
* cij = α * aij + β * bij
*
*
*
* Matrix C can be the same instance as Matrix A and/or B.
*
*
* @param alpha A scaling factor for matrix a.
* @param a A Matrix. Not modified.
* @param beta A scaling factor for matrix b.
* @param b A Matrix. Not modified.
* @param output (output) A Matrix where the results are stored. Can be null. Modified.
* @return The results.
*/
public static T add( float alpha, T a, float beta, T b, @Nullable T output ) {
UtilEjml.checkSameShape(a, b, true);
output = UtilEjml.reshapeOrDeclare(output, a);
final int length = a.getNumElements();
for (int i = 0; i < length; i++) {
output.set(i, alpha*a.get(i) + beta*b.get(i));
}
return output;
}
/**
* Performs the following operation:
*
* c = α * a + b
* cij = α * aij + bij
*
*
*
* Matrix C can be the same instance as Matrix A and/or B.
*
*
* @param alpha A scaling factor for matrix a.
* @param a A Matrix. Not modified.
* @param b A Matrix. Not modified.
* @param output (output) A Matrix where the results are stored. Can be null. Modified.
* @return The results.
*/
public static T add( float alpha, T a, T b, T output ) {
UtilEjml.checkSameShape(a, b, true);
output = UtilEjml.reshapeOrDeclare(output, a);
final int length = a.getNumElements();
for (int i = 0; i < length; i++) {
output.set(i, alpha*a.get(i) + b.get(i));
}
return output;
}
/**
* Performs an in-place scalar addition:
*
* a = a + val
* aij = aij + val
*
*
* @param a A matrix. Modified.
* @param val The value that's added to each element.
*/
public static void add( FMatrixD1 a, float val ) {
final int length = a.getNumElements();
for (int i = 0; i < length; i++) {
a.plus(i, val);
}
}
/**
* Performs scalar addition:
*
* c = a + val
* cij = aij + val
*
*
* @param a A matrix. Not modified.
* @param val The value that's added to each element.
* @param output (output) Storage for results. Can be null. Modified.
* @return The resulting matrix
*/
public static T add( T a, float val, T output ) {
output = UtilEjml.reshapeOrDeclare(output, a);
final int length = a.getNumElements();
for (int i = 0; i < length; i++) {
output.data[i] = a.data[i] + val;
}
return output;
}
/**
* Performs matrix scalar subtraction:
*
* c = a - val
* cij = aij - val
*
*
* @param a (input) A matrix. Not modified.
* @param val (input) The value that's subtracted to each element.
* @param output (output) Storage for results. Can be null. Modified.
* @return The resulting matrix
*/
public static T subtract( T a, float val, @Nullable T output ) {
output = UtilEjml.reshapeOrDeclare(output, a);
final int length = a.getNumElements();
for (int i = 0; i < length; i++) {
output.data[i] = a.data[i] - val;
}
return output;
}
/**
* Performs matrix scalar subtraction:
*
* c = val - a
* cij = val - aij
*
*
* @param val (input) The value that's subtracted to each element.
* @param a (input) A matrix. Not modified.
* @param output (output) Storage for results. Can be null. Modified.
* @return The resulting matrix
*/
public static T subtract( float val, T a, @Nullable T output ) {
output = UtilEjml.reshapeOrDeclare(output, a);
final int length = a.getNumElements();
for (int i = 0; i < length; i++) {
output.data[i] = val - a.data[i];
}
return output;
}
/**
* Performs the following subtraction operation:
*
* a = a - b
* aij = aij - bij
*
*
* @param a (input) A Matrix. Modified.
* @param b (input) A Matrix. Not modified.
*/
public static void subtractEquals( FMatrixD1 a, FMatrixD1 b ) {
UtilEjml.checkSameShape(a, b, true);
final int length = a.getNumElements();
for (int i = 0; i < length; i++) {
a.data[i] -= b.data[i];
}
}
/**
* Performs the following subtraction operation:
*
* c = a - b
* cij = aij - bij
*
*
* Matrix C can be the same instance as Matrix A and/or B.
*
*
* @param a (input) A Matrix. Not modified.
* @param b (input) A Matrix. Not modified.
* @param output (output) A Matrix. Can be null. Modified.
* @return The resulting matrix
*/
public static T subtract( T a, T b, @Nullable T output ) {
UtilEjml.checkSameShape(a, b, true);
output = UtilEjml.reshapeOrDeclare(output, a);
final int length = a.getNumElements();
for (int i = 0; i < length; i++) {
output.data[i] = a.data[i] - b.data[i];
}
return output;
}
/**
*
* Performs an in-place element by element scalar multiplication.
*
* aij = α*aij
*
*
* @param a The matrix that is to be scaled. Modified.
* @param alpha the amount each element is multiplied by.
*/
public static void scale( float alpha, FMatrixD1 a ) {
// on very small matrices (2 by 2) the call to getNumElements() can slow it down
// slightly compared to other libraries since it involves an extra multiplication.
final int size = a.getNumElements();
for (int i = 0; i < size; i++) {
a.data[i] *= alpha;
}
}
/**
*
* Performs an element by element scalar multiplication.
*
* bij = α*aij
*
*
* @param alpha the amount each element is multiplied by.
* @param a The matrix that is to be scaled. Not modified.
* @param b Where the scaled matrix is stored. Modified.
*/
public static void scale( float alpha, FMatrixD1 a, FMatrixD1 b ) {
b.reshape(a.numRows, a.numCols);
final int size = a.getNumElements();
for (int i = 0; i < size; i++) {
b.data[i] = a.data[i]*alpha;
}
}
/**
* In-place scaling of a row in A
*
* @param alpha scale factor
* @param A matrix
* @param row which row in A
*/
public static void scaleRow( float alpha, FMatrixRMaj A, int row ) {
int idx = row*A.numCols;
for (int col = 0; col < A.numCols; col++) {
A.data[idx++] *= alpha;
}
}
/**
* In-place scaling of a column in A
*
* @param alpha scale factor
* @param A matrix
* @param col which row in A
*/
public static void scaleCol( float alpha, FMatrixRMaj A, int col ) {
int idx = col;
for (int row = 0; row < A.numRows; row++, idx += A.numCols) {
A.data[idx] *= alpha;
}
}
/**
*
* Performs an in-place element by element scalar division with the scalar on top.
*
* aij = α/aij
*
*
* @param a (input/output) The matrix whose elements are divide the scalar. Modified.
* @param alpha top value in division
*/
public static void divide( float alpha, FMatrixD1 a ) {
final int size = a.getNumElements();
for (int i = 0; i < size; i++) {
a.data[i] = alpha/a.data[i];
}
}
/**
*
* Performs an in-place element by element scalar division with the scalar on bottom.
*
* aij = aij/α
*
*
* @param a (input/output) The matrix whose elements are to be divided. Modified.
* @param alpha the amount each element is divided by.
*/
public static void divide( FMatrixD1 a, float alpha ) {
final int size = a.getNumElements();
for (int i = 0; i < size; i++) {
a.data[i] /= alpha;
}
}
/**
*
* Performs an element by element scalar division with the scalar on top.
*
* bij = α/aij
*
*
* @param alpha The numerator.
* @param input The matrix whose elements are the divisor. Not modified.
* @param output Where the results are stored. Modified. Can be null.
* @return The resulting matrix
*/
public static T divide( float alpha, T input, T output ) {
output = UtilEjml.reshapeOrDeclare(output, input);
final int size = input.getNumElements();
for (int i = 0; i < size; i++) {
output.data[i] = alpha/input.data[i];
}
return output;
}
/**
*
* Performs an element by element scalar division with the scalar on botton.
*
* bij = aij /α
*
*
* @param input The matrix whose elements are to be divided. Not modified.
* @param alpha the amount each element is divided by.
* @param output Where the results are stored. Modified. Can be null.
* @return The resulting matrix
*/
public static T divide( T input, float alpha, @Nullable T output ) {
output = UtilEjml.reshapeOrDeclare(output, input);
final int size = input.getNumElements();
for (int i = 0; i < size; i++) {
output.data[i] = input.data[i]/alpha;
}
return output;
}
/**
*
* Changes the sign of every element in the matrix.
*
* aij = -aij
*
*
* @param a A matrix. Modified.
*/
public static void changeSign( FMatrixD1 a ) {
final int size = a.getNumElements();
for (int i = 0; i < size; i++) {
a.data[i] = -a.data[i];
}
}
/**
*
* Changes the sign of every element in the matrix.
*
* outputij = -inputij
*
*
* @param input A matrix. Modified.
*/
public static T changeSign( T input, @Nullable T output ) {
output = UtilEjml.reshapeOrDeclare(output, input);
final int size = input.getNumElements();
for (int i = 0; i < size; i++) {
output.data[i] = -input.data[i];
}
return output;
}
/**
*
* Sets every element in the matrix to the specified value.
*
* aij = value
*
*
* @param a A matrix whose elements are about to be set. Modified.
* @param value The value each element will have.
*/
public static void fill( FMatrixD1 a, float value ) {
Arrays.fill(a.data, 0, a.getNumElements(), value);
}
/**
*
* Puts the augmented system matrix into reduced row echelon form (RREF) using Gauss-Jordan
* elimination with row (partial) pivots. A matrix is said to be in RREF is the following conditions are true:
*
*
*
* - If a row has non-zero entries, then the first non-zero entry is 1. This is known as the leading one.
* - If a column contains a leading one then all other entries in that column are zero.
* - If a row contains a leading 1, then each row above contains a leading 1 further to the left.
*
*
*
* [1] Page 19 in, Otter Bretscherm "Linear Algebra with Applications" Prentice-Hall Inc, 1997
*
*
* @param A Input matrix. Unmodified.
* @param numUnknowns Number of unknowns/columns that are reduced. Set to -1 to default to
* A.numCols, which works for most applications.
* @param reduced Storage for reduced echelon matrix. If null then a new matrix is returned. Modified.
* @return Reduced echelon form of A
* @see RrefGaussJordanRowPivot_FDRM
*/
public static FMatrixRMaj rref( FMatrixRMaj A, int numUnknowns, @Nullable FMatrixRMaj reduced ) {
reduced = UtilEjml.reshapeOrDeclare(reduced, A);
if (numUnknowns <= 0)
numUnknowns = A.numCols;
ReducedRowEchelonForm_F32 alg = new RrefGaussJordanRowPivot_FDRM();
alg.setTolerance(elementMaxAbs(A)*UtilEjml.F_EPS*Math.max(A.numRows, A.numCols));
reduced.setTo(A);
alg.reduce(reduced, numUnknowns);
return reduced;
}
/**
* Applies the > operator to each element in A. Results are stored in a boolean matrix.
*
* @param A Input matrx
* @param value value each element is compared against
* @param output (Optional) Storage for results. Can be null. Is reshaped.
* @return Boolean matrix with results
*/
public static BMatrixRMaj elementLessThan( FMatrixRMaj A, float value, BMatrixRMaj output ) {
output = UtilEjml.reshapeOrDeclare(output, A.numRows, A.numCols);
int N = A.getNumElements();
for (int i = 0; i < N; i++) {
output.data[i] = A.data[i] < value;
}
return output;
}
/**
* Applies the ≥ operator to each element in A. Results are stored in a boolean matrix.
*
* @param A Input matrix
* @param value value each element is compared against
* @param output (Optional) Storage for results. Can be null. Is reshaped.
* @return Boolean matrix with results
*/
public static BMatrixRMaj elementLessThanOrEqual( FMatrixRMaj A, float value, BMatrixRMaj output ) {
output = UtilEjml.reshapeOrDeclare(output, A.numRows, A.numCols);
int N = A.getNumElements();
for (int i = 0; i < N; i++) {
output.data[i] = A.data[i] <= value;
}
return output;
}
/**
* Applies the > operator to each element in A. Results are stored in a boolean matrix.
*
* @param A Input matrix
* @param value value each element is compared against
* @param output (Optional) Storage for results. Can be null. Is reshaped.
* @return Boolean matrix with results
*/
public static BMatrixRMaj elementMoreThan( FMatrixRMaj A, float value, BMatrixRMaj output ) {
output = UtilEjml.reshapeOrDeclare(output, A.numRows, A.numCols);
int N = A.getNumElements();
for (int i = 0; i < N; i++) {
output.data[i] = A.data[i] > value;
}
return output;
}
/**
* Applies the ≥ operator to each element in A. Results are stored in a boolean matrix.
*
* @param A Input matrix
* @param value value each element is compared against
* @param output (Optional) Storage for results. Can be null. Is reshaped.
* @return Boolean matrix with results
*/
public static BMatrixRMaj elementMoreThanOrEqual( FMatrixRMaj A, float value, BMatrixRMaj output ) {
output = UtilEjml.reshapeOrDeclare(output, A.numRows, A.numCols);
int N = A.getNumElements();
for (int i = 0; i < N; i++) {
output.data[i] = A.data[i] >= value;
}
return output;
}
/**
* Applies the < operator to each element in A. Results are stored in a boolean matrix.
*
* @param A Input matrix
* @param B Input matrix
* @param output (Optional) Storage for results. Can be null. Is reshaped.
* @return Boolean matrix with results
*/
public static BMatrixRMaj elementLessThan( FMatrixRMaj A, FMatrixRMaj B, BMatrixRMaj output ) {
output = UtilEjml.reshapeOrDeclare(output, A.numRows, A.numCols);
int N = A.getNumElements();
for (int i = 0; i < N; i++) {
output.data[i] = A.data[i] < B.data[i];
}
return output;
}
/**
* Applies the A ≤ B operator to each element. Results are stored in a boolean matrix.
*
* @param A Input matrix
* @param B Input matrix
* @param output (Optional) Storage for results. Can be null. Is reshaped.
* @return Boolean matrix with results
*/
public static BMatrixRMaj elementLessThanOrEqual( FMatrixRMaj A, FMatrixRMaj B, BMatrixRMaj output ) {
output = UtilEjml.reshapeOrDeclare(output, A.numRows, A.numCols);
int N = A.getNumElements();
for (int i = 0; i < N; i++) {
output.data[i] = A.data[i] <= B.data[i];
}
return output;
}
/**
* Returns a row matrix which contains all the elements in A which are flagged as true in 'marked'
*
* @param A Input matrix
* @param marked Input matrix marking elements in A
* @param output Storage for output row vector. Can be null. Will be reshaped.
* @return Row vector with marked elements
*/
public static FMatrixRMaj elements( FMatrixRMaj A, BMatrixRMaj marked, @Nullable FMatrixRMaj output ) {
checkSameShape(A, marked, false);
if (output == null)
output = new FMatrixRMaj(1, 1);
output.reshape(countTrue(marked), 1);
int N = A.getNumElements();
int index = 0;
for (int i = 0; i < N; i++) {
if (marked.data[i]) {
output.data[index++] = A.data[i];
}
}
return output;
}
/**
* Counts the number of elements in A which are true
*
* @param A input matrix
* @return number of true elements
*/
public static int countTrue( BMatrixRMaj A ) {
int total = 0;
int N = A.getNumElements();
for (int i = 0; i < N; i++) {
if (A.data[i])
total++;
}
return total;
}
/**
* output = [a , b]
*/
public static FMatrixRMaj concatColumns( FMatrixRMaj a, FMatrixRMaj b, @Nullable FMatrixRMaj output ) {
int rows = Math.max(a.numRows, b.numRows);
int cols = a.numCols + b.numCols;
output = reshapeOrDeclare(output,rows,cols);
output.zero();
insert(a, output, 0, 0);
insert(b, output, 0, a.numCols);
return output;
}
/**
* Concatinates all the matrices together along their columns. If the rows do not match the upper elements
* are set to zero.
*
* A = [ m[0] , ... , m[n-1] ]
*
* @param m Set of matrices
* @return Resulting matrix
*/
public static FMatrixRMaj concatColumnsMulti( FMatrixRMaj... m ) {
int rows = 0;
int cols = 0;
for (int i = 0; i < m.length; i++) {
rows = Math.max(rows, m[i].numRows);
cols += m[i].numCols;
}
FMatrixRMaj R = new FMatrixRMaj(rows, cols);
int col = 0;
for (int i = 0; i < m.length; i++) {
insert(m[i], R, 0, col);
col += m[i].numCols;
}
return R;
}
/**
* output = [a ; b]
*/
public static void concatRows( FMatrixRMaj a, FMatrixRMaj b, FMatrixRMaj output ) {
int rows = a.numRows + b.numRows;
int cols = Math.max(a.numCols, b.numCols);
output.reshape(rows, cols);
output.zero();
insert(a, output, 0, 0);
insert(b, output, a.numRows, 0);
}
/**
* Concatinates all the matrices together along their columns. If the rows do not match the upper elements
* are set to zero.
*
* A = [ m[0] ; ... ; m[n-1] ]
*
* @param m Set of matrices
* @return Resulting matrix
*/
public static FMatrixRMaj concatRowsMulti( FMatrixRMaj... m ) {
int rows = 0;
int cols = 0;
for (int i = 0; i < m.length; i++) {
rows += m[i].numRows;
cols = Math.max(cols, m[i].numCols);
}
FMatrixRMaj R = new FMatrixRMaj(rows, cols);
int row = 0;
for (int i = 0; i < m.length; i++) {
insert(m[i], R, row, 0);
row += m[i].numRows;
}
return R;
}
/**
* Applies the row permutation specified by the vector to the input matrix and save the results
* in the output matrix. output[perm[j],:] = input[j,:]
*
* @param pinv (Input) Inverse permutation vector. Specifies new order of the rows.
* @param input (Input) Matrix which is to be permuted
* @param output (Output) Matrix which has the permutation stored in it. Is reshaped.
*/
public static FMatrixRMaj permuteRowInv( int[] pinv, FMatrixRMaj input, FMatrixRMaj output ) {
if (input.numRows > pinv.length)
throw new MatrixDimensionException("permutation vector must have at least as many elements as input has rows");
output = UtilEjml.reshapeOrDeclare(output, input.numRows, input.numCols);
int m = input.numCols;
for (int row = 0; row < input.numRows; row++) {
System.arraycopy(input.data, row*m, output.data, pinv[row]*m, m);
}
return output;
}
/**
* Performs absolute value of a matrix:
*
* c = abs(a)
* cij = abs(aij)
*
*
* @param a A matrix. Not modified.
* @param c A matrix. Modified.
*/
public static void abs( FMatrixD1 a, FMatrixD1 c ) {
c.reshape(a.numRows, a.numCols);
final int length = a.getNumElements();
for (int i = 0; i < length; i++) {
c.data[i] = Math.abs(a.data[i]);
}
}
/**
* Performs absolute value of a matrix:
*
* a = abs(a)
* aij = abs(aij)
*
*
* @param a A matrix. Modified.
*/
public static void abs( FMatrixD1 a ) {
final int length = a.getNumElements();
for (int i = 0; i < length; i++) {
a.data[i] = Math.abs(a.data[i]);
}
}
/**
* Given a symmetric matrix which is represented by a lower triangular matrix convert it back into
* a full symmetric matrix.
*
* @param A (Input) Lower triangular matrix (Output) symmetric matrix
*/
public static void symmLowerToFull( FMatrixRMaj A ) {
if (A.numRows != A.numCols)
throw new MatrixDimensionException("Must be a square matrix");
final int cols = A.numCols;
for (int row = 0; row < A.numRows; row++) {
for (int col = row + 1; col < cols; col++) {
A.data[row*cols + col] = A.data[col*cols + row];
}
}
}
/**
* Given a symmetric matrix which is represented by a lower triangular matrix convert it back into
* a full symmetric matrix.
*
* @param A (Input) Lower triangular matrix (Output) symmetric matrix
*/
public static void symmUpperToFull( FMatrixRMaj A ) {
if (A.numRows != A.numCols)
throw new MatrixDimensionException("Must be a square matrix");
final int cols = A.numCols;
for (int row = 0; row < A.numRows; row++) {
for (int col = 0; col <= row; col++) {
A.data[row*cols + col] = A.data[col*cols + row];
}
}
}
/**
* This applies a given unary function on every value stored in the matrix
*
*
* output[i,j] = func(input[i,j])
*
*
* A and B can be the same instance.
*
* @param input (Input) input matrix. Not modified
* @param func Unary function accepting a float
* @param output (Output) Matrix. Can be same instance as A. Modified.
* @return The output matrix
*/
public static FMatrixRMaj apply( FMatrixRMaj input, FOperatorUnary func, @Nullable FMatrixRMaj output ) {
output = UtilEjml.reshapeOrDeclare(output, input.numRows, input.numCols);
for (int i = 0; i < input.data.length; i++) {
output.data[i] = func.apply(input.data[i]);
}
return output;
}
public static FMatrixRMaj apply( FMatrixRMaj input, FOperatorUnary func ) {
return apply(input, func, input);
}
}