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.experiment.evaluation.cluster;
031
032import java.util.ArrayList;
033import java.util.List;
034import java.util.Map;
035import java.util.Map.Entry;
036
037import org.openimaj.experiment.evaluation.AnalysisResult;
038import org.openimaj.experiment.evaluation.Evaluator;
039import org.openimaj.experiment.evaluation.cluster.analyser.ClusterAnalyser;
040import org.openimaj.experiment.evaluation.cluster.processor.Clusterer;
041import org.openimaj.util.function.Function;
042
043/**
044 * @author Sina Samangooei (ss@ecs.soton.ac.uk)
045 *
046 * @param <D> The type of data which the internal clusterer can cluster lists of
047 * @param <T> The type of results the
048 */
049public class ClusterEvaluator<D, T extends AnalysisResult> implements Evaluator<int[][],T>{
050
051        private int[][] correct;
052        private ClusterAnalyser<T> analyser;
053        private Clusterer<D> gen;
054        private D data;
055
056        /**
057         * @param gen
058         * @param data 
059         * @param clusters
060         * @param analyser
061         */
062        public ClusterEvaluator(Clusterer<D> gen, D data, int[][] clusters, ClusterAnalyser<T> analyser) {
063                this.gen = gen;
064                this.correct = clusters;
065                this.analyser = analyser;
066                this.data = data;
067        }
068        
069        /**
070         * @param gen
071         * @param data 
072         * @param dataset extract the elements of this map "in order" and build a ground truth. very dangerous.
073         * @param analyser
074         */
075        public <A,B> ClusterEvaluator(Clusterer<D> gen, D data, Map<A,? extends List<B>> dataset, ClusterAnalyser<T> analyser) {
076                this.gen = gen;
077                this.correct = new int[dataset.size()][];
078                int j = 0;
079                int k = 0;
080                for (Entry<A, ? extends List<B>> es : dataset.entrySet()) {
081                        this.correct[j] = new int[es.getValue().size()];
082                        int i = 0;
083                        List<B> value = es.getValue();
084                        for (int l = 0; l < value.size(); l++) {
085                                this.correct[j][i++] = k;
086                                k++;
087                        }
088                        j++;
089                }
090                this.analyser = analyser;
091                this.data = data;
092        }
093        
094        /**
095         * @param gen
096         * @param data 
097         * @param indexFunc given a data instance, return its index
098         * @param dataset 
099         * @param analyser
100         */
101        public <A,B> ClusterEvaluator(
102                        Clusterer<D> gen, 
103                        D data, 
104                        Function<B,Integer> indexFunc,
105                        Map<A,? extends List<B>> dataset, 
106                        ClusterAnalyser<T> analyser) {
107                this.gen = gen;
108                this.correct = new int[dataset.size()][];
109                int j = 0;
110                for (Entry<A, ? extends List<B>> es : dataset.entrySet()) {
111                        this.correct[j] = new int[es.getValue().size()];
112                        int i = 0;
113                        List<B> value = es.getValue();
114                        for (B b : value) {
115                                this.correct[j][i++] = indexFunc.apply(b);
116                        }
117                        j++;
118                }
119                this.analyser = analyser;
120                this.data = data;
121        }
122        
123        /**
124         * @param gen
125         * @param dataset
126         * @param transform turn a list of dataset items into the required type for clustering
127         * @param analyser
128         */
129        public <A,B> ClusterEvaluator(
130                Clusterer<D> gen, 
131                Map<A,? extends List<B>> dataset, 
132                Function<List<B>,D> transform, 
133                ClusterAnalyser<T> analyser
134        ) {
135                this.gen = gen;
136                this.analyser = analyser;
137                this.correct = new int[dataset.size()][];
138                int j = 0;
139                List<B> flattened = new ArrayList<B>();
140                for (Entry<A, ? extends List<B>> es : dataset.entrySet()) {
141                        this.correct[j] = new int[es.getValue().size()];
142                        int i = 0;
143                        for (B b : es.getValue()) {
144                                this.correct[j][i++] = flattened.size();
145                                flattened.add(b);
146                        }
147                        j++;
148                }
149                this.data = transform.apply(flattened);
150        }
151        
152        
153        
154        
155
156        @Override
157        public int[][] evaluate() {
158                return this.gen.performClustering(this.data);
159        }
160
161        @Override
162        public T analyse(int[][] estimated) {
163                return this.analyser.analyse(correct, estimated);
164        }
165
166}