Guía de Usuario de XFL

FUZZY LOGIC DESIGN TOOLS

Guía de Usuario de XFL


English

Introducción a XFL

XFL es un lenguaje para la definición de sistemas basados en lógica difusa que facilita la descripción, verificación y síntesis de especificaciones difusas. Constituye la base para las herramientas de desarrollo de sistemas difusos integrados en Xfuzzy.

La definición de un sistema difuso mediante XFL consiste de dos partes básicas: declaraciones de tipos y especificación de los módulos que conforman el sistema. La primera parte contiene la definición de las variables del sistema, incluyendo sus universos de discurso y las funciones de pertenencia correspondientes a cada uno de los conjuntos difusos definidos para dichas variables. La segunda define la estructura y el contenido de la base de reglas que controla el comportamiento del sistema. Es posible incluir comentarios en cualquier lugar de un fichero fuente XFL: todo el texto de una línea que siga a los caracteres // es considerado un comentario.

El modelo asociado a una especificación escrita en XFL consta de tres fases:

XFL soporta un conjunto de clases de funciones de pertenencia predefinidas que incluye a la mayoría de las funciones descritas en la literatura. También proporciona un método para definir cualquier función no contemplada en las clases predefinidas. Dicho método está basado en la definición de una lista de puntos y los valores de la función de pertenencia en esos puntos, realizándose una aproximación lineal de la función entre dos puntos consecutivos de la lista.

XFL no impone ninguna restricción en la complejidad de la base de reglas que controla el comportamiento del sistema difuso. Esto es cierto tanto para la estructura de cualquier regla individual como para las relaciones entre bases de reglas diferentes dentro del sistema.

Una regla individual es una combinación arbitraria, mediante conectivas and, or y not, de predicados que incluyen las funciones de pertenencia de los antecedentes. Los predicados pueden ser agrupados mediante paréntesis y se aplican las reglas tradicionales de precedencia, asociatividad y distributividad, de forma que se garantiza una interpretación "natural" de las reglas.

XFL soporta dos modos diferentes para calcular las funciones de pertenencia de salida:

En ambos casos, la función de pertenencia de cada una de las variables de salida se obtiene componiendo los valores de salida de la función de implicación mediante la conectiva also.

Cuando se define una estructura compuesta para la base de reglas del sistema, XFL admite dos modos de composición de las bases de reglas:

Ambos modos de composición pueden ser combinados arbitrariamente, como en el caso de reglas individuales, para definir la estructura de la base de reglas del sistema. De esta forma, por ejemplo, una base de reglas compuesta en serie con otras dos compuestas en paralelo corresponde a un modelo en el que la base de reglas primaria controla la activación de reglas en las bases de reglas secundarias que proporcionan las salidas del sistema:

Aunque una especificación XFL es inherentemente independiente del método de defuzzificación empleado, las utilidades de configuración de las herramientas basadas en el lenguaje proporcionan construcciones especialmente ajustadas a los dos paradigmas que soportan la estructura básica de los métodos de defuzzificación descritos en la literatura:

XFL soporta un mecanismo para la inclusión de ficheros fuente, de forma que cualquier línea que contenga la construcción:

#use "FileName"

implica que el fichero referenciado por FileName será incluido en la posición del fichero original donde aparezca la construcción #use. Dicha construcción puede ser combinada arbitrariamente en un fichero XFL.

Estructura de una Especificación XFL

Definición de tipos

La característica más relevante del modo en que se define en XFL los universos de discurso y las funciones de pertenencia (lo que se denomina definición de tipos) es el soporte de mecanismos de herencia. Estos mecanismos permiten simplificar la especificación de sistemas complejos y facilitar la reutilización de módulos.

Una definición de tipos en XFL tiene el siguiente formato:

type Identifier : BaseType {
MembershipFunction
MembershipFunction
...
}

donde BaseType contiene una referencia al tipo (o tipos) de los que se deriva el tipo definido. Esta referencia puede corresponder a un tipo predefinido o a cualquier tipo cuya definición haya sido hecha previamente en la especificación.

XFL proporciona dos tipos predefinidos: integer y real. Cuando una definición de tipos utiliza uno de los tipos predefinidos BaseType toma la forma:

PredefinedType [ Cardinality ] ( Range )

donde Range indica los valores que definen el universo de discurso de las variables de este tipo. Se especifica mediante dos valores numéricos con el carácter < como separador. Cardinality es un parámetro opcional que puede ser usado para indicar el número de valores distintos considerados en el universo de discurso de una variable de este tipo. Para tipos integer su valor por defecto coincide con el número de enteros en el rango definido, mientras que para tipos real se asume un valor por defecto (256) cuando no se ha especificado explícitamente. la cardinalidad es utilizada en aplicaciones como la síntesis de hardware digital (donde define el número de bits que utilizarán las variables) y en la implementación de algunos métodos de defuzzificación cuando se calcula el tamaño del paso con que se recorrerá el universo de discurso.

Cuando el tipo que está siendo definido es un tipo derivado BaseType puede contener una lista (separada por comas) de identificadores de tipos previamente definidos, con la única restricción de que todos ellos deben derivar finalmente del mismo tipo predefinido. El rango del tipo derivado se obtiene a partir de la intersección de los rangos de sus antecesores y su cardinalidad coincide con la más pequeña de todos ellos. Un tipo derivado hereda automáticamente todas las funciones de pertenencia definidas para sus antecesores. Cuando una función aparece en más de uno de los tipos padre se sigue la siguiente regla de precedencia: se utiliza la definición correspondiente al último tipo de la lista de antecesores.

Funciones de Pertenencia

La definición de una función de pertenencia nueva (o la sobrecarga de una previamente definida para un tipo derivado) corresponde a una construcción de la forma:

Identifier FunctionClass ( PointList )

donde PointList contiene los valores de los puntos significativos en la definición de la función de acuerdo a la clase especificada por FunctionClass. Estos valores no tienen otras restricciones que las requeridas por la coherencia de clases y el hecho de que la función debe tomar como mínimo un valor distinto de cero dentro de su universo de discurso. Las clases de funciones de pertenencia soportadas son:

triangle

PointList corresponde a los tres puntos que definen el triángulo (basis, apex, basis). La función toma el valor cero en los puntos basis, y el valor 1 en apex.

rectangle

PointList corresponde a un par de valores que definen un intervalo en el que la función toma el valor 1, mientras que fuera de este intervalo el valor es cero.

trapezoid PointList corresponde a los cuatro valores que define un trapecio (major basis, minor basis, minor basis, major basis). La función toma el valor 1 entre los puntos minor basis, y el valor cero en los puntos major basis.

bell

PointList define dos valores, a y b. El valor de la función en el punto x viene dado por exp(-((x-a)/b)**2)

sigma

PointList define dos valores, a y b. El valor de la función en el punto x viene dado por 1/(1+exp(x-a)/b)

delta

Toma el valor cero en todo el universo de discurso salvo en un punto (identificado por PointList) donde toma el valor 1

points Define una aproximación lineal a una función arbitraria. PointList toma un formato especial en el que cada elemento de la lista es un par de valores numéricos separados por el carácter :. El primer número corresponde a un punto del universo de discurso y el segundo al valor de la función de pertenencia en dicho punto. Entre cada par de puntos sucesivos la función viene definida por la línea que une ambos puntos.

A modo de ejemplo, a continuación se muestra la definición de algunos tipos y las gráficas correspondientes a las funciones de pertenencia:

type X : integer (0<100){
LE trapezoid (-25,0,10,35)
LC triangle (30,40,50)
CE triangle (45,50,55)
RC triangle (50,60,70)
RI trapezoid (65,90,100,125) }

type TrAng : integer (-90<270) {
RB triangle (-100,-45,10)
RU triangle (-10,30,60)
RV triangle (50,70,90)
VE triangle (80,90,100)
LV triangle (90,110,130)
LU triangle (120,150,190)
LB triangle (170,225,280) }

type Wheels : integer (-30<30) {
NB triangle (-43,-30,-17)
NM triangle (-25,-15,-6)
NS triangle (-12,-6,0)
ZE triangle (-6,0,6)
PS triangle (0,6,12)
PM triangle (6,15,25)
PB triangle (17,30,43) }

Definición de Bases de Reglas

El elemento básico en la definición de la base de reglas que controla el comportamiento de un sistema difuso en XFL se denomina módulo. Cada módulo posee un conjunto de variables (entrada y salida) y una especificación de su estructura. En términos generales una definición de módulo tiene el siguiente formato:

Identifier ( VariableList )
ModuleStructure

donde identifier permite hacer referencias posteriores a este módulo desde algún otro módulo (compuesto). XFL requiere que las especificaciones definan un módulo denominado system, que describe el comportamiento global del sistema y cuyas variables de entrada/salida son las del sistema difuso completo. Cada una de las variables de este módulo deben ser definidas en VariableList mediante construcciones:

TypeIdentifier ? Identifier

para las entradas, y:

TypeIdentifier ! Identifier

para las salidas.

El identifier será usado en cualquier referencia a la variable dentro del módulo, mientras que TypeIdentifier define el tipo de la variable.

Como se mencionó anteriormente, XFL permite la definición de bases de reglas de estructura arbitrariamente compleja. Esta característica es soportada mediante la especificación de estructuras de módulos. Existen dos formas diferentes de hacer esta especificación: definir un conjunto de reglas, o definir un módulo en términos de un conjunto de módulos definidos previamente. Cuando se define la estructura de un módulo mediante un conjunto de reglas ModuleStructure es:

rulebase {
Rule
Rule
...
}

Mientras que para definir la estructura de un módulo mediante la interconexión de varios componentes ModuleStructure toma el formato:

components { ModuleReferences }

Estructura de las Reglas

Cada regla individual tiene la siguiente estructura:

if Antecedent -> Consequent

El antecedente de una regla es una combinación arbitraria de expresiones que asocian cualquiera de las variables de entrada con cualquiera de las funciones de pertenencia definidas para su tipo. Cada una de estas expresiones es de la forma:

VariableIdentifier is MembershipFunctionIdentifier

Los operadores que combinan las expresiones en el antecedente de la regla son identificados por:

Se mantienen las reglas usuales de asociatividad, distributividad y precedencia. Como es habitual, las expresiones pueden ser agrupadas mediante paréntesis.

El consecuente de una regla consiste en una lista (separada por comas) de expresiones que asocian cualquiera de las variables de salida con cualquiera de las funciones de pertenencia definidas para su tipo.

Como ejemplo consideremos la siguiente tabla que define el comportamiento de un sistema con dos entradas y una salida utilizando las funciones de pertenencia que aparecían en el ejemplo anterior:

La definición de su comportamiento en XFL se realiza mediante un módulo system con la siguiente estructura:

system (X ? vx, TrAng ? ta, Wheels ! wa)
rulebase {
...
}

Las celdas de la esquina superior derecha de la tabla corresponden a la siguiente regla:

if ((vx is RC | vx is RI) &
(ta is RB | ta is RU)) |
(vx is RI & ta is RV) -> wa is PB

y las de la esquina inferior izquierda corresponden a:

if (vx is LE & ta is LV) |
((vx is LE | vx is LC) & (ta is LU | ta is LB)) -> wa is NB

Composición de Módulos

Cuando la estructura de un módulo se define mediante la composición de otros módulos, dicha definición consiste en la combinación arbitraria de referencias a los módulos componentes por medio de los operadores de composición:

Para referenciar un módulo se incluye su identificador y se instancian sus variables de entrada salida a las variables de entrada salida del módulo padre, o a variables dummy de interconexión en el caso de composición serie.

Para la semántica de composición de módulos se aplican las reglas siguientes:

A modo de ejemplo, a continuación se inclute la estructura en términos de composición de módulos para la base de reglas jerárquica mostrada previamente:

Primary (tI1 ? pi1, tI2 ? pi2, tI3 ? pi3, tD0 ! po)
rulebase {
...
}
Secondary1 (tD0 ? s1d, tI1 ? si1, tI2 ? si2, tO1 ? so1)
rulebase {
...
}

Secondary2 (tD0 ? s2d, tI2 ? si2, tI3 ? si3, tO2 ? so2)
rulebase {
...
}

system (tI1 ? I1, ti2 ? I2, tI3 ? I3,
tO1 ! O1, tO2 ! O2)
components {
Primary (I1, I2, I3, D0) ;
(Secondary1 (D0, I1, I2, O1) []
Secondary2 (D0, I2, I3, O2))
}

Definición de Operaciones difusas

Aunque la definición de operaciones difusas se encuentra fuera del campo de acción de XFL, el mecanismo utilizado juega un papel fundamental en el uso del lenguaje por las diferentes herramientas de desarrollo de sistemas difusos. Esencialmente, cualquier herramienta capaz de trasladar una especificación XFL en un formato de implementación apropiado debe usar un método de configuración para definir (en términos del lenguaje objetivo) las operaciones difusas que pueden ser utilizadas. Una herramienta basada en XFL debe soportar mecanismos para identificar estas operaciones de forma que pueda producir una implementación completa de la especificación fuente. Esta sección introduce los mecanismos que se utilizan en las herramientas disponibles actualmente. En general dichos mecanismos son suficientemente flexibles como para ser extendidos a cualquier lenguaje objetivo.

En la generación actual de herramientas basadas en XFL las operaciones difusas que van a ser utilizadas en una implementación son seleccionadas mediante una serie de directivas incluidas en el fichero fuente. Dichas directivas identifican una de las definiciones de operación del fichero de configuración de la herramienta:

Cada una de estas directivas usa un identificador que corresponde a la palabra clave para la definición de la operación en el fichero de configuración de la herramienta. Las herramientas basadas en XFL deben proporcionar un conjunto de valores por defecto para cada operación.

Como se mencionó anteriormente, el caso de la directiva #composition es ligeramente diferente: si no existe esa directiva en el fichero fuente no se llevará a cabo ningún mecanismo de preagregación de reglas.

Fichero de Configuración

El fichero de configuración contiene un conjunto de secciones, cada una de las cuales corresponde a una clase de los elementos definidos y viene delimitada por símbolos que marcan el principio y el final de la sección. Como en XFL, los comentarios van precedidos del símbolo //. Los símbolos de comienzo son:

Dentro de cada sección, la definición de operaciones tiene dos partes: el identificador de la operación (que comienza en una línea separada); y el cuerpo de la definición, incluido detrás de su identificador en líneas sucesivas que deben comenzar con el carácter tabulador (tab). Cualquier cuerpo de definición (tanto para una operación simple como para un método de defuzzificación) puede incluir líneas del lenguaje objetivo usando las siguientes construcciones:

Operaciones

El cuerpo de una definición de operación (salvo en el caso de los métodos de defuzzificación, que utilizan un formato especial) debe contener las construcciones nativas del lenguaje objetivo (función, procedimiento, macro, etc.) que devuelven el resultado de la operación.

Para operaciones binarias, el primer operando es identificado por _a y el segundo por _b. Para operaciones unarias (negaciones) el único operador utilizado es identificado por _a.

Como ejemplo, a continuación aparece un listado parcial del fichero de configuración incluido en la distribución de Xfuzzy:

%Tnorm
prod ((_a)*(_b))
min ((_a)>(_b)?(_b):(_a))
. . .
%%
%Tconorm
max ((_a)>(_b)?(_a):(_b))
. . .
disjoint_sum (delta(_a,_b))
%proc
FUZZY delta (a, b) FUZZY a,b; {
FUZZY x, y;
x = a > (1-b) ? 1-b : a;
y = b > (1-a) ? 1-a : b;
return x > y ? x : y;
}
%end
%%
%Implication
min ((_a)>(_b)?(_b):(_a))
prod ((_a)*(_b))
Diene ((1-(_a))>(_b)?1-(_a):(_b))
. . .
%%

Note el uso de la construcción %proc para implementar cálculos un poco más complejos para una operación dentro de la sección %Tconorm.

Métodos de Defuzzificación

La definición de métodos de defuzzificación es más compleja que la de otras operaciones: las líneas del cuerpo de la definición van precedidas por símbolos que indican los requerimientos impuestos sobre las funciones de pertenencia para que el método sea aplicable, así como el punto del proceso de defuzzificación en que se utilizan dichas líneas. Estos símbolos son:

Cuando se define un método de defuzzificación el valor final de salida es identificado por _out y los valores intermedios pueden ser accedidos mediante un array predefinido (de dimensión indefinida) identificado por _in. Los valores de las variables de entrada se almacenan en el array _input, mientras que el número de entradas y el de salidas del sistema son identificados por _NIN y _NOUT, respectivamente.

Dentro de una %numloop el punto actual corresponde a _x y el valor de la función de pertenencia a _mx.

Dentro de una %linloop el grado de activación corresponde a _a y los parámetros de la función de pertenencia a _p1, _p2... (si uno de los _pN no está definido el valor asumido es 0). _mft contiene la clase de la función de pertenencia. Los valores posibles de _mft corresponden a las constantes _POINTS, _DELTA, _BELL, _SIGMA, _TRIANGLE, _TRAPEZOID y _RECTANGLE.

A continuación se muestran dos ejemplos de definición de métodos de defuzzificación que utilizan los dos tipos de bucles descritos anteriormente.

%Defuzzification
// Numerical methods (Loop through the universe of discourse)
CenterOfArea
%init
_in[0]=0.0;
_in[1]=0.0;
%end
%numloop
_in[0]+=_mx*_x;
_in[1]+=_mx;
%end
%exit
_out=_in[0]/_in[1];
%end

. . .

// Linguistic methods (loop through the linguistic labels)
FuzzyMean
%requires delta bell triangle
%init
_in[0]=0.0;
_in[1]=0.0;
%end
%linloop
_in[0]+=_a;
if (_mft==_TRIANGLE) _in[1]+=_a*_p2;
else _in[1]+=_a*_p1;
%end
%exit
_out=_in[1]/_in[0];
%end

. . .
%%

[Xfuzzy Home Page]

xfuzzy-team@imse.cnm.es

©IMSE-CNM 1997-2001
Last update: Thu Oct 18 17:55:53 2001