@Nonnull private Long2DoubleAccumulator newAccumulator() { Long2DoubleAccumulator accum; if (modelSize <= 0) { accum = new UnlimitedLong2DoubleAccumulator(); } else { accum = new TopNLong2DoubleAccumulator(modelSize); } return accum; }
@Override public LongSet finishSet() { assert size == heap.size(); LongSet longs = new LongOpenHashSet(size); while (!heap.isEmpty()) { longs.add(items.getLong(heap.dequeueInt())); } clear(); return longs; }
/** * Create a new accumulator to accumulate the top <var>n</var> IDs. * * @param n The number of IDs to retain. */ public TopNLong2DoubleAccumulator(int n) { this.targetCount = n; slot = 0; size = 0; int isz = findInitialSize(targetCount + 1); scores = new DoubleArrayList(isz); items = new CompactableLongArrayList(isz); heap = new IntHeapPriorityQueue(this::comparePositions); // item lists are lazy-allocated }
@Override public Long2DoubleMap truncate(Long2DoubleMap v) { TopNLong2DoubleAccumulator accumulator = new TopNLong2DoubleAccumulator(n); for (Long2DoubleMap.Entry e : Vectors.fastEntries(v)) { double x = e.getDoubleValue(); if (threshold == null || threshold.retain(x)) { accumulator.put(e.getLongKey(), x); } } return accumulator.finishMap(); } }
@Override public Long2DoubleMap truncate(Long2DoubleMap v) { TopNLong2DoubleAccumulator accumulator = new TopNLong2DoubleAccumulator(n); for (Long2DoubleMap.Entry e : Vectors.fastEntries(v)) { double x = e.getDoubleValue(); if (threshold == null || threshold.retain(x)) { accumulator.put(e.getLongKey(), x); } } return accumulator.finishMap(); } }
@Before public void createAccumulator() { accum = new TopNLong2DoubleAccumulator(3); }
@Override public LongList finishList() { assert size == heap.size(); int[] indices = new int[size]; // Copy backwards so the scored list is sorted. for (int i = size - 1; i >= 0; i--) { indices[i] = heap.dequeueInt(); } LongList list = new LongArrayList(size); for (int i : indices) { list.add(items.getLong(i)); } assert heap.isEmpty(); clear(); return list; }
int isz = findInitialSize(targetCount + 1); scores = new DoubleArrayList(isz); items = new CompactableLongArrayList(isz);
@Override public BiConsumer<Map<Long, Long2DoubleMap>, IdBox<Long2DoubleMap>> accumulator() { return (acc, row) -> { Long2DoubleMap r2; if (modelSize <= 0) { r2 = LongUtils.frozenMap(row.getValue()); } else { Long2DoubleAccumulator racc = new TopNLong2DoubleAccumulator(modelSize); racc.putAll(row.getValue()); r2 = racc.finishMap(); } Long2DoubleMap res = acc.putIfAbsent(row.getId(), r2); assert res == null; }; }
@Override public Long2DoubleMap finishMap() { if (scores == null) { return Long2DoubleMaps.EMPTY_MAP; } assert size == heap.size(); int[] indices = new int[size]; // Copy backwards so the scored list is sorted. for (int i = size - 1; i >= 0; i--) { indices[i] = heap.dequeueInt(); } assert heap.isEmpty(); long[] keys = new long[indices.length]; double[] values = new double[indices.length]; for (int i = 0; i < indices.length; i++) { keys[i] = items.getLong(indices[i]); values[i] = scores.getDouble(indices[i]); } clear(); return Long2DoubleSortedArrayMap.wrapUnsorted(keys, values); }
/** * Create a new accumulator to accumulate the top <var>n</var> IDs. * * @param n The number of IDs to retain. */ public TopNLong2DoubleAccumulator(int n) { this.targetCount = n; slot = 0; size = 0; int isz = findInitialSize(targetCount + 1); scores = new DoubleArrayList(isz); items = new CompactableLongArrayList(isz); heap = new IntHeapPriorityQueue(this::comparePositions); // item lists are lazy-allocated }
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); } }
@Override public LongSet finishSet() { assert size == heap.size(); LongSet longs = new LongOpenHashSet(size); while (!heap.isEmpty()) { longs.add(items.getLong(heap.dequeueInt())); } clear(); return longs; }
int isz = findInitialSize(targetCount + 1); scores = new DoubleArrayList(isz); items = new CompactableLongArrayList(isz);
/** * Implement recommendation by calling {@link ItemScorer#score(long, Collection)} and sorting * the results by score. This method uses {@link #getDefaultExcludes(long)} to get the default * exclude set for the user, if none is provided. */ @Override protected List<Long> recommend(long user, int n, LongSet candidates, LongSet exclude) { candidates = getEffectiveCandidates(user, candidates, exclude); logger.debug("Computing {} recommendations for user {} from {} candidates", n, user, candidates.size()); Map<Long, Double> scores = scorer.score(user, candidates); Long2DoubleAccumulator accum; if (n >= 0) { accum = new TopNLong2DoubleAccumulator(n); } else { accum = new UnlimitedLong2DoubleAccumulator(); } Long2DoubleMap map = LongUtils.asLong2DoubleMap(scores); for (Long2DoubleMap.Entry e: Vectors.fastEntries(map)) { accum.put(e.getLongKey(), e.getDoubleValue()); } return accum.finishList(); }
@Override public LongList finishList() { assert size == heap.size(); int[] indices = new int[size]; // Copy backwards so the scored list is sorted. for (int i = size - 1; i >= 0; i--) { indices[i] = heap.dequeueInt(); } LongList list = new LongArrayList(size); for (int i : indices) { list.add(items.getLong(i)); } assert heap.isEmpty(); clear(); return list; }
/** * Score a single item into an accumulator. * @param scores The reference scores. * @param item The item to score. * @param accum The accumulator. */ protected void scoreItem(Long2DoubleMap scores, long item, ItemItemScoreAccumulator accum) { Long2DoubleMap allNeighbors = model.getNeighbors(item); Long2DoubleAccumulator acc; if (neighborhoodSize > 0) { // FIXME Abstract accumulator selection logic acc = new TopNLong2DoubleAccumulator(neighborhoodSize); } else { acc = new UnlimitedLong2DoubleAccumulator(); } for (Long2DoubleMap.Entry nbr: allNeighbors.long2DoubleEntrySet()) { if (scores.containsKey(nbr.getLongKey())) { acc.put(nbr.getLongKey(), nbr.getDoubleValue()); } } Long2DoubleMap neighborhood = acc.finishMap(); scorer.score(item, neighborhood, scores, accum); } }
@Override public Long2DoubleMap finishMap() { if (scores == null) { return Long2DoubleMaps.EMPTY_MAP; } assert size == heap.size(); int[] indices = new int[size]; // Copy backwards so the scored list is sorted. for (int i = size - 1; i >= 0; i--) { indices[i] = heap.dequeueInt(); } assert heap.isEmpty(); long[] keys = new long[indices.length]; double[] values = new double[indices.length]; for (int i = 0; i < indices.length; i++) { keys[i] = items.getLong(indices[i]); values[i] = scores.getDouble(indices[i]); } clear(); return Long2DoubleSortedArrayMap.wrapUnsorted(keys, values); }
@Nonnull private Long2DoubleAccumulator newAccumulator() { Long2DoubleAccumulator accum; if (modelSize <= 0) { accum = new UnlimitedLong2DoubleAccumulator(); } else { accum = new TopNLong2DoubleAccumulator(modelSize); } return accum; }
@Override public BiConsumer<Map<Long, Long2DoubleMap>, IdBox<Long2DoubleMap>> accumulator() { return (acc, row) -> { Long2DoubleMap r2; if (modelSize <= 0) { r2 = LongUtils.frozenMap(row.getValue()); } else { Long2DoubleAccumulator racc = new TopNLong2DoubleAccumulator(modelSize); racc.putAll(row.getValue()); r2 = racc.finishMap(); } Long2DoubleMap res = acc.putIfAbsent(row.getId(), r2); assert res == null; }; }