001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.ml.clustering.assignment.hard; 031 032import java.lang.reflect.Array; 033import java.util.List; 034 035import org.openimaj.feature.FeatureVector; 036import org.openimaj.knn.ObjectNearestNeighboursExact; 037import org.openimaj.ml.clustering.CentroidsProvider; 038import org.openimaj.ml.clustering.assignment.HardAssigner; 039import org.openimaj.util.comparator.DistanceComparator; 040import org.openimaj.util.pair.IntFloatPair; 041 042/** 043 * A {@link HardAssigner} that assigns points to the closest cluster based on 044 * the distance to the centroid. 045 * 046 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 047 * @param <T> 048 * Type of features 049 */ 050public class ExactFeatureVectorAssigner<T extends FeatureVector> implements HardAssigner<T, float[], IntFloatPair> { 051 protected ObjectNearestNeighboursExact<T> nn; 052 protected int ndims; 053 protected Class<T> clz; 054 055 /** 056 * Construct the assigner using the given cluster data and distance 057 * function. 058 * 059 * @param provider 060 * the cluster data provider 061 * @param comparison 062 * the distance function 063 */ 064 @SuppressWarnings("unchecked") 065 public ExactFeatureVectorAssigner(CentroidsProvider<T> provider, DistanceComparator<? super T> comparison) { 066 final T[] centroids = provider.getCentroids(); 067 nn = new ObjectNearestNeighboursExact<T>(centroids, comparison); 068 this.ndims = centroids[0].length(); 069 this.clz = (Class<T>) centroids.getClass().getComponentType(); 070 } 071 072 /** 073 * Construct the assigner using the given cluster data and distance 074 * function. 075 * 076 * @param data 077 * the cluster data 078 * @param comparison 079 * the distance function 080 */ 081 @SuppressWarnings("unchecked") 082 public ExactFeatureVectorAssigner(T[] data, DistanceComparator<? super T> comparison) { 083 nn = new ObjectNearestNeighboursExact<T>(data, comparison); 084 this.ndims = data[0].length(); 085 this.clz = (Class<T>) data.getClass().getComponentType(); 086 } 087 088 /** 089 * Construct the assigner using the given cluster data and distance 090 * function. 091 * 092 * @param data 093 * the cluster data 094 * @param comparison 095 * the distance function 096 */ 097 @SuppressWarnings("unchecked") 098 public ExactFeatureVectorAssigner(List<T> data, DistanceComparator<? super T> comparison) { 099 nn = new ObjectNearestNeighboursExact<T>(data, comparison); 100 this.ndims = data.get(0).length(); 101 this.clz = (Class<T>) data.get(0).getClass(); 102 } 103 104 @Override 105 public int[] assign(T[] data) { 106 final int[] argmins = new int[data.length]; 107 final float[] mins = new float[data.length]; 108 109 nn.searchNN(data, argmins, mins); 110 111 return argmins; 112 } 113 114 @Override 115 public int assign(T data) { 116 @SuppressWarnings("unchecked") 117 final T[] arr = (T[]) Array.newInstance(clz, 1); 118 arr[0] = data; 119 return assign(arr)[0]; 120 } 121 122 @Override 123 public void assignDistance(T[] data, int[] indices, float[] distances) { 124 nn.searchNN(data, indices, distances); 125 } 126 127 @Override 128 public IntFloatPair assignDistance(T data) { 129 final int[] index = new int[1]; 130 final float[] distance = new float[1]; 131 @SuppressWarnings("unchecked") 132 final T[] arr = (T[]) Array.newInstance(clz, 1); 133 arr[0] = data; 134 135 nn.searchNN(arr, index, distance); 136 137 return new IntFloatPair(index[0], distance[0]); 138 } 139 140 @Override 141 public int size() { 142 return nn.size(); 143 } 144 145 @Override 146 public int numDimensions() { 147 return ndims; 148 } 149 150 /** 151 * Get the underlying nearest-neighbour implementation. 152 * 153 * @return the underlying nearest-neighbour implementation. 154 */ 155 public ObjectNearestNeighboursExact<T> getNN() { 156 return this.nn; 157 } 158}