package mikera.vectorz.impl;
import java.nio.DoubleBuffer;
import java.util.Arrays;
import mikera.arrayz.INDArray;
import mikera.arrayz.impl.IDenseArray;
import mikera.vectorz.AVector;
import mikera.vectorz.Op;
import mikera.vectorz.Vector;
import mikera.vectorz.Vectorz;
import mikera.vectorz.util.DoubleArrays;
import mikera.vectorz.util.IntArrays;
import mikera.vectorz.util.VectorzException;
/**
* Base class for mutable dense vectors backed by a double[] array with a fixed stride of 1
*
* The double array can be directly accessed for performance purposes
*
* @author Mike
*/
@SuppressWarnings("serial")
public abstract class ADenseArrayVector extends AStridedVector implements IDenseArray {
protected ADenseArrayVector(int length, double[] data) {
super(length,data);
}
/**
* ADenseArrayVector has a fixed stride of 1, which enables efficient operations
* on arrays
*/
@Override
public final int getStride() {
return 1;
}
/**
* Returns a vector referencing a sub-vector of the current vector
*
* @param offset
* @param length
* @return
*/
public AVector subVector(int offset, int length) {
int len = checkRange(offset,length);
if (length == 0) return Vector0.INSTANCE;
if (length == len) return this;
return new ArraySubVector(this, offset, length);
}
@Override
public ArrayIndexScalar slice(int position) {
checkIndex(position);
return new ArrayIndexScalar(getArray(), getArrayOffset() + position);
}
@Override
public AVector selectView(int... inds) {
inds=inds.clone();
IntArrays.add(inds,getArrayOffset());
return IndexedArrayVector.wrap(getArray(), inds);
}
public boolean isPackedArray() {
return (getArrayOffset() == 0) && (length() == getArray().length);
}
@Override
public boolean isView() {
// ArrayVector is usually a view
return true;
}
@Override
public boolean isZero() {
return DoubleArrays.isZero(getArray(), getArrayOffset(), length());
}
@Override
public boolean isRangeZero(int start, int length) {
return DoubleArrays.isZero(getArray(), getArrayOffset()+start, length);
}
@Override
public void toDoubleBuffer(DoubleBuffer dest) {
dest.put(getArray(), getArrayOffset(), length());
}
@Override
public void getElements(double[] data, int offset) {
System.arraycopy(getArray(), getArrayOffset(), data, offset, length());
}
@Override
public ADenseArrayVector dense() {
// we are already dense!
return this;
}
@Override
public void fillRange(int offset, int length, double value) {
assert ((offset >= 0) && (length >= 0) && ((offset + length) <= length()));
double[] arr = getArray();
int off = getArrayOffset();
Arrays.fill(arr, off + offset, off + offset + length, value);
}
@Override
public void set(AVector a) {
checkSameLength(a);
a.getElements(getArray(), getArrayOffset());
}
@Override
public void set(AVector a, int offset) {
assert (offset >= 0);
assert (offset + length() <= a.length());
a.copyTo(offset, this, 0, length());
}
@Override
public void setRange(int offset, double[] data, int dataOffset, int length) {
System.arraycopy(data, dataOffset, getArray(), getArrayOffset()
+ offset, length);
}
@Override
public void setElements(int pos,double[] values, int offset, int length) {
checkRange(pos,length);
System.arraycopy(values, offset, getArray(), getArrayOffset()+pos, length);
}
@Override
public abstract double get(int i);
@Override
public abstract void set(int i, double value);
@Override
public abstract double unsafeGet(int i);
@Override
public abstract void unsafeSet(int i, double value);
@Override
public void add(AVector src) {
src.addToArray(0, getArray(), getArrayOffset(), length());
}
@Override
public void add(ADenseArrayVector v) {
add(v, 0);
}
@Override
public void add(AVector src, int srcOffset) {
src.addToArray(srcOffset, getArray(), getArrayOffset(), length);
}
@Override
public void add(int offset, AVector src) {
src.addToArray(0, getArray(), getArrayOffset() + offset, length);
}
public void add(int offset, ADenseArrayVector src) {
int length = src.length();
DoubleArrays.add(src.getArray(), src.getArrayOffset(), getArray(),
offset + getArrayOffset(), length);
}
public void add(int offset, ADenseArrayVector src, int srcOffset, int length) {
DoubleArrays.add(src.getArray(), src.getArrayOffset() + srcOffset,
getArray(), offset + getArrayOffset(), length);
}
@Override
public void addMultiple(AVector v, double factor) {
int length = checkSameLength(v);
v.addMultipleToArray(factor, 0, getArray(), getArrayOffset(), length);
}
@Override
public void scaleAdd(double factor, double constant) {
DoubleArrays.scaleAdd(getArray(), getArrayOffset(), length(), factor,
constant);
}
@Override
public void add(double constant) {
DoubleArrays.add(getArray(), getArrayOffset(), length(), constant);
}
@Override
public void addProduct(AVector a, int aOffset, AVector b, int bOffset,
double factor) {
int length = length();
double[] array = getArray();
int offset = getArrayOffset();
a.addProductToArray(factor, aOffset, b, bOffset, array, offset, length);
}
@Override
public void addToArray(int offset, double[] destData, int destOffset, int length) {
double[] data = getArray();
int dataOffset = getArrayOffset() + offset;
DoubleArrays.add(data, dataOffset, destData, destOffset, length);
}
@Override
public void addToArray(double[] dest, int offset, int stride) {
double[] data = getArray();
int dataOffset = getArrayOffset();
for (int i = 0; i < length; i++) {
dest[offset + i*stride] += data[dataOffset + i];
}
}
@Override
public void addProduct(AVector a, AVector b) {
int len = length();
assert (len == a.length());
assert (len == b.length());
double[] array = getArray();
int offset = getArrayOffset();
if (b instanceof ADenseArrayVector) {
a.addProductToArray(1.0, 0, (ADenseArrayVector)b, 0, array, offset, len);
} else {
a.addProductToArray(1.0, 0, b, 0, array, offset, len);
}
}
@Override
public void addProduct(AVector a, AVector b, double factor) {
if (factor==0) return;
int len = length();
assert (len == a.length());
assert (len == b.length());
double[] array = getArray();
int offset = getArrayOffset();
if (b instanceof ADenseArrayVector) {
a.addProductToArray(factor, 0, (ADenseArrayVector)b, 0, array, offset, len);
} else {
a.addProductToArray(factor, 0, b, 0, array, offset, len);
}
}
@Override
public void addMultipleToArray(double factor, int offset, double[] array,
int arrayOffset, int length) {
if (factor==0) return;
double[] data = getArray();
int dataOffset = getArrayOffset() + offset;
for (int i = 0; i < length; i++) {
array[i + arrayOffset] += factor * data[i + dataOffset];
}
}
@Override
public void addProductToArray(double factor, int offset, AVector other,
int otherOffset, double[] array, int arrayOffset, int length) {
if (factor==0) return;
if (other instanceof ADenseArrayVector) {
addProductToArray(factor, offset, (ADenseArrayVector) other,
otherOffset, array, arrayOffset, length);
return;
}
assert (offset >= 0);
assert (offset + length <= length());
double[] thisArray = getArray();
offset += getArrayOffset();
for (int i = 0; i < length; i++) {
array[i + arrayOffset] += factor * thisArray[i + offset]
* other.unsafeGet(i + otherOffset);
}
}
@Override
public void addProductToArray(double factor, int offset,
ADenseArrayVector other, int otherOffset, double[] array,
int arrayOffset, int length) {
if (factor==0) return;
assert (offset >= 0);
assert (offset + length <= length());
double[] otherArray = other.getArray();
otherOffset += other.getArrayOffset();
double[] thisArray = getArray();
offset += getArrayOffset();
for (int i = 0; i < length; i++) {
array[i + arrayOffset] += factor * thisArray[i + offset]
* otherArray[i + otherOffset];
}
}
public void add(ADenseArrayVector src, int srcOffset) {
src.checkRange(srcOffset,length);
double[] vdata = src.getArray();
double[] data = getArray();
int offset = getArrayOffset();
int voffset = src.getArrayOffset() + srcOffset;
for (int i = 0; i < length; i++) {
data[offset + i] += vdata[voffset + i];
}
}
@Override
public void add(double[] data, int offset) {
DoubleArrays.add(data, offset, getArray(), getArrayOffset(), length);
}
@Override
public void addAt(int i, double v) {
assert ((i >= 0) && (i < length())); // just an assert since this is unchecked
double[] data = getArray();
int offset = getArrayOffset();
data[i + offset] += v;
}
@Override
public double dotProduct(double[] data, int offset) {
return DoubleArrays.dotProduct(getArray(), getArrayOffset(), data, offset, length());
}
@Override
public double dotProduct(AVector v) {
int length = checkSameLength(v);
if (v instanceof ADenseArrayVector) {
ADenseArrayVector vv = (ADenseArrayVector) v;
return DoubleArrays.dotProduct(getArray(), getArrayOffset(),
vv.getArray(), vv.getArrayOffset(), length);
} else {
return v.dotProduct(this.getArray(), this.getArrayOffset());
}
}
@Override
public void abs() {
DoubleArrays.abs(getArray(), getArrayOffset(), length());
}
@Override
public void log() {
DoubleArrays.log(getArray(), getArrayOffset(), length());
}
@Override
public void exp() {
DoubleArrays.exp(getArray(), getArrayOffset(), length());
}
@Override
public void applyOp(Op op) {
op.applyTo(getArray(), getArrayOffset(), length());
}
@Override
public ADenseArrayVector applyOpCopy(Op op) {
int len=length();
Vector v=Vector.createLength(len);
op.applyTo(v.getArray(), v.getArrayOffset(), len);
return v;
}
@Override
public double elementSum() {
return DoubleArrays.elementSum(getArray(), getArrayOffset(), length());
}
@Override
public double elementPowSum(double exponent) {
return DoubleArrays.elementPowSum(getArray(), getArrayOffset(), length(),exponent);
}
@Override
public double elementAbsPowSum(double exponent) {
return DoubleArrays.elementAbsPowSum(getArray(), getArrayOffset(), length(),exponent);
}
@Override
public double elementProduct() {
return DoubleArrays.elementProduct(getArray(), getArrayOffset(), length());
}
@Override
public double elementMax(){
return DoubleArrays.elementMax(getArray(), getArrayOffset(), length());
}
@Override
public double elementMin(){
return DoubleArrays.elementMin(getArray(), getArrayOffset(), length());
}
@Override
public double maxAbsElement(){
return DoubleArrays.elementMaxAbs(getArray(), getArrayOffset(), length());
}
@Override
public int minElementIndex(){
return DoubleArrays.elementMinIndex(getArray(), getArrayOffset(), length());
}
@Override
public int maxElementIndex(){
return DoubleArrays.elementMaxIndex(getArray(), getArrayOffset(), length());
}
@Override
public int maxAbsElementIndex(){
return DoubleArrays.elementMaxAbsIndex(getArray(), getArrayOffset(), length());
}
@Override
public long nonZeroCount() {
return DoubleArrays
.nonZeroCount(getArray(), getArrayOffset(), length());
}
@Override
public int[] nonZeroIndices() {
return DoubleArrays.nonZeroIndices(getArray(), getArrayOffset(), length());
}
@Override
public void square() {
DoubleArrays.square(getArray(), getArrayOffset(), length());
}
@Override
public Vector squareCopy() {
double[] ds=toDoubleArray();
DoubleArrays.square(ds);
return Vector.wrap(ds);
}
@Override
public void sqrt() {
DoubleArrays.sqrt(getArray(), getArrayOffset(), length());
}
/**
* Sets each component of the vector to its sign value (-1, 0 or 1)
*/
public void signum() {
DoubleArrays.signum(getArray(), getArrayOffset(), length());
}
@Override
public void multiply(AVector v) {
v.multiplyTo(getArray(), getArrayOffset());
}
@Override
public void multiply(double[] src, int srcOffset) {
int len = length();
double[] cdata = getArray();
int coffset = getArrayOffset();
for (int i = 0; i < len; i++) {
cdata[i + coffset] *= src[i + srcOffset];
}
}
@Override
public void multiplyTo(double[] dest, int destOffset) {
DoubleArrays.arraymultiply(getArray(), getArrayOffset(), dest, destOffset,
length());
}
@Override
public void divide(AVector v) {
v.divideTo(getArray(), getArrayOffset());
}
@Override
public void divide(double[] data, int offset) {
DoubleArrays.arraydivide(data, offset, getArray(), getArrayOffset(), length());
}
@Override
public void divideTo(double[] data, int offset) {
DoubleArrays.arraydivide(getArray(), getArrayOffset(), data, offset, length());
}
@Override
public void copyTo(int start, AVector dest, int destOffset, int length) {
dest.setElements(destOffset, getArray(), getArrayOffset()+start, length);
}
public void copyTo(int offset, ADenseArrayVector dest, int destOffset, int length) {
double[] src = getArray();
int off = getArrayOffset();
double[] dst = dest.getArray();
System.arraycopy(src, off + offset, dst, dest.getArrayOffset()
+ destOffset, length);
}
@Override
public void copyTo(int offset, double[] dest, int destOffset, int length, int stride) {
for (int i=0; i<length; i++) {
dest[destOffset+i*stride]=data[i+offset];
}
}
@Override
public void copyTo(int offset, double[] dest, int destOffset, int length) {
double[] src = getArray();
int off = getArrayOffset();
System.arraycopy(src, off + offset, dest, destOffset, length);
}
public void addMultiple(ADenseArrayVector v, double factor) {
int length = checkSameLength(v);
v.addMultipleToArray(factor, 0, getArray(), getArrayOffset(), length);
}
@Override
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;
int tOffset=offset+this.getArrayOffset();
src.addMultipleToArray(factor, srcOffset, this.getArray(), tOffset, length);
}
@Override
public double magnitudeSquared() {
return DoubleArrays.elementSquaredSum(data, getArrayOffset(), length);
}
@Override
public double magnitude() {
return Math.sqrt(magnitudeSquared());
}
@Override
public void fill(double value) {
int offset = getArrayOffset();
Arrays.fill(getArray(), offset, offset + length, value);
}
@Override
public void pow(double exponent) {
int len = length();
double[] data = getArray();
int offset = getArrayOffset();
DoubleArrays.pow(data, offset, len, exponent);
}
@Override
public void reciprocal() {
DoubleArrays.reciprocal(getArray(), getArrayOffset(), length());
}
@Override
public void clamp(double min, double max) {
DoubleArrays.clamp(getArray(), getArrayOffset(), length(), min, max);
}
@Override
public void multiply(double factor) {
DoubleArrays.multiply(getArray(), getArrayOffset(), length(), factor);
}
@Override
public AVector tryEfficientJoin(AVector v) {
if (v instanceof ADenseArrayVector) return join((ADenseArrayVector) v);
if (v instanceof JoinedArrayVector) return join((JoinedArrayVector) v);
return null;
}
public AVector join(ADenseArrayVector v) {
if ((v.getArray() == getArray())
&& ((getArrayOffset() + length) == v.getArrayOffset())) {
return Vectorz.wrap(getArray(), getArrayOffset(), length + v.length());
}
return JoinedArrayVector.joinVectors(this, v);
}
public JoinedArrayVector join(JoinedArrayVector v) {
return JoinedArrayVector.wrap(this).join(v);
}
@Override
public boolean equals(INDArray v) {
if (v.dimensionality()!=1) return false;
int len=length();
if (len != v.getShape(0)) return false;
return v.equalsArray(getArray(), getArrayOffset());
}
@Override
public boolean equals(AVector v) {
if (v==this) return true;
int len = length();
if (v.length() != len) return false;
return v.equalsArray(getArray(), getArrayOffset());
}
@Override
public boolean equalsArray(double[] data, int offset) {
return DoubleArrays.equals(data, offset, getArray(), getArrayOffset(), length);
}
@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();
double[] data = getArray();
int offset = getArrayOffset();
return DoubleArrays.elementsEqual(data,offset,length,value);
}
@Override
public void validate() {
int length = length();
double[] data = getArray();
int offset = getArrayOffset();
if ((offset < 0) || (offset + length > data.length)) {
throw new VectorzException("ArrayVector out of bounds");
}
super.validate();
}
}