com.meliorbis.numerics.generic.impl.GenericBlockedArray 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.Iterator;
import com.meliorbis.numerics.NumericsException;
import com.meliorbis.numerics.generic.ArrayFactory1D;
import com.meliorbis.numerics.generic.ArrayFactory2D;
import com.meliorbis.numerics.generic.BinaryOp;
import com.meliorbis.numerics.generic.GenericArray;
import com.meliorbis.numerics.generic.Matcher;
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.ParallelIterator;
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.index.SubIndex;
import com.meliorbis.numerics.index.impl.Index;
import com.meliorbis.numerics.threading.ComputableRecursiveAction;
import com.meliorbis.numerics.threading.Executor;
/**
* Array implementation for generic types
*/
public abstract class GenericBlockedArray> extends AbstractBlockedArray
implements GenericArray
{
public GenericBlockedArray(Executor executor_, int[] dimensions_)
{
super(executor_, dimensions_);
}
public GenericBlockedArray(BlockedArrayData data_, SubIndex dimensionCounter_, Executor executor_)
{
super(data_, dimensionCounter_, executor_);
}
@Override
protected BlockedArrayData createData(int[] dimensions_)
{
return new GenericBlockedArrayData(dimensions_, getZero(), getArrayFactory1D(), getArrayFactory2D());
}
protected GenericBlockedArray(BlockedArrayData data_, Executor executor_)
{
super(data_, executor_);
}
protected GenericBlockedArray(T[] data_, Executor executor_)
{
super(data_, executor_);
}
public GenericBlockedArray(BlockedArrayData data_, Index.SubIndex subIndex_, Executor executor_)
{
super(data_, subIndex_, executor_);
}
@Override
protected NaryOp getSecondOperandOp()
{
return (BinaryOp) (a,b) -> b;
}
@Override
protected BlockedArrayData createDataFromValues(T[] data_)
{
final GenericBlockedArrayData data = (GenericBlockedArrayData) createData(new int[]{data_.length, 1});
for (int i = 0; i < data_.length; i++)
{
data.setLinear(data_[i], i);
}
return data;
}
@Override
public T get(int... indices_) throws MultiDimensionalArrayException
{
return getInternal(indices_);
}
@Override
public T first()
{
return get(0);
}
@Override
public T last()
{
return get(numberOfElements()-1);
}
@Override
public void set(T val_, int... indices_)
throws MultiDimensionalArrayException
{
setInternal(val_, indices_);
}
protected T getInternal(int[] indices_)
throws MultiDimensionalArrayException {
if (indices_.length == 1) {
if (_subIndex != null) {
indices_ = _subIndex.toLogicalIndex(indices_[0]);
} else {
return ((GenericBlockedArrayData)_data).getLinear(indices_[0]);
}
}
if (_subIndex != null) {
indices_ = ((Index.SubIndex) _subIndex).fullIndex(indices_);
}
return ((GenericBlockedArrayData)_data).get(indices_);
}
protected void setInternal(T val_, int[] indices_)
throws MultiDimensionalArrayException {
if (indices_.length == 1) {
if (_subIndex != null) {
indices_ = _subIndex.toLogicalIndex(indices_[0]);
} else {
((GenericBlockedArrayData)_data).setLinear(val_, indices_[0]);
return;
}
}
if (_subIndex != null) {
indices_ = ((Index.SubIndex) _subIndex).fullIndex(indices_);
}
((GenericBlockedArrayData)_data).set(val_, indices_);
}
@Override
public void setMatching(final T matching_, final T val_)
throws MultiDimensionalArrayException
{
setMatching(new Matcher()
{
@Override
public boolean matches(T otherVal_)
{
return matching_.equals(otherVal_);
}
}, val_);
}
@Override
public void setMatching(Matcher matcher_, T val_)
{
modifying().map((UnaryOp) v -> matcher_.matches(v) ? val_ : v);
}
/* (non-Javadoc)
* @see com.meliorbis.numerics.generic.IMultiDimensionalArray#fill(T[])
*/
@SuppressWarnings("unchecked")
@Override
public R fill(final T... data_) throws MultiDimensionalArrayException {
// Check that the data is the right size
if(numberOfElements() % data_.length != 0)
{
throw new MultiDimensionalArrayException("The array size must be a multiple of input data length");
}
SettableIndexedIterator targetIterator = iterator();
int i = 0;
while(targetIterator.hasNext())
{
// Reset to go around the array again
if(i == data_.length)
{
i = 0;
}
targetIterator.next();
targetIterator.set(data_[i++]);
}
return (R) this;
}
@Override
public void fillDimensions(T[] values_, int... dimensions_)
throws MultiDimensionalArrayException
{
R filler = createNew(values_.length).fill(values_);
fillDimensions(filler, dimensions_);
}
@Override
public T sum() throws MultiDimensionalArrayException
{
return reduce(new Reduction()
{
@Override
public T perform(SettableIterator iterator_) throws RuntimeException
{
// Initialise the sum to zero
T sum = getZero();
// Successively add each value of the iterator to the sum
while(iterator_.hasNext())
{
sum = getAddOp().perform(sum, iterator_.next());
}
// Return the calculated sum
return sum;
}
});
}
@Override
public T mean(MultiDimensionalArray extends T, ?> levels_, int dimension_) throws MultiDimensionalArrayException
{
SubSpaceSplitIterator levelsDimIter = iteratorAcross(new int[]{dimension_});
T mean = getZero();
final SettableIndexedIterator extends T> levelIter = levels_.iterator();
while (levelsDimIter.hasNext())
{
// Go to the next level
levelsDimIter.next();
// Get the level at that index from the passed levels
T level = levelIter.next();
// iterate over all points at that level, in other dimensions
SubSpaceSplitIterator pointsWithLevelIter = levelsDimIter.getOrthogonalIterator();
// Calculate the total weight at the current level
T weightAtLevel = getZero();
while (pointsWithLevelIter.hasNext())
{
T weight = (T) pointsWithLevelIter.next();
weightAtLevel = getAddOp().perform(weightAtLevel, weight);
}
// add the weight times the level to the mean
mean = getAddOp().perform(mean, getMultOp().perform(level, weightAtLevel));
}
return mean;
}
@Override
public T secondMoment(MultiDimensionalArray extends T,?> levels_, int dimension_)
{
SubSpaceSplitIterator levelsDimIter = iteratorAcross(new int[]{dimension_});
T sumOfSquares = getZero();
BinaryOp mult = getMultOp();
BinaryOp add = getAddOp();
final SettableIndexedIterator extends T> levelIter = levels_.iterator();
while (levelsDimIter.hasNext())
{
// Go to the next level
levelsDimIter.next();
// Get the level at that index from the passed levels
T level = levelIter.next();
// iterate over all points at that level, in other dimensions
SubSpaceSplitIterator pointsWithLevelIter = levelsDimIter.getOrthogonalIterator();
// Calculate the total weight at the current level
T weightAtLevel = getZero();
while (pointsWithLevelIter.hasNext())
{
T weight = (T) pointsWithLevelIter.next();
weightAtLevel = add.perform(weightAtLevel, weight);
}
// add the weight times the level squared to the sum of squares
sumOfSquares = add.perform(sumOfSquares,mult.perform(mult.perform(level,level),weightAtLevel));
}
// mean of squares minus square of means = variance
return sumOfSquares;
}
@Override
public R multiply(MultiDimensionalArray other_)
{
return with(other_).map(getMultOp());
}
@Override
public R add(MultiDimensionalArray other_)
{
return with(other_).map(getAddOp());
}
@Override
public R divide(MultiDimensionalArray other_)
{
return with(other_).map(getDivisionOp());
}
@Override
public R subtract(MultiDimensionalArray other_)
{
return with(other_).map(getSubtractionOp());
}
public UnaryOp getDivisionOp(T denominator_)
{
return binaryOpWithConstant(getDivisionOp(), denominator_);
}
public UnaryOp getMultOp(T multiplicand_)
{
return binaryOpWithConstant(getMultOp(), multiplicand_);
}
public UnaryOp getAddOp(T summand_)
{
return binaryOpWithConstant(getAddOp(), summand_);
}
public UnaryOp getSubtractionOp(T summand_)
{
return binaryOpWithConstant(getSubtractionOp(), summand_);
}
protected UnaryOp binaryOpWithConstant(BinaryOp op_, T constant_)
{
return (x) -> op_.perform(x, constant_);
}
@Override
public final R add(T summand_)
{
return map(getAddOp(summand_));
}
@Override
public R multiply(T multiplicand_)
{
return map(getMultOp(multiplicand_));
}
@Override
public R divide(T other_)
{
return map(getDivisionOp(other_));
}
@Override
public R subtract(T other_)
{
return map(getSubtractionOp(other_));
}
@Override
public T[] toArray()
{
// If the array is not restricted, let the data object do the work.
if(_subIndex == null)
{
return ((GenericBlockedArrayData)_data).toArray();
}
else
{
// Otherwise, iterate over the array and copy each element.
T[] data = getArrayFactory1D().createArray(numberOfElements());
SettableIndexedIterator iterator = iterator();
int index = 0;
while(iterator.hasNext())
{
data[index++] = iterator.next();
}
return data;
}
}
@SuppressWarnings("unchecked")
@Override
public boolean equals(Object obj_)
{
if(!(obj_ instanceof MultiDimensionalArray))
{
return false;
}
final boolean same[] = new boolean[]{true};
try {
with((MultiDimensionalArray extends T, ?>)obj_).map((BinaryOp) (left_, right_) -> {
if (left_ == null)
{
if (right_ != null)
{
same[0] = false;
}
} else if (!left_.equals(right_))
{
same[0] = false;
}
return getZero();
});
}
catch(MultiDimensionalArrayException e) {
// Silently drop - most likely size difference
return false;
}
return same[0];
}
@Override
protected NaryOpCallable createNaryOpCallable(NaryOp op_,
SettableIterator extends T>[] inputs_, SettableIterator> result_, boolean iterateResult_)
{
return new GenericNaryOpCallable(op_, inputs_, result_, iterateResult_)
{
@Override
protected T[] createTypedArray(int length_)
{
return GenericBlockedArray.this.createTypedArray(length_);
}
};
}
@Override
protected SettableIterator createMultiSettableIterator(SettableIterator[] iters_)
{
return null;
}
@SuppressWarnings("unchecked")
@Override
protected R[] createPointWiseMultiValuedResult(MultiValuedNaryOp op_, MultiDimensionalArray extends T, ?>[] others_)
{
T[] tester = createTypedArray(others_.length + 1);
tester[0] = get(0);
for (int j = 0; j < others_.length; j++)
{
tester[j+1] = ((GenericBlockedArray)others_[j]).get(0);
}
try
{
T[] results = op_.perform(tester);
R first = createNew(size());
R[] arrays = (R[]) java.lang.reflect.Array.newInstance(first.getClass(), results.length);
arrays[0] = first;
for (int i = 1; i < arrays.length; i++)
{
arrays[i] = createNew(size());
}
return arrays;
} catch (Exception ex_)
{
throw new NumericsException("Op failed whilst trying to determine output count", ex_);
}
}
@Override
public R copy()
{
return createNew(size()).fill(this);
}
@Override
public T[] createTypedArray(int length_)
{
return getArrayFactory1D().createArray(length_);
}
protected abstract ArrayFactory2D getArrayFactory2D();
protected abstract ArrayFactory1D getArrayFactory1D();
@SuppressWarnings("unchecked")
@Override
protected ComputableRecursiveAction createReduceAction(ReductionBase, E> reduction_,
SettableIterator currentIterator_, AbstractMappable target_)
{
int initialTargetIndex = ((ParallelIterator)currentIterator_).nextParallel();
final SettableIndexedIterator targetIterator = ((GenericBlockedArray)target_).rangeIterator(initialTargetIndex, initialTargetIndex + ((ParallelIterator)currentIterator_).parallelCount());
return ()-> {
try
{
// Do the first one outside the loop because it was necessary to iterate to the next parallel to get
// the initial index above
targetIterator.next();
targetIterator.set(((Reduction)reduction_).perform(currentIterator_));
// Do the rest in a loop
while(((ParallelIterator)currentIterator_).hasNextParallel())
{
((ParallelIterator)currentIterator_).nextParallel();
targetIterator.next();
targetIterator.set(((Reduction)reduction_).perform(currentIterator_));
}
} catch (Exception e)
{
throw new MultiDimensionalArrayException(e);
}
};
}
}