package mikera.vectorz.impl;
import java.util.Arrays;
import mikera.indexz.Index;
import mikera.vectorz.AVector;
import mikera.vectorz.util.DoubleArrays;
import mikera.vectorz.util.IntArrays;
import mikera.vectorz.util.VectorzException;
/**
* Base class containing common implementations for sparse indexed vectors
* @author Mike
*
*/
public abstract class ASparseIndexedVector extends ASparseVector {
private static final long serialVersionUID = -8106136233328863653L;
public ASparseIndexedVector(int length) {
super(length);
}
abstract double[] internalData();
abstract Index internalIndex();
int[] internalIndexArray() {
return internalIndex().data;
}
@Override
public boolean isZero() {
return DoubleArrays.isZero(internalData());
}
@Override
public boolean isRangeZero(int start, int length) {
int end=start+length;
Index index=internalIndex();
double[] data=internalData();
int si=index.seekPosition(start);
int di=index.seekPosition(end);
for (int i=si; i<di; i++) {
if (data[i]!=0.0) return false;
}
return true;
}
@Override
public double elementSum() {
return DoubleArrays.elementSum(internalData());
}
@Override
public double magnitudeSquared() {
return DoubleArrays.elementSquaredSum(internalData());
}
@Override
public long nonZeroCount() {
return DoubleArrays.nonZeroCount(internalData());
}
@Override
public double dotProduct(double[] data, int offset) {
double result=0.0;
double[] tdata=this.internalData();
int[] ixs=internalIndex().data;
for (int j=0; j<tdata.length; j++) {
result+=tdata[j]*data[offset+ixs[j]];
}
return result;
}
@Override
public final double dotProduct(AVector v) {
if (v instanceof ADenseArrayVector) return dotProduct((ADenseArrayVector)v);
double result=0.0;
double[] data=internalData();
int[] ixs=internalIndexArray();
for (int j=0; j<data.length; j++) {
result+=data[j]*v.unsafeGet(ixs[j]);
}
return result;
}
@Override
public double dotProduct(ADenseArrayVector v) {
double[] array=v.getArray();
int offset=v.getArrayOffset();
return dotProduct(array,offset);
}
@Override
public int[] nonZeroIndices() {
int n=(int)nonZeroCount();
double[] data=internalData();
Index index=internalIndex();
int[] ret=new int[n];
int di=0;
for (int i=0; i<data.length; i++) {
if (data[i]!=0.0) ret[di++]=index.get(i);
}
if (di!=n) throw new VectorzException("Invalid non-zero index count. Maybe concurrent modification of vector?");
return ret;
}
@Override
public void addToArray(int offset, double[] array, int arrayOffset, int length) {
assert((offset>=0)&&(offset+length<=this.length));
double[] data=internalData();
Index index=internalIndex();
int start=index.seekPosition(offset);
int[] ixs=index.data;
int dataLength=data.length;
for (int j=start; j<dataLength; j++) {
int di=ixs[j]-offset; // index relative to offset
if (di>=length) return;
array[arrayOffset+di]+=data[j];
}
}
@Override
public void addToArray(double[] dest, int offset) {
double[] data=internalData();
int[] ixs=internalIndexArray();
int dataLength=data.length;
for (int i=0; i<dataLength; i++) {
dest[offset+ixs[i]]+=data[i];
}
}
@Override
public void addToArray(double[] dest, int offset, int stride) {
double[] data=internalData();
int[] ixs=internalIndexArray();
for (int i=0; i<data.length; i++) {
dest[offset+ixs[i]*stride]+=data[i];
}
}
@Override
public void addMultipleToArray(double factor,int offset, double[] array, int arrayOffset, int length) {
int aOffset=arrayOffset-offset;
double[] data=internalData();
Index index=internalIndex();
int[] ixs=index.data;
int start=index.seekPosition(offset);
for (int i=start; i<data.length; i++) {
int di=ixs[i];
// if (di<offset) continue; not needed because of seekPosition!
if (di>=(offset+length)) return;
array[di+aOffset]+=factor*data[i];
}
}
@Override
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;
}
assert(offset>=0);
assert(offset+length<=length());
double[] data=internalData();
Index index=internalIndex();
int[] ixs=index.data;
int dataLength=data.length;
for (int j=index.seekPosition(offset); j<dataLength; j++) {
int i =ixs[j]-offset; // index relative to offset
if (i>=length) return;
array[i+arrayOffset]+=factor*data[j]*other.get(i+otherOffset);
}
}
@Override
public void addProductToArray(double factor, int offset, ADenseArrayVector other,int otherOffset, double[] array, int arrayOffset, int length) {
assert(offset>=0);
assert(offset+length<=length());
double[] otherArray=other.getArray();
otherOffset+=other.getArrayOffset();
double[] data=internalData();
Index index=internalIndex();
int[] ixs=index.data;
int dataLength=data.length;
for (int j=index.seekPosition(offset); j<dataLength; j++) {
int i =ixs[j]-offset; // index relative to offset
if (i>=length) return;
array[i+arrayOffset]+=factor*data[j]*otherArray[i+otherOffset];
}
}
@Override
public boolean equalsArray(double[] ds, int offset) {
double[] data=internalData();
int[] ixs=internalIndexArray();
int n=data.length;
if (n==0) return DoubleArrays.isZero(ds, offset, length);
int di=0;
int i=0;
while (di<n) {
int t=ixs[di];
while (i<t) {
if (ds[offset+i]!=0.0) return false;
i++;
}
if (ds[offset+t]!=data[di]) return false;
i++;
di++;
}
// check any remaining segment of array
return DoubleArrays.isZero(ds, offset+i, length-i);
}
@Override
public boolean equals(AVector v) {
int len=length();
if (v.length()!=len) return false;
if (v instanceof ADenseArrayVector) {
ADenseArrayVector vv=(ADenseArrayVector) v;
return equalsArray(vv.getArray(),vv.getArrayOffset());
}
double[] data=internalData();
int[] ixs=internalIndexArray();
int n=ixs.length;
int start=0;
for (int i=0; i<n; i++) {
int pos=ixs[i];
if (!v.isRangeZero(start, pos-start)) return false;
if (v.unsafeGet(pos)!=data[i]) return false;
start=pos+1;
}
return v.isRangeZero(start, len-start);
}
/**
* Create a clone of this sparse indexed vector including the new indexes specified
* Intended to allow fast subsequent modification
*/
public final SparseIndexedVector cloneIncludingIndices(int [] ixs) {
Index index=internalIndex();
int[] nixs = IntArrays.mergeSorted(index.data,ixs);
double[] data=internalData();
int nl=nixs.length;
double[] ndata=new double[nl];
int si=0;
for (int i=0; i<nl; i++) {
int z=index.data[si];
if (z==nixs[i]) {
ndata[i]=data[si];
si++;
if (si>=data.length) break;
}
}
return SparseIndexedVector.wrap(length, nixs, ndata);
}
@Override
public final void getElements(double[] array, int offset) {
Arrays.fill(array,offset,offset+length,0.0);
copySparseValuesTo(array,offset);
}
@Override public final void copyTo(AVector v, int offset) {
if (v instanceof ADenseArrayVector) {
ADenseArrayVector av=(ADenseArrayVector)v;
getElements(av.getArray(),av.getArrayOffset()+offset);
}
v.fillRange(offset,length,0.0);
double[] data=internalData();
int[] ixs=internalIndexArray();
for (int i=0; i<data.length; i++) {
v.unsafeSet(offset+ixs[i],data[i]);
}
}
/**
* Copy only the sparse values in this vector to a target array. Other values in the target array are unchanged
* @param array
* @param offset
*/
protected final void copySparseValuesTo(double[] array, int offset) {
Index index=internalIndex();
int[] ixs = index.data;
double[] data=internalData();
for (int i=0; i<data.length; i++) {
int di=ixs[i];
array[offset+di]=data[i];
}
}
}