package mikera.vectorz.impl;
import java.nio.DoubleBuffer;
import java.util.Iterator;
import mikera.arrayz.impl.IDense;
import mikera.randomz.Hash;
import mikera.vectorz.AVector;
import mikera.vectorz.Vector;
import mikera.vectorz.util.DoubleArrays;
import mikera.vectorz.util.ErrorMessages;
import mikera.vectorz.util.VectorzException;
/**
* Immutable array-backed vector. Keeps defensive array copy to ensure immutability.
*
* @author Mike
*
*/
public class ImmutableVector extends AArrayVector implements IDense {
private static final long serialVersionUID = -3679147880242779555L;
public final int offset;
private ImmutableVector(double[] data) {
this(data,0,data.length);
}
public static ImmutableVector of(double... data) {
return wrap(data.clone());
}
private ImmutableVector(double[] data, int offset, int length) {
super(length,data);
this.offset=offset;
}
public static ImmutableVector create(double[] data) {
return wrap(DoubleArrays.copyOf(data));
}
public static ImmutableVector create(AVector v) {
int length=v.length();
double[] data=new double[length];
v.getElements(data, 0);
return new ImmutableVector(data, 0,length);
}
public static ImmutableVector wrap(double[] data) {
return new ImmutableVector(data,0,data.length);
}
public static ImmutableVector wrap(double[] data, int offset, int length) {
if ((offset<0)||(length<0)||((offset+length>data.length))) throw new IndexOutOfBoundsException();
return new ImmutableVector(data,offset,length);
}
public static ImmutableVector wrap(Vector source) {
double[] data=source.data;
return new ImmutableVector(data,0,data.length);
}
@Override
public boolean isMutable() {
return false;
}
@Override
public boolean isFullyMutable() {
return false;
}
@Override
public boolean isView() {
return false;
}
@Override
public boolean isZero() {
return DoubleArrays.isZero(data,offset,length);
}
@Override
public boolean isRangeZero(int start, int length) {
return DoubleArrays.isZero(data, offset+start, length);
}
@Override
public final ImmutableScalar slice(int i) {
return ImmutableScalar.create(get(i));
}
@Override
public AVector subVector(int start, int length) {
int len=checkRange(start,length);
if (length==0) return Vector0.INSTANCE;
if (length==len) return this;
return new ImmutableVector(data,offset+start,length);
}
@Override
public void toDoubleBuffer(DoubleBuffer dest) {
dest.put(data,offset,length());
}
@Override
public double[] toDoubleArray() {
return DoubleArrays.copyOf(data,offset,length);
}
@Override
public void getElements(double[] data, int offset) {
System.arraycopy(this.data, this.offset, data, offset, length());
}
@Override
public void copyTo(int offset, double[] dest, int destOffset, int length) {
System.arraycopy(data, this.offset+offset, dest, destOffset, length);
}
@Override
public void multiplyTo(double[] data, int offset) {
DoubleArrays.arraymultiply(this.data, this.offset, data,offset,length());
}
@Override
public void addToArray(double[] array, int offset) {
addToArray(0,array,offset,length());
}
@Override
public void addToArray(int offset, double[] array, int arrayOffset, int length) {
DoubleArrays.add(data, offset+this.offset, array, arrayOffset, length);
}
@Override
public void addMultipleToArray(double factor,int offset, double[] array, int arrayOffset, int length) {
int dataOffset=this.offset+offset;
DoubleArrays.addMultiple(array, arrayOffset, data, dataOffset, length, factor);
}
@Override
public void divideTo(double[] data, int offset) {
DoubleArrays.arraydivide(this.data, this.offset, data,offset,length());
}
@Override public double dotProduct(double[] data, int offset) {
return DoubleArrays.dotProduct(this.data, this.offset, data, offset, length());
}
@Override public double dotProduct(AVector v) {
checkSameLength(v);
return v.dotProduct(data, offset);
}
@Override
public double magnitudeSquared() {
return DoubleArrays.elementSquaredSum(data, offset, length);
}
@Override
public double get(int i) {
checkIndex(i);
return data[offset+i];
}
@Override
public void set(int i, double value) {
throw new UnsupportedOperationException(ErrorMessages.immutable(this));
}
@Override
public double unsafeGet(int i) {
return data[offset+i];
}
@Override
public void unsafeSet(int i, double value) {
throw new UnsupportedOperationException(ErrorMessages.immutable(this));
}
@Override
public void addAt(int i, double v) {
throw new UnsupportedOperationException(ErrorMessages.immutable(this));
}
@Override
public Iterator<Double> iterator() {
return new StridedElementIterator(data,offset,length,1);
}
@Override
public int hashCode() {
int hashCode = 1;
for (int i = 0; i < length; i++) {
hashCode = 31 * hashCode + (Hash.hashCode(data[offset+i]));
}
return hashCode;
}
@Override
public boolean equals(AVector v) {
if (v.length()!=length) return false;
return v.equalsArray(data, offset);
}
@Override
public boolean equalsArray(double[] data, int offset) {
return DoubleArrays.equals(data,offset,this.data, this.offset,length());
}
@Override
public Vector clone() {
return Vector.wrap(toDoubleArray());
}
@Override
public AVector sparse() {
return SparseImmutableVector.create(this);
}
@Override
public AVector exactClone() {
return new ImmutableVector(data,offset,length);
}
@Override
public AVector immutable() {
return this;
}
@Override
public void validate() {
if ((offset<0)||(offset+length>data.length)||(length<0)) throw new VectorzException("ImmutableVector data out of bounds");
super.validate();
}
@Override
protected int index(int i) {
return offset+i;
}
}