All Downloads are FREE. Search and download functionalities are using the official Maven repository.

mikera.vectorz.impl.SparseHashedVector Maven / Gradle / Ivy

Go to download

Fast double-precision vector and matrix maths library for Java, supporting N-dimensional numeric arrays.

There is a newer version: 0.67.0
Show newest version
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