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

mikera.arrayz.impl.AbstractArray 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.impl;

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

import mikera.arrayz.Array;
import mikera.arrayz.Arrayz;
import mikera.arrayz.INDArray;
import mikera.arrayz.ISparse;
import mikera.indexz.AIndex;
import mikera.indexz.Index;
import mikera.matrixx.AMatrix;
import mikera.matrixx.Matrix;
import mikera.matrixx.Matrixx;
import mikera.matrixx.impl.SparseRowMatrix;
import mikera.util.Maths;
import mikera.vectorz.AScalar;
import mikera.vectorz.AVector;
import mikera.vectorz.IOperator;
import mikera.vectorz.Op;
import mikera.vectorz.Op2;
import mikera.vectorz.Ops;
import mikera.vectorz.Scalar;
import mikera.vectorz.Tools;
import mikera.vectorz.Vector;
import mikera.vectorz.Vectorz;
import mikera.vectorz.impl.SingleDoubleIterator;
import mikera.vectorz.util.Constants;
import mikera.vectorz.util.DoubleArrays;
import mikera.vectorz.util.ErrorMessages;
import mikera.vectorz.util.IntArrays;
import mikera.vectorz.util.LongArrays;
import mikera.vectorz.util.VectorzException;
/**
 * Abstract base class for INDArray implementations
 * 
 * Contains generic implementations for most INDArray operations, enabling new INDArray implementations
 * to inherit these (at least until more optimised implementations can be written).
 * 
 * Default implementations assume dimensionality of 1 or above
 * 
 * Most INDArray instances should ultimately inherit from AbstractArray
 * 
 * @author Mike
 * @param  The type of array slices
 */
public abstract class AbstractArray implements INDArray, Iterable {
	private static final long serialVersionUID = -958234961396539071L;

	@Override
	public abstract double get();
	
	@Override
	public abstract double get(int i);
	
	@Override
	public double get(long i) {
		return get(Tools.toInt(i));
	}
	
	@Override
	public abstract double get(int i, int j);
	
	@Override
	public double get(long x,long y) {
		return get(Tools.toInt(x),Tools.toInt(y));
	}
	
	@Override
	public double get(long[] xs) {
		int n=xs.length;
		int[] ixs=new int[n];
		for (int i=0; i0) {
			int sc = sliceCount();
			for (int i = 0; i < sc; i++) {
				slice(i).applyOp(op,(dims==b.dimensionality())?b.slice(i):b);
			}			
		} else {
			set(op.apply(get(),b.get()));
		}
	}

	@Override
	public void applyOp(Op2 op, double b) {
		if (dimensionality()>0) {
			int rc = sliceCount();
			for (int i = 0; i < rc; i++) {
				slice(i).applyOp(op,b);
			}			
		} else {
			set(op.apply(get(),b));
		}
	}

	@Override
	public void multiply(double d) {
		if (d==1.0) return;
		int n=sliceCount();
		for (int i=0; i0) {
			slice(s1).setElements(pos-s1*ss, values, si, l1);
			si+=l1;
		}
		for (int i=s1+1; i0) {
			slice(s2).setElements(0,values,si,l2);
		}
	}
	
	@Override
	public boolean isZero() {
		if (dimensionality()==0) return (get()==0.0);
		int sc=sliceCount();
		for (int i=0; i sliceInnerProducts=new ArrayList(sc);
		for (int i=0; i al=new ArrayList(sliceCount());
		for (Object s:this) {
			if (s instanceof INDArray) {
				al.add(((INDArray)s).outerProduct(a));
			} else {
				double x=Tools.toDouble(s);
				INDArray sa=a.clone();
				sa.scale(x);
				al.add(sa);
			}
		}
		return Arrayz.create(al);
	}
	
	@Override
	public INDArray getTranspose() {
		return getTransposeCopy();
	}
	
	@Override
	public INDArray getTransposeView() {
		throw new UnsupportedOperationException();
	}
	
	@Override
	public INDArray getTransposeCopy() {
		Array nd=Array.create(this);
		return nd.getTransposeView();
	}
	
	@Override
	public final void scale(double d) {
		multiply(d);
	}
	
	@Override
	public void scaleAdd(double factor, double constant) {
		if (factor==0.0) {
			set(constant);
		} else {
			if (factor!=1.0) multiply(factor);
			if (constant!=0.0) add(constant);
		}
	}
	
	@Override
	public void scaleAdd(double factor, INDArray b, double bfactor, double constant) {
		scaleAdd(factor,constant);
		addMultiple(b,bfactor);
	}
	
	@Override
	public void addMultiple(INDArray src, double factor) {
		if (factor==0.0) return;
		if (factor==1.0) {
			add(src);
		} else {
			add(src.multiplyCopy(factor));
		}
	}
	
	@Override
	public void addMultipleSparse(INDArray src, double factor) {
		INDArray res=src.multiplyCopy(factor);
		res=res.mutable();
		res.add(this);
		setSparse(res);
	}
	
	@Override
	public void addPower(INDArray src, double exponent) {
		INDArray tmp=src.clone();
		tmp.pow(exponent);
		add(tmp);
	}

	@Override
	public void addPower(INDArray src, double exponent, double factor) {
		INDArray tmp=src.clone();
		tmp.pow(exponent);
		addMultiple(tmp,factor);
	}
	
	@Override
	public void addInnerProduct(INDArray a, INDArray b) {
		if (a.dimensionality()==0) {
			addMultiple(b,a.get());
		} else if (a instanceof AMatrix) {
			addInnerProduct((AMatrix) a,b);
		} else if (a instanceof AVector) {
			addInnerProduct((AVector) a,b);
		} else {
			add(a.innerProduct(b));
		}
	}
	
	@Override
	public void addInnerProduct(INDArray a, INDArray b, double d) {
		if (a.elementCount()adims){
			INDArray sl=slice(0);
			int sc=sliceCount();
			sl.setApplyOp(op, a);
			for (int i=1; i) {
			int i=0;
			for (Object ob: ((Iterable)o)) {
				slice(i).set(ob);
			}
			return;
		}
		if (o instanceof double[]) { 
			setElements((double[])o);
			return;
		}
		throw new UnsupportedOperationException("Can't set to value for "+o.getClass().toString());		
	}
	
	@Override
	public void setElements(double... values) {
		int vl=values.length;
		if (vl!=elementCount()) throw new IllegalArgumentException("Wrong array length: "+vl);
		setElements(0,values,0,vl);
	}
	
	@Override
	public void square() {
		applyOp(Ops.SQUARE);
	}
	
	@Override
	public INDArray squareCopy() {
		INDArray r=clone();
		r.square();
		return r;
	}
	
	@Override
	public INDArray absCopy() {
		INDArray r=clone();
		r.abs();
		return r;
	}
	
	@Override
	public INDArray reciprocalCopy() {
		INDArray r=clone();
		r.reciprocal();
		return r;
	}
	
	@Override
	public INDArray signumCopy() {
		INDArray r=clone();
		r.signum();
		return r;
	}
	
	@Override
	public Iterator iterator() {
		return new SliceIterator(this);
	}
	
	@Override
	public Iterator elementIterator() {
		if (dimensionality()==0) {
			return new SingleDoubleIterator(get());
		} else {
			return new SliceElementIterator(this);
		}
	}
	
	@Override
	public boolean equals(Object o) {
		if (!(o instanceof INDArray)) return false;
		return equals((INDArray)o);
	}
	
	@Override
	public boolean equalsArray(double[] data) {
		if (data.length!=elementCount()) return false;
		return equalsArray(data,0);
	}

	@Override
	public int hashCode() {
		return asVector().hashCode();
	}
	
	@Override
	public String toString() {
		if (elementCount()>Constants.PRINT_THRESHOLD) {
			Index shape=Index.create(getShape());
			return "Large array with shape: "+shape.toString();
		}
		
		return toStringFull();
	}
	
	public String toStringFull() {
		
		if (dimensionality()==0) {
			return Double.toString(get());
		}
		StringBuilder sb=new StringBuilder();
		int length=sliceCount();
		sb.append('[');
		if (length>0) {
			sb.append(slice(0).toString());
			for (int i = 1; i < length; i++) {
				sb.append(',');
				sb.append(slice(i).toString());
			}
		}
		sb.append(']');
		return sb.toString();
	}
	
	@Override
	public INDArray clone() {
		return Arrayz.create(this);
	}
	
	@Override
	public INDArray copy() {
		if (!isMutable()) return this;
		return clone();
	}
	
	@Override
	public INDArray scaleCopy(double d) {
		INDArray r=clone();
		r.scale(d);
		return r;
	}
	
	@Override
	public INDArray negateCopy() {
		INDArray r=clone();
		r.negate();
		return r;
	}
	
	@Override
	public boolean equals(INDArray a) {
		int dims=dimensionality();
		if (a.dimensionality()!=dims) return false;
		if (dims==0) {
			return Tools.equals(get(),a.get());
		} else if (dims==1) {
			return equals(a.asVector());
		} else {
			int sc=sliceCount();
			if (a.sliceCount()!=sc) return false;
			for (int i=0; iresult) result=v;
		}
		return result;	
	}
	
	@Override
	public boolean elementsEqual(double value) {
		if (dimensionality()==0) {
			return get()==value;
		}
		int n=sliceCount();
		for (int i=0; i=dims)) throw new IndexOutOfBoundsException(ErrorMessages.invalidDimension(this, dim));
		ArrayList newSlices=new ArrayList(n);
		for (int si : order) {
			newSlices.add(slice(dim,si));
		}
		int[] shp=this.getShapeClone();
		shp[dim]=n;

		if (dims==2) {
			if (dim==0) {
				return SparseRowMatrix.create(newSlices, shp[0], shp[1]);
			}
		}
		if (dim==0) {
			return SliceArray.create(newSlices,shp);
		} else {
			Array a=Array.newArray(shp);
			for (int di=0; di getSlices(int dimension) {
		int l=getShape(dimension);
		ArrayList al=new ArrayList(l);
		for (int i=0; i getSlices() {
		int n=sliceCount();
		ArrayList al=new ArrayList(n);
		for (int i=0; i getSliceViews() {
		int n=sliceCount();
		ArrayList al=new ArrayList(n);
		for (int i=0; i al=new ArrayList(nslices);
		int endIndex=offsets[0]+nslices;
		int[] zzoffsets=IntArrays.removeIndex(offsets, 0);
		int[] zzshape=IntArrays.removeIndex(shape, 0);
		for (int i=offsets[0]; i asElementList() {
		return asVector().asElementList();
	}

	@Override
	public final double[] getElements() {
		return toDoubleArray();
	}
	
	@Override
	public void getElements(double[] dest, int offset) {
		if (dimensionality()==0) {
			dest[offset]=get();
			return;
		}
		int sc=sliceCount();
		for (int i=0; i sls=this.getSliceViews();
		for (int i=0; i= dimensionality()))
			throw new IndexOutOfBoundsException(ErrorMessages.invalidDimension(this,dimension));
	}

	/**
	 * Returns true if any element is this array is NaN or infinite
	 * @return
	 */
	@Override
	public boolean hasUncountable() {
		if (dimensionality()==0) return Vectorz.isUncountable(get());
		int sc=sliceCount();
		for (int i=0; i