Package mikera.vectorz.impl

Source Code of mikera.vectorz.impl.SparseIndexedVector

package mikera.vectorz.impl;

import mikera.indexz.Index;
import mikera.matrixx.AMatrix;
import mikera.matrixx.impl.AVectorMatrix;
import mikera.vectorz.AVector;
import mikera.vectorz.Op;
import mikera.vectorz.Vector;
import mikera.vectorz.util.DoubleArrays;
import mikera.vectorz.util.ErrorMessages;
import mikera.vectorz.util.IntArrays;
import mikera.vectorz.util.VectorzException;

/**
* Indexed sparse vector.
*
* Efficient for mostly sparse vectors. Maintains a indexed array of elements which may be non-zero.
*
* WARNING: individual updates of non-indexed elements are O(n) in the number of non-sparse elements. You should not normally
* perform element-wise mutation on a SparseIndexedVector if performance is a concern
*
* Index must be distinct and sorted.
*
* @author Mike
*
*/
public class SparseIndexedVector extends ASparseIndexedVector {
  private static final long serialVersionUID = 750093598603613879L;

  private Index index;
  private double[] data;
 
  private SparseIndexedVector(int length, Index index) {
    this(length,index,new double[index.length()]);
  }
 
  private SparseIndexedVector(int length, Index index, double[] data) {
    super(length);
    this.index=index;
    this.data=data;
  }
 
  private SparseIndexedVector(int length, Index index, AVector source) {
    this(length,index,source.toDoubleArray());
  }
 
  /**
   * Creates a SparseIndexedVector with the specified index and data values.
   * Performs no checking - Index must be distinct and sorted.
   */
  public static SparseIndexedVector wrap(int length, Index index, double[] data) {
    assert(index.length()==data.length);
    assert(index.isDistinctSorted());
    return new SparseIndexedVector(length, index,data);
  }
 
  /**
   * Creates a SparseIndexedVector with the specified index and data values.
   * Performs no checking - Index must be distinct and sorted.
   */
  public static SparseIndexedVector wrap(int length, int[] indices, double[] data) {
    Index index=Index.wrap(indices);
    assert(index.length()==data.length);
    assert(index.isDistinctSorted());
    return new SparseIndexedVector(length, index,data);
  }
 
  /**
   * Creates a SparseIndexedVector using the given sorted Index to identify the indexes of non-zero values,
   * and a double[] array to specify all the non-zero element values
   */
  public static SparseIndexedVector create(int length, Index index, double[] data) {
    if (!index.isDistinctSorted()) {
      throw new VectorzException("Index must be sorted and distinct");
    }
    if (!(index.length()==data.length)) {
      throw new VectorzException("Length of index: mismatch woth data");     
    }
    return new SparseIndexedVector(length, index.clone(),DoubleArrays.copyOf(data));
  }
 
  public static SparseIndexedVector createLength(int length) {
    return new SparseIndexedVector(length, Index.EMPTY,DoubleArrays.EMPTY);
  }
 
  /**
   * Creates a SparseIndexedVector using the given sorted Index to identify the indexes of non-zero values,
   * and a dense vector to specify all the non-zero element values
   */
  public static SparseIndexedVector create(int length, Index index, AVector data) {
    SparseIndexedVector sv= create(length, index, new double[index.length()]);
    data.getElements(sv.data, 0);
    return sv;
  }
 
  /**
   * Creates a SparseIndexedVector from the given vector, ignoring the zeros in the source.
   *
   */
  public static SparseIndexedVector create(AVector source) {
    if (source instanceof ASparseVector) return create((ASparseVector) source);
    int srcLength = source.length();
    if (srcLength==0) throw new IllegalArgumentException("Can't create a length 0 SparseIndexedVector");
    int[] indexes=source.nonZeroIndices();
    int len=indexes.length;
    double[] vals=new double[len];
    for (int i=0; i<len; i++) {
      vals[i]=source.unsafeGet(indexes[i]);
    }
    return wrap(srcLength,Index.wrap(indexes),vals);
  }
 
  public static SparseIndexedVector create(ASparseVector source) {
    int length = source.length();
    if (length==0) throw new IllegalArgumentException("Can't create a length 0 SparseIndexedVector");
    Index ixs=source.nonSparseIndex();
    int n=ixs.length();
    double[] vals=new double[n];
    for (int i=0; i<n; i++) {
      vals[i]=source.unsafeGet(ixs.unsafeGet(i));
    }
    return wrap(length,ixs,vals);
  }
 
  public static SparseIndexedVector create(SparseHashedVector source) {
    int length = source.length();
    if (length==0) throw new IllegalArgumentException("Can't create a length 0 SparseIndexedVector");
    Index ixs=source.nonSparseIndex();
    int n=ixs.length();
    double[] vals=new double[n];
    for (int i=0; i<n; i++) {
      vals[i]=source.unsafeGet(ixs.unsafeGet(i));
    }
    return wrap(length,ixs,vals);
  }
 
  /** Creates a SparseIndexedVector from a row of an existing matrix */
  public static AVector createFromRow(AMatrix m, int row) {
    if (m instanceof AVectorMatrix) return create(m.getRow(row));
    return create(m.getRow(row));
  }
 
  @Override
  public int nonSparseElementCount() {
    return data.length;
  }
 
  @Override
  public void add(AVector v) {
    if (v instanceof ASparseVector) {
      add((ASparseVector)v);
      return;
    }
    includeIndices(v)
    for (int i=0; i<data.length; i++) {
      data[i]+=v.unsafeGet(index.get(i));
    }
  }
 
  @Override
  public void add(ASparseVector v) {
        if (v instanceof ZeroVector) {
            return;
        }
    includeIndices(v)
    for (int i=0; i<data.length; i++) {
      data[i]+=v.unsafeGet(index.get(i));
    }
  }
 
  @Override
  public void multiply (double d) {
    if (d==0.0) {
      data=DoubleArrays.EMPTY;
      index=Index.EMPTY;
    } else {
      DoubleArrays.multiply(data, d);
    }
  }
 
  @Override
  public void multiply(AVector v) {
    if (v instanceof ADenseArrayVector) {
      multiply((ADenseArrayVector)v);
      return;
    }
    checkSameLength(v);
    double[] data=this.data;
    int[] ixs=index.data;
    for (int i=0; i<data.length; i++) {
      data[i]*=v.unsafeGet(ixs[i]);
    }
  }
 
  public void multiply(ADenseArrayVector v) {
    multiply(v.getArray(),v.getArrayOffset());
  }
 
  @Override
  public void multiply(double[] array, int offset) {
    double[] data=this.data;
    int[] ixs=index.data;
    for (int i=0; i<data.length; i++) {
      data[i]*=array[offset+ixs[i]];
    }
  }
 
  @Override
  public double maxAbsElement() {
    double[] data=this.data;
    double result=0.0;
    for (int i=0; i<data.length; i++) {
      double d=Math.abs(data[i]);
      if (d>result) result=d;
    }
    return result;
  }
 
  @Override
  public int maxElementIndex(){
    double[] data=this.data;
    if (data.length==0) return 0;
    double result=data[0];
    int di=0;
    for (int i=1; i<data.length; i++) {
      double d=data[i];
      if (d>result) {
        result=d;
        di=i;
      }
    }
    if (result<0.0) { // need to find a sparse element
      int ind=sparseElementIndex();
      if (ind>0) return ind;
    }
    return index.get(di);
  }
 
  @Override
  public int maxAbsElementIndex(){
    double[] data=this.data;
    if (data.length==0) return 0;
    double result=data[0];
    int di=0;
    for (int i=1; i<data.length; i++) {
      double d=Math.abs(data[i]);
      if (d>result) {
        result=d;
        di=i;
      }
    }
    return index.get(di);
  }
 
  @Override
  public int minElementIndex(){
    double[] data=this.data;
    if (data.length==0) return 0;
    double result=data[0];
    int di=0;
    for (int i=1; i<data.length; i++) {
      double d=data[i];
      if (d<result) {
        result=d;
        di=i;
      }
    }
    if (result>0.0) { // need to find a sparse element
      int ind=sparseElementIndex();
      if (ind>0) return ind;
    }
    return index.get(di);
  }
 
  /**
   * Return this index of a sparse zero element, or -1 if not sparse
   * @return
   */
  private int sparseElementIndex() {
    if (data.length==length) {
      return -1;
    }
    for (int i=0; i<length; i++) {
      if (!index.contains(i)) return i;
    }
    throw new VectorzException(ErrorMessages.impossible());
  }

 
  @Override
  public void negate() {
    DoubleArrays.negate(data);
  }
 
  @Override
  public void applyOp(Op op) {
    int dlen=data.length;
    if ((dlen<length())&&(op.isStochastic()||(op.apply(0.0)!=0.0))) {
      super.applyOp(op);
    } else {
      op.applyTo(data);
    }
  }
 
  @Override
  public void abs() {
    DoubleArrays.abs(data);
  }

  @Override
  public double get(int i) {
    checkIndex(i);
    int ip=index.indexPosition(i);
    if (ip<0) return 0.0;
    return data[ip];
  }
 
  @Override
  public double unsafeGet(int i) {
    int ip=index.indexPosition(i);
    if (ip<0) return 0.0;
    return data[ip];
  }
 
  @Override
  public boolean isFullyMutable() {
    return true;
  }
 
  @Override
  public boolean isMutable() {
    return length>0;
  }
 
  @Override
  public void setElements(double[] array, int offset) {
    int nz=DoubleArrays.nonZeroCount(array, offset, length);
    int[] ixs=new int[nz];
    double[] data=new double[nz];
    this.data=data;
    int di=0;
    for (int i=0; i<length; i++) {
      double x=array[offset+i];
      if (x==0.0) continue;
      ixs[di]=i;
      data[di]=x;
      di++;
    }
    index=Index.wrap(ixs);
  }
 
  @Override
  public void setElements(int pos,double[] array, int offset, int length) {
    if (length>=this.length) {
      setElements(array,offset);
      return;
    }
   
    int nz=DoubleArrays.nonZeroCount(array, offset, length);
    int[] ixs=new int[nz];
    double[] data=new double[nz];
    this.data=data;
    int di=pos;
    for (int i=0; i<length; i++) {
      double x=array[offset+i];
      if (x==0.0) continue;
      ixs[di]=i;
      data[di]=x;
      di++;
    }
    index=Index.wrap(ixs);
  }
 
  @Override
  public void set(AVector v) {
    checkSameLength(v);
   
    if (v instanceof ADenseArrayVector) {
      set((ADenseArrayVector)v);
      return;
    } else if (v instanceof ASparseVector) {
            int[] nzi = v.nonZeroIndices();
            index=Index.wrap(nzi);
            if (nzi.length!=data.length) {
                data=new double[nzi.length];
            }
            for (int i=0; i<index.length(); i++) {
                double val=v.unsafeGet(index.get(i));
                data[i]=val;
            }
            return;
        } else {
            double[] data=this.data;
            int nz=(int) v.nonZeroCount();
            if (nz!=data.length) {
                data=new double[nz];
                this.data=data;
                index=Index.createLength(nz);
            }
           
            int di=0;
            for (int i=0; i<nz; i++) {
                double val=v.unsafeGet(i);
                if (val!=0) {
                    data[di]=val;
                    index.set(di, i);
                    di++;
                }
            }
        }
  }
 
  @Override
  public void set(ADenseArrayVector v) {
    checkSameLength(v);
    setElements(v.getArray(),v.getArrayOffset());
  }

  @Override
  public void set(int i, double value) {
    checkIndex(i);
    int ip=index.indexPosition(i);
    if (ip<0) {
      if (value==0.0) return;
      int npos=index.seekPosition(i);
      data=DoubleArrays.insert(data,npos,value);
      index=index.insert(npos,i);
    } else {
      data[ip]=value;
    }
  }
 
  @Override
  public void addAt(int i, double value) {
    // worth checking for zero when dealing with sparse vectors
    // can often avoid a relatively expensive index lookup
    if (value==0.0) return;
   
    int ip=index.indexPosition(i);
    if (ip<0) {
      unsafeSet(i,value);
    } else {
      data[ip]+=value;
    }
  }

  @Override
  public Vector nonSparseValues() {
    return Vector.wrap(data);
  }
 
  @Override
  public Index nonSparseIndex() {
    return index;
  }

  @Override
  public boolean includesIndex(int i) {
    return index.indexPosition(i)>=0;
  }
 
  @Override
  public Vector toVector() {
    Vector v=Vector.createLength(length);
    double[] data=this.data;
    int[] ixs=index.data;
    for (int i=0; i<data.length; i++) {
      v.unsafeSet(ixs[i],data[i]);
   
    return v;
  }
 
  @Override
  public SparseIndexedVector clone() {
    return exactClone();
  }
 
  /**
   * Include additional indices in the non-sparse index set of this vector.
   *
   * Useful to improve performance if subsequent operations will access these indices.
   *
   * @param ixs
   */
  public void includeIndices(int[] ixs) {
    int[] nixs = IntArrays.mergeSorted(index.data,ixs);
    if (nixs.length==index.length()) return;
    int nl=nixs.length;
    double[] data=this.data;
    double[] ndata=new double[nl];
    int si=0;
       
    for (int i=0; i<nl; i++) {
            if (si>=data.length) break;
      int z=index.data[si];
      if (z==nixs[i]) {
        ndata[i]=data[si];
        si++;
      }
    }
    this.data=ndata;
    index=Index.wrap(nixs);
  }
 
  /**
   * Include additional indices in the non-sparse index set of this vector.
   *
   * Useful to improve performance if subsequent operations will access these indices.
   *
   * @param ixs
   */
  public void includeIndices(Index ixs) {
    includeIndices(ixs.data);
  }
 
  /**
   * Include additional indices in the non-sparse index set of this vector.
   *
   * Useful to improve performance if subsequent operations will access these indices.
   *
   * @param ixs
   */
  public void includeIndices(AVector v) {
    if (v instanceof ASparseIndexedVector) {
      includeIndices((ASparseIndexedVector)v);
    } else {
      includeIndices(v.nonSparseIndex());
    }
  }
 
  public void includeIndices(ASparseIndexedVector v) {
    includeIndices(v.internalIndex());
  }
 
  @Override
  public SparseIndexedVector sparseClone() {
    return exactClone();
  }
 
  @Override
  public SparseIndexedVector exactClone() {
    return new SparseIndexedVector(length,index.clone(),data.clone());
  }
 
  @Override
  public void validate() {
    if (index.length()!=data.length) throw new VectorzException("Inconsistent data and index!");
    if (!index.isDistinctSorted()) throw new VectorzException("Invalid index: "+index);
    super.validate();
  }
 
  @Override
  public AVector immutable() {
    return SparseImmutableVector.create(this);
  }

  @Override
  double[] internalData() {
    return data;
  }

  @Override
  Index internalIndex() {
    return index;
  }


}
TOP

Related Classes of mikera.vectorz.impl.SparseIndexedVector

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.