com.meliorbis.numerics.generic.impl.AbstractArray Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Numerics Show documentation
Show all versions of Numerics Show documentation
A library for working with large multi-dimensional arrays and the functions they represent
package com.meliorbis.numerics.generic.impl;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.lang.ArrayUtils;
import com.meliorbis.numerics.NumericsException;
import com.meliorbis.numerics.generic.Acrossable;
import com.meliorbis.numerics.generic.BinaryOp;
import com.meliorbis.numerics.generic.Mappable;
import com.meliorbis.numerics.generic.MappableWithSimpleOps;
import com.meliorbis.numerics.generic.MultiDimensionalArray;
import com.meliorbis.numerics.generic.MultiDimensionalArrayException;
import com.meliorbis.numerics.generic.MultiValuedNaryOp;
import com.meliorbis.numerics.generic.NaryOp;
import com.meliorbis.numerics.generic.SettableIndexedIterator;
import com.meliorbis.numerics.generic.SettableIterator;
import com.meliorbis.numerics.generic.SubSpaceSplitIterator;
import com.meliorbis.numerics.generic.UnaryOp;
import com.meliorbis.numerics.generic.primitives.impl.DoubleArrayFunctions;
import com.meliorbis.numerics.index.Index;
import com.meliorbis.numerics.threading.ComputableRecursiveAction;
import com.meliorbis.numerics.threading.CurrentThreadExecutor;
import com.meliorbis.numerics.threading.Executor;
import com.meliorbis.utils.Timer;
import com.meliorbis.utils.Timer.Stoppable;
import com.meliorbis.utils.Utils;
@SuppressWarnings("unchecked")
public abstract class AbstractArray> extends AbstractMappable
implements MultiDimensionalArray
{
protected final Index _index;
protected final ModifyingWrapper _modifyingWrapper;
public AbstractArray(Executor executor_, int[] dimensions_)
{
this(new com.meliorbis.numerics.index.impl.Index(dimensions_), executor_);
}
public AbstractArray(Index logicalDimensions_, Executor executor_)
{
super(executor_);
_index = logicalDimensions_;
_modifyingWrapper = createModifyingWrapper();
}
/**
* @return The same array but in a reference that will cause results of any operations to be applied to this array
*/
protected AbstractArray.ModifyingWrapper createModifyingWrapper()
{
return new ModifyingWrapper();
}
@Override
public T reduce(ReductionBase, E> reduction_) throws E
{
if(reduction_ instanceof Reduction)
{
Timer timer = new Timer();
Stoppable stoppable = timer.start("execReduce");
T result = ((Reduction)reduction_).perform(iterator());
stoppable.stop();
return result;
}
else
{
throw new UnsupportedOperationException("Only instances of IReduction supported");
}
}
@Override
public int numberOfElements()
{
return _index.numberOfElements();
}
@Override
public int numberOfDimensions()
{
return _index.numberOfDimensions();
}
@Override
public int[] size()
{
return _index.getSizes();
}
public Reduction getMaxOp()
{
return iter -> {
T max = null;
while(iter.hasNext()) {
T cur = iter.next();
if(max == null || getComparator().compare(max, cur) < 0) {
max = cur;
}
}
return max;
};
}
public Reduction getMinOp()
{
return iter -> {
T min = null;
while(iter.hasNext()) {
T cur = iter.next();
if(min == null || getComparator().compare(min, cur) > 0) {
min = cur;
}
}
return min;
};
}
public Reduction getSumOp()
{
return iterator_-> {
T sum = getZero();
while (iterator_.hasNext())
{
// Add the next item to the running total
sum = getAddOp().perform(sum, iterator_.next());
}
return sum;
};
}
@Override
protected RM getPointwiseResult()
{
return createNew(size());
}
protected abstract RM createNew(int... dimensions_);
@Override
public RM matrixMultiply(
MultiDimensionalArray extends T,?> other_)
throws MultiDimensionalArrayException
{
// Call the product with a do-nothing transformer
return matrixMultiply(other_, getIdentityOp());
}
protected UnaryOp getIdentityOp()
{
return x -> x;
}
/*
* (non-Javadoc)
*
* @see
* com.meliorbis.numerics.generic.IMultiDimensionalArray#matrixMultiply(
* com.meliorbis.numerics.generic.IMultiDimensionalArray,
* com.meliorbis.numerics.generic.ITransformer)
*/
@Override
public RM matrixMultiply(
MultiDimensionalArray extends T,?> other_,
UnaryOp transformer_)
throws MultiDimensionalArrayException
{
if(size().length > 2 || other_.size().length > 2)
{
throw new MultiDimensionalArrayException("Only two dimensional matrices may be multiplied");
}
// Handle the case where we are essentially dealing with (a) vector(s)
if(numberOfDimensions() == 1)
{
if(other_.numberOfDimensions() == 1)
{
RM result = createNew(1);
final SettableIndexedIterator resIter = result.iterator();
resIter.next();
resIter.set(calcDotProduct(iterator(), other_.iterator(), transformer_));
return result;
}
// Create a matrix with one row to multiply with
final RM vecAsMatrix = createNew(1,numberOfElements());
vecAsMatrix.fillDimensions(this, 1);
return vecAsMatrix.matrixMultiply(other_, transformer_);
}
// Check that the matrices are conformable
if (size()[1] != other_.size()[0])
{
throw new MultiDimensionalArrayException(
"The matrices are not conformable");
}
// Create the output array
RM result = createNew(new int[] { size()[0],
other_.numberOfDimensions() == 1 ? 1 : other_.size()[1] });
SubSpaceSplitIterator rowIter = iteratorAcross(new int[]{0});
SettableIndexedIterator resultIterator = result.iterator();
// Iterate over the rows of the left matrix
while(rowIter.hasNext())
{
rowIter.next();
// If the other is a vector just multiply it with each row
if(other_.numberOfDimensions() == 1)
{
resultIterator.next();
resultIterator.set(calcDotProduct(rowIter.getOrthogonalIterator(), other_.iterator(), transformer_));
}
else
{
SubSpaceSplitIterator extends T> otherColIter = other_.iteratorAcross(new int[]{1});
// And, for each row, over the columns of the right matrix
while(otherColIter.hasNext())
{
otherColIter.next();
// Get orthogonal iterators for each matrix, which will be the same length (conformable!)
SubSpaceSplitIterator leftValIter = rowIter.getOrthogonalIterator();
SubSpaceSplitIterator extends T> rightValIter = otherColIter.getOrthogonalIterator();
T value = calcDotProduct(leftValIter, rightValIter, transformer_);
// The result matrix is iterated in the right order and will be the right size, so just go to the next
// and set it
resultIterator.next();
resultIterator.set(value);
}
}
}
return result;
}
/**
* @param leftValIter the value on the left
* @param rightValIter The values on the right
*
* @param transformer_ The transformation to apply to each individual product before summing
*
* @return The resulting value
*/
protected T calcDotProduct(Iterator leftValIter, Iterator extends T> rightValIter, UnaryOp transformer_)
{
T value = getZero();
while(leftValIter.hasNext())
{
// Multiply the appropriate values and add them to the
// running total
T individualProduct = getMultOp().perform(leftValIter.next(), rightValIter.next());
// Transform the individual product using the provided transformer
T transformedProduct = transformer_.perform(individualProduct);
value = getAddOp().perform(
transformedProduct,
value);
}
return value;
}
@Override
public RM fill(MultiDimensionalArray extends T, ?> values_)
{
modifying().with(values_).map(getSecondOperandOp());
return (RM) this;
}
@Override
public RM fill(Iterator extends T> values_)
{
fillIterator(iterator(), values_);
return (RM) this;
}
@Override
public RM lastDimSlice(int index_)
{
final int[] selector = Utils.repeatArray(-1, numberOfDimensions());
selector[numberOfDimensions() - 1] = index_;
return at(selector);
}
/*
* (non-Javadoc)
*
* @see
* com.meliorbis.numerics.generic.IMultiDimensionalArray#fillAt(com.meliorbis
* .numerics.generic.IMultiDimensionalArray, int[])
*/
@Override
public void fillAt(MultiDimensionalArray extends T,?> values_,int... index_)
{
at(index_).modifying().with(values_).map(getSecondOperandOp());
}
protected void fillIterator(SettableIndexedIterator targetIterator_, Iterator extends T> values_)
{
Iterator extends T> inputIter = values_;
// Iterate over the dimensions to be filled
while (targetIterator_.hasNext())
{
targetIterator_.next();
if(!inputIter.hasNext())
{
throw new MultiDimensionalArrayException("Not enough elements in input");
// // Start again
// inputIter = values_.iterator();
}
// Get the value from the appropriate place in source and copy to
// the current target location
targetIterator_.set(inputIter.next());
}
// If there is another input we had incorrectly sized inputs
if(inputIter.hasNext())
{
throw new MultiDimensionalArrayException("The target size must be an exact multiple of the input size");
}
}
@Override
public void fillDimensions(MultiDimensionalArray extends T, ?> values_, int... dimensions_)
{
try
{
modifying().across(dimensions_).with(values_).map(getSecondOperandOp());
} catch (Exception e)
{
throw new MultiDimensionalArrayException("Error during fill", e);
}
}
protected abstract NaryOp getSecondOperandOp();
public int[] getSubDimensions(int... dimensions_)
{
int[] targetSize = new int[dimensions_.length];
// Determine the sizes of the target dimensions, as well as the total
// size
for (int dimIndex = 0; dimIndex < targetSize.length; dimIndex++)
{
targetSize[dimIndex] = size()[dimensions_[dimIndex]];
}
return targetSize;
}
public int[] getOtherSubDimensions(int... excluded_)
{
// Create an array to contain the dimensions except the ones requested
int[] targetSize = new int[numberOfDimensions() - excluded_.length];
// Initialise counter for all three lists - all dimensions, targetDimensions and the dimensions specified
int excludedIndex = 0;
int targetIndex = 0;
for (int dimIndex = 0; dimIndex < numberOfDimensions(); dimIndex++)
{
// If the current dimenion is the next one specified
if(excludedIndex < excluded_.length && excluded_[excludedIndex] == dimIndex)
{
// Increment the excluded dimensions index
excludedIndex++;
// don't copy this dimension's size
continue;
}
// Otherwise, copy this dimensions size
targetSize[targetIndex++] = size()[dimIndex];
}
return targetSize;
}
final protected RM createOtherDimsArray(int[] dimensions_, T[] array_)
{
RM created = createOtherDimsArray(dimensions_);
created.fill(Arrays.asList(array_).iterator());
return created;
}
final protected RM createOtherDimsArray(int[] dimensions_)
{
int[] otherDims = getOtherSubDimensions(dimensions_);
// If there are no other dims, create a 1-element array (i.e. a 'scalar')
if(otherDims.length == 0)
{
otherDims = new int[]{1};
}
RM created = createNew(otherDims);
return created;
}
/*
* (non-Javadoc)
*
* @see com.meliorbis.numerics.generic.IMultiDimensionalArray#max(int[])
*/
@Override
public T sum()
{
return reduce(getSumOp());
}
/*
* (non-Javadoc)
*
* @see com.meliorbis.numerics.generic.IMultiDimensionalArray#max(int[])
*/
@Override
public T max()
{
return reduce(getMaxOp());
}
/*
* (non-Javadoc)
*
* @see com.meliorbis.numerics.generic.IMultiDimensionalArray#max(int[])
*/
@Override
public T min()
{
return reduce(getMinOp());
}
protected int[] ensureDimensions(int... dimensions_) {
return (dimensions_.length == 0) ? Utils.sequence(0,numberOfDimensions()): dimensions_;
}
public void performSubspaceOpST(IndexedSubSpaceOperation operation_, int...dimensions_)
throws E
{
// Always the possibility that no dimensions were specified, i.e. the entire space as subspace is to be used...
// Get an iterator over the dimensions to maximise...
SubSpaceSplitIterator maxIter = iteratorAcross(dimensions_);
// ... and its orthogonal twin!
SubSpaceSplitIterator otherIterator = maxIter.getOrthogonalIterator();
// Initialise the operation wit the orthogonal iterator
operation_.initialise(otherIterator);
// Iterate over the orthogonal dimension, finding the max at each point
// along the max dimensions
while (otherIterator.hasNext())
{
otherIterator.next();
operation_.perform(otherIterator.getOrthogonalIterator());
}
}
@Override
public RM stack(MultiDimensionalArray extends T, ?>... others_)
{
DoubleArrayFunctions.ensureAllEqualSize(this, others_);
// Create a new array with one extra dimension as this one, which is the stack dimension
int[] newArraySize = new int[this.numberOfDimensions()+1];
System.arraycopy(this.size(), 0, newArraySize, 0, this.numberOfDimensions());
newArraySize[newArraySize.length-1] = others_.length + 1;
RM result = createNew(newArraySize);
// Create an array to choose the appropriate slice
int[] fillIndex = Utils.repeatArray(-1, newArraySize.length);
int stackDimension = newArraySize.length-1;
fillIndex[stackDimension] = 0;
// Put this in the first slice
result.fillAt(this, fillIndex);
// And fill the others into the other slices
for(int index = 0; index < others_.length; index++)
{
fillIndex[stackDimension] = index+1;
result.fillAt(others_[index], fillIndex);
}
return result;
}
@Override
public RM stackFinal(MultiDimensionalArray extends T, ?>... others_)
{
//DoubleArrayFunctions.ensureAllEqualSize(this, others_);
// Create a new array with one extra dimension as this one, which is the stack dimension
int[] newArraySize = new int[this.numberOfDimensions()];
System.arraycopy(this.size(), 0, newArraySize, 0, this.numberOfDimensions());
for (MultiDimensionalArray extends T, ?> other : others_)
{
newArraySize[newArraySize.length-1] += other.size()[newArraySize.length-1];
}
RM result = createNew(newArraySize);
// Create an array to choose the appropriate slice
int[] fillIndex = Utils.repeatArray(-1, newArraySize.length);
int[] srcIndex = Utils.repeatArray(-1, newArraySize.length);
int stackDimension = newArraySize.length-1;
fillIndex[stackDimension] = 0;
for(int i = 0; i < size()[stackDimension];i++)
{
srcIndex[stackDimension] = i;
// Put this in the first slice
result.fillAt(this.at(srcIndex), fillIndex);
fillIndex[stackDimension]++;
}
// And fill the others into the other slices
for (MultiDimensionalArray extends T, ?> other : others_)
{
for(int i = 0; i < other.size()[stackDimension];i++)
{
srcIndex[stackDimension] = i;
// Put this in the first slice
result.fillAt(other.at(srcIndex), fillIndex);
fillIndex[stackDimension]++;
}
}
return result;
}
@Override
public IModifyableMappable> modifying()
{
return _modifyingWrapper;
}
@Override
public AbstractArray nonModifying()
{
return this;
}
@Override
public String toString()
{
StringBuilder result = new StringBuilder();
result.append(String.format("(size=%s)\n",Arrays.toString(size())));
result.append("[");
toString(result);
result.append("]");
return result.toString();
}
public void toString(StringBuilder builder_)
{
if(numberOfDimensions() > 2)
{
SubSpaceSplitIterator outerDims = iteratorAcross(Utils.sequence(0,numberOfDimensions() - 2));
while (outerDims.hasNext()) {
outerDims.next();
builder_.append(indexString(outerDims.getIndex()));
builder_.append("\n");
at(outerDims.getFullIndex()).toString(builder_);
builder_.append("\n");
}
}
else if(numberOfDimensions() == 2)
{
SubSpaceSplitIterator rowIter = iteratorAcross(new int[]{0});
while (rowIter.hasNext()) {
rowIter.next();
SubSpaceSplitIterator colIter = rowIter.getOrthogonalIterator();
while (colIter.hasNext()) {
T t = (T) colIter.next();
builder_.append(t);
builder_.append(", ");
}
builder_.append(";\n");
}
}
else // Only other option is one dimension
{
SettableIndexedIterator colIter = iterator();
while (colIter.hasNext()) {
T t = (T) colIter.next();
builder_.append(t);
builder_.append("\t");
}
builder_.append("\n");
}
}
public String indexString(int[] index_)
{
StringBuilder result = new StringBuilder("(");
int i;
for (i = 0; i < index_.length-1; i++) {
result.append(i);
result.append(",");
}
result.append(index_[i]);
result.append(")");
return result.toString();
}
/**
* @return The object that represents 0
*/
protected abstract T getZero();
/**
* @return The object that represents -1
*/
protected abstract T getMinusOne();
public abstract T[] createTypedArray(int length_);
protected interface IDimTransposer
{
int[] changeIndex(int[] in_);
IDimTransposer transpose(int numDims_, int dimA_, int dimB_);
}
protected NaryOpCallable createBatchedNaryOpCallable(final NaryOp op_,
MultiDimensionalArray result_,
int from_, int to_,
final MultiDimensionalArray extends T, ?>... other_)
{
Stoppable timer = new Timer().start("createBatchedNaryOpCallable");
// If the result is the same as this, there is no need to need to create a separate result iterator
boolean iterateResult = !((AbstractMappable) result_).isModifying();
SettableIndexedIterator extends T>[] inputs = new SettableIndexedIterator[other_.length + 1];
final SettableIndexedIterator selfIterator = from_ == -1 ? iterator() : rangeIterator(from_, to_);
inputs[0] = selfIterator;
for (int i = 0; i < other_.length; )
{
// Note the increment happens and then it is assigned to (prior) i+1
SettableIndexedIterator extends T> iter = from_ == -1 ? other_[i++].iterator() :
other_[i++].rangeIterator(from_, to_);
inputs[i] = iter;
}
SettableIndexedIterator resultIter = iterateResult ?
(from_ == -1 ? result_.iterator() : result_.rangeIterator(from_, to_)) : selfIterator;
timer.stop();
return createNaryOpCallable(op_, inputs, resultIter, iterateResult);
}
protected NaryOpCallable createBatchedNaryOpCallable(final MultiValuedNaryOp op_,
MultiDimensionalArray[] results_,
int from_, int to_,
final MultiDimensionalArray extends T, ?>... other_)
{
SettableIndexedIterator extends T>[] inputs = new SettableIndexedIterator[other_.length + 1];
final SettableIndexedIterator selfIterator = from_ == -1 ? iterator() : rangeIterator(from_, to_);
inputs[0] = selfIterator;
for (int i = 0; i < other_.length; )
{
// Note the increment happens and then it is assigned to (prior) i+1
SettableIndexedIterator extends T> iter = from_ == -1 ? other_[i++].iterator() :
other_[i++].rangeIterator(from_, to_);
inputs[i] = iter;
}
SettableIterator resultIter = createMultiSettableIterator(Arrays.stream(results_).map(array -> from_ == -1 ? array.iterator() : array.rangeIterator(from_, to_)).toArray(len->new SettableIterator[len]));
return createNaryOpCallable(op_, inputs, resultIter, true);
}
@SafeVarargs
@Override
final public Mappable with(final MultiDimensionalArray... otherOperands_)
{
return this.withInternal(otherOperands_, null, null);
}
private > Mappable withInternal(
final MultiDimensionalArray[] otherOperands_,
final AbstractArray targetArray_,
final alt_R returnValue_)
{
return new Mappable()
{
@Override
public Mappable with(MultiDimensionalArray... otherOperands2_)
{
final MultiDimensionalArray[] allOtherOperands = (MultiDimensionalArray[]) ArrayUtils.addAll(otherOperands_, otherOperands2_);
return AbstractArray.this.withInternal(allOtherOperands, targetArray_, returnValue_);
}
@Override
public alt_R[] map(MultiValuedNaryOp operation_) throws E
{
RM[] target = createPointWiseMultiValuedResult(operation_, otherOperands_);
DoubleArrayFunctions.ensureAllEqualSize(AbstractArray.this, otherOperands_);
int batchSize;
int batches = POINTWISE_BATCH_COUNT;
if(numberOfElements() < 10000) {
batches = 1;
batchSize = numberOfElements();
}
else
{
batchSize = numberOfElements()/batches + (numberOfElements()%batches == 0? 0 : 1);
batches = numberOfElements()/batchSize + (numberOfElements()%batchSize == 0? 0 : 1);
}
Timer timer = new Timer();
if (batches > 1)
{
Stoppable stoppable = timer.start("prep");
List> callables = new LinkedList>();
for (int batch = 0; batch < batches; )
{
int from = batch++ * batchSize;
int to = Math.min(batch * batchSize, numberOfElements());
callables.add(createBatchedNaryOpCallable(operation_, target, from, to, otherOperands_));
}
stoppable.stop();
stoppable = timer.start("execMap");
try
{
_executor.executeAndWait(callables);
} catch (NumericsException e)
{
throw new MultiDimensionalArrayException(e);
}
stoppable.stop();
} else
{
try
{
Stoppable stoppable = timer.start("execMapSingle");
new CurrentThreadExecutor().executeAndWait(Arrays.asList(createBatchedNaryOpCallable(operation_, target, -1, -1, otherOperands_)));
stoppable.stop();
}
catch (NumericsException e)
{
throw new MultiDimensionalArrayException(e);
}
}
return (alt_R[])target;
}
@Override
public alt_R map(NaryOp operation_) throws E
{
// Make sure there is a target array
AbstractArray target = targetArray_ != null ? targetArray_ : getPointwiseResult();
DoubleArrayFunctions.ensureAllEqualSize(AbstractArray.this, otherOperands_);
int batchSize;
int batches = POINTWISE_BATCH_COUNT;
if(numberOfElements() < 10000) {
batches = 1;
batchSize = numberOfElements();
}
else
{
batchSize = numberOfElements()/batches + (numberOfElements()%batches == 0? 0 : 1);
batches = numberOfElements()/batchSize + (numberOfElements()%batchSize == 0? 0 : 1);
}
Timer timer = new Timer();
if (batches > 1)
{
Stoppable stoppable = timer.start("prep");
List> callables = new LinkedList>();
for (int batch = 0; batch < batches; )
{
int from = batch++ * batchSize;
int to = Math.min(batch * batchSize, numberOfElements());
callables.add(createBatchedNaryOpCallable(operation_, target, from, to, otherOperands_));
}
stoppable.stop();
stoppable = timer.start("execMap");
try
{
_executor.executeAndWait(callables);
} catch (NumericsException e)
{
throw new MultiDimensionalArrayException(e);
}
stoppable.stop();
} else
{
try
{
Stoppable stoppable = timer.start("execMapSingle");
new CurrentThreadExecutor().executeAndWait(Arrays.asList(createBatchedNaryOpCallable(operation_, target, -1, -1, otherOperands_)));
stoppable.stop();
}
catch (NumericsException e)
{
throw new MultiDimensionalArrayException(e);
}
}
return returnValue_ != null ? returnValue_ : (alt_R) target;
}
};
}
public interface IModifyableMappable> extends MappableWithSimpleOps, Acrossable
{
boolean isModifying();
}
public class ModifyingWrapper extends AbstractMappable implements IModifyableMappable
{
public ModifyingWrapper()
{
super(AbstractArray.this._executor);
}
@Override
public int numberOfDimensions() {
return AbstractArray.this.numberOfDimensions();
}
@Override
public boolean isModifying()
{
return true;
}
@Override
public Mappable with(MultiDimensionalArray... otherArrays_)
{
return AbstractArray.this.withInternal(otherArrays_, AbstractArray.this, getPointwiseResult());
}
@Override
public ModifyingWrapper getPointwiseResult()
{
return this;
}
public void fill(Iterator extends T> values_)
{
AbstractArray.this.fill(values_);
}
public void fill(MultiDimensionalArray extends T,?> values_)
{
AbstractArray.this.fill(values_);
}
public void fillDimensions(MultiDimensionalArray extends T,?> values_, int... dimensions_)
{
AbstractArray.this.fillDimensions(values_, dimensions_);
}
public void fillAt(MultiDimensionalArray extends T,?> values_, int... index_)
{
AbstractArray.this.fillAt(values_, index_);
}
@Override
protected NaryOpCallable createNaryOpCallable(NaryOp op_, SettableIterator extends T>[] inputs_, SettableIterator> result_, boolean iterateResult_)
{
return AbstractArray.this.createNaryOpCallable(op_, inputs_, result_, iterateResult_);
}
@Override
public BinaryOp getAddOp()
{
return AbstractArray.this.getAddOp();
}
@Override
public BinaryOp getSubtractionOp()
{
return AbstractArray.this.getSubtractionOp();
}
@Override
public BinaryOp getMultOp()
{
return AbstractArray.this.getMultOp();
}
@Override
public BinaryOp getDivisionOp()
{
return AbstractArray.this.getDivisionOp();
}
@Override
public T reduce(ReductionBase, E> reduction_) throws E
{
return AbstractArray.this.reduce(reduction_);
}
@Override
public List extends SettableIterator> parallelIterators(int[] dimensions_)
{
return AbstractArray.this.parallelIterators(dimensions_);
}
@Override
public T max()
{
return AbstractArray.this.max();
}
@Override
public T sum()
{
return AbstractArray.this.sum();
}
@Override
public T min()
{
return AbstractArray.this.min();
}
@Override
protected MultiDimensionalArray createOtherDimsArray(int[] dimensions_, T[] array_)
{
return AbstractArray.this.createOtherDimsArray(dimensions_, array_);
}
@Override
public Reduction getMaxOp()
{
return AbstractArray.this.getMaxOp();
}
@Override
public Reduction getMinOp()
{
return AbstractArray.this.getMinOp();
}
@Override
public Reduction getSumOp()
{
return AbstractArray.this.getSumOp();
}
@Override
public SubSpaceSplitIterator iteratorAcross(int[] dimensions_)
{
return AbstractArray.this.iteratorAcross(dimensions_);
}
@Override
public AbstractMappable modifying()
{
return this;
}
@Override
protected MultiDimensionalArray createOtherDimsArray(int[] dimensions_)
{
return AbstractArray.this.createOtherDimsArray(dimensions_);
}
@Override
protected ComputableRecursiveAction createReduceAction(ReductionBase, E> reduction_,
SettableIterator currentIterator_, AbstractMappable target_)
{
return AbstractArray.this.createReduceAction(reduction_, currentIterator_, target_);
}
@Override
public AbstractArray.ModifyingWrapper[] map(MultiValuedNaryOp operation_) throws E
{
throw new UnsupportedOperationException("Multimap can't be used to modify an array");
}
@Override
protected SettableIterator createMultiSettableIterator(SettableIterator[] iters_)
{
return AbstractArray.this.createMultiSettableIterator(iters_);
}
@Override
protected ModifyingWrapper[] createPointWiseMultiValuedResult(MultiValuedNaryOp op_, MultiDimensionalArray extends T, ?>[] others_)
{
throw new UnsupportedOperationException("Can't multimap a modifyable");
}
@Override
public MappableWithSimpleOps> nonModifying()
{
return AbstractArray.this;
}
}
}