001/*
002        AUTOMATICALLY GENERATED BY jTemp FROM
003        /Users/jsh2/Work/openimaj/target/checkout/machine-learning/nearest-neighbour/src/main/jtemp/org/openimaj/knn/pq/#T#SDCNearestNeighbours.jtemp
004*/
005/**
006 * Copyright (c) 2011, The University of Southampton and the individual contributors.
007 * All rights reserved.
008 *
009 * Redistribution and use in source and binary forms, with or without modification,
010 * are permitted provided that the following conditions are met:
011 *
012 *   *  Redistributions of source code must retain the above copyright notice,
013 *      this list of conditions and the following disclaimer.
014 *
015 *   *  Redistributions in binary form must reproduce the above copyright notice,
016 *      this list of conditions and the following disclaimer in the documentation
017 *      and/or other materials provided with the distribution.
018 *
019 *   *  Neither the name of the University of Southampton nor the names of its
020 *      contributors may be used to endorse or promote products derived from this
021 *      software without specific prior written permission.
022 *
023 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
024 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
025 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
026 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
027 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
028 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
029 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
030 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
031 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
032 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
033 */
034 
035 package org.openimaj.knn.pq;
036
037import org.openimaj.citation.annotation.Reference;
038import org.openimaj.citation.annotation.ReferenceType;
039import org.openimaj.feature.FloatFVComparison;
040import org.openimaj.util.pair.IntFloatPair;
041import org.openimaj.util.queue.BoundedPriorityQueue;
042/**
043 * Nearest-neighbours using Symmetric Distance Computation (SDC) on Product
044 * Quantised vectors. In SDC, both query and the database points are quantised.
045 * Distances are calculated by look-up from precomputed tables of the distance
046 * between all centroids for each subvector.
047 * <p>
048 * <strong>SDC has the same computational cost as ADC, but a higher error in the
049 * computed distance, so its use is not recommended. This implementation is
050 * provided for completeness only.</strong>
051 * 
052 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
053 */
054@Reference(
055                type = ReferenceType.Article,
056                author = { "Jegou, Herve", "Douze, Matthijs", "Schmid, Cordelia" },
057                title = "Product Quantization for Nearest Neighbor Search",
058                year = "2011",
059                journal = "IEEE Trans. Pattern Anal. Mach. Intell.",
060                pages = { "117", "", "128" },
061                url = "http://dx.doi.org/10.1109/TPAMI.2010.57",
062                month = "January",
063                number = "1",
064                publisher = "IEEE Computer Society",
065                volume = "33",
066                customData = {
067                                "issn", "0162-8828",
068                                "numpages", "12",
069                                "doi", "10.1109/TPAMI.2010.57",
070                                "acmid", "1916695",
071                                "address", "Washington, DC, USA",
072                                "keywords", "High-dimensional indexing, High-dimensional indexing, image indexing, very large databases, approximate search., approximate search., image indexing, very large databases"
073                })
074public class FloatSDCNearestNeighbours extends FloatADCNearestNeighbours {
075        float[][][] distances;
076
077        /**
078         * Construct the SDC with the given quantiser, centroids (corresponding to
079         * the quantiser's internal assigners), and data.
080         * 
081         * @param pq
082         *            the Product Quantiser
083         * @param pqCentroids
084         *            the centroids corresponding to the the Product Quantiser's
085         *            internal assigners.
086         * @param dataPoints
087         *            the data to index
088         */
089        public FloatSDCNearestNeighbours(FloatProductQuantiser pq, float[][][] pqCentroids, float[][] dataPoints) {
090                super(pq, dataPoints);
091
092                this.distances = new float[pq.assigners.length][][];
093
094                for (int i = 0; i < pq.assigners.length; i++) {
095                        final float[][] centroids = pqCentroids[i];
096
097                        distances[i] = new float[centroids.length][centroids.length];
098
099                        for (int j = 0; j < centroids.length; j++) {
100                                for (int k = j; k < centroids.length; k++) {
101                                        distances[i][j][k] = (float) FloatFVComparison.SUM_SQUARE.compare(centroids[j], centroids[k]);
102                                        distances[i][k][j] = distances[i][j][k];
103                                }
104                        }
105                }
106        }
107
108        @Override
109        protected void computeDistances(float[] fullQuery, BoundedPriorityQueue<IntFloatPair> queue, IntFloatPair workingPair)
110        {
111                final byte[] query = pq.quantise(fullQuery);
112
113                for (int i = 0; i < data.length; i++) {
114                        workingPair.first = i;
115                        workingPair.second = 0;
116
117                        for (int j = 0; j < query.length; j++) {
118                                workingPair.second += distances[j][query[j] + 128][data[i][j] + 128];
119                        }
120
121                        workingPair = queue.offerItem(workingPair);
122                }
123        }
124}