Information, Calcul, Communication Ce videoclip produit par l’Ecole Polytechnique Fédérale de Lausanne fait partie de son cours d’introduction à l’information, à la communication, et au calcul. Il s’inscrit dans le 1er module du cours qui offre une 1ere approche des notions de calcul et d’information. Information, Calcul, Communication 1. Information & Calcul – Leçon 2: Conception des Algorithmes Clip 7: Calcul du plus court chemin J. Sam, J-C. Chappelier, R. Boulic, commentaire: P. Janson
Plan de la leçon Introduction Approche descendante Divide & conquer Récursion Principe Exemple: les tours de Hanoï Terminaison Exemple: somme des N premiers nombres entiers Déroulement Exemple: tri par insertion Programmation dynamique Exemple: calcul du plus court chemin Sommaire et perspective Le dernier clip de cette leçon propose un autre exemple de programmation dynamique, le calcul du plus court chemin entre deux points, avant de résumer l’essentiel sur la conception des algorithmes et d’envisager la suite du cours.
Programmation dynamique – Calcul du plus court chemin Calcul du plus court chemin, par exemple entre toutes les gares du réseau CFF => Programmation dynamique selon l’algorithme de Floyd Principe de base Le plus court chemin de i (Lausanne) à j (Zurich) est le minimum entre le plus court chemin découvert jusqu’ici Dk-1(i,j) le chemin passant par une ville intermédiaire k (Bern) pas encore considérée jusqu’ici Dk(i,j) = min{ Dk−1(i,j), Dk−1(i,k)+Dk−1(k,j) } Zurich j 1 A titre d’exemple imaginons devoir calculer le trajet le plus rapide entre toutes les paires de gares du réseau des Chemins de Fer Fédéraux Suisse. 2 Floyd a proposé un algorithme pour résoudre ce problème par programmation dynamique. 3 Son principe de base est que le plus court chemin entre deux gares (dans le cas présent nous imaginerons Lausanne (gare i) et Zurich (gare j)) est le minimum entre … 4 … d’une part le chemin le plus court qu’on aurait pu découvrir par un calcul antérieur (nous l’appellerons ici Dk-1(i,j), chemin le plus court entre i et j au terme de la k-1e étape) dont on imagine ici qu’il aurait été calculé pour aller de Lausanne à Zurich via Neuchâtel. 5 … et un chemin potentiellement plus court qu’on pourrait découvrir en passant par une autre ville intermédiaire k (Bern dans cet exemple) via laquelle on n’a jusqu’ici pas encore calculé le chemin. 6 Selon ce principe, à la ke étape, le chemin de i à j Dk(i,j) est le minimum entre Dk−1(i,j), le plus court chemin découvert au terme de la k-1e étape et la somme des chemins partiels Dk−1(i,k) et Dk−1(k,j) via Bern découverts jusqu’ici. Neuchâtel Dk-1(k,j) k-1 k Bern Dk-1(i,j) Dk(i,j) Dk-1(i,k) i Lausanne
Calcul du plus court chemin – Algorithme de Floyd L’algorithme est donc le suivant, pour n gares dans le réseau Initialisation Pour i de 1 à n Pour j de 1 à n D(i,j) ← 0 si i=j distance directe de i à j selon horaire CFF ∞ si i & j ne sont pas directement connectés Déroulement Pour k de 1 à n D(i,j)←min{ D(i,j), D(i,k)+D(k,j) } Combien de boucles ? ☞ n3 ! 1 En faisant l’hypothèse que le réseau des CFF comporte n gares, l’algorithme complet serait donc le suivant: 2 Une 1e phase consiste à initialiser une table des distances D(i,j) entre toutes les paires de gares i et j. 3 De chacune des n gares … 4 … à chacune des n gares … 5 … on initialise la table en indiquant 0 comme distance entre une gare et elle-même, les valeurs données par les horaires des CFF pour toutes les paires de gares directement connectées et l’infini pour toutes les gares qui ne sont pas directement reliées. 6 Ensuite vient la phase de calcul des plus courts chemins indirects. 7 On imagine passer successivement par chacune des n gares intermédiaires … 8 … en route entre la ie gare … 9 … et la je gare. 10 Ce faisant on ajuste chaque fois D(i,j) à la valeur minimum entre sa dernière valeur calculée D(i,j) et la somme des dernières valeurs calculées pour le chemins partiels D(i,k) et D(k,j) passant par la gare k. 11 Si on prend du recul et on se demande alors combien d’étapes un tel calcul requiert … 12 … on voit aisément que les 3 boucles imbriquées de n étapes chacune impliquent un coût total de l’ordre de n3.
Algorithme de Floyd – Etapes du déroulement Temps de voyage CFF Lausanne Neuchâtel Bern Zurich 42 66 ∞ 34 89 56 D1 = D0 Zurich 4 On peut visualiser l’évolution du calcul de l’algorithme de Floyd dans le cas particulier du chemin Lausanne-Zurich. 1 Durant la phase d’initialisation, l’algorithme remplit une table n x n des distances entre les n villes du réseau directement connectées selon les tables des CFF, n étant égal à 4 dans notre exemple simplifié. La diagonale de cette table est nulle vu que le chemin de chaque ville à elle-même est évidemment de longueur nulle. Par contre les chemins Lausanne-Zurich et inverse sont infinis vu qu’il n’y a pas de connexion CFF directe entre ces villes. Cette table reste inchangée à l’étape k=1 puisque que de toute évidence aucun chemin passant par la ville k=1 (Lausanne) n’est plus court que les chemins directs renseignés par les CFF. 2 Par contre, à l’étape k=2 (Neuchâtel), le calcul révèle immédiatement que la somme des chemins Lausanne-Neuchâtel et Neuchâtel-Zurich (et leurs inverses) prennent évidemment moins de temps que le chemin Lausanne-Zurich ou retour qui étaient jusqu’ici inconnus et donc de durée infinie. Le résultat aurait été similaire si k=2 avait été via Bâle. 3 A l’étape suivante k=3 (via Bern) le calcul révèle une fois de plus que la somme des chemins Lausanne-Bern et Bern-Zurich (et leurs inverses) prennent encore moins de temps que le chemin qui passait par k=1 (Neuchâtel). La table est donc mise à jour en conséquence. La dernière itération via k=4 (Zurich) ne change évidemment plus rien à la table. Le chemin le plus court dans cet exemple est donc, comme prévu, via Bern. Si k=2 avait été via Bâle, k=3 via Neuchâtel, et k=4 via Bern, le calcul aurait requis une étape de plus, le chemin via Bern étant plus court que celui via Neuchâtel, qui est à son tour plus court que celui via Bâle. 89 Lausanne Neuchâtel Bern Zurich 42 66 131 34 89 56 D2 56 Neuchâtel 2 34 3 Bern Lausanne Neuchâtel Bern Zurich 42 66 122 34 89 56 D4 = D3 42 66 1 Lausanne
Algorithmes de calcul du plus court chemin en général L’algorithme de Floyd calcule le plus court chemin entre toutes les paires de gares en O(n3) étapes En appliquant le même principe de programmation dynamique L’algorithme de Dijkstra calcule le plus court chemin entre une gare donnée et toutes les autres en O(n2) étapes (L’algorithme A* (« A star ») est une généralisation de l’algorithme de Dijkstra plus efficace si on peut estimer une borne inférieure de la distance restant à parcourir) L’algorithme de Viterbi calcule le plus court chemin entre deux gares données en O(n) étapes Il existe beaucoup d’autres algorithmes en fonction des conditions spécifiques (graphe orienté/non orienté, graphe à cycles ou sans cycle, coût positifs ou quelconques) 1 L’algorithme de Floyd juste étudié fournit donc en O(n3) étapes le chemin le plus court entre toutes les paires de gares du réseau. 2 En appliquant le même principe de programmation dynamique, l’algorithme de Dijkstra fournit en O(n2) étapes le chemin le plus court entre une gare donnée et toutes les autres, l’itération sur i étant inutile. 3 Une généralisation de l’algorithme de Dijkstra est l’algorithme A* qui est plus efficace si on peut lui fournir une estimation pour la borne inférieure du chemin restant à parcourir. Cela lui permet d’éviter de calculer certains chemins visiblement trop couteux. 4 En appliquant toujours le même principe de programmation dynamique, l’algorithme de Viterbi fournit en O(n) étapes le chemin le plus court entre deux gares données, les itérations sur i ET j étant dans ce cas spécifique inutiles. 5 En pratique il existe plein d’autres algorithmes permettant diverses optimisations selon les conditions spécifiques telles que par exemple des réseaux orientés ou non, des réseaux avec ou sans cycles, ou des coûts de chemins positifs ou quelconques en distance, en temps, en prix ou en toute autre mesure.
Conclusion 1 Problèmes typiques : recherche, tri, plus « court » chemin La conception d’une méthode de résolution automatisée d’un problème consiste à choisir les bons algorithmes et les bonnes structures de données Formalisation des données : structures de données abstraites (voir leçon 1.4) Formalisation des traitements : algorithmes Trouver des solutions algorithmiques correctes Distinguer formellement les solutions efficaces des inefficaces Pour résumer les enseignements de cette leçon, … 1 … il existe une multitude de problèmes qui tombent le plus souvent dans l’une des grandes catégories telles que recherche, tri, calcul du plus court chemin, etc. 2 La conception d’une méthode permettant de résoudre systématiquement un problème quelconque consiste à choisir non seulement un algorithme ad hoc mais aussi des structures de données appropriées. 3 D’un point de vue formel, cela exige la définition de structures de données abstraites, ce qui sera le sujet de la 4e leçon de ce 1er module de cours … 4 … ainsi que d’algorithmes … 5 … qui doivent être non seulement corrects … 6 … mais encore efficaces de façon quantifiable.
Conclusion 2 Le choix de bons algorithmes et de bonnes structures de données n’est pas une tâche triviale Il n’y a pas de recette miracle pour cela mais il existe des grandes familles de stratégies de résolution Décomposer (« Divide and Conquer ») Essayer de résoudre le problème en le décomposant en instances plus simples Les algorithmes récursifs sont des illustrations de cette stratégie Regrouper (« Programmation Dynamique ») Mémoriser les calculs intermédiaires pour éviter de les effectuer plusieurs fois 1 Le choix de bons algorithmes et de bonnes structures de données pour un problème spécifique n’est pas une tâche triviale. 2 Il n’y a pas de recette miracle mais il existe à cette fin des grandes familles de stratégies de résolution 3 Une des principales consiste décomposer un problème en des instances plus simples de lui-même. 4 Les algorithmes récursifs sont des archétypes de ce genre de stratégie. 5 Une autre classe de stratégie importante – la programmation dynamique – consiste à regrouper et conserver les résultats de problèmes simples rencontrés en cours de calcul pour éviter de devoir les recalculer plusieurs fois lors de la résolution de problèmes plus compliqués.
Qu’est-ce qui est calculable et ne l’est pas ? La suite … La prochaine leçon (1.3) Qu’est-ce qui est calculable et ne l’est pas ? La leçon sursuivante (1.4) Comment représenter l’information (les données sur lesquelles calculer) ? 1 A ce stade nous sommes à même d’aborder la 3e leçon du 1er module de ce cours, qui va tenter de tirer une ligne de démarcation plus ou moins claire entre les problèmes pour lesquels des solutions sont calculables et des problèmes qui semblent jusqu’ici insolubles de façon algorithmique. 2 De là nous enchaînerons sur la 4e et dernière leçon du 1er module de ce cours, qui va porter sur la façon de représenter l’information et de structurer les données à traiter et les résultats du traitement.