Programas mutantes: manipulación de la base de

Anuncio
Programas mutantes: manipulación de la base de
conocimiento
1 / 30
Programas mutantes
Una de las razones por las que Prolog está tan ligado a la
inteligencia artificial es por su capacidad para permitir que los
programas se modifiquen a sı́ mismos.
Un programa es un conjunto de reglas que representan
conocimiento... si el programa puede modificarse a sı́ mismo,
entonces puede aprender (?)
Muchas de las expectativas en el ámbito de la inteligencia
artificial de los años 70 han quedado relegadas al olvido...
inteligencia, aprendizaje, son términos complejos (y hasta
polémicos).
Pero Prolog sigue joven y en activo!!
Hacer que un programa se auto-modifique sigue teniendo
aplicaciones algorı́tmicas interesantes, versátiles y muy útiles.
2 / 30
Acceso al programa desde el programa
Un programa Prolog es un conjunto de cláusulas (hechos,
reglas).
Podrı́amos concebir predicados para introducir una nueva
cláusula en el programa o eliminar una cláusula existente
predicados para la modificación dinámica del programa.
Prolog proporciona esos predicados: assert, retract.
Son predicados metalógicos (igual que el corte o la negación,
su semántica es extra-lógica), pero son sencillos de utilizar... y
muy útiles!
Nota: estos predicados pueden utilizarse para simular variables
globales y asignación. En general es una mala práctica en
programación lógica y conduce a programas mal diseñados,
difı́ciles de entender y de mantener.
3 / 30
Manipulación de la base de conocimiento (programa)
El predicado listing muestra las cláusulas de programa (las
definidas por el usuario).
Si arrancamos el intérprete y resolvemos:
?- listing.
...
Yes
?-
Es decir, la base de conocimiento está vacı́a (no hay ninguna
regla de programa).
Si ahora hacemos (desde el prompt de Prolog):
?- assert(guapa(sara)).
habremos introducido la cláusula (hecho):
guapa(sara).
4 / 30
Manipulación del programa II
Ahora:
?- listing.
...
guapa(sara).
Introducimos más hechos:
?- assert(guapa(laura)), assert(guapa(ana)),
assert(guapa(maria)), guapa(sara).
Ahora:
?- listing.
...
guapa(sara).
guapa(laura).
guapa(ana).
guapa(maria).
guapa(sara).
(Ojo: sara es guapa “dos veces”, porque se ha asertado dos
veces ese hecho)
5 / 30
Manipulación del programa III
Hasta ahora hemos introducido solo hechos, pero también
podemos asertar reglas:
?- assert((lista(X):-guapa(X))).
X = G180
Yes
?- listing.
guapa(sara).
guapa(laura).
guapa(ana).
guapa(maria).
guapa(sara).
lista(A) :- guapa(A).
6 / 30
Manipulación del programa IV
Este proceso serı́a equivalente a escribir en un archivo los hechos y
la regla anteriores y haber hecho la consulta de dicho archivo.
Podemos también eliminar cláusulas:
?- retract(guapa(sara)), retract(guapa(ana)).
?- listing.
guapa(laura).
guapa(maria).
guapa(sara).
lista(A) :- guapa(A).
Se ha eliminado el primer hecho “guapa(sara)” y
“guapa(ana)”.
Para eliminar todos los hechos “guapa(...)” harı́amos:
?- retract(guapa(X)).
?- listing.
lista(A) :- guapa(A).
7 / 30
Más control sobre los asserts y retracts
asserta(+C)::= aserta la cláusula C al principio de la base de
conocimiento
assertz(+C)::= aserta la cláusula C al final de la base de
conocimiento
retractall(+Head)::= elimina todas las cláusulas cuya cabeza
unifique con Head
record[a,z,ed](. . . ), abolish(. . . ): consultar manual de Prolog.
8 / 30
Memoization or caching: almacenando conocimiento.
Supongamos que definimos el siguiente predicado:
tabla(L) :member(X,L), member(Y,L), V is X*Y,
assert(mult(X,Y,V)), fail.
Y supongamos que resolvemos el siguiente objetivo:
?- tabla([1,2,3,4,5,6,7,8,9]).
Qué efecto tiene?
toma dos elementos X e Y de la lista [1,2,3,4,5,6,7,8,9]
calcula su producto X*Y en V
aserta un hecho mult(X,Y,V)
falla...
y por backtraking vuelve a tomar otros dos elementos, etc
9 / 30
Memoization or caching II
El objetivo falla, pero como efecto lateral obtenemos una colección
de hechos mult(X,Y,V) que contienen la tabla de multiplicar que
aprendiamos en el cole.
Para qué puede ser esto útil?
Guardar la tabla de multiplicar no ofrece muchas ventajas:
cuesta poco calcular el producto de dos números.
Pero esta misma técnica puede ser útil para almacenar
cómputos más complejos y evitar reevaluaciones.
10 / 30
Fibonacci revisitado
:- dynamic tab fib/2.
tab fib(0,1).
tab fib(1,1).
fibTabulado(N,F):- tab fib(N,F), !.
fibTabulado(N,F):- N1 is N-1, N2 is N-2,
fibTabulado(N1,F1), fibTabulado(N2,F2),
F is F1+F2, assert(tab fib(N,F)).
La declaración :- dynamic tab fib/2. indica que el predicado tab fib
de aridad 2 es dinámico, i.e., es susceptible de cambiar durante la
ejecución (por medio de assert/retract).
Los hechos tab fib(0,1). y tab fib(1,1). tabular el valor de los dos
primeros términos de la serie.
El predicado fibTabulado(N,F) calcula el valor del N-ésimo término
de la serie utilizando tabulación o caching o memoization, es decir,
utilizando la tabla.
11 / 30
Fibonacci revisitado (II)
Veamos en detalle:
fibTabulado(N,F):- tab fib(N,F), !.
fibTabulado(N,F):- N1 is N-1, N2 is N-2,
fibTabulado(N1,F1), fibTabulado(N2,F2),
F is F1+F2, assert(tab fib(N,F)).
Para resolver fibTabulado(N,F):
la primera cláusula comprueba si ese valor está tabulado. Si es
ası́, devuelve ese valor de la tabla y corta la búsqueda (no hay
más que calcular).
Si ese valor aún no esta tabulado (segunda cláusula):
Lo calcula en F, que es el valor de devolución
pero además lo aserta como un nuevo hecho tab fib(N,F), de
modo que si vuelve a necesitarse ese valor no se calculará de
nuevo, sino que se obtendrá de la base de conocimiento
mediante la primera cláusula.
12 / 30
Descargar