Algorithme de Moore-Dijkstra
Fonctionnalités de l'algorithme de Moore-Dijkstra
- Moore-Dijkstra est un algorithme de recherche de chemin extrême.
- Moore-Dijkstra est utilisé sur des graphes pondérés1
- Moore-Dijkstra s'applique aux graphes dont toutes les pondération sont positives ou nulles2. Il n'accepte pas les pondérations négatives2.
- Moore-Dijkstra donne un résultat erroné pour la recherche de chemins extrémaux si le graphe ne possède pas de circuit.
Caractéristiques de l'algorithme de Moore-Dijkstra
Nous sommes à la recherche du chemin le plus court. Cela signifie que la somme des poids des arcs du chemin sélectionné doit être le plus faible possible.
L'algorithme de Moore-Dijkstra est une amélioration de l'algorithme de Floyd. Il est plus complexe que ce dernier, mais son exécution est beaucoup plus rapide.
Si nous sommes certains que notre graphe présente un ou plusieurs circuits, nous pouvons appliquer l'algorithme de Moore-Dijkstra qui nous permet une exploration progressive, sans back-tracking (retours en arrière)3.
Nous utiliserons un ensemble D (definedVertices) qui contiendra les sommets traités.
Au départ, definedVertices contient seulement le sommet racine4.
Principe de relâchement
Nous allons fixer une valeur tellement haute5 que tout au long de l'exécution de l'algorithme nous ne devrons jamais définir de nouvelles valeurs qui lui soient égales ou supérieures.
Le principe de relâchement nous permet d'utiliser cette borne supérieure sur le poids du plus court chemin, et de diminuer progressivement cette borne.
A chaque étape, nous devons choisir le sommet x à traiter parmi les sommets non encore traités, avec le chemin de poids le plus faible depuis le sommet précédent (x->y).
Il s'agit d'un choix glouton6, qui dans ce cas se révèle optimal.
Nous retirons ensuite x des sommets à traiter (en ajoutant son indice dans definedVertices).
Nous devons maintenant consulter les poids de x vers tout sommet non traité.
Pour tous les sommets non traités restants, nous comparons le poids du chemin (r->x->y) entre la racine r et ce sommet y en passant par x.
Si le poids du nouveau chemin est inférieur au poids précédent (dans pathMinWeights), il est retenu comme meilleur chemin, et la valeur de pathMinWeights est remplacée par ce meilleur chemin, et donc diminuée (relâchement).
Code de l'algorithme de Moore-Dijkstra
Nous pouvons décomposer notre algorithme en deux phases : une phase d'initialisation des valeurs, et une phase d'exécution qui décrit ce qui se passe lorsque l'algorithme est exécuté.
Variables
Dans cette approche, nous utilisons des collections indexées (par exemple des tableaux) pour maintenir les différentes informations relatives aux états de chaque objet Sommet. Dans une approche "orienté-objet", nous pouvons maintenir ces informations par exemple dans l'objet Sommet lui même.
- verticesLabels est le tableau qui contient les étiquettes. L'étiquette d'un sommet x est l'indice du sommet y précédent de x dans le chemin optimum de la racine vers le sommet x.
- pathMinWeights est le tableau du coût (poids) des chemins depuis la racine jusqu'aux différents sommets.
pathMinWeights[i] est le poids du chemin entre la racine et le sommet X[i]. - definedVertices est le tableau qui contient les sommets traités (définis comme ∈ au chemin à renvoyer).
Nous utiliserons aussi certaines variables supplémentaires :
- X est l'ensemble des sommets du graphe
- n est le nombre de sommets du graphe (la cardinalité de X).
arrayFirstIndex : indice du premier élément dans un tableau7.
Phase d'initialisation
- k := arrayFirstIndex // Le compteur pointe sur le premier élément d'un tableau.
- j := indice_de_la_racine // indice (dans X) du sommet racine (départ du chemin).
- Sommets traités :
- definedVertices[k] := j //la racine fait d'office partie du chemin, car elle est le point de départ4. Nous pouvons donc stocker au premier emplacement de definedVertices l'indice (dans X) du sommet de départ.
- ∀(i > k) : definedVertices[i] := arrayFirstIndex-1 // Initialisation du tableau avec une valeur hors des limites du tableau8.
- Poids (r->x) :
- pathMinWeights[definedVertices[k]] := 0 // Le chemin de la racine vers la racine a un poids égal à zéro.
- ∀(i > k) pathMinWeights[i] := 2maxCost // Valeur hors des limites du possible (double de maxCost5).
- Étiquettes :
- verticesLabels[definedVertices[k]] := arrayFirstIndex // Étiquette de la racine. Pointe vers un emplacement non valide car la racine n'a pas de précédent.
- ∀(i > k) verticesLabels[i] := arrayFirstIndex-1 // Initialisation du tableau avec une valeur hors des limites du tableau8.
Phase d'exécution
Code (Pseudo-code de Moore-Dijkstra) (31 lignes)
//Il reste des sommets non traités /*i est l'indice de x, j est l'indice de y x est non traité, et le chemin(r,x) est le plus court de tous les chemins de r vers un sommet non traité */ (pathMinWeights[i]=minimum{pathMinWeights[j]∀j∈ X\definedVertices})}; //k pointe à présent sur le prochain emplacement libre de definedVertices k := k+1; //i est défini comme étant traité definedVertices[k] := i; //vérifier si ce chemin est le meilleur /*si x est un précédent de y sur un chemin plus court que le meilleur chemin actuel...*/ //le poids du chemin vers "y" est mis à jour pathMinWeights[j] := pathMinWeights[i]+weight(i,j); //j est l'indice du sommet précédent de "x" verticesLabels[i] := j;
Remarques
A la ligne 2, le test de comparaison k < n s'applique aux langages pour lesquels le premier indice d'un tableau est 0. Dans le cas où le premier indice est 1, nous devons remplacer le test par k ≤ n.
Nous pouvons éviter de calculer un certain nombre de fois l'opération pathMinWeigths[j]+weight(j,i) en utilisant une fonction memo qui effectuera seulement les calculs nécessaires.
//vérifier si ce chemin est le meilleur tempWeight := memo(pathMinWeights[i]+weight(i,j)); /*si x est un précédent de y sur un chemin plus court que le meilleur chemin actuel...*/ //le poids du chemin vers "y" est mis à jour pathMinWeights[j] := tempWeight; //j est l'indice du sommet précédent de "x" verticesLabels[i] := j;
Pourquoi utiliser l'algorithme de Moore-Dijkstra
Même si nous utilisons une stratégie gloutonne6, l'algorithme de Moore-Dijkstra nous retourne toujours le chemin optimum, pour autant que les hypothèses de départ sur notre graphe s'avérent exactes (notamment le fait que le graphe ne possède aucun arc de poids négatif). L'algorithme de Moore-Dijkstra est plus rapide que l'algorithme de Ford-Bellman.
Lorsque nous sommes en possession de bornes (sommet de départ, sommet d'arrivée, etc.), nous préférerons l'algorithme de l'heuristique A*, qui est plus rapide que l'algorithme de Moore-Dijkstra, car il limitera l'exploration aux sommets qui sont "dans la direction" de l'arivée au lieu d'évaluer les sommets "tout azimut".
Exemples d'application de l'algorithme de Moore-Dijkstra
Nous pouvons avoir, au lieu d'un graphe, un tableau à double entrée dans lequel chaque sommet est une colonne et une ligne. Chaque cellule contient donc le poids (la distance, le coût, etc.) entre deux sommets (villes).
Ce type de représentation (par exemple les distances entre différentes villes) est totalement identique à un graphe dont les arêtes (trajet entre deux villes) sont pondérées (distance entre deux villes).
Le protocole de routage IP OSPF (Open Shortest Path First) utilise l'algorithme de Dijkstra pour déterminer la route la plus courte vers les différents réseaux.
Version en cache
21/11/2024 09:38:04 Cette version de la page est en cache (à la date du 21/11/2024 09:38:04) afin d'accélérer le traitement. Vous pouvez activer le mode utilisateur dans le menu en haut pour afficher la dernère version de la page.Document créé le 27/12/2009, dernière modification le 26/10/2018
Source du document imprimé : https://www.gaudry.be/graphes-moore-dijkstra.html
L'infobrol est un site personnel dont le contenu n'engage que moi. Le texte est mis à disposition sous licence CreativeCommons(BY-NC-SA). Plus d'info sur les conditions d'utilisation et sur l'auteur.
- ↑ pondération : La pondération est une valeur associée à un arc (ou une arête), et correspond au coût du passage par cet arc. Par exemple, il peut s'agir d'une distance entre deux villes représentées chacune par un sommet du graphe.
- ↑a,b Moore-Dijkstra & poids négatifs : L'algorithme de Moore-Dijkstra ne permet pas la présence de pondération négative dans notre exemple car nous sommes à la recherche de chemin extrême minimum. Dans le cas de la recherche d'un chemin extrême maximum avec l'algorithme de Moore-Dijkstra le graphe ne peut contenir aucun arc de pondération positive, et nous devons légèrement modifier le pseudo code.
- ↑ retour en arrière : Les résultats stockés dans l'ensemble D sont acquis au fur et à mesure, et ne sont plus mis en doute par la suite.
- ↑a,b definedVertices[k] := indice_de_la_racine : Dans certains exemples de pseudo code de l'algorithme de Moore-Dijkstra, nous trouvons une initialisation D := ∅ (un ensemble vide pour les sommets déjà traités), contrairement à l'algorithme de Bellman-Kalaba pour lequel D contient seulement le sommet racine.
Cela impose des contraintes superflues lors de l\implémentation, car il faut alors choisir la racine pour y uniquement lors du premier passage dans la boucle.
Par rapport à notre pseudo code de l'algorithme de Bellman-Kalaba, l'incrémentation de k se fait alors après avoir marqué le sommet comme "traité", car definedVertices est dans ce cas initialement vide.
Nous utiliserons donc le même type d'initialisation que pour Bellman-Kalaba pour éviter ces désagréments. - ↑a,b maxCost : La majorité des pseudo codes utilisent le symbole ∞ (infini) pour représenter une valeur hors des limites du possible, et dont les variations sont insignifiantes. JP Leclercq nous propose donc de travailler avec une valeur qui correspond à la somme des poids des arcs du graphe, car l'infini est une notion qui existe en mathématiques, mais qui ne correspond pas toujours à la réalité de la programmation. Nous utiliserons la notation maxCost, ou même 2maxCost dans les algorithmes pour lesquels cette valeur n'est pas suffisante.
- ↑a,b Choix glouton : L'algorithme de Moore-Dijkstra choisit le plus faible poids sur le moment, en espérant que la succession de choix de meilleure solution à court terme mène à la meilleure solution finale.
- ↑ arrayFirstIndex : Ce n'est pas à proprement parler une variable, mais cela me permet d'éviter d'écrire 0 ou 1 dans le pseudo-code de l'algorithme selon le type de langage utilisé.
Selon l'implémentation choisie, la collection utilisée peut démarrer son indexation à 0 (ex : tableau en Java) ou à 1 (ex : tableau en Pascal). Par exemple, en Java nous initialisons avec ∀i : previousVertices[i] = 0 - ↑a,b arrayFirstIndex-1 : Comme nous sélectionnons une valeur qui précède le premier indice du tableau, cela signifie que la valeur n'est pas encore significative.
Références
- INFOB321 - Théorie des graphes : JP Leclercq,
Cours de Théorie des Graphes et réseaux de Petri
(September 2008) - Implémentation : Sébastien BOUCLET ,
Implémentation de l'algorithme de Moore Dijkstra
(version 28/12/09) - Graph Theory Applet : Rensselaer Polytechnic Institute,
Démonstration interactive par applet Java
(version 28/12/09) - Applet : Cara Laffra,
L'algorithme de Dijkstra
(version 28/12/09)
Ces références et liens indiquent des documents consultés lors de la rédaction de cette page, ou qui peuvent apporter un complément d'information, mais les auteurs de ces sources ne peuvent être tenus responsables du contenu de cette page.
L'auteur de ce site est seul responsable de la manière dont sont présentés ici les différents concepts, et des libertés qui sont prises avec les ouvrages de référence. N'oubliez pas que vous devez croiser les informations de sources multiples afin de diminuer les risques d'erreurs.