Extrait These Doctorat

383 vues

Publié le

0 commentaire
0 j’aime
Statistiques
Remarques
  • Soyez le premier à commenter

  • Soyez le premier à aimer ceci

Aucun téléchargement
Vues
Nombre de vues
383
Sur SlideShare
0
Issues des intégrations
0
Intégrations
15
Actions
Partages
0
Téléchargements
2
Commentaires
0
J’aime
0
Intégrations 0
Aucune incorporation

Aucune remarque pour cette diapositive

Extrait These Doctorat

  1. 1. ' THESE présentée à ,, L'ECOLE POLYTECHNIQUE pour obtenir le titre de DOCTEUR de l'ÉCOLE POLYTECHNIQUE en INFORMATIQUE par Olivier MALLET Interprétation Abstraite appliquée à la Compilation et la Parallélisation en Programmation Logique Soutenue le 29 Juin 1992 devant le jury composé de : Patrick COUSOT Maurice BRUYNOOGHE Pierre DERANSART Gilberto FILE Yves BEKKERS Serge BOURG AULT Président du jury Rapporteur Rapporteur Rapporteur Examinateur Examinateur
  2. 2. THESE DE DOCTORAT EN INFORMATIQUE DE L'ECOLE POLYTECHNIQUE soutenue le 29 Juin 1992, par Olivier Mallet Interprétation abstraite appliquée à la cornpilation et la parallélisation en progra1nrr1ation logique Résumé L'interprétation abstraite est une technique puissante d'analyse sémantique qui permet la détection de propriétés dynamiques. Elle repose sur la notion d'abstraction (ou approximation) qui rëmplace les éléments du domaine habituel - dit concret - par ceux du domaine abstrait. Nous présentons une sémantique déductive de Prolog, qui approche la sémantique opérationnelle standard et possède une propriété de compositionnalité gril.ce à l'utilisation de l'espace des termes quotienté par la relation de renommage et griice à une décomposition de l'opérateur d'unification en deux parties indépendantes. Puis nous proposons pour cette sémantique un interprète abstrait "générique", c'est-à-dire qui nécessite pour une analyse donnée un nombre très limité d'informations décrivant le domaine et les opérateurs abstraits. Cet interprète est implémenté en C, fonctionne avec précision et efficacité, et n'est pas restreint aux treillis abst.raits de hauteur finie. Nous utilisons ensuite cet outil pour détecter certaines familles de propriétés, et expliquons comment un compilateur ou un répartiteur de programmes Prolog peut tirer parti de telles informations. Optimizing Compilation and Parallel Scheduling of Logic Programs with Abstract Interpretation Abstract Abstract interpret.ation is a powerful technique for semantic analysis t.hat can discover run-time properties of programs. It relies upon the notion of an abstraction (or approximation) which substitute the elements of the concrete, i.e. standard, domain with those of the abstract domain. We propose a deductive semant.ics for Prolog which approximates the standard operational one and is compositional, thanks to the use of the quotient set of the terms space with respect to the variance relation and thanks to the splitting of unification into two independent parts. Then we build for this semantics a "generic" abstract interpreter, meaning it needs minimal amounts of information about the abstract domain and operators in order to cope with a new analysis. This interpreter is written in C, works accurately and efficiently, and can handle non finite-height lattices as abstract domains. We then put this too! to work with various types of properties and show how the computed results can help a Prolog compiler or parallel scheduler.
  3. 3. Table des matières INTRODUCTION 9 1 INTERPRETATION ABSTRAITE 13 1.1 Introduction . 13 1.1.1 Historique . 13 1.1.2 Pourquoi? . 13 1.1.3 Comment? 14 1.1.4 Pourquoi la programmation logique ? 17 1.2 Modélisation des programmes 18 1.3 Simplification des systèmes d'équations 21 1.3.1 Introduction . 21 1.3.2 Treillis complets . 22 1.3.3 Opérateurs sur un treillis . 22 1.3.4 Points fixes et théorème de Tarski 23 1.3.5 Fermetures sur un treillis complet 25 1.3.6 Connexion de Galois 26 1.3.7 Paire de fonctions adjointes supérieure 27 1.3.8 Approximation de points fixes d'un opérateur par approxi- mation de l'opérateur . 29 1.3.9 Amélioration d'une approximation 30 1.4 Accélération de la convergence . .. 31 1.4.1 Itération croissante approchée supérieurement 31 1.4.2 Itération croissante approchée inférieurement . 31 1.4.3 Application 31 1.4.4 Elargissement et rétrécissement 32 1.4.5 Solution approchée d'un système d'équations . 33 1.5 Exemples d'interprétations abstraites 34 1.5.1 La règle des signes 34 1.5.2 Les intervalles . 37 1.5.3 Les modulas . 38 1.5.4 Combinaison d'abstractions 39 2 APPLICATION A LA PROGRAMMATION LOGIQUE 41 2.1 Fondements de la Programmation Logique 41 2.1.l Notions classiques . 41
  4. 4. 6 TABLE DES MATIÈRES 2.1.2 Terminologie spécifique à l'interprétation abstraite . 48 2.2 Nouveaux espaces ............. . 2.2.1 L'espace de Herbrand étendu 2.2.2 Produit de deux n-uplets de termes 2.2.3 Le produit externe sur Un . 2.2.4 Produit et unification . . . . 2.3 Les diverses sémantiques de Prolog 2.3.l Semantique déclarative ... 2.3.2 La sémantique du point fixe 2.3.3 La sémantique de la résolution SLD 2.3.4 Autres sémantiques ........ . 2.3.5 Conclusion : choix de la sémantique . 2.4 Les travaux précédents . . . . 2.4.1 Mellish . . . . . . . . . 2.4.2 Jones and S!Z)ndergaard 2.4.3 Bruynooghe . . 2.4.4 Et les autres ... . . . . 2.5 Objectif ........... . 2.5.1 Un Interprète Abstrait Générique 2.5.2 Propriétés recherchées . . . . 2.5.3 Le compromis précision/coût . 2.6 Modèle simplifié . . . . . . . . . . . . 2.6.1 Introduction ......... . 2.6.2 Sémantique déductive concrète 2.6.3 Sémantique Abstraite . 2.6.4 Exemple des modes 2.7 Modèle récursif complet . . . 2. 7.1 Introduction . . . . . . 2.7.2 Les points de programme. 2.7.3 Les états mémoire. . . . . 2.7.4 Arbres résolus d'un programme 2.7.5 La sémantique collectionneuse . 2.7.6 2.7.7 2.7.8 2.7.9 2.7.10 2.7.11 2.7.12 Le système de la sémantique concrète . Lien entre les sémantiques déductive et collectionneuse L'abstraction ............ . La sémantique abstraite . . . . . . . . . . . Correction de la sémantique abstraite .... Abstraction par morphisme de substitutions Abstraction par morhisme de termes 2.7.13 La résolution . 2.7.14 Mise en oeuvre ........... . 2. 7.15 Reexécution ............. . 2.7.16 Réalisation de l'analyseur sémantique . 49 49 57 60 62 65 66 66 67 67 68 68 69 74 77 80 80 80 81 81 83 83 84 87 90 93 93 95 96 97 99 101 105 111 113 116 119 121 127 134 134 135
  5. 5. TABLE DES MA TIÈRES 3 APPLICATION A LA COMPILATION 3.1 Les Analyses ............ . 3.1.1 Les modes ......... . 3.1.2 Modes : deuxième approche 3.1.3 Typage ........... . 3.1.4 Couverture et partage . . . 3.1.5 Quotient par les constantes 3.1.6 Intervalles d'entiers . . .. . 3.2 Utilisation des Analyses ..... . 3.2.1 Optimisation de l'unification . 3.2.2 Suppression de vérifications dynamiques de types 3.2.3 La gestion de la mémoire . . . . 3.2.4 Suppression de points de choix . 3.2.5 Déverminage ......... . 4 APPLICATION A LA PARALLELISATION 4.1 Parallélisme et programmation logique 4.1.1 L'architecture ... 4.1.2 Modèle d'exécution .. 4.1.3 Le parallélisme 0 U . . 4.1.4 Le parallélisme d'appel 4.1.5 Parallélisme ET 7 137 138 138 143 147 154 168 171 175 175 178 179 181 183 185 186 186 188 189 191 192 4.2 Analyses . . . . . . . . . . . . 197 4.2.1 Typage récursif . . . . 197 4.2.2 Profondeur des termes 202 4.3 Utilisation des résultats . . . . 204 4.3.1 Identification des directions des streams 204 4.3.2 Calcul des CGE pour le parallélisme ET restreint 205 4.3.3 Groupage et allocation de ressources . . . . . . . 206 4.4 Conclusion sur l'interprétation Abstraite et le parallélisme 207 CONCLUSION 209 BIBLIOGRAPHIE 211 NOTATIONS 227 INDEX 231
  6. 6. INTRODUCTION L'analyse sémantique des programmes a pour objectif de découvrir certaines de leurs propriétés dynamiques, c'est-à-dire relatives à leur exécution. Lorsqu'une telle analyse est entièrement automatique et efficace, elle constitue un outil qui peut être intégré dans une chaîne de production de logiciel, et dont les appli- cations s'étendent de l'optimisation du code compilé jusqu'à la validation de programmes. L'interprétation abstraite est une technique d'analyse sémantique introduite par P. et R. Cousot dans [CC77]. Son principe de base est celui de l'approximation par abstraction : le programme est exécuté sur un domaine plus simple que le domaine standard, où les éléments sont regroupés selon certains critères. Bien sûr, l'exécution elle-même du programme - qu'on qualifie d'interprétation abstraite - doit être modifiée, d'une part pour prendre en compte ces regroupements, et d'autre part pour assurer sa terminaison. Cette approche constitue un bon compromis pratique entre les techniques de vérification systématique, généralement affligés de complexités pathologiques, et les techniques de démonstration de théorèmes qui restent malheureusement non automatisables. L'interprétation abstraite est appliquée depuis quelques années à l'optimi- sation de la compilation dans le domaine des langages procéduraux (surtout le célèbre FORTRAN). Le phénomène s'est emparé de la recherche en programma- tion logique vers 1986. A juste titre, en effet, puisque Prolog et ses nombreux cousins présentent deux caractéristiques qui en font les cibles idéales d'une ana- lyse sémantique : • Ce sont des langages déclaratifs, ce qui veut dire que le programmeur four- nit très peu de détails explicites concernant l'exécution. En particulier, il ne déclare pas les types de ses variables, il ne précise pas si un paramètre d'appel est utilisé en entrée ou en sortie (ou les deux), il ne spécifie pas quelles clauses peuvent être utilisées pour un appel donné. Ce déficit d'in- formation explicite fait que les meilleurs compilateurs Prolog ne permettent pas - et de loin - d'atteindre les performances des langages procéduraux pour des programmes simples. • La sémantique des programmes logiques est excessivement simple et régu- lière, ce qui en favorise naturellement l'analyse.
  7. 7. 10 INTRODUCTION L'optimisation de la compilation des programmes logiques est donc un pre- mier but que nous nous fixons. Le second est l'optimisation de leur parallélisation. En effet, les modèles d'exécution parallèle pour cette famille de langages ne man- quent pas, mais ne parviennent pas à des taux élevés de parallélisation sans l'aide d'annotations manuelles des programmes. Ces annotations, qui sont à nouveau le reflet des informations dissimulées par la sémantique très concise des langages logiques, peuvent être partiellement engendrées par un outil d'interprétation abs- traite, et ce sera notre second but. Depuis 1986, la recherche s'est structurée et l'on a vu apparaître la notion de cadre générique d'interprétation abstraite. Il s'agit d'une structure d'accueil qui s'instancie en un interprète abstrait capable de détecter une propriété donnée. Les renseignements nécessaires à cette instanciation sont les différents domaines et opérateurs abstraits, le mécanisme d'interprétation abstraite restant, lui, le même. Les cadres génériques existants présentent des qualités variables de faci- lité d'instanciation, d'adaptabilité (à une analyse), de précision des résultats et d'efficacité (dans leur exécution). Nous avons défini dans ce travail un cadre générique qui se démarque des pré- cédents à l'occasion de plusieurs choix fondamentaux (cf. ci-dessous), ce qui lui permet d'atteindre de bons niveaux dans ces quatre catégories de performances. La facilité d'instanciation est le fait du petit nombre d'opérateurs abstraits à fournir (2 ou 3, sans compter les prédicats prédéfinis). L'adaptabilité est démon- trée par la palette des analyses des chapitres 3 et 4 (en particulier, l'analyse des intervalles est une première). La précision des résultats est tout à fait comparable à celle des meilleurs approches actuelles. L'efficacité pratique de l'outil (écrit en C) lui permettrait d'être intégré sans aucun problème à la phase d'optimisation globale d'un compilateur. Plan Le Chapitre 1 rappelle brièvement les fondements théoriques de l'interprétation abstraite telle qu'elle a été définie dans [CC77], et tente de donner une compré- hension intuitive de la méthode. Le Chapitre 2 présente notre cadre générique. Après une première section destinée à rappeler les fondements de la programmation en logique et à en figer le vocabulaire, une deuxième section introduit l'espace de Herbrand étendu qui jouera un rôle important dans le cadre générique. L'idée est de quotienter l'espace des termes courants par la relation de renommage afin de disposer d'une forme canonique unique. De nombreuses propriétés de cet espace sont démontrées, et des opérateurs y sont définis et étudiés, - homologues des opérateurs standards d'application d'une substitution et d'unificateur le plus général-. Les sections 2.3, 2.4 et 2.5 préparent la définition du cadre générique en justifiant le choix primitif de la sémantique de la résolution SLD comme base de départ pour la sémantique concrète, puis en s'intéressant à quelques approches représentatives de l'état actuel de la recherche. La section 2.6 présente un modèle simplifié dont l'utilité pratique est très
  8. 8. INTRODUCTION 11 limitée et qui a pour but de mettre en évidence les écueils qui rendent impossible une approche trop directe du problème. Enfin, la section 2.7 contient la description complète de notre cadre générique, de la sémantique concrète - déductive - jusqu'à l'algorithme de résolution, et les consignes de mise en oeuvre pratique de l'outil associé. Les caractéristiques ori- ginales de notre approche comprennent en particulier le choix de l'espace quotient des n-uplets de termes comme domaine concret, l'utilisation d'une sémantique déductive compositionnelle favorisant la résolution du système sémantique ap- proché et la présence de plusieurs mécanismes d'élargissement dans l'algorithme de résolution afin d'en garantir la terminaison rapide. Le Chapitre 3 satisfait notre premier but : optimiser la compilation des pro- grammes Prolog (dans le cadre de la machine de Warren) grâce à notre outil. La section 3.1 décrit en détail la configuration du cadre générique pour quelques analyses plus ou moins classiques, et la section 3.2 explique comment utiliser les résultats de ces analyses pour obtenir des programmes cibles plus efficaces. Le Chapitre 4 remplit le même rôle que le précédent vis-à-vis de notre second but : la parallélisation des programmes logiques. Ici, l'hypothèse que nous faisons est celle d'une architecture parallèle de type hypercube, du langage Prolog pur, et d'un modèle d'exécution exploitant à la fois les parallélismes de type ET et OU. La section 4.1 décrit deux nouvelles analyses, et la section 4.2 montre com- ment leurs résultats peuvent optimiser et simplifier les algorithmes de répartition dynamique des calculs. La conclusion est suivie d'une importante bibliographie, d'une liste des nota- tions employées et d'un index des principaux termes spécifiques.
  9. 9. Chapitre 1 INTERPRETATION ABSTRAITE 1.1 Introduction 1.1.1 Historique L'interprétation abstraite est une technique relativement récente mais était déjà pratiquée sans bases formelles avant [CC77] sous diverses formes et multiples noms (entre autres évaluation partielle et propagation de contraintes). Des formes primitives (au sens chronologique) particulièrement célèbres en sont les méthodes de preuve de Hoare et de Floyd. A l'origine en effet, l'interpré- tation abstraite est un outil de preuve de programmes, c'est-à-dire un analyseur de programme qui vérifie statiquement que telle ou telle propriété dynamique concernant les valeurs des variables est vraie à tel point du programme au cours de toute exécution. On l'utilisait alors notamment pour prouver des variants et invariants de boucle ou autres assertions visant à déterminer correction et ter- minaison. Malheureusement l'absence de support mathématique formel ne per- mettait pas d'obtenir toute la souplesse et l'automatisation souhaitables. Une autre famille de méthodes de preuve s'oppose à la précédente. Il s'agit des méthodes de transformations de programmes, qui sont fermement établies sur la sémantique dénotationnelle des programmes, mais dont la lourdeur limite l'usage. Cousot [CC77] [Cou78] a donné un cadre mathématique solide à l'interpré- tation abstraite ainsi qu'un ensemble de techniques à appliquer dans ce cadre, qui ont permis à de nouvelles applications plus complexes de voir le jour dans le domaine des langages impératifs et même fonctionnels ([Str90]). 1.1.2 Pourquoi ? L'interprétation abstraite peut être utilisée soit comme un outil de preuve de programmes à part entière, soit comme un auxiliaire qui permet à d'autres outils informatiques - tels que compilateur, interprète, répartiteur de tâches dans le
  10. 10. 14 INTERPRETATION ABSTRAITE cas parallèle, - d'opérer plus efficacement grâce à une meilleure connaissance des conditions d'exécution, et ce pour un faible coût (fini) de traitement initial. Voici une liste non exhaustive d'applications (sans a pr.iori sur le langage) • preuves de programme : vérification d'invariants booléens du programme (ex.: correction) vérification de variance d'une expression entière (ex.: terminaison) • optimisation de code compilé : suppression de tests dynamiques (ex.: indices de tableaux) expressions redondantes ou constantes prétypage statique • meilleur contrôle : détection de parallélisme détection de branches mortes (code inutile) • renseignements divers : indications sur la forme des solutions estimations de complexité/ coût Certaines de ces propriétés n'auront guère d'intérêt dans l'environnement de la programmation logique (par exemple la détection d'expressions redondantes, étant donné le caractère généralement symbolique des données manipulées) et inversement des propriétés qui n'apparaissent pas ici y seront très fécondes. 1.1.3 Comment? L'interprétation abstraite consiste à exécuter au lieu du programme étudié une bonne approximation de ce programme, et à observer au cours de cette exécution dite abstraite des propriétés qu'on pourra alors transférer sur l'exécution réelle dite concrète. Le lien entre l'exécution réelle et l'exécution approchée est défini initialement par deux applications dites respectivement d'abstraction et de concrétisation qui font correspondre à un terme réel de l'exécution réelle (on dira du domaine concret) un terme approché ou abstrait de l'exécution approchée (du domaine abstrait) et réciproquement. Ce lien détermine ensuite la façon dont l'exécution abstraite va se dérouler. Idéalement, on aimerait que, à tout instant de l'exécution réelle, l'abstraction d'un terme réel soit égale au terme abstrait correspondant, au même point de contrôle de l'exécution abstraite. On se contentera de moins puisqu'on demandera simplement une relation d'infériorité ou de supériorité entre les deux.
  11. 11. INTERPRETATION ABSTRAITE 1 1 Exécution 1 J Sémantique concrète1--1 ~~~~~~~~~-- 1 solution concrète Approximation de la sémantique Approximation du domaine 15 Interprétation !Sémantique abstraite 1 1 r-~~~~~~~~~~1 1 Solution abstraite! abstraite Figure 1.1: Principe de l'interprétation abstraite : ce diagramme commute Plus formellement, on considère le programme comme un système dynamique discret, c'est-à-dire un automate à états finis déterministe (avec en plus la no- tion d'états erronés). Ce modèle s'applique aussi bien aux programmes parallèles qu'aux programmes séquentiels. Dans les langages classiques (impératifs et sé- quentiels), l'état est généralement un couple (contexte, position) où "contexte" encapsule l'ensemble des données dynamiques de l'interprète au point de pro- gramme repéré par "position". L'ensemble des transitions possibles est décrit par la sémantique opérationnelle du langage. Cette formulation permet de considé- rer la sémantique opérationnelle du programme comme un système d'équations, dont la solution est l'exécution concrète. Une fois munis d'une sémantique opérationnelle et de la notion d'états, il nous reste à définir les propriétés à vérifier. Ces propriétés ne font pas nécessairement partie du langage cible, autrement dit ne s'expriment pas toujours en tant que formule bien formée du langage. Ce sont de manière générale des prédicats sur l'ensemble des états (c'est-à-dire des applications de l'ensemble des états sur {vrai,faux}). Un premier exemple est celui du typage automatique dans les langages pos- sédant des systèmes de types mais n'obligeant pas le programmeur à declarer le type de chaque variable (Prolog, LISP, BASIC). Dans ce cas, soit Ex le prédicat qui à un couple (contexte, point de programme) associe le booléen : "dans ce contexte, la variable X est de type entier" qui est vrai si la variable X visible en ce point de programme représente un entier. Ce prédicat n'est pas une expression booléenne du langage, mais il constitue une propriété à laquelle on est en droit de s'intéresser. Autre exemple, les preuves de terminaison de boucles utilisent fréquemment un test de décroissance stricte d'une expression positive entière dite variante. Or cette notion de décroissance fait intervenir un couple (état précédent, état courant), ce qui n'est pas exprimable directement en général dans le langage de programmation (sauf si le programmeur a eu la prévenance de fournir une va- riable contenant la valeur précédente de la variante). Il faut alors faire intervenir
  12. 12. 16 Programme logique Système d'équations INTERPRETATION ABSTRAITE Exécution ,... - - - - - - - - - - - , ·····························>• Solution concrète Résolution : : .. : : 1: --~---- - .J : approche Solution concrète approchée Approximation Concrétisation Résolution Système d'équations approché Solution abstraite approchée Figure 1.2: Les étapes d'une interprétation abstraite dans le prédicat des entités définies au niveau de la sémantique opérationnelle du langage. La propriété de variance peut ainsi s'écrire : (E'x ~ 0) et (E'x - Ex < 0) où E et E' sont respectivement l'état précédent et l'état courant, x est l'ex- pression variante et Ex représente la valeur de l'expression variante x dans l'état E. Disposant du système d'équations représentant la sémantique opérationnelle concrète du programme et d'une propriété à vérifier, on doit trouver une version approchée (abstraite) de ce système, compatible avec la détection de cette pro- priété. Cette version doit être la plus simple possible afin que sa résolution soit aisée, mais l'approximation doit préserver autant que possible la propriété afin d'obtenir des résultats précis. Nous fournissons dans cette thèse des méthodes afin de franchir cette étape qui est souvent la plus aventureuse. La dernière étape est l' "interprétation abstraite" proprement dite : elle con- siste à résoudre le système approché par des méthodes itératives de convergence simple ou accélérée. Nous récapitulons ci-dessous la liste des choix à effectuer pour obtenir une interprétation abstraite : • le langage avec sa sémantique opérationnelle • la sémantique déductive équivalente basée sur des états
  13. 13. INTERPRETATION ABSTRAITE 17 • la propriété à détecter • l' "opérateur" de simplification adapté à cette propriété • la méthode de résolution du système approché Il est à noter que ces choix ne sont pas tous de même niveau. Si l'on établit un parallèle avec le cycle de vie d'un logiciel, on peut dire que certains relèvent du niveau spécification (langage et propriété), certains du niveau conception (séman- tique déductive et opérateur de simplification) et d'autres du niveau réalisation (méthode de résolution). Pour le présent mémoire, le premier choix seul est fixé : la programmation logique (il s'agit plutôt d'une famille de langages que d'un langage unique, mais une famille très homogène). La suite traite donc des choix restants qui pourront avoir chacun des réponses multiples. 1.1.4 Pourquoi la programmation logique ? Les langages de la programmation logique sont réputés pour leur concision. Cette concision tient à l'importance de l'aspect spécificatif (ou déclaratif) des pro- grammes par rapport à l'aspect impératif : on exprime ce qu'on doit obtenir, mais pas comment l'obtenir. Les informations dont dispose un compilateur ou tout autre outil manipulant un programme logique sont donc minimes en l'ab- sence d'analyseur sémantique, ce qui rend ces outils généralement peu perfor- mants par rapport à ceux qui travaillent dans des langages plus diserts. Cette particularité rend l'interprétation abstraite particulièrement attrayante pour la programmation logique. Nous exposerons aux chapitres 3 et 4 les nom- breuses propriétés inexprimées par les langages et dont la connaissance présente un intérêt pour le programmeur ou un outil tel que compilateur ou gestionnaire de parallélisme. Nous pouvons dès maintenant citer la liste suivante : 1. état d'instanciation des variables 2. partage de variables 3. typage des termes 4. parallélisabilité 5. évaluation de complexité qui sont orientés vers l'optimisation de l'unification (1,2,3), de la résolution (1,3) et de la répartition des tâches en environnement multi-processeurs (4,5). Idéalement, la prise en compte de ces propriétés par un compilateur-répartiteur "intelligent" pourrait permettre :
  14. 14. 18 INTERPRETATION ABSTRAITE • de faire disparaître le surcoût en temps d'exécution qu'induit habituelle- ment la programmation logique par rapport à des langages procéduraux plus directs comme C (qui est devenu la référence en matière de perfor- mance) ; • de conserver l'avantage, pour le concepteur, d'une programmation symbo- lique et déclarative ; • de fournir une implantation parallèle simple et efficace. Une telle évolution permettrait de reclasser la programmation logique comme une famille de langages tout à fait performants et en même temps possédant puissance et facilité d'expression, ce qui constitue un avantage indéniable en matière de génie logiciel. 1.2 Modélisation des programmes Le but de ce paragraphe est d'introduire un nouveau type de sémantique : la sémantique déductive (en avant ou en arrière), qui se prête particulièrement bien, de par son caractère très mathématique, aux approximations que nous désirons lui faire subir. A cette fin, on modélise les programmes informatiques comme des systèmes dynamiques discrets. Définition 1 un système dynamique discret est un quintuplet (S, r, Ve, V17 , vç) où • S est l'ensemble des états • r est une relation interne de S dite de transition • Ve est le sous-ensemble de S des états d'entrée • V17 est le sous-ensemble de S des états de sortie • vç est le sous-ensemble de S des états erronés et qui vérifie les conditions : 1. S est non vide 4. Vn v1,, vç sont deux à deux disjoints. Eclairons cette définition par quelques indications d'ordre intuitif: • les états dont il est question sont les couples (états de mémoire, point de programme) des programmes informatiques ;
  15. 15. INTERPRETATION ABSTRAITE 19 • la relation de transition lie les états précédant et suivant l'exécution d'une instruction élémer.taire quelconque. On parle d'état successeur direct d'un état e pour désigner les états e' tels que T(e, e'). Réciproquement les anté- cédents directs de e' sont les états e tels que T(e,'e') ; • la condition 2 dit que les états d'entrée sont inatteignables, c'est-à-dire qu'ils n'ont aucun antécédent, direct ou indirect ; • la condition 3 dit que les états de sortie sont stables (si on y est, alors on y reste). NB : dans le cas d'un programme déterministe, où chaque état a un successeur au plus, la relation de transition est une fonction. NB : un prédicat de S est un élément de S ---+ B ={vrai,faux} qui définit par l'image réciproque de {vrai} un sous-ensemble de S. Dans la suite, on considèrera indifféremment un prédicat comme une fonction ou comme l'ensemble ainsi défini. NB : pour plus de clarté, nous ne noterons pas l'application d'une fonction J à un élément x sous la forme normale du lambda-calcul (Jx), mais sous la forme fonctionnelle plus pratique J(x). Définition 2 Soient a, j3 E S2 ---+ B deux relations. Le produit de a par j3 est la relation notée a o j3 définie par : La notion de fermeture transitive réflexive d'une relation découle de manière classique de la définition du produit. Définition 3 Si j3 est un prédicat de S et T une relation de transition, on définit les deux prédicats de S suivants : wp(T)(j3) = Àe.{3e' ES, T(e, e') et /3(e')} est l'ensemble des ascendants directs des états qui satisfont /3, sp(T)(j3) = Àe.{3e' E S,T(e',e) et j3(e')} est l'ensemble des descendants directs des états qui satisfont /3. En fait on s'intéressera surtout à wp(T*) et sp(T*) où T'" est la fermeture réflexive et transitive de T, ce qui correspond à l'exécution d'un nombre quel- conque (voire nul) d'instructions élémentaires du programme. Voici une première caractérisation de T* : Théorème 1 Soient T E S2 ---+ B une relation de transition et eq la relation d'égalité sur S, alors : T* = lfp (Àa.[eq ou a o T]) = lfp (Àa.[eq ou T o a])
  16. 16. 20 INTERPRETATION ABSTRAITE Ce théorème exprime que la fermeture réflexive et transitive d'une relation r est la plus petite relation dont le graphe vérifie les deux conditions suivantes : - être stable par une composition par T (à gauche ou à droite), - contenir le graphe de la transition nulle (relation eq). La première condition correspond à la transitivité et la seconde à la réflexivité de la fermeture. On a ensuite une proposition démontrant la dualité entre les ensembles sp et wp d'une part, et les relations de transition T et r-1 d'autre part : Proposition 1 Pour toute relation de transition T d'inverse r-1 (définie comme À(e1 , e2 ).r(e2 , e1) ), les égalités suivantes sont vraies: sp(r) wp(r) (r*t1 wp(T-l) sp(T-l) (r-1)* En reportant l'égalité du théorème 1 dans la définition de wp et sp, on obtient le principal résultat de cette section : Théorème 2 les égalités suivantes sont vraies : wp(r*) À/3.(,e'.{:le2 : /3(e2) et lfp (,a.(,e.(e = e') ou sp(r)(a)))(e2)}) - À/3.lfp (Àa.{/1 ou wp(r)(a)}) sp(r*) Àf1.(,e'.{3e1 : /3(e1) et lfp (,a.(,e.(e = e') ou wp(r)(a)))(e1)}) - À/3.lfp (Àa.{/1 ou sp(r)(a)}) wp(r* )(/3), où le prédicat /3 désigne un ensemble d'états de sortie, représente tous les états susceptibles d'être les prédécesseurs (directs ou indirects) d'un de ces états. On dit que wp(r*) représente la sémantique déductive en arrière du programme. De même, sp(r*)(/1), où le prédicat /3 désigne un ensemble d'états d'entrée, représente tous les états susceptibles d'être les successeurs d'un de ces états. On dit que sp(r*) représente la sémantique déductive en avant du programme. Le théorème que nous venons d'énoncer offre une formulation en terme de point fixe de chacune de ces sémantiques, et en utilisant l'opérateur de transition unitaire que l'on souhaite: wp(r) ou sp(r). En pratique, les états sont décomposés en un couple (point de programme, état mémoire) et l'équation de point fixe à résoudre pour la sémantique déduc- tive en avant (ou en arrière) d'un programme TI et pour une condition initiale (ou finale) <.p prend la forme d'un système X = Frr(i.p)(X), où chaque équation correspond à un des points du programme. Le théorème fondamental qui permet de faire le pont entre la modélisation sous forme de systèmes dynamiques discrets et les programmes informatiques est le suivant (donné ici pour un système en avant) :
  17. 17. INTERPRETATION ABSTRAITE 21 Théorème 3 Soit Il un programme comportant n variables à valeurs dans U et a points de programme. Le plus petit point fix( (P1 , ... ,Pa) de Fn(<p) est tel que, ViE{l, ...,a}: P; = .m2 .{:lm1 E un :<p(m1 ) et r•(< m1 ,a~ >, < m 2 ,a;) >)} où a; est le ième point de programme, et a~ le point d'entrée. Ce qui veut dire, en clair, qu'en chaque point de programme i, le prédicat P;, ième composante du plus petit point fixe de Fn(<p), dit si un état de mémoire est atteignable en ce point à partir d'un état de mémoire en entrée vérifiant la condition <p. Donc P; caractérise tous les états mémoires que l'on est susceptible de ren- contrer au point de programme i au cours de l'exécution à condition qu'on parte d'un état d'entrée respectant la spécification <p. Le plus petit point fixe de Fn(<p) contient ainsi toute l'information locale nécessaire pour dire si une propriété donnée est vérifiée en un point de programme ou non. A partir de là, notre tâche va consister à calculer une approximation de ce point fixe. En conclusion, une des indications les plus utiles fournies par [Cou78] est qu'il est plus aisé de chercher des propriétés à partir d'une sémantique déductive (i.e. sous forme d'un système d'équations) plutôt que d'une sémantique opéra- tionnelle. Cela permet en effet de transférer le problème du terrain informatique - plus ou moins propice à l'intuition - vers le terrain mathématique où les méthodes d'approximation et de résolution de systèmes d'équations sont plus classiques et connues. 1.3 Simplification des systèmes d'équations 1.3.1 Introduction Nous venons de voir que la sémantique d'un programme peut s'exprimer sous la forme d'un système d'équations. Le plus souvent ce système est réactif, c'est-à- dire que la même variable apparaît plusieurs fois dans le système, ce qui interdit un calcul direct des solutions. La méthode standard pour résoudre complètement le système est naturel- lement d'utiliser la sémantique opérationnelle sur le programme d'où provient le système, mais nous ne voulons en aucun cas d'une exécution totale du pro- gramme, car le gain de la méthode serait nul. Rappelons qu'on ne s'intéresse ici qu'à des vues partielles des solutions du système puisqu'on ne cherche que certaines propriétés dynamiques pouvant don- ner lieu à une optimisation. Il faut donc dégager des méthodes permettant, étant donnée la propriété à rechercher, de passer du système initial - dit concret - à un système approché - dit abstrait - le plus simple possible pour en faci- liter la résolution et pourtant assez complet pour détecter le mieux possible les propriétés cherchées. Nous décrivons dans les paragraphes qui suivent quelques techniques permettant d'obtenir des approximations correctes.
  18. 18. 22 INTERPRETAT/ON ABSTRAITE 1.3.2 Treillis complets Pour définir ce qu'est une approximation cc rrecte d'un système d'équations, et pouvoir utiliser des bonnes propriétés générales de ce type de fonctions, on se placera dans des treillis complets. Suivent quelques définitions destinées à fixer le vocabulaire que nous utiliserons par la suite. Définition 4 un treillis complet est un hexuplet (L, ::;, .l, T , U, n) tel que : • ::; est un ordre partiel sur L • toute partie S de L admet une borne supérieure notée US • toute partie S de L admet une borne inférieure notée nS • .l est le plus petit élément de L • T est le plus grand élément de L Définition 5 Soient (L, ::;, .l, T, U, n) et (M, ::;, .l', T', U', n') deux treillis com- plets tels que M Ç L ; alors M est un sous-treillis de L si et seulement si U = U' et n = n'. Définition 6 Soit (L, ::;, .l, T, U, n) un treillis complet. J est un idéal de L si et seulement si J est un sous-ensemble non vide de L tel que : • (aEl,xEL,x::;a)=*(xEJ) • (a E 1, b E 1) =* (a U b E 1) Proposition 2 J est un idéal de (L, ::;, .l, T, U, n) si et seulement si J est un sous-ensemble non vide de L tel que : (a E J, bE J) {::? (a U b E J) 1.3.3 Opérateurs sur un treillis Les applications internes d'un treillis complet sur lui-même sont appelées opéra- teurs. Définition 7 Un opérateur f du treillis complet (L, ::;, .l, T, U, n) est un mor- phisme complet pour l'union si et seulement si VS Ç L, f (US) = Uf( S). Définition 8 Un opérateur f sur un treillis (L, ::;) est dit monotone ssi V(x,y) E L2 ,(x:::; y)=* (J(x):::; J(y)) NB : on emploiera parfois le terme croissant dans le même sens.
  19. 19. INTERPRETATION ABSTRAITE 23 Définition 9 Soient µ un ordinal quelconque et < x 6 : ô E µ > une famille d 'éléments de L. On dit que < x 6 : ô E µ > est une chaîne ascendant; si ou une chaîne strictement ascendante si La propriété suivante sera très utile pour assurer la terminaison des calculs par itération lorsqu'on travaillera dans un treillis infini : Définition 10 On dit qu'un treillis L vérifie la condition de chaîne ascendante si toute chaîne strictement ascendante de L est finie. Définition 11 Soit w le premier ordinal limite infini. Nous dirons qu'un opé- rateur f de (L, ::;, 1-, T , U, n) est continu supérieurement ssi pour toute chaîne ascendante < x 6 : ô E w > nous avons : [ Définition duale pour la continuité inférieure. ] Définition 12 Un opérateur f de L est dit continu ssi il est continu inférieure- ment et supérieurement. Proposition 3 Tout opérateur continu est monotone. 1.3.4 Points fixes et théorème de Tarski Définition 13 Soit f un opérateur sur le treillis L, on définit les ensembles suivants : postfp (!) = {x/f(x):::; x} est l'ensemble des post-points fixes de f prefp (!) = {x/x :S f(x)} est l'ensemble des pré-points fixes de f fp (!) = {x/x = J(x)} est l'ensemble des points fixes de J L'ensemble fp (!) des points fixes d'un opérateur monotone est du plus haut intérêt puisque la résolution du système d'équations de la sémantique abstraite est essentiellement un calcul de point fixe. fp (!) possède un plus petit élément (le plus petit point fixe) noté lfp (!) et un plus grand élément (le plus grand point fixe) noté gfp (!). Nous rappelons ici les principaux résultats concernant fp (!).
  20. 20. 24 INTERPRETATION ABSTRAITE Définition 14 Soient L un treillis complet etµ( L) le plus petit ordinal tel que la cardinalité de la classe {8 : 8 E µ( L)} soit strictement supérieure à !a cardinalité de L. Soit f un opérateur monotone de L. L'itération crois~ante partant de d E L et définie par f est la séquence < x8 : 8 E µ( L) > d'éléments de L définie par récurrence transfinie comme suit : { x0 = d x 8 = f (x8 - 1 ) pour tout ordinal successeur 8 E µ( L) x8 = lJa<S xa pour tout ordinal limite 8 E µ( L) L'utilisation d'itération transfinie au lieu d'une simple itération sur les natu- rels permet de ne pas demander à J d'être continu. Dans le cas où J l'est ou bien si L est fini, on pourra revenir à une simple itération sur les naturels. Définition 15 La séquence < x8 : 8 E µ(L) > d'éléments de L treillis complet, est dite stationnaire ssi :le E µ,[V,B E µ, ,B ~ c ::::} x" = xP], auquel cas la limite de cette séquence est x". Nous noterons luis(!)(d) (resp. !lis(!)(d)) la limite d'une itération croissante (resp. décroissante} partant de d et définie par f E mon(L ~ L). Voici le théorème principal qui donne les méthodes de calcul de points fixes : Théorème 4 Soient f un opérateur monotone du treillis complet L, et d un élément de L. Alors l'itération croissante partant de d et définie par f, si elle est une chaîne ascendante, est stationnaire et sa limite est le plus petit des points fixes de J supérieurs à d. Corollaire 1 Si f est un opérateur monotone du treillis complet L, et si de plus J est continu ou L est fini, alors : Id E prefp (!), .lim Ji(d) E pf(f) 1...... 00 Corollaire 2 Si f est un opérateur monotone du treillis complet L, alors l'itéra- tion croissante partant de 1- et définie par f est stationnaire et de limite lfp (!). Théorème de Tarski 1 L'ensemble fp (!) des points fixes d'un opérateur J du treillis complet (L, ~' 1-, T, U, n) est un treillis complet pour l'ordre~ (mais pas nécessairement un sous-treillis de L). Une deuxième version (dite constructive) du théorème de Tarski donne ex- plicitement les éléments du treillis fp (!) en fonction de ceux de L : plus grand élément, plus petit élément, bornes inférieure et supérieure. Le théorème 4 ci-dessus nous a donné une méthode de calcul itérative du plus petit point fixe d'un opérateur monotone. Mais dans le cas général, ce calcul reste complexe lorsque l'opérateur f représente la sémantique déductive concrète d'un programme. Nous avons deux moyens de rendre possible en pratique ce calcul : les techniques d'accélération de la convergence et les techniques de simplification des équations. Nous utiliserons les deux.
  21. 21. INTERPRETATION ABSTRAITE 25 1.3.5 Fermetures sur un treillis complet La fermeture est une pièce de la plus haute utilité dans la conception des in- terprétations abstraites. Il s'agit d'une fonction d'approximation qui possède de nombreuses vertus, et que nous utiliserons pour simplifier le système d'équations décrivant la sémantique d'un programme. Définition 16 Une fermeture supérieure est un opérateur monotone, extensif (i.e. Vx,x ~ f(x)} et idempotent. La propriété principale des fermetures, due à Ward en 1942, est la suivante : Proposition 4 Si (L, ~' 1-, T, U, n) est un treillis complet et f une fermeture supérieure de L, alors (J(L), ~' f(1-), f(T), >.S.j(US), n) est un treillis complet. Les parties de Moore sont des sous-ensembles distingués de L qui induisent naturellement certaines fermetures, c'est-à-dire certaines approximations. Il sera donc utile de pouvoir les reconnaître. Définition 17 Une partie M de L est une partie de Moore inférieure de L ssi pour tout x E L, l'ensemble {y E M / x ~ y} n'est pas vide et admet un plus petit élément. Proposition 5 M est une partie de Moore inférieure ssi il existe une fermeture supérieure de L dont M est l'image. Théorème 5 Soit S une partie quelconque de L , la fermeture supérieure dont l'image est la plus petite partie de Moore inférieure contenant S est égale à : x 1--+ n{y Es u {T}/x ~y} On pourra utiliser une "méta-fermeture" supérieure pour trouver les ferme- tures supérieures qui constitueront nos approximations. Pour cela, trois ferme- tures supérieures mon, ext et idem vont permettre d'approcher tout opérateur par un opérateur respectivement monotone, extensif, ou idempotent, et la com- position des trois sera également une fermeture supérieure, qui permettra d'ap- procher tout opérateur par une fermeture supérieure. Définition 18 mon, ext et idem sont des opérateurs sur le treillis L --+ L des opérateurs de L définis ainsi : mon: (L-+L) ----t (L-+L) f 1--+ >.x. U {f(y)/y E L,y ~ x} ext: (L-+L) ----t (L-+L) f 1--+ >.x.x U f(x) idem: (L-+L) ----t (L-+L) f 1--+ luis(>.g.g o g)(f)
  22. 22. 26 INTERPRETATION ABSTRAITE La version constructive du théorème de Tarski (à laquelle nous avons fait allusion plus haut) donne alors les résultats suivants : Proposition 6 • ext est une fermeture supérieure de L --+ L et pour tout f de L --+ L, ext(J) est le plus petit opérateur extensif de L plus grand ou égal à f. (ext( L --+ L), ::=;, Àx.x, Àx.T, LJ, n) est le treillis complet des opérateurs extensifs. • De même, mon est une fermeture supérieure de L --+ L et pour tout f de L --+ L, mon(!) est le plus petit opérateur monotone de L plus grand ou égal à f. mon( L --+ L) est le sous-treillis complet des opérateurs monotones de L--+ L. • mono ext = ext o mon est une fermeture supérieure de L --+ L. L'ensemble Z =mono ext(L--+ L) = mon(L--+ L) n ext(L--+ L) est un sous-treillis complet (Z, ::=;, Àx.x, Àx.T, LJ, n) de L--+ L (sous-treillis des opérateurs ex- tensifs et monotones). • fers = idem o ext o mon = idem o mon o ext est une fermeture supérieure de L --+ L et pour tout f E L --+ L, fers (!) est la plus petite fermeture supérieure de L supérieure ou égale à f. fers (L --+ L) est le treillis complet des fermetures supérieures de L. L'opérateur fers constitue donc un méta-opérateur optimal d'approximation supérieure d'un opérateur quelconque par une fermeture supérieure, et mérite à ce titre d'être retenu. Donnons-en toutefois une forme plus maniable en pratique: fers(!) = Àx.lfp (,y.x LJ mon(J)(y)) Voici un résultat simple et utile : Proposition 7 Si p est une fermeture supérieure du treillis L d'image M, alors p= (p, ..., p) est une fermeture supérieure du treillis produit Ln d'image Mn . 1.3.6 Connexion de Galois La connexion de Galois est une autre façon de définir une approximation. A la différence de la fermeture supérieure qui opère à l'intérieur d'un treillis, une connexion de Galois établit un pont bidirectionnel entre deux treillis différents, ce qui permet de changer radicalement le domaine de calcul. Définition 19 Une connexion de Galois [EM85} est un couple d'applications (a,/) telles que : • A et C sont des treillis complets • a : C --+ A est continue
  23. 23. INTERPRETATION ABSTRAITE 27 • / : A ---+ C est continue • VxEC,1(a(x))~x • VaEA,a(r(a))=a NB : dans le vocabulaire de l'interprétation abstraite, a est appelée abstrac- tion, / concrétisation, A domaine abstrait et C domaine concret. La continuité requise pour a et / est une propriété forte et n'est pas souvent utilisée. Une notion plus faible est celle de paire de fonctions adjointes superieure. 1.3.7 Paire de fonctions adjointes supérieure Définition 20 Une paire de fonctions adjointes supérieure est un couple d'ap- plications (a,/) telles que : • A et C sont des treillis complets • a : C ---+ A est monotone • / : A ---+ C est monotone • V(x,a) E C x A,(x::; 1(a)) {:} (a(x)::; a) On note alors : A i>(a,/) C. On dispose de la caractérisation équivalente suivante : Proposition 8 A i>(a,/) C si et seulement si : • A et C sont des treillis complets • a : C ---+ A est monotone • / : A ---+ C est monotone • /00'.~ld • 0'.0/~ld Il est clair que toute connexion de Galois est a fortiori une paire de fonctions adjointes supérieure. Une fermeture supérieure détermine également une paire de fonctions adjointes supérieure : Proposition 9 Si p est une fermeture supérieure du treillis complet L, alors (p, Id) est une paire de Jonctions adjointes supérieure entre L et le treillis image de p. Démonstration : On a bien deux treillis complets.

×