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.dbscan; 031 032import java.util.ArrayList; 033import java.util.List; 034 035import org.openimaj.ml.clustering.SparseMatrixClusterer; 036import org.openimaj.ml.clustering.dbscan.neighbourhood.RegionMode; 037import org.openimaj.util.pair.IntDoublePair; 038 039import ch.akuhn.matrix.SparseMatrix; 040import ch.akuhn.matrix.Vector; 041import ch.akuhn.matrix.Vector.Entry; 042 043/** 044 * Implementation of DBSCAN (http://en.wikipedia.org/wiki/DBSCAN) using 045 * a 046 * @author Sina Samangooei (ss@ecs.soton.ac.uk) 047 * 048 */ 049public abstract class SparseMatrixDBSCAN extends DBSCAN implements SparseMatrixClusterer<DoubleDBSCANClusters>{ 050 051 private double eps; 052 private int minPts; 053 054 /** 055 * Perform a DBScane with this configuration 056 * @param eps 057 * @param minPts 058 */ 059 public SparseMatrixDBSCAN(double eps, int minPts) { 060 this.eps = eps; 061 this.minPts = minPts; 062 } 063 064 class SparseMatrixRegionMode implements RegionMode<IntDoublePair>{ 065 private SparseMatrix mat; 066 private boolean distanceMode; 067 public SparseMatrixRegionMode(SparseMatrix mat, boolean distanceMode) { 068 this.mat = mat; 069 this.distanceMode = distanceMode; 070 } 071 @Override 072 public List<IntDoublePair> regionQuery(int index) { 073 Vector vec = mat.row(index); 074 List<IntDoublePair> ret = new ArrayList<IntDoublePair>(); 075 if(distanceMode){ 076 ret.add(IntDoublePair.pair(index, 0)); 077 for (Entry ent: vec.entries()) { 078 double v= ent.value; 079 if(v<eps) 080 ret.add(IntDoublePair.pair(ent.index, v)); 081 else break; 082 } 083 } 084 else{ 085 ret.add(IntDoublePair.pair(index, eps * 2)); // HACK 086 for (Entry ent: vec.entries()) { 087 if(ent.value>eps) 088 ret.add(IntDoublePair.pair(ent.index, ent.value)); 089 } 090 } 091 return ret; 092 } 093 @Override 094 public boolean validRegion(List<IntDoublePair> region) { 095 return region.size() >= minPts; 096 } 097 098 } 099 100 @Override 101 public int[][] performClustering(SparseMatrix data) { 102 return this.cluster(data).clusters(); 103 } 104 105 /** 106 * @return the eps of this dbscan 107 */ 108 public double getEps() { 109 return this.eps; 110 } 111 112 /** 113 * @param eps the new eps 114 */ 115 public void setEps(double eps) { 116 this.eps = eps; 117 } 118 119 @Override 120 public String toString() { 121 return String.format("%s: eps=%2.2f, minpts=%d",this.getClass().getSimpleName(),eps,minPts); 122 } 123 124}