Chapitre 4. Le voyageur de commerce (TSP)
Transcription
Chapitre 4. Le voyageur de commerce (TSP)
4. Chapitre 4. Le voyageur de commerce (TSP) Le problème du voyageur de commerce (ou TSP pour Traveling Salesman Problem) est le suivant : un représentant de commerce peut vendre sa marchandise dans un certain nombre de villes, il doit donc planifier sa tournée de manière à passer par toutes les villes en voyageant au total le moins possible. Ce problème est sans doute un des plus vieux et problèmes d'optimisation combinatoire et certainement l'un des plus étudiés. Les applications du problème du voyageur de commerce sont nombreuses : D'une part, certains problèmes d'optimisation de parcours en robotique ou en conception de circuits électroniques ainsi que certains problèmes de séquencement (passage de trains sur une voie, atterrissage d'avions, processus de fabrication en industrie chimique, etc.) s'expriment directement sous forme de TSP. D'autre part, et c'est sans doute la famille d'application la plus importante, les problèmes de transport abordés au chapitre 7, sont généralement plus complexes que le TSP, mais comportent des sous-problèmes de type TSP. L'étude du problème du voyageur de commerce est donc un préalable à la résolution de ces problèmes de transport. On présentera un rapide tour d'horizon des méthode disponibles pour la résolution du TSP et, à partir de [CL 97a], on montrera comment résoudre de manière efficace des TSP de taille inférieure à 70 nœuds. 4.1 Circuits Hamiltoniens 4.1.1 Définition, typologie, applications. Soit G = (V,E) un graphe, et soit d une fonction positive sur les arêtes, on appelle circuit Hamiltonien un chemin fermé passant par tous les sommets v ∈ V. De manière duale, on appelle circuit Eulérien un chemin fermé passant par toutes les arêtes e ∈ E. Le problème du voyageur de commerce revient ainsi à trouver un circuit Hamiltonien de longueur minimale dans le graphe de distance des villes. Bien que les définitions des circuits Eulériens et Hamiltoniens soient très proches, ces deux problèmes sont de difficultés très différentes. Le simple problème de l'existence d'un circuit est NP-complet pour les circuits Hamiltoniens et polynomial pour les circuits Eulériens. En effet, il existe un circuit Eulérien si et seulement si le graphe est connexe et tous les sommets sont de degré pair (théorème d’Euler). Dans ce cas, la recherche d'un tel circuit peut se faire avec un algorithme de complexité O(m) [Sch 95] (on rappelle que m = |E| désigne le nombre d'arêtes de G). Pour le problème de minimisation de parcours, la fonction d peut être quelconque. Des algorithmes spécifiques peuvent être proposés quand il s'agit d'une distance L1, L2 ou L , (par exemple, en procédant à une triangulation de Delaunay de l'espace géographique sous-jacent), ou simplement quand la fonction d vérifie l'inégalité triangulaire. Enfin, la matrice de distance peut aussi être asymétrique (par exemple, si l'on considère le cas d'une ville avec des sens uniques). La cas particulier du TSP asymétrique (ou ATSP) est particulier puisque ce problème est en fait beaucoup plus facile que le TSP symétrique. L'algorithme que nous proposerons s'appliquera aussi bien au TSP asymétriques que symétriques. Enfin, ce problème du voyageur peut être envisagé avec des contraintes supplémentaires. Les plus courantes viennent du domaine du transport et sont liées soit à une formulation temporelle, soit à des problèmes de capacité. •= Dans la métaphore habituelle du voyageur de commerce, la fonction d représente une distance géographique. Elle peut tout aussi bien représenter un temps de trajet. Si l'on particularise une ville comme ville de départ (appelée le dépot), d'où le tour commence au temps 0, on peut associer une heure de visite à chaque ville. Dans cette description temporelle du problème, on peut considérer deux types de contraintes supplémentaires. On peut contraindre les dates de visite en associant à chaque ville une fenêtre de temps pendant laquelle le tour doit y passer. Le problème est alors dénoté par les 1 initiales TSPTW (Traveling Salesman Problem with Time Windows). D'autres contraintes peuvent aussi faire dépendre le temps de trajet entre deux endroits (c'est à dire la distance d) de l'heure à laquelle le trajet est effectué. Cette formulation rend bien compte des situations d'embouteillages autour des grandes villes le matin et le soir. •= Si l'on considère que le voyageur de commerce est en fait un transporteur qui peut à chaque endroit prendre et déposer de la marchandise (les pickup and delivery problems), on est amené à rajouter deux types de contraintes. D'une part des contraintes de précédences (aller chercher la marchandise avant de la livrer), et d'autre part des contraintes de capacité vérifiant que l'on est bien physiquement capable de transporter toutes les marchandises. Ceci peut éventuellement interdire des trajets qui commenceraient par procéder à tous les enlèvements avant de faire la moindre livraison. On traitera dans ce chapitre de la résolution du TSP pur et de la prise en compte d'éventuelles fenêtres de temps. Le TSPTW est en effet particulièrement intéressant puisqu'il est à mi-chemin entre un TSP et un problème d'ordonnancement disjonctif. Si toutes les fenêtres de temps sont égales à [0, M], on obtient le TSP pur, et si les distances dij ne dépendent que de i (ce qui peut correspondre à un temps de visite au noeud i et un temps de trajet nul entre i et j), on retrouve un job-shop à une machine. Il y a donc un continuum entre le TSP auquel on ajoute des fenêtres de temps et l'ordonnancement disjonctif auquel on ajoute des temps d'adaptation de la ressource entre le traitement de deux tâches successives. Mentionnons enfin qu’il existe de nombreuses autres variantes du TSPTW, suivant ce que l’on cherche à optimiser : au lieu de chercher à minimiser la date de fin, on peut vouloir minimiser une distance géographique (on n’additionne que les temps de parcours et on ignore les temps d’attente), ou bien minimiser la somme des temps d’attente. On peut aussi autoriser le tour à ne pas commencer en 0 au dépôt, mais un peu plus tard afin de pouvoir réduire certains temps d’attente intermédiaires. 4.1.2 Modélisation linéaire. La formulation linéaire classique du problème est la suivante: on associe à chaque arête e du graphe une variable binaire xe reflétant la présence de e dans le tour. On cherche alors : dij xij min i, j ∀i, x j ij = 1, ∀j, ∀S ⊂ V, S ≠ ∅, x i ij x ij i ∈S, j∉S =1 ≥2 ∀i, j, x ij ∈{0,1} Les deux premières contraintes traduisent le fait que le degré sortant (resp. entrant) d’un noeud dans un circuit vaut 1, la troisième contrainte interdit les solutions composées de sous-tours disjoints. Enfin, on impose aux variables xe de représenter des valeurs Booléennes. Remarquons enfin dans cette modélisation linéaire que si l'on omet la contrainte sur le degré sortant des noeuds (∀i, j xij = 1), le problème revient à trouver un arbre couvrant de poids minimal (ce problème est polynomial). On montrera (§ 4.3.4) comment utiliser cette relaxation du problème pour obtenir des bornes inférieures de grande qualité. Si l'on veut rajouter des fenêtres de temps, la formalisation linéaire s'étend facilement en représentant la date de visite de chaque nœud i par une variable ti . Le problème devient alors : 2 dij xij min i, j ∀i, x j ij = 1, ∀j, ∀S ⊂ V, S ≠ ∅, x i ij x ij i ∈S, j∉S =1 ≥2 ∀i, j, x ij ∈{0,1} t depot = 0, ∀i, j, t j ≥ ti + xij d ij ∀i, ai ≤ ti ≤ bi 4.2 Algorithmes de résolution exacte 4.2.1 Programmation linéaire en nombres entiers L'examen des techniques de résolution linéaire sur le problème du TSP est intéressant d'un point de vue historique, car les méthodes de programmation linéaire ont été bâties pour ce problème en particulier. La formulation linéaire présentée ci-dessus a deux inconvénients. 1. Le nombre de contraintes d’élimination de sous-tours est exponentiel. Même la méthode de génération de colonnes évoquée au chapitre 1, qui permet d'éviter de stocker ces inéquations de manière explicite, serait pénalisée en temps par cette formulation exponentielle du problème. On va donc utiliser ces contraintes linéaires comme des plans de coupes : dès que l'algorithme de programmation linéaire (le simplexe, par exemple) renvoie une solution au problème simplifié (sans les contraintes d'élimination de sous-tours), on cherche une contrainte d'élimination de sous-tours violée par la solution, on l'ajoute au programme linéaire et on résout le nouveau problème. On peut ainsi réinjecter une à une, des contraintes d'élimination de sous-tours. Ceci peut être fait de manière très efficace car pour identifier une contrainte de sous-tours violée il suffit de résoudre un problème de coupe minimale. Ce problème est équivalent au problème du flot maximal, et peut donc être résolu en temps polynomial. •= Une fois que l'on dispose d'une solution qui vérifie toutes les contraintes énoncées ci-dessus, celle-ci est généralement à valeurs fractionnaires. Et il est difficile de la transformer en une solution à valeurs entières. En effet, on ne connaît aujourd’hui que des familles de plans de coupes qui séparent ces solutions; la description exacte du polytope des solutions entières est elle, encore inconnue (parmi les plans de coupes célèbres, on peut citer les inégalités du peigne proposées par Chvàtal [ABCC 94]). Ainsi, pour résoudre un problème de TSP en utilisant la modélisation linéaire, on est amené à développer un arbre de recherche en posant des points de choix sur les valeurs des variables qui sont fractionnaires dans la solution optimale courante. A chaque nœud de cet arbre, on rajoute des contraintes au programme linéaire courant. De multiples algorithmes peuvent être obtenus suivant le nombre de contraintes rajoutées à chaque itération. •= Si l'on se contente de rajouter la contrainte d'affectation de la variable du point de choix, on obtient la version la plus simple d'algorithme de branch and bound. Pour le cas asymétrique (ATSP), les algorithmes de branch and bound sont généralement très efficaces, car la borne inférieure est très précise (proche de la valeur optimale). •= On peut aussi obtenir des algorithmes qui font plus de raisonnement à chaque étape en rajoutant des contraintes d'élimination de sous-tours ainsi que des plans de coupes. Cette dernière famille d'algorithme qui conduit à l'exploration d'arbres de recherche plus petits, s'appelle le branch and cut, et a été développé pour le TSP par [PR 91]. Ces algorithmes sont particulièrement utilisés sur les 3 problèmes symétriques pour lesquels le branch and bound est peu efficace (à cause de la piètre qualité de la borne inférieure linéaire). Ces algorithmes permettent la résolution de problèmes de TSP jusqu'à un millier de villes et de TSPTW de l'ordre de quelques centaines à un millier de villes. 4.2.2 Programmation dynamique. La programmation dynamique est une technique générale de résolution exacte de problèmes d'optimisation qui consiste à énumérer les solutions du problème. Cependant, contrairement à la programmation par contraintes qui énumère de manière implicite l'ensemble des solutions, et évite de les générer toutes en rejetant des ensembles de solutions pour lesquels on prouve que la valeur de la fonction objective ne sera pas assez intéressante, la programmation dynamique, elle, procède à une énumération explicite de l'ensemble des solutions. Quand la programmation par contraintes s'efforce de propager de manière aussi efficace que possible les contraintes pour couper autant que possible l'arbre de rechercher et est ainsi parfois amenée à faire des calculs lourds à chaque nœud de l'arbre, la programmation dynamique prend le contre-pied de cette approche et cherche à factoriser autant que possible les calculs pour faire le minimum de travail possible à chaque étape et éviter tout raisonnement redondant. La programmation dynamique n'énumère ainsi pas toutes les solutions séparément les unes des autres, mais filtre l'ensemble des solutions pour énumérer des groupes de solutions. Il s'agit ainsi d'une énumération factorisée et complète. La programmation dynamique travaille sur une formulation récursive du problème, pour laquelle on fait de la tabulation des résultats intermédiaires. Prenons par exemple, le calcul de la suite de Fibonacci. Plutôt que de recalculer fib(n-1) et fib(n-2) pour obtenir fib(n), ce qui conduit à une complexité exponentielle, le calcul par programmation dynamique commence du cas de base en stockant fib(0) et fib(1), utilise la formule de récurrence du bas vers le haut, mémoïse tous les résultats intermédiaires, jusqu'à obtenir le résultats désiré. Cette technique nécessite un stockage compact des résultats (pour des raisons évidentes de taille mémoire). Pour trouver une formulation par récurrence du TSP, on ouvre le cycle et on appelle chaîne Hamiltonienne tout chemin passant une et une seule fois par chaque sommet. Soit alors V={0,...,n} et soit 0 le dépôt, pour x ∈ {1,.., n} et S ⊆ {1,.., n}, x ∉ S, on note f(S,x) la longueur de la plus petite chaîne Hamiltonienne partant du dépôt, visitant tous les sommets de S et terminant en x. f peut être calculée par une fonction de récurrence : f (S, x) = min y∈S ( f (S − {y}, y) + d(y, x)) et la valeur du tour optimal est f({1,.., n}, 0). Le calcul du tour optimal nécessite de stocker n2n valeurs de f (on est en effet amené à considérer les 2n parties de {1,.., n} pour le premier argument et toutes les valeurs de {1,.., n} pour le second). L'utilisation astucieuse de la formule de récurrence permet a ainsi permis de diminuer la complexité par rapport à une énumération naïve des n! solutions possibles). Si l’on stocke ces valeurs dans un tableau d’entiers, en utilisant un codage binaire (par vecteur de bits) de S, alors, on peut remplir le tableau en le parcourant par index croissants (le codage étant croissant pour l’inclusion d’ensembles, quand on veut remplir f(S,x), les valeurs de f pour tous les sous ensembles de S ont déjà été calculées et on peut appliquer la formule de récurrence). Cet algorithme peut se généraliser aisément au cas du TSPTW. Par exemple, si l'on minimise le temps total de parcours, on dénote par f(S,x) le temps minimal pour partir du dépôt, visiter tous les sommets de S et terminer en x. On peut alors modifier la formule de récurrence comme suit : 4 max(a x ,d(0, x)) si d(0, x) ≤ bx f (∅, x) = +∞ sinon f (S, x) = min y ∈S g(x, y,S −{y}) max( f (y,T ) + d(y,x), ax ) si f (y,T ) + d(y, x) ≤ bx g(∅, x) = +∞ sinon L’intérêt de la résolution du TSP par programmation dynamique réside d'une part dans la rapidité des calculs et d'autres part dans la possibilité d'intégrer des contraintes supplémentaires (on a donné l'exemple des fenêtres de temps, on aurait aussi bien évoquer les contraintes de capacité ou d'autres encore); l’inconvénient est la taille de la mémoïsation des calculs. On peut ainsi résoudre des problèmes de 10 noeuds en 100 ms. et de 15 noeuds en 30 s. Au delà, la mémoire requise pour le tableau devient rapidement déraisonnable. Cette méthode n'est donc applicable que pour de très petits problèmes. Mentionnons qu'une autre approche utilisant la programmation dynamique est capable de résoudre des problèmes de taille plus importante [Du 95]. Mais cet algorithme est beaucoup plus complexe et repose sur une discrétisation très forte des données (distances, fenêtre de temps) qui peut parfois changer suffisamment le problème au point rendre certaines solutions irréalisables ou de rendre réalisables certaines solution qui violent des contraintes. 4.3 Contraintes On s'intéresse à la résolution du TSP en programmation par contraintes. La première constatation que l'on peut faire est que les contraintes arithmétiques classiques sur les domaines finis (+, ×, =, ≠, min/max, etc.) ne permettent pas d'exprimer simplement la configuration de cycle Hamiltonien. Les systèmes usuels ont donc été amenés à introduire des contraintes globales spécialisées pour ces situations : on a ainsi cycle dans CHIP [BC 94] et IlcPath dans ILOG SOLVER. Nous allons proposer une technique d'implémentation de ces contraintes globales. 4.3.1 Modélisation Alors que dans la formulation linéaire, une solution au TSP est un ensemble d’arêtes vérifiant toute une série de contraintes additionnelles, la programmation par contraintes, plus expressive, permet d’incorporer une partie de ces contraintes (par exemple celles sur le degré sortant des noeuds) dans la formulation même du problème. Ainsi, on orientera le tour et on modélisera une solution au TSP par une relation Next : V∅V associant à chaque sommet son successeur immédiat. Next doit ainsi vérifier certaines contraintes additionnelles : •= Next est bijective. Si l’on duplique l’ensemble des sommets pour considérer la relation Next dans un graphe biparti, cette contrainte affirme que Next est un couplage dans un graphe biparti. La propagation simple de cette contrainte consiste, après chaque affectation Next(x):=y à retirer y de tous les domaines de Next(z) pour z≠x. •= Next ne contient pas de cycle de longueur inférieure à n : Ainsi, quand une chaîne x1,...,xk a été construite pour Next, on retire x1 du domaine de Next(xk). Un algorithme de propagation de cette contrainte d'élimination de sous-cycles est proposé dans [CL 97b]. Dans le cas du TSPTW, on peut envisager d'autres modélisations inspirées du problème d'ordonnancement disjonctif. •= On peut modéliser le problème comme un problème d'ordonnancement de tâches dont les durées représentent le temps de trajet depuis la tâche précédente. Les durées ne sont donc plus des données, 5 mais dépendent de la solution. Pour appliquer des règles de coupe dérivées de celles des intervalles de tâches, on est amené à estimer ces durées, c'est à dire évaluer des bornes inférieures des temps de trajets entre un nœud et ses prédecesseurs potentiels. Ces règles de propagation peuvent ensuite être utilisées à l'intérieur d'un arbre de recherche binaire raisonnant sur l'ordre respectif de deux tâches dans le tour. •= Une troisième solution consiste à reprendre le modèle de séquence [Zh 97] où l'on choisit d'affecter à une tâche une position dans le tour. Pour ce modèle, on peut décrire des règles similaires à celles du modèle d'ordonnancement (avec la même difficulté liée à l'estimation de la durée d'une tâche). Le modèle le plus adapté dépend du type de données. Quand le problème est dominé par les contraintes temporelles, il vaut mieux utiliser le schéma de branchement inspiré du job-shop. Dans certains cas, où ni l'aspect temporel ni l'aspect géographique ne domine, le modèle par séquence peut être le plus intéressant. Dans les autres cas du TSP pur, ou d'un TSPTW avec quelques contraintes temporelles (ce qui semble être le cas le plus réaliste), le modèle issu des couplages est le plus adapté au problème. Parmi les techniques de résolution des problèmes de couplages bipartis (décrites au chapitre 2), on retient l'utilité de maintenir une relation redondante symétrique Prev : V∅V (Celle-ci est en particulier indispensable pour le cas où les distances sont asymétriques) et l'évaluation d'une borne inférieure de la longueur du tour, LB, en sommant les distances de chaque nœud à son plus proche voisin. Cette borne inférieure permet d’éliminer certaines arêtes du graphe (les arêtes ij telles que dij - best(i) ≥ UB - LB). On gardera aussi le terme correctif sur cette borne permettant de prendre en compte à l'avance les regrets qui feront augmenter la borne. Enfin, on sélectionnera les points de choix par un critère mixte qui considère le regret pour les domaines de cardinalité importante et le first-fail pour ceux de cardinalité faible. L’ensemble de ces techniques directement issues de la modélisation du TSP comme un problème de couplage ne permettent de résoudre que des problèmes jusqu’à 12 ou 15 noeuds. La contrainte d’élimination des sous-tours, qui fait la particularité du TSP par rapport au problème des couplage est en effet trop peu propagée. 4.3.2 Propagation en présence de fenêtres de temps Comme pour l'ordonnancement disjonctif, on peut réduire dynamiquement les fenêtres de temps attachées à chaque nœud. Pour cela, on a enrichit la modélisation du problème de deux relations redondantes. On associe à chaque tâche t une fenêtre de temps (dynamique) [t,t] initialisée à la fenêtre imposée [at, bt] et que l'on va réduire au cours de la résolution. On associe aussi à chaque tâche t une liste d'autres tâches before(t) (resp. after(t)) représentant l'ensemble des tâches effectuées avant (resp. après) t. Ainsi, la relation after (resp. before) représente la fermeture transitive de la relation next (resp. prev). L'ensemble de ces structures internes peut être utilisé pour mettre en œuvre les règles de propagation suivantes : •= règles structurelles de la fermeture transitive y = next(x) y ∈after(x) y ∈after(x) ∧ z ∈after(y) y ∈after(x) next(x) ≠ z next(y) ≠ x •= propagation des précédences sur les fenêtres de temps (PERT) : y ∈after(x) y ≥ x + d(x,y) ∧ x ≤ y − d(x,y) •= propagation des fenêtres de temps sur les précédences y ≥ min x ∈domain( prev ( y)) (x + d(x, y)) 6 •= "edge finding" limité à deux tâches : y + d(y, x) > x y ∈after(x) Des règles similaires impliquent les relations symétriques (prev, before). L'ensemble de ces règles de propagation relativement simples peuvent être enrichies d'autres règles de propagation globales, plus complexes, que nous décrivons dans les paragraphes qui suivent. 4.3.3 Contraintes redondantes: connectivité, isthmes On propose maintenant une contrainte redondante pour mieux propager la contrainte structurelle de circuit Hamiltonien. En effet, pour l'instant, la seule contrainte structurelle que l'on rajoute à la modélisation comme couplage biparti est la contrainte d'élimination de sous-tours qui interdit une arête à chaque affectation (l'arête qui fermerait la chaîne dans laquelle on vient d'insérer une nouvelle arête en un sous tour). On peut renforcer cette propagation de manière significative si l'on remarque que la contrainte d'interdiction de sous-tours est une contraintes de connexité : en effet, un circuit Hamiltonien est un ensemble connexe d'arêtes, alors qu'un ensemble Hamiltonien de sous-circuits a autant de composantes connexes que de tours. On peut ainsi vérifier à chaque noeud de la recherche que le graphe (dynamique) des arêtes autorisées (formé par les domaines de la relation next) est connexe. Attention, on n'impose pas que l'ensemble des arêtes sélectionnées jusqu'à cette étape du calcul soit connexe, mais que l'ensemble des arêtes “encore sélectionnables” soit connexe. Ce test permet de rejeter de nombreuses situations dans lesquelles il n'existe plus aucun circuit Hamiltonien. On peut aussi faire une vérification plus fine: puisqu’on dispose par la modélisation en couplage biparti des relations prev et next qui portent sur des arcs orientés, on peut vérifier une condition beaucoup plus forte que la simple connexité: la forte connexité, qui assure qu'entre deux sommets il existe toujours un chemin faits d'arcs orientés, de l'un vers l'autre et vice-versa. La vérification de la forte connexité se fait ainsi par un parcours en largeur du graphe (algorithme en O(m) ). On peut proposer une propagation encore plus forte de la contrainte de connexité en cherchant à détecter à l'avance les arcs (appelés isthmes) qui sont indispensables à la forte connexité du graphe. Ainsi quand un arc e est tel que si on le supprime du graphe, celui n'est plus connexe, e peut être immédiatement sélectionné dans le tour. La détection d'isthmes ne peut pas se faire, à notre connaissance, de manière aussi simple que la vérification de la (forte) connexité, et a une complexité en O(mn). Si la simple vérification de la (forte) connexité permet d’accélérer la résolution, la détection d'isthmes ne permet de gagner qu'un seul retour arrière par isthme (puisque sans cette propagation, si l'on ne sélectionnait pas un isthme dans le tour, on s'apercevrait au noeud suivant de l'arbre de recherche que le graphe ne serait plus fortement connexe, et on abandonnerait la branche). Le surcoût en complexité d'un facteur n n'est expérimentalement pas justifié par la réduction de l'espace de recherche qu'il procure. 4.3.4 Bornes inférieures 4.3.4.1 Relaxation en couplage parfait de poids minimum La modélisation du TSP comme un problème de couplage biparti permet d'obtenir facilement des bornes inférieures sur la longueur minimale du tour. Comme on l'a mentionné plus haut, on peut obtenir simplement une borne inférieure grossière en sommant les distances des nœuds à leurs plus proches voisins. Cette borne peut être raffinée en y ajoutant un terme correctif prenant en compte à l'avance l'ajout de regrets. 7 Une première idée pour renforcer encore cette borne serait de calculer de manière exacte la valeur du couplage optimal dans le graphe. Ceci peut être fait avec une complexité faible en utilisant la méthode Hongroise incrémentale [CL 97b]. Ces trois bornes associées à la relaxation du TSP en un problème de couplage parfait de poids minimal fournissent des résultats irréguliers suivant la distribution des données. Dans le cas d'une distance symétrique, le couplage optimal a tendance à contenir de nombreux cycles élémentaires à deux éléments : si x est le plus proche voisin de y, y a de bonnes chances d'être le plus proche voisin de x, et donc le couplage optimal a de fortes chances de contenir le cycle xyx, ce qui l'éloigne d'un cycle Hamiltonien, et donc la borne inférieure peut être de piètre qualité [BT 86]. Une autre situation dans laquelle la relaxation du couplage peut fournir une borne imprécise se produit lorsque les villes sont réparties géographiquement par agrégats (clusters). Dans ce cas, chaque ville a une voisin très proche, et le couplage optimal ne tient compte que de ces distances locales, en oubliant que les distances (plus importantes) entre agrégats devront aussi être parcourues puisqu’on ne veut pas un tour par agrégat, mais un seul et unique tour. Pour toutes ces raisons, on cherche à disposer d'une autre borne inférieure, plus robuste par rapport aux distributions de données. C'est l'objet du paragraphe suivant qui explore les relaxations en problèmes d'arbre couvrant de poids minimum. 4.3.4.2 Relaxation en arbre couvrant de poids minimum Si l’on oublie, dans la formulation linéaire du TSP, les contraintes sur les degrés sortant des sommets, le problème se relaxe en un problème d’arbre couvrant de poids minimal (MST pour Minimal Spanning Tree). En effet, pour peu que l'on duplique un sommet (disons que 1 est dupliqué en {1,n+1}), les cycles Hamiltoniens correspondent aux chaînes Hamiltoniennes entre 1 et n+1. Or une chaîne Hamiltonienne est un arbre couvrant particulier dont tous les noeuds ont un degré sortant égal à 1. Le problème MST est donc une relaxation du TSP. Or, trouver un arbre couvrant de poids minimal est un problème polynomial, que le graphe soit orienté [CLR 86] ou non. cas non orienté : algorithme de Prim Trouver un MST dans un graphe non orienté est extrêmement facile: deux algorithmes gloutons résolvent le problème de manière naturelle. L’algorithme de Prim ([Pr 57], cf. [CLR 86]) part d’un arbre réduit à un sommet et lui rajoute à chaque étape une arête incidente de poids minimal (cette arête relie donc un sommet de l’arbre à un sommet extérieur). L’arbre obtenu après n-1 insertions est un MST. La complexité est en O(n3) ou O(n2) pour une implémentation soignée. L’autre algorithme glouton classique est celui de Kruskal ([Kr 56], cf. [CLR 86]) qui part d’un ensemble d’arêtes vide et ajoute une par une les arêtes de poids minimal (non nécessairement incidentes) qui ne créent pas de cycle avec l’ensemble déjà sélectionné. La complexité est en O(m2) ou O(m.log(n)) pour une implémentation soignée. En pratique, l’algorithme de Prim est plus simple et plus rapide sur les graphes de taille petite ou moyenne. cas orienté : algorithme d’Edmonds Dans le cas d'un graphe orienté, on ne s'intéresse plus aux arbres couvrants, mais aux arborescences couvrantes. Soit s un noeud (qu'on prend comme racine), une arborescence est un ensemble de n-1 arcs de sorte que de tout nœud sauf s ne parte qu'un seul arc et tel qu'il n'y ait aucun cycle. On peut voir une arborescence comme un arbre où tous les arcs sont orientés vers la racine s. Une chaîne Hamiltonienne est non seulement un arbre couvrant, c'est aussi une arborescence couvrante. Ceci nous donne donc une deuxième relaxation plus précise que la précédente : celle de l'arborescence couvrante de poids minimal. Ce problème peut être résolu par l'algorithme d’Edmonds [Edm 71] qui 8 construit, pour un sommet s fixé, une arborescence de racine s de poids minimal (notée s-MSA). Le principe de construction ressemble à un algorithme glouton: on fixe le sommet racine s, et on part d’un ensemble d’arêtes F=∅. On considère successivement les n-1 sommets y ≠ s et l’on ajoute à F l’arc xy de poids minimal. On obtient un graphe orienté (V,F) couvrant tous les sommets, mais qui n’est pas forcément une arborescence (auquel cas, il n’est pas connexe non plus). En effet, il se peut que l’addition de sommets ait créé des cycles. On va transformer ce graphe petit à petit en une arborescence en ouvrant un à un les cycles. Plus précisément, soit µ un cycle dans (V,F), on construit à partir de G=(V,F) un graphe contracté G’=G/µ=(V’,F’) dans lequel on a remplacé le cycle µ par un seul sommet. On étend la distance de G à G' en posant : •= d’(x,y) = d(x,y) si xy n’est pas un arc entrant dans µ= •= d’(x,y) = d(x,y) - d(z,y) où z est le prédécesseur de y dans µ sinon. (on fait cette modification pour avoir d(F) = d’(F’) + d(µ)). L’ensemble d’arêtes F’ dans le graphe contracté contient ainsi un cycle de moins que F. Après une série de telles transformations, on obtient une s-MSA F(k) pour un graphe contracté G(k) et cette arborecence est de poids minimal. On revient ensuite progressivement au graphe de départ G par une suite de s-MSA dans les graphes G(k) en expansant progressivement les cycles que l’on avait contracté : On commence avec l’arborescence A(k) = F(k). Supposons ensuite qu’entre G(k-1) et G(k), on ait contracté un cycle µ en un noeud α, soit αβ l’arc partant de α sélectionné dans A(k), cet arc correspond à yβ dans le graphe F(k-1) . On obtient alors A(k-1) à partir de A(k) en expansant le noeud α ainsi: on garde tous les arcs de µ sauf xy. A(k-1) est alors une s-MSA dans le graphe G(k-1). On expanse ainsi tous les cycles, jusqu’à obtenir une arborescence couvrant A(0) dont on peut prouver qu’elle est de poids minimal: d(A (0) )= d (k ) (A ( k) ( i) )+ i d (µ i ) où µi est le cycle qui a été contracté entre G(i) et G(i+1). On peut donc se passer des phases d’expansion si on ne cherche que la valeur de la s-MSA. La complexité de cet algorithme est en O(mn). On pourrait calculer la valeur de la s-MSA pour tous les sommets racine s. En fait, on préfère procéder à un calcul pour le graphe des domaines de la relation next et un calcul pour le graphe des domaines de la relation prev, ce qui correspond aux deux orientations possibles de l'arborescence. On va voir de manière expérimentale que cette borne permet de diminuer grandement la taille des arbres de recherche développés, mais que son coût en temps annule le gain en taille de l'arbre de recherche. L'application de relaxation Lagrangienne au calcul de s-MSA va permettre d'affiner grandement la borne au prix d'un surcoût faible en temps de calcul et va ainsi améliorer substantiellement les performances de l'algorithme de résolution. Relaxation Lagrangienne, borne inférieure de Held & Karp Comme on l'a décrit plus haut, le problème de la s-MSA est une relaxation polynomiale du TSP. Held et Karp ont proposé [HK 71] d'affiner cette relaxation en lui appliquant le principe de la relaxation Lagrangienne : on fait passer dans la fonction objective les contraintes qui imposent que les degrés sortants valent 1. Les multiplicateurs de Lagrange (cf. § 1.3.3.) sont ainsi des poids πi attachés à chaque sommet. Ces poids peuvent être vus comme des pénalités puisque la fonction objective est transformée en : (d(ij) + π i ) = ij ∈MST πiδ i d(ij) + ij ∈MST (on prend i 9 πi = 0 ) où δi est le degré sortant de i moins 1. Le vecteur δ des excès de degré sortant forme un sous-gradient. On va ensuite faire évoluer les multiplicateurs de Lagrange en donnant des pénalités positives aux sommets de fort degré sortant dans le MST et en donnant des pénalités négatives aux feuilles du MST. Ces pénalités visent à rendre le MST plus “filiforme”, et on remarquera ici l’analogie avec le calcul du terme correctif de la borne supérieure du couplage de poids minimal par prise en compte à l'avance de regrets. Pour la mise à jour des multiplicateurs, on suit la méthode proposée par Beasley [Bea 93] : on pose π i := π i + α (UB − LB) δi δ i2 où α est un facteur de l’ordre de l’unité qui décroît avec le temps, UB est une borne supérieure et LB une borne inférieure. Le principe de cette marche ressemble à du recuit simulé: on avance à grands pas tant qu’on est loin de l’optimum, puis à mesure qu’on s’en rapproche, on diminue ses pas. LB est réactualisé à chaque nouvelle solution trouvée pour le problème paramétrique de MST. Ces paramètres demandent à être réglés de manière fine pour que les multiplicateurs convergent rapidement non loin de l’optimum (en particulier, si l'on veut utiliser cette borne inférieure à chaque nœud d'un arbre de recherche, il faut converger vers une bonne solution en peu d'itérations). 4.3.5 Recherche arborescente Nous avions mentionné pour la résolution du problème du couplage biparti de poids minimal deux constructions possibles de l'arbre de recherche : pour un sommet X sélectionné, on pouvait soit essayer toutes les arêtes par ordre de poids décroissant, soit poser l'alternative binaire “X est associé à son meilleur choix” ou “X ne l'est pas”, sans préciser plus la seconde branche. Cette deuxième construction se justifie par le fait que la décision “X n'est pas associé à son meilleur candidat” suffit à faire augmenter la borne inférieure naïve du couplage et évite d’examiner plusieurs branches similaires quand tous les seconds choix sont relativement indifférents pour X. Alors que ce schéma de branchement avait eu un comportement parfois instable pour le problème du couplage (programme PPC3, tableau 2-1), il s'avère nettement plus efficace que le premier dans le TSP. Pour l’optimisation on préfère redémarrer un arbre nouveau à chaque solution trouvée plutôt que d’explorer un seul arbre de manière exhaustive en diminuant dynamiquement la valeur de la borne supérieure à chaque solution trouvée. Ceci s’explique par l'explosion combinatoire lores de la recherche de solutions proches de l'optimum : dès qu’on a trouvé une solution, le problème suivant (en trouver une meilleure) est sensiblement plus difficile. Quitte à réexplorer une partie de l’arbre, on préfère recommencer pour explorer un arbre dont la structure soit la mieux adaptée possible au problème (dont les noeuds près de la racine réduisent la complexité de la recherche). 4.3.6 Résultats expérimentaux Nous avons maintenant décrits tous les composants d'une résolution en programmation par contraintes : les modèles, les algorithmes de propagation et leurs structures internes associées, les contraintes redondantes et une série de bornes inférieures, des stratégies de branchement et un schéma d'optimisation. Nous pouvons maintenant décrire rapidement quelques expérimentations permettant de valider ce cadre algorithmique. Toutes les expériences on été faites sur des problèmes à distance symétrique pour éviter de surévaluer la qualité de l'algorithme en l'évaluant sur des problèmes asymériques pour lesquels la borne inférieure issue du modèle de couplage biparti est très précise. La méthode présentée est générique et pourrait éventuellement donner de meilleurs résultats sur des problèmes asymétriques. Le tableau 4-1 compare différents algorithmes de programmation par contraintes sur des problèmes entre 10 et 21 nœuds (nous avons généré aléatoirement les problèmes cl à 10, 13, 15 et 20 nœuds, et les problèmes gr17 et gr21 viennent de la collection TSPLIB [Rei 94]). Le premier programme propage de 10 manière naïve la contrainte de couplage, le second y ajoute la modélisation symétrique et les bornes symétriques, l'utilisation du regret, le troisième ajoute aux bornes inférieures le terme correctif lié au regret, et vérifie la contrainte redondante de connexité forte. Le quatrième parcourt un arbre de décision binaire. Enfin, le dernier intègre tous ces composants et y ajoute le calcul d'une arborescence de poids minimal comme borne inférieure. cl 10 cl 13 cl 15 gr 17 cl 20 gr 21 2.3 kb. 9.2 kb. 120 kb. 28.9 Mb. 7.6 Mb. 21.3 Mb. 0.3 s. 2 s. 16 s. 3.5 ks. 1.1 ks. 3 ks. PPC "couplage symétrique" 1.8 kb. 8.7 kb. 44.2 kb. 315 kb. 676 kb. 180 kb. 0.3 s. 1.5 s. 8 s. 85 s. 165 s. 44 s. Propagation complète 146 b. 717 b. 2.4 kb. 12.7 kb. 65 kb. 14.1 kb. 0.1 s. 0.5 s. 1.9 s. 12 s. 67 s. 14 s. PPC naïve Propagation complète et arbre binaire 118 b. 583 b. 2 kb. 5.8 kb. 27 kb. 12.5 kb. 0.07 s. 0.2 s. 0.9 s. 3.1 s. 15 s. 7 s. Idem + s-MSA 112 b. 553 b. 1.7 kb. 5.5 kb. 24.2 kb. 12.3 kb. 0.07 s. 0.3 s. 1 s. 3.5 s. 18 s. 9 s. Tableau 4-1: différents algorithmes de PPC pour la résolution de petits TSP (10-21 nœuds) Le meilleur de ces algorithmes (celui faisant une propagation complète et parcourant un arbre binaire) peut résoudre des problèmes jusqu'à une trentaine de nœuds. On donne à titre d'exemple dans le tableau 42 la résolution de huit problèmes entre 20 et 29 nœuds, avec ou sans fenêtres de temps (les 4 premiers proviennent de TSPLIB, les suivants sont issus d'un problème de tournées [So 87],[PGPR 96]). On remarquera que les fenêtres de temps, en contraignant plus le problème, facilitent sa résolution (le phénomère inverse se produit pour les approches linéaires). PPC gr 24 TSP (n=24) fri 26 TSP (n=24) bayg 29 TSP (n=29) bays 29 TSP (n=29) rc201.0 TSPTW (n=26) rc201.1 TSPTW (n=29) rc201.2 TSPTW (n=29) rc201.3 TSPTW (n=20) 6.6 kb. 934 kb. 4.56 Mb. 1.1 Mb. 542 b. 649 b. 1676 b. 158 b. 6.9 s. 930 s. 4.4 ks. 1.2 ks. 5.8 s. 8.2 s. 19 s. 1.8 s. Tableau 4-2: résolution de problèmes TSP(TW) entre 20 et 29 nœuds à l'aide de P.P.C. Enfin, le tableau 4-3 illustre l'efficacité de l'utilisation de la relaxation Lagrangienne comme technique de borne inférieure (les problèmes résolus sont encore issus de TSPLIB [Rei 94]). Dans ce cas, on peut avoir intérêt à changer de schéma de branchement pour sélectionner en priorité les sommets dont le degré sortant est le plus fort dans la MSA. Choisir l'arête incidente concernant ce sommet permet non seulement d'améliorer la qualité de la borne inférieure au calcul suivant de MSA, mais cette stratégie conduit aussi à obtenir des solutions (des MSA qui sont en fait des chaînes Hamiltoniennes) beaucoup plus tôt dans l'arbre. Ceci permet de limiter la profondeur de l'arbre de recherche parcouru. 11 PPC avec une borne inf. de relaxation Lagrangienne bayg29 dantzig42 att48 hk48 brazil58 st70 4 b. 46 b. 60 b. 127 b. 42 b. 172 b. 14 s. 437 s. 180 s. 330 s. 1.1 ks. 3.3 ks. Tableau 4-3: utilisation de la relaxation Lagrangienne sur le calcul d'une MSA comme borne inférieure pour la résolution de TSP de 29 à 70 nœuds 4.4 Solutions heuristiques. Après avoir décrit trois familles de méthodes pour résoudre de manière exacte le TSP (méthodes linéaires, programmation dynamique et programmation par contraintes), on s'intéresse maintenant aux techniques permettant de fournir une réponse approchée au problème d'optimisation. On abordera deux classes d'algorithmes : les méthodes heuristiques pour construire une solution et les méthodes d'optimisation locale pour améliorer une solution. 4.4.1 Heuristiques gloutonnes de construction de solution Il existe de nombreuses procédures de construction heuristiques d'une solution au TSP. Parmi les plus courantes, on peut citer : 1. L'heuristique du plus proche voisin. Cet algorithme glouton construit le cycle en faisant croître une chaîne. On part d'un sommet arbitraire à partir duquel on va au sommet voisin le plus proche, puis de celui-là à son plus proche voisin non visité, etc ...., jusqu’à ce que tous les sommets aient été parcourus, où l’on revient au départ. Cet algorithme (valable pour les graphes complets) est en O(n2), et on a prouvé que les solutions qu’il fournit peuvent être arbitrairement mauvaises (voir [Rei 94]). En effet, cette procédure commence généralement par faire de très bons choix en sélectionnant des arêtes de poids faible, mais, vers la fin, la chaîne doit ensuite aller visiter des sommets qui ont été “oubliés”, et des distances importantes sont alors rajoutées à la chaîne. 2. Les algorithmes d'insertion. Ces algorithmes fonctionnent de la manière suivante : on part d’un tour réduit à quelques sommets (par exemple, un boucle entre 2 sommets), puis on sélectionne un sommet hors du tour que l’on insère entre deux sommets du tour (à la place qui fait augmenter le moins possible la longueur totale de celui-ci). On insère ainsi tous les sommets jusqu’à obtenir un circuit de longueur n. Le choix du sommet à insérer peut être fait suivant de nombreux critères : •= plus proche (resp. plus lointaine) insertion: on peut insérer le sommet dont la distance minimale à un sommet du tour est minimale (resp. maximale), •= insertion au hasard: on peut insérer un sommet choisi au hasard, •= insertion de coût minimal (resp. maximal): on peut insérer le sommet qui fera le moins (resp. le plus) augmenter la longueur du tour partiel. 3. L'algorithme des économies. Un troisième solution, l’algorithme des “savings” de Clarke et Wright [CW 64] est issue de la résolution du problème des tournées: on particularise un sommet v1 et l’on crée n-1 tours élémentaires: des boucles v1-vi-v1. On procède ensuite à n-2 étapes de fusion où l’on prend deux tours v1-vσ(1)-....-vσ(i)-v1 et v1-vξ(1)-....-vξ(k)-v1 que l’on fusionne en v1-vσ(1)-....-vσ(i)-vξ(1)-....-vξ(k)-v1. Une telle fusion permet d'éviter un aller-retour au sommet v1 et diminue la somme des longueur des tours de la quantité d(σ(i),1) + d(1,ξ(k)) - d(σ(i),ξ(k)). L’algorithme consiste à effectuer à chaque fois la fusion qui permettra de diminuer le plus possible la somme de ces longueurs. 12 4. Sélection gloutonne d'arêtes. Il s’agit d’un algorithme glouton classique, où l’on sélectionne les arêtes une à une, sans nécessairement avoir une chaîne à tout moment. On commence donc par l’arête de poids le plus faible, puis l’on sélectionne l’arête de poids minimal qui ne crée pas de sous-cycle, et ainsi de suite. Cette procédure devient un peu plus complexe dans le cas de graphes non complets: on doit alors faire un peu de backtracking. Le tableau 4-4, obtenu à partir des résultats de [Rei 94], présente une comparaison des ces différentes procédures heuristiques sur de très grands problèmes (les chiffres sont donc un peu pessimistes pour les tailles de problèmes qui nous intéressent). HEURISTIQUE distance moyenne à l’optimum savings 11% greedy 12% plus lointaine insertion 23% insertion au hasard 23,5% plus proche insertion 29,5% plus proche voisin 26% insertion de coût minimal 34% Tableau 4-4: comparaison d'heuristiques pour le TSP [Rei 94] Il existe encore bien d’autres heuristiques basées sur des méthodes géométriques spécifiques à la distance considérée et utilisant par exemple l’enveloppe convexe des points, ou une triangulation de l'espace ou encore utilisant l’arbre couvrant de poids minimal, etc. Dans le cadre du TSPTW, l'application de ces procédures devient beaucoup plus problématique. Le problème de la satisfiabilité (trouver un circuit admissible) peut devenir difficile, et ces méthodes ne sont plus toujours à même de produire une solution (elles peuvent s'arrêter en échec si elles n'arrivent plus, par exemple, à insérer une tâche pour des raisons de contraintes temporelles). D'autre part, les bonnes solutions du TSPTW peuvent être éloignées des bonnes solutions au problème de TSP dans lequel on a relaxé les contraintes temporelles : il devient ainsi beaucoup plus difficile de trouver des critères pertinents pour guider la construction incrémentale du tour. On a en effet deux objectifs qui peuvent être contradictoires : d'une part, produire un tour admissible, c'est à dire une séquence des villes compatible avec les fenêtres de temps et d'autre part, produire un tour de faible longueur totale, c'est à dire une séquence basée sur les relations de proximités géographique. On est donc amené à privilégier les insertions qui non seulement n’augmentent pas trop la longueur du cycle partiel, et aussi qui n'engendrent trop de temps d’attente. Il est ainsi parfois difficile de juger de la pertinence d'une insertion dans un tour partiel au regard de ces deux critères parfois antagonistes (on verra au chapitre 7, comment la recherche LDS permet de résoudre de tels conflits). 4.5 Optimisation locale Une fois la solution de départ obtenue, celle-ci peut généralement être facilement améliorée par une série de transformations locales. 13 4.5.1 Déplacements Les transformation les plus simples qui permettent de transformer un tour en un autre tour sont basées sur les procédures gloutonnes précédentes, en utilisant le mécanisme d'insertion en avant et en arrière. A partir d'un tour donné, on peut obtenir une famille d'autres tours proches en supprimant un sommet (ou une arête) et en cherchant à le réinsérer ailleurs dans le tour. Ces transformations sont appelées le déplacement de sommet (ou d'arête). On peut ainsi chercher par une passe en O(n2) s'il existe un déplacement de sommet qui diminue la longueur du tour et par une passe en O(mn) s'il existe un déplacement d'arête améliorant le tour. Figure 4-1: deux transformations locales pour le TSP, le déplacement de sommet et le déplacement d'arête 4.5.2 Procédures 2-opt, 3-opt Une autre transformation possible consiste à effacer k arêtes du tour, ce qui a pour effet de couper celui-ci en k chaînes (séquences de nœuds) disjointes et à recomposer un autre tour en reconnectant ces chaînes d'une autre manière. L’algorithme k-opt, qui essaye toutes les possibilités, a une complexité en O(nk). Ces transformations nécessitent parfois de changer le sens de parcours de certaines chaînes. En particulier, 2opt parcours toujours une des deux chaînes à rebours et 3-opt comporte 4 possibilités de transformations dont une seule ne rebrousse aucune chaîne. Changer l'orientation d'une chaîne ne pose pas de problèmes dans le cas du TSP symétrique pur, mais, dans le cas de TSP asymétriques, la longueur de la sous-chaîne dépend du sens de parcours, et en présence de fenêtres de temps (TSPTW) ou de contraintes de précédence, les deux sens de parcours ne sont pas forcément admissibles. Ainsi, ces procédures basées sur l'échange d'arêtes deviennent plus coûteuses et moins efficaces (car le voisinage en question contient moins de solutions admissibles) pour le TSPTW. Les voisinages définis par k-opt peuvent être explorés de nombreuses manières: la méthode classique (algorithme k-opt stricto sensu) applique une stratégie de descente qui consiste à aller d’une solution à sa meilleure voisine, et améliorer ainsi de suite la solution jusqu’à ce que la solution soit de coût minimal pour son voisinage. On peut cependant aussi utiliser ces voisinages pour faire des marches aléatoires, de la recherche tabou, etc. Les grandes valeurs de k conduisent ainsi aux meilleures améliorations, mais la complexité de l’algorithme croit rapidement avec k. Dans la pratique, 3-opt fournit d’excellents résultats et a l’avantage de comporter une transformation qui ne retourne aucune chaîne (ce qui est important pour la robustesse aux contraintes supplémentaires). Quand 3-opt est trop lent pour la taille du problème à résoudre, on utilise 2-opt, ou une version réduite de 3-opt qui examine O(n2) voisins de la solution (on réduit la complexité en limitant la taille d’une des 3 chaînes). Cette procédure est souvent appelée 21/2-opt ou OR-opt [Or 76]). 14 Figure 4-2: la transformation de la procédure 3-opt conservant l'orientation des sous-chaînes On peut définir les voisinages k-opt pour k arbitrairement grand. En pratique, on ne fait de l'exploration systématique de voisinage que pour n ≤ 3. Le paragraphe suivant décrit une méthode pour faire une exploration partielle de voisinages correspondant à des valeurs supérieures de k. 4.5.3 Procédure de Lin et Kernighan L’algorithme de Lin et Kernighan [LK 73] est basé sur les voisinages de k-opt, avec deux particularités : d’une part, ces voisinages sont (partiellement) explorés pour de grandes valeurs de k (on envisage donc des mouvements complexes), d'autre part, l'exploration est suffisamment limitée pour garder une complexité pratique inférieure à celle de 3-opt (en O(n3)). L’idée de l’algorithme est la suivante: une transformation locale consiste toujours à remplacer un ensemble d’arêtes {e1,..., ek} par {f1,..., fk} : sans perdre trop de généralité, on peut considérer que ces deux ensembles sont classés de sorte que pour tout i, ei et fi se terminent sur le même sommet. On peut donc construire séquentiellement la transformation en remplaçant e1 par f1, e2 et f2, etc. Puisque la transformation améliore le tour, k i=1 (dei − d fi ) > 0 . Le point-clé est de remarquer qu’on peut alors ordonner les i de sorte que pour toutes les sommes partielles Sl soient strictement positives Sl = l i =1 (dei − d f i ) L’algorithme consiste alors à partir d’un sommet x’ dans le tour, à remplacer l’arête e1=xx’ qui arrive sur x’ par une autre f1 =yx’ plus courte (d(f1) < d(e1)), puis à remplacer l’arête e2=yy’ qui part de y dans le tour par une autre f2 =zy’ telle que d(f1) + d(f2) < d(e1) + d(e2) et ainsi de suite. On intègre généralement à cette recherche un peu de backtracking pour les deux premiers niveaux de choix (y et z). On peut aussi vouloir contrôler la complexité de cette recherche en limitant le nombre total k d’arêtes remises en jeu (par exemple, si l’on ne veut que du 2-opt, ceci revient à imposer que x=z). Le tableau 4-5 résume une comparaison faite dans [Rei 94] de plusieurs procédure d’optimisation locale sur une série de très grands problèmes. La méthode de Lin et Kernighan est de très loin la meilleure et fournit des solutions de qualité remarquable. 15 méthode d’optimisation locale distance moyenne à l’optimum LK 1% LK (limité à 2-opt et DS) 2% 3-opt 4% 2-opt et DS 6% 8,5% déplacement de sommet (DS) 2-opt 9% déplacement d’arêtes 10% Tableau 4-5 : comparaison de méthodes d'optimisation locale pour le TSP [Rei 94] Comme on l'a mentionné, les performances des procédures d'optimisation locale se dégradent en présence de fenêtres de temps. De manière générale, l'optimisation locale se combine mal avec les contraintes supplémentaires. D'une part, il devient nécessaire de tester la satisfiabilité des contraintes pour chaque mouvement, ce qui peut être long. D'autre part, comme de nombreuses solutions du voisinage deviennent irréalisables, l'algorithme est plus rapidement "piégé" dans des optima locaux. 4.6 Bilan. En résumé, le problème du voyageur de commerce est aujourd'hui un problème bien connu, pour lequel on dispose de bonnes procédure heuristiques, et d'excellentes techniques d'optimisation locale (Lin & Kernighan) et de bornes inférieures (Held & Karp). Il est donc relativement aisé de fournir rapidement un bon encadrement de l'optimum. Pour le cas de problèmes asymétriques, la relaxation en un problème d'affectation bijective (en relachant les contraintes d'élimination de sous-tours) fournit d'excellentes bornes inférieures qui peuvent être utilisées dans le cadre d'une optimisation en branch&bound sur des problèmes de grande taille. Le cas symétrique est beaucoup plus difficile. Pour les petits problèmes, jusqu'à 10-15 nœuds, la programmation dynamique et la programmation par contraintes sont deux techniques simples à mettre en œuvre, robustes aux contraintes supplémentaires, et qui fournissent de bons résultats. Si l'on veut résoudre très rapidement de tels petits problèmes (ce peut être le cas comme nous le verrons au chapitre 7 pour l'optimisation individuelle des routes dans un grand problème de tournées), la programmation par contraintes est la méthode la plus rapide. Pour les problèmes jusqu'à 30 nœuds, une approche soignée par contraintes permet la résolution aisée de problèmes avec ou sans contraintes additionnelles. Pour les problèmes entre 30 et 70 nœuds, la programmation par contraintes peut s'appliquer si on lui adjoint un calcul de borne inférieure utilisant le relaxation Lagrangienne. Jusqu'à 100 nœuds, on peut encore utiliser la programmation par contraintes et la relaxation Lagrangienne dans un parcours partiel de l'arbre de recherche, pour trouver de bonnes solutions (non nécessairement optimales). Au delà de 100 nœuds, il faut utiliser soit les méthodes linéaires (branch & cut) si l'on souhaite un résultat exact soit les techniques d'optimisation locale si l'on cherche seulement une bonne solution. 16 17