//--------------------------------------------------------------------------------//
// 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. //
//--------------------------------------------------------------------------------//
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// ALGORITMO DE AGRUPAMIENTO DE FUNCIONES DE PERTENENCIA //
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
package xfuzzy.xfsl;
import xfuzzy.lang.*;
import java.util.Vector;
public class XfspClustering implements Cloneable {
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// CONSTANTES PUBLICAS //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
public static final int NONE = 0;
public static final int CLUST_BEST = 1;
public static final int CLUST_SELECTED = 2;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// MIEMBROS PRIVADOS //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
private int clustering;
private int clusters;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// CONSTRUCTOR //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//-------------------------------------------------------------//
// Constructor por defecto //
//-------------------------------------------------------------//
public XfspClustering() {
this.clustering = NONE;
this.clusters = -1;
}
//-------------------------------------------------------------//
// Constructor con datos //
//-------------------------------------------------------------//
public XfspClustering(int kind, int num) {
this.clustering = kind;
this.clusters = num;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// METODOS PUBLICOS //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//-------------------------------------------------------------//
// Duplicar el objeto //
//-------------------------------------------------------------//
public Object clone() {
return new XfspClustering(this.clustering, this.clusters);
}
//-------------------------------------------------------------//
// Obtiene el tipo de agrupamiento //
//-------------------------------------------------------------//
public int getKind() {
return this.clustering;
}
//-------------------------------------------------------------//
// Obtiene el numero de clusters //
//-------------------------------------------------------------//
public int getParam() {
return this.clusters;
}
//-------------------------------------------------------------//
// Verificar si esta activo //
//-------------------------------------------------------------//
public boolean isOn() {
return (this.clustering != NONE);
}
//-------------------------------------------------------------//
// Configura el proceso desde una directiva //
//-------------------------------------------------------------//
public void set(String name, double[] param) {
if(name.equals("output_clustering") && param.length == 0)
{ clustering = CLUST_BEST; clusters = -1; }
if(name.equals("output_clustering") && param.length > 0)
{ clustering = CLUST_SELECTED; clusters = (int) param[0]; }
}
//-------------------------------------------------------------//
// Codigo de la directiva de configuracion //
//-------------------------------------------------------------//
public String toCode() {
String eol = System.getProperty("line.separator", "\n");
String src = "";
if(clustering == CLUST_SELECTED)
src = "(output_clustering,"+clusters+")"+eol;
if(clustering == CLUST_BEST)
src = "(output_clustering)"+eol;
return src;
}
//-------------------------------------------------------------//
// Ejecucion del proceso de simplificacion //
//-------------------------------------------------------------//
public String[] compute(Specification spec) {
if(clustering == NONE) return new String[0];
Vector message = new Vector();
Vector reduced = new Vector();
Rulebase[] rulebase = spec.getRulebases();
for(int i=0; i<rulebase.length; i++) {
Variable[] output = rulebase[i].getOutputs();
for(int j=0; j<output.length; j++) {
Type type = output[j].getType();
if(reduced.contains(type) || !reducible(type)) continue;
message.addElement( clustering(type,spec) );
reduced.addElement(type);
}
}
Object[] omsg = message.toArray();
String msg[] = new String[omsg.length];
for(int i=0; i<omsg.length; i++) msg[i] = (String) omsg[i];
return msg;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// METODOS PRIVADOS //
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//-------------------------------------------------------------//
// Verifica que un tipo sea agrupable //
//-------------------------------------------------------------//
private boolean reducible(Type type) {
ParamMemFunc[] mf = type.getParamMembershipFunctions();
if(mf.length == 0) return false;
String mfclass = mf[0].getClass().getName();
for(int i=0; i<mf.length; i++)
if(!(mf[i].getClass().getName().equals(mfclass))) return false;
return true;
}
//-------------------------------------------------------------//
// Simplifica las funciones de pertenencia de un tipo //
//-------------------------------------------------------------//
private String clustering(Type type, Specification spec) {
ParamMemFunc[] mf = type.getParamMembershipFunctions();
double[][] data = new double[mf.length][];
for(int i=0; i<mf.length; i++) data[i] = mf[i].get();
int M = mf.length;
int C = (clustering == CLUST_BEST? num_cluster(data) : clusters);
XfspCluster cl = new XfspCluster(data, C);
simplifyType(type,cl,spec);
String msg = "Clustering: Membership functions of type "+type.getName();
msg += " reduced from "+M+" to "+C+".";
return msg;
}
//-------------------------------------------------------------//
// Calcula el numero de clusters optimo //
//-------------------------------------------------------------//
private int num_cluster(double[][] data) {
double max=0;
int num=2;
for(int i=2; i<data.length/2 ; i++) {
XfspCluster cl = new XfspCluster(data, i);
double eval = cl.evaluation();
if(eval>max) { max = eval; num = i;}
}
return num;
}
//-------------------------------------------------------------//
// Sustituye las funciones de un tipo por los clusters //
//-------------------------------------------------------------//
private void simplifyType(Type type, XfspCluster cl, Specification spec) {
ParamMemFunc[] pmf= new ParamMemFunc[cl.cluster.length];
for(int i=0; i<cl.cluster.length; i++) {
pmf[i] = createClusterMemFunc(type, cl, i);
}
ParamMemFunc[] omf = type.getParamMembershipFunctions();
for(int j=0; j<omf.length; j++) spec.exchange(omf[j],pmf[ cl.assign[j] ]);
type.setMembershipFunctions(pmf);
}
//-------------------------------------------------------------//
// Genera una MF con los parametros del cluster //
//-------------------------------------------------------------//
private ParamMemFunc createClusterMemFunc(Type type, XfspCluster cl, int i) {
ParamMemFunc[] omf = type.getParamMembershipFunctions();
int index = 0;
for(int j = 0; j < omf.length; j++) if(cl.assign[j] == i) { index=j; break; }
ParamMemFunc pmf = (ParamMemFunc) omf[index].clone(type.getUniverse());
pmf.setLabel("mf"+i);
double oldparam[] = pmf.get();
boolean wrong = false;
try { pmf.set(cl.cluster[i]); } catch(Exception ex) { wrong = true; }
if(wrong || !pmf.test()) {
try { pmf.set(oldparam); } catch(Exception ex) { }
Parameter param[] = pmf.getParameters();
for(int j=0; j<cl.cluster[i].length && j<param.length; j++) {
param[j].setDesp(cl.cluster[i][j] - param[j].value);
}
pmf.update();
}
return pmf;
}
}