View Javadoc

1   /**
2    * Copyright (c) 2011, The University of Southampton and the individual contributors.
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without modification,
6    * are permitted provided that the following conditions are met:
7    *
8    *   * 	Redistributions of source code must retain the above copyright notice,
9    * 	this list of conditions and the following disclaimer.
10   *
11   *   *	Redistributions in binary form must reproduce the above copyright notice,
12   * 	this list of conditions and the following disclaimer in the documentation
13   * 	and/or other materials provided with the distribution.
14   *
15   *   *	Neither the name of the University of Southampton nor the names of its
16   * 	contributors may be used to endorse or promote products derived from this
17   * 	software without specific prior written permission.
18   *
19   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22   * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23   * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26   * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29   */
30  package org.openimaj.ml.clustering.spectral;
31  
32  import static org.junit.Assert.assertTrue;
33  
34  import java.io.IOException;
35  import java.util.ArrayList;
36  import java.util.Collection;
37  import java.util.HashSet;
38  import java.util.Set;
39  
40  import org.junit.Before;
41  import org.junit.Test;
42  import org.openimaj.feature.DoubleFVComparison;
43  import org.openimaj.io.FileUtils;
44  import org.openimaj.knn.DoubleNearestNeighboursExact;
45  import org.openimaj.logger.LoggerUtils;
46  import org.openimaj.math.matrix.MatlibMatrixUtils;
47  import org.openimaj.ml.clustering.IndexClusters;
48  import org.openimaj.ml.clustering.SpatialClusterer;
49  import org.openimaj.ml.clustering.dbscan.ClusterTestDataLoader;
50  import org.openimaj.ml.clustering.dbscan.ClusterTestDataLoader.TestStats;
51  import org.openimaj.ml.clustering.dbscan.DoubleDBSCANClusters;
52  import org.openimaj.ml.clustering.dbscan.DoubleNNDBSCAN;
53  
54  import ch.akuhn.matrix.SparseMatrix;
55  
56  import com.jmatio.types.MLArray;
57  
58  /**
59   * Test Spectral Clustering implementation using data generated from:
60   * http://people.cs.nctu.edu.tw/~rsliang/dbscan/testdatagen.html
61   *
62   * @author Sina Samangooei (ss@ecs.soton.ac.uk)
63   *
64   */
65  public class TestDoubleNormalisedSpecralClustering {
66  	private TestStats testStats;
67  	private double[][] testData;
68  	private int[][] testClusters;
69  	/**
70  	 * @throws IOException
71  	 */
72  	@Before
73  	public void loadTest() throws IOException{
74  		LoggerUtils.prepareConsoleLogger();
75  		String[] data = FileUtils.readlines(TestDoubleNormalisedSpecralClustering.class.getResourceAsStream("/org/openimaj/ml/clustering/dbscan/dbscandata"));
76  		ClusterTestDataLoader loader = new ClusterTestDataLoader();
77  		this.testStats = loader.readTestStats(data);
78  		this.testData = loader.readTestData(data);
79  		this.testClusters = loader.readTestClusters(data);
80  	}
81  
82  
83  
84  	/**
85  	 *
86  	 */
87  	@Test
88  	public void testSimSpatialClusterInverse(){
89  		SpatialClusterer<DoubleDBSCANClusters,double[]> inner = new DoubleNNDBSCAN(
90  			0.5, 3, new DoubleNearestNeighboursExact.Factory(DoubleFVComparison.EUCLIDEAN)
91  		);
92  		SpectralClusteringConf<double[]> conf = new SpectralClusteringConf<double[]>(inner, new GraphLaplacian.Normalised());
93  		conf.eigenChooser = new AbsoluteValueEigenChooser(0.2, 0.1);
94  		DoubleSpectralClustering clust = new DoubleSpectralClustering(conf);
95   		SparseMatrix mat_norm = normalisedSimilarity();
96  		IndexClusters res = clust.cluster(mat_norm);
97  		confirmClusters(res);
98  	}
99  	
100 	/**
101 	 * @throws IOException 
102 	 *
103 	 */
104 	@Test
105 	public void testSimSpatialClusterInverseHardcoded() throws IOException{
106 		SpatialClusterer<DoubleDBSCANClusters,double[]> inner = new DoubleNNDBSCAN(
107 			0.2, 2, new DoubleNearestNeighboursExact.Factory(DoubleFVComparison.EUCLIDEAN)
108 		);
109 		SpectralClusteringConf<double[]> conf = new SpectralClusteringConf<double[]>(inner, new GraphLaplacian.Normalised());
110 		conf.eigenChooser = new AbsoluteValueEigenChooser(0.95, 0.1);
111 		DoubleSpectralClustering clust = new DoubleSpectralClustering(conf);
112 		SparseMatrix mat_norm = normalisedSimilarity(Double.MAX_VALUE);
113 		Collection<MLArray> col = new ArrayList<MLArray>();
114 		col.add(MatlibMatrixUtils.asMatlab(mat_norm));
115 //		MatFileWriter writ = new MatFileWriter(new File("/Users/ss/Experiments/python/Whard.mat"), col);
116 		IndexClusters res = clust.cluster(mat_norm);
117 		confirmClusters(res);
118 	}
119 
120 
121 	private void confirmClusters(IndexClusters res) {
122 		for (int i = 0; i < this.testClusters.length; i++) {
123 			System.err.println(toSet(this.testClusters[i]));
124 			System.err.println(toSet(res.clusters()[i]));
125 			assertTrue(toSet(this.testClusters[i]).equals(toSet(res.clusters()[i])));
126 		}
127 	}
128 
129 
130 	
131 	private SparseMatrix normalisedSimilarity() {
132 		return normalisedSimilarity(this.testStats.eps);
133 	}
134 	private SparseMatrix normalisedSimilarity(double eps) {
135 		final SparseMatrix mat = new SparseMatrix(testData.length,testData.length);
136 		final DoubleFVComparison dist = DoubleFVComparison.EUCLIDEAN;
137 		double maxD = 0;
138 		for (int i = 0; i < testData.length; i++) {
139 			for (int j = i; j < testData.length; j++) {
140 				double d = dist.compare(testData[i], testData[j]);
141 				if(d>eps) d = Double.NaN;
142 				else{
143 					maxD = Math.max(d, maxD);
144 				}
145 				mat.put(i, j, d);
146 				mat.put(j, i, d);
147 			}
148 		}
149 		SparseMatrix mat_norm = new SparseMatrix(testData.length,testData.length);
150 		for (int i = 0; i < testData.length; i++) {
151 			for (int j = i+1; j < testData.length; j++) {
152 				double d = mat.get(i, j);
153 				if(Double.isNaN(d)){
154 					continue;
155 				}
156 				else{
157 					d/=maxD;
158 				}
159 				mat_norm.put(i, j, 1-d);
160 				mat_norm.put(j, i, 1-d);
161 			}
162 		}
163 		return mat_norm;
164 	}
165 	private Set<Integer> toSet(int[] is) {
166 		Set<Integer> set = new HashSet<Integer>();
167 		for (int i = 0; i < is.length; i++) {
168 			set.add(is[i]);
169 		}
170 		return set;
171 	}
172 
173 }