001/*
002        AUTOMATICALLY GENERATED BY jTemp FROM
003        /Users/jsh2/Work/openimaj/target/checkout/machine-learning/clustering/src/main/jtemp/org/openimaj/ml/clustering/assignment/soft/Hierarchical#T#PathAssigner.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 */
034package org.openimaj.ml.clustering.assignment.soft;
035
036import java.util.Arrays;
037import java.util.HashMap;
038import java.util.Map;
039
040import org.openimaj.ml.clustering.assignment.HardAssigner;
041import org.openimaj.ml.clustering.assignment.SoftAssigner;
042import org.openimaj.ml.clustering.assignment.hard.ExactByteAssigner;
043import org.openimaj.ml.clustering.CentroidsProvider;
044import org.openimaj.ml.clustering.kmeans.HierarchicalByteKMeansResult;
045import org.openimaj.ml.clustering.kmeans.HierarchicalByteKMeansResult.Node;
046import org.openimaj.util.pair.IndependentPair;
047import org.openimaj.util.pair.IntFloatPair;
048
049/**
050 * A {@link SoftAssigner} for gathering the clusters assigned
051 * to a point from a hierarchical clustering. The returned clusters
052 * represent the path down the tree to the final closest leaf node.
053 * 
054 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk)
055 */
056public class HierarchicalBytePathAssigner implements SoftAssigner<byte[], float[]> {
057        protected HierarchicalByteKMeansResult result;
058        protected Map<CentroidsProvider<byte[]>, HardAssigner<byte[], float[], IntFloatPair>> assigners;
059        
060        /**
061         * Construct with the given {@link HierarchicalByteKMeansResult} instance.
062         * @param result the {@link HierarchicalByteKMeansResult} instance.
063         */
064        public HierarchicalBytePathAssigner(HierarchicalByteKMeansResult result) {
065                this.result = result;
066                assigners = new HashMap<CentroidsProvider<byte[]>, HardAssigner<byte[], float[], IntFloatPair>>();
067        }
068        
069        @Override
070        public int[][] assign(byte[][] data) {
071                int[][] assignments = new int[data.length][result.getDepth()];
072                
073                for (int i = 0; i < data.length; i++) {
074                        Node node = result.getRoot();
075                        
076                        int d = 0;
077                        while (node != null) {
078                                HardAssigner<byte[], float[], IntFloatPair> assigner = assigners.get(node.result);
079                                
080                                if (assigner == null) {
081                                        assigner = new ExactByteAssigner(node.result);
082                                        assigners.put(node.result, assigner);
083                                }
084                                
085                                int best = assigner.assign(data[i]);
086
087                                assignments[i][d] = best;
088                                ++d;
089
090                                if (node.children == null)
091                                        break;
092                                node = node.children[best];
093                        }
094                }
095                
096                return assignments;
097        }
098
099        @Override
100        public int[] assign(byte[] data) {
101                return assign(new byte[][] {data})[0];
102        }
103
104        @Override
105        public void assignWeighted(byte[][] data, int[][] assignments, float[][] weights) {
106                int depth = result.getDepth();
107                
108                for (int i = 0; i < data.length; i++) {
109                        Node node = result.getRoot();
110                        
111                        if (assignments[i].length != depth)
112                                assignments[i] = new int[depth];
113                        Arrays.fill(assignments, -1);
114                        
115                        if (weights[i].length != depth)
116                                weights[i] = new float[depth];
117                        
118                        int d = 0;
119                        while (node != null) {
120                                HardAssigner<byte[], float[], IntFloatPair> assigner = assigners.get(node.result);
121                                
122                                if (assigner == null) {
123                                        assigner = new ExactByteAssigner(node.result);
124                                        assigners.put(node.result, assigner);
125                                }
126                                
127                                IntFloatPair best = assigner.assignDistance(data[i]);
128                                
129                                assignments[i][d] = best.first;
130                                weights[i][d] = best.second;
131                                ++d;
132
133                                if (node.children == null)
134                                        break;
135                                
136                                node = node.children[best.first];
137                        }
138                }
139        }
140
141        @Override
142        public IndependentPair<int[], float[]> assignWeighted(byte[] data) {
143                int[][] assignments = new int[1][];
144                float[][] weights = new float[1][];
145                
146                assignWeighted(new byte[][] { data }, assignments, weights);
147                
148                return new IndependentPair<int[], float[]>(assignments[0], weights[0]);
149        }
150        
151        @Override
152        public int numDimensions() {
153            return result.numDimensions();
154        }
155        
156        @Override
157        public int size() {
158            return result.numClusters();
159        }
160}