Introducción Búsqueda primero en profundidad Búsqueda en amplitud Metodologı́a de Programación I Espacios de soluciones Dr. Alejandro Guerra-Hernández Departamento de Inteligencia Artificial Facultad de Fı́sica e Inteligencia Artificial [email protected] http://www.uv.mx/aguerra Maestrı́a en Inteligencia Artificial 2011 Búsqueda primero el mejor Introducción Búsqueda primero en profundidad Búsqueda en amplitud Laberinto I Un movimiento válido es a una casilla adyacente. I ¿Cual será la estrategia para salir? Búsqueda primero el mejor Introducción Búsqueda primero en profundidad Búsqueda en amplitud Representación de Conocimiento I conecta ( inicio ,2) . conecta (1 ,7) . conecta (2 ,8) . conecta (2 ,3) . % % % agrega varias soluciones . conecta (3 ,4) . conecta (3 ,9) . conecta (4 ,10) . ... conectado ( Pos1 , Pos2 ) : - conecta ( Pos1 , Pos2 ) . conectado ( Pos1 , Pos2 ) : - conecta ( Pos2 , Pos1 ) . 1 2 3 4 5 6 7 8 9 10 I 1 2 Adyacencia: Miembro de una lista: miembro (X , [ X | _ ]) . miembro (X , [ _ | Y ]) : - miembro (X , Y ) . Búsqueda primero el mejor Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Estrategia 1 sol : - camino ([ inicio ] , Sol ) , write ( Sol ) . 2 3 4 5 6 7 camino ([ fin | RestoDe lCamino ] ,[ fin | Res toDelCa mino ]) . camino ([ PosActual | Rest oDelCami no ] , Sol ) : conectado ( PosActual , PosSiguiente ) , \+ miembro ( PosSiguiente , Re stoDelC amino ) , camino ([ PosSiguiente , PosActual | RestoDe lCamino ] , Sol ) . Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Estados y Acciones I ¿Cómo podemos definir un problema y sus soluciones de manera declarativa? I Consideren otro ejemplo: I Las acciones son del tipo pon en(a, b), etc. I Los estados son configuraciones de cubos. Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Espacio de estados I Estados y acciones configuran un grafo dirigido conocido como espacio de estados de un problema. C A B B A C A BC C B A B AC A BC B AC B C A C AB ABC C AB A B C Adaptado de Bratko(1990), p. 259 A C B Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Soluciones en un espacio de estados I La solución a un problema dado consiste en encontrar un camino desde un nodo representando el estado inicial, hasta el estado final deseado. I Cada paso en ese camino está dado por una acción válida. I ¿Cómo podemos representar todo esto en Prolog? Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Sucesor I El espacio de estados se representa mediante la relación succ/2 cuyos argumentos son estados del problema. I succ(X , Y ) denota que existe un movimiento o acción válida para ir del estado X al estado Y . I Podemos definir esta relación por extensión, aunque para problemas interesantes esto no suele ser posible. I Ası́, la definición de sucesor suele ser intensional. Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Estados I La representación de los estados debe ser compacta y favorecer el computo eficiente de los sucesores. I En el mundo de los cubos representaremos los estados como una lista de pilas (listas a su vez). I El estado inicial es: [[c, b, a], [], []] Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Metas I Si asumimos que hay lugar en la mesa para tres pilas de cubos, la meta puede representarse como: I I I [[a,b,c],[],[]], ó [[],[a,b,c],[]] ó [[],[],[a,b,c]]. Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Computo de sucesores I 1 2 3 Si quito el tope T 1 de la pila P1 y lo pongo en la pila P2, obtengo un sucesor: s ( Pilas , [ Pila1 ,[ Tope1 | Pila2 ]| OtrasPilas ]) : quitar ([ Tope1 | Pila1 ] , Pilas , Pilas1 ) , quitar ( Pila2 , Pilas1 , OtrasPilas ) . 4 5 6 7 quitar (X ,[ X | Ys ] , Ys ) . quitar (X ,[ Y | Ys ] ,[ Y | Ys1 ]) : quitar (X , Ys , Ys1 ) . ? - s ([[ a ] ,[ b ] ,[ c ]] , Succ ) . Succ = [[] , [a , b ] , [ c ]] ; Succ = [[] , [a , c ] , [ b ]] ; ... false . Introducción Búsqueda primero en profundidad Búsqueda en amplitud Slowing Down ? - quitar ([ T1 | P1 ] ,[[ a ] ,[ b ] ,[ c ]] , Pilas1 ) , quitar ( P2 , Pilas1 , OtrasP ) , Succ =[ P1 ,[ T1 | P2 ]| OtrasP ]. T1 = a , P1 = [] , Pilas1 = [[ b ] , [ c ]] , P2 = [ b ] , OtrasP = [[ c ]] , Succ = [[] , [a , b ] , [ c ]] Búsqueda primero el mejor Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Meta I 1 2 Una meta se puede caracterizar en términos de propiedades esperadas de los estados: meta ( Estado ) : member ([ a ,b , c ] , Estado ) . Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Estrategia I Comenzaremos con una idea simple. Para encontrar un camino solución Sol, de un nodo dado N a un nodo meta: I I I 1 2 Si N es un nodo meta, entonces Sol = [N], o Si existe un nodo sucesor N1 tal que existe un camino Sol1 de N1 al nodo meta, entonces Sol = [N|Sol1]. Lo cual traduce a Prolog como: solucion (N ,[ N ]) : meta ( N ) . 3 4 5 6 solucion (N , [ N | Sol1 ]) : s (N , N1 ) , solucion ( N1 , Sol1 ) . Introducción Búsqueda primero en profundidad Búsqueda en amplitud Corrida I Usando el mundo de los cubos: ? - solucion ([[ a ,b , c ] ,[] ,[]] , S ) . S = [[[ a , b , c ] , [] , []]] ? - solucion ([[ c ,b , a ] ,[] ,[]] , S ) . S = [[[ c , b , a ] , [] , []] , [[ b , a ] , [ c ] , []] , [[ a ] , [b , c ] , []] , [[] , [a , b , c ] , []]] I Pero, los ciclos pueden dar problemas: ? - solucion ([[ b ,c , a ] ,[] ,[]] , S ) . ERROR : Out of local stack % Execution Aborted Búsqueda primero el mejor Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Evitando ciclos I 1 2 La idea es la que usamos al resolver el laberinto. No visites estados ya visitados: solucion2 ( Nodo , Sol ) : p r i m e r o P r o f u n d i d a d ([] , Nodo , Sol ) . 3 4 5 p r i m e r o P r o f u n d i d a d ( Camino ,N ,[ N | Camino ]) : meta ( N ) . 6 7 8 9 10 p r i m e r o P r o f u n d i d a d ( Camino , Nodo , Sol ) : s ( Nodo , N1 ) , \+( member ( N1 , Camino ) ) , p r i m e r o P r o f u n i d a d ([ Nodo | Camino ] , N1 , Sol ) . Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Corrida I Claro que la salida está en orden inverso: ? - solucion2 ([[ b ,c , a ] ,[] ,[]] , S ) . S = [[[] , [a , b , c ] , []] , [[ a ] , [b , c ] , []] , [[] , [b , a ] , [ c ]] , [[ c ] , [ b ] , [ a ]] , [[] , [b , c ] , [ a ]] , [[ b ] , [ c ] , [...]] , [[] , [...|...]|...] , I 1 2 y es muy larga. Podemos formatearla con un imprime edos/1: impr_edos ([]) : - write ( ’ Fin ’) , nl . impr_edos ([ Edo | Edos ]) : - write ( Edo ) ,nl , impr_edos ( Edos ) . ? - solucion2 ([[ b ,c , a ] ,[] ,[]] , S ) , reverse (S , Saux ) , impr_edos ( Saux ) . [[ b , c , a ] , [] , []] [[ c , a ] , [ b ] , []] [[ a ] , [c , b ] , []]... Introducción Búsqueda primero en profundidad Búsqueda en amplitud Limitando la profundidad 1 2 solucion3 ( Nodo , Sol , MaxProf ) : p r i m e r o P r o f u n d i d a d 2 ( Nodo , Sol , MaxProf ) . 3 4 5 p r i m e r o P r o f u n d i d a d 2 ( Nodo ,[ Nodo ] , _ ) : meta ( Nodo ) . 6 7 8 9 10 11 p r i m e r o P r o f u n d i d a d 2 ( Nodo ,[ Nodo | Sol ] , MaxProf ) : MaxProf > 0 , s ( Nodo , Nodo1 ) , Max1 is MaxProf -1 , p r i m e r o P r o f u n d i d a d 2 ( Nodo1 , Sol , Max1 ) . Búsqueda primero el mejor Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Estrategia I I Contamos con un solo camino candidato: [[NodoInicial]]. Luego, dado un conjunto de caminos candidatos: I I I I I Si el primer camino contiene un nodo meta como su cabeza, entonces esa es la solución al problema. De otra forma Eliminar el primer camino del conjunto de caminos candidatos y generar el conjunto de todas las posibles extensiones de un paso de este camino. Agregar este conjunto de extensiones al final del conjunto de candidatos. Ejecutar la búsqueda primero en amplitud en este nuevo conjunto de caminos candidatos. Para generar las extensiones de un sólo paso, usemos el predicado predefinido bagof /3 Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor El código 1 2 solucion4 ( Inicio , Sol ) : p r i m e r o E n A m p l i t u d ([[ Inicio ]] , Sol ) . 3 4 5 6 7 8 9 p r i m e r o E n A m p l i t u d ([[ Nodo | Camino ]| _ ] ,[ Nodo | Camino ]) : meta ( Nodo ) . p r i m e r o E n A m p l i t u d ([ Camino | Caminos ] , Sol ) : extender ( Camino , NuevosCaminos ) , append ( Caminos , NuevosCaminos , Caminos1 ) , p r i m e r o E n A m p l i t u d ( Caminos1 , Sol ) . 10 11 12 13 14 15 16 extender ([ Nodo | Camino ] , NuevosCaminos ) : bagof ([ NuevoNodo , Nodo | Camino ] , ( s ( Nodo , NuevoNodo ) , \+ ( member ( NuevoNodo , [ Nodo | Camino ]) ) ) , NuevosCaminos ) , !. extender ( Camino_ ,[]) . Introducción Búsqueda primero en profundidad Búsqueda en amplitud Corrida ? - solucion4 ([[ c ,b , a ] ,[] ,[]] , S ) . S = [[[] , [a , b , c ] , []] , [[ a ] , [b , c ] , []] , [[ b , a ] , [ c ] , []] , [[ c , b , a ] , [] , []]] Búsqueda primero el mejor Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Otro ejemplo I Consideremos otro ejemplo para comparar las dos estrategias implementadas hasta ahora. I Hagamos una búsqueda sobre el grafo: a d h j b c e f i g k Introducción Búsqueda primero en profundidad El programa 1 2 3 4 5 s (a , b ) . s (b , d ) . s (d , h ) . s (e , j ) . s (c , g ) . s (a , c ) . s (b , e ) . s (e , i ) . s (c , f ) . s (f , k ) . 6 7 meta ( j ) . meta ( f ) . Búsqueda en amplitud Búsqueda primero el mejor Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Las búsquedas I La búsqueda en amplitud encuentra primero el nodo más cercano a la raı́z. ? - solucion4 (a , R ) . R = [f , c , a ] ; R = [j , e , b , a ] ; false . ? - solucion (a , R ) . R = [a , b , e , j ] ; R = [a , c , f ] ; false . Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Búsquedas optimizadas I Dado el siguiente mapa, la tarea es encontrar la ruta más corta entre una ciudad inicial s y una ciudad meta t. 7 I Los cı́rculos son estados a visitar. I Las flechas representan sucesores. I Las etiquetas en las flechas son distancias. I Los cuadros son distancias lineales a la meta. e 2 s 5 2 5 f 2 2 4 4 a b 2 c g 4 2 2 3 t 3 3 d 0 Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Heurı́sticas I Las búsquedas anteriores son ciegas ante los criterios de optimización. I Un algoritmo primero el mejor afina la búsqueda en amplitud, expandiendo el mejor candidato. I Una función costo s(n, m, c) representa el costo c de moverse de un nodo n al nodo m en el espacio de estados. I Se puede diseñar una función heurı́stica h que estime la dificultad de llegar de un nodo n a la meta. I La búsqueda puede guiarse entonces minimizando el costo recorrido y la distancia por recorrer. Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Grafo, costo, heurı́stica y meta I El grafo del ejemplo puede representarse, considerando costo, heurı́stica y metas como: 7 1 2 3 4 5 s (s ,a ,2) . s (e ,f ,5) . s (f ,g ,2) . s (g ,t ,2) . s (d ,t ,3) . e s (s ,e ,2) . s (a ,b ,2) . s (b ,c ,2) . s (c ,d ,3) . 2 s 5 2 5 f 6 7 8 9 10 h (b ,4) . h (d ,3) . h (f ,4) . h (t ,0) . 4 meta ( t ) . b 2 c g 4 2 2 3 t 11 12 2 2 h (a ,5) . h (c ,4) . h (e ,7) . h (g ,2) . 4 a 3 3 d 0 Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Costo y costo estimado I f (n) será construida para estimar el costo del mejor camino solución entre el nodo inicial s y el nodo meta t, con la restricción de que el camino pase por el nodo n. I Supongamos que tal camino existe y que un nodo meta que minimiza su costo es n. Entonces el estimado de f (n) puede calcularse como la suma de dos términos: f (n) = g (n) + h(n) donde g (n) es el costo del camino óptimo de s a n; y h(n) es el costo estimado de un camino óptimo de n a la meta t. Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Gráficamente I La heurı́stica computa el costo hasta el momento g (n) y estima el costo por venir h(n): s g(n) n n' n'' h(n) t I Evidentemente g (n) es fácil de computar, mientras que h(n) requiere de ingenierı́a del conocimiento. Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Ejemplo de problema real I Un portal web de servicios para el DIA: inscripciones, biblioteca, productos del departamento, visitas, etc. I Uno puede pensar en rutas desde el inicio del portal, hasta que se ha logrado concretar un servicio. Ej., el último paper del Dr. Guerra. I El costo es el número de ligas recorridas. I El costo estimado es cuanto me falta para llegar a concretar el servicio. I Problema: minimizar la ruta al servicio requerido. Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Búsqueda I En los pasos iniciales el proceso 1 está más activo porque los valores f en ese camino son más bajos que los del otro. Cuando el proceso 1 llega a c y el proceso 2 sigue en e, la situación cambia: f (c) = g (c) + h(c) = 6 + 4 = 10 f (e) = g (e) + h(e) = 2 + 7 = 9 I f (e) < f (c) y ahora el proceso 2 procede al nodo f y el proceso 1 espera. Pero entonces: f (f ) = 7 + 4 + 11, f (c) = 10, f (c) < f (f ) I El proceso 2 es detenido y se le permite al proceso 1 continuar... Introducción Búsqueda primero en profundidad Búsqueda en amplitud Gráficamente I La búsqueda: s f(a)=2+5=7 e a f(e)=2+7=9 f(b)=4+4=8 b f(c)=6+4=10 f f(f)=7+4=11 c f(g)=9+2=11 g f(t)=11+0=11 t d Búsqueda primero el mejor Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Representación I I Esta estrategia requiere una representación más elaborada para los nodos de búsqueda. Representaremos el proceso como un árbol, donde los nodos son: 1. l(N, F /G ) representa una hoja (leaf) del árbol, donde N es un nodo en el espacio de estados, G es g (N) y F es f (N) = G + h(N). 2. t(N, F /G , Subarboles) representa un nodo interno (tree) del árbol, con una lista de subárboles. F es el valor f (N) actualizado por el valor para f (N) del sucesor más prometedor. Los subárboles se ordenan de acuerdo a su f -valor. I Por ejemplo: t(s, 7/0, [l(a, 7/2), l(e, 9/2)] Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Actualizaciones de F -valores I A partir del árbol t(s, 7/0, [l(a, 7/2), l(e, 9/2)], el proceso continua alcanzando el árbol: t (s ,9/0 ,[ l (e ,9/2) ,t (a ,10/2 ,[ t (b ,10/4 ,[ l (c ,10/6) ]) ]) ]) I Para una hoja N del árbol, mantenemos la definición original: f (N) = g (N) + h(N) I Para un árbol N con subárboles S1 , S2 , . . . : f (N) = mı́n f (Si ) i Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor El código I Definimos una función interfaz, que encuentre la solución Sol a partir de un estado inicial Ini. Para ello primeroMejor /2 llama a expandir /6: primeroMejor ( Ini , Sol ) : expandir ([] , hoja ( Ini ,0/0) ,9999 , _ , si , Sol ) . 1 2 I El predicado expandir (Camino, Arbol, Umbral, Arbol1, Solucionado, Sol) tiene como argumentos el Camino recorrido entre Inicio y el nodo en Arbol. Arbol1 es el Arbol expandido bajo el Umbral. Si la meta se encuentra, Sol guarda el camino solución y Solucionado = si. I Hay cinco casos de expansión. Expandir (1/2) 1. Nodo es una meta del espacio de soluciones: 1 2 expandir ( Camino , l ( Nodo , _ ) ,_ ,_ , si ,[ Nodo | Camino ]) : meta ( Nodo ) . 2. Una hoja, cuyo F -valor es menor o igual que el Umbral. 1 2 3 4 5 6 7 8 9 10 11 expandir ( Camino , l ( Nodo , F / G ) , Umbral , Arbol1 , Solucionado , Sol ) : F = < Umbral , ( bagof ( M /C ,( s ( Nodo ,M , C ) , not ( member (M , Camino ) ) ) , Succ ) , ! , % Nodo tiene sucesores listaSuccs (G , Succ , As ) , % Encontras subárboles As mejorF ( As , F1 ) , % f - value of best successor expandir ( Camino , t ( Nodo , F1 /G , As ) , Umbral , Arbol1 , Solucionado , Sol ) ; Solucionado = nunca ) . % Nodo no tiene sucesores Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Corridas iniciales I Se llama a expandir ([], l(s, 0/0), 9999,, si, Solucion) I La primer llamada no satisface meta(Nodo). I El primer caso es expandir la hoja l(s, 0/0). I La primera parte del trabajo, lo hace bagof /3 que computa los sucesores de s con sus distancias asociadas Succ/[a/2, e/2]. I El predicado listaSuccs/3 construye la lista de posibles árboles sucesores As/[l(a, 7/2), l(e, 9/2)]. I Con esa lista mejorF /2 encuentra que el mejor F 1/7 y I Se llama recursivamente a expandir con el árbol expandido a t(s, 7/0, [l(a, 7/2), l(e, 9/2)]). El resto no ha cambiado. Expandir (2/2) 3. Un nodo interno cuyo F -valor es menor o igual que el Umbral. 1 2 3 4 5 6 7 expandir ( Camino , t ( Nodo , F /G ,[ A | As ]) , Umbral , Arbol1 , Solucionado , Sol ) : F = < Umbral , mejorF ( As , MejorF ) , min ( Umbral , MejorF , Umbral1 ) , expandir ([ Nodo | Camino ] ,A , Umbral1 , A1 , Solucionado1 , Sol ) , continuar ( Camino , t ( Nodo , F /G ,[ A1 | As ]) , Umbral , Arbol1 , Solucionado1 , Solucionado , Sol ) . 4. Cubre los puntos muertos, cuando no hay solución: 1 expandir (_ , arbol (_ ,_ ,[]) ,_ ,_ , nunca , _ ) : - !. 5. El f -valor es mayor que el Umbral, el árbol no crece: 1 2 expandir (_ , Arbol , Umbral , Arbol , no , _ ) f ( Arbol , F ) , F > Umbral . :- Introducción Búsqueda primero en profundidad Búsqueda en amplitud Búsqueda primero el mejor Contiunación de la corrida I La tercer llamada es expandir ([], t(s, 7/0, [l(a, 7/2), l(e, 9/2)]), 9999,, si, Solucion). I Como F /9 9999 la evaluación continua en el tercer caso. I I Se actualiza el umbral con el mejor F del resto de la expansión [l(a, 7/2), l(e, 9/2)] (el valor de F para a ya esta guardado en el nodo s, 7/ . . . . Y se llama recursivamente a expandir el camino recorrido aumentado con s|Camino, Arbol/l(a, 7/2), el Umbral1/9 y el resto sigue igual. Continuar I 1 continuar /7 decide como procede la búsqueda de acuerdo al árbol expandido. Si una solución Sol se ha encontrado, se regresa este valor. En cualquier otro caso, la expansión continua dependiendo del valor de Solucionado (no o nunca). continuar (_ ,_ ,_ ,_ , si , si , Sol ) . 2 3 4 5 6 7 8 continuar ( Camino , t ( Nodo , F /G ,[ A1 | As ]) , Umbral , Arbol1 , no , Solucionado , Sol ) : insertarArbol ( A1 , As , NAs ) , mejorF ( NAs , F1 ) , expandir ( Camino , t ( Nodo , F1 /G , NAs ) , Umbral , Arbol1 , Solucionado , Sol ) . 9 10 11 12 13 continuar ( Camino , t ( Nodo , F /G ,[ _ | As ]) , Umbral , Arbol1 , nunca , Solucionado , Sol ) : mejorF ( As , F1 ) , expandir ( Camino , t ( Nodo , F1 /G , As ) , Umbral , Arbol1 , Solucionado , Sol ) . Introducción Búsqueda primero en profundidad Búsqueda en amplitud Funciones auxiliares (1/2) 1 listaSuccs (_ ,[] ,[]) . 2 3 4 5 6 7 8 listaSuccs ( G0 ,[ Nodo / C | NCs ] , As ) : G is G0 + C , h ( Nodo , H ) , % Heuristic term h ( N ) F is G + H , listaSuccs ( G0 , NCs , As1 ) , insertarArbol ( hoja ( Nodo , F / G ) ,As1 , As ) . 9 10 11 12 insertarArbol (A , As ,[ A | As ]) : f (A , F ) , mejorF ( As , F1 ) , F = < F1 , !. 13 14 15 insertarArbol (A ,[ A1 | As ] , [ A1 | As1 ]) insertarArbol (A , As , As1 ) . :- Búsqueda primero el mejor Introducción Búsqueda primero en profundidad Búsqueda en amplitud Funciones auxiliares (2/2) 1 2 f ( hoja (_ , F / _ ) ,F ) . % f - valor de una hoja f ( arbol (_ , F /_ , _ ) ,F ) . % f - valor de un árbol 3 4 5 mejorF ([ A | _ ] , F ) : - f ( A , F ) . mejorF ([] , 9999) . 6 7 8 min (X ,Y , X ) : - X min (_ ,Y , Y ) . =< Y , !. Búsqueda primero el mejor