• Aucun résultat trouvé

Équivalence observationnelle

Dans le document Typage et contrôle de la mobilité (Page 32-38)

Modéliser une application dans un formalisme donné prend tout son sens lorsqu’on peut retirer du modèle une meilleure compréhension de l’application. Une des façons de mieux la comprendre, celle à laquelle nous allons particulière- ment nous attacher dans cette thèse, est de pouvoir utiliser une notion précise d’équivalence existant dans le formalisme. Cette équivalence peut alors servir à vérifier l’adéquation entre l’application et sa spécification, lorsque toutes deux sont exprimées dans le formalisme. La littérature traitant de cette approche est riche, par exemple [LM87], [Par87], [Wal89] ou encore [BH00]. Bien entendu, pour qu’une telle approche du problème de vérification soit fructueuse, il faut que la spécification soit exprimée de façon suffisamment simple, même lorsque la modélisation de l’application proprement dite est bien plus difficile à appréhen- der. L’équivalence qui sera utile devra donc discerner subtilement les aspects des modèles qui doivent être distingués de ceux qui peuvent sans risques être confondus.

Par ailleurs il est très facile de définir une multitude d’équivalences totalement ou subtilement distinctes les unes des autres. Pour qu’une équivalence ne soit pas purement arbitraire, il est essentiel de bien justifier ses différents aspects, les choix qui mènent à sa définition particulière. C’est pourquoi les choix qui régissent la définition que nous allons voir sont façonnés par leurs intuitions.

Notre équivalence sera donc observationnelle. Cela signifie que le critère retenu pour affirmer que deux systèmes sont non-équivalents sera la possibilité pour un observateur de faire la différence entre ces deux systèmes. En effet, si en interagissant avec l’un ou l’autre de ces deux systèmes, tout se déroule exactement de la même manière, on devrait pouvoir remplacer l’un par l’autre. L’intuition qui suggère ce choix repose sur la simple idée qu’il importe peu à l’utilisateur d’un serveur de savoir comment sont effectués les calculs si le comportement qu’il constate est identique. Cette intuition est très proche de la notion d’égalité extensionnelle pour les fonctions mathématiques : quelle que soit la formule précise utilisée pour le calcul, on les prend pour égales dès qu’on ne peut les différencier en observant leur valeur en un point donné. Les systèmes seront donc considérés comme des boîtes noires, l’observateur devra se contenter d’interagir avec elles pour les différencier.

Forts de cette intuition, il nous faut maintenant décrire les principes qui régissent l’observation :

1. il pourra voir si la boîte noire peut émettre un message sur un canal libre car, lors d’une telle émission, le système interroge en quelque sorte son environnement, en particulier l’observateur de la boîte noire, pour savoir s’il accepte de communiquer avec lui sur ce canal ;

2. il pourra placer la boîte noire dans un plus grand système de son choix et observer le résultat ;

3. par contre, il ne pourra pas distinguer si la boîte noire effectue des calculs, dans la mesure où cela relève de la façon particulière dont le système implémente ses fonctionnalités, c’est-à-dire les interactions qu’il peut enga- ger avec son environnement ; pour poursuivre la métaphore des fonctions mathématiques, on cherchera à confondre les fonctions x 7→ 0 et x 7→ x!−x!. Formalisons la notion d’équivalence qui découle de ces droits et contraintes. Pour le droit numéro 1, nous appellerons barbe un tel message.

Définition 1.9 (Barbe). Le système M exhibe une barbe sur le canal a dans la

localité l si et seulement s’il existe un processus P et un système M0 tels que

M =⇒≡ (new ~n : ~E)(M0| lJa ! hV i P K)

avec a, l 6∈ ~n.

On notera l’exhibition d’une telle barbe M ⇓ a@l.

Cette définition d’une barbe découle tout simplement du fait qu’un système pouvant émettre un message doit être de la forme

(new ~n(1) : ~E(1))(M(1)| (new ~n(2): ~E(2))(M(2)| . . . lJa ! hV i P K . . . | N(2)) | N(1)) ce qui est structurellement équivalent à un système de la forme bien plus simple

(new ~n : ~E)(M0| lJa ! hV i P K)

Quant au fait que l’on autorise au passage un nombre arbitraire de réductions avant que ne soit atteint cet état du système, cela retranscrit la contrainte numéro 3 qui empêche l’observateur de comptabiliser les réductions du système observé.

Le droit numéro 1 peut alors s’exprimer comme une contrainte sur les systèmes qu’une équivalence peut mettre en relation.

Définition 1.10 (Respect des barbes9). On dit qu’une relation R respecte les

barbes quand M R N implique que, quels que soient a et l, M ⇓ a@l si et

seulement si N ⇓ a@l.

Le droit numéro 2 que nous accordons à l’observateur implique que la relation d’équivalence que nous cherchons doit être contextuelle, puisque placer un système dans un autre plus grand, c’est le placer dans un contexte.

Enfin, la contrainte numéro 3 se formalise également facilement sous la forme d’une propriété de la relation d’équivalence.

Définition 1.11 (Fermeture par réduction). On dit qu’une relation R est fermée

par réduction quand M R N implique que pour toute réduction M −→ M0 il existe une réduction faible N =⇒ N0 telle que M0 R N0.

9Et des barbus

Nous avons maintenant tous les outils pour définir la relation d’équivalence décrite informellement.

Définition 1.12 (Congruence barbue fermée par réduction). La congruence

barbue fermée par réduction est la plus grande relation symétrique contextuelle,

fermée par réduction et qui respecte les barbes. On la note ∼=br.

Bien entendu, la première propriété intéressante à propos de cette relation est le fait qu’il s’agit bien d’une relation d’équivalence, comme promis. ∼=br est définie comme la plus grande relation vérifiant ses hypothèses de définition, elle contient donc toutes les autres relations qui vérifient ces mêmes hypothèses. Il suffira ainsi, pour démontrer qu’une relation est contenue dans ∼=br, de prouver qu’elle vérifie ses hypothèses de définition.

Proposition 1.13. La congruence barbue fermée par réduction est une relation

d’équivalence.

Démonstration. Il suffit pour cela de montrer que cette relation doit être réflexive

et transitive car on sait déjà qu’elle est symétrique.

Pour prouver qu’elle est réflexive, il suffit de voir que la relation identité, c’est-à-dire contenant tous les couples (M, M ) pour tout système M , vérifie les hypothèses de définition de ∼=br.

Pour prouver sa transitivité, on peut constater assez facilement que la com- position de ∼=br avec elle-même, c’est-à-dire ∼=br ◦ ∼=br, vérifie toujours ses hypothèses de définition. En effet, si (M1, M3) est un couple de ∼=br◦ ∼=br, il doit exister M2 tel que M1∼=brM2 et M2∼=brM3. Par symétrie de ∼=br, on obtient M3 ∼=br M2 et M2 ∼=br M1 soit (M3, M1) ∈ (∼=br ◦ ∼=br). Le raisonnement est identique pour la contextualité et le respect des barbes. Pour la fermeture par réduction, M1−→ M10 implique que M2=⇒ M20, c’est-à-dire M2−→nM20. Une simple induction sur n donne M3=⇒n M30, ce qui achève la preuve.

Armés de cette équivalence et étant donnés deux systèmes, nous voudrions maintenant pouvoir prouver qu’ils sont équivalents ou qu’ils ne le sont pas. La preuve que nous venons de voir illustre une méthodologie pour prouver qu’un couple de systèmes est dans ∼=br : on choisit une « bonne » relation contenant le couple, on prouve que cette relation vérifie les hypothèses de définition de ∼=br et on en déduit que cette relation, en particulier le couple de systèmes auquel on s’intéresse, est inclus dans ∼=br.

Exemple 1.14. Considérons un exemple d’équivalents, en omettant les annota-

tions de types qui ne sont pas encore expliquées et ne jouent de toute façon aucun rôle pour la congruence ∼=br. Nous allons voir comment se passerait la preuve que le système M = (new a) lJa ! hiK | lJa ? ()K est équivalent au simple système 0. En procédant suivant la méthode que nous venons d’esquisser, il faut exhiber une relation contenant (M, 0) et vérifiant les caractéristiques de ∼=br. Essayons de construire cette relation R en partant de ce simple couple. Pour rendre R symé- trique, rajoutons simplement (0, M ). Pour tous les éléments que nous rajouterons dans la relation par la suite, nous veillerons à toujours y rajouter également le symétrique. Comme M et 0 n’exhibent pas la moindre barbe ni l’un ni l’autre, il n’y a pas d’effort particulier à faire pour cela. Pour fermer notre relation par réduction, la tâche est encore assez facile car les seules réductions pouvant se faire sont celles menant M à M0= (new a) lJstopK | lJstopK et aux systèmes qui lui sont

structurellement congrus, par exemple ((new a) lJstopK) | lJstopK. Il nous suffit donc de rajouter à R les couples (M0, 0) et (0, M0) et les couples correspondant pour les autres systèmes structurellement congrus à M0. Malheureusement, il faut encore prendre en compte la contextualité, donc passer de notre petite relation à la relation constituée des couples (C[M1], C[M2]) où (M1, M2) est dans notre relation et C est un contexte quelconque. Il nous faut maintenant vérifier que cette relation R vérifie toujours les autres propriétés. Elle est bien sûr toujours symétrique et elle respecte toujours les barbes. Celles-ci sont en effet toujours dues au contexte qui est identique pour les deux composantes de chaque paire, puisque nos deux systèmes initiaux n’en exhibaient aucune. Par contre, la preuve que, lorsque C[M1] effectue une étape de calcul, le résultat doit forcément être structurellement équivalent à un C0[M10] où M10 est l’un des trois M , M0 ou 0, est bien plus technique. La preuve que R est effectivement fermée par réduction découle alors de l’imitation de cette réduction par une réduction C[M2] =⇒ C0[M20] où (M10, M20) est l’un des quatre couples (M, 0), (0, M ), (M0, 0) ou (0, M0). Alors seulement nous pouvons déduire que R est incluse dans ∼=br.

Bien que nous ayons maintenant une notion d’équivalence sur les systèmes, le petit exemple de preuve que nous venons d’esquisser montre à quel point l’équivalence est dure à prouver même dans un cas très simple. Quand nous introduirons dans la suite des variantes typées de cette congruence, nous verrons une formulation alternative de l’équivalence plus adaptée aux preuves et plus propice à comprendre les raisons en cas de non-équivalence.

Typage

2.1

Misère du calcul sans type

Voyons sur des exemples quelques problèmes que le typage permettra de traiter.

La sémantique du Dπ-calcul définie au chapitre précédent affirme que le système

lJa ! hV i P K | lJa ? (X : T) QK peut se réduire, en une étape de calcul, au système

lJP K | lJQ{V/X} K

où la valeur V et le motif X ne sont pas spécifiés avec précision. Par ailleurs, nous avons vu comment définir cette substitution {V/X} en la décomposant en une suite de substitutions élémentaires. Mais cette substitution n’est définie que lorsque X et V partagent la même structure arborescente. Dans le cas contraire, on aboutit à une expression de la forme

lJa ! h(b, c)i P K | lJa ? ((x, y, z) : T) QK

qui n’a guère de signification intuitive. De plus, la sémantique ne permet pas de l’interpréter. Nous chercherons alors à assurer que toutes les utilisations d’un canal de communication mettent en jeu des messages de même structure.

D’autre part on peut très facilement construire un système tout aussi problé- matique pour une raison plus subtile. Considérons donc le système

kJc ? () P K | lJa ! hk, ciK | lJa ? ((x, y) : T) goto y. x ! hiK

où le deuxième processus avertit le troisième que le canal sur lequel il doit émettre un message est le canal c dans la localité k. Mais, tous les noms du calcul étant confondus, cette information est interprétée par le troisième processus comme étant le canal k dans la localité c. En effet la syntaxe ne différencie pas les localités des canaux. Qui plus est, elle ne permet pas d’indiquer que le canal c est situé dans la localité k et non ailleurs car, comme nous l’avons déjà signalé, un canal n’existe que dans une localité précise. Nous nous efforcerons donc de différencier les localités des canaux et de fournir un moyen de spécifier dans quelle localité est disponible quel canal.

Bien entendu, les deux problèmes précédents sont moins évidents à détecter quand les communications ont lieu sur des canaux dont les noms ont été reçus dynamiquement. Par exemple le système

lJd ! hai e ! haiK | lJd ? (x1) x1! h(b, c)i PK | lJe ? (x2) x2? ((y1, y2, y3) : T) QK laisse apparaître après deux communications, sur les canaux d et d0, le problème des tailles différentes de message sur le canal a. Alors que les deux exemples précédents pouvaient laisser envisager une solution très simple qui associerait à chaque nom soit le statut de localité soit celui de canal apte à transmettre des messages d’une taille donnée, cet exemple illustre le fait qu’il faille également, dans le cas des canaux, indiquer entièrement le statut qu’ont les données qui y transitent.

Ces problèmes rappellent fortement ceux d’un langage de programmation : un nombre incorrect d’arguments lors d’un appel de fonction, une chaîne de caractères confondue avec un entier ou encore l’utilisation de fonctions d’ordre supérieur. Une approche souvent suivie pour leur apporter une solution, au moins pour les cas les plus simples, est de rajouter du typage au langage. Nous allons aussi suivre cette voie en associant à chaque nom et chaque variable un

type, c’est-à-dire une information indiquant si l’identifiant est une localité ou un

canal et, si c’est un canal, les types des valeurs pouvant y être échangées. Cette association permettra de vérifier qu’un processus ou un système utilise toujours ses noms et variables de façon légitime, dans des circonstances conformes au type associé. De plus, cette vérification pourra être effectuée par une analyse statique, c’est-à-dire avant l’exécution du système ; ainsi elle n’entravera pas son exécution tout en garantissant qu’aucune erreur ne sera commise au cours du calcul.

Deux autres exemples dicteront des choix importants quant aux types effective- ment introduits par la suite. Tout d’abord, revenons sur le processus-prospecteur présenté à la section 1.1.

l J (

rec Z : R (xval, xvois) .

xval? (x : T)

if x = or

then here (y) goto campement. locOr ! hyi else xvois? ((y, X) : T0) goto y. Z hXi

) hval, voisi K

Considérons le type que l’on pourrait associer à la variable xvois. Sur ce canal,

on attend un couple composé d’une localité (y) et des arguments nécessaires à l’appel récursif (X). Or les arguments de l’appel récursif sont les deux canaux xval

et, surtout, xvoislui-même, comme l’indique la déclaration du processus récursif.

Suivant les conclusions auxquelles nous étions arrivés quant aux informations que doivent véhiculer les types, le type du canal xvois devrait donc mentionner son

propre type. C’est pourquoi nous utiliserons des types récursifs, fort utiles pour parler de processus récursifs aussi bien que d’autres comportements infinis décrits en utilisant la réplication, l’autre construction fournie par le calcul autorisant la répétition.

Enfin, le dernier aspect important du typage permettra de contrôler l’usage qui est fait des ressources. Imaginons par exemple un serveur de calcul, exprimé par un processus répliqué de la forme

lJ∗req ? (X : T) P K

autorisant d’autres processus à lui envoyer des requêtes. La mise en place d’un tel service suppose la création de ce processus répliqué ainsi que la diffusion du nom du canal req sur lequel lancer les requêtes. Cela pourrait par exemple prendre la forme suivante :

lJ∗req ? (X : T) P | ∗nouv-service ! hreqiK

La définition même du service suppose que tous les clients qui recevront ainsi le canal req n’utiliseront que le droit d’y émettre des messages. Mais il est possible d’envisager un processus-usurpateur

lJnouv-service ? (y : T0) y ? (X : T) P0K

qui reçoit le nom du canal servant à émettre des requêtes et en détourne une, en remplaçant le comportement du service par P0. Nous pourrons empêcher ce détournement en distinguant les capacités d’émission et de réception sur les canaux et en ne transmettant que la capacité d’émettre sur le canal req lorsque le nom est diffusé sur le canal nouv-service.

Dans le document Typage et contrôle de la mobilité (Page 32-38)