package mikera.vectorz.impl; import mikera.indexz.Index; import mikera.matrixx.AMatrix; import mikera.vectorz.AScalar; import mikera.vectorz.AVector; import mikera.vectorz.Scalar; import mikera.vectorz.Vector1; import mikera.vectorz.util.ErrorMessages; import mikera.vectorz.util.IntArrays; /** * A sparse immutable vector that has a only one element that can be non-zero. * * @author Mike * */ @SuppressWarnings("serial") public final class SingleElementVector extends ASingleElementVector { final double value; public SingleElementVector(int componentIndex, int dimensions) { this(componentIndex,dimensions,0.0); } public SingleElementVector(int componentIndex, int dimensions, double value) { super(componentIndex, dimensions); if (dimensions<=0) throw new IllegalArgumentException("SingleElementVEctor must have >= 1 dimensions"); if (componentIndex<0||componentIndex>=dimensions) throw new IllegalArgumentException("Invalid non-zero component index: "+componentIndex); this.value=value; } public static SingleElementVector create(double val, int i, int len) { return new SingleElementVector(i,len,val); } @Override public boolean isZero() { return value==0.0; } @Override public boolean isRangeZero(int start, int length) { if (value==0.0) return true; return (start>index)||(start+length<=index); } @Override public double magnitude() { return value; } @Override public double elementSum() { return value; } @Override public double elementProduct() { return (length>1)?0.0:value; } @Override public double elementMax(){ return (length>1)?Math.max(0.0, value):value; } @Override public double elementMin(){ return (length>1)?Math.min(0.0, value):value; } @Override public double magnitudeSquared() { return value*value; } @Override public boolean isFullyMutable() { return false; } @Override public boolean isMutable() { return false; } @Override public boolean isElementConstrained() { return true; } @Override public double density() { return 1.0/length(); } @Override public double get(int i) { if(!((i>=0)&&(i<length))) throw new IndexOutOfBoundsException(); return (i==index)?value:0.0; } @Override public double unsafeGet(int i) { return (i==index)?value:0.0; } @Override public void set(int i, double value) { throw new UnsupportedOperationException(ErrorMessages.immutable(this)); } @Override public void addToArray(int offset, double[] array, int arrayOffset, int length) { if (index<offset) return; if (index>=offset+length) return; array[arrayOffset-offset+index]+=value; } @Override public void addToArray(double[] array, int offset, int stride) { array[offset+index*stride]+=value; } @Override public void addMultipleToArray(double factor, int offset, double[] array, int arrayOffset, int length) { if (index<offset) return; if (index>=offset+length) return; array[arrayOffset-offset+index]+=value*factor; } @Override public final AScalar slice(int i) { if (i==index) return VectorIndexScalar.wrap(this, i); if ((i<0)||(i>=length)) throw new IndexOutOfBoundsException(ErrorMessages.invalidIndex(this, i)); return ImmutableScalar.ZERO; } @Override public AVector subVector(int offset, int length) { int len=checkRange(offset,length); if (length==0) return Vector0.INSTANCE; if (length==len) return this; if ((offset>index)||((offset+length)<=index)) { return ZeroVector.create(length); } return SingleElementVector.create(value, index-offset, length); } @Override public AVector tryEfficientJoin(AVector a) { if (a instanceof ZeroVector) { return SingleElementVector.create(value, index, length+a.length()); } return null; } @Override public AVector innerProduct(double d) { return SingleElementVector.create(value*d,index,length); } @Override public AScalar innerProduct(AVector v) { checkSameLength(v); return Scalar.create(value*v.unsafeGet(index)); } @Override public AVector innerProduct(AMatrix a) { return a.getRow(index).multiplyCopy(value); } @Override public SingleElementVector exactClone() { return new SingleElementVector(index,length,value); } @Override public SparseIndexedVector sparseClone() { return SparseIndexedVector.create(length, Index.of(index), new double[] {value}); } @Override public boolean equalsArray(double[] data, int offset) { if (data[offset+index]!=value) return false; for (int i=0; i<index; i++) { if (data[offset+i]!=0.0) return false; } for (int i=index+1; i<length; i++) { if (data[offset+i]!=0.0) return false; } return true; } @Override public int nonSparseElementCount() { return 1; } @Override public AVector nonSparseValues() { return Vector1.of(value); } @Override public Index nonSparseIndex() { return Index.of(index); } @Override public int[] nonZeroIndices() { if (value==0.0) { return IntArrays.EMPTY_INT_ARRAY; } else { return new int[]{index}; } } @Override public boolean includesIndex(int i) { return (i==index); } @Override public void add(ASparseVector v) { throw new UnsupportedOperationException(ErrorMessages.immutable(this)); } @Override public boolean hasUncountable() { return Double.isNaN(value) || Double.isInfinite(value); } /** * Returns the sum of all the elements raised to a specified power * @return */ @Override public double elementPowSum(double p) { return Math.pow(value, p); } /** * Returns the sum of the absolute values of all the elements raised to a specified power * @return */ @Override public double elementAbsPowSum(double p) { return Math.pow(Math.abs(value), p); } @Override public double dotProduct(double[] data, int offset) { return value*data[offset+index]; } @Override protected double value() { return value; } }