assert itemDomain.size() == itemDomain.domainSize();
assert itemDomain.domainSize() == nitems;
List<List<ScoredId>> matrix = Lists.newArrayListWithCapacity(itemDomain.domainSize());
// working space for accumulating each row (reuse between rows)
MutableSparseVector currentRow = MutableSparseVector.create(itemUniverse);
Stopwatch timer = Stopwatch.createStarted();
for (int i = 0; i < nitems; i++) {
assert matrix.size() == i;
final long rowItem = itemDomain.getKey(i);
final SparseVector vec1 = buildContext.itemVector(rowItem);
// Take advantage of sparsity if we can
LongIterator neighbors = iterationStrategy.neighborIterator(buildContext, rowItem, false);
currentRow.fill(0);
// Compute similarities and populate the vector
while (neighbors.hasNext()) {
final long colItem = neighbors.nextLong();
final SparseVector vec2 = buildContext.itemVector(colItem);
assert currentRow.containsKey(colItem);
currentRow.set(colItem, similarity.similarity(rowItem, vec1, colItem, vec2));
}
// Remove the current item (it is not its own neighbor)
currentRow.unset(rowItem);
// Normalize and truncate the row
MutableSparseVector normalized = rowNormalizer.normalize(rowItem, currentRow, null);
truncator.truncate(normalized);
// Build up and save the row
ScoredIdListBuilder bld = new ScoredIdListBuilder(normalized.size());
// TODO Allow the symbols in use to be customized
List<ScoredId> row = bld.addChannels(normalized.getChannelVectorSymbols())
.addTypedChannels(normalized.getChannelSymbols())
.addAll(ScoredIds.collectionFromVector(normalized))
.sort(ScoredIds.scoreOrder().reverse())
.finish();
matrix.add(row);
}