@Override public FloatNearestNeighboursExact create(float[][] data) { return new FloatNearestNeighboursExact(data, distance); } }
/** * Quantise the given data using this Product Quantiser. The output is an * array of bytes corresponding to the index of the matching centroid for * each sub-vector (index numbers are offset by -128 so that 256 centroids * indexes can fit in a single byte). * * @param data * the data to quantise * @return the quantised data. */ public byte[] quantise(float[] data) { final byte[] quantised = new byte[assigners.length]; final int[] idx = { 0 }; final float[] dst = { 0 }; final float[][] qus = new float[1][0]; for (int i = 0, from = 0; i < assigners.length; i++) { final int to = assigners[i].numDimensions(); qus[0] = Arrays.copyOfRange(data, from, from + to); assigners[i].searchNN(qus, idx, dst); quantised[i] = (byte) (idx[0] - 128); from += to; } return quantised; }
/** * Decompress the quantised data by replacing each encoded index with the actual centroid subvector. * * @param qdata the quantised data * * @return the (approximate) decompressed feature */ public float[] decompress(byte[] qdata) { final float[] data = new float[ndims]; for (int i = 0, from = 0; i < assigners.length; i++) { final int len = assigners[i].numDimensions(); int index = (int)qdata[i] + 128; System.arraycopy(this.assigners[i].getPoints()[index], 0, data, from, len); from += len; } return data; } }
@Override public List<IntFloatPair> searchKNN(float[] query, int K) { // Fix for when the user asks for too many points. K = Math.min(K, pnts.length); final BoundedPriorityQueue<IntFloatPair> queue = new BoundedPriorityQueue<IntFloatPair>(K, IntFloatPair.SECOND_ITEM_ASCENDING_COMPARATOR); //prepare working data List<IntFloatPair> list = new ArrayList<IntFloatPair>(K + 1); for (int i = 0; i < K + 1; i++) { list.add(new IntFloatPair()); } // search return search(query, queue, list); }
@Override public int[] assign(float[][] data) { int [] argmins = new int [data.length]; float [] mins = new float [data.length]; nn.searchNN(data, argmins, mins); return argmins; }
@Override public int numDimensions() { return nn.numDimensions(); }
private List<IntFloatPair> search(float[] query, BoundedPriorityQueue<IntFloatPair> queue, List<IntFloatPair> results) { IntFloatPair wp = null; // reset all values in the queue to MAX, -1 for (final IntFloatPair p : results) { p.second = Float.MAX_VALUE; p.first = -1; wp = queue.offerItem(p); } // perform the search for (int i = 0; i < this.pnts.length; i++) { wp.second = distanceFunc(distance, query, pnts[i]); wp.first = i; wp = queue.offerItem(wp); } return queue.toOrderedListDestructive(); }
@Override public int size() { return nn.size(); }
@Override public HardAssigner<float[], float[], IntFloatPair> defaultHardAssigner() { if (nn instanceof FloatNearestNeighboursExact) return new ExactFloatAssigner(this, ((FloatNearestNeighboursExact)nn).distanceComparator()); return new KDTreeFloatEuclideanAssigner(this); }
@Override public IntFloatPair searchNN(final float[] query) { final BoundedPriorityQueue<IntFloatPair> queue = new BoundedPriorityQueue<IntFloatPair>(1, IntFloatPair.SECOND_ITEM_ASCENDING_COMPARATOR); //prepare working data List<IntFloatPair> list = new ArrayList<IntFloatPair>(2); list.add(new IntFloatPair()); list.add(new IntFloatPair()); return search(query, queue, list).get(0); }
@Override public void assignDistance(float[][] data, int[] indices, float[] distances) { nn.searchNN(data, indices, distances); }
/** * Construct a {@link FloatProductQuantiser} with the given * nearest-neighbour assigners. The number of dimensions of the assigners * determines how long each sub-vector is. There is a one-to-one mapping * between in the order of assigners and sub-vectors. * * @param assigners * the nearest-neighbour assigners. */ public FloatProductQuantiser(FloatNearestNeighboursExact[] assigners) { this.assigners = assigners; for (final FloatNearestNeighboursExact nn : assigners) ndims += nn.numDimensions(); }
private List<IntFloatPair> search(float[] query, BoundedPriorityQueue<IntFloatPair> queue, List<IntFloatPair> results) { IntFloatPair wp = null; // reset all values in the queue to MAX, -1 for (final IntFloatPair p : results) { p.second = Float.MAX_VALUE; p.first = -1; wp = queue.offerItem(p); } // perform the search for (int i = 0; i < this.pnts.length; i++) { wp.second = distanceFunc(distance, query, pnts[i]); wp.first = i; wp = queue.offerItem(wp); } return queue.toOrderedListDestructive(); }
/** * Construct the assigner using the given cluster data and * distance function. The assigner will operate in exact mode, * using a {@link FloatNearestNeighboursExact}. * * @param data the cluster data * @param comparison the distance function * @param numNeighbours the number of nearest neighbours to select. */ public FloatKNNAssigner(float[][] data, FloatFVComparison comparison, int numNeighbours) { this.numNeighbours = numNeighbours; nn = new FloatNearestNeighboursExact(data, comparison); }
/** * Quantise the given data using this Product Quantiser. The output is an * array of bytes corresponding to the index of the matching centroid for * each sub-vector (index numbers are offset by -128 so that 256 centroids * indexes can fit in a single byte). * * @param data * the data to quantise * @return the quantised data. */ public byte[] quantise(float[] data) { final byte[] quantised = new byte[assigners.length]; final int[] idx = { 0 }; final float[] dst = { 0 }; final float[][] qus = new float[1][0]; for (int i = 0, from = 0; i < assigners.length; i++) { final int to = assigners[i].numDimensions(); qus[0] = Arrays.copyOfRange(data, from, from + to); assigners[i].searchNN(qus, idx, dst); quantised[i] = (byte) (idx[0] - 128); from += to; } return quantised; }
/** * Decompress the quantised data by replacing each encoded index with the actual centroid subvector. * * @param qdata the quantised data * * @return the (approximate) decompressed feature */ public float[] decompress(byte[] qdata) { final float[] data = new float[ndims]; for (int i = 0, from = 0; i < assigners.length; i++) { final int len = assigners[i].numDimensions(); int index = (int)qdata[i] + 128; System.arraycopy(this.assigners[i].getPoints()[index], 0, data, from, len); from += len; } return data; } }
@Override public List<IntFloatPair> searchKNN(float[] query, int K) { // Fix for when the user asks for too many points. K = Math.min(K, pnts.length); final BoundedPriorityQueue<IntFloatPair> queue = new BoundedPriorityQueue<IntFloatPair>(K, IntFloatPair.SECOND_ITEM_ASCENDING_COMPARATOR); //prepare working data List<IntFloatPair> list = new ArrayList<IntFloatPair>(K + 1); for (int i = 0; i < K + 1; i++) { list.add(new IntFloatPair()); } // search return search(query, queue, list); }
@Override public IntFloatPair assignDistance(float[] data) { int [] index = new int [1]; float [] distance = new float [1]; nn.searchNN(new float[][] { data }, index, distance); return new IntFloatPair(index[0], distance[0]); }
/** * Construct a {@link FloatProductQuantiser} with the given * nearest-neighbour assigners. The number of dimensions of the assigners * determines how long each sub-vector is. There is a one-to-one mapping * between in the order of assigners and sub-vectors. * * @param assigners * the nearest-neighbour assigners. */ public FloatProductQuantiser(FloatNearestNeighboursExact[] assigners) { this.assigners = assigners; for (final FloatNearestNeighboursExact nn : assigners) ndims += nn.numDimensions(); }
/** * Construct the assigner using the given cluster data and * distance function. * * @param data the cluster data * @param comparison the distance function */ public ExactFloatAssigner(float[][] data, FloatFVComparator comparison) { nn = new FloatNearestNeighboursExact(data, comparison); }