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.Index;
import mikera.matrixx.AMatrix;
import mikera.matrixx.Matrix;
import mikera.matrixx.Matrixx;
import mikera.matrixx.impl.BroadcastVectorMatrix;
import mikera.matrixx.impl.ColumnMatrix;
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.ImmutableVector;
import mikera.vectorz.impl.IndexedSubVector;
import mikera.vectorz.impl.JoinedVector;
import mikera.vectorz.impl.ListWrapper;
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.DoubleArrays;
import mikera.vectorz.util.ErrorMessages;
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<Double> implements IVector, Comparable<AVector> {
private static final long SPARSE_ELEMENT_THRESHOLD = 1000L;
// ================================================
// 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
public double get(long i) {
return get((int)i);
}
public void set(long i, double value) {
set((int)i,value);
}
@Override
public void set(int[] indexes, double value) {
if (indexes.length==1) {
set(indexes[0],value);
} if (indexes.length==0) {
fill(value);
} else {
throw new UnsupportedOperationException(""+indexes.length+"D set not supported on AVector");
}
}
public void unsafeSet(int i, double value) {
set(i,value);
}
public double unsafeGet(int i) {
return get(i);
}
protected void unsafeSetInteger(Integer i,double value) {
unsafeSet(i,value);
}
protected double unsafeGetInteger(Integer i) {
return unsafeGet(i);
}
@Override
public 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) {
return get(indexes[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) {
if (dimension!=0) throw new IllegalArgumentException(ErrorMessages.invalidDimension(this, dimension));
return slice(index);
}
@Override
public int sliceCount() {
return length();
}
@Override
public List<Double> getSlices() {
// TODO: consider returning a ListWrapper directly?
ArrayList<Double> al=new ArrayList<Double>();
int l=length();
for (int i=0; i<l; i++) {
al.add(unsafeGet(i));
}
return al;
}
@Override
public int[] getShape() {
return new int[] {length()};
}
@Override
public int[] getShapeClone() {
return new int[] {length()};
}
@Override
public 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; i++) {
if (unsafeGet(i)!=0.0) result++;
}
return result;
}
/**
* Return an double array specifying the values in this vector which are non-zero
*
* @return
*/
public double[] nonZeroValues() {
int len=length();
int n=(int)nonZeroCount();
if (n==0) return DoubleArrays.EMPTY;
double[] vs=new double[n];
int vi=0;
for (int i=0; i<len; i++) {
double d=unsafeGet(i);
if (d!=0.0) {
vs[vi++]=d;
if (vi>=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) {
if (dimension!=0) throw new IllegalArgumentException(ErrorMessages.invalidDimension(this, dimension));
return rotateView(shift);
}
public INDArray 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));
}
/**
* 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) {
if (dimension!=0) throw new IllegalArgumentException(ErrorMessages.invalidDimension(this, 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(AVector a) {
int len=checkSameLength(a);
for (int i=0; i<len; i++) {
double diff=unsafeGet(i)-a.unsafeGet(i);
if (diff<0.0) return -1;
if (diff>0.0) return 1;
}
return 0;
}
/**
* Test for equality on vectors. Returns true iff all values in the vector
* are identical
*/
@Override
public boolean equals(Object o) {
if (o instanceof AVector) return equals((AVector)o);
if (o instanceof INDArray) return equals((INDArray)o);
return false;
}
@Override
public boolean equals(AVector v) {
if (v instanceof ADenseArrayVector) {
return equals((ADenseArrayVector)v);
}
if (this==v) return true;
int len=length();
if (len != v.length())
return false;
for (int i = 0; i < len; i++) {
if (unsafeGet(i) != v.unsafeGet(i))
return false;
}
return true;
}
public boolean equals(ADenseArrayVector v) {
if (length()!=v.length()) return false;
return equalsArray(v.getArray(),v.getArrayOffset());
}
@Override
public boolean equals(INDArray v) {
if (v instanceof AVector) return equals((AVector)v);
if (v.dimensionality()!=1) return false;
int len=length();
if (len != v.getShape(0)) return false;
for (int i = 0; i < len; i++) {
if (unsafeGet(i) != v.get(i))
return false;
}
return true;
}
public List<Double> toList() {
ArrayList<Double> al=new ArrayList<Double>();
int len=length();
for (int i=0; i<len; i++) {
al.add(unsafeGet(i));
}
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;
}
@Override
public boolean epsilonEquals(INDArray a) {
return epsilonEquals(a,Vectorz.TEST_EPSILON);
}
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 final void copyTo(double[] arr) {
getElements(arr,0);
}
public final void copyTo(double[] arr, int offset) {
getElements(arr,offset);
}
/**
* Copies a subset of this vector to a specified destination array offset
*/
public void copyTo(int offset, double[] dest, int destOffset, int length) {
for (int i=0; i<length; i++) {
dest[destOffset+i]=unsafeGet(i+offset);
}
}
/**
* Copies a subset of this vector to a specified destination array offset
* using the given stride.
*
* Unsafe operation: performs no bounds checking
*/
public void copyTo(int offset, double[] dest, int destOffset, int length, int stride) {
for (int i=0; i<length; i++) {
dest[destOffset+i*stride]=unsafeGet(i+offset);
}
}
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; i<n; i++) {
al[i]=slice(i);
}
return al;
}
@Override
public double[] asDoubleArray() {
return null;
}
@Override
public void toDoubleBuffer(DoubleBuffer dest) {
int len=length();
for (int i=0; i<len; i++) {
dest.put(unsafeGet(i));
}
}
/**
* Copies a the contents of a vector to a vector at the specified offset
*/
public void copyTo(AVector dest, int destOffset) {
if (dest instanceof ADenseArrayVector) {
copyTo((ADenseArrayVector) dest,destOffset);
return;
}
int len = length();
if (destOffset+len>dest.length()) throw new IndexOutOfBoundsException();
for (int i=0; i<len; i++) {
dest.unsafeSet(destOffset+i,unsafeGet(i));
}
}
/**
* Copies a the contents of a vector to a vector at the specified offset
*/
public void copyTo(ADenseArrayVector dest, int destOffset) {
getElements(dest.getArray(),dest.getArrayOffset()+destOffset);
}
/**
* Copies a subset of this vector to a vector at the specified offset
*/
public void copyTo(int offset, AVector dest, int destOffset, int length) {
checkRange(offset,length);
dest.checkRange(destOffset,length);
for (int i=0; i<length; i++) {
dest.unsafeSet(destOffset+i,unsafeGet(offset+i));
}
}
/**
* Fills the entire vector with a given value
* @param value
*/
public void fill(double value) {
int len=length();
for (int i=0; i<len; i++) {
unsafeSet(i,value);
}
}
public void fillRange(int offset, int length, double value) {
subVector(offset,length).fill(value);
}
/**
* Clamps all values in the vector to a given range
* @param value
*/
@Override
public void clamp(double min, double max) {
int len=length();
for (int i = 0; i < len; i++) {
double v=unsafeGet(i);
if (v<min) {
unsafeSet(i,min);
} else if (v>max) {
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 (v<min) {
unsafeSet(i,min);
}
}
}
/**
* Multiplies the vector by a constant factor
* @param factor Factor by which to multiply each component of the vector
*/
public void multiply(double factor) {
int len=length();
for (int i = 0; i < len; i++) {
unsafeSet(i,unsafeGet(i)*factor);
}
}
public void multiply(INDArray a) {
if (a instanceof AVector) {
multiply((AVector)a);
} else if (a instanceof AScalar) {
multiply(((AScalar)a).get());
} else {
int dims=a.dimensionality();
switch (dims) {
case 0: multiply(a.get()); return;
case 1: multiply(a.asVector()); return;
default: throw new VectorzException("Can't multiply vector with array of dimensionality: "+dims);
}
}
}
public void multiply(AVector v) {
if (v instanceof ADenseArrayVector) {
multiply((ADenseArrayVector) v);
return;
}
int len=checkSameLength(v);
for (int i = 0; i < len; i++) {
unsafeSet(i,unsafeGet(i)*v.unsafeGet(i));
}
}
public void multiply(ADenseArrayVector v) {
checkSameLength(v);
multiply(v.getArray(),v.getArrayOffset());
}
public void multiply(double[] data, int offset) {
int len=length();
for (int i = 0; i < len; i++) {
unsafeSet(i,unsafeGet(i)*data[i+offset]);
}
}
public void multiplyTo(double[] data, int offset) {
int len=length();
for (int i = 0; i < len; i++) {
data[i+offset]*=unsafeGet(i);
}
}
public void divide(double factor) {
multiply(1.0/factor);
}
@Override
public void divide(INDArray a) {
if (a instanceof AVector) {
divide((AVector)a);
} else {
super.divide(a);
}
}
public void divide(AVector v) {
int len=checkSameLength(v);
for (int i = 0; i < len; i++) {
unsafeSet(i,unsafeGet(i)/v.unsafeGet(i));
}
}
public void divide(double[] data, int offset) {
int len=length();
for (int i = 0; i < len; i++) {
unsafeSet(i,unsafeGet(i)/data[i+offset]);
}
}
public void divideTo(double[] data, int offset) {
int len=length();
for (int i = 0; i < len; i++) {
data[i+offset]/=unsafeGet(i);
}
}
@Override
public void abs() {
int len=length();
for (int i=0; i<len; i++) {
double val=unsafeGet(i);
if (val<0) unsafeSet(i,-val);
}
}
@Override
public AVector absCopy() {
AVector v=clone();
v.abs();
return v;
}
@Override
public void log() {
int len=length();
for (int i=0; i<len; i++) {
double val=unsafeGet(i);
unsafeSet(i,Math.log(val));
}
}
@Override
public void signum() {
int len=length();
for (int i=0; i<len; i++) {
unsafeSet(i,Math.signum(unsafeGet(i)));
}
}
@Override
public void square() {
int len=length();
for (int i=0; i<len; i++) {
double x=unsafeGet(i);
unsafeSet(i,x*x);
}
}
@Override
public AVector squareCopy() {
AVector r=clone();
r.square();
return r;
}
@Override
public AVector sqrtCopy() {
AVector r=clone();
r.square();
return r;
}
public void tanh() {
int len=length();
for (int i=0; i<len; i++) {
double x=unsafeGet(i);
unsafeSet(i,Math.tanh(x));
}
}
public void logistic() {
int len=length();
for (int i=0; i<len; i++) {
double x=unsafeGet(i);
unsafeSet(i,Logistic.logisticFunction(x));
}
}
/**
* Scales the vector by another vector of the same size
* @param v
*/
public final void scale(AVector v) {
multiply(v);
}
/**
* Scales the vector up to a specific target magnitude
* @return the old magnitude of the vector
*/
public double scaleToMagnitude(double targetMagnitude) {
double oldMagnitude=magnitude();
multiply(targetMagnitude/oldMagnitude);
return oldMagnitude;
}
public void scaleAdd(double factor, AVector v) {
multiply(factor);
add(v);
}
public void interpolate(AVector v, double alpha) {
multiply(1.0-alpha);
addMultiple(v,alpha);
}
public void interpolate(AVector a, AVector b, double alpha) {
set(a);
interpolate(b,alpha);
}
public double magnitudeSquared() {
int len=length();
double total=0.0;
for (int i=0; i<len; i++) {
double x=unsafeGet(i);
total+=x*x;
}
return total;
}
@Override
public AVector getTranspose() {return this;}
@Override
public Vector getTransposeCopy() {
return Vector.create(this);
}
@Override
public final AVector getTransposeView() {return this;}
public AVector select(int... inds) {
if (isMutable()) {
return selectView(inds);
} else {
return selectClone(inds);
}
}
public AVector selectView(int... inds) {
return IndexedSubVector.wrap(this, inds.clone());
}
public AVector selectClone(int... inds) {
Vector v=Vector.createLength(inds.length);
double[] tdata=v.getArray();
for (int i=0; i<inds.length; i++) {
tdata[i]=get(inds[i]);
}
return v;
}
public AMatrix outerProduct(AVector a) {
int rc=length();
int cc=a.length();
Matrix m=Matrix.create(rc, cc);
int di=0;
for (int i=0; i<rc; i++) {
for (int j=0; j<cc; j++) {
m.data[di++]=unsafeGet(i)*a.unsafeGet(j);
}
}
return m;
}
public INDArray outerProduct(INDArray a) {
if (a instanceof AVector) {
return outerProduct((AVector)a);
}
return super.outerProduct(a);
}
public AScalar innerProduct(AVector v) {
return Scalar.create(dotProduct(v));
}
public Scalar innerProduct(Vector v) {
double[] data=v.getArray();
int vl=data.length;
checkLength(vl);
return Scalar.create(dotProduct(data,0));
}
public AVector innerProduct(AMatrix m) {
int cc=m.columnCount();
int rc=m.rowCount();
checkLength(rc);
Vector r=Vector.createLength(cc);
for (int i=0; i<cc; i++) {
r.unsafeSet(i,this.dotProduct(m.getColumn(i)));
}
return r;
}
public AVector innerProduct(AScalar s) {
return scaleCopy(s.get());
}
@Override
public INDArray innerProduct(INDArray a) {
if (a instanceof AVector) {
return innerProduct((AVector)a);
} else if (a instanceof AScalar) {
return innerProduct((AScalar)a);
} else if (a instanceof AMatrix) {
return innerProduct((AMatrix)a);
} else if (a.dimensionality()<=2) {
return innerProduct(Arrayz.create(a));
}
int len=checkLength(a.sliceCount());
List<INDArray> al=a.getSliceViews();
INDArray result=Arrayz.newArray(al.get(0).getShape());
for (int i=0; i<len; i++) {
// TODO: make faster with addMultiple?
result.add(al.get(i).innerProduct(get(i)));
}
return result;
}
@Override
public AVector innerProduct(double a) {
return scaleCopy(a);
}
/**
* Returns the dot product of this vector with another vector
*
* The vectors must have the same length: if not the result is undefined
*
* @param v
* @return
*/
public double dotProduct(AVector v) {
if (v instanceof ADenseArrayVector) return dotProduct((ADenseArrayVector)v);
int len=checkSameLength(v);
double total=0.0;
for (int i=0; i<len; i++) {
total+=unsafeGet(i)*v.unsafeGet(i);
}
return total;
}
/**
* Returns the dot product of this vector with a target Vector.
*
* @param v
* @return
*/
public double dotProduct(Vector v) {
v.checkLength(length());
return dotProduct(v.getArray(), 0);
}
public double dotProduct(ADenseArrayVector v) {
v.checkLength(length());
return dotProduct(v.getArray(), v.getArrayOffset());
}
/**
* Returns the dotProduct of this vector with the elements of another vector mapped to specified indexes in this vector.
*
* @param v
* @param ix
* @return
*/
public double dotProduct(AVector v, Index ix) {
int vl=v.length();
if (vl!=ix.length()) throw new IllegalArgumentException("Mismatched source vector and index lengths. Index length should be "+vl);
double result=0.0;
for (int i=0; i<vl; i++) {
result+=unsafeGet(ix.get(i))*v.unsafeGet(i);
}
return result;
}
/**
* Fast dot product with a double[] array. Performs no bounds checking.
*
* Likely to be faster than other dot product operations
*/
public abstract double dotProduct(double[] data, int offset);
/**
* Computes the crossProduct of this vector with another vector, and stores the result in this vector.
*
* Both vectors must have length 3.
*
* @param a
*/
public void crossProduct(AVector a) {
if(!((length()==3)&&(a.length()==3))) throw new IllegalArgumentException("Cross product requires length 3 vectors");
double x=unsafeGet(0);
double y=unsafeGet(1);
double z=unsafeGet(2);
double x2=a.unsafeGet(0);
double y2=a.unsafeGet(1);
double z2=a.unsafeGet(2);
double tx=y*z2-z*y2;
double ty=z*x2-x*z2;
double tz=x*y2-y*x2;
unsafeSet(0,tx);
unsafeSet(1,ty);
unsafeSet(2,tz);
}
/**
* Computes the crossProduct of this vector with another vector, and stores the result in this vector.
*
* Both vectors must have length 3.
*
* @param a
*/
public void crossProduct(Vector3 a) {
if(!(length()==3)) throw new IllegalArgumentException("Cross product requires length 3 vectors");
double x=unsafeGet(0);
double y=unsafeGet(1);
double z=unsafeGet(2);
double x2=a.x;
double y2=a.y;
double z2=a.z;
double tx=y*z2-z*y2;
double ty=z*x2-x*z2;
double tz=x*y2-y*x2;
unsafeSet(0,tx);
unsafeSet(1,ty);
unsafeSet(2,tz);
}
/**
* Returns the magnitude (Euclidean length) of the vector
* @return
*/
public double magnitude() {
return Math.sqrt(magnitudeSquared());
}
/**
* Returns the squared Euclidean distance to another vector.
* @param v
* @return
*/
public double distanceSquared(AVector v) {
int len=length();
double total=0.0;
for (int i=0; i<len; i++) {
double d=unsafeGet(i)-v.unsafeGet(i);
total+=d*d;
}
return total;
}
/**
* Returns the Euclidean distance to another vector.
* @param v
* @return
*/
public double distance(AVector v) {
return Math.sqrt(distanceSquared(v));
}
/**
* Returns the distance from this vector to another vector according to the L1 (Taxicab) norm.
*
* @param v
* @return
*/
public double distanceL1(AVector v) {
int len=length();
double total=0.0;
for (int i=0; i<len; i++) {
double d=unsafeGet(i)-v.unsafeGet(i);
total+=Math.abs(d);
}
return total;
}
public double distanceLinf(AVector v) {
int len=length();
double result=0.0;
for (int i=0; i<len; i++) {
double d=Math.abs(unsafeGet(i)-v.unsafeGet(i));
result=Math.max(result,d);
}
return result;
}
/**
* Returns the maximum absolute element value of a vector
* @return
*/
public double maxAbsElement() {
int len=length();
double result=0.0;
for (int i=0; i<len; i++) {
double comp=Math.abs(unsafeGet(i));
if (comp>result) {
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; i<len; i++) {
double comp=Math.abs(unsafeGet(i));
if (comp>best) {
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; i<len; i++) {
double comp=unsafeGet(i);
if (comp>best) {
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; i<len; i++) {
double comp=unsafeGet(i);
if (comp<best) {
result=i;
best=comp;
}
}
return result;
}
/**
* Normalises so that the maximum absolute element is 1.0
* Returns the previous maximum absolute element.
*/
public double normaliseMaxAbsElement() {
double scale=maxAbsElement();
if (scale!=0.0) scale(1.0/scale);
return scale;
}
/**
* Returns the sum of all elements in a vector
* @return
*/
@Override
public double elementSum() {
int len=length();
double result=0.0;
for (int i=0; i<len; i++) {
result+=unsafeGet(i);
}
return result;
}
public double elementProduct() {
int len=length();
double result=1.0;
for (int i=0; i<len; i++) {
result*=unsafeGet(i);
}
return result;
}
@Override
public double elementMax(){
return unsafeGet(maxElementIndex());
}
@Override
public double elementMin(){
return unsafeGet(minElementIndex());
}
@Override public final double elementSquaredSum() {
return magnitudeSquared();
}
@Override
public double elementPowSum(double exponent) {
int n=length();
double result=0.0;
for (int i=0; i<n; i++) {
double x=unsafeGet(i);
result+=Math.pow(x,exponent);
}
return result;
}
@Override
public double elementAbsPowSum(double exponent) {
int n=length();
double result=0.0;
for (int i=0; i<n; i++) {
double x=Math.abs(unsafeGet(i));
result+=Math.pow(x,exponent);
}
return result;
}
/**
* Returns the Euclidean angle between this vector and another vector
* @return angle in radians
*/
public double angle(AVector v) {
return Math.acos(dotProduct(v)/(v.magnitude()*this.magnitude()));
}
/**
* Normalises this vector to a magnitude of 1.0
*
* Has no effect on a zero-length vector (i.e. it will remain zero)
*
*/
@Override
public double normalise() {
double d=magnitude();
if (d>0) multiply(1.0/d);
return d;
}
/**
* Returns a copy of this vector normalised to a Euclidean length of 1.0
*/
@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() {
AVector r=clone();
r.negate();
return r;
}
@Override
public AVector scaleCopy(double d) {
AVector r=clone();
r.scale(d);
return r;
}
@Override
public void pow(double exponent) {
int len=length();
for (int i=0; i<len; i++) {
unsafeSet(i,Math.pow(unsafeGet(i),exponent));
}
}
/**
* Sets the vector to equal the value of another vector
*/
public void set(AVector src) {
if (src instanceof ADenseArrayVector) {
set((ADenseArrayVector)src);
} else {
int len=length();
if (src.length()!=len) throw new IllegalArgumentException("Source Vector of wrong size: "+src.length());
for (int i=0; i<len; i++) {
unsafeSet(i,src.unsafeGet(i));
}
}
}
/**
* Sets the vector equal to the value of an ADenseArrayVector
* @param v
*/
public void set(ADenseArrayVector v) {
if (v.length()!=length()) throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, v));
setElements(v.getArray(),v.getArrayOffset());
}
@Override
public void set(double a) {
fill(a);
}
@Deprecated
public void set(double[] data) {
setElements(data);
}
@Override
public void setElements(double... data) {
checkLength(data.length);
setElements(data,0);
}
@Override
public void setElements(double[] data,int offset) {
setElements(0,data,offset,length());
}
@Override
public void set(INDArray a) {
if (a instanceof AVector) {set((AVector)a); return;}
if (a.dimensionality()==1) {
int len=length();
for (int i=0; i<len; i++) {
unsafeSet(i,a.get(i));
}
} else {
throw new IllegalArgumentException("Cannot set vector using array of dimensonality: "+a.dimensionality());
}
}
@Override
public void setElements(int pos,double[] values, int offset, int length) {
checkRange(pos,length);
for (int i=0; i<length; i++) {
unsafeSet(i+pos,values[offset+i]);
}
}
@Override
public void getElements(double[] dest, int offset) {
copyTo(0,dest,offset,length());
}
/**
* Set the vector equal to an offset into another vector
*/
public void set(AVector src, int srcOffset) {
int len=length();
if ((srcOffset<0)||(len+srcOffset>src.length())) throw new IndexOutOfBoundsException();
for (int i=0; i<len; i++) {
unsafeSet(i,src.unsafeGet(srcOffset+i));
}
}
public long zeroCount() {
return elementCount()-nonZeroCount();
}
/**
* Clones the vector, creating a new mutable copy of all data.
*
* The clone is:
* - not guaranteed to be of the same type.
* - guaranteed to be fully mutable
* - guaranteed not to contain a reference (i.e. is a full deep copy)
*/
@Override
public AVector clone() {
return Vector.create(this);
}
@Override
public AVector copy() {
if (!isMutable()) return this;
return clone();
}
/**
* Clones the vector into a sparse mutable format
*/
public AVector sparseClone() {
return Vectorz.createSparseMutable(this);
}
@Override
public final AVector asVector() {
return this;
}
@Override
public INDArray reshape(int... dimensions) {
int ndims=dimensions.length;
if (ndims==1) {
return Vector.createFromVector(this, dimensions[0]);
} else if (ndims==2) {
return Matrixx.createFromVector(this, dimensions[0], dimensions[1]);
} else {
return Arrayz.createFromVector(this,dimensions);
}
}
@Override
public AVector reorder(int[] order) {
return reorder(0,order);
}
@Override
public AVector reorder(int dim, int[] order) {
if (dim!=0) throw new IndexOutOfBoundsException(ErrorMessages.invalidDimension(this, dim));
Vector result=Vector.createLength(order.length);
result.set(this, order);
return result;
}
/**
* Returns true if this vector is of a view type that references other vectors / data.
*/
@Override
public boolean isView() {
return true;
}
/**
* Returns true if this vector is mutable.
*/
@Override
public boolean isMutable() {
return true;
}
@Override
public boolean isElementConstrained() {
return false;
}
/**
* Returns true if this vector is fully mutable, i.e. can contain any unconstrained double values
*/
@Override
public boolean isFullyMutable() {
return isMutable();
}
/**
* Adds another vector to this one
*/
public void add(AVector v) {
if (v instanceof ADenseArrayVector) {
add((ADenseArrayVector)v);
return;
}
int vlength=v.length();
int length=length();
if (vlength != length) {
throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, v));
}
for (int i = 0; i < length; i++) {
addAt(i,v.unsafeGet(i));
}
}
public void add(ADenseArrayVector v) {
if (length() != v.length()) {
throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, v));
}
add(v.getArray(),v.getArrayOffset());
}
@Override
public void add(INDArray a) {
if (a instanceof AVector) {
add((AVector)a);
} else if (a instanceof AScalar) {
add(a.get());
}else {
super.add(a);
}
}
@Override
public INDArray addCopy(INDArray a) {
if (a instanceof AVector) {
return addCopy((AVector)a);
} else if (a.dimensionality()==1) {
if (length()!=a.getShape(0)) throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, a));
return addCopy(a.asVector());
} else if (a.dimensionality()==0) {
return addCopy(a.get());
} else {
return addCopy(a.broadcastLike(this));
}
}
@Override
public AVector addCopy(AVector a) {
// clone ensures mutability
AVector r=this.clone();
r.add(a);
return r;
}
public AVector addCopy(double a) {
// clone ensures mutability
AVector r=this.clone();
r.add(a);
return r;
}
@Override
public INDArray subCopy(INDArray a) {
if (a instanceof AVector) {
return subCopy((AVector)a);
} else if (a.dimensionality()==1) {
if (length()!=a.getShape(0)) throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, a));
return subCopy(a.asVector());
} else {
return subCopy(a.broadcastLike(this));
}
}
@Override
public AVector subCopy(AVector a) {
// clone ensures mutability
AVector r=this.clone();
r.sub(a);
return r;
}
@Override
public INDArray multiplyCopy(INDArray a) {
if (a instanceof AVector) {
return multiplyCopy((AVector)a);
} else if (a.dimensionality()==1) {
if (length()!=a.getShape(0)) throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, a));
return multiplyCopy(a.asVector());
} else {
return multiplyCopy(a.broadcastLike(this));
}
}
@Override
public INDArray divideCopy(INDArray a) {
if (a instanceof AVector) {
return divideCopy((AVector)a);
} else if (a.dimensionality()==1) {
if (length()!=a.getShape(0)) throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, a));
return divideCopy(a.asVector());
} else {
return divideCopy(a.broadcastLike(this));
}
}
@Override
public AVector multiplyCopy(AVector a) {
AVector r=this.clone();
r.multiply(a);
return r;
}
@Override
public AVector divideCopy(AVector a) {
AVector r=this.clone();
r.divide(a);
return r;
}
@Override
public void sub(INDArray a) {
if (a instanceof AVector) {
sub((AVector)a);
} else if (a instanceof AScalar) {
sub(a.get());
}else {
super.sub(a);
}
}
/**
* Adds part another vector to this one, starting at the specified offset in the source vector
* @param src
*/
public void add(AVector src, int srcOffset) {
int length=length();
if (!((srcOffset>=0)&&(srcOffset+length<=src.length()))) throw new IndexOutOfBoundsException();
for (int i = 0; i < length; i++) {
addAt(i,src.unsafeGet(srcOffset+i));
}
}
public void add(Vector v) {
add((ADenseArrayVector)v);
}
/**
* Adds another vector into this one, at the specified offset
* @param offset
* @param a
*/
public void add(int offset, AVector a) {
add(offset,a,0,a.length());
}
/**
* Adds another vector into this one, at the specified offset
* @param offset
* @param a
*/
public void add(int offset, AVector a, int aOffset, int length) {
for (int i = 0; i < length; i++) {
addAt(offset+i,a.unsafeGet(i+aOffset));
}
}
public void addProduct(AVector a, AVector b) {
addProduct(a,b,1.0);
}
public AVector addProductCopy(AVector a, AVector b) {
AVector r=clone();
r.addProduct(a,b);
return r;
}
public AVector addProductCopy(AVector a, AVector b, double factor) {
AVector r=clone();
r.addProduct(a,b,factor);
return r;
}
public void addProduct(AVector a, AVector b, double factor) {
checkSameLength(a,b);
if (factor==0.0) return;
if (a.isSparse()||b.isSparse()) {
AVector t=a.multiplyCopy(b);
addMultiple(t,factor);
} else {
addProduct(a,0,b,0,factor);
}
}
/**
* Checks that a vector is the specified length, throws an exception if not.
* @param length
* @return
*/
public int checkLength(int length) {
int len=length();
if (len!=length) throw new IllegalArgumentException("Vector length mismatch, expected length = "+length+", but got length = "+len);
return len;
}
/**
* Adds a scaled multiple of another vector to this one
* @param src
*/
public void addMultiple(AVector src, double factor) {
checkSameLength(src);
addMultiple(src,0,factor);
}
public AVector addMultipleCopy(AVector src, double factor) {
AVector r=clone();
r.addMultiple(src, factor);
return r;
}
public void addMultiple(AVector src, int srcOffset, double factor) {
addMultiple(0,src,srcOffset,length(),factor);
}
public void addMultiple(int offset, AVector src, int srcOffset, int length, double factor) {
checkRange(offset,length);
src.checkRange(srcOffset, length);
if (factor==0.0) return;
for (int i = 0; i < length; i++) {
addAt(i+offset,src.unsafeGet(i+srcOffset)*factor);
}
}
public void addMultiple(int offset, AVector v, double factor) {
addMultiple(offset,v,0,v.length(),factor);
}
/**
* Updates a weighted average of this vector with another vector
* @param v
*/
public void addWeighted(AVector v, double factor) {
multiply(1.0-factor);
addMultiple(v,factor);
}
/**
* Subtracts a vector from this vector
* @param v
*/
public void sub(AVector v) {
addMultiple(v,-1.0);
}
@Override
public void sub(double d) {
add(-d);
}
public void subAt(int i, double v) {
addAt(i,-v);
}
/**
* Returns true if this vector is a zero vector (all components zero)
* @return
*/
public boolean isZero() {
return isRangeZero(0,length());
}
/**
* Returns true if a sub-vector range is completely zero.
*
* Unsafe operation - does not perform bounds checking, results are undefined if sub-vector is out of range
*
* @param start
* @param length
* @return
*/
public boolean isRangeZero(int start, int length) {
for (int i=0; i<length; i++) {
if (unsafeGet(start+i)!=0.0) return false;
}
return true;
}
/**
* Returns true if the vector has unit length
* @return
*/
public boolean isUnitLengthVector() {
return isUnitLengthVector(Vectorz.TEST_EPSILON);
}
public boolean isUnitLengthVector(double tolerance) {
double mag=magnitudeSquared();
return Math.abs(mag-1.0)<tolerance;
}
@Override
public final boolean isSameShape(INDArray a) {
if (a instanceof AVector) return isSameShape((AVector)a);
if (a.dimensionality()!=1) return false;
return length()==a.getShape(0);
}
public boolean isSameShape(AVector a) {
return length()==a.length();
}
/**
* Utility function to check vector length and throw an exception in not same shape
*/
protected int checkSameLength(AVector v) {
int len=length();
if (len!=v.length()) throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, v));
return len;
}
protected int checkSameLength(AVector v, AVector w) {
int len=length();
if (len!=v.length()) throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, v));
if (len!=w.length()) throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, w));
return len;
}
/**
* Utility function to check vector range and throw an exception if not valid.
*
* Returns the length of this vector
*/
public int checkRange(int offset, int length) {
int len=this.length();
int end=offset+length;
if ((offset<0)||(end>len)) {
throw new IndexOutOfBoundsException(ErrorMessages.invalidRange(this, offset, length));
}
return len;
}
/**
* Utility function to check an index and throw an exception in not in bounds.
* Returns the vector length
*/
protected int checkIndex(int i) {
int len=length();
if ((i<0)||(i>=len)) throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, i));
return len;
}
protected int checkSameLength(ASizedVector v) {
int len=length();
if (len!=v.length()) throw new IllegalArgumentException(ErrorMessages.incompatibleShapes(this, v));
return len;
}
public void projectToPlane(AVector normal, double distance) {
assert(Tools.epsilonEquals(normal.magnitude(), 1.0));
double d=dotProduct(normal);
addMultiple(normal,distance-d);
}
/**
* Subtracts a scaled multiple of another vector from this vector
* @param v
*/
public void subMultiple(AVector v, double factor) {
addMultiple(v,-factor);
}
@Override
public String toString() {
StringBuilder sb=new StringBuilder();
int length=length();
sb.append('[');
if (length>0) {
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 thsis 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 {
if (elementCount()>SPARSE_ELEMENT_THRESHOLD) {
return Vectorz.createSparseMutable(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
* @return
*/
public AVector toNormal() {
Vector v= Vector.create(this);
v.normalise();
return v;
}
public List<Double> asElementList() {
return new ListWrapper(this);
}
@Override
public Iterator<Double> iterator() {
return new VectorIterator(this);
}
@Override
public Iterator<Double> elementIterator() {
return iterator();
}
public void set(IVector vector) {
int len=length();
if (len!=vector.length()) throw new IllegalArgumentException(ErrorMessages.mismatch(this, vector));
for (int i=0; i<len; i++) {
this.unsafeSet(i,vector.get(i));
}
}
/**
* 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; i<len; i++) {
int j=sourceToDest.data[i];
this.addAt(j,data[i]*factor);
}
}
/**
* 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(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<len; i++) {
int j=sourceToDest.data[i];
this.addAt(j,source.unsafeGet(i)*factor);
}
}
/**
* Adds to this vector at taking values from source at the specified indexes which should map from this->source
* @param source
* @param destToSource
* @param factor
*/
public void addMultiple(Index destToSource, Vector source, double factor) {
int len=this.length();
if (len!=destToSource.length()) throw new IllegalArgumentException("Index length must match this vector length.");
double[] data=source.getArray();
for (int i=0; i<len; i++) {
int j=destToSource.data[i];
this.addAt(i,data[j]*factor);
}
}
/**
* Adds to this vector at taking values from source at the specified indexes which should map from this->source
* @param source
* @param destToSource
* @param factor
*/
public void addMultiple(Index destToSource, AVector source, double factor) {
int len=this.length();
if (len!=destToSource.length()) throw new IllegalArgumentException("Index length must match this vector length.");
for (int i=0; i<len; i++) {
int j=destToSource.data[i];
this.addAt(i,source.get(j)*factor);
}
}
/**
* sets the vector using values indexed from another vector
*/
public final void set(AVector source, Index indexes) {
set(source,indexes.data);
}
/**
* sets the vector using values indexed from another vector
*/
public void set(AVector source, int[] indexes) {
int len=length();
if (len!=indexes.length) throw new IllegalArgumentException("Index length must match this vector length.");
for (int i=0; i<len ; i++) {
unsafeSet(i, source.get(indexes[i]));
}
}
/**
* Adds this vector to a double[] array, starting at the specified offset.
*
* @param array
* @param offset
*/
@Override
public void addToArray(double[] array, int offset) {
addToArray(0,array,offset,length());
}
/**
* Adds this vector to a double[] array, using the specified offset and stride into the target array
*/
public void addToArray(double[] data, int offset, int stride) {
int n=length();
for (int i=0; i<n; i++) {
data[offset+i*stride]+=unsafeGet(i);
}
}
public void addToArray(int offset, double[] array, int arrayOffset, int length) {
checkRange(offset,length);
for (int i=0; i<length; i++) {
array[i+arrayOffset]+=unsafeGet(i+offset);
}
}
public void addMultipleToArray(double factor, int offset, double[] array, int arrayOffset, int length) {
checkRange(offset,length);
for (int i=0; i<length; i++) {
array[i+arrayOffset]+=factor*unsafeGet(i+offset);
}
}
public void addProductToArray(double factor, int offset, AVector other,int otherOffset, double[] array, int arrayOffset, int length) {
if (other instanceof ADenseArrayVector) {
addProductToArray(factor,offset,(ADenseArrayVector)other,otherOffset,array,arrayOffset,length);
return;
}
if((offset<0)||(offset+length>length())) throw new IndexOutOfBoundsException();
for (int i=0; i<length; i++) {
array[i+arrayOffset]+=factor*unsafeGet(i+offset)*other.get(i+otherOffset);
}
}
public void addProductToArray(double factor, int offset, ADenseArrayVector other,int otherOffset, double[] array, int arrayOffset, int length) {
if((offset<0)||(offset+length>length())) throw new IndexOutOfBoundsException();
double[] otherArray=other.getArray();
otherOffset+=other.getArrayOffset();
for (int i=0; i<length; i++) {
array[i+arrayOffset]+=factor*unsafeGet(i+offset)*otherArray[i+otherOffset];
}
}
public void addProduct(AVector a, int aOffset, AVector b, int bOffset, double factor) {
int length=length();
a.checkRange(aOffset, length);
b.checkRange(bOffset, length);
for (int i=0; i<length; i++) {
addAt(i, (a.unsafeGet(i+aOffset)* b.unsafeGet(i+bOffset)*factor));
}
}
@Override
public void applyOp(IOperator op) {
if (op instanceof Op) {
applyOp((Op) op);
}
int len=length();
for (int i=0; i<len; i++) {
unsafeSet(i,op.apply(unsafeGet(i)));
}
}
@Override
public void applyOp(Op op) {
int len=length();
for (int i=0; i<len; i++) {
unsafeSet(i,op.apply(unsafeGet(i)));
}
}
@Override
public AVector applyOpCopy(Op op) {
AVector r=clone();
r.applyOp(op);
return r;
}
/**
* Adds a value to a specific element of the vector
*
* This function does not perform bounds checking, i.e. is an unsafe operation
*
* @param i
* @param v
*/
public void addAt(int i, double v) {
unsafeSet(i,unsafeGet(i)+v);
}
/**
* Scales this vector and adds a constant to every element
*/
public void scaleAdd(double factor, double constant) {
scale(factor);
add(constant);
}
@Override
public void add(double constant) {
int len=length();
for (int i=0; i<len; i++) {
addAt(i,constant);
}
}
/**
* Adds to this vector from a given double array.
* @param data
* @param offset
*/
public void add(double[] data, int offset) {
int len=length();
for (int i=0; i<len; i++) {
addAt(i,data[i+offset]);
}
}
public void add(double[] data) {
add(data,0);
}
/**
* Returns an exact clone of this vector, i.e. of the same type
* @return
*/
public abstract AVector exactClone();
/**
* Returns true if this vector exactly matches a double[] array.
* @param data
* @return
*/
@Override
public boolean equalsArray(double[] data) {
if (length()!=data.length) return false;
return equalsArray(data,0);
}
@Override
public boolean elementsEqual(double value) {
int length=length();
for (int i=0; i<length; i++) {
if (unsafeGet(i)!=value) return false;
}
return true;
}
/**
* Returns true if this vector exactly matches the elements in double[] array, starting
* from the specified offset
*
* @param data
* @return
*/
public boolean equalsArray(double[] data, int offset) {
int len=length();
for (int i=0; i<len; i++) {
if (unsafeGet(i)!=data[offset+i]) return false;
}
return true;
}
/**
* Set a subrange of this vector from a double array
*/
public void setRange(int offset, double[] data, int dataOffset, int length) {
if ((offset<0)||(offset+length>this.length())) throw new IndexOutOfBoundsException(ErrorMessages.invalidRange(this, offset, length));
for (int i=0; i<length; i++) {
unsafeSet(offset+i,data[dataOffset+i]);
}
}
@Override
public INDArray broadcast(int... targetShape) {
int tdims=targetShape.length;
int len=this.length();
if (tdims<1) {
throw new IllegalArgumentException(ErrorMessages.incompatibleBroadcast(this, targetShape));
} else if (tdims==1) {
if (targetShape[0]!=len) {
throw new IllegalArgumentException(ErrorMessages.incompatibleBroadcast(this, targetShape));
}
return this;
} else if (tdims==2) {
int n=targetShape[0];
if (len!=targetShape[1]) throw new IllegalArgumentException(ErrorMessages.incompatibleBroadcast(this, targetShape));
AVector[] vs=new AVector[n];
for (int i=0; i<n; i++) {vs[i]=this;}
return Matrixx.createFromVectors(vs);
} else {
int n=targetShape[0];
if (len!=targetShape[tdims-1]) throw new IllegalArgumentException(ErrorMessages.incompatibleBroadcast(this, targetShape));
INDArray s=broadcast(Arrays.copyOfRange(targetShape, 1, tdims));
return SliceArray.repeat(s,n);
}
}
@Override
public INDArray broadcastLike(INDArray target) {
if (target instanceof AVector) {
return broadcastLike((AVector)target);
} else if (target instanceof AMatrix) {
return broadcastLike((AMatrix)target);
}
return broadcast(target.getShape());
}
@Override
public AVector broadcastLike(AVector target) {
if (this.length()==target.length()) {
return this;
} else {
throw new IllegalArgumentException(ErrorMessages.incompatibleBroadcast(this, target));
}
}
@Override
public AMatrix broadcastLike(AMatrix target) {
int cc=target.columnCount();
if (length()==cc) {
int rc=target.rowCount();
if (rc==1) return RowMatrix.wrap(this);
return BroadcastVectorMatrix.wrap(this, rc);
} else {
throw new IllegalArgumentException(ErrorMessages.incompatibleBroadcast(this, target));
}
}
@Override
public void validate() {
if (length()<0) throw new VectorzException("Illegal length! Length = "+length());
super.validate();
}
/**
* Returns an Index indicating which elements of this vector are defined as non-sparse.
*
* A sparse index must be zero. A non-sparse element may be zero, but is expected be non-zero.
*
* @return
*/
public Index nonSparseIndex(){
int n=(int)nonZeroCount();
int length=length();
Index ind=Index.createLength(n);
int di=0;
for (int i=0; i<length; i++) {
double v=unsafeGet(i);
if (v!=0.0) {
ind.data[di++]=i;
}
}
return ind;
}
/**
* Return an int array specifying the positions in this vector which are non-zero
*
* @return
*/
public int[] nonZeroIndices() {
int n=(int)nonZeroCount();
int[] ret=new int[n];
int length=length();
int di=0;
for (int i=0; i<length; i++) {
if (unsafeGet(i)!=0.0) ret[di++]=i;
}
if (di!=n) throw new VectorzException("Invalid non-zero index count. Maybe concurrent modification of vector?");
return ret;
}
@Override
public AVector multiplyCopy(double d) {
AVector r= clone();
r.multiply(d);
return r;
}
@Override
public boolean hasUncountable() {
int len = length();
for(int i=0; i<len; i++) {
double v=unsafeGet(i);
if (Double.isNaN(v) || Double.isInfinite(v)) {
return true;
}
}
return false;
}
public AMatrix asColumnMatrix() {
return ColumnMatrix.wrap(this);
}
}