Java tutorial
/* * LensKit, an open source recommender systems toolkit. * Copyright 2010-2014 LensKit Contributors. See CONTRIBUTORS.md. * Work on LensKit has been funded by the National Science Foundation under * grants IIS 05-34939, 08-08692, 08-12148, and 10-17697. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ package org.grouplens.lenskit.vectors; import com.google.common.base.Function; import com.google.common.collect.Iterators; import it.unimi.dsi.fastutil.ints.IntIterator; import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import it.unimi.dsi.fastutil.longs.LongSet; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.MutablePair; import org.apache.commons.lang3.tuple.Pair; import org.grouplens.lenskit.scored.ScoredId; import org.grouplens.lenskit.symbols.Symbol; import org.grouplens.lenskit.symbols.TypedSymbol; import javax.annotation.Nullable; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; /** * Utility methods for interacting with vectors. * * @compat Public * @author <a href="http://www.grouplens.org">GroupLens Research</a> * @deprecated Use the new vector utilities and maps in `lenskit-core` instead. */ @Deprecated public final class Vectors { /** * Private constructor. This class is meant to be used * via its static methods, not instantiated. */ private Vectors() { } @SuppressWarnings({ "rawtypes", "unchecked" }) public static MutableSparseVector fromScoredIds(List<ScoredId> scores) { LongSet ids = new LongOpenHashSet(); for (ScoredId sid : scores) { ids.add(sid.getId()); } MutableSparseVector vec = MutableSparseVector.create(ids); for (ScoredId sid : scores) { long id = sid.getId(); if (!vec.containsKey(id)) { vec.set(id, sid.getScore()); for (Symbol sym : sid.getUnboxedChannelSymbols()) { vec.getOrAddChannelVector(sym).set(id, sid.getUnboxedChannelValue(sym)); } for (TypedSymbol tsym : sid.getChannelSymbols()) { if (!tsym.getType().equals(Double.class)) { vec.getOrAddChannel(tsym).put(id, sid.getChannelValue(tsym)); } } } } return vec; } //region Paired iteration private static final Function<Pair<VectorEntry, VectorEntry>, ImmutablePair<VectorEntry, VectorEntry>> IMMUTABLE_PAIR_COPY = new Function<Pair<VectorEntry, VectorEntry>, ImmutablePair<VectorEntry, VectorEntry>>() { @Nullable @Override public ImmutablePair<VectorEntry, VectorEntry> apply(@Nullable Pair<VectorEntry, VectorEntry> p) { if (p == null) { return null; } else { VectorEntry left = p.getLeft(); if (left != null) { left = left.clone(); } VectorEntry right = p.getRight(); if (right != null) { right = right.clone(); } return ImmutablePair.of(left, right); } } }; /** * Iterate over the intersection of two vectors - they keys they have in common. * @param v1 The first vector. * @param v2 The second vector. * @return An iterator over the common pairs. This iterator will never contain null entries. */ public static Iterable<ImmutablePair<VectorEntry, VectorEntry>> intersect(final SparseVector v1, final SparseVector v2) { return new Iterable<ImmutablePair<VectorEntry, VectorEntry>>() { @Override public Iterator<ImmutablePair<VectorEntry, VectorEntry>> iterator() { return Iterators.transform(new FastIntersectIterImpl(v1, v2), IMMUTABLE_PAIR_COPY); } }; } /** * Iterate over the intersection of two vectors without the overhead of object creation. * @param v1 The first vector. * @param v2 The second vector. * @return A fast iterator over the common keys of the two vectors. * @see #intersect(SparseVector, SparseVector) */ public static Iterable<Pair<VectorEntry, VectorEntry>> fastIntersect(final SparseVector v1, final SparseVector v2) { return new Iterable<Pair<VectorEntry, VectorEntry>>() { @Override public Iterator<Pair<VectorEntry, VectorEntry>> iterator() { return new FastIntersectIterImpl(v1, v2); } }; } private static class FastIntersectIterImpl implements Iterator<Pair<VectorEntry, VectorEntry>> { private boolean atNext = false; private final SparseVector vec1, vec2; private IntIterator iterA, iterB; // indexes, or -1 for exhausted iterators private int idxA, idxB; private VectorEntry leftEnt; private VectorEntry rightEnt; private MutablePair<VectorEntry, VectorEntry> pair; public FastIntersectIterImpl(SparseVector v1, SparseVector v2) { vec1 = v1; vec2 = v2; // FIXME The true here slows things down iterA = v1.keys.activeIndexIterator(true); iterB = v2.keys.activeIndexIterator(true); idxA = iterA.hasNext() ? iterA.nextInt() : -1; idxB = iterB.hasNext() ? iterB.nextInt() : -1; leftEnt = new VectorEntry(v1, -1, 0, 0, false); rightEnt = new VectorEntry(v2, -1, 0, 0, false); pair = MutablePair.of(leftEnt, rightEnt); } @Override public boolean hasNext() { if (!atNext) { while (idxA >= 0 && idxB >= 0) { long ka = vec1.keys.getKey(idxA); long kb = vec2.keys.getKey(idxB); if (ka == kb) { atNext = true; break; } else if (ka < kb) { idxA = iterA.hasNext() ? iterA.nextInt() : -1; } else { idxB = iterB.hasNext() ? iterB.nextInt() : -1; } } } return atNext; } @Override public Pair<VectorEntry, VectorEntry> next() { if (!hasNext()) { throw new NoSuchElementException(); } assert vec1.keys.getKey(idxA) == vec2.keys.getKey(idxB); leftEnt.set(idxA, vec1.keys.getKey(idxA), vec1.values[idxA], true); idxA = iterA.hasNext() ? iterA.nextInt() : -1; rightEnt.set(idxB, vec2.keys.getKey(idxB), vec2.values[idxB], true); idxB = iterB.hasNext() ? iterB.nextInt() : -1; atNext = false; return pair; } @Override public void remove() { throw new UnsupportedOperationException(); } } //endregion }