mikera.vectorz.impl.SparseHashedVector Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of vectorz Show documentation
Show all versions of vectorz Show documentation
Fast double-precision vector and matrix maths library for Java, supporting N-dimensional numeric arrays.
package mikera.vectorz.impl;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import mikera.indexz.Index;
import mikera.matrixx.AMatrix;
import mikera.vectorz.AVector;
import mikera.vectorz.Vector;
import mikera.vectorz.util.ErrorMessages;
import mikera.vectorz.util.VectorzException;
/**
* Hashed sparse vector, intended for large vectors with very few randomly positioned non-zero elements.
*
* Maintains hash elements for non-zero values only. This is useful (and maybe better than SparseIndexedVector)
* if random individual elements are likely to be changed, accessed or set back to zero on a frequent basis
*
* Mutable in all elements, but performance will be reduced if density is high. In general, if density
* is more than about 1% then a dense Vector is likely to be better.
*
* @author Mike
*
*/
public class SparseHashedVector extends ASparseVector {
private static final long serialVersionUID = 750093598603613879L;
private HashMap hash;
private SparseHashedVector(int length) {
this(length, new HashMap());
}
private SparseHashedVector(int length, HashMap hashMap) {
super(length);
if (length<=0) throw new IllegalArgumentException("Can't create SparseHashedVector of length "+length);
hash=hashMap;
}
/**
* Creates a SparseHashedVector with the specified values
*/
public static SparseHashedVector create(AVector v) {
Index ix=v.nonSparseIndex();
int n=ix.length();
HashMap hm=new HashMap(n);
for (int i=0; i hm=new HashMap();
for (int i=0; i e:hash.entrySet()) {
double r=e.getValue()*d;
e.setValue(r);
}
}
@Override
public double dotProduct(AVector v) {
v.checkLength(length);
double result=0.0;
for (int i: hash.keySet()) {
result+=hash.get(i)*v.unsafeGet(i);
}
return result;
}
@Override
public double dotProduct(double[] data, int offset) {
double result=0.0;
for (Integer i: hash.keySet()) {
result+=hash.get(i)*data[offset+i];
}
return result;
}
@Override
public double dotProduct(double[] data, int offset, int stride) {
double result=0.0;
for (Integer i: hash.keySet()) {
result+=hash.get(i)*data[offset+i*stride];
}
return result;
}
@Override
public void addMultipleToArray(double factor,int offset, double[] array, int arrayOffset, int length) {
int aOffset=arrayOffset-offset;
for (Integer i: hash.keySet()) {
if ((i=(offset+length))) continue;
array[aOffset+i]+=factor*hash.get(i);
}
}
@Override
public void addToArray(int offset, double[] array, int arrayOffset, int length) {
int aOffset=arrayOffset-offset;
for (int i: hash.keySet()) {
if ((i=(offset+length))) continue;
array[aOffset+i]+=hash.get(i);
}
}
@Override
public void addToArray(double[] dest, int offset, int stride) {
for (Entry e: hash.entrySet()) {
int i=e.getKey();
dest[offset+i*stride]+=e.getValue();
}
}
@Override
public void addProductToArray(double factor, int offset, AVector other,int otherOffset, double[] array, int arrayOffset, int length) {
int aOffset=arrayOffset-offset;
int oOffset=otherOffset-offset;
for (Entry e: hash.entrySet()) {
Integer io=e.getKey();
int i=io;
if ((i=(offset+length))) continue;
array[aOffset+i]+=factor*e.getValue()*other.get(i+oOffset);
}
}
@Override
public void addProductToArray(double factor, int offset, ADenseArrayVector other,int otherOffset, double[] array, int arrayOffset, int length) {
int aOffset=arrayOffset-offset;
int oArrayOffset=other.getArrayOffset()+otherOffset-offset;
double[] oArray=other.getArray();
for (Entry e: hash.entrySet()) {
Integer io=e.getKey();
int i=io;
if ((i=(offset+length))) continue;
double ov=oArray[i+oArrayOffset];
if (ov!=0.0) array[aOffset+i]+=factor*e.getValue()*ov;
}
}
@Override public void getElements(double[] array, int offset) {
Arrays.fill(array,offset,offset+length,0.0);
copySparseValuesTo(array,offset);
}
public void copySparseValuesTo(double[] array, int offset) {
for (Entry e: hash.entrySet()) {
int i=e.getKey();
array[offset+i]=e.getValue();
}
}
@Override public 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);
for (Entry e: hash.entrySet()) {
int i=e.getKey();
v.unsafeSet(offset+i,e.getValue());
}
}
@Override
public void set(int i, double value) {
checkIndex(i);
if (value!=0.0) {
hash.put(i, value);
} else {
hash.remove(i);
}
}
@Override
public void set(AVector v) {
if (v instanceof SparseHashedVector) {
set((SparseHashedVector) v);
return;
}
v.checkLength(length);
hash=new HashMap();
for (int i=0; i) v.hash.clone();
}
@Override
public void unsafeSet(int i, double value) {
if (value!=0.0) {
hash.put(i, value);
} else {
hash.remove(i);
}
}
/**
* Special method to allow re-use of integer instances as keys
*
* @param i
* @param value
*/
private void unsafeSetInteger(Integer i, double value) {
if (value!=0.0) {
hash.put(i, value);
} else {
hash.remove(i);
}
}
@Override
public void addAt(int i, double value) {
if (value==0.0) return;
Integer ind=i;
unsafeSetInteger(ind, value+unsafeGet(ind));
}
@Override
public double maxAbsElement() {
double result=0.0;
for (Map.Entry e:hash.entrySet()) {
double d=Math.abs(e.getValue());
if (d>result) {
result=d;
}
}
return result;
}
@Override
public double elementMax() {
double result=-Double.MAX_VALUE;
for (Map.Entry e:hash.entrySet()) {
double d=e.getValue();
if (d>result) {
result=d;
}
}
if ((result<0)&&(hash.size() e:hash.entrySet()) {
double d=e.getValue();
if (d0)&&(hash.size() e:hash.entrySet()) {
double d=e.getValue();
if (d>result) {
result=d;
ind=e.getKey();
}
}
if ((result<0)&&(hash.size() e:hash.entrySet()) {
double d=Math.abs(e.getValue());
if (d>result) {
result=d;
ind=e.getKey();
}
}
return ind;
}
@Override
public int minElementIndex(){
if (hash.size()==0) return 0;
int ind=0;
double result=Double.MAX_VALUE;
for (Map.Entry e:hash.entrySet()) {
double d=e.getValue();
if (d0)&&(hash.size() e:hash.entrySet()) {
double d=e.getValue();
result+=d;
}
return result;
}
@Override
public double elementSquaredSum() {
double result=0.0;
for (Map.Entry e:hash.entrySet()) {
double d=e.getValue();
result+=d*d;
}
return result;
}
@Override
public Vector nonSparseValues() {
int n=hash.size();
double[] vs=new double[n];
Index index=nonSparseIndex();
for (int i=0; i e: hash.entrySet()) {
ret[di++]=e.getKey();
}
Arrays.sort(ret);
return ret;
}
@Override
public Index nonSparseIndex() {
int n=hash.size();
int[] in=new int[n];
int di=0;
for (Map.Entry e:hash.entrySet()) {
in[di++]=e.getKey();
}
Index result=Index.wrap(in);
result.sort();
return result;
}
@Override
public boolean includesIndex(int i) {
return hash.containsKey(i);
}
@Override
public void add(ASparseVector v) {
Index ind=v.nonSparseIndex();
int n=ind.length();
for (int i=0; i) hash.clone());
}
@Override
public SparseIndexedVector sparseClone() {
// by default switch to SparsIndexedVector: will normally be faster
return SparseIndexedVector.create(this);
}
@Override
public void validate() {
if (length<=0) throw new VectorzException("Illegal length: "+length);
for (Entry e:hash.entrySet()) {
int i=e.getKey();
if ((i<0)||(i>=length)) throw new VectorzException(ErrorMessages.invalidIndex(this, i));
if (e.getValue()==0.0) throw new VectorzException("Unexpected zero at index: "+i);
}
super.validate();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy