All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mikera.arrayz.Array Maven / Gradle / Ivy

Go to download

Fast double-precision vector and matrix maths library for Java, supporting N-dimensional numeric arrays.

There is a newer version: 0.67.0
Show newest version
package mikera.arrayz;

import java.nio.DoubleBuffer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import mikera.arrayz.impl.BaseShapedArray;
import mikera.arrayz.impl.IDenseArray;
import mikera.arrayz.impl.IStridedArray;
import mikera.arrayz.impl.ImmutableArray;
import mikera.indexz.Index;
import mikera.matrixx.Matrix;
import mikera.vectorz.AVector;
import mikera.vectorz.IOperator;
import mikera.vectorz.Op;
import mikera.vectorz.Op2;
import mikera.vectorz.Scalar;
import mikera.vectorz.Tools;
import mikera.vectorz.Vector;
import mikera.vectorz.Vectorz;
import mikera.vectorz.impl.ArrayIndexScalar;
import mikera.vectorz.impl.StridedElementIterator;
import mikera.vectorz.util.DoubleArrays;
import mikera.vectorz.util.ErrorMessages;
import mikera.vectorz.util.IntArrays;
import mikera.vectorz.util.VectorzException;

/**
 * General purpose, mutable, packed, dense N-dimensional array
 * 
 * This is the general multi-dimensional equivalent of Matrix and Vector, and as such is the 
 * most efficient storage type for dense 3D+ arrays
 * 
 * @author Mike
 * 
 */
public final class Array extends BaseShapedArray implements IStridedArray, IDenseArray {
	private static final long serialVersionUID = -8636720562647069034L;

	private final int dimensions;
	private final int[] strides;
	private final double[] data;

	private Array(int dims, int[] shape, int[] strides) {
		super(shape);
		this.dimensions = dims;
		this.strides = strides;
		int n = (int) IntArrays.arrayProduct(shape);
		this.data = new double[n];
	}
	
	private Array(int[] shape, double[] data) {
		this(shape.length, shape, IntArrays.calcStrides(shape), data);
	}

	private Array(int dims, int[] shape, double[] data) {
		this(dims, shape, IntArrays.calcStrides(shape), data);
	}
	
	/**
	 * Wraps double[] array data in an Array of the specified shape.
	 * 
	 * The number of elements in the array must exactly match the length of the array.
	 * 
	 * @param data
	 * @param shape
	 * @return
	 */
	public static Array wrap(double[] data, int... shape) {
		long ec=IntArrays.arrayProduct(shape);
		if (data.length!=ec) throw new IllegalArgumentException("Data array does not have correct number of elements, expected: "+ec);
		return new Array(shape.length,shape,data);
	}

	private Array(int dims, int[] shape, int[] strides, double[] data) {
		super(shape);
		this.dimensions = dims;
		this.strides = strides;
		this.data = data;
	}
	
	/**
	 * Wraps the underlying data from a dense Vector as an array with the same shape
	 * @param v
	 * @return
	 */
	public static Array wrap(Vector v) {
		return new Array(v.getShape(),v.getArray());
	}
	
	/**
	 * Wraps the underlying data from a dense Matrix as an array with the same shape
	 * @param v
	 * @return
	 */
	public static Array wrap(Matrix m) {
		return new Array(m.getShape(),m.getArray());
	}

	/**
	 * Creates a new zero-filled mutable Array of the specified shape
	 * @param shape
	 * @return
	 */
	public static Array newArray(int... shape) {
		return new Array(shape.length, shape, DoubleArrays.createStorageArray(shape));
	}

	/** 
	 * Crates a new Array with a copt of the data from the sepcified array, in the same shape 
	 * @param a
	 * @return
	 */
	public static Array create(INDArray a) {
		int[] shape=a.getShape();
		return new Array(a.dimensionality(), shape, a.toDoubleArray());
	}
	
	@Override
	public int dimensionality() {
		return dimensions;
	}
	
	@Override
	protected final void checkDimension(int dimension) {
		if ((dimension < 0) || (dimension >= dimensions))
			throw new IndexOutOfBoundsException(ErrorMessages.invalidDimension(this,dimension));
	}

	@Override
	public long[] getLongShape() {
		long[] lshape = new long[dimensions];
		IntArrays.copyIntsToLongs(shape, lshape);
		return lshape;
	}

	@Override
	public int getStride(int dim) {
		return strides[dim];
	}

	/**
	 * Computes the array index of the specified index position in the underlyind data array
	 * @param indexes
	 * @return
	 */
	protected int getIndex(int... indexes) {
		int ix = 0;
		for (int i = 0; i < dimensions; i++) {
			ix += indexes[i] * getStride(i);
		}
		return ix;
	}

	@Override
	public double get(int... indexes) {
		return data[getIndex(indexes)];
	}

	@Override
	public void set(int[] indexes, double value) {
		data[getIndex(indexes)] = value;
	}

	@Override
	public Vector asVector() {
		return Vector.wrap(data);
	}

	@Override
	public Vector toVector() {
		return Vector.create(data);
	}

	@Override
	public INDArray slice(int majorSlice) {
		return slice(0, majorSlice);
	}

	@Override
	public INDArray slice(int dimension, int index) {
		Arrayz.checkShape(this,dimension,index);
		
		if (dimensions == 1) return ArrayIndexScalar.wrap(data, index);
		if (dimensions == 2) {
			if (dimension == 0) {
				return Vectorz.wrap(data, index * shape[1], shape[1]);
			} else {
				return Vectorz.wrapStrided(data, index, shape[0], strides[0]);
			}
		}

		int offset = index * getStride(dimension);
		return Arrayz.wrapStrided(
				data, 
				offset,
				IntArrays.removeIndex(shape, dimension), 
				IntArrays.removeIndex(strides, dimension));
	}
	
	@Override
	public INDArray getTranspose() {
		return getTransposeView();
	}
	
	@Override
	public INDArray getTransposeView() {
		return NDArray.wrapStrided(data, 0, IntArrays.reverse(shape), IntArrays.reverse(strides));
	}
	
	@Override
	public INDArray subArray(int[] offsets, int[] shape) {
		int n=dimensions;
		if (offsets.length!=n) throw new IllegalArgumentException(ErrorMessages.invalidIndex(this, offsets));
		if (shape.length!=n) throw new IllegalArgumentException(ErrorMessages.invalidIndex(this, offsets));
		
		// check if we can return the whole array
		if (IntArrays.equals(shape, this.shape)) {
			if (IntArrays.isZero(offsets)) {
				return this;
			} else {
				throw new IllegalArgumentException("Invalid subArray offsets");
			}
		}
		
		int[] strides=IntArrays.calcStrides(this.shape);
		return new NDArray(data,
				IntArrays.dotProduct(offsets, strides),
				IntArrays.copyOf(shape),
				strides);
	}

	@Override
	public long elementCount() {
		return data.length;
	}

	@Override
	public double elementSum() {
		return DoubleArrays.elementSum(data);
	}
	
	@Override
	public double elementMax(){
		return DoubleArrays.elementMax(data);
	}
	
	@Override
	public double elementMin(){
		return DoubleArrays.elementMin(data);
	}

	@Override
	public double elementSquaredSum() {
		return DoubleArrays.elementSquaredSum(data);
	}

	@Override
	public void abs() {
		DoubleArrays.abs(data);
	}

	@Override
	public void signum() {
		DoubleArrays.signum(data);
	}

	@Override
	public void square() {
		DoubleArrays.square(data);
	}

	@Override
	public void exp() {
		DoubleArrays.exp(data);
	}

	@Override
	public void log() {
		DoubleArrays.log(data);
	}

	@Override
	public boolean isMutable() {
		return true;
	}

	@Override
	public boolean isFullyMutable() {
		return true;
	}

	@Override
	public boolean isElementConstrained() {
		return false;
	}

	@Override
	public boolean isView() {
		return false;
	}

	@Override
	public void applyOp(Op op) {
		op.applyTo(data);
	}
	
	@Override
	public double reduce(Op2 op) {
		return DoubleArrays.reduce(op, data, 0, data.length);
	}
	
	@Override
	public double reduce(Op2 op, double init) {
		return op.reduce(init, data, 0, data.length);
	}

	@Override
	public void applyOp(IOperator op) {
		if (op instanceof Op) {
			((Op) op).applyTo(data);
		} else {
			for (int i = 0; i < data.length; i++) {
				data[i] = op.apply(data[i]);
			}
		}
	}

	@Override
	public boolean equals(INDArray a) {
		if (!isSameShape(a)) return false;
		return a.equalsArray(data, 0);
	}

	@Override
	public Array exactClone() {
		return new Array(dimensions, shape, strides, data.clone());
	}

	@Override
	public void setElements(int pos, double[] values, int offset, int length) {
		System.arraycopy(values, offset, data, pos, length);
	}
	
	@Override
	public void getElements(double[] values, int offset) {
		System.arraycopy(data, 0, values, offset, data.length);
	}
	
	@Override
	public Iterator elementIterator() {
		return new StridedElementIterator(data,0,(int)elementCount(),1);
	}

	@Override
	public void multiply(double factor) {
		DoubleArrays.multiply(data, 0, data.length, factor);
	}

	@Override
	public List getSlices() {
		if (dimensions==1) {
			int n=sliceCount();
			ArrayList al=new ArrayList(n);
			for (int i=0; i 0) && (strides[dimensions - 1] != 1))
			throw new VectorzException("Last stride should be 1");

		if (data.length != IntArrays.arrayProduct(shape))
			throw new VectorzException("Inconsistent shape");
		if (!IntArrays.equals(strides, IntArrays.calcStrides(shape)))
			throw new VectorzException("Inconsistent strides");
	}

	/**
	 * Creates a new matrix using the elements in the specified vector.
	 * Truncates or zero-pads the data as required to fill the new matrix
	 * @param data
	 * @param rows
	 * @param columns
	 * @return
	 */
	public static Array createFromVector(AVector a, int... shape) {
		Array m = Array.newArray(shape);
		int n=(int)Math.min(m.elementCount(), a.length());
		a.copyTo(0, m.data, 0, n);
		return m;
	}

	@Override
	public double[] getArray() {
		return data;
	}

	@Override
	public int getArrayOffset() {
		return 0;
	}

	@Override
	public int[] getStrides() {
		return strides;
	}

	@Override
	public boolean isPackedArray() {
		return true;
	}
	
	@Override
	public boolean isZero() {
		return DoubleArrays.isZero(data);
	}

	@Override
	public INDArray immutable() {
		return ImmutableArray.wrap(DoubleArrays.copyOf(data), this.shape);
	}

	@Override
	public double get() {
		if (dimensions==0) {
			return data[0];
		} else {
			throw new IllegalArgumentException("O-d get not supported on Array of shape: "+Index.of(this.getShape()).toString());
		}
	}

	@Override
	public double get(int x) {
		if (dimensions==1) {
			return data[x];
		} else {
			throw new IllegalArgumentException("1-d get not supported on Array of shape: "+Index.of(this.getShape()).toString());
		}
	}

	@Override
	public double get(int x, int y) {
		if (dimensions==2) {
			return data[x*strides[0]+y];
		} else {
			throw new IllegalArgumentException("2-d get not supported on Array of shape: "+Index.of(this.getShape()).toString());
		}
	}

	@Override
	public boolean equalsArray(double[] data, int offset) {
		return DoubleArrays.equals(this.data, 0, data, offset, Tools.toInt(elementCount()));
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy