Planification avec PSC (Partie 1)

Exercice 1 : Modélisation sur papier

Il existe souvent différentes façons de modéliser un problème de planification donné sous la forme d’un Problème de Satisfaction de Contraintes. Le modèle que nous vous proposons ici correspond à celui qui est décrit dans le chapitre 10.6 du cours. Si vous avez développé une solution différente, il est cependant possible qu’elle soit tout aussi valide.

Si vous pensez avoir réussi à élaborer un modèle PSC différent et qui vous semble tout aussi valide, nous vous invitons à en discuter avec un(e) assistant(e) pendant la séance d’exercices.

Définition du problème de planification

Rappelons qu’un problème de planification est défini par les éléments suivants :

  • Une liste de propositions qui décrivent l’état du monde.
  • Une liste d’opérateurs qui décrivent les actions qui peuvent être exécutées pour changer l’état du monde. Chaque opérateur possède des préconditions et des postconditions.
  • Des conditions initiales, qui décrivent complètement l’état initial du monde en termes de propositions.
  • Des conditions finales, qui décrivent complètement ou partiellement l’état du monde désiré en termes de propositions.
  • Des mutex, qui stipulent des contraintes d’exclusion mutuelle entre les propositions et entre les opérateurs. Les mutex de propositions sont des paires de propositions qui ne peuvent être vraies en même temps. Par exemple, un missionnaire ne peut pas simultanément se trouver sur la rive gauche et sur la rive droite. Les mutex d’opérateurs définissent les paires d’opérateurs qui ne peuvent être exécutés en même temps. Par exemple, un même bateau ne peut pas être piloté à la fois par le missionnaire M_{1} pour transporter le canibale C_{1} et par M_{2} pour transporter C_{2}.

Dans notre problème de planification, nous considérons trois types d’acteurs :

  • Les bateaux, qui correspondent au type B. Dans notre exemple, il n’y a qu’un seul bateau, dénoté par B.
  • Les missionnaires, qui correspondent au type M. Il y a deux missionnaires, M_{1} et M_{2}.
  • Les cannibales, qui correspondent au type C. Il y a deux cannibales, C_{1} et C_{2}.

Le choix des propositions du problème de planification doit permettre de décrire complètement la position de chaque acteur.

Notre problème présente aussi deux types d’actions possibles :

  • Traversée du fleuve depuis la rive gauche jusqu’à la rive droite ;
  • Traversée du fleuve depuis la rive droite jusqu’à la rive gauche.

Chacun de ces deux types d’actions peut faire intervenir un certain nombre d’acteurs. Par exemple, une traversée ne peut avoir lieu qu’à l’aide d’un bateau (c’est-à-dire un acteur de type B). Seul un missionnaire (c’est-à-dire un acteur de type M) peut conduire le bateau. Le bateau ne peut contenir qu’un passager supplémentaire, qui peut être indifféremment de type M (un missionnaire) ou de type C (un cannibale). La liste des opérateurs du problème de planification doit couvrir toutes les combinaisons d’acteurs pour les deux types d’actions.

Choix des propositions du problème de planification

Afin de décrire la position d’un acteur, nous vous proposons d’utiliser deux propositions, correspondant aux deux positions possibles de l’acteur (rive gauche ou rive droite). Pour un acteur A donné, nous introduisons donc les deux propositions suivantes :

  • g(A) est vraie si et seulement si l’acteur A est sur la rive gauche ;
  • d(A) est vraie si et seulement si l’acteur A est sur la rive droite.

Ces deux propositions peuvent vous sembler redondantes, puisque A est nécessairement sur la rive droite s’il n’est pas sur la rive gauche (d(A) est vraie si g(A) est fausse et vice-versa). Nous avons cependant choisi cette représentation car elle se généralise aisément à des problèmes plus compliqués, dans lesquels un acteur peut occuper plus de deux positions.

Choix des opérateurs du problème de planification

Comme nous l’avons indiqué plus haut, des opérateurs seront nécessaires pour modéliser la traversée du fleuve par des groupes d’acteurs. Pour un état donné, les opérateurs seront les suivants :

  • gd(B, M, A) est l’opérateur décrivant la traversée du fleuve de gauche à droite, à bord du bateau B, piloté par le missionnaire M, avec pour passager A (qui peut par ailleurs être de type M ou C). Les préconditions de cet opérateur sont que les propositions g(B), g(M) et g(A) doivent être vraies. Les postconditions sont que les propositions d(B), d(M) et d(A) doivent être vraies.
  • dg(B, M) est l’opérateur décrivant la traversée de droite à gauche du missionnaire M à bord du bateau B. Les préconditions de cet opérateur sont que les propositions d(B) et d(M) doivent être vraies. Les postconditions sont que les propositions g(B) et g(M) doivent être vraies.

Le choix a été fait dans ce modèle de ne pas tenir compte de la possibilité pour un bateau de faire la traversée de droite à gauche avec un passager en plus du pilote. Ce choix limite l’éventail des plans valides possibles. Il a l’avantage de correspondre à un problème de planification plus petit, plus facile à résoudre, et qui générera des plans plus courts (puisqu’il n’est alors pas permis de perdre du temps à faire traverser un cannibale dans un sens, puis dans l’autre sens). Dans cet exercice, sachant que les deux cannibales sont sur la rive gauche dans l’état initial, il est très facile de constater qu’il existe un plan valide qui ne fait jamais traverser un cannibale de la rive droite à la rive gauche. Il faut cependant se rappeler, que, dans le cas d’un problème plus général, un tel choix de modélisation pourrait déboucher sur un problème de planification infaisable, quand bien même le problème initial serait soluble.

Conditions initiales du problème de planification

Au début, tous les acteurs sont sur la rive gauche. Les conditions initiales sont donc les suivantes :

g(B) = g(M_1) = g(M_2) = g(C_1) = g(C_2) = True

Conditions finales du problème de planification

Le but est de faire passer tous les acteurs du côté droit de la rivière. Les conditions finales sont donc les suivantes :

d(B) = d(M_1) = d(M_2) = d(C_1) = d(C_2) = True

Mutex de propositions du problème de planification

Les mutex de propositions sont des paires de propositions qui ne peuvent être vraies en même temps. Dans notre problème, pour chaque acteur A, nous avons le mutex suivant :

[g(A), d(A)]

En effet, un acteur ne peut se trouver en même temps sur la rive gauche et sur la rive droite.

Mutex d’opérateurs du problème de planification

Les mutex d’opérateurs sont des paires d’opérateurs qui ne peuvent être exécutés en même temps. Dans notre problème, pour chaque paire d’opérateurs distincts op_1 et op_2, si les deux opérateurs ont un acteur en commun (qu’il soit de type B, M ou C), alors on a le mutex suivant :

[op_1, op_2]

Dans le cas où l’acteur en commun est de type B, ce mutex traduit le fait qu’un même bateau ne peut pas contenir deux équipages différents en même temps. Dans le cas où l’acteur en commun est de type M ou C, et si l’on a plusieurs bateaux à disposition, un même missionnaire ou un même cannibale ne peut se trouver sur deux bateaux différents en même temps.

Définition d’un PSC correspondant

Rappelons qu’un plan non linéaire est constitué d’une séquence d’états S_{0}, S_{1}, ..., S_{n}, chaque état S_{i} étant décrit par des propositions qui sont vraies ou fausses au début de l’état, un ensemble d’opérateurs qui sont exécutés pendant cet état, et des propositions qui sont vraies ou fausses à la fin de l’état (après l’exécution des opérateurs), et qui correspondent aux propositions du début de l’état suivant.

Un opérateur est caractérisé par des préconditions, c’est-à-dire des propositions qui doivent être vraies au début de l’état S_{i} pour que l’opérateur puisse être exécuté durant S_{i}, et des postconditions, c’est-à-dire des propositions qui devront être vraies au début de l’état S_{i+1}.

Choix des variables PSC pour les propositions

Pour chaque état S_{i}, avec i = 0...n+1, et chaque acteur A, le PSC contiendra les variables booléennes suivantes, qui correspondent aux propositions du problème de planification introduites plus haut :

  • g(A, S_{i}) = True si et seulement si l’acteur A est sur la rive gauche à la fin de l’état S_{i-1} et au début de l’état S_{i} ;
  • d(A, S_{i}) = True si et seulement si l’acteur A est sur la rive droite à la fin de l’état S_{i-1} et au début de l’état S_{i}.

Choix des variables PSC pour les opérateurs

Pour chaque état S_{i}, avec i = 0...n, et chaque opérateur op (par exemple, dg(B, M_{1})), le PSC contiendra la variable booléenne op(S_{i}), qui indiquera si oui ou non l’opérateur est exécuté dans l’état S_{i}.

Expression des contraintes du PSC

Il existe six types de contraintes qui doivent être vérifiées pour qu’un plan soit valide :

  • Les contraintes sur l’état initial ;
  • Les contraintes sur l’état final ;
  • Les préconditions et les postconditions des opérateurs ;
  • Les axiomes de cadre ;
  • Les mutex de propositions ;
  • Les mutex d’opérateurs.

Contraintes PSC correspondant aux contraintes sur l’état initial Tous les acteurs sont initialement sur la rive gauche. Par conséquent, les contraintes sur l’état initial prennent une forme très simple, qui est la suivante :

g(B, S_0) = g(M_1, S_0) = g(M_2, S_0) = g(C_1, S_0) = g(C_2, S_0) = True

Contraintes PSC correspondant aux contraintes sur l’état final Les contraintes sur l’état final sont comparables aux contraintes sur l’état initial, à la différence fondamentale près qu’il faut définir lequel des états S_{0}, S_{1}, ..., S_{n} correspond à cet état final. En d’autres termes, il faut choisir par avance la longueur des plans solutions que l’on veut considérer, c’est-à-dire le nombre total d’états.

Si l’on ne considère que des plans très courts, il est possible que l’on n’obtienne aucune solution, car il peut n’exister aucun plan qui parvienne à passer de l’état initial à l’état final avec si peu d’états intermédiaires. Si en revanche on autorise des plans très longs, la taille du PSC et la complexité de sa résolution explosent. Traditionnellement, on commence donc par des plans courts, et on augmente progressivement leur taille tant qu’aucune solution n’est découverte.

Dans notre cas, le problème se résout très facilement à la main. On peut donc tricher et choisir le nombre d’états en sachant qu’il existe un plan solution qui le contient. Les étapes suivantes constituent ainsi une solution possible, sachant que le but à atteindre est d’avoir tous les acteurs sur la rive droite :

  • gd(B, M_{1}, C_{1})
  • dg(B, M_{1})
  • gd(B, M_{1}, C_{2})
  • dg(B, M_{1})
  • gd(B, M_{1}, M_{2}).

Il suffit donc de cinq étapes, soit cinq états (sans compter l’état initial S_{0}) pour obtenir l’état final désiré. On choisira donc S_{5} comme état final. Les contraintes sur l’état final sont par conséquent les suivantes :

d(B, S_5) = d(M_1, S_5) = d(M_2, S_5) = d(C_1, S_5) = d(C_2, S_5) = True

Contraintes PSC correspondant aux contraintes de préconditions et de postconditions des opérateurs Reprenons les deux types d’opérateurs introduits précédemment et explicitons leurs préconditions et postconditions en termes de variables du PSC :

  • L’opérateur gd(B, M, A) a pour préconditions que g(B), g(M) et g(A) doivent toutes être vraies. Les postconditions stipulent que d(B), d(M) et d(A) doivent toutes être vraies.
  • L’opérateur dg(B, M) a pour préconditions que d(B) et d(M) doivent être vraies. Les postconditions stipulent que g(B) et g(M) doivent être vraies.

On n’a pas mentionné ici les suppressions de chaque opérateur. Par exemple, une autre postcondition de dg(B, M) est que d(B) doit être fausse. Il n’est cependant pas nécessaire d’expliciter ces postconditions négatives, car elles seront automatiquement imposées par les mutex de propositions introduits précédemment et présentés en détail plus bas.

En termes de PSC, ces préconditions et postconditions prennent la forme des contraintes suivantes sur les variables du PSC, pour chaque état S_{i} avec i = 0...n et chaque opérateur op :

  • Pour chaque proposition prop qui est une postcondition de l’opérateur op, on a : op(S_{i}) \Rightarrow prop(S_{i+1}) ;
  • Pour chaque proposition prop qui est une précondition de l’opérateur op, on a : op(S_{i}) \Rightarrow prop(S_{i}).

On utilise ici la notation \Rightarrow pour indiquer l’implication logique. Ainsi, si prop est une postcondition de l’opérateur op, alors op(S_{i}) \Rightarrow prop(S_{i+1}) est équivalent à si op(S_{i}) = True, alors prop(S_{i+1}) = True. Ceci traduit bien le fait que si l’opérateur op est exécuté dans l’état S_{i}, alors sa postcondition prop doit être vraie à la fin de l’état S_{i}, c’est-à-dire au début de l’état S_{i+1}.

Contraintes PSC correspondant aux axiomes de cadre Les axiomes de cadre stipulent que si aucun opérateur ne vient, dans l’état S_{i}, modifier une proposition prop, alors elle reste identique à l’état S_{i+1}. De manière équivalente : si la valeur d’une proposition change d’un état S_{i} à l’état suivant S_{i+1}, c’est que l’opérateur op(S_{i}) y est pour quelque chose. Par exemple, si g(C_{1}, S_{i}) = True et g(C_{1}, S_{i+1}) = False, alors op(S_{i}) est nécessairement l’un des deux opérateurs suivants : gd(B, M_{1}, C_{1}) ou gd(B, M_{2}, C_{1}).

Remarquez que cette contrainte est de formulation relativement complexe, et en particulier qu’elle implique plus de deux variables : prop(S_{i}), prop(S_{i+1}), et les variables pour l’état S_{i} de tous les opérateurs qui ont prop comme précondition ou postcondition. Plus précisément, les contraintes d’axiomes de cadre prennent les deux formes suivantes, pour chaque état S_{i}, et pour chaque proposition prop :

  • Si prop(S_{i}) = False et prop(S_{i+1}) = True, alors pour au moins un opérateur op qui a prop comme postcondition, on a op(S_{i}) = True ;
  • Si prop(S_{i}) = True et prop(S_{i+1}) = False, alors pour au moins un opérateur op qui a prop comme postcondition négative, on a op(S_{i}) = True.

Comme indiqué précédemment, il n’est pas nécessaire de considérer le deuxième cas, qui comporte une postcondition négative. En effet, si nous prenons l’exemple de la proposition d(M_{1}), lorsque celle-ci passe de True à False, il n’est pas nécessaire de vérifier que l’opérateur dg(M_{1}) est exécuté, puisqu’alors les contraintes de mutex de propositions imposeront que g(M_{1}) passe (à l’inverse) de False à True. Le premier cas ci-dessus suffit alors pour assurer que dg(M_{1}) soit exécuté.

Rappelons que ces contraintes ne sont pas simplement unaires ou binaires, mais qu’elles ont une multiplicité plus grande que deux. Il faut donc aussi modifier le module PSC pour qu’il puisse manipuler de telles contraintes.

Contraintes PSC correspondant aux mutex de propositions Les mutex de propositions sont des contraintes qui stipulent que deux propositions sont mutuellement exclusives, c’est-à-dire qu’elles sont incompatibles et ne peuvent pas être vraies en même temps. Par exemple, on ne peut pas avoir g(M_{1}) et d(M_{1}) vraies en même temps, puisque le missionnaire M_{1} ne peut pas se trouver à la fois sur la rive droite et sur la rive gauche.

Plus généralement donc, pour chaque état S_{i}, et pour chaque acteur A (de n’importe quel type), le modèle PSC contiendra les contraintes suivantes :

g(A, S_i)\text{ NAND }d(A, S_i)

Cette contrainte autorise virtuellement qu’un acteur puisse n’être ni sur la rive gauche, si sur la rive droite (g(A, S_{i}) = d(A, S_{i}) = False). Mais, dans la pratique, cette situation ne pourra pas se produire. Ceci peut se démontrer par récurrence : Nous partons du principe que les contraintes sur l’état initial décrivent complètement la situation initiale. C’est-à-dire qu’au début de l’état 0, un acteur est nécessairement sur une rive donnée. Considérons maintenant l’état k, et supposons qu’un acteur se trouve sur la rive gauche (g(A) = True) au début de cet état (le raisonnement est tout aussi valide si l’on remplace gauche par droite et droite par gauche). Deux possibilités se présentent alors pour les opérateurs exécutés dans l’état k : 1) aucun opérateur n’a g(A) comme précondition, et alors les contraintes d’axiomes de cadre vont imposer que g(A) reste vraie à la fin de l’état ; 2) au moins un opérateur a g(A) comme précondition, et alors les contraintes de postconditions vont imposer que d(A) soit vraie à la fin de l’état. Dans les deux cas, la rive sur laquelle se trouve l’acteur à la fin de l’état est clairement définie.

Contraintes PSC correspondant aux mutex d’opérateurs De manière analogue aux mutex de propositions, chaque mutex d’opérateur [op_1, op_2] va donner lieu, pour chaque état S_{i}, à la contrainte suivante :

op_1(S_i)\text{ NAND }op_2(S_i)

Résumé du modèle PSC

Au bout du compte, voici le modèle que nous obtenons :

Variables :

  • Variables booléennes g(A, S_{i}), pour chaque acteur A et chaque état S_{i} ;
  • Variables booléennes d(A, S_{i}), pour chaque acteur A et chaque état S_{i} ;
  • Variables booléennes op(S_{i}), pour chaque opérateur op et chaque état S_{i}.

Contraintes :

  • Contraintes sur l’état initial :

g(B, S_0) = g(M_1, S_0) = g(M_2, S_0) = g(C_1, S_0) = g(C_2, S_0) = True

  • Contraintes sur l’état final :

d(B, S_5) = d(M_1, S_5) = d(M_2, S_5) = d(C_1, S_5) = d(C_2, S_5) = True

  • Contraintes de préconditions et postconditions des opérateurs, pour chaque état S_{i} et chaque opérateur op :

    • Pour chaque proposition prop qui est une postcondition de l’opérateur op : op(S_{i}) \Rightarrow prop(S_{i+1}).
    • Pour chaque proposition prop qui est une précondition de l’opérateur op : op(S_{i}) \Rightarrow prop(S_{i}).
  • Contraintes d’axiomes de cadre, pour chaque état S_{i} et chaque proposition prop :

    • Si prop(S_{i}) = False et prop(S_{i+1}) = True, alors pour au moins un opérateur op qui a prop comme postcondition, on a op(S_{i}) = True
  • Contraintes de mutex de propositions, pour chaque état S_{i} et pour chaque acteur A :

g(A, S_i)\text{ NAND }d(A, S_i)

  • Contraintes de mutex d’opérateurs, pour chaque état S_{i}, et pour chaque paire d’opérateurs distincts op_1 et op_2 qui ont un acteur en commun :

op_1(S_i)\text{ NAND }op_2(S_i)

Dans ce PSC, toutes les variables sont booléennes. Typiquement, plutôt qu’un algorithme PSC, on utiliserait un algorithme SAT pour résoudre ce genre de problèmes. Un algorithme SAT est en effet spécialisé dans la résolution de PSC exprimés sous la forme de clauses (des expressions qui peuvent être vraies ou fausses) ne comportant que des variables booléennes.