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 }