All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.ejml.dense.row.CommonOps_FDRM Maven / Gradle / Ivy

Go to download

A fast and easy to use dense and sparse matrix linear algebra library written in Java.

There is a newer version: 0.43.1
Show newest version
/*
 * Copyright (c) 2009-2019, 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 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 java.util.Arrays;

import static org.ejml.UtilEjml.stringShapes;

/**
 * 

* 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}. *

* @see MatrixMatrixMult_FDRM * @see MatrixVectorMult_FDRM * @see SpecializedOps_FDRM * @see MatrixFeatures_FDRM * * @author Peter Abeles */ @SuppressWarnings({"ForLoopReplaceableByForEach"}) 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 c Where the results of the operation are stored. Modified. */ public static void mult(FMatrix1Row a , FMatrix1Row b , FMatrix1Row c ) { if( b.numCols == 1 ) { MatrixVectorMult_FDRM.mult(a, b, c); } else if( b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ) { MatrixMatrixMult_FDRM.mult_reorder(a,b,c); } else { MatrixMatrixMult_FDRM.mult_small(a,b,c); } } /** *

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 c Where the results of the operation are stored. Modified. */ public static void mult(float alpha , FMatrix1Row a , FMatrix1Row b , FMatrix1Row c ) { // TODO add a matrix vectory multiply here if( b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ) { MatrixMatrixMult_FDRM.mult_reorder(alpha, a, b, c); } else { MatrixMatrixMult_FDRM.mult_small(alpha,a,b,c); } } /** *

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 c Where the results of the operation are stored. Modified. */ public static void multTransA(FMatrix1Row a , FMatrix1Row b , FMatrix1Row c ) { 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,c); } else { MatrixVectorMult_FDRM.multTransA_small(a,b,c); } } else if( a.numCols >= EjmlParameters.MULT_COLUMN_SWITCH || b.numCols >= EjmlParameters.MULT_COLUMN_SWITCH ) { MatrixMatrixMult_FDRM.multTransA_reorder(a, b, c); } else { MatrixMatrixMult_FDRM.multTransA_small(a, b, c); } } /** *

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 c Where the results of the operation are stored. Modified. */ public static void multTransA(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.multTransA_reorder(alpha, a, b, c); } else { MatrixMatrixMult_FDRM.multTransA_small(alpha, a, b, c); } } /** *

* 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 c Where the results of the operation are stored. Modified. */ public static void multTransB(FMatrix1Row a , FMatrix1Row b , FMatrix1Row c ) { if( b.numRows == 1 ) { MatrixVectorMult_FDRM.mult(a, b, c); } else { MatrixMatrixMult_FDRM.multTransB(a, b, c); } } /** *

* 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 c Where the results of the operation are stored. Modified. */ public static void multTransB(float alpha , FMatrix1Row a , FMatrix1Row b , FMatrix1Row c ) { // TODO add a matrix vectory multiply here MatrixMatrixMult_FDRM.multTransB(alpha,a,b,c); } /** *

* 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 c Where the results of the operation are stored. Modified. */ public static void multTransAB(FMatrix1Row a , FMatrix1Row b , FMatrix1Row c ) { 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,c); } else { MatrixVectorMult_FDRM.multTransA_small(a,b,c); } } else if( a.numCols >= EjmlParameters.MULT_TRANAB_COLUMN_SWITCH ) { MatrixMatrixMult_FDRM.multTransAB_aux(a, b, c, null); } else { MatrixMatrixMult_FDRM.multTransAB(a, b, c); } } /** *

* 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 c Where the results of the operation are stored. Modified. */ public static void multTransAB(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.multTransAB_aux(alpha, a, b, c, null); } else { MatrixMatrixMult_FDRM.multTransAB(alpha, a, b, c); } } /** *

* 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 c Where the results of the operation are stored. Modified. */ public static void multInner(FMatrix1Row a , FMatrix1Row c ) { c.reshape(a.numCols,a.numCols); if( a.numCols >= EjmlParameters.MULT_INNER_SWITCH ) { MatrixMultProduct_FDRM.inner_small(a, c); } else { MatrixMultProduct_FDRM.inner_reorder(a, c); } } /** *

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 c Where the results of the operation are stored. Modified. */ public static void multOuter(FMatrix1Row a , FMatrix1Row c ) { c.reshape(a.numRows,a.numRows); MatrixMultProduct_FDRM.outer(a, c); } /** *

* 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( b.numRows == 1 ) { // there are significantly faster algorithms when dealing with vectors 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_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 *

* * @see UnrolledCholesky_FDRM * @see LinearSolverFactory_FDRM * * @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. */ 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.set(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.set(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, FMatrixRMaj A_tran) { if( A_tran == null ) { A_tran = new FMatrixRMaj(A.numCols,A.numRows); } else { if( A.numRows != A_tran.numCols || A.numCols != A_tran.numRows ) { throw new MatrixDimensionException("Incompatible matrix dimensions"); } } 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. * * @see UnrolledCholesky_FDRM * @see LinearSolverFactory_FDRM#chol(int) * * @param mat (Input) SPD matrix * @param result (Output) Inverted matrix. * @return true if it could invert the matrix false if it could not. */ 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. * @param v * @return An array of vectors. */ public static FMatrixRMaj[] columnsToVector(FMatrixRMaj A, 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. * @param v * @return An array of vectors. */ public static FMatrixRMaj[] rowsToVector(FMatrixRMaj A, 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. * * @see #identity(int) * * @param mat A square matrix. */ 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
*

* * @see #diagR * * @param diagEl Contains the values of the diagonal elements of the resulting matrix. * @return A new matrix. */ public static FMatrixRMaj diag(float ...diagEl ) { return diag(null,diagEl.length,diagEl); } /** * @see #diag(float...) */ public static FMatrixRMaj diag(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
*

* * @see #diag * * @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. */ 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. Modified. */ public static void kron(FMatrixRMaj A , FMatrixRMaj B , FMatrixRMaj C ) { int numColsC = A.numCols*B.numCols; int numRowsC = A.numRows*B.numRows; if( C.numCols != numColsC || C.numRows != numRowsC) { throw new MatrixDimensionException("C does not have the expected dimensions"); } // 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.set(i*B.numRows+rowB,j*B.numCols+colB,val); } } } } } /** *

* 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 void extract( FMatrixRMaj src, int rows[] , int rowsSize , int cols[] , int colsSize , FMatrixRMaj dst ) { if( rowsSize != dst.numRows || colsSize != dst.numCols ) throw new MatrixDimensionException("Unexpected number of rows and/or columns in dst matrix"); 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]]; } } } /** * 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 void extract(FMatrixRMaj src, int indexes[] , int length , FMatrixRMaj dst ) { if( !MatrixFeatures_FDRM.isVector(dst)) throw new MatrixDimensionException("Dst must be a vector"); if( length != dst.getNumElements()) throw new MatrixDimensionException("Unexpected number of elements in dst vector"); for (int i = 0; i < length; i++) { dst.data[i] = src.data[indexes[i]]; } } /** * 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 ) { if( rowsSize != src.numRows || colsSize != src.numCols ) throw new MatrixDimensionException("Unexpected number of rows and/or columns in dst matrix"); 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 void extractDiag(FMatrixRMaj src, FMatrixRMaj dst ) { int N = Math.min(src.numRows, src.numCols); 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) ); } } /** * 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 , FMatrixRMaj out ) { if( out == null) out = new FMatrixRMaj(1,a.numCols); else if( !MatrixFeatures_FDRM.isVector(out) || out.getNumElements() != a.numCols ) throw new MatrixDimensionException("Output must be a vector of length "+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 , FMatrixRMaj out ) { if( out == null) out = new FMatrixRMaj(a.numRows,1); else if( !MatrixFeatures_FDRM.isVector(out) || out.getNumElements() != a.numRows ) throw new MatrixDimensionException("Output must be a vector of length "+a.numRows); 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 ) { if( col1 < col0 ) { throw new IllegalArgumentException("col1 must be >= col0"); } else if( col0 >= A.numCols || col1 >= A.numCols ) { throw new IllegalArgumentException("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 ) { final int size = a.getNumElements(); float max = a.get(0); for( int i = 1; i < size; i++ ) { float val = a.get(i); if( val >= max ) { max = val; } } return max; } /** *

* 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 ) { final int size = a.getNumElements(); float max = 0; for( int i = 0; i < size; i++ ) { float val = Math.abs(a.get(i)); if( val > max ) { max = val; } } return max; } /** *

* 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 ) { final int size = a.getNumElements(); float min = a.get(0); for( int i = 1; i < size; i++ ) { float val = a.get(i); if( val < min ) { min = val; } } return min; } /** *

* 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 ) { final int size = a.getNumElements(); float min = Float.MAX_VALUE; for( int i = 0; i < size; i++ ) { float val = Math.abs(a.get(i)); if( val < min ) { min = val; } } return min; } /** *

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 ) { if( a.numCols != b.numCols || a.numRows != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { a.times(i, b.get(i)); } } /** *

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 c Where the results of the operation are stored. Modified. */ public static void elementMult(FMatrixD1 a , FMatrixD1 b , FMatrixD1 c ) { if( a.numCols != b.numCols || a.numRows != b.numRows || a.numRows != c.numRows || a.numCols != c.numCols ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.set(i, a.get(i) * b.get(i)); } } /** *

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 ) { if( a.numCols != b.numCols || a.numRows != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { a.div(i, b.get(i)); } } /** *

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 c Where the results of the operation are stored. Modified. */ public static void elementDiv(FMatrixD1 a , FMatrixD1 b , FMatrixD1 c ) { if( a.numCols != b.numCols || a.numRows != b.numRows || a.numRows != c.numRows || a.numCols != c.numCols ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.set(i, a.get(i) / b.get(i)); } } /** *

* 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 ) { float total = 0; int size = mat.getNumElements(); for( int i = 0; i < size; i++ ) { total += mat.get(i); } return total; } /** *

* 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 ) { float total = 0; int size = mat.getNumElements(); for( int i = 0; i < size; i++ ) { total += Math.abs(mat.get(i)); } return total; } /** *

* Element-wise power operation
* cij = aij ^ bij *

* * @param A left side * @param B right side * @param C output (modified) */ public static void elementPower(FMatrixD1 A , FMatrixD1 B , FMatrixD1 C ) { if( A.numRows != B.numRows || A.numRows != C.numRows || A.numCols != B.numCols || A.numCols != C.numCols ) { throw new MatrixDimensionException("All matrices must be the same shape"); } int size = A.getNumElements(); for( int i = 0; i < size; i++ ) { C.data[i] = (float)Math.pow(A.data[i], B.data[i]); } } /** *

* Element-wise power operation
* cij = a ^ bij *

* * @param a left scalar * @param B right side * @param C output (modified) */ public static void elementPower(float a , FMatrixD1 B , FMatrixD1 C ) { if( B.numRows != C.numRows || B.numCols != C.numCols ) { throw new MatrixDimensionException("All matrices must be the same shape"); } int size = B.getNumElements(); for( int i = 0; i < size; i++ ) { C.data[i] = (float)Math.pow(a, B.data[i]); } } /** *

* Element-wise power operation
* cij = aij ^ b *

* * @param A left side * @param b right scalar * @param C output (modified) */ public static void elementPower(FMatrixD1 A , float b, FMatrixD1 C ) { if( A.numRows != C.numRows || A.numCols != C.numCols ) { throw new MatrixDimensionException("All matrices must be the same shape"); } int size = A.getNumElements(); for( int i = 0; i < size; i++ ) { C.data[i] = (float)Math.pow(A.data[i], b); } } /** *

* Element-wise log operation
* cij = (float)Math.log(aij) *

* * @param A input * @param C output (modified) */ public static void elementLog(FMatrixD1 A , FMatrixD1 C ) { if( A.numCols != C.numCols || A.numRows != C.numRows ) { throw new MatrixDimensionException("All matrices must be the same shape"); } int size = A.getNumElements(); for( int i = 0; i < size; i++ ) { C.data[i] = (float)Math.log(A.data[i]); } } /** *

* Element-wise exp operation
* cij = (float)Math.log(aij) *

* * @param A input * @param C output (modified) */ public static void elementExp(FMatrixD1 A , FMatrixD1 C ) { if( A.numCols != C.numCols || A.numRows != C.numRows ) { throw new MatrixDimensionException("All matrices must be the same shape"); } int size = A.getNumElements(); for( int i = 0; i < size; i++ ) { C.data[i] = (float)Math.exp(A.data[i]); } } /** * 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 , FMatrixRMaj output ) { if( output == null ) { output = new FMatrixRMaj(input.numRows,1); } else { output.reshape(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 , FMatrixRMaj output ) { if( output == null ) { output = new FMatrixRMaj(input.numRows,1); } else { output.reshape(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 , FMatrixRMaj output ) { if( output == null ) { output = new FMatrixRMaj(input.numRows,1); } else { output.reshape(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 = 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 sum of each column */ public static FMatrixRMaj sumCols(FMatrixRMaj input , FMatrixRMaj output ) { if( output == null ) { output = new FMatrixRMaj(1,input.numCols); } else { output.reshape(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 , FMatrixRMaj output ) { if( output == null ) { output = new FMatrixRMaj(1,input.numCols); } else { output.reshape(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 , FMatrixRMaj output ) { if( output == null ) { output = new FMatrixRMaj(1,input.numCols); } else { output.reshape(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 A Matrix. Modified. * @param b A Matrix. Not modified. */ public static void addEquals(FMatrixD1 a , FMatrixD1 b ) { if( a.numCols != b.numCols || a.numRows != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } 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 A Matrix. Modified. * @param b A Matrix. Not modified. */ public static void addEquals(FMatrixD1 a , float beta, FMatrixD1 b ) { if( a.numCols != b.numCols || a.numRows != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } 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 c A Matrix where the results are stored. Modified. */ public static void add(final FMatrixD1 a , final FMatrixD1 b , final FMatrixD1 c ) { if( a.numCols != b.numCols || a.numRows != b.numRows ) { throw new MatrixDimensionException("The matrices are not all the same dimension."); } c.reshape(a.numRows,a.numCols); final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.set(i, a.get(i) + 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 beta Scaling factor for matrix b. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void add(FMatrixD1 a , float beta , FMatrixD1 b , FMatrixD1 c ) { if( a.numCols != b.numCols || a.numRows != b.numRows ) { throw new MatrixDimensionException("The matrices are not all the same dimension."); } c.reshape(a.numRows,a.numCols); final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.set(i, a.get(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 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 c A Matrix where the results are stored. Modified. */ public static void add(float alpha , FMatrixD1 a , float beta , FMatrixD1 b , FMatrixD1 c ) { if( a.numCols != b.numCols || a.numRows != b.numRows ) { throw new MatrixDimensionException("The matrices are not all the same dimension."); } c.reshape(a.numRows,a.numCols); final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.set(i, alpha * a.get(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 alpha A scaling factor for matrix a. * @param a A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix where the results are stored. Modified. */ public static void add(float alpha , FMatrixD1 a , FMatrixD1 b , FMatrixD1 c ) { if( a.numCols != b.numCols || a.numRows != b.numRows ) { throw new MatrixDimensionException("The matrices are not all the same dimension."); } c.reshape(a.numRows,a.numCols); final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.set(i, alpha * a.get(i) + b.get(i)); } } /** *

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 c A matrix. Modified. * @param val The value that's added to each element. */ public static void add(FMatrixD1 a , float val , FMatrixD1 c ) { c.reshape(a.numRows,a.numCols); final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.data[i] = a.data[i] + val; } } /** *

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 c (Output) A matrix. Modified. */ public static void subtract(FMatrixD1 a , float val , FMatrixD1 c ) { c.reshape(a.numRows,a.numCols); final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.data[i] = a.data[i] - val; } } /** *

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 c (Output) A matrix. Modified. */ public static void subtract(float val , 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] = val - a.data[i]; } } /** *

Performs the following subtraction operation:
*
* a = a - b
* aij = aij - bij *

* * @param a A Matrix. Modified. * @param b A Matrix. Not modified. */ public static void subtractEquals(FMatrixD1 a, FMatrixD1 b) { if( a.numCols != b.numCols || a.numRows != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } 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 A Matrix. Not modified. * @param b A Matrix. Not modified. * @param c A Matrix. Modified. */ public static void subtract(FMatrixD1 a, FMatrixD1 b, FMatrixD1 c) { if( a.numCols != b.numCols || a.numRows != b.numRows ) { throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions"); } c.reshape(a.numRows,a.numCols); final int length = a.getNumElements(); for( int i = 0; i < length; i++ ) { c.data[i] = a.data[i] - b.data[i]; } } /** *

* 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 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 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 a The matrix whose elements are the divisor. Not modified. * @param b Where the results are stored. Modified. */ public static void divide(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] = alpha/a.data[i]; } } /** *

* Performs an element by element scalar division with the scalar on botton.
*
* bij = aij /α *

* * @param a The matrix whose elements are to be divided. Not modified. * @param alpha the amount each element is divided by. * @param b Where the results are stored. Modified. */ public static void divide(FMatrixD1 a , float alpha , 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; } } /** *

* 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 void changeSign(FMatrixD1 input , FMatrixD1 output) { output.reshape(input.numRows,input.numCols); final int size = input.getNumElements(); for( int i = 0; i < size; i++ ) { output.data[i] = -input.data[i]; } } /** *

* 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: *

* *
    *
  1. If a row has non-zero entries, then the first non-zero entry is 1. This is known as the leading one.
  2. *
  3. If a column contains a leading one then all other entries in that column are zero.
  4. *
  5. If a row contains a leading 1, then each row above contains a leading 1 further to the left.
  6. *
* *

* [1] Page 19 in, Otter Bretscherm "Linear Algebra with Applications" Prentice-Hall Inc, 1997 *

* * @see RrefGaussJordanRowPivot_FDRM * * @param A Input matrix. Unmodified. * @param numUnknowns Number of unknowns/columns that are reduced. Set to -1 to default to * Math.min(A.numRows,A.numCols), which works for most systems. * @param reduced Storage for reduced echelon matrix. If null then a new matrix is returned. Modified. * @return Reduced echelon form of A */ public static FMatrixRMaj rref(FMatrixRMaj A , int numUnknowns, FMatrixRMaj reduced ) { if( reduced == null ) { reduced = new FMatrixRMaj(A.numRows,A.numCols); } reduced.reshape(A.numRows,A.numCols); if( numUnknowns <= 0 ) numUnknowns = Math.min(A.numCols,A.numRows); ReducedRowEchelonForm_F32 alg = new RrefGaussJordanRowPivot_FDRM(); alg.setTolerance(elementMaxAbs(A)* UtilEjml.F_EPS*Math.max(A.numRows,A.numCols)); reduced.set(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 ) { if( output == null ) { output = new BMatrixRMaj(A.numRows,A.numCols); } output.reshape(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 ) { if( output == null ) { output = new BMatrixRMaj(A.numRows,A.numCols); } output.reshape(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 ) { if( output == null ) { output = new BMatrixRMaj(A.numRows,A.numCols); } output.reshape(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 ) { if( output == null ) { output = new BMatrixRMaj(A.numRows,A.numCols); } output.reshape(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 ) { if( output == null ) { output = new BMatrixRMaj(A.numRows,A.numCols); } output.reshape(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 ) { if( output == null ) { output = new BMatrixRMaj(A.numRows,A.numCols); } output.reshape(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 , FMatrixRMaj output ) { if( A.numRows != marked.numRows || A.numCols != marked.numCols ) throw new MatrixDimensionException("Input matrices must have the same shape"); 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 void concatColumns(FMatrixRMaj a , FMatrixRMaj b , FMatrixRMaj output ) { int rows = Math.max(a.numRows , b.numRows); int cols = a.numCols + b.numCols; output.reshape(rows,cols); output.zero(); insert(a,output,0,0); insert(b,output,0,a.numCols); } /** *

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"); if( output == null ) output = new FMatrixRMaj(1,1); output.reshape(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]; } } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy