1 /* 2 AUTOMATICALLY GENERATED BY jTemp FROM 3 /Users/jsh2/Work/openimaj/target/checkout/machine-learning/clustering/src/main/jtemp/org/openimaj/ml/clustering/assignment/soft/#T#KNNAssigner.jtemp 4 */ 5 /** 6 * Copyright (c) 2011, The University of Southampton and the individual contributors. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without modification, 10 * are permitted provided that the following conditions are met: 11 * 12 * * Redistributions of source code must retain the above copyright notice, 13 * this list of conditions and the following disclaimer. 14 * 15 * * Redistributions in binary form must reproduce the above copyright notice, 16 * this list of conditions and the following disclaimer in the documentation 17 * and/or other materials provided with the distribution. 18 * 19 * * Neither the name of the University of Southampton nor the names of its 20 * contributors may be used to endorse or promote products derived from this 21 * software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 26 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 27 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 30 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 package org.openimaj.ml.clustering.assignment.soft; 35 36 import org.openimaj.feature.FloatFVComparison; 37 import org.openimaj.knn.FloatNearestNeighbours; 38 import org.openimaj.knn.FloatNearestNeighboursExact; 39 import org.openimaj.knn.FloatNearestNeighboursProvider; 40 import org.openimaj.knn.approximate.FloatNearestNeighboursKDTree; 41 import org.openimaj.ml.clustering.assignment.SoftAssigner; 42 import org.openimaj.ml.clustering.CentroidsProvider; 43 import org.openimaj.util.pair.IndependentPair; 44 45 /** 46 * A {@link SoftAssigner} that picks a fixed number of nearest neighbours. 47 * Weights returned are actually the distances to the centroids. 48 * 49 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 50 * 51 */ 52 public class FloatKNNAssigner implements SoftAssigner<float[], float[]> { 53 protected FloatNearestNeighbours nn; 54 protected int numNeighbours; 55 56 /** 57 * Construct the assigner using the given cluster data. The assigner 58 * is backed by either a {@link FloatNearestNeighboursExact} or 59 * {@link FloatNearestNeighboursKDTree}, depending on whether the exact 60 * parameter is true or false. If the parameter is true, then the 61 * resultant {@link FloatNearestNeighboursExact} will use Euclidean 62 * distance. 63 * 64 * @param provider the cluster data provider 65 * @param exact if true, then use exact mode; false implies approximate mode. 66 * @param numNeighbours the number of nearest neighbours to select. 67 */ 68 public FloatKNNAssigner(CentroidsProvider<float[]> provider, boolean exact, int numNeighbours) { 69 this.numNeighbours = numNeighbours; 70 71 if (exact) { 72 nn = new FloatNearestNeighboursExact(provider.getCentroids()); 73 } else { 74 if (provider instanceof FloatNearestNeighboursProvider) { 75 FloatNearestNeighbours internal = ((FloatNearestNeighboursProvider)provider).getNearestNeighbours(); 76 77 if (internal != null && internal instanceof FloatNearestNeighboursKDTree) { 78 nn = (FloatNearestNeighboursKDTree) internal; 79 return; 80 } 81 } 82 83 nn = new FloatNearestNeighboursKDTree(provider.getCentroids(), FloatNearestNeighboursKDTree.DEFAULT_NTREES, FloatNearestNeighboursKDTree.DEFAULT_NCHECKS); 84 } 85 } 86 87 /** 88 * Construct the assigner using the given cluster data. The assigner 89 * is backed by either a {@link FloatNearestNeighboursExact} or 90 * {@link FloatNearestNeighboursKDTree}, depending on whether the exact 91 * parameter is true or false. If the parameter is true, then the 92 * resultant {@link FloatNearestNeighboursExact} will use Euclidean 93 * distance. 94 * 95 * @param data the cluster data 96 * @param exact if true, then use exact mode; false implies approximate mode. 97 * @param numNeighbours the number of nearest neighbours to select. 98 */ 99 public FloatKNNAssigner(float[][] data, boolean exact, int numNeighbours) { 100 this.numNeighbours = numNeighbours; 101 102 if (exact) { 103 nn = new FloatNearestNeighboursExact(data); 104 } else { 105 nn = new FloatNearestNeighboursKDTree(data, FloatNearestNeighboursKDTree.DEFAULT_NTREES, FloatNearestNeighboursKDTree.DEFAULT_NCHECKS); 106 } 107 } 108 109 /** 110 * Construct the assigner using the given cluster data and 111 * distance function. The assigner will operate in exact mode, 112 * using a {@link FloatNearestNeighboursExact}. 113 * 114 * @param provider the cluster data provider 115 * @param comparison the distance function 116 * @param numNeighbours the number of nearest neighbours to select. 117 */ 118 public FloatKNNAssigner(CentroidsProvider<float[]> provider, FloatFVComparison comparison, int numNeighbours) { 119 this.numNeighbours = numNeighbours; 120 121 nn = new FloatNearestNeighboursExact(provider.getCentroids(), comparison); 122 } 123 124 /** 125 * Construct the assigner using the given cluster data and 126 * distance function. The assigner will operate in exact mode, 127 * using a {@link FloatNearestNeighboursExact}. 128 * 129 * @param data the cluster data 130 * @param comparison the distance function 131 * @param numNeighbours the number of nearest neighbours to select. 132 */ 133 public FloatKNNAssigner(float[][] data, FloatFVComparison comparison, int numNeighbours) { 134 this.numNeighbours = numNeighbours; 135 136 nn = new FloatNearestNeighboursExact(data, comparison); 137 } 138 139 @Override 140 public int[][] assign(float[][] data) { 141 int [][] indices = new int [data.length][numNeighbours]; 142 float [][] distances = new float [data.length][numNeighbours]; 143 144 nn.searchKNN(data, numNeighbours, indices, distances); 145 146 return indices; 147 } 148 149 @Override 150 public int[] assign(float[] data) { 151 return assign(new float[][] { data })[0]; 152 } 153 154 @Override 155 public void assignWeighted(float[][] data, int[][] assignments, float[][] weights) { 156 nn.searchKNN(data, numNeighbours, assignments, weights); 157 } 158 159 @Override 160 public IndependentPair<int[], float[]> assignWeighted(float[] data) { 161 int [][] indices = new int [data.length][numNeighbours]; 162 float [][] distances = new float [data.length][numNeighbours]; 163 164 nn.searchKNN(new float[][] { data }, numNeighbours, indices, distances); 165 166 return new IndependentPair<int[], float[]>(indices[0], distances[0]); 167 } 168 169 @Override 170 public int numDimensions() { 171 return nn.numDimensions(); 172 } 173 174 @Override 175 public int size() { 176 return nn.size(); 177 } 178 }