====== Lógica difusa ====== ===== Lógica difusa (Fuzzy logic) en general ===== La lógica difusa aparece debido a las limitaciones de la lógica convencional la cual sólo conseguimos dos soluciones extremas //true// o //false//. La lógica difusa se utiliza para encontrar más niveles entre estos dos extremos imitando así el //modus operandi// del ser humano realizando una toma de decisiones realista y proporcional al problema que se le plantee. \\ La implementación de la lógica difusa en un juego consta de tres pasos: - **Fuzzification** (Ofuscación), que consiste en la conversión de un problema a un formato que pueda ser tratado mediante lógica difusa (conjuntos difusos). - Aplicación de **reglas difusas**, es la combinación de los datos anteriores para elegir qué opción es la adecuada para resolver el problema. - **Defuzzification** (Desofuscación); una vez tenemos seleccionada la acción a realizar, mediante la defuzzification se elige en qué medida es realizada. ==== Conjuntos difusos (Fuzzy Sets) ==== En algunos juegos sus elementos pueden adquirir cualidades, como por ejemplo inteligencia, daño, fuerza, hambre... Estas cualidades (o características) se consiguen en un grado de intensidad, un personaje puede estar poco o muy dañado; en lógica difusa lo que decimos es que existe un //conjunto// de elementos por cada una de estas características compuesto por esos elementos que las pueden adquirir, ese es el concepto de conjuntos difusos. \\ Cada conjunto difuso representa una de característica y un componente del conjunto lo es en cierto grado según cuanto tenga de esa característica, dicho grado se representa como un valor dentro de un rango, por ejemplo, en un rango de daño entre 0 y 1 un personaje que está dañado en 0,8 lo está más que aquel que está en 0,3. A este valor se le llama grado de membresía al conjunto (en este caso al conjunto daño). \\ Un elemento puede estar en varios conjuntos difusos a la vez (un personaje puede estar herido y hambriento) y, al contrario que en la lógica natural, un personaje puede estar en conjuntos opuestos, eso sí, en distinto grado en cada uno. Por ejemplo, nosotros no diremos que un personaje está dañado y sano a la vez, pero en términos de lógica difusa sí que podemos decir que un personaje tiene un grado de membresía al conjunto salud de 0,7 y al de daño de 0,3. ==== Fuzzification ==== Consiste en convertir datos correspondientes a los elementos que queremos tratar (generalmente números reales) en grados de membresía a los conjuntos difusos a los cuales han de pertenecer. Por ejemplo, coger el peso de una person en kilos y encontrar el grado en el que la persona tiene sobrepeso, peso ideal o delgadez. \\ Podemos representar el grado de membresía de un elemento a un conjunto mediante una función matemática y su gráfica correspondiente. Tomando por ejemplo la siguiente gráfico: {{ ai:g1.png |}} Esta gráfica podría representar perfectamente el grado de membresía de un individuo a un conjunto difuso que indique el sobrepeso, este grado estaría en el eje de coordenadas vertical (entre 0 y 1) y el peso global estaría en el eje horizontal. Imaginemos que X_0 es 175kg y X_1 es 195kg, esto significaría que si el peso de una persona no llega a 175kg no tiene sobrepeso, pero si lo pasa tiene un grado de sobrepeso, un grado que sería sobrepeso al 100% si pasa de 195kg. \\ Para encontrar el grado de membresía de un elemento al conjunto difuso del sobrepeso deberemos aplicar la siguiente fórmula, que nos dará el valor entre 0 y 1 de //y// para la //x// dada (el peso del individuo). {{ ai:f1.png |}} Dicha función, evidentemente, puede ser calculada mediante código: double FuzzyGrade (double value, double x0, double x1) { double result = 0; double x = value; if(x <= x0) result = 0; else if(x >= x1) result = 1; else result = (x/(x1-x0))-(x0/(x1-x0)); return result; } Podemos representar la membresía a los conjuntos difusos utilizando distintas gráficas: \\ {{ ai:funciones.png?400 |}} \\ Cada una de ella con sus funciones correspondientes: {{ ai:funciones-graficas.png?400 |}} Estas gráficas pueden ser combinadas para representar el grado de membresía a los conjuntos difusos respecto al peso a los que una persona puede pertenecer: \\ {{ ai:combinacion.png?400 |}} \\ Por ejemplo, en los juegos de rol la forma de la derecha de combinar las gráficas solapandolas se utiliza para definir la personalidad de un personaje, de un extremo a otro podemos indicar cuan bueno o malo es (en nomenclaturas de juego de rol sería algo así como: neutral, neutral bueno, bueno, extremadamente bueno, neutral malvado, malvado, y extremadamente malvado). \\ Hemos de tener en cuenta que para conseguir reacciones de personajes que no sean bruscas es aconsejable seguir estos consejos: - Solapar las funciones al rededor del 25% y no más. - Es conveniente que el solapamiento de un de un grupo difuso no se haga con más de dos grupos. ==== Hedges ==== Las funciones de los extremos (hedges) se utilizan para modificar el grado de membresía. La idea principal es ampliar, como nosotros lo hacemos lingüísticamente, el concepto que rodea un conjunto difuso. \\ Los extremos más característicos son el “muy” y el “poco”, con ellos podemos decir que una persona es “muy inteligente” o “poco inteligente” y se definen como: \\ grado(muy A) = grado(A)^2 \\ grado(poco A) = grado(A)^0.5 {{ ai:hedges.png?250 | }} ==== Variables difusas ==== Una variable difusa es el compuesto que forman los distintos conjuntos difusos que forman un concepto o dominio: \\ ''Velocidad = {lento, normal, rápido} \\ IQ = {cortito, normal, inteligente} '' ==== Operadores de lógica difusa ==== De la misma forma que en la lógica tradicional existen operadores (AND, OR, XOR, NOT) en lógica difusa también, sólo que no se tratan de igual forma. En lógica difusa tenemos la conjunción (AND), disjunción (OR) y la negación (NOT). \\ Partiendo de un ejemplo que muestre el coeficiente intelectual de una persona (IQ), podemos decir qué grado de inteligencia tiene, teniendo, por ejemplo, un individuo que es 0,75 inteligente (clever), 0,25 normal (average) y 0 cortito (dumb): {{ ai:fig1.png?300 |}} Definimos... * **Conjunción** \\ grado(A and B) = Minimo (grado(A), grado(B)) \\ {{ai:fig2.png?300|}} * **Disjunción** \\ grado(A or B) = Maximo (grado(A), grado(B)) \\ {{ai:fig3.png?300|}} * **Negación** \\ grado(not A) = 1 - grado(A) \\ {{ai:fig4.png?300|}} ==== Reglas difusas ==== Cuando en lógica convencional tenemos la siguiente regla: IF yo.Fuerte AND enemigo.Flojo THEN yo.atacar la acción a realizar es fácil de elegir, si el personaje que decide es fuerte y el enemigo es flojo él atacará, pero si no es fuerte no atacará. En cambio en lógica difusa, siendo la misma condición, existen grados de fortaleza, si yo.Fuerte = 0,3 y enemigo.Flojo = 0,6, la regla es cierta al 0,3, entonces ataca o no ataca? \\ El tomar una decisión puede hacerse de distintas formas, se puede poner un punto de corte, por ejemplo 0,5, y si la regla supera ese valor entonces se toma como cierta. En el caso de arriba 0,3 no supera al 0,5 por lo que no se atacaría. También se puede tomar una decisión aleatoria dando una probabilidad de que sea cierta del valor dado, es decir, en la condición anterior habría una probabilidad de 30% de atacar y un 70% de no atacar. \\ Otras veces pueden haber varias reglas que pueden llevar al personaje a atacar, por ejemplo: IF yo.Fuerte AND enemigo.Flojo THEN yo.atacar IF yo.Grande AND enemigo.Verde THEN yo.atacar IF yo.Poder > 10 AND yo.Salud > 5 THEN yo.atacar Como antes, tenemos varias opciones en el momento de tomar una decisión, por ejemplo elegiríamos atacar si dos de las condiciones dan al menos 0,5, o podríamos coger la media del resultado de las reglas y si esta supera este punto de corte atacar, o dar la probabilidad de atacar a dicha media y escoger una decisión aleatoria. Otra forma de decidir si seguir una decisión o no al utilizar varias reglas es utilizar una variable difusa adicional que nos indique la conveniencia de la decisión. Pongamos por ejemplo el de un soldado que ha de decidir si utilizar o no su arma en estos momentos para disparar al enemigo, el arma que lleva es un lanza-misiles, un arma que tarda un tiempo considerable en ser recargada y a la vez es fácil fallar si la distancia del enemigo es muy grande. Aquí tenemos tres factores a tener en cuenta correspondientes a tres variables difusas: - Cuanta munición tenemos disponible (//ammo status//): poca (low), cantidad correcta (ok) o bastante cantidad (loads). - Cuan lejos está el enemigo (//distance to target//): cerca (close), a media distancia (medium) o lejos (far). - Cuanto nos interesa disparar (//desirability//), la adicional: no es conveniente (undesirable), conviene (desirable) o es muy conveniente (very desirable). {{ ai:seleccion_arma.png?400 |}} Diseñamos las reglas para el arma que lleva el soldado. Como nuestro soldado tardará bastante en recargarla es conveniente que el enemigo esté lejos, pero tampoco ha de estarlo mucho porque si no será muy probable fallar el tiro; por lo que se ha decidido que utilizar el lanzamisiles es la acción más conveniente si el enemigo está a una distancia media y nuestra munición disponible es suficiente como para que después podamos volver a disparar. Regla 1 : IF Target_Far AND Ammo_Loads THEN Desirable Regla 2 : IF Target_Far AND Ammo_Okay THEN Undesirable Regla 3 : IF Target_Far AND Ammo_Low THEN Undesirable Regla 4 : IF Target_Medium AND Ammo_Loads THEN VeryDesirable Regla 5 : IF Target_Medium AND Ammo_Okay THEN VeryDesirable Regla 6 : IF Target_Medium AND Ammo_Low THEN Desirable Regla 7 : IF Target_Close AND Ammo_Loads THEN Undesirable Regla 8 : IF Target_Close AND Ammo_Okay THEN Undesirable Regla 9 : IF Target_Close AND Ammo_Low THEN Undesirable Pongámonos en el lugar del soldado y analicemos la situación. Digamos que el enemigo está a una distancia de 200 píxels y tenemos disponibles 8 misiles. * 200 píxels, respecto a la variable lógica correspondiente a la distancia del enemigo, es un grado de membresía de 0.33 de Target_Far, 0.00 de Target_Close y 0.67 de Target_Medium. * 8 misiles respecto al Ammo_Status, es 0.00 de Ammo_Loads, 0.78 de Ammo_Ok y 0.20 de Ammo_Low. Esto nos dá unos valores para las reglas anteriormente dadas: - 0.33 AND 0.00 -> MIN = 0.00 (desirable) - 0.33 AND 0.78 -> MIN = 0.33 (undesirable) - 0.33 AND 0.20 -> MIN = 0.20 (undesirable) - 0.67 AND 0.00 -> MIN = 0.00 (very desirable) - 0.67 AND 0.78 -> MIN = 0.67 (very desirable) - 0.67 AND 0.20 -> MIN = 0.20 (desirable) - 0.00 AND 0.00 -> MIN = 0.00 (undesirable) - 0.00 AND 0.78 -> MIN = 0.00 (undesirable) - 0.00 AND 0.20 -> MIN = 0.00 (undesirable) Con los cuales podemos montar la matriz difusa asociativa (//fuzzy associative matrix// (FAM)): \\ {{ ai:fam.jpg?250 |}} \\ Para decidir qué valor tomar en la variable difusa desirability lo que haremos será hacer un OR por cada uno de los valores agrupados por sus grupos correspondientes. Es decir, hacer los máximos: * Undesirable -> MAX (0.33, 0.20, 0.00, 0.00, 0.00) -> 0.33 * Desirable -> MAX (0.20) -> 0.20 * Very_Desirable = MAX (0.00, 0.67) -> 0.67 Lo que podemos representar gráficamente como: {{ ai:combinacion2.png?500 |}} \\ A partir de estos valores elegiremos la acción a realizar, esto se explica en el siguiente apartado. ==== Defuzzification ==== Consiste en convertir los valores conseguidos mediante las reglas difusas a un único valor, este será el que utilicemos para tomar una decisión. Existen distintas técnicas de defuzzification entre las cuales encontramos: === Mean of Maximum === Se escogen los valores más altos y se hace una media entre ellos. En el caso del soldado corresponden a los de Very Desirable que es una función que en //y// va creciendo de 0 a 0.67, y en //x// va desde 50 a 100 siendo el 66 el valor donde se queda constante (esto lo encontramos substituyendo en la fórmula de la función), es decir el primero más alto y por lo tanto, el 100 es el segundo más alto. \\ MOM = {66 + 100}/2 = 83 \\ \\ {{ai:fig456_01.png|}} \\ Este método tiene el inconveniente que no tiene en cuenta los demás grupos difusos. === Average of Maxima === Consiste en dar a cada conjunto difuso un valor representativo y aplicar la siguiente fórmula: \\ sum{}{}{(valorRepresentativo x gradoMembresía)}/sum{}{}{gradoMembresía} \\ \\ Si por ejemplo, para el caso del soldado damos como valores representativos a Undesirable 12.5, a Desirable 50 y a Very Desirable 87.5 (son el punto medio de la porción de //x// donde se encuentra la //y// máxima del correspondiente grupo) el valor que nos daría sería: \\ \\ {12.5 x 0.33 + 50 x 0.2 + 87.5 x 0.67}/{0.33 + 0.2 + 0.67} = 60.6 \\ \\ El valor representativo lo elige el programador, y puede elegirse según qué uso se le quiera dar. Un ejemplo sería el de un personaje que ha de elegir si atacar a un monstruo, huir o pasar de él, tras aplicar las reglas difusas para los conjuntos difusos huir, seguir hacia delante, atacar llega a los grados 0.7, 0.4 y 0.3 respectivamente y los valores representativos serían -10 para huir, 1 pasar de él y seguir hacia delante y 10 atacar. Corresponden a las velocidades que el personaje puede correr, -10 es correr hacia atrás a máxima velocidad y 10 correr hacia delante a máxima velocidad. El resultado sería -2.5, es decir que huiría, corriendo a una velocidad de 2.5. \\ \\ {-10 x 0.7 + 1 x 0.4 + 10 x 0.3}/{0.7 + 0.4 + 0.3} = -2.5 \\ \\ Este es el método más recomendado de utilizar en la programación de juegos ya que dá un resultado más concreto que el Mean of Maximum. Existe otro llamado Centroid, su resultado es más exacto que este pero su cálculo es mucho más costoso. === Cómo interpretar el resultado? === El dilema que tenía nuestro personaje del apartado anterior sobre utilizar o no su lanzamisiles ya tiene una solución dependiendo del método de defuzzification (83 o 60.6). Como hemos indicado a partir de este valor podríamos decidir si utilizar o no el lanzamisiles aunque también puede tener otros usos, como por ejemplo si repetimos el proceso con cada arma de la que dispone el soldado este valor sería el que indicaría cual es el arma más conveniente a utilizar en el caso actual. ==== Método de Comb ==== A medida que agregamos variables el número de reglas que necesitaremos incrementa exponencialmente; para el ejemplo anterior del soldado necesitamos 9 reglas para 3 variables difusas (3 variables x 3 conjuntos), imaginemos que añadimos otra variable más, necesitaríamos 27 reglas, y así iría incrementandose (125, 625...). El método de Comb consiste en minimizar el número de reglas mediante equivalencias, haciendo que de 9 reglas pasen a 6, de 125 a 15, de 625 a 20 y así. \\ El método de Comb parte de la igualdad lógica ''[(P AND Q) then R] = [(P then R) OR (Q then R)]''. \\ Esto significa que las reglas que son IF a_1 AND ... AND a_n THEN c pueden ser reescritas como IF a_1 THEN c OR ... OR IF a_n THEN c \\ \\ Por lo que unas reglas como corner-entry AND going-fast THEN brake corner-exit AND going-fast THEN accelerate corner-entry AND going-slow THEN accelerate corner-exit AND going-slow THEN accelerate ----------- Posible resultado : Brake = 0.1 Accelerate = 0.6 Pueden ser expresadas como: corner-entry THEN brake corner-exit THEN accelerate going-fast THEN brake going-slow THEN accelerate ----------- Posible resultado : Brake = 0.4 Accelerate = 0.9 En efecto el resultado es distinto, pero cuando se hace una defuzzification del resultado la elección será la misma: realizar una pequeña aceleración. Por ejemplo en el anterior caso del soldado pasaríamos de las anteriores 9 reglas a sólo estas 6: IF Target_Close THEN Undesirable IF Target_Medium THEN VeryDesirable IF Target_Far THEN Undesirable IF Ammo_Low THEN Undesirable IF Ammo_Okay THEN Desirable IF Ammo_Loads THEN VeryDesirable Esto daría como resultado * Target_Close -> 0.00 (undesirable) * Target_Medium -> 0.67 (very desirable) * Target_Far -> 0.33 (undesirable) * Ammo_Low -> 0.20 (undesirable) * Ammo_Okay -> 0.78 (desirable) * Ammo_Loads -> 0.00 (very desirable) Por lo que * Undesirable -> MAX (0.00, 0.33, 0.20) = 0.33 * Desirable -> MAX (0.78) = 0.78 * VeryDesirable -> MAX (0.67, 0.00) = 0.67 Y aplicando el //Average of Maxima//: \\ \\ {12.5 x 0.33 + 50 x 0.78 + 87.5 x 0.67} / {0.33 + 0.78 + 0.67} = 57.1 \\ \\ Un resultado muy parecido al anterior. ==== Documentos ==== * {{ai:nafips2004.pdf|Fuzzy Logic in Agent-Based Game Design}}.