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

com.linkedin.dagli.math.vector.SparseDoubleMapVector Maven / Gradle / Ivy

// AUTOGENERATED CODE.  DO NOT MODIFY DIRECTLY!  Instead, please modify the math/vector/SparseXMapVector.ftl file.
// See the README in the module's src/template directory for details.
package com.linkedin.dagli.math.vector;

import it.unimi.dsi.fastutil.Hash;
import it.unimi.dsi.fastutil.longs.Long2DoubleMap;
import it.unimi.dsi.fastutil.longs.Long2DoubleOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import java.io.Serializable;


/**
 * Implementation of a (sparse) {@link Vector} using double values and backed by a hashtable.
 *
 * This implementation is efficient when modification and iteration are not interleaved: the elements must be resorted
 * when {@link #iterator()} or {@link #reverseIterator()} is called if the vector has changed since the previous call.
 * Note that caching the sorted values means that this class is also relatively memory inefficient compared to a
 * {@link SparseDoubleArrayVector}.
 */
public class SparseDoubleMapVector extends AbstractVector implements MutableVector, Serializable {
  private static final long serialVersionUID = 1;

  private final Long2DoubleOpenHashMap _vectorMap;

  // used to cache a SparseArrayVector that provides sorted element iterators when needed; this must be recalculated
  // whenever an entry is added or removed to the _vectorMap.  Using a self-balancing tree as our primary data
  // structure would avoid the need for this extra cached data, but we operate under the premise that iteration and
  // modification are almost never interleaved.
  private transient SparseDoubleArrayVector _cachedSparseArrayVector = null;

  /**
   * Create a new vector with the default initial capacity.
   */
  public SparseDoubleMapVector() {
    this(Hash.DEFAULT_INITIAL_SIZE);
  }

  /**
   * Create a new vector with the specified initial capacity.
   *
   * @param initialCapacity the number of vector components to pre-allocate space for.  The vector can still have more
   *                        entries than this, of course--it will automatically grow as needed.
   */
  public SparseDoubleMapVector(int initialCapacity) {
    _vectorMap = new Long2DoubleOpenHashMap(initialCapacity);
  }

  @Override
  public Class valueType() {
    return double.class;
  }

  @Override
  public long size64() {
    return _vectorMap.size();
  }

  @Override
  public double increase(long index, double amount) {
    // addTo returns the *previous* value
    double result = _vectorMap.addTo(index, amount);
    if (result == 0) { // adding new entry
      _cachedSparseArrayVector = null;
    }
    if ((result + (amount)) == 0) {
      _cachedSparseArrayVector = null;
      _vectorMap.remove(index);
    }
    return result;
  }

  @Override
  public double get(long index) {
    return _vectorMap.get(index);
  }

  /**
   * Sets the value of a particular index in the vector.  Values of 0 are not stored explicitly; putting a value of 0
   * thus removes the element from this instance's backing hashtable.
   *
   * @param index the index of the value
   * @param value the value to be put
   * @return the value previously associated with the index
   */
  public double getAndSet(long index, double value) {
    final double result;
    if (value == 0) {
      result = _vectorMap.remove(index);
      if (result != 0) { // deleted an entry
        _cachedSparseArrayVector = null;
      }
    } else {
      result = _vectorMap.put(index, value);
      if (result == 0) { // added an entry
        _cachedSparseArrayVector = null;
      }
    }
    return result;
  }

  @Override
  public void put(long index, double value) {
    getAndSet(index, value);
  }

  @Override
  public void transformInPlace(VectorElementTransformer transformer) {
    LongArrayList lal = new LongArrayList(4);
    _vectorMap.long2DoubleEntrySet().fastForEach(keyAndValuePair -> {
      long key = keyAndValuePair.getLongKey();

      double res = transformer.transform(key, keyAndValuePair.getDoubleValue());
      if (res != 0) {
        // can safely modify entries while iterating
        _vectorMap.put(key, res);
      } else {
        // cannot safely delete here, because the map enforces a minimum load factor and might resize
        lal.add(key);
      }
    });

    lal.forEach((long v) -> _vectorMap.remove(v));
  }

  private class UnorderedIterator implements VectorElementIterator {
    private ObjectIterator _iterator = _vectorMap.long2DoubleEntrySet().fastIterator();

    @Override
    public  T mapNext(VectorElementFunction mapper) {
      Long2DoubleOpenHashMap.Entry nextVal = _iterator.next();
      return mapper.apply(nextVal.getLongKey(), nextVal.getDoubleValue());
    }

    @Override
    public void next(VectorElementConsumer consumer) {
      Long2DoubleOpenHashMap.Entry nextVal = _iterator.next();
      consumer.consume(nextVal.getLongKey(), nextVal.getDoubleValue());
    }

    @Override
    public boolean hasNext() {
      return _iterator.hasNext();
    }
  }

  private void ensureCachedSparseArrayVector() {
    if (_cachedSparseArrayVector == null) {
      long[] indices = new long[_vectorMap.size()];
      double[] values = new double[_vectorMap.size()];

      ObjectIterator iterator = _vectorMap.long2DoubleEntrySet().fastIterator();
      for (int offset = 0; offset < indices.length; offset++) {
        Long2DoubleMap.Entry entry = iterator.next();
        indices[offset] = entry.getLongKey();
        values[offset] = entry.getDoubleValue();
      }

      _cachedSparseArrayVector = SparseDoubleArrayVector.wrap(indices, values);
    }
  }

  @Override
  public VectorElementIterator unorderedIterator() {
    return new UnorderedIterator();
  }

  @Override
  public VectorElementIterator iterator() {
    ensureCachedSparseArrayVector();
    return _cachedSparseArrayVector.iterator();
  }

  @Override
  public VectorElementIterator reverseIterator() {
    ensureCachedSparseArrayVector();
    return _cachedSparseArrayVector.reverseIterator();
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy