org.ejml.alg.dense.mult.MatrixMatrixMult Maven / Gradle / Ivy
Show all versions of ejml Show documentation
/*
* Copyright (c) 2009-2012, Peter Abeles. All Rights Reserved.
*
* This file is part of Efficient Java Matrix Library (EJML).
*
* EJML is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* EJML is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with EJML. If not, see .
*/
package org.ejml.alg.dense.mult;
import org.ejml.data.RowD1Matrix64F;
/**
*
* This class contains various types of matrix matrix multiplication operations for {@link RowD1Matrix64F}.
*
*
* Two algorithms that are equivalent can often have very different runtime performance.
* This is because of how modern computers uses fast memory caches to speed up reading/writing to data.
* Depending on the order in which variables are processed different algorithms can run much faster than others,
* even if the number of operations is the same.
*
*
*
* Algorithms that are labeled as 'reorder' are designed to avoid caching jumping issues, some times at the cost
* of increasing the number of operations. This is important for large matrices. The straight forward
* implementation seems to be faster for small matrices.
*
*
*
* Algorithms that are labeled as 'aux' use an auxiliary array of length n. This array is used to create
* a copy of an out of sequence column vector that is referenced several times. This reduces the number
* of cache misses. If the 'aux' parameter passed in is null then the array is declared internally.
*
*
*
* Typically the straight forward implementation runs about 30% faster on smaller matrices and
* about 5 times slower on larger matrices. This is all computer architecture and matrix shape/size specific.
*
*
*
*
******** IMPORTANT **********
* This class was auto generated using {@link GeneratorMatrixMatrixMult}
* If this code needs to be modified, please modify {@link GeneratorMatrixMatrixMult} instead
* and regenerate the code by running that.
*
*
* @author Peter Abeles
*/
public class MatrixMatrixMult {
/**
* @see org.ejml.ops.CommonOps#mult( org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F)
*/
public static void mult_reorder( RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c )
{
if( a == c || b == c )
throw new IllegalArgumentException("Neither 'a' or 'b' can be the same matrix as 'c'");
else if( a.numCols != b.numRows ) {
throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions");
} else if( a.numRows != c.numRows || b.numCols != c.numCols ) {
throw new MatrixDimensionException("The results matrix does not have the desired dimensions");
}
double valA;
int indexCbase= 0;
int endOfKLoop = b.numRows*b.numCols;
for( int i = 0; i < a.numRows; i++ ) {
int indexA = i*a.numCols;
// need to assign c.data to a value initially
int indexB = 0;
int indexC = indexCbase;
int end = indexB + b.numCols;
valA = a.get(indexA++);
while( indexB < end ) {
c.set(indexC++ , valA*b.get(indexB++));
}
// now add to it
while( indexB != endOfKLoop ) { // k loop
indexC = indexCbase;
end = indexB + b.numCols;
valA = a.get(indexA++);
while( indexB < end ) { // j loop
c.plus(indexC++ , valA*b.get(indexB++));
}
}
indexCbase += c.numCols;
}
}
/**
* @see org.ejml.ops.CommonOps#mult( org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F)
*/
public static void mult_small( RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c )
{
if( a == c || b == c )
throw new IllegalArgumentException("Neither 'a' or 'b' can be the same matrix as 'c'");
else if( a.numCols != b.numRows ) {
throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions");
} else if( a.numRows != c.numRows || b.numCols != c.numCols ) {
throw new MatrixDimensionException("The results matrix does not have the desired dimensions");
}
int aIndexStart = 0;
int cIndex = 0;
for( int i = 0; i < a.numRows; i++ ) {
for( int j = 0; j < b.numCols; j++ ) {
double total = 0;
int indexA = aIndexStart;
int indexB = j;
int end = indexA + b.numRows;
while( indexA < end ) {
total += a.get(indexA++) * b.get(indexB);
indexB += b.numCols;
}
c.set( cIndex++ , total );
}
aIndexStart += a.numCols;
}
}
/**
* @see org.ejml.ops.CommonOps#mult( org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F)
*/
public static void mult_aux( RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c , double []aux )
{
if( a == c || b == c )
throw new IllegalArgumentException("Neither 'a' or 'b' can be the same matrix as 'c'");
else if( a.numCols != b.numRows ) {
throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions");
} else if( a.numRows != c.numRows || b.numCols != c.numCols ) {
throw new MatrixDimensionException("The results matrix does not have the desired dimensions");
}
if( aux == null ) aux = new double[ b.numRows ];
for( int j = 0; j < b.numCols; j++ ) {
// create a copy of the column in B to avoid cache issues
for( int k = 0; k < b.numRows; k++ ) {
aux[k] = b.unsafe_get(k,j);
}
int indexA = 0;
for( int i = 0; i < a.numRows; i++ ) {
double total = 0;
for( int k = 0; k < b.numRows; ) {
total += a.get(indexA++)*aux[k++];
}
c.set( i*c.numCols+j , total );
}
}
}
/**
* @see org.ejml.ops.CommonOps#multTransA( org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F, org.ejml.data.RowD1Matrix64F)
*/
public static void multTransA_reorder( RowD1Matrix64F a , RowD1Matrix64F b , RowD1Matrix64F c )
{
if( a == c || b == c )
throw new IllegalArgumentException("Neither 'a' or 'b' can be the same matrix as 'c'");
else if( a.numRows != b.numRows ) {
throw new MatrixDimensionException("The 'a' and 'b' matrices do not have compatible dimensions");
} else if( a.numCols != c.numRows || b.numCols != c.numCols ) {
throw new MatrixDimensionException("The results matrix does not have the desired dimensions");
}
double valA;
for( int i = 0; i < a.numCols; i++ ) {
int indexC_start = i*c.numCols;
// first assign R
valA = a.get(i);
int indexB = 0;
int end = indexB+b.numCols;
int indexC = indexC_start;
while( indexB