Programmation par contraintes

Un article de Wikipédia, l'encyclopédie libre.

La programmation par contraintes (PPC, ou CP pour constraint programming en anglais) est un paradigme de programmation apparu dans les années 1970 et 1980[1],[2] permettant de résoudre des problèmes combinatoires de grande taille tels que les problèmes de planification et d'ordonnancement[3]. En programmation par contraintes, on sépare la partie modélisation à l'aide de problèmes de satisfaction de contraintes (ou CSP pour Constraint Satisfaction Problem), de la partie résolution dont la particularité réside dans l'utilisation active des contraintes du problème pour réduire la taille de l'espace des solutions à parcourir (on parle de propagation de contraintes).

« En informatique, de toutes les approches en programmation, la programmation par contraintes se rapproche le plus de l'idéal : l'utilisateur décrit le problème, l'ordinateur le résout. »

— E. Freuder[4]

Dans le cadre de la programmation par contraintes, les problèmes sont modélisés à l'aide de variables de décision et de contraintes, où une contrainte est une relation entre une ou plusieurs variables qui limite les valeurs que peuvent prendre simultanément chacune des variables liées par la contrainte. Les algorithmes de recherche de solution, en PPC, s'appuient généralement sur la propagation de contraintes, pour réduire le nombre de solutions candidates à explorer, ainsi que sur une recherche systématique parmi les différentes affectations possibles de chacune des variables. De tels algorithmes garantissent de trouver une solution, quand elle existe, et permettent de prouver qu'il n'existe pas de solution à un problème s'ils n'ont pas trouvé de solution à la fin de la recherche exhaustive.

Un des premiers solveur de contraintes est ALICE écrit en 1976 par Jean-Louis Laurière[5],[6],[7].

Problème de satisfaction de contraintes sur les domaines finis[modifier | modifier le code]

Une contrainte est une relation entre plusieurs variables qui limitent l'ensemble des valeurs que peuvent prendre ces variables simultanément.

Définition — Un problème de satisfaction de contraintes sur des domaines finis (ou CSP) est défini par un triplet où:

  • est l'ensemble de variables du problème;
  • est l'ensemble des domaines des variables, c'est-à-dire que pour tout on a ;
  • est un ensemble de contraintes. Une contrainte est définie par l'ensemble des variables sur lequel elle porte et la relation qui définit l'ensemble des valeurs que peuvent prendre simultanément les variables de :

Lorsque l'on définit une contrainte en énumérant l'ensemble des valeurs qui satisfont cette contrainte, on dit que la contrainte est définie en extension. On trouve aussi d'autres représentations[réf. nécessaire] de contraintes telles que:

  • contraintes arithmétiques () sur des expressions ;
  • contraintes logiques (disjonction, implication, etc.) ;
  • contraintes dont la sémantique est décrite : « toutes différentes », etc.

On appelle affectation, le fait d'associer une valeur de son domaine à une variable. Dans le cadre de la résolution de problème de satisfaction de contraintes, on parle d'affectation partielle lorsque l'on affecte un sous-ensemble de l'ensemble des variables du problème, et d'affectation totale lorsque l'on affecte toutes les variables du problème.

Définition —  Une affectation d'un CSP est définie par le couple où:

  • est un sous-ensemble de variables;
  • est le tuple des valeurs prises par les variables affectées.

On dit qu'une affectation est partielle lorsque l'ensemble de variables affectées est différent de l'ensemble des variables du problème, sinon on parle d'affectation totale.

Propriété — Soit une affectation (partielle ou totale) d'un CSP , et une contrainte de telle que , l'affectation satisfait la contrainte si et seulement si l'ensemble des valeurs des variables sur lesquelles porte la contrainte appartient à .

Définition — Une solution d'un CSP est une affectation totale qui satisfait l'ensemble des contraintes.

Lors de la recherche de solutions à un problème de satisfaction de contraintes, on peut souhaiter par exemple :

  • trouver une solution (satisfaisant l'ensemble des contraintes) ;
  • trouver l'ensemble des solutions du problème ;
  • trouver une solution optimale par rapport à un critère (généralement minimisation ou maximisation d'une variable) ;
  • prouver la non existence de solution (dans le cas d'un problème sur-contraint).

Recherche de solutions[modifier | modifier le code]

Recherche arborescente[modifier | modifier le code]

Dans le cas de la résolution sur domaines finis, il est en théorie possible d'énumérer toutes les possibilités et de vérifier si elles violent ou non les contraintes, cette méthode est appelée générer et tester. Cependant, cela s'avère impraticable pour des problèmes de taille moyenne en raison du grand nombre de combinaisons possibles. Une des majeures parties de la résolution, appelée « filtrage », a pour but d'éviter cette énumération exhaustive. Elle consiste à déduire à partir des contraintes les valeurs impossibles. Lorsqu'une variable ne possède plus qu'un candidat, celle-ci est instanciée (i.e. cette valeur lui est affectée). Cependant, le filtrage seul ne permet pas d'instancier toutes les variables, et il est donc nécessaire de scinder le problème en plusieurs parties (par exemple en instanciant une variable à chacune de ses valeurs possibles) et relancer le filtrage sur l'une de ces parties et ce, de manière récursive jusqu'à obtenir l'instanciation de toutes les variables. Lorsque le filtrage détecte que l'instanciation partielle viole une contrainte, on utilise généralement alors un mécanisme de retour sur trace afin de remettre en cause le dernier choix effectué.

Cette série de découpages du problème peut être représentée sous forme d'un arbre. Le but de la recherche est de parcourir cet arbre (en le construisant au fur et à mesure) jusqu'à trouver une solution au problème tandis que le filtrage consiste à « élaguer » cet arbre en supprimant toutes les parties n'aboutissant qu'à des contradictions.

Propagation de contraintes[modifier | modifier le code]

La propagation de contraintes (ou filtrage) consiste à supprimer d'un problème de PPC des valeurs de variables ne pouvant pas prendre part à une solution. Pour accélérer la recherche d'une solution d'un problème, il est nécessaire d'obtenir un bon compromis entre le temps nécessaire au filtrage et l'efficacité de celui-ci. C'est pourquoi il existe plusieurs niveaux d'efficacités de filtrage, capables de retirer plus ou moins de valeurs, pour un coût en temps plus ou moins élevé. Étant donné que toutes les contraintes d'un problème de PPC doivent être satisfaites, le fait pour une valeur d'une variable de ne pas pouvoir satisfaire une seule contrainte du problème implique qu'elle ne pourra prendre part à aucune solution du problème. Il est donc possible de raisonner séparément sur chaque contrainte afin de pouvoir trouver des valeurs pour lesquelles cette contrainte ne peut être satisfaite, et donc les retirer du problème entier.

On appelle consistance locale le fait de vérifier que certaines variables ne violent pas les contraintes qui lui sont liées. On ignore alors les autres variables et contraintes. Cela permet de filtrer alors certaines valeurs impossibles pour un coût réduit. Il existe plusieurs consistances locales, offrant chacune un équilibre différent entre efficacité du filtrage et rapidité de calcul.

Extensions[modifier | modifier le code]

  • contraintes valuées
  • contraintes globales[8]
  • étude et détection des symétries
  • techniques de décomposition et classes de problèmes « traitables »
  • métaheuristiques
  • transition de phase

Exemples de problèmes[modifier | modifier le code]

Parmi les problèmes classiques pouvant être traités par programmation par contraintes, on peut citer :

  • le problème des huit dames, qui consiste à placer huit dames sur un échiquier de manière qu'aucune dame ne puisse en prendre une autre ;
  • le sudoku, où il faut remplir une grille 9x9 avec des chiffres de 1 à 9 de manière que chaque chiffre n'apparaisse qu'une seule fois dans chaque ligne, colonne, et sous-boîte de taille 3x3.

Solveurs de contraintes[modifier | modifier le code]

  • Logiciels académiques
    • Prolog III (1989)
    • MiniCP (Bibliothèque Java destinée à l'enseignement de la programmation par contraintes. License Libre) (2018)[9]
  • Logiciels commerciaux
    • Artelys Kalis (Bibliothèques C++, Java, Python, module de la suite FICO Xpress)
    • CHIP V5 (C, C++, Prolog) (1988) [10],[8]
    • Comet (Langage orienté objet destiné à la résolution de problèmes de contraintes. Usage académique libre.)
    • Disolver (Bibliothèque C++)
    • IBM CP Optimizer[11],[12], successeur de ILOG Solver/Scheduler (Bibliothèques C++, Python[13], Java, .NET)
    • Prolog IV (1996)
  • Logiciels sous licences libres
    • AbsCon (Bibliothèque Java)
    • Choco (Bibliothèque Java, logiciel libre : X11 style)
    • Cream (Bibliothèque Java)
    • Eclipse Prolog (Bibliothèque Prolog)
    • Gecode (Bibliothèque C++)
    • Google OR-tools (Bibliothèque C++, bindings Java, C#, Python)
    • JaCoP (Bibliothèque Java)
    • JOpt (Bibliothèque Java)
    • Minion (C++)
    • OscaR (Scala)
    • Scarab (Bibliothèque Scala)
    • python-constraint (Bibliothèque Python)

Bibliographie[modifier | modifier le code]

Notes et références[modifier | modifier le code]

  1. Mackworth, Consistency in networks of relations, Artificial Intelligence, 9:99-118, 1977
  2. Haralick, Eliott, Increasing Tree search efficiency for Constraint Satisfaction Problems, Artificial Intelligence, 14:263-313, 1980
  3. Roman Bartak, A Guide to Constraint Programming, 1998
  4. E. Freuder. "Constraint Programming represents one of the closest approaches computer science has yet made to the Holy Grail of programming: the user states the problem, the computer solves it."
  5. Jean-Louis Laurière, Un langage et un programme pour énoncer et résoudre des problèmes combinatoires, Paris, Thèse d'Etat, Université Pierre et Marie Curie, , 227 p. (SUDOC 029557313)
  6. (en) Jean-Louis Laurière, « A language and a program for stating and solving combinatorial problems », Artificial Intelligence, vol. 10, no 1,‎ , p. 29-127 (lire en ligne, consulté le )
  7. (en) Pierre Flener, « Constraint Programming in a Nutshell », Joint ACP and GdR RO Summer School 2017, sur lien, (consulté le )
  8. a et b Introducing global constraints in CHIP N.Beldiceanu, E.Contejean, Mathematical and Computer Modelling, December 1994, Elsevier
  9. « www.minicp.org », sur www.minicp.org (consulté le )
  10. The constraint logic programming language CHIP, Proceedings of international conference on Fifth Generation Computer Systems FGCS-88 (1988), pp. 693–702
  11. (en) « IBM ILOG CP Optimizer », sur ibm.com.
  12. Laborie P, Rogerie J, Shaw P, Vilim P, « IBM ILOG CP optimizer for scheduling », Constraints, vol. 23, no 2,‎ , p. 210–250 (DOI 10.1007/s10601-018-9281-x)
  13. (en) « docplex 2.10.154 », sur python.org.
  14. Trends in Constraint Programming

Voir aussi[modifier | modifier le code]

Articles connexes[modifier | modifier le code]

Liens externes[modifier | modifier le code]