Visualiseur d'algorithmes de recherche de chemin

observez différents algorithmes de recherche s'affronter sur la même grille, front par front

Chargement de la simulation interactive...

Leçon

La théorie — Visualiseur d'algorithmes de recherche de chemin

Trois des quatre algorithmes du menu déroulant sont un seul et même algorithme. Ils classent tous les cellules en attente d'exploration à l'aide d'une seule expression, f(n) = g(n) + h(n) — le coût accumulé plus l'estimation du coût restant — et ne diffèrent que par celui des deux termes qu'ils conservent. Retirez h et vous obtenez l'algorithme de Dijkstra. Ignorez g et vous obtenez Greedy Best-First. Le quatrième, le parcours en largeur (BFS), est ce à quoi se réduit l'algorithme de Dijkstra lorsque chaque déplacement coûte la même chose.

Ce que signifie chaque symbole

g(n)
le coût du trajet le moins cher trouvé jusqu'ici du départ à la cellule n. Un déplacement latéral ou vertical coûte 1 ; une diagonale coûte √2, car le déplacement est mesuré sous forme de longueur plutôt que compté comme un seul mouvement.
h(n)
l'estimation du coût restant à parcourir. Pour l'algorithme de Dijkstra et le parcours en largeur (BFS), elle n'est pas seulement inutilisée — elle est zéro, et c'est précisément ce qui en fait la même expression avec un terme en moins.
f(n)
la clé de classement : la cellule avec le plus petit f est celle explorée ensuite. Elle est affichée au-dessus de la grille avec les valeurs numériques de la cellule actuelle substituées, de sorte que le choix que l'algorithme vient de faire soit visible plutôt qu'affirmé.
frontier
les cellules ambres — découvertes, mais pas encore explorées. Nœuds développés compte ce qui a quitté cet ensemble, ce qui en fait une mesure du travail effectué, non de la qualité de la réponse.

D’où vient la formule

  1. Définissez ce que signifie « le plus court » avant de choisir un algorithme. Le coût d'un chemin est la somme des longueurs de ses étapes : 1 pour un déplacement latéral ou vertical, √2 pour une diagonale. On ne compte pas les cellules ; on additionne les distances.
  2. Voici maintenant la boucle, identique pour les quatre : retirez une cellule du front, marquez-la comme explorée, et proposez à nouveau chaque voisin franchissable au front avec un g mis à jour. Remarquez ce que cette boucle ne mentionne jamais — une heuristique, la direction de l'arrivée, ou l'algorithme que vous avez choisi.
  3. La seule décision restante est donc quelle cellule retirer, et cela tient en une seule expression. Classez par g + h et vous avez la Recherche A*. Fixez h = 0 et le classement se fait uniquement selon le coût accumulé — c'est l'algorithme de Dijkstra, qui s'étend vers l'extérieur en cercles concentriques parce qu'il n'a aucune idée d'où se trouve l'arrivée. Ignorez plutôt g et le classement se fait uniquement selon l'estimation — c'est Greedy Best-First, qui fonce vers l'arrivée et accepte n'importe quel itinéraire auquel il est parvenu.
  4. Le parcours en largeur (BFS) ne classe pas du tout : premier entré, premier sorti. Lorsque l'option Autoriser les diagonales est désactivée, chaque étape coûte exactement 1, donc l'ordre d'arrivée des cellules est l'ordre des g croissants — et le parcours en largeur explore donc exactement ce qu'explore l'algorithme de Dijkstra. Vous pouvez le vérifier sans régénérer la grille : basculez entre les deux et Nœuds développés ne bouge pas. Activez les diagonales et l'argument s'effondre, car une diagonale coûte √2 plutôt que 1 et l'ordre d'arrivée ne suit plus le coût.

Comment lire ce que vous voyez

Le score de priorité se trouve au-dessus de la grille avec les valeurs g et h propres à la cellule actuelle remplies, afin que vous puissiez lire le classement qui a produit le dernier choix. En dessous se trouvent deux compteurs : Nœuds développés et Longueur du chemin. L'ambre représente le front, l'indigo est déjà exploré. Changer d'algorithme ne génère pas de nouvelle grille, et c'est ce qui donne toute sa valeur à la comparaison — sur la même disposition, le nombre de Nœuds développés de l'algorithme de Dijkstra n'est jamais inférieur à celui de la Recherche A*, et celui de Greedy Best-First n'en représente qu'une petite fraction.

Suppose
Des coûts d'étape qui ne sont jamais négatifs, et une grille qui ne change pas pendant l'exécution de la recherche. Le départ est toujours la cellule en haut à gauche et l'arrivée celle en bas à droite. La fermeture d'une cellule est définitive — la boucle ne revient jamais sur une cellule — et cela n'est sûr que parce qu'aucun itinéraire ultérieur ne peut arriver à moindre coût lorsque chaque étape ajoute une quantité non négative.
Ne tient plus quand
Nœuds développés est le nombre qui varie le plus spectaculairement, et ce n'est pas une mesure de qualité. Choisissez Greedy Best-First : sur la même grille, il explore une petite fraction de ce que fait la Recherche A*, et sur la plupart des dispositions, il renvoie une Longueur du chemin plus grande. Générez quelques nouvelles grilles et observez les deux compteurs évoluer dans des directions opposées. Examiner moins de cellules indique à quel point l'algorithme a travaillé dur, et jamais la qualité de sa réponse.

pourquoi les heuristiques comptent 🖖

La formule f(n)=g(n)+h(n) fait préférer à A* les nœuds peu coûteux jusqu'ici et qui semblent encore proches de l'arrivée. Si h ne surestime jamais le coût restant, A* conserve sa garantie de plus court chemin ; une heuristique admissible plus forte explore moins de cellules inutiles. Changez le menu déroulant d'algorithme pour voir ce qui se passe si l'on retire l'heuristique (Dijkstra), le coût déjà payé (Greedy), ou tout système de score (BFS).

Une boucle, quatre personnalités 🖖

Les quatre algorithmes répètent exactement la même boucle : retirer de la liste d’attente la case qui paraît la plus prometteuse — la frontière ambrée —, la marquer comme visitée (indigo), puis ajouter à la liste ses voisines accessibles. Seule change la manière de déterminer quelle case semble la plus prometteuse. Le nombre de nœuds développés permet de les départager, et son évolution réserve une surprise. Sur une grille vide, A* développe toutes les cases : avec la distance de Manhattan, tous les chemins monotones vers le coin obtiennent le même score f, si bien qu’aucun ne peut être privilégié. Ajoutez des obstacles, et ce nombre diminue.

Les diagonales peuvent briser la garantie 🖖

Activez 'Autoriser les diagonales' avec l'heuristique de Manhattan et A* peut discrètement renvoyer un chemin qui n'est pas le plus court. Ici un pas diagonal ne coûte que √2 ≈ 1.41, mais la distance de Manhattan le facture 2 — l'heuristique surestime donc, devient non admissible, et la garantie d'optimalité est perdue. Passez à Euclidienne, qui ne dépasse jamais la distance à vol d'oiseau, et le plus court chemin revient.

Parcours

Compter le travail, pas les secondes

Références (3)

Exemples de problèmes

  • grille ouverte - Une grille de 20 × 20 dont un dixième est bloqué ; A* en développe encore la majeure partie. Tous les chemins monotones ont un score f = 38, si bien que rien ne les départage.
  • façon labyrinthe - Les obstacles accélèrent A*. Une densité de blocage de 0,28 élimine les égalités qui rendent une grille ouverte coûteuse, et la recherche se limite à environ la moitié des cases libres.
  • heuristique faible - Sur une grille ouverte à 4 voisins, la distance de Manhattan est exacte, tandis que la distance euclidienne la sous-estime toujours : des deux heuristiques admissibles, cette dernière est donc la moins informative. Même chemin, mais environ un tiers de cases en plus.
  • Dijkstra explore - La même grille de 24 × 24, avec la même densité de 0,22 que dans « Mauvaise heuristique », mais sans aucune heuristique. Comme il ignore la direction du but, Dijkstra développe environ moitié plus de cases qu’A*.
  • piège greedy - La recherche gloutonne n’évalue que h : elle fonce vers le but et développe moins de la moitié des cases explorées par A*. En contrepartie, elle revient le plus souvent avec un chemin plus long.
  • bfs + diagonales - Le parcours en largeur ne dispose d’aucune information sur le but et atteint donc presque toutes les cases accessibles. Lorsque les diagonales sont autorisées, chacune compte pour un pas : il minimise le nombre de déplacements, pas la distance.