Aller au contenu principal

Modéliser une décision

Ce que ce chapitre apporte6 points
  • Distinguer, dans une situation d'atelier, la décision, la solution, les contraintes et l'objectif.
  • Écrire une fonction de coût qui évalue une solution, et un test qui dit si elle est réalisable.
  • Reconnaître une solution réalisable, l'optimum, une instance, l'espace des solutions.
  • Juger une représentation d'une solution : ce qu'elle laisse passer d'impossible, ce qu'elle interdit d'utile.
  • Choisir entre une contrainte dure et une pénalité, et régler le poids d'une pénalité en mesurant.
  • Évaluer une solution en Python, sans la chercher.
Lundi matin, chez Valdrome Mécanique, la cheffe d'atelier a sur son bureau dix commandes en attente et une semaine de machines qui n'en absorbera pas plus de cent heures. Il faut choisir lesquelles lancer. Une fois ce choix fait, il reste à décider dans quel ordre la perceuse à commande numérique visitera les douze trous d'une plaque, parce que chaque millimètre parcouru à vide est du temps de machine perdu. Avant d'en chercher la meilleure issue, il faut les écrire de façon qu'un programme puisse juger chacune de leurs issues. Ce chapitre pose ce vocabulaire, insiste sur la représentation d'une solution, et sépare ce qu'on cherche à optimiser de ce qu'on n'a pas le droit de violer.
Ce que ce parcours suppose
Écrire un peu de Python (fonctions, listes, boucles) et, plus loin dans le parcours, lire un graphe : le parcours Python et le parcours Graphes suffisent. La règle gloutonne, qui choisit toujours ce qui paraît le mieux sur le moment, a son chapitre : gloutons et programmation dynamique. Ici, on l'emploie sans la redémontrer.

Une décision de la semaine

Décider quand les choix sont nombreux et les ressources limitées est le métier de la recherche opérationnelle (operations research en anglais). Quand les choix sont des objets qu'on peut énumérer (des sélections, des ordres, des affectations), on parle d'optimisation combinatoire : c'est le cadre de ce parcours.

Valdrome Mécanique est une entreprise d'usinage et d'assemblage d'une centaine de personnes : un atelier de machines-outils, une perceuse à commande numérique, un poste de découpe de barres et de tôles, des postes d'assemblage. Ses problèmes reviendront tout au long de ce parcours, toujours avec les mêmes données, pour que deux méthodes puissent se comparer sur le même cas.

Le premier est celui du lundi. Dix commandes attendent. Chacune consomme des heures de machine et rapporte une marge, et il y a cent heures de machine disponibles cette semaine.

CommandeDésignationHeures machineMarge (€)
C1Carters de pompe385 200
C2Bagues de guidage121 300
C3Supports moteur273 300
C4Arbres cannelés456 100
C5Brides DN80182 100
C6Boîtiers de capteur222 900
C7Platines de fixation9800
C8Pignons314 300
C9Galets141 900
C10Entretoises7600

La commande n'est pas divisible : on lance C4 en entier ou pas du tout. La question est simple à poser. Quelles commandes lancer, pour que la marge soit la plus grande possible sans dépasser les cent heures ? C'est un problème de sac à dos (knapsack en anglais) : des objets qui ont chacun un poids et une valeur, un sac dont la capacité ne se dépasse pas.

Avant de modéliser quoi que ce soit, essayer à la main. La figure suivante dessine la semaine de machine comme un conteneur gradué en heures, et chaque commande comme une caisse dont la hauteur est proportionnelle à ses heures. Le but est de charger la sélection la plus rentable qui tienne dans les cent heures. La figure ne dit pas où se trouve la meilleure : elle ne répond qu'à une proposition, une fois celle-ci soumise.

Le défi de la semaine10 commandes, capacité 100 h
C1 · 38 h5 200 €137 €/hC2 · 12 h1 300 € · 108 €/hC3 · 27 h3 300 €122 €/hC4 · 45 h6 100 €136 €/hC5 · 18 h2 100 €117 €/hC6 · 22 h2 900 €132 €/hC7 · 9 h · 800 €C8 · 31 h4 300 €139 €/hC9 · 14 h1 900 € · 136 €/hC10 · 7 h · 600 €
Heures
0 / 100
Marge
0 €
Capacité
respectée
Glisser des caisses dans le conteneur (ou les cliquer, ou Tab puis Entrée) pour chercher la sélection la plus rentable qui tienne dans la capacité (100 h).
Rendementplein : 136 à 139 €/hrayé : 117 à 132 €/hpointillé : 86 à 108 €/h
Les dix commandes de Valdrome, sur le quai, et la semaine de machine à charger (100 heures). La hauteur d'une caisse suit ses heures ; le remplissage (plein, rayé, pointillé) suit sa marge par heure.
À manipuler
Glisser des caisses dans le conteneur (à la souris ou au doigt), les cliquer, ou les choisir au clavier avec Tab puis Entrée, et regarder le niveau monter, la marge défiler. Une caisse qui dépasse le trait des cent heures reste posée au-dessus, hachurée : le conteneur la refuse, et la sélection ne peut pas être proposée. Proposer plusieurs sélections réalisables, et lire l'historique : la figure répond seulement « c'est l'optimum » ou « il existe mieux », puis, après plusieurs essais, donne des indices de plus en plus précis. Une fois l'optimum trouvé, rejouer les deux règles de bon sens et comparer ce qu'elles chargent avec ce qu'on avait trouvé à la main.

Pour répondre « c'est l'optimum », la figure a en coulisse énuméré les 1 024 sélections possibles, ce qu'un atelier ne peut pas toujours faire. Elle propose ensuite de rejouer deux règles de bon sens, celles qu'on essaie d'instinct : les commandes les plus rentables d'abord, ou celles qui rapportent le plus par heure de machine. Une règle aussi naturelle atteint-elle l'optimum ? La figure répond, règle par règle, une fois rejouée : c'est en la regardant charger le conteneur qu'on le constate, pas en croyant ce texte.

Le vocabulaire

Le même petit nombre de mots sert à décrire n'importe quelle décision d'atelier. Ils ont un sens précis, et la moitié des erreurs de modélisation vient de les employer l'un pour l'autre.

Définitions

Une décision est un choix à faire parmi plusieurs possibilités : quelles commandes lancer, dans quel ordre percer.

Une instance est un cas particulier de ce problème, avec ses données : ces dix commandes et ces cent heures, cette plaque et ces douze trous. Le problème est général, l'instance est ce qu'on doit résoudre lundi matin.

Une solution est une manière complète de trancher : la liste des commandes retenues, l'ordre de perçage. Une solution ne dit rien encore sur sa qualité, ni même sur sa possibilité.

Une contrainte est une condition qu'une solution doit respecter : ne pas dépasser cent heures, percer chaque trou une fois.

Une solution est réalisable si elle respecte toutes les contraintes.

Une fonction de coût (ou fonction objectif) associe à toute solution un nombre : la marge, la longueur parcourue. L'objectif est de rendre ce nombre le plus petit possible, ou le plus grand.

Un optimum est une solution réalisable dont le coût est le meilleur de toutes les solutions réalisables. L'espace des solutions est l'ensemble de toutes les solutions, réalisables ou non.

Le tableau met ces mots en face des deux décisions du chapitre.

MotLes commandes de la semaineLa plaque à percer
Décisionquelles commandes lancerdans quel ordre percer
Solutionun ensemble de commandes, par exemple C1, C4, C9un ordre des douze trous
Contrainteau plus 100 heures de machinechaque trou percé une fois, retour au départ
Coûtla marge, à rendre la plus grande possiblela longueur parcourue, à rendre la plus petite
Espace des solutions1 024 ensembles possibles479 001 600 ordres possibles

Une remarque sur le sens de l'optimisation. Maximiser une marge et minimiser une longueur sont le même problème vu de deux côtés : maximiser une grandeur revient à minimiser son opposé. Dans la suite, on parlera de coût sans se soucier du sens, et le texte dira chaque fois si l'on cherche le plus petit ou le plus grand.

Optimum et bonne solution ne sont pas synonymes
Un optimum est la meilleure solution réalisable, et il n'existe pas toujours d'algorithme qui le trouve en un temps raisonnable. Dans presque tout le parcours, on cherche une bonne solution, dont on mesure la distance à ce qu'on peut espérer. Confondre les deux mots fait annoncer « optimal » sur une solution simplement correcte.

Évaluer une solution

Avant de chercher une bonne solution, il faut savoir en juger une. C'est la première chose qu'un programme d'optimisation doit savoir faire, et c'est étonnamment facile : évaluer une solution ne demande que de l'additionner.

main.py
Sortie
>_ Prêt à exécuter…

Trois solutions, trois lignes de résultat, et déjà une surprise : la troisième rapporte le plus, et elle est irréalisable. Ce n'est pas un détail. Une fonction de coût seule, qui ne regarderait que la marge, la préférerait aux deux autres. Un coût sans contrainte recommande l'impossible. Toute la partie « pénalité » plus bas tourne autour de cette phrase.

La première ligne du résultat, « les plus rentables », est justement la règle de bon sens de la figure : on prend la commande la plus rentable, puis la suivante qui tient encore, jusqu'à ne plus pouvoir. Elle donne ici 13 200 euros pour 97 heures. Or aucune des deux règles n'atteint l'optimum, comme la figure le montre en les rejouant, une fois l'optimum trouvé : il existe, dans les deux cas, une sélection réalisable qui rapporte davantage. Une règle de bon sens donne des solutions plausibles, proches les unes des autres, et sans tout essayer on ne sait pas s'il en existe une meilleure. Cette incertitude est le sujet du parcours : une décision se juge par rapport à ce qu'on aurait pu faire, et pour cela il faut d'abord la mettre en forme.

Deux fonctions, pas une
Un problème d'optimisation se modélise avec deux outils distincts : une fonction de coût, qui note une solution, et un test de réalisabilité, qui dit si elle a le droit d'exister. Les mélanger dans une seule formule est possible (c'est la pénalité) mais c'est un choix à faire en connaissance de cause, pas un raccourci.

Représenter une solution

Pour manipuler une solution dans un programme, il faut la ranger dans une structure : une liste, un tableau de zéros et de uns, un dictionnaire. Ce choix s'appelle la représentation, et c'est de loin la décision de modélisation qui pèse le plus sur la suite. Un voisinage, un croisement, une mutation, des notions que les chapitres suivants poseront, se définissent sur la représentation et pas sur la solution abstraite.

Ce qu'on attend d'une représentation

Une bonne représentation vérifie quatre choses.

  1. Aucun objet impossible. Tout ce qu'on peut écrire dans la structure désigne une solution qui a un sens. Sinon, il faut tester la validité à chaque étape.
  2. Aucune solution oubliée. Toute solution utile, l'optimum en particulier, s'écrit. Une représentation qui l'exclut ne le trouvera jamais.
  3. Peu de doublons. Chaque solution s'écrit d'une seule façon, ou d'un petit nombre de façons. Sinon l'espace se gonfle de copies.
  4. Un petit changement de l'objet est un petit changement de la solution. C'est ce qui permettra de « bouger un peu » une solution pour la comparer à ses voisines.

Pour les commandes

Trois façons de ranger une sélection de commandes, et le tableau dit ce que chacune laisse passer.

ReprésentationExempleCe qu'elle laisse passer
Une liste de numéros[4, 1, 9][4, 4, 9] (une commande deux fois), [12] (une commande qui n'existe pas), et [1, 4, 9] comme [4, 1, 9] pour la même sélection
Dix zéros et uns, un par commande[1, 0, 0, 1, 0, 0, 0, 0, 1, 0]rien d'impossible : les 1 024 listes sont 1 024 sélections, chacune écrite d'une seule façon
Un ordre de lancement, avec la règle « on lance chaque commande si elle tient encore »[4, 1, 9, 6, ...]rien d'impossible non plus, mais une sélection qui peut encore accueillir une commande ne s'écrit jamais, et beaucoup d'ordres donnent la même sélection

La liste de numéros paraît naturelle, et elle est la pire : elle n'interdit ni le doublon ni le numéro inexistant, et chaque sélection s'y écrit de plusieurs façons. Les zéros et les uns n'ont aucun de ces défauts. Notons ce qu'ils ne font pas : ils ne garantissent pas la capacité. Une liste de dix zéros et uns est toujours une sélection, mais pas toujours une sélection réalisable, et la contrainte des cent heures reste à tester séparément.

La troisième représentation est plus subtile : elle règle ce problème en faisant de la contrainte une partie de la lecture. Un programme qui décode l'ordre en lançant chaque commande tant qu'elle tient ne produit jamais une sélection irréalisable. Le prix est un décodage à faire et beaucoup d'ordres qui ne changent rien. C'est un compromis, et le parcours en rencontrera d'autres.

Il se chiffre. Les 3 628 800 ordres possibles n'écrivent que 79 des 1 024 sélections : celles où plus aucune commande ne tient. C7 seule n'en fait pas partie, puisque, quel que soit l'ordre, au moins deux commandes se lancent. L'optimum en fait partie, et ce n'est pas un hasard : tant que chaque marge est positive, une sélection à laquelle on peut ajouter une commande est battue par la sélection agrandie. La représentation oublie donc des sélections, mais aucune qui puisse être la meilleure.

Pour la plaque

Même exercice pour l'ordre de perçage.

ReprésentationExempleCe qu'elle laisse passer
Une liste libre de douze noms["T4", "T9", "T4", ...]un trou percé deux fois, un trou oublié
Une permutation des douze trous["T4", "T9", "T11", ...]rien d'impossible, mais un ordre et son inverse mesurent la même chose
Pour chaque trou, le trou suivant{"T1": "T7", "T7": "T4", ...}des tournées en plusieurs boucles

La dernière est la plus trompeuse, parce qu'elle a l'air de respecter la règle : chaque trou a un suivant et un seul, chaque trou est le suivant d'un seul autre. Et pourtant.

main.py
Sortie
>_ Prêt à exécuter…

Le test le plus naturel répond « valide », et la représentation décrit deux boucles distinctes de trois trous : l'outil ne peut pas suivre deux boucles à la fois. Un test de validité incomplet est pire qu'aucun test, parce qu'il donne une confiance qu'il ne mérite pas. Un algorithme qui cherche la tournée la plus courte trouverait, dans un espace qui contient des doubles boucles, des « tournées » sensiblement plus courtes que les vraies, et les annoncerait avec fierté. Le remède est de choisir la permutation, qui ne laisse rien passer, plutôt que de compliquer le test.

Une représentation qui semble naturelle
Écrire d'abord ce qui vient à l'esprit, puis se demander « quels objets cette structure peut-elle contenir que je ne voulais pas ? ». La réponse est rarement « aucun ». Dresser la liste de ces objets, avant d'écrire une ligne de recherche, évite de chercher dans un espace faux.
Vérification rapideon peut se reprendre

1.Une représentation d'une solution est mauvaise quand…

2.Pour chaque trou de la plaque, on note le trou suivant. Un test vérifie que chaque trou a un seul suivant et un seul prédécesseur. Peut-on en déduire que c'est une tournée ?

Le coût : la trajectoire de la perceuse

Passons à la deuxième décision. La perceuse à commande numérique perce, sur une plaque de bride, douze trous dont les positions sont fixées par le plan. L'outil part de l'origine de la plaque, perce les douze trous, et revient à l'origine pour le changement de pièce. Il se déplace à vide à 30 mm par seconde. Ce qui est libre, c'est l'ordre. C'est le problème du voyageur de commerce (travelling salesman problem, TSP en anglais) : visiter chaque point une fois, revenir au départ, et parcourir le moins possible.

La fonction de coût est la longueur de la trajectoire, d'où l'on tire le temps de déplacement en divisant par la vitesse. Les contraintes sont dans la représentation : un ordre est une permutation, donc chaque trou est percé une fois, et le retour au départ fait partie de la mesure.

Dans la figure suivante, on construit soi-même un ordre de perçage en cliquant les trous l'un après l'autre. Le tracé, la longueur et le temps se mettent à jour à chaque trou. La figure ne juge pas l'ordre avant la fin, et l'ordre dans lequel le plan écrit les trous, celui que le programme suit sans réfléchir, peut se superposer à tout moment.

Ordre de perçage12 trous, distance euclidienne
Trous percés
0 / 12
Longueur
0,0 mm
Déplacement
0,0 s
T1T2T3T4T5T6T7T8T9T10T11T12
  1. Cliquer les trous dans l'ordre voulu. Au clavier : Tab pour passer d'un trou à l'autre, Entrée pour le percer, Retour arrière pour annuler.
L'outil attend au départ. Le premier trou cliqué est le premier percé.
La plaque P-217 : douze trous, coordonnées en millimètres. L'outil part de l'origine et y revient.
À manipuler
Percer d'abord les trous dans l'ordre de leur numéro, T1, T2, T3 et ainsi de suite, et regarder la longueur : c'est ce que fait le programme de la machine quand personne n'y a touché. Puis recommencer, en cherchant à raccourcir. Chaque trait qui traverse la plaque de part en part coûte cher ; se demander lesquels on peut supprimer, et à quel prix pour les autres. Cliquer le dernier trou percé, ou appuyer sur Retour arrière, défait le dernier choix. Une fois la tournée complète, comparer avec l'ordre d'écriture, puis avec la meilleure tournée connue. Superposer l'ordre d'écriture dessine ses traits en pointillés sous la tournée en cours.

L'ordre du plan mesure environ 1 080 mm, soit 36 secondes de déplacement. Une fois la tournée complète, la figure donne aussi la meilleure tournée connue, obtenue par un calcul exact mené une fois pour toutes : c'est elle qui sert de référence dans le calcul qui suit.

Ce que vaut un ordre de perçage

  • 1.

    Combien d'ordres de perçage existe-t-il pour les douze trous (tous les ordres, sans se soucier du sens de parcours) ?

  • 2.

    Combien de sélections possibles y a-t-il pour les dix commandes, chacune étant retenue ou non ?

  • 3.

    L'ordre d'écriture fait 1079,8 mm, et la meilleure tournée connue celle que la figure donne à la fin, 633,2 mm. À 30 mm par seconde, combien de secondes de déplacement une plaque économiserait-elle ?

  • 4.

    Si Valdrome perce 300 plaques de ce modèle par semaine, combien de minutes de machine cela représente-t-il ?

Environ soixante-quatorze minutes de machine par semaine, sans acheter quoi que ce soit ni changer une seule pièce : c'est le rendement d'une bonne modélisation suivie d'une bonne recherche, et c'est pourquoi l'entreprise s'y intéresse.

Et le pire est qu'on ne peut pas se contenter d'essayer tous les ordres : 479 millions pour douze trous, et ce nombre se multiplie par treize au trou suivant. Le chapitre suivant en fait le sujet.

Le coût est le modèle, pas la réalité
La longueur est un bon indicateur du temps de déplacement, mais elle n'est pas le temps de fabrication de la plaque. Si l'outil ralentit dans les virages, si la plaque bouge, si un trou demande un autre foret et un changement d'outil, minimiser la longueur ne minimise plus le temps perdu. Le modèle est une décision, et il est faux d'une manière qu'il faut savoir énoncer. Une bonne solution à un mauvais modèle est une mauvaise solution.

Contrainte dure ou pénalité

La capacité de cent heures est une contrainte dure : une solution qui la viole est irréalisable, et elle est écartée. C'est le cas le plus simple, mais ce n'est pas le seul choix possible. Une autre manière de traiter la capacité est d'autoriser les solutions qui la dépassent, et de les punir : on retranche à la marge un montant proportionnel au dépassement.

Contrainte dure, pénalité

Une contrainte dure écarte tout ce qui la viole : une solution qui ne la respecte pas est irréalisable, et n'est jamais retenue.

Une pénalité intègre la contrainte au coût. Si d(s)d(s) est le dépassement de la solution ss (nul quand elle est réalisable) et λ\lambda un poids, on note

valeur peˊnaliseˊe(s)=marge(s)−λ⋅d(s)\text{valeur pénalisée}(s) = \text{marge}(s) - \lambda \cdot d(s)

et on cherche à rendre cette valeur la plus grande possible. La solution irréalisable n'est plus interdite : elle est seulement moins bonne. Une contrainte traitée par une pénalité est dite souple.

Les deux choix ont chacun leur intérêt. La contrainte dure ne recommande jamais l'impossible, mais elle interdit à une recherche de traverser une zone irréalisable pour atteindre une bonne solution de l'autre côté : en imposant de rester dedans, on la coince. La pénalité laisse passer, et tout dépend alors de λ\lambda. Trop faible, la recherche préfère violer la capacité, parce que ça rapporte. Trop forte, elle a peur d'en approcher et se comporte comme une contrainte dure. Le bon λ\lambda se règle en mesurant.

main.py
Sortie
>_ Prêt à exécuter…

Lire la colonne des heures. Sans pénalité, la meilleure sélection retient les dix commandes, soit 223 heures. Avec un poids modeste, elle dépasse encore la capacité, et à 190 € par heure c'est encore le cas : C1, C6, C8 et C9 (105 heures, 14 300 €) valent 13 350, plus que la meilleure sélection réalisable, 13 300, parce que les cinq heures de trop rapportent 1 000 € et n'en coûtent que 950. Le seuil se lit dans ce rapport, 1 000 € pour cinq heures : au-dessus de 200 € par heure, la recherche revient à la meilleure sélection réalisable.

Une pénalité est une décision de gestion, pas un paramètre de technicien
Si une heure supplémentaire coûte réellement 150 € à Valdrome, alors dépasser la capacité n'est pas une violation : c'est une option chiffrée, et la bonne modélisation est la pénalité, avec λ égal à 150. Le tableau ci-dessus donne alors C1, C6, C8 et C9, 105 heures, 13 550 € pénalisés contre 13 300 € sans dépassement. Si les heures supplémentaires sont plafonnées à dix par semaine, ce plafond est une contrainte dure de plus, que la pénalité ne remplace pas. Si la machine est physiquement arrêtée après cent heures, la contrainte est dure et λ n'a pas de sens. Choisir entre les deux, c'est répondre à la question « que se passe-t-il vraiment ? », pas à « que trouve-t-on de plus commode ? ».

Au fil du parcours, les deux approches reviendront : la contrainte dure, quand une solution fabriquée est vérifiée puis rejetée ou réparée ; la pénalité, quand une recherche doit pouvoir traverser une zone interdite, comme dans le recuit simulé, une méthode que le parcours présentera plus loin.

Vérification rapideon peut se reprendre

1.Une pénalité de 50 € par heure de dépassement est retenue pour une contrainte de capacité. La recherche renvoie une solution qui dépasse la capacité de dix heures. Qu'en conclure ?

2.Laquelle de ces contraintes se modélise le mieux par une pénalité ?

Les erreurs de modélisation d'un débutant

Mettre la contrainte dans l'objectif, sans pente à suivre
« Maximiser la marge en respectant cent heures » contient les deux, et il est facile de les confondre. Écrire une fonction qui renvoie la marge seulement quand la capacité est respectée, et zéro sinon, donne une recherche aveugle : toutes les solutions irréalisables valent zéro, et rien ne dit laquelle est proche de la frontière. Une pénalité proportionnelle au dépassement, elle, donne une pente à suivre.
Oublier une contrainte implicite
Personne n'écrit « chaque trou doit être percé » parce que cela va de soi. Une représentation qui ne l'impose pas le laisse violer. Écrire la liste complète des contraintes, y compris celles qui paraissent évidentes, avant de choisir la représentation : c'est le moment le moins coûteux pour les découvrir.
Comparer des choses incomparables
Deux solutions ne se comparent que sur la même instance, avec la même fonction de coût. Dire qu'une méthode a trouvé 640 mm et une autre 12 900 € n'a aucun sens, et dire qu'elle est bonne parce qu'elle bat une autre sur une instance choisie pour elle n'en a pas davantage. Le parcours garde les mêmes données pour cette raison.
Croire qu'évaluer, c'est chercher
Évaluer une solution est facile, en temps proportionnel à sa taille. Chercher la meilleure parmi des millions ne l'est pas. Le premier est une fonction, le second est un algorithme, et il est fréquent qu'un débutant considère que sa fonction de coût est « la solution » du problème. Elle n'est que la règle du jeu.

Le fil du parcours

Valdrome revient avec cinq problèmes, toujours les mêmes données, consignées dans un fichier de référence.

ProblèmeDécisionCe qu'on y étudie
Commandes à lancerquelles commandes retenir sous une capacitéle sac à dos : contrainte, pénalité, bornes
Trajectoire de la perceusedans quel ordre percerle voyageur de commerce : voisinages, recuit, tabou, génétique
Découpe de barrescomment ranger des pièces dans des barres de 6 mle bin packing : règles gloutonnes, bornes
Ordonnancement d'une machinedans quel ordre fabriquer dix ordrespermutations, retards
Affectation des opérateursqui à quel postereprésentations qui laissent passer l'impossible

Le chapitre suivant montre pourquoi on ne peut pas tout essayer. Viennent ensuite des bornes, qui disent ce qu'on peut espérer, puis des règles simples de construction, la recherche locale, le recuit simulé, la recherche tabou, les algorithmes génétiques, les fourmis, et enfin la comparaison des méthodes entre elles et avec un solveur. L'ordonnancement de ce parcours n'a ni précédences entre ordres ni conflits à colorer ; si l'on en ajoutait, les chapitres graphes orientés et coloration du parcours Graphes serviraient. Sur la notion de difficulté, on renvoie à ce que le chapitre complexité pose déjà.

Exercices type

Dans la situation d'un atelier qui doit répartir 6 opérateurs sur 6 postes, qu'est-ce que la décision, la solution, les contraintes, le coût ?

La décision : quel opérateur va à quel poste. Une solution est une affectation complète, par exemple « l'opérateur 1 au poste 4, l'opérateur 2 au poste 1, et ainsi de suite ». Les contraintes : chaque opérateur tient un poste, chaque poste a un opérateur. Le coût : le temps total, ou l'un des temps individuels le plus long, selon ce qu'on veut optimiser, et ce choix est déjà une décision de modélisation.

Les affectations réalisables sont au nombre de 6!=7206! = 720. L'espace des solutions est plus vaste quand la représentation laisse passer les doubles affectations : avec une liste de six numéros de poste, il compte 66=46 6566^6 = 46\,656 listes, dont 720 seulement sont réalisables.

Une solution S1 rapporte 13 200 € pour 97 heures, une solution S2 rapporte 14 600 € pour 110 heures. Laquelle est meilleure ?

Le mot « meilleure » dépend de la contrainte. Avec cent heures de capacité dure, S2 est irréalisable, et S1 est la seule des deux qu'on puisse retenir. Avec une pénalité de 250 € par heure, S2 vaut 14 600−10×250=12 10014\,600 - 10 \times 250 = 12\,100, donc moins que S1 : S1 reste la meilleure. Avec une pénalité de 100 € par heure, S2 vaut 13 600 et l'emporte, ce qui montre qu'un poids trop faible recommande de violer la capacité.

Comparer deux marges sans regarder les contraintes ne compare rien.

Pourquoi ne pas représenter une tournée par « pour chaque trou, le trou suivant » ?

Parce que la structure décrit aussi des solutions qui n'en sont pas. Chaque trou peut avoir un suivant unique et un prédécesseur unique, et pourtant l'ensemble se décompose en plusieurs boucles disjointes, que l'outil ne peut pas suivre d'un seul trait. Un test qui ne vérifie que « un suivant, un prédécesseur » ne les voit pas.

Il faut soit un test supplémentaire (un seul cycle en partant de n'importe quel trou), soit une représentation qui ne laisse pas passer : une permutation. On paie la seconde option une fois, à la conception, au lieu de payer la première à chaque évaluation.

Une sélection est représentée par dix zéros et uns. Combien de listes sont réalisables pour cent heures ?

Le nombre de listes est 1 024, toutes des sélections. Le nombre de listes réalisables est le nombre de sélections qui tiennent dans les cent heures : le contrôle est un programme de trois lignes (parcourir les 1 024 listes, additionner les heures, compter celles qui ne dépassent pas la capacité), et il en trouve 406 sur cette instance. Environ quatre sélections sur dix.

Ce nombre n'est pas connu d'avance et il change avec la capacité, ce qui rappelle que la représentation ne garantit que ce qu'elle garantit : elle exclut l'impossible structurel, pas l'impossible numérique.

Quand une pénalité est-elle préférable à une contrainte dure ?

Quand la violation a un prix réel (heures supplémentaires, retard facturé, sous-traitance), parce qu'alors elle fait partie de la décision. Et quand la recherche a besoin de traverser des solutions irréalisables pour aller d'une région réalisable à une autre : interdire tout passage la couperait en morceaux.

Elle est plus risquée quand la violation est physiquement impossible : un poids mal réglé fait alors recommander l'impossible, et il faut ajouter un contrôle en sortie pour ne jamais présenter une solution irréalisable comme une réponse.

La méthode

  1. Écrire la décision en une phrase, avec ce qu'on choisit et ce qu'on ne choisit pas.
  2. Lister toutes les contraintes, y compris celles qui « vont de soi ».
  3. Écrire la fonction de coût, et dire si l'on minimise ou maximise.
  4. Choisir la représentation en se demandant quels objets elle laisse passer qui ne sont pas des solutions.
  5. Décider de chaque contrainte : dure, ou pénalité, en se demandant ce qui se passe réellement quand elle est violée.
  6. Évaluer à la main quelques solutions, dont une irréalisable, avant de programmer la moindre recherche.
  7. Fixer l'instance, pour que deux méthodes se comparent sur les mêmes données.

Synthèse

  • Une décision se modélise par une instance, une solution, des contraintes et une fonction de coût.
  • Une solution est réalisable si elle respecte toutes les contraintes ; l'optimum est la meilleure solution réalisable ; l'espace des solutions contient aussi les irréalisables.
  • Évaluer une solution est facile, en temps proportionnel à sa taille ; trouver la meilleure ne l'est pas.
  • Un coût sans contrainte recommande l'impossible : il faut deux outils, le coût et le test de réalisabilité.
  • La représentation décide de tout ce qui suit. Une bonne représentation n'admet aucun objet impossible, oublie aucune solution utile, en écrit peu de doublons.
  • Une représentation qui laisse passer l'impossible oblige à tester à chaque étape, et un test incomplet est pire que pas de test.
  • Une contrainte dure écarte toute solution qui la viole ; une contrainte souple passe par une pénalité, qui l'intègre au coût, avec un poids λ à régler en mesurant.
  • Le coût est un modèle : la longueur n'est pas le temps. Une bonne solution d'un mauvais modèle est une mauvaise solution.
  • Les cinq problèmes de Valdrome reviennent dans tout le parcours avec les mêmes données.

Mettre en pratique