@Override public Long2DoubleMap unapply(Long2DoubleMap vector) { return Long2DoubleSortedArrayMap.create(vector); } };
/** * Compute the dot product of two maps (optimized). This method assumes any value missing in one map is 0, so it is the dot * product of the values of common keys. * @param v1 The first vector. * @param v2 The second vector. * @return The sum of the products of corresponding values in the two vectors. */ public static double dotProduct(Long2DoubleSortedArrayMap v1, Long2DoubleSortedArrayMap v2) { double result; result = 0; final int sz1 = v1.size(); final int sz2 = v2.size(); int i1 = 0, i2 = 0; while (i1 < sz1 && i2 < sz2) { final long k1 = v1.getKeyByIndex(i1); final long k2 = v2.getKeyByIndex(i2); if (k1 < k2) { i1++; } else if (k2 < k1) { i2++; } else { result += v1.getValueByIndex(i1) * v2.getValueByIndex(i2); i1++; i2++; } } return result; }
@Override public Long2DoubleMap getItemBiases(LongSet items) { return itemBiases.subMap(items); }
/** * Compute the sum of the squares of elements of a map (optimized). * @param v The vector * @return The sum of the squares of the values of {@code v}. */ public static double sumOfSquares(Long2DoubleSortedArrayMap v) { final int sz = v.size(); double ssq = 0; for (int i = 0; i < sz; i++) { double val = v.getValueByIndex(i); ssq += val * val; } return ssq; }
/** * Return a subset of this map containing only the keys that appear in another set. * @param toKeep The set of keys to keep. * @return A copy of this map containing only those keys that appear in {@code keys}. */ public Long2DoubleSortedArrayMap subMap(LongSet toKeep) { if (toKeep == keySet()) { return this; } if (toKeep instanceof LongSortedArraySet) { return fastSubMap((LongSortedArraySet) toKeep); } else { return slowSubMap(toKeep); } }
@Test public void testSubMapIndexes() { Long2DoubleMap map = new Long2DoubleOpenHashMap(); map.put(1, 1.0); map.put(2, 2.0); map.put(3, 3.0); map.put(4, 4.0); Long2DoubleSortedArrayMap sam = Long2DoubleSortedArrayMap.create(map); Long2DoubleSortedArrayMap s2 = sam.subMap(2, 4); assertThat(s2.keySet(), contains(2L, 3L)); assertThat(s2.getKeyByIndex(0), equalTo(2L)); assertThat(s2.getKeyByIndex(1), equalTo(3L)); assertThat(s2.getValueByIndex(0), equalTo(2.0)); assertThat(s2.getValueByIndex(1), equalTo(3.0)); } }
protected void scoreItem(Long2DoubleMap userData, long item, ItemItemScoreAccumulator accum) { // find the usable neighbors Long2DoubleSortedArrayMap allNeighbors = Long2DoubleSortedArrayMap.create(model.getNeighbors(item)); Long2DoubleMap neighborhood = allNeighbors.subMap(userData.keySet()); if (neighborhoodSize > 0) { if (logger.isTraceEnabled()) { logger.trace("truncating {} neighbors to {}", neighborhood.size(), neighborhoodSize); } Long2DoubleAccumulator acc = new TopNLong2DoubleAccumulator(neighborhoodSize); for (Long2DoubleMap.Entry e: neighborhood.long2DoubleEntrySet()) { acc.put(e.getLongKey(), e.getDoubleValue()); } neighborhood = acc.finishMap(); } assert neighborhoodSize <= 0 || neighborhood.size() <= neighborhoodSize; if (neighborhood.size() < minNeighbors) { return; } if (logger.isTraceEnabled()) { logger.trace("scoring item {} with {} of {} neighbors", item, neighborhood.size(), allNeighbors.size()); } scorer.score(item, neighborhood, userData, accum); } }
public Long2DoubleSortedArrayMap getItemOffets() { return Long2DoubleSortedArrayMap.wrap(itemIndex, itemOffsets); } }
@Test public void testSubMap() { SortedKeyIndex idx = SortedKeyIndex.create(1, 2, 3, 4, 5); double[] values = { 1.5, 2.4, -3.2, 4.3, -5.7 }; Long2DoubleSortedArrayMap map = new Long2DoubleSortedArrayMap(idx, values); assertThat(map.size(), equalTo(5)); Long2DoubleSortedMap sub = map.subMap(LongUtils.packedSet(2L, 4L)); assertThat(sub.size(), equalTo(2)); assertThat(sub.containsKey(2L), equalTo(true)); assertThat(sub.containsKey(1L), equalTo(false)); assertThat(sub.containsKey(5L), equalTo(false)); assertThat(sub.containsKey(4L), equalTo(true)); assertThat(sub.containsKey(3L), equalTo(false)); assertThat(sub.keySet(), contains(2L, 4L)); assertThat(sub, hasEntry(2L, 2.4)); assertThat(sub, hasEntry(4L, 4.3)); }
/** * Add a scalar to each element of a vector. * @param vec The vector to rescale. * @param val The value to add. * @return A new map with every value in {@code vec} increased by {@code val}. */ public static Long2DoubleMap addScalar(Long2DoubleMap vec, double val) { SortedKeyIndex keys = SortedKeyIndex.fromCollection(vec.keySet()); final int n = keys.size(); double[] values = new double[n]; if (vec instanceof Long2DoubleSortedArrayMap) { Long2DoubleSortedArrayMap sorted = (Long2DoubleSortedArrayMap) vec; for (int i = 0; i < n; i++) { assert sorted.getKeyByIndex(i) == keys.getKey(i); values[i] = sorted.getValueByIndex(i) + val; } } else { for (int i = 0; i < n; i++) { values[i] = vec.get(keys.getKey(i)) + val; } } return Long2DoubleSortedArrayMap.wrap(keys, values); }
/** * Add a vector to another (scaled) vector and a scalar. The result is \\(x_i + s_y y_i + o\\). * * @param x The source vector. * @param y The addition vector. {@link Long2DoubleFunction#defaultReturnValue()} is assumed for missing values. * @param sy The scale by which elements of {@code y} are multipled. * @param o The offset to add. * @return A vector with the same keys as {@code x}, transformed by the specified linear formula. */ public static Long2DoubleMap combine(Long2DoubleMap x, Long2DoubleFunction y, double sy, double o) { SortedKeyIndex idx = SortedKeyIndex.fromCollection(x.keySet()); final int n = idx.size(); double[] values = new double[n]; if (x instanceof Long2DoubleSortedArrayMap) { // TODO make this fast for two sorted maps Long2DoubleSortedArrayMap sx = (Long2DoubleSortedArrayMap) x; assert idx == sx.keySet().getIndex(); for (int i = 0; i < n; i++) { values[i] = sx.getValueByIndex(i) + y.get(idx.getKey(i)) * sy + o; } } else { for (int i = 0; i < n; i++) { long k = idx.getKey(i); values[i] = x.get(k) + y.get(k) * sy + o; } } return Long2DoubleSortedArrayMap.wrap(idx, values); }
/** * Create a new long-to-double map backed by a key index and a corresponding value array. * @param keys The keys. * @param vs The values (the array is used as-is, it is *not* copied). * @return The array map. */ public static Long2DoubleSortedArrayMap wrap(SortedKeyIndex keys, double[] vs) { return new Long2DoubleSortedArrayMap(keys, vs); }
@Test public void testRandomMaps() { for (Map<Long,Double> map: someMaps(longs(), doubles())) { Long2DoubleSortedArrayMap vec = Long2DoubleSortedArrayMap.create(map); Set<Long> picked = sets(map.keySet()).next(); Set<Long> extra = sets(longs()).next(); LongSortedSet wanted = LongUtils.setUnion(LongUtils.asLongSet(picked), LongUtils.asLongSet(extra)); Long2DoubleSortedMap sv = vec.subMap(wanted); assertThat(sv.keySet(), everyItem(isIn(wanted))); assertThat(sv.keySet(), containsInAnyOrder(picked.toArray())); assertThat(sv.entrySet(), everyItem(isIn(map.entrySet()))); } }
@Override public ObjectSortedSet<Entry> subSet(Entry from, Entry to) { return subMap(from.getLongKey(), to.getLongKey()).long2DoubleEntrySet(); }
private Long2DoubleSortedArrayMap slowSubMap(LongSet toKeep) { LongSortedSet kept = LongUtils.setIntersect(keySet(), toKeep); double[] nvs = new double[kept.size()]; int i = keys.getLowerBound(); int j = 0; LongIterator iter = kept.iterator(); while (iter.hasNext()) { long key = iter.nextLong(); while (keys.getKey(i) < key) { i++; } nvs[j] = values[i]; j++; i++; } return wrap(SortedKeyIndex.fromCollection(kept), nvs); }
@Override public int size() { return keySet().size(); } }
@Test public void testFastIterStartFrom() { double[] values = { 1.5, 2.4, -3.2, 4.3, -5.7 }; Long2DoubleSortedArrayMap map = new Long2DoubleSortedArrayMap(SortedKeyIndex.create(1, 2, 3, 4, 5), values); AbstractLong2DoubleMap.BasicEntry key = new AbstractLong2DoubleMap.BasicEntry(2, 2.0); ObjectBidirectionalIterator<Long2DoubleMap.Entry> iter = map.long2DoubleEntrySet().fastIterator(key); assertThat(iter.next().getLongKey(), equalTo(3L)); assertThat(iter.previous().getLongKey(), equalTo(3L)); assertThat(iter.previous().getLongKey(), equalTo(2L)); }
/** * Create a map from an array and index mapping. * * @param mapping The index mapping specifying the keys. * @param values The array of values. * @return A sparse vector mapping the IDs in {@code map} to the values in {@code values}. * @throws IllegalArgumentException if {@code values} not the same size as {@code idx}. */ public static Long2DoubleSortedArrayMap fromArray(KeyIndex mapping, double[] values) { return fromArray(mapping, DoubleArrayList.wrap(values)); }
protected void scoreItem(Long2DoubleMap userData, long item, ItemItemScoreAccumulator accum) { // find the usable neighbors Long2DoubleSortedArrayMap allNeighbors = Long2DoubleSortedArrayMap.create(model.getNeighbors(item)); Long2DoubleMap neighborhood = allNeighbors.subMap(userData.keySet()); if (neighborhoodSize > 0) { if (logger.isTraceEnabled()) { logger.trace("truncating {} neighbors to {}", neighborhood.size(), neighborhoodSize); } Long2DoubleAccumulator acc = new TopNLong2DoubleAccumulator(neighborhoodSize); for (Long2DoubleMap.Entry e: neighborhood.long2DoubleEntrySet()) { acc.put(e.getLongKey(), e.getDoubleValue()); } neighborhood = acc.finishMap(); } assert neighborhoodSize <= 0 || neighborhood.size() <= neighborhoodSize; if (neighborhood.size() < minNeighbors) { return; } if (logger.isTraceEnabled()) { logger.trace("scoring item {} with {} of {} neighbors", item, neighborhood.size(), allNeighbors.size()); } scorer.score(item, neighborhood, userData, accum); } }