//--------------------------------------------------------------------------------//
// 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. //
//--------------------------------------------------------------------------------//
package xfuzzy.lang;
import java.io.*;
/**
* Descripci�n de la estructura de un sistema difuso
*
* @author Francisco Jos� Moreno Velo
*
*/
public class Specification {
//----------------------------------------------------------------------------//
// MIEMBROS PRIVADOS //
//----------------------------------------------------------------------------//
/**
* Nombre del sistema difuso
*/
private String name;
/**
* Fichero donde se encuentra almacenada la descripci�n
*/
private File file;
/**
* Lista de conjuntos de operadores definidas en el sistema difuso
*/
private Operatorset operation[];
/**
* Lista de bloques no difusos definida en el sistema difuso
*/
private CrispBlockSet crisp;
/**
* Lista de tipos de variables definidas en el sistma difuso
*/
private Type type[];
/**
* Lista de bases de reglas definidas en el sistema difuso
*/
private Rulebase rulebase[];
/**
* Estructura jer�rquica del sistema difuso
*/
private SystemModule system;
/**
* Lista de par�metros del sistema que se desean ajustar en un proceso
* de aprendizaje autom�tico
*/
private Parameter[] adjustable;
/**
* Marcador para indicar que el sistema ha sufrido modificaciones no
* almacenadas en su correspondiente archivo
*/
private boolean modified;
/**
* Marcador para indicar que el sistema est� siendo editado directamente
* por un objeto XfeditFileEditor
*/
private boolean fileediting;
/**
* Referencia a la ventana de edici�n que est� editando el sistema
*/
private Object editor;
//----------------------------------------------------------------------------//
// CONSTRUCTOR //
//----------------------------------------------------------------------------//
/**
* Constructor a partir de un fichero
*/
public Specification(File file) {
String filename = file.getName();
int index = filename.toLowerCase().lastIndexOf(".xfl");
if(index <= 0) this.name = new String(filename);
else this.name = filename.substring(0,index);
this.file = file;
this.operation = new Operatorset[0];
this.type = new Type[0];
this.rulebase = new Rulebase[0];
this.crisp = new CrispBlockSet();
this.system = new SystemModule();
this.modified = false;
this.editor = null;
this.fileediting = false;
}
/**
* Constructor a partir de un nombre
*/
public Specification(String name) {
this.name = name;
this.file = null;
this.operation = new Operatorset[0];
this.type = new Type[0];
this.rulebase = new Rulebase[0];
this.crisp = new CrispBlockSet();
this.system = new SystemModule();
this.modified = false;
this.editor = null;
this.fileediting = false;
}
//----------------------------------------------------------------------------//
// M�TODOS P�BLICOS //
//----------------------------------------------------------------------------//
//----------------------------------------------------------------------------//
// M�todos de acceso a los campos //
//----------------------------------------------------------------------------//
/**
* Obtiene el nombre del sistema difuso
*/
public String getName() {
return new String(this.name);
}
/**
* Obtiene el fichero de almacenamiento del sistema difuso
*/
public File getFile() {
return this.file;
}
/**
* Obtiene la lista de conjuntos de operadores del sistema
*/
public Operatorset [] getOperatorsets() {
return this.operation;
}
/**
* Obtiene la lista de tipos del sistema
*/
public Type [] getTypes() {
return this.type;
}
/**
* Obtiene la lista de bases de reglas del sistema
*/
public Rulebase [] getRulebases() {
return this.rulebase;
}
/**
* Obtiene la lista de bloques no difusos
*/
public CrispBlockSet getCrispBlockSet() {
return this.crisp;
}
/**
* Obtiene la estructura modular del sistema difuso
*/
public SystemModule getSystemModule() {
return this.system;
}
/**
* Obtiene la referencia a la ventana de edici�n del sistema
*/
public Object getEditor() {
return this.editor;
}
/**
* Verifica si existen cambios no almacenados en el sistema
*/
public boolean isModified() {
return this.modified;
}
/**
* Verifica si el sistema difuso est� siendo editado
*/
public boolean isEditing() {
return (this.editor!=null);
}
/**
* Verifica si la descripci�n XFL3 est� siendo editada
*/
public boolean isFileEditing() {
return this.fileediting;
}
//----------------------------------------------------------------------------//
// M�todos para asignar los valores de los campos //
//----------------------------------------------------------------------------//
/**
* Asigna el fichero de almacenamiento del sistema
*/
public void setFile(File file) {
String filename = file.getName();
int index = filename.lastIndexOf(".xfl");
if(index == -1) this.name = new String(filename);
else this.name = filename.substring(0,index);
this.file = file;
}
/**
* Asigna la lista de conjuntos de operadores del sistema
*/
public void setOperatorsets(Operatorset op[]) {
this.operation = op;
}
/**
* Asigna la lista de tipos del sistema
*/
public void setTypes(Type type[]) {
this.type = type;
}
/**
* Asigna la lista de bases de reglas del sistema
*/
public void setRulebases(Rulebase rulebase[]) {
this.rulebase = rulebase;
}
/**
* Asigna la lista de bloques no difusos
*/
public void setCrispBlockSet(CrispBlockSet cbset) {
this.crisp = cbset;
}
/**
* Asigna la estructura modular del sistema
*/
public void setSystemModule(SystemModule system) {
this.system = system;
}
/**
* Asigna el marcador de modificado del sistema
*/
public void setModified(boolean modif) {
this.modified = modif;
}
/**
* Asigna la referencia al editor del sistema
*/
public void setEditor(Object editor) {
this.editor = editor;
}
/**
* Asigna el marcador de edici�n del c�digo XFL3 del sistema
*/
public void setFileEditing(boolean editing) {
this.fileediting = editing;
}
//----------------------------------------------------------------------------//
// M�todos para a�adir y eliminar componentes //
//----------------------------------------------------------------------------//
/**
* A�ade un conjunto de operadores
*/
public void addOperatorset(Operatorset op) {
Operatorset aop[] = new Operatorset[this.operation.length+1];
System.arraycopy(this.operation,0,aop,0,this.operation.length);
aop[this.operation.length] = op;
this.operation = aop;
}
/**
* A�ade un tipo de variable
*/
public void addType(Type tp) {
Type atp[] = new Type[this.type.length+1];
System.arraycopy(this.type,0,atp,0,this.type.length);
atp[this.type.length] = tp;
this.type = atp;
}
/**
* A�ade un base de reglas
*/
public void addRulebase(Rulebase rb) {
Rulebase arb[] = new Rulebase[this.rulebase.length+1];
System.arraycopy(this.rulebase,0,arb,0,this.rulebase.length);
arb[this.rulebase.length] = rb;
this.rulebase = arb;
}
/**
* Elimina un conjunto de operadores
*/
public void removeOperatorset(Operatorset op) {
if(op.isLinked()) return;
int i;
for(i=0; i<this.operation.length ; i++) if(this.operation[i]==op) break;
if(i == this.operation.length) return;
Operatorset aop[] = new Operatorset[this.operation.length-1];
System.arraycopy(this.operation,0,aop,0,i);
System.arraycopy(this.operation,i+1,aop,i,this.operation.length-i-1);
this.operation = aop;
}
/**
* Elimina un tipo de variable
*/
public void removeType(Type tp) {
if(tp.isLinked()) return;
int i;
for(i=0; i<this.type.length ; i++) if(this.type[i]==tp) break;
if(i == this.type.length) return;
Type atp[] = new Type[this.type.length-1];
System.arraycopy(this.type,0,atp,0,i);
System.arraycopy(this.type,i+1,atp,i,this.type.length-i-1);
this.type = atp;
}
/**
* Elimina un base de reglas
*/
public void removeRulebase(Rulebase rb) {
if(rb.isLinked()) return;
int i;
for(i=0; i<this.rulebase.length ; i++) if(this.rulebase[i]==rb) break;
if(i == this.rulebase.length) return;
Rulebase arb[] = new Rulebase[this.rulebase.length-1];
System.arraycopy(this.rulebase,0,arb,0,i);
System.arraycopy(this.rulebase,i+1,arb,i,this.rulebase.length-i-1);
this.rulebase = arb;
rb.dispose();
}
//----------------------------------------------------------------------------//
// M�todos para buscar e intercambiar componentes //
//----------------------------------------------------------------------------//
/**
* Intercambia dos bases de reglas
*/
public void exchangeRulebase(Rulebase oldrb, Rulebase newrb) {
for(int i=0; i<this.rulebase.length ; i++)
if(this.rulebase[i]==oldrb) { this.rulebase[i] = newrb; oldrb.dispose(); }
system.exchangeRulebase(oldrb, newrb);
}
/**
* Intercambia dos funciones de pertenencia
*/
public void exchange(LinguisticLabel oldmf, LinguisticLabel newmf) {
for(int i=0; i<this.rulebase.length; i++)
if(oldmf != null) rulebase[i].exchange(oldmf,newmf);
}
/**
* Busca un conjunto de operadores
*/
public Operatorset searchOperatorset(String opname) {
for(int i=0; i<this.operation.length ; i++)
if(this.operation[i].equals(opname))
return this.operation[i];
return null;
}
/**
* Busca un tipo de variable
*/
public Type searchType(String typename) {
for(int i=0; i<this.type.length ; i++)
if(this.type[i].equals(typename))
return this.type[i];
return null;
}
/**
* Busca una base de reglas
*/
public Rulebase searchRulebase(String rbname) {
for(int i=0; i<this.rulebase.length ; i++)
if(this.rulebase[i].equals(rbname))
return this.rulebase[i];
return null;
}
//----------------------------------------------------------------------------//
// M�todos gen�ricos //
//----------------------------------------------------------------------------//
/**
* Compara una cadena con el nombre del sistema
*/
public boolean equals(String name) {
return this.name.equals(name);
}
/**
* Obtiene el nombre del sistema
*/
public String toString() {
return new String(this.name);
}
/**
* Genera la descripci�n XFL3 del sistema
*/
public String toXfl() {
String code = "";
for(int i=0; i<this.operation.length; i++) code += this.operation[i].toXfl();
for(int i=0; i<this.type.length; i++) code += this.type[i].toXfl();
for(int i=0; i<this.rulebase.length; i++) code += this.rulebase[i].toXfl();
if(this.crisp != null) code += this.crisp.toXfl();
if(this.system != null) code += this.system.toXfl();
return code;
}
/**
* Almacena la descripci�n XFL3 del sistema en su fichero
*/
public boolean save() {
return XflSaver.save(this, this.file);
}
/**
* Almacena la descripci�n XFL3 del sistema en un fichero dado
*/
public boolean save_as(File file) {
setFile(file);
return save();
}
//----------------------------------------------------------------------------//
// M�todos utilizados por el aprendizaje //
//----------------------------------------------------------------------------//
/**
* Actualiza los par�metros de los tipos de variables
*/
public void update() {
for(int i=0; i<this.type.length; i++) this.type[i].update();
}
/**
* Actualiza el marcador de ajustable de los componentes
*/
public void setAdjustable() {
for(int i=0; i<this.type.length; i++) this.type[i].setAdjustable();
for(int i=0; i<this.rulebase.length; i++) this.rulebase[i].setAdjustable();
int count = 0;
int outputs = system.getOutputs().length;
for(int i=0; i<type.length; i++) {
Family fam[] = type[i].getFamilies();
for(int j=0; j<fam.length; j++) {
Parameter param[] = fam[j].getParameters();
for(int k=0; k<param.length; k++) if(param[k].isAdjustable()) count++;
}
ParamMemFunc[] mf = type[i].getParamMembershipFunctions();
for(int j=0; j<mf.length; j++) {
Parameter param[] = mf[j].getParameters();
for(int k=0; k<param.length; k++) if(param[k].isAdjustable()) count++;
}
}
adjustable = new Parameter[count];
for(int i=0,p=0; i<type.length; i++) {
Family fam[] = type[i].getFamilies();
for(int j=0; j<fam.length; j++) {
Parameter param[] = fam[j].getParameters();
for(int k=0; k<param.length; k++) if(param[k].isAdjustable()) {
param[k].oderiv = new double[outputs];
adjustable[p] = param[k];
p++;
}
}
ParamMemFunc[] mf = type[i].getParamMembershipFunctions();
for(int j=0; j<mf.length; j++) {
Parameter param[] = mf[j].getParameters();
for(int k=0; k<param.length; k++) if(param[k].isAdjustable()) {
param[k].oderiv = new double[outputs];
adjustable[p] = param[k];
p++;
}
}
}
}
/**
* Obtiene la lista de par�metros ajustables
*/
public Parameter[] getAdjustable() {
return adjustable;
}
/**
* Estima la derivada de los par�metros mediante la tangente
*/
public double[] estimate_derivatives(double[] input, double perturb) {
double[] output1 = system.crispInference(input);
for(int i=0; i<type.length; i++) {
Family fam[] = type[i].getFamilies();
for(int j=0; j<fam.length; j++) {
Parameter param[] = fam[j].getParameters();
for(int k=0; k<param.length; k++) {
if(!param[k].isAdjustable()) continue;
param[k].oderiv = new double[output1.length];
double prev = param[k].value;
double sign = (Math.random() <0.5? 1.0 : -1.0);
param[k].setDesp(sign*perturb);
fam[j].update();
double[] output2 = system.crispInference(input);
if((param[k].value - prev)/(sign*perturb) >0.001 )
for(int o=0; o<output1.length; o++)
param[k].oderiv[o] = (output2[o] - output1[o])/(param[k].value - prev);
param[k].value = prev;
}
}
ParamMemFunc[] mf = type[i].getParamMembershipFunctions();
for(int j=0; j<mf.length; j++) {
Parameter param[] = mf[j].getParameters();
for(int k=0; k<param.length; k++) {
if(!param[k].isAdjustable()) continue;
param[k].oderiv = new double[output1.length];
double prev = param[k].value;
double sign = (Math.random() <0.5? 1.0 : -1.0);
param[k].setDesp(sign*perturb);
mf[j].update();
double[] output2 = system.crispInference(input);
if((param[k].value - prev)/(sign*perturb) >0.001 )
for(int o=0; o<output1.length; o++)
param[k].oderiv[o] = (output2[o] - output1[o])/(param[k].value - prev);
param[k].value = prev;
}
}
}
return output1;
}
/**
* Estima la derivada de los par�metros de forma grosera
*/
public double[] stochastic_derivatives(double[] input, double perturb) {
double prev[] = new double[adjustable.length];
double val1[] = new double[adjustable.length];
double sign[] = new double[adjustable.length];
for(int i=0; i<adjustable.length; i++) {
prev[i] = adjustable[i].value;
sign[i] = (Math.random() <0.5? 1.0 : -1.0);
adjustable[i].setDesp(sign[i]*perturb);
}
update();
double[] output1 = system.crispInference(input);
for(int i=0; i<adjustable.length; i++) {
val1[i] = adjustable[i].value;
adjustable[i].value = prev[i];
adjustable[i].setDesp(-sign[i]*perturb);
}
update();
double[] output2 = system.crispInference(input);
for(int i=0; i<adjustable.length; i++) {
double val2 = adjustable[i].value;
adjustable[i].value = prev[i];
if( (val1[i]-val2)/(sign[i]*perturb) >0.001 )
for(int o=0; o<output1.length; o++)
adjustable[i].oderiv[o] = (output2[o] - output1[o])/(val2 - val1[i]);
}
return system.crispInference(input);
}
/**
* Calcula las derivadas del sistema
*/
public double[] compute_derivatives(double[] input) throws XflException {
double[] output = system.crispInference(input);
for(int i=0; i<output.length; i++) {
double[] deriv = new double[output.length];
deriv[i] = 1;
system.derivative(deriv);
for(int p=0; p<adjustable.length; p++) {
adjustable[p].oderiv[i] = adjustable[p].getDeriv();
adjustable[p].setDeriv(0);
}
}
return output;
}
}