Clase | Algoritmo de búsqueda |
---|---|
Estructura de datos | Grafico |
Algoritmos de búsqueda de gráficos y árboles |
---|
Listados |
Temas relacionados |
LPA * o Lifelong Planning A * es un algoritmo de búsqueda heurística incremental basado en A * . Fue descrito por primera vez por Sven Koenig y Maxim Likhachev en 2001. [1]
LPA * es una versión incremental de A *, que puede adaptarse a los cambios en el gráfico sin recalcular el gráfico completo, actualizando los valores g (distancia desde el inicio) de la búsqueda anterior durante la búsqueda actual para corregirlos cuando sea necesario. Al igual que A *, LPA * utiliza una heurística, que es un límite inferior para el costo de la ruta desde un nodo determinado hasta el objetivo. Una heurística es admisible si se garantiza que no será negativa (cero es admisible) y nunca mayor que el costo del camino más barato hacia la meta.
Con la excepción del nodo de inicio y objetivo, cada nodo n tiene predecesores y sucesores :
En la siguiente descripción, estos dos términos se refieren únicamente a los predecesores y sucesores inmediatos , no a los predecesores de predecesores o sucesores de sucesores.
LPA * mantiene dos estimaciones de la distancia inicial g * ( n ) para cada nodo:
Para el nodo de inicio, lo siguiente siempre es válido:
Si rhs ( n ) es igual a g ( n ) , entonces n se llama localmente consistente . Si todos los nodos son consistentes localmente, entonces se puede determinar una ruta más corta como con A *. Sin embargo, cuando los costos de borde cambian, la consistencia local debe restablecerse solo para aquellos nodos que son relevantes para la ruta.
Cuando un nodo se vuelve localmente inconsistente (porque el costo de su predecesor o el borde que lo vincula a un predecesor ha cambiado), se coloca en una cola de prioridad para su reevaluación. LPA * utiliza una clave bidimensional:
Las entradas están ordenadas por k 1 (que corresponde directamente a los valores f usados en A *), luego por k 2 .
El nodo superior de la cola se expande de la siguiente manera:
Dado que cambiar el valor g de un nodo también puede cambiar los valores rhs de sus sucesores (y por lo tanto su consistencia local), se evalúan y su membresía de cola y clave se actualiza si es necesario.
La expansión de nodos continúa con el siguiente nodo en la parte superior de la cola hasta que se cumplen dos condiciones:
El gráfico se inicializa estableciendo el valor rhs del nodo de inicio en 0 y su valor g en infinito. Para todos los demás nodos, se supone que tanto el valor g como el valor rhs son infinitos hasta que se asignen de otro modo. Esto inicialmente hace que el nodo de inicio sea el único nodo localmente inconsistente y, por lo tanto, el único nodo en la cola. Después de eso, comienza la expansión del nodo. La primera ejecución de LPA * se comporta de la misma manera que A *, expandiendo los mismos nodos en el mismo orden.
Cuando cambia el costo de un borde, LPA * examina todos los nodos afectados por el cambio, es decir, todos los nodos en los que termina uno de los bordes cambiados (si un borde puede atravesarse en ambas direcciones y el cambio afecta a ambas direcciones, ambos nodos están conectados por se examinan el borde):
Después de eso, la expansión del nodo se reanuda hasta que se alcanza la condición final.
Una vez que la expansión del nodo ha finalizado (es decir, se cumplen las condiciones de salida), se evalúa la ruta más corta. Si el costo de la meta es infinito, no hay un camino de costo finito desde el principio hasta la meta. De lo contrario, el camino más corto se puede determinar retrocediendo:
Este código asume una cola de prioridad queue
, que admite las siguientes operaciones:
topKey()
devuelve la prioridad más baja (numéricamente) de cualquier nodo en la cola (o infinito si la cola está vacía)pop()
elimina el nodo con la prioridad más baja de la cola y lo devuelveinsert(node, priority)
inserta un nodo con una prioridad determinada en la colaremove(node)
elimina un nodo de la colacontains(node)
devuelve verdadero si la cola contiene el nodo especificado, falso si novoid main () { inicializar (); while ( verdadero ) { computeShortestPath (); while ( ! hasCostChanges ()) sleep ; para ( borde : getChangedEdges ()) { borde . setCost ( getNewCost ( borde )); updateNode ( borde . endNode ); } } }void initialize () { cola = new PriorityQueue (); para ( nodo : getAllNodes ()) { nodo . g = INFINITO ; nodo . rhs = INFINITO ; } inicio . rhs = 0 ; cola . insertar ( iniciar , calcularClave ( inicio )); }/ ** Expande los nodos en la cola de prioridad. * / void computeShortestPath () { while (( cola . getTopKey () < calculateKey ( objetivo )) || ( objetivo . rhs ! = objetivo . g )) { nodo = cola . pop (); si ( nodo . g > nodo . rhs ) { nodo . g = nodo . rhs; para ( sucesor : nodo . getSuccessors ()) updateNode ( sucesor ); } else { nodo . g = INFINITO ; updateNode ( nodo ); para ( sucesor : nodo . getSuccessors ()) updateNode ( sucesor ); } } }/ ** Recalcula rhs para un nodo y lo elimina de la cola. * Si el nodo se ha vuelto localmente inconsistente, se (re) inserta en la cola con su nueva clave. * / void updateNode ( nodo ) { if ( nodo ! = inicio ) { nodo . rhs = INFINITO ; para ( predecesor : nodo . getPredecessors ()) nodo . rhs = min ( nodo . rhs , predecesor . g + predecesor . getCostTo ( nodo )); if ( cola . contiene ( nodo )) cola . eliminar ( nodo ); if ( nodo . g ! = nodo . rhs ) cola . insert ( nodo , calculateKey ( nodo )); } }int [] calculateKey ( nodo ) { retorno { min ( nodo . g , nodo . rhs ) + nodo . getHeuristic ( objetivo ), min ( nodo . g , nodo . rhs )}; }
[2]
Al ser algorítmicamente similar a A *, LPA * comparte muchas de sus propiedades.
Para una implementación A * que rompe los lazos entre dos nodos con valores f iguales a favor del nodo con el valor g más pequeño (que no está bien definido en A *), las siguientes afirmaciones también son verdaderas:
Además, LPA * tiene las siguientes propiedades: