Beruflich Dokumente
Kultur Dokumente
1.INTRODUCCIÓN
El objetivo de estos apuntes es que el alumno adquiera los fundamentos de los
sistemas basados en el conocimiento (SBCs) y de su programación sobre los
paradigmas de reglas y objetos. Que el alumno aprenda hacer uso de estos
paradigmas y aprovechar sus capacidades en las aplicaciones más adecuadas y en
aquellas áreas para las que realmente tiene sentido. Para ello se toma como soporte
el entorno de desarrollo sobre los lenguajes Clips y COOL.
Para cualquier duda respecto a un comando o palabra reservada lo mejor es
acudir a la documentación “oficial” de Clips en:
http://clipsrules.sourceforge.net/OnlineDocs.html
Índice:
1. Introducción a Clips: Estructuración, módulos, templates, facts, rules, etc.
Agenda. Secuenciación. Encadenamiento hacia adelante.
2. Primeros pasos prácticos en Clips. Entorno de desarrollo. Componentes del
lenguaje. Cláusulas básicas. Ejercicios con reglas y comparación de patrones.
Entrada y salida de datos. (taller, 1,5 hora)
1
Tema 2. Desarrollo de SBCs en Clips
1. Introducción a Clips.
Desarrollada por Software Technology Branch de la NASA/Lyndon B. Johnson
Space Center
Características:
- 3 paradigmas de programación:
* programación basada en reglas: reglas+ hechos (facts)
* programación procedural: funciones
* programación orientada a objetos (COOL): objetos+paso de mensajes
- El mecanismo de inferencia básico es el encadenamiento hacia adelante.
- CLIPS es una herramienta escrita en C
- Plena integración con otros lenguajes como C y ADA
- Desde un lenguaje procedural se puede llamar a un proceso CLIPS, éste
realiza su función y luego le devuelve el control al programa.
- Se puede incorporar código procedural como funciones externas en CLIPS
- Las reglas pueden hacer "pattern-matching" sobre objetos (COOL) y facts
formando así un sistema integrado.
- CLIPS tiene una sintaxis estilo LISP que utiliza paréntesis como
delimitadores.
2
Apuntes de Ingeniería y Gestión del Conocimiento
- Tiene una versión en Java denominada Jess) que es muy usada y una versión
con lógica difusa fuzzy denominada FuzzyClips (y FuzzyJess).
- Dispone de un entorno de trabajo desde el que se puede trabajar con un
terminal, línea de comandos, y un sistema de menús, que básicamente lanzan
comandos: La ayuda del programa permite tener en línea la descripción completa
de cada comando y cada elemento del lenguaje, por lo que en este documento no se
necesita ser exhaustivo en estas particularidades.
> (+ 5 9)
> 14
>
Los comandos, aparte de introducirse directamente en la línea de comandos del
sistema, pueden agruparse en un fichero batch y ejecutarse como tal. Un programa
Clips será un fichero de este tipo con comandos para definir construcciones. Desde
el entorno se lanza este programa y se monitoriza su ejecución.
Para esto último hay comandos específicos. En particular el comando watch
permite visualizar las modificaciones de uno o unos elementos determinados del
lenguaje o del programa. El argumento del comando es la referencia al elemento o
elementos que se desean observar. Puede ser específico, una instancia o una regla
(en este caso se observarían sus activaciones) determinadas, por ejemplo, o
genérico, todos los hechos, también por ejemplo. Para esto último, el argumento
debería ser la denominación de los elementos genéricos que se irán referenciando
en este apartado: facts, rules, instances, activations, etc. El comando inverso es
unwatch.
Así el entorno permite definir:
Y controlar la:
3
Tema 2. Desarrollo de SBCs en Clips
• Hechos:
Todos los hechos tienen un identificador (una clave que genera el sistema)
por el que puede ser referenciado.
4
Apuntes de Ingeniería y Gestión del Conocimiento
Todos los hechos se insertan en la lista fact-list. Se puede ver esta lista con
el comando (facts)
Clips permite definir plantillas para (posteriormente) poder definir hechos con esa
estructura común:
5
Tema 2. Desarrollo de SBCs en Clips
Los slot pueden ser simples (slot) o slots múltiples (multislot), esto es, que
pueden contener varios valores (campo multivaluado).
En el ejemplo anterior de template no se ha definido el tipo de datos de slot y
por lo tanto esos slots admiten cualquier tipo de datos, pero esto se puede restringir
a través del operador type. En el ejemplo:
(deftemplate vehiculo
(slot matricula (type SYMBOL))
(slot color (type SYMBOL))
(slot propietario (type STRING))
(slot antiguedad (type INTEGER))
(slot cilindrada (type INTEGER))
(slot kilometraje(type INTEGER)))
Los identificadores del tipo de datos son: SYMBOL, STRING, LEXEME
(válido para símbolos y strings), INTEGER, FLOAT, NUMBER (válido para
enteros y reales) y ?VARIABLE, este último permite cualquier valor y es la
restricción por defecto, como hemos visto.
Hay otras posibilidades para la restricción de datos en los slots. Por ejemplo los
operadores que definen por enumeración los valores permitidos, que se indica con
el operador allowed-tipo-datos, donde tipo-datos pude ser symbols, strings, lexems,
integers, floats, numbers o values. Por ejemplo:
(deftemplate vehiculo
...
(slot color (type SYMBOL)(allowed-symbols verde rojo azul))
...
Para restringir valores numéricos es más habitual definir un rango. Para ellos se
dispone, lógicamente, de range:
(deftemplate vehiculo
...
6
Apuntes de Ingeniería y Gestión del Conocimiento
7
Tema 2. Desarrollo de SBCs en Clips
8
Apuntes de Ingeniería y Gestión del Conocimiento
Reset elimina todos los hechos y afirma todos los hechos especificados por los
deffacts.
El comando (assert hecho) añade el hecho a la base de hechos. Desde luego si
ese hecho ya estaba en la base, no tiene efecto la adición. Pero hecho debe ser la
descripción completa del hecho, puesto que en caso de no describirse unos
determinados slots, estos se consideran como nil. Así si afirmamos:
(assert (vehiculo
(matricula MIB-3456-ERC)))
El resultado en la base de hechos es la inclusión de:
(vehiculo
(matricula MIB-3456-ERC)
(color nil)
(propietario nil)
(antiguedad nil)
(cilindrada nil)
(kilometraje nil))
9
Tema 2. Desarrollo de SBCs en Clips
10
Apuntes de Ingeniería y Gestión del Conocimiento
(slot matricula)
(slot color))
(defrule realizar-modificacion-de-color)
?f1 <- (modificacion-color (matricula ?matricula) (color ?color))
?f2 <- (vehiculo (matricula ?matricula))
=> (retract ?f1)
(modify ?f2 (color ?color)))
11
Tema 2. Desarrollo de SBCs en Clips
Para los casos en que interesa comparar un valor con todos los campos de un
multislot, por ejemplo buscar las letras IX en la matrícula, que pueden aparecer en
el primer campo o en el último, se dispone del símbolo $?, que representa a cero o
más campos. En el ejemplo se imprimirían los nombres de los propietarios cuyos
vehículos tengan matriculas que contengan esos dos caracteres.
(defrule imprime-matriculas-IX
(vehiculo (matricula $? IX) Patrones en los ECs:
(propietario ?propietario))
=> (printout t ?propietario crlf)) Con restricciones literales.
(temperatura 28 grados)
El caracter $ tiene también la función de designar a
una variable como multivaluada. En el siguiente ejemplo Con comodines simples y multicampo.
se imprimen los nombres de los propietarios y las (temperatura ? grados)
(pacientes $? Lopez $?)
matrículas de sus vehículos. Sin este símbolo, la variable
?matricula solo haría referencia a su primer campo. Con variables simples y multicampo.
Obsérvese como en la parte derecha de la regla el (temperatura ?t grados)
carácter $ ya no precede al nombre de la variable (pacientes ?primero $?resto)parámetros de
multivaluada, porque ya capturó todo su contenido en la funciones ni métodos
Con operadores lógicos.
parte izquierda. (opcion-elegida 1|2|3)
(defrule imprime-propietario-matriculas (num-pacientes ~0)
(vehiculo (matricula $?matricula) (opcion-elegida ~1&~2&~3)
(propietario ?propietario))
=> (printout t ?propietario " es Con predicados o llamadas a funciones:
propietario de " ?matricula crlf)) (temperatura (maximo ?tmax)
(corporal ?t &:(> ?t ?tmax)))
Como ejemplo final de este apartado mostramos las
reglas que permiten manejar una pila. Se parte de un
multislot pila y de un slot nuevo-valor que contiene el ECs:
valor a insertar.
(defrule apilar Tipo test: (test <llamada-a-función>)
(temp-max ?tmax)
?apilar <- (nuevo-valor ?valor) (temp-corporal ?t)
?pila <- (pila ?ant-contenido) (test (>= ?tmax ?t)
=> (retract ?apilar ?pila)
(assert (pila ?valor ?ant-contenido)) Tipo or: (or <elemento-condicional>+)
(printout t "Apilado "?valor crlf))
(defrule desapilar-correcto (or (temperatura-corporal alta)
?desapilar <- (desapilar) (presion-arterial baja))
?pila <- (pila ?cima ?resto)
Tipo and: (and <elemento-condicional>+)
12
(or (and (presion-arterial baja) (temperatura-
corporal baja))
(and (presion ?p&:(<?p 1500) (temperatura
?t&:(< ?t 35)
Apuntes de Ingeniería y Gestión del Conocimiento
13
Tema 2. Desarrollo de SBCs en Clips
(defrule imprime-propietarios-vehiculos-media-antiguedad
(vehiculo (antiguedad ?antiguedad&: (> ?antiguedad 12) &: (< ?antiguedad 24))
(propietario ?propietario))
=> (printout t ?propietario " tiene un vehiculo de uno a dos años de
antiguedad" crlf))
Claro que también se podría haber utilizado la función test, que devuelve el
valor booleano de una expresión:
(defrule imprime-propietarios-vehiculos-antiguos Acciones procedurales:
(vehiculo (antiguedad ?antiguedad) Asignación a una variable
(propietario ?propietario)) (bind <variable> <expresión>*) (sólo en la
(test (> ?antiguedad 12)) RHS)
=> (printout t ?propietario " tiene un vehiculo Condicional:
con más de 12 meses" crlf)) (if <expresión> then <acción>+ [else <acción>+])
(switch <expresión-test> <sentencia-
Vamos a ver un ejemplo de utilización de las case><sentencia-case>+
[(default <acción>*)])
restricciones, como la anteriores, pero para seleccionar <sentencia-case> ::= (case <comparación> then
dos instancias (hechos) de la misma clase y en la misma <acción>*)
regla, que imprime los nombres de dos propietarios de Iteraciones:
sendos vehículos del mismo color. (while <expresión> [do] <acción>*)
(defrule imprime-propietarios-vehiculos-mismo-color (loop-for-count (<var> <inicio> <final>) [do]
(vehiculo (propietario ?propietario1) (color ?color1)) <acción>*)
(break)
(vehiculo (propietario ?propietario2&~?propietario1)
(color ?color2&?color1))
=> (printout t ?propietario1 " y " ?propietario2 " tienen un vehículo del
mismo color " ?color1 crlf))
14
Apuntes de Ingeniería y Gestión del Conocimiento
(defrule imprime-vehiculos-impuestos-circulacion
(vehiculo (cilindrada ?cilindrada)
(matricula ?matricula))
(impuesto-circulacion (tipo =(div ?cilindrada
500))
(impuesto ?impuesto))
=> (printout t "El vehiculo " ?matricula " tiene
que pagar " ?impuesto crlf))
(deffacts tabla-impuestos
(impuesto-circulacion (tipo 3)(impuesto 150)) Funciones predefinidas
(impuesto-circulacion (tipo 4)(impuesto 225)) Funciones de entorno:
(impuesto-circulacion (tipo 5)(impuesto 250))) (load <nombre-de-fichero>)
(load-facts <nombre-de-fichero>)
Los anteriores ejemplos se han basado en (save <nombre-de-fichero>)
restricciones sobre slots o variables pero que no se (save-facts <nombre-de-fichero>)
(exit) ; cierra el entorno Clips
combinaban en una misma expresión de restricción.
Matemáticas: abs, div, mod, round..., sin, cos..
Pero esto también es posible mediante las funciones or, (<op> <expresión-numérica> <expresión-
and y not. Entre las premisas de una misma regla numérica>+)
evidentemente hay ya un and implícito, el uso explícito E/S: (open <nombre-fichero> <nombre-lógico>
de esta función tendrá sentido al combinarse con las [<modo>])
(close [<nombre-lógico>])
otras dos. En el caso del or hay que tener en cuenta en su (read [<nombre-lógico>])
utilización, que puede generar varias concordancias del (printout <nombre-lógico> <expresión>*)
patrón de las premisas, por ejemplo: Strings: (str-cat <expresión>*)
(defrule imprime-vehiculos-seguro-TipoB (sym-cat <expresión>*)
(or (str-index
(vehiculo (antiguedad ?antiguedad&:(> ?antiguedad 120))) <expresión-lexema> <expresión-
lexema>)
(vehiculo (kilometraje ?kilometraje&:(> ?kilometraje 150000))))
(sub-string <inicio> <fin> <expresión-de-cadena>)
(vehiculo (matricula ?matricula))
(str-length <expresión-simbólica-o-de-cadena>)
=> (printout t "El vehiculo " ?matricula " paga seguro tipo B " crlf))
La respuesta del lanzamiento de la regla serían cuatro líneas en vez una, que
sería lo correcto. Para que funcionar adecuadamente la regla debería haber sido la
siguiente:
(defrule imprime-vehiculos-seguro-TipoB
(vehiculo (antiguedad ?antiguedad)(kilometraje ?kilometraje)
(matricula ?matricula))
(test (or (> ?antiguedad 120)(> ?kilometraje 150000)))
15
Tema 2. Desarrollo de SBCs en Clips
=> (printout t "El vehiculo " ?matricula " paga seguro tipo B " crlf))
En este otro ejemplo, la ejecución de la regla obtendrá la máxima antigüedad de
entre todos los vehículos:
(defrule imprime-mayor-antiguedad
(vehiculo (antiguedad ?antiguedad1))
(not (vehiculo (antiguedad ?antiguedad2&:(> ?antiguedad2 ?antiguedad1 ))))
=>(printout t "La máxima antiguedad de un vehiculo es " ?antiguedad1 crlf))
Ahora que, si queremos obtener la matrícula del coche de mayor antigüedad, la
regla quedaría así:
(defrule imprime-vehiculo-mayor-antiguedad
(vehiculo (antiguedad ?antiguedad1)(matricula ?matricula))
(not (vehiculo (antiguedad ?antiguedad2&:(> ?antiguedad2 ?antiguedad1 ))))
=>(printout t "El vehiculo de maxima antiguedad es " ?matricula crlf))
16
Apuntes de Ingeniería y Gestión del Conocimiento
4ENTRADA/SALIDA DE DATOS
Hemos estado utilizando la función printout (t es el nombre de referencia del
terminal estándar, normalmente pantalla para salida y teclado para entrada) para
visualizar datos por el terminal. La función read puede utilizarse para el proceso
complementario de captura de datos desde el teclado. Devuelve el valor y el control
al introducirse el enter:
(defrule introducir-propietario
=> (printout t "Nombre del propietario: ")
(bind ?propietario (read))
(assert nombre-propietario ?propietario))
La función bind almacena en la variable, que se indica como primer argumento
en el comando, el valor resultante de la expresión del segundo argumento.
Las funciones para lectura escritura en ficheros son también estas mismas read
y printout, pero se requiere que los correspondientes ficheros hayan sido
previamente abiertos con (open nom-archivo identificador tipo-acceso). Por
ejemplo: (open “camiones.dat” camiones “r”) abrirá el archivo camiones.dat para
lectura y le asignará el identificador interno camiones. Los tipos pueden ser “r”
para solo lectura, “w” para solo escritura, “r+” lectura y escritura y “a” para poder
únicamente añadir.
Existe la posibilidad de en vez de utilizar read para leer desde un fichero de
texto, utilizar (readline identificador) para leer caracteres hasta el cambio de línea.
Esta línea se introduce como un campo simple, si se desea descomponer, se puede
utilizar la función explode$, veamos el siguiente ejemplo:
(defrule obtener-propietario
=> (printout t "Nombre del propietario: ")
(bind ?propietario (explode$(readline)))
(assert (nombre-propietario ?propietario))
Si a la pregunta de esta regla respondemos con tres palabras (nombre y
apellidos), la regla producirá 3 nuevos hechos. Si no hubiéramos utilizado
explode$, se hubiese producido un único hecho.
17
Tema 2. Desarrollo de SBCs en Clips
5 MANTENIMIENTO DE LA VERDAD
En Clips, cuando una regla da lugar a un nuevo hecho, éste no desaparece
cuando, ante nuevos eventos, las condiciones de las premisas de la regla ya no se
cumplen. Para algunas situaciones o problemas esto está bien así, es coherente con
el conocimiento que se desea representar, pero en otras ocasiones no. Ante el
incumplimiento de una premisa de una regla, deberían desaparecer los hechos a los
que previamente dio lugar. Para Clips dispone del operador logical, que crea
18
Apuntes de Ingeniería y Gestión del Conocimiento
dependencias entre los hechos que coinciden con los patrones contenidos por el
operador, en el lado izquierdo de la regla, y los hechos afirmados en la parte
derecha.
Dado el siguiente hecho (sea f-4) y al lanzar la siguiente regla, se afirmaría un
nuevo hecho (sea f-5):
(deffacts incautaciones
(incautado (matricula BBB-6765-IXC)))
(defrule determina-incautados
(logical (incautado (matricula ?matricula)))
(vehiculo (matricula ?matricula)(inhabilitado false))
=> (assert (vehiculo (matricula ?matricula)
(inhabilitado true))))
De tal forma que si retiramos este hecho, con (retract 4), desaparecen de la base
de hechos tanto f-4 como f-5.
6 PRIORIDAD Y CONTROL
Por defecto, el orden de ejecución de las reglas depende de su orden de llegada
a la pila de la agenda, por tanto y como tal pila, se activan primero las últimas
reglas recibidas. El orden de llegada a la agenda depende a su vez del orden en la
afirmación de los hechos que las disparan. Pero este orden de ejecución puede ser
alterado gracias a la posibilidad de establecer prioridades para cada regla particular.
Es posible definir un nivel de prioridad desde –10.000 a +10.000, siendo el valor
por defecto 0. Se indica con (declare(salience n)) como premisa de la parte
izquierda de la regla. En definitiva, en la agenda las reglas se ordenan por su valor
salience y, con igual valor, por su orden inverso de llegada.
19
Tema 2. Desarrollo de SBCs en Clips
20
Apuntes de Ingeniería y Gestión del Conocimiento
distinto
21
Tema 2. Desarrollo de SBCs en Clips
Para establecer una estructura de control de este tipo mediante reglas como las
que hemos visto, podemos utilizar uno de los siguientes métodos. En los ejemplos
se supondrá que la subtareas se suceden sin interrupción.
Incluir en cada regla una premisa que determine la fase (predice, obtiene, etc.)
del proceso en que podrá ser activada y la afirmación del hecho que sitúa al sistema
en la siguiente fase (si ha lugar):
(defrule predice-...
?fase <-(fase predice)
...
=> ...
(retract ?fase)
(assert (fase obtiene)))
Otra opción es secuenciar a través de los niveles de prioridad, pero esto tiene el
problema de que se pueden mezclar las fases, en tanto que, si en la fase obtiene
entra a la agenda una regla de las de apoyo al predice, esta se activará antes que
restantes correspondientes a obtiene. El ejemplo auto.clp (en el sitio web de Clips)
utiliza este sistema.
La tercera opción, podríamos decir que híbrida de las anteriores, es definir unas
reglas específicamente para secuenciar las fases, que tienen una prioridad más baja
que las reglas que soportan el conocimiento experto propiamente dicho, y que
cambian el hecho de define las subtarea activa.
(defrule predecir-obtener
(declare (salience –100))
?subtarea <- (subtarea predecir)
=> (retract ?subtarea)
(assert (subtarea obtener)))
(defrule obtener-comparar
(declare (salience –100))
?subtarea <- (subtarea obtener)
=> (retract ?subtarea)
(assert (subtarea comparar)))
(defrule comparar-predecir
(declare (salience –100))
?subtarea <- (subtarea comparar)
=> (retract ?subtarea)
(assert (subtarea predecir)))
Cada regla “experta” comienza con una premisa que la identifica como
perteneciente al conocimiento de apoyo de una subtarea:
(defrule predice-...
(subtarea predecir)
; premisas que determinan la hipótesis de una avería
22
Apuntes de Ingeniería y Gestión del Conocimiento
...
=> ...
)
Alternativamente a esta opción, podría escribirse una regla única de control que
fuera lanzando las sucesivas subtareas sin tener que aparecer explícitamente en la
regla, de esta forma:
(defrule lanza-subtarea
(declare (salience –100))
?subtarea <- (subtarea ?subtarea-actual)
(subtarea-siguiente-a ?subtarea-actual ?subtarea-siguiente)
=> (retract ?subtarea)
(assert (subtarea ?subtarea-siguiente)))
Siempre y cuando se hayan definido estas fases como hechos sucesivos de un
slot fase-posterior:
(deffacts secuencia-subtareas
(subtarea predecir)
(subtarea-siguiente-a predecir obtener)
(subtarea-siguiente-a obtener comparar)
(subtarea-siguiente-a comparar predecir))
Algo totalmente equivalente sería utilizar una lista de subtareas y una regla que
las secuenciara, es decir:
(defrule lanza-subtarea
(declare (salience –100))
?subt <- (subtarea ?subt-actual)
?sec-subts <- (secuencia-subts ?subt-siguiente $?otras-subts)
=> (retract ?subt ?sec-subts)
(assert (subtarea ?subt-siguiente))
(assert (secuencia-subts ?otras-subts ?subt-siguiente)))
Con
(deffacts estructura-subtareas
(subtarea predecir)
(secuencia-subts obtener comparar predecir))
Según cualquiera de estas opciones anteriores, tendríamos dos niveles de
prioridad, uno asignado a las reglas que hemos denominado expertas y otro a las
reglas de control. Aún podrían introducirse dos niveles más, también para el
correcto control en la evaluación de las reglas. El mayor nivel de prioridad
deberían tenerlo aquellas reglas que detectan situaciones que se han definido como
ilegales del programa. Las reglas especificas para plantear preguntas al usuario
deber deberían tener un nivel intermedio de prioridad, entre las reglas de control y
las reglas expertas, de tal forma que solo se pregunte al usuario cuando no haya
conocimiento experto para inferir el valor que se cuestiona.
23
Tema 2. Desarrollo de SBCs en Clips
Los patrones más específicos, con más restricciones, deben de ir primero, ya que,
generalmente, producirán el número más pequeño de coincidencias y tendrán un
mayor número de variables asignadas. Lo que provocará una mayor restricción en
los otros patrones.
➮ Los patrones temporales deben de ir los ú́ ltimos. Es decir, los
correspondientes a hechos que se añaden y borran frecuentemente de la lista de
hechos. Esto provocará un menor número de cambios en las coincidencias
parciales.
➮ Los patrones más raros deben ser los primeros. Los patrones
correspondientes a hechos que se presentarán pocas veces en la lista de hechos, si se
colocan al principio reducirán el número de coincidencias parciales.
➮ La función test debe ponerse lo antes posible: ¿Así, cuál es mejor de R1 y
R2?
(defrule R1
?p1 <- (valor ?x)
?p2 <- (valor ?y)
?p3 <- (valor ?z) ; comprueba que ningun valor es igual a otro
(test (and (neq ?p1 ?p2) (neq ?p2 ?p3) (neq ?p1 ?p3))
=> )
(defrule R2
?p1 <- (valor ?x)
?p2 <- (valor ?y)
(test (neq ?p1 ?p2))
?p3 <- (valor ?z)
(test (and (neq ?p2 ?p3) (neq ?p1 ?p3))
=> )
; una variante
(deftemplate registro 25
(slot anda)
(slot ya))
(deffacts error
(registro (anda nil) (ya nil))
(defrule anda-que
?anda <- (registro (anda ?var))
=>
(modify ?anda (anda ?var) (ya bien)))
Tema 2. Desarrollo de SBCs en Clips
7. PROGRAMACIÓN PROCEDIMENTAL
Clips dispone de algunas funciones para implementar las estructuras de control
propias de la programación procedimental. En conjunción con las reglas, se pueden
utilizar estas estructuras principalmente expresadas en la parte derecha de la regla,
de tal forma, que la veracidad de las premisas suponga la ejecución de un pequeño
procedimiento expresado, como decimos en la parte derecha. Principalmente son if,
while y halt. La primera obviamente soporta la estructura if..the..else, por todos
conocida. La segunda soporta la ejecución del típico bucle while y la función halt,
sin argumentos, permite parar la ejecución de las reglas de la agenda. La siguiente
regla nos muestra la utilización de estas tres funciones. En la secuencialidad de las
subtareas podemos dar la opción al usuario de parar momentáneamente o
definitivamente la ejecución.
(defrule plantear-revision
?subtarea <- (subtarea plantear-revision)
=> (retract ?subtarea)
(printout t "¿continuamos?(S/N) ")
(bind ?respuesta (read))
(while (and (neq ?respuesta S) (neq ?respuesta N)) do
(printout t "¿continuamos?(S/N) ")
(bind ?respuesta (read)))
(assert (subtarea continuar))
(if (neq ?respuesta S)
26
Apuntes de Ingeniería y Gestión del Conocimiento
then (halt)))
La función while nos permite seguir planteando la pregunta al usuario hasta que
éste responda una de los dos caracteres reconocidos. La función if permite parar la
ejecución, con halt, si la respuesta es afirmativa.
27
Tema 2. Desarrollo de SBCs en Clips
<acción>*
)
El valor devuelto por la función es la última acción o expresión evaluada dentro de la función. Si una
deffunction no tiene acciones, devolverá el símbolo FALSE. Si se produce algún error mientras se ejecuta la
función, cualquier otra acción de la función aún no ejecutada se abortará, y la función devolverá el símbolo
FALSE.
Ejemplo: (subseq$ <expresión-multicampo> <inicio> <final>)
(sym-cat <expresión>*)
(str-index <expresión-lexema> <expresión-lexema>)
(sub-string <inicio> <fin> <expresión-de-cadena>)
(str-length <expresión-simbólica-o-de-cadena>)
(deffunction respuesta_si_no (?pregunta)
(bind ?respuesta (preguntar ?pregunta si no s n))
(if (or (eq ?respuesta si)
(eq ?respuesta s)) (deffunction preguntar (?pregunta $?valores-permitidos)
then TRUE (printout t crlf ?pregunta)
else FALSE)) (bind ?respuesta (read))
(if (lexemep ?respuesta) then
(bind ?respuesta (lowcase ?respuesta)))
(while (not (member ?respuesta ?valores-permitidos)) do
(printout t ?pregunta)
(bind ?respuesta (read))
(if (lexemep ?respuesta)
then (bind ?respuesta (lowcase ?respuesta))))
?respuesta)
Otro ejemplo:
(bind ?carroceria 0)
(while (or (< ?carroceria 1)(> ?carroceria 5))
(printout t crlf "Estado de la carroceria:")
(printout t crlf "1 - Muy bueno")
(printout t crlf "2 - Bueno")
(printout t crlf "3 - Regular")
(printout t crlf "4 - Malo")
(printout t crlf "5 - Muy malo")
(printout t crlf ": ")
(bind ?carroceria (read))
)
con:
(defrule pide-datos-iniciales "Pide los datos de matricula y anio de matriculacion"
(initial-fact)
=>
(printout t crlf "Datos del vehiculo")
(printout t crlf "Matricula: ")
(bind ?matricula (read))
(printout t crlf "Anio de matriculacion: ")
(bind ?anio (read))
(assert (vehiculo (matricula ?matricula)(anio-matriculacion ?anio)))
)
28
Apuntes de Ingeniería y Gestión del Conocimiento
Estructura Switch
(defrule precio_mecanico ""
?f2 <- (estado mecanico ?mec)
=>
(retract ?f2)
(if (or (eq ?mec leves) (eq ?mec graves)) then
(bind ?respuesta (preguntar_valor "Cuál es el precio de las reparaciones
mecánicas suministrado por los mecánicos (Pesetas): " )))
(switch ?mec
(case ninguna then (assert (estado mecanico ?mec 0)))
(case leves then (assert (estado mecanico ?mec ?respuesta)))
(case graves then (assert (estado mecanico ?mec ?respuesta)))
(case gravisimas then (assert (tasacion nula "Las reparaciones son
demasiado costosas")))))
Ejemplo de funciones:
(deffunction CalculaPorcentajeEntero(?Num ?Porcentaje)
(bind ?ParteEntera (div (* ?Num ?Porcentaje) 100))
(bind ?Resto (mod (* ?Num ?Porcentaje) 100))
(if (> ?Resto 0.5) then
(bind ?Resultado (+ ?ParteEntera 1))
else
(bind ?Resultado ?ParteEntera)
)
)
29
Tema 2. Desarrollo de SBCs en Clips
ejemplo de captura:
(deffunction es-del-tipo (?respuesta ?tipo ?posibilidades)
;; Si es de tipo mutiple recorre las posibilidades y devuelve TRUE si alguna
coincide.
;;;En caso contrario devuelve FALSE.
(if (eq ?tipo multiple) then
(progn$ (?item ?posibilidades) ; para cada elemento de la lista ?posibilidades
(if (eq ?respuesta ?item) then ;si coincide con la respuesta
(return TRUE))) ; devuelve TRUE
(return FALSE))
;; Si es de tipo numerico devuelve TRUE si la respuesta lo es y FALSE en
;; caso contrario.
(if (eq ?tipo numerico) then
(return (numberp ?respuesta)))
;; Para los demas casos devuelve TRUE si la respuesta tiene una longitud
;; mayor que 0 y FALSE en caso contrario.
(return (> (str-length ?respuesta) 0)))
(defrule sum-areas
Un bucle menos implícito
(declare (salience 20)) ;;; regla que
(deffacts initial-information ;datos de los
suma todas las areas
rectangulos de cuyas areas se obtendra la media
?sum-adr <- (sum ?total)
(rectangle 10 6)
?new-area-adr <- (add-to-sum ?area)
(rectangle 7 5)
?count-adr <- (count ?counter)
(rectangle 6 8)
=>
(rectangle 2 5)
(retract ?sum-adr ?new-area-adr
(rectangle 9 4)
?count-adr)
(sum 0)
(assert (sum (+ ?total ?area)))
(count 0))
(assert (count (+ ?counter 1))))
(defrule sum-rectangles
(defrule average
(declare (salience 30))
(declare (salience 10)) ;;; regla que
(rectangle ?height ?width)
calcula e imprime la media
=>
?sum-adr <- (sum ?total)
(assert (add-to-sum (* ?height
?count-adr <-(count ?counter)
?width)))) ; crea un hecho add-to-sum por cada
=>
rectangulo
(printout t crlf "Here is the average
area" (/ ?total ?counter) crlf))
31
Tema 2. Desarrollo de SBCs en Clips
32
Apuntes de Ingeniería y Gestión del Conocimiento
33
Tema 2. Desarrollo de SBCs en Clips
9 ÁRBOLES DE DECISIÓN.
Recordemos el problema de diagnóstico de una hemorragia a través de la
siguiente estructura:
“test de Rumpell Leede
positivo”
Cierto
Falso
“Recuento de
”VASCULITIS” plaquetas bajo”
Cierto
Falso
Cierto Falso
Cierto Falso
“SECUESTRO “CAUSAS
“Deficiencia del “Deficiencia del
LEUCOCITARIO” INMUNOLOGICAS”
FACTOR XII, XI, FACTOR X, V,
IX o VIII” Prothrombina o
Fibrinógeno”
34
Apuntes de Ingeniería y Gestión del Conocimiento
35
Tema 2. Desarrollo de SBCs en Clips
TNB
Afirmación: “Tamaño
normal del bazo”
Tipo: Intermedio
Siguiente-H-Cierto: SL
Siguiente-H-Falso: CI
SL CI
Afirmación: “Secuestro Afirmación: “Causas
Leucocitario” Inmunes”
Tipo: Hoja Tipo: Hoja
Siguiente-H-Cierto: NIL Siguiente-H-Cierto: NIL
Siguiente-H-Falso: NIL Siguiente-H-Falso: NIL
Por tanto, los nodos se definen como hechos con este formato:
(deffacts arbol-diagnostico
(nodo
(nombre PRLP)
(tipo intermedio)
(afirmación "Prueba de Rumpell-Leede positiva")
(sig-h-cierto VAS)
(sig-h-falso RPB))
…
(nodo
(nombre TNB)
(tipo intermedio)
(afirmación "Tamaño normal del bazo")
(sig-h-cierto SL)
(sig-h-falso CI))
…
36
Apuntes de Ingeniería y Gestión del Conocimiento
O bien se activa:
(defrule respuesta-negativa
?nodo <- (nodo-actual ?nombre))
(nodo (nombre ?nombre)
(tipo intermedio)
(sig-h-falso ?descendiente-falso))
(?respuesta <- (respuesta N))
=> (retract ?nodo ?respuesta)
(assert (nodo-actual ?descendiente-falso))
37
Tema 2. Desarrollo de SBCs en Clips
(defrule nuevo-caso
?nuevo-caso <- (nuevo-caso)
?respuesta <- (respuesta S)
=> (retract ?nuevo-caso ?respuesta)
(assert (nodo-actual PRLP)))
(defrule terminar
?nuevo-caso <- (nuevo-caso)
?respuesta <- (respuesta N)
=> (retract ?nuevo-caso ?respuesta)
(printout t "FIN DE LA EJECUCION" crlf))
38
Apuntes de Ingeniería y Gestión del Conocimiento
Mientras not(nodo-hoja(nodo-actual))
Hacer
respuesta:= preguntar(nodo-actual);
i:=1;
Mientras existe-descendiente(nodo-actual, i) y
respuesta <> valor-descendiente(nodo-actual, i)
Hacer
i:= i+1;
Fin
Si existe-descendiente(nodo-actual, i) entonces
nodo-actual := descendiente(nodo-actual, i);
Fin
Visualizar-afirmacion(nodo-actual)
Fin
39
Tema 2. Desarrollo de SBCs en Clips
Cierto
Falso
“Recuento de
”VASCULITIS” plaquetas bajo”
Cierto
Falso
Cierto Falso
Cierto Falso
Cierto Falso
40
Apuntes de Ingeniería y Gestión del Conocimiento
Secuestro leucocitario
> Entonces, ¿cuál debería ser la hipótesis cuya afirmación conduce a esta
conclusión?
Tamaño normal del bazo
Con esto, el subárbol que estamos corrigiendo debería quedar así:
“No hay reducción o
ausencia de megacariocito”
Cierto
Cierto
Falso
“SECUESTRO “CAUSAS
LEUCOCITARIO” INMUNOLOGICAS”
41
Tema 2. Desarrollo de SBCs en Clips
Por supuesto el slot if sostendrá las premisas mientras que then lo hará con las
conclusiones. En if (o parte izquierda, LHS) determinaremos que las premisas
sencillas tengan la estructura: <atributo> es <valor>, con es como palabra
reservada. Admitiremos esta misma estructura pero entendida como una única
asignación de un valor simple o inclusión de un hecho, como conclusión de la regla
(then o parte derecha, RHS). En la LHS admitiremos la composición a través de la
conectiva y.
<atributo-1> es <valor-1> y
...
<atributo-n> es <valor-n>
42
Apuntes de Ingeniería y Gestión del Conocimiento
(deftemplate propiedad-valor
(slot propiedad)
(slot valor))
43
Tema 2. Desarrollo de SBCs en Clips
Cierto
Falso
“Recuento de
”VASCULITIS” plaquetas bajo”
Cierto
Falso
Cierto
Falso
“SECUESTRO “CAUSAS
LEUCOCITARIO” INMUNOLOGICAS”
44
Apuntes de Ingeniería y Gestión del Conocimiento
dimension-bazo es anormal)
(then diagnostico es causas-inmunologicas)))
Junto con los hechos iniciales:
(propiedad-valor (propiedad rumpell-leede))
(propiedad-valor (propiedad recuento-plaquetas))
(propiedad-valor (propiedad reduccion-megacariocitos))
(propiedad-valor (propiedad dimension-bazo))
Y la otra que pregunte al usuario por el valor del antecedente cuando no haya
rules que lo incluyan en su consecuente.
(defrule pedir-valor-propiedad
?hecho-objetivo <- (objetivo (propiedad ?objetivo))
(not (propiedad-valor (propiedad ?objetivo)))
(not (rule (then ?objetivo $?)))
=>
(retract ?hecho-objetivo)
(printout t "Introduzca el valor de " ?objetivo ": ")
(assert (propiedad-valor (propiedad ?objetivo)
(valor (read)))))
Complementando a estas dos reglas, debe haber otra regla que elimine como
objetivo aquél que ya se ha logrado y esto, es evidente, debe tener prioridad sobre
la búsqueda de objetivos (las anteriores reglas):
(defrule retractar-objetivo-logrado
(declare (salience 10))
?hecho-objetivo <- (objetivo (propiedad ?objetivo))
(propiedad-valor (propiedad ?objetivo))
=>
45
Tema 2. Desarrollo de SBCs en Clips
(retract ?hecho-objetivo))
También tiene que tener prevalencia la afirmación del consecuente de una rule
cuando su antecedente, como anterior objetivo, se haya logrado. Esto tiene que
llevar asociado la eliminación de esa rule.
(defrule afirmar-consecuente
(declare (salience 10))
(objetivo (propiedad ?objetivo))
(propiedad-valor (propiedad ?propiedad)
(valor ?valor))
?rule <- (rule (if ?propiedad es ?valor)
(then ?objetivo es ?valor-objetivo))
=>
(retract ?rule)
(assert (propiedad-valor (propiedad ?objetivo)
(valor ?valor-objetivo))))
Cuando se cumple la primera premisa del antecedente de una rule, esta misma
premisa se elimina de la rule, para no volverla a tener en cuenta:
(defrule eliminar-premisa-cumplida
(declare (salience 10))
(objetivo (propiedad ?objetivo))
(propiedad-valor (propiedad ?propiedad)
(valor ?valor))
?rule <- (rule (if ?propiedad es ?valor y $?resto-if)
(then ?objetivo es ?valor-objetivo)))
=>
(modify ?rule (if $?resto-if)))
46
Apuntes de Ingeniería y Gestión del Conocimiento
Herencia: Proceso por el cual una clase puede ser definida en términos de
otra(s) clase(s).
Polimorfismo: Capacidad de diferentes objetos para responder al mismo
mensaje de una forma especializada.
Ligadura dinámica (dynamic binding): Capacidad para seleccionar en
tiempo de ejecución el gestor de mensajes que corresponde a un mensaje
concreto.
Definición de Clases:
Construcción:
(defclass <nombre> [<comentario>]
(is-a <nombre-de-superclase>+) ;;; indica un orden de herencia
[(role concrete | abstract)];;; puede instanciarse o no
[(pattern-match reactive | non-reactive)];;; admite machting en una regla o no
<slot>* ;;; definición de los atributos de la clase
<documentación-handler>*
)
Herencia múltiple
COOL examina cada nueva clase utilizando la lista de precedencia de clases (de
superclases) para establecer un orden lineal y le hace heredar slots y gestores
(conducta) de cada una de las clases de esta lista en orden. Tiene prioridad las
primeras clases de la lista (las más específicas) para heredar si hay conflicto (tienen
el mismo nombre).
Definición de slots:
(describe-class <nombre-de-clase>)
En la cláusula is-a ya se establece una precedencia
(slot <nombre> <facet>*)
(single-slot <nombre> <facet>*)
(multislot <nombre> <facet>*)
facets: son las propiedades de los atributos, las cuales son ciertas para todos los
objetos que comparten dichos slots.
48
Apuntes de Ingeniería y Gestión del Conocimiento
49
Tema 2. Desarrollo de SBCs en Clips
(estado encendida))
(object (is-a Habitacion) (name ?h) (ocupación vacía))
=>
(send ?inst Apagar)
)
Paso de mensajes:
Los objetos se manipulan mediante el envío de mensajes utilizando la función
send.
La implementación de un mensaje consta de una serie de fragmentos de
código procedural llamados gestores de mensajes (message-handlers). El
valor devuelto por un gestor de mensajes es el resultado de la evaluación
de la última acción.
La construcción defmessage-handler se utiliza para especificar la conducta de
los objetos de una clase en respuesta a un mensaje particular.
Dentro de una clase, los gestores para un mensaje particular pueden ser de
diferentes tipos diferentes: Primary (el proceso principal), Before, After.
50
Apuntes de Ingeniería y Gestión del Conocimiento
Manipulación de instancias
Los objetos se manipulan mediante el envío de mensajes de unos a otros.
(send <expresión-de-objeto> <nombre-de-mensaje>
<expresión>*)
La función send devuelve el valor del último gestor (primary o around)
ejecutado.
(definstances <nombre-colección-instancias>
51
Tema 2. Desarrollo de SBCs en Clips
[active] [<comentario>]
(<definición-de-instancia>)*)
get-<nombre-atributo>
put-<nombre-atributo>
delete
52
Apuntes de Ingeniería y Gestión del Conocimiento
53