NDTrait.java
package neureka.ndim.config;
import java.util.*;
import java.util.function.Predicate;
import java.util.stream.IntStream;
public enum NDTrait
{
COMPACT(NDTrait::_isCompact),
SIMPLE(NDTrait::_isSimple),
ROW_MAJOR(NDTrait::_isRM),
COL_MAJOR(NDTrait::_isCM),
CONTINUOUS_MATRIX(NDTrait::_isContinuousMatrix),
OFFSET_MATRIX(NDTrait::_isOffsetMatrix),;
private final Predicate<NDConfiguration> _predicate;
NDTrait( Predicate<NDConfiguration> predicate ) { _predicate = Objects.requireNonNull(predicate); }
static List<NDTrait> traitsOf( NDConfiguration ndc ) {
List<NDTrait> traits = new ArrayList<>();
for ( NDTrait trait : NDTrait.values() )
if ( trait._predicate.test( ndc ) ) traits.add( trait );
return Collections.unmodifiableList( traits );
}
private static int _rightSpreadPadding(NDConfiguration ndc ) {
int numberOf0Spreads = 0;
for ( int i = ndc.rank() - 1; i >= 0; i-- ) {
if ( ndc.spread( i ) == 0 ) numberOf0Spreads++;
else break;
}
return numberOf0Spreads;
}
private static boolean _isCompact( NDConfiguration ndc ) {
return
IntStream.range(0, ndc.rank()).allMatch(i -> ndc.spread(i) == 1 || ndc.spread(i) == 0 )
&&
IntStream.range(0, ndc.rank()).allMatch(i -> ndc.offset(i) == 0);
}
private static boolean _isSimple( NDConfiguration ndc ) {
int[] simpleTranslation = ndc.getLayout().newStridesFor(ndc.shape());
return Arrays.equals(ndc.strides(), simpleTranslation)
&&
Arrays.equals(ndc.indicesMap(), simpleTranslation)
&&
_isCompact(ndc);
}
/**
* What does it mean to be row major essentially? <br>
* Well all it really means is that the last dimension of a nd-array configuration
* has a stride of 1! <br>
*
* @param ndc The configuration to check.
* @return Whether the configuration is row major.
*/
private static boolean _isRM( NDConfiguration ndc ) {
/*
We simply need to check if the last real dimension has a stride and spread of 1.
This tells us that at the last dimension we have all elements in
a contiguous block of memory.
*/
int realRank = ndc.rank() - _rightSpreadPadding( ndc );
if ( realRank < 1 ) return false;
boolean strides = ndc.strides( realRank - 1 ) == 1;
boolean spread = ndc.spread( realRank - 1 ) == 1;
return strides && spread;
}
/**
* What does it mean to be column major essentially? <br>
* Well all it really means is that the second last dimension of a nd-array configuration
* has a stride of 1! <br>
*
* @param ndc The configuration to check.
* @return Whether the configuration is column major.
*/
private static boolean _isCM( NDConfiguration ndc ) {
/*
We simply need to check if the second last real dimension has a stride and spread of 1.
This tells us that at the second last dimension we have all elements in
a contiguous block of memory.
*/
int realRank = ndc.rank() - _rightSpreadPadding( ndc );
if ( realRank < 1 ) return false;
boolean strideIs1 = ndc.strides( realRank - 2 ) == 1;
boolean spreadIs1 = ndc.spread( realRank - 2 ) == 1;
return strideIs1 && spreadIs1;
}
private static boolean _last2DimensionsAreNotPermuted( NDConfiguration ndc ) {
int realRank = ndc.rank() - _rightSpreadPadding( ndc );
if ( realRank < 2 ) return true;
int strideCol = ndc.strides( realRank - 2 );
int strideRow = ndc.strides( realRank - 1 );
return strideCol == 1 || strideRow == 1;
}
private static boolean _isContinuousMatrix(NDConfiguration ndc ) {
boolean isMatrix = _isMatrix( ndc );
if ( !isMatrix ) return false;
int realRank = ndc.rank() - _rightSpreadPadding( ndc );
if ( _isRM(ndc) ) {
// We need to check if the there is no row offset!
return ndc.offset( realRank - 1 ) == 0;
} else {
// We need to check if the there is no column offset!
return ndc.offset( realRank - 2 ) == 0;
}
}
private static boolean _isOffsetMatrix(NDConfiguration ndc) {
boolean isMatrix = _isMatrix( ndc );
if ( !isMatrix ) return false;
int realRank = ndc.rank() - _rightSpreadPadding( ndc );
if ( _isRM(ndc) ) {
// We need to check if the there is no row offset!
return ndc.offset( realRank - 1 ) != 0;
} else if ( _isCM(ndc) ) {
// We need to check if the there is no column offset!
return ndc.offset( realRank - 2 ) != 0;
}
return false;
}
private static boolean _isMatrix( NDConfiguration ndc ) {
boolean last2DimsNotPermuted = _last2DimensionsAreNotPermuted( ndc );
if ( !last2DimsNotPermuted ) return false;
int realRank = ndc.rank() - _rightSpreadPadding( ndc );
if ( realRank < 2 ) return false;
// Now we need to make sure the steps of the last 2 dimensions are both 1.
int spreadCol = ndc.spread( realRank - 2 );
int spreadRow = ndc.spread( realRank - 1 );
return spreadCol == 1 && spreadRow == 1;
}
}