org.ejml.dense.block.MatrixOps_FDRB Maven / Gradle / Ivy
Show all versions of ejml-fdense Show documentation
/*
* Copyright (c) 2020, 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.block;
import javax.annotation.Generated;
import org.ejml.EjmlParameters;
import org.ejml.UtilEjml;
import org.ejml.data.FGrowArray;
import org.ejml.data.FMatrixRBlock;
import org.ejml.data.FMatrixRMaj;
import org.ejml.data.FSubmatrixD1;
import org.ejml.dense.row.CommonOps_FDRM;
import org.ejml.dense.row.MatrixFeatures_FDRM;
import org.ejml.dense.row.RandomMatrices_FDRM;
import org.ejml.ops.FConvertMatrixStruct;
import org.jetbrains.annotations.Nullable;
import java.util.Random;
//CONCURRENT_MACRO MatrixMult_FDRB MatrixMult_MT_FDRB
/**
* Various operations on {@link FMatrixRBlock}.
*
* @author Peter Abeles
*/
@Generated("org.ejml.dense.block.MatrixOps_DDRB")
public class MatrixOps_FDRB {
//CONCURRENT_OMIT_BEGIN
/**
* Converts a row major matrix into a row major block matrix.
*
* @param src Original FMatrixRMaj. Not modified.
* @param dst Equivalent FMatrixRBlock. Modified.
*/
public static void convert( FMatrixRMaj src, FMatrixRBlock dst ) {
FConvertMatrixStruct.convert(src, dst);
}
/**
* Converts a row major matrix into a row major block matrix. Both matrices will contain
* the same data array. Useful when you wish to avoid declaring two large matrices.
*
* @param src Original FMatrixRMaj. Modified.
* @param dst Equivalent FMatrixRBlock. Modified.
*/
public static FMatrixRBlock convertInplace( FMatrixRMaj src, @Nullable FMatrixRBlock dst,
@Nullable FGrowArray workspace ) {
if (dst == null)
dst = new FMatrixRBlock();
dst.data = src.data;
dst.blockLength = EjmlParameters.BLOCK_WIDTH;
dst.numRows = src.numRows;
dst.numCols = src.numCols;
convertRowToBlock(src.numRows, src.numCols, dst.blockLength, src.data, workspace);
return dst;
}
/**
*
* Converts matrix data stored is a row major format into a block row major format in place.
*
*
* @param numRows number of rows in the matrix.
* @param numCols number of columns in the matrix.
* @param blockLength Block size in the converted matrix.
* @param data Matrix data in a row-major format. Modified.
* @param workspace Optional internal workspace. Nullable.
*/
public static void convertRowToBlock( int numRows, int numCols, int blockLength,
float[] data, @Nullable FGrowArray workspace ) {
int minLength = Math.min(blockLength, numRows)*numCols;
float[] tmp = UtilEjml.adjust(workspace, minLength);
for (int i = 0; i < numRows; i += blockLength) {
int blockHeight = Math.min(blockLength, numRows - i);
System.arraycopy(data, i*numCols, tmp, 0, blockHeight*numCols);
for (int j = 0; j < numCols; j += blockLength) {
int blockWidth = Math.min(blockLength, numCols - j);
int indexDst = i*numCols + blockHeight*j;
int indexSrcRow = j;
for (int k = 0; k < blockHeight; k++) {
System.arraycopy(tmp, indexSrcRow, data, indexDst, blockWidth);
indexDst += blockWidth;
indexSrcRow += numCols;
}
}
}
}
/**
* Converts a row major block matrix into a row major matrix.
*
* @param src Original FMatrixRBlock.. Not modified.
* @param dst Equivalent FMatrixRMaj. Modified.
*/
public static FMatrixRMaj convert( FMatrixRBlock src, FMatrixRMaj dst ) {
return FConvertMatrixStruct.convert(src, dst);
}
/**
* Converts a row major block matrix into a row major matrix. Both matrices will contain
* the same data array. Useful when you wish to avoid declaring two large matrices.
*
* @param src Original FMatrixRBlock. Modified.
* @param dst Equivalent FMatrixRMaj. Modified.
*/
public static FMatrixRMaj convertInplace( FMatrixRBlock src, @Nullable FMatrixRMaj dst,
@Nullable FGrowArray workspace ) {
if (dst == null)
dst = new FMatrixRMaj();
dst.data = src.data;
dst.numRows = src.numRows;
dst.numCols = src.numCols;
convertBlockToRow(src.numRows, src.numCols, src.blockLength, src.data, workspace);
return dst;
}
/**
*
* Converts matrix data stored is a block row major format into a row major format in place.
*
*
* @param numRows number of rows in the matrix.
* @param numCols number of columns in the matrix.
* @param blockLength Block size in the converted matrix.
* @param data Matrix data in a block row-major format. Modified.
* @param workspace Optional internal workspace. Nullable.
*/
public static void convertBlockToRow( int numRows, int numCols, int blockLength,
float[] data, @Nullable FGrowArray workspace ) {
int minLength = Math.min(blockLength, numRows)*numCols;
float[] tmp = UtilEjml.adjust(workspace, minLength);
for (int i = 0; i < numRows; i += blockLength) {
int blockHeight = Math.min(blockLength, numRows - i);
System.arraycopy(data, i*numCols, tmp, 0, blockHeight*numCols);
for (int j = 0; j < numCols; j += blockLength) {
int blockWidth = Math.min(blockLength, numCols - j);
int indexSrc = blockHeight*j;
int indexDstRow = i*numCols + j;
for (int k = 0; k < blockHeight; k++) {
System.arraycopy(tmp, indexSrc, data, indexDstRow, blockWidth);
indexSrc += blockWidth;
indexDstRow += numCols;
}
}
}
}
/**
* Converts the transpose of a row major matrix into a row major block matrix.
*
* @param src Original FMatrixRMaj. Not modified.
* @param dst Equivalent FMatrixRBlock. Modified.
*/
public static void convertTranSrc( FMatrixRMaj src, FMatrixRBlock dst ) {
if (src.numRows != dst.numCols || src.numCols != dst.numRows)
throw new IllegalArgumentException("Incompatible matrix shapes.");
for (int i = 0; i < dst.numRows; i += dst.blockLength) {
int blockHeight = Math.min(dst.blockLength, dst.numRows - i);
for (int j = 0; j < dst.numCols; j += dst.blockLength) {
int blockWidth = Math.min(dst.blockLength, dst.numCols - j);
int indexDst = i*dst.numCols + blockHeight*j;
int indexSrc = j*src.numCols + i;
for (int l = 0; l < blockWidth; l++) {
int rowSrc = indexSrc + l*src.numCols;
int rowDst = indexDst + l;
for (int k = 0; k < blockHeight; k++, rowDst += blockWidth) {
dst.data[rowDst] = src.data[rowSrc++];
}
}
}
}
}
//CONCURRENT_OMIT_END
// This can be speed up by inlining the multBlock* calls, reducing number of multiplications
// and other stuff. doesn't seem to have any speed advantage over mult_reorder()
public static void mult( FMatrixRBlock A, FMatrixRBlock B, FMatrixRBlock C ) {
if (A.numCols != B.numRows)
throw new IllegalArgumentException("Columns in A are incompatible with rows in B");
if (A.numRows != C.numRows)
throw new IllegalArgumentException("Rows in A are incompatible with rows in C");
if (B.numCols != C.numCols)
throw new IllegalArgumentException("Columns in B are incompatible with columns in C");
if (A.blockLength != B.blockLength || A.blockLength != C.blockLength)
throw new IllegalArgumentException("Block lengths are not all the same.");
final int blockLength = A.blockLength;
FSubmatrixD1 Asub = new FSubmatrixD1(A, 0, A.numRows, 0, A.numCols);
FSubmatrixD1 Bsub = new FSubmatrixD1(B, 0, B.numRows, 0, B.numCols);
FSubmatrixD1 Csub = new FSubmatrixD1(C, 0, C.numRows, 0, C.numCols);
MatrixMult_FDRB.mult(blockLength, Asub, Bsub, Csub);
}
public static void multTransA( FMatrixRBlock A, FMatrixRBlock B, FMatrixRBlock C ) {
if (A.numRows != B.numRows)
throw new IllegalArgumentException("Rows in A are incompatible with rows in B");
if (A.numCols != C.numRows)
throw new IllegalArgumentException("Columns in A are incompatible with rows in C");
if (B.numCols != C.numCols)
throw new IllegalArgumentException("Columns in B are incompatible with columns in C");
if (A.blockLength != B.blockLength || A.blockLength != C.blockLength)
throw new IllegalArgumentException("Block lengths are not all the same.");
final int blockLength = A.blockLength;
FSubmatrixD1 Asub = new FSubmatrixD1(A, 0, A.numRows, 0, A.numCols);
FSubmatrixD1 Bsub = new FSubmatrixD1(B, 0, B.numRows, 0, B.numCols);
FSubmatrixD1 Csub = new FSubmatrixD1(C, 0, C.numRows, 0, C.numCols);
MatrixMult_FDRB.multTransA(blockLength, Asub, Bsub, Csub);
}
public static void multTransB( FMatrixRBlock A, FMatrixRBlock B, FMatrixRBlock C ) {
if (A.numCols != B.numCols)
throw new IllegalArgumentException("Columns in A are incompatible with columns in B");
if (A.numRows != C.numRows)
throw new IllegalArgumentException("Rows in A are incompatible with rows in C");
if (B.numRows != C.numCols)
throw new IllegalArgumentException("Rows in B are incompatible with columns in C");
if (A.blockLength != B.blockLength || A.blockLength != C.blockLength)
throw new IllegalArgumentException("Block lengths are not all the same.");
final int blockLength = A.blockLength;
FSubmatrixD1 Asub = new FSubmatrixD1(A, 0, A.numRows, 0, A.numCols);
FSubmatrixD1 Bsub = new FSubmatrixD1(B, 0, B.numRows, 0, B.numCols);
FSubmatrixD1 Csub = new FSubmatrixD1(C, 0, C.numRows, 0, C.numCols);
MatrixMult_FDRB.multTransB(blockLength, Asub, Bsub, Csub);
}
//CONCURRENT_OMIT_BEGIN
/**
* Transposes a block matrix.
*
* @param A Original matrix. Not modified.
* @param A_tran Transposed matrix. Modified.
*/
public static FMatrixRBlock transpose( FMatrixRBlock A, @Nullable FMatrixRBlock A_tran ) {
if (A_tran != null) {
if (A.numRows != A_tran.numCols || A.numCols != A_tran.numRows)
throw new IllegalArgumentException("Incompatible dimensions.");
if (A.blockLength != A_tran.blockLength)
throw new IllegalArgumentException("Incompatible block size.");
} else {
A_tran = new FMatrixRBlock(A.numCols, A.numRows, A.blockLength);
}
for (int i = 0; i < A.numRows; i += A.blockLength) {
int blockHeight = Math.min(A.blockLength, A.numRows - i);
for (int j = 0; j < A.numCols; j += A.blockLength) {
int blockWidth = Math.min(A.blockLength, A.numCols - j);
int indexA = i*A.numCols + blockHeight*j;
int indexC = j*A_tran.numCols + blockWidth*i;
transposeBlock(A, A_tran, indexA, indexC, blockWidth, blockHeight);
}
}
return A_tran;
}
/**
* Transposes an individual block inside a block matrix.
*/
private static void transposeBlock( FMatrixRBlock A, FMatrixRBlock A_tran,
int indexA, int indexC,
int width, int height ) {
for (int i = 0; i < height; i++) {
int rowIndexC = indexC + i;
int rowIndexA = indexA + width*i;
int end = rowIndexA + width;
for (; rowIndexA < end; rowIndexC += height, rowIndexA++) {
A_tran.data[rowIndexC] = A.data[rowIndexA];
}
}
}
public static FMatrixRBlock createRandom( int numRows, int numCols,
float min, float max, Random rand ) {
FMatrixRBlock ret = new FMatrixRBlock(numRows, numCols);
RandomMatrices_FDRM.fillUniform(ret, min, max, rand);
return ret;
}
public static FMatrixRBlock createRandom( int numRows, int numCols,
float min, float max, Random rand,
int blockLength ) {
FMatrixRBlock ret = new FMatrixRBlock(numRows, numCols, blockLength);
RandomMatrices_FDRM.fillUniform(ret, min, max, rand);
return ret;
}
public static FMatrixRBlock convert( FMatrixRMaj A, int blockLength ) {
FMatrixRBlock ret = new FMatrixRBlock(A.numRows, A.numCols, blockLength);
convert(A, ret);
return ret;
}
public static FMatrixRBlock convert( FMatrixRMaj A ) {
FMatrixRBlock ret = new FMatrixRBlock(A.numRows, A.numCols);
convert(A, ret);
return ret;
}
public static boolean isEquals( FMatrixRBlock A, FMatrixRBlock B ) {
if (A.blockLength != B.blockLength)
return false;
return MatrixFeatures_FDRM.isEquals(A, B);
}
public static boolean isEquals( FMatrixRBlock A, FMatrixRBlock B, float tol ) {
if (A.blockLength != B.blockLength)
return false;
return MatrixFeatures_FDRM.isEquals(A, B, tol);
}
/**
* Sets either the upper or low triangle of a matrix to zero
*/
public static void zeroTriangle( boolean upper, FMatrixRBlock A ) {
int blockLength = A.blockLength;
if (upper) {
for (int i = 0; i < A.numRows; i += blockLength) {
int h = Math.min(blockLength, A.numRows - i);
for (int j = i; j < A.numCols; j += blockLength) {
int w = Math.min(blockLength, A.numCols - j);
int index = i*A.numCols + h*j;
if (j == i) {
for (int k = 0; k < h; k++) {
for (int l = k + 1; l < w; l++) {
A.data[index + w*k + l] = 0;
}
}
} else {
for (int k = 0; k < h; k++) {
for (int l = 0; l < w; l++) {
A.data[index + w*k + l] = 0;
}
}
}
}
}
} else {
for (int i = 0; i < A.numRows; i += blockLength) {
int h = Math.min(blockLength, A.numRows - i);
for (int j = 0; j <= i; j += blockLength) {
int w = Math.min(blockLength, A.numCols - j);
int index = i*A.numCols + h*j;
if (j == i) {
for (int k = 0; k < h; k++) {
int z = Math.min(k, w);
for (int l = 0; l < z; l++) {
A.data[index + w*k + l] = 0;
}
}
} else {
for (int k = 0; k < h; k++) {
for (int l = 0; l < w; l++) {
A.data[index + w*k + l] = 0;
}
}
}
}
}
}
}
/**
* Copies either the upper or lower triangular portion of src into dst. Dst can be smaller
* than src.
*
* @param upper If the upper or lower triangle is copied.
* @param src The source matrix. Not modified.
* @param dst The destination matrix. Modified.
*/
public static void copyTriangle( boolean upper, FMatrixRBlock src, FMatrixRBlock dst ) {
if (src.blockLength != dst.blockLength)
throw new IllegalArgumentException("Block size is different");
if (src.numRows < dst.numRows)
throw new IllegalArgumentException("The src has fewer rows than dst");
if (src.numCols < dst.numCols)
throw new IllegalArgumentException("The src has fewer columns than dst");
int blockLength = src.blockLength;
int numRows = Math.min(src.numRows, dst.numRows);
int numCols = Math.min(src.numCols, dst.numCols);
if (upper) {
for (int i = 0; i < numRows; i += blockLength) {
int heightSrc = Math.min(blockLength, src.numRows - i);
int heightDst = Math.min(blockLength, dst.numRows - i);
for (int j = i; j < numCols; j += blockLength) {
int widthSrc = Math.min(blockLength, src.numCols - j);
int widthDst = Math.min(blockLength, dst.numCols - j);
int indexSrc = i*src.numCols + heightSrc*j;
int indexDst = i*dst.numCols + heightDst*j;
if (j == i) {
for (int k = 0; k < heightDst; k++) {
for (int l = k; l < widthDst; l++) {
dst.data[indexDst + widthDst*k + l] = src.data[indexSrc + widthSrc*k + l];
}
}
} else {
for (int k = 0; k < heightDst; k++) {
System.arraycopy(src.data, indexSrc + widthSrc*k, dst.data, indexDst + widthDst*k, widthDst);
}
}
}
}
} else {
for (int i = 0; i < numRows; i += blockLength) {
int heightSrc = Math.min(blockLength, src.numRows - i);
int heightDst = Math.min(blockLength, dst.numRows - i);
for (int j = 0; j <= i; j += blockLength) {
int widthSrc = Math.min(blockLength, src.numCols - j);
int widthDst = Math.min(blockLength, dst.numCols - j);
int indexSrc = i*src.numCols + heightSrc*j;
int indexDst = i*dst.numCols + heightDst*j;
if (j == i) {
for (int k = 0; k < heightDst; k++) {
int z = Math.min(k + 1, widthDst);
for (int l = 0; l < z; l++) {
dst.data[indexDst + widthDst*k + l] = src.data[indexSrc + widthSrc*k + l];
}
}
} else {
for (int k = 0; k < heightDst; k++) {
System.arraycopy(src.data, indexSrc + widthSrc*k, dst.data, indexDst + widthDst*k, widthDst);
}
}
}
}
}
}
/**
*
* 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 set( FMatrixRBlock A, float value ) {
CommonOps_FDRM.fill(A, value);
}
/**
*
Sets the value of A to all zeros except along the diagonal.
*
* @param A Block matrix.
*/
public static void setIdentity( FMatrixRBlock A ) {
int minLength = Math.min(A.numRows, A.numCols);
CommonOps_FDRM.fill(A, 0);
int blockLength = A.blockLength;
for (int i = 0; i < minLength; i += blockLength) {
int h = Math.min(blockLength, A.numRows - i);
int w = Math.min(blockLength, A.numCols - i);
int index = i*A.numCols + h*i;
int m = Math.min(h, w);
for (int k = 0; k < m; k++) {
A.data[index + k*w + k] = 1;
}
}
}
/**
*
* Returns a new matrix with ones along the diagonal and zeros everywhere else.
*
*
* @param numRows Number of rows.
* @param numCols NUmber of columns.
* @param blockLength Block length.
* @return An identify matrix.
*/
public static FMatrixRBlock identity( int numRows, int numCols, int blockLength ) {
FMatrixRBlock A = new FMatrixRBlock(numRows, numCols, blockLength);
int minLength = Math.min(numRows, numCols);
for (int i = 0; i < minLength; i += blockLength) {
int h = Math.min(blockLength, A.numRows - i);
int w = Math.min(blockLength, A.numCols - i);
int index = i*A.numCols + h*i;
int m = Math.min(h, w);
for (int k = 0; k < m; k++) {
A.data[index + k*w + k] = 1;
}
}
return A;
}
/**
*
* Checks to see if the two matrices have an identical shape an block size.
*
*
* @param A Matrix.
* @param B Matrix.
*/
public static void checkIdenticalShape( FMatrixRBlock A, FMatrixRBlock B ) {
if (A.blockLength != B.blockLength)
throw new IllegalArgumentException("Block size is different");
if (A.numRows != B.numRows)
throw new IllegalArgumentException("Number of rows is different");
if (A.numCols != B.numCols)
throw new IllegalArgumentException("NUmber of columns is different");
}
/**
*
* Extracts a matrix from src into dst. The submatrix which is copied has its initial coordinate
* at (0,0) and ends at (dst.numRows,dst.numCols). The end rows/columns must be aligned along blocks
* or else it will silently screw things up.
*
*
* @param src Matrix which a submatrix is being extracted from. Not modified.
* @param dst Where the submatrix is written to. Its rows and columns be less than or equal to 'src'. Modified.
*/
public static void extractAligned( FMatrixRBlock src, FMatrixRBlock dst ) {
if (src.blockLength != dst.blockLength)
throw new IllegalArgumentException("Block size is different");
if (src.numRows < dst.numRows)
throw new IllegalArgumentException("The src has fewer rows than dst");
if (src.numCols < dst.numCols)
throw new IllegalArgumentException("The src has fewer columns than dst");
int blockLength = src.blockLength;
int numRows = Math.min(src.numRows, dst.numRows);
int numCols = Math.min(src.numCols, dst.numCols);
for (int i = 0; i < numRows; i += blockLength) {
int heightSrc = Math.min(blockLength, src.numRows - i);
int heightDst = Math.min(blockLength, dst.numRows - i);
for (int j = 0; j < numCols; j += blockLength) {
int widthSrc = Math.min(blockLength, src.numCols - j);
int widthDst = Math.min(blockLength, dst.numCols - j);
int indexSrc = i*src.numCols + heightSrc*j;
int indexDst = i*dst.numCols + heightDst*j;
for (int k = 0; k < heightDst; k++) {
System.arraycopy(src.data, indexSrc + widthSrc*k, dst.data, indexDst + widthDst*k, widthDst);
}
}
}
}
/**
* Checks to see if the submatrix has its boundaries along inner blocks.
*
* @param blockLength Size of an inner block.
* @param A Submatrix.
* @return If it is block aligned or not.
*/
public static boolean blockAligned( int blockLength, FSubmatrixD1 A ) {
if (A.col0%blockLength != 0)
return false;
if (A.row0%blockLength != 0)
return false;
if (A.col1%blockLength != 0 && A.col1 != A.original.numCols) {
return false;
}
if (A.row1%blockLength != 0 && A.row1 != A.original.numRows) {
return false;
}
return true;
}
static void checkShapeMult( int blockLength,
FSubmatrixD1 A, FSubmatrixD1 B,
FSubmatrixD1 C ) {
//@formatter:off
int Arow = A.getRows(); int Acol = A.getCols();
int Brow = B.getRows(); int Bcol = B.getCols();
int Crow = C.getRows(); int Ccol = C.getCols();
//@formatter:on
if (Arow != Crow)
throw new RuntimeException("Mismatch A and C rows");
if (Bcol != Ccol)
throw new RuntimeException("Mismatch B and C columns");
if (Acol != Brow)
throw new RuntimeException("Mismatch A columns and B rows");
if (!MatrixOps_FDRB.blockAligned(blockLength, A))
throw new RuntimeException("Sub-Matrix A is not block aligned");
if (!MatrixOps_FDRB.blockAligned(blockLength, B))
throw new RuntimeException("Sub-Matrix B is not block aligned");
if (!MatrixOps_FDRB.blockAligned(blockLength, C))
throw new RuntimeException("Sub-Matrix C is not block aligned");
}
//CONCURRENT_OMIT_END
}