XFL3: El lenguaje de especificación de Xfuzzy 3

Definición de funciones de pertenencia

Las funciones de pertenencia son asignadas a las etiquetas lingüísticas que forman un tipo de variable lingüística. La estructura de una definición de función de pertenencia en un paquete de funciones es como sigue:

		mf identifier { blocks }                    

Los bloques que pueden aparecer en la definición de una función de pertenencia son: alias, parameter, requires, java, ansi_c, cplusplus, derivative, update y source.

El bloque alias se utiliza para definir nombres alternativos para identificar a la función. Cualquiera de esos identificadores puede ser usado para hacer referencia a la función. La sintaxis del bloque alias es:

		alias identifier, identifier, ... ;                   

El bloque parameter permite la definición de los parámetros de los que depende la función. El último identificador puede ir seguido de corchetes para definir una lista de parámetros. Su formato es:

		parameter identifier, identifier, ..., identifier[] ;                   

El bloque requires expresa las restricciones sobre los valores de los parámetros por medio de una expresión Booleana en Java que valida los valores de los parámetros. Esta expresión puede usar también los valores de las variables 'min' y 'max', que representan los valores mínimo y máximo del universo de discurso de la variable lingüística considerada. La estructura de este bloque es:

		requires { expression }                    

Los bloques java, ansi_c y cplusplus describen el comportamiento de la función por medio de su descripción como el cuerpo de una función en los lenguajes de programación Java, C y C++, respectivamente. El formato de estos bloques es el siguiente:

		java { Java_function_body } 
		ansi_c { C_function_body } 
		cplusplus { C++_function_body } 

La definición de una función de pertenencia incluye no sólo la descripción del comportamiento de la función en sí misma, sino también del comportamiento de la función bajo la acción de los modificadores greater-or-equal y smaller-or-equal, así como el cálculo de los valores del centro y la base de la función de pertenencia. Como consecuencia, los bloques java, ansi_c y cplusplus se dividen en los siguientes subbloques:

		equal { code }
		greatereq { code }
		smallereq { code }
		center { code }
		basis { code }   

El subbloque equal describe el comportamiento de la función. Los subbloques greatereq y smallereq describen la acción de los modificadores greater-or-equal y smaller-or-equal respectivamente. La variable de entrada en estos subbloques se denomina 'x'. El código puede usar los valores de los parámetros de la función, así como las variables 'min' y 'max', que representan los valores mínimo y máximo del universo de discurso de la función. Los subbloques greatereq y smallereq pueden ser omitidos. En ese caso las transformaciones correspondientes son calculadas recorriendo todos los valores del universo de discurso. Sin embargo, resulta mucho más eficiente usar la función analítica, por lo que la definición de estos subbloques está fuertemente recomendada.

Los subbloques center y basis describen el centro y la base de la función de pertenencia. El código de estos subbloques puede usar los valores de los parámetros de la función y las variables 'min' y 'max'. Esta información es usada por varios métodos de defuzzificación simplificados. Estos subbloques son opcionales y su función por defecto devuelve un valor nulo.

El bloque derivative describe la derivada de la función con respecto a cada parámetro. Este bloque es también dividido en los subbloques equal, greatereq, smallereq, center y basis. El código de estos subbloques consiste en expresiones Java que asignan valores a la variable 'deriv[]'. El valor de 'deriv[i]' representa la derivada de la función con respecto al i-ésimo parámetro de la función de pertenencia. La descripción de la derivada de la función permite calcular la derivada de la función de error del sistema utilizada por los algoritmos de aprendizaje basados en gradiente descendente. El formato es:

		derivative { subblocks }                       

El bloque update se utiliza para calcular unos valores válidos para el conjunto de parámetros (almacenados en la variable pos[]) a partir de los desplazamientos deseados (almacenados en la variable disp[]) generados en un proceso de ajuste automático, teniendo en cuenta la selección de parámetros a ajustar (almacenados en la variable booleana adj[]). Un tipo de restricción muy común para el desplazamiento consiste en mantener el orden de los parámetros. Este proceso puede garantizarse utilizando la función sortedUpdate(pos,disp,adj). El código Java puede utilizar las variables 'min', 'max' y 'step', que representan el mínimo, el máximo y la división del universo de discurso, respectivamente. La sintaxis del bloque update es:

		update { Java_function_body }                      

El bloque source es utilizado para definir código Java que es directamente incluido en el código de la clase generada para la definición de la función. Este código nos permite definir métodos locales que pueden ser empleados dentro de otros bloques. La estructura es:

		source { Java_code }                      

El siguiente ejemplo muestra la definición de una función de pertenencia en forma de triángulo.

 mf triangle {
   parameter a, b, c;
   requires { a<b && b<c && b>=min && b<=max }
   java {
    equal { return (a<x && x<=b? (x-a)/(b-a) : (b<x && x<c? (c-x)/(c-b) : 0)); }
    greatereq { return (x<a? 0 : (x>b? 1 : (x-a)/(b-a) )); }
    smallereq { return (x<b? 1 : (x>c? 0 : (c-x)/(c-b) )); }
    center { return b; }
    basis { return (c-a); }
   }
   ansi_c {
    equal { return (a<x && x<=b? (x-a)/(b-a) : (b<x && x<c? (c-x)/(c-b) : 0)); }
    greatereq { return (x<a? 0 : (x>b? 1 : (x-a)/(b-a) )); }
    smallereq { return (x<b? 1 : (x>c? 0 : (c-x)/(c-b) )); }
    center { return b; }
    basis { return (c-a); }
   }
   cplusplus {
    equal { return (a<x && x<=b? (x-a)/(b-a) : (b<x && x<c? (c-x)/(c-b) : 0)); }
    greatereq { return (x<a? 0 : (x>b? 1 : (x-a)/(b-a) )); }
    smallereq { return (x<b? 1 : (x>c? 0 : (c-x)/(c-b) )); }
    center { return b; }
    basis { return (c-a); }
   }
   derivative {
    equal {
     deriv[0] = (a<x && x<b ? (x-b)/((b-a)*(b-a)) : (x==a? 0.5/(a-b) : 0));
     deriv[1] = (a<x && x<b ? (a-x)/((b-a)*(b-a)) :
                (b<x && x<c ? (c-x)/((c-b)*(c-b)) :
                (x==b? 0.5/(a-b) + 0.5/(c-b) : 0)));
     deriv[2] = (b<x && x<c ? (x-b)/((c-b)*(c-b)) : (x==c? 0.5/(c-b) : 0));
    }
    greatereq {
     deriv[0] = (a<x && x<b ? (x-b)/((b-a)*(b-a)) : (x==a? 0.5/(a-b) : 0));
     deriv[1] = (a<x && x<b ? (a-x)/((b-a)*(b-a)) : (x==b? 0.5/(a-b) : 0));
     deriv[2] = 0;
    }
    smallereq {
     deriv[0] = 0;
     deriv[1] = (b<x && x<c ? (c-x)/((c-b)*(c-b)) : (x==b? 0.5/(c-b) : 0));
     deriv[2] = (b<x && x<c ? (x-b)/((c-b)*(c-b)) : (x==c? 0.5/(c-b) : 0));
    }
    center {
     deriv[0] = 1;
     deriv[1] = 1;
     deriv[2] = 1;
    }
    basis {
     deriv[0] = -1;
     deriv[1] = 0;
     deriv[2] = 1;
    }
   }
   update {
    pos = sortedUpdate(pos,desp,adj);
    if(pos[1]<min) pos[1]=min;
    if(pos[2]<=pos[1]) pos[2] = pos[1]+step;
    if(pos[1]>max) pos[1]=max;
    if(pos[0]>=pos[1]) pos[0] = pos[1]-step;
   }
  }

Para comentarios, sugerencias, notificación de bugs, etc. contacte con nosotros en:   xfuzzy-team@imse-cnm.csic.es

©IMSE-CNM 2018