26
Control Prolog realiza, en forma general, una búsqueda por profundidad con “backtracking". Al intentar probar una meta (regla), busca primero probar la primera condición, después la segunda, etc. Si alguna es falsa, entonces falla dicha regla, e intenta la siguiente regla (si existe) para la misma meta. Hay ciertas formas de alterar la estrategia básica de búsqueda: CUT (!) - evita el “backtracking”, ejemplos: X:- a, b, c,!, d, e. % Predicados mutuamente exclusivos - escalón: esc(X,-1):- X < 0, !.

Control

Embed Size (px)

DESCRIPTION

Control - PowerPoint PPT Presentation

Citation preview

ControlProlog realiza, en forma general, una búsqueda por profundidad

con “backtracking". Al intentar probar una meta (regla), busca primero probar la primera condición, después la segunda, etc. Si alguna es falsa, entonces falla dicha regla, e intenta la siguiente regla (si existe) para la misma meta.

Hay ciertas formas de alterar la estrategia básica de búsqueda:

CUT (!) - evita el “backtracking”, ejemplos:

X:- a, b, c,!, d, e.

% Predicados mutuamente exclusivos - escalón:

esc(X,-1):- X < 0, !.esc(X, 0):- X = 0, !.esc(X, 1):- X > 0.

FAIL - siempre es falso (TRUE - siempre es verdadero)

Ejemplos:

impuesto(Persona,X):- desempleado(Persona),!,fail.impuesto(Persona,X):- ...

% Excepciones:

diferente(X,X):- !,fail.diferente(X,Y).

NOT - verdadero si no se puede probar la meta.Predicado predefinido que se podría definir como:

not(P):- P,!,fail.not(P).

Búsqueda con Información

Podemos extender los algoritmos básicos de búsqueda (DF y BF) considerando que tenemos información para seleccionar el camino.

Primero consideremos extender el algoritmo de búsqueda por profundidad a “hill-climbing”. Para ello tendríamos que hacer 3 modificaciones principales al algoritmo:

1. Generar una función de evaluación para cada estado, la cual es dependiente de la aplicación.

2. Ordenar la lista de estados de acuerdo a la evaluación.

3. Dejar sólo el primer elemento en la lista.

Para “best-first” y “beam-search” seria algo similar, excepto la tercera modificación. En el primero dejaríamos todos los elementos en la lista, y en el segundo se dejarían “N”.

Ordenamiento de Listas: Una solución es insertar el elemento en el lugar que le corresponde:

sort([H|T],L0) :-sort(T,T0),insertao(H,T0,L0).

sort([ ],[ ]).

insertao (H, E] , [H]).insertao(H,[F|T],[F|R]) :-

H > F,insertao(H,T,R).

insertao(H,[F|R],[H,F|R]) :-H =< F.

Todavía más eficiente es hacer quicksort (¡.e., dividir en menores y mayores a un cierto elemento, ordenarlos y juntarlos todos).

qsort ([H|T] , L0) :-divide(H,T,Men,May),qsort(Men,Men0),qsort(May,May0) ,agrega(Men0,[H|May0],L0).

qsort([ ],[ ]).

divide(El,[H|T],[H|Men],May) :-El >= H,divide(El,T,Men,May).

divide(E1,[H|T],Men,[H|May]) :-El < H,divide(El,T,Men,May).

divide(_,[ ],[ ],[ ]).

Ejercicio:

Para el problema del “bloque deslizante” asume que hay cierto costo dependiendo del movimiento:

- No salta - costo=1- Salta una - costo=2- Salta dos - costo=3

a) Plantear como podrías extender tu programa para considerar esta información (técnica de búsqueda con información)

b) Proponer una heurística para estimar el costo faltante y analizarla.

busca(NI,NF):-encuentra([NI/0],NF/EF).

encuentra([NF|_ ],NF).encuentra(Agenda, NF) :-

n-agenda(Agenda, Nagenda),write(Nagenda),nl, encuentra(Nagenda, NF).

n-agenda([NI|Agenda], 0agenda) :-expande(NI, Nodos),agrega(Nodos, Agenda, Nagenda), /* por profundidad */qsortb(Nagenda, 0agenda). /* ordena estados */

agrega([ ],L,L).agrega([H|L1],L2,[H|L3]):-

agrega(Ll,L2,L3).

% Quicksort para búsqueda con información: dividir en menores% y mayores a un cierto elemento, ordenarlos y juntarlos todos.% Cada elemento incluye el estado y su valor [Estado,Valor]

qsortb([H|T],L0) :-divide(H,T,Men,May),qsortb(Men,Men0),qsortb(May,May0),agrega(Men0,[H|May0],L0).

qsortb( [ ] , [ ] ) .

divide( S1/El,[S2/H|T],[S2/H|Men],May) :-El >= H,

divide(S1/El,T,Men,May).divide([S1/El,[S2/H|T],Men,[S2/H|May]) :-

El < H,divide(S1/El,T,Men,May).

divide(_ , [] , [] , [] ) .

% Concatena dos listasagrega([],L,L).agrega([H|L1],L2,[H|L3]):- agrega(L1,L2,L3).

% expande: ejemplo de rutas con evaluación

expande(N,LN):- dist(N,LD),acum(N,LD,LN).

% calcula distancia acumulada

acum(X,[],[]).acum(N/Dp,[X/D|Otros],[X/Da|Mas]) :-

Da is D + Dp, acum(N/Dp,Otros,Mas).

dist(a/Da,[b/3, c/2, d/4]). % nodos (ciudades)dist(d/Da,[z/1]). % con sus destinosdist(c/Da,[e/3, f/5]). % y distanciasdist(e/Da,[z/2]).dist(b/Da,[])

Ejemplo de pregunta-

? - busca(a,z).[c /2, b/3, d/4][b/3, d/4, e/5, f/7][d/4, e/5, f/7][e/5, z/5, f/7][z/5, f/7, z/7]yes

Si queremos agregar una heurística de distancia faltante (Subestimación), simplemente habría que calcularla y sumarla a la distancia acumulada.

Predicados Predefinidos

Entrada - Salida

Desplegar en la terminal:write(X).

Si "X" esta instanciada se despliega su valor, si no se despliega un identificador.

Saltar al sig. renglón: nl.

Leer del teclado: read(X).

Si "X" no esta instanciada se instancia al valor leído, si no se compara el valor que tiene con el leído y falla si son diferentes.

Cargar predicados de un archivo:consult (archivo).

Cargar substituyendo predicados repetidos:reconsult(archivo).

Estos predicados sólo se ejecutan una vez (no backtrcking).

Clasificación de términos

Checar si un término es una variable no instanciada:var(X).

Ejemplo:var(X), X=5.X=5, var(X).

El contrario es:nonvar(X). % no es una variable no instanciada

Checar si un término es un "átomo":atomo(X).

Ejemplos de átomos: juan, manzana, x, '/user/prog', 'X',

Checar si un variable es un número entero:integer(X).

Es "atómica" si es un número o átomo:atomic(X).

Listar una cláusula:listing(sort). % listar todas "listing".

Algoritmo MiniMax

A continuación veremos una implementación básica de “minimax” en Prolog. La función principal es dado un estado en el juego (Pos) desde el punto de vista de “Max", obtener el mejor movimiento a realizar (MejMov) y su valor estimado de acuerdo al algoritmo (Valor).

minimax(Pos,MejMgv,Valor) :-jugadas(Pos,ListaPos),! ,mejor(ListaPos,MejMov,Valor). % Obtener mejor

% evaluandominimax(Pos,MejMov,Valor):- % el árbol

evalua(Pos,Valor). % Si no hay sucesores,%

evalúa directo

mejor([Pos],Pos,Valor) :- % Una posible, evaluaminimax(Pos,_,Valor).

mejor([Posl | ListaPos] ,MejPos,MejValor) :- % Dos o mas,minimax(Posl,_,Valorl), % compara recursivo mejor(ListaPos ,Pos2,Valor2),compara(Posl ,Valorl ,Pos2 ,Valor2 ,MejPos ,MejVal).

compara(Posl,Valor1,Pos2,Valor2, Posl,Valor1) :- % 1 mejor que 2min(Posl), % Mueve MinValor0 < Valor1, ! .

compara(Posl,Valorl, Pos2,Valor2, Posl, Valorl) :- % 1 mejor que 2max(Posl), % Mueve MaxValor4 > Valor1, ! .

compara(Posl,Valorl,Pos2,Valor2,Pos2,Valor2). % 2 mejor que 1

Los predicados "jugadas" (obtener siguientes movimientos posibles), "evalua" (evaluación estática de una posición), y “min" y "max" (checar si mueve Min o Max) dependen del juego.

Manipulación de la Base de Datos

Un programa en Prolog se puede ver como una "base de datos", de forma que ésta puede ser modificada dinámicamente agregando y borrando cláusulas. Para ello existen varios predicados predefinidos:

assert: agregar una cláusula a la base de datosasserta: agregar una cláusula al inicio de la base de datosassertz: agregar una cláusula al final la base de datosretract: borra una cláusula de la base de datos

Ejemplos:

assert(padre(juan,rita)).retract(padre(juan,rita)).

Estas facilidades son muy poderosas y útiles en algunas aplicaciones, pero hay que usarlas con cuidado ya que en realidad se esta modificando el programa resultando en que en diferentes momentos puede dar diferentes resultados.

Sistemas Expertos en Prolog

Es casi directo implementar un sistema de reglas de producción en Prolog, ya que las cláusulas de Prolog se pueden ver como reglas y el interprete de Prolog como una máquina de inferencia que realiza encadenamiento hacia atrás y búsqueda por profundidad.

El ejemplo del sistema experto para créditos bancarios podría codificarse como el siguiente programa en Prolog:

prest (X,C) :-solv(X,C),hist(X,C),ref(X,C).

hist (X,C) :-tarjeta(X,T1),tarjeta(X,T2), T1 \= T2.

hist (X,C):-prestamo(X,casa).

hist (X,C):-prestamo(X,carro).

solv (X,C):-ing(X,I), P is 3 * C / 10, I > P.

ref (X,C) :-refer(X,Y), refer(X,Z), refer(X,W), Y\=Z, Z\=W.

% Un caso:prestamo(juan, carro) .ing(juan,100).refer(juan,pedro).refer(juan,maria).refer(juan,sol).

Sin embargo, es mejor implementar un interprete (shell) que realice el proceso de inferencia y ver las reglas y datos como cláusulas unitarias (sin condiciones). Esto es por varias razones:

- Para tener una más clara separación entre la base de conocimientos, la máquina de inferencia y los datos (memoria de trabajo).- Para poder alterar las estrategias de inferencia (Ej. encadenamiento hacia adelante) y de control (resolución de conflicto). - Para agregar otros aspectos como manejo de incertidumbre y otras representaciones

Interprete para reglas

Fácilmente podemos implementar un interprete de reglas con la misma estrategia de Prolog -encadenamiento hacia atrás por profundidad.

% Shell mínima:experto(no(Meta)) :-

not (experto (Meta)).experto(Meta) :-

dato(Meta).experto(Meta) :-

regla(Meta,Condiciones),experto(Condiciones).

experto((Cond1,Cond2)) :-experto(Cond1),

experto(Cond2).experto(Meta) :-

system(Meta), ! ,Meta.

% predicados del sistema:

system(X > Y).system(X is Y).system(X * Y).system(X / Y).system(X = Y).

% B de C de creditos:

regla(prest(X,C) , (solv(X,C) , hist(X,C) , ref(X))). regla(hist(X,C) , (tarjeta(X,T1) , tarjeta(X,T2), T1\=T2)). regla(hist(X,C) , (prestamo(X,cas))). regla(hist(X,C) , (prestamo(X,carr))).regla(solv(X,C) , (ing(X,I) , P is 3 * C / 10, I > P)). regla(ref(X,C) , (refer(X,Y) , refer(X,Z) , refer(X,W) , Y\=Z,

Z\=W ) ).

% Memoria de trabajo:

dato(prestamo(juan,carro)).dato(ing(juan,100)).dato(refer(juan,pedro)).dato(refer(juan,maria)).dato(refer(juan,sol)).