Herramientas de usuario

Herramientas del sitio


ai:techniques:search_algorithms

¡Esta es una revisión vieja del documento!


Algoritmos de búsqueda

A*

Es un algoritmo que se basa en tratar la evolución de estados de un problema como si de un grafo se tratase. Los nodos de este grafo son los posibles estados del problema, y estos pueden representar cualquier cosa, desde una coordenada 2d hasta la posición de las piezas de un puzle.

Los nodos se unen por aristas, estas corresponden a los cambios que hay que hacer para cambiar de un estado a otro. De un nodo salen tantas aristas como cambios inmediatos pueden hacerse.

A cada nodo del árbol se le asigna un coste, este coste corresponde a lo cerca que está un estado del estado final, es decir, la solución. La forma de calcular el coste es distinta para cada problema y a la vez importante para su resolución. Cuando el estado final es desconocido o complejo de calcular podemos indicar que el coste del nodo corresponde a la dificultad que plantea tomarlo, por ejemplo, en una carrera un terreno plano tendrá menos costo que una subida.

Para llevar a cabo el algoritmo A* necesitaremos…

  • Los tres atributos, como mínimo que tendrá cada nodo del grafo de estados:
    • g, el coste de tomar ese nodo. Este es el coste de llevar a cabo la acción que representa dicho nodo más el coste de su padre.
    • h, cuanto dista nodo del objetivo, este valor más que ser una distancia “física” es una función heurística que calcula “las diferencias”.
    • f, el fitness del nodo, una puntuación que represente su calidad. f = g + h
  • Dos listas:
    • La lista de los nodos abiertos, los que aún no han sido (o no han podido ser) explorados. En él iremos colocando los nodos que vayamos encontrando pero que aún no han sido tratados.
    • La lista de los nodos cerrados, los que han sido explorados.

El algoritmo

Partiendo de un estado que será el denominado “estado actual”…

  1. Encontramos los próximos estados.
    1. Del estado actual encontramos los posibles estados siguientes.
    2. Calculamos la g y la h (1 más la h del nodo padre) de ese nodo.
    3. Guardamos estos nodos en la lista de nodos abiertos.
  2. Ponemos el nodo actual en la lista de nodos cerrados.
  3. Elegimos el siguiente nodo actual.
    1. De todos los nodos de la lista de nodos cerrados escogemos el de f más baja.
  4. Si el estado actual es el estado objetivo ya hemos acabado. Si no, volvemos al paso 1.

Solución de un puzzle

Como ejemplo al estudio del A* haremos un seguimiento del algoritmo en la resolución de un puzzle de 8 fichas, un 3×3.
Se seguirá el siguiente diagrama que parte de un posible estado (1) e intenta llegar a un objetivo (4) utilizando el A*. Aunque para cada problema el cálculo del parámetro h es distinto y en él radica la calidad de la solución, en este se ha utilizado la Distancia Manhattan (aunque se podría haber utilizado cualquier otra). La forma concreta de cálculo ha sido: h = r(sum{i=n}{n}{{dManhattan_i}^2})
Siendo r el número de piezas mal colocadas en cada iteración, con esto conseguimos dar más puntuación a aquel estado que tiene más fichas mal colocadas. La i, por lo tanto sería el número de pieza.

  1. Desde un estado (1) el algoritmo calcula el f,g y h de este.
  2. Luego encuentra los estados posibles (2) y (3), calcula de cada uno de estos f,g y h y los introduce en la lista de abiertos.
  3. Coloca el estado (1) en la lista de cerrados.
  4. En la lista de abiertos comprueba qué h es más baja, la del estado (2).
  5. El estado (2) es el objetivo? No, por lo que seguirá expandiendo el árbol a partir de este.
  6. Del estado (2) encuentra el (4) y el (5), calcula sus f, g, h y los introduce en la lista de abiertos.
  7. Coloca el estado (2) en la lista de cerrados.
  8. Comprueba cual de los de la lista de abiertos ((3), (4), (5)) tiene el f más pequeño.
  9. Escoge el (4).
  10. Es el objetivo? Sí → fin!.

Y aquí una implementación.

Hill-Climbing

El hill-climbing (también llamado rather descent si su función evalua el coste en vez de la calidad, aunque también podríamos convertir el valor de coste a negativo) intenta, sobre una solución ya existente del problema qué cambios hay que hacer hasta conseguir una solución mejor.
Representa la búsqueda que realiza como si fuese un escalador que busca la cima de un monte pero este no sabe cual es, ya que un monte puede tener varios picos y el escalador puede creer que un pico es la cima.
El algoritmo consiste en un bucle que busca incrementar la calidad de una situación. Empieza con una solución inicial (generada aleatoriamente) y de forma iterativa va haciendo pequeños cambios hasta llegar a la solución mejor que pueda encontrar, entonces usa dicha solución como solución inicial y así continúa. Por lo tanto no depende de un árbol de búsqueda (nodos) por lo que el problema le ha de permitir evaluar dichos nodos (o estados) de forma independiente. Cuando los estados a los cuales se puede acceder desde el estado actual tienen un valor equivalente el siguiente que se evaluará se seleccionará aleatoriamente. En este algoritmo se distinguen los siguientes conceptos:

  • Máxima local: Consiste en un “pico” que puede ser más bajo que el pico más alto (óptimo) y es al que ha de llegar ya que, aún no siendo la mejor solución es una satisfactoria.
  • Explanada: Un area en el que al evaluar los siguientes pasos tenemos un valor equivalente. La búsqueda seguirá un camino aleatorio.
  • Colinas: Hay máximas locales muy próximas y la búsqueda oscila entre ellas haciendo mínimo o ningún progreso. Si esto ocurre lo mejor que puede hacerse es reiniciar en otro punto aleatorio.


Realmente el algoritmo lo que hace es iniciar en una solución aleatoria y busca una mejor y próxima solución hasta encontrar una que no pueda mejorar. Puede restringirse el número de iteraciones. Si hay suficientes iteraciones permitidas un reinicio aleatorio puede llegar a encontrar la solución óptima. El éxito depende de la diversidad de estados “picos”, si sólo existen pocas máximas locales un reinicio aleatorio encontrará una solución óptima bastante rápido, pero por desgracia los problemas reales tienen una superficie parecida a la de un puercoespín. Aún así es fácil encontrar rápidamente una buena solución.

function Hill-Climbing (problema) retorna una posible solución
  entrada: problema
  utiliza: currentNode, nextNode
  currentNode = getInitialState (problem)
  loop do
    nextNode = currentNode.getSuccessors().getNodeWithMaximumValue()
    if (nextNode.value < currentNode.value)
      return current
    currentNode = nextNode
  end loop 

Variantes

Simulated annealing

ai/techniques/search_algorithms.1287909764.txt.gz · Última modificación: 2020/05/09 09:24 (editor externo)