Archives de catégorie : PPC

Contrôle continu 2 – M2 IIA

Documents autorisés : une feuille A4 recto-verso pour chacune de parties A, B, C, D, manuscrite ou imprimée.

Partie A

A1 (1 point)

Donnez les solutions, si applicable, du réseau de contraintes suivant :

Variables : \(A\) de domaine \(\{1,2,3\}\), \(B\) de domaine \(\{4,5,6\}\), \(D\) de domaine \(\{7,8,9\}\), \(C\) de domaine \(\{10,11,12\}\).

Contraintes :

  • \(q_1\) sur \(A,B\) : \(\{(1,4),(2,6),(3,5)\}\)
  • \(q_2\) sur \(B,C\) : \(\{(4,11),(5,10)\}\)
  • \(q_3\) sur \(C,D\) : \(\{(10,8),(11,9),(12,9)\}\)
  • \(q_4\) sur \(A,D\) : \(\{(1,9),(2,7),(3,9)\}\)
Solution

Une solution : \(A=1, B=4, C=11, D=9\).

A2 (1 point)

Donnez la représentation en extension de le contrainte logique \(C = A \vee B\) (où, bien évidemment, les variables ont toutes le domaine \(\{0,1\}\)).

Solution

Sur \(A,B,C\) : \(\{(0,0,0),(0,1,1),(1,0,1),(1,1,1)\}\).

Partie B

Soit un entier positif \(N\). Soit une variable \(X\) ayant pour domaine \(1..N\). Soit les variables Booléennes \(X_1,…,X_N\) . On appelle représentation unaire d’une assignation \(X=x\) l’assignation de \(X_1,…,X_N\) telle que :

  • \(X_x = 1\),
  • pour tout \(y\in 1..N, y\neq x\), \(X_y = 0\).

Par exemple, pour \(N=3\), la représentation unaire de l’assignation \(X=2\) est \(X_1=0, X_2=1, X_3=0\).


Soit la variable \(X\) de domaine \(\{1,2,3\}\) et les variables \(X_1, X_2, X_3\) de domaines \(\{0,1\}\). On souhaite spécifier une ensemble \(Q\) de contraintes appelées contraintes de liaison (chanelling constraints en anglais) qui assure que toute assignation de \(X, X_1, X_2, X_3\) satisfait toutes les contraintes de \(Q\) si et seulement si les valeurs de \(X_1, X_2, X_3\) constituent la représentation unaire de la valeur de \(X\).

B1 (1 point)

Donnez une spécification de \(Q\) en extension. Une seule contrainte est suffisante, donc on a \(Q=\{q\}\) où \(q\) est une contrainte sur \(X, X_1, X_2, X_3\).

Solution

\(q\) sur \(X,X_1,X_2,X_3\) : \(\{(1,1,0,0),(2,0,1,0),(3,0,0,1)\}\)

B2 (2 points)

Donnez une spécification de \(Q\) en compréhension avec des contraintes arithmétiques. Une solution est possibles avec 2 contraintes.

Solution

\(X_1 + X_2 + X_3 = 1\)

\(X1 + 2X_2 + 3X_3 = X\)

B3 (1 point)

Donnez une spécification de \(Q\) en compréhension dans le cas général d’une contrainte de liaison entre une variable \(X\) et les variables Booléennes \(X_1,…,X_N\), où \(N\) est un entier positif quelconque.

Solution

\(\sum_{i=1}^n X_i = 1\)

\(\sum_{i=1}^n i X_i = X\)

Partie C

Pour chacune des questions, vous devez répondre en donnant, dans un ordre plausible, les valeurs retirées lors de la restauration de la cohérence de domaines du réseau de contraintes ou de la contrainte donnée dans l’énoncé. Aucune justification n’est demandée. Vous devez juste donner la liste des valeurs retirées en utilisant la notation \(V\neq x\) pour dire que la valeur \(x\) est retirée du domaine de \(V\).

C1 (1 point)

Restaurez la cohérence de domaine de la contrainte \(\text{alldiff}(A, B, C, D, E, F)\) dont les variables ayant respectivement pour domaines \(\{1, 2, 4\}\), \(\{1, 3, 5\}\), \(\{2,3,6\}\), \(\{4,5\}\), \(\{4,6\}\), \(\{5,6\}\).

Solution

\(A \neq 4, B \neq 5, C \neq 6\) (dans n’importe quel ordre puisqu’il y a une seule contrainte)

C2 (1,5 point)

Restaurez la cohérence de domaine du réseau de contraintes suivant :

  • Variables : \(A, B, C\) ayant toutes pour domaine \(\{1,2,3\}\).
  • Contraintes :
    • \(q_1\) : \(A + 2B + 3C = 12\).
    • \(q_2\) : \(A + 2B + 2C = 10\).
Solution

\(q_2 : A\neq 1, A\neq 3\)

\(q_1 : B \neq 1, B \neq 3, C \neq 1, C \neq 3\)

Il reste la valeur 2 dans chaque domaine, ce qui constitue une solution.

C3 (1,5 point)

Restaurez la cohérence de domaine du réseau suivant :

Variables : \(A,B,C,D\) ayant toutes pour domaine \(\{1,2,3\}\).

Contraintes :

  • \(q_1\) sur \(A,B\) : \(\{(3,3),(2,1),(1,2)\}\)
  • \(q_2\) sur \(B,C\) : \(\{(3,3),(2,1),(1,1)\}\)
  • \(q_3\) sur \(C,D\) : \(\{(1,2),(2,1),(3,3)\}\)
  • \(q_4\) sur \(A,D\) : \(\{(1,1,(2,2),(3,3)\}\)
Solution

\(q_2 : C \neq 2\)

\(q_3 : D \neq 1\)

\(q_4 : A \neq 1\)

\(q_1 : B \neq 2\)

Il reste respectivement dans les domaines de \(A,b,C,D\) : \(\{2,3\}, \{1,3\}, \{1,3\}, \{2,3\}\).

Partie D

D1 (2 points)

Soit le réseau de contraintes suivant dont les variables ont pour domaines {0,1} (représentant les valeurs vrai et faux) :

\((\neg a \vee b)\), \((\neg a \vee \neg b \vee c)\), \((\neg a \vee \neg b \vee \neg c)\), \((a \vee b \vee \neg e)\), \((e \vee a \vee d)\), \((e \vee a \vee \neg d)\), \((a \vee \neg b \vee e)\), \((\neg e \vee \neg b \vee d)\), \((\neg e \vee \neg b \vee \neg d)\).

Donnez l’arbre de recherche illustrant le déroulement de l’algorithme MAC sur ce réseau de contraintes. Vous devez utiliser \(a\) comme première variable de branchement. Précisez à chaque nœud les domaines des variables en barrant celles qui sont filtrées.

Solution

image-20211201150854115

CC2 – M2BDIA

Documents autorisés : une feuille A4 recto-verso pour chacune de parties A, B, C, D, manuscrite ou imprimée.

Partie A

A1 (1 point)

Donnez les solutions, si applicable, du réseau de contraintes suivant :

Variables : \(A, C\) de domaine \(\{1,2,3\}\), \(B,D\) de domaine \(\{4,5,6\}\).

Contraintes :

  • Sur \(A,B\) : \(\{(1,5),(2,6),(3,4)\}\).
  • Sur \(B,C\) : \(\{(4,2),(5,3),(6,1)\}\).
  • Sur \(C,D\) : \(\{(1,5),(2,6),(3,4),(3,6)\}\).
  • Sur \(A,D\) : \(\{(1,6),(2,4),(3,5)\}\).
Solution

Une solution : \(A=1, B=5, C=3, D=6\).

A2 (1 point)

Donnez la spécification en extension de la contrainte logique \(A\vee \neg B \vee C\).

Solution

Sur \(A,B,C\) : \(\{(0,0,0),(0,0,1),(0,1,1),(1,0,0),(1,0,1),(1,1,0),(1,1,1)\}\).

Partie B

Soit \(V\) un ensemble de variables, \(q\) une contrainte reliant les variables de \(V\) et un ensemble \(Q\) de contraintes tel que les variables reliées par chaque contrainte de \(Q\) appartiennent à \(V\).

On dit que \(Q\) est équivalent à \(q\) si et seulement si toute assignation complète des variables de \(V\) satisfait toutes les contraintes de \(Q\) si et seulement si elle satisfait \(q\).

Par exemple, l’ensemble de contraintes \(Q = \{A\neq B, A\neq C, B\neq C\}\) est équivalent à la contrainte \(q = \text{allDiff}(A,B,C)\).

On appelle contrainte logique toute contrainte spécifiée en compréhension uniquement à l’aide des opérateurs \(\vee, \wedge, \neg\).

Dans les questions suivantes, il sera uniquement question de variables Booléennes, donc à domaine \(\{0,1\}\).

B1 (1 point)

Donnez un ensemble de contraintes logiques équivalent à la contrainte \(X_1+…+X_N \neq 0\). Cet ensemble peut ne contenir qu’une seule contrainte.

Solution

\(X_1\vee…\vee X_N\)

B2 (1 point)

Donnez un ensemble de contraintes logiques aussi petit que possible équivalent à la contrainte \(A+B+C+D \leq 2\).

Solution

\((\neg A \vee \neg B \vee \neg C)\), \((\neg A \vee \neg B \vee \neg D)\), \((\neg A \vee \neg C \vee \neg D)\), \((\neg B \vee \neg C \vee \neg D)\)

B3 (2 points)

Donnez un ensemble de contraintes logiques aussi petit que possible équivalent à la contrainte \(X_1+…+X_N \leq 1\), pour tout entier \(N\) supérieur à 1.

Solution

\(\forall i \in 1..N, \forall j \in i+1..N, (\neg X_i \vee \neg X_j)\)

Partie C

Pour chacune des questions, vous devez répondre en donnant, dans un ordre plausible, les valeurs retirées lors de la restauration de la cohérence de domaines du réseau de contraintes ou de la contrainte donnée dans l’énoncé. Aucune justification n’est demandée. Vous devez juste donner, à raison d’une ligne par visite d’une contrainte, la liste des valeurs retirées en utilisant la notation \(V\neq x\) pour dire que la valeur \(x\) est retirée du domaine de \(V\).

Par exemple pour décrire le filtrage du réseau \(q_1 : A<B\), \(q_2 : B<C\) où \(A, B, C\) ont pour domaine \(\{1,2,3\}\), vous devez adopter la présentation suivante :

  • \(q_1\) : \(A\neq 3, B\neq 1\)
  • \(q_2\) : \(B\neq 3, C\neq 1, C\neq 2\)
  • \(q_1\) : \(A\neq 2\)

C1 (2points)

Restaurez la cohérence de domaine du réseau de contraintes suivant :

Variables : \(A\) de domaine \(\{1,2,3\}\), \(B\) de domaine \(\{4,5,6\}\), \(C\) de domaine \(\{7,8,9\}\).

Contraintes :

  • \(q_1\) sur \(A,B\) : \(\{(1,5),(2,4),(3,6)\}\)
  • \(q_2\) sur \(B,C\) : \(\{(4,8),(5,7),(6,8)\}\)
  • \(q_3\) sur \(A,C\) : \(\{(1,7),(2,8),(3,9)\}\)
Solution

  • \(q_2 : C\neq 9\)
  • \(q_3 : A\neq 3\)
  • \(q_1 : B \neq 6\)

C2 (2 points)

Restaurez la cohérence de domaine du réseau de contraintes suivant :

Variables : \(A,B,C\) de domaine \(\{1,2,3\}\).

Contraintes :

  • \(q_1\) : \(A+B+C=6\)
  • \(q_2\) : \(A+2B+C=9\)
  • \(q_3\) : \(2A+B+3C=10\)
Solution

  • \(q_2 : B\neq 1\)
  • \(q_3 : A\neq 3, C\neq 3\)
  • \(q_1 : A\neq 1\)
  • \(q_2 : B\neq 2, C \neq 2\)

Partie D

D1 (2 points)

Soit le réseau de contraintes suivant :

Variables : \(A,B,C,D\) ayant toutes pour domaine \(\{3,7,11\}\).

Contraintes :

  • \(A+B+C+D \leq 17\)
  • \(A+B+C+D \geq 17\)

Donnez l’arbre de recherche illustrant le déroulement de l’algorithme MAC sur ce réseau de contraintes. Précisez à chaque nœud les domaines des variables en barrant celles qui sont filtrées.

Solution

image-20211110102312984

Contrôle continu 1 – M2 IIA

Documents autorisés : une feuille A4 recto-verso pour chacune de parties A, B, C, D, manuscrite ou imprimée.

Partie A

A1 (1 point)

Donnez les solutions, si applicable, du réseau de contraintes suivant :

image-20211014094131783

"Solution"

Aucune solution.

A2 (1 point)

Soient les variables A, B, C de domaines respectifs {1,2}, {2,3} et {3,4}. Soient les contraintes suivantes :

  • q1 sur A, B : {(1,2), (2,3)}.
  • q2 sur B, C : {(2,4)}.
  • q : q1 ou q2 (la contrainte satisfaite par et seulement par les assignations de A, B, C qui satisfont q1 ou q2).

Donnez la représentation en extension de q.

"Solution"

Sur \(A,B,C\) : \(\{(1,2,3),(1,2,4),(2,3,3),(2,3,4),(2,2,4)\}\).

Partie B

B1 (1 point)

On veut placer \(k\) personnes sur un coté d’une table rectangulaire disposant de \(k\) places. On attribue, par commodité, un numéro compris entre \(1\) et \(k\) à chaque place et on fait de même pour chaque personne à placer.

Chaque personne \(i\) peut exclure certaines autres personnes, c’est à dire refuser que ces autres personnes (si applicable) soient placées à coté de lui. Les personnes exclues par une personne \(x\) sont données par un ensemble \(E_x\). Voici un exemple avec \(k=4\) :

\[E_1=\{2,3\}, E_2=\{1\}, E_3=\{1,4\}, E_4=\{3\}
\]

  • La personne 1 exclut les personnes 2 et 3,
  • la personne 2 exclut la personne 1,
  • la personne 3 exclut les personnes 1 et 4,
  • la personne 4 exclut la personne 3.

Voici une solution permettant de placer les 4 personnes en respectent leurs incompatibilités.

image-20211018102909393

Proposez une modélisation en extension de l’exemple ci-dessus en utilisant les variables, domaines et contraintes qui vous paraissent les plus pertinentes.

"Solution"

Une variable par place : \(P_1, P_2, P_3, P_4\) de domaine \(\{1,2,3,4\}\). \(P_i=j\) signifie que la personne \(j\) occupe la place \(i\).

Contraintes de compatibilité :

  • Sur \(P_1, P_2\) : \(\{(1,4), (4,1), (2,3), (2,4), (3,2), (4,2)\}\).
  • Sur \(P_2, P_3\) : \(\{(1,4), (4,1), (2,3), (2,4), (3,2), (4,2)\}\).
  • Sur \(P_3, P_4\) : \(\{(1,4), (4,1), (2,3), (2,4), (3,2), (4,2)\}\).

Contraintes de différence (pour que chaque place soit occupée par une personne différente) :

  • Sur \(P_1, P_3\) : \(\{(1,2), (1,3), (1,4), (2,1), (2,3), (2,4), (3,1), (3,2), (3,4), (4,1), (4,2), (4,3)\}\).
  • Sur \(P_1, P_4\) : \(\{(1,2), (1,3), (1,4), (2,1), (2,3), (2,4), (3,1), (3,2), (3,4), (4,1), (4,2), (4,3)\}\).
  • Sur \(P_2, P_4\) : \(\{(1,2), (1,3), (1,4), (2,1), (2,3), (2,4), (3,1), (3,2), (3,4), (4,1), (4,2), (4,3)\}\).

B2 (3 points)

On revient au cas général où on a \(k\) personnes à placer. On souhaite modéliser le problème à l’aide de variables Booléennes \(P_{ix}\), pour \(i\) et \(x\) compris entre 1 et \(k\), avec la convention suivante : \(P_{ix}=1\) signifie que la place \(i\) est occupée par la personne \(x\).

Donnez une spécification en compréhension de toutes les contraintes nécessaires, les données du problèmes étant les ensembles \(E_1\) à \(E_k\). Vous pouvez utiliser des contraintes arithmétiques et / ou logiques.

"Solution"

Chaque place est occupée par une personne, chaque personne occupe exactement une place :

\(\forall i \in 1..k, \sum_{x=1}^k P_{i,x} = 1\), \(\forall x \in 1..k, \sum_{i=1}^k P_{i,x} = 1\).

Incompatibilités :

\(\forall i\in 1..k-1, \forall x\in 1..k, \forall y\in E_x, \neg(P_{i,x}\wedge P_{i+1,y})\)

\(\forall i\in 1..k-1, \forall x\in 1..k, \forall y\in E_x, \neg(P_{i+1,x}\wedge P_{i,y})\)

Partie C

Pour chacune des questions, vous devez répondre en donnant, dans un ordre plausible, les valeurs retirées lors de la restauration de la cohérence de domaines du réseau de contraintes ou de la contrainte donnée dans l’énoncé. Aucune justification n’est demandée. Vous devez juste donner la liste des valeurs retirées en utilisant la notation \(V\neq x\) pour dire que la valeur \(x\) est retirée du domaine de \(V\).

C1 (1 point)

Restaurez la cohérence de domaine de la contrainte \(\text{alldiff}(A, B, C, D, E)\) dont les variables ont les domaines suivants :

\(A, B\) : \(\{1, 2, 3\}\), \(C\) : \(\{1, 2, 3, 4\}\), \(D\) : \(\{4,2\}\), \(E\) : \(\{4,3\}\).

"Solution"

\(D\neq 4\), \(A\neq 2\), \(B\neq 2\), \(C\neq 2\), \(E\neq 4\), \(E\neq 3\), incohérence globale.

C2 (2 points)

Restaurez la cohérence de domaine du réseau de contraintes suivant :

  • Variables : \(A\) de domaine \(\{1,2\}\), \(B\) de domaine \(\{4,5\}\), \(C\) de domaine \(\{4,5\}\), \(X\) de domaine \(\{1,2,3\}\), \(Y\) de domaine \(\{1,2,3\}\).
  • Contraintes :
    • Sur \(A, B, C\) : \(\{(1,4,5), (1,5,4), (2,5,5)\}\).
    • Sur \(B, X\) : \(\{(4,1), (4,2), (5,3)\}\).
    • Sur \(C, Y\) : \(\{(4,3), (5,2)\}\).
    • Sur \(X,Y\) : \(\{(1,2), (2,3), (3,1)\}\).
"Solution"

\(Y\neq 1, X\neq 3, B\neq 5, A\neq 2, C\neq 4, Y\neq 3, X\neq 2\)

Le filtrage peut être plus facile en s’appuyant sur une représentation graphique telle que celles-ci :

image-20211027111411567

C3 (1 point)

Restaurez la cohérence de domaine de la contrainte \(9 X_2 + 3 X_1 + X_0 = Y\) dont les variables ont les domaines suivants :

\(X_0, X_1, X_2\) : \(\{0,1,2\}\), \(Y\) : \(\{10,13,16\}\).

"Solution"

\(X_2\neq 0, X_2\neq 2, X_0\neq 0, X_0 \neq 2\)

Partie D

D1 (2 points)

Soit le réseau de contraintes suivant dont les variables ont pour domaines {0,1} (représentant les valeurs vrai et faux) :

\((a \vee \neg b), (a \vee c), (b \vee \neg c), (\neg a \vee c), (\neg c \vee \neg d), (\neg a \vee \neg b \vee \neg c \vee d \vee e)\).

Donnez l’arbre de recherche illustrant le déroulement de l’algorithme MAC sur ce réseau de contraintes. Choisissez les variables de branchement qui vous paraissent être pertinentes pour minimiser l’arbre de recherche. Précisez à chaque nœud les domaines des variables en barrant celles qui sont filtrées.

"Solution"

image-20211027112821429

Contrôle continu 1 – M2 BDIA

Documents autorisés : une feuille A4 recto-verso pour chacune de parties A, B, C, D, manuscrite ou imprimée.

Partie A

A1 (1 point)

Donnez les solutions, si applicable, du réseau de contraintes suivant :

image-20211004105729855

A2 (1 point)

"Solution"

Une solution : \(A=1, B=4, C=8, D=10\).

Soient les variables A, B, C de domaines respectifs {1,2}, {2,3} et {3,4}. Soient les contraintes suivantes :

  • q1 : A < B.
  • q2 : B < C.
  • q : q1 et q2 (la contrainte satisfaite par et seulement par les assignations de A, B, C qui satisfont q1 et q2).

Donnez les représentations en extension de q1, q2 et q.

"Solution"

  • \(q_1\) : sur \(A,B\), \(\{(1,2),(1,3),(2,3)\}\).
  • \(q_2\) : sur \(B,C\), \(\{(2,3),(2,4),(3,4)\}\).
  • \(q\) : sur \(A,B,C\), \(\{(1,2,3),(1,2,4),(1,3,4),(2,3,4)\}\).

Partie B

Soit \(N\) un entier au mois égal à 3 et \(A_1,…,A_N\), \(B_1,…,B_N\) des variables Booléennes, i.e., ayant pour domaine \(\{0,1\}\).

Toute assignation complète des variables \(A_1,…,A_N\) représentent le positionnement d’une tâche \(A\) dont l’heure de début est la plus petite valeur \(i\) telle que \(A_i=1\) et la durée est le nombre de valeurs de consécutives assignées à 1.

Par exemple, pour \(N=5\) les valeurs autorisées des variables \(A_1\) à \(A_5\) pour représenter de tâche d’une durée de 3 heures sont les suivantes :

11100 // tâche A commence à 0h, durée 3h
01110 // tâche A commence à 1h, durée 3h
00111 // tâche A commence à 2h, durée 3h

Les assignations dans lesquelles un ou plusieurs 0 sont encadrés par des 1, telles que 10110, sont interdites.

La même convention est appliquée aux variables \(B_1,…,B_N\) pour la représentation d’une tâche \(B\).

Pour exprimer mathématiquement que tous les bits à 1 d’une assignation sont consécutifs, on dit qu’il ne peut y avoir de motif 1…01 ni de motif 10…1 dans la séquence.

Ceci correspond aux deux ensembles de contraintes suivants :

  • \(\forall i\in 2..N-1, \forall j\in 1..i-1, \neg A_j \vee A_i \vee \neg A_{i+1}\)
  • \(\forall i\in 1..N-2, \forall j\in i+2..N, \neg A_i \vee A_{i+1} \vee \neg A_{j}\)

Par exemple, l’assignation 10110 falsifie la contrainte \(\neg A_1 \vee A_3 \vee \neg A_4\) qui est une des contraintes mentionnées plus haut.

Les mêmes contraintes sont appliquées aux variables \(B_1,…,B_N\).

B1 (1 point)

Soient \(K_A\) et \(K_B\) deux entiers. On suppose que \(K_A+K_B\leq N\). Donnez une spécification en compréhension (sur les variables \(A_1,…,A_N\), \(B_1,…,B_N\)) des contraintes qui expriment les propriétés suivantes :

  • La durée de la tâche \(A\) est \(K_A\),
  • La durée de la tâche \(B\) est \(K_B\).
"Solution"

  • \(\sum_{i=1}^N A_i = K_A\).
  • \(\sum_{i=1}^N B_i = K_B\).

B2 (1 point)

Donnez une spécification en extension de la contrainte qui exprime que la tâche \(A\) dure 2 heures, pour \(N=5\).

"Solution"

Sur \(A_1,A_2,A_3, A_4,A_5\) : \(\{(1,1,0,0,0),(0,1,1,0,0),(0,0,1,1,0),(0,0,0,1,1)\}\).

B3 (2 points)

Donnez la spécification en compréhension les contraintes supplémentaires (sur les variables \(A_1,…,A_N\), \(B_1,…,B_N\)) qui permettent de dire que la tâche \(A\) doit être complètement réalisée lorsque la tâche \(B\) commence.

Vous devez utiliser des contraintes logiques (basées sur \(\neg, \vee, \wedge\)) ou arithmétiques linéaires (basées sur -, +, <, >, =, etc.) ou des compositions logiques de contraintes arithmétiques.

Voici un exemple d’assignations avec \(N=10\) et \(K=3\) qui satisfont les contraintes supplémentaires que vous devez spécifier.

0011100000 // tâche A
0000001110 // tâche B

Et trois exemples qui doivent falsifier au moins une de ces contraintes.

0011110000 // tâche A
0000111100 // tâche B
0011100000 // tâche A
0111000000 // tâche B
0000011000 // tâche A
0110000000 // tâche B
"Solution"

\(\forall i \in 1..N\), \(\forall j\in 1..i\), \(\neg(A_i \wedge B_j)\).

D’autres solutions existent.

Partie C

C1 (4 points)

Voici le réseau de contrainte qui modélise le problème de l’existence d’une règle de Golomb de longueur 6 à 4 graduations.

Variables :

  • \(G_0\) de domaine \(\{0\}\), \(G_3\) de domaine \(\{6\}\),
  • \(G_1, G_2\) de domaine \(\{1,2,3,4,5\}\)
  • \(D_0, D_1, D_2, D_3, D_4, D_5\) de domaine \(\{1,2,3,4,5,6\}\).

Contraintes :

  • \(G_0 < G_1, G_1 < G_2, G_2 < G_3\),
  • \(D_0=G_1-G_0\), \(D_1=G_2-G_0\), \(D_2=G_3-G_0\), \(D_3=G_2-G_1\), \(D_4=G_3-G_1\), \(D_5=G_3-G_2\),
  • AllDiff\((D_0, D_1, D_2, D_3, D_4, D_5)\)

Voici une représentation graphique de ce réseau de contraintes :

image-20211004210025254

Restaurez la cohérence de domaine de ce réseau de contrainte. Donnez les valeurs retirées dans un ordre cohérent avec le principe de filtrage. Utilisez la notation \(V\neq x\) pour indiquer que la valeur \(x\) est retirée du domaine de la variable \(V\).

Par exemple, vous pouvez commencer par \(D_2 \neq 1\) car la valeur \(D_2=1\) n’a pas de support pour la contrainte \(D_2=G_3-G_0\). Mais il existe plusieurs séquences correctes.

"Solution"

\(G_1\neq 5, G_2\neq 1, D_0\neq 5, D_0\neq 6, D_3\neq 5, D_3\neq 6,\)

\(D_5\neq 5, D_5\neq 6, D_1\neq 1, D_1\neq 6, D_4\neq 1, D_4\neq 6,\)

\(D_2\neq 1, D_2\neq 2, D_2\neq 3, D_2\neq 4, D_2\neq 5.\)

Partie D

D1 (2 points)

Voici un réseau de 6 contraintes logiques et le début de l’arbre de recherche de l’algorithme MAC sur ce réseau. Vous devez compléter l’arbre en choisissant au mieux (si applicable) les variables de branchement restantes. A chaque nœud ou feuille, redonnez les domaines en barrant les valeurs éliminées par filtrage ou par assignation de la variable de branchement. A chaque feuille de l’arbre de recherche, précisez s’il y a échec ou solution.

image1

"Solution"

image-20211026210048911

Projet de recherche locale stochastique

En M2 Bases de données et IA et M2 Image et IA

Par Olivier Bailleux, Maître de conférences HDR, Université de bourgogne

Coloration de nombres entiers

Ce travail facultatif peut rapporter jusqu’à 3 points.


Énoncé

Le problème abordé est la coloration des entiers de 1 à \(N\) en utilisant \(K\) couleurs, où \(N\) et \(K\) sont des entiers donnés, en respectant la propriété suivante : pour tout \(a,b,c\) appartenant à l’ensemble \(1..N\), si \(a+b=c\) alors \(a,b\) et \(c\) ne doivent pas tous avoir la même couleur.

Une autre manière d’énoncer le problème consiste à dire que l’ensemble \(1..N\) doit être partitionné en \( K\) parties telles que pour tout triplet \((a,b,c)\in (1..N)^3\), si \(a+b=c\) alors \(a,b\) et \(c\) ne sont pas dans la même partie. Attention, la règle s’applique aussi si \(a=b\), donc par exemple 3 et 6 ne doivent pas appartenir à la même partie, ou en d’autres termes ne pas avoir la même couleur.

Voici un exemple de solution pour \(N=13\) et \(K=3\) :

  • \(P_1=\{1,4,10,13\}\)
  • \(P_2=\{2,3,11,12\}\)
  • \(P_3=\{5,6,7,8,9\}\)

On vérifie que les sommes inférieures ou égales à 13 de deux valeurs de \(P_1\), c’est à dire \(2,8,5,11\), ne sont pas dans \(P_1\). Le même constat est valable pour \(P_2\) et \(P_3\).

Ce problème est directement lié à la notion de nombre de Schur. Vous pourrez trouver des précisions ici.

Vous devez programmer une application qui tente de trouver une solution à ce problème à l’aide d’un algorithme de recherche locale stochastique.

La solution trouvée, si applicable, doit être affichée de manière lisible et facilement vérifiable, à savoir pour chaque partie \(P_i\), la liste des éléments de cette partie, puis la liste croissante des sommes de ces éléments inférieures ou égale à \(N\).

Par exemple, pour \(N=13\) et \(K=3\), on devrait avoir l’affichage :

P1 : 1 4 10 13 [2 5 8 11]
P2 : 2 3 11 12 [4 5 6 13]
P3 : 5 6 7 8 9 [10 11 12 13]

Monôme ou binôme

Vous pouvez traiter ce sujet seul ou en binôme.

Si vous le traitez seul, vous devrez à minima implémenter l’algorithme de Métropolis et rechercher expérimentalement la température qui maximise l’efficacité de la recherche.

Si vous travaillez en binôme, vous devez implémenter en plus au moins une deuxième stratégie, comme par exemple le recuit simulé avec une variation de température en cours de la recherche.

Critères d’évaluation

Vous serez évalués sur les critères suivants :

  • Pertinence de la représentation des configurations, du voisinage et de la fonction coût.
  • Démarche expérimentale de recherche des meilleurs réglages.
  • Clarté et efficacité du code.
  • Performance de l’application.

Si vous inspirez de travaux publiés, merci de donner les références. Vous pouvez utiliser le langage de programmation de votre choix, après validation par l’enseignant si vous utilisez un autre langage de Java ou C++.


Livrables

Pour livrer ce projet, vous devez vous inscrire à l’équipe Teams Livraison projets PPC 2122 grâce au code d’accès ipr9fop. Vous aurez alors accès à un devoir permettant de livrer le projet.

Les fichiers à remettre sont les suivants. Merci de ne pas les placer dans des archives zip ou autres.

  • Le code commenté, dans un unique fichier. Le code devra être indenté en style Allman, c’est à dire avec un alignement strict des accolades ouvrantes et fermantes.
  • Un document au format pdf d’au plus 10 pages comportant :
    • Une présentation et une justification (théorique et/ou expérimentale) de vos choix en matière de représentation, voisinage, fonction de coût (si applicable).
    • Une description de la ou des stratégies de recherche implémentées.
    • Une présentation des résultats obtenus, avec les temps de calculs correspondants.

Si vous avez travaillé en binôme,

  • l’un des auteurs doit livrer les deux fichiers du projet, avec le nom du coauteur mentionné dans chaque document,
  • et l’autre auteur doit seulement livrer un fichier pdf d’une page sur laquelle est juste indiqué le nom du coauteur.

PPC : Miniprojets

En M2 Bases de données et IA et M2 Image et IA

Par Olivier Bailleux, Maître de conférences HDR, Université de bourgogne

Mini-projets de PPC

Objectif

Maîtriser les bases de l’utilisation de CHOCO avec des contraintes à domaines finis.

Prérequis

Partie I

Miniprojet 1

Ce travail peut rapporter jusqu’à 2 points. Vous pourrez avoir une assistance et une pré-validation avec droit à l’erreur en séances de TP.


Énoncé

Vous devez implémenter en Java et CHOCO un programme permettant de résoudre le problèmes des sacs à dos présenté en exercice de modélisation dans la partie B du cours.

On a \(N\) objets numérotés de 0 à \(N-\)1 et \(K\) sacs numérotés de 0 à \(K-1\). Chaque objet peut être embarqué dans au plus un sac. Chaque objet a un poids et une valeur. On note \(w_0, …, w_{N-1}\) les poids des objets et \(v_0, …, v_{K-1}\) leurs valeurs. Le poids cumulé des objet embarqués dans un même sac ne doit pas excéder une valeur \(W\). La valeur cumulée de tous les objets embarqués dans tous les sacs doit être au moins égale à \(V\).

Vous pouvez bien sûr vous inspirer de la modélisation proposée dans les indices et solutions de la partie B du cours.

Voici comment les données d’une instance du problème peuvent être représentées en Java :

int[] w = {7000,2000,3000,5000,5000,4000,4000,3000,5000,7000};
int[] v = {150,100,200,50,100,200,150,200,100,100};
int N = 10; int K=3;
int V = 1000; int W = 10000;

Votre solution devra être testée avec des instances cohérentes et des instances incohérentes non trivialement simplifiables. Une instance est dite trivialement simplifiable si elle comporte des objets de poids supérieur à \(W\) ou si la somme des valeurs des objets est inférieure à \(V\).

Pour toute instance cohérente, votre programme doit afficher une solution. L’affichage devra indiquer les objet embarqués dans chaque sac, soit sous forme explicite, soit sous une forme permettant de retrouver l’information à partir de l’affichage des valeurs des variables. Dans ce dernier cas, vous devrez donner sous forme explicite, par exemple à l’aide d’une représentation sur papier, les solutions de vos instances de test.


Livrables

Si vous terminez ce projet avant la fin de la première heure de la troisième et dernière séance de TP, vous n’avez pas à rédiger de document. Vous devrez monter à votre enseignant votre code commenté et lui faire une démo en faisant apparaitre explicitement les solutions, quand applicable.

Si vous terminez plus tard et que l’enseignant n’a pas le temps de valider votre travail, vous devrez lui transmettre votre code commenté, une copie d’écran de vos instances de tests et résultats, un document illustrant les solutions obtenues si celle-ci ne sont pas explicites sur les copies d’écran (par explicite on entend que les objets embarqués dans chaque sac apparaissent clairement), et un document d’une ou deux pages expliquant comment vous avez traduit votre modèle théorique en Java + CHOCO.



Miniprojet 2

Énoncé

Vous devez modéliser le problème suivant :

Soit un rectangle de largeur \(L\) et de hauteur \(H\), ou \(H\) et \(L\) sont des entiers. Soient \(K\) rectangles de largeurs et hauteurs \(l_1, h_1,…, l_k, h_k\), qui sont également des valeurs entières.

Peut-on placer les \(K\) petits rectangles dans le grand rectangle sans qu’aucun petit rectangle ne chevauche un autre ? Si c’est possible, une solution doit être donnée. Un affichage graphique de cette solution n’est pas exigé. Les positions des coins inférieurs gauche de chaque petit rectangle sont suffisantes.

La figure ci-dessous donne un exemple d’instance du problème et d’une solution.

image-20211003134447539

Pour traiter ce sujet, vous pourriez avoir besoin de spécifier des contraintes complexes par composition logique (négation, disjonction,…) de contraintes plus simple. La lecture de la documentation du site https://choco-solver.org, et notamment de cette page concernant la composition de contraintes arithmétiques, pourra vous apporter des informations très utiles.

Le petit exemple suivant (sans rapport avec le sujet) montre comment exprimer facilement la contrainte \((A+B=3) \vee (A+B=5)\), où \(A\) et \(B\) sont des variables de domaine \(1..5\).

Model model = new Model("Test");
IntVar A = model.intVar("A", 1,5);
IntVar B = model.intVar("B", 1,5);
( A.add(B).eq(3) ).or( A.add(B).eq(5) ).post();

Livrables

Pour livrer ce projet, vous devez vous inscrire à l’équipe Teams Livraison projets PPC 2122 grâce au code d’accès ipr9fop. Vous aurez alors accès à un devoir permettant de livrer le projet.

Les fichiers à remettre sont les suivants. Merci de ne pas les placer dans des archives zip ou autres.

  • Le code java, dans un unique fichier avec l’extension java, de votre solution. Le code devra être commenté et indenté en style Allman, c’est à dire avec un alignement strict des accolades ouvrantes et fermantes.
  • Un document au format pdf d’au plus 3 pages
    • expliquant succinctement le principe de votre modélisation, avec autant que possible des illustrations qui peuvent être des photographies de dessins réalisées à la main,
    • et présentant les instances avec lesquelles vous avez testé votre programme et les résultats obtenus. Les résultats doivent être représentés sous la forme d’un dessins, ne serait-ce que la photographie d’un croquis fait à la main sur papier. Vous ne serez pas évalués sur la forme. Le seul but est que le correcteur et vous-même puissent vérifier que les solutions trouvées par le solveur sont correctes.

Vous pouvez utiliser l’instance présentée en exemple ci-dessus pour la mise au point de votre programme, mais vous devez créer au moins deux instances de votre cru : une criticalement cohérente et une incohérente non triviale.

Par criticalement cohérente, on entend que la somme des aires des petits rectangles est égale à l’aire du grand rectangle.

Par incohérente non triviale, on entend que la somme des aires des petits rectangles est au plus égale à l’aire du grand rectangle, mais qu’il n’y a aucune solution. Faites preuve de créativité.

Si vous avez travaillé en binôme,

  • l’un des auteurs doit livrer les deux fichiers du projet, avec le nom du coauteur mentionné dans chaque document,
  • et l’autre auteur doit seulement livrer un fichier pdf d’une page sur laquelle est juste indiqué le nom du coauteur.

PPC : Test d’auto-évaluation sur la partie B

En M2 Bases de données et IA et M2 Image et IA

Par Olivier Bailleux, Maître de conférences HDR, Université de bourgogne

Objectif

Entraînement et évaluation partielle des vos compétences en modélisation.

Prérequis

Parties A et B


Question 1

On appelle séquenceur d’un mot binaire \(a_1 a_2 … a_n\) le mot binaire \(x_2 … x_n\) tel que \(x_i = 1\) si et seulement si \(a_{i-1} \neq a_i\).

Voici un exemple de mot binaire et de son séquenceur.

mot m :           001110000000
séquenceur de m :  01001000000

On considère les variables \(A_1, …, A_n\) et \(X_2, …, X_n\) ayant toutes pour domaines \(\{0,1\}\).

Vous devez spécifier un réseau de contraintes \(T_n\) tel que toute assignation \(A_1=a_1,…,A_n=a_n\), \(X_2=x_2,…,X_n=x_n\) satisfait \(T_n\) si et seulement si le mot binaire \(x_2 … x_n\) est le séquenceur du mot binaire \(a_1 a_2 … a_n\).

Par exemple, l’assignation \(A_1=1, A_2=0, A_3=1, X_2=1, X_3=1\) satisfait \(T_3\) car 11 est le séquenceur de 101. Par contre l’assignation \(A_1=1, A_2=0, A_3=1, X_2=0, X_3=1\) ne satisfait pas \(T_3\) car 01 n’est pas le séquenceur de 101.

\(T_n\) est constitué de \(n-1\) contraintes nommées \(q_1, …, q_{n-1}\).

Précisez les variables reliées par chaque contrainte. Donnez une spécification en extension et une spécification en compréhension (avec des opérations arithmétiques ou logiques) d’une de ces contraintes.

Réponse

Chaque contrainte \(q_i\) relie les variables \(A_i\), \(A_{i+1}\) et \(X_{i+1}\).

Exemple de spécification de \(q_i\) en compréhension : $X_{i+1} = |A_{i}-A_{i+1}|$.

Spécification de \(q_i\) en extension : sur \(A_i\), \(A_{i+1}\), \(X_{i+1}\) : \(\{(0,0,0),(1,1,0),(0,1,1),(1,0,1)\}\).

Question 2

En supposant que \(n>3\), quelles contraintes faut-il ajouter au réseau \(T_n\) de la question précédente pour exprimer que le mot binaire \(a_1 a_2 … a_n\) comporte exactement une séquence de 3 bits à 1 consécutifs, tous les autres bits étant à 0 ?

On entend par là que si on note le réseau \(T’_n\) le réseau obtenu en ajoutant à \(T_n\) ces nouvelles contraintes, alors toute assignation partielle \(A_1=a_1,…,A_n=a_n\) a une extension satisfaisant \(T’_n\) si et seulement si le mot binaire \(a_1 a_2 … a_n\) comporte exactement une séquence de 3 bits à 1 consécutifs, tous les autres bits étant à 0, comme dans les exemples suivants : 00111100, 000111, 111000000.

Les nouvelles contraintes sont à donner en compréhension.

Réponse

  • \(\sum_{i=1}^n A_i = 3\) (Il y a trois bits à 1).
  • \(\sum_{i=2}^n X_i \leq 2\) (Il y a au plus deux transitions).
  • \(A_1 + A_n \leq 1\) (Il ne doit pas y avoir un bit à 1 aux deux extrémité)

Question 3

On considère un dirigeable dont la nacelle est scindée en trois parties : une cabine destinée aux passagers au milieu et deux compartiments de fret, nommés A et B, aux extrémités. Parmi \(N\) objets, numérotés de 1 à \(N\) et de poids \(w_1, …, w_n\) , au moins \(K\) doivent être embarqués en respectant les conditions suivantes :

  • La somme des poids des objets embarqués dans le compartiment A doit être égale à la somme des poids des objets embarqués dans le compartiment B.
  • La somme des poids des objets embarqués dans les deux compartiments ne doit pas dépasser une valeur W.

Les valeurs \(K\) et W, ainsi que les poids des \(N\) objets susceptibles d’être embarqués, sont des données connues. Vous devez modéliser ce problème sous la forme d’un réseau de contraintes utilisant exclusivement des variables à domaine {0,1}. Vous devez utiliser des contraintes arithmétiques linéaires construites à l’aide de sommes, produits d’une variable par une constante, opérateurs de comparaison (\(=\), \(\neq\), \(<\), \(>\), \(\leq\), \(\geq\)). Précisez bien le rôle et la signification d’une assignation à 1 de chaque variable.

Réponse

Variables :

  • \(A_1, … ,A_N\) de domaine \(\{0,1\}\). \(A_N=1\) signifie que l’objet numéro \(i\) va dans le compartiment A.
  • \(B_1, … ,B_N\) de domaine \(\{0,1\}\). \(B_N=1\) signifie que l’objet numéro \(i\) va dans le compartiment B.

Contraintes :

  • \((\sum_{i=1}^n A_i) + (\sum_{i=1}^n B_i) \geq K\) (au moins \(K\) objets embarqués)
  • \(\sum_{i=1}^n w_i A_i = \sum_{i=1}^n w_i B_i\) (équilibre des charges)
  • \(\sum_{i=1}^n w_i A_i + \sum_{i=1}^n w_i B_i \leq W\) (charge maximale autorisée)
  • Pour tout \(i\in 1..N\), \(A_i + B_i < 2\) (un objet est est embarqué dans un seul compartiment ou n’est pas embarqué)

Question 4

On considère 8 variables \(X_1, X_2, Y_1, Y_2\), \(X’_1, X’_2, Y’_1, Y’_2\) ayant toutes pour domaine l’ensemble \(0..N\) des entiers naturels compris entre 0 et \(N\).

Une assignation de ces variables représente deux rectangles situés dans un repère cartésien discret avec les conventions suivantes :

  • \(X_1, Y_1\) sont les coordonnées du coin inférieur gauche du premier rectangle.
  • \(X_2, Y_2\) sont les coordonnées du coin supérieur droit du premier rectangle.
  • \(X’_1, Y’_1\) sont les coordonnées du coin inférieur gauche du deuxième rectangle.
  • \(X’_2, Y’_2\) sont les coordonnées du coin supérieur droit du deuxième rectangle.

La figure ci-dessous représente un exemple de positions et formes des deux rectangles, mais il y a un très grand nombre d’autres possibilités.

Vous devez spécifier les contraintes qui expriment que les deux rectangles se recouvrent (l’intersection entre les 2 est non vide). La ou les contraintes à écrire peuvent combiner des opérations arithmétiques (additions, soustractions, comparaisons) et logiques (et, non).

On suppose que \(X_2 > X_1\), \(Y_2 >Y_2\), \(X’_2 > X’_1\) et \(Y’_2 >Y’_2\).

Réponse

\(X’_1 < X_2\),

\(X_1 < X’_2\), 

\(Y’_1 < Y_2\), 

\(Y_1 < Y’_2\)

Question 5

On considère un échiquier (une grille) de N par N. Une pièce appelée cavalier peut se déplacer sur cette grille en se décalant de deux positions horizontalement et d’une verticalement ou de deux positions verticalement et d’une horizontalement. La figure ci-dessous donne deux exemples indépendants dans lesquels la grosse pastille désigne la position initiale d’un cavalier et les petites pastilles désignent les cases pouvant être atteintes par ce cavalier.

image2

On considère les variables \(X_1, Y_1, X_2, Y_2, V, H\) de domaines respectifs \(1..N\), \(1..N\), \(1..N\), \(1..N\), \(\{-2,-1,1,2\}\), \(\{-2,-1,1,2\}\).

Donnez en compréhension les contraintes qui spécifient qu’un cavalier situé en position \((X_1,Y_1)\) peut aller en \((X_2,Y_2)\) en se déplaçant de \(H\) cases horizontalement et de \(V\) case verticalement.

Réponse

  • $|X_1-X_2| = H$
  • $|Y_1-Y_2| = V$
  • \(H\neq V\)

Question 6

On numérote de la manière suivante les 8 déplacements réalisables par un cavalier sous réserve que les cases de destination soient dans les limites de l’échiquier.

image3

On ajoute une variable \(D\) de domaine \(1..8\) au réseau de contraintes précédent. Donnez en extension la contrainte à ajouter entre \(V\), \(H\) et \(D\) pour que dans toute assignation satisfaisant toutes les contraintes, \(D\) aie pour valeur le numéro du déplacement correspondant aux valeurs de \(V\) et \(H\).

Réponse

Sur \(V,H,D\) : \(\{(2,1,1),(1,2,2),(-1,2,3),(-2,1,4),(-2,-1,5),(-1,-2,6),(1,-2,7),(2,-1,8)\}\)

Programmation par contraintes : partie D

Programmation par contraintes

En M2 Bases de données et IA et M2 Image et IA

Par Olivier Bailleux, Maître de conférences HDR, Université de bourgogne

Partie D : résolution énumérative

Objectif

Comprendre le principe de fonctionnement d’un solveur de type MAC (Maintaining Arc Consistency) et être capable de simuler le déroulement de l’exécution d’un tel solveur sur une instance de problème dont l’arbre de recherche peut être dessiné sur une feuille A4, et d’énumérer ou comptabiliser les solutions (si applicable) de cette instance.

Prérequis

Parties A et C

Introduction

Résoudre un réseau de contraintes, c’est déterminer s’il existe au moins une assignation des variables qui satisfait toutes les contraintes. Le nombre de ces assignations étant proprement astronomique – il croît exponentiellement en fonction du nombre de variables – il n’est pas possible en pratique d’énumérer et de tester une par une toutes les assignations possibles.

La résolution dite « énumérative » ne l’est donc pas totalement mais fait aussi appel à des déductions pour accélérer la recherche d’éventuelle solutions. Dans le cas du solveur MAC que nous allons étudier, ces déductions sont des restaurations de cohérence de domaines.

L’idée de l’algorithme MAC est de décomposer le réseau de contraintes à résoudre, après restauration de la cohérence de domaines, en plusieurs réseaux plus simples dans lesquels une des variables du réseau initial a été assignée avec une des valeurs de son domaine. Par exemple, un réseau ayant une variable A de domaine {1, 2} sera décomposé en deux réseaux : un dans lequel la variable A vaut 1 et un dans lequel elle vaut 2. Chacun de ses réseaux sera filtré et si nécessaire, à nouveau décomposé sur la base d’une autre variable. La variable A est appelée variable de branchement.

image1

D-dec-10

Soit le réseau de contraintes $(a\vee b \vee c), (\neg a \vee \neg c), (\neg b \vee c)$, où les variables $a,b,c$ ont toutes pour domaine ${0,1}$. Donnez les réseaux obtenus pour $a=0$ et $a=1$.

"Solution"

  • $a=0$ : $(b \vee c), (\neg b \vee c)$
  • $a=1$ : $(\neg c), (\neg b \vee c)$

En effet, pour $a=0$, la contrainte $(\neg a\vee \neg c)$ est satisfaite, on peut donc la retirer du réseau. D’autre part, la contrainte $(a\vee b \vee c)$ peut se simplifier en $(b \vee c)$.

Pour $a=1$, je vous laisse vérifier par vous-même les simplifications.

D2 : Algorithme MAC

Cette version de l’algorithme produit toutes les solutions. On peut la modifier pour qu’elle s’arrête dès qu’une solution est trouvée.

image2

Simulons l’exécution de cet algorithme sur le réseau suivant :

image3

La première chose à faire est de restaurer la cohérence de domaines. Cela peut permettre de simplifier le problème avant de faire le premier branchement. Voici le résultat du filtrage.

image4

Si ce résultat vous paraît étonnant, c’est que vous ne maîtrisez pas le badge C, qui est un prérequis (où que le rédacteur du présent document s’est trompé).

Le filtrage simplifie le réseau (ce n’est pas toujours le cas), mais ne produit pas immédiatement de solution et ne fait pas apparaître d’incohérence (domaine vide).

Il nous faut donc choisir une variable de branchement. Nous allons utiliser la variable A. Nous obtenons l’arbre de recherche suivant, qui permet d’énumérer les deux solutions du réseau. Selon les besoins, on peut arrêter la recherche à la première solution ou n’énumérer qu’une partie des solutions. Si toute les branches de l’arbre de recherche aboutissent à une incohérence (domaine vide après filtrage), on conclut à l’incohérence du réseau.

image5

En pratique, pour présenter une simulation de résolution, on ne redessinera pas tout le réseau de contraintes à chaque nœud, mais seulement les domaines et les variables de branchement.

image6

D-dec-20

Est-il plus avantageux, moins avantageux ou aussi avantageux d’utiliser la variable $B$ comme variable de branchement à la racine de l’arbre de recherche ?

"Solution"

C’est plus avantageux car pour $B=2$, on déduit $A\neq 2$ puis $C\neq 4$ par filtrage et on obtient une solution. Pour $B=3$, on déduit $C \neq 3$ puis $A \neq 2$ par filtrage et on obtient la deuxième solution. On a donc un seul branchement au lieu de deux.

D3 : variantes

Filtrage affaibli

Dans l’algorithme MAC, un filtrage complet par restauration de cohérence de domaine est réalisé à chaque nœud (y compris racine) de l’arbre de recherche. Ce filtrage est généralement rentable dans la mesure où le temps qu’il consomme est largement compensé par la réduction du nombre de branchements, donc de la taille de l’arbre de recherche. Mais il peut y avoir des exceptions pour certaines contraintes dont la restauration de cohérence de domaines est couteuse, pour lesquelles on peut utiliser un filtrage plus « faible ».

Par exemple, restaurer la cohérence de domaine sur une contrainte de type $a_{1} x_{1} + \ldots + a_{n} x_{n} = b$, où $a_{1}, \ldots, a_{n}$ et $b$ sont des entiers relatifs, est très couteux. On ne connait aucun algorithme capable de le faire en temps polynomial. (Ce qui est contre-intuitif !)

On peut utiliser à la place un filtrage très rapide bien que moins puissant, qui consiste à restaurer la cohérence de domaine sur les deux contraintes $a_{1} x_{1} + \ldots + a_{n} x_{n} \leq b$ et $a_{1}\ x_{1} + \ldots + a_{n} x_{n} \geq b$. Même si cela vous paraît très étrange en première lecture, restaurer la cohérence de domaine sur les deux inégalités ne permet pas de la restaurer sur l’égalité.

Pas convaincu ?

D-dec-30

Restaurez la cohérence de domaine sur le réseau de contraintes suivant, avec domaine {0,1} pour toutes les variables :

  • $q_{1}: x_{1} + 2x_{2} + 3x_{3} + 4x_{4} \leq 6$

  • $q_{2}: x_{1} + 2x_{2} + 3x_{3} + 4x_{4} \geq 6$

"Solution"

On ne peut retirer aucune valeur des domaines en considérant les deux contraintes séparément. Si vous ne voyez pas pourquoi, c’est que le badge C n’est pas complètement acquis. Vous avez peut-être été en excès de confiance si vous pensiez le maîtriser.

En effet, en mettant n’importe laquelle des variables à 0, on peut toujours trouver une manière d’assigner les autres variables pour obtenir une somme au moins égale à 6 et une manière de les assigner pour obtenir une somme au plus égale à 6. Il en va de même en assignant n’importe quelle variable à 1.

D-dec-31

A présent, toujours avec les mêmes domaines initiaux {0,1}, restaurez la cohérence de domaine sur la contrainte suivante :

  • $q : x_{1} + 2x_{2} + 3x_{3} + 4x_{4} = 6$

Ce n’est pas immédiat à réaliser. Il faut se poser des questions du genre « est-il possible d’obtenir une somme égale à 6 si $x_{1}$ vaut 1 ? »

"Solution"

La réponse est oui. Il suffit d’assigner $x_{2} = 1, x_{3} = 1,x_{4} = 0$. Donc $x_{1} = 1$ a un support, et donc on ne retire pas 1 du domaine de $x_{1}$. En faisant un raisonnement similaire pour les autres valeurs, on obtient les domaines respectifs suivants pour les variables $x_{1}$ à $x_{4}$ : {0,1}, {1}, {0,1}, {0,1}.


La restauration de la cohérence de domaines sur $q$ a permis de faire un filtrage qui n’a pas été réalisé par la restauration de la cohérence de domaines sur $q_{1}$ et $q_{2}$. Mais faute de disposer d’un algorithme efficace pour les contraintes telles que $q$, c’est-à-dire les égalités pseudo-Booléennes, on peut appliquer à ces contraintes des filtrages moins puissants qui restaurent la cohérence de domaines sur leur décomposition en deux inégalités pseudo-Booléennes.

Dans certains cas, contrairement à ce qui s’est produit dans notre exemple, ce filtrage affaibli réduit certains domaines et c’est mieux que rien.

Filtrage partiel

La restauration de cohérence de domaines s’applique itérativement à toutes les contraintes d’un réseau jusqu’à ce que toutes les valeurs de chaque domaine aient au moins un support pour toutes les contraintes. On peut réduire le coût du filtrage – et son efficacité – en ne filtrant que les contraintes directement reliées à la variable de branchement. L’algorithme obtenu est appelé forward checking (FC).

MAC est en général plus rapide que FC, mais on ne peut en faire un dogme. Dans certains cas particuliers où le filtrage complet serait couteux et peu rentable, on peut envisager d’utiliser FC, en prolongeant toutefois le filtrage lorsque certains domaines deviennent des singletons.

Dans le cadre de cet enseignement, on travaillera uniquement avec MAC.

Au delà de la cohérence de domaines

La restauration de la cohérence de domaines déduit tout ce qu’il est possible de déduire à partir d’une seule contrainte et lorsque la conclusion de la déduction est une restriction des domaines. Mais on peut imaginer d’autres formes de déductions faisant intervenir plusieurs contraintes. Lorsque le résultat d’une telle déduction est une nouvelle contrainte, on parlera d’apprentissage, mais si le résultat est une restriction de domaines on peut encore parler de filtrage.

L’exemple typique est la notion de k-cohérence, souvent appelée k-consistance dans la littérature par francisation du terme anglais consistency qui se dit en français cohérence. Un réseau de contraintes et k-cohérent si toute assignation partielle de k-1 variables peut être étendue à une assignation partielle de k variables sans falsifier de contrainte.

Cette notion ne sera pas développée ici, mais rien n’empêche de remplacer dans un solveur de type MAC la restauration de la cohérence de domaines par la restauration de la k-cohérence. Le risque est que le coût d’un tel filtrage soit plus élevé que son bénéfice, mais rien ne permet d’affirmer qu’il ne soit pas rentable pour certains types de contraintes ou de réseaux.

Branchements binaires

Dans l’algorithme MAC décrit au début de ce document, chaque nœud de l’arbre de recherche est associé à une certaine variable de branchement, appelons-là $V$, et chaque branche partant de ce nœud correspond à une valeur du domaine de $V$. On peut donc avoir des nœuds à deux, trois, quatre branches et plus. On peut interpréter ces branchements comme des hypothèses. En branchant sur $V = x$, où $x$ est dans le domaine de $V$, on fait l’hypothèse qu’il existe au moins une solution pour laquelle $V = x$. Si cette hypothèse est vraie, on trouvera de telles solutions dans le sous-arbre induit par le branchement. Si elle est fausse, on aura acquis une connaissance, à savoir qu’avec les domaines considérés avant le branchement, il n’existe aucun moyen de satisfaire le réseau si $V = x$. Cette connaissance est enregistrée implicitement par le solveur grâce au mécanisme qu’il utilise pour éviter de faire à nouveau le branchement $V = x$ à partir du même nœud de son arbre de recherche. On parle parfois de phase de la variable de branchement.

image7

Il existe une variante de MAC dans laquelle on réalise exactement deux branchements à chaque nœud. Dans cette variante, pour une variable de branchement $V$, on va avoir un branchement correspondant à l’hypothèse $V = x$ et un autre correspondant à l’hypothèse $V \neq x$.

image8

Tout arbre de MAC classique peut être aisément simulé par un MAC à branchements binaires. Par exemple dans le cas d’une variable de branchement $V$ de domaine ${ 1,2,3}$, le deuxième branchement correspondant à $V \neq 1$ pourra être prolongé par un branchement basé sur la même variable $V$ avec les hypothèses $V = 2$ et $V \neq 2$, mais comme à ce stade il n’y aura plus que 2 et 3 dans le domaine de $V$, cela reviendra au même que brancher sur $V = 2$ et $V = 3$.

image9

La réciproque n’est pas vraie. MAC à branchements binaires peut produire des arbres de recherche impossibles à obtenir avec MAC classique.

MAC à branchements binaires peut être plus efficace que MAC classique sur certains problèmes, à condition de bien choisir les variables et valeurs de branchements. Or ce choix est loin d’être évident, comme nous le verrons plus loin.

D-dec-32

Soit le réseau de contraintes suivant :

  • Variables : $A, B, C$ ayant toutes pour domaine ${1,2,3}$.

  • Contraintes : $\text{allDiff}(A,B,C)$, $A+B=4$.

Donnez l’arbre de recherche MAC à branchement binaire en utilisant $A$ comme première variable de branchement.

"Solution"

image-20210927104846784

Apprentissage (approfondissement hors programme)

Dans MAC classique et MAC à branchements binaires, il y a une forme d’apprentissage dans le sens où le solveur accumule des connaissances sur des assignations partielles qui ne peuvent être étendues à des solutions. Prenons comme exemple l’arbre de recherche suivant (peu importe les contraintes).

image10

Cet arbre est parfaitement plausible. Rien n’oblige à choisir les variables de branchement dans le même ordre sur chaque branche. D’autre part, en raison des filtrages réalisés à chaque nœud, une même variable de branchement peut avoir un domaine différent selon le nœud où elle est utilisée. Les croix représentent des échecs, ou incohérences, c’est-à-dire des situations où après branchement et filtrage, un domaine devient vide.

Intéressons-nous au moment où la recherche vient de produire le quatrième échec. A ce moment précis, le solveur à accumulé les connaissances suivantes :

  • Il n’y a pas de solution avec $A = 1$.

  • Il n’y a pas de solution avec $A = 2$ et $C = 1$.

image11

C’est ce que l’auteur de ce cours appelle de l’apprentissage implicite. C’est le mécanisme de retour arrière qui permet au solveur de conserver ces connaissances. Par exemple, après le stade matérialisé sur la figure ci-dessus, le solveur n’essaiera plus de trouver des solutions avec $A = 1$, ni avec $A = 2$ et $C = 1$.

Mais certains mécanismes d’apprentissage explicite peuvent être ajouté au solveur. Il peut s’agir de systèmes déductifs activés au moment des échecs. Par exemple, imaginons que le deuxième échec ne dépende pas de la valeur de la variable $A$. On dira que ${B = 5,\ C = 1}$ est un nogood. Trouver ce genre de nogood requiert des algorithmes spécifiques qui sortent du périmètre de ce cours.

Si notre algorithme MAC était équipé d’un mécanisme permettant de détecter le nogood ${B = 5,\ C = 1}$, alors on pourrait ajouter cette information dans une base de connaissances ou l’ajouter au réseau comme une nouvelle contrainte. Ainsi, si par exemple l’assignation $B = 5$ se reproduit plus tard, la valeur $1$ sera retirée du domaine de $C$, ce qui évitera des branchements qui auraient été nécessaires sans cet apprentissage.

image12

En pratique, les solveurs avec apprentissage sont très complexes et font généralement des redémarrages et des retours arrière non chronologiques, c’est-à-dire qu’après certains échecs et apprentissages associés, ils remontent plus haut que la dernière variable de branchement même si toutes les valeurs du domaine de cette variable n’ont pas été essayées.

Les nogoods ou autres connaissances qu’ils apprennent occupent un espace mémoire important, ce qui impose de retirer régulièrement certaines connaissances apprises. Malgré cette grande complexité, ces solveurs peuvent être beaucoup plus efficaces que les solveurs sans apprentissage (ou à apprentissage implicite). Par exemple pour problème SAT, dans lequel les contraintes sont des clauses en logique propositionnelle, les solveurs de type CDCL (pour Conflict Driven Clause Learning) qui apprennent (comme leur nom l’indique) de nouvelles clauses, pulvérisent les performances des solveurs énumératifs de type MAC (qui dans le contexte de SAT sont appelés DPLL d’après les initiales des noms des inventeurs).

D4 : Heuristiques de branchement

Le choix des variables de branchement (et des valeurs dans le cas de la version à branchement binaire) est critique pour l’efficacité des solveurs de type MAC. Sur des réseaux de quelques dizaines de variables, on peut facilement observer des rapports de temps d’exécution de l’ordre du milliard, ou beaucoup plus, selon la manière dont les variables de branchement sont choisies.

Pour comprendre l’importance de choisir les « bonnes » variable de branchement, considérons cet exemple.

image13

La cohérence de domaine est vérifiée pour toutes les contraintes. (Rappelez-vous que cette forme de cohérence ne considère qu’une seule contrainte à la fois !).

Si MAC commence par brancher avec une des variables A, B ou C, il déduira rapidement que le réseau est incohérent. Mais s’il commence par la variable D, il revérifiera trois fois l’incohérence du sous-réseau A, B, C.

Trouver la meilleure variable de branchement est (dans le cas général) plus difficile que résoudre le réseau, mais il existe des heuristiques de choix de la variable de branchement qui sont plus ou moins efficaces selon la nature des contraintes et la structure du réseau.

On appelle heuristique un critère de choix facile à calculer (qui prend un temps faible au regard des autres traitement réalisé par le solveur) mais qui ne donne aucune garantie d’optimalité.

Ces heuristiques peuvent prendre en compte, par exemple :

  • la taille du domaine de chaque variable,

  • le nombre de contraintes dans lesquelles chaque variable intervient,

  • le nombre d’assignations partielles autorisées par chaque contraintes,

  • des poids attribués à chaque variable, qui évoluent au cours de la recherche en fonction de l’efficacité des filtrages réalisés sur leurs domaines (on parle alors d’heuristiques dynamiques)…

C’est un très vaste sujet que nous n’approfondirons pas ici. Même lorsque le réseau de contraintes est cohérent, c’est le choix des variables de branchement qui est particulièrement critique pour trouver une solution. Bien évidemment, si on pouvait « deviner » les assignations des variables d’une solution, on la trouverait immédiatement quelles que soient les variables de branchement. Mais en pratique il s’avère souvent que « deviner » les solutions à l’aide d’une heuristique ne fonctionne pas, alors que les heuristiques efficaces pour prouver l’incohérence du réseau de contraintes sont celles qui sont également les plus efficaces pour trouver des solutions lorsque le réseau de contraintes est cohérent.


Exercices d’assimilation

D-ass-01

Complétez cet arbre de recherche de l’algorithme MAC sur le problème des 5 reines. Chaque pastille ronde rose représente l’assignation d’une variable de branchement. Les croix grises représentent les valeurs des domaines des variables qui ont été filtrées (ou éliminées du fait de l’assignation de la variable). Les pastilles carrées roses représentent les valeurs assignées par filtrage (quand il ne reste qu’une valeur dans le domaine concerné). On considère qu’il y a 10 contraintes reliant respectivement A et B, A et C, A et D, A et E, B et C, B et D, B et E, C et D, C et E, D et E. Chacune de ces contraintes exprime que les reines situées sur les colonnes associées aux variables concernées ne sont ni sur une même ligne, ni sur une même diagonale.

image14

"Indice1"

Tout d’abord, il faut que vous soyez convaincu du résultat du filtrage pour $A = 1$. Les croix apparaissant sur la figure de gauche sont assez évidentes, puis qu’elles correspondent à des valeurs des variables B, C, D, E qui représentent des reines positionnées sur une même ligne ou une même diagonale que la reine représentée par A=1. Par exemple, il y a une croix pour C=3 parce-que C=3 n’a pas de support pour la contrainte entre A et C, parce que si on avait A=1 et C=3, cela reviendrait à mettre les reines des colonnes A et C sur une même diagonale.

image16

Mais pourquoi faut-il aussi mettre des croix pour C=4 et D=3 ? N’oubliez pas que vous devez continuer le filtrage tant qu’il reste dans certains domaines des valeurs n’ayant pas de support pour certaines contraintes.

Or C=4 n’a pas de support pour la contrainte entre B et C ! En effet, le domaine de B est {3,4,5} (les valeurs non barrées dans la colonne B. Si on assignait C=4, on ne pourrait pas assigner B=3 (conflit diagonale), ni B=4 (conflit ligne), ni B=5 (conflit diagonale). Donc aucune des valeurs du domaine de B n’est compatible avec C=4 au regard de la contrainte entre B et C. On doit donc retirer C=4.

Un raisonnement similaire pour la contrainte entre D et E permet de supprimer D=3, d’où les deux croix en C=4 et D=3. Quels sont les filtrages supplémentaires à ajouter si on assigne C=5 ? Trouvez les vous-même avant de consulter la réponse au prochain indice.

"Indice2"

Sur cette figure, le filtrage pour la branche A=1, C=5 a été terminé et a donné lieu à une solution. Le filtrage pour A=2 a été réalisé. Merci de continuer avec la variable de branchement C.

image20

"Indice3"

Les branchements C=1 et C=3 après A=2 produisent chacun une solution par filtrage. A vous de tenter de terminer l’arbre de recherche avant de consulter le dernier indice.

image25

"Solution"

Voici le développement complet des branches A=1, A=2, A=3.

image32

Comme les branches A=4 et A=5 sont symétriques avec les branches A=2 et A=1 (bien que peu de solveurs soient capables de le prendre en compte), on en déduit que le problème des 5 reines a 10 solutions.

D-ass-02

Soit le problème suivant :

Variables :

image15

Contraintes :

Pour chaque ligne et chaque colonne, une contrainte exprime que la somme des variables concernées vaut 2. $A + B + C = 2$, $D + E + F = 2$, $G + H + I = 2$, $A + D + G = 2$,$B + E + H = 2$, $C + F + I = 2$.

Réalisez une simulation de l’exécution d’un solveur MAC sur cette instance de problème. Dessinez l’arbre de recherche complet (recherchant toutes les solutions), en précisant à chaque nœud les domaines des différentes variables. Pour faciliter la lecture, merci de représenter ces domaines sous la forme d’une grille de 3 par 3 avec la convention suivante : une case blanche représente le domaine {0,1} , une case contenant la valeur 0 représente le domaine {0} , et une case contenant la valeur 1 représente le domaine {1}.

"Indice1"

Voici le premier niveau de l’arbre de recherche en choisissant E comme variable de branchement. Ce n’est pas obligatoire, mais les indices suivants seront basés sur ce choix.

image17

On voit que le côté gauche filtre un peu, alors que le côté droit ne filtre pas, mais cela aurait été la même chose avec tout autre choix de la variable de branchement.

"Indice2"

La branche gauche aboutit à deux solutions en branchant sur A, par exemple. Le prochain indice sera basé sur un branchement sur D à droite.

image21

"Indice3"

Voici le développement de tout le deuxième niveau. Pour la suite, E est la variable de branchement préconisée.

image26

"Solution"

Voici l’arbre de résolution complet, qui fait apparaitre les 6 solutions du réseau. Étant donné qu’il y a 6 solutions, quelles que soit les choix des variables de branchement, l’arbre de recherche aura au moins 6 branches, donc 5 nœuds binaires. Il n’existe donc pas de stratégie de branchement produisant un arbre plus petit.

image33

D-ass-03

Soit le réseau de contraintes suivant :

  • Variables : A avec domaine {0,5}, B avec domaine {0,6}, C avec domaine {0,9}, D avec domaine {0,2}.

  • Contraintes : A + B + C + D >= 15 et A + B + C + D <= 15.

Détaillez la résolution de ce problème par l’algorithme MAC (Maintaining Arc Consistency). Choisissez les variables de branchement de manière à minimiser la taille de l’arbre de recherche.

"Indice1"

La première chose à faire est de rétablir la cohérence de domaine, si applicable. Or il y a bien une valeur à enlever. C=0 n’a pas de support pour la contrainte A + B + C + D >= 15. C’est le seul filtrage possible, donc pour continuer il faut choisir une variable de branchement. Pourquoi pas B ?

image18

"Indice2"

Avec B=0, A=0 et D=0 ne peuvent satisfaire la contrainte A + B + C + D = 15. Les valeurs 0 sont donc retirées des domaines de A et D. Mais alors, aucune des valeurs restant dans les domaines ne permet de satisfaire la contrainte A + B + C + D <= 15.

image22

Pour la forme, on matérialise l’incohérence en retirant 5 du domaine de A, mais on aurait pu vider tout autre domaine, puisque les valeurs restantes, par définition, n’ont pas de support pour A + B + C + D <= 15.

Il reste un espoir de trouver une solution avec la branche B=6…

"Solution"

Voici l’arbre de recherche complet. Le filtrage des domaines de A et D au regard de la contrainte A + B + C + D >= 15 permet de retirer les valeurs non nulles et de produire une solution.

image27

D-ass-04

Soit le réseau constitué des 6 contraintes logiques suivantes, appelées clauses.

$$(a \vee b), (\neg a \vee b), (a \vee \neg b), (\neg a \vee \neg b \vee c), (\neg c \vee d), (\neg c \vee \neg d)$$

Les variables ont toutes pour domaine {0,1}.

Détaillez la résolution de ce problème par l’algorithme MAC. A chaque nœud ou feuille, redonnez les domaines en barrant les valeurs éliminées par filtrage ou par assignation de la variable de branchement. A chaque feuille, précisez s’il y a échec ou solution. Essayez de choisir les variables de branchement de manière à minimiser la taille de l’arbre de recherche.

"Indice1"

Tout d’abord il faut restaurer la cohérence de domaine. Mais il n’y a aucun filtrage possible avec les domaines initiaux. Chaque clause fait intervenir plusieurs variables et quelle que soit la valeur d’une de ces variables, il existe toujours au moins une valeur pour l’autre qui permet de satisfaire la clause.

Pour la suite, merci d’utiliser la variable $a$ comme variable debranchement.

image19

"Indice2"

Avec $a = 0$, $b = 0$ n’a pas de support pour la clause $(a \vee b)$ et $b = 1$ n’a pas de support pour la clause $(\neg a \vee b)$.

image23

Avec les clauses, on peut raisonner directement sur les contraintes en barrant les littéraux qui sont falsifiés par les assignations déjà réalisées.

image24

Quand il reste un seul littéral dans une clause, cela impose une assignation de la variable concernée. Dans le contexte du problème SAT, c’est-à-dire quand toutes les contraintes sont des clauses, cette technique est appelée propagation unitaire.

"Solution"

Voici l’arbre de résolution complet.

image28

Puisque $a = 1$, $b = 0$ n’a pas de support pour la clause $(\neg a \vee b)$ qui ne peut être satisfaite que si $b = 1$. Cette première étape peut aussi être formalisée comme ci-dessous en termes de propagation unitaire.

image29

Ensuite, puisque le domaine de $b$ est ${ 1}$, ce qui revient à dire que $b = 1$, et que par ailleurs $a = 1$, $c = 0$ n’a pas de support pour la clause $(\neg a \vee \neg b \vee c)$ qui ne peut être satisfaite que si $c = 1$.

image30

Mais avec $c = 1$, $d = 0$ n’a plus de support pour la clause $(\neg c \vee d)$ et $d = 1$ n’a plus de support pour la clause $(\neg c \vee \neg d)$. Le domaine de $d$ se retrouve vide et la branche aboutit à un échec. Le réseau initial est donc incohérent.

image31


PPC : test d’autoévaluation partie A

Programmation par contraintes

En M2 Bases de données et IA et M2 Image et IA

Par Olivier Bailleux, Maître de conférences HDR, Université de bourgogne

Test d’auto-évaluation sur la partie A

Objectif

Vérifier si vous avez assimilé de manière approfondie les notions de la partie A

Prérequis

Partie A


Question 1

Pour chacune de ces deux contraintes, dites si elle est donnée en extension et/ou en compréhension et/ou sous forme énumérative. On suppose que les variable ont toutes pour domaines ${1,2,3}$.

  1. $A > C+1$
  2. sur $A,B,C$, ${(1,1,1),(1,2,1),(2,1,2)}$
"Réponse"

La première contrainte est en compréhension. La deuxième est en extension. Elle est donnée sous forme énumérative. (Les deux termes sont équivalents.)

Question 2

Le réseau de contraintes suivant a-t-il des solutions ? Si oui, donnez les.

![](img

"Réponse"

Ce réseau n’a pas de solution. Il est incohérent.

Question 3

Le réseau de contraintes suivant a-t-il des solutions ? Si oui, donnez les.

"Réponse"

  1. $A=\alpha, B=\beta, C=\alpha, D=\beta$
  2. $A=\beta, B=\alpha, C=\beta, D=\alpha$

Question 4

On dit que deux contraintes sont équivalentes si et seulement si elles relient les mêmes variables, de même domaines, et sont satisfaites par les même assignations de ces variables.

Soit $A$ et $B$ deux variables à domaine ${0,1}$. Les contraintes $A=\neg B$ et $A\vee B$ sont elles équivalentes ?

"Réponse"

Non, car l’assignation $A=1,B=1$ falsifie la première contrainte et satisfait la deuxième.

Question 5

Soit $A$ et $B$ deux variables à domaine ${0,1}$. Les contraintes $A=\neg B$ et $(A\vee B)\wedge(\neg A\vee \neg B)$ sont elles équivalentes ?

"Réponse"

Oui.

Question 6

Soit la contrainte $10 A + 5 B + C \leq 11$, où $A$, $B$ et $C$ ont pour domaine ${0, 1}$.

Donnez une assignation partielle $I$ qui falsifie cette contrainte et une assignation partielle $J$ qui la satisfait.

"Réponse"

$I$ : $A=1, B=1$.

$J$ : $A=0$ ou $B=0$ ou toute extension de ces assignations.

Question 7

Soient $A$ et $B$ deux variables ayant pour domaine ${0,1}$. Donnez une contrainte équivalente à $A = \neg B$ spécifiée en compréhension en utilisant uniquement des opérateurs arithmétiques +, -, = et des constantes entières (0, 1, …).

"Réponse"

$A = 1 – B$ ou $B= 1 – A$ ou $A+B = 1$.

Question 8

Soient les variables $A$ et $B$ de domaine ${0,1}$ et les variables $X$ et $Y$ de domaine ${0,2}$.

On considère :

  • la contrainte $q : A\vee B$,
  • et le réseau $r : A\neq X, B\neq Y, X\neq Y$.

Soit $I$ une assignation des variable $A,B$, qui est aussi une assignation partielle des variables de $r$. Parmi les affirmations suivantes, lesquelles sont vraies ?

  1. Si $I$ satisfait $q$ alors il existe une extension de $I$ qui satisfait $r$.
  2. Si il existe une extension de $I$ qui satisfait $r$ alors $I$ satisfait $q$.
  3. Si $I$ falsifie $q$ alors $I$ (vu comme une assignation partielle des variables de $r$) falsifie $r$.
  4. Si $I$ satisfait $q$ alors $I$ (vu comme une assignation partielle des variables de $r$) satisfait $r$.
"Réponse"

  1. Oui. On peut vérifier que pour chacune des assignations qui satisfont $q$, c’est à dire ${A=0,B=1}$, ${A=1,B=0}$, et ${A=1, B=1}$, il existe une valeur de $X$ et une valeur de $Y$ qui permettent de satisfaire $r$.
  2. Oui. Il existe une extension de $I$ qui satisfait $r$ si $I={A=0,B=1}$ ou si $I={A=1,B=0}$ ou si $I={A=1, B=1}$. (et pas si $I={A=0, B=0}$). Ces trois assignations satisfont $q$.
  3. Oui. La seule assignation $I$ qui falsifie $q$ est ${A=0, B=0}$. Cette assignation falsifie $r$.
  4. Non. Par exemple, $A=1,B=1$ satisfait $q$ mais son extension $A=1,B=1,X=2,Y=2$ falsifie $r$.

Programmation par contraintes : partie I

Programmation par contraintes

En M2 Bases de données et IA et M2 Image et IA

Par Olivier Bailleux, Maître de conférences HDR, Université de bourgogne

Implémentation avec CHOCO v4

Objectif

Être capable de concevoir une application Java permettant de résoudre un problème de satisfaction de contraintes en utilisant la bibliothèque CHOCO version 4.

Prérequis

Partie B et bases de programmation en JAVA.

Introduction

Entendons-nous bien. La programmation par contraintes est une programmation déclarative : on spécifie un problème à l’aide de contraintes, et un solveur résout ce problème. L’intérêt est précisément de ne pas avoir à programmer un solveur. Java n’est pas un langage déclaratif mais impératif, qui exige de détailler toutes les étapes et opérations nécessaires à l’exécution d’un programme.

Alors pourquoi et comment utiliser un langage impératif pour faire de la programmation déclarative ?

Il faut comprendre que les applications réalisées avec la bibliothèque CHOCO s’exécutent en deux temps. Dans un premier temps, un programme Java produits des objets de types variables et contraintes, qui sont placés dans un objet appelé modèle, qui représente un réseau de contraintes.

Une application utilisant CHOCO exécute un algorithme qui « fabrique » une spécification déclarative d’un problème de satisfaction de contraintes. Dans un deuxième temps, un objet solveur prend en charge le modèle préalablement construit pour résoudre le réseau de contraintes. Donc le code Java ne sert pas à résoudre le problème, mais à construire des réseaux de contraintes représentant des instances du problème à résoudre. La résolution en elle-même est assurée par le solveur fourni par CHOCO.

image1

Avant d’aller plus loin, vous devez récupérer la bibliothèque CHOCO qui est disponible sous la forme d’une archive au format jar en suivant les instructions du site choco-solver.org. On vous envoie vers un dépôt github où, en cherchant bien, vous pourrez trouver un lien vers la "latest release". Au moment où j’écris ces lignes, il s’agit de la version 4.10.6. Vous arrivez enfin à une page proposant plusieurs archives. Celle qui nous intéresse est nommée choco-solver-4.10.6-jar-with-dependencies.jar au moment où j’écris ce ligne. Il se peut qu’il s’agisse d’une version ultérieur lorsque vous vous rendrez sur le site, mais l’important est que la bonne archive a l’extension jar et comporte les termes choco-solver et with-dependencies dans son nom.

Vous devez ensuite faire en sorte d’utiliser cette bibliothèque dans le code Java que vous allez écrire et compiler. Les IDE proposent tous un moyen spécifique de faire cela. Il faut parfois tâtonner un peu.

Exemple introductif

Avant de coder une application CHOCO, il faut modéliser le problème à résoudre sous la forme d’un réseau de contraintes comme nous avons appris à le faire dans la préparation du badge B.

Nous parlons ici du problème suivant : peut-on placer n reines sur un échiquier n par n de manière à qu’il y ait exactement une reine sur chaque ligne et chaque colonne et au plus une reine sur chaque diagonale ?

Pour modéliser ce problème, nous utilisons $n$ variables $v_{0},\ldots,\ v_{n – 1}$ à domaines ${ 1..n}$. Chaque variable est associée à une colonne de l’échiquier. Une assignation $v_{i} = j$ signifie que la reine située dans la colonne $i$ se trouve en ligne $j$.

La figure ci-dessous représente une solution pour $n = 5$ et l’assignation des variables $v_{0}$ à $v_{4}$ qui représente cette solution.

image3

Pour chaque couple $(i,j),\ i \in 0..(n – 2),\ j \in (i + 1)..(n – 1)$, on pose les trois contraintes suivantes :

  1. $v_{i} \neq v_{j}$, qui interdit que les reines des colonnes $i$ et $j$ soient une même ligne.

  2. $v_{i} \neq v_{j} – (j – i)$, qui interdit que les reines des colonnes $i$ et $j$ soient sur une même diagonale descendante.

  3. $v_{i} \neq v_{j} + (j – i)$, qui interdit que les reines des colonnes $i$ et $j$ soient sur une même diagonale montante.

Par exemple, on aura trois contraintes reliant les variables $v_{0}$ et $v_{2}$, à savoir $v_{0} \neq v_{2}$, $v_{0} \neq v_{2} – 2$ et $v_{0} \neq v_{2} + 2$. Si par exemple $v_{0} = 3$, ces trois contraintes interdiront les valeurs 2, 4 et 6 pour $v_{2}$.

image4

Au total, pour $n$ reines, on aura $3n(n – 1)/2$ contraintes.


Il nous faut maintenant traduire ce modèle en un ensemble d’objets créés avec la bibliothèque CHOCO. Voici les différentes étapes.

Création du modèle

Ces deux lignes permettent de créer un modèle (instance de la classe Model) à laquelle seront ensuite ajoutées les contraintes et les variables. La chaîne passée en paramètre est purement « cosmétique ».

    int n = 8;
    Model model = new Model(n + "-queens problem");

Création des variables

Ces lignes permettent de créer les variables du réseau de contraintes. Attention. Nous parlons bien ici des variables du réseau de contraintes, dont les domaines contiennent des entiers. Ces variables ne sont pas des variables de type int de Java. Ce sont des instances de la classe IntVar de CHOCO qui représentent les variables du réseau de contraintes sur lequel le solveur CHOCO va raisonner.

    IntVar[] vars = new IntVar[n];
    for(int q = 0; q < n; q++)
    {
        vars[q] = model.intVar("Q_"+q, 1, n);
    }

La première ligne crée un tableau qui regroupera toutes les variables du problème. Attention, cette liste produit juste un tableau dont les cellules contiennent la pseudo-référence null.

image7

En Java, les cellules d’un tableau, tout comme les variables ayant un type non scalaire T ne contiennent jamais une instance de type T, mais contiennent soit la valeur null, soit la référence d’un objet de type T.

En résumé, une variable ou une cellule de tableau ne peut pas contenir un objet, mais seulement sa référence. Donc dans notre cas, la création du tableau ne crée pas les variables de notre réseau mais juste les cellules destinées à contenir les références de ces variables.

C’est la boucle for qui va créer les variables de notre réseau de contraintes, qui est appelé modèle dans la documentation CHOCO, et placer les références de ces variables, représentées par des objets de type IntVar, dans le tableau vars.

La création de chaque variable est assurée par la méthode intvar de la classe Model de CHOCO.

L’appel model.intVar(\"Q\_\"+q, 1, n) retourne la référence un objet de type IntVar qui représente une variable (au sens de la programmation par contrainte) nommée Q_q (où q désigne la colonne associée à la variable) et de domaine 1..n (où n est le nombre de reines). Le nom de la variable est un attribut purement cosmétique qui pourra servir pour des affichages et lors de la mise au point du programme.

Création des contraintes

Les contraintes de notre modèle sont des objets de type Constraint. Ces objets sont produits par la méthode arithm de la classe Model. Différentes variantes surchargées de cette méthode permettent de construire aisément des contraintes arithmétiques à partir de variables, d’opérateurs et de constantes comme le montrent les lignes de code suivantes qui créent les contraintes pour le problème de n reines et les intègrent dans le modèle.

    for(int i  = 0; i < n-1; i++)
    {
        for(int j = i + 1; j < n; j++)
        {
            model.arithm(vars[i], "!=",vars[j]).post();
            model.arithm(vars[i], "!=", vars[j], "-", j - i).post();
            model.arithm(vars[i], "!=", vars[j], "+", j - i).post();
        }
    }

Examinons par exemple la ligne model.arithm(vars\[i\], \"!=\", vars\[j\], \"-\", j - i).post(). Cette ligne appelle la méthode arithm qui, avec les paramètres qui lui sont transmis, crée un objet de type Constraint représentant la contrainte $v_{i} \neq v_{j} – (j – i)$. La méthode post de la classe Constraint est ensuite appelée pour intégrer cette contrainte dans le modèle dans lequel elle a été créée. Il faut bien comprendre que du point de vue de CHOCO, les valeurs des variables Java i et j sont des constantes qui vont être figées dans la contrainte au moment de sa création.

En pratique, toutes les contraintes créées dans un modèle doivent y être intégrées par la méthode post sauf les contraintes dites réifiées.

La réification d’une contrainte $q$ sur un ensemble $V$ de variables est une contrainte $q^{r}$ sur $V \cup { r}$, où $r$ est une variable additionnelle appelée variable de réification à domaine Booléen {0,1}, telle que pour toute assignation $A$ sur $V$, $A \cup { r = 1}$ satisfait $q^{r}$ si et seulement si $A$ satisfait $q$ et $A \cup { r = 0}$ satisfait $q^{r}$ si et seulement si $A$ falsifie $q$. En résumé, la réification $q^{r}$ d’une contrainte $q$ peut toujours être satisfaite mais avec une valeur de sa variable de réification qui indique si $q$ est satisfaite par les valeurs des autres variables.

Si cela vous parait confus, pour l’instant retenez juste que pour ajouter des contraintes ordinaires, telle que celles que nous avons vu dans la préparation des parties A et B, il faut toujours intégrer les contraintes avec la méthode post et que si vous oubliez de le faire, le solveur ne prendra pas en compte les contraintes concernées.

Dans notre exemple, les boucles for imbriquées ne servent donc en aucun cas à résoudre le problème des n reines. Elles servent à fabriquer les contraintes qui spécifient ce problème et à intégrer ces contraintes dans le modèle qui servira ensuite au solveur pour résoudre le problème.

Résolution

Pour résoudre notre problème, il suffit de créer un objet de type Solveur et d’exécuter une méthode de cet objet permettant de lancer la résolution du réseau de contraintes spécifiée par le modèle précédemment construit. C’est ce que font les lignes de code ci-dessous.

    Solution solution = model.getSolver().findSolution();
    if(solution != null)
    {
        System.out.println(solution.toString());
    }

La méthode getSolver crée un objet de type Solver dédié au modèle représenté par l’objet model. La méthode findSolution appelée avec cet objet recherche une solution de ce modèle. Si le réseau de contraintes représenté par le modèle est incohérent, findSolution retourne null, sinon elle retourne un objet de type Solution qui contient les détails de la solution trouvée. La méthode toString de l’objet solution permet d’afficher les valeurs assignées aux variables par cette solution.

Il existe d’autres méthodes applicables aux objets de type Solver pour rechercher toutes les solutions du problème.

Voici le code complet de cet exemple introductif avec les imports des packages de CHOCO requis pour son fonctionnement.

public static void main(String[] args)
{
    int n = 8;
    Model model = new Model(n + "-queens problem");
    IntVar[] vars = new IntVar[n];
    for(int q = 0; q < n; q++)
    {
        vars[q] = model.intVar("Q_"+q, 1, n);
    }
    for(int i  = 0; i < n-1; i++)
    {
        for(int j = i + 1; j < n; j++)
        {
            model.arithm(vars[i], "!=",vars[j]).post();
            model.arithm(vars[i], "!=", vars[j], "-", j - i).post();
            model.arithm(vars[i], "!=", vars[j], "+", j - i).post();
        }
    }
    Solution solution = model.getSolver().findSolution();
    if(solution != null)
    {
        System.out.println(solution.toString());
    }
}

L’auteur a compilé ce code dans l’IDE IntelliJIDEA et l’exécution a produit l’affichage suivant :

Solution: Q_0=7, Q_1=4, Q_2=2, Q_3=5, Q_4=8, Q_5=1, Q_6=3, Q_7=6

Voici une représentation graphique de la solution trouvée par le solveur.

image10

Exercices d’assimilation

A-ass-00

Le problème des reines en booléens. On modélise le problème des $N$ reines en utilisant uniquement des variables Booléennes. Le réseau de contraintes comporte $N^{2}$ variables, chacune associée à une case de l’échiquier. Voici par exemple les variables pour $N = 5$.

image11

Une contrainte est associée à chaque ligne, chaque colonne et chaque diagonale de l’échiquier. Les contraintes relient toutes les variables d’une même ligne ou d’une même colonne expriment qu’une seule des variables concernées vaut 1. Les contraintes qui relient toutes les variables d’une même diagonale expriment qu’au plus une des variables concernées vaut 1.

Voici deux exemples de contraintes pour $N = 5$.

image12

image13

Réalisez une application CHOCO qui résout ce problème.

"Indice1"

La première chose à faire est de créer un modèle et de lui ajouter les variables du problème. Voici les lignes de code qui permettent de faire cela.

    int N = 8;

    //Création du modèle
    Model model = new Model(N + "-queens problem");

    // Création des variables
    IntVar[][] x = new IntVar[N][N];
    for(int i=0; i<N; i++)
    {
        for(int j=0; j<N; j++)
        {
            x[i][j] = model.intVar("X_"+i+"_"+j, 0, 1);
        }
    }

Voici les données créées en mémoire (dans le tas) par l’exécution de ces lignes de code.

image14

"Indice2"

A présent il nous faut construire les contraintes. Commençons par les plus faciles, qui concernent les lignes de l’échiquier. En cherchant un peu dans la documentation CHOCO, on trouve une contrainte somme qui exprime que la somme de toutes les variables situées dans un tableau est égale à une valeur donnée (des variantes de cette contrainte permettent d’exprimer une inégalité $\leq ,\ \geq ,\ > ,\ <$ avec une constante ou une variable du réseau).

Pour construire une contrainte somme, les références des variables à prendre en compte doivent être dans un tableau. Ça tombe bien, les variables de chaque ligne de l’échiquier sont déjà dans des tableaux. Vous pouvez le vérifier en observant la figure donnée dans l’indice précédent. En java, chaque cellule d’un tableau à 2 dimensions contient la référence d’un tableau à une dimension.

Le code suivant permet de produire toutes les contraintes relatives aux lignes de l’échiquier.

    for(int i=0; i<N; i++)
    {
        model.sum(x[i], "=", 1).post();
    }

Dans la lignemodel.sum(x[i], "=" 1).post(), x[i] désigne un tableau de taille N dont les cellules contiennent les références des objets de type IntVar qui représentent les variables d’une ligne de l’échiquier.

"Indice3"

Après les lignes, il nous faut produire les contraintes relatives aux colonnes. Mais cette fois-ci, nous ne disposons pas de tableau tout fait contenant les références des variables d’une même colonne. Il faut donc, pour chaque colonne, créer un tel tableau et le remplir avant de l’utiliser pour créer une contrainte de type somme similaire à celles utilisées pour les lignes.

Voici les lignes de codes permettant de faire cela.

    for(int j=0; j<N; j++)
    {
        IntVar[] col = new IntVar[N];
        for(int i=0; i<N; i++)
        {
            col[i] = x[i][j];
        }
        model.sum(col, "=", 1).post();
    }

"Indice4"

Nous devons maintenant produire une contrainte pour chacune des $2N – 1$ diagonales montantes et des $2N – 1$ diagonales descendantes de l’échiquier. Il existe plusieurs moyens de collecter les variables de ces diagonales. Voici celui que je propose pour les diagonales montantes. Comme le montre la figure ci-dessous, on peut numéroter les diagonales montantes de 0 à $2N – 2$. Les cellules appartenant à la diagonale $i$ ont pour particularité que la somme de leurs indices vaut $i$. Par exemple, la cellule d’indice $(3,1)$ est sur la diagonale 4.

image15

On peut créer les listes des variables des différentes diagonale en parcourant une seule fois toutes les cellules du tableau représentant l’échiquier. Pour ce faire, on crée un tableau dUp de $2n – 1$ listes initialement vides. On parcourt l’échiquier en faisant varier les indices $i$ et $j$ entre $0$ et $N – 1$ et pour chaque $(i,j)$ on ajoute la variable $x_{\text{ij}}$ à la liste dUp[i+j].

A l’issue du parcours, il suffit de parcourir le tableau dUp, de transformer chaque liste qu’il contient en un tableau de références d’objet de type IntVar représentant les variables d’une diagonale, et de produire une contrainte expriment que la somme de ces variables est inférieure ou égale à 1. Voici les lignes de code qui font cela.

    //Diagonales montantes
    ArrayList<IntVar>[] dUp = new ArrayList[2*N-1];

    for(int k=0; k<2*N-1; k++)
    {
        dUp[k] = new ArrayList<>();
    }

    for(int i=0; i<N; i++)
    {
        for(int j=0; j<N; j++)
        {
            dUp[i+j].add(x[i][j]);
        }
    }

    for(int k=0; k<2*N-1; k++)
    {
        IntVar[] tmp = dUp[k].toArray(new IntVar[0]);
        model.sum(tmp, "<=", 1).post();
    }

La première boucle crée les $2N – 1$ listes vides. La double boucle suivante parcoure toutes les variables et place chacune d’elles dans la liste qui représente la diagonale montante à laquelle elle appartient.

La dernière boucle récupère chaque liste de variable, la transforme en un tableau, crée une contrainte exprimant que la somme des variables de ce tableau est inférieure ou égale à 1, et enregistre cette contrainte dans le modèle.

Il ne reste plus qu’à produire les contraintes correspondant aux diagonales descendantes. Essayez de trouver vous-même le moyen de le faire en vous inspirant de la méthode qui vient d’être décrite pour les diagonales montante.

"Solution"

On peut numéroter les $2N – 1$ diagonale comme indiqué sur la figure ci-dessous. Une cellule de coordonnées $(i,j)$ appartient à la diagonale descendante numéro $i – j + N – 1$.

image16

Cette observation étant faite, il devient facile d’implémenter la production des contraintes relatives aux diagonales descendantes.

    //Diagonales descendantes
    ArrayList<IntVar>[] dDown = new ArrayList[2*N-1];

    for(int k=0; k<2*N-1; k++)
    {
        dDown[k] = new ArrayList<>();
    }

    for(int i=0; i<N; i++)
    {
        for(int j=0; j<N; j++)
        {
            dDown[i-j+N-1].add(x[i][j]);
        }
    }

    for(int k=0; k<2*N-1; k++)
    {
        IntVar[] tmp = dDown[k].toArray(new IntVar[0]);
        model.sum(tmp, "<=", 1).post();
    }

Lorsque ces contraintes sont ajoutées au modèle, le reste du code est similaire à celui de l’exemple introductif.

    //Résolution
    Solution solution = model.getSolver().findSolution();
    if(solution != null)
    {
        System.out.println(solution.toString());
    }

A-ass-01

Le problème du sac à dos. Les données du problème sont les suivantes :

  • Deux entiers $W$ et $V$ représentant respectivement le poids maximum et la valeur minimum des objets à mettre dans un sac à dos.

  • Une liste $w_{0},\ldots w_{n – 1}$ des poids des objets susceptibles d’être mis dans le sac.

  • Une liste $v_{0},\ldots v_{n – 1}$ des valeurs des objets susceptibles d’être mis dans le sac.

Les variables du problème, $x_{0},\ldots,x_{n}$ ont toutes pour domaine {0,1}.

Les contraintes sont : $\sum_{i = 0}^{n – 1}{w_{i}\ x_{i}} \leq W$ et $\sum_{i = 0}^{n – 1}{\text{wv}{i}\ x{i}} \geq V$.

Réalisez une application CHOCO qui résout ce problème et testez-là avec l’instance suivante :

  • Poids des objets (en kg) : 2, 5, 7, 8, 15, 21, 23

  • Prix correspondants (en Euros) : 3, 11, 8, 10, 10, 8, 9

  • Valeur minimum des objets emportés : 40 Euros

  • Poids maximum des objets emportés : 50 Kgs

"Indice1"

Il faut définir les constantes représentant les données de l’instance de problème. On peut le faire de la manière suivante :

    int W = 50;
    int V = 40;
    int[] w = new int[]{2,5,7,8,15,21,23};
    int[] v = new int[]{3,11,8,10,10,8,9};

Dans une version plus sophistiquée de l’application, ces variables seraient initialisées par des données issues d’un fichier représentant l’instance à résoudre. A vous maintenant de définir le modèle et les variables.

"Indice2"

Le code permettant de définir et initialiser les variables est très proche de ce que nous avons déjà rencontré.

    //Création du modèle
    Model model = new Model("Backpack");

    // Création des variables
    int N = w.length;
    IntVar[] x = new IntVar[w.length];
    for(int i=0; i<N; i++)
    {
        x[i] = model.intVar("X_"+i, 0, 1);
    }

Il faut maintenant trouver le moyen de produire les contraintes. CHOCO dispose de contrainte de type $a_{0} x_{0} + \ldots + a_{n – 1} x_{n – 1} \ \text{op} \ b$ où, $a_{0}$ à $a_{n – 1}$ et $b$ sont des coefficients réels et $x_{0}$ à $x_{n – 1}$ des variables dont les domaines contiennent des entiers. Plusieurs possibilités existe pour l’opérateur op, telles que <, >, = etc.

Cette contrainte est produite par la méthode scalar de la classe Model. Consultez la documentation de CHOCO pour savoir comment utiliser cette méthode.

"Solution"

Voici le code permettant de produire les deux contraintes du problème, et dans la foulée celui permettant de lancer la résolution.

    // Création des contraintes
    model.scalar(x, w, "<=", W).post();
    model.scalar(x, v, ">=", V).post();

    //Résolution
    Solution solution = model.getSolver().findSolution();
    if(solution != null)
    {
        System.out.println(solution.toString());
    }

L’implémentation est terminée et l’exécution produit immédiatement une solution du problème.