package mikera.vectorz;
import java.nio.DoubleBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import mikera.arrayz.Arrayz;
import mikera.arrayz.INDArray;
import mikera.arrayz.ISparse;
import mikera.arrayz.impl.AbstractArray;
import mikera.arrayz.impl.SliceArray;
import mikera.indexz.AIndex;
import mikera.indexz.Index;
import mikera.matrixx.AMatrix;
import mikera.matrixx.Matrix;
import mikera.matrixx.Matrixx;
import mikera.matrixx.impl.BroadcastVectorMatrix;
import mikera.matrixx.impl.RowMatrix;
import mikera.randomz.Hash;
import mikera.util.Maths;
import mikera.vectorz.impl.ADenseArrayVector;
import mikera.vectorz.impl.ASizedVector;
import mikera.vectorz.impl.ASparseVector;
import mikera.vectorz.impl.ArraySubVector;
import mikera.vectorz.impl.ImmutableVector;
import mikera.vectorz.impl.IndexedElementVisitor;
import mikera.vectorz.impl.IndexedSubVector;
import mikera.vectorz.impl.JoinedVector;
import mikera.vectorz.impl.ListWrapper;
import mikera.vectorz.impl.SparseIndexedVector;
import mikera.vectorz.impl.Vector0;
import mikera.vectorz.impl.VectorIndexScalar;
import mikera.vectorz.impl.VectorIterator;
import mikera.vectorz.impl.WrappedSubVector;
import mikera.vectorz.ops.Logistic;
import mikera.vectorz.util.Constants;
import mikera.vectorz.util.DoubleArrays;
import mikera.vectorz.util.ErrorMessages;
import mikera.vectorz.util.IntArrays;
import mikera.vectorz.util.VectorzException;
/**
* Main abstract base class for all types of vector
*
* Contains default implementations for most vector operations which can be
* overriden to achieve better performance in derived classes.
*
* @author Mike
*
*/
@SuppressWarnings("serial")
public abstract class AVector extends AbstractArray implements IVector {
// ================================================
// Abstract interface
@Override
public abstract int length();
@Override
public abstract double get(int i);
@Override
public abstract void set(int i, double value);
// ================================================
// Standard implementations
@Override
public double get(long i) {
if ((i<0)||(i>=length())) throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, i));
return unsafeGet((int)i);
}
public void set(long i, double value) {
if ((i<0)||(i>=length())) throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, i));
unsafeSet((int)i,value);
}
@Override
public final double getElement(long i) {
return get(i);
}
@Override
public void set(int[] indexes, double value) {
if (indexes.length==1) {
set(indexes[0],value);
} else {
throw new UnsupportedOperationException(""+indexes.length+"D set not supported on AVector");
}
}
@Override
public void set(long[] indexes, double value) {
if (indexes.length==1) {
set(Tools.toInt(indexes[0]),value);
} else {
throw new UnsupportedOperationException(""+indexes.length+"D set not supported on AVector");
}
}
/**
* Like set, but performs no bounds checking.
*
* Results are undefined if the index is out of range
* @param i
* @param value
*/
public void unsafeSet(int i, double value) {
set(i,value);
}
/**
* Like get, but performs no bounds checking.
*
* Results are undefined if the index is out of range
* @param i
* @param value
*/
public double unsafeGet(int i) {
return get(i);
}
@Override
public final double get(int x, int y) {
throw new IllegalArgumentException(ErrorMessages.invalidIndex(this, x,y));
}
@Override
public final int dimensionality() {
return 1;
}
@Override
public final double get(int... indexes) {
if (indexes.length!=1) throw new IllegalArgumentException(ErrorMessages.invalidIndex(this, indexes));
return get(indexes[0]);
}
@Override
public final double get(long[] indexes) {
if (indexes.length!=1) throw new IllegalArgumentException(ErrorMessages.invalidIndex(this, indexes));
return get(Tools.toInt(indexes[0]));
}
@Override
public final double get(AIndex ix) {
if (ix.length()!=1) throw new IllegalArgumentException(ErrorMessages.invalidIndex(this, ix));
return get(ix.get(0));
}
@Override
public double get() {
throw new UnsupportedOperationException("Can't do 0-d get on a vector!");
}
@Override
public AScalar slice(int position) {
return VectorIndexScalar.wrap(this,position);
}
@Override
public Object sliceValue(int i) {
return get(i);
}
@Override
public AScalar slice(int dimension, int index) {
checkDimension(dimension);
return slice(index);
}
@Override
public int sliceCount() {
return length();
}
@Override
public List getSlices() {
return new ListWrapper(this);
}
@Override
public int[] getShape() {
return new int[] {length()};
}
@Override
public int[] getShapeClone() {
return new int[] {length()};
}
@Override
public final int getShape(int dim) {
if (dim==0) {
return length();
} else {
throw new IndexOutOfBoundsException(ErrorMessages.invalidDimension(this, dim));
}
}
@Override
public long[] getLongShape() {
return new long[] {length()};
}
@Override
public long elementCount() {
return length();
}
@Override
public long nonZeroCount() {
int n=length();
long result=0;
for (int i=0; i=n) return vs;
}
}
return vs;
}
@Override
public AVector subArray(int[] offsets, int[] shape) {
if (offsets.length!=1) throw new IllegalArgumentException(ErrorMessages.invalidIndex(this, offsets));
if (shape.length!=1) throw new IllegalArgumentException(ErrorMessages.invalidIndex(this, offsets));
return subVector(offsets[0],shape[0]);
}
@Override
public INDArray rotateView(int dimension, int shift) {
checkDimension(dimension);
return rotateView(shift);
}
@Override
public AVector rotateView(int shift) {
int n=length();
if (n==0) return this;
shift = Maths.mod(shift,n);
if (shift==0) return this;
return subVector(shift,n-shift).join(subVector(0,shift));
}
@Override
public AVector rotateCopy(int shift) {
return rotateView(shift).copy();
}
/**
* Obtains a sub-vector view that refers to this vector.
* Changes to the sub-vector will be reflected in this vector
*/
public AVector subVector(int offset, int length) {
int len=checkRange(offset,length);
if (length==0) return Vector0.INSTANCE;
if (length==len) return this;
return WrappedSubVector.wrap(this,offset,length);
}
/**
* Returns a new vector that refers to this vector joined to a second vector.
*
* Optimises the type of the returned vector to be as efficient as possible.
*
* @param second
* @return
*/
@Override
public AVector join(INDArray b) {
if (b.dimensionality()!=1) throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, b));
return join(b.asVector());
}
public AVector join(AVector second) {
if (second.length()==0) return this;
AVector ej=tryEfficientJoin(second);
if (ej!=null) return ej;
return JoinedVector.joinVectors(this,second);
}
/**
* Attempts to perform an efficient join with a second vector. An efficient join is guaranteed
* to be better than a simple JoinedVector(left,right)
*
* If possible, returns the joined vector. If not, returns null
*/
public AVector tryEfficientJoin(AVector second) {
return null;
}
@Override
public INDArray join(INDArray a, int dimension) {
checkDimension(dimension);
if (a instanceof AVector) {
return join((AVector)a);
}
if (a.dimensionality()!=1) throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, a));
return join(a.asVector());
}
@Override
public int compareTo(INDArray a) {
if (a instanceof AVector) {
return compareTo((AVector)a);
} else if (a.dimensionality()!=1) {
throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, a));
} else {
return compareTo(a.asVector());
}
}
/**
* Compares this vector to another vector
*/
public int compareTo(AVector a) {
int len=checkSameLength(a);
for (int i=0; i toList() {
ArrayList al=new ArrayList(length());
double[] ds=asDoubleArray();
if (ds==null) ds=toDoubleArray();
for (double d: getElements()) {
al.add(d);
}
return al;
}
@Override
public boolean epsilonEquals(INDArray a, double tolerance) {
if (a instanceof AVector) return epsilonEquals((AVector)a,tolerance);
if (a.dimensionality()!=1) throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, a));
int len=length();
if (len!=a.getShape(0)) throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, a));
for (int i = 0; i < len; i++) {
if (!Tools.epsilonEquals(unsafeGet(i), a.get(i), tolerance)) return false;
}
return true;
}
/**
* Returns true if this vector is approximately equal to another vector.
* A small default tolerance is used.
* @param v
* @return
*/
public boolean epsilonEquals(AVector v) {
return epsilonEquals(v,Vectorz.TEST_EPSILON);
}
@Override
public boolean epsilonEquals(AVector v,double tolerance) {
if (this == v) return true;
int len=checkSameLength(v);
for (int i = 0; i < len; i++) {
if (!Tools.epsilonEquals(unsafeGet(i), v.unsafeGet(i), tolerance)) return false;
}
return true;
}
/**
* Computes the hashcode of a vector.
*
* Currently defined to be equal to List.hashCode for a equivalent list of Double values,
* this may change in future versions.
*/
@Override
public int hashCode() {
int hashCode = 1;
int len=length();
for (int i = 0; i < len; i++) {
hashCode = 31 * hashCode + (Hash.hashCode(unsafeGet(i)));
}
return hashCode;
}
@Override
public double[] toDoubleArray() {
double[] result=new double[length()];
getElements(result,0);
return result;
}
@Override
public INDArray[] toSliceArray() {
int n=sliceCount();
INDArray[] al=new INDArray[n];
for (int i=0; imax) {
unsafeSet(i,max);
}
}
}
public void clampMax(double max) {
int len=length();
for (int i = 0; i < len; i++) {
double v=unsafeGet(i);
if (v>max) {
unsafeSet(i,max);
}
}
}
public void clampMin(double min) {
int len=length();
for (int i = 0; i < len; i++) {
double v=unsafeGet(i);
if (v100) sub(max); // ensure we don't overflow exp calculation
applyOp(Ops.EXP);
divide(elementSum());
}
@Override
public void square() {
applyOp(Ops.SQUARE);
}
@Override
public AVector squareCopy() {
AVector r=clone();
r.square();
return r;
}
@Override
public AVector sqrtCopy() {
AVector r=clone();
r.square();
return r;
}
/**
* Computes the tanh of every element in this vector. Mutates this vector.
*/
public void tanh() {
int len=length();
for (int i=0; i cols=m.getColumns();
for (int i=0; i al=a.getSliceViews();
INDArray result=Arrayz.newArray(al.get(0).getShape());
for (int i=0; iresult) {
result=comp;
}
}
return result;
}
/**
* Returns the index of the maximum absolute element of a vector
* @return
*/
public int maxAbsElementIndex() {
int len=length();
if (len==0) throw new IllegalArgumentException("Can't find maxAbsElementIndex of a 0-length vector");
int result=0;
double best=Math.abs(unsafeGet(0));
for (int i=1; ibest) {
result=i;
best=comp;
}
}
return result;
}
/**
* Returns the maximum element value in a vector. Synonym for elementMax()
* @return
*/
public final double maxElement() {
return elementMax();
}
/**
* Returns the index of the maximum element of a vector
* @return
*/
public int maxElementIndex() {
int len=length();
if (len==0) throw new IllegalArgumentException("Can't find maxElementIndex of a 0-length vector");
int result=0;
double best=unsafeGet(0);
for (int i=1; ibest) {
result=i;
best=comp;
}
}
return result;
}
/**
* Returns the minimum element value in a vector. Synonym for elementMin()
*/
public final double minElement() {
return elementMin();
}
/**
* Returns the index of the minimum element of a vector
*/
public int minElementIndex() {
int len=length();
if (len==0) throw new IllegalArgumentException("Can't find minElementIndex of a 0-length vector");
int result=0;
double best=unsafeGet(0);
for (int i=1; i0) multiply(1.0/d);
return d;
}
/**
* Returns a copy of this vector normalised to a Euclidean length of 1.0
*
* Has no effect on a zero-length vector (i.e. it will return a zero length vector)
*/
@Override
public AVector normaliseCopy() {
double d=magnitude();
if (d>0.0) return multiplyCopy(1.0/d);
return copy();
}
/**
* Negates all emlements of this vector in place.
*/
@Override
public void negate() {
multiply(-1.0);
}
@Override
public AVector negateCopy() {
return multiplyCopy(-1.0);
}
@Override
public final AVector scaleCopy(double d) {
return multiplyCopy(d);
}
@Override
public AVector shiftCopy(int shift) {
if (shift==0) return copy();
int n=length();
Vector v=Vector.createLength(n);
if ((shift>=n)||(shift<=-n)) return v;
if (shift<0) {
v.add(-shift,this,0,n+shift);
} else {
v.add(0,this,shift,n-shift);
}
return v;
}
@Override
public void pow(double exponent) {
if (exponent==1.0) return;
if (exponent==0.0) {
set(1.0);
return;
}
if (exponent==2.0) {
square();
return;
}
// default for arbitrary exponent
int len=length();
for (int i=0; i0) {
sb.append(unsafeGet(0));
for (int i = 1; i < length; i++) {
sb.append(',');
sb.append(unsafeGet(i));
}
}
sb.append(']');
return sb.toString();
}
/**
* Coerces this vector to the standard dense Vector format.
*
* May return the same vector is this is already a dense Vector, otherwise returns a Vector
* containing a new clone of the vector elements.
*/
@Override
public Vector toVector() {
return Vector.create(this);
}
/**
* Creates an immutable copy of a vector
* @return
*/
@Override
public AVector immutable() {
if (!isMutable()) return this;
return ImmutableVector.create(this);
}
/**
* Coerces to a mutable version of a vector. May or may not be a copy,
* but guaranteed to be fully mutable
* @return
*/
@Override
public AVector mutable() {
if (this.isFullyMutable()) {
return this;
} else {
return this.clone();
}
}
@Override
public AVector sparse() {
if (this instanceof ISparse) return this;
return Vectorz.createSparse(this);
}
@Override
public AVector dense() {
return denseClone();
}
@Override
public final Vector denseClone() {
return Vector.wrap(this.toDoubleArray());
}
/**
* Creates a new mutable vector representing the normalised value of this vector
*
* Returns null if the vector cannot be normalised (i.e. is a zero length vector)
* @return
*/
public AVector toNormal() {
double dd=elementSquaredSum();
if (dd==0.0) return null;
return scaleCopy(1.0/Math.sqrt(dd));
}
@Override
public List asElementList() {
return new ListWrapper(this);
}
@Override
public Iterator iterator() {
return new VectorIterator(this);
}
@Override
public final Iterator elementIterator() {
return iterator();
}
/**
* Adds source vector to this vector at the specified indexes which should map from source->this
* @param source
* @param sourceToDest
* @param factor
*/
public void addMultiple(Vector source, Index sourceToDest, double factor) {
int len=source.length();
if (len!=sourceToDest.length()) throw new IllegalArgumentException("Index length must match source length.");
double[] data=source.getArray();
for (int i=0; ithis
* @param source
* @param sourceToDest
* @param factor
*/
public void addMultiple(AVector source, Index sourceToDest, double factor) {
int len=source.length();
if (len!=sourceToDest.length()) throw new IllegalArgumentException("Index length must match source length.");
for (int i=0; i
Ads help maintain this website.