//--------------------------------------------------------------------------------//
// 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.xfsg;
import xfuzzy.lang.*;
import java.io.*;
/**
* Clase que gestiona la estructura que contiene la informaci�n
* de la base de reglas
*
* @author Jes�s Izquierdo Tena
*/
public class XfsgRulesMemData {
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// ATRIBUTOS PRIVADOS DE LA CLASE
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
private Object vector[][]; // Estructura de datos
private Object tak_sug[][]; // Estructura para almacenar las constantes en Takagi-sugeno
private int longitud; // N�mero de filas de la estructura
private int bits_var; // N�mero de bits con los que se codifica una variable de entrada
private Variable[] var_in; // Variables de entrada
private Variable[] var_output; // Variables de salida
// Funciones de pertenencia de las variables de entrada ordenadas
private XfsgInOrderMemFunc[] inOrderMfInput;
// Funciones de pertenencia de la variable de salida ordenadas
//private XfsgInOrderParamMemFunc[] inOrderMfOutput2;
private int mfUsed[][]; // Funciones de pertenencia usadas
private int [] n_mf_var;
private boolean calcularpesos=false;
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// CONSTRUCTOR DE LA CLASE
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/**
* Constructor de <code>XfsgdlRulesMemData</code>
* Inicializa la estructura l�nea a l�nea a partir de los datos
* obtenidos de la base de reglas
*
* NOTA: Cuando una l�nea de la estructura contiene datos la marca
* como verdadero y en caso contrario la marca como falso.
*/
public XfsgRulesMemData(int filas, Rulebase rulebase, String defuzzy) throws IOException {
// Calcula la longitud de la estructura
longitud = (int) Math.pow((double) 2, (double) filas);
// Inicializa la estructura
var_in = rulebase.getInputs();
n_mf_var=new int[var_in.length];
for(int i=0;i<n_mf_var.length;i++){
n_mf_var[i]=var_in[i].getType().getAllMembershipFunctions().length;
//System.out.println("entradas "+n_mf_var[i]);
}
bits_var = filas / var_in.length;
var_output = rulebase.getOutputs();
if(defuzzy.equals("GammaQuality") || defuzzy.equals("Quality") || defuzzy.equals("WeightedFuzzyMean"))
calcularpesos=true;
double gamma=0;
if (defuzzy.equals("GammaQuality"))
gamma= rulebase.getOperatorset().defuz.getSingleParameters()[0].value;
if(defuzzy.equals("TakagiSugeno")){
tak_sug=new Object[longitud][1+var_output.length*3];
}
//System.out.println("Gamma: "+ gamma);
// PARA N VARIABLES DE ENTRADA:
// PASO 1: Se crea la estructura inOrderMfInput[i] (donde el
// �ndice i direcciona las distintas variables de entrada)
// que contiene una lista con las funciones de pertenencia
// ordenadas
inOrderMfInput = new XfsgInOrderMemFunc[var_in.length];
for (int i = 0; i < var_in.length; i++) {
inOrderMfInput[i] = new XfsgInOrderMemFunc(var_in[i]);
inOrderMfInput[i].sort();
}
// PASO 2: Guarda las reglas del sistema XFL en cprule
Rule[] cprule = rulebase.getRules();
// PASO 3: Inicializa la estructura vector donde se guardar� el
// contenido de la memoria de reglas. Inicializa todas
// sus filas a false
//
// Estructura de vector:
// vector[_][0] ==> Almacena el n�mero de fila en binario
// vector[_][1] ==> Indica si la fila es v�lida o no
// vector[_][2] ==> Almacena el grado de certeza de la regla
//
// Los siguientes dos campos se repiten por cada variable de salida.
// vector[_][3] ==> Almacena el peso de la regla
// vector[_][4] ==> Almacena el nombre de la mf que se activa
vector = new Object[longitud][2+3*var_output.length];
XfsgBinaryDecimal converter = new XfsgBinaryDecimal();
for (int i = 0; i < longitud; i++) {
vector[i][0] = converter.toBinary(i, filas);
vector[i][1] = new Boolean(false);
vector[i][2]=0.0;
for(int j=4;j<vector[i].length;j=j+2)
vector[i][j] = new String ("NR");
for(int j=3;j<vector[i].length;j=j+2)
vector[i][j] = 0.0;
}
if(defuzzy.equals("TakagiSugeno")){
for (int i = 0; i < longitud; i++) {
tak_sug[i][0] = converter.toBinary(i, filas);
for(int j=1;j<tak_sug[i].length;j++){
tak_sug[i][j]=0.0;
}
}
}
// PASO 4: Se van recorriendo las reglas y se guarda su informaci�n en
// vector
mfUsed = new int[var_in.length][2];
for (int k = 0; k < cprule.length; k++) {
// Obtiene el consecuente
Conclusion conc[] = cprule[k].getConclusions();
//System.out.println(conc.length);
// Inicializa mfUsed
for (int i = 0; i < mfUsed.length; i++){
mfUsed[i][0] = -1;
mfUsed[i][1] = -1;
}
Relation left = null;
Relation right = null;
// Aseguramos que la regla es de tipo correcto
Relation rl = cprule[k].getPremise();
if (rl.getKind() != Relation.AND && rl.getKind() != Relation.IS && rl.getKind()!=Relation.GREATER
&& rl.getKind()!=Relation.GR_EQ && rl.getKind()!=Relation.SMALLER
&& rl.getKind()!=Relation.SM_EQ && rl.getKind()!=Relation.ISNOT) {
new XfsgError(4, "" + cprule[k].toXfl());
//err.show();
return;
} else if (rl.getKind() == Relation.IS || rl.getKind()==Relation.GREATER
|| rl.getKind()==Relation.GR_EQ || rl.getKind()==Relation.SMALLER
|| rl.getKind()==Relation.SM_EQ || rl.getKind()==Relation.ISNOT) {
left = rl;
} else {
// parte izquierda
left = rl.getLeftRelation();
// parte derecha
right = rl.getRightRelation();
}
// calcula las mf usadas
getMfUsed(left, right, k);
// PASO 5: Guarda la informaci�n correspondiente en vector
XfsgVectorCount v =new XfsgVectorCount(var_in.length, n_mf_var, mfUsed);
if(!v.Error()){
int tmp1, tmp2;
String aux = new String();
for (int tt = 0; tt < var_in.length; tt++) {
tmp1 = v.get(tt);
aux += converter.toBinary(tmp1, bits_var);
}
tmp2 = converter.toDecimal(aux);
vector[tmp2][1] = new Boolean(true);
vector[tmp2][2]= cprule[k].getDegree();
for(int j=0;j<conc.length;j++){
Variable var=conc[j].getVariable();
//System.out.println(var);
int v_aux=0;
boolean enc=false;
for(int ii=0;ii<var_output.length && !enc;ii++){
if(var_output[ii].equals(var)){
enc=true;
v_aux=ii;
}
}
LinguisticLabel p = conc[j].getMembershipFunction();
vector[tmp2][4+v_aux*2] = p.getLabel();
v.reset(0);
if(defuzzy.equals("TakagiSugeno")){
Parameter [] params =((ParamMemFunc)p).getParameters();
tak_sug[tmp2][1+v_aux*3]=params[0].value;
tak_sug[tmp2][2+v_aux*3]=params[1].value;
tak_sug[tmp2][3+v_aux*3]=params[2].value;
}
// calcula el peso
if (calcularpesos == true) {
String clase=p.getClass().toString();
if(clase.contains("singleton")){
//XfsgError err=new XfsgError();
//err.newWarning(10, "Defuzzification method -> "+defuzzy +" .Membership function -> "+ p.getClass()+"..");
}
else
vector[tmp2][3+v_aux*2] =calculateWeight2(p, defuzzy, gamma);
}
while (v.sub()) {
aux = "";
for (int tt = 0; tt < var_in.length; tt++) {
tmp1 = v.get(tt);
aux += converter.toBinary(tmp1, bits_var);
}
int tmp3 = converter.toDecimal(aux);
//tmp2= converter.toDecimal(aux);
vector[tmp3][1] = new Boolean(true);
vector[tmp3][4+v_aux*2] = p.getLabel();
vector[tmp3][2]= cprule[k].getDegree();
if(defuzzy.equals("TakagiSugeno")){
Parameter [] params =((ParamMemFunc)p).getSingleParameters();
tak_sug[tmp3][1+v_aux*3]=params[0].value;
tak_sug[tmp3][2+v_aux*3]=params[1].value;
tak_sug[tmp3][3+v_aux*3]=params[2].value;
}
// calcula el peso
if (calcularpesos == true) {
vector[tmp3][3+v_aux*2] = calculateWeight2(p,defuzzy, gamma);
}
}
}
}
}
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// M�TO_DOS P�BLICOS DE LA CLASE
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
/**
* M�todo que obtiene la mf de una linea dada
*/
public String getMF2(int line, int j) {
return (String) vector[line][j];
}
/**
* M�todo que obtiene el peso de una linea (line) dada en la posicion j
*/
public Double getPeso(int line, int j) {
return (Double) vector[line][j];
}
/**
* M�todo que obtiene el grado de certeza de una linea (line) dada en la posici�n j
*/
public Double getGrado(int line, int j) {
return (Double) vector[line][j];
}
public Double getConstante(int line, int j) {
return (Double) tak_sug[line][j];
}
/**
*
* @param line numero de linea de
* @return si la linea indicada esta activa
*/
public boolean isActive2(int line) {
return ((Boolean)vector[line][1]).booleanValue();
}
/**
* M�todo para obtener el n�mero de l�neas de la estructura
*/
public int getLength() {
return longitud;
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
// M�TO_DOS PRIVADOS DE LA CLASE
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
private void getMfUsed(Relation left, Relation right, int nrule) {
//System.out.println(left.toString()+" ");
int min=0,max=0;
if ((left.getKind() == Relation.IS || left.getKind() == Relation.GREATER ||
left.getKind() == Relation.GR_EQ || left.getKind() == Relation.SMALLER ||
left.getKind() == Relation.SM_EQ || left.getKind()==Relation.ISNOT) && (right == null || right.getKind() == Relation.IS ||
right.getKind() == Relation.GREATER || right.getKind() == Relation.GR_EQ ||
right.getKind() == Relation.SMALLER || right.getKind() == Relation.SM_EQ
|| right.getKind()==Relation.ISNOT)) {
// ********** Trata la parte izquierda ***********
int pos_v = 0, pos_mf = 0;
Variable v = left.getVariable();
LinguisticLabel mf = null;
try {
mf = left.getMembershipFunction();
} catch(Exception ex) {
new XfsgError(7, ex.getMessage());
}
// averigua de qu� variable se trata
boolean enc = false;
for (int kk = 0; kk < var_in.length && !enc; kk++) {
if (var_in[kk].equals(v.getName())) {
pos_v = kk;
enc = true;
}
}
// averigua de qu� mf se trata
enc = false;
LinguisticLabel tmp;
for (int kk = 0;
kk < inOrderMfInput[pos_v].getInOrderMemFunc().size()&& !enc; kk++) {
tmp =inOrderMfInput[pos_v].getInOrderMemFunc().get(kk);
if (mf != null && tmp.equals(mf.getLabel())) {
pos_mf = kk;
enc = true;
}
}
// guarda la informaci�n en mfUsed
min = calculamin_max(pos_mf,v,"min", left.getKind());
max = calculamin_max(pos_mf,v,"max", left.getKind());
actuliza_min_max(min,max,pos_v,left.getKind());
//mfUsed[pos_v][0] = calculamin_max(pos_mf,v,"min", left.getKind());
//mfUsed[pos_v][1] = calculamin_max(pos_mf,v,"max", left.getKind());
// ****** Trata la parte derecha, si es distinta de null *****
if (right != null) {
pos_v = 0;
pos_mf = 0;
v = right.getVariable();
try {
mf = right.getMembershipFunction();
} catch(Exception ex) {
new XfsgError(7, ex.getMessage());
}
// averigua de qu� variable se trata
enc = false;
for (int kk = 0; kk < var_in.length && !enc; kk++) {
if (var_in[kk].equals(v.getName())) {
pos_v = kk;
enc = true;
}
}
// averigua de qu� mf se trata
enc = false;
for (int kk = 0;
kk < inOrderMfInput[pos_v].getInOrderMemFunc().size()&& !enc; kk++) {
tmp =inOrderMfInput[pos_v].getInOrderMemFunc().get(kk);
if (mf != null && tmp.equals(mf.getLabel())) {
pos_mf = kk;
enc = true;
}
}
// guarda la informaci�n en mfUsed
min = calculamin_max(pos_mf,v,"min", right.getKind());
max = calculamin_max(pos_mf,v,"max", right.getKind());
actuliza_min_max(min,max,pos_v,right.getKind());
//mfUsed[pos_v][0] = calculamin_max(pos_mf,v,"min", right.getKind());
//mfUsed[pos_v][1] = calculamin_max(pos_mf,v,"max", right.getKind());
}
} else if (
(left.getKind() == Relation.AND) && (right.getKind() == Relation.IS ||
right.getKind() == Relation.GREATER || right.getKind() == Relation.GR_EQ ||
right.getKind() == Relation.SMALLER || right.getKind() == Relation.SM_EQ
|| right.getKind()==Relation.ISNOT)) {
// ***** Trata la parte derecha que es de tipo IS, GREATER, GR_EQ, SMALLER, SM_EQ � ISNOT *****
int pos_v = 0, pos_mf = 0;
Variable v = right.getVariable();
LinguisticLabel mf = null;
try {
mf = right.getMembershipFunction();
} catch(Exception ex) {
new XfsgError(7, ex.getMessage());
}
// averigua de qu� variable se trata
boolean enc = false;
for (int kk = 0; kk < var_in.length && !enc; kk++) {
if (var_in[kk].equals(v.getName())) {
pos_v = kk;
enc = true;
}
}
// averigua de qu� mf se trata
enc = false;
LinguisticLabel tmp;
for (int kk = 0;
kk < inOrderMfInput[pos_v].getInOrderMemFunc().size()&& !enc; kk++) {
tmp = inOrderMfInput[pos_v].getInOrderMemFunc().get(kk);
if (mf != null && tmp.equals(mf.getLabel())) {
pos_mf = kk;
enc = true;
}
}
// guarda la informaci�n en mfUsed
min = calculamin_max(pos_mf,v,"min", right.getKind());
max = calculamin_max(pos_mf,v,"max", right.getKind());
actuliza_min_max(min,max,pos_v,right.getKind());
//mfUsed[pos_v][0] = calculamin_max(pos_mf,v,"min", right.getKind());
//mfUsed[pos_v][1] = calculamin_max(pos_mf,v,"max", right.getKind());
// ******* Llama recursivamente a esta funci�n con ****
// ******* la parte izquierda ****
// ******* es de tipo AND. ****************************
Relation newLeft = left.getLeftRelation();
Relation newRight = left.getRightRelation();
getMfUsed(newLeft, newRight, nrule);
} else {
// Informa de que la regla nrule no es del tipo
// A & B & C ... ==> Z
new XfsgError(4, "Left: " + left.toXfl()+" Right: "+right.toXfl());
return;
}
}
private double calculateWeight2(LinguisticLabel p, String defuzzy, double gamma) {
double universeRange = 0, peso = 0;
universeRange = p.max()-p.min();
try {
if(defuzzy.equals("WeightedFuzzyMean")){
peso = p.basis() / universeRange;
}
else if(defuzzy.equals("GammaQuality")){
double w = Math.pow(p.basis(), gamma);
peso=w/universeRange;
}
else if(defuzzy.equals("Quality")){
peso=(1/ p.basis()) / universeRange;
}
} catch (Exception e) {
new XfsgError(5, defuzzy);
//err.show();
return 0;
}
return peso;
}
private int calculamin_max(int valor, Variable var, String s, int tipo){
int res=0;
int nmf=var.getType().getAllMembershipFunctions().length;
if(tipo==Relation.IS){
if(s.equals("min")){
res=valor;
}else if(s.equals("max")){
res=valor;
}
}else if(tipo==Relation.GREATER){
if(s.equals("min")){
res=valor+1;
}else if(s.equals("max")){
res=nmf-1;
}
}else if(tipo==Relation.GR_EQ){
if(s.equals("min")){
res=valor;
}else if(s.equals("max")){
res=nmf-1;
}
}else if(tipo==Relation.SMALLER){
if(s.equals("min")){
res=0;
}else if(s.equals("max")){
res=valor-1;
}
}else if(tipo==Relation.SM_EQ){
if(s.equals("min")){
res=0;
}else if(s.equals("max")){
res=valor;
}
}else if(tipo==Relation.ISNOT){
if(s.equals("min")){
res=-2;
}else if(s.equals("max")){
res=valor;
}
}
//System.out.println(s+res);
return res;
}
private void actuliza_min_max(int min, int max, int pos_v, int tipo){
if(mfUsed[pos_v][0]==-1 && mfUsed[pos_v][1]==-1){
mfUsed[pos_v][0]=min;
mfUsed[pos_v][1]=max;
}
else if(mfUsed[pos_v][0]!=-1 && mfUsed[pos_v][1]!=-1){
if(tipo==Relation.GR_EQ | tipo==Relation.GREATER)
mfUsed[pos_v][0]=min;
else if(tipo==Relation.SM_EQ | tipo==Relation.SMALLER)
mfUsed[pos_v][1]=max;
}
}
} // Fin de la clase