11.07.2015 Views

PROLOG Inteligencia Artificial Universidad de Talca, II Semestre ...

PROLOG Inteligencia Artificial Universidad de Talca, II Semestre ...

PROLOG Inteligencia Artificial Universidad de Talca, II Semestre ...

SHOW MORE
SHOW LESS

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

<strong>PROLOG</strong><strong>Inteligencia</strong> <strong>Artificial</strong><strong>Universidad</strong> <strong>de</strong> <strong>Talca</strong>, <strong>II</strong> <strong>Semestre</strong> 2005Jorge Pérez R.1


Introducción a <strong>PROLOG</strong><strong>PROLOG</strong> es un lenguaje interpretado basado en la lógica<strong>de</strong> predicados <strong>de</strong> primer or<strong>de</strong>n.Pue<strong>de</strong> ser visto como un lenguaje <strong>de</strong> programación o comoun <strong>de</strong>mostrador mecánico <strong>de</strong> teoremas.Fue implementado a principios <strong>de</strong> los años 70 por Alain Colmerauery junto con Lisp son los lenguajes que históricamentese han utilizado para construir aplicaciones en gran parte <strong>de</strong>las ramas <strong>de</strong> IA.Hoy existen muchas implementaciones <strong>de</strong> <strong>PROLOG</strong>, la quenosotros usaremos es SWI-Prolog <strong>de</strong>sarrollado en la <strong>Universidad</strong><strong>de</strong> Amsterdam. Es una versión libre y pue<strong>de</strong> ser <strong>de</strong>scargadapara distintos ambientes.http://www.swi-prolog.org2


LPOP a la rápida...(supondremos cierta familiaridad con el tema)A gran<strong>de</strong>s razgos la lógica <strong>de</strong> predicados <strong>de</strong> primer or<strong>de</strong>n(LPOP) es un lenguaje formal para expresar cierta parte <strong>de</strong>llenguaje matemático.Sus componentes principales son los predicados (atributos,relaciones), constantes, variables, y cuantificadores (∀, ∃).Ejemplo:“Todos los hombres son mortales,y dado que Sócrates es un hombre,po<strong>de</strong>mos concluir que Sócrates es mortal.”Po<strong>de</strong>mos mo<strong>de</strong>larla con la siguiente fórmula:(∀X(hom(X) → mor(X)) ∧ hom(socrates)) → mor(socrates)que es una fórmula <strong>de</strong> LPOP don<strong>de</strong> hom y mor son predicados,X es una variable cuantificada y socrates es unaconstante... la fórmula resulta ser siempre verda<strong>de</strong>ra.Des<strong>de</strong> otro punto <strong>de</strong> vista podríamos pensar en la mismafórmula anterior pero en un esquema <strong>de</strong> consulta don<strong>de</strong>:1. ∀X(hom(X) → mor(X))2. hom(socrates)son oraciones, yQ: ¿mor(socrates)?es una consulta.Luego si suponemos las oraciones 1 y 2 como hechos verda<strong>de</strong>ros,y preguntamos por la consulta Q, la respuesta <strong>de</strong>bieraser SI.<strong>PROLOG</strong> sigue un esquema similar <strong>de</strong> hechos y consultas.3


<strong>PROLOG</strong><strong>PROLOG</strong> es un lenguaje interpretado que nos permite especificarhechos y reglas, similares a los <strong>de</strong> LPOP, y luegohacer consultas sobre ellos.El interprete presenta un prompt para iteractuar ?-.La interacción con el interprete es a partir <strong>de</strong>l ingreso <strong>de</strong>hechos y reglas <strong>de</strong> manera directa?- [user].|: aquí se ingresan los hechos y reglas uno a uno...o cargando <strong>de</strong>s<strong>de</strong> un archivo?- [’ejemplo.pl’].Don<strong>de</strong> ’ejemplo.pl’ es el nombre <strong>de</strong> un archivo con los hechosy reglas a cargar.El prompt siempre está a la espera <strong>de</strong> consultas a respon<strong>de</strong>r.Veremos con ejemplos las distintas formas <strong>de</strong> interacción ylos conceptos fundamentales <strong>de</strong> <strong>PROLOG</strong>.4


HechosLos hechos son el tipo básico <strong>de</strong> oraciones <strong>de</strong> un programa<strong>PROLOG</strong>. Supongamos que queremos mo<strong>de</strong>lar informacióngenealógica acerca <strong>de</strong> un grupo <strong>de</strong> personas. Para estoutilizaremos los predicados o relaciones padre y madre sobreciertas constantes.padre(juan, amanda).madre(ximena, amanda).madre(laura, juan).padre(andres, juan).padre(patricio, bonifacio).padre(juan, patricio).padre(juan, ana).madre(ximena, ana).Esto lo po<strong>de</strong>mos ingresar haciendo?- [user].|: padre(juan, amanda).|: madre(ximena, amanda).|: ....o cargando <strong>de</strong>s<strong>de</strong> un archivo?- [’genealogico.pl’].Los hechos anteriores representan un mo<strong>de</strong>lamiento <strong>de</strong>l mundoen don<strong>de</strong>, por ejemplo “Juan es el padre <strong>de</strong> Amanda”.Algunas observaciones <strong>de</strong> sintaxis: los hechos son predicadosinstanciados en valores constantes, en nuestro caso juan yamanda son valores constantes.En <strong>PROLOG</strong> siempre las constantes comienzan con minúscula,según esto la oración padre(Juan, Ana) no sería un hecho<strong>de</strong> <strong>PROLOG</strong> más a<strong>de</strong>lante veremos qué significa.5


ConsultasDados los hechos agregados al interprete <strong>PROLOG</strong>, po<strong>de</strong>moshacer consultas como por ejemplo?- madre(ximena,ana).Yes?- padre(juan, ximena).NoLos Yes y No son las respuestas que entrega <strong>PROLOG</strong> luego<strong>de</strong> presionar [enter]. Note que son consistentes con los hechosagregados.Consultas más interesantes involucran el uso <strong>de</strong> variables (enel sentido <strong>de</strong> la lógica LPOP que es distinta al <strong>de</strong> una variableusual <strong>de</strong> un lenguaje <strong>de</strong> programación).Todas las variables en <strong>PROLOG</strong> comienzan con mayúsculas.¿Cuál pue<strong>de</strong> ser el significado <strong>de</strong> la siguiente consulta??- padre(X, juan).En la anterior consulta X representa a una variable y juan aun valor constante.Cuando aparece una variable en una consulta, <strong>PROLOG</strong> lainterpreta cómo una pregunta existencial, o sea sería equivalentea la consulta en LPOP¿∃X padre(X, juan)?Entonces la respuesta <strong>de</strong> <strong>PROLOG</strong> <strong>de</strong>biera ser Yes segúnnuestros hechos, pero la respuesta va más allá...?- padre(X, juan).X = andres6


Consultas (cont.)La respuesta fue X = andres porque <strong>PROLOG</strong> <strong>de</strong>terminó quesi la variable X se reemplazaba por el valor constante andresla consulta era verda<strong>de</strong>ra a partir <strong>de</strong> los hechos. En este caso<strong>PROLOG</strong> respon<strong>de</strong> más que sólo Yes o No.En el ejemplo anterior <strong>de</strong>spués <strong>de</strong> respon<strong>de</strong>r X = andres PRO-LOG espera una acción <strong>de</strong>l usuario, este pue<strong>de</strong> preionar [enter]o digitar ; obteniendo las siguientes respuestas:?- padre(X, juan).X = andresYessi presiona [enter], o?- padre(X, juan).X = andres;Nosi digita ;.Para respon<strong>de</strong>r consultas <strong>PROLOG</strong> realiza un proceso <strong>de</strong>búsqueda entre los valores constantes y los predicados.Si digitamos ; se le pi<strong>de</strong> a <strong>PROLOG</strong> que siga buscando, sien el proceso <strong>de</strong> búsqueda <strong>PROLOG</strong> no encuentra un valorconstante para satisfacer la consulta la respuesta final es No,por ejemplo?- madre(ximena, X).X = amanda;X = ana;No7


Consultas (cont.)También se pue<strong>de</strong>n hacer consultas que involucren más <strong>de</strong>una variable.?- madre(X,Y).X = ximena,Y = amandaYesDel mundo mo<strong>de</strong>lado por nuestros hechos es fácilmente <strong>de</strong>ducibleque “el abuelo paterno <strong>de</strong> Ana es Andrés”. ¿cómopo<strong>de</strong>mos consultar esto en <strong>PROLOG</strong>?Primero, sabemos que “Andrés es el abuelo paterno <strong>de</strong> Ana”porque entre nuestros hechos existen los hechospadre(andres,juan).padre(juan,ana).La consulta a <strong>PROLOG</strong> <strong>de</strong>biéramos hacerla pensando en preguntarsi existe un abuelo paterno para ana, dado que si estoefectivamente ocurre <strong>PROLOG</strong> respon<strong>de</strong>rá Yes y a<strong>de</strong>más entregarála constante que hace verda<strong>de</strong>ra la consulta.Si lo miramos en LPOP la consulta <strong>de</strong>biera ser algo como¿∃Z(∃X(padre(Z, X) ∧ padre(X, ana)))?En <strong>PROLOG</strong> se sigue exactamente la misma i<strong>de</strong>a:?- padre(Z,X), padre(X,ana).Z = andresX = juanYesEn <strong>PROLOG</strong> el símbolo ‘,’ representa al conector <strong>de</strong> conjunciónlógico ∧.Si no nos interesa el valor <strong>de</strong> X po<strong>de</strong>mos usar la variable X.8


ReglasLas reglas en <strong>PROLOG</strong> son oraciones que nos permiten <strong>de</strong>ducirinformación.Su correspon<strong>de</strong>ncia en LPOP son las cláusulas <strong>de</strong> Horn<strong>de</strong>finitivas.En nuestro primer ejemplo <strong>de</strong> LPOP teníamos1. ∀X(hom(X) → mor(X))2. hom(socrates).La oración 2 pue<strong>de</strong> representarse por hom(socrates), ¿y 1?Un tipo especial <strong>de</strong> oración en <strong>PROLOG</strong> son las reglas quesirven para representar consecuencia lógica.En <strong>PROLOG</strong> se usan los caracteres ‘:-’ en correspon<strong>de</strong>nciacon el ← lógico.La reglamor(X) :- hom(X).es la representación en <strong>PROLOG</strong> <strong>de</strong> 1.<strong>PROLOG</strong> impĺıcitamente supone cuantificación universal (∀)en todas las variables utilizadas en una regla particularAsí, si ingresamos el programa <strong>PROLOG</strong>hom(socrates).mor(X) :- hom(X).obtenemos respuestas como?- mor(socrates).Yes9


Predicados a partir <strong>de</strong> ReglasEn nuestro ejemplo <strong>de</strong> información genealógica nos gustaríacontar con información <strong>de</strong> los abuelos (diferenciando el sexo).Queremos tener un predicado abuelo(X,Y) que sea verda<strong>de</strong>rocuando X sea abuelo <strong>de</strong> Y.Esta información pue<strong>de</strong> ser <strong>de</strong>ducida <strong>de</strong>s<strong>de</strong> los hechos, lomenos práctico sería agregar nuevos hechos, mucho mejoragregamos reglas...abuelo(X,Y) :- padre(X,Z), padre(Z,Y).abuelo(X,Y) :- padre(X,Z), madre(Z,Y).Ahora po<strong>de</strong>mos preguntar quién es abuelo <strong>de</strong> quién?- abuelo(X,Y).X = andres, X = andres,Y = amanda ; Y = ana ;X = andres, X = juan,Y = patricio ; Y = bonifacio ;NoLa regla anterior se podría haber <strong>de</strong>finido también comoabuelo(X,Y) :- padre(X,Z), (padre(Z,Y); madre(Z,Y)).El símbolo ‘;’ representa la disyunción ∨, el “o” lógico.Ejercicio: <strong>de</strong>fina la relación herm(X,Y) para representar que Xe Y son hermanos.10


Predicados RecursivosLas reglas también pue<strong>de</strong>n ser recursivas... tendrán la forma<strong>de</strong> una <strong>de</strong>finición recursiva usual <strong>de</strong> matemáticas.Queremos <strong>de</strong>finir la relación ancestro(X,Y) con el sentido genealógicousual.Para esto <strong>de</strong>finimos un predicado para la relación ancestroDirecto.ancestroDirecto(X,Y) :- (padre(X,Y); madre(X,Y)).que representa el caso base <strong>de</strong> la <strong>de</strong>finición recursiva.Luego <strong>de</strong>finimos la relación ancestro a parir <strong>de</strong>l caso base yuna recursión:ancestro(X,Y):- ancestroDirecto(X,Y).ancestro(X,Y):- ancestroDirecto(X,Z), ancestro(Z,Y).Así obtenemos?- ancestro(X,Y).X = juan, X = andres,Y = amanda ; Y = juan ;......Ejercicio: mo<strong>de</strong>le un grafo dirigido usando constantes paralos nodos (u,v, etc.) y un predicado e(U,V) para indicar lasaristas. Un grafo particular resultará <strong>de</strong> los hechos que agreguea <strong>PROLOG</strong>.• Defina un predicado camino(U,V) para <strong>de</strong>terminar si existeun camino dirigido entre dos nodos U y V.• Defina un predicado ciclo(U) para <strong>de</strong>terminar si en el grafohay un ciclo dirigido que contenga al nodo U.• ¿Pue<strong>de</strong> <strong>de</strong>finir un predicado ciclo (sin argumentos)? ¿Y unpredicado caminoNoDirigido(U,V) para <strong>de</strong>terminar si existeun camino entre U y V que no toma en cuenta la dirección<strong>de</strong> las aristas?11


Sintaxis y SemánticaLos eleméntos sintácticos básicos <strong>de</strong> un programa <strong>PROLOG</strong>son constantes, variables, functores y predicados.Los predicados son los elementos más importantes y ha sidoel centro <strong>de</strong> nuestra discusión anterior. Cada predicado tienecierta aridad (cantidad <strong>de</strong> argumentos). Si el predicado p tienearidad m escribiremos p/m. A cada predicado en <strong>PROLOG</strong>se le asocia un valor <strong>de</strong> verdad Yes o No.Las constantes pue<strong>de</strong>n ser:• Símbolos que comienzan con letra minúscula, por ej. x, y,abc, etc., símbolos encerrados en comillas simples, por ej.’X’, ’5’, ’x23’, ’a’, etc.• Números: enteros y/o reales, por ej. 4, 4.5, etc.• Caracteres y textos (strings): Los caracteres y los stringsse encierran entre comillas dobles, por ej. "f", "fam", etc.Las variables son símbolos que comienzan con mayúsculas oun un<strong>de</strong>rscore, por ej. X, x23, etc. La variable representadapor el símbolo es especial, ya veremos su significado.Los functores representan a funciones, son similares sintácticamentea los predicados con la diferencia <strong>de</strong> que a ellos seles asocia un objeto en vez <strong>de</strong> un valor <strong>de</strong> verdad (no seconsulta por un functor). Si f es un functor y m es su arida<strong>de</strong>scribiremos f/m. Veremos que los functores nos sirven porejemplo para crear estructuras <strong>de</strong> datos en <strong>PROLOG</strong>.Estos tres últimos tipos <strong>de</strong> elementos se llaman términos.Diremos que un literal es un elemento <strong>de</strong> la formap(t1,t2,...,tm)don<strong>de</strong> p/m es un predicado y cada ti es un término.12


Programas y ConsultasUn programa <strong>PROLOG</strong> está compuesto por un conjunto <strong>de</strong>reglas <strong>de</strong> la formal0 :- l1, l2, ..., ln.don<strong>de</strong> cada li es un literal.Los hechos pue<strong>de</strong>n verse como reglas don<strong>de</strong> sólo existe elliteral <strong>de</strong> más a la izquierda (l0:-. o simplemente l0.).Por ejemplo un programa sería:padre(juan, amanda).padre(andres, juan).abuelo(X,Y) :- padre(X,Z), padre(Z,Y).bisabuelo(X,Y) :- abuelo(X,Z), padre(Z,Y).Una consulta <strong>PROLOG</strong> es simplemente una conjunción <strong>de</strong>literales (literales separados por comas)g1, g2, ..., gm.Los literales que aparecen en la consulta se llaman objetivosEl interprete <strong>de</strong> <strong>PROLOG</strong> recibe como entrada un programamás una consulta. La salida será Yes si a partir <strong>de</strong>l programafue posible <strong>de</strong>mostrar la consulta haciendo verda<strong>de</strong>ro simultáneamentetodos sus objetivos, y No en el caso contrario.Al <strong>de</strong>mostrar un objetivo el interprete usa los conceptos <strong>de</strong>sustitución y unificación.13


Sustitución y UnificaciónUna sustitución es simplemente un mapeo entre variables ytérminos, por ejemplo{X = juan, Y = amanda}es una sustitución.Dada una sustitución esta pue<strong>de</strong> ser aplicada a un literal. Sil es un literal y θ una sustitución diremos que lθ es el literalque resulta <strong>de</strong> l al cambiar sus variables según el mapeoindicado por θ, por ejemplo:padre(X,Y){X = juan, Y = amanda}correspon<strong>de</strong> al términopadre(juan,amanda)Se dice que una sustitución θ unifica a dos literales l1 y l2 siocurre que l1θ es igual caracter a caracter a l2θ (a vecesusaremos ≡ para referirnos a esta igualdad).Por ejemplo, los literales padre(X,ana) y padre(juan,Y) sonunificados por la sustitución {X = juan, Y = ana} ya queypadre(X,ana){X = juan, Y = ana}padre(juan,Y){X = juan, Y = ana}resultan ambos ser padre(juan, ana).En algunos casos hay más <strong>de</strong> una sustitución que unifica aun par <strong>de</strong> literales, ej. padre(X,ana) y padre(Y,Z)¿Cuál podría ser el unificador para el par <strong>de</strong> literales padre(X,ana)y padre(Y,X)? ¿Hay más <strong>de</strong> uno? ¿Y para el par padre(X,ana)y padre(Y,juan)?14


Sustitución y Unificación (cont.)El proceso <strong>de</strong> unificación pue<strong>de</strong> ser llamado en <strong>PROLOG</strong>directamente usando el operador ‘=’?- padre(Y,ana)=padre(Z,X).Y = _G339X = _G339Z = anaYesAquí <strong>PROLOG</strong> respon<strong>de</strong> con Y = G339 y X = G339 queriendo<strong>de</strong>cir que los valores para Y y X pue<strong>de</strong>n ser cualquiera siemprey cuando sean iguales.Otros ejemplos:?- p(X,b,Z)=p(a,Y,f(T)).X = aZ = f(_G155)Y = bT = _G155Yes?- p(X)=q(a).NoNote que en el primer ejemplo impĺıcitamente se supone quef/1 <strong>de</strong>be ser un functor.15


¿Qué Hace el Interprete <strong>PROLOG</strong>?Como ya mencionamos, el interprete <strong>de</strong> <strong>PROLOG</strong> recibe unprograma y una consulta como entrada:g1, g2, ..., gmDes<strong>de</strong> el punto <strong>de</strong> vista DECLARATIVO el interprete respon<strong>de</strong>ráYes si existe un sustitución θ tal que simultáneamenteg1θ, g2θ, . . ., gmθ sean <strong>de</strong>mostrables <strong>de</strong>s<strong>de</strong> el programa. Queun objetivo unificado giθ sea <strong>de</strong>mostrable se pue<strong>de</strong> <strong>de</strong>finirrecursivametne <strong>de</strong> la siguiente manera:Un objetivo gi es <strong>de</strong>mostrable usando la unificación θ si1. Existe una regla ch:-c1,c2,...,cn en el programa tal que2. giθ ≡ chθ y,3. c1θ, c2θ, . . ., cnθ son <strong>de</strong>mostrables a partir <strong>de</strong>l programa.Des<strong>de</strong> un punto <strong>de</strong> vista PROCEDIMENTAL la respuesta <strong>de</strong>linterprete estará dada por la forma en que intenta y logra encontrarla unificación θ. El interprete hace una búsqueda enprofundidad usando backt-tracking para encontrar θ, mantieneuna lista <strong>de</strong> objetivos que se quieren <strong>de</strong>mostrar y terminacuando la lista se vacía:1. Recorre las reglas <strong>de</strong>l programa secuencialmente intentandounificar el lado izquierdo <strong>de</strong> la regla con el primer objetivo<strong>de</strong> la lista.2. Cuando logra unificar cambia el objetivo actual por el lado<strong>de</strong>recho <strong>de</strong> la regla aplicando la sustitución a todos losobjetivos y prosigue con el nuevo primer objetivo.3. Si el objetivo no pudo unificarse con el lado <strong>de</strong>recho <strong>de</strong>ninguna regla hace back-track al objetivo anterior y repiteel paso 1 con la siguiente regla secuencial.En el proceso anterior siempre se busca el unificador másgeneral (no unifica variables que no sea necesario unificar) yse tiene especial cuidado con los nombres <strong>de</strong> las variables.16


¿Qué Hace el Interprete <strong>PROLOG</strong>? Ejemplo:Supongamos el siguiente programa1. gran<strong>de</strong>(oso).2. gran<strong>de</strong>(elefante).3. chico(gato).4. cafe(oso).5. negro(gato).6. gris(elefante).7. oscuro(Z):- negro(Z).8. oscuro(Z):- cafe(Z).y la consulta ?- oscuro(X),gran<strong>de</strong>(X). el interprete ejecutaríala siguiente secuencia:1: oscuro(X), gran<strong>de</strong>(X) (reg.7)2: negro(X), gran<strong>de</strong>(X) (X = gato reg.5)3: gran<strong>de</strong>(gato) (Falla, back-track 2)4: negro(X), gran<strong>de</strong>(X) (Falla, back-track 1)5: oscuro(X), gran<strong>de</strong>(X) (reg. 8)4: cafe(X), gran<strong>de</strong>(X) (X = oso reg.4)5: gran<strong>de</strong>(oso) (reg.1)(Yes, lista vacía)Si tenemos en cambio el programapadre(juan, ramon).padre(ramon, jorge).ancestro(X,Y) :- ancestro(X,Z), padre(Z,Y).ancestro(X,Y) :- padre(X,Y).obtenemos el siguiente resultado al preguntar por los ancestros<strong>de</strong> Jorge:?- ancestro(X,jorge).ERROR: Out of local stack¿Cuál es el problema?17


Estructuras <strong>de</strong> Datos en <strong>PROLOG</strong>Veremos el primer ejemplo <strong>de</strong> una lista. En forma abstractauna lista se pue<strong>de</strong> <strong>de</strong>finir recursivamente <strong>de</strong> la siguientemanera:• nil es una lista y correspon<strong>de</strong> a la lista vacía.• Si l es una lista y a es una constante entonces, a seguida<strong>de</strong> l es también una lista.Si la i<strong>de</strong>a <strong>de</strong> “a seguida <strong>de</strong> l” la capturamos por el functorseg(a,l) nuestra <strong>de</strong>finición <strong>de</strong> lista resulta:lista(nil).lista(seg(X,L)) :- lista(L).así por ejemplo:?- lista(seg(a,seg(b,seg(c,(seg(d,nil)))))).YesPo<strong>de</strong>mos <strong>de</strong>finir algunos predicados sobre listas, por ejemploel predicado primero/2, que se satisface cuando el primerargumento es el primer elemento <strong>de</strong> la lista en el segundoargumento.primero(X,L) :- L = seg(X,L2).Nótese como se usó la unificación. En este caso la variableL2 no nos interesa para nada por lo que po<strong>de</strong>mos usar ‘ ’primero(X,L) :- L = seg(X,_).Otra cosa importante es que lo único que hacemos con Lunificarla por lo que po<strong>de</strong>mos simplemente reemplazarla paraobtenerprimero(X,seg(X,_)).que es la versión más pequeña <strong>de</strong>l predicado primero/2. Ahorapo<strong>de</strong>mos hacer:18


?- primero(X, seg(a,seg(b,seg(c,(seg(d,nil)))))).X = aYesPo<strong>de</strong>mos <strong>de</strong>finir el predicado ultimo/2 con el significado evi<strong>de</strong>nteultimo(X,seg(X,nil)).ultimo(X,seg(_,L)) :- ultimo(X,L).así por ejemplo:?- ultimo(X, seg(a,seg(b,seg(c,(seg(d,nil)))))).X = dYesNote que en esta <strong>de</strong>finición se ve claramente la recursividad,una <strong>de</strong>finición base más una regla <strong>de</strong>finida en función <strong>de</strong>lmismo predicado.Es claro que en los dos ejemplos anteriores los predicados sepue<strong>de</strong>n utilizar como operaciones sobre listas para obtenerel primer y último elemento <strong>de</strong> ellas.Ejercicio: ¿Qué tan eficientes son las operaciones anteriorescon respecto a la cantidad <strong>de</strong> elementos <strong>de</strong> las listas? (laeficiencia está dada por la cantidad <strong>de</strong> pasos <strong>de</strong>l backtrakingusado para respon<strong>de</strong>r).Ejercicio: <strong>de</strong>fina predicados segundo/2 que se satisfaga cuandoel primer argumento sea el segundo elemento <strong>de</strong> la lista en elsegundo argumento, y penultimo/2 que se satisfaga cuandoel primer argumento sea el penúltimo elemento <strong>de</strong> la lista enel segundo argumento.


Listas en <strong>PROLOG</strong>Las listas son elementos básicos <strong>de</strong>l lenguaje <strong>PROLOG</strong> y seencuentran pre<strong>de</strong>finidas.En esta <strong>de</strong>finición, la lista vacía se <strong>de</strong>nota como [] y nuestrofunctor seg correspon<strong>de</strong> al operador ‘.’ (punto).Así por ejemplo nuestros predicados primero/2 y ultimo/2pue<strong>de</strong>n <strong>de</strong>finirse comoprimero(X,.(X,_)).ultimo(X,.(X,[])).ultimo(X,.(_,L)) :- ultimo(X,L).Para simplificar la lectura y creación <strong>de</strong> listas <strong>PROLOG</strong> <strong>de</strong>finenuevas formas, por ejemplo la lista.(a,.(b,.(c,.(d,[]))))es equivalente a [a,b,c,d], que también pue<strong>de</strong> escribirse como[a|[b,c,d]] o [a,b|[c,d]]. Algunas otras equivalencias:.(a,[]) [a|[]] [a].(a,.(b,[])) [a|[b|[]]] [a,b].(a,X) [a|X] [a|X].(a,.(b,X)) [a|[b|X]] [a,b|X]Hay que tener cuidado al trabajar con el operador |, la lista[a|L] es totalmente diferente a la lista [a,L] ¿por qué?Con esta notación nuestros predicados se pue<strong>de</strong>n implementarcomoprimero(X,[X|_]).ultimo(X,[X])).ultimo(X,[_|L]) :- ultimo(X,L).19


PertenenciaOperaciones sobre ListasEl predicado estándar en <strong>PROLOG</strong> es member/2 y se pue<strong>de</strong>implementar comomember(X,[X|_]).member(X,[_|L]) :- member(X,L).ConcatenaciónEl predicado estándar es append/3 que recibe como argumentotres listas y es tal que append(L1,L2,L3) es verda<strong>de</strong>ro cuandoL3 es el resultado <strong>de</strong> la concatencación entre L1 y L2.Separando el caso base y el recursivo obtenemos la siguiente<strong>de</strong>finiciónappend(L1,L2,L3) :- L1 = [], L2 = L3.append(L1,L2,L3) :- L1 = [X|L1s],append(L1s,L2,L3s),L3 = [X|L3s].La <strong>de</strong>finición dice que el predicado es verda<strong>de</strong>ro si L1 es vacíoy L2 es igual a L3, o si L3 es igual al primer elemento <strong>de</strong> L1seguido <strong>de</strong> la concatenación entre L1 sin su primer elementoy L2.Lo anterior también se pue<strong>de</strong> representar porappend([],L2,L2).append([X|L1s],L2,[X|L3s]) :- append(L1s,L2,L3s).Note que solamente se reemplazaron las unificaciones.20


ReversoOperaciones sobre Listas (cont.)Llamaremos reverse/2 al predicado, siendo reverse(L1,L2)verda<strong>de</strong>ro cuando la lista L2 tenga exactamente los mismoselementos que la lista L1 pero en or<strong>de</strong>n inverso. La siguientees una implementación que usa append/3.reverse([],[]).reverse([X|L1s],L2) :- reverse(L1s,R),append(R,[X],L2).La siguiente es una versión alternativa para reverse/2, usa unpredicado auxiliar reverse/3 pero evita el uso <strong>de</strong> append/3.reverse(L,R):- reverse(L,[],R).reverse([X|Ls],Acum,R):- reverse(Ls,[X|Acum],R).reverse([],R,R).¿Qué respon<strong>de</strong>n las dos versiones <strong>de</strong> reverse frente a la consultareverse(L,[1,2,3])?primera versión: L = [3, 2, 1]segunda versión: ERROR: Out of local stackEl problema surge porque para la segunda versión el primerargumento no pue<strong>de</strong> ser una variable.Cuando se diseña un predicado en <strong>PROLOG</strong>, se <strong>de</strong>biera tenerclaro cuáles <strong>de</strong> sus argumentos <strong>de</strong>ben estar instanciados (noser una variable) al momento <strong>de</strong> la llamada, cuáles no y paracuáles no hay restricción.21


Operaciones sobre Listas (cont.)Ejercicios: escriba los predicadoseliminar/3 tal que eliminar(L1,X,L2) se satisface cuando L2es igual a L1, pero sin una ocurrencia <strong>de</strong> X.sublista/2 que se satisface cuando el primer argumento esuna sublista <strong>de</strong>l segundo.igual largo/2, mayor largo/2 y menor largo/2 predicados entrelistas.PermutaciónLlamaremos permutacion/2 al predicado que queremos, siendopermutacion(L1,L2) verda<strong>de</strong>ro cuando la lista L2 sea unapermutación <strong>de</strong> L1. Usaremos el predicado eliminar/3 reciénmencionado.permutacion([],[]).permutacion(L1,[X|L2]) :- eliminar(L1,X,L3),permutacion(L3,L2).Este predicado <strong>de</strong>be ser llamado instanciando siempre su primerargumento. ¿Por qué?¿Qué pasaría si intercambiáramos los argumentos <strong>de</strong> la llamadarecursiva (si hiciéramos permutacion(L2,L3))?22


Manejo <strong>de</strong> Constantes NuméricasEn <strong>PROLOG</strong> los objetos numéricos pue<strong>de</strong>n correspon<strong>de</strong>r atipos integer o float <strong>de</strong> C. Para realizar operaciones numéricas,se tiene el predicado is, que se comporta como unaasignación en un lenguaje imperativo. Así, el objetivo X is será verda<strong>de</strong>ro cuando X unifique con el resultadonumérico <strong>de</strong> evaluar .Por ejemplo, si <strong>de</strong>finimos:masuno(X,Y):- Y is X+1.xmasuno(X,Y):- Y = X+1.observaremos el siguiente comportamiento:?- masuno(4,5). ?- xmasuno(4,5).Yes No?- masuno(5,Y). ?- xmasuno(5,Y).Y = 6 Y = 5+1Yes Yes?- masuno(6,6+1). ?- xmasuno(6,6+1).NoYes<strong>PROLOG</strong> ofrece a<strong>de</strong>más el siguiente conjunto <strong>de</strong> predicados:• =:= y =\= que permiten comparar dos valores numéricos. Elprimero es verda<strong>de</strong>ro si los valores son iguales, y el segundosi son diferentes.• , =< y >=, que correspon<strong>de</strong>n a comparaciones usuales.Las expresiones aritméticas se forman <strong>de</strong> la manera usualutilizando paréntesis y operadores +, -, *, mod, / y // correspondiendoestos últimos a la división <strong>de</strong> punto flotante yentera, respectivamente.23


Manejo <strong>de</strong> Caracteres y <strong>de</strong> StringsUn caracter en Prolog es simplemente un número entre 0 y127, correspondiente a los caracteres <strong>de</strong> la tabla ASC<strong>II</strong>.Un string se maneja como una lista <strong>de</strong> caracteres. Por ejemplo:?- X = "un string.".X = [117,110,32,115,116,114,105,110,103,46]YesInteresante porque po<strong>de</strong>mos usar operaciones sobre listas paramanipular y hacer consultas sobre strings, por ejemplo sitenemos la regla:palindrome(X) :- reverse(X,X).po<strong>de</strong>mos hacer las consultas?- palindrome("hola").No?- palindrome("anicocina").Yes?- palindrome("maripositatisopiram").Yes24


Aplicaciones: Generación y PruebaUna estrategia común usada para resolver problemas en IA.La i<strong>de</strong>a básica es generar las distintas posibilida<strong>de</strong>s <strong>de</strong>l espacio<strong>de</strong> búsqueda (generación) hasta que se encuentre unasolución (prueba).Or<strong>de</strong>nar una ListaQueremos crear un predicado or<strong>de</strong>nar/2 tal que or<strong>de</strong>nar(L1,L2)que se hace verda<strong>de</strong>ro cuando L2 es equivalente a la lista L1or<strong>de</strong>nada. Supondremos que siempre L1 estará instanciada yno es vacía.Las distintas posibilida<strong>de</strong>s las po<strong>de</strong>mos generar usando elpredicado permutacion/2.Sólo necesitamos un predicado para verificar si una lista cualquierase encuentra or<strong>de</strong>nada, lo llamaremo or<strong>de</strong>nada/1:or<strong>de</strong>nada([_]).or<strong>de</strong>nada([X,Y|L]) :- X =< Y, or<strong>de</strong>nada([Y|L]).Ahora sólo tenemos que generar y probar:or<strong>de</strong>nar(L1,L2) :- permutacion(L1,L2), or<strong>de</strong>nada(L2).Ahora po<strong>de</strong>mos haceror<strong>de</strong>nar([4,1,3,2],L).L = [1, 2, 3, 4]YesEste algoritmo es my ineficiente en el peor caso tendrá quegenerar las N! permutaciones para una lista <strong>de</strong> largo N.Ejercicio: implemente otros algoritmos <strong>de</strong> or<strong>de</strong>nación (nopor generación y prueba) con predicados como selectsort/2,insertsort/2 y quicksort/2 correspondientes a los algoritmosmás conocidos.25


Aplicaciones: Generación y Prueba (cont.)Generalmente problemas como el <strong>de</strong> or<strong>de</strong>nación no se resuelvenusando esta estrategia, veremos otro ejemplo en el quesi se usa esta estrategia.8 ReinasEl problema consiste en ubicar las reinas en el tablero <strong>de</strong>ajedréz <strong>de</strong> manera que ningún par <strong>de</strong> ellas se ataque. Lasiguiente es una solución al problema.Necesitamos una representación para la solución, usaremosuna lista <strong>de</strong> la siguiente forma[[1,Y1],[2,Y2],[3,Y3],[4,Y4],[5,Y5],[6,Y6],[7,Y7],[8,Y8]]don<strong>de</strong> el par [i,Yi] representa las coor<strong>de</strong>nadas <strong>de</strong> la reina ien el tablero, claramente no pue<strong>de</strong> haber más <strong>de</strong> una reinapor columna).Ahora sólo tenemos que generar y probar...26


8 Reinas (cont.)El siguiente predicado genera/1 genera distintas configuraciones<strong>de</strong> tableros (usa un predicado auxiliar gen aux/1).genera(L) :- gen_aux(L,1).gen_aux([],N) :- N>8.gen_aux([[N,X]|L],N) :-N=


8 Reinas (cont.)Ahora simplemente generamos y comprobamosocho_reinas(C) :- genera(C), no_se_atacan(C).Ya po<strong>de</strong>mos encontrar soluciones al problema?- ocho_reinas(C).C = [[1,1], [2,5], [3,8], [4,6], [5,3], [6,7], [7,2], [8,4]];C = [[1,1], [2,6], [3,8], [4,3], [5,7], [6,4], [7,2], [8,5]];...La solución <strong>de</strong> todas maneras no es muy eficiente, <strong>de</strong> hechopo<strong>de</strong>mos tomar el tiempo?- time(ocho_reinas(_)).% 21,875,983 inferences,... in 14.45 seconds (97% CPU,...)14.45 segundos en una máquina <strong>de</strong> 2GHz usando casi el100 % <strong>de</strong> la CPU¿Cómo po<strong>de</strong>mos mejorarla? hay muchas configuraciones queestamos generando y que po<strong>de</strong>mos <strong>de</strong>scartar a priori, el siguientepredicado genera configuraciones con reinas siempreen distintas filas usando permutacion/2.genera(L) :- permutacion([1,2,3,4,5,6,7,8],P),empareja([1,2,3,4,5,6,7,8],P,L).empareja([],[],[]).empareja([X|Xs],[Y|Ys],[[X,Y]|L]) :- empareja(Xs,Ys,L).Si medimos el tiempo en la misma máquina ahora obtenemos?- time(ocho_reinas(_)).% 102,920 inferences,... in 0.06 seconds (100% CPU,...)aproximadamente <strong>de</strong> 200 veces más rápido!!!28


<strong>PROLOG</strong> AvanzadoEstudiaremos ahora <strong>PROLOG</strong> como un lenguaje <strong>de</strong> programación,para esto veremos extensiones que se hacen a lalógica pura que es la que hemos usado hasta ahora.<strong>PROLOG</strong> posee varios predicado extra–logicos y meta–lógicos,por ejemplo el predicado is/2 es extra–lógico ya queinvoca a un procedimiento fuera <strong>de</strong> la LPOP para evaluaruna expresión y posteriormente unificar variables.El Operador <strong>de</strong> Corte<strong>PROLOG</strong> siempre busca todas las posibilida<strong>de</strong>s para resatisfacerun objetivo, por ejemplo usando member/2 obtenemos?- member(X,[a,b])X = a;Y = b;NoMuchas veces estaremos interesados en sólo una solución,en estos casos <strong>PROLOG</strong> nos da la posibilidad <strong>de</strong> cortar labúsqueda mediante el operador <strong>de</strong> corte ‘!’Si usamos ! en el ejemplo anterior obtenemos?- member(X,[a,b]), !.X = a;NoCuando se encuentra con el objetivo !, <strong>PROLOG</strong> se comprometecon todas las unificaciones que se han realizado antes<strong>de</strong>l !, y a<strong>de</strong>más con la regla que se está usando en estemomento para la <strong>de</strong>mostración, la búsqueda se corta.El operador <strong>de</strong> corte pue<strong>de</strong> ayudar a la eficiencia <strong>de</strong> la ejecuciónal no intentar resatisfacer objetivos, suponga las siguientes<strong>de</strong>finiciones para el “aparente” mismo predicado.29


en_ambas1(X,L1,L2) :- member(X,L1), member(X,L2).en_ambas2(X,L1,L2) :- member(X,L1), !, member(X,L2).Aparentemente no hay diferencias, pero qué pasa internamentesi hacemos las consultas?- en_ambas1(a,[a,a,a,a,a],[]).No?- en_ambas2(a,[a,a,a,a,a],[]).NoLa diferencia principal está en la eficiencia, en el primer casose <strong>de</strong>muestra varias veces el predicado member(a,[a,a,a,a,a]),en la segunda sólo una vez, <strong>de</strong> hecho po<strong>de</strong>mos usar el predicadotime/1 para medir el trabajo realizado?- time(en_ambas1(a,[a,a,a,a,a,a,a,a,a],[])).% 53 inferences,...?- time(en_ambas2(a,[a,a,a,a,a,a,a,a,a],[])).% 3 inferences,...Con el corte se realizó mucho menos trabajo.Lamentablemente el corte trae comportamientos extraños sino se usa con cuidado, por ejemplo:?- en_ambas1(X,[a,b,c],[c,d,e]).X = cYes?- en_ambas2(X,[a,b,c],[c,d,e]).No¿Por qué se da este comportamiento?... sólo se pue<strong>de</strong> usar elsegundo predicado si su primer argumento está instanciado.En resumen, los cortes <strong>de</strong>bieran agregarse con mucho cuidadopensando en el uso <strong>de</strong> los predicados y sólo con el objetivo<strong>de</strong> mejorar la eficiencia <strong>de</strong>l intérprete.

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!