//--------------------------------------------------------------------------------//
// COPYRIGHT NOTICE //
//--------------------------------------------------------------------------------//
// Copyright (c) 2012, Instituto de Microelectronica de Sevilla (IMSE-CNM) //
// //
// All rights reserved. //
// //
// Redistribution and use in source and binary forms, with or without //
// modification, are permitted provided that the following conditions are met: //
// //
// * Redistributions of source code must retain the above copyright notice, //
// this list of conditions and the following disclaimer. //
// //
// * Redistributions in binary form must reproduce the above copyright //
// notice, this list of conditions and the following disclaimer in the //
// documentation and/or other materials provided with the distribution. //
// //
// * Neither the name of the IMSE-CNM nor the names of its contributors may //
// be used to endorse or promote products derived from this software //
// without specific prior written permission. //
// //
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" //
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE //
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE //
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE //
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL //
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR //
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER //
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, //
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE //
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. //
//--------------------------------------------------------------------------------//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// Agrupamiento de un conjunto de datos en N clusters //
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
package xfuzzy.xfsl;
public class XfspCluster {
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// MIEMBROS PUBLICOS //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
public double[][] data;
public double[][] cluster;
public int[] assign;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// CONSTRUCTOR //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
public XfspCluster(double[][] data, int C) {
this.data = data;
this.cluster = new double[C][data[0].length];
this.assign = new int[data.length];
for(int i=0; i<C; i++) assign[i] = i;
for(int i=C; i<assign.length; i++) assign[i] = -1;
for(int i=C; i<assign.length; i++) insert(i);
do { set_cluster(); } while (reassign());
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// METODOS PUBLICOS //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//-------------------------------------------------------------//
// Funcion de evaluacion del agrupamiento //
//-------------------------------------------------------------//
public double evaluation() {
double max=0, min=Double.MAX_VALUE;
for(int i=0; i<cluster.length; i++)
for(int j=i+1; j<cluster.length; j++){
double dist = dist1_cl_cl(i,j);
if(dist<min) min = dist;
}
for(int i=0; i<cluster.length; i++) {
double dist = diameter(i);
if(dist>max) max = dist;
}
return min/max;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// METODOS PRIVADOS //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//-------------------------------------------------------------//
// Distancia entre dos datos //
//-------------------------------------------------------------//
private double distance_mf_mf(int i, int j) {
double dist = 0;
for(int k=0; k<data[i].length; k++) {
double diff = (data[i][k]-data[j][k]);
dist += diff*diff;
}
return dist;
}
//-------------------------------------------------------------//
// Distancia entre un dato y un cluster //
//-------------------------------------------------------------//
private double distance_mf_cl(int i, int j) {
double dist = 0;
for(int k=0; k<data[i].length; k++) {
double diff = (data[i][k]-cluster[j][k]);
dist += diff*diff;
}
return dist;
}
//-------------------------------------------------------------//
// Distancia entre dos clusters //
//-------------------------------------------------------------//
private double distance_cl_cl(int i, int j) {
double dist = 0;
for(int k=0; k<cluster[i].length; k++) {
double diff = (cluster[i][k]-cluster[j][k]);
dist += diff*diff;
}
return dist;
}
//-------------------------------------------------------------//
// Distancia minima entre los puntos de dos clusters //
//-------------------------------------------------------------//
private double dist1_cl_cl(int cl1, int cl2) {
double min=Double.MAX_VALUE;
for(int i=0; i<data.length; i++) {
if(assign[i] != cl1) continue;
for(int j=0; j<data.length; j++) {
if(assign[j] != cl2) continue;
double dist = distance_mf_mf(i,j);
if(dist<min) min = dist;
}
}
return min;
}
//-------------------------------------------------------------//
// Distancia maxima entre los puntos de un cluster //
//-------------------------------------------------------------//
private double diameter(int cl) {
double max=0;
for(int i=0; i<data.length; i++) {
if(assign[i] != cl) continue;
for(int j=i+1; j<data.length; j++) {
if(assign[j] != cl) continue;
double dist = distance_mf_mf(i,j);
if(dist>max) max = dist;
}
}
return max;
}
//-------------------------------------------------------------//
// Calcula el centro del cluster a partir de sus puntos //
//-------------------------------------------------------------//
private void set_cluster() {
for(int i=0;i<cluster.length; i++){
int n=0;
for(int k=0;k<cluster[i].length;k++) cluster[i][k] = 0;
for(int j=0;j<data.length;j++) if(assign[j] == i) {
for(int k=0;k<cluster[i].length;k++) cluster[i][k] += data[j][k];
n++;
}
if(n>0) for(int k=0;k<cluster[i].length;k++) cluster[i][k] /= n;
}
}
//-------------------------------------------------------------//
// Asigna el punto i-esimo al cluster mejor o a uno nuevo //
//-------------------------------------------------------------//
private void insert(int n) {
double dist_new, dist_cl, min;
int sel_new=0, sel_cl1=0, sel_cl2=0;
set_cluster();
min=Double.MAX_VALUE;
for(int i=0; i<cluster.length; i++){
double dist = distance_mf_cl(n, i);
if(dist<min) { min = dist; sel_new = i; }
}
dist_new = min;
min=Double.MAX_VALUE;
for(int i=0; i<cluster.length ; i++)
for(int j=i+1; j<cluster.length ; j++) {
double dist = distance_cl_cl(i, j);
if(dist<min) {min = dist; sel_cl1 = i; sel_cl2 = j;}
}
dist_cl = min;
if(dist_new < dist_cl) assign[n] = sel_new;
else {
for(int i=0; i<n; i++) if(assign[i] == sel_cl2) assign[i] = sel_cl1;
assign[n] = sel_cl2;
}
}
//-------------------------------------------------------------//
// Reasigna los puntos a los clusters //
//-------------------------------------------------------------//
private boolean reassign(){
boolean change=false;
for(int i=0; i<data.length; i++){
int sel = 0;
double min = distance_mf_cl(i,0);
for(int j=1; j<cluster.length; j++){
double dist = distance_mf_cl(i, j);
if(min > dist) { min = dist; sel = j; }
}
if(assign[i] != sel) { assign[i] = sel; change = true; }
}
return change;
}
}