Package de.torstennahm.integrate.sparse.index

Source Code of de.torstennahm.integrate.sparse.index.FastIndex

/*
* Created on Jan 2, 2004
*/
package de.torstennahm.integrate.sparse.index;

import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;

import de.torstennahm.math.IntEntry;
import de.torstennahm.math.MathTN;
import de.torstennahm.math.SparseIntVector;

/**
* Implements <code>Index</code>.
*
* Only the non-zero entries for the index are stored. For performance,
* an array is used for storage, which is grown when needed.
* <p>
* According to general index contract, this class is thread-safe.
*
* @author Torsten Nahm
*/
public class FastIndex implements Index {
  /**
   * Number of entries that are not zero.
   */
  protected int nonZeroEntries;
 
  /**
   * Array storing the entry number of each entry.
   */
  protected int[] entryNums;
  /**
   * Array storing the corresponding value of each entry.
   */
  protected int[] entryVals;
 
  /**
   * Hash code.
   */
  protected int hashCode;
 
  /**
   * Creates a new fast index. All entries are initially zero.
   */
  public FastIndex() {
    nonZeroEntries = 0;
    entryNums = new int[nonZeroEntries];
    entryVals = new int[nonZeroEntries];
    hashCode = 0;
  }
 
  /**
   * Creates an new <code>FastIndex</code> from any <code>Index</code>.
   *
   * @param index index to initialize from
   */
  public FastIndex(Index index) {
    this(index.nonZeroEntries(), index.iterator());
  }
 
  /**
   * Creates a new <code>FastIndex</code> from a <code>PackedIntVector</code>.
   *
   * @param vector vector to initialize from
   */
  public FastIndex(SparseIntVector vector) {
    this(vector.nonZeroEntries(), vector.iterator());
  }
 
  /**
   * Creates a fast index from an array.
   *
   * @param array array to initialize from
   */
  public FastIndex(int[] array) {
    this(new SparseIntVector(array));
  }
 
  private FastIndex(int nonZeroEntries, Iterator<IntEntry> iter) {
    this.nonZeroEntries = nonZeroEntries;
   
    entryNums = new int[nonZeroEntries];
    entryVals = new int[nonZeroEntries];
   
    for (int pos = 0; iter.hasNext(); pos++)  {
      IntEntry entry = iter.next();
      entryNums[pos] = entry.getNumber();
      entryVals[pos] = entry.getValue();
      hashCode = newHash(hashCode, entry.getNumber(), 0, entry.getValue());
    }
  }
 
  /**
   * Private constructor for creating a modified fast index.
   *
   * @param nonZeroEntries
   * @param entryNums
   * @param entryVals
   * @param hash
   */
  private FastIndex(int nonZeroEntries, int[] entryNums, int[] entryVals, int hash) {
    this.nonZeroEntries = nonZeroEntries;
    this.entryNums = entryNums;
    this.entryVals = entryVals;
    this.hashCode = hash;
  }
 
  public int nonZeroEntries() {
    return nonZeroEntries;
  }
 
  public int lastEntry() {
    return nonZeroEntries == 0 ? -1 : entryNums[nonZeroEntries - 1];
  }

  public int get(int entryNum) {
    if (entryNum < 0) {
      throw new IllegalArgumentException("Entry may not be negative");
    }
   
    int pos = Arrays.binarySearch(entryNums, entryNum);
    return pos >= 0 ? entryVals[pos] : 0;
  }
 
  public Index set(int entryNum, int value) {
    if (entryNum < 0) {
      throw new IllegalArgumentException("Entry may not be negative");
    }
   
    int oldVal;
   
    int newNonZeroEntries;
    int[] newNums;
    int[] newVals;
   
    int pos = Arrays.binarySearch(entryNums, entryNum);
    if (pos >= 0) {      // Entry exists
      oldVal = entryVals[pos];
      if (value != 0) {  // Change entry
        if (oldVal == value) {
          return this;
        }
        newNonZeroEntries = nonZeroEntries;
        newNums = entryNums.clone();
        newVals = entryVals.clone();
        newVals[pos] = value;
      } else {      // Remove entry
        newNonZeroEntries = nonZeroEntries - 1;
        newNums = new int[newNonZeroEntries];
        newVals = new int[newNonZeroEntries];
        System.arraycopy(entryNums, 0, newNums, 0, pos);
        System.arraycopy(entryNums, pos + 1, newNums, pos, newNonZeroEntries - pos);
        System.arraycopy(entryVals, 0, newVals, 0, pos);
        System.arraycopy(entryVals, pos + 1, newVals, pos, newNonZeroEntries - pos);
      }
    } else {
      pos = -pos - 1;
      oldVal = 0;
      if (value == 0) {
        return this;
      } else {
        newNonZeroEntries = nonZeroEntries + 1;
        newNums = new int[newNonZeroEntries];
        newVals = new int[newNonZeroEntries];
        System.arraycopy(entryNums, 0, newNums, 0, pos);
        newNums[pos] = entryNum;
        System.arraycopy(entryNums, pos, newNums, pos + 1, newNonZeroEntries - (pos + 1));
        System.arraycopy(entryVals, 0, newVals, 0, pos);
        newVals[pos] = value;
        System.arraycopy(entryVals, pos, newVals, pos + 1, newNonZeroEntries - (pos + 1));
      }
    }
   
    return new FastIndex(newNonZeroEntries, newNums, newVals, newHash(hashCode, entryNum, oldVal, value));
  }

  public Index add(int entryNum, int add) {
    return set(entryNum, get(entryNum) + add);
  }
 
  public int sum() {
    return MathTN.arraySum(entryVals);
  }

  public Iterator<IntEntry> iterator() {
    return new Iterator<IntEntry>() {
      private int index = 0;
     
      public boolean hasNext() {
        return index < nonZeroEntries;
      }

      public IntEntry next() {
        if (index >= nonZeroEntries) {
          throw new NoSuchElementException();
        }
       
        final int i = index;
        index++;
       
        return new IntEntry() {
          public int getNumber() {
            return entryNums[i];
          }
          public int getValue() {
            return entryVals[i];
          }
        };
      }

      public void remove() {
        throw new UnsupportedOperationException();
      }
    };
  }
 
  protected static int newHash(int hashCode, int entryNum, int oldVal, int newVal) {
    return hashCode + (newVal - oldVal) * ((entryNum + 13) << entryNum);
  }
 
  @Override
  public int hashCode() {
    return hashCode;
  }
 
  @Override
  public boolean equals(Object o) {
    if (o instanceof FastIndex) {
      FastIndex comp = (FastIndex) o;
     
      if (nonZeroEntries != comp.nonZeroEntries) {
        return false;
      } else {
        return Arrays.equals(entryNums, comp.entryNums) &&
             Arrays.equals(entryVals, comp.entryVals);
      }
    } else if (o instanceof Index) {
      Index comp = (Index) o;
      if (nonZeroEntries() != comp.nonZeroEntries()) {
        return false;
      } else {
        for (int i = 0; i < nonZeroEntries; i++) {
          if (entryVals[i] != comp.get(entryNums[i])) {
            return false;
          }
        }
       
        return true;
      }
    }
   
    return false;
  }
 
  @Override
  public String toString() {
    StringBuffer sb = new StringBuffer();
   
    if (nonZeroEntries == 0) {
      sb.append("()");
    } else {
      for (int i = 0; i < nonZeroEntries; i++) {
        if (i > 0) {
          sb.append(" ");
        }
        sb.append("(" + entryNums[i] + ", " + entryVals[i] + ")");
      }
    }
    return sb.toString();
  }
}
TOP

Related Classes of de.torstennahm.integrate.sparse.index.FastIndex

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.