org.ejml.dense.block.MatrixOps_FDRB Maven / Gradle / Ivy
Show all versions of ejml-fdense Show documentation
/*
* Copyright (c) 2009-2017, 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 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.ConvertFMatrixStruct;
import java.util.Random;
/**
* Various operations on {@link FMatrixRBlock}.
*
* @author Peter Abeles
*/
public class MatrixOps_FDRB {
/**
* 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 )
{
ConvertFMatrixStruct.convert(src,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 tmp Temporary data structure that is to be the size of a block row.
*/
public static void convertRowToBlock( int numRows , int numCols , int blockLength ,
float[] data, float[] tmp )
{
int minLength = Math.min( blockLength , numRows ) * numCols;
if( tmp.length < minLength ) {
throw new IllegalArgumentException("tmp must be at least "+minLength+" long ");
}
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 ConvertFMatrixStruct.convert(src,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 tmp Temporary data structure that is to be the size of a block row.
*/
public static void convertBlockToRow( int numRows , int numCols , int blockLength ,
float[] data, float[] tmp )
{
int minLength = Math.min( blockLength , numRows ) * numCols;
if( tmp.length < minLength ) {
throw new IllegalArgumentException("tmp must be at least "+minLength+" long and not "+tmp.length);
}
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++];
}
}
}
}
}
// 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);
}
/**
* Transposes a block matrix.
*
* @param A Original matrix. Not modified.
* @param A_tran Transposed matrix. Modified.
*/
public static FMatrixRBlock transpose(FMatrixRBlock A , 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;
}
}