Aller au contenu principal

D'autres modèles de calcul

Ce que ce chapitre apporte 6 points
  • Décrire les modèles de calcul de la recherche opérationnelle par ce qu'ils acceptent (variables, contraintes, objectif) et par ce que leur solveur rend.
  • Écrire un petit problème en programmation par contraintes : des variables à domaine fini, des contraintes logiques, sans objectif obligatoire.
  • Réduire des domaines par propagation, chercher par décisions et retour arrière, et lire ce que chaque étape retire.
  • Reconnaître un problème non linéaire, le résoudre avec scipy.optimize.minimize depuis plusieurs départs, et distinguer optimum local et optimum global.
  • Dire ce qui rend possible la programmation dynamique, et ce qui la limite.
  • Choisir un modèle de calcul d'après le problème, et ranger les problèmes concrets de la recherche opérationnelle selon le modèle qui leur va.
Les deux chapitres précédents ont écrit les problèmes de Valdrome Mécanique dans une seule langue, celle des inégalités linéaires, et un solveur les a résolus. Cette langue a ses limites. La règle « deux opérateurs ne tiennent jamais le même poste » y demande soixante-quatre variables et seize égalités ; une distance, une surface, un coût qui baisse avec la quantité ne s'y écrivent pas du tout. Ce chapitre présente les autres modèles de calcul de la recherche opérationnelle : la programmation par contraintes, pratiquée sur un petit solveur écrit dans la page, la programmation non linéaire, et, en rappel, la programmation dynamique. Il se termine sur la question qui relie les méthodes exactes à la suite du parcours : devant un problème, quel modèle choisir, et que faire quand aucun ne suffit.

Un modèle de calcul, ce qu'il accepte et ce qu'il rend

Un modèle de calcul est une façon d'écrire un problème pour qu'une famille de solveurs le résolve. Il fixe ce que peuvent être les variables, ce que peuvent dire les contraintes, la forme de l'objectif. En échange, le solveur promet une réponse d'une certaine nature : un optimum prouvé, une solution sans garantie, ou la preuve qu'il n'en existe aucune. Le parcours en a déjà employé deux, et en croise un troisième dans un autre parcours.

ModèleVariablesContraintes et objectifCe que rend le solveurDans le parcours
Programmation linéaireréellessommes de termes proportionnels aux variablesl'optimum, à un sommet du domaine, et sa preuvechapitre 3
Programmation linéaire en nombres entiersentières, binaires ou réellesles mêmesl'optimum et sa preuve, ou une solution et une bornechapitre 4
Satisfiabilité (SAT)booléennesdes clauses, sans objectifune affectation qui satisfait toutes les clauses, ou la preuve qu'il n'y en a pasparcours Logique et solveurs SAT
Programmation par contraintesentières, chacune dans un domaine finides contraintes logiques ; un objectif facultatifune solution, toutes, ou la meilleure, prouvée par une recherche complètece chapitre
Programmation non linéaireréellesun objectif ou des contraintes non linéaires : un produit, un carré, une distanceun optimum local, qui n'est garanti global que si le problème est convexece chapitre
Programmation dynamiquedes états, un par sous-problèmeun coût qui se calcule de sous-problème en sous-problèmel'optimum, si les états tiennent en mémoirechapitres 2 et 4, et ce chapitre

La programmation dynamique fait exception dans ce tableau : c'est une méthode plutôt qu'une langue, et aucun solveur général ne la prend en entrée. Elle y figure parce qu'elle est le troisième grand chemin vers un optimum exact, après la programmation linéaire et la séparation et évaluation.

La programmation par contraintes

Une question sans objectif

Le chef d'atelier de Valdrome reprend l'affectation des huit opérateurs du chapitre 4 sous un autre angle. Il ne demande pas le temps total le plus court : il veut que personne ne soit envoyé à un poste où il perd plus de 4 minutes sur son meilleur temps. Amel, dont le meilleur temps est de 11 minutes, au tournage comme à la peinture, peut donc tenir aussi le montage (15 minutes), mais pas le fraisage (18 minutes). La question est : une telle affectation existe-t-elle, et laquelle ?

Il n'y a pas d'objectif. Il y a huit décisions, une par opérateur, et deux règles. C'est le cadre de la programmation par contraintes.

Variable, domaine, contrainte

Une variable est une décision : ici, le poste d'un opérateur. Il y en a huit.

Son domaine est l'ensemble fini des valeurs qu'elle peut prendre : pour Amel, {Tournage, Peinture, Montage}, les postes où elle met au plus 4 minutes de plus qu'à son meilleur.

Une contrainte est une règle qui lie des variables. Ici, une seule : tous différents, deux opérateurs ne tiennent jamais le même poste.

Une solution donne à chaque variable une valeur de son domaine, de sorte que toutes les contraintes soient respectées. Un objectif peut s'ajouter ; il n'est pas obligatoire.

Le même problème, écrit pour milp au chapitre 4, demandait 64 variables binaires, une par couple opérateur-poste, et 16 égalités pour dire « un poste par opérateur, un opérateur par poste ». Ici, huit variables et une contrainte, qui se lit comme l'énoncé. La règle des 4 minutes ne coûte même pas une contrainte : elle est dans les domaines.

Essayer à la main

La figure pose une version plus sévère de la question : 3 minutes au plus au-dessus de son meilleur temps. À gauche les opérateurs, à droite les postes, une arête quand le poste est dans le domaine de l'opérateur. Placer chacun sur un poste différent revient à choisir huit arêtes sans extrémité commune, un couplage au sens du chapitre flots et couplages.

Couplage biparti8 candidats, 8 postes, 16 candidatures
AmelBrunoChloéDimitriÉliseFaridGaëlleHugoTournageFraisagePerçageÉbavurageSoudurePeintureMontageContrôle

Trait épais : le couplage. Contour tireté : sans affectation. Cliquer une arête pour la prendre ou la rendre.

Placer des candidats en cliquant leurs arêtes.

Couplage de taille 0.

Sans poste : Amel, Bruno, Chloé, Dimitri, Élise, Farid, Gaëlle et Hugo. Vacants : Tournage, Fraisage, Perçage, Ébavurage, Soudure, Peinture, Montage et Contrôle.

Les opérateurs à gauche, les postes à droite, une arête quand l'opérateur met au plus 3 minutes de plus qu'à son meilleur poste. Placer chacun sur un poste différent.
À manipuler
Placer les opérateurs un à un en cliquant leurs arêtes, Dimitri d'abord, qui n'a qu'un poste possible. Quand un opérateur reste sans poste, demander un chemin augmentant, et échanger tant que la figure en trouve un. Quand elle n'en trouve plus, elle désigne un groupe d'opérateurs : compter les postes que ce groupe vise, et les comparer à son effectif.
Ajouter ensuite une candidature, Amel au montage, où elle met 15 minutes, 4 de plus qu'à son meilleur poste, et demander de nouveau un chemin.

Le couplage plafonne à 7, quel que soit l'ordre des placements, et la figure en donne la raison : Amel, Dimitri et Farid ne visent, à eux trois, que deux postes, le tournage et la peinture. Trois opérateurs pour deux postes : l'un des trois restera sans poste. C'est une preuve d'impossibilité qui tient en une ligne, la condition de Hall. Avec la candidature d'Amel au montage, l'une de celles qu'ajoute la règle des 4 minutes, un chemin augmentant apparaît et les huit trouvent leur place. L'affectation obtenue est la seule possible : Amel au montage, Bruno au perçage, Chloé à la soudure, Dimitri au tournage, Élise au contrôle, Farid à la peinture, Gaëlle à l'ébavurage, Hugo au fraisage. C'est l'affectation de 95 minutes, l'optimum du chapitre 4, trouvée sans avoir jamais parlé de temps total.

Propager : réduire les domaines

Un solveur par contraintes ne commence pas par essayer. Il commence par propager : chaque contrainte retire des domaines les valeurs qu'aucune solution ne peut employer. Pour « tous différents », la règle la plus simple tient en une phrase : un opérateur dont le domaine n'a plus qu'un poste le tient, et ce poste disparaît du domaine des autres. Un retrait peut laisser un autre opérateur avec un seul poste, qui se propage à son tour : la propagation continue tant qu'un domaine change.

À 4 minutes, trois opérateurs n'ont qu'un poste dès le départ : Dimitri (le tournage), Farid (la peinture) et Gaëlle (l'ébavurage). Le programme suivant est un solveur par contraintes complet, en une cinquantaine de lignes : la propagation, la recherche, et un plafond de temps dont une section plus bas dit l'usage. Il affiche, à chaque étape, ce que la propagation retire.

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

À 4 minutes, la propagation résout le problème à elle seule, sans une seule décision. Dimitri tient le tournage, qu'Amel perd ; Farid tient la peinture, qu'Amel, Bruno et Élise perdent ; Gaëlle tient l'ébavurage, que Chloé perd ; Amel n'a plus que le montage, qu'elle retire à Chloé et à Hugo ; et la cascade continue jusqu'à ce que chacun ait un seul poste. Sept étapes, onze postes retirés en tout, une affectation, et la preuve qu'elle est la seule : chaque valeur retirée l'a été parce qu'aucune solution ne pouvait l'employer.

À 3 minutes, la cascade tourne court : Dimitri et Farid prennent les deux seuls postes d'Amel, et son domaine se vide. C'est une impasse, et comme aucune décision n'a été prise, elle vaut preuve : aucune affectation ne respecte la règle. Le groupe Amel, Dimitri, Farid de la figure ressort du journal sans avoir été cherché.

La règle du poste unique s'écrit en une quinzaine de lignes. Le bloc suivant la fait écrire sur des domaines donnés comme des listes de noms, et l'éprouve sur les opérateurs de Valdrome.

Exercice : écrire puis vérifier

La propagation de « tous différents »

Écrire propager(domaines). domaines associe à chaque opérateur la liste des postes qu'il peut encore tenir. La fonction renvoie un nouveau dictionnaire où chaque opérateur dont la liste n'a plus qu'un poste a retiré ce poste de la liste des autres, et cela tant qu'un retrait en entraîne un autre. Chaque liste garde l'ordre de la liste reçue.

Si une liste devient vide, l'affectation est impossible : la fonction renvoie None. Le dictionnaire reçu ne doit pas être modifié.

À compléter

Écrire la fonction, puis « Vérifier » : 7 vérifications sur des cas qu'on sait faire de tête.

Le troisième essai dit la limite de cette règle : trois opérateurs qui se partagent deux postes ne laissent aucune liste à un seul poste, et la propagation ne retire rien, alors que le problème est impossible. Pour le prouver, il faut chercher, ou propager plus fort.

Chercher : décider, propager, revenir en arrière

Quand la propagation ne retire plus rien et que des opérateurs ont encore le choix, le solveur décide : il prend l'opérateur qui a le moins de postes possibles, lui donne l'un d'eux, et propage de nouveau. Si une impasse survient, il revient en arrière : il oublie la décision et essaie le poste suivant. Dans le solveur plus haut, la décision se prend sur une copie des domaines, et revenir en arrière consiste à abandonner cette copie.

Le choix du plus contraint d'abord n'est pas un détail. Un opérateur qui n'a plus que deux postes possibles a une chance sur deux de recevoir le bon, et sa décision déclenche aussitôt des retraits ; commencer par Bruno, qui en a cinq, ferait explorer des branches qu'une propagation aurait coupées plus tôt. Remplacer (4, 3) par (5, 6) dans le solveur : la propagation ne suffit plus, et le journal montre les décisions, puis les retours à la décision précédente pour essayer le poste suivant. Il compte 7 affectations à 5 minutes et 12 à 6.

Propager, décider, revenir en arrière
C'est tout l'algorithme d'un solveur par contraintes, et c'est aussi celui de DPLL, dans le parcours Logique et solveurs SAT : la satisfiabilité est le cas où chaque domaine n'a que deux valeurs, vrai et faux, et où chaque contrainte est une clause. Ce parcours la traite à part, avec ses propres solveurs. La propagation fait le travail qui ne demande aucun pari ; la recherche ne parie que sur ce qui reste.

Optimiser : un plafond qui descend

La programmation par contraintes n'a pas besoin d'objectif, mais elle sait en traiter un, à sa manière : en le changeant en contrainte. Pour l'affectation au plus court, la contrainte est « le temps total ne dépasse pas un plafond ». Sa propagation reprend le calcul de borne du chapitre 4 : le temps total est au moins la somme des temps les plus courts que chaque domaine permet encore, et un poste est retiré s'il pousse cette somme au-dessus du plafond. Sans écart imposé, cette somme vaut au départ 88 minutes, la borne des minima de ligne, et elle monte à mesure que les domaines rétrécissent.

Le dernier appel du solveur, resoudre(ecart=99, plafond=999), permet tous les postes et part d'un plafond inatteignable, 999 minutes. À chaque solution trouvée, le plafond descend juste en dessous de son temps, et la recherche continue : elle ne cherche plus qu'une affectation strictement meilleure. Quand elle a tout parcouru, la dernière solution trouvée est prouvée optimale.

La première solution, 125 minutes, est celle de la règle gloutonne du chapitre 6, chacun dans l'ordre au poste libre le plus rapide : tant que le plafond ne gêne pas, la recherche commence comme elle. Suivent 122, 105, 99, 98 et 95 minutes, puis la preuve. Il a fallu 40 nœuds, c'est-à-dire 40 appels à chercher, dont 25 finissent en impasse ; la même recherche sans plafond, resoudre(ecart=99), en visite 69 281 pour énumérer les 40 320 affectations. Le plafond joue ici le rôle de l'élagage du chapitre 4.

Sur ce problème, la programmation linéaire voit pourtant plus loin : sa relaxation continue vaut 95 minutes d'emblée (chapitre 4), quand la propagation du plafond part de 88. Une somme se borne mieux par un programme linéaire ; une règle logique se dit mieux en contraintes. Les solveurs industriels mêlent les deux.

Ce qui la distingue de la programmation linéaire

  • Des contraintes logiques, écrites telles quelles : tous différents, « ces deux ordres ne passent pas sur la machine en même temps », « si Amel est au montage, Hugo est au fraisage ». En programme linéaire, chacune se traduit en variables binaires et en inégalités, parfois au prix de centaines de variables : 424 pour les dix ordres du modèle indexé par le temps du chapitre 13.
  • Des variables à domaine fini, que la propagation réduit, et aucune variable réelle.
  • Pas d'objectif obligatoire : une question de faisabilité est un problème complet, et sa réponse peut être une preuve d'impossibilité. Un objectif se traite comme un plafond qui descend.
  • Une preuve par recherche complète, et non par une borne de relaxation. La propagation borne mal les sommes ; la programmation linéaire dit mal les règles logiques.

Les solveurs industriels poussent chacun de ces traits plus loin. Leur propagation de « tous différents » s'appuie sur le couplage de la figure : elle retire tout poste qu'aucune affectation complète ne peut employer, et voit d'un coup le groupe d'Amel, Dimitri et Farid. CP-SAT, d'OR-Tools, ajoute l'apprentissage sur les impasses des solveurs SAT (le chapitre CDCL) et des relaxations linéaires pour les sommes. Le chapitre 13 écrit l'ordonnancement des dix ordres pour lui, avec des intervalles et une contrainte de non-recouvrement, et le compare au modèle linéaire du même problème.

Vérification rapideon peut se reprendre

1.La propagation de « tous différents » s'arrête en laissant au moins un poste à chaque opérateur, et plusieurs à certains d'entre eux. Que peut-on conclure ?

2.Quel trait distingue la programmation par contraintes de la programmation linéaire en nombres entiers ?

La programmation non linéaire

La plus grande ventouse

Pendant le perçage de la plaque P-217, une ventouse tient la tôle par-dessous. Elle est ronde, et le foret ne doit jamais la toucher : son disque ne doit contenir aucun des douze trous. Où la poser, et de quel rayon au plus, pour qu'elle tienne le mieux ? Son centre reste dans le rectangle des trous, de 20 à 180 mm en largeur et de 15 à 105 mm en hauteur.

Les variables sont trois : le centre (x ; y)(x \,;\, y) et le rayon rr. L'objectif est rr, à rendre le plus grand possible. Chaque trou (a ; b)(a \,;\, b) donne une contrainte :

(x−a)2+(y−b)2  ≥  r.\sqrt{(x - a)^2 + (y - b)^2} \;\ge\; r .

L'objectif est linéaire ; les douze contraintes ne le sont pas, parce qu'une distance est la racine d'une somme de carrés et non une somme de termes proportionnels aux variables. Dessinée, la contrainte d'un trou n'est pas un demi-plan mais l'extérieur d'un disque, et le domaine où le centre peut aller, pour un rayon donné, est un rectangle percé de douze disques : rien d'un polygone. C'est un programme non linéaire.

Plusieurs départs, plusieurs réponses

scipy.optimize.minimize résout ce genre de problème. Avec la méthode SLSQP, elle part d'un point, suit la pente de l'objectif en tenant compte des contraintes, et s'arrête quand plus aucun petit déplacement n'améliore. Elle minimise : pour agrandir rr, elle reçoit −r-r. Le programme la lance depuis dix départs tirés au hasard (graine 5), puis, pour comparer, minimise depuis les mêmes départs une fonction d'une autre nature : la somme des distances du centre aux douze trous.

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

Dix départs, huit réponses différentes, de 18,75 à 45,25 mm. Chacune est un optimum local : un petit déplacement du centre, dans n'importe quelle direction, le rapproche d'un trou. Deux départs seulement, (25 ; 57) et (22 ; 35), trouvent 45,25 mm, avec le centre en (24,75 ; 60), à égale distance de T1, T4 et T9 ; les autres s'arrêtent chacun sur un autre optimum local, à égale distance de deux ou trois trous. Un balayage de tout le rectangle au vingtième de millimètre, calculé à part, ne trouve rien au-dessus de 45,25 mm : c'est l'optimum global, et le programme n'avait aucun moyen de le savoir. La somme des distances, elle, ramène les dix départs au même point, (102,0 ; 58,8).

Local, global, convexe

Optimum local, optimum global, convexité

Un optimum local est une solution qu'aucune solution voisine n'améliore. Un optimum global est la meilleure de toutes. Un solveur comme SLSQP, qui ne regarde que les environs du point courant, ne garantit que le premier.

Un problème de minimisation est convexe quand le segment qui joint deux solutions reste fait de solutions, et que le coût, le long de ce segment, ne passe jamais au-dessus de la corde qui joint ses valeurs aux deux bouts : il n'a qu'une vallée. Dans un problème convexe, tout optimum local est global.

La somme des distances est convexe : d'où que parte la recherche, elle descend dans la même vallée. Le problème de la ventouse ne l'est pas : le segment qui joint deux bons centres peut traverser le disque d'un trou, et le relief du rayon possible a plusieurs bosses, une par zone libre entre les trous. Le programme linéaire du chapitre 3, lui, est toujours convexe, son domaine est un polygone et son objectif linéaire : c'est pourquoi un sommet dont aucun voisin ne fait mieux y est l'optimum, et c'est ce dont le simplexe profite.

Deux propriétés de la programmation linéaire se perdent donc en non linéaire. Plus de sommet garanti : le meilleur centre, en (24,75 ; 60), n'est le coin de rien, c'est un point où trois distances deviennent égales. Plus de garantie qu'un optimum local soit global, dès que le problème n'est pas convexe. La descente de gradient du parcours Intelligence artificielle fait la même expérience sur une courbe à deux vallées, dans le chapitre la descente de gradient : deux départs, deux minimums. La convexité d'une fonction d'une variable est étudiée dans le chapitre étude d'une fonction, les extremums de deux variables dans le chapitre fonctions de plusieurs variables.

Devant un problème non convexe, trois attitudes sont possibles. Lancer plusieurs départs et garder le meilleur, ce que fait le programme, sans jamais l'annoncer global. Employer un solveur global, qui découpe le domaine en morceaux et borne chacun, comme la séparation et évaluation du chapitre 4 : il prouve l'optimum de petits problèmes, au prix d'un temps qui explose avec le nombre de variables. Ou chercher par une métaheuristique, qui accepte de remonter pour franchir un col : c'est l'idée du recuit simulé, au chapitre 8.

Dix départs pour une ventouse

Une seule étape est fausse. Désigner laquelle.

Un technicien relance le programme de la ventouse avec la graine 10 au lieu de 5, et conclut. Pour éprouver sa démarche : le point (x ; 60)(x \,;\, 60) de la plaque, sur la droite qui passe par T9 et T11, pour xx entre 20 et 40 mm, et sa marge, la distance au trou le plus proche.

Vérification rapideon peut se reprendre

1.Depuis dix départs, SLSQP rend dix optimums locaux, dont le meilleur fait 41,41 mm. Que représente 41,41 mm ?

2.Un problème de minimisation est convexe. La recherche locale part de trois points différents. Que rendra-t-elle ?

La programmation dynamique, en rappel

Le parcours l'a déjà rencontrée deux fois : au chapitre 2, la méthode de Held et Karp donnait la meilleure tournée de la plaque P-217 ; au chapitre 4, un tableau meilleure[c] donnait la meilleure marge des commandes pour chaque capacité. Le chapitre gloutons et programmation dynamique du parcours Algorithmique en donne la technique. Ce qui compte ici, c'est ce qui la rend possible et ce qui la limite.

Elle repose sur deux conditions.

  • Des sous-problèmes qui se recouvrent. Beaucoup de solutions différentes passent par le même état. Dans l'ordonnancement des dix ordres, tous les plans qui commencent par O3 et O7, dans un ordre ou dans l'autre, partagent la même suite possible : le même sous-problème, « placer au mieux les huit autres à partir de l'heure 4 ».
  • Le principe d'optimalité. La meilleure solution du tout est faite des meilleures solutions de ses parties : la meilleure façon de finir ne dépend pas de la façon dont on a commencé, seulement de l'état atteint. Pour un ensemble SS d'ordres passés en premier, la machine est libre à l'heure ∑j∈Spj\sum_{j \in S} p_j, quel que soit leur ordre ; le meilleur plan de SS s'obtient donc en choisissant l'ordre de SS qui passe en dernier, et en reprenant le meilleur plan des autres.

Le programme suivant applique cette idée aux dix ordres : un sous-problème par ensemble d'ordres, soit 210=1 0242^{10} = 1\,024.

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

Le programme retrouve les 17 heures de retard de l'optimum, avec l'un des ordres qui les atteignent, en résolvant 1 024 sous-problèmes au lieu d'essayer les 3 628 800 ordres de passage. C'est ce qui fait la force de la méthode : elle est exacte, et elle ne refait jamais deux fois le même calcul.

Sa limite est la mémoire : il faut garder un résultat par état. Pour le sac à dos, les états sont les capacités, de 0 à 100 heures, et leur nombre grandit avec la taille des nombres, pas avec le nombre de commandes : c'est pourquoi le chapitre 4 traite mille commandes en une fraction de seconde. Pour l'ordonnancement et pour la tournée, les états sont des ensembles, et leur nombre double à chaque ordre ou à chaque trou de plus.

Ce que coûtent les états

  • 1.

    Combien d'ensembles d'ordres la programmation dynamique examine-t-elle pour vingt ordres ?

  • 2.

    Pour trente ordres, à 8 octets par résultat gardé, combien de milliards d'octets (gigaoctets) faut-il ?

  • 3.

    Held et Karp gardent un résultat par ensemble de trous et par trou d'arrivée, dans un tableau de n×2nn \times 2^n cases. Pour trente trous, à 8 octets la case, combien de gigaoctets ?

Vingt ordres tiennent dans un million de résultats ; trente demandent 8,6 gigaoctets, et Held et Karp en demandent près de 258 pour trente trous, les « centaines de gigaoctets » du chapitre 2. À soixante trous, le nombre d'ensembles dépasse 101810^{18} : aucune mémoire ne le contient. La programmation dynamique déplace la frontière de l'exact, elle ne la supprime pas.

Quel modèle pour quel problème

Le choix d'un modèle ne se fait pas au goût : il se lit sur le problème. Sept questions suffisent presque toujours.

Question sur le problèmeCe que la réponse indique
Les variables sont-elles réelles, entières, ou une valeur parmi quelques-unes (un poste, un créneau) ?réelles : programmation linéaire ou non linéaire ; entières : programmation en nombres entiers ; une valeur parmi quelques-unes : programmation par contraintes
L'objectif et les contraintes sont-ils linéaires ?oui : programmation linéaire, en nombres entiers si besoin ; non, mais une formule : programmation non linéaire ; un coût calculé par une simulation : métaheuristique
Y a-t-il des contraintes logiques : tous différents, pas en même temps, si… alors ?programmation par contraintes, ou SAT si tout est vrai ou faux ; en programmation linéaire, au prix de variables binaires
Le problème se découpe-t-il en sous-problèmes qui se recouvrent, et en petit nombre ?programmation dynamique
Quelle taille ?petite à moyenne : une méthode exacte passe ; très grande : une métaheuristique
Combien de temps pour répondre ?des minutes : un solveur exact avec une limite de temps ; une seconde : une règle constructive et une recherche locale
Faut-il une preuve d'optimalité ?oui : programmation linéaire, en nombres entiers, par contraintes, dynamique ; un écart garanti suffit : un solveur arrêté avec sa borne ; non : une métaheuristique

Les problèmes concrets que la recherche opérationnelle résout se rangent alors d'eux-mêmes. Le tableau suivant les reprend, avec leur exemple chez Valdrome quand le parcours en a un.

ProblèmeExempleLe modèle qui lui vaQuand il ne suffit plus
Planification et emploi du tempsdes sessions à placer dans des créneaux, sans chevauchement pour un même formateurprogrammation par contraintes, ou SATdes milliers de créneaux et des préférences pondérées : recherche locale
Ordonnancementles dix ordres sur une machine, 17 h de retardprogrammation par contraintes (CP-SAT, chapitre 13) ; programmation dynamique jusqu'à une vingtaine d'ordres ; nombres entiers indexés par le tempsdes centaines d'ordres et des temps de réglage : recherche locale, tabou (chapitres 7 et 9)
Affectationhuit opérateurs, huit postes, 95 minprogrammation linéaire, dont les sommets sont entiers, ou méthode hongroisedes règles logiques en plus : programmation par contraintes
Transportles trois carrières et les quatre chantiers du chapitre 3programmation linéaire, aux sommets entiers dès que les offres et les demandes le sontdes coûts fixes d'ouverture : nombres entiers
Tournéesla perceuse, plaques P-217 et P-600nombres entiers avec coupes de sous-tour (chapitre 4) ; Held et Karp jusqu'à une vingtaine de trousdes centaines de points, une réponse en secondes : métaheuristiques, bibliothèque de routage
Découpevingt pièces dans des barres de 6 m, 5 barresnombres entiersde grandes séries : règles constructives (chapitre 6), algorithme génétique (chapitre 10)
Sac à dosdix commandes, 100 heures, 13 300 €programmation dynamique tant que la capacité est un petit entier ; nombres entiersrarement : c'est le plus docile des problèmes difficiles

La table conclut sans ambiguïté pour les grands problèmes difficiles du parcours, ceux dont la taille dépasse ce que l'exact sait traiter dans le temps disponible, ou dont le coût ne s'écrit dans aucun modèle : aucun solveur ne rendra l'optimum à temps, et il faut une méthode qui rende une bonne solution sans preuve, jugée contre une borne. Ce sont les métaheuristiques, qu'ouvre le chapitre suivant.

Vérification rapideon peut se reprendre

Valdrome doit replanifier quarante ordres avec des temps de réglage, et le chef d'atelier veut une réponse en une seconde. Quel modèle convient le mieux ?

Les erreurs d'un débutant

Tout écrire en inégalités
La programmation linéaire est la première langue apprise, et la tentation est de tout y traduire. « Tous différents » y coûte 64 variables binaires pour huit opérateurs, « pas en même temps » 424 pour dix ordres. Quand une règle se dit en une contrainte logique, un modèle par contraintes la garde lisible, et la propagation la traite directement.
Croire que la propagation a tout dit
Une propagation qui s'arrête sans vider de domaine ne prouve pas qu'une solution existe. Trois opérateurs qui se partagent les deux mêmes postes gardent chacun deux postes possibles : la règle du poste unique ne retire rien, et pourtant l'affectation est impossible. Seule la recherche, ou une propagation plus forte, conclut.
Prendre le meilleur des départs pour l'optimum
Dix départs de SLSQP avec la graine 10 donnent au mieux 41,41 mm ; la plaque admet 45,25 mm. Le meilleur de plusieurs optimums locaux est une solution, pas une preuve. L'annoncer global demande un argument : la convexité du problème, un balayage complet, ou une borne.
Croire le message de fin du solveur
Depuis le départ (90 ; 60), SLSQP s'arrête en (85 ; 60), à mi-chemin de T9 et de T11, sur un rayon de 15 mm, avec le message « Optimization terminated successfully ». Ce point n'est même pas un optimum local : un millimètre plus haut, en (85 ; 61), la ventouse peut déjà mesurer 15,03 mm. C'est un col, au sens du chapitre fonctions de plusieurs variables : le rayon possible y est le plus grand dans le sens horizontal, le plus petit dans le sens vertical, et le solveur, qui ne regarde que la pente, n'y voit aucune pente qui monte. Le statut dit que le solveur ne sait plus progresser, rien de plus.
Lancer une programmation dynamique sans compter ses états
Le principe d'optimalité garantit la justesse, pas la taille. Avant d'écrire la récurrence, compter les états : une capacité de quelques milliers d'heures passe, 2302^{30} ensembles d'ordres demandent 8,6 gigaoctets, 2602^{60} n'existent dans aucune mémoire.

Exercices type

Trois opérateurs ont chacun pour domaine {Tournage, Peinture}. Que fait le solveur de la page, et combien de nœuds lui faut-il pour conclure ?

La propagation ne retire rien : aucun domaine n'a un seul poste. Le solveur décide donc pour le premier opérateur : le tournage. La propagation retire le tournage aux deux autres, qui n'ont plus que la peinture ; le deuxième la tient et la retire au troisième, dont le domaine se vide. Impasse. Retour arrière : le premier prend la peinture, et la même cascade, symétrique, vide un domaine. Deuxième impasse. Trois nœuds (la racine et deux décisions) prouvent qu'aucune affectation n'existe.

Une propagation fondée sur le couplage l'aurait vu sans décision : trois opérateurs pour deux postes, la condition de Hall est violée. C'est ce que font les solveurs industriels.

Écrire en programmation par contraintes l'ordonnancement des dix ordres du chapitre 6 : variables, domaines, contraintes, objectif.

Une variable par ordre, son heure de début djd_j. Les durées font 46 heures en tout : le domaine de djd_j va de 0 à 46−pj46 - p_j, où pjp_j est sa durée. Une contrainte par paire d'ordres, logique : dj+pj≤dkd_j + p_j \le d_k ou dk+pk≤djd_k + p_k \le d_j, l'un finit avant que l'autre commence. L'objectif est de minimiser la somme des max⁡(0, dj+pj−ej)\max(0,\ d_j + p_j - e_j), où eje_j est l'échéance.

Dix variables, quand le modèle linéaire indexé par le temps du chapitre 13 en compte 424. Un solveur par contraintes regroupe les quarante-cinq paires en une seule contrainte de non-recouvrement, celle du modèle CP-SAT du chapitre 13.

La programmation dynamique du sac à dos traite mille commandes et une capacité de 25 424 heures. Combien de résultats garde-t-elle, et pourquoi la mémoire n'est-elle pas un obstacle ?

Un résultat par capacité, de 0 à 25 424 heures : 25 425 nombres, mis à jour une fois par commande, soit de l'ordre de 25 millions d'opérations. Les états sont des capacités, pas des ensembles de commandes : leur nombre suit la taille des nombres, pas le nombre de commandes. C'est la différence avec Held et Karp, dont les états sont des ensembles de trous, et dont le nombre double à chaque trou.

Un client demande de répartir des pièces entre trois ateliers et cinq clients au moindre coût de transport ; un autre, de placer quarante ordres avec des temps de réglage, réponse en une seconde. Quel modèle pour chacun ?

Le premier est un problème de transport, de la même forme que celui des carrières et des chantiers du chapitre 3 : un programme linéaire, dont les sommets sont entiers dès que les offres et les demandes le sont. Un solveur le résout exactement, en un instant.

Le second est un ordonnancement de taille moyenne, avec un coût qui dépend de la séquence, et une limite de temps sévère : une règle constructive suivie d'une recherche locale rend une bonne solution dans la seconde. Un solveur par contraintes avec une limite de temps peut servir de référence sur le même cas, hors délai.

La méthode

  1. Écrire le problème en mots : les décisions, les règles, le coût, et repérer ce qui n'est pas une inégalité linéaire (une règle logique, un produit, une distance).
  2. Choisir la nature des variables : réelles, entières, booléennes, ou une valeur parmi quelques-unes.
  3. Passer la table de décision : linéarité, contraintes logiques, sous-problèmes qui se recouvrent, taille, temps disponible, besoin d'une preuve.
  4. En programmation par contraintes, poser les domaines et les contraintes, propager, décider pour le plus contraint d'abord, revenir en arrière sur une impasse ; optimiser par un plafond qui descend.
  5. En non linéaire, lancer plusieurs départs, garder le meilleur, lire le statut sans le croire, et n'annoncer un optimum global qu'avec un argument : convexité, balayage, borne.
  6. En programmation dynamique, nommer l'état, vérifier le principe d'optimalité, et compter les états avant de lancer le calcul.
  7. Si aucune méthode exacte ne passe dans la taille et le temps donnés, chercher une bonne solution par une métaheuristique, et la juger contre une borne.

Synthèse

  • Un modèle de calcul fixe ce que les variables, les contraintes et l'objectif peuvent être, et le solveur rend en échange une réponse d'une nature donnée : optimum prouvé, solution sans garantie, preuve d'impossibilité.
  • La programmation par contraintes pose des variables à domaine fini et des contraintes logiques, sans objectif obligatoire. Elle propage (retirer des domaines ce qu'aucune solution n'emploie), décide pour le plus contraint et revient en arrière sur une impasse. Sur les opérateurs de Valdrome, la propagation seule trouve l'unique affectation à 4 minutes au plus de chacun, celle de 95 minutes, et prouve qu'il n'y en a aucune à 3 minutes.
  • Elle optimise en changeant l'objectif en plafond : 40 nœuds pour prouver les 95 minutes, contre 40 320 affectations à énumérer. SAT en est le cas à deux valeurs, traité dans son propre parcours, et CP-SAT (chapitre 13) la version industrielle.
  • La programmation non linéaire accepte un objectif ou des contraintes non linéaires, au prix de deux garanties : l'optimum n'est plus à un sommet, et un optimum local n'est plus forcément global. Pour la ventouse de la plaque P-217, dix départs trouvent huit optimums locaux, de 18,75 à 45,25 mm. Seul un problème convexe assure que tout optimum local est global.
  • La programmation dynamique demande des sous-problèmes qui se recouvrent et le principe d'optimalité ; elle retrouve les 17 heures des dix ordres en 1 024 sous-problèmes. Sa limite est la mémoire, qui double à chaque élément quand les états sont des ensembles.
  • Le modèle se choisit sur le problème : nature des variables, linéarité, contraintes logiques, taille, temps, preuve. Pour les grands problèmes difficiles, aucun ne rend l'optimum à temps : ce sont les métaheuristiques qui prennent le relais.

Et ensuite

Quand un problème est trop grand pour un solveur, ou que son coût ne s'écrit dans aucun de ces modèles, il faut chercher autrement : le chapitre suivant construit une solution par une règle simple, et les chapitres qui le suivent l'améliorent. La règle gloutonne que le chapitre 6 applique aux opérateurs est celle que le solveur par contraintes a trouvée en premier, à 125 minutes. Pour les solveurs industriels, CP-SAT et la bibliothèque de routage d'OR-Tools, le chapitre 13 ; pour ce qui fait tourner un solveur de satisfiabilité, le parcours Logique et solveurs SAT.

Chapitre révisé en octobre 2026 · Une erreur dans ce chapitre ?

Mettre en pratique

Compter ce que la propagation retire, écrire un retour arrière, attraper un plafond qui retire trop, et lancer un problème non linéaire depuis plusieurs départs.

Tous les exercices sur d'autres modèles de calcul