Documentos de Académico
Documentos de Profesional
Documentos de Cultura
• Interfaz del usuario. El código que controla el diálogo entre el usuario y el SE.
Para entender un SE es necesario entender también el rol de los usuarios que inter-
accionan con el sistema:
• Experto del Dominio. El o los individuos que son los expertos en resolver el
problema que el SE intentará resolver.
• Usuario. El individuo que consultará el SE para obtener los consejos que espera-
ría de un experto del dominio.
89
90 �������� ��������
Usuario
Experto en
el Dominio
Interface con
el Usuario
Experiencia
Máquina de Ingeniero en
Ingeniero del Inferencia Sistemas
Conocimieno
Base de Almacén de
Conocimiento Trabajo
• Razonamiento guiado por las metas y encadenamiento hacia atrás. Una técnica
de inferencia que usa las reglas IF-THEN para descomponer las metas en sub-
metas más fáciles de probar.
• Razonamiento guiado por los datos y encadenamiento hacia adelante. Una téc-
nica de inferencia que usa las reglas IF-THEN para deducir soluciones a un
problema a partir de los datos iniciales disponibles.
• Interfaz del usuario. La parte del SE que se usa para una interacción más ami-
gable con el usuario.
�.� ��������������� �� ��� �� 91
1 IF
2 familia es albatros AND
3 color es blanco
4 THEN
5 ave es albatros laysan.
6
7 IF
8 familia es albatros AND
9 color es negro
10 THEN
11 ave es albatros de pies negros.
El sistema puede usar otras reglas para resolver las sub-metas planteadas por las
reglas de alto nivel, por ejemplo:
1 IF
2 orden es tubonasales AND
3 tamaño es grande AND
4 alas es grandes anguladas
5 THEN
6 familia es albatros.
�.�.� Incertidumbre
Para muchos problemas no es posible enumerar las soluciones alternativas a las pre-
guntas planteadas con antelación. Los problemas de configuración caen en esta cate-
goría. El encadenamiento hacia adelante, o razonamiento guiado por los datos, usa
reglas IF-THEN para explorar el estado actual en la solución del problema y moverse
a estados más cercanos a la solución.
Un SE para acomodar el mobiliario puede tener reglas para la ubicación de un
mueble en particular. Una vez que un mueble ha sido colocado, se puede proceder
con los demás. La regla para colocar la TV enfrente del sofá es como sigue:
1 IF
2 no_colocada tv AND
3 sofá en pared(X) AND
4 pared(Y) opuesta a pared(X)
5 THEN
6 colocar tv en pared(Y).
Esta regla toma un estado del problema con la televisión no situada y regresa un
estado nuevo, donde la televisión ya ha sido colocada. Puesto que la televisión ya ha
sido colocada en su lugar, esta regla no volverá a ser disparada por el SE. Otras reglas
serán usadas para colocar el resto de los muebles hasta terminar.
�.�.� Reglas
1 IF
2 primera premisa AND
3 segunda premisa AND
4 ...
5 THEN
6 conclusión
1 conclusión :-
2 primera premisa,
3 segunda premisa,
4 ...
Esto puede ser confuso pués la regla en prolog dice más THEN-IF que IF-THEN.
Retomemos los ejemplos anteriores, si queremos representar en Prolog la regla:
1 IF
2 familia es albatros AND
3 color es blanco
4 THEN
5 ave es albatros laysan
1 ave(albatros_laysan) :-
2 familia(albatros),
3 color(blanco).
Las siguientes reglas distinguen entre dos tipos de albatros y cisne (Ver la figura
27). Todas son cláusulas del predicado ave/1:
1 ave(albatros_laysan) :-
2 familia(albatros),
3 color(blanco).
4 ave(albatros_patas_negras) :-
5 familia(albatros),
6 color(obscuro).
7 ave(cisne_silbador) :-
8 familia(cisne),
9 voz(suave_musical).
10 ave(cisne_trompetero) :-
11 famila(cisne),
12 voz(alta_trompeta).
Para que estas reglas tengan éxito al distinguir un ave, necesitamos almacenar he-
chos acerca del ave que deseamos identificar con el SE. Por ejemplo, si agregamos
estos hechos al programa:
1 familia(albatros).
2 color(obscuro).
?- ave(X).
X = albatros_patas_negras
Yes
94 �������� ��������
Observen que aún en esta etapa temprana tenemos un SE completo, donde la ex-
perticia consiste en distinguir entre cuatro aves. La interfaz con el usuario es el REPL
de Prolog y los datos de entrada se almacenan directamente en el programa.
1 orden(nariz_tubular) :-
2 fosas(externas_tubulares),
3 habitat(mar),
4 pico(gancho).
5 orden(acuatico) :-
6 patas(membrana),
7 pico(plano).
8 familia(albatros) :-
9 orden(nariz_tubular),
10 tamaño(grande),
11 alas(muy_largas).
12 familia(cisne) :-
13 orden(acuatico),
14 cuello(largo),
15 color(blanco),
16 vuelo(pesado).
1 fosas(externas_tubulares).
2 habitat(mar).
3 pico(gancho).
4 tamaño(grande).
5 alas(muy_largas).
6 color(obscuro).
?- ave(X).
X = albatros_patas_negras
Yes
1 ave(ganso_canadiense) :-
2 familia(ganso),
3 estacion(invierno),
4 pais(estados_unidos),
5 cabeza(negra),
6 pecho(blanco).
7 ave(ganso_canadiense) :-
8 familia(ganso),
9 estacion(verano),
10 pais(canada),
11 cabeza(negra),
12 pecho(blanco).
Estas metas pueden hacer referencia a otros predicados en una jerarquía diferente:
1 pais(estados_unidos) :- region(oeste_medio).
2 pais(estados_unidos) :- region(sur_oeste).
3 pais(estados_unidos) :- region(nor_oeste).
4 pais(estados_unidos) :- region(atlantico_medio).
5 pais(canada) :- provincia(ontario).
6 pais(canada) :- provincia(quebec).
7
8 region(nueva_inglaterra) :-
9 estado(X),
10 member(X,[massachusetts, vermont, connecticut, maine]).
11
12 region(sur_oeste) :-
13 estado(X),
14 member(X,[florida, mississippi, alabama, nueva_orleans]).
96 �������� ��������
Figura 28: Pato común del norte (Mallard) en ilustración de John James Audubon (1838).
Otras aves necesitarán de predicados múltiples para ser identificada. Por ejemplo,
el Mallard (Anas platyrhynchos) macho, o pato común del norte (Figura 28), tiene la
cabeza verde con un anillo blanco; la hembra tiene la cabeza café moteada:
1 ave(mallard):-
2 familia(pato),
3 voz(graznido),
4 cabeza(verde).
5 ave(mallard) :-
6 familia(pato),
7 voz(graznido),
8 cabeza(cafe_moteada).
Basicamente, cualquier situación del libro de las aves norte americanas puede ser ex-
presado fácilmente en Prolog. Las reglas expresadas forman la base de conocimientos
del SE. El único punto débil del programa es su interfaz con el usuario, que requiere
que los datos sean introducidos como hechos del programa.
atributo valor
familia pato
voz graznido
cabeza verde
Cuadro 2: Atributos valor para el mallard
Esta es una de las representaciones más simples usadas en los SE, pero es suficiente
para muchas aplicaciones. Existen representaciones más expresivas, como los tripletes
objeto–atributo–valor, o las redes semánticas, o los marcos.
Como estamos programando en Prolog, la riqueza del lenguaje puede usarse di-
rectamente en el SE. Por ejemplo, los pares atributo–valor han sido representados
como predicados unarios de la forma atributo(valor): familia(pato), voz(graznido),
cabeza(verde). Pero en region/1 usamos la membresia en listas para su definición.
Usaremos el predicado pregunta para determinar con ayuda del usuario, cuando
un par atributo–valor es verdadero. El SE debe modificarse para determinar que atri-
butos son verificables por el usuario. Esto se logra con reglas para los atributos que
llaman a pregunta:
1 fosas(X) :- pregunta(fosas,X).
2 habitat(X) :- pregunta(habitat,X).
3 pico(X) :- pregunta(pico,X).
4 tamano(X) :- pregunta(tamano,X).
5 come(X) :- pregunta(come,X).
6 pies(X) :- pregunta(pies,X).
7 alas(X) :- pregunta(alas,X).
8 cuello(X) :- pregunta(cuello,X).
9 color(X) :- pregunta(color,X).
1 pregunta(Atrib,Val):-
2 write(Atrib:Val),
3 write(’? ’),
4 read(si).
El predicado read/1 tendrá éxito sólo si el usuario responde “si” y falla si el usuario
responde cualquier otra cosa. Ahora el programa puede ser ejecutado sin datos de
trabajo iniciales. La misma llamada a ave/1 inicia la consulta al SE.
?- ave(X).
fosas:externas_tubulares? si.
habitat:mar? si.
pico:gancho? si.
tamano:grande? si.
alas:muy_largas? si.
color:blanco? si.
X = albratros_laysan
Yes.
98 �������� ��������
El problema con este enfoque es que si el usuario responde “no” a la última pre-
gunta, la regla para ave(albratros_laysan) falla, llevandonos a un backtracking. De
esta manera el SE nos preguntaría nuevamente información que ya sabe. De alguna
manera deberíamos implementar un predicado pregunta que recuerde lo pregunta-
do.
?- ave(X).
fosas:externas_tubulares? si.
habitat:mar? si.
pico:gancho? si.
tamano:grande? si.
alas:muy_largas? si.
color:blanco? no.
fosas:externas_tubulares? si.
habitat:mar? si.
pico:gancho? si.
tamano:grande? si.
alas:muy_largas? si.
color:obscuro? si.
X = albratros_patas_negras
Yes.
Definiremos un nuevo predicado conocido/3 que nos ayude a recordar las res-
puestas del usuario. Las respuestas no se guardarán directamente en memoria, sino
que serán guardadas dinámicamente con asserta/1 cuando pregunta provea infor-
mación nueva para el SE:
1 pregunta(A,V) :- conocido(si,A,V), !.
2
3 pregunta(A,V) :- conocido(_,A,V), !, fail.
4
5 pregunta(A,V) :-
6 write(A:V),
7 write’? : ’),
8 read(Resp),
9 asserta(conocido(Resp,A,V)),
10 Resp == si.
1 pregunta(A,V) :-
2 not(multivariado(A)),
3 conocido(si,A,V2),
4 V \== V2,
5 !,
6 fail.
Una guía sobre los valores válidos para un atributo se implementa con el predicado
menu_pregunta que trabaja de manera análoga a pregunta:
�.� �� ����� ������ 99
1 tamaño(X) :-
2 menu_pregunta(tamaño, X, [grande, mediano, pequeño]).
3 color(X) :-
4 menu_pregunta(color,X,[blanco,verde,cafe,negro]).
1 menu_pregunta(A,V,MenuLista) :-
2 write(’Cual es el valor para ’,
3 write(A), write(’? ’), nl,
4 write(MenuLista),nl,
5 read(Resp),
6 checar(Resp,A,V,MenuLista),
7 asserta(conocido(si,A,X)),
8 X == V.
9
10 checar(X,A,V,MenuLista) :-
11 member(X,MenuLista), !.
12
13 checar(X,A,V,MenuLista) :-
14 write(’Ese valor no es válido, intente nuevamente’), nl,
15 menu_pregunta(A,V,MenuLista).
1 meta(X) :- ave(X).
1 solucion :-
2 abolish(conocido,3),
3 define(conocido,3),
4 meta(X),
5 write(’La respuesta es: ’), write(X), nl.
6
7 solucion :-
8 write(’No se encontró una respuesta.’), nl.
100 �������� ��������
El predicado Prolog abolish/2 se usa para eliminar los hechos definidos previamen-
te con conocido/3, cada vez que una consulta se va a ejecutar. Esto permite al usuario
ejecutar solucion multiples veces en una sola sesión. El predicado define/2 permite
indicarle a Prolog que conocido estará definido en el SE, de forma que no cause error
la primera utilización de este predicado. Este predicado puede variar dependiendo
de la versión de Prolog utilizada.
De esta manera tenemos que el SE ha sido dividido en dos partes. Los predicados
en el shell son:
• solucion,
• pregunta,
• menu_pregunta,
• meta,
Para usar este shell en Prolog, tanto el shell como la base de conocimientos deben
ser cargados:
1 ?- consult(shell).
2 yes
3 ?- consult(’aves.kb’).
4 yes
5 ?- solucion.
6 fosas_nasales : externas_tubulares ? ...
�.�.� REPL
1 se :-
2 bienvenida,
3 repeat,
4 write(’> ’),
5 read(X),
6 do(X),
7 X == quit.
8
�.� �������������� ����� ����� ��� ������������� 101
se
pregunta
menu_pregunta
Máquina de inferencia
solucion
cargar
meta conocido
reglas
mulivaluado
preguntado
9 bienvenida :-
10 write(’Este es el shell de su SE.’), nl,
11 write(’Escriba: cargar, consultar, o salir en el prompt.’), nl
12
13 do(cargar) :-
14 cargar_bd, !.
15
16 do(consultar) :-
17 solucion, !.
18
19 do(salir).
20
21 do(X) :-
22 write(X),
23 write(’ no es un comando válido.’), nl,
24 fail.
25
26 cargar_bd :-
27 write(’Nombre del archivo: ’),
28 read(F),
29 reconsult(F).
mido que no hay incertidumbre, ni el los datos provistos por el usuario, ni en las
reglas de los expertos. Por ejemplo, el albatros puede ser observado en la bruma, con
lo que sería difícil precisar si su color es blanco u obscuro. Es de esperar que un SE
que maneje incertidumbre, pueda contender con este tipo de problemas.
Desarrollaremos un shell que permita manejar reglas con incertidumbre y encade-
namiento de ellas hacía atrás. Evidentemente, este SE tendrá un formato de reglas
propio, diferente a las reglas de Prolog, y por lo tanto, una máquina de inferencia
propia.
1 GOAL problema.
2
3 RULE 1
4 IF not arranca AND
5 bateria_mala
6 THEN problema is bateria.
7
8 RULE 2
9 IF luces_debiles
10 THEN bateria_mala cf 50.
11
12 RULE 3
13 IF radio_debil
14 THEN bateria_mala cf 50.
15
16 RULE 4
17 IF arranca AND
18 olor_gasolina
19 THEN problema is fuga cf 80.
20
21 RULE 5
22 IF arranca AND
23 indicador_gasolina is vacio
24 THEN problema is tanque_vacio cf 90.
25
26 RULE 6
27 IF arranca AND
28 indicador_gasolina is bajo
29 THEN problema is tanque_vacio cf 30.
30
31 ASK arranca
32 MENU (si no)
�.� �������������� ����� ����� ��� ������������� 103
39 ASK radio_debile
40 MENU (si no)
41 PROMPT ’Su radio está débil? ’.
42
43 ASK olor_gasolina
44 MENU (si no)
45 PROMPT ’Huele a gasolina?’.
46
47 ASK indicador_gasolina
48 MENU (vacio, medio, lleno)
49 PROMPT ’Que indica al aguja de gasolina? ’.
Por el momento la inferencia usaría encadenamiento hacía atrás, similar al que usa
Prolog. La regla GOAL indica que el proceso buscará un valor para problema. La
regla 1 causará que la sub-meta bateria_mala sea procesada, etc. Observen que las
reglas especifican también factores de certidumbre. Las reglas 2 y 3 proveen evidencia
de que la batería está en mal estado, pero ninguna es conclusiva al respecto.
Un diálogo con este sistema sería como sigue:
1 : consultar
2 ...
3 Huele a gasolina?
4 si cf 50
5 ...
MYCIN [5], uno de los SE más conocidos en IA, introduce factores de certidumbre
diseñados para producir resultados intuitivos desde la perspectiva de los expertos.
Revisemos el uso de estos factores por casos. El más simple, sería aquel donde las
premisas son totalmente ciertas:
1 arranca cf 100.
2 olor_gas cf 100.
1 arranca cf 80.
2 olor_gas cf 50.
Por ejemplo, si disparamos la regla 2 (luces débiles) con su premisa sin incerti-
dumbre, tendríamos que agregar al almacén de trabajo bateria_mala cf 50. Luego
si disparamos la regla 3 (radio débil), el factor de certidumbre de este hecho debe
modificarse a bateria_mala cf 75. Lo cual resulta intuitivo (hay más evidencia de
que la batería tiene problemas). Lo que también resulta intuitivo es que necesitamos
programar nuestra propia máquina de inferencia.
conclusion(Meta, CF).
premisas(ListaMetas).
av(Atributo, Valor).
1 regla(Nombre,
2 premisas( [av(A1,V1), av(A2,V2), ... ] ),
3 conclusion(av(Attr,Val), CF)).
1 regla(5,
2 premisas([av(arranca,si), av(indicador_gasolina,vacio)]),
3 conclusion(av(problema,fuga), 80)).
Estas reglas no son fáciles de leer, pero tienen una estructura adecuada para ser
procesadas por Prolog. Otras herramientas de Prolog como las gramáticas de cláusula
definitivas (DCG) o la definición de operadores, puede ayudarnos a simplificar esta
representación.
106 �������� ��������
Dado el formato de las reglas del SE deseamos que la inferencia tome en cuenta los
siguientes aspectos:
1 hecho(av(A,V),CF).
1 ?- meta(av(problema,X),CF).
Veamos ahora los tres casos para meta/2. El primero de ellos ocurre cuando la
información ya está en la memoria de trabajo:
1 meta(av(Atr,Val),CF) :-
2 hecho( av(Atr,Val), CF),
3 !.
1 meta(av(Atr,Val), CF) :-
2 \+ hecho( av(Atr,_),_),
3 pregunta(Atr,Msg),
4 preguntar(Atr,Msg),
5 !,
6 meta(av(Atr,Val), CF).
1 preguntar(Atr,Msg) :-
2 write(Msg),
3 read(Val),
4 read(CF),
5 asserta(fact(av(Atr,Val),CF)).
El tercer caso para meta/2 es cuando el valor del atributo es desconocido, pero se
puede deducir usando las reglas definidas en el sistema, en ese caso la llamada es:
1 meta(Meta,CFactual) :-
2 buscaReglas(Meta,CFactual).
Esta llamada hace uso de la máquina de inferencia que diseñaremos para nuestro
SE con incertidumbre. El factor de certidumbre se etiqueta como actual, porque es
posible que cambie de valor al ir aplicando las reglas definidas en el sistema.
El predicado buscaReglas/2 se encarga de encontrar aquellas reglas cuya conclu-
sión unifica con la Meta en cuestión y de actualizar el factor de certidumbre con base
en las premisas de estas reglas. Si la Meta es un hecho conocido, no hay nada que
hacer, sólo regresar true:
1 buscaReglas(Meta,CFactual) :-
2 regla(N, premisas(ListaPremisas),
3 conclusion(Meta,CF)),
4 probar(ListaPremisas,Contador),
5 ajustar(CF,Contador,NuevoCF),
6 actualizar(Meta,NuevoCF,CFactual),
7 CFactual == 100,
8 !.
9
10 buscaReglas(Meta,CF) :-
11 hecho(Meta,CF).
Dada una lista de premisas pertenecientes a una regla encontrada para satisfacer
la Meta del SE, es necesario que buscaReglas/2 las pruebe. Para ello definimos
probar/2:
1 probar(ListaPremisas, Contador) :-
2 probAux(ListaPremisas, 100, Contador).
3
4 probAux([],Contador,Contador).
108 �������� ��������
5 probAux([Premisa1|RestoPremisas],ContadorActual,Contador) :-
6 meta(Premisa1,CF,Cont),
7 Cont >= 20,
8 probAux(RestoPremisas,Cont,Contador).
5 int_redondear(X,I) :-
6 X >= 0,
7 I is integer(X + 0.5).
8
9 int_redondear(X,I) :-
10 X < 0,
11 I is integer(X - 0.5).
1 actualizar(Meta,NuevoCF,CF) :-
2 hecho(Meta,ViejoCF),
3 combinar(NuevoCF,ViejoCF,CF),
4 retract(hecho(Meta,ViejoCF)),
5 asserta(hecho(Meta,CF)),
6 !.
7
8 actualizar(Meta,CF,CF) :-
9 asserta(hecho(Meta,CF)).
10
11 combinar(CF1, CF2, CF) :-
12 CF1 >= 0,
13 CF2 >= 0,
14 X is CF1 + CF2*(100 - CF1)/100,
15 int_redondear(X,CF).
16
17
18 combinar(CF1,CF2,CF) :-
19 CF1 < 0,
20 CF2 < 0,
21 X is -( -CF1-CF2*(100+CF1)/100),
22 int_redondear(X,CF).
23
24 combinar(CF1,CF2,CF) :-
25 (CF1 < 0 ; CF2 < 0),
26 (CF1 > 0 ; CF2 > 0),
27 abs_minimum(CF1,CF2,MCF),
28 X is 100 * (CF1 + CF2) / (100 - MCF),
29 int_redondear(X,CF).
�.� �������������� ����� ����� ��� ������������� 109
1 se :-
2 repeat,
3 write(’consultar, cargar, salir’), nl,
4 write(’: ’),
5 read_line(X),
6 ejec(X),
7 X == salir.
8
9 ejec(consultar) :-
10 metas_principales,
11 !.
12
13 ejec(cargar) :-
14 cargar_reglas,
15 !.
16
17 ejec(salir).
18
19 %% % Auxiliares
20
21 metas_principales :-
22 meta_principal(Atr),
23 principal(Atr),
24 imprime_meta(Atr),
25 fail.
26 metas_principales.
27
28 principal(Atr) :-
29 meta(av(Atr,Val,CF)),
30 !.
31 principal(_) :- true.
32
33 imprime_meta(Atr) :-
34 nl,
35 hecho(av(Atr,Val), CF),
36 CF >= 20,
37 salidap(av(Atr,Val),CF), nl
38 fail.
39 imprime_meta(Atr) :-
40 write (’Meta: ’), write(Attr), write(’ solucionada.’),
41 nl, nl.
42
43 salidap(av(Atr,Val),CF) :-
44 output(Atr,Val,ListaImprimir),
45 write(Atr-’cf’-CF),
46 imprimeLista(ListaImprimir), !.
47 salidap(av(Atr,Val),CF) :-
48 write(Atr-Val-’cf’-CF).
49
110 �������� ��������
50 imprimeLista([]).
51 imprimeLista([X|Xs]) :-
52 write(X),
53 imprimeLista(Xs).