Anexo 5: Implementaciones en Lisp José A. Alonso Jiménez Carmen Graciani Dı́az Francisco Jesús Martı́n Mateos José Luis Ruiz Reina Dpto. Ciencias de la Computación e Inteligencia Artificial U NIVERSIDAD IIA 2004-05 C c Ia DE S EVILLA Implementaciones en Lisp A5.1 Representación de PSRs • Representación de las variables: (defstruct (variable-psr (:constructor crea-variable) (:conc-name psr-var-)) nombre dominio) • Representación de las restricciones: (defstruct (restriccion-psr (:constructor crea-restriccion) (:conc-name psr-restr-)) variables funcion) IIA 2004-05 C c Ia Implementaciones en Lisp A5.2 N reinas (defun crea-dominio (n) (loop for i from 1 to n collect i)) (defun n-reinas (n) (defparameter *variables* (loop for i from 1 to n collect (crea-variable :nombre i :dominio (crea-dominio n)))) (defparameter *restricciones* (loop for i from 1 to n append (loop for j from 1 to n when (> j i) collect (crea-restriccion :variables (list i j) :funcion (restriccion-reinas i j)))))) (defun restriccion-reinas (i j) #’(lambda (x y) (and (not (= x y)) (not (= (abs (- x y)) (abs (- i j))))))) IIA 2004-05 C c Ia Implementaciones en Lisp A5.3 Colorear el mapa de Andalucía (I) (defparameter *colores* ’(azul rojo verde)) (defparameter *variables* (list (crea-variable :nombre (crea-variable :nombre (crea-variable :nombre (crea-variable :nombre (crea-variable :nombre (crea-variable :nombre (crea-variable :nombre (crea-variable :nombre IIA 2004-05 ’Huelva :dominio *colores*) ’Sevilla :dominio *colores*) ’Cadiz :dominio *colores*) ’Malaga :dominio *colores*) ’Cordoba :dominio *colores*) ’Jaen :dominio *colores*) ’Granada :dominio *colores*) ’Almeria :dominio *colores*))) C c Ia Implementaciones en Lisp A5.4 Colorear el mapa de Andalucía (II) (defun distintos (x y) (not (eq x y))) (defparameter *restricciones* (list (crea-restriccion :variables (crea-restriccion :variables (crea-restriccion :variables (crea-restriccion :variables (crea-restriccion :variables (crea-restriccion :variables (crea-restriccion :variables (crea-restriccion :variables (crea-restriccion :variables (crea-restriccion :variables (crea-restriccion :variables IIA 2004-05 C c Ia ’(Huelva Sevilla) :funcion #’distintos)) ’(Huelva Cadiz) :funcion #’distintos)) ’(Cadiz Malaga) :funcion #’distintos)) ’(Cadiz Sevilla) :funcion #’distintos)) ’(Sevilla Cordoba) :funcion #’distintos)) ’(Sevilla Malaga) :funcion #’distintos)) ’(Cordoba Jaen) :funcion #’distintos)) ’(Cordoba Malaga) :funcion #’distintos)) ’(Malaga Granada) :funcion #’distintos)) ’(Granada Jaen) :funcion #’distintos)) ’(Granada Almeria) :funcion #’distintos)) Implementaciones en Lisp A5.5 Búsqueda en profundidad (I) • Estados finales: (defun es-asignacion-completa (estado) (= (length estado) (length *variables*))) • Sucesores: (defun bpr-sucesores (actual) (elimina-inconsistentes-nueva-asignacion (asigna-nueva-variable actual))) IIA 2004-05 C c Ia Implementaciones en Lisp A5.6 Búsqueda en profundidad (II) • Asignación de nuevas variables: (defun asignada (variable estado) (assoc variable estado)) (defun primera-variable-no-asignada (estado) (find-if-not #’(lambda (x) (asignada (psr-var-nombre x) estado)) *variables*)) (defun asigna-nueva-variable (estado) (let* ((variable (primera-variable-no-asignada estado)) (nombre (psr-var-nombre variable)) (dominio (psr-var-dominio variable))) (loop for val in dominio collect (acons nombre val estado)))) IIA 2004-05 C c Ia Implementaciones en Lisp A5.7 Búsqueda en profundidad (III) • Eliminación de asignaciones inconsistentes: (defun elimina-inconsistentes-nueva-asignacion (estados) (loop for estado in estados when (verifica-restricciones-posibles estado) collect estado)) (defun verifica-restricciones-posibles (estado) (loop for restriccion in *restricciones* always (let* ((variables (psr-restr-variables restriccion)) (a1 (assoc (first variables) estado)) (a2 (assoc (second variables) estado))) (or (not (member (caar estado) variables)) (not a1) (not a2) (funcall (psr-restr-funcion restriccion) (cdr a1) (cdr a2)))))) IIA 2004-05 C c Ia Implementaciones en Lisp A5.8 Búsqueda en profundidad (y IV) • Búsqueda en profundidad: (defun psr-busqueda-en-profundidad () (let ((abiertos (list nil))) (loop until (null abiertos) do (setf actual (first abiertos)) (setf abiertos (rest abiertos)) (cond ((es-asignacion-completa actual) (return actual)) (t (setf nuevos-sucesores (bpr-sucesores actual)) (setf abiertos (append nuevos-sucesores abiertos))))))) IIA 2004-05 C c Ia Implementaciones en Lisp A5.9 Consistencia de arcos • Arco = Restricción + Variable (defstruct (arco (:constructor crea-arco) (:conc-name arco-)) variable restriccion) • Lista de arcos de un P.S.R.: (defun arcos () (loop for restriccion in *restricciones* append (loop for var in (psr-restr-variables restriccion) collect (crea-arco :variable var :restriccion restriccion)))) IIA 2004-05 C c Ia Implementaciones en Lisp A5.10 Algoritmo de consistencia de arcos AC-3 (defun ac3 (variables) (let ((red (arcos)) (actual nil)) (loop until (null red) do (setf actual (first red)) (setf red (rest red)) (let* ((variable-mod (variable-nombre (arco-variable actual) variables)) (restriccion (arco-restriccion actual)) (viejo-dominio (psr-var-dominio variable-mod)) (nuevo-dominio (actualiza-dominio variable-mod variables restriccion))) (when (not (equal nuevo-dominio viejo-dominio)) (setf (psr-var-dominio variable-mod) nuevo-dominio) (when (null nuevo-dominio) (return)) (setf red (append red (nuevos-arcos variable-mod red))))))) variables) IIA 2004-05 C c Ia Implementaciones en Lisp A5.11 Algoritmo de consistencia de arcos AC-3 • Obtención de arcos cuya consistencia es discutible: (defun nuevos-arcos (variable-mod red) (let ((var-mod (psr-var-nombre variable-mod)) (arcos (arcos))) (loop for arco in arcos when (and (not (equal var-mod (arco-variable arco))) (not (member arco red :test #’equalp)) (member var-mod (psr-restr-variables (arco-restriccion arco)))) collect arco))) IIA 2004-05 C c Ia Implementaciones en Lisp A5.12 Algoritmo de consistencia de arcos AC-3 • Actualización de dominios (restricciones binarias): (defun actualiza-dominio (variable-mod variables restriccion) (let ((nombre1 (first (psr-restr-variables restriccion))) (nombre2 (second (psr-restr-variables restriccion))) (funcion (psr-restr-funcion restriccion))) (cond ((equal (psr-var-nombre variable-mod) nombre1) (loop for val1 in (psr-var-dominio variable-mod) when (test-de-existencia-1 val1 (variable-nombre nombre2 variables) funcion) collect val1)) (t (loop for val2 in (psr-var-dominio variable-mod) when (test-de-existencia-2 val2 (variable-nombre nombre1 variables) funcion) collect val2))))) IIA 2004-05 C c Ia Implementaciones en Lisp A5.13 Algoritmo de consistencia de arcos AC-3 • Tests de existencia: (defun test-de-existencia-1 (val1 var2 funcion) (loop for val2 in (psr-var-dominio var2) thereis (funcall funcion val1 val2))) (defun test-de-existencia-2 (val2 var1 funcion) (loop for val1 in (psr-var-dominio var1) thereis (funcall funcion val1 val2))) IIA 2004-05 C c Ia Implementaciones en Lisp A5.14 Búsqueda mediante consistencia de arcos • Búsqueda por consistencia de arcos: (defun busqueda-ac3 () (let ((abiertos (list (copia-lista-variables-psr *variables*))) (actual nil)) (loop until (null abiertos) do (setf actual (ac3 (first abiertos))) (setf abiertos (rest abiertos)) (cond ((hay-dominio-vacio actual) nil) ((dominios-unitarios actual) (return actual)) (t (setf abiertos (append (cda-sucesores actual) abiertos))))))) IIA 2004-05 C c Ia Implementaciones en Lisp A5.15 Búsqueda mediante consistencia de arcos • Comprobación de dominios vacíos: (defun hay-dominio-vacio (variables) (loop for var in variables thereis (dominio-vacio var))) • Generación de sucesores: (defun cda-sucesores (estado) (let* ((seleccion (selecciona-dominio estado)) (inicio (first seleccion)) (variable (second seleccion)) (final (third seleccion)) (nuevos-dominios (rompe-dominio variable))) (loop for var in nuevos-dominios collect (append (copia-lista-variables-psr inicio) (list var) (copia-lista-variables-psr final))))) IIA 2004-05 C c Ia Implementaciones en Lisp A5.16 Búsqueda mediante consistencia arcos • Seleccionar una variable con dominio no unitario: (V1 . . . Vi . . . Vn ) =⇒ ((V1 . . . Vi−1 ) Vi (Vi+1 . . . Vn )) (defun selecciona-dominio (variables) (let ((indice (position-if-not #’dominio-unitario variables))) (list (subseq variables 0 indice) (nth indice variables) (subseq variables (+ indice 1))))) • Romper un dominio en subdominios (unitario más el resto): (defun rompe-dominio (variable) (list (crea-variable :nombre (psr-var-nombre variable) :dominio (list (first (psr-var-dominio variable)))) (crea-variable :nombre (psr-var-nombre variable) :dominio (rest (psr-var-dominio variable))))) IIA 2004-05 C c Ia Implementaciones en Lisp A5.17