code: package cc.mallet.types;
  
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Arrays;
  import java.util.logging.*;
  import java.io.*;
  
  import cc.mallet.types.Alphabet;
  import cc.mallet.types.FeatureSequence;
  import cc.mallet.types.Vector;
  import cc.mallet.util.MalletLogger;
  import cc.mallet.util.PropertyList;
  import gnu.trove.TIntIntHashMap;
  
  public class HashedSparseVector extends SparseVector implements Serializable 
  {
  	private static Logger logger = MalletLogger.getLogger(SparseVector.class.getName());
  
  	
  	TIntIntHashMap index2location;
  	int maxIndex;
  	
  	public HashedSparseVector (int[] indices, double[] values, 
  											 int capacity, int size,
  											 boolean copy,
  											 boolean checkIndicesSorted,
  											 boolean removeDuplicates)
  	{
  		super (indices, values, capacity, size, copy, checkIndicesSorted, removeDuplicates);
  		assert (indices != null);
  	}
  
  	/** Create an empty vector */
  	public HashedSparseVector ()
  	{
  		super (new int[0], new double[0], 0, 0, false, false, false);
  	}
  
  	/** Create non-binary vector, possibly dense if "featureIndices" or possibly sparse, if not */
  	public HashedSparseVector (int[] featureIndices,
  											 double[] values)
  	{
  		super (featureIndices, values);
  	}
  
  	/** Create binary vector */
  	public HashedSparseVector (int[] featureIndices)
  	{
  		super (featureIndices);
  	}
  
  	// xxx We need to implement this in FeatureVector subclasses
  	public ConstantMatrix cloneMatrix ()
  	{
  		return new HashedSparseVector (indices, values);
  	}
  
  	public ConstantMatrix cloneMatrixZeroed () {
  		assert (values != null);
  		int[] newIndices = new int[indices.length];
  		System.arraycopy (indices, 0, newIndices, 0, indices.length);
  		HashedSparseVector sv = new HashedSparseVector (newIndices, new double[values.length],
  														 values.length, values.length, false, false, false);
      // share index2location trick ala IndexedSparseVector
      if (index2location != null) {
        sv.index2location = index2location;
        sv.maxIndex = maxIndex;
      }
      return sv;
  	}
  	
  	// Methods that change values
  
    public void indexVector ()
    {
      if ((index2location == null) && (indices.length > 0))
        setIndex2Location ();
    }
  
  	private void setIndex2Location ()
  	{
  		//System.out.println ("HashedSparseVector setIndex2Location indices.length="+indices.length+" maxindex="+indices[indices.length-1]);
  		assert (index2location == null);
  		assert (indices.length > 0);
  		this.maxIndex = indices[indices.length - 1];
  		this.index2location = new TIntIntHashMap (numLocations ());
  		//index2location.setDefaultValue (-1);
  		for (int i = 0; i < indices.length; i++)
  			index2location.put (indices[i], i);
  	}
  
  	public final void setValue (int index, double value) {
  		if (index2location == null)
  			setIndex2Location ();
  		int location = index2location.get(index);
  		if (index2location.contains (index))
  			values[location] = value;
  		else
  			throw new IllegalArgumentException ("Trying to set value that isn't present in HashedSparseVector");
  	}
  
  	public final void setValueAtLocation (int location, double value)
  	{
  		values[location] = value;
  	}
  
  	// I dislike this name, but it's consistent with DenseVector. -cas
  	public void columnPlusEquals (int index, double value) {
  		if (index2location == null)
  			setIndex2Location ();
  		int location = index2location.get(index);
  		if (index2location.contains (index))
  			values[location] += value;
  		else
  			throw new IllegalArgumentException ("Trying to set value that isn't present in HashedSparseVector");
  	}
  		
  	public final double dotProduct (DenseVector v) {
  		double ret = 0;
  		if (values == null)
  			for (int i = 0; i < indices.length; i++)
  				ret += v.value(indices[i]);
  		else
  			for (int i = 0; i < indices.length; i++)
  				ret += values[i] * v.value(indices[i]);
  		return ret;
  	}
  		
      public final double dotProduct (SparseVector v)
      {
  	if (indices.length == 0)
  	    return 0;
  	if (index2location == null)
  	    setIndex2Location ();
  	double ret = 0;
  	int vNumLocs = v.numLocations();
  	if (values == null) {
  	    // this vector is binary
  	    for (int i = 0; i < vNumLocs; i++) {
  		int index = v.indexAtLocation(i);
  		if (index > maxIndex)
  		    break;
  		if (index2location.contains(index))
  		    ret += v.valueAtLocation (i);
  	    }
  	} else {
  	    for (int i = 0; i < vNumLocs; i++) {
  		int index = v.indexAtLocation(i);
  		if (index > maxIndex)
  		    break;
  		
  		if (index2location.containsKey(index)) {
  		    ret += values[ index2location.get(index) ] * v.valueAtLocation (i);
  		}
  		
  		
  		//int location = index2location.get(index);
  		//if (location >= 0)
  		//	ret += values[location] * v.valueAtLocation (i);
  	    }
  	}
  	return ret;
      }
  	
      public final void plusEqualsSparse (SparseVector v, double factor)
      {
  	if (indices.length == 0)
  	    return;
  	if (index2location == null)
  	    setIndex2Location ();
  	int vNumLocs = v.numLocations();
  	for (int i = 0; i < vNumLocs; i++) {
  	    int index = v.indexAtLocation(i);
  	    if (index > maxIndex)
  		break;
  	    
  	    if (index2location.containsKey(index)) {
  		values[ index2location.get(index) ] += v.valueAtLocation (i) * factor;
  	    }
  	    
  	    //int location = index2location.get(index);
  	    //if (location >= 0)
  	    //			values[location] += v.valueAtLocation (i) * factor;
  	}
      }
  
  	public final void plusEqualsSparse (SparseVector v)
  	{
  		if (indices.length == 0)
  	    return;
  		if (index2location == null)
  	    setIndex2Location ();
  		for (int i = 0; i < v.numLocations(); i++) {
  	    int index = v.indexAtLocation(i);
  	    if (index > maxIndex)
  				break;
  	    int location = index2location.get(index);
  	    if (index2location.contains (index))
  				values[location] += v.valueAtLocation (i);
  		}
  	}
  	
  	public final void setAll (double v)
  	{
  		for (int i = 0; i < values.length; i++)
  			values[i] = v;
  	}
  
  
  	
  	//Serialization
  
  	private static final long serialVersionUID = 1;
  
    // Version history:
    //   0 == Wrote out index2location.  Probably a bad idea.
  	private static final int CURRENT_SERIAL_VERSION = 1;
  	static final int NULL_INTEGER = -1;
  
  	private void writeObject (ObjectOutputStream out) throws IOException {
  		out.writeInt (CURRENT_SERIAL_VERSION);
      out.writeInt (maxIndex);
  	}
  
  	private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException {
  		int version = in.readInt ();
      maxIndex = in.readInt ();
  
      if (version == 0) {
        // gobble up index2location
        Object obj = in.readObject ();
        if (obj != null && !(obj instanceof TIntIntHashMap)) {
          throw new IOException ("Unexpected object in de-serialization: "+obj);
        }
      }
  
  	}
  
  }
  