Des Professeur

KING'S COLLEGE DE LONDRES Universites

Monsieur David Monniaux

Directeur De Recherche

Madame Mihaela Sighireanu

Monsieur Mnacho Echenim

Monsieur LUCA VIGANO

This thesis introduces a generic method to compute the prime implicates of a logical formula, i.e., the most general clausal consequences of a given logical formula, in any given decidable theory. The principle used is to recursively add to an initially empty set, literals taken from a preselected set of hypotheses until it can be proven that the disjunction of these literals is a consequence of the formula under consideration. Proofs of the termination, correctness and completeness of this algorithm are provided, which ensures that clauses computed by the method are indeed implicates and that all the prime implicates that can be constructed from the initial set are indeed returned. This algorithm is then applied in the context of program verification, in which it is used to generate loop invariants that permit to verify assertions on programs. The Abdulot framework, a C++ implementation of the system, is also introduced. Technical considerations required for the design of such systems are detailed, such as their insertion within a well-furnished ecosystem of provers and SMT-solvers. This implemented framework will be used to perform an experimental evaluation of the method and will show its practical relevance, as it can be used to solve a large scope of problems.

This thesis also presents introductory work on an implicant minimizer and applies it in the context of separation logic. The method described in this part could also be used to perform bi-abduction in separation logic, with an algorithm that is described but has not been implemented.

Résumé

Le travail présenté dans cette thèse introduit une méthode générique pour calculer les impliqués premiers d'une formule logique donnée dans une théorie décidable. Il s'agit intuitivement des conséquences clausales les plus générales de cette formule modulo cette théorie. Cette méthode fonctionne en ajoutant récursivement à un ensemble initialement vide des littéraux extraits d'un ensemble d'hypothèses présélectionnées, et ce jusqu'à ce qu'elle puisse démontrer que la disjonction des littéraux de cet ensemble est une conséquence de la formule sur laquelle elle travaille. On démontrera la terminaison, la correction et la complétude de cet algorithme. Cela confirmera qu'il calcule effectivement des impliqués de la formule de départ et qu'il retourne tous les impliqués premiers qui peuvent être construits à partir de l'ensemble d'hypothèses de départ. On construira ensuite à partir de cette méthode un algorithme l'appliquant à la génération d'invariants de boucles de programmes que l'on cherche à vérifier. On présentera également une implémentation C++ de ces deux méthodes, regroupées dans une infrastructure logicielle baptisée Abdulot. Cette implémentation sera utilisée pour évaluer expérimentalement les deux méthodes. On découvrira à cette occasion qu'elles sont capables de générer des solutions pour une large classe de problèmes.

Cette thèse présente également un travail introductif sur la minimisation de modèles en logique de séparation et son implémentation. La méthode décrite pourrait également être utilisée pour résoudre des instances de bi-abduction en logique de séparation, à l'aide d'un algorithme qui sera décrit mais pas implémenté. i

Résumé détaillé

Cette section a pour but de proposer un résumé en français, chapitre par chapitre, de ce manuscrit. Les travaux qui y sont présentés concernent l'étude et le développement de méthodes pour le raisonnement abductif modulo des théories et une de ses applications : la vérification de programmes. Bien qu'épuré des détails théoriques et techniques nécessaires pour établir les résultats scientifiques présentés, il pourra fournir au lecteur peu familier avec la langue anglaise un aperçu du contenu et de la portée de ces travaux.

Chapitre 1 -Contexte et définitions

 10], outils dont nous nous servirons pour effectuer lesdits tests de satisfaisabilité.

Chapitre 2 -État de l'art

Le chapitre 2 présente brièvement l'état de l'art des deux domaines de recherche sur lesquels cette thèse repose : le raisonnement abductif automatisé par la génération d'impliqués premiers et la génération d'invariants de boucles de programmes.

, qui cible la logique du premier ordre, et l'algorithme cSP [173] pour la logique equationnelle.

.

Annexe A -Grammaire des fichiers de littéraux abducibles utilisés par Abdulot Cette annexe présente la grammaire complète de la syntaxe des fichiers de littéraux pour la procédure d'abduction.

Annexe B -Exemple de condition de vérification générée par Why3

Cette annexe présente des conditions de vérification complètes générées par Why3 pour les exemples détaillés dans ce mémoire.

Annexe C -Manuel utilisateur de l'infrastructure logicielle Abdulot Cette annexe présente un court manuel utilisateur à utiliser pour installer et démarrer l'infrastructure logicielle Abdulot, comportant GPiD, Ilinva, et plusieurs outils associés.

Partie I -Une infrastructure générique pour le raisonnement abductif modulo des théories Chapitre 3 -Un générateur d'impliqués premiers efficace modulo des théories Le chapitre 3 nous sert à introduire et à présenter un nouvel algorithme pour générer des impliqués premiers modulo des théories, et ce indépendamment de la théorie considérée, dès lors qu'il est possible de tester la satisfaisabilité des formules dans cette théorie. On y présente en premier lieu un algorithme naïf, nommé ImpGen, à partir duquel on obtiendra ensuite une version plus efficace. Ce premier algorithme construit des impliqués à partir d'un ensemble initial de littéraux que l'on nomme littéraux abducibles. Il explore ensuite des conjonctions de ces littéraux jusqu'à construire une hypothèse dont l'adjonction à la formule initiale est insatisfaisable. La négation d'une telle hypothèse étant nécessairement une conséquence logique de la formule de départ, l'algorithme peut ainsi retourner un impliqué de cette formule. Cette première version fonctionne en explorant toutes les conjonctions possibles. Elle définit et applique ensuite des méthodes de gestion de redondance, ce qui lui permet de retourner tous les impliqués premiers (non-redondants) qu'il est possible de construire à partir des littéraux abducibles qui lui auront été fournis.

L'énumération systématique de toutes les conjonctions possibles n'étant pas efficace, nous proposons des améliorations pour réduire l'espace de recherche et rendre l'algorithme suffisamment efficace pour être utilisable en pratique. Parmi ces améliorations, nous nous intéressons d'abord à l'utilisation d'un ordre sur les littéraux. Grâce à celui-ci, nous pouvons éviter de reconstruire plusieurs fois le même impliqué en ajoutant ses littéraux dans des ordres différents. Nous détaillons aussi l'utilisation que nous pouvons faire des modèles qu'il est possible de récupérer lors des tests de satisfaisabilité. Nous montrons que grâce à cela, nous pouvons réduire le nombre de littéraux à tester lorsque certains d'entre eux sont vrais dans ces modèles. Nous présentons alors un algorithme final, nommé ImpGen-PiD, intégrant l'ensemble de ces ajustements.

Nous démontrons alors que, dès lors que le problème de la satisfaisabilité d'une formule est décidable pour la théorie dans laquelle nous travaillons et que l'ensemble des littéraux abducibles est fini, cet algorithme termine. Nous démontrons également que l'algorithme de départ et celui obtenu après l'ajout des améliorations sont à la fois corrects, c'està-dire qu'ils génèrent uniquement des impliqués de leur formule de départ, et complets, c'est-à-dire qu'ils génèrent tous les impliqués premiers de leur formule d'entrée, dès lors qu'il peuvent être construits à partir des littéraux abducibles fournis. Dans le cas général, la terminaison de l'algorithme n'est pas garantie. Il est toutefois possible de forcer cette terminaison en sacrifiant la complétude. Cela peut être réalisé en imposant un temps maximal aux tests de satisfaisabilité et en considérant que tout test dépassant ce temps ne dénotait pas la présence d'un impliqué.

Nous terminons le chapitre en étudiant ce qu'il est possible de changer dans ce nouvel algorithme pour améliorer ses performances dans une théorie particulière, la plus simple, en logique propositionnelle. Cela passe par l'intégration plus en profondeur de l'algorithme dans une procédure classique vérifiant la satisfaisabilité des formules en logique propositionnelle (CDCL [START_REF] Davis | A machine program for theorem-proving[END_REF][START_REF] Zhang | Efficient conflict driven learning in a boolean satisfiability solver[END_REF]). Grâce aux conflits détectés lors de l'application des règles de propagation unitaire de cette procédure, nous pouvons détecter et ajouter des impliqués supplémentaires en amont du test qui les aurait détectés. Par ailleurs, l'exploitation des informations calculées par ces mêmes règles nous permettent de minimiser les impliqués ainsi obtenus en utilisant les raisons pour lesquelles les littéraux en conflit ont été choisis par la procédure de décision. L'algorithme obtenu spécifiquement pour cette logique est également présenté.

Chapitre 4 -Stockage et réutilisation des impliqués modulo des théories

Dans le chapitre 4, nous nous intéressons au stockage des impliqués générés par l'algorithme du chapitre précédent. Nous nous concentrons en particulier sur deux objectifs. D'une part, nous cherchons à obtenir une structure qui réduit au maximum la complexité des opérations de stockage d'impliqués, notamment grâce une gestion de la redondance par des opérations de suppression des conséquences logiques. D'autre part, nous cherchons une structure qui nous permet de réutiliser efficacement les impliqués déjà engendrés pour éviter des calculs inutiles à l'algorithme principal.

Pour ce faire, nous introduisons une structure ordonnée sur les littéraux que nous appelons A-arbre-préfixe, et dont chaque chemin de la racine à une feuille sera interprété comme un impliqué. Nous détaillons ensuite les opérations classiques sur cette structure permettant l'insertion et la suppression d'impliqués. Nous détaillons également un algorithme permettant de vérifier s'il existe dans l'A-arbre-préfixe une conséquence logique d'une formule donnée et un autre algorithme permettant de vérifier si une formule donnée est la conséquence logique d'un des impliqués de l'A-arbre-préfixe. Ces deux derniers v algorithmes réalisant des appels à un SMT-solver pour vérifier les propriétés d'implications, nous préciserons que le nombre de tels tests est de l'ordre de la profondeur de l'A-arbre-préfixe pour le premier algorithme et de celle de la taille de l'A-arbre-préfixe pour le second.

Nous achevons le chapitre en donnant une version adaptée de l'algorithme ImpGen-PiD utilisant nos A-arbre-préfixes pour stocker et réutiliser les impliqués générés.

Partie II -Une infrastructure générique pour utiliser le raisonnement abductif dans un cadre de vérification Chapitre 5 -Un modèle abstrait pour utiliser un générateur d'impliqués premiers en vérification Ce chapitre présente une infrastructure générale permettant l'utilisation d'algorithmes d'abduction pour la résolution de problèmes de vérification. Ce travail se concentre sur la résolution des problèmes pour lesquels il est possible d'obtenir des conditions de vérification, formules logiques qui, lorsqu'elles sont valides, assurent la correction du problème. Nous introduisons ainsi une représentation des problèmes de vérification définie par un ensemble de formules dites « guides » et par un ensemble de « générateurs », fonctions associant aux formules guides un ensemble de conditions de vérification. Le problème est alors de trouver un ensemble de formules guides à partir desquelles les générateurs ne produisent que des conditions de vérification valides.

À partir de cette représentation, nous construisons un algorithme basé sur les travaux de Dillig et al. [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF], nommé Ilinva, pour résoudre ces problèmes de vérification. Recevant en entrée la représentation d'un problème dont certains générateurs produisent des conditions de vérification non-valides, l'algorithme renforce successivement les formules guides de la représentation jusqu'à ce que le problème soit résolu. Pour ce faire, il commence par sélectionner un générateur dont l'image n'est pas une formule valide. Il appelle ensuite la procédure d'abduction développée en partie I sur cette formule pour obtenir des hypothèses supplémentaires qui garantissent sa validité. Il choisit alors une de ces solutions et la traduit dans le contexte du programme de telle sorte que son ajout à l'une des formules guides du problème garantisse que l'image du générateur considéré à cette étape soit désormais une formule valide. L'existence d'une telle traduction devra être garantie par la définition des générateurs de conditions de vérification. L'algorithme renforce alors la formule guide choisie avec cette traduction puis poursuit son travail sur les autres conditions de vérification. Si besoin, il peut également revenir sur certaines de ses décisions (choix de solution, choix de formule guide, choix de générateur) pour essayer les autres possibilités. Un tel retour arrière est nécessaire lorsque des choix précédents ont conduit à un programme dont certaines conditions de vérification ne peuvent plus être renforcées pour être valide. Il termine lorsqu'il obtient une représentation valide ou échoue après avoir essayé toutes les possibilités.

Nous concluons alors le chapitre en donnant une preuve que si l'algorithme n'échoue pas, son résultat est effectivement une séquence de formules guides pouvant remplacer vi celles du problème de départ et de sorte que tous les générateurs du problème ainsi construit ne retournent que des formules valides.

Chapitre 6 -Une application du modèle pour générer des invariants de boucles de programmes Dans le chapitre 6, nous définissons une spécialisation de l'algorithme Ilinva que nous avons introduit au chapitre précédent. Nous commençons par proposer une représentation standardisée des programmes. Nous définissons notamment les constructions que l'on autorise, la manière dont nous y représentons les invariants de boucle (potentiels) ainsi que la manière nous y ajoutons des assertions : formules logiques supposées vraies à l'endroit où elles apparaissent dans un programme. Nous rappelons ensuite les méthodes usuelles pour générer des conditions permettant d'assurer que des assertions sont effectivement vérifiées et que des invariants de boucle potentiels sont effectivement des invariants de boucle.

Nous détaillons ensuite la manière dont nous utilisons le cadre du chapitre 5 pour représenter ces programmes. Nous utilisons les formules guides pour représenter les invariants de boucle potentiels et les générateurs de conditions de vérification pour représenter la sémantique du programme et obtenir les conditions de vérification assurant la validité de ses assertions et de ses invariants. Nous obtenons ainsi une représentation qui nous permet d'utiliser l'algorithme Ilinva pour mettre à jour ces invariants potentiels jusqu'à ce qu'ils soient de vrais invariants et qu'ils permettent de démontrer que les assertions du programme sont vérifiées.

Nous poursuivons en détaillant les différents ajustements nécessaires pour rendre l'utilisation de l'algorithme Ilinva sur cette représentation utilisable en pratique. En particulier, nous expliquons quelles heuristiques nous utilisons pour choisir les générateurs, les impliqués et les invariants de boucle potentiels. Nous développons également une méthode pour générer les littéraux abducibles nécessaires à l'algorithme ImpGen-PiD pour résoudre nos problèmes d'abduction. En extrayant du programme les variables et fonctions qu'il utilise, nous construisons des littéraux correspondant à leur traduction dans la logique utilisée par les conditions de vérification que l'on obtient des générateurs et que l'on utilise pour l'abduction. Nous précisons enfin les paramètres avec lesquels nous configurons le générateur d'impliqués pour en obtenir les meilleurs performances possibles dans cette application.

Le chapitre conclut en détaillant les différences avec les travaux dont l'algorithme Ilinva est inspiré (Dillig et al. [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF]), ainsi que les limites théoriques de la méthode présentée dans cette partie, notamment le fait que certaines de nos heuristiques de sélection nous empêchent de résoudre certains problèmes.

Partie III -Implémentation et évaluation

La troisième partie de la thèse est consacrée à la description et à l'évaluation d'une infrastructure logicielle générique dans laquelle nous avons implémenté les algorithmes présentés dans les deux parties précédentes. À l'aide d'un système d'interfaces avec des vii outils externes, nous pouvons tirer parti de la généricité de ces algorithmes pour obtenir des outils pratiques conservant cette généricité. En branchant cette infrastructure à des démonstrateurs automatiques et à la plateforme Why3 [START_REF] Bobot | Why3: Shepherd your herd of provers[END_REF][START_REF] Filliâtre | The Why/Krakatoa/Caduceus platform for deductive program verification[END_REF][START_REF] Filliâtre | Why3 -where programs meet provers[END_REF] pour travailler sur les programmes, nous obtenons des exécutables sur lesquels nous effectuons des tests de performance.

Chapitre 7 -Une infrastructure logicielle générique

Nous utilisons le chapitre 7 pour présenter le développement d'une infrastructure logicielle permettant de tirer partie de la généricité théorique des algorithmes ImpGen-PiD de la partie I et Ilinva de la partie II. Nous commençons par présenter une méthode pour brancher nos outils avec des démonstrateurs automatiques que nous traitons comme boites noires. Nous proposons pour cela des modèles d'interface capables de construire des tests de satisfaisabilité puis d'invoquer un démonstrateur pour obtenir l'état de la formule.

Le chapitre présente ensuite une infrastructure pour l'implémentation du générateur d'impliqués premiers ImpGen-PiD. Cette infrastructure est constituée de trois composants : un exécutant l'algorithme, un second travaillant sur le choix des littéraux pour construire l'hypothèse servant à obtenir les impliqués, et enfin une interface avec un démonstrateur. Nous détaillons alors la manière dont le composant qui construit les conjonctions de littéraux implémente l'ensemble des aménagements réduisant l'espace de recherche proposés au chapitre 3. Nous appelons l'outil obtenu GPiD. Nous introduisons ensuite un format de fichier pour représenter les littéraux utilisés pour l'abduction et nous détaillons sa syntaxe à l'aide d'exemples.

Nous détaillons également dans ce chapitre la manière dont nous implémentons l'algorithme Ilinva, toujours de manière générique, à l'aide d'une interface qui aura pour but de représenter les problèmes traités. Cette interface s'occupe en particulier de transmettre au composant exécutant l'algorithme les conditions de vérification non-valides du problème qu'elle représente, ainsi que de choisir les formules guides qui devront être modifiées par les solutions retournées par GPiD. L'interface sert enfin à implémenter les techniques de traduction nécessaires pour transformer les conditions de vérification du programme en formules traitables pour la procédure d'abduction et, inversement, les impliqués obtenus en formules syntaxiquement valides dans les assertions du programme. Nous appelons l'outil obtenu Ilinva.

Chapitre 8 -Des interfaces pour brancher l'infrastructures à des outils concrets

Le chapitre 8 nous permet de détailler l'implémentation d'interfaces concrètes. Nous y expliquons les adaptation nécessaires pour brancher de vrais démonstrateurs ou vérificateurs de programmes dans notre infrastructure.

Nous détaillons ainsi la création d'interfaces pour le démonstrateur de logique propositionnelle MiniSAT [START_REF] Eén | An extensible sat-solver[END_REF], les démonstrateurs modulo des théories Alt-Ergo [START_REF] Conchon | SMT Workshop: International Workshop on Satisfiability Modulo Theories[END_REF], CVC4 [7], VeriT [START_REF] Bouton | verit: An open, trustable and efficient smt-solver[END_REF] et Z3 [START_REF] Moura | Z3: An efficient smt solver[END_REF], ainsi que les raisons justifiant la création d'une interface plus viii générale, pouvant être utilisée comme sur-couche à n'importe quel démonstrateur capable de traiter des problèmes exprimés au format SMT-lib [START_REF] Barrett | The SMT-LIB Standard: Version 2[END_REF].

Nous présentons ensuite l'implémentation d'une interface de représentation de programme pour Ilinva qui utilise la plateforme de raisonnement déductif pour programmes Why3 [START_REF] Bobot | Why3: Shepherd your herd of provers[END_REF][START_REF] Filliâtre | The Why/Krakatoa/Caduceus platform for deductive program verification[END_REF][START_REF] Filliâtre | Why3 -where programs meet provers[END_REF]. Cette plateforme, déjà capable de générer les conditions de vérifications dont nous avons besoin, nous permet de traiter la plupart du travail sur les programmes considérés en boite grise à l'extérieur de notre infrastructure. En représentant nos programmes dans le format de fichier défini par Why3 (WhyML), nous pouvons obtenir une interface pratique pour la génération d'invariants de boucles dans ces programmes, moyennant quelques ajustements sur la configuration de GPiD. Nous détaillons également la manière dont nous extrayons les littéraux pour l'abduction des programmes WhyML, en ajoutant dans nos fichiers de littéraux des informations supplémentaires sur le contexte des variables du programme. Ces informations serviront notamment à retraduire correctement la syntaxe des impliqués de la logique du démonstrateur à la logique de WhyML.

Le chapitre se conclut par des remarques sur la documentation, la compilation et la distribution de l'infrastructure, disponible publiquement sur la plateforme GitHub [START_REF] Sellami | Abdulot framework and tools[END_REF].

Chapitre 9 -Évaluation expérimentale de GPiD et Ilinva

Le dernier chapitre de la partie III est consacré à l'évaluation expérimentale des outils présentés dans les deux chapitres précédents. Après avoir présenté l'infrastructure technique sur laquelle les expériences ont été effectuées, nous étudions les résultats obtenus pour le générateur d'impliqués premiers et le générateur d'invariants.

Nous commençons par l'évaluation de GPiD en logique propositionnelle, où nous observerons que sur de nombreux exemples tirés de dépôts standards (not. SAT-lib [START_REF] Hoos | Satlib: Benchmarks[END_REF]), notre outils est capable de générer soit tous les impliqués premiers en quelques secondes, soit au moins quelques impliquées en moins d'une minute. Nous observons également que, comme attendu, l'algorithme se comporte d'autant mieux que les problèmes qu'il traite contiennent moins de littéraux d'abduction ou possèdent peu d'impliqués. En comparant notre outil aux meilleurs concurrents disponibles : ZRes [START_REF] Simon | Efficient consequence finding[END_REF] et primer [START_REF] Previti | Prime compilation of non-clausal formulae[END_REF], nous constatons que le temps de calcul observé est du même ordre de grandeur que celui de ces outils dès lors que les problèmes considérés possèdent beaucoup de contraintes. Pour les autres problèmes, notre algorithme met généralement plus de temps que les deux autres pour retourner des impliqués.

Nous poursuivons ensuite l'évaluation de GPiD en lui faisant traiter des problèmes avec égalités entre variables et des problèmes d'arithmétique linéaire sur les entiers, tous tirés des bibliothèques de problèmes SMT-lib [START_REF] Barrett | The SMT-LIB Standard: Version 2[END_REF]. Nous observons que, pour tous ces exemples, GPiD est capable de générer des impliqués, bien que la génération de tous les impliqués soit en général impossible au regard de la taille importante de cet ensemble. Pour les problèmes equationnels, nous comparons également les performances de notre générateur à celles de cSP [START_REF] Tourret | Prime implicate generation in equational logic[END_REF]. Nous observons que nous sommes systématiquement capable de générer des impliqués plus rapidement que cSP sur les exemples étudiés.

La deuxième partie du chapitre est consacrée à l'évaluation de notre générateur d'invariants de boucles Ilinva. Après avoir construit un ensemble de programmes à partir de problèmes de génération d'invariants habituels et des bibliothèques d'exemples de Why3, nous testons notre algorithme afin de vérifier s'il est capable de générer des invariants satisfaisants. Nous observons que, même si le temps de calcul est généralement élevé, notre outil est capable de générer des solutions pour des exemples dans diverses théories, dont certaines n'étaient pas connues pour être dans le domaine des outils précédents. Nous nous intéressons également aux limites mises en évidence par les résultats. Nous relevons notamment le fait que le nombre de littéraux envoyés aux problèmes d'abduction a un impact significatif sur la performance du système global et que, d'une manière générale, davantage de travaux pour réduire l'espace de recherche du générateur d'impliqués, peut-être aux dépends de sa complétude, seront nécessaires pour obtenir de meilleures performances.

Partie IV -Un algorithme de minimisation de modèles pour le raisonnement abductif en logique de séparation La dernière partie de cette thèse est consacrée à l'élaboration d'un algorithme alternatif pour obtenir des impliquants d'une formule logique. Cet algorithme consiste à utiliser un modèle de la formule pour construire un impliquant initial. Ensuite, grâce à une décomposition de cet impliquant en sous-formules et à des règles d'affaiblissement prédéfinies, nous affaiblissant les sous-formules de cet impliquant tant que la formule obtenue reste un impliquant de celle de départ.

Chapitre 10 -Un algorithme générique de minimisation d'implicants

Le chapitre 10 présente l'algorithme de minimisation d'impliquant évoqué ci-dessus. Notre algorithme se base sur une procédure de minimisation de modèles en logique propositionnelle [START_REF] Bradley | Checking safety by inductive generalization of counterexamples to induction[END_REF]. Cette méthode peut être vue comme la minimisation d'un impliquant d'une formule propositionnelle obtenu en prenant la conjonction de tous les littéraux valides dans un modèle. Elle retire ensuite des littéraux de cet impliquant tant que ces suppressions ne brisent pas son caractère d'impliquant. Cette suppression est réalisée en découpant l'ensemble des littéraux en deux dès lors qu'ils ne peuvent pas tous être retirés, puis en appliquant récursivement la méthode sur ces deux parties en considérant l'autre comme étant fixe. L'algorithme retourne alors un impliquant plus faible que le premier.

L'algorithme que nous présentons étend cette méthode pour qu'elle soit capable de traiter des théories dans lesquelles l'affaiblissement d'un impliquant ne résume pas à la suppression de certains de ses littéraux, mais peut consister à les remplacer successivement par des formules moins fortes. Il permet aussi d'étendre la décomposition en sous parties à plus de deux. Pour faire cela, nous définissons des séquences de formules, qui représentent x les affaiblissements successifs des sous-formules de l'impliquant initial. À l'aide de règles de généralisation, prédéfinies pour le contexte des formules traitées, l'algorithme ajoute à ces séquences les généralisations associées aux formules qu'elles représentent, et ne considère ainsi que la dernière formule de chaque séquence comme partie de l'impliquant potentiel représenté. Grâce à des opérateurs permettant de reconstruire une séquence minimale dont la représentation implique toujours la formule de départ, nous obtenons une structure sur laquelle appliquer l'algorithme pour affaiblir au maximum et sur plusieurs niveaux les sous-formules de l'impliquant initial.

Nous poursuivons ensuite en proposant deux spécialisations de cet algorithme (ce qui consiste à définir les règles de généralisation et les formules considérées) pour obtenir une version équivalent à l'algorithme en logique propositionnelle dont nous nous sommes inspirés [START_REF] Bradley | Checking safety by inductive generalization of counterexamples to induction[END_REF] et une version permettant de minimiser des formules en logique de séparation [START_REF] Reynolds | Separation logic: A logic for shared mutable data structures[END_REF]. Nous terminons le chapitre en proposant un algorithme simple qui utilise cette procédure de minimisation pour résoudre des problèmes d'abduction en logique de séparation (dans lesquels la conjonctions est remplacée par la conjonction séparée).

Chapitre 11 -Implémentation et évaluation de l'algorithme et de son utilité pour la logique de séparation Le chapitre 11 présente l'implémentation et l'évaluation de l'algorithme de minimisation et de ses spécialisations présentées dans le chapitre 10. Nous commençons par y décrire une spécialisation simple de l'algorithme qui a pour but de simplifier son évaluation (en en réduisant le temps de calcul). Nous détaillons ensuite les considérations qui doivent être étudiées pour l'implémentation de l'algorithme de minimisation et nous présentons comment cela a été fait dans l'infrastructure Abdulot. Une interface utilisant la procédure de décision vérifiant la satisfaisabilité des formules en logique de séparation proposée par le démonstrateur CVC4 [7] a également été implémentée. Les détails de cette implémentation sont présentés à la suite de celle de l'algorithme de minimisation.

Nous évaluons ensuite l'algorithme en comptant le nombre de tests de satisfaisabilité (nécessaires pour vérifier si une formule est bien un impliquant) qu'il exécute, et le comparant au nombre de tests effectués par un algorithme de minimisation naïf. Les expériences montrent que l'algorithme proposé est particulièrement efficace pour minimiser des impliquants lorsque le nombre de composants que contiennent ces derniers est important ou que ces composants peuvent être généralisés de nombreuses fois (plus de cinq). Il apparait également que cet algorithme est efficace lorsqu'une part importante des composants de l'impliquant initial peuvent être généralisés. Dans les autres cas, les tests de satisfaisabilité provoqués par la décomposition en partitions échouent et provoquent ainsi un surcoût par rapport à l'algorithme naïf. Nous évaluons également le nombre de tests de satisfaisabilité et le temps de calcul nécessaire à la minimisation en pratique de formules simples en logique de séparation, puis vérifions s'il est possible d'utiliser cette méthode en pratique pour résoudre quelques problèmes d'abduction. Les résultats montrent que tant que les formules ne contiennent ni quantificateur ni implication séparée, l'algorithme est capable de minimiser les impliquants obtenus à partir des modèles du démonstrateur xi modulo des théories. En revanche, lorsque les formules contiennent des quantificateurs ou implications séparées, le démonstrateur modulo des théories n'est plus en mesure de résoudre les problèmes qui lui sont envoyés.

Conclusion

Les contributions principales de ce travail de thèse sont la conception et l'implémentation de deux systèmes génériques. L'un automatisant un raisonnement abductif en générant des impliqués premiers de formules logiques. L'autre utilisant le premier pour générer des invariants de boucles de programmes.

Les résultats expérimentaux montrent l'intérêt pratique de ces travaux pour générer des solutions à des problèmes qui n'avaient pas de solution automatisée connue. Ils ouvrent également la voie à des travaux de recherche s'intéressant à la limitation de leurs espaces de recherche et à la génération des littéraux abducibles.

Introduction

One day, one person may make the following hypothesis: "If I am an animal, then I can cross a bridge". Another day, a smarter person will assess the opposite, build a rope bridge between two buildings and have a carp try to cross it.

This ability to produce conjectures and then try to decide whether they are true or false is a structural foundation of mathematics and scientific reasoning [START_REF] Popper | Conjectures and refutations: The growth of scientific knowledge[END_REF]. On one end, people devise hypotheses based on either their intuition or observations and, on the other end, they devise theoretical or experimental techniques to either prove or provide evidence for these hypotheses.

Both hypothesis assessment and verification have been done more or less successfully by human beings through history. However, with the development of computer science, it became possible to search for automated methods to perform these bases of mathematical reasoning.

Let us first talk about the problem of automatically deciding whether a given conjecture holds. In computer science, this has been studied under the name of automated theorem proving [START_REF] Robinson | Handbook of automated reasoning[END_REF]. Being a little more formal, we first need to decide on a common language to express facts as well as on a logic to determine whether these facts are true or not. Now if we define a theory by a set of axioms, or facts we admit hold, the goal of such methods is to automatically check if given properties can be deduced from them. Typically, if we can define a theory in which we can express what an animal is, what a bridge is and what crossing is, then, we may be interested in obtaining an automatic system to prove or disprove conjectures expressed in it, such as whether an animal can cross a bridge or not. Different approaches have been tried to produce such systems. Some are designed to imitate the process humans use to prove conjectures, by defining deduction rules and letting an algorithm apply them until it reaches the expected conclusion [4,[START_REF] Hoare | An axiomatic basis for computer programming[END_REF][START_REF] Newell | Empirical explorations of the logic theory machine: a case study in heuristic[END_REF]. Others rewrite the problems in a form that is more adapted to the use of computers and design alternative techniques that would be very fastidious for humans to apply but can be naturally processed by computers [START_REF] Davis | A machine program for theorem-proving[END_REF][START_REF] Zhang | Efficient conflict driven learning in a boolean satisfiability solver[END_REF]. This has produced an ecosystem of tools we call automated theorem provers, in which each tool is usually adapted for solving problems in a specific logic and theory (such as propositional logic [START_REF] Eén | An extensible sat-solver[END_REF], first order logic [START_REF] Schulz | System Description: E 1.8[END_REF][START_REF] Kovács | First-order theorem proving and vampire[END_REF][START_REF] Monniaux | A survey of satisfiability modulo theory[END_REF], modal logic [START_REF] Benzmüller | Implementing and evaluating provers for first-order modal logics[END_REF]11,[START_REF] Otten | Mleancop: A connection prover for first-order modal logic[END_REF], etc).

When the conjectures we want to prove are expressed in theories that are too hard for such systems to reason on, one could also use another class of system that are called proof assistants [START_REF] Geuvers | Proof assistants: History, ideas and future[END_REF]. Such systems may be able to produce a valid logical proof of the conjectures with the help of some additional input from their users. They may also make use of automated theorem provers to produce proofs of parts of their reasoning [START_REF] Blanchette | Extending sledgehammer with SMT solvers[END_REF]. For instance, there could exist a bridge crossing simulation that, given the model of an animal and the model of a bridge, can provide a proof detailing why the animal can or xiii cannot cross the bridge successfully. The user of such a system would then be tasked with providing the simulation with interesting animal and bridge models or abstractions in order to prove some given property on this bridge crossing experiment, such as what family of animals is always able to cross bridges. Again, a large collection of tools has been produced, in which each tool is well-adapted/oriented for handling a particular type of problem or formalism (such as program proofs [START_REF] Bobot | Why3: Shepherd your herd of provers[END_REF], mathematical or logic proofs [START_REF] Coquand | The calculus of constructions[END_REF][START_REF] Nipkow | Isabelle/HOL: a proof assistant for higher-order logic[END_REF], etc).

Concerning the ability to produce conjectures from a set of observations, various methods have also been explored. The method we take an interest in for this work is a logical formalism called abduction [START_REF] Josephson | Abductive inference: Computation, philosophy, technology[END_REF]. The idea behind it is, given some logical axioms and a set of facts unexplained by them, to look for additional conjectures that, when added to the initial axioms, allow us to explain those facts. For instance, even though they were shown evidence that not all animals can cross any bridge, our first person may be interested in finding additional restrictions that would make this possible, that is, additional conjectures stating among others the fact that a carp cannot cross a rope bridge. Examples of such conjectures would typically be restrictions on the shape of the animals or on the type of the bridge. Obviously, we do not want these additional conjectures to be too weak (typically by choosing the unexplained facts themselves, such as "if I am an animal that can cross a bridge, then I can cross a bridge"), or contradictory (such as "if I am an animal that is not an animal, then I can cross a bridge"). What we actually look for is a set of conjectures as generic as possible, consistent, and if possible minimal.

Many techniques have been tried to automatically perform abductive reasoning, some of which will be presented in Chapter 2. In this thesis, we devise a new method for it that is theory-generic and, as such, can be applied to solve abduction problems as long as there exists an algorithm to check if a given additional candidate permits to prove the initial goal. Our technique uses an initial set of abducible literals, that is, a set of elementary hypotheses we have good reasons to think may be part of satisfying additional candidates. The method then efficiently builds logical conjunctions of these literals to produce such additional candidates. The theorem prover is used to check whether these hypotheses permit to entail de desired property. If we go back to our illustration and assume that we do own some sort of animal-bridge checker that, given an animal and a bridge, can tell us whether or not the animal can cross the bridge, our algorithm would then build from an initial set of animal parts and bridge parts possible solutions for the problem. It will then check these possible solutions using the animal-bridge checker and return only those that work. As our algorithm returns minimal solutions, we will obtain the set of minimal restrictions on our animals and bridges that could allow them to successfully perform this crossing experiment.

Still, a picky person may wonder how we can be certain that the program we use to check if an animal can cross a bridge is not broken, giving results that are not actually consistent due to some implementation mistakes or design incompleteness. Thankfully, theorem proving can be naturally applied to the verification of systems [START_REF] Wos | Automated reasoning: introduction and applications[END_REF], in particular for computer software, hardware structures [START_REF] Gupta | Formal hardware verification methods: A survey[END_REF], etc. Indeed, with the development of computer programs and their applications to many critical tasks (such as traffic lights, automated pilot, banking, etc), people got interested in obtaining evidence that these programs were indeed executing the tasks they were designed to accomplish. This has first xiv been done extensively by running tests on the programs, but this method does not ensure any property out of the conditions of these tests, which can have tragic consequences.

In order to obtain such proofs, researchers have designed so-called static analysis verification techniques. Such techniques use the programs themselves along with a model of their behaviour to try and prove the expected properties. Here also, it is possible that a given technique fails to return a proof for a given program property. For those cases, researchers have designed methods to find additional preconditions on the inputs of a program that could be added to ensure that its properties are verified. Again, a brief overview of some of these techniques will be presented in Chapter 2. In this thesis, we use a generic algorithm developed in [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF] that uses abduction to solve this second problem. To prove a property on a program, such as the fact that a condition is always satisfied at the end of its execution, it is usually necessary to establish intermediate properties within the program, to show that those are also verified, that they are preserved by the loops of the programs or by the functions it invokes. By starting from an initially empty set of additional conjectures, we try to prove the properties expected from the handled program and, if this fails, we use abduction to produce the additional conjectures allowing the system to make this proof. Thanks to the genericity of the abduction algorithm we devised, we will be able to use this algorithm to target the generation of preconditions in a large range of problems.

This covers the scope of this thesis: the design of an automated theory-generic method of abduction and its application to program verification. It presents both the theoretical frameworks and their implementation and shows that they permit to generate solutions in a large range of theories.

Outline and publications

This thesis is organized as follows. After recalling the theoretical notions and terminology we use (Chapter 1) and presenting the related and state-of-the-art automated techniques used to solve the issues we introduced (Chapter 2), we will present our techniques for abductive reasoning (Part I) and for program verification (Part II, extending the work of Dillig et al. [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF]). These two works have been published and presented in international peer-reviewed committee computer science conferences: the abduction algorithm at the International Joint Conference on Automated Reasoning (IJCAR), 2018, Oxford, U.K. [START_REF] Echenim | A Generic Framework for Implicate Generation Modulo Theories[END_REF] and the theory-generic abduction-based loop invariant generator at the Frontiers of Combining Systems (FroCoS) conference, 2019, London, U.K. [START_REF] Echenim | Ilinva: Using abduction to generate loop invariants[END_REF]. These two theoretical framework descriptions will be followed in Part III by the details on how we implemented our approaches in practice. We will also perform an experimental evaluation of the resulting tools. Finally, Part IV will present a closely related implicant minimization algorithm extending a propositional logic model minimizer [START_REF] Bradley | Checking safety by inductive generalization of counterexamples to induction[END_REF]. This technique will use the models we can recover from the satisfiability tests we use to prove that a given set of literals is an implicant of a formula (such as the ones we used in Part I), construct an implicant from this model and refine this implicant by decomposing it into several components that will be weakened independently. This implicant minimizer will additionally be used to perform abduction in separation logic [START_REF] Reynolds | Separation logic: A logic for shared mutable data structures[END_REF].

Introduction xiii

. xv

Contents xvii

List of Algorithms and Interfaces xxii

List of Figures xxii

List of Tables xxiii

Aknowledgements 1

1 Context and general definitions 3 1.1 Usual notions of logics .

II Using abduction in verification

III Implementation and evaluation of the abduction algorithm

and of its application 11.4 Testing the minimization of separation-logic formulas . . . . . . . . . . . 11.5 Wrapping the minpart for performing abduction .

Conclusion

Future work List of Figures

List of Tables

Aknowledgements

First, I would like to thank all the members of my PhD committee for the time they invested in reading this thesis, for the comments the provided and for remaining available to reschedule the defense, test the video-conference system and attend this unusual defense in those times of covid-19 pandemic. I also want to thank my two advisors, Nicolas and Mnacho, for the wonderful job they have done supervising me, providing help and directions when needed and without whom I couldn't have hoped to achieve the results I present here. I can also thank the other members of the CAPP team for welcoming me and hosting me during this work.

A word to the friends I spent these years with: Nicolas, Valentin, Remy, Clément, Cyril, with whom I had the joy to share both interesting and uninteresting discussions as well as the tasteful meals of the university restaurants.

Finally, I have to thank my family for the support they haven given me throughout my thesis.

Chapter 1

Context and general definitions

This chapter presents the theoretical background that is common to all the parts of this work. We start by recalling usual notions of logic, then pursue with the definitions of the core concepts this work is built upon. In the last section, we will also recall definitions required by the use of theories as external dependencies.

Usual notions of logics

The notions and notations used within this work for propositional logic and first order logic are mostly standard. We present the exact formalism we use in this thesis and highlight some required differences with standard definitions, as introduced in, e.g., [START_REF] Caferra | Logic for computer science and artificial intelligence[END_REF]. Definition 1. A sorted signature Σ is a set of function symbols and types (or sorts), as well as a function σ assigning to every function in its domain a tuple of sorts the first element of which defines the return type of the function's value and the other elements define the type of its parameters. We assume that a signature Σ always contains a boolean sort B. If the return type of a function is this boolean sort, we will call this function a predicate. For clarity reasons, we will assume that the denomination function in this context will not refer to predicates. We will call arity of a function or predicate symbol the number of its parameters. If the arity of a function or predicate is equal to zero, we will call it a constant. We also assume that a countably infinite set of variables V of every sort is given.

In all the following, will assume given a fixed sorted signature Σ and a set of variables V on its sorts. Notation 2. Given a variable v ∈ V, we will denote by sort(v) the sort of the variable v. Definition 3. We define the terms on Σ recursively as follows:

• Any constant of Σ is a term.

• Any variable of V for any sort is a term.

• Given a function or predicate f in Σ such that σ(f ) = (s 0 , s 1 , . . . s n ) and t 1 , . . . , t n such that n is the arity of f and such that for any i ∈ 1, n , t i is either a constant of sort s i , a variable of sort s i or a term whose outermost symbol has the return type s i , then f (t 1 , . . . , t n ) is a term.

Remark 4. Note that, contrarily to the usual practice, we allow function or predicate symbols with boolean parameters. This choice has been made to ease the use of generic provers and fits in with the SMT-lib standard.

Remark 5. For simplicity reasons, we will assume that Σ contains an equality predicate for all the sorts it contains. We will denote these predicates using their usual infix notation , independently of the sort they apply to.

Definition 6. We call atoms the terms of the sort B. We will denote by K the set of atoms that can be built on Σ and V.

Definition 7. We define the set of logical formulas on Σ, denoted by S, inductively as follows:

• and ⊥ are elements of S.

• Any atom of K is an element of S.

• If φ ∈ S, then its negation ¬φ is in S.

• For any two formulas φ, ψ ∈ S, their conjunction φ ∧ ψ and their disjunction φ ∨ ψ are also formulas in S.

• Given a formula φ ∈ S and a variable v ∈ V the quantified expressions ∀v.φ and ∃v.φ are formulas in S.

Definition 8. We call literal either an atom of K or its negation. We will denote by L the set of all literals that can be built on Σ and V.

Notation 9. For any two formulas φ, ψ ∈ S, we will use the usual notations φ ⇒ ψ for ¬φ ∨ ψ and φ ⇔ ψ for (φ ⇒ ψ) ∧ (ψ ⇒ φ).

Definition 10. Given a formula φ ∈ S, we define φ the complement of φ inductively as follows:

• = ⊥.
• ⊥ = .

• If φ is an atom of L, then φ = ¬ψ.

• If φ = ¬ψ with ψ ∈ S, then φ = ψ.

• If φ = ψ 1 ∧ ψ 2 with ψ 1 , ψ 2 ∈ S, then φ = ψ 1 ∨ ψ 2 . • If φ = ψ 1 ∨ ψ 2 with ψ 1 , ψ 2 ∈ S, then φ = ψ 1 ∧ ψ 2 .
• If φ = ∀v.ψ with v a variable in Σ and ψ ∈ S, then φ = ∃v.ψ.

• If φ = ∃v.ψ with v a variable in Σ and ψ ∈ S, then φ = ∀v.ψ. We now briefly recall the usual notions of interpretation, model and satisfiability. Though we will mostly work with total interpretation and models in this thesis, partial models will be required in Section 3. 4. This explains why we give a definition for partial interpretations and not exclusively for total interpretations. Definition 12. Given a signature Σ, an interpretation of Σ is a tuple I : (I s , I f ) such that:

1. I s is a total function associating to each sort s in Σ a non-empty set of possible values denoted by I s (s). We also impose that, for any two sorts s 0 , s

1 in Σ, if s 0 = s 1 then I s (s 0 ) ∩ I s (s 1 ) = ∅. 2. I s (B) = { , ⊥}.
3. I f is a partial function associating to each function symbol f ∈ Σ, in the domain of σ and such that σ(f

) = (s 0 , s 1 , . . . , s n ), I f (f ) a function from I s (s 1 ) × . . . × I s (s n ) to I s (s 0 ).
Definition 13. Given a set of variables of V and an interpretation I, we call interpretation of the variables, and denote by I v , a partial function associating to any variable v of the sort s in its domain a value in I s (s). Given an interpretation of the variables I v , a variable v and x ∈ I s (sort(v)), we will denote by I v v →x the function defined on

Dom(I v ) ∪ {v}, such that ∀v ∈ Dom(I v ) \ {v}, I v v →x (v ) = I v (v) and such that I v v →x (v) = x.
Definition 14. Given a term t on Σ, an interpretation I and an interpretation of the variables of V I v , the evaluation of the term t, denoted by t I,I v , is defined inductively as follows:

• If t is a constant, then t I,I v is the image of I f (t) if t ∈ Dom(I f ) and is undefined otherwise. • If t is a variable, then t I,I v = I v (t) if t ∈ Dom(I v
) and is undefined otherwise.

• If t = f (t 1 , .
I v = I f (t)( t 1 I,I v , . . . , t n I,I v ).
Definition 15. Given a formula φ, an interpretation I of Σ and an interpretation of the variables I v , we call evaluation of φ in I, I v and denote by φ I,I v the value in { , ⊥, ι} defined inductively as follows:

•

I,I v = . • ⊥ I,I v = ⊥.
• If φ is an atom, then φ I,I v is equal to the evaluation of the term φ if it exists. Otherwise, φ I,I v = ι.

• If φ = ¬ψ then φ I,I v = if and only if ψ I,I v = ⊥ and φ I,I v = ⊥ if and only if ψ I,I v = . Otherwise, φ I,I v = ι. • If φ = ψ 1 ∧ ψ 2 then φ I,I v = if and only if both ψ 1 I,I v = and ψ 2 I,I v = . If either ψ 1 I,I v = ⊥ or ψ 2 I,I v = ⊥, then φ I,I v = ⊥. Otherwise, φ I,I v = ι. • If φ = ψ 1 ∨ ψ 2 then φ I,I v = if and only if either ψ 1 I,I v = or ψ 2 I,I v = . If both ψ 1 I,I v = ⊥ and ψ 2 I,I v = ⊥, then φ I,I v = ⊥. Otherwise, φ I,I v = ι.
• If φ = ∀v.ψ with v a variable in Σ then φ I,I v = if and only if, for any element

x in I s (sort(v)) we have ψ I,I v v →x = . If there exists an element x of I s (sort(v)) such that ψ I,I v v →x = ⊥, then φ I,I v = ⊥. Otherwise, φ I,I v = ι. • If φ = ∃v.ψ with v a variable in Σ then φ I,I v = if and only if there exists an x element of I s (sort(v)) such that ψ I,I v v →x = . If for any element x of I s (sort(v)) we have ψ I,I v v →x = ⊥, then φ I,I v = ⊥. Otherwise, φ I,I v = ι.
Given a closed formula φ and an interpretation I, we call evaluation of φ in I and denote by φ I the value φ I,∅ . Definition 16. We say that an interpretation I is total if I f is a total function. Otherwise, we say that I is a partial interpretation.

Proposition 17. Let I be a total interpretation. For any formula φ with no free variables, φ I ∈ { , ⊥}.

In all the following, unless we explicitly mention the use of partial interpretations, we will only consider closed formulas and total interpretations. Remark 19. We will assume that for any interpretation I and for any sort s of Σ, we have for the equality predicate of s that

I f ( ) = (t l , t r ) → t l = t r .
Definition 20. Given a formula φ and an interpretation I, we say that I is a model of φ if φ I = . In this case, we will write I |= φ.

If we review Example 18, we can say that the interpretation I is a model of a c ∧ ¬(a b).

Definition 21. Let φ 1 and φ 2 be two formulas. We say that φ 1 entails φ 2 , and write φ 1 |= φ 2 , if all the total models of φ 1 are also models of φ 2 . In this case, we will also say that φ 2 is a logical consequence of φ 1 .

Definition 22.

If there exists a model of a formula φ, we say that φ is satisfiable. If no such interpretation exists, we say that φ is unsatisfiable. Proposition 23. A formula φ is unsatisfiable if and only if φ |= ⊥.

Notation 24. As a consequence of proposition 23, we will use the notation φ |= ⊥ to denote that a formula φ is satisfiable and φ |= ⊥ to denote that φ is unsatisfiable.

Typically, a c ∧ ¬(a b) is a satisfiable formula, as we exhibited a model of it. The formula a b ∧ ¬(a b) however, does not admit any model, as an interpretation I such that a b I = will impose that ¬(a b) I = ⊥ and conversely. This formula is thus unsatisfiable.

Definition 25. Given a signature Σ and the set S of logical formulas we can build on it, we call theory a subset T ⊆ S such that any logical consequence of T belongs to T . We will say that an interpretation I is a model of the theory T if I |= T .

Definition 26. Let T be a theory. Given a formula φ and an interpretation I such that I |= T , we say that I is a T -model of φ, and write

I |= T φ, if φ I = .
If such an interpretation exists for a given formula φ, we will say that this formula is T -satisfiable. If no such interpretation exists, we will say that φ is T -unsatisfiable When all the total T -models of a formula φ are also models of another formula ψ, we will write φ |= T ψ and say that φ entails ψ in T or that ψ is a T -consequence of φ. Similarly to what we did in Notation 24, we may thus write φ |= T ⊥ to denote that φ is T -satisfiable and φ |= T ⊥ to denote that it is T -unsatisfiable.

Usual examples of theories include the theory of linear arithmetic [START_REF] Dutertre | A fast linear-arithmetic solver for dpll(t)[END_REF][START_REF] Griggio | A practical approach to satisfiability modulo linear integer arithmetic[END_REF] or the theory of arrays [START_REF] Brummayer | Boolector: An efficient smt solver for bit-vectors and arrays[END_REF]. The main goal of this work is to define systems that are theory-independent. This means that we do not want to design algorithms that will use particular properties of one given theory but rather that will remain generic until instantiated with external systems that deal with the specific theory.

In all the following, and unless specified otherwise, we will assume that we are given a specific but undetermined theory T . We will also assume the existence of a correct procedure to check whether a given formula is T -satisfiable or not, that is, for which it is guaranteed that when it gives an answer, this answer correctly describes the status of the formula. Even though it is clear that it is better to work with decidable procedures, we do not impose the decidability of the satisfiability problem in general. We will later propose solutions to handle semi-decidable procedures at the expense of some completeness properties for the algorithms we will present. Definition 28. We call tautology any formula that is satisfied by every total interpretation. Given a theory T , we call T -tautology any formula that is satisfied by every model of T .

Notation 29. In all the following, we will identify sets of formulas with the conjunction of their elements. That is, given a finite set of formulas Φ = {φ 1 , . . . φ n } and any other formula ψ, the notation ψ |= Φ will be equivalent to ψ |= i∈ 1,n φ i , the formula ψ ∧ Φ to ψ ∧ i∈ 1,n φ i , etc. Definition 30. We define clauses as possibly empty disjunctions of literals with no repetition. If a clause contains only one literal, we will call it is a unit clause. If a clause does not contain any literal, we will call it the empty clause.

A consequence of Definition 30 is that, for two clauses C and D, if C ∨ D is also a clause, then C and D share no literal.

For clarity reasons, we will also identify unit clauses with the literal they contain.

In this work, we will mostly study the generation of logical consequences that can be represented as clauses.

Notation 31. We will denote the empty clause by ⊥. This is justified by the fact that the empty clause has no model.

Implicates and implicants

The main line of contribution of the work presented here is the computation and usage of logical consequences of a given formula (the implicates of this formula). We will restrict this work to the computation of logical consequences in the form of clauses, and define the corresponding notions accordingly:

Definition 35. We say that a clause C is an implicate of a formula

ψ if ψ |= C. Similarly, we say that C is a T -implicate of ψ if ψ |= T C.
We also define the dual notion of implicants:

a set of literals Q is an implicant of ψ if Q |= ψ and a T -implicant of ψ if Q |= T ψ.
Remark 36. The definitions of implicates and implicants could be extended to include formulas that cannot be represented by a conjunction of clauses. As we will not compute formulas of this form in this work, we will stick to this definition to clarify what we compute.

It is easy to see that the implicates of a formula can be numerous and redundant. Let us take, for instance, the formula a b ∨ b c in the context of Example 11. If interpreted within the theory of linear arithmetic, this formula admits many implicates (such as ¬(a c) ∨ a b, a b ∨ a c ∨ b c, a b ∨ a c ∨ b c -in a different order -or a b ∨ b c -the formula itself) which could all be derived from the formula itself. This is why we are interested in a minimality property for the set of implicates of a formula. To obtain a set of implicates only composed of formulas that carry mutually distinct information from the others, we define the concept of prime implicates. Similarly to what we did in Definition 35, we will also consider the dual notion of prime implicant and prime T -implicant:

an implicant Q of a formula ψ is a prime implicant of ψ if for every implicant D of ψ, D |= Q only if Q |= D, and it is a prime T -implicant of ψ if for every T -implicant D of ψ, D |= T Q only if Q |= T D.
As previously explained, we will mostly consider sets of formulas (typically sets of implicates). This means that will we need a way to express whether a formula is already a consequence that could be derived from an element in the set. The following definitions serve this purpose.

Definition 38. Given a set of formulas Φ and a formula φ, we say that Φ strongly entails φ, and write Φ ||= φ, if there is a formula ψ ∈ Φ such that ψ |= φ. Identically, we will say that Φ strongly entails φ in T , and write Φ ||= T φ, if there is a formula ψ ∈ Φ such that ψ |= T φ. Definition 39. Given two sets of formulas Φ and Ψ, we say that Φ strongly entails Ψ, and write Φ ||= Ψ, if Φ strongly entails all the formulas in Ψ. Identically, we will say that Φ strongly entails Ψ in T , and denote Φ ||= T Ψ, if and only if ∀ψ ∈ Ψ, Φ ||= T ψ. Definition 40. We will say that two sets of formulas Φ 1 and Φ 2 are identical modulo T -equivalence if they verify both Φ 1 ||= T Φ 2 and Φ 2 ||= T Φ 1 . Such a property will be written Φ 1 ∼ T Φ 2 .

Such sets carry the same information about the consequences of the formulas they represent.

The following definitions are aimed at defining more precisely the problem we tackle, and a first requirement for that is the definition of a framework to reduce a set of implicates into a minimal equivalent one.

Notation 41. In all the following, we will assume the existence of a total well-founded order ≺ on clauses, that agrees with inclusion. This means that for any two clauses C and D, we will have C ≺ D whenever C D. Similarly, given a theory T , we call subsumption minimal equivalent in T , and denote by SubMin T (Φ), the set obtained by deleting from Φ all clauses D such that either 1. D is a T -tautology. Proof. SubMin(Φ) ⊂ Φ by definition. This gives us that Φ ||= T SubMin(Φ) as any formula entails itself. Now let us take a formula D ∈ Φ. If D ∈ SubMin(Φ), then it entails itself and we have found a satisfying entailing formula. If it is not the case, then by Definition 43, it is either a T -tautology (in which case it is entailed by any formula of SubMin(Φ)) or it verifies the second point of the definition. In this case, there exists C ∈ Φ entailing D that is either not entailed by D or smaller than D with respect to ≺. If C ∈ SubMin(Φ), we have found our entailing clause. If not, we can recursively apply the same definition to C. We are certain to find one clause of SubMin(Φ) because ≺ is well-founded, This gives us that SubMin(Φ) ||= T Φ Definition 46. In the following, we will also consider the notion of abducible literals, that is, a finite subset of L upon which we want to obtain implicates or implicants of a given formula.

Given a set of abducible literals A, we will say that an implicate I of a formula φ is an A-implicate of φ if I ⊆ A. Similarly, we will say that an implicant

I of φ is an A-implicant of φ if I ⊆ A, that a T -implicate I of φ is a (T , A)-implicate of φ if I ⊆ A, and that a T -implicant I of φ is a (T , A)-implicant of φ if I ⊆ A.
Intuitively, the set of abducible literals will contains the literals that are considered interesting in the context of the formula we are studying. Typically, if the formula is obtained from the logical representation of a program, it could exclude the literals containing symbols not corresponding to any inputs available to the programmer.

Example 47. Let us consider the sample program presented in Algorithm 1.1 on two integer inputs x and y. And let us consider the problem of computing a sufficient precondition for the program not to perform a division by zero at Line 4. An obvious precondition for this to be verified would be that δ = 0. However, it is clear that, in the context, the user has no way to act directly on the value of δ, as it is a variable only used by the program internally. This means that the precondition we are actually interested in is expressed in the form of x + y = 0 (which in this case is strictly equivalent). This type of issue can be solved by using this concept of abducible literals. Indeed, in this context composed of the three integer constants x, y, δ, will we define a set of abducible literals such that it does not contain any literal referencing δ. This will permit to prune the logical solutions containing it and to generate only the ones that are relevant in the context.

Algorithm 1.1: SP0 1 input x Int; 2 input y Int; 3 let δ ← x + y; 4 return x δ ;
It is clear that the notion of abducible literals puts an additional burden on the user of any method using it, as he will also be tasked with defining this set and forwarding it to the system. We will see (Chapter 6.4) however that we can design generic methods relevant to the problems we tackle that generate sets of abducible literals that, even if they contain some non-relevant elements, allow to obtain an acceptable solution for the problems we aim to solve.

We now define the notations we will use to represent the sets of implicates we will generate.

Notation 48. For any given theory T , set of formulas Φ and set of abducible literals A, we will denote by I T ,A (Φ) the set consisting of all the (T , A)-implicates of Φ, and by I * T ,A (Φ) the one consisting all the prime (T , A)-implicates of Φ.

In a context where we do not consider any theory, we will also use the notation I A (Φ) for the set of A-implicates of Φ, as well as I * A (Φ) for its prime A-implicates. Likewise, we will allow the notations I T (Φ) and I * T (Φ) when a theory but no abducible literal set is considered.

Theories as external dependencies

As explained in both this chapter's introduction and content, one of the major advantages of the work presented in this thesis is its independence on the concrete theory it handles. Users can express the problems they want to solve in the theory they deem appropriate then plug our systems with tools that can handle the theories they chose. This genericity suggests that we can abstract the usage of the theory-dependent elements used within the methods we provide. This will be done through the framework we present in this section.

Definition 50. Given a signature Σ and a theory T , we call satisfiability problem in T the problem of deciding whether a given formula admits a model in T , that is if there exists a model of T that is also a model of this formula.

In the work presented in this thesis, all the tasks delegated to theory-related operations will be in the form of satisfiability tests. This means that as long as one can provide an algorithm to decide such satisfiability queries in a theory, it will be possible to use the methods presented in this work within this theory. We formalize this fact with the following definition: Definition 51. By a slight abuse of words, we will say that a given theory T is decidable if there exists an algorithm that is able to decide for any formula φ expressible within T if it admits a model in T or not. If no such algorithm exists, we shall say that T is undecidable.

In what follows, when we talk about theories and genericity modulo theories, we restrict ourselves to decidable theories, because the queries we require an answer for are satisfiability tests. We point out here that more general properties could be derived as, technically, we should not require full decidability for the theories we use, but only that of the fragment we use. We will also see that, in practice (see Chapters 6.4 and 8), we can in some cases tweak our algorithms to bypass some satisfiability tests whose results cannot be computed but still reach an acceptable conclusion for the problem we tackled. However, within the theoretical presentation of those methods, we will stick to decidable theories.

We will call decision procedure any algorithm that decides a satisfiability problem in at least one theory. The theory will be detailed when necessary and a decision procedure for a given theory T will be called a T -decision procedure. A technical system for computationally deciding such queries is called an SMT-solver [78,10,[START_REF] Moura | Satisfiability modulo theories: Introduction and applications[END_REF][START_REF] Monniaux | A survey of satisfiability modulo theory[END_REF]. Such systems usually implement several T -decision procedures.

We will assume that a decision procedure will always return an element of B = {Sat, Unsat, Unknown}. For a formula φ and a theory T , we will assume that the decision procedure ensures the following:

1. If it returns Sat, then φ is T -satisfiable. 2. If it returns Unsat, then φ is T -unsatisfiable.
If T is a decidable theory, we will assume that any decision procedure handling this theory will never return Unknown. Even though, in practice, an SMT-solver may still return Unknown.

When Sat is returned, the decision procedure (and the SMT-solver) may additionally return a model of the formula it computed. If it is the case, we assume that we can retrieve this model.

In all the following, every time we test a satisfiability problem, we will assume that it is handled by a decision procedure handling the underlying theory. We assume that such queries will thus be handled by an SMT-solver in any practical system implementing the algorithms we will define in Chapters 3 to 6. An SMT-solver is incremental if it offers a way to update only a part of the formula it was trying to determine the satisfiability of. Intuitively, we expect that if the SMT-solver previously obtained a result for an initial formula, the computation for the updated one will be more efficient than if it was restarting from scratch.

Such solvers are particularly adapted to algorithms that compute their solutions by incrementally building hypotheses and test them against a given formula until reaching the desired conclusion. As we will see in the following chapters, the algorithms we design in this work comply with this framework, which makes the use of incremental SMT-solver to decide the satisfiability tests they contain particularly relevant.

This consideration concludes this chapter of global definitions to which the readers can continuously refer when browsing this document. The readers can also read the Index of definitions and symbols at the end of this document. They will be redirected from there to the corresponding definition within this chapter or any of the following ones.

Chapter 2

State of the art

This chapter aims at presenting the context the research of this thesis was carried out in. The terminology used in this chapter complies with the one introduced in Chapter 1 and any additional notion specific to this chapter will be specified when it is used. We start by presenting the related methods for the abduction technique we consider in this work: the generation of the prime implicates of logical formulas. Prime implicate generation, and abduction in general, is used in a wide range of applications and in a large range of logical frameworks. We can note in particular its use in error diagnosis [START_REF] Dillig | Automated error diagnosis using abductive inference[END_REF] and program synthesis as well as its recent applications to description logic [START_REF] Klarman | Abox abduction in the description logic alc[END_REF][START_REF] Del-Pinto | Forgetting-based abduction in alc[END_REF][START_REF] Du | Practical tbox abduction based on justification patterns[END_REF] and separation logic [START_REF] Calcagno | Compositional shape analysis by means of bi-abduction[END_REF][START_REF] Distefano | A local shape analysis based on separation logic[END_REF]. In this thesis we consider an application of abductive reasoning to generate (property-directed) loop invariants of programs, that is, formulas associated to a program loop that should be and remain true whenever the loop is executed (see also Definition 130). Thus, we will also briefly introduce alternatives and state-of-the-art algorithms for performing loop invariant generation.

Prime implicate computation

We start by presenting in this section an overview of the various methods existing for performing abduction by computing prime implicates, that is, minimal clausal consequences of a given formula (see also Definitions 35 and 37). Prime implicate computation is a natural method to perform abduction. Indeed, finding the missing conjunctive hypotheses M allowing a formula φ to entail another formula ψ (i.e. ensuring that φ ∧ M |= ψ) can be done simply by computing the implicates of φ ∧ ¬ψ. The negation of any such implicate is a conjunctive hypothesis ensuring such an entailment.

Example 52. Let us consider the following logical formula over the four boolean variables p, q, r, s:

φ = (p ∨ ¬q ∨ r) ∧ (q ∨ ¬r ∨ ¬s) ∧ (¬p ∨ ¬q ∨ s)
If one wants to find the minimal set for inclusion of minimal consequences of φ expressed in the form of disjunctions of boolean constants or their negation, they will find that the three disjunctions (made explicit by the lines of the formula description) belong to this set. Moreover, the clause C = ¬q ∨ r ∨ s is another consequence that was not originally part of the formula. Any consequence of φ will be a logical consequence of one of these four disjunctive formulas.

Early prime implicate computation in propositional logic

The concept of prime implicate for propositional logic was introduced by Quine [START_REF] Quine | A way to simplify truth functions[END_REF] at the beginning of the second half of the twentieth century. Since then, work has been done to develop techniques to automatically compute the prime implicates of a propositional formula. The complexity of this computation has been found to be DPhard [START_REF] Knuth | Postscript about np-hard problems[END_REF][START_REF] Leeuwen | Handbook of Theoretical Computer Science: Algorithms and Complexity[END_REF][START_REF] Eiter | The complexity of logic-based abduction[END_REF][START_REF] Bienvenu | Prime implicates and prime implicants: From propositional to modal logic[END_REF]. This ensures that any general algorithm automatically computing the prime implicates of propositional formulas will have at least an exponential complexity (unless P = NP).

For almost twenty years, the tools tackling this problem were built upon a specific representation of propositional formulas: the minterm representation [START_REF] Boole | The Calculus of Logic[END_REF]. This consists in substituting the formula by the set of its models, usually represented as sequences of boolean values to explicitly exhibit the value of each propositional variable in a given model.

Example 53. Let us consider once again the formula φ of Example 52. This formula admits ten models:

p = , q = , r = ⊥, s = (2.1)
p = , q = , r = , s = (2.2)
p = , q = ⊥, r = ⊥, s = ⊥ (2.3) p = , q = ⊥, r = , s = ⊥ (2.4) p = , q = ⊥, r = ⊥, s = (2.5) p = ⊥, q = , r = , s = (2.6) p = ⊥, q = , r = , s = ⊥ (2.7) p = ⊥, q = ⊥, r = , s = ⊥ (2.8) p = ⊥, q = ⊥, r = ⊥, s = ⊥ (2.9) p = ⊥, q = ⊥, r = ⊥, s = (2.10)
By always representing the variables in the order p, q, r, s and interpreting 0 as ⊥ and 1 as , we can represent φ using the minterm representation by the set {(1, 1, 0, 1), (1, 1, 1, 1), (1, 0, 0, 0), (1, 0, 1, 0), (1, 0, 0, 1), (0, 1, 1, 1), (0, 1, 1, 0), (0, 0, 1, 0), (0, 0, 0, 0), (0, 0, 0, 1)}.

This representation is space consuming (exponential w.r.t. to the size of the initial formula), which is one of the main reasons why, even though polynomial algorithms were found to compute the prime implicates of formulas previously rewritten using minterms [START_REF] Strzemecki | Polynomial-time algorithms for generation of prime implicants[END_REF], those were never able to perform efficiently on even reasonably sized problems. We let the reader refer to more detailed surveys (e.g. [START_REF] Raut | A survey on computing prime implicants and implicates in classical and non-classical logics[END_REF]) for additional information on these early works.

Around 1970, people started working on alternative approaches for computing prime implicates, which were based directly on the formula. These methods are usually arranged in two categories: those based on the resolution rule and those based on a decomposition of the formula, though other approaches not fitting in any of these classes also exist.

Resolution-based prime implicate computation in propositional logic

Prime implicate computation methods fitting in this category are built upon the resolution calculus [4] which consists of the following rule:

Definition 54. Given two clauses (disjunctions of boolean variables or their negation, see also 30) C = l ∨ χ and D = ¬l ∨ ρ, the (propositional) resolution rule is

C D χ ∨ ρ
The clause that is generated is called a resolvent.

As this rule is defined for clauses, these methods will require their input formula to be in conjunctive normal form (CNF). They will then select two clauses, produce their resolvent and remove both the tautologies and the clauses subsumed by another within the updated clause set. This will be performed until a fixed-point in found for the set of clauses, this fixed-point being the expected set of prime implicates of the formula.

Example 55. Let us consider once again the formula φ of Example 52. The clausal form of this formula consists of three clauses {p ∨ ¬q ∨ r, q ∨ ¬r ∨ ¬s, ¬p ∨ ¬q ∨ s}. Applying the resolution rule on these clauses will, most of the time, result in a valid clause (that is, satisfied in all interpretations or a tautology). For instance, applying the resolution rule on the clauses p ∨ ¬q ∨ r and q ∨ ¬r ∨ ¬s on the variable q generates the resolvent p ∨ r ∨ ¬r ∨ ¬s which is a valid clause. One can get the missing implicate of this set by applying the resolution rule on p ∨ ¬q ∨ r and ¬p ∨ ¬q ∨ s for the variable p. Once all the tautologies have been removed, and as no smaller clauses can be generated, the set will be composed of all the prime implicates of φ.

An improvement of this algorithm introduced by Tison [START_REF] Tison | Generalization of consensus theory and application to the minimization of boolean functions[END_REF] and refined as the incremental technique IPIA [START_REF] Kean | An incremental method for generating prime implicants/implicates[END_REF] makes use of an order on the variables. By following this order and applying all the possible resolutions on a given variable at the same time, it is able to limit as much as possible the number of redundant resolution steps, as it avoids the need to reapply the resolution rule on one of the previously handled variables. It is also important to consider the problem of selecting on which clauses the resolution rule should be applied, as a smarter choice has a good chance to reduce the total number of steps of the algorithm. Such techniques have been implemented in yet another incremental refinement of Tison's method called PIGLET [START_REF] Jackson | Computing prime implicates incrementally[END_REF], where the authors have chosen to prioritize the selection of clauses sharing literals, producing smaller resolvents that are more likely to be minimal. This technique was found to be more efficient than IPIA.

Another line of work that has been investigated over IPIA and Tison's method is related to the efficiency of clausal subsumption tests. By using tries [START_REF] Fredkin | Trie memory[END_REF] to store the clauses (thus represented as ordered sets of literals), one can perform the subsumption tests directly within the storage structure which improves the general performance significantly. This was implemented in a method called CLTMS [START_REF] De Kleer | An improved incremental algorithm for generating prime implicates[END_REF] which incrementally constructs the trie of all the prime implicants for a formula. The method permitted to solve non-trivial prime implicate generation problems for the first time.

Refining this work on the efficient storage of prime implicates, Simon and del Val proposed a last algorithm based on Tison's method [START_REF] Simon | Efficient consequence finding[END_REF] called ZRes or ZRes- Tison. In ZRes-Tison, clauses are represented using Zero-suppressed binary decision diagrams (or ZBDDs) [START_REF] Minato | Zero-suppressed bdds for set manipulation in combinatorial problems[END_REF], in which they appear as paths between the root and a 1-labeled terminal node (see Figure 2.2). Moreover, by applying multi-resolution (a variant of the resolution calculus) directly on the ZBDD, ZRes-Tison can perform all the resolutions on a given variable at the same time, thus making the algorithm independent of the number of actual resolution steps. All those considerations allow ZRes-Tison to produce ZBDDs containing all the prime implicates of a set of clauses very efficiently.

Decomposition-based prime implicate computation in propositional logic

The other main class of prime implicate generators (those not built upon inference rules) is usually referred to as decomposition-based. Algorithms is this category tend to decompose their input problems into smaller formulas, clauses, conjunction of literals, etc, recursively compute a result on these smaller part and finally merge these computed results. Depending on the type of decomposition they perform, they may accept more various forms of input problems than the one we described in the previous subsection (such as disjunctive normal forms (DNF), negative normal forms (NNF)). One of the oldest decomposition-based prime implicate generation method is called the Tree Method [START_REF] Slagle | A new algorithm for generating prime implicants[END_REF]. It works by constructing the set of prime implicates by a depth-first search in an ordered semantic tree with edges labelled by literals and nodes labelled by DNF formulas. This technique has also been improved by using set enumeration trees, a generalization of the semantic trees used in the Tree Method [START_REF] Rymon | An se-tree-based prime implicant generation algorithm[END_REF].

The Matrix Method [START_REF] Jackson | Computing prime implicants[END_REF] is another approach similar to the Tree Method but browsing the tree in breadth instead and labelling nodes based on conjunctions of literals instead of the literals themselves. Jackson and Pais additionally compared the two approaches and showed that their method (Matrix Method) performed better. By requiring their input formula to be expressed in a specific form before being processed (CNF, DNF, NNF), the prime implicate generators previously introduced (including those based on resolution) can be impractical to use in some contexts [START_REF] Ngair | A new algorithm for incremental prime implicate generation[END_REF][START_REF] Ramesh | Cnf and dnf considered harmful for computing prime implicants/implicates[END_REF][START_REF] Ramesh | Some applications of non clausal deduction[END_REF]. GEN-PI [START_REF] Ngair | A new algorithm for incremental prime implicate generation[END_REF] is an incremental algorithm proposed to solve this issue. By computing closure operations, it is able to compute all the prime implicates of inputs expressed as conjunctions of DNF formulas. Ngair showed that this algorithm is as efficient as CLTMS in general but exhibits much better performances on formulas one cannot easily represent in normal form. An alternative approach extending the Matrix Method for NNF formulas [START_REF] Ramesh | Some applications of non clausal deduction[END_REF][START_REF] Ramesh | Cnf and dnf considered harmful for computing prime implicants/implicates[END_REF] by looking for paths in a previously simplified graph representation of the NNF formula has also been tried, but it was found to require numerous subsumption tests.

A tentative to reduce the need for logical operation by choosing an adequate representation of the input and results was proposed by Coudert and Madre in 1992. They combined the use of Binary decision diagrams (BDD) [1] to store clauses and a metaproduct representation of the variables of an initial DNF formula. This resulted in an algorithm only depending on BDD operations to compute the prime implicates, which put into light the need for a variable ordering leading to a BDD as compact as possible. Most such orderings are heuristic-based (see e.g. [START_REF] Manquinho | Models and algorithms for computing minimum-size prime implicants[END_REF]).

Manquinho et al. [START_REF] Manquinho | Models and algorithms for computing minimum-size prime implicants[END_REF] later compared Coudert and Madre's method with a more efficient strategy, introduced by Errico et al. [START_REF] Errico | Finding prime implicants by minimizing integer programming problems[END_REF], and making use of integer linear programming (ILP) [START_REF] Schrijver | Theory of linear and integer programming[END_REF]. This technique computes the prime implicates of a DNF formula by converting it into an ILP problem by representing literals with integer variables and constructing constraints that correspond to the formulas of the problem. It is also able to compute the prime implicates one at a time and can be hinted on the literals the next generated implicate should be comprised of. The other major advantage of the use of integer linear programming is that it gives us access to all the techniques already developed for solving such problems. The prime implicate generator exposed in [START_REF] Manquinho | Models and algorithms for computing minimum-size prime implicants[END_REF] made use of the search algorithm GRASP [START_REF] Silva | Grasp—a new search algorithm for satisfiability[END_REF][START_REF] Nieuwenhuis | Solving sat and sat modulo theories: From an abstract davis-putnam-logemann-loveland procedure to dpll(t)[END_REF], inspired from the propositional satisfiability testing algorithm DPLL [START_REF] Davis | A computing procedure for quantification theory[END_REF][START_REF] Davis | A machine program for theorem-proving[END_REF], and specifically optimized for its use in prime implicate generation.

Coudert and Madre's technique [START_REF] Madre | A new method to compute prime and essential prime implicants of boolean functions[END_REF] has been reused beside ILP to produce many other modern decomposition-based prime implicate generators. Examples include the algorithm by Henocque [START_REF] Henocque | The prime normal form of boolean formulas[END_REF] creating three cases for the variables of DNF input formulas in a DPLL fashion and Matusiewicz et al.'s method using prime implicate tries [START_REF] Matusiewicz | Prime implicate tries[END_REF][START_REF] Matusiewicz | Tri-based set operations and selective computation of prime implicates[END_REF] for CNF formulas. By using BDDs in the first case and prime implicate tries in the latter to store the prime implicates efficiently, these techniques managed to tackle problems with up to tens of quintillions of prime implicates. The refinement of Matusiewicz et al.'s method [START_REF] Matusiewicz | Tri-based set operations and selective computation of prime implicates[END_REF] was also shown to perform twice as fast as resolution-based methods.

Other approaches for prime implicate computation in propositional logic

More recently, alternative approaches have emerged for generation of prime implicates.

For instance, Bittencourt et al. applied the use of quantum notation [START_REF] Bittencourt | Combining syntax and semantics through prime form representation[END_REF] on DNF formulas, which annotates each literal with the identifiers of each conjunction of literals it belongs to and then selects the smallest set of quanta covering all terms to obtain the prime implicates. Alternative approaches also include the work of Ribeiro et al. [START_REF] Ribeiro | Learning Prime Implicant Conditions From Interpretation Transition[END_REF] which learns transition rules and uses specialization to obtain the prime implicants of a formula.

Finally, the most efficient method to generate prime implicates in propositional logic up to this date is built upon works from Jabbour et al. [START_REF] Jabbour | Enumerating prime implicants of propositional formulae in conjunctive normal form[END_REF] and Palopoli et al. [START_REF] Palopoli | Algorithms for selective enumeration of prime implicants[END_REF] and reduces the problem of computing prime implicates to a model building problem by transforming the formula. It is thus possible to obtain the prime implicates of the initial formula by performing a model enumeration of the new one [START_REF] Previti | Prime compilation of non-clausal formulae[END_REF].

Example 56. Consider one last time the formula φ of Example 52. The method of Previti et al. generates the equisatisfiable formula ψ ∪ D where ψ = (l p ∨ l ¬q ∨ l r ) ∧ (l q ∨ l ¬r ∨ l ¬s ) ∧ (l ¬p ∨ l ¬q ∨ l s ) and D = (¬l p ∨ ¬l ¬p ) ∧ (¬l q ∨ ¬l ¬q ) ∧ (¬l r ∨ ¬l ¬r ) ∧ (¬l s ∨ ¬l ¬s ).

The method then generates formulas encoding the fact that when a variable is evaluated to true, then the clause it appears in does not require its literals to be true any longer. In our case, this gives us the following formulas:

(¬l p ∨ ¬l ¬q ) ∧ (¬l p ∨ ¬l r ) (2.11) (¬l ¬q ∨ ¬l p ) ∧ (¬l ¬q ∨ ¬l r )
(2.12)

(¬l r ∨ ¬l ¬q ) ∧ (¬l r ∨ ¬l p ) (2.13)
(¬l q ∨ ¬l ¬r ) ∧ (¬l q ∨ ¬l ¬s ) (2.14)

(¬l ¬r ∨ ¬l q ) ∧ (¬l ¬r ∨ ¬l ¬s ) (2.15)
(¬l ¬s ∨ ¬l q ) ∧ (¬l ¬s ∨ ¬l ¬r ) (2.16)

(¬l ¬p ∨ ¬l ¬q ) ∧ (¬l ¬p ∨ ¬l q ) (2.17) (¬l ¬q ∨ ¬l ¬p ) ∧ (¬l ¬q ∨ ¬l s ) (2.18) (¬l s ∨ ¬l ¬p ) ∧ (¬l s ∨ ¬l ¬q ) (2.19)
From this onwards, the algorithm looks for the models of the union of these formulas with ψ ∪ D to find the implicants or the implicates of φ.

This method has been implemented in a tool called primer and found to perform better than all the previously introduced methods.

If the reader is interested in a more complete survey of the methods and algorithms presented in this chapter for the computation of prime implicates of propositional formulas, it can refer to, e.g., [START_REF] Marquis | Consequence finding algorithms[END_REF]. .

Prime implicate computation out of propositional logic

To extend prime implicate generation out of propositional logic, various lines of work have been explored [START_REF] Inoue | Consequence-finding based on ordered linear resolution[END_REF][START_REF] Marquis | Extending abduction from propositional to first-order logic[END_REF][START_REF] Knill | Equality and abductive residua for horn clauses[END_REF][START_REF] Mayer | First order abduction via tableau and sequent calculi[END_REF][START_REF] Raut | Prime implicants of first order formulas via transversal clauses[END_REF][START_REF] Raut | Prime implicates of first order formulas[END_REF][START_REF] Bienvenu | Prime implicates and prime implicants in modal logic[END_REF][START_REF] Tran | Combination of Convex Theories: Modularity, Deduction Completeness, and Explanation[END_REF][START_REF] Raut | An incremental knowledge compilation in first order logic[END_REF][START_REF] Dillig | Minimum satisfying assignments for smt[END_REF][START_REF] Raut | An incremental algorithm for computing prime implicates in modal logic[END_REF][START_REF] Echenim | Quantifier-free equational logic and prime implicate generation[END_REF][START_REF] Tourret | Prime implicate generation in equational logic[END_REF][START_REF] Echenim | Prime implicate generation in equational logic[END_REF], mainly focusing on restricted subsets of logical interest of the theory their consider. This first required to extend the notion of prime implicate to first-order logic, which was done by Marquis in 1991 [START_REF] Marquis | Extending abduction from propositional to first-order logic[END_REF], which also permitted to identify related issues that were not present in propositional logic, such as the minimality of the set of implicates or the undecidability of their computation. These additional difficulties led to the subsequent definition of classes of first-order logic formulas for which the computation of prime implicates can be performed, such as the clauses of bounded length and of bounded depth. Most methods devised to compute prime implicates in first-order logic use either first-order resolution [START_REF] Marquis | Extending abduction from propositional to first-order logic[END_REF] or the sequent calculus [START_REF] Mayer | First order abduction via tableau and sequent calculi[END_REF]. The greater complexity of the problem is probably a cause to the fact that only few prime implicate generators for first-order logic can display reasonable performance. One of them is the SOL calculus [START_REF] Inoue | Consequence-finding based on ordered linear resolution[END_REF], for full first-order logic, based on tableau resolution for theorem refutation [START_REF] Hähnle | Tableaux and related methods[END_REF]. After building a tableau for the formula, it uses a skip rule to stop developing branches of the tableau without refuting them, letting the leaves of the skipped branches form an implicate of the formula. This method has been implemented in a Java program called SOLAR [START_REF] Nabeshima | Solar: An automated deduction system for consequence finding[END_REF]. By using a modification method [START_REF] Brand | Proving theorems with the modification method[END_REF][START_REF] Iwanuma | Toward an efficient equality computation in connection tableaux: A modification method without symmetry transformation[END_REF], the tool can also work natively with equational formula [START_REF] Tarski | Equational logic and equational theories of algebras[END_REF].

Another method of practical use for the computation of prime implicates in subsets of first-order logic has been devised by Dillig et al. [START_REF] Dillig | Minimum satisfying assignments for smt[END_REF]. It can be used for any formula expressed in a first-order theory for which both a quantifier elimination procedure and a decision procedure for satisfiability exist, and has been implemented within the MISTRAL SMT-solver [START_REF] Dillig | Mistral smt solver[END_REF][START_REF] Dillig | Automated error diagnosis using abductive inference[END_REF], using a branch and bound algorithm. This method is, however, not complete, and only computes the implicates of the formula that can be expressed as the negation of minimum partial variable assignments falsifying the formulas.

Prime implicate generation methods targetting other specific logics have also been developed. Examples of such techniques include the work of Knill et al. [START_REF] Knill | Equality and abductive residua for horn clauses[END_REF] which analyses unification failures to generate prime implicates for first order logic or equational logic formulas, the work of Tran et al. [START_REF] Tran | Combination of Convex Theories: Modularity, Deduction Completeness, and Explanation[END_REF] using the superposition calculus [3] to generate positive and unit prime implicates and the work of Sofronie-Stokkermans [START_REF] Sofronie-Stokkermans | Hierarchical reasoning for the verification of parametric systems[END_REF][START_REF] Sofronie-Stokkermans | Hierarchical reasoning and model generation for the verification of parametric hybrid systems[END_REF] relying on external first-order satisfiability checkers to generate application-targetted constraints. It was shown however [START_REF] Knill | Equality and abductive residua for horn clauses[END_REF][START_REF] Echenim | An approach to abductive reasoning in equational logic[END_REF] that the superposition calculus is not complete out of the scope of positive unit prime implicates. Furthermore, no result simplification procedure is known to simplify the constraints generated in [START_REF] Sofronie-Stokkermans | Hierarchical reasoning for the verification of parametric systems[END_REF][START_REF] Sofronie-Stokkermans | Hierarchical reasoning and model generation for the verification of parametric hybrid systems[END_REF].

To bypass these limitations, Tourret et al. devised an alternative approach using instantiated equality axioms [START_REF] Echenim | Quantifier-free equational logic and prime implicate generation[END_REF][START_REF] Echenim | Prime implicate generation in equational logic[END_REF] built over the work of de Kleer et al. [START_REF] De Kleer | An improved incremental algorithm for generating prime implicates[END_REF]. This approach is based is based on constrained calculus defined by the usual inference rules of the superposition calculus together with additional rules to dynamically assert new abducible hypotheses on demand into the search space. The asserted hypotheses are attached to clauses as constraints and, when an empty clause is generated, the negation of these hypotheses yields an implicate. They shown that their approach, targetting the generation of prime implicates in equational logic, offered better results than previously mentioned approaches.

Other approaches experimenting the generation of prime implicate in other logics such as modal logics [START_REF] Blackburn | Handbook of Modal Logic[END_REF][START_REF] Bienvenu | Prime implicates and prime implicants in modal logic[END_REF][START_REF] Raut | An incremental algorithm for computing prime implicates in modal logic[END_REF], where decomposition algorithms similar to those used in propositional logic have been devised.

Loop invariant generation

We present in this section a brief overview of some known practical techniques to generate loop invariants of programs. As a lot of work has been done on this problem, we do not try to provide the reader with an exhaustive introduction to the many existing approaches. More complete descriptions of method-specific techniques can be found in e.g. [START_REF] Silva | A survey of automated techniques for formal software verification[END_REF][START_REF] Miné | Tutorial on Static Inference of Numeric Invariants by Abstract Interpretation[END_REF][START_REF] Monniaux | A survey of satisfiability modulo theory[END_REF]. Rather, we present a small introduction that should help the readers familiarize themselves with the loop invariant generation issue and get some pointers on the efficient techniques that have been proposed to tackle it.

Example 57. Let us consider the very simple program presented in Sample Program 2.1, for which we would have to obtain a proof of the proposition it contains at its last line (y ≥ 1). It is clear that, in this case, the expected property cannot be derived from the negation of the loop condition. This means that the proof will require an invariant for the loop from which we would be able to derive the asserted formula. A satisfying invariant for this program would be, e.g., y ≥ 1 ∧ x ≥ 1, in which the first part ensures the validity of the assertion and the second part is necessary to ensure that this property is preserved by the loop (see also Example 131). The problem considered here is the one of automatically generating such an invariant.

The work on loop invariant generation derived from early works on automated program verification [START_REF] Hoare | An axiomatic basis for computer programming[END_REF][START_REF] Karr | Affine relationships among variables of a program[END_REF]. Those led to many different approaches that are usually Sample Program 2.1: LoopCheck1() classified as either static or dynamic.

1 let x ← 1; 2 let y ← 1; 3 while random({ , ⊥}) do 4 invariant [?]; 5 let _x ← x;

Static loop invariant generation

Static approaches for loop invariant generation consist in building an abstract representation of the considered programs from which we can derive interesting properties. The first historical approaches for loop invariant generation fall in this category (see e.g. [START_REF] Karr | Affine relationships among variables of a program[END_REF]). One of the most successful approach for static property inference is the Abstract interpretation framework [START_REF] Cousot | Abstract interpretation: A unified lattice model for static analysis of programs by construction or approximation of fixpoints[END_REF][START_REF] Cousot | Automatic discovery of linear restraints among variables of a program[END_REF], which performs a symbolic execution of the program over an abstract domain. It then computes over-estimations of possible memory states after an unbounded number of loop iterations and removes from these sets the ones it finds contradict other known program constraints. This process is then repeated until a fixed point is reached, which gives us the invariant exhibited by the method on the selected abstract domain.

Example 58. Let us consider the Sample Program 2.1. Now let us consider a symbolic execution of this program over the abstract domain of linear inequalities, that is, associating to each program state a set intervals for each variable, representing its execution. After the initial assignments of Lines 1 and 2, the program state would typically be {1 ≤ x ≤ 1, 1 ≤ y ≤ 1}. To obtain an invariant from this symbolic execution, an abstract interpretation framework will start by executing the content of the loop one time on its abstract domain. As both variables are increased by the value of the other, this would give us, at the end of Line 8, the set {2 ≤ x ≤ 2, 2 ≤ y ≤ 2}. Now, the program will detect that some of the states represented by the set are unreachable due to the condition of the loop (as the loop may never be entered due to its condition). Removing these unreachable states from the intervals we obtained would give us the updated set {1 ≤ x ≤ 2, 1 ≤ y ≤ 2}. By executing the code of the loop again and repeating the same state exclusion process (and, as required in this case, by using a widening operation to obtain the limit of the execution states), the framework will generate the fixed point representing the set of abstracted states reachable at the end of loop on the domain of integer intervals: {1 ≤ x ≤ +∞, 1 ≤ y ≤ +∞}. This set gives us an invariant for the considered loop (x ≥ 1 ∧ y ≥ 1) and additionally permits to prove the assertion Line 9.

The technique has been refined from the initial work of Cousot and Cousot to obtain efficient abstract domains [START_REF] Miné | The octagon abstract domain[END_REF] and handle other modern program structures [START_REF] Halbwachs | Discovering properties about arrays in simple programs[END_REF]. Though it may be difficult to find an abstract domain in which the generated invariants are precise enough [START_REF] Mauborgne | Trace partitioning in abstract interpretation based static analyzers[END_REF], the abstract interpretation framework was successfully applied to develop tools of practical use for program verification [START_REF] Cousot | The astrée analyzer[END_REF][START_REF] Henry | Static analysis of program by Abstract Interpretation and Decision Procedures[END_REF].

Other successful static approaches for loop invariant generation use decision procedures over specific domains to compute exact estimations of possible memory states after the loop for some specific templated invariant shapes [START_REF] Ernst | Dynamically discovering likely program invariants to support program evolution[END_REF][START_REF] Suzuki | Implementation of an array bound checker[END_REF][START_REF] Kapur | A quantifier-elimination based heuristic for automatically generating inductive assertions for programs[END_REF]. The initial property can also be iteratively reinforced until it is found to be inductive for a given transition relation [START_REF] Bradley | Sat-based model checking without unrolling[END_REF][START_REF] Hoder | Generalized property directed reachability[END_REF]. It is also possible to abstract the states of a program using predicates and then use model checking techniques to automatically generate such predicates, among which are loop invariants [START_REF] Graf | Construction of abstract state graphs with pvs[END_REF]5]. Researchers have also investigated the use of other theoretical framework to obtain invariants from symbolic execution such as the use of SMT-solvers [START_REF] Cimatti | Ic3 modulo theories via implicit predicate abstraction[END_REF] or quantifier-elimination based abduction [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF]. In the latter case, authors derived from an initial oracle-found invariant necessary consequences after loop executions through Hoare logic [START_REF] Hoare | An axiomatic basis for computer programming[END_REF]. When such consequences did not permit to ensure pre-existing safety-property within the program, they used an quantifier elimination-based algorithm to infer missing requirements within these invariants.

Example 59. Consider once more Sample Program 2.1. Here the method consists in starting by replacing the placeholder invariant Line 4 by a propagating invariant for the considered loop, e.g., . Using Hoare Logic, one can derive from this initial placeholder invariant a formula that should hold if the assertion Line 9 is verified. For this program and the current placeholder invariant, this condition will be ( ⇒ y ≥ 1). As it is clear that this formula does not hold (take for instance y = 0), the algorithm will try to strengthen the invariant by finding an abductive strengthening in the form of a placeholder ψ for the formula (true ∧ ψ ⇒ y ≥ 1). Many solutions for this problem exists but let us assume that we always obtain a good solution for the sake of keeping this example small. Using a quantifier-elimination based algorithm for Presburger arithmetic [START_REF] Haase | A survival guide to presburger arithmetic[END_REF] to produce this solution, we will obtain that for instance, ψ = y ≥ 1 works as intended. The algorithm will then replace the place holder invariant Line 4 by the new computed one (true∧y ≥ 1, or simply y ≥ 1) and proceed with Hoare Logic to ensure that new placeholder invariant is a true invariant (it is preserved by the content of the loop). The formula derived to ensure this fact will in this case be (y ≥ 1 ⇒ (x + y ≥ 1)). Once again, this formula is not verified (take for instance y = 1 and x = -8000), which will lead the algorithm to generate a new abduction problem for this condition: (y ≥ 1 ∧ ψ ⇒ (x + y ≥ 1)). Applying the quantifier-elimination based abduction algorithm again will return a satisfying solution such as x ≥ 1, whose resulting invariant y ≥ 1 ∧ x ≥ 1 will finally be proven to both propagate and ensure the safety of the assertion Line 9.

In general, static analysis techniques rely on theoretical results over the mathematical domain they build their inference procedures on [START_REF] Padon | Decidability of inferring inductive invariants[END_REF]. The mathematical theories they usually target and for which they have been found to produce invariants efficiently include numeric domains [START_REF] Bradley | Checking safety by inductive generalization of counterexamples to induction[END_REF][START_REF] Bradley | Property-directed incremental invariant generation[END_REF][START_REF] Bradley | Ic3 and beyond: Incremental, inductive verification[END_REF][START_REF] Kapur | A quantifier-elimination based heuristic for automatically generating inductive assertions for programs[END_REF], linear inequality [START_REF] Cousot | Automatic discovery of linear restraints among variables of a program[END_REF][START_REF] Colón | Linear invariant generation using non-linear constraint solving[END_REF], polynomial invariants [START_REF] Rodríguez-Carbonell | Generating all polynomial invariants in simple loops[END_REF][START_REF] Sankaranarayanan | Non-linear loop invariant generation using gröbner bases[END_REF], octagons [START_REF] Miné | The octagon abstract domain[END_REF], arrays [START_REF] Bradley | What's decidable about arrays?[END_REF][START_REF] Bozga | Automatic verification of integer array programs[END_REF][START_REF] Kovacs | Finding loop invariants for programs over arrays using a theorem prover[END_REF][START_REF] Ghilardi | Backward reachability of array-based systems by smt solving: Termination and invariant synthesis[END_REF], etc. More recently, methods to combine these theories or extend the methods to work with higher-level properties have been investigated. Such techniques were developed for the combination of linear arithmetic and uninterpreted function symbols [START_REF] Beyer | Invariant synthesis for combined theories[END_REF] by reducing the invariant inference to the verification of a sequence of arithmetic, for first-order logic [START_REF] Kovács | Interpolation and symbol elimination[END_REF] by extracting interpolants from local or split proofs using symbol-eliminating inferences, for universal invariants [START_REF] Karbyshev | Propertydirected inference of universal invariants or proving their absence[END_REF] by extending the work of Bradley et al. on incremental invariant reinforcement, and for parametric systems [START_REF] Peuter | On invariant synthesis for parametric systems[END_REF] again by iteratively strengthening based on a symbol-elimination procedure.

Dynamic loop invariant generation

Another class of techniques to generate loop invariants use direct executions of the program to infer the invariants, and are thus referred to as dynamic. These methods are briefly presented in this section but stay mainly out of the scope this work.

Early works on dynamic loop invariant generation [START_REF] Ernst | Dynamically discovering likely program invariants to support program evolution[END_REF] showed the practical efficiency of executing the program over many possible inputs to detect in an initial set of possible invariants those that happen to be violated by these executions. Refinements of this technique [START_REF] Perkins | Efficient incremental algorithms for dynamic detection of likely invariants[END_REF][START_REF] Nguyen | Using dynamic analysis to discover polynomial and array invariants[END_REF][START_REF] Csallner | Dysy: Dynamic symbolic execution for invariant inference[END_REF] lead to efficient dynamic loop invariant generators. Though such techniques do not provide formal proofs that the invariants they generate are indeed correct, a posteriori evidence [176] has shown that they are able to produce true invariants most of the time.

Summary

We have seen in this chapter various techniques to computes prime implicates of logical formulas in propositional logic and beyond. We saw that most of the techniques proposed required their input formulas to be expressed in a specific format (such as CNF, DNF, NNF) and that, beyond propositional logic, the existing methods were either specialized for a very specific subclass of logical formulas or unable to perform very efficiently. In this thesis, we will present a novel approach for prime implicate generation that solves these two issues by relying on satisfiability tests modulo theories.

We also briefly presented the issue of loop invariant generation of programs and some of the approaches that can be used to solved it. We also explained how Dillig et al. used an abduction algorithm to generate loop invariants for numeric programs. In this thesis, we will extend their work by replacing their quantifier-based abduction algorithm by our approach to prime implicate generation. We will then adapt their algorithm to fit our needs and produce a loop invariant generator independent of the theory.

Part I A generic framework for abduction modulo theories

Chapter 3

Efficient prime implicate generation modulo theories

The core contribution of this work is the design of a generic, in the sense of theoryindependent, algorithm to compute prime implicates of a formula. More formally, given a decidable theory T , a finite set of T -satisfiable abducible literals A ⊆ L and a set of formulas Φ, we will construct an algorithm that is able to generate all the prime

(T , A)-implicates of Φ (modulo T -equivalence).
The algorithm we present is based on the fact that a clause C is a (T , A)-implicate of a set of clauses Φ if and only if C ⊆ A and Φ ∪ C |= T ⊥. This means that we can find the (T , A)-implicates of Φ by simply enumerating the subsets of A and keeping those whose union with Φ is T -unsatisfiable.

An intuitive decomposition algorithm for prime implicate generation

We start by presenting in this section a naive but intuitive algorithm to perform this task. It consists in a systematic enumeration of the subsets of A performed by adding one of its elements to a candidate implicate or hypothesis until the union of this candidate with the set Φ is unsatisfiable. Each of these sets is the complement of an implicate of Φ.

Then, after finding an implicate, we can backtrack to the last literal added and pursue the exploration until the whole set of abducible literals A has been explored. Clearly this is not an efficient algorithm. For instance, we are certain that the same non-unit (T , A)-implicate will be generated several times, depending on the order in which the literals are selected. However, it serves as a basis algorithm to present the core concept of the method and as a didactic framework for its applications in the following chapters.

It will be improved in the following sections of the chapter to obtain a more efficient algorithm that can be used in practice.

We start by exposing formally the reasons that allow us to construct (T , A)-implicates iteratively by decomposition: Definition 60. Let Φ be a set of formulas. Let M, A be sets of literals such that

M ∪ A ⊆ A. We define I M ,A (Φ) = C ∈ I T ,A (Φ) ∃Q ⊆ A, C = M ∨ Q , I * M ,A (Φ) = SubMin T (I M ,A (Φ)). Intuitively, a clause M ∨ Q thus belongs to I M ,A (Φ) if and only if Q is a (T , A)- implicate of Φ ∪ M .
This justifies the fact that we can handle a single candidate (T , A)implicate to which we successively add relevant literals of A until we obtain an actual (T , A)-implicate. We also have to justify that we can stop adding literals to this candidate implicate and backtrack when it is an actual implicate.

Proposition 61. Let Φ be a set of formulas, M and A be sets of literals such that

M ∪A ⊆ A. If M is T -satisfiable, then Φ ∪ M is T -unsatisfiable if and only if I * M ,A (Φ) = {M }. If M is T -unsatisfiable, then I * M ,A (Φ) = ∅. Proof. If Φ ∪ M is T -unsatisfiable then Φ |= T M and M ∈ I T ,A (Φ), thus M ∈ I M ,A (Φ) (by letting Q = ∅ in Definition 60). By definition, for any clause C ∈ I M ,A (Φ), we have M ⊆ C; thus M C and M |= T C. Since M is not a T -tautology by hypothesis, we deduce that SubMin T (I * M ,A (Φ)) = {M }. Conversely, if I * M ,A (Φ) = {M } then M ∈ I T ,A (Φ) by definition, hence Φ ∪ M is T -unsatisfiable. If M is T -unsatisfiable, then any clause containing M is a T -tautology.
Consequently, all clauses in I M ,A (Φ) are T -tautologies, and I * M ,A (Φ) is empty. Proposition 61 justifies both that we can stop adding literals when our candidate (T , A)-implicate M is a (T , A)-implicate of the initial formula (as it will not be possible to construct implicates that are not consequences of M by adding more literals to it), and that we can stop adding literals to it when the candidate (T , A)-implicate is by itself a tautology.

Proposition 62. Let Φ be a set of formulas and

M ⊆ A. If Φ ∪ M ∼ T Ψ ∪ M , then I M ,A (Φ) = I M ,A (Ψ). Proof. Assume that C ∈ I M ,A (Φ). Then C = M ∨Q, with Q ⊆ A and C ∈ I T ,A (Φ). Since C ∈ I T ,A (Φ) we have Φ |= C, hence Φ ∪ M ∪ Q |= T ⊥. Since Φ ∪ M ∼ T Ψ ∪ M we deduce that Ψ ∪ M ∪ Q |= T ⊥, hence C ∈ I T ,A (Ψ), and therefore C ∈ I M ,A (Ψ). Consequently, I M ,A (Φ) ⊆ I M ,A (Ψ). By symmetry, we deduce that I M ,A (Φ) = I M ,A (Ψ).
Propositions 61 and 62 prove that the exploration schema that was described in the introduction allows us to generate a set of prime (T , A)-implicates entailing the set of (T , A)-implicates of the initial formula. Still, it is clear that some very obvious and minimal improvements can be made in the choice of the literals we add to a candidate (T , A)-implicate. Typically, it is clear that it is useless to add a new hypothesis l into M both if M ∪ {l} is T -unsatisfiable (because the obtained T -implicate would be a T -tautology), or if this set is equivalent to M (because the T -implicate would not be minimal). This motivates the following definition: Definition 63. Let Φ be a set of formulas and let M, A be two sets of literals. We denote by fix(M, A, Φ) a set obtained by deleting from A some literals l such that either

M ∪ Φ |= T l or Φ |= T l.
This definition permits to reduce the number of abducible hypotheses to try, and thus the search space of the algorithm. Still, we do not assume that all the literals l satisfying the condition above are to be deleted because, in practice, such literals may be hard to detect. Hence, we prefer to state the properties of our algorithm without relying on this assumption. To ensure termination, we will assume, however, that no element from M is in fix(A, M, Φ).

Proposition 64. Given a set of formulas Φ, a set of abducible literals A, and a set of literals M , we have

I * M ,fix(A,M,Φ) (Φ) ⊆ I * M ,A (Φ). Proof. Let I ∈ I * M ,fix(A,M,Φ) (Φ). As fix(A, M, Φ) ⊆ A, we have that I ∈ I M ,A (Φ). As I ∈ I * M ,fix(A,M,Φ) (Φ), we are certain that I is not a T -tautology. Now let us consider a clause C ∈ I M ,A (Φ) such that C |= T I. Necessarily C contains at least one literal l ∈ A \ fix(A, M, Φ). This means that either M ∪ Φ |= T l or that Φ |= T l, from which we can deduce from the form of C that I |= C.
At this point, we have described the core elements of an algorithm to compute a set of (T , A)-implicates for a set of formulas Φ, and such that no prime (T , A)-implicate is missed. What misses from this point to the goal we have set is to reduce this set of (T , A)-implicates we obtained in order to keep the most general ones only. In order to do this, we devise a method to build the set of (T , A)-implicates incrementally. Proposition 65 provides a method to inductively enlarge the set of (T , A)-implicates by incrementally adding new elements to it. If Proposition 61 represented the base cases of our algorithm, Proposition 65 presents the inductive case to guarantee its completeness.

I *

M ,A (Φ) = I * M ,fix(A,M,Φ) (Φ).
Proof.

It suffices to prove that I

M ,A (Φ) = l∈A\M I M ∪{l},A (Φ)). Let C ∈ I M ,A (Φ). By hypothesis, C is of the form M ∨ Q, where Q ⊆ A and M ∩ Q = ∅. Since I * M ,A (Φ) = {M }, necessarily C = M and Q = ∅. Let l ∈ Q and m = l. We have C = M ∨ m ∨ Q , with Q = Q \ {l}, and since l ∈ A, C ∈ I M ∪{l},A (Φ). Conversely, if C ∈ I M ∪{l},A (Φ) with l ∈ A, then C ∈ I M ,A (Φ) and C = M ∨ l ∨ Q, for some Q ⊆ A, so that C ∈ I M ,A (Φ).

Since fix(A, M, Φ) ⊆ A, we have by proposition 64 that

I * M ,fix(A,M,Φ) (Φ) ⊆ I * M ,A (Φ). Now let l be a literal in A such that either M ∪ Φ |= l or M |= l. If C ∈ SubMin T (I M ,A (Φ)) is of the form M ∨ Q, then Q cannot contain l: indeed,
in the former case l could be removed from Φ ∪ C while preserving equivalence, hence the implicate would not be minimal, and in the later case C would be a T -tautology.

The results above lead to a basic algorithm for generating (T , A)-implicates which is described in Algorithm 3.1.

Algorithm 3.1: ImpGen (Φ, M, A) 1 if M |= T ⊥ then 2 return ∅ ; 3 if Φ ∪ M |= ⊥ then 4 return {M } ; 5 let B = fix(A, M, Φ) ; 6 foreach l ∈ B do 7 let P l = ImpGen(Φ, M ∪ {l}, B) ; 8 return SubMin T ( l∈B P l ) ; Lemma 66. I * M ,A (Φ) = ImpGen(Φ, M, A). Proof.
The result is proved by a straightforward induction on Card(A\M ). As explained above, the algorithm works by adding literals from A as hypotheses until a contradiction can be derived. The return statement at Line 4 avoids enumerating the subsets that strictly contain M once it is known that Φ ∪ M is T -unsatisfiable. The return statement at Line 2 similarly avoids the generation of inconsistent (T , A)-implicates. Thus by Proposition 61,

I * M ,A (Φ) = ∅ if M is T -unsatisfiable, and I * M ,A (Φ) = {M } if M is T - satisfiable and Φ ∪ M is T -unsatisfiable.
Otherwise, after reducing the set of abducible literals according to Definition 63 (Line 5), we generate the (T , A)-implicates we can derive from all the possible adding to our hypothesis still available (Line 7). by Proposition 65, we have This leads to the following result:

I * M ,A (Φ) = I * M ,fix(A,M,Φ) (Φ) = I * M ,B (Φ).
Theorem 67. If Φ is a set of formulas then I * T ,A (Φ) = ImpGen(Φ, ∅, A)
. We obtain a very simple algorithm that is able to compute all the prime (T , A)implicates of a set of formulas in any decidable theory. However, as announced in the introduction, this algorithm is clearly not efficient, and thus not usable in practice. Though it is easy to design simple improvements on this algorithm, we are going to push this further and dedicate Section 3.2 to the design of an efficient algorithm based on this one.

Remark 68. As mentioned in the introduction of the chapter, we have assumed that all the satisfiability tests we query in our algorithm are decidable. This is obviously a result that will depend on the theory in which the formulas we handle are expressed. In practice, as long as the SMT-solver used is correct, Algorithm 3.1 will also be correct (in the sense that all the clauses it will generate will indeed be (T , A)-implicates of Φ). The Algorithm will be complete, and thus return a set of clauses entailing the set of prime (T , A)-implicates of Φ, only if the SMT-solver is also complete (never returns Unknown). Finally, if the SMT-solver may not terminate, Algorithm 3.1 may not either, though this limitation will be discussed in Chapters 6.4 and 8.

Improving the prime implicates generator

In this section, we present several improvements that can be made to the previous algorithm to prevent as many redundant or uninteresting (as in not permitting to obtain an implicate) recursive call to be made. This results in a significant decrease of the size of the exploration tree (as supported by experiments in Chapter 9). The final algorithm is presented as Algorithm 4.1, and will conclude this part of the work.

Reducing the number of candidates

Let us start with the example of our introduction chapter, where l 1 ∨ l 2 is a prime (T , A)implicate of a set Φ, but is generated twice by the ImpGen algorithm. Such redundant calls are quite straightforward to avoid by ensuring that every invocation of the algorithm corresponds to a distinct set of literals M . This can be done by fixing an ordering < among literals in A, and by assuming that hypotheses are always added in increasing order with respect to <. Typically, in our case, assuming that l 1 < l 2 , the order will prevent the generation of this implicate in the form l 2 < l 1 , as at the moment l 2 has been added as an hypothesis in our candidate (T , A)-implicate, the algorithm will not be allowed to add l 1 after it.

Another interesting method for restricting the set of candidate hypotheses is to exploit information that can be extracted from the satisfiability tests made by the algorithm. Indeed, along with the result of a satisfiability test occurring at line 1 of Algorithm 3.1, if Φ ∪ M is satisfiable, it is likely that we can also recover a model of Φ ∪ M . Let us assume that Φ ∪ {l 1 } is satisfiable, and that we can recover the corresponding model. Then if the model of this set also satisfies l 2 , we are already certain that Φ ∪ {l 1 } ∪ {l 2 } is also satisfiable (as the same model ensures this fact). Thus, it is not necessary to consider l 2 as a hypothesis. In particular, if a model of Φ ∪ {l 1 } validates all the literals in A at Line 1 of Algorithm 3.1, then I * M ,A (Φ) is necessarily empty and no literal should be selected. We can thus take advantage of the existence of a model of Φ ∪ M in order to guide the choice of the next literals in A. We will refer to this refinement as a semantic guidance on the choices of the literals.

Observe, however, that this refinement interferes with the previous one based on the order <. Indeed, non-minimal hypotheses will have to be considered if all the smaller hypotheses are dismissed because they are true in the model.

Example 69. To illustrate this conflict between literal ordering and semantic guidance using models, let us consider the following example. Assume that we have a set of abducible literals A = {a, b, a, b} such that a < b < b < a, and that we are looking for the prime (T , A)-implicates of Φ = {a ∨ b}. Now let us choose to prune the set of abducible literals using our order on literals (such that we do not consider smaller literals) and semantic guidance using models when we can recover them from the satisfiability tests. Let us execute our (T , A)-implicate generation algorithm starting with a hypothesis set M = ∅.

We start the execution by verifying the satisfiability of Φ. As it is satisfiable, we will assume that we recover a model from the satisfiability test, such as M = a ∧ b. In this case, we will prune from the set of abducible literals the literals the model satisfies, which will result in A = {b, a}.

At this step, we have to choose which literal we want to add to our hypothesis. We follow the rule we set at the beginning of the example and take M = {b}, then call the algorithm again. From this point, we will not be able to derive any (T , A)-implicate of Φ, because all the satisfiable hypotheses we can obtain by adding literals from A to {b} would not be in contradiction with a ∨ b. This means that, after trying those possibilities, the algorithm will backtrack to the initial level where it will try the other possible addition to the empty hypothesis set: M = {a}.

From here, one would expect that it could derive the (T , A)-implicate of Φ, but as b (which is the literal required to generate the (T , A)-implicate) happens to be smaller than a in our example, it will never be added as a hypothesis during this stage. And because it was pruned from A at the previous level, it was never added as a hypothesis there either. Thus the algorithm will terminate without generating the (T , A)-implicate we wanted to obtain, which is a shame.

Notice that this problem only occurs due to the joint usage of literal ordering and semantic guidance. This exhibits the fact that if we want to use them simultaneously, we will need to tweak the algorithm to prevent such (T , A)-implicates to be missed.

These two improvement ideas and the consideration detailed in Example 69 justify the following formalization of the principles. In what follows, we consider a total ordering < on the elements of A, not necessarily related to the ordering ≺ on clauses.

Definition 70. For A ⊆ A and l ∈ A, we define A[l] def = {l ∈ A | l < l }. If I is a set of literals then we denote by A I [l] the set l ∈ A l < l ∧ l ∈ I ∪ A[l]. Example 71. Assume that A = {p i , ¬p i | i = 1, . . . , 6}
and that for all i, j ∈ 1, 6 , for all literals l ∈ {p i , ¬p i } and l ∈ {p j , ¬p j }, l < l if and only if either i < j or (i = j, l = p i and l = ¬p i ). Then A[p 4 ] = {¬p 4 , p 5 , ¬p 5 , p 6 , ¬p 6 }.

If

I = {p 1 , ¬p 2 }, then A I [p 4 ] = {p 1 , ¬p 2 , p 3 , ¬p 3 , ¬p 4 , p 5 , ¬p 5 , p 6 , ¬p 6 }.
Intuitively, the definition A[l] is an implementation of the literal ordering pruning strategy (based on a given literal l). It defines which literals can be kept as possible hypotheses for the enclosed sublevels such that fewer redundant calls are made. The definition A I [l] aims to repair the issue that was discussed in Example 69. It defines the set of literals that should be considered when some have been removed by the use of a model at the previous level. These literals are actually the ones that were consequences of the model but happened to be smaller than the hypothesis added to the candidate (T , A)-implicate for the current level.

We now have to define how we handle the models we may obtain from the satisfiability tests in our framework. This is done through the following definitions: Definition 72. Let Φ be a set of formulas. A set of literals I is Φ-compatible with respect to A (or simply Φ-compatible) if every prime (T , A)-implicate of Φ contains a literal in I.

Intuitively, a Φ-compatible set I consists of literals l such that l will be allowed to be added as a hypothesis to generate (T , A)-implicates of Φ (see Lemma 78 below). The set I can always be defined by taking the negations of all the abducible literals from A. In this case, all literals will remain possible hypotheses. It is possible, however, to restrict the size of I when a model of Φ is known, as evidenced by the following proposition: Proposition 73. If Φ is a set of clauses and J is a model of Φ, then the set

I def = {l ∈ L | J |= l} is Φ-compatible.
Proof. Let M be a set of literals such that M is a prime (T , A)-implicate of Φ, and assume that for all l ∈ M , l ∈ I, i.e., that for all l ∈ M , J |= l. Then J |= l holds for every l ∈ M , hence J |= Φ ∪ M and M cannot be a (T , A)-implicate of Φ.

The goal here will thus be to use the models we recover from the satisfiability tests to build Φ-compatible sets that are as small as possible. Note that the condition of having a model of Φ was not added to Definition 72 because in practice, such a model cannot always be constructed efficiently, or may not be available. Still, this completes the modification of the framework for using both literal orderings and models.

Reusing the (T , A)-implicates

The next update we will discuss is based on some considerations on how we can reuse the logical consequences we generate during the execution of the algorithm. In this section, we only work with sets of formulas in negative normal form. The results could be extended to other formulas by reasoning on the polarity of their atoms (number of negations applied to them). One thing we can do is to use the implicates we have generated to simplify the formula we are computing, in the hope to detect additional consequences without the need of a satisfiability test. We can also expect an SMT-solver to perform faster on a simplified formula. The easiest consequences to reuse are the unit clauses of the problem. This motivates the handling of the unit consequences we can derive from our initial set of formulas Φ; it can pay off if we update Φ with them when they are derived. Note that U is not necessarily identical to U T ,Φ,M , because in practice the latter set is hard to generate. Similarly we do not assume that all literals l are replaced in Definition 74 since testing logical entailment may be costly. Thus we prefer to give a very general and flexible formulation of the definition so that upcoming results hold for any possible choice of U and l . Lemma 76 shows that the (T , A)-implicates of a set of clauses Φ and those of U T ,M [U ](Φ) are identical. In the case where Φ is not a set of clauses, we will assume that this property holds.

Proposition 75. Let Φ be a set of formulas and M ⊆ A. Consider a set of literals U such that M ⊆ U ⊆ U T ,Φ,M . We have:

Φ ∪ M ∼ T U T ,M [U ](Φ) ∪ M Proof. We have Φ ∪ M |= U T ,M [U ](Φ), since Φ ∪ M |= T U , and U |= (l ⇒ ⊥) if U |= l . Conversely, it is clear that U T ,M [U ](Φ) ∪ M |= Φ ∪ M .
Lemma 76. Let Φ be a set of formulas and M ⊆ A. Consider a set of literals U such that M ⊆ U ⊆ U T ,Φ,M . Then:

I M ,A (Φ) = I M ,A (U T ,M [U ](Φ))
Proof. This is an immediate consequence of Proposition 75. We are now left to implement the use of those newly acquired unit consequences within our algorithm.

Definition 77. Let U, M, A be sets of literals. We define:

U * T ,M,A,U (Φ) def = M ∨ l l ∈ A ∧ l ∈ U
The lemma below can be viewed as a refinement of Proposition 65. It is based on the previous results, according to which, when adding a new hypothesis l, it is possible to remove from the set of abducible literals A every literal that is strictly smaller than l, provided its complementary is in I (because we can always assume that the smallest available hypothesis is considered first). This is why the recursive call is on A I [l] instead of A. Note also that due to the interference between semantic guidance and the ordering <, the smaller the set I is, the larger A I [l] will be.

Lemma 78. Assume that Φ ∪ M is T -satisfiable and let I be an (Φ ∪ M )-compatible set of literals. Let U be a set of literals such that M ⊆ U ⊆ U T ,Φ,M . We have the following:

I * M ,A (Φ) = SubMin T (   U * T ,M,A,U (Φ) ∪ l∈A,l∈I I * M ∪{l},A I [l] (Φ)   ) Proof. First note that I * M ,A (Φ) = {M }, since Φ ∪ M is T -satisfiable. We first prove that I * M ,A (Φ) ⊆ U * T ,M,A,U (Φ) ∪ l∈A,l∈I I * M ∪{l},A I [l] (Φ). Let C ∈ I * M ,A (Φ). By hypothesis, C is of the form M ∨ Q, where ∅ = Q ⊆ A. Since I is (Φ ∪ M )-compatible, Q necessarily contains a literal l ∈ A such that l ∈ I.
Assume that l is the smallest literal in Q satisfying this property. We distinguish the following cases.

Assume that Q contains a literal l such that l ∈ U . In this case, since

U ⊆ U T ,Φ,M , Φ ∪ M |= T l . Since Q ⊆ A,
we also have l ∈ A, and since

I * M ,A (Φ) = {M }, we deduce that M ∨ l ∈ I * M ,A (Φ). Since M ∨ l |= T C and C ∈ I * M ,A (Φ), C must be smaller or equal to M ∨ l , which is possible only if C = M ∨ l . We deduce that C ∈ U * T ,M,A,U (Φ). Otherwise, we show that Q\{l} ⊆ A I [l]. By Definition 70, we have A[l] = {l ∈ A | l < l } and A I [l] = {l ∈ A | l < l ∧ l ∈ l} ∪ A[l]. Let l ∈ Q, with l = l. If l > l then l ∈ A[l] ⊆ A I [l]. If l > l, then since > is total and l = l , necessarily l > l .
Since l is the smallest literal in Q such that l ∈ I, we deduce that l ∈ I. Thus l < l and l ∈ I, which entails that l

∈ A I [l]. Consequently, Q \ {l} ⊆ A I [l]. Since C = M ∪ {l} ∨ Q \ {l}, this entails that C ∈ I * M ∪{l},A I [l] (Φ).
We now prove that

U * T ,M,A,U (Φ) ∪ l∈B,l∈I I * M ∪{l},B I [l] (Φ) ⊆ I M ,A (Φ). Let C ∈ U * T ,M,A,U (Φ). By definition, C is of the form M ∪ l with l ∈ A ∩ U . Since U ⊆ U T ,Φ,M , we deduce that Φ ∪ M |= T l, i.e., that Φ |= T M ∨ l. Since l ∈ A, this entails that M ∨ l ∈ I M ,A (Φ), hence C ∈ I M ,A (Φ). Let C ∈ I * M ∪{l},A I [l] (Φ) with l ∈ A, l ∈ I. By definition, C = M ∨ l ∨ Q, with Q ⊆ A I [l] and C ∈ I * T ,A (Φ). But A I [l] ⊆ A by definition, thus Q ∪ {l} ⊆ A and C = M ∨ (Q ∨ l) ∈ I M ,A (Φ).
We restrict the usage of this solution to the T -implicates of size one because using larger ones could be numerous and thus increase the complexity of the related computation.

External restrictions to prune more candidates

Another change we can do to our algorithm targets a more user-oriented feature. As the set of (T , A)-implicate can be very large, one may not necessarily want to generate them all. Pruning the (T , A)-implicates that are not of use after their generation is the easiest way to obtain the result we expect, but it may also be possible to use those external restrictions directly within the generation algorithm. This has at least two advantages. First, it removes the necessity to prune the first result set, which reduces the total computation time. Second, it may be used to detect that some hypothesis M would only lead to (T , A)-implicates violating the restrictions. Such discoveries can be used to prevent those literals from being added to the candidate (T , A)-implicate and reduce the computation time once more. In order to implement that into our framework, we parametrize our algorithm by a predicate P. This predicate will be used to filter the implicates that are generated according to the choices of the user. We also assume it has the following property: Definition 79. A predicate P on sets of literals is ⊆-closed if for all sets of literals A such that P(A) holds, if B ⊆ A then P(B) also holds.

Examples of ⊆-closed predicates include cardinality constraints: P

k def = λA. Card(A) ≤ k, where k ∈ N, or implicant constraints: P φ def = λA. φ |= T A
, where φ is a formula. Note that ⊆-closed predicates can safely be combined by the conjunction and disjunction operators.

An important feature of ⊆-closed predicates is that implicates verifying such predicates can be generated on the fly without any post-processing step, as evidenced below:

Example 80. To understand the use of such predicates better, let us consider the following example: Assume that a user wants to generate the (T , A)-implicates of a formula φ that are not logical consequences of another formula ψ. If he were to use our algorithm to generate all the prime implicates of the formula, then retain only those satisfying this constraint, ImpGen would have made a lot work constructing hypotheses that are necessarily consequences of ψ, typically when adding more literal to a hypothesis that was already a consequence of ψ while not being an implicate of φ. This also means that a lot of additional satisfiability tests are performed. This work can typically take a lot of time as the deeper the algorithm searches, the larger the exploration tree becomes (which is a trivial consequence of the structure of the algorithm). Moreover, the user would have to check, at the end of the computation, all the implicates that were generated to remove from them those that are a consequence of ψ. If he were to use the version with a filter predicate however, in this case P : V → ψ |= T V, he could recover the same result while preventing the algorithm from executing all the unnecessary computation. This, as we will see in Chapter 9, can have a significant impact on the interest of our method.

An updated version of the prime implicate generation algorithm

We now take some time to formally insert the previously described changes that have been made to our initial Algorithm 3.1. The resulting algorithm is presented in Algorithm 3.2. The general structure remains identical. We add at Line 1 the restriction to the hypotheses that derive from the use of a filtering predicate that is given as a parameter of the algorithm. It removes from the exploration all the branches that do not satisfy P. Lines 5 to 6 handle the update of the initial formula using the unit consequences that could be derived at the time of the computation. The set of literals created at Line 8 will typically be constructed from a model recovered from the satisfiability test performed Line 3, as explained in Proposition 73. It is then used to prune the abducible literals we try to add to our main hypothesis M in the branching loop Line 9; we point out that the order on abducible literals is effectively used by the construction of the new abducible set sent as a parameter to the recursive call Line 10. This same construction also handles the correction necessary to use this method alongside the semantic guidance, as detailed in previous sections. The minimal set of (T , A)-implicate we can obtain from all the recursive calls is finally computed and returned at Line 11.

Algorithm 3.2: ImpGen-PiD (Φ, M, A, P)

1 if M |= ⊥ or ¬P(M ) then 2 return ∅ ; 3 if Φ ∪ M |= ⊥ then 4 return {M } ; 5 let U ⊆ U T ,Φ,M such that M ⊆ U ; 6 let Φ = U T ,M [U ](Φ) ; 7 let A = fix(M, A, Φ) ; 8 let I be an (Φ ∪ M )-compatible set of literals ; 9 foreach l ∈ A such that l ∈ I do 10 let P l = ImpGen-PiD(Φ, M ∪ {l}, A I [l], P) ; 11 return SubMin T (U * M,A,U (Φ) ∪ l∈A P l ) ;
This leaves us with the task of proving that this modified algorithm still performs the way we expect it to. Proof. This is a direct consequence of Lemma 81 and Definition 60

Improvements for performing abduction in propositional logic

We present in this section some restrictions to the ImpGen-PiD Algorithm that can be used to improve its efficiency when generating prime implicates of propositional formulas [START_REF] Sellami | A dpll-based approach to prime implicate generation[END_REF]. It is important to note that the modifications presented in this section only apply in the context of propositional logic as they use hypotheses verified in this context only to preserve the completeness of the algorithm. Their use is thus not applicable in the general context. It is possible to represent any logical formula in clausal form. In propositional logic, this can be done for instance by using the following transformation. Definition 83. Let φ be a propositional logic formula. We define the Conjunctive normal form transformation of φ, and denote cnf(φ), the formula inductively defined as follows:

• cnf( ) = .

• cnf(⊥) = ⊥.

• If φ is an atom, then cnf(φ) = φ. • If φ = ¬ψ then cnf(φ) = φ. • If φ = ψ 1 ∧ ψ 2 then cnf(φ) = cnf(ψ 1 ) ∧ cnf(ψ 2 ). • If φ = ψ 1 ∨ ψ 2 then cnf(φ) = C i ∈cnf(ψ 1 ),D j ∈cnf(ψ 2 ) (C i ∨ D j ).
Building on this result, we will assume in this section that the sets of formulas of which we want to generate the prime implicates of are sets of clauses.

Remark 84. Note that the transformation of Definition 83 may, due to the last rule, construct a new formula that is exponential in the size of φ. To solve this problem, there exists structure-preserving transformations [START_REF] Plaisted | A structure-preserving clause form translation[END_REF]2] that construct clauses linear in the size of φ by adding new variables. Such transformations could also be used here as long as one does not consider these added variables when providing abducible literals to the prime implicates generation algorithm.

Definition 85. Given a propositional formula φ that admits a (possibly partial) model M, we say that M is a minimal model of φ if, for any model J of φ, either J = M or J coincides with M on all the atoms interpreted in the latter and there exists an atom in φ that has an interpretation in J but not in M.

We can easily see that, when we use models recovered from the satisfiability tests to obtain sets of literals reducing the size of the search space in the ImpGen-PiD Algorithm that, if we can minimize the model we use, we will also reduce the corresponding set of literals and thus the search space. As we believe that the size of the search space is one of the major factors that could degrade the performance of the prime implicate generator, we will try to minimize the models we recover from the satisfiability tests when handling propositional logic formulas. A method to perform this minimization is described in Chapter 10. However, before we can minimize our models, we have to ensure that the use of partial models in the ImpGen-PiD Algorithm preserves its properties.

Proposition 86. If Φ is a set of propositional clauses and J is a partial model of Φ, then the set

I def = {l ∈ L | J |= l} is Φ-compatible (see Definition 72).
Proof. Let M be a set of literals such that M is a prime A-implicate of Φ, and assume that for all l ∈ M , l / ∈ I, i.e., that for all l ∈ M , J |= l. Then for every l ∈ M , either J |= l, in which case J |= Φ ∪ M and M cannot be an A-implicate of Φ, or there exists a model J of Φ such that J |= l, in which case M cannot be an A-implicate of Φ either.

Moreover, it is possible to unfold the behaviour of the SAT-solver (especially the unit propagation) within the execution of the ImpGen-PiD algorithm. Typically, instead of performing a complete satisfiability test when the algorithm adds a new literal to its set of hypotheses, we can delay this costly operation by unit-propagating this literal instead. This means that we will update the set of formulas we consider by deleting the clauses in which we detect that this selected literal appears and removing its complement from the clauses where we detect that it appears. For efficiency reasons, these operations are usually not performed in a systematic way in modern SAT-solver. Instead the program merely watches two literals in each clause which is sufficient to detect when new unit clauses are produced (which can be in turn unit propagated) [START_REF] Moskewicz | Chaff: Engineering an efficient sat solver[END_REF]. This detection is usually performed by watching two literals for each clause until the corresponding variable is assigned by the SAT-solver. This permits to reduce the number of abducible candidates for the next recursive call of the algorithm.

Similarly, unit propagation can be used to detect beforehand possible conflicts with previously selected literals. In this case, we can immediately deduce that the current hypothesis in an implicate of the initial formula.

Definition 87. Given a set of clauses Φ, the set of literals deduced by unit propagation from Φ, which we will denote by U * (Φ), and the explanation of a literal l in Φ are defined inductively as follows:

• If l ∈ Φ is a unit clause, then l ∈ U * (Φ) and E * Φ (l) def = ⊥. • If C ∈ Φ is of the form D ∨ l and D ⊆ U * (Φ), then l ∈ U * (Φ) and E * Φ (l) def = C (if several such clauses exist then one is chosen arbitrarily).
With the help of Definition 87, we describe the unfolding of unit propagation in Algorithm 3.3 and the adapted version of the ImpGen-PiD algorithm for the generation of prime implicates in propositional logic in Algorithm 3. 4. In both algorithms, the set of prime implicates Π we construct is handled by reference. The calls to UpdateImplicates and UpdateImplicatesLocal are assumed to update this set of implicates according to the information they obtained from their location within the algorithms and by the unfolding of the unit propagation of the literals. They proceed by applying the following definitions: Definition 88. Given a set of clauses Φ, three sets of literals M, U, A and a set of clauses Π, UpdateImplicates(Φ, M, U, A, Π) is a strong entailment minimal equivalent of the union of Π with a set of A-implicates of Φ ∧ M denoted by Π and ensuring that

Π ∪ Π ||= M ∨ l l ∈ A ∧ l ∈ U .
Remark 89. As the choice of Π is arbitrary, Definition 88 does not ensure the unicity of UpdateImplicates(Φ, M, U, A, Π).

In the ImpGen-PiD Algorithm, when checking whether Φ ∪ M |= ⊥ or not at Line 3, we can (if the test succeeds) conclude that M is an A-implicate of Φ. This single implicate is a good choice for the set Π of Definition 88 because the satisfiability test it results from is already mandatory in the main algorithm. Definition 90 leaves us with the problem of finding good such subsets, as this is the key point of this algorithmic improvement for propositional logic. Once again, we can reuse the fact that we unfold unit propagation to our advantage and construct a method of building such subsets that uses the reasons why literals are unit propagated.

Algorithm 3.3: UnitUpdate(Φ, M, A, ref Π) 1 let Π I ⊆ Π; 2 let U = U * (M ∪ Π I ∪ Φ); 3 repeat 4 UpdateImplicates(Φ, M, U, A, Π); 5 Π I = Π I ⊆ Π; 6 U = U ∪ U * (M ∪ Π I ∪ Φ); 7 until U is no longer updated ; 8 return U ;
Definition 91. Given a set of clauses, a hypothesis M and a set of abducible literals A, we define the A-reason of a literal l in the addition of M to Φ and denote by R A,Φ,M (l) the following set:

• If l ∈ Φ then R A,Φ,M (l) def = {∅}. Algorithm 3.4: ImpGen-Propositional(Φ, M , A, ref Π) 1 let U = UnitUpdate(Φ, M, A, Π) ; 2 let Φ U = {C ∈ Φ | U |= C} ; 3 let Φ U = C \ U C ∈ Φ \ Φ U ; 4 let A = A ∩ l ∈ L l ∈ Lits(Φ U ) ∧ {l, l} ∩ U = ∅ ; 5 if ⊥ ∈ Φ U or A = ∅ ∧ Φ U |= ⊥ then 6 UpdateImplicatesLocal(Φ, M, A, Π) ; 7 return ; 8 let I = {l | M |= l} if a (partial) model M of Φ ∪ M is found, I = L otherwise.; 9 ImpGen-Propositional(Φ, M ∪ {max(A)}, A I [max(A)], Π) ; 10 if P ||= M then 11 return ; 12 U = UnitUpdate(Φ, M, A, Π) ; 13 A = {l i } i<j⇒l i <l j ; 14 foreach l i ∈ l ∈ A l ∈ I ∧ l = max(A) in decreasing order do 15 if Π ||= M ∨ l i then 16 ImpGen-Propositional(Φ, M ∪ {l i }, A I [l i ], Π) ; • If l ∈ M \ Φ then R A,Φ,M (l) def = {{l}}. • Otherwise, if E * Φ∪M (l) = l 1 ∨ . . . ∨ l n ∨ l, then R A,Φ,M (l) def = n i=1 P i ∀i = 1, . . . , n, P i ∈ R A,Φ,M (l i ) if l∈A {{l}} . Proposition 92. Let l ∈ U * (Φ ∪ M ). If P ∈ R A,Φ,M (l), then P ⊆ (A ∪ M ) ∩ U * (Φ ∪ M ) and P ∪ Φ |= l.
Proof. This is proved by induction. The result is obvious if l ∈ Φ or l ∈ M . Otherwise, let D ∨ l = E * Φ∪M (l), where D = l 1 ∨ . . . ∨ l n , so that P = n i=1 P i and P i ∈ R A,Φ,M (l i ).

By hypothesis, for all

i = 1, . . . , n, Φ ∪ P i |= l i . Hence, Φ ∪ P |= Φ ∪ D |= l. The fact that P ⊆ (A ∪ M ) ∩ U * (Φ ∪ M ) is similarly proved by induction. Proposition 93. For all l ∈ U * (Φ ∪ M ), there exists a P ∈ R A,Φ,M (l) such that P ⊆ M .
Proof. The proof is by induction on the length of the derivation of

l from Φ ∪ M . If l ∈ Φ then R A,Φ,M (l) = {∅} and ∅ ⊆ M . If l ∈ M \ Φ then R A,Φ,M (l) = {{l}} and {l} ⊆ M . Otherwise, necessarily E * Φ∪M (l) = l 1 ∨ • • • ∨ l n ∨ l
where, for all i ∈ 1, n , l i ∈ U * (Φ ∪ M ) and the derivation yielding l i is strictly lower than that of l. Thus by the induction hypothesis R A,Φ,M (l i ) contains a set P i ⊆ M and R A,Φ,M (l i ) contains the set n i=1 P i ⊆ M . Notation 94. We will denote by ρ M (l) an (arbitrary) element P ∈ R A,Φ,M (l) such that P ⊆ M . Definition 95. Given a set of clauses Φ and a set of literals M , we let H A (Φ, M ) be defined by

H A (Φ, M ) def = P ∨ l l ∈ U * (Φ ∪ M ) ∩ A ∧ P ∈ R A,Φ,M (l) Lemma 96. If U = U * (Φ ∪ M ), then we have H A (Φ, M ) ⊆ C C ⊆ U ∩ (M ∪ A) ∧ Φ ∪ C |= ⊥
(where C denotes a clause), and also

H A (Φ, M ) ||= M ∨ l l ∈ A ∧ l ∈ U . Proof. Let P ∨ l ∈ H A (Φ, M ), where l ∈ U ∩ A. By Proposition 92, P ⊆ (A ∪ M ) ∩ U and Φ ∪ P ∪ {l} |= ⊥, which proves that P ∨ l ∈ C C ⊆ U ∩ (M ∪ A) ∧ Φ ∪ C |= ⊥ .
By definition, every clause in The A-implicates of Φ that can be added to the set of already generated implicates can therefore be taken from H A (Φ, M ). Any subset of the latter that contains ρ M (l) for all l ∈ U * (Φ∪M ) can be safely added while maintaining the correctness of the algorithm.

M ∨ l l ∈ A ∧ l ∈ U is of the form M ∨ l where l ∈ U ∩ A. By Proposition 93, there is a P ∈ R A,Φ,M (l ) such that P ⊆ M , which proves that H A (Φ, M ) ||= M ∨ l . Lemma 97. Let l be a literal such that {l, l} ⊆ U * (Φ ∪ M ) and let D = ρ M (l) ∪ ρ M (l).

Chapter 4 Storing (T , A)-implicates efficiently

The number of implicates of a given formula may be huge, hence it is essential in practice to have appropriate data structures to store them in a compact way. Moreover, as stored implicates can be used to prune exploration branches (typically by detecting that all the (T , A)-implicates it can generate will be a consequence of a stored one), it is also critical to possess efficient algorithms to check that a newly generated (T , A)-implicate I is not redundant (this is usually called forward subsumption modulo T ), and if so, to delete all the already generated implicates that are less general than I (usually called backward subsumption modulo T ), before inserting I into the structure for stored implicates.

A structure for storing the (T , A)-implicates

In this section, we devise a trie-like data structure to perform these tasks. We will also explain how we can make use of this data structure to improve the efficiency of Algorithm 3. 2.

In order to comply with the genericity restrictions of our main algorithm, once again, the definition and usage of the structure we define only rely on the existence of a decision procedure for testing satisfiability in T . We will use this procedure to perform the implication verifications required for storing the implicates. Definition 98. Let < s be an order on the literals in A, possibly, but not necessarily, equal to the order < used for literal ordering in the implicate generation algorithm. An A-trie is inductively defined as ⊥ (the empty leaf ) or a possibly empty set of pairs {l 1 : τ 1 , . . . , l n : τ n }, where l 1 , . . . , l n are pairwise distinct literals in A and τ i , i ∈ 1, n is an A-trie only containing literals that are strictly greater than l i (according to the order < s ). An A-trie is associated with a set of A-clauses inductively defined as follows:

S(⊥) def = {⊥}, S({l 1 : τ 1 , . . . , l n : τ n }) def = n i=1 {l i ∨ C | C ∈ S(τ i )} . T • • ⊥ ⊥ ⊥ f (a) f (b) d e f (c) f (b) f (d) f (a) f (d) f (a)
(a) f (b) ∨ f (c) f (b), f (a) f (b) ∨ f (d) f (a), d e ∨ f (d) f (a)}.

Algorithms to efficiently insert and reuse the (T , A)-implicates

We now have to define the operations we need on this structure. We start by presenting the straightforward algorithm permitting the insertion of a clause in an A-trie.

Definition 100. Let C be a clause and let τ be an A-trie. insert(τ, C) denotes the A-trie defined inductively as follows: One can remark that this algorithm does not perform any subsumption verification. Indeed, we expect the subsumption verifications and modifications to be done before any insertion into the A-trie. Before inserting a given clause, we will first verify that it is not already entailed by another one in the storage, then remove from the A-trie any clause that would be less general than it is, and then only insert it into the A-trie. We now describe these two subsumption algorithms.

• If C = ⊥ then insert(τ, C) = ⊥ • If C = l 0 ∨ l 1 ∨ . . . l n with l 0 < s l 1 < s . . . < s l n then -If there exists a pair (l , τ ) ∈ τ verifying l = l 0 then insert(τ, C) = (τ \ {(l , τ )}) ∪ {(l , insert(τ , l 1 ∨ . . . l n ))} -Otherwise, insert(τ, C) = τ ∪ {(l 0 , insert(∅, l 1 ∨ . . . l n ))} Proposition
Definition 102. We introduce the following simplification rule (which may be applied at any depth inside a tree, not only at the root level):

del : τ ∪ {l : ∅} → τ
Informally, the rule deletes all leaves labeled by ∅ except for the root. It may be applied recursively, for instance {l : {l 1 : ∅, . . . , l n : ∅}} → n+1 del ∅. Termination is immediate since the size of the tree is strictly decreasing. This rule will be used to clean A-tries after some path deletion operations have been performed in it (see below).

Proposition 103. If τ → del τ then τ is an A-trie and S(τ ) = S(τ ).

The following lemma provides a simple algorithm to check whether a clause is a logical consequence modulo T of some clause in S(τ ) (forward subsumption). The algorithm proceeds by induction on the A-trie. Before inserting any clause into an A-trie, we will thus use this algorithm to check if the insertion is useful. If it is, we will then use the following definition, which provides an algorithm to remove, in a given A-trie, all branches corresponding to clauses that are logical consequences of a given formula modulo T (backward subsumption).

τ n }) = n i=1 {l i ∨ E | E ∈ S(τ i )},
• • ⊥ ⊥ ⊥ f (a) f (b) d e f (c) f (b) f (d) f (a) f (d) f (a) T • • ⊥ ⊥ ⊥ f (a) f (b) d e f (c) f (b) f (d) f (a) f (d) f (a)
Definition 106. Let φ be a formula and let τ be an A-trie. clear(τ, φ) denotes the A-trie defined as follows:

• If φ is T -unsatisfiable, then clear(τ, φ) def = ∅. • If φ is T -satisfiable, then: -clear(⊥, φ) def = ⊥, -clear({l 1 : τ 1 , . . . , l n : τ n }, φ) def = n i=1 {l i : clear(τ i , φ ∧ l i )}.
Intuitively, starting with some clause φ, the algorithm incrementally adds to a temporary set literals l 1 , . . . , l n occurring in the clauses D = l 1 ∨ • • • ∨ l n ∈ S(τ ) and invokes the SMT-solver after each addition. If a contradiction is found then this means that φ |= T D, hence the branch corresponding to D can be removed. The advantage of using this within the A-trie is that the calls are shared among all common prefixes. Of course, this algorithm is even more interesting if the SMT-solver is able to perform efficient incremental satisfiability testing. The following Lemma provides a proof that the function effectively removes from an A-trie the clauses entailed by its parameter. Proof. The proof is by induction on τ . We also prove that all literals in clear(τ, φ) also occur in τ . We distinguish several cases.

• If φ is T -unsatisfiable, then φ |= T C, for every C ∈ S(τ ). Consequently, {C ∈ S(τ ) | φ |= T C} = ∅.
Furthermore, clear(τ, φ) = ∅, thus clear(τ, φ) is an A-trie and S(clear(τ, φ)) = ∅. Therefore, the result holds. Note that clear(τ, φ) contains no literal at all. Furthermore, clear(τ, φ) = ⊥, thus clear(τ, φ) is an A-trie and the equality holds. As in the previous case, clear(τ, φ) contains no literal.

• Now assume φ is T -satisfiable and τ = {l 1 : τ 1 , . . . , l n : τ n }, where l 1 , . . . , l n are pairwise distinct, and all literals in τ i are strictly greater than l i . Then S({l 1 : τ 1 , . . . , l n :

τ n }) = n i=1 {l i ∨ D | D ∈ S(τ i )} .
hence

{C ∈ S(τ ) | φ |= T C} = n i=1 {l i ∨ D | D ∈ S(τ i ) and φ |= T l i ∨ D} .
By Proposition 34, we deduce that

{C ∈ S(τ ) | φ |= T C} = n i=1 l i ∨ D D ∈ S(τ i ) and φ ∧ l i |= T D .
By the induction hypothesis, clear(τ i , φ ∧ l i ) is an A-trie and

S(clear(τ i , φ ∧ l i )) = D ∈ S(τ i ) φ ∧ l i |= D thus: {C ∈ S(τ ) | φ |= T C} = n i=1 l i ∨ D D ∈ S(clear(τ i , φ ∧ l i )) .
By definition, clear(τ, φ) = n i=1 {l i : clear(τ i , φ ∧ l)}. The l 1 , . . . , l n are pairwise distinct and all literals in S(τ i ) also occur in τ i , thus are greater than l i . Hence this entails that clear(τ, φ) is an A-trie, and

S(clear(τ, φ)) = n i=1 l i ∧ D D ∈ S(clear(τ i , φ ∧ l)) = {C ∈ S(τ ) | φ |= T C} .
By definition, the literals in clear(τ, φ) occur either in l 1 , . . . , l n or clear(τ i , φ ∧ l) (hence τ i ), thus must occur in τ . No contradiction can be found with this second literal, nor when we add the one in the related subtrie later. This means that we will keep this part of the A-trie. In this case, it is clear that the complexity, when defined as the number of satisfiability tests of forward subsumption (as defined in Lemma 104) is of the same order as the size of the directed acyclic graph, since the recursive calls only depend on the considered subtree. For backward subsumption (see Definition 106), the situation is different since the recursive calls have an additional parameter that is the formula φ, which depends on the path in the A-trie. The maximal number of satisfiability tests is therefore equal to the size of the underlying tree, and not that of the directed acyclic graph.

T • • ⊥ ⊥ ⊥ f (a) f (b) d e f (c) f (b) f (d) f (a) f (d) f (a) T • • ⊥ ⊥ ⊥ f (a) f (b) d e f (c) f (b) f (d) f (a) f (d) f (a)

An updated algorithm including storage management

We provide in Algorithm 4.1 an updated version of ImpGen-PiD that uses A-tries to store the generated implicates.

Algorithm 4.1: ImpGen-Storage (Φ, M, A, τ, P) This concludes the presentation of the efficient generic algorithm to compute the prime (T , A)-implicates of a set of formulas Φ. We have considered various improvements to reduce the search space of the algorithm, provided a storage structure that permits to store and work efficiently with the (T , A)-implicates we have already generated, and added a user-tunable filter feature that can help pruning the search space even further if we can design external restrictions on the form of the desired implicates. It is clear that more improvements could be made to this algorithm, this will discussed in Chapter 11.6 after we have performed an extensive evaluation of the version we designed in this chapter (see Chapter 9 for this). Still, this generic implicate generation algorithm will be at the centre of an application to program loop invariants generation we will develop in Chapters 5 and 6. Finally, the next chapter provides some interesting information on methods that can be used to adapt this algorithm for the specific case of prime implicate generation in propositional logic.

1 if M |= ⊥ or ¬P(M ) or S(τ ) |= T M then 2 return τ ; 3 if Φ ∪ M |= ⊥ then 4 return insert(clear(τ, M ), M ) ; 5 let U ⊆ U T ,Φ,M such that M ⊆ U ; 6 let Φ = U T ,M [U ](Φ) ; 7 let A = fix(M, A ,

Part II

Using abduction in verification

Chapter 5

An abstract theoretical framework

In part I, we devised an algorithm that, given a set of formulas Φ expressed in a decidable theory T and a set of abducible literals A, computes all the prime (T , A)-implicates of Φ. Now let us consider, for instance, a program, with a set of preconditions (a set of logical formulas we assume to hold at the beginning of the program), and for which we want to ensure some postconditions (a set of logical formulas we want to prove hold after the execution of the program). A standard method to perform this type of verification is to generate from the program, its preconditions and its postconditions, a set of verification conditions that are valid if and only if the postconditions of the program hold. When the program is only composed of a sequence of instructions with no loops or recursive calls, it is usually easy to generate these verification conditions and to decide whether they are valid or not. As long as the verification conditions are expressed in a simple enough theory, we can decide whether or not they are verified, typically by tasking an SMT-solver to answer this question. When no such restrictions are considered however, this problem is undecidable. In the case where the programs under consideration contain loops, it is possible to use loop invariants to extend this verification framework. Intuitively, a loop invariant is a formula that holds when the program first enters the loop and is preserved by the instructions contained in this loop. By using these loop invariants as preconditions of loop-free sequences of instructions, it becomes possible to check whether the postconditions of programs containing loops are verified. This, however, requires that the loop invariants are also verified, that is, that they hold at the moment the program enters the loop they refer to and they are preserved by the content of this loop. A similar approach can be devised for recursive functions. This leaves us with the problem of generating loop invariants for the programs we consider.

Given a program in which not all the verification conditions are valid, we want to update the preconditions or find loop invariants to ensure that all the verification conditions are satisfied. In this chapter, we present an algorithm that performs this task of finding meaningful additional preconditions to ensure that a set of derived verification conditions is satisfied. In [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF], Dillig et al. proposed a similar approach to generate property-directed loop invariants of numeric programs, and restricted to theories admitting quantifier elimination.

In their work, given a program decorated with loop invariant candidates, preconditions and postconditions, they derive verification conditions ensuring when valid that the considered candidates are indeed loop invariants and that they are strong enough to deduce the postconditions. If not all these verification conditions are valid, they use an abduction algorithm based on quantifier elimination to strengthen their candidate loop invariants until they are able to obtain valid verification conditions only.

Here we reuse the techniques they introduced in [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF] and combine them with the more general abductive reasoning procedure introduced in Chapter 3. We thus obtain a completely generic approach for computing either loop invariants or preconditions of programs. In order to cope with the huge search space related to this genericity, we will also instantiate and adapt this algorithm specifically for loop invariant generation in Chapter 6, notably by introducing strategies to determine which verification conditions should be considered first and which loop invariants should be strengthened.

A framework for describing verification problems

Definition 112. We define a verification structure P as a tuple (Φ, Υ) where Φ = (ϕ 1 , . . . , ϕ n ) is a sequence of logical formulas called guide formulas, and where Υ = (υ 1 , . . . , υ m ) is a sequence of functions from S n to S called verification conditions generators.

We will say that a verification structure

P = (Φ, Υ) is satisfied if |= i∈ 1,m υ i (Φ).
If this is the case, we will write |= P Intuitively, verification structures are a generic representation in which we can encode our programs. The preconditions and loop invariants we consider will be encoded into guide formulas and the content of the programs (as well the postconditions we want to prove on them) will be encoded into verification condition generators. The fact that we can have several guide formulas will be useful in the context of loop invariant generation, where we can encode a loop invariant by a guide formula.

Notation 113. Given a verification structure P = (Φ, Υ), we will denote its i th guide formula by Guide i (P ) and its j th verification condition generator by VCGen j (P ). We will also denote by Guides(P ) the sequence Φ and by VCGen(P ) the sequence Υ.

Definition 114. Given a verification structure P = (Φ, Υ), we will call verification conditions of P the set of formulas

V C(P ) = {VCGen i (P )(Φ) | 1 ≤ i ≤ Card(Υ)} .
We will call i th verification condition of P the formula )), we obtain a verification structure that represents the problem of verifying whether Algorithm 5.1 verifies all its postconditions. As this is not the case, our goal will be to update the guide formula of P 5.1 until it represents a set of preconditions that solves this problem.

V C i (P ) = VCGen i (P )(Φ).
Notation 116. Given a verification structure P = ((ϕ 1 , . . . , ϕ i-1 , ϕ i , ϕ i+1 , . . . , ϕ n ), Υ) and a formula φ, we will denote by P [i ←-φ] the verification structure in which we have replaced the i th guide formula by φ, that is, ((ϕ 1 , . . . , ϕ i-1 , φ, ϕ i+1 , . . . , ϕ n ), Υ).

Similarly, given a verification structure P = ((ϕ 1 , . . . , ϕ n ), Υ) and a sequence of formulas Φ = (φ 1 , . . . , φ n ) such that Card(Φ) = Card(Guides(P )), we will denote by P [ * ←-Φ] the verification structure in which all the guide formulas have been replaced by the formulas at the same index in Φ, that is, ((φ 1 , . . . , φ n ), Υ). Definition 117. We will say that two verification structures P 1 = (Φ 1 , Υ 1 ) and P 2 = (Φ 2 , Υ 2 ) are similar if they only differ by their guide formulas, that is, if Υ 1 = Υ 2 . In this case, we will write P 1 ∼ P 2 .

The problem we wish to solve is thus, given a verification structure P that is not satisfied, to find a satisfied verification structure P that is similar to P . Typically, in Example 115, the verification structure P 5.1 = P 5.1 [1 ←-Guide 1 (P 5.1 ) ∧ a = b] is a solution to this problem.

As mentioned in the introduction, we want to search for this similar verification structure by using an abduction algorithm to compute strengthenings of the guide formulas we already have. In order to do that, we are going to select in our verification structure a verification condition that is not valid, and use an abduction algorithm for the theory it is expressed in to generate relevant additional formulas to make it valid. Once such a formula is recovered, we will have to select one of the guide formulas of the verification structure to strengthen. What we need to ensure is that, when the guide formula is strengthened, the verification condition generated within the new program by the same verification condition generator will be valid. We will succeed if we can find a sequence of strengthenings to update our initial verification structure with and satisfy it.

Notation 118. Let P = (Φ, Υ) be a non-satisfied verification structure. We will denote by pending(P ) the set of indices of verification condition generators returning non-valid verification conditions in P . More formally, we have pending(P ) = {j | |= VCGen j (P )(Guides(P ))} .

Definition 119. Consider a verification condition generator υ and an index i such that υ has at least i parameters. We say that υ depends on its i th parameter if we have ∃(φ 1 , . .

. , φ

i-1 , φ i+1 , φ n ) ∈ S n-1 .∃ψ 1 , ψ 2 ∈ S 2 .υ(φ 1 , . . . , φ i-1 , ψ 1 , φ i+1 , . . . , φ n ) = υ(φ 1 , . . . , φ i-1 , ψ 2 , φ i+1 , . . . , φ n ).
Given a verification structure P = (Φ, Υ) and an index i such that the verification condition generators of P have at least i parameters, we will denote by D i (P ) the set of verification condition generators of P that depend on their i th parameter.

Definition 120. We say that a verification structure P 0 is a strict update of another verification structure P 1 , and write P 0 ≺ P 1 , if P 0 ∼ P 1 and there exists an index i and a formula φ such that P 0 = P 1 [i ←-φ], Guide i (P 1 ) |= φ and φ |= Guide i (P 1 ).

We say that a verification structure P 0 is an update of another verification structure P 1 , and write P 0 ≺ + P 1 , if either P 0 is a strict update of P 1 or there exists a non-empty finite sequence (Q 0 , . . . , Q n ) such that P 0 is a strict update of Q 0 , Q n is a strict update of P 1 , and for any i ∈ 0, n , Q i is a strict update of Q i+1 .

Definition 121. We say that a verification structure P is inconsistent if it is not satisfied and there exists no satisfied update of P .

Verifying that a verification structure is inconsistent is undecidable in the general case. However, it is still possible, in some particular cases, to detect that a given verification structure in inconsistent.

Notation 122. We assume given a correct but incomplete procedure that always terminates and that may detect that a verification structure is inconsistent. If this procedure detects that a given verification structure P is inconsistent, we will write P -→ fails.

Remark 123. Note that P -→ fails entails that P is inconsistent but that the converse does not hold.

Definition 124. Let P = (Φ, Υ) be a verification structure, υ be a verification condition generator of P and let φ = υ(Φ). Let i be the index of a guide formula in Φ. We call verification update inverter on i, and denote by υ -1 | i any partial function such that for any formula I, one of the following is verified:

• υ -1 | i (I) does not exist. • We have υ(Guides(P [i ←-Guide i (P ) ∧ υ -1 | i (I)]) = I ∧ φ.
Definition 124 will be used to translate the solution of the abduction problems into corresponding updates for the verification structure. It is clear that if we want the algorithm to work, we will need verification update inverters whose domain contains the abduction solutions we generate on our verification conditions.

Using implicate generation to solve abstract verification problems

We now have all the background required to present our strengthening algorithm. It is shown in Algorithm 5.2.

Proof. The proof is by induction on the recursive calls. It is clear that Ilinva(P ) ∼ P because the algorithm only modifies guide formulas. By construction (Line 1 of Algorithm 5.2), the verification structure returned must be satisfied. Similarly, when returning at Line 4 or at Line 13, the result is always a failure by construction. By induction, we have that any verification structure returned at Line 12 is necessarily satisfied.

Theorem 126. Let P be a verification structure and let T be a decidable theory. Let A be a finite set of literals expressible in T . Assume that the verification conditions of P and updates of P are in T . Assume also that for every such verification condition, the associated set of abducible literals A (the one we recover at Line 2 of Algorithm 5.

3) is such that A ⊆ A, and such that the conjunction of any conjunction of its literals with the verification condition is in T . Then Ilinva(P ) terminates.

Proof. Termination can be derived from the fact that there are only finitely many possible guide formulas built on A. At each recursive call, the verification structure is strictly strengthened, as one of the guide formulas is strictly updated and the other ones are left unchanged. Hence, the multiset of guide formulas is strictly decreasing, according to the multiset extension of the update relation.

Remark 127. We point out that, even though Theorem 126 assumes that T is decidable, the result holds as long as we can decide the satisfiability of the verification conditions we generate. If this is not the case, we will see in Chapter 7 that we can tweak the computation of satisfiability tests to ensure termination, although we may miss some possible solutions when doing so.

This concludes the presentation of the generic Ilinva algorithm to satisfy verification structures by strengthening them. It can be used as is to generate, e.g., additional preconditions for the verification of programs (see again Example 115). In the next chapter, we will present an instantiation of the verification structures that will allow us to use this algorithm to generate property-directed loop invariants of programs.

Chapter 6

An instance of the framework to generate loop invariants of programs

In Chapter 5, we devised an algorithm to strengthen unsatisfied verification structures until they are satisfied. We saw (through Example 115), that we could use it to generate additional preconditions for the verification of programs. In the present chapter, we are going to develop an instance of verification structures that allow to use the Ilinva algorithm for the generation of property-directed loop invariants. The problem tackled is thus similar to that of [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF] but the genericity of the abduction algorithm used within Ilinva (the one we presented in Chapter 3.2) allows for the generation of loop invariants in theories that are out of the scope of [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF]. A more detailed comparison with this approach will be proposed in Section 6.4.

Representing the programs

In order to define our problem formally, we will consider the class of programs we detail in Definition 128. It is clear that all the work in this chapter could be adapted to other definitions of programs, as long as we can obtain the associated verification condition generators we detail later. We will also assume, to stick to the framework of Chapter 5 and for clarity reasons, that the logical formulas in which we express, within the programs, properties on its memory (such as preconditions, postconditions, invariants) are expressed within the same signature and theory as the ones the abduction algorithm will handle. If this were not the case, one could tweak the definition of the verification conditions generators and their inverters to perform the required translation.

Definition 128. We define the programs we consider by induction as follows :

P ::= empty | I; P I ::= base-instruction | assume [φ] | assert [φ] | if C then P else P end | while C do [φ] P done
where C is a condition on the state of the memory, φ is a formula and I is an instruction.

Notation 129. We will denote by P 1 • P 2 the concatenation of two programs P 1 and P 2 .

That is, the program containing all the instructions of P 1 followed by all the instructions of P 2 .

The semantics of program sequences and conditionals are standard. Instructions are executed in the order in which they appear in the program, within a conditional, the first subprogram is executed if and only if the condition is satisfied and the second subprogram if and only if the condition is not. The semantics for assumptions (assume [φ]) corresponds to formulas that are taken as hypotheses, and thus assumed to hold where they appear within a program. They are typically used to specify preconditions. Assertions (assert [φ]) correspond to formulas that are to be proved. We say informally that a program is verified if all the assertions it contains hold in all executions of the programs that fulfills the assumptions. Base instructions are left unspecified, they shall depend on the target language and application domain; they may include, for instance, assignments and pointer redirections. The semantics of the loop instruction is also standard: the subprogram is executed if and only if the initial condition is verified when the program attains the loop instruction and, when its execution is complete, it jumps back to the initial condition of loop and executes the subprogram again as long as the condition is verified. It jumps after the loop whenever its condition is not verified any longer.

Definition 130. Given a loop instruction while C do [φ] P done, we call the formula φ a candidate loop invariant.

Given a loop instruction while C do [φ] P done, we will say that its candidate loop invariant is a loop invariant if it holds every time the condition C is tested during any execution of the program. This algorithm is standard for computing, given two integers n, m such that m ≥ 0 (expressed within an assumption Line 1), the quantity n m . The postcondition at Line 8 is meant to guarantee this is indeed the case. It contains base instructions at Lines 2, 3, 6, 7 and 9, and a loop at Line 4. The current candidate loop invariant of the loop is (Line 4), we will see later that it does not permit to deduce the assertion of the program. We will delegate the generation of verification conditions and the satisfiability tests required to check their validity to external tools. The method we design is an Notation 133. In the following, we will sometime represent sequences of integers as separated by a dot (such as 1.2.0 = 1, 2, 0 ). We will also extend this notation for sets of sequences, which means that for any integer n and any two sets of sequences

L 1 , L 2 we will write n.L 1 = {n.n | n ∈ L 1 }, L 1 .n = {n .n | n ∈ L 1 } and also L 1 .L 2 = {n 1 .n 2 | n 1 ∈ L 1 , n 2 ∈ L 2 }.
As we want to express the problem of property-directed loop invariant generation in the framework of Definition 112, it is fairly intuitive to use the candidate loop invariants as guide formulas. What we need now is a generic method to construct verification conditions generators that can generate conditions ensuring that all the properties we want our programs to have hold. In the technical system (see Chapter 8), this will be delegated to an external tool, for which we will only require that the validity of the generated verification conditions guarantees all the properties of the program hold. For self-completeness, we shall now briefly review a well-known algorithm for generating verification conditions. It is based on calculi for computing weakest preconditions and strongest postconditions of logical formulas.

The first element we need is a formal way to locate a specific instruction within a program. This is the purpose of the following definition: Definition 134. We define a location within a program or an instruction. We define locs(P ) the set of locations within a program P inductively as follows:

empty → {0} I; P 1 → {0} ∪ 0.locs(I) ∪ {(i + 1). | i. ∈ locs(P 1 )} base-instruction → ∅ assume [φ] → ∅ assert [φ] → ∅ if C then P 1 else P 2 end → 1.locs(P 1 ) ∪ 2.locs(P 2 ) while C do [φ] P 1 done → 1.locs(P 1 )
Definition 135. In the following, we will identify an instruction within a program by the location preceding it. For a given program P and a given location within P , we will denote the instruction appearing directly after in P by P | and define it inductively as follows:

I; P 1 | 0 → I I; P 1 | 0. → I| I; P 1 | (i+1). → P 1 | i. if P 1 = empty if C then P 1 else P 2 end| 1. → P 1 | if P 1 = empty if C then P 1 else P 2 end| 2. → P 2 | if P 2 = empty while C do [φ] P 1 done| 1. → P 1 | if P 1 = empty Remark 136.
Note that, given a program P , P | is a partial function, since locations denoting the end of a sequence do not correspond to any instruction.

Notation 137. In all the following, we will order program locations as we would lexicographically order sequences of integers. For two given locations 1 , 2 , we will denote

1 < 2 if 1 is lower than 2 ,
P [ : ] = empty P [ : .(i+1)] = P [ : .i] • P | .i if ≤ .i P [ : .0] = P [ : ] if ≤ P [ .

A standard method for verifying assertions within programs

In all the following, we will associate to a given program P a verification structure (Φ, Υ), where Φ are the candidate loop invariants of the program, in the order they appear in (according to Notation 137). Υ will be a set of verification condition generators generating all the verification conditions for the program at hand. We describe below how we construct this set from a source program. First, we distinguish three types of verification conditions for a program:

1. The assertion conditions, which check that the assertion formulas hold at the corresponding locations in the program. These conditions may also include so-called property verifiers to ensure usual verifications not explicitly expressed within the program (such as divisions by zero, bounds of array accesses, etc). Given a program P , we will denote those by V assert (P ).

2. The propagation conditions, which check that the candidate loop invariants within the program do propagate. Given a program P , we will denote those by V ind (P ) and, given a loop L ∈ P , we will denote the propagation conditions for L by V L ind (P ).

3. The loop preconditions, which check that the candidate loop invariants hold when the program first enters the loop they appear in. Given a program P , we will denote those by V init (P ) and, given a loop L ∈ P , we will denote the propagation conditions for L by V L init (P ). Given a verification structure P representing a program, we assume that V C(P ) = V assert (P ) ∪ V ind (P ) ∪ V init (P ). Moreover, we expect that the pairwise intersections of V assert (P ), V ind (P ) and V init (P ) are all empty.

A classical way to generate such verification conditions from a program is to use a weakest precondition calculus and/or a strongest postcondition calculus, such as the ones presented in Definitions 139 and 140.

Definition 139. We define the weakest precondition of the formula ψ relatively to the program P , and denote by wp(ψ, P ), the formula inductively defined as follows:

ψ, empty → ψ ψ, I; P 1 → wp(wp(ψ, P 1 ), I) ψ, base-instruction → ψ depending on the specific instruction

ψ, assume [φ] → φ ⇒ ψ ψ, assert [φ] → φ ∧ ψ ψ, if C then P 1 else P 2 end → C ⇒ wp(ψ, P 1 ) ∧ ¬C ⇒ wp(ψ, P 2 ) ψ, while C do [φ] P 1 done → φ ∧ ∀x.(φ ⇒ wp(ψ, P 1 )) ∧ ∀x.(φ ∧ ¬C ⇒ ψ) Definition 140.
Similarly, we define a strongest postcondition of the formula ψ relatively to the program P and denote by sp(φ, P ), the formula inductively defined by: ψ, empty → ψ ψ, I; P 1 → sp(sp(ψ, I), P 1 ) ψ, base-instruction → ψ depending on the specific instruction ψ, assume

[φ] → φ ∧ ψ ψ, assert [φ] → ψ ψ, if C then P 1 else P 2 end → sp(ψ ∧ C, P 1 ) ∨ sp(ψ ∧ ¬C, P 2 ) ψ, while C do [φ] P 1 done → φ ∧ ¬C Remark 141.
The reader can observe that, contrarily to the weakest precondition calculus of Definition 139, the strongest postcondition calculus of Definition 140 does not contain the loop verification conditions.

Remark 142. For simplicity reasons, we assumed that C is expressed in the same logic as the one we use to express the formula within the program (such as loop invariants).

In practice, it may not be true and, in this case, one should start by translating those conditions into the logic the formulas are expressed in beforehand.

A loop invariant generation framework

Given a program, we can now define a verification structure to represent the problem we tackle.

Definition 143. Given a program P , we define (Φ, Υ) the verification structure representing P as follows.

• Φ is the sequence of candidate loop invariants in P , in their order of appearance.

• For any location ∈ P such that P | is of the form assert [φ],

υ assert : ϕ 1 , . • Given the verification condition generator υ assert of an assertion occurring in the program at the location , and given i the location of a loop it depends on (assuming this loop is the i th loop of the program), we define the associated verification update inverter υ assert -1 | i as follows:

υ assert -1 | i : I → wp(I, rmLoops(P [ i : ] ))
• Given the initialization verification condition generator υ init of a loop occurring in the program at the location , and given i the location of a loop it depends on (assuming this loop is the i th loop of the program), we define the associated verification update inverter υ init -1 | i as follows:

υ init -1 | i : I → wp(I, rmLoops(P [ i : ] ))
• Given the propagation verification condition generator υ ind of a loop occurring in the program at the location , and given i the location of a loop it depends on (assuming this loop is the i th loop of the program), we define the associated verification update inverter υ ind -1 | i as follows:

υ ind -1 | i : I → I
This gives us a verification structure able to represent a program. We can use the Ilinva algorithm presented in Chapter 5 to try and compute satisfying loop invariants for it. sented in this section, we would obtain for this program the following verification condition generators:

• υ 2 init : φ → x = -50 ∧ y = y 0 ⇒ φ • υ 2 ind : φ → φ ⇒ wp(wp(φ, x ← x + y), y ← y + 1) • υ 6 assert : φ → x = -50 ∧ y = y 0 ∧ ¬x < 0 ∧ φ ⇒ y ≥ 0
Similarly, the associated verification update inverters will be defined as follows: Proof. This is a consequence of the Definition 143. The fact that the verification structure is satisfied ensures that all its verification conditions are valid. The assertion verification conditions ensure that the assertions of the program are verified and the other ensure the validity of the loop invariants.

• υ 2 init -1 | 2 : I → I • υ 2 ind -1 | 2 : I → I • υ 6
Corollary 147. Let P be a verification structure representing a program in the sense of Definitions 128 and 143, to which we associate the verification update inverters as defined in Definition 144. If Ilinva(P ) terminates and if we have Ilinva(P ) = failure, then all the verification conditions of the program are valid. This means that all the assertions it contains hold and that all its candidate loop invariants are actual loop invariants.

Proof. This is a direct consequence of Theorems 125, 126 and Lemma 146, applying the result we obtained for the general algorithm in this particular case.

Even though this algorithm works in theory, it still contains a lot of imprecision for someone who would like to implement it. In particular, we did not detail how we select the abducible literals required for using ImpGen-PiD as the abduction algorithm within Ilinva. Likewise, we did not explain how we can obtain interesting filtering predicates for abduction from the program. Finally, we will see that additional considerations can be made regarding the use of ImpGen-PiD. Those issues will be discussed in Section 6. 4. The readers interested in the practical implementation of the system can refer to Chapters 7 and 8. In order to use the Ilinva algorithm to generate loop invariants of programs in practice, we will delegate the verification condition generation tasks to the program verification platform Why3 [START_REF] Filliâtre | Why3 -where programs meet provers[END_REF][START_REF] Bobot | Why3: Shepherd your herd of provers[END_REF]. It performs roughly the tasks let to the verification condition generator as defined in the present chapter, even though these conditions are tweaked to handle a larger class of programs and with additional considerations on, e.g., the simplification of the verification condition generated. Still, it gives us the guarantee we expect on the program it handles

Parametrization of the algorithm

In Chapters 5 and 6, we devised an algorithm using the ImpGen-PiD abduction algorithm to compute loop invariants of programs. In this part, we describe the additional parametrization required to implement such a system. In particular, we discuss how we generate abducible literals for the ImpGen-Ilinva abduction algorithm (see Line 2 of Algorithm 5.3), the order we use to test the solution it returns, and the method we use to select an unsatisfied verification condition to perform abduction on, and which candidate loop invariant to strengthen with the solutions.

Selecting verification conditions and candidate loop invariants

The first nondeterministic part of the Ilinva algorithm we need to discuss is the selection of the verification condition to strengthen, as well as the candidate loop invariants we will strengthen using the solutions of the abduction algorithm (see Lines 5 and 6 of Algorithm 5.2). As explained in Section 6.2, we decompose the verification conditions of our program into three subsets: the set V init (P ) of verification conditions ensuring that all the candidate loop invariants hold when the program first enters the loop they belong to, the set V ind (P ) of verification conditions ensuring that all the candidate loop invariants propagate, and the set V assert (P ) of verification conditions ensuring that we can prove the assertions of the program.

For simplicity reasons, we made the choice to never perform abduction on the verification conditions of V init (P ). We will assume, even though this is not always true, that the verification structure associated with a program for which the set of verification conditions related to the loop invariants initializations contains at least one unsatisfied verification condition is inconsistent. This will permit to define a filtering predicate for the ImpGen-PiD algorithm that can be used if we do not wish to compute the disjunctions of the abduction solutions. Indeed, refusing to add a candidate to the current hypothesis during the execution of the ImpGen-PiD algorithm if the result happens not to satisfy one of the loop initializations verification conditions will allow us to remove exploration branches we are certain would only produce such candidate loop invariants.

We make the choice of always considering the verification conditions ensuring the propagation of the candidate loop invariants first. This means that whenever the set V ind (P ) contains at least one non-valid formula, the verification condition we send to the abduction algorithm will be in it. We do this in order to ensure that the candidate invariants we strengthened when trying to prove the program's assertions are not too strong to propagate. This prevents the algorithm from exploring strengthening possibilities that would indeed prove other assertions within the program but would never allow us to obtain a complete proof of the program due to this failure to propagate.

This leaves us with the problem of deciding, within a set V ind (P ) of verification conditions related to the propagation of a loop invariant, which one we should select. We decided to consider the verification conditions in the reverse order of the loops in the program. When we have at least two candidate loop invariants that do not propagate within the program, we will consider the location of the loops they belong to, and select the verification condition corresponding the maximum of those locations. Intuitively, this is the condition that is the closest to the loop we have to prove the propagation of, and thus the one the modification of which would introduce the least amount of data in the system.

We now have to select the candidate loop invariant we will try to strengthen with the strengthenings that the abduction algorithm will return. In the most simple case (that is, with no nested loops), the candidate loop invariant of a loop will always be the guide formula associated with the verification condition related to the propagation of itself. When the loop contains other loops, it is clear that the verification condition for the propagation of its candidate loop invariants is based on the value of the nested loops invariants. More work should be done to design relevant heuristics allowing to try to strengthen the invariants of those nested loops to obtain a propagation proof for the main loop. In this work however, we will stick to always selecting the candidate loop invariant of the loop from which the verification conditions was derived.

Concerning the selections of the verification condition for proving the assertions of program, we consider them in the order they appear in within the program. This means that whenever the set V assert (P ) contains more than one unsatisfied verification condition, we will always select the one derived from the assertion with a minimal location. We now have to select which candidate loop invariant to strengthen using the solutions of the abduction algorithm. It is easy to see that the verification condition of an assertion does not depend on the candidate loop invariants appearing after it within the program. Those will thus never be considered. This leaves us with the candidate loop invariants preceding the assertion. We make the choice of trying all these possible strengthening locations in their reverse order within the program, unless they belong to a loop nested in the path leading to the assertion. Obviously, if we can show that the verification condition did not depend on a given candidate loop invariant, we will not try to strengthen it with the abduction solution of the verification of the assertion. 12 assert x = y; 13 assert y = n; loops and two assertions (which are, in this case, equivalent), we will have to decide which ones we consider first. Applying the rules we suggested in the present section, we will first try to find a strengthening allowing to prove the assertion at Line 12, reinforcing first the invariant at Line 9, then the one at Line 5 if nothing is found. If we reach a state in which one of the candidate loop invariants does not propagate, we will immediately try to strengthen this candidate with one of the non-valid verification condition built from this propagation requirement. If none of the candidates propagate, we will start by reinforcing the one at Line 9.

Selecting abducible literals

We can now tackle the construction of the abducible literals for the ImpGen-PiD algorithm. This will be done using the following method, of which all steps will be detailed below. We start by extracting from the program a set of core abducible elements. Then, for each verification condition forwarded to the abduction algorithm, we will remove from this initial set of core abducible elements the ones that are unrelated to the current verification condition (e.g. those containing variables undefined in the context of the verification condition). The remaining set will be forwarded to the ImpGen-PiD algorithm alongside the unsatisfied verification condition.

Using the program, it is clear that we can obtain relevant abducible literals from the identifiers (variables, functions, etc) it contains. This is what we use to build our set of core abducible elements. We will consider all the literals built upon the set of symbols occurring in the program up to the maximal depth of the terms occurring in the program. We can also allow the use of additional functions or predicates defined by the user to help the verification of the program. In this case, those will also be used to generate the set of core abducible elements.

Example 149. Going back to the algorithm of Example 131 (Algorithm 6.1), we see that it contains four variable identifiers (n, m, p, w), two constant integers (0, 1), three binary functions (×, +, ). and three binary predicates (≥, <, =). All the functions of the algorithm are only applied to variables, which is also the case of the two comparison predicates. The equality predicate will not be applied for two parameter that are results of the power function. This means that our set of core abducible elements will contain all the possible comparisons between constants and variable identifiers, as well as the equalities between variables, constants, and in one side results of the application of the power function.

As such, the set of core abducible elements contains elements expressed within the framework of the program, that do not relate to any of the verification conditions. Those cannot be forwarded to the abduction algorithm in this state, which is why we now present a transformation method to adapt this set when given a verification condition. Given a verification condition, we first remove from the set of core abducible elements the elements that are unrelated to the verification condition. Those are the elements containing variables or functions not appearing in the context of the verification condition, or undefined at the location of the candidate loop invariant. When this is done, we use the same method as the one we used for the translation of the verification condition (see again Definition 143) to obtain the corresponding logical formula of the core abducibles at the location of the verification condition we consider. This is the set of abducible literals we will forward to the ImpGen-PiD algorithm.

It is clear that additional work should be done to obtain smaller and more relevant sets of abducible literals. Indeed, even if we removed all the elements clearly unrelated to the verification conditions we process, most of the resulting literals are not particularly relevant for the proof, because they were built using only low-level information and do not encode any higher-level information on the program. We also refer the reader to Chapter 9 for the effects this has on the practical efficiency of the algorithm.

Parametrizing the ImpGen-PiD algorithm and the generation of abduction solutions

Even though it is stated that in Algorithm 5.3 we recover all the solutions from ImpGen-PiD before using them to strengthen our candidate loop invariants, it is natural to assume that any implementation of the algorithm will generate these solutions one by one, at the moment a new candidate is required. Such an implementation will guarantee that the only solutions that are generated are the ones that will actually be tested as candidate loop invariant strengthenings. This suggests that it will be important to generate the best possible strengthenings in the least amount of time.

The first element to consider to obtain this result is the use of the ImpGen-PiD algorithm. This algorithm explores the hypotheses it can construct from its set of abducible literals depth first. In particular, this implies that when this set is large, it may spend a lot of time exploring and trying hypothesis within a branch where all the hypotheses will end up being satisfiable before trying other possible solutions that may be more relevant. We will see in Chapter 9 that this behaviour can severely degrade the performance of the system. Moreover, as the Ilinva algorithm already uses a recursive method to strengthen the same candidate several times if necessary, it appears that we are not necessarily interested in obtaining deep (i.e., containing many literals) solutions, but rather in obtaining simpler ones, sufficient enough to obtain a proof. These considerations suggest that it may be useful to tweak the ImpGen-PiD algorithm slightly to simulate a breadth-first search. The method described below is recent work, and it is clear that more work should be done to devise a more integrated and efficient breadth-first version of the ImpGen-PiD algorithm.

We proceed using an iterative deepening strategy, that is, by calling the ImpGen-PiD algorithm multiple time with additional size filtering predicates. Given a maximal limitation size n, we will call successively the ImpGen-PiD algorithm n times with a filtering predicate limiting the size of the solutions to the current number of times the algorithm was called. We will also call the algorithm without those restrictions one last time, to be certain not to miss any solution. This ensures that we will generate small solutions first, even though it also implies that we are doing redundant work.

The second thing we have to consider is the behaviour of the UpdateImplicants method in Algorithm 5. 3. The way we decide to use it within this work is to construct disjunctions of the previously obtained solutions. Assuming that no strengthening leading to a complete proof of the program was found using the implicants returned by the ImpGen-PiD algorithm, it is possible to construct weaker implicants, by building disjunctions of those first ones. Still, it is clear that the number of such implicants can be extremely large, even if we limit the number of disjunctions in a given implicant.

Differences with the work of Dillig et al. [57]

The algorithm proposed by Dillig et al. in [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF] is similar to ours and also uses abduction to strengthen candidate invariants so that verification conditions are satisfied. The algorithms differ by the way the verification conditions and abductive hypotheses are proceeded. In our approach, the conditions always propagate forward from an invariant to another along execution paths, and we eagerly ensure that all the loop invariants are inductive. In their work, Dillig et al. allow for a more general selection structure, which may result in a larger search space, though they also additionally use a strongest postcondition calculus to instantiate their candidate loop invariants, which helps counterbalancing this effect. Another difference is that we use a completely different technique to perform abductive reasoning: the one in [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF] is based on model construction and quantifier elimination for Presburger arithmetic, whereas our approach uses a generic algorithm, assuming only the existence of a decision procedure for the underlying theory. This permits to generate invariants expressed in theories that are out of the scope of [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF].

Limitations

After all these considerations, we observe that the Ilinva algorithm used for the generation of loop invariants of programs still suffers some limitations. The first issue we notice comes from the construction of the set of abducible literals. As it is extracted strictly from the elements of the program (or additional user-provided elements). This means that if the candidate loop invariants can only be expressed using more complex functions or predicates, or expressed more clearly using those, we will not be able to find such solutions. Secondly, as mentioned before, the way we handle the loop initialization verification conditions may prevent us from generating a complete proof of a program if it can only be obtained by strengthening candidate loop invariants of other loops afterwards. Thirdly, the tweak we operate for the use of the ImpGen-PiD algorithm makes it perform some redundant work, notably redundant satisfiability tests, which is notably costly. We also note that we generate many abduction solutions that can appear as irrelevant to a human user. Finally, the algorithm uses successive strengthenings of candidate invariants to generate the proof that the verification conditions of the system are valid. This implies that if the program has no unsatisfied verification condition that can be verified by strengthening one and only one candidate loop invariant, then we will not be able to generate a solution for proving all its verification condition, even though such a solution may exist.

We will see in Chapter 9 that those limitations strongly influence the efficiency of the algorithm. However, we will also see that the fairly simple heuristics we chose still permit to generate solution for a wide range of programs, although not always in reasonable time. This suggest that this solution is promising and that additional work should be initiated to tackle the issues we mentioned.

Part III Implementation and evaluation of the abduction algorithm and of its application

Chapter 7

An infrastructure that transcribes the genericity of the algorithms

In Part I, we designed an algorithm to compute the prime (T , A)-implicates of a formula and, in Part II, we used this algorithm to design a generic loop invariant generator. In order to evaluate and test these two algorithms, we present in this part a C++ framework implementing both. This system is called Abdulot for abduction modulo theories. This chapter describes the design, development and basic usage of the system. We will discuss in Chapter 8 the details related to the implementation of concrete interfaces for SMT-solvers and program provers, and we will evaluate the framework experimentally in Chapter 9. For a detailed user manual, the reader is referred to Appendix C. As described in Chapter 3, we have designed an abduction algorithm that works modulo theories. It is independent of the theory, as long as we can provide a decision procedure for testing the satisfiability of formulas in this theory. This genericity being the main goal of this work, we implemented a system that is also generic. This means that it does not depend on any specific satisfiability decision algorithm, but rather exposes a generic interface for formula satisfiability checkers in which we will plug any SMT-solver that can handle the problems we consider.

Similarly, the strengthening algorithm is not inherently dependent on the tool it uses to detect strengthening locations and ensure the global verification of the program. This is why the system will also be generic with respect to this tool, and will communicate with it via a standardized interface.

Generic interfaces for SMT-solvers

We start by describing the interface we use to communicate with SMT-solvers in our system. We recall that we assume an SMT-solver to always return an element of B = {Sat, Unsat, Unknown}, and possibly a model when it returns Sat. In practice, it is possible that the SMT-solver, being a technical system, fails more significantly when trying to compute a formula and ends up returning an error. We will handle those errors as if they were Unknown results, as it is the only information we can extract from them. It is also possible for the SMT-solver not to terminate on a given formula. To ensure the termination of the main algorithm in those cases, it is possible to restrict the computation time of any SMT-solver query with a timeout. In this case, and if the SMT-solver has not returned any answer before the timeout ends, we will also interpret it as the SMT-solver returning Unknown.

The issue that arises when we allow the SMT-solver to return Unknown is that the ImpGen-PiD algorithm is not conceived to handle such answers. This justifies the following assumption:

In all the following, we will assume that it is possible to project the answers in B given by SMT-solvers into {Sat, Unsat}. We will use such projections to change the value of Unknown results to either Sat or Unsat depending on our needs. The most natural solution being to interpret Unknown answers as if they were Sat answers. Indeed, the ImpGen-PiD algorithm searches for implicates by deriving contradictions between the initial formula and a set of hypotheses it is constructing. If the SMT-solver tasked with the verification of those contradictions is unable to answer, we cannot ensure that the hypothesis it tried is a contradiction. In this case, rather that stopping the algorithm, we will handle it as if it was not a contradiction. It is clear that, in this case, we may miss actual implicates of the initial formulas. This choice ensures, however, that the algorithm is correct at the expense of completeness.

Now that the issue of Unknown results has been handled, we can tackle the presentation of the generic SMT-solver interface we designed in order to make the system independent of the SMT-solver. If one wants to plug an SMT-solver to our abduction algorithm, in order to generate implicates in a theory of his or her choice for instance, the only work that will be required is to write the corresponding wrapper to make the use of the SMT-solver match the interface. We present this interface in Interface 7.1. An SMT-solver interface contains a constraint wrapper, which represents the constraints that can be added to the set of formulas the SMT-solver should handle. We require that such constraints can be converted to C++ strings in order to print them when generating implicates or related results (such as implicants). We also expect the interface to wrap its models (when they exist) to allow the system to check whether a given constraint is validated by this model. The actual interface for the SMT-solver contains the usual methods to add constraints to the formula set, push and pop functions to stack constraints on multiple levels (necessary for solving incremental problems without recreating a new formula from scratch for each test) and a method to check the satisfiability of the constraints, and recover a model if possible. An additional class (usually called a manager) can also be sent to the solver via the interface if necessary, though this has not been explicitly expressed in Interface 7. 1. Such classes are usually required by SMT-solver APIs to allocate, construct and manage the formulas.

One may also have to devise a specific problem loader, which will handle the loading of a problem file and its conversion into constraints in the format handled by the interface defined above. The generic interface for problem loaders is described in Interface 7. 2. It contains code to load problem files for the solver used and will perform a step-by-step constraint forwarding. This means that it works by being asked whether it contains at least one more constraint before being called to return this constraint. Similarly, one can also devise a specific abducible literal loader. As we presented it in Chapter 3, the ImpGen-PiD algorithm computes (T , A)-implicates of a formula, that is, the T -implicates it can construct from the literals contained in A. This means that, in the implementation, it is necessary to compute the set A that is fed to to the ImpGen-PiD algorithm. This is done by adding a component to the system that will recover information about those abducible literals and will generate constraints (in the sense of Interface 7.1) corresponding to the actual literals that can be selected to build hypotheses during the generation of (T , A)-implicates by the algorithm. The generic interface for abducible literal generators is described in Interface 7. 3. It provides a method to load abducible literals from a file (technically in any format, even if we provide a specific one to represent them -see also Section 7.4). It should also provide a method for automatically generating abducible literals from the problem. Finally, after loading or generating abducible literals, the interface is able to return the total number of literals it obtained and to return them in an array. The finite set of abducible literals is then stored in memory and the literals referred by their index in the corresponding table. This table will be accessed when we need to use the value of the literals (such as when performing satisfiability tests). We will additionally assume that the order we should use on abducible literals is the one induced by their indices in this context. If the literals have been obtained by loading an input file, this order will correspond to the one they appeared in within the file. If the literals have been generated from the problem, then this order will be set by the generators; It is generally induced by the order in which the literals were found within the problem but can be set differently by modifying the generator.

The Abdulot framework comes with already implemented interfaces for Alt-Ergo [START_REF] Conchon | SMT Workshop: International Workshop on Satisfiability Modulo Theories[END_REF] (via its SMT-lib interface only), CVC4 [7] (via SMT-lib [START_REF] Barrett | The SMT-LIB Standard: Version 2[END_REF] and via its C++ API), MiniSAT [START_REF] Eén | An extensible sat-solver[END_REF] (using its Dimacs [START_REF]Dimacs challenge -satisfiability: Suggested format[END_REF] format and its C++ API), VeriT [START_REF] Bouton | verit: An open, trustable and efficient smt-solver[END_REF] (via its SMT-lib interface) and Z3 [START_REF] Moura | Z3: An efficient smt solver[END_REF] (via SMT-lib and via its C++ API). The framework also provides a generic interface for SMT-lib-compliant [START_REF] Barrett | The SMT-LIB Standard: Version 2[END_REF] solvers, which can be easily

Implementation of ImpGen-PiD

In this section, we will describe the implementation of the ImpGen-PiD algorithm. This implementation will be called GPiD and is schematically represented in Figure 7. 1. It is decomposed into three components: a hypothesis engine, with the task of selecting which abducible literals should be added to the hypothesis constructed to contradict the original problem, the interface of the SMT-solver, that will be used to test the satisfiability of the queries and conclude whether any hypothesis it is given is an implicate of the source problem or not, and an algorithmic engine (called implicate generator in Figure 7.1), which will manage the other two and handle the global execution of the ImpGen-PiD algorithm. All those components are packaged in a wrapping interface that is available within the library and also compiled as executables.

We consider the GPiD implicate generation system as a process taking as input some problem data, exporting implicates and possibly communicating with external hypothesis checkers. The inputs it requires are a set of logical formulas (compatible with the theories handled by the SMT-solver it was configured with) and a method to generate the abducible literals it should work with (see 7.4). We offer two methods to inject those in the system: one using files as well as a command line interface to tell the executable in which files these inputs can be found; and another using the C++ API directly. The input data is then split to send the formula to the implicate generator and the abducible literals to the hypothesis engine, where they will be ordered according to the order they were sent in, and then selected (by following the refinements we presented in Chapters 3 and 4) in order to build possible implicates. Similarly, the source problem is forwarded to the formula manager of the implicate generator to configure the tasks that will be delegated to the SMT-solver for finding its implicates. The source formula can also be used by the implicate generator to implement Definition 63 and prune some of the abducible literals stored within the hypothesis engine when they are logical consequences of the conjunction of the input formula and of the current hypothesis.

The ImpGen-PiD algorithm is executed by the implicate manager. It requests the hypothesis engine to select an abducible literal to add to its current hypothesis, forges a task with its formula manager and forwards it to the SMT-solver. Depending on the answer, it can forward a model to the hypothesis engine to prune future abducible candidates, or notify any external tool using it that it has found an implicate. hypothesis engine will also store this implicate. This will also allow it to prune exploration branches (see Algorithm 4.1). Similarly, the hypothesis engine can communicate with any available hypothesis checker, which are external components implementing user-defined filtering predicates (see Definition 79 and the use of filtering predicates in Algorithm 3.2), in order to prune abducible candidates those checkers do not accept.

The implicates forwarded by GPiD can be reused for any other purpose when returned within the Abdulot library. They are simply printed on the terminal when a test executable is used.

After an implicate has been found (or after we are sure that no more implicate can be derived by adding more abducible literals to the current hypothesis), the hypothesis engine will backtrack to the last abducible literal selection it made and pursue the exploration by adding to the hypothesis an abducible literal not previously tried at this level.

Finally, the execution can be interrupted by the usual interruption signals. These signals are not forwarded to the SMT-solver however. This can explain the delay between the detection of the interruption and the actual termination of the execution.

In the implementation, the wrapping interface can be instantiated through a C++ template GPiDAlgorithm<EngineT, LitGenT, IHandlerT> within the Abdulot library. Its Engine, the class used to select hypotheses, also contains the reference to the SMTsolver interface that should be used and its corresponding problem loader. The LitGenT object allows one to load and generate core abducible literals that will be used by the engine. It is the object that is plugged as the problem data interface. Finally, the class IHandlerT will be used to handle the implicates generated during the execution of the algorithm. It is the object that is plugged as the implicate interface. Additional hypothesis checkers can also be forwarded to the template, to possibly reject some of the hypotheses the engine will be tempted to make.

A GPiD hypothesis engine for selecting the candidates and handling the hypotheses

As explicitly induced by the structure of GPiD, it can be plugged with various hypothesis engines, possibly implementing some or all of the algorithm refinements presented in Chapter 3. 2. This section provides the description of an implementation providing all the refinements of Chapter 3.2 except the use of unit clauses. A sample description for the standard behaviour of this engine is provided in Figure 7. 2 .

The engine stores the abducible literal candidates it recovers for the system it is embedded in as well as the currently selected hypothesis (set of such literals). Following the commands of the parent object, it will add or remove elements from this currently selected hypothesis before forwarding the latter when asked to. When it has to add literals to its hypothesis, it will take into consideration all the elements it has available and apply the corresponding selections as presented in the theoretical sections. The elements it can usually count on are the models forwarded through its interface, the known implicates it stores and any external checker it can access via its wrapping interface. If necessary, it also usually comes with an internal SMT-solver interface to perform some minimal queries in order to prune some candidates that may be inconsistent or leading to implicates that are already part of the initial problem for instance. The hypothesis engine implemented in the Abdulot framework uses all these improvements, though they can be optionally deactivated. The framework also contains a so-called naive hypothesis engine which only uses minimal information to select abducible literals, and thus may not use any of those. The latter can be used for development or testing reasons.

Defining, generating and handling abducible literals

The hypothesis engine requires an initial set of abducible literals. As such literals are necessary on all the systems of this thesis, and as their formulation will most probably depend on the theory of the problem they relate to, we need some sort of generic method to describe, load and/or generate them. This is what we describe now.

We start by recalling that one can always write a custom abducible literal generator and plug it within the system. Two generators of this sort are provided within the Abdulot framework: one for propositional logic problems, used by default jointly with the MiniSAT interface on Dimacs [START_REF]Dimacs challenge -satisfiability: Suggested format[END_REF] problems, and one prototype for SMT-lib [START_REF] Barrett | The SMT-LIB Standard: Version 2[END_REF] problems. The first one generates the literals corresponding to all the propositional variables declared in the problem and their negation. The second generates all the equalities and disequalities between declared variables of the same sort. If none of those generators are useable and if the user does not want to provide their own generator, the framework also contains a generic method to build abducible literals from the problem loader interface of the SMT-solver. This is done using files we will call abducible files, that will be parsed and executed to generate source abducible text elements. All the text elements generated will then be parsed and converted into working abducible literals for the solver via its problem loader.

It is basically an SMT-lib-oriented file format to define core formula templates and to unroll them using macros. It is best used for defining abducible literals as SMT-lib elements but can also be used for any other file format. The commands of an abducible file are executed sequentially and before abducible literals can be recovered from it. We give the full grammar of the abducible files in Appendix A and detail the semantics of the commands below. A practical illustration will be given in Example 150.

• size

Set the number of literals to load. If auto, it will be computed as the total number of literals generated.

• rsize

Set the number of references to load. References are literals that are specially marked. They can typically be used when handling the implicates generated if a post-treatment requires such distinction (such as back translating a formula derived from a program containing both pointers and non-pointers variables).

• abduce/ible

Define one or more abducible literals.

• ref(erence)

Define one or more reference literals.

• declare Define (non abducible) literals of one or more sorts. For instance, the command (declare x y as int) defines two literals x and y in the sort int. Such literals are temporarily stored in a set indexed by the name of the sort. Multiple such sets can be created if multiple sorts are declared. The literals in these sets will not be forwarded as abducible literals.

• extend Make all the literals in the given sets abducible literals. Only affects literals contained in the sets at the moment.

• (declare-)lambda

Define a macro. When applied, it will create a new literal by textually replacing its named parameters by their value in its data.

• apply

Create new literals by applying a function. The function must have been declared. The parameters follow the order of the definition and are either the name of a sort, in which case literals will be created by iterating over the elements of the corresponding set, or of the form (strict <data>), in which case the exact content of <data> is used. All the literals generated are stored in the target set. Additional options can be specified such as symmetric for symmetric operations and nonself for non reflexive operations.

• copy

Copy the elements in the sources sets into the target sets. This can be used to factor the computation of some functions. If one wants to apply, e.g., the usual sum function + to literals referenced as both int and real, it can first copy all these literals in a new set intOrReal beforehand with the command (copy int real as intOrReal).

• annotate

Attach a forwardable annotation to some literals. Such annotations are forwarded to the problem loader or to the system extracting literals from the generator, while the names of the sets they were contained in is not. This can be used the same way reference literals are used to forward more complex information to the system (such as, e.g., specific conversion rules that were used to generate them from a program).

Example 150. We give in Figures 7.3 and 7.4 some sample abducible files for abducibles written as SMT-lib formulas, with the corresponding set of abducible literals that is built from them. In Figure 7.3, we define a simple abducible set directly by providing six literals. As we mentioned in the first line that this file contains four abducible literals, ( s i z e auto ) ( d e c l a r e a b c a s i n t ) ( lambda eq ( l r ) (= l r ) ) ( lambda neq ( l r ) ( d i s t i n c t l r ) ) ( apply eq ( o v e r i n t i n t ) r e s symmetric ) ( apply neq ( o v e r i n t i n t ) r e s symmetric ) ( extend r e s ) only the first four will be generated. In Figure 7.4, we define the same abducible literals but using the computational commands of the DSL. We start by declaring our three constants a, b and c as well the macros for equality and disequality. Then we apply these two predicates over our constants and store the resulting formulas in a set names res. Finally, we specify that the formulas of res should be considered as abducible literals. Because this time we did not explicitly set the number of abducible literals to extract, we will obtain the six literals. Note that if we did not add the symmetric keyword when applying the predicates, we would have also generated the literals with the constants in the other order, as well the tautologies a a, ..., and the contradictions a a, ...

The Abdulot framework provides an executable to parse and verify such files (called abdulot-parser). If abducible files are provided to any executable of the framework, they will have precedence over the generators we presented before. This means that the abducible literals that will be forwarded to the algorithm will be the one loaded from the file, and not the one generated by any other mean.

A version of the ImpGen-PiD algorithm re-expressed within this framework is provided in Algorithm 7. 4.

It actually consists in a standardized version of the ImpGen-PiD algorithm where all the work related to the selection of the hypothesis has been delegated to the associated engine within the framework.

Parametrization of the GPiD tool

We finally take a look at the options accepted by the GPiD tool. It is possible to toggle the use of models, implicate storage and external checker within the hypothesis engine. It is also possible to toggle additional SMT-solver checks within the engine to prevent the generation of inconsistent hypotheses. This is deactivated by default for propositional logic as the only inconsistent hypotheses we could construct would contain both a literal and its complement and we handle such cases by automatically removing from the set of abducible literals the complement of any literal added to the hypothesis; links between literals and there complements are created during the automatic generation of abducible literals by the system for propositional logic problems. Additional SMT-solver checks should also be deactivated by the user if the original set of abducible literals does not will expect as a result a modified problem for which the tool is able to produce a complete proof.

When sent to the Ilinva tool, the problem will be forwarded to the problem handler, which handles the task of constructing the associated verification structure and will communicate with the core tool to generate the verification conditions and check the status of the strengthened problems. Regarding the verification structure, exactly which part of the work is done by the tool itself and which part is done by the interface is left unspecified. We will assume that the problem handler as a whole acts as a checker for verification structures and implements an interface that handles the technical details required to do so. All the operations on verification conditions, complete proofs and strengthenings will be done under the command of the main component of the system which is the invariant generator -this last component basically runs the Ilinva algorithm.

We know recall how the algorithm is implemented within the framework. The invariant generator will, depending on the data sent to the Ilinva system, ask the problem handler to select a strengthenable part of the problem (couple verification conditionguide formula, see Lines 5 and 6 of Algorithm 5.2). It will then construct an abduction problem, which essentially means constructing a set of abducible literals and a configuration for the GPiD tool, and request the abduction system to produce solutions for it (implicates we will convert to implicants). It would naturally be possible to plug another abduction procedure into the system instead of GPiD, but this functionality is not explicitly provided, which means that a user would have to change the code initializing GPiD instances within Ilinva to do so. While GPiD computes the implicates of the problem it was sent, the invariant generator will recover them, sort them in the order they are returned, possibly prune some or construct others from the first ones (typically disjunction of the implicants it recovered) -this is what happens during the enhancement part on the figure -and then select which one it should use to strengthen the guide formula it was provided by the problem handler. From this point, it can ask the handler to recheck the problem, conclude if it succeeded or pursue the computation by trying to satisfy other verification conditions, backtrack, etc. Note that the construction of GPiD instances and their consequent computation of abduction solutions are done in parallel of the main system. This means that while a GPiD instance is generating abduction solutions for a given problem part, the invariant generator can try the solutions it receives at the same time, and even possibly explore subtrees of strengthenings if the assignment of one of those strengthenings was deemed useful by the problem handler.

Finally, we emphasize that additional checkers, representing additional information of the expected solution related to the prover used or the problem at hand can be used by GPiD, provided they are made available by the problem handler and possibly configured by the invariant generator. This is typically what we will use to remove candidates that do not satisfy loop initialization verification conditions.

Inside the Abdulot library, this strengthening system is available as a C++ template IlinvaAlgorithm<EngineT<ProblemHandler, Interface> >, which will be instantiated by the problem handler we use and by the SMT-solver interface that should be used by GPiD. One again, the Ilinva system is made available through a test-executable which will depend on the problem handler it uses. Details on the problem handlers we built are exposed in Chapter 8. In order to make the system independent on the problem handler we use, we specify in Interface 7.5 the interface formalism we will consider for problem handler. Any problem prover that can be enclosed into such a structure is accepted by the system. According to this, we rewrite in Algorithm 7.6 the Ilinva algorithm enclosed within the invariant generator component of the technical framework of the Ilinva tool. We store in a stack the sequence of verification conditions that we are currently computing strengthenings for. This stack also serves as a means to derecursify the initial algorithm. Non-valid verification conditions are selected for the current state of the problem at Line 6 and we detect Line 7 if it is possible to strengthen the selected verification condition (see Section 6.4). If this is the case, we create at Lines 18 and 19 a new parallel execution of GPiD for this verification condition and remember this choice Line 20. The strenghtening of the candidate loop invariant with the first implicant is performed on the following line. If it was not the case, we have either explored all the possibilities and failed to solve our input problem (Line 8), or we need to backtrack to explore other possible implicants (Line 16) or verification conditions (Lines 13-14).

The Abdulot framework provides a problem handler for generating loop invariants on Why3 programs. The details of this implementation are described in Chapter 8. The corresponding executable is ilinva-why3-wrapped, which is already plugged to all the SMT-solver interfaces that were available for GPiD on the system the framework was build on. A complete list of options that can be used to configure the Ilinva tool is available in Appendix C, as well as a more complete user manual. For a minimal usage, if one wants to generate loop invariants of a given Why3 program program.mlw, using the solver solver for solving abduction problems with GPiD, and with a core set of abducible elements abducibles.abd, one can use the command ilinva-why3-wrapped -i program.mlw -g solver -a abducibles.abd.

Chapter 8

Concrete interfaces for concrete problems

In Chapter 7, we presented the framework for a generic implementation of the prime implicate generation Algorithm ImpGen-PiD (see Chapter 3) into the GPiD tool and of the precondition strengthener Algorithm Ilinva (see Chapters 5) into the Ilinva tool. We showed that its generic design allowed us to plug it with interfaces of any SMTsolvers and program verifiers. In this chapter, we will describe how we designed concrete interfaces in order to generate actual tools that can be used to solve real problems. The resulting tools will also be used in Chapter 9 to evaluate and discuss the efficiency of these algorithms.

We will start by presenting how we plug widely used SAT-solvers and SMT-solvers into the SMT-solver interface framework we presented. We will build such interfaces for MiniSAT [START_REF] Eén | An extensible sat-solver[END_REF], CVC4 [7] and Z3 [START_REF] Moura | Z3: An efficient smt solver[END_REF]. Moreover, we will design a generic SMTsolver interface that can work with any SMT-solver that exposes an SMT-lib interface [START_REF] Barrett | The SMT-LIB Standard: Version 2[END_REF]. Then, we will see how we can plug the Why3 [START_REF] Bobot | Why3: Shepherd your herd of provers[END_REF][START_REF] Filliâtre | The Why/Krakatoa/Caduceus platform for deductive program verification[END_REF] verification platform into an interface to use it within Ilinva and generate loop invariants for programs it can handle. This chapter will be concluded by an explanation on how the corresponding tool are compiled in the Abdulot library and on how one can write additional interfaces for other solvers or provers.

SAT-solver and SMT-solver interfaces

The main guideline we considered when designing interfaces for solvers was to reuse as much as possible the elements they provide. Those include their parsers, formula internal representations and formula printers.

An interface for MiniSAT

MiniSAT is an open-source SAT-solver the design of which is intended to be minimal while still providing very good performance. It handles propositional clauses (disjunction of literals) expressed in the Dimacs format [START_REF]Dimacs challenge -satisfiability: Suggested format[END_REF]. Example 151. Let us consider the set of propositional clauses we introduced in Example 52: Φ = {p ∨ ¬q ∨ r, q ∨ ¬r ∨ ¬s, ¬p ∨ ¬q ∨ s} over the four propositional variables p, q, r, s. As MiniSAT is open-source and provides a C++ API, we have access to this content and can write an interface plugged directly within the solver, and bypass its external interface reading Dimacs data on the command line. We will still use the Dimacs parser of MiniSAT but by sending data directly to it. If we use the interface framework that was presented as Interface 7.1, we plug the representation of the clausal constraints defined in the MiniSAT API to the Constraint interface and use the clause printer of the solver to convert them into printable strings. The incremental interface for the solver (see Section 1.3) is not implemented directly within the MiniSAT API, as it was not made explicitly available in the version we used. It is simulated using an external stack of literals that is forwarded as a set of assumptions during each satisfiability check call.

For these reasons, the problems that will be handled by GPiD when instantiated with the MiniSAT interface must be presented in the Dimacs format. The given file will be parsed exactly as it would have been by MiniSAT. GPiD will then generate all the prime implicates of the set of clauses it is given from an initial set of abducible. As computing prime implicates in propositional logic is fairly standard, we implemented a generic abducible generator that constructs from a given Dimacs file all the usual propositional literals we can extract from it. This generator extracts all the propositional variables declared in the file and generates all the corresponding positive and negative literals. If the user wants to reduce the number of abducible literals (which can typically happen when the set of clauses has to be obtained by the Tseitin transformation [START_REF] Plaisted | A structure-preserving clause form translation[END_REF] of an initial formula), he or she will have to use an abduction file in the format presented in Section 7. 4.

When MiniSAT answers that a given problem is Sat, the assignment of the variables it used to satisfy all the clauses can be recovered and used as a model. This model is always total, which means that all the propositional variables of the problem are assigned a boolean value. The structure of the API sadly ensures that whenever a new satisfiability check call is made by the solver, this model will stop being available (as it will be modified by the solver to compute the result of the new formula it was given). This means that if we want to keep these models, we have to store them ourselves. This storage is thus mandatory if we want to check which abducible literals are entailed by the models directly within the exploration loop, as described at Line 9 of Algorithm 3.2. To prevent this additional storage requirement, we can configure the GPiD implementation to instead remove all the candidates implied by the model at the moment we recover it from the satisfiability test. With this method, the model is only used once, when it is still valid, and can be broken by the MiniSAT solver afterwards while being sure that no additional invalid access to it will be made.

Interfaces for the C++ API of CVC4 and Z3

In order to solve problems formalized in more expressive theories, it is clear that we need interfaces to SMT-solvers. CVC4 and Z3 are both widely used, handle a wide range of theories and offer a C++ API from which we can construct an efficient interface for our framework. Similarly to what we did for the MiniSAT interface, we reused as much as possible from the solvers' available code. This ensures that, as both solvers can handle multiple file formats, the problems we can handle will also be expressible in these formats. The API of CVC4 provides parsers for SMT-lib, TPTP [START_REF] Sutcliffe | The tptp problem library[END_REF], and its own CVC4 script file format. Likewise, Z3 provides parsers for files written in SMT-lib or TPTP. This means that when using the interfaces we built on these solvers, the user can inform the Abdulot tool it is using of the format their problem is in and forward the problem as it is. It is important to note however that the parser we select to load the problem file is also the one we will use to parse the abducible literals. In the current version of the Abdulot framework, the problem and the adbucibles must be expressed in the same format.

The fact that we use the formula framework of the SMT-solvers' API means that we recover the context manager they provide, that is, the class they use to allocate, construct and manage formulas. This also means that all the internal work they can do to process formulas forwarded to them via those methods will also be active. It is also from this context manager that we obtain the formula printers of the solvers to return the solutions we generate, usually expressed in the SMT-lib format.

Incremental functions are already implemented in both SMT-solvers and used by our tools. Contrarily to the MiniSAT interface, we do not need to simulate it with an additional stack packaged in the interface. Also, both SMT-solvers provide classes to represent models that we can use to prune our candidate hypotheses. It is interesting to note however that they also both provide a specific method to check whether a given formula is satisfied by the model they currently contain (i.e., the model of the last formula they processed, if the formula was found satisfiable). Similarly to what we did in the MiniSAT interface, we can use these methods to prune the candidate hypotheses once only which avoids the need to store the models in memory.

We provide for both solvers simple generation rules that generate either all the equalities and disequalities between the constants of the problem, or all the inequalities between those constants. For any other use of abducible literals, the user has to provide an abducible file.

It is important to take into account the fact that SMT-solver APIs tend to evolve rather frequently alongside the tool they belong to. This means, in particular, that the interfaces built on them can be broken in future versions. The exact versions of the SMT-solvers handled by the interfaces are provided in the documentation of the tool. Overcoming this development instability is the purpose of the standard, more stable interfaces presented in the next section.

A generic interface for SMT-lib-compliant SMT-solvers

In order to obtain a stable interface for SMT-solvers, and in order to be able to easily plug our framework into many such solvers, we have implemented a generic interface for SMT-solvers providing an SMT-lib command-line interface. The principle of this interface is to load input files and abducible files in the SMT-lib format and to represent the corresponding formulas as strings of characters. It can then implement simple formula constructors (conjunction, disjunction and negation) to permit the creation of satisfiability queries for abduction hypotheses and finally invoke a compatible SMT-solver program by sending to it the adapted problem (rewritten in the SMT-lib format) within a file. It is clear that some definitions of the problem files the interface handles are dependent on the solver that should be used to solve them. This is typically the case when notifying the theory in which the problem is expressed or when using quantified formulas. The purpose of this generic interface is not to provide a type of universal representation of any problem that could permit it to be sent to any SMT-solver. Rather, it uses a standard representation for satisfiability modulo theories problems that can allow the user to plug the correct solver to the Abdulot framework for a given problem easily.

In order to handle such problems, we implemented a simple Lisp parser in the Abdulot system. Given an SMT-lib problem file, it will return the associated abstract syntax tree from which we can extract the SMT-lib commands of the file as well as their arguments. The configuration commands as well the constants and function declarations are recovered and stored in memory. They will be added to the header of any file later constructed by the interface. The assert commands containing the facts that the problem contains are then stored as strings and can be negated when necessary. Similarly, the abducible literals obtained from an abducible file will be stored as strings and added to the assertions of the problems we construct when necessary.

The interface then performs as expected: the incremental structure is implemented internally using a stack and, when a satisfiability test is queried, the interface constructs an SMT-lib problem file (juxtaposing the configurations and declarations of the initial problem file, the assertions of the initial problem file and any additional facts added through the incremental interface) and sends it to the executable of the SMT-solver it was configured with. It then recovers the result from the SMT-solver to answer the query. It is standard for SMT-solvers to additionally output a model of the formula that they computed, when this formula was found satisfiable. Technically, it could be possible to parse such models and use them within our framework. However, it appears that the format of those models is less standard than the SMT-lib file format. Moreover, as no model verification algorithm on SMT-lib formulas represented by character strings was implemented in the interface, we would require an additional call to the SMT-solver executable to check whether or not a given formula is satisfied by those recovered models. For those reasons, the recovery and usage of these models is not available in the current version and has been left for future work. When asked for a model of a given formula previously found satisfiable by the SMT-solver, the interface will act as if no such model was available.

Instantiations of this standard interface are available in the Abdulot framework for Alt-Ergo [START_REF] Conchon | SMT Workshop: International Workshop on Satisfiability Modulo Theories[END_REF], CVC4, VeriT [START_REF] Bouton | verit: An open, trustable and efficient smt-solver[END_REF] and Z3. If a user wants to plug another SMTsolver into the Abdulot framework, they can copy the configuration file of one of those instances and replace the executable of the chosen solver with one of its own.

A Why3 interface for Ilinva

In this section, we will present the implementation of a problem handler interface for the Ilinva algorithm and a tool using the Why3 platform to generate loop invariants of programs.

Presenting the Why3 platform

Why3 [START_REF] Bobot | Why3: Shepherd your herd of provers[END_REF][START_REF] Filliâtre | The Why/Krakatoa/Caduceus platform for deductive program verification[END_REF][START_REF] Filliâtre | Why3 -where programs meet provers[END_REF] is a widely-used platform for deductive program verification. It is written in OCaml and uses an internal logic formula representation (in the form of the Why language) as well an internal ml-oriented language (WhyML) to define programs and express logical properties on them. From these two representations, Why3 is able to generate verification conditions that can be sent to SMT-solvers to ensure the correctness of the property they express. The main advantages of the Why3 platform is that we can express a very large set of programs and properties in it, and that it can be plugged into most of the SMT-solvers and theorem provers available. These features are extremely useful in our context as we also aim to build a generic system that can plugged to many SMT-solvers to handle various theories.

The use of the Why3 platform also permits to avoid implementing a front-end for a program language, which would have otherwise been necessary to evaluate programs and their loop invariants. Moreover, we can delegate to Why3 the back-end verification condition generators that construct from a program they are given the verification conditions necessary to prove its property. Why3 provides back-ends for all the SMT-solvers it can work with. Moreover, there exists a variety of tools [START_REF] Cuoq | Frama-c: A software analysis perspective[END_REF][START_REF] Filliâtre | The Why/Krakatoa/Caduceus platform for deductive program verification[END_REF] that allow one to automatically translate classes of programs written in well-known programming languages into a format that Why3 can handle.

Why3 is thus a deductive program verification platform able to perform most of the operations required by the Ilinva algorithm on verification structures (see Definition 112). It is a very good system to build an Ilinva interface upon as it will perform most of the work by itself. The following paragraph of this section details how we build the elements we have to implement to do that: wrappers to obtain an efficient communication between the Why3 tool and the Abdulot framework.

We emphasize that the purpose of the implementation of this interface is to study the feasability of the generation of loop invariants through abduction in many theories more than to obtain a tool as efficient as possible to do so. It is also intended to be inserted in the generic framework of the Ilinva algorithm. If one wants to implement an efficient system to compute the loop invariants of programs using the Ilinva algorithm, a better choice would be to extract directly the instantiated version of the Ilinva algorithm for the generation of program loop invariants and to implement this algorithm directly inside a deductive program verification system such as Why3 (see e.g. [START_REF] Bobot | The Why3 platform 1.2.0[END_REF]).

Recovering and using the verification conditions generated by Why3

We will now describe the structure of the Ilinva interface we built to plug Why3 into our tool. The primary goal of this interface is to be able to represent the WhyML program, to modify its invariants and to communicate with Why3 in order to check whether a proof can be obtained and/or to obtain verification conditions for a particular property expected from the program. For these reasons, we designed a component that (loosely) parses the WhyML program it is given, extracts the loops and the associated invariants, and then constructs a structure linking these candidate invariants to the location they appear at within the program. From this structure, the component is able to export a WhyML program that would correspond to the one it was previously given where all the invariants are replaced by the candidates the structure contains. This exported WhyML program can then be returned outside of the interface (a functionality that will be used when we have obtained a proof to return a result) or forwarded to the Why3 platform to check the status of the program decorated with the current candidate invariants.

In the latter case, the interface will recover the verification conditions that Why3 generates for the program it was given, as well as the result it obtained out of the computation (that is, whether the generated formulas were found to be valid or not). It will then associate each verification condition to the loop invariant location it depends on (see Section 6.4) and generate relevant couples of loop invariant locations and verification conditions that it forwards to the main algorithm. In practice, we generate all possible couples of this type and try them one after the other: if the selection of one couple does not permit to generate a solution to the problem, we will backtrack until this selection was made and try the next couple. When the main system obtains a strengthening from abduction for a given couple, it will send this strengthening to our Why3 interface that will use it to strengthen the designated candidate loop invariants. Similarly, when backtracking, the main algorithm will delegate the task of relaxing previously strengthened invariants to the interface.

Configuring GPiD and its SMT-solver interfaces

As we use GPiD to compute the abduction solutions of the system, we detail in this section the configuration we forward to it from the Ilinva tool. We mentioned in Chapter 7 that the GPiD implementation is generic (with respect to the SMT-solver). However, when using it in practice, we need to decide which SMT-solver to use. As mentioned in Section 8.2.1, the Why3 platform already uses SMT-solvers to decide whether the verification conditions it generates are valid or not. As we recover those verification conditions, it is natural to use the SMT-solver that Why3 targeted when it generated them. For this reason, we will ask the user to choose which SMT-solver Why3 should use to prove the program and use the same SMT-solver within GPiD. It is clear that one of the major advantages of the Why3 platform lies in the fact that one can use a distinct prover for any given verification condition, as it is very possible that, within a problem, some verification conditions will be found more easily by one particular prover. This suggests that some work should be carried out on trying to check the verification conditions with the various SMT-solvers available in Why3 or even to do the same for the computation of the abduction solutions. However, as the use of such a functionality would greatly increase the number of satisfiability tests without further refinements, it has not been implemented.

Also, as we explained in Section 6.4, we decided not to try to strengthen candidate loop invariants when verification conditions related to the initial conditions of the loop are not valid. In particular, when we do not allow the invariant generator to produce disjunctions of implicants, this means that we can, instead of removing such possible strengthenings after they have been generated, use a filtering predicate within GPiD to prevent their generation directly. When the algorithm will construct its hypotheses, it will check, before adding any literal, that these literals necessarily hold when the loop is entered (see also Section 3.2). This verification will be done by the Why3 interface, to which the GPiD wrapped execution will forward its candidate hypotheses for verification before pursuing its computation. This technique cannot be used if disjunctive loop invariants are allowed, since, in this case, such implicants (those invalidating the loop initialisation verification condition) generated by GPiD may still be used in a disjunction that could, as it will be less restrictive implicants, satisfy the corresponding verification condition.

Abducible literals for the strengthening of WhyML programs loops

We now present some practical details on how we can generate and handle abducible literals for WhyML programs. As we explained in Chapter 6.4, a natural way to obtain relevant abducible literals on programs is to consider the symbols they contain (program variables, program functions) and to generate the literals we can obtain from those. In order to do that, the Ilinva implementation contains a set of tools that are able to (loosely) parse WhyML programs, extract such symbols and generate the corresponding abducible literals expressed in the abducible format handled by our system. This initial set of abducible literals will be used by the algorithm as its core set of abducible literals. When tackling a particular abduction problem however, we do not need all those abducible literals to be considered. The Why3 interface will be tasked with the removal from this initial set of the literals that are not related to the current verification condition.

Those include the ones that contain symbols that either are undefined at the location of the condition or that do not appear in it. This updated set will be the one forwarded to GPiD to perform abduction on the verification condition.

The translation that is required to adapt abducible literals to a specific verification condition (and backward, to translate the solutions it returns into a correctly expressed loop invariant strengthening), as it can differ depending on the type of verification condition at hand (see again Section 6.3), should also be done by the interface. As it happens deeply within the GPiD system however, we cannot expect it to be executed this transparently in the implementation. In order to obtain the result, the interface will wrap alongside the loop invariant condition/verification condition couple a conversion toolbox that will perform this translation. The GPiD tool will handle the abducible literal it was provided blindly. However, whenever it exports a problem for its SMT-solver, the practical construction of problem will not use the abducible literal itself but the result of its conversion by this toolbox. Similarly, the implicates it generates will transit by this conversion toolbox to be translated before being returned. This allows us to perform the l e t main ( ) : u n i t d i v e r g e s = l e t t = r e f 0 i n w h i l e ! t < 10 do i n v a r i a n t { t r u e } t := ! t + 1 done ; a s s e r t { ! t = 10 } Figure 8.2: Simple WhyML loop necessary adaptation of the abducible literals for the problem without explicitly defining a distinct behaviour within the GPiD tool.

We also remark that, in addition to the the minimal translation required by the Ilinva Algorithm presented in Chapters 5 and 6, additional technical conversions are necessary and will be performed by the same toolbox. This is typically the case for WhyML program variables that are WhyML references. Indeed, such a distinction is usually omitted within the verification conditions but is mandatory for the program to be contextually valid. By using the reference keyword on variables within the abducible file we generate from WhyML programs, the conversion toolbox will be able to detect whether a given variable should be written as a reference or not and perform the translation of the implicates accordingly.

Example 152. Let us consider the sample WhyML program presented in Figure 8. 2. A satisfying loop invariant to prove the assertion of this program would be, e.g., t ≤ 10. However, as t is represented in the program by a reference variable t, this invariant should be written in WhyML as { !t <= 10 }. As the verification condition generated by Why3 makes no distinction between reference and non-reference variables, we will need to define t as a reference variable within our abducible file. Now let us unroll a complete execution for this sample program. First, we need to obtain the set of abducible literals we will use for the computation of abduction solutions. This program contains only one variable (t) and two integer constants: 0 and 10 (we do not consider the incrementation). The predicates contained in the program are the usual equality for integers = and the inequality contained in the loop condition <. From this information, we can generate an abducible file applying the generation rules we described in this chapter. This result is exposed in Figure 8. 3 The files will generate 18 abducible literals that will be used by GPiD to generate implicates.

We can now send the files of Figures 8.2 and 8.3 to the Ilinva tool, select an SMTsolver for the computation, e.g. CVC4, and try to generate conjunctive invariants for our WhyML program (command line: ilinva-why3-wrapped -i tenten.mlw -a tenten.abd -g ccvc4 -H "solver:cvc4" -c). The tool will then forward the program to Why3, which in turn will answer that the assertion it contains cannot be proved and return the associated verification condition (see Appendix B). This condition can be used directly for the abduction in GPiD. Moreover, as this example program is very simple, all the abducible literals will be kept for the execution. Ilinva will thus call GPiD with this verification condition and recover implicants of the formula expressed in SMT-lib 8.3 Documentation, compilation structure and distribution of the implementation

Dummy interfaces for documentation

Two additional interfaces (called documentation interfaces) are available in the Abdulot framework. They are named Tisi interfaces and do not implement any real satisfiability solving algorithm or any precondition verification algorithm. Instead, they serve as generation proxies for a documentation presenting the exact technical requirement of an interface. If a user wants to implement an interface, either for an SMT-solver or for problem prover, they can refer to the documentation generated for these two interfaces to obtain the exact definitions, classes and functions prototypes, preconditions and expected behaviours in order to design it. Additional method descriptions are provided in the documentation to help this design process.

A note on the compilation framework

The compilation of interfaces is included within the compilation structure of the Abdulot framework. The compilation scripts start by generating the additional libraries required by the framework to work, then compile the algorithms and standard tools in the Abdulot library. Once this first step is done, it will detect the SMT-solvers available in the system and generate additional libraries containing the compiled interfaces for those SMT-solvers. The same process is applied to the problem handler interfaces used by Ilinva. We point out that the case of the MiniSAT interface is particular as the compilation scripts will automatically download, patch and compile a correct version of the solver to generate an interface that can be plugged in the Abdulot framework. This additional step is required to let us create an access to some of the functionalities of MiniSAT that are not available in its usual public API (most notably to compute statistics). All the other solvers must have been previously installed on the system by the user (as well as their API if one wants to use the interfaces built upon them). Finally, after all the interfaces have been compiled into libraries, the compilation scripts will compile tool executables for both GPiD and Ilinva using all the interfaces available. These tool instances are the one that be used by the user on actual problem files. They are also the ones we will use in Chapter 9 to evaluate the algorithms developed in this thesis.

Distribution

This concludes the presentation of the implementation of a generic infrastructure implementing the ImpGen-PiD algorithm presented in Chapter 3.2 and the Ilinva algorithm presented in Chapter 5, as well as their instantiations to compute prime implicates modulo theories and to generate loop invariants for programs. The complete Abdulot framework (which includes all the required libraries, algorithm and the interfaces presented in this chapter) is available under a three-clause BSD license on GitHub [START_REF] Sellami | Abdulot framework and tools[END_REF]. The version in use at the time of this thesis was composed of 16000 lines of code, among which 1500 concern to the compilation structure, 1500 to the implementation of the ImpGen-PiD algorithm, 600 to the implementation of the Ilinva algorithm, 3500 to the SMT-solvers interfaces and 3500 to the Why3 interface.

Chapter 9

Experimental evaluation of GPiD and Ilinva

In Chapters 7 and 8, we presented an implementation of the prime implicate generation algorithm we devised in Part I and of the loop invariant generator we devised in Part II.

In the current chapter, we are going to use this implementation in order to perform an experimental evaluation of those methods. We will take a particular interest in showing that the methods devised are indeed generic and that they can solve problems expressed in many different theories, even though, when competing with other tools specifically designed for some particular theory, they do not always perform as efficiently. We will also take some time to discuss which lines of research we think should be explored to improve the prime implicate generator in regard of the application we used it for, namely, loop invariant generation.

Experimental infrastructure

All experiments presented in this chapter have been performed on a computer powered by a dual-core Intel i5-4250U processor running at 1.3 GHz and running macOS version 10.14.

Evaluating the ImpGen-PiD algorithm in propositional logic

We start by evaluating our prime implicate generator in propositional logic, where it is reasonable to try and to generate all the prime implicates of a given set of clauses, and where we can compare the efficiency of our approach with other state-of-the-art alternatives. In order to evaluate the ImpGen-PiD algorithm in this context, we implemented in the Abdulot framework the model minimization (see also Chapter 11) and unit propagation unfolding we presented in 3. 4. This was done by partly merging the main algorithmic component with its MiniSAT interface. We compared the resulting implementation with two state-of-the-art prime implicate generator for propositional logic: ZRes [START_REF] Simon | Efficient consequence finding[END_REF] and primer [START_REF] Previti | Prime compilation of non-clausal formulae[END_REF]. We will look at whether or not these algorithms are able to generate all the implicates of a given benchmark or some implicates of a given benchmark. Moreover, we will discuss the results we can obtain by reducing the size of the set of abducible literals and what is says on the behaviour of the algorithm. We will also discuss the use of the filtering predicate within GPiD to generate implicate of small size more efficiently than with the other tools.

Benchmarks

We first present the benchmarks we used for prime implicate generation in propositional logic.

• uf20: Set of 1000 uniform random satisfiable almost unsatisfiable problems (few models). 20 variables and 91 clauses (4.3 clause-to-variable ratio, i.e. 4.3 times more clauses than variables) with clauses of length 3. Benchmark available on the SAT-lib [START_REF] Hoos | Satlib: An online resource for research on sat[END_REF][START_REF] Hoos | Satlib: Benchmarks[END_REF] • mid20-8: Set of 1000 uniform random satisfiable problems. 20 variables, 91 clauses with clauses of length 8.

• high20-18: Set of 1000 uniform random satisfiable problems. 20 variables, 91 clauses with clauses of length 18.

• small: Set of 298 uniform random problems with 7 variables and 21 clauses of length 3.

• hcp: 5 problems with 100 variables and two problems with 250 variables rendered almost unsatisfiable from a first-hand uniform random generation with a 4.3 clauseto-variable ratio. Clauses of length 3.

• rider: Uniform random problems with a 4.3 clause-to-variable ratio and clauses of length 3. 20 problems for each number of variables between 20 and 300.

These benchmarks have been chosen to evaluate the various properties GPiD is supposed to possess. Typically, the fact that as expected, it performs best on almost unsatisfiable problems (with a small number of models). Apart from the uf20 benchmark, all the benchmarks were generated manually. For all the experiments of this section, the implicit set of abducible literals we consider contains all the propositional literals that are contained in the problem handled.

Evaluating GPiD alone

To evaluate the general performance of GPiD in propositional logic, we started by studying how well it performs on the benchmarks we chose. On the uf20, high20-18 and small benchmarks, the tool was able to generate all the prime implicates of any example within ten seconds. For the problems contained in mid20-8 however, there are no examples for which it was able to generate all the prime implicates under a minute. We then used the hcp benchmark to evaluate how the tool performs on almost unsatisfiable problems.

The five examples with a hundred variables were solved (in the sense that we generate all of their prime implicates) under ten seconds by GPiD. One of the problems containing 250 variables was also solved under ten seconds, however, the time to solve the other one exceeded fifteen minutes.

We continued with the evaluation of GPiD by studying the performance of the algorithm when we reduce the number of abducible literals of the problem we send it. We did this on the rider benchmark by randomly selecting a set of abducible literals among the literals of every problem. The average evaluation time of the problems for every given number of variable has been represented on Figure 9.1, where GPiD[x]p is the evaluation of the GPiD algorithm with x percent of abducible literals. It shows that as expected, the lower the number of abducible literals, the faster the algorithm performs. A profiling of some of the examples with a large number of variable showed that most computation time was spent within the satisfiability tests performed by MiniSAT and during unit propagation. As those are parts of a state of the art SAT-solver implementation, this is a limitation of the GPiD algorithm that is hard to overcome.

Comparison with ZRes and primer

The last part of the evaluation consisted in comparing the results of GPiD to those obtained by other state-of-the-art prime implicate generators in propositional logic. We compared with implementations of algorithms introduced in Chapter 2: ZRes [START_REF] Simon | Efficient consequence finding[END_REF] and primer [START_REF] Previti | Prime compilation of non-clausal formulae[END_REF].

On Figure 9.2, we represent the comparison of the execution time (in seconds) with ZRes (left) and primer (right) on the small (top) and uf20 (bottom) benchmarks. We observe that we are generally faster than ZRes and a little slower than primer on these benchmarks. Moreover, while ZRes and primer appear to be uniform on these benchmarks (all the problems are solved in almost the same time), we can see that GPiD is not on the uf20. Indeed, some of the examples take much more time to solve than the others (the ones with more implicates). This result scales on almost unsatisfiable problems, which means that when we solve such problems fast enough, we solve them faster than ZRes and a little slower than primer. However, the larger the number of variables, the larger the number of problems with a small number of implicates for which we fail to answer in a reasonable time. This is also shown on the hcp benchmark: for the six problems for which we answer under ten seconds, we compute the prime implicates between one to two seconds slower than primer; for the other one, while primer gives an answer in almost the same time, we do not. For this particular example we fail to solve, primer finds 374 implicates. On the other example with 250 variables we solved, there are 255 implicates. We emphasize that ZRes did not give an answer in a reasonable time for these examples.

The experiments on less constrained problems (with more implicates) show that we are not as fast as the two other implementations. On the high-20-18 benchmark, while both ZRes and primer compute the set of prime implicates under ten seconds for all the problems, we are above this time on forty percent of them. Moreover, there are no examples where we appear to be faster than any of the two. The mid-20-8 benchmark provides another interesting information: on this benchmark, ZRes is the only algorithm that answers under ten seconds (both primer and GPiD taking more time, primer still being the fastest of these two). It is thus possible that such problems are harder to solve with decomposition-based algorithms. In a more general way, even if slower, the results we have in computation time over the various benchmarks are closer to the ones primer gives.

Summary

While not performing as fast as primer, it appears that GPiD falls in the range of the state-of-the-art for solving highly constrained prime implicates generation problems (with a small number of models). Indeed, experiments have shown that on such problems, we solve problems between two to ten times faster than ZRes and slightly slower than primer. When the number of variables increases however, it appears that the GPiD algorithm takes more time than the other algorithms for solving a problem. Analyses on these examples show that they have more prime implicates than the ones we solved, which tends to demonstrate that the GPiD efficiency heavily depends on the number of prime implicates. This makes it hard for GPiD to compete with the other algorithms on examples with a large number of implicates, which is not necessarily the case for, e.g., ZRes. However, those are not the examples we are interested in solving.

Even though GPiD does not prove fast enough on general problems, it is still almost as fast as primer on highly constrained problems, even with a large number of variables, as long as the number of prime implicates remains low. GPiD also offers the possibility to control the literals we need in the implicates. This is a distinctive advantage compared to other algorithms, especially when working on problems converted from actual programs. It also reflects that the flexibility we gain on the form of both problems and solutions can have a negative impact on the efficiency of the implicate generation.

Evaluating the ImpGen-PiD algorithm in the general context

We now tackle the direct evaluation of the ImpGen-PiD Algorithm via the GPiD tool in the general context (modulo any given theory for which an implementation of a decision procedure for testing satisfiability is available). In this case, it is not reasonable to try to generate all the implicates of a given formula (as they can be particularly numerous, even for simple problems), the goal of this section is restricted to the evaluation of whether the system is able to generate some implicates for a wide range of problems and, if so, how many (and/or how fast) it can generate. As a secondary experiment, we will also evaluate how this implementation compares to another prime implicate generator in the theory it handles.

In order to obtain a large range of logical problems in various theories, we built our benchmarks from problems extracted from the SMT-lib [START_REF] Barrett | The SMT-LIB Standard: Version 2[END_REF][START_REF] Barrett | The Satisfiability Modulo Theories Library (SMT-LIB)[END_REF] library. We considered the theories of quantifier-free uninterpreted functions (which are contained within the QF_UF folder of the SMT-lib library) and of quantifier-free linear integer arithmetic with uninterpreted functions (which belong to the QF_UFLIA folder). From those sets, only the satisfiable examples have been kept for analysis. As it is induced by the implementation, the sets of abducible literals are part of the problem input. We generated them by considering all ground equalities and disequalities with a maximal depth provided by the user; all the experiments were conducted using a maximal depth of 1 and the average number of abducible literals is around 13397 (min. 1741, max. 17 • 10 6 ). For the experiments, we chose not to apply unit propagation simplifications to the considered sets of clauses. The reason for this decision is that efficiently performing such simplifications can be difficult and strongly depends on the theory. We also define fix(, , ) (see Definition 63) as the complementation on literals and P (see Definition 79) as either or a predicate ensuring Card(M ) ≤ n to generate T -implicates of size at most n. In all the experiments, the prime implicates filter (SubMin(), see Definition 43) was not active, so that T -implicates can be generated on the fly. This implicitly means that, when an T -implicate is generated and returned at the same time, there is no guarantee that no more general T -implicate will be generated at a later time. It is guaranteed, however, that no more general T -implicate have already been generated. Finally, we recovered the models from the SMT-solvers in order to further prune the set of abducible literals (see Definition 72 and Proposition 73).

Tables 9.1 and 9.2 show the number of examples for which the GPiD tool generates at least one T -implicate for a given timespan, for the QF_UF and QF_UFLIA benchmarks respectively. The results show that our tool is quite efficient, since it fails to generate any T -implicate within 35 seconds for only 2% (resp. 1%) of the QF_UF (resp. QF_UFLIA) benchmarks. Figure 9.3 additionally shows the proportion of the QF_UFLIA set for which GPiD generates an implicate in less than 15 seconds, depending on the maximal size constraint. For the QF_UF benchmark, the proportion decreases from 97% for a maximal size constraint of 1 to 95% when there are no size restrictions. We also point out that for 57% of the QF_UF benchmark, we are actually able to generate all the T -implicates of size 1 in less than 15 seconds.

We ran additional experiments to compare this approach with a previous one based on a superposition-based approach [START_REF] Echenim | Quantifier-free equational logic and prime implicate generation[END_REF][START_REF] Echenim | Prime implicate generation in equational logic[END_REF] and implemented in the cSP tool (see also Size/Time [0, 0.5[ [0.5, 1[ [1, 1.5[ [1.5, 2[ [2, 5[ [5, 10[ [10, 35[ Chapter 2). As far as we are aware, cSP is the only other available tool for implicate generation in the theory of equality with uninterpreted function symbols. Previous experiments (see, e.g., [START_REF] Echenim | Quantifier-free equational logic and prime implicate generation[END_REF][START_REF] Echenim | Prime implicate generation in equational logic[END_REF]) showed that cSP is already more efficient than approaches based on a reduction to propositional logic for generating implicates of ground equational formulas. This is why we did not run comparisons against tools for propositional implicate generation. We chose to compare the tools by focusing on their ability to generate at least one T -implicate of a given size. Indeed, generating all (prime) T -implicates is unfeasible within a reasonable amount of time except for very simple formulas, and comparing the raw number of T -implicates generated is not relevant because some of these may actually be redundant with respect to non-generated ones. We believe that, in practice, being able to efficiently compute a small number of T -implicates for a complex problem is more useful than computing huge sets of T -implicates but only for simple formulas. This is typically the case when we use this algorithm for the generation of loop invariants within the Ilinva Algorithm, where we want to obtain a relevant strengthening as fast as possible, not a huge set of uninteresting strengthenings leading to dead-ends.

The following experiments are only based on the previously used benchmarks that can be solved by both prototypes. As cSP is not capable of handling integer arithmetics, this only includes the examples of the QF_UF benchmark. We represented on Figure 9.4 the number of examples for which both tools can generate at least one T -implicate with a given maximal size constraint for various timeouts (a) and generate at least one T -implicate within a given time limit for various maximal size constraints (b). Figure 9.4 shows that GPiD is able to generate at least one Timplicate for more examples than cSP. It is able to generate at least one T -implicate for more than twice the number of examples cSP handles when the time limit is low, though this gap tends to be reduced the more time we allow. Moreover, if we limit the size of the T -implicates we generate (which can be done internally by both prototypes), the experiments show that GPiD is still able to generate at least one T -implicate for more examples than cSP. Here also, the difference between the two prototypes tends to be reduced when we allow for larger T -implicates. This result was to be expected since DP LL(T )-based approaches are more efficient than engines using the superposition calculus for testing the satisfiability of quantifier-free formulas with a large combinatorial structure. Furthermore, the superposition engine used in the previous approach had to be specifically tuned for implicate generation, and thus is already less efficient than stateof-the-art systems such as Vampire, E or Spass. This is part of the advantage of having a generic algorithm using decision procedures as black boxes.

Evaluating the loop invariant generator Ilinva

We now consider the evaluation of the Ilinva tool for generating loop invariants for WhyML programs. In order to evaluate both the efficiency and the genericity of the approach, we devised a benchmark set containing both examples expressed in theories that are usually considered by such tools (such as linear arithmetic) and examples that are extracted or crafted in more expressive theories, such as those for which SMT-solvers show difficulties to decide the satisfiability. We collected our benchmarks from several sources [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF][START_REF] Gupta | Invgen: An efficient invariant generator[END_REF]157,[START_REF] Lévy | Sorting algorithms[END_REF][START_REF] Boldo | Gallery of proved programs[END_REF]172] corresponding to those considerations. We also added examples corresponding to standard algorithms for division and exponentiation (involving lists, arrays, and nonlinear arithmetic). A detailed view of each benchmark source and of the theories it uses is given in Table 9. 3.

Some of these benchmarks have been translated by hand from C or Java into WhyML when they were not already expressed in the language. In all the experiments, the initial invariant associated with each loop was . We configured the Ilinva and GPiD tools with Z3 for the benchmarks containing real arithmetic, with Alt-Ergo for lists and arrays and with CVC4 in all the other cases. All those examples, as not easily recoverable from their sources (due to the WhyML translation that was performed), are distributed with the source of the Ilinva tool.

Results of the generation

We ran Ilinva on each example, first without disjunctive invariants then with disjunctions of size 2. The results are reported in Tables 9.4 and 9.5. For each example, we report whether our tool was able to generate invariants allowing Why3 to check the soundness of all program assertions before the timeout. If this is the case, we also report the time Ilinva took to do so (columns T(C) when generating conjunctions only and T(D) when generating implicants containing disjunctions). We also report the number of candidate invariants that have been tried (columns C(D) and C(D)) and the number of abducible literals that were sent to the GPiD algorithm (column Abd). Note that the number of candidate invariants does not correspond to the number of satisfiability queries that are made by the system: those made by GPiD to generate these candidates are not taken into account. The timeout is set to 20 min. For some of the examples that represent key crafted examples expressed in more difficult theories, we allowed the algorithm to run longer. We report those cases by putting the results between parentheses. Light gray cells indicate that the program terminates before the timeout without returning any solution, and dark gray cells indicate that the timeout was reached. Empty cells mean that the tool could not generate any candidate invariant. The last column of both tables report the time Why3 takes to prove all the assertions of an example when correct invariants are provided.

An essential point concerns the handling of local solver timeouts. Indeed, most calls to the SMT-solver in the abductive reasoning procedure will involve satisfiable formulas, and the solvers usually take a lot of time to terminate on such formulas (or in the worst case will not terminate at all if the theory is not decidable, e.g., for problems involving first-order axioms). We thus need to set a timeout after which a call will be considered as satisfiable (see Section 7.1). Obviously, we neither want this timeout to be too high as it can significantly increase computation time, nor too low, since it could make us miss solutions. We decided to set this timeout to 1 second, independently of the solver used, after measuring the computation time of the Why3 verification conditions already satisfied (for which the solver returns Unsat) across all benchmarks. We worked under the assumption that the computation time required to prove the other verification conditions when possible would be roughly similar.

Discussing the results of the evaluation of Ilinva

As can be observed, Ilinva is able to generate solutions for a wide range of theories, although the execution time is usually high. The number of invariant candidates is relatively high, which has a major impact on the efficiency and scalability of the approach.

When applied to examples involving arithmetic invariants, the program is rather slow, compared to the approach based on minimization and quantifier elimination [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF]. This is not surprising, since it is very unlikely that a purely generic approach based on a modelbased tree exploration algorithm involving many calls to an SMT-solver can possibly compete with a more specific procedure exploiting particular properties of the considered theory. We also wish to emphasize that the fact that our framework is based on an external program verification system (which itself calls external solvers) involves a significant overcost compared to a more integrated approach: for instance, for the Oxy examples (taken from [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF][START_REF] Gupta | Invgen: An efficient invariant generator[END_REF]), the time used by Why3 to check the verification conditions once the correct invariants have been generated is often greater than the total time reported in [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF] for computing the invariants and checking all properties. Of course, our choice also has clear advantages in terms of genericity, generality and evolvability.

When applied to theories that are harder for SMT-solvers, the algorithm can still generate satisfying invariants. However, due to the high number of candidates it tries, combined with the heavy time cost of a verification (which can be several seconds), it may take some time to do so.

The number of abducible literals also has a strong impact on the efficiency of the process, leading to timeouts when the considered program contains many variables or Our prototype has some technical limitations that have a significant impact on the time cost of the execution. For instance, we use SMT-lib files for communication between GPiD and CVC4 or Z3, instead of using the available APIs. We went back to this solution, which is clearly not optimal for performance, because we experienced many problems coping with the numerous changes in the specifications when updating the solvers to always use the latest versions. The fact that Why3 is taken as a black box also yields some time consumption, first in the (backward and forward) translations (e.g., to associate program variables to their logical counterparts), but also in the verification tasks, which have to be rechecked from the beginning each time an invariant is updated. Our aim was not to devise an efficient system, but rather to assess the feasibility and usefulness of this approach.

This finally gives us some additional information on the behaviour of the GPiD tool. When we used it within the Ilinva tool, it was shown to be the main bottleneck of the system. This is due to both the cost of the numerous calls to the SMT-solvers and the size of the search tree of the abduction procedure, especially for hard theories (e.g., non-linear arithmetic) for which most calls with satisfiable formulas were stopped by the local timeout of Ilinva. This suggests that the focus we took on reducing the search space in Chapter 3.2 was important, and that more work should be invested in reducing this set further. It may even interesting to relax the completeness of the algorithm if we can produce "good" implicates by trying less hypotheses.

Still these experiments show that both systems are already of practical use to solve generic problems where no specific or more adapted solutions is known, or even more classical problems in the case of GPiD, even though it does not compete extensively against state-of-the-art tools aimed at solving a specific class of problems.

Part IV A model minimization algorithm for performing abduction in separation logic

Chapter 10

Multi-level implicant minimization by formula component-based generalization

In this part, we present the bases of another approach to generate implicants of a formula.

The idea we investigate is based on model construction. Once a model of the considered formula has been found, we try to deduce a first implicant from it. In some cases, this implicant can be obtained by considering the conjunction of all the abducible literals that are true in the model. It can be viewed as an abstract description of a class of interpretations satisfying the considered formula. If it is possible to obtain this implicant, the proposed approach will then refine it to produce a new implicant as general as possible. This refinement can be done by either removing hypotheses from the initial implicant or replacing them by weaker ones. When no such operation allows to obtain a formula that remains an implicant of the initial problem, we conclude that we have obtained the best implicant we could get from this method.

In order to compute this refinement of the initial implicant, we present in this part an algorithm to minimize the model-obtained implicants when they can be expressed as a conjunction of smaller, base logical formulas for which we assume basic weakening rules are given. We then perform a weakening on each component by trying to replace it by a more general formula and backtracking if this replacement prevents the new conjunction from remaining an implicant of the considered formula. The method we present is an extension of [START_REF] Bradley | Checking safety by inductive generalization of counterexamples to induction[END_REF], where the authors present an algorithm to efficiently minimize models of propositional logic formulas. In this context, minimizing a formula is equivalent to minimizing the set of literals that are true in the model. The approach of [START_REF] Bradley | Checking safety by inductive generalization of counterexamples to induction[END_REF] uses the divide-and-conquer principle to perform this minimization. It is also proven that their approach performs a number satisfiability checks in both O((l -1) + l log( l l )) and Ω(l + l log( l-l l )) where l is the size of the initial model and l is the size of the minimal model returned by their algorithm. In our context, we can review this propositional logic approach as follows. The method of [START_REF] Bradley | Checking safety by inductive generalization of counterexamples to induction[END_REF] first constructs a formula from a propositional model by considering the conjunction of all the literals that are satisfied by the model. To obtain a more general implicant, the weakening that is performed consists in removing some of the literals of the formula. Indeed, this gives a formula that is more general than the previous one and thus, if it keeps the initial problem as a logical consequence, gives a more general implicant (from which we can immediately deduce a smaller, partial model) of the problem. In other theories however, the weakening of the literals of a formula is not that simple. For instance, a literal can be a logical consequence of another (such as x 1 |= x ≤ 1 in linear arithmetic). The framework we devise can be applied to other logics and provides a finer control on the components of the model we try to minimize (finer than just deciding between keeping or discarding a literal, as it is done in [START_REF] Bradley | Checking safety by inductive generalization of counterexamples to induction[END_REF]).

We will start by presenting the framework for this algorithm, based on the same divide-and-conquer paradigm, and then detail instantiations to minimize implicants in propositional logic and separation logic (a well-known logic for reasoning on programs [START_REF] Reynolds | Separation logic: A logic for shared mutable data structures[END_REF]). We will also introduce a simple algorithm to perform abduction on separation logic formulas based on this minimization algorithm. In Chapter 11, we will present and evaluate an implementation of this method and discuss the observed behaviour.

A framework for representing implicants

We assume given a class of logical formulas S.

In all the following, we are going to consider what we call the generalization of logical formulas according to a generalization relation. For this reason, we will assume the existence of a predefined generalization relation → g on the formulas of S (saying that φ 2 is more general than φ 1 when φ 1 → g φ 2 ).

Assumption 153. We assume that → g is well-founded. This property permits to prevent the possibility to generate some infinite generalization sequence leading to the nontermination of our algorithm.

Assumption 154. We assume that → g is functional ( i.e. ∀φ 1 .∀φ 2 .∀φ 3 .φ 1 → g φ 2 ∧φ 1 → g φ 3 ⇒ φ 2 = φ 3 ). This property permits to obtain a deterministic generalization relation, which in turns reduces the search space of exploration-based algorithms.

We will generalize the components of an initial formula that can be expressed as a conjunction of formulas of S using this generalization relation.

As our goal is to represent a formula by a set of generalizable components, we first define a way to represent these components and the state they are in (whether they have been generalized or not). To apply the algorithm, we will need a way to keep a memory of the states the components are in, of how many times they were generalized and of their previous states. This information will permit to backtrack the generalization that were made if the resulting formula is not an implicant for the problem anymore. In order to represent these generalizable components, we will thus use sequences of formulas. These sequences will track the consecutive generalizations of the source component while keeping in memory all the previous generalization steps.

Definition 155. We consider non-empty finite sequences of formulas of S that we call S-sequences. Such sequences are of the form φ 1 , φ 2 , . . . , φ n where ∀i ∈ 1, n , φ i is a formula of S.

For an S-sequence s = φ 1 , φ 2 , . . . , φ n , we will call base(s) Example 157. Let us consider the following S-sequences: s = x y, x ≤ y, and t = t r . We have active(s) = , base(t) = active(t) = t r and base(s) = x y. Moreover, t + s = t r, x y, x ≤ y, .

Definition 158. We say that an S-sequence φ 1 , φ 2 , . . . , φ n is a generalization sequence if ∀i ∈ 1, n , φ i → g φ i+1 .

Intuitively, when representing a generalizable component, the base formula of a generalization sequence is the initial description of the component and the active formula is its current description. The main algorithm starts with a representation of a formula containing only generalization sequences of one element. It updates these sequences so that, at the end of its execution, we are able to construct a minimal model by taking the active formulas of all the generalization sequences that it built. Definition 159. Given two generalization sequences s 1 and s 2 , we say that s 1 is a prefix of s 2 if there exists a generalization sequence s 3 such that s 1 = s 2 + s 3 . Similarly, we will say that s 2 is a suffix of s 1 if there exists a generalization sequence s 3 such that

s 3 = s 1 + s 2 .
We will additionally say that a generalization sequence s 1 is a strict prefix (resp. strict suffix ) of a generalization sequence s 2 if it a prefix (resp. suffix) of it and if s 1 = s 2 .

Definition 160. We define < g the well-founded order induced by → g on generalization sequences as follows: for two generalization sequences s 1 , s 2 , we write that s 1 < g s 2 if s 2 is a strict prefix of s 1 . This implies that s 1 and s 2 start with the same elements but φ 1 contains more generalizations and therefore admits an active formula more general than the active formula of φ 2 .

Remark 161. Notice that because → g is functional, for any two generalization sequences s 1 , s 2 such that base(s 1 ) = base(s 2 ), we have necessarily that either s 1 is a prefix of s 2 or s 2 a prefix of s 1 .

In order to simplify the recovery of initial components and the association of various possible generalizations of the same initial formula, we define the following notations: Remark 163. Note that base -[]() is a partial function. Note also that, if the set of Ssequences W was obtained from an initial set of S-sequences of size one by appending to them any given number of their successive generalizations by → g , then for any formula φ that is the base of one of the sequences of W , base -[φ](W ) exists and is unique (because → g is functional).

Definition 164. In order to define the way we construct the main formula from its components, we assume, in the following, the existence of a representation function S from a set of S-sequences to formulas of S.

An example of such a function can be the conjunction of the active formulas of the set.

Definition 165. We say that a representation function S is monotonous for a generalization relation → g if for any two sets of S-sequences W and W such that W is obtained by replacing an element φ 1 , . . . , φ n of W by an S-sequence s = φ 1 , . . . , φ n , ψ such that φ n → g ψ, we have that S(W ) |= S(W ).

Example 166. Let us consider the generalization relation → g such that for any φ ∈ S, φ → g . Let us also consider the representation function S ∧ : {s 1 , . . . , s n } → i∈ 1,n active(s i ). Now let us consider a set of S-sequences W = {s 1 , . . . , s n }. For any i ∈ 1, n , j∈ 1,n active(s j ) |= j∈ 1,n \{i} active(s j ) ∧ . This ensures that S ∧ is monotonous for → g .

Note also that S ∧ is monotonous when → g is such that φ |= ψ every time φ → g ψ.

In all the following, we will always assume that our representation functions are monotonous for the generalization relations we consider.

We now discuss the way we will regroup the base formulas to obtain a coherent representation of an implicant. Definition 167. Let W be a finite set of generalization sequences. We say that W is a representation set if it verifies all the following : 1. Card(W ) = Card(base(W )) (no two elements in W have the same base.)

S(W ) is satisfiable.

This is meant to ensure both that the generalized formula will be satisfiable and that every generalization sequence in W will be unambiguously related to a unique component of the original formula.

Example 168. For instance { x y, , r t, } is a valid representation set while { x y, , x y, x ≤ y } is not, because its two generalization sequences have the same base.

We also need to define additional properties to ensure that the representation set we modify is and remains the representation of an implicant of the original formula. Finally, we present a notation for representing the fact that we recover the first implicant representation set from our source formula. Definition 171. We assume the existence of a possibly partial function Iextract that, given a satisfiable formula φ, will return an implicant representation set for φ. We call such a function an implicant extractor.

Example 172. In propositional logic, an intuitive example of implicant extractor would be the following. Given a finite set of propositional literals L from which we construct propositional formulas, for any satisfiable formula φ constructed on L, Iextract would first compute a model M |= φ and return { l | l ∈ L ∧ M |= l}.

A framework for generalizing implicants

In this part, we present the generalization formalism used to replace components of implicants by more general ones.

Notation 173. In what follows, we will denote by → g + the transitive closure of → g over the formulas of S. We also consider the usual associated notation → g * .

The main idea with this order is to define possible generalization sequences for components. We then try to apply these predefined generalization steps to the components we have at hand. Definition 174. We consider a partial function Gen mapping any pair (W, s) where W is a representation set and s ∈ W to a set of sequences defined as follows:

1. For any pair (W, s) in the domain of Gen, W |= Gen(W, s).

2.

For any pair (W, s) in the domain of Gen, Gen(W, s) = (W \ {s}) ∪ {s } where s < g s.

We call this function an atomic generalization function.

This function is defined as partial in order to make a distinction between active components we are allowed to generalize and the ones we are not allowed to generalize (typically because it would break the implicant property of the result). This function can be viewed as an extension of the generalization order to generalize representation sets.

Proposition 175. For (W, s) ∈ Dom(Gen), Gen(W, s) is a representation set.

Proof. Let us consider (W, s) ∈ Dom(Gen).

1. Because W is a representation set, and because the construction does not, by definition, add any new base in the returned set, we cannot introduce a duplicate base in the set. Thus we have Card(Gen(W, s)) = Card(base(Gen(W, s)))). Moreover, if s < g s, then base(s ) = base(s). Therefore, Gen(W, s) contains the same set of bases as W .

S(W

) is satisfiable because W is a representation set. Moreover, we have that S(W ) |= S(Gen(W, s)) by definition of Gen. This means that S(Gen(W, s)) admits at least one model (the same model as W ). S(Gen(W, s)) is therefore satisfiable.

Thus Gen(W, s) is indeed another S-representation set.

Definition 176. Let W 1 and W 2 be two representation sets. We say that W 2 is a generalization of W 1 according to an atomic generalization function Gen (and note W 2 Gen W 1 ) if either W 2 = W 1 or ∃W I a representation set and s ∈ W I such that W 2 = Gen(W I , s) and W I Gen W 1 .

We say that W 2 is a strict generalization of W 1 according to an atomic generalization function Gen (and note W 2 ≺ Gen W 1 ) if it is a generalization of W 1 and distinct from W 1 .

Proposition 177. Let us consider an atomic generalization function Gen and the relation Gen on representation sets as described in Definition 176. 1. Gen is an order.

≺

Gen is well-founded. Proof. By definition, if W 1 ≺ Gen W 2 , then the set {|s| | s ∈ W 1 } is strictly lower than {|s| | s ∈ W 2 }
according to the multiset extension of the reverse ordering on natural number. This entails that ≺ is well-founded. Note also that as ≺ is well-founded, it is necessarily antisymmetric. Definition 178. Let Gen be an atomic generalization function and let W be a representation set. We say that W is generalizable according to Gen if there exists s ∈ W such that (W, s) ∈ Dom(Gen). We say that s ∈ W is generalizable in W according to Gen if (W, s) ∈ Dom(Gen).

The algorithm we will use to minimize implicants will perform a decomposition of the initial representation set into smaller, more general ones. In order to reconstruct the correct representation of the complete implicant from these sets, we need to recover the generalization sequence they contain and keep only those for which the active formula is the least general for a given base. Indeed, when we generalize the active formulas of a given representation set, it is possible that the resulting formulas do not entail the one we are constructing an implicant for. This means that at least one component has been generalized more than possible and that this generalization must be undone. We thus need to backtrack this generalization to obtain once more an implicant representation set using the active formulas that were kept in the other sets. This is the purpose of the following definition.

Definition 179. Let W 1 and W 2 two representation sets. We define the merging operation

W 1 ⊗ W 2 def = base -[φ](W 1 ∪ W 2 ) φ ∈ base(W 1 ∪ W 2 ) .
Using this operator, we can recover previous states of the generalization from one representation set used to test a new generalization and one keeping components in a representation known to provide an implicant of the initial formula.

Example 180. Taking for instance W

1 = { p 1 ∧ p 2 , p 3 ∧ p 4 , p 3 } and W 2 = { p 1 ∧ p 2 , p 2 , p 3 ∧ p 4 }, we will obtain W 1 ⊗ W 2 = { p 1 ∧ p 2 , p 3 ∧ p 4 }.
The context would typically be that we tried to generalize p 1 ∧ p 2 by p 2 in one part and p 3 ∧ p 4 by p 3 in the other but then discovered that it would have broken the properties we needed thus wanted to backtrack to the previous result. The advantage of the merging operator being that it allows us to backtrack all breaking generalizations even if made separately.

Proposition 181. If W 1 and W 2 are two representation sets, then W 1 ⊗ W 2 is also a representation set.

Proof. Reusing the two points of Definition 167. The fact that Card(W 1 ⊗ W 2 ) = Card(base(W 1 ⊗ W 2 )) is ensured by construction. The said construction also ensures that W 1 ⊗ W 2 ⊂ W 1 ∪ W 2 , which proves that S(W 1 ⊗ W 2 ) is satisfiable as the parameters are both representation sets.

Proposition 182. As we have a deterministic way to compute the base -[]() function for representation sets, the merging operator is associative and commutative.

Proof.

• Commutativity is trivial when applying the properties of the set union operation.

• Associativity uses the same properties after noting that for a representation set W and a formula φ, we have base(base

-[φ](W )) = φ.
Thus, base( base -[φ](W ) φ ∈ base(W ) ) = base(W ) and for two representation sets W 1 and W 2 , base(W 1 ∪ W 2 ) = base(W 1 ) ∪ base(W 2 ). This permits to ensure that base

-[φ](W 1 ∪ W 2 ) = base -[φ](base -[φ](W 1 ) ∪ W 2 )
as we look for the minimal sequences on the same set of bases.

It is now possible to tackle the construction of our implicant minimization algorithm. In propositional logic, the usual algorithm that is used to minimize an initial implicant built from the conjunction of all the literals satisfied by an initial model consists in splitting these literals into two parts. For each part, the algorithm tries to minimize the set of propositional literals by removing some of them while assuming that all the literals of the other part are present in the model. Of course, only the literals that do not break the implicant property of the whole formula are removed. To perform this simplification, it recursively calls itself. This first step gives the algorithm a minimal implicant for the first part, assuming the second. It can then minimize the second part while assuming that the literals of the first are present in the final conjunction. Once the two parts have been minimized under the support the other, the algorithm is able to return a minimal implicant of the initial formula.

What we present below is an adaptation of this algorithm that permits to handle more complex cases where the weakening of a literal does not consist in its removal. Moreover, we also extend the algorithm to be able to decompose the initial set in more than two parts, hence the following definition.

Definition 183. Let W be a representation set. We say that {W 1 , W 2 , . . . , W n } is a generalization partition of W if all the following are verified:

1. i∈ 1,n W i = W . 2. For any W i , i ∈ 1, n , W i ≺ Gen W . 3. For any W i , W j , i, j ∈ 1, n , i = j, s i ∈ W 1 ∧ s j ∈ W j ⇒ base(s i ) = base(s j ).
Example 184. Let us consider the generalization function that transforms equality between terms into lower inequality and lower inequality to . This means that, for any two terms t 1 , t 2 , we have t 1 t 2 → g t 1 ≤ t 2 → g . Now let us consider the constants a, b, c, d, e, f, g, h and the representation set

W = { a b , c d , e f , g h }.
The set {{ a b, a ≤ b , c d, c ≤ d , e f , g h }, { a b , c d , e f, e ≤ f , g h, g ≤ h }} is a generalization partition of W as well as the set {{ a b, a ≤ b, , c d , e f , g h }, { a b , c d, c ≤ d , e f, e ≤ f , g h, g ≤ h }}.

The set {{ a

b, a ≤ b, , c d , e f , g h }, { a b, a ≤ b , c d, c ≤ d , e f, e ≤ f , g h, g ≤ h }} however is not a generalization partition of W . Indeed { a b, a ≤ b, , c d , e f , g h } ⊗ { a b, a ≤ b , c d, c ≤ d , e f, e ≤ f , g h, g ≤ h } = { a b, a ≤ b , c d , e f , g h } which is distinct from W .
After decomposing representation sets into smaller parts, we also need to remove from the considered parts of the partition any element that would be replaced when merging it back with the remaining parts of the partition. This cleaning process is the purpose of the following procedure.

Definition 185. Considering two representation sets W 1 and W 2 , we define the cleanrepresentation set of W 1 according to W 2 as the set

Clean[W 2 ](W 1 ) def = {s ∈ W 1 | ∀t ∈ W 2 , base(t) = base(s) ⇒ t < g s} .
Proposition 186. For any two representation sets W 1 , W 2 , we have

W 1 ⊗ W 2 = Clean[W 2 ](W 1 ) ⊗ W 2 .
Proof. As W 1 and W 2 are representation sets and → g is functional, we have that ∀s

, t ∈ W 1 ∪ W 2 , base(s) = base(t) ∧ |s| = |t| ⇒ s = t. Let s ∈ W 1 ⊗ W 2 .
By construction, we know that s is at least in one of the two sets W 1 and W 2 . We also have that ∀t

∈ W 1 ∪ W 2 , base(t) = base(s) ⇒ t ≤ g s because t = base -[base(s)](W 1 ⊗ W 2 ). Adding the premise of the property, this means that ∀t ∈ W 1 ∪ W 2 , base(t) = base(s) ⇒ t ≤ g s. • If s ∈ W 2 and s / ∈ Clean[W 2 ](W 1 ) ⊗ W 2 ,
s ∈ Clean[W 2 ](W 1 ) ⊗ W 2 . Now let s ∈ Clean[W 2 ](W 1 )⊗W 2 . By construction, s ∈ W 1 ∪W 2 .
The same reasoning on the sequences lengths allows us to deduce that s is the smallest element with its base in W 1 ∪ W 2 , thus that it will be kept when constructing W 1 ∪ W 2 .

This completes the set equality proof.

We now describe our algorithm to minimize an initial representation set. The algorithm is presented in Algorithm 10.1 and depends on a given atomic generalization function.

The main idea of Algorithm 10.1 for generalizing formulas goes as follows: first we ensure that we are not already considering a minimal set of formulas. If it is not the case, we try various possible generalizations we suspect could preserve the property of the original set. If no such generalization actually works, we decompose our set in a generalization partition and try to generalize each independently, assuming elements of other parts are fixed. An additional representation set Sup is kept to store the maximal generalization level allowed for each component.

Algorithm 10.1: MinimalPart(ψ, Gen, W, Sup) We note W R = MinimalPart(ψ, Gen, W, Sup) (which exists by Lemma 188). There exists no W H ≺ Gen W R such that both Clean

1 let W = Clean[Sup](W ); 2 if
foreach W i , i ∈ 1, n do 19 let W i = MinimalPart(ψ, Gen, W i , Sup ⊗ j∈ 1,n ,j =i W j ) ;
[Sup](W H ) = Clean[Sup](W R ) and W H ⊗ Sup |= ψ.
Proof. We proceed by induction on the structure of Algorithm 10.1. The result is immediate for the base cases at Lines 3, 5 and 10. It is also immediate by the induction hypothesis for the tail-recursive calls at Lines 8 and 14.

For the last case, the induction hypothesis ensures that, for any i ∈ 1, n , we have at the end of Line 19 that there exist no

W H i ≺ Gen W i such that W H i ⊗ Sup ⊗ j∈ 1,n ,j =i W j |= ψ. Now let us assume that there exists W H 1→i ≺ Gen j∈ 1,i W j such that W H 1→i ⊗ Sup ⊗ j∈ 1,n ,j =i W j |= ψ.
Then there exists a generalization sequence in s ∈ W H 1→i that could replace base -[base(s)]( j∈ 1,i W j ) in j∈ 1,i W j and still produce an implicant representation set when merged with Sup.

If base -[base(s)]( j∈ 1,i W j ) < g base -[base(s)](Sup ⊗ j∈ 1,n ,j =i W j ) then we have Clean[W H 1→i ](Sup ⊗ j∈ 1,n ,j =i W j ) = Clean[W i ](Sup ⊗ j∈ 1,n ,j =i W j ). Oth- erwise either base -[base(s)]( j∈ 1,i W j ) ∈ W i , in which case we have by induction that Clean[W H 1→i ](Sup ⊗ j∈ 1,n ,j =i W j ) = Clean[W i ](Sup ⊗ j∈ 1,n ,j =i W j ), or that base -[base(s)]( j∈ 1,i W j ) ∈ W k∈ 1,i
, in which case we have the same result from the induction in the previous step.

We finally describe with the following result how the MinimalPart algorithm can be used to find a general implicant of a given formula. We have all the following:

1. W |= ψ 2. For any strict generalization W H ≺ Gen W , W H |= ψ.
Proof. These are immediate from Lemmas 187 and 189, whose application conditions are met by the result of the extractor (see Definition 171). 10.3 Instantiating the algorithm 10. 3

.1 Minimizing propositional logic models

We start by giving an instantiation of the framework of Section 10.1 that makes it equivalent to the algorithm of [START_REF] Bradley | Checking safety by inductive generalization of counterexamples to induction[END_REF].

Definition 191. In this section, we consider the class of propositional logic formulas. We give an inductive definition of a propositional logic formula φ:

φ : | ⊥ | v | ¬ψ 1 | ψ 1 ∨ ψ 2 | ψ 1 ∧ ψ 2
where v is a boolean constant and both ψ 1 and ψ 1 are propositional logic formulas.

Definition 192. Let φ be satisfiable propositional logic formula and M a model of φ. We consider the following implicant extractor: prex(φ)

def = l M = { l }.
Definition 193. We consider the generalization relation → g on propositional logic formula that is such that for any propositional literal l, we have l → g , and such that no other formulas are in relation.

The generalization using this order on the formulas returned by prex (that only contains literals) will thus consist in replacing a given literal from the model by , which is equivalent to removing it in the representation of the formula. If we only consider generalization partitions of size two, then Algorithm 10.1 will basically consist in randomly separating the literals of the model in two parts and trying to minimize these parts independently. This instance produces the algorithm that is described in [START_REF] Bradley | Checking safety by inductive generalization of counterexamples to induction[END_REF] and of which this work is a nontrivial extension. This is moreover, the algorithm we use to minimize propositional logic models in Section 3.4.

Minimizing separation logic implicants

In this section, we describe an instantiation of the minimization algorithm to separation logic. Most real-life programs handle more or less complex data structures that are represented in a memory such as memory tables or linked lists. When one wants to express some information on a program in order to prove properties on them, it is natural to look for a way to work with this memory. This requires practical representations and methods to express properties over such memories. Many solutions have been developed in order to tackle this issue. Separation logic [START_REF] Reynolds | Separation logic: A logic for shared mutable data structures[END_REF] is one of them.

Definition 194. We give an inductive definition of a separation logic formula P ∈ S:

P : φ | E → (v 1 , . . . , v n ) | ⊥ | P 1 ∧ P 2 | P 1 ⇒ P 2 | emp | P 1 * P 2 | P 1 - * P 2
where φ is an equality or disequality between variables, E, v 1 , . . . , v n are variables, n ≥ 1 and P 1 , P 2 are separation logic formulas.

In separation logic, we can naturally express properties over separated memory blocks. Conceptually, the logic describes a mapping of variables to memory locations. On top of that, it also defines two new logical operators. One is the separating conjunction, denoted by P * Q for two properties P and Q, and represents the fact that the properties are verified on two separate parts of the memory. The second is the separating implication, denoted by P - * Q, which represents the fact that the memory obtained by any extension using a block verifying P will always verify Q. Intuitively, this second operator is meant to express how one adds elements in memory. When we want to verify properties in a program, as we did in Chapter 6, and if we want to express properties on the shape of the memory handled by this program, it can be useful to do so in separation logic. It can then be interesting the discard the previously introduced abduction problem and to consider instead the problem of bi-abduction, which will be presented in Section 10. 4.

Definition 200. We say that a separation logic formula P is satisfiable if there exists (D, s, h) such that (D, s, h) is a model of P .

Definition 201. Let (D, s, h) an interpretation for separation logic. For any x ∈ Dom(h), we call equivalence class of x in (D, s, h) the set

E (D,s,h) (x) = {v variable | s(v) = x} .
For any x ∈ Dom(h) such that E (D,s,h) (x) = ∅, we call representation of x in (D, s, h) and denote by E (D,s,h) (x) an arbitrary element of E (D,s,h) (x).

Definition 202. Let P be a (satisfiable) separation logic formula and (D, s, h) |= P . We consider the implicant extractor slex defined as follows:

slex(P ) def = v 1 ,v 2 ∈Dom(s) v 1 =v 2 s(v 1 )=s(v 2 ) { v 1 = v 2 } ∪ v 1 ,v 2 ∈Dom(s) s(v 1 ) =s(v 2 ) { v 1 = v 2 } ∪ x 0 ∈Dom(h),h(x 0 )=x 1 ,...,xn E (D,s,h) (x 0 ) =∅ ∀i∈ 1,n .E (D,s,h) (x i ) =∅ { E (D,s,h) (x 0 ) → E (D,s,h) (x 1 ), . . . , E (D,s,h) (x n ) } ∪ if Dom(h)=∅ { emp }
We justify this definition by the following proposition.

Proposition 203. If P is a satisfiable separation logic formula, the result of slex(P ) is a representation set.

Proof. The single base is ensured by the fact that we return a set of sequences of length 1, and the satisfiability of active elements is trivial by construction.

slex(P ) is consistent: (D, s, h) the model of P used to construct the representation set is also a model of S(slex(P )).

It is not certain, however, that slex(P ) entails P . Indeed, the formalism we use to represent the models by formulas does not include much information that appears in the model such as the exact domain of h. It could be possible to extend slex by inserting components extracting this information from the model but in order to keep the presentation simple, this has not been done. Instead, we will check if slex(P ) entails P before proceeding with its minimization and fail if this is not the case.

Definition 204. We present here the generalization relation → g we define on separation logic formulas:

1. ¬emp → g . 2. emp → g .
Remark 208. Note that the formula P - * Q is actually the most general solution to the bi-abduction problem. However, it is possible that a model of this formula would prove unusable by stating that any extension verifying P would contradict itself. To prevent this cases to occur, we add the restriction ¬(P - * ⊥) to the solution we consider in order to filter such models.

Unfortunately, such a solution is not in a form that makes it easily usable. Indeed, practical tools based on separation logic rarely handle the separating implication, and tend to work with a subclass of separation logic formulas called symbolic heaps [START_REF] Brotherston | Model checking for symbolic-heap separation logic with inductive predicates[END_REF][START_REF] Berdine | Symbolic execution with separation logic[END_REF][START_REF] Distefano | A local shape analysis based on separation logic[END_REF], which intuitively represent the exact mappings of memory cells. It is also interesting to note that the formula P - * Q is not explicit regarding the actual shape the memory should have. Indeed, the formula describes the memory indirectly by stating a property some of its extensions must verify, and not the memory itself. For these reasons, we need to refine this solution to obtain a formula that can be handled by such tools. To do that, we choose to obtain the formula from model of this solution, then refine this formula further in order to construct another solution with a more practical form. The first step of this method, obtaining an initial model of the most general solution, can be done using a solver for separation logic. CVC4 provides one such solver. From this model, we can use the Algorithm presented in Sections 10.1 and 10. 3.2 to obtain a more general solution. This process is summarized in Algorithm 10.2.

Algorithm 10.2: SL-Abduce(P, Q) Proof. This is a direct consequence of Propositions 207 and 190.

1 if P |= Q then
We will present in Chapter 11 an evaluation of the algorithm to see when this effect occurs and whether or not it remains possible to solve even simple abduction problems with this method. (a) (b) In this context, we can apply our minimization algorithm for, e.g., a partition of size two. Let us take the example of Figure 11.1 as a source sequence and execute the algorithm (see also Figure 11.2).

1 2 3 4 1 2 3 4 (c) (d) 1 2 3 4 1 2 3 4 (e) (f)
Assuming the partitions we consider always split the set of stacks we consider in two, as all the stacks of the source contain at least one token, the algorithm will proceed and generalize our representation by adding these tokens (a). The second time, the generalization will not be accepted because our third stack would then contain more tokens that the one in the source (b). The algorithm will thus split the stacks, fix our third and fourth stacks and minimize the other two in this context. It will then manage to generalize both stacks once more by adding one token, then it will fail again as the second stack in the source contains only two tokens (c). By splitting the set of stacks it works on again, it will obtain sets of one stack and thus generalize them as much as possible. First by adding a new token to the first stack (d), then by noticing than no more tokens can be added, neither in the first nor in the second one. By backtracing until its first split, the algorithm will now have to obtain the stacks it is looking for in the right of the sequence. As the two first sequences have already been obtained, it will fix them and work on the other part (e). Because it is not possible to generalize the whole set, the algorithm will also split the stacks at this moment. It will then try to minimize Proposition 219. If f is a satisfiable token-stack formula, the result of syex(f) is a representation set.

Proof. The unicity of the base is ensured by the definition of the interpretation and the satisfiability of the active elements is trivial.

Definition 220. We now define the generalization relation → g we use token-stack formulas:

y k 1 → g y k 2 if and only if k 1 < k 2 .
Definition 221. We define the domain of the associated atomic generalization function Gen: (W, s) ∈ Dom(Gen) if and only if active(s) is a token-stack formula of the form y k and such that k < n where n is the depth limit.

Proposition 222. Let f be a token-stack formula. S(MinimalPart(f, Gen, syex(f, 0 | y ∈ Y ), ∅)) = f.
This instantiation offers two major advantages for an experimental evaluation: first, it is easy to verify if a formula is a logical consequence of another (this can be checked with a number of integer comparisons linear in the size of the formula), second, it is easy to verify if the implementation works correctly by returning a minimal implicant of the initial formula, thanks to Proposition 222.

Implementation of the minimization algorithm

We now present an implementation of our implicant minimization algorithm. The Min-imalPart algorithm has been implemented within the Abdulot framework [START_REF] Sellami | Abdulot framework and tools[END_REF], in an additional library called minpart. The implementation is generic in the two following senses. First, it can be plugged with any heuristic algorithm to generate the partitions on which the MinimalPart algorithm performs the recursive minimization. Two simple such heuristics implementations are also included in the library. Second, as presented in the theoretical approach, it is independent of the problem context, that is, the class of formulas we minimize and the associated generalization function and representation set extractors.

Implementing representation sets

We start by presenting the implementation of representation sets. We decided to implement the representation sets as vectors of integers, representing the number of times the generalization rules has been applied to the subformulas they contain. Given an initial satisfiable formula and a model for it provided at the beginning of the execution, we can deduce the number of elements its representation set will contain. Hence, this initial formula will be represented by a vector containing as many zeros as it has sequences of formulas. During an execution, all the representation sets for this problem will be vectors of the same size, allowing the integer at a given index in the vector to always represent the same generalization sequence, independently of the concrete representation set that is considered. In practice, all the representation sets generated for this execution will represent the same generalization sequence in different states. Every time a generalization sequence is generalized, the value of the corresponding index within the corresponding vector will be increased by one. The actual formula this represents will then be computed from the initial formula and the number of times the generalization relation has to be applied by a Context component handling the concrete formulas considered and implementing the generalization rules (see Section 11.2.2).

In order to maintain some consistency between all the representation sets that will be used and required by the MinimalPart algorithm, we have implemented a representation set engine component. This component is designed to allocate the integer vectors when required, to perform the operations that can be computed directly on this structure (such as merging two representation sets) and forward any context-related operation to the Context component it will include. The current implementation allocates a new vector every time a new representation is needed. Note that, as various sequence indices may represent distinct generalization structures, the maximal depth of the vector representation of representation sets may differ from index to index. The fact that all the representation set-related operations are performed within the engine allows to prevent the framework to transfer integer vectors between its components. This is done by generating an identifier for each vector representation. This identifier will be the only representation transferred outside of this engine component and manipulated by the main algorithm.

Within the implementation, this engine is thus implemented as a C++ template GSetEngine<Context> which can be instantiated for any given Context component. It exposes methods to perform all the generalization-set related operations and only externalize the vectors it contains by their indices.

Context Interfaces

The minpart framework uses a Context component that will be tasked to perform all the operations that depend on the instantiation of the MinimalPart algorithm. These operations are the application of the generalization relation, the verification that a representation set is an implicant of the initial formula and that it is consistent, and an information access to the initial model that was initially minimized (returning data such as the size of the corresponding representation set). This context component has to be provided by the user of the minpart framework to apply the minimization algorithm in the instantiation they wish to solve. It will then be given information on the implicant to minimize (such as the formula it should be an implicant of) at the beginning of the execution of the MinimalPart algorithm. The interface that such a component must have is presented in Interface 11. 1.

The Abdulot framework contains two instantiations of this component that are presented below.

Token-stack formulas

The implementation for the token-stack formulas is done internally by comparing the indices of generalizations of the symbols contained within a given formula. At the beginning of an execution, it is presented the generalization depth and the number of symbols that are considered and implements the verification rules as they are presented in Section Similarly, the generalization of a subformula will be performed by increasing its index until it reaches the maximal depth allowed.

Propositional logic

The implementation for propositional logic has been intertwined with the C++ library of MiniSAT [START_REF] Eén | An extensible sat-solver[END_REF]. The components takes a propositional formula expressed in the Dimacs format [START_REF]Dimacs challenge -satisfiability: Suggested format[END_REF]. It starts by calling MiniSAT on this formula to obtain the first model and stores the resulting MiniSAT C++ instance in memory. Then, the component has to check whether a given subset of literals of the model it returns remains a model of the initial formula. Thanks to an instrumentation of the source code of MiniSAT, this can be performed without negating the input formula and querying a new satisfiability test. Indeed, the MiniSAT C++ instance stores enough information to deduce which clauses (if any) may stop being validated when a given literal is removed from the model. We therefore use this information to test if our representation sets are still models of the initial formula.

Separation logic

The implementation of the separation logic Context component has been implemented using the satisfiability procedure of CVC4 [START_REF] Reynolds | A Decision Procedure for Separation Logic in SMT[END_REF]. Similarly to what we did in Chapter 8, we intertwined the component with the C++ library of the SMT-solver. The component thus builds the logical formulas corresponding to the entailment checks and forward them to CVC4 to obtain the result. In order to build the formula corresponding to the representation set it is given, the component will have to know which generalization rule to apply for a given subformula. This is done using the initial formula that it is provided at the beginning of the execution. Indeed, this initial implicant and its corresponding representation set contain enough information for the Context to know which rule should be applied to each formula and which new formula should be obtained from them. Given the number of generalizations for a given index within the representation set, the component will take the formula corresponding to the given index within the initial implicant and apply the correct generalization rule accordingly, as many times as the number of generalizations instructs. This permits to obtain the corresponding active formula for the current representation set, and thus the formula to check the modelling and consistency properties for.

Generating partitions

Another major component of the minpart framework targets the generation of partitions and generalization blocks. As the actual method to generate such partitions was left open in Chapter 10, we decided to implement a generic component that can be instantiated with various generation methods. The external behaviour of the component is fairly simple: given the identifier of a representation set, it will generate and return a partition of this set, querying the representation set engine to know which subformulas can be generalized and which ones cannot. Similarly, the partition generator will be tasked to produced the generalization blocks we try before looping on the representation sets of the partition, which may or may not be equivalent.

Within the minpart framework, we implemented an instantiation of the partition generator. Our generator simply splits the vectors in a given n parts of the same size and generates a partition of size n corresponding to the generalization of all the formulas of each part. This decomposition in n parts can be done in the order of the vector indices, randomized at the beginning of the execution or randomized every time a new partition is requested. For each generalized component within the set of a partition, the atomic generalization function is applied a given k number of times.

Structure of the implementation

We finally describe the complete implementation model of the minpart framework, which is represented in Figure 11. 3. It is available as a library and can be tried from two example executables for token-stack formulas and separation logic formulas.

Given an input consisting in an initial logical formula accompanied by its representation set representation, the framework forwards the formula to the context component to allow it to handle the modelling verification tests for it and instantiate an integer vector for its representation. The index of this vector is then sent to the minimization algorithm and will be used as the initial set within the minimization algorithm. The minimization component then executes the MinimalPart algorithm, requesting the partition generator for partitions and the representation set engine for cleaning, merging, and verifying representation sets. Depending on the results of the modelling tests, the minimization component will update its representation sets and support as detailed in the Minimal-Part algorithm. Once a minimal set has been obtained, it will return it. The user (or the executable) should then apply the Context component one last time to get the corresponding logical formula.

Distribution

The whole minpart library, as well as two executables: one for set-symbols literals and one for separation logic, are publicly available within the Abdulot framework [START_REF] Sellami | Abdulot framework and tools[END_REF]. In order to use the separation logic context furnished, one should first install the C++ library of the CVC4 SMT-solver. when the size of the problem increases. Note that the fact that the MinimalPart algorithm invokes more satisfiability tests than the naive algorithm on uniformly randomized problems when the number of possible generalizations is low is expected. Indeed, when only few components can be generalized, the satisfiability queries trying to generalize many components at once will mostly fail, forcing the algorithm to fallback to base cases which corresponds to the satisfiability tests made by the naive algorithm. As it has already queried the satisfiability tests for these global generalization strategies, this will result in more tests in general. Figure 11.6 shows the distributions for a set of symbols of size 100 as a function of the maximal depth but for different generalization depth probabilities. It shows that our algorithm is also interesting when the components of a representation set have a good chance to be generalizable. Indeed, the higher this probability is, the more likely it is for the naive algorithm to perform much more redundant tests.

Partitions

We now study various heuristics for the generalization partitions we can use to minimize token-stack formulas.

In Figure 11.7 (resp. Figure 11.8), we present the distribution of the number of satisfiability tests required to minimize 100 token-stack formulas as a function of the size of the partition, for a set of symbols of size 100, a depth limit of 5 (resp. 10) and a generalization depth of 1 in the partitions.

We observe that in both cases, the number of satisfiability tests that is required to minimize random problems increases with the number of partitions. Once again, this can be explained by the fact that increasing the number of partitions increases the number of satisfiability tests that have to be made in the recursive calls of the MinimalPart algorithm. This also degrades the general performance of the algorithm as this can lead to redundant satisfiability queries when generalizing the many parts a partitions under the support of the others.

Figure 11.9 presents the influence of the generalization depth applied on the representation sets of the partition. Again, we draw the distribution of the number of satisfiability tests required to minimize 100 random token-stack formulas built on 100 symbols with a depth limit of 10. The size of the partition is reset to 2 and the result is expressed as a function of the number of times the atomic generalization function is applied to each element the generalized representation set.

This shows that it can be interesting to generalize the components of the sets of a partition more than once to help the algorithm converge faster to a given solution. It also shows that, as expected, if the depth of this systematic generalization is too high, then the general performance will decrease as most of the satisfiability tests for these parts will fail (because we are past the maximal generalization possible for at least one component), and the algorithm will end up querying many unuseful tests before falling back into its base case and generalizing all the components independently.

Finally, Figure 11.10 shows the effect of choosing random sets of generalization sequences each time a new partition is needed. It shows the distribution of the number of satisfiability tests required to minimize 100 random token-stack formulas of size 50, with a depth limit of 10 and partitions of size 2 generalizing each of their components once. The distribution id drawn for both the case of random partitions and partition structure set at the beginning of the execution. Note that the number of satisfiability tests is presented in a logarithmic scale for this figure.

This clearly shows that randomizing the structure of the partitions each time is inefficient.

Testing the minimization of separation-logic formulas

We now apply our minimization algorithm in the context of separation logic. We start by trying the minimization algorithm on randomly generated simple separation logic formulas. Such formulas are generated using Algorithm 11.3 where V denotes a set of variables and p a depth probability, and by only keeping the generated formulas that are satisfiable and for which Iextract returns an implicant. We use CVC4 to obtain an initial model for them and minimize the corresponding representation set. We now present the distribution of the number of satisfiability tests that are required to solve 78400 such randomly generated separation logic formulas with a number of variables ranging from 2 to 50 a depth probability ranging from 0.5 to 0.65. Note that following the results of the previous section, we decided to generate the structure of the partitions at the beginning of the execution only and that we used partitions of size 2 generalizing their components once. The mean minimization time required on these problems is at 2 seconds. The number of satisfiability tests is detailed as a function of the number of variables in Figure 11.11 and as a function of the depth probability in Figure 11.12 where the three hardest problems have been discarded (which required more than 1000 satisfiability tests). All the distribution subsets of these graphs are evenly sized.

The influence of the number of variables in the problem is expected as it results in larger generalization sets generated by Iextract. It is interesting to remark that, considering the number of possible generalizations this instantiation offers (either one or two), the number of satisfiability tests required is significantly below the results we obtained for uniformly random problems. This is a consequence of the fact that most of the components can be generalized in the implicant we obtained, which in turn reduces the number of satisfiability required tests to ensure that representation sets with few generalized components still represent an implicant. This in turns permits to obtain the final result from less base-case generalizations, resulting in less satisfiability tests. It is important, however, to understand that part of this effect results from the simplification of the redundant equalities and disequalities between variables that are present in the initial implicant.

It is also interesting to notice that the depth probability of the random generalization seemingly has no influence on the number of satisfiability tests that are performed. This is due to the fact that it neither impacts the size of the representation set nor the maximal generalization depth. It has, however, an influence on the complexity of the formulas and thus on the time necessary to compute the satisfiability tests.

Wrapping the minpart for performing abduction

Finally, we evaluated an implementation of Algorithm 10.2 for computing abduction results in separation logic. We implemented this algorithm as an executable wrapper of the separation logic formula minimizer used in the previous section. In order to do perform its evaluation, we generated some random separation logic abduction problems using Algorithm 11.3 and we constructed formulas of the form RandomSLF ormula(V, p) - * RandomSLF ormula(V, p). We checked that the obtained formula were indeed satisfiable and that the formula returned by Iextract was an actual implicant before trying to minimize them. We generated 23900 such formulas, again with a depth probability ranging from 0.5 to 0.65 and a number of variables between 2 and 25. For 9600 of these problems, the algorithm was able to produce a minimal implicant in less than two minutes. The distribution of the corresponding examples is presented on Figure 11. [START_REF] Berdine | Symbolic execution with separation logic[END_REF]. Most of these problems correspond to formulas with only a small number of constraints, which results in easier satisfiability tests for the SMT-solver. Only few harder problems (those requiring more satisfiability tests) were solved by the system, contrarily to what we could observe on formulas not containing any separating implication. This shows that the impact of the computation cost of the satisfiability tests in this context prevents the algorithm to generate solution on problems that have more than a very limited number of constraints. This effect reduces the interest of the implicant minimization strategy to solve the bi-abduction problem by minimizing an initial implicant of the most general solution of the problem, as the practical computation cost of the required satisfiability tests appears to be too heavy.

Conclusion

Experiments show the practical use of the MinimalPart on large representation sets, when the generalization function can produce many successive generalizations and on problems where the number of generalized components in the result is important. The experiments have additionally shown that out of these classes of problems, the satisfiability tests required by the decomposition become an overcost compared to the naive algorithm. The evaluation of its instantiation in separation logic has shown that it is able to generate minimal implicants of separation logic formulas from the models that are returned by CVC4 in a reasonable time, as long as these formulas do not include any quantification or separating implication. This last result compromises the direct application of the method for solving abduction problems as proposed by the SL-Abduce

Conclusion

In the present work, we devised a theory-independent algorithm for abductive reasoning via implicate generation, over a set of user-defined abducible literals. This algorithm works by successively trying possible conjunctions of abducible literals until it can derive a contradiction with its input formula. It additionally uses an order on the literals and models of the formulas it works with to reduce as much as possible the number of conjunctions it has to try. These latter methods are mandatory to obtain an efficient algorithm. After presenting general definitions in Chapter 1, we proposed in Chapter 2 an overview of related prime implicate generation methods and of loop invariant generation.

We then formally defined the proposed abduction method in Chapter 3 and showed that it is sound and complete. This means that it generates and returns the set of prime implicates of any given formula (up to redundancy). We then proposed in Chapter 4 an efficient structure for representing, storing and reusing the implicates computed by our algorithm.

In Part II, we applied this algorithm to program verification. We started by defining in Chapter 5 a generic framework for applying abductive reasoning in the context of program verification, inspired by the work of Dillig et al. [START_REF] Dillig | Inductive invariant generation via abductive inference[END_REF]. Starting from an abstract representation of the structure of a program containing formulas to prove (assertions) and formulas that can be modified to obtain these proofs (such as candidate loop invariants), the algorithm uses external verification conditions generators to produce logical problems ensuring the validity of the assertions. Then it uses abduction, typically the prime implicated generator we devised in Part I, to infer interesting updates of the modifiable formulas of the program that should lead to a complete proof. This framework was instantiated in Chapter 6 to be applied to the generation of property-directed loop invariants of programs.

In Chapter 7, we investigated the issues related to the implementation of the methods introduced in the previous parts. We presented a generic structure that permits to obtain in practice both the abstraction of the theory in the prime implicate generator of Part I and the abstraction of the programs and verification conditions of the loop invariant generator of Part II. For the first abstraction, we designed generic SMT-solvers interface wrappers to plug the main system to any available satisfiability decision procedure. For the second one, we designed a program representation wrapper allowing the system to be plugged to any concrete program representation and associated verification tools. The issues related to the implementation of such interfaces were discussed in Chapter 8: we presented the design of SMT-solver interfaces based on both library API and SMTlib command-line interfaces for the widely used SMT-solvers CVC4, Z3, Alt-Ergo, VeriT, as well as a detailed program representation interface based on Why3 for an easy use in our program verification framework. We concluded Part III by performing an experimental evaluation of both systems, on which additional discussion will be presented below.

Finally, Part IV was focused on our work on an algorithm for minimizing sets of variables with many possible values, which was inspired by a dichotomic propositional formula model minimizer [START_REF] Bradley | Checking safety by inductive generalization of counterexamples to induction[END_REF]. This algorithm was formally defined in Chapter 10. We also provided an algorithm using this method to perform some sort abductive reasoning on separation logic formulas (relying on its separating conjunction instead of the usual boolean conjunction). These two algorithms were implemented and briefly evaluated in Chapter 11 where we found that the model minimizer was of practical interest but that its use in abduction for separation logic was relying on operators for which currently available separation logic satisfiability checkers are unfortunately unable to perform efficiently.

In summary, the main achievement of this work is the design of a prime implicate generation algorithm which is generic both in theory (through an abstraction of theoryrelated operations by satisfiability tests) and in practice (through the use of SMT-solvers interfaces) and its application to generate loop invariants of programs, even in non usually targeted theories. Experiments showed that this approach was able to compete with state-of-the-art propositional logic prime implicate generators for classes of highly constrained formulas and managed to generate more implicates than state-of-the-art approaches modulo theories under a given time. By combining this work with the Why3 platform to generate loop invariants, we additionally obtained a system able to check properties of WhyML programs and to automatically infer loop invariants for them. Practical results showed that, in its current state, the system is able to generate loop invariants of programs both on usual numerical domain and on more complex theories. It was typically able to generate loop invariants proving the result of exponentiation algorithms, list algorithms and floating point data handling algorithms. As practical work on abducible literals, solution guiding and information reuse are mostly inexistent in the current prototype, we consider these results very encouraging.

Future work

These results allowed us to extract three main point that have to be investigated to develop more efficient abduction procedures and facilitate their usage for solving practical problems. First, it is clear that the costly operations in our prime implicate generator are the satisfiability tests. Improving the efficiency of the satisfiability tests themselves stays clearly out of the scope of the project, though it is clear that by entirely delegating them to external SMT-solvers, we can always benefit from the improvements these tools receive. Reducing this cost within the ImpGen-PiD algorithm could be done by reducing the number of satisfiability tests we require. Methods should be investigated to cut more exploration branches from which we could be hinted that no relevant implicate will be derived. Obtaining more intelligence from the models we recover from satisfiability tests, such as the literals that appear on many models for instance, or deriving consequences beforehand from the information we already have, are possible solutions for this problem. This could be used to define a more relevant order, maybe built dynamically, that could help the algorithm build a search tree finding minimal implicates sooner. Depending on the application we target the implicate generation for, it could also be interesting to investigate changes to the algorithm that would permit to cut more exploration branches at the expense of completeness, if such cuts can lead to the generation an implicate relevant to the problem faster. As a very simple illustration, counting the number of occurrences of a symbol in the source problem, or more generally, building some sort of correlation table exhibiting which symbols are tightly intertwined to the problem and which are less, could help us build heuristics in favour of their corresponding literals.

Second, as we previously mentioned, the use we made of abducible literals for the application to loop invariant generation was mostly blind and contained many systematic literals that would immediately appear as irrelevant to any human user. It is thus clear that work should be done to devise more interesting and knowledgable methods to generate and use abducible literals. This includes pruning literals, for instance from contextual information extracted from the program, or obtained for larger knowledge bases on program invariants. It could also be interesting, in a more distant perspective, to develop methods generating higher-level literals that could permit to generate solutions for problems requiring higher level properties than the one directly present within the program. Merging such a literal generator with a method to extract interesting predicates that can represent relevant properties of a program could thus also permit to generate invariants for more complex programs. Other than that, it will also be important to look for techniques, heuristics or learning procedures, to order the abducible literals more efficiently such that those we expect to lead to the generation of a relevant solution are tried first. Within the loop invariant generation algorithm, this ordering should also be different for each call to GPiD, as we try to strengthen possibly very different abduction problems with them.

Third, it is clear that within its application to loop invariant generation, many redundant computations are performed (on similar abduction problems, between the verification condition checks performed within the program prover and those within the prime implicate generator, etc.) and could thus be reduced. Possible ways to reduce redundant computations include methods to reuse information obtained from the verification conditions checks performed by the program prover to guide the exploration within the ImpGen-PiD algorithm. It should also be possible to extract from the program some additional properties that could be forwarded to the prime implicate generation and used there to cut exploration branches or, as previously suggested, reorder abducible literals. This could then be used to hint GPiD not to generate implicates that appear relevant in the current problem but that we can detect cannot produce a solution in the broader context. The need for such information retrieval from the programs additionally suggests that a better integration between the static analyser and the abductive reasoning tool would be beneficial.

Additionally, it would be interesting to refine the loop invariant generation algorithm in order to intertwine it better with its abductive component. This could typically ease the implementation of our second and third points, as the two algorithms follow a similar structure and could probably share parts of their execution (e.g. for a program with only one loop invariant, GPiD could be adapted to the loop invariant construction directly, confounding its satisfiability tests with the ones made by the program checker). This could also help switch between SMT-solvers within the GPiD algorithm, and taking advantage of this functionality present in Why3 to be able to derive implicates more automatically, without the need to previously select the most adapted tool for the problem at hand. It could also be interesting to tweak our method to integrate it in a semi-automatic infrastructure where it could communicate with a user, sending them information on the failure of the tasks to help them tweak the inputs to solve the problem. Finally, it is clear that the higher the expressivity of the properties we want to derive, the more we need methods to deduce contextual information to reduce the search space. In the long run, such methods will be necessary to increase further the scope of the program we can verify.

Index

. . 7 . 4

 74 Defining, generating and handling abducible literals . . . . . . . . . . . . 7.5 Parametrization of the GPiD tool

. . 9 . 3 9 . 4 . 1

 93941 Evaluating the ImpGen-PiD algorithm in the general context . . . . . . 9.4 Evaluating the loop invariant generator Ilinva . . . . . . . . . . . . . . . Results of the generation . . . . . . . . . . . . . . . . . . . . . . . 9.5 Discussing the results of the evaluation of Ilinva . . . . . . . . . . . . . IV A model minimization algorithm for performing abduction in separation logic 10 Multi-level implicant minimization by formula component-based generalization 121 10.1 A framework for representing implicants . . . . . . . . . . . . . . . . . . 10.2 A framework for generalizing implicants . . . . . . . . . . . . . . . . . . 10.3 Instantiating the algorithm

. . A

 . Grammar of the abducible file format used by the Abdulot framework159 B Why3 verification condition used as an abduction problem in Example 152

Example 11 .

 11 In order to illustrate the notions introduced in this chapter, we will consider a signature Σ 0 containing the function symbols a, b, c of arity 0 and return type N, the usual unary minus and sum functions -, + over integers, and the usual equality predicate . In this context, expressions such as a b, ¬(b c), a + b -c are elements of L 0 . Likewise, expressions such as a b ∧ ¬(b c), ¬(a b) ∨ c c, ¬(a c) ∧ a b are elements of S 0 .

Example 18 .

 18 Assume we interpret the functions and predicates of Example 11 with their usual definition on integers. If we take an interpretation I that maps, a and c to 0 and b to 1, then we will have a c I = , a + b c I = ⊥, a c ∧ ¬(a b) I = .

Proposition 27 .

 27 Given a theory T , a formula φ is T -unsatisfiable if and only if φ |= T ⊥.

  Within the context of Example 11, we will write indistinctively {a b, ¬(c b)} and a b ∧ ¬(c b).

Notation 32 .Proposition 34 .

 3234 As a consequence of Notation 29, for a given clause C = l 1 ∨ . . . ∨ l n we will denote by C the set {l 1 , . . . , l n }. Notation 33. Given a set of clauses Φ, we will denote by Lits(Φ) the set of literals contained in at least one clause of Φ. Let l be a literal and let C, D be clauses. The following statements hold: 1. l ∨ C |= T D iff l |= T D and C |= T D.

2 . C

 . |= T l ∨ D iff C ∧ l |= T D. Proof. Let l be a literal and let C, D be clauses. 1. Let us assume that l ∨ C |= T D. The definition of the disjunction gives us both that l |= T l ∨ C and C |= T l ∨ C. This means that all models l are models l ∨ C, thus models of D. Thus we have that l |= T D. Similarly we have that C |= T D.

Definition 37 .

 37 An implicate C of a formula ψ is a prime implicate of ψ if for every implicate D of ψ, D |= C only if C |= D. Similarly, C is a prime T -implicate of ψ if for every T -implicate D of ψ, D |= T C only if C |= T D.

Example 42 .

 42 Let us consider the clauses C 0 : a b, C 1 : a b ∨ c d, C 2 : c d. As we have C 0 ⊂ C 1 and C 2 ⊂ C 1 , we will necessarily have C 0 ≺ C 1 and C 2 ≺ C 1 . The clauses C 0 and C 2 can then be ordered arbitrarily, e.g., C 0 ≺ C 2 . Definition 43. Given a set of clauses Φ, we denote by SubMin(Φ), and call entailment minimal equivalent of Φ, the set obtained by deleting from Φ all clauses D such that one of the following hold: 1. D is a tautology.

2 .

 2 There exists C ∈ Φ such that C entails D and either C is not an implicate of D or C ≺ D.

2 .

 2 There exists C ∈ Φ such that C entails D in T and either C is not a T -implicate of D or C ≺ D. Example 44. If we consider the set of clauses Ψ = {a b, a b ∨ c d, c d, a a, d c}, with interpreted with the usual definition of the equality, we first notice that the clause a a is a T -tautology. As we saw in the previous example, a b ∨ c d is a logical consequence of both a b and c d. We also have both c d |= T d c and d c |= T c d. Let us assume that we have c d ≺ d c. In this case, we will have SubMin T (Ψ) = {a b, c d} as we removed the T -tautology, the weaker logical consequence a b ∨ c d and kept only the smallest of the two equivalent clauses c d and d c.

Proposition 45 .

 45 Given a set of clauses Φ containing at least one formula that is not a T -tautology, SubMin(Φ) ∼ T Φ.

Proposition 49 .

 49 For any given theory T , set of formulas Φ and set of abducible literals A, we have I * T ,A (Φ) ∼ T SubMin T (I T ,A (Φ)). Proof. This is a direct consequence of Proposition 45 and of the fact that I * T ,A (Φ) ∼ T I T ,A (Φ).

Figure 2 . 1 :

 21 Figure 2.1: Trie representation of the formula φ from Example 52; literal order q > ¬q > p > ¬p > r > ¬r > s > ¬s

Figure 2 . 2 :

 22 Figure 2.2: ZBDD representation of the prime implicates of the formula φ from Example 52; literal order q > ¬q > p > ¬p > r > ¬r > s > ¬s

6 let _y ← y; 7 x 8 y

 678 ← _x + _y; ← _x + _y; 9 assert y ≥ 1;

Proposition 65 .

 65 Consider a set of formulas Φ and two sets of literals M, A such that I * M ,A (Φ) = {M }. The following equalities hold: 1. I * M ,A (Φ) = SubMin T ( l∈A I * M ∪{l},A (Φ)).

  By the induction hypothesis, for each l ∈ A, P l = I * M ∪{l},B (Φ), and by Proposition 65, P l = I * M ∪{l},A (Φ); we deduce that I * M ,A (Φ) = SubMin T ( l∈A P l ). Note that at each recursive call, a new element is added to M , since fix(A, M, Φ) is assumed not to contain any element from M .

Definition 74 .

 74 Let Φ be a set of formulas and M ⊆ A. We denote by U T ,Φ,M the set of unit clauses logically entailed by Φ ∪ M modulo T , i.e., U T ,Φ,M def = {l ∈ L | Φ ∪ M |= T l} If Φ is a set of clauses, given a set U such that M ⊆ U ⊆ U T ,Φ,M , we denote by U T ,M [U ](Φ) a formula obtained from Φ by replacing some (arbitrarily chosen) literals l by ⊥ if U |= T l and by if M |= T l .

Lemma 81 .

 81 If P is ⊆-closed then ImpGen-PiD(Φ, M, A, P) = I * M ,A (Φ) ∩ A A ∈ P . Proof. If one of M or Φ ∪ M is T -unsatisfiable, or P(M ) does not hold, then the result follows from Proposition 61 and Definition 79. Otherwise the result is proved by induction on Card(A \ M ), using Proposition 65 and Lemmata 78 and 76. Theorem 82. If P is ⊆-closed then I * T ,A (Φ) ∩ A A ∈ P = ImpGen-PiD(Φ, ∅, A, P).

Definition 90 .

 90 Given a set of clauses Φ, two sets of literals M, A and a set of clauses Π, UpdateImplicatesLocal(Φ, M, A, Π) is the strong entailment minimal equivalent of the union of Π with a set of A-implicates of Φ ∧ M denoted by Π and ensuring that Π ∪ Π ||= M .

  Then D ||= M and Φ |= D. Proof. By Proposition 92 we have Φ ∪ D |= {l, l} |= ⊥.

Figure 4 . 1 :

 41 Figure 4.1: A representation of an A-trie

101 .

 101 Given a clause C and an A-trie, S(insert(τ, C)) ||= S(τ ) ∪ {C}. Proof. This is ensured inductively. For any clause C, {C} ||= {C}. Moreover, for C = l 0 ∨ D with D a clause, if S(insert(∅, D)) ||= S(∅) ∪ {D} then S(τ ∪ {(l 0 , insert(∅, D))}) ||= S(τ ) ∪ {C} and if S(insert(τ , D)) ||= S(τ ) ∪ {D} then S((τ \ {(l , τ )}) ∪ {(l , insert(τ , D))}) ||= S(τ ) ∪ {C}.

Lemma 104 .

 104 Let C be a clause and let τ be an A-trie. We have S(τ ) ||= C if and only if one of the following conditions hold: • τ = ⊥. • τ = {l 1 : τ 1 , . . . , l n : τ n } and there exists i ∈ 1, n such that l i |= T C and S(τ i ) ||= C. Proof. If τ = ⊥ then S(τ ) = {⊥} ||= C hence the equivalence holds. Otherwise, let τ = {l 1 : τ 1 , . . . , l n : τ n }. By definition, S(τ ) ||= C holds if and only if there exists a clause D ∈ S(τ ) such that D |= T C. Since S({l 1 : τ 1 , . . . , l n :

Example 105 .

 105 Let us consider again the A-trie we presented in Example 99. Now let us assume that we want to check if S(T ) ||= T D = f (d) f (e) ∨ f (d) f (a) with the algorithm of Lemma 104. The execution is detailed in Figure 4.2 and described below. It starts by verifying if a clause entailing D can be found in the left part of T . To do this, it checks whether f (a) f (b) |= T D (second point of Lemma 104). As this is not the case, it proceeds to the second possible literal it can find from the root of T : d e. This time, we have d e |= T D. The algorithm will then look at the subtrie below this literal and continue to check if they subsumes the clause. As we have both that f (d) f (a) |= T D and that ⊥ is a subtrie below this literal, we can conclude that D is entailed by S(T ), and that the clause showing this is d e ∨ f (d) f (a).

T

Figure 4 . 2 :

 42 Figure 4.2: Example of forward subsumption

Lemma 107 .

 107 Let φ be a formula and let τ be an A-trie. Then clear(τ, φ) is an A-trie, and S(clear(τ, φ)) = {C ∈ S(τ ) | φ |= T C}.

•

  If φ is T -satisfiable and τ = ⊥, then S(τ ) = {⊥} and φ ||= ⊥, thus {C ∈ S(τ ) | φ |= T C} = {⊥}.

Example 108 .

 108 Let us consider one last time the A-trie of Example 99. This time, let us consider that we are about to add the unit clause C = a b to T . Before that, we will have to remove all the clauses contained in T that are logical consequences of C. We describe this execution of the algorithm from Definition 106. It is also represented in Figure4.3. It starts at the root of T , by adding the complement of the first literal of the node (f (a) f (b)) to C. As we can immediately derive a contradiction from this, the algorithm will remove this whole subtrie. It then pursues its exploration of T with the other literal it finds at the root: d e.

Figure 4 . 3 :

 43 Figure 4.3: Example of backward subsumption

Φ) ; 8

 8 let I be an (Φ ∪ M )-compatible set of literals ; 9 foreach l ∈ A such that l ∈ I do 10 let τ = ImpGen-Storage(Φ, M ∪ {l}, A I [l], τ, P) ; 11 return τ ; Theorem 110. If P is ⊆-closed then I * T ,A (Φ) ∩ A A ∈ P = ImpGen-Storage(Φ, ∅, A, ⊥, P).

Example 111 .

 111 Let us consider the sample program presented in Algorithm 5.1. It turns out that the postcondition of this program is not verified. Take for instance an array T = [-1, 0, 0], a = 1 and b = 1. After executing Algorithm 5.1, we would have T = [-1, 0, -1] and thus T [b + 1] < T [b], which contradicts the postcondition. Such instances of T, a and b could be obtained from an SMT-solver. If we want to obtain an additional precondition ensuring the postcondition holds however, we are not interested in trivial solutions such as ⊥ or too restrictive solutions such as a = 0∧b = 1. The kind of "interesting conditions" we look for are, for example a = b or T [b -1] ≥ 0.

Example 115 .

 115 Let us consider the sample program of Example 111 (Algorithm 5.1). We can express the problem of whether the program verifies its postcondition within the framework of Definition 112. Consider first the sequence Φ 5.1 = ((∀x, y ∈ a, b .x ≤ y ⇒ T [x] ≤ T [y]) ∧ T [a] > 0). Now consider the verification condition generator υ 5.1 : φ → ¬φ ∨ (∀x, y ∈ a, b + 1 .x ≤ y ⇒ T [x] ≤ T [y]). If we consider the verification structure P 5.1 = (Φ 5.1 , (υ 5.1

Example 131 .

 131 Let us consider the sample program presented in Algorithm 6.1, expressed within the framework of Definition 128.

Algorithm 6 . 1 : 5 [ ] 6 p 7 w

 61567 SampleExp(n, m)1 assume [m ≥ 0] ; 2 let p ←-1 ; 3 let w ←-0 ; 4 while w < m do ←-p × n ; ←-w + 1 ; 8 assert [p = n m ] ; 9 return p ;algorithm that updates the candidate loop invariant to allow those tools to produce a proof of the program's assertions.Definition 132. Given a program P , we define rmLoops(P ) by the program P in which we have removed all the loop instructions.

  i. : .(i+1)] = P [ .i. : .i.m] m = max({j | .i.j ∈ locs(P )})

Example 145 . 4 invariant [ψ] ; 5 x ← x + y; 6 y

 145456 Let us consider the Sample Program 6.2. Using the definitions we pre-Sample Program 6.2: LoopCheck2(y 0 ) 1 let x ← -50; 2 let y ← y 0 ; 3 while x < 0 do ← y + 1; 7 assert y ≥ 0;

assert - 1 | 2 :

 12 I → I Lemma 146. Consider a verification structure P representing a program in the sense of Definitions 128, 143 and 144. If P is satisfied then we have both that 1. the assertions of the program are verified and 2. all the loop invariants it contains are true when first checked and propagate.

Example 148 . 6 x ← x + 1 ; 7 y ← y + 1 ;8 while x = n do 9 invariant [?]; 10 x ← x - 1 ; 11 y

 1486171910111 Let us consider the Sample Program 6.3. As this program contains two Sample Program 6.3: M ultiLoopCheck() 1 let x ← 0; 2 let y ← 0; 3 let n ← 0; 4 while random({ , ⊥)} do 5 invariant [?]; ← y -1;

Interface 7 . 1 :

 71 SMT-solver Interface Template 1 interface Constraint contains 2 str : void -→ string ; 3 interface Model contains 4 implies : Constraint -→ { , ⊥} ; 5 interface Solver contains 6 getModel : void -→ M odel (only if the last check call returned Sat); 7 addConstraint : Constraint -→ void ; 8 push : void -→ void ; 9 pop : void -→ void ; 10 check : void -→ B ;

Interface 7 . 2 :

 72 SMT-solver Problem Loader Template 1 interface ProblemLoader contains 2 load : (f ilename : string), (opts : string) -→ void ; 3 hasConstraint : void -→ { , ⊥} ; 4 nextConstraint : void -→ Constraint (only valid if the last access to the interface was a call to hasConstraint that returned );

Interface 7 . 3 :

 73 SMT-solver Literal Generator Template 1 interface LiteralGenerator contains 2 load : (f ilename : string) -→ void ; 3 generate : (generatorId : string) -→ void ; 4 count : void -→ N ; 5 getMapper : void -→ {cid ∈ N → Constraint} ; parametrized with the executable of the SMT-solver. All of the interfaces provided are used to generate test executables for the implementation of both the ImpGen-PiD algorithm and the Ilinva algorithm.

Figure 7 . 1 :

 71 Figure 7.1: Structure of GPiD within the Abdulot framework

Figure 7 . 2 :

 72 Figure 7.2: Standard structure of a GPiD Hypothesis Engine

( s i z e 4 )Figure 7 . 3 :

 473 Figure 7.3: A simple abducible file.

↓A=Figure 7 . 4 :

 74 Figure 7.4: A more complex abducible file.

Figure 7 . 5 :

 75 Figure 7.5: Structure of Ilinva within the Abdulot framework

Interface 7 . 5 :3 interface ProblemHandler contains 4 proof 6 strengthen:

 7546 SMT-solver Problem Handler Template 1 interface ProblemProof contains 2 valid : void -→ b ∈ { , ⊥}; : void -→ P roblemP roof ; 5 selectStrengthenablePart : void -→ guide formula/verification condition; GuideF ormula : ϕ, Strengthening : φ -→ void; 7 release : void -→ void;

Figure 8 . 1 :Figure 8 . 1

 8181 Figure 8.1: Dimacs representation of the set of clauses {p∨¬q ∨r, q ∨¬r ∨¬s, ¬p∨¬q ∨s}

3 .

 3 The computer possessed 4 GB of DDR3 RAM running 1.6 GHz and a SSD Hard Drive. The version of Abdulot framework used for the experiments in this Chapter is 0.7.11, compiled with Clang (Apple version 10.0.1-0.46.4). The SMT-solvers used are CVC4 (a prerelease of version 1.7), Z3 (version 4.7.1) and Alt-Ergo (version 2.3.0).The version of the MiniSAT SAT-solver we used is a patched compilation of version 2.2.0. Finally, the version of the Why3 platform we used is 1.2.0. The exact version of the systems and tools we compare ourselves to will be mentioned when such tools are introduced within the chapter. Most of the raw results were processed using either Python or ToEv scripts available in the public repository of the Abdulot tool before being presented here. Such scripts were used mostly to compute statistical values on the results, recheck the obtained results to ensure that they are correct and draw the graph included in this work. The benchmarks and set of examples we used are described in detail when introduced within the chapter. They mostly consist of known examples obtained from standard repositories and of crafted examples used for testing and analysing specific properties of the algorithms we study.

Figure 9 . 1 :

 91 Figure 9.1: Execution of the GPiD algorithm as a function of the number of variables in almost unsatisfiable problems with various abducible ratios.

Figure 9 . 2 :

 92 Figure 9.2: Comparison of GPiD with ZRes and primer on the uf20 (bottom) and small benchmarks

Figure 9 . 3 :

 93 Figure 9.3: Proportion (out of 100) of examples of the QF_UFLIA benchmark where GPiD generates at least one implicate under 15 seconds.

Figure 9 . 4 :

 94 Figure 9.4: Number of examples from the QF_UF benchmark set for which GPiD (on the left, darker color) and cSP (on the right, lighter color) generate at least one T -implicate within a given time (a) and generate at least one implicate of a given maximal size under 15 seconds (b)

def = φ 1 Definition 156 .

 1156 the base formula of s and active(s) def = φ n the active formula of s. For s = φ 1 , . . . , φ n and t = ψ 1 , . . . , ψ m two (possibly empty) Ssequences, we define the concatenation of s and t as s + t = φ 1 , . . . , φ n , ψ 1 , . . . , ψ m .

Definition 162 .

 162 Given a set of S-sequences W , we will define the set of base formulas base(W ) def = {base(s) | s ∈ W } and, given a formula φ ∈ base(W ), we will denote by base -[φ](W ) an arbitrary element of W with a base equal to φ and verifying ∀s ∈ W, base(s) = φ ⇒ |s| ≥ |base -[φ](W )|.

Definition 169 .Definition 170 .

 169170 Let W be a representation set. We say that S(W ) is the formula represented by W . We also use the notations M |= W or W 1 |= W 2 when we mean M |= S(W ) or S(W 1 ) |= S(W 2 ). We say that a representation set W is an implicant representation set for a formula φ if W |= φ.

20 end 21

 2021 return i∈ 1,n W i ; Lemma 187. Let ψ ∈ S and Gen be an atomic generalization function. Let W and Sup be two representation sets such that W ⊗ Sup |= ψ. The two following properties hold. 1. W ⊗ Sup |= ψ for any recursive call MinimalPart(ψ, Gen, W , Sup ) made by the call MinimalPart(ψ, Gen, W, Sup).

Proposition 190 .

 190 Let ψ ∈ S and M |= ψ. Let Gen be an atomic generalization function and Iextract a implicant extractor. Finally, let W = MinimalPart(ψ, Gen, Iextract(ψ, M), ∅).

2 return ; 3

 23 let (D, s, h) be a model of F = P - * Q ∧ ¬(P - * ⊥) ; 4 return MinimalPart(F, Gen, slex(F, ((D, s, h))), ∅) ; Theorem 209. Given two separation logic formulas P, Q such that P |= Q, the formula F = SL-Abduce(P, Q) satisfies P * F |= Q.

  Figure 11.1: A sequence of stacks of tokens

Figure 11 . 2 :

 112 Figure 11.2: Generalization for sequences of stacks of tokens

Interface 11 . 1 : 2 Context : φ -→ 3 getHypothesisSize

 11123 Generalization Context Interface Template 1 interface Context contains : void -→ size ; 4 isLastGeneralization : vector<int>, index -→ { , ⊥} ; 5 isGeneralizable : vector<int>, index -→ { , ⊥} ; 6 isValidHypothesis : vector<int> -→ { , ⊥} ;

7 isConsistentHypothesis:

 7 vector<int> -→ { , ⊥} ; 8 print : vector<int> -→ void ; 11.1.

Figure 11 . 3 :Figure 11 . 4 :

 113114 Figure 11.3: Structure of minpart within the Abdulot framework

Figure 11 . 5 :

 115 Figure 11.5: Distribution of the number of satisfiability tests required to minimize 100 random token-stack formulas of a given depth limit, for a number of symbols of 100 and partitions of size 2 and of depth 1.

  0.015, 0.061, 0.092, 0.

Figure 11 . 6 :

 116 Figure11.6: Distribution of the number of satisfiability tests required to minimize 100 random token-stack formulas of a given depth limit, for a number of symbols of 100 and partitions of size 2 and of depth 1 for various probability distributions.

Figure 11 . 7 :

 117 Figure11.7: Distribution of the number of satisfiability tests required to minimize 100 random token-stack formulas with a given partition size, for a number of symbols of 100, a depth limit of 5 and partitions of depth 1.

Figure 11 . 8 :

 118 Figure11.8: Distribution of the number of satisfiability tests required to minimize 100 random token-stack formulas with a given partition size, for a number of symbols of 100, a depth limit of 10 and partitions of depth 1.

Figure 11 . 9 :

 119 Figure11.9: Distribution of the number of satisfiability tests required to minimize 100 random token-stack formulas with a given partition depth, for a number of symbols of 100, a depth limit of 10 and partitions of size 2.

Figure 11 . 10 :

 1110 Figure11.10: Distribution of the number of satisfiability tests required to minimize 100 random token-stack formulas with or without randomizing the partitions, for a number of symbols of 100, a depth limit of 10 and partitions of size 2 and depth 1.

Algorithm 11 . 3 :else 4 let 6 return

 11346 RandomSLF ormula(V, p)1 if random() < p then 2 let • ←-randomChoice({∧, ⇒, * }); 3 • ←-randomChoice({φ, →, emp, ⊥}); 5 if • ∈ {∧, ⇒, * } then RandomSLF ormula(V, p) • RandomSLF ormula(V, p); 7 else if • = φ then 8 let • e ←-randomChoice({=, =}); 9 let v l ←-randomChoice(V); 10 let v r ←-randomChoice(V \ {v l }); 11 return v l • e v r ; 12 else if • = → then 13 let v 0 ←-randomChoice(V); 14 let v 1 , . . . , v n ←-randomChoices(V); 15 return v 0 → v 1 , .. . , v n ; 16 else if • ∈ {emp, ⊥} then 17 return •;

Figure 11 . 11 :

 1111 Figure 11.11: Distribution of the number of satisfiability tests required to minimize implicants of 78400 randomly generated separation logic formulas as a function of the number of variables in the random generation.

Figure 11 . 12 :

 1112 Figure 11.12: Distribution of the number of satisfiability tests required to minimize implicants of 78400 randomly generated separation logic formulas as a function of the probability depth in the random generation.

Figure 11 . 13 :

 1113 Figure11.13: Distribution of the number of satisfiability tests required to minimize implicants of 9600 randomly generated separation logic formulas with separating implications as a function of the number of variables in the random generation.

  . 91.3 Theories as external dependencies .. . . . . . . . . . . . . . . . . . .. . 12 Prime implicate computation . . . . . . . . . . . . . . . . . . . . . . . . 15 2.1.1 Early prime implicate computation in propositional logic . . . . . 16 2.1.2 Resolution-based prime implicate computation in propositional logic 17 2.1.3 Decomposition-based prime implicate computation in propositional logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18 2.1.4 Other approaches for prime implicate computation in propositional logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.1.5 Prime implicate computation out of propositional logic . . . . . . 21 2.2 Loop invariant generation

	2 State of the art	15
	2.1

  . . 22 2.2.1 Static loop invariant generation . . . . . . . . . . . . . . . . . . . 23 2.2.2 Dynamic loop invariant generation

  An intuitive decomposition algorithm for prime implicate generation . . . 3.2 Improving the prime implicates generator . . . . . . . . . . . . . . . . . . 3.2.1 Reducing the number of candidates . . . . . . . . . . . . . . . . . 3.2.2 Reusing the (T , A)-implicates . . . . . . . . . . . . . . . . . . . . 3.2.3 External restrictions to prune more candidates . . . . . . . . . . . 3.3 An updated version of the prime implicate generation algorithm . . . . . 3.4 Improvements for performing abduction in propositional logic . . . . . . 4 Storing (T , A)-implicates efficiently 4.1 A structure for storing the (T , A)-implicates . . . . . . . . . . . . . . . . 4.2 Algorithms to efficiently insert and reuse the (T , A)-implicates . . . . . 4.3 An updated algorithm including storage management . . . . . . . . . . .

	I A generic framework for abduction modulo theories
	3 Efficient prime implicate generation modulo theories
	3.1
	. .	25
	xvii

7

  An infrastructure that transcribes the genericity of the algorithms 7.1 Generic interfaces for SMT-solvers . . . . . . . . . . . . . . . . . . . . . 7.2 Implementation of ImpGen-PiD . . . . . . . . . . . . . . . . . . . . . . 7.3 A GPiD hypothesis engine for selecting the candidates and handling the hypotheses

  . . xviii 8 Concrete interfaces for concrete problems 8.1 SAT-solver and SMT-solver interfaces . . . . . . . . . . . . . . . . . . . 8.1.1 An interface for MiniSAT . . . . . . . . . . . . . . . . . . . . . . 8.1.2 Interfaces for the C++ API of CVC4 and Z3 . . . . . . . . . . . 8.1.3 A generic interface for SMT-lib-compliant SMT-solvers . . . . . 8.2 A Why3 interface for

  . . 8.2.1 Presenting the Why3 platform . . . . . . . . . . . . . . . . . . . 8.2.2 Recovering and using the verification conditions generated by Why3 8.2.3 Configuring GPiD and its SMT-solver interfaces . . . . . . . . . 8.2.4 Abducible literals for the strengthening of WhyML programs loops 8.3 Documentation, compilation structure and distribution of the implementation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.3.1 Dummy interfaces for documentation . . . . . . . . . . . . . . . . 8.3.2 A note on the compilation framework . . . . . . . . . . . . . . . . 8.3.3 Distribution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

9 Experimental evaluation of GPiD and Ilinva 105 9.1 Experimental infrastructure

  . . 9.2 Evaluating the ImpGen-PiD algorithm in propositional logic . . . . . . .

9.2.1

Benchmarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.2.2 Evaluating GPiD alone . . . . . . . . . . . . . . . . . . . . .

. . 9.2.3 Comparison with ZRes and primer

  . . 10.3.1 Minimizing propositional logic models . . . . . . . . . . . . . . . . 10.3.2 Minimizing separation logic implicants . . . . . . . . . . . . . . . 10.4 Applying this algorithm as a subservient tool for bi-abduction in separation logic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Context Interfaces . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2.3 Generating partitions . . . . . . . . . . . . . . . . . . . . . . . . . 11.2.4 Structure of the implementation . . . . . . . . . . . . . . . . . . . 11.2.5 Distribution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.3 Testing the model minimization algorithm . . . . . . . . . . . . . . . . . 11.3.1 Shape of the problem

	11 A simple implementation and evaluation of the minimization algo-
	rithm and of its use for abduction in separation logic	137
	11.

1 A instantiation for evaluating the minimization algorithm . . . . . . . . . 11.2 Implementation of the minimization algorithm . . . . . . . . . . . . . . . 11.2.1 Implementing representation sets . . . . . . . . . . . . . . . . . . xix 11.2.2

  Trie representation of the formula φ from Example 52; literal order q > ¬q > p > ¬p > r > ¬r > s > ¬s .. . . . . . . . . . . . . . . . . . .. . 2.2 ZBDD representation of the prime implicates of the formula φ from Example 52; literal order q > ¬q > p > ¬p > r > ¬r > s > ¬s . . . . . . . 4.1 A representation of an A-trie . . . . . . . . . . . . . . . . . . . . . . . . Distribution of the number of satisfiability tests required to minimize 100 random token-stack formulas of a given depth limit, for a number of symbols of 100 and partitions of size 2 and of depth 1. . . . . . . . . . . 11.6 Distribution of the number of satisfiability tests required to minimize 100 random token-stack formulas of a given depth limit, for a number of symbols of 100 and partitions of size 2 and of depth 1 for various probability distributions. . . . . . . . . . . . . . . . . . . . . . . . . . . 11.7 Distribution of the number of satisfiability tests required to minimize 100 random token-stack formulas with a given partition size, for a number of symbols of 100, a depth limit of 5 and partitions of depth 1. . . . . . . 11.8 Distribution of the number of satisfiability tests required to minimize 100 random token-stack formulas with a given partition size, for a number of symbols of 100, a depth limit of 10 and partitions of depth 1. . . . . . . 11.9 Distribution of the number of satisfiability tests required to minimize 100 random token-stack formulas with a given partition depth, for a number of symbols of 100, a depth limit of 10 and partitions of size 2. . . . . . 11.10 Distribution of the number of satisfiability tests required to minimize 100 random token-stack formulas with or without randomizing the partitions,

	2.1

4.2

Example of forward subsumption .

. . . . . . . . . . . . . . . . . .

. . 4.3 Example of backward subsumption . . . . . . . . . . . . . . . . . . . . 7.1 Structure of GPiD within the Abdulot framework . . . . . . . . . . . 7.2 Standard structure of a GPiD Hypothesis Engine . . . . . . . . . . . . 7.3 A simple abducible file. . . . . . . . . . . . . . . . . . . . . . . . . . . . 7.4 A more complex abducible file. . . . . . . . . . . . . . . . . . . . . . . . 7.5 Structure of Ilinva within the Abdulot framework . . . . . . . . . . 8.1 Dimacs representation of the set of clauses {p∨¬q∨r, q∨¬r∨¬s, ¬p∨¬q∨s} 8.2 Simple WhyML loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8.3 Abducible file for the WhyML program of Figure 8.2 . . . . . . . . . . 8.4 Simple WhyML loop with a valid loop invariant . . . . . . . . . . . . . 9.1 Execution of the GPiD algorithm as a function of the number of variables in almost unsatisfiable problems with various abducible ratios. . . . . . 9.2 Comparison of GPiD with ZRes and primer on the uf20 (bottom) and small benchmarks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.3 Proportion (out of 100) of examples of the QF_UFLIA benchmark where GPiD generates at least one implicate under 15 seconds. . . . . . . . . 9.4 Number of examples from the QF_UF benchmark set for which GPiD (on the left, darker color) and cSP (on the right, lighter color) generate at least one T -implicate within a given time (a) and generate at least one implicate of a given maximal size under 15 seconds (b) . . . . . . . 11.1 A sequence of stacks of tokens . . . . . . . . . . . . . . . . . . . . . . . 11.2 Generalization for sequences of stacks of tokens . . . . . . . . . . . . . 11.3 Structure of minpart within the Abdulot framework . . . . . . . . . 11.4 Distribution of the number of satisfiability tests required to minimize 100 random token-stack formulas of a given size, for a depth limit of 10 and partitions of size 2 and of depth 1. . . . . . . . . . . . . . . . . . . . . . xxii 11.5 for a number of symbols of 100, a depth limit of 10 and partitions of size 2 and depth

1. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

. 11.11 Distribution of the number of satisfiability tests required to minimize implicants of 78400 randomly generated separation logic formulas as a function of the number of variables in the random generation. . . . . . 11.12 Distribution of the number of satisfiability tests required to minimize implicants of 78400 randomly generated separation logic formulas as a function of the probability depth in the random generation. . . . . . . . 11.13 Distribution of the number of satisfiability tests required to minimize implicants of 9600 randomly generated separation logic formulas with separating implications as a function of the number of variables in the random generation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

  Benchmark sources and content for the experimental evaluation of the Ilinva prototype.. . . . . . . . . . . . . . . . . . . . . . . . . . . .. . 9.4 Experimental Results of the Ilinva tool (Part 1). . . . . . . . . . . . . 9.5 Experimental Results of the Ilinva tool (Part 2). . . . . . . . . . . . .

	9.3
	9.1	Number of problems for which at least one T -implicate of a given maxi-
		mal size can be generated in a given amount of time (in seconds), for the
		QF_UF SMTLib benchmark (2549 examples). xxiii xxiv

. . . . . . . . . . . .

. . 9.2 Number of problems for which at least one T -implicate of a given maximal size can be generated in a given amount of time (in seconds), for the QF_UFLIA SMTLib benchmark (400 examples). . . . . . . . . . . . .

  . . , t n ) where t 1 , . . . , t n are terms, then t I,I v is undefined if the evaluation of at least one of the terms t 1 , . . . , t n is undefined or if f is not in the domain of I f . Otherwise, t I,

  Conversely, if we assume that both l |= T D and C |= T D, as any model of l ∨ C if necessarily a model of l and/or a model of C, we have that l ∨ C |= T D.2. Let us assume that C |= T l ∨ D. Let us take a model of C ∧ l. The definition of conjunctions ensures that this model is both a model of C and of l.

	The first point
	gives us that it is model of l ∨ D and the second that it is not a model of l, hence
	that it is necessarily a model of D. Conversely, if we assume that C ∧ l |= T D, we
	can split the models of C into those that also satisfy l (in which case the hypothesis
	gives us that they satisfy D, thus also l ∨ D), and those that do not, and thus
	necessarily satisfy l, thus l ∨ D.

  the previous property holds if and only if there exists i ∈ 1, n and E ∈ S(τ i ) such that l i ∨ E |= T C, i.e., such that l i |= T C and E |= T C by Proposition 34. By definition, ∃E (E |= T C ∧ E ∈ S(τ i )) if and only if (S(τ i ) ||= C). Furthermore, l i ||= C holds if and only if C ∪ {l i } is T -unsatisfiable, hence the result.

  and 1 ≤ 2 if it is lower or equal.

Definition

[START_REF] Peuter | On invariant synthesis for parametric systems[END_REF]

. Given a program P and two locations , in P , we define P [ : ] the subprogram of P between and inductively as follows:

  . . , ϕ n → sp( , P [ * ←-ϕ 1 , . . . , ϕ n ] [0: ] ) ⇒ φ belongs to Υ. It is the verification condition generator ensuring that the assertion at location is verified. Remark that this verification condition generator depends on all the candidate loop invariant locations of P [0: ] . • For any location ∈ P such that P | is of the form while C do [φ] P done, υ init : ϕ 1 , . . . , ϕ n → sp( , P [ * ←-ϕ 1 , . . . , ϕ n ] [0: ] ) ⇒ ϕ

i belongs to Υ, where ϕ i is such that P [ * ←-ϕ 1 , . . . , ϕ n ]| is the instruction

while C do [ϕ i ] P * done.

It is the verification condition generator ensuring that the candidate loop invariant of the loop at location is verified whenever the loop is entered. Note that this verification condition generator depends on all the candidate loop invariants of P [0: ] as well as on the candidate loop invariant of P | . • For any location ∈ P such that P | is of the form while C do [φ] P done, υ ind : ϕ 1 , . . . , ϕ n → ϕ i ⇒ wp(ϕ i , rmLoops(P * )) belongs to Υ, where P * and ϕ i are such that P [ * ←-ϕ 1 , . . . , ϕ n ]| is the instruction while C do [ϕ i ] P * done.

It is the verification condition generator ensuring that the candidate loop invariant of the loop at location propagates. Note that this verification condition generator depends on all the candidate loop invariants of P as well as on the candidate loop invariant of P | .

• Υ does not contain any other verification condition generator.

Definition 144. Given a verification structure (Φ, Υ) representing a program P as in Definition 143, we define verification update inverters for its verification condition generators as follows:

Table 9 .

 9 1: Number of problems for which at least one T -implicate of a given maximal size can be generated in a given amount of time (in seconds), for the QF_UF SMTLib benchmark (2549 examples).

	None

Table 9 .

 9 2: Number of problems for which at least one T -implicate of a given maximal size can be generated in a given amount of time (in seconds), for the QF_UFLIA SMTLib benchmark (400 examples).

Table 9 .

 9 3: Benchmark sources and content for the experimental evaluation of the Ilinva prototype.

	Examples	Sources	Theories
	Ox	[57, 85]	LIA
	534	[114, 22, 172] Array, NLIA
	509, H04, H05 [114, 22, 172]	NLIA
	BM	[157]	LIA
	Scmp, Dmd	[157]	(N)LIA, Float
	listx	Crafted	List
	arrayx	Crafted	Array
	expox	Crafted	NLIA
	square	Crafted	NLIA
	realx	Crafted	LRA
	B00	Crafted	NLIA
	DIVx	Crafted	NLIA

Table 9 .

 9 4: Experimental Results of the Ilinva tool (Part 1).

	T(D)	C(D)	Why3

Table 9 .

 9 5: Experimental Results of the Ilinva tool (Part 2).

		Abd	T(C)	C(C)	T(D)	C(D)	Why3
	509	130	(1h50 )	(95)		0	0.66
	534	172k		8		0	0.62
	H04	120	2 54.8	223		1383	0.31
	H05	1260		0		0	0.37
	list0	60	6 30.4	77		1722	0.40
	list1	20	40.82	3	3 26.2	385	0.47
	list2	720		40		0	0.40
	list3	126	3 35.1	11		930	0.44
	list4	816		18		0
	list5	468		22		0	0.44
	array0			0		0	0.72
	array1			0		0	0.50
	array2			0		0	0.50
	array3			0		0	0.82
	expo0	171	(6h36 )	(9)		0	0.40
	expo1	2130		0		0
	square	705		62		148
	real0	965		81		213	0.55
	real1	965		73		115	0.55
	real2	240		9		2	0.40
	realO0	36	4 9.6	25	5 32.18	40	0.47
	realS	66	1 5.3	5	1 0.1	5	0.33
	real3	17460		0		0
	BM	1260	3 15.2	74		33	3.35
	Scmp			0		0	0.83
	Dmd	42		6		0	1 44.9
	B00	639k		0		0	0.76
	DIV0	560	3 58	35		534	0.83
	DIV1	310	14.6	19	14.6	19	0.44
	DIVE	42250		0		0
	function/predicate symbols. It can be observed that the abduction depth is rather low
	in all examples (1 or 2).

  then by definition this entails that either Clean[W 2 ](W 1 ) or W 2 contains a sequence s such that s < g s . Necessarily s is contained in W 1 ∪ W 2 , which contradicts the previous property. This ensures thats ∈ Clean[W 2 ](W 1 ) ⊗ W 2 . • If s / ∈ W 2 , then necessarily s ∈ W 1 .As no sequence distinct from s but with the same base in W 1 ∪ W 2 is smaller than s, this gives us that s ∈ Clean[W 2 ](W 1 ) and then

  there exist no W ≺ Gen W then H in an arbitrary set of hypotheses such that W H ≺ Gen W do , . . . , W n be a generalization-partition of W ; 18

	8	return MinimalPart(ψ, Gen, Gen(W, s), Sup) ;
	9	else
	10	return W ;
	15	end
	16 end
	17 let W 1

3 return W ; 4 else if we can detect that there are no more general hypotheses W ≺ Gen W such that W ⊗ Sup |= ψ then 5 return W ; 6 else if W = {s} then 7 if Gen(W, s) ⊗ Sup |= ψ then 11 end 12 foreach W 13 if W H ⊗ Sup |= ψ then 14 return MinimalPart(ψ, Gen, W H , Sup) ;

  104, 0.104, Pv = [0.0055, 0.0270, 0.1075, 0.1075, 0.1075, 0.104, 0.104, 0.104, 0.104, 0.104, 0.104] 0.1075, 0.1075, 0.1075, 0.1075, 0.1075, 0.1075] Pv = [0.004, 0.027, 0.057, 0.114, 0.114, Pv = [0.004, 0.019, 0.076, 0.096, 0.115, 0.114, 0.114, 0.114, 0.114, 0.114, 0.114] 0.115, 0.115, 0.115, 0.115, 0.115, 0.115]

		700
		600										600
		500										500
	Satisfiability tests	300 400									Satisfiability tests	300 400
		200										200
		100										100
		0	1	2	3	4	5 Maximal depth 6	7	8	9	10	1	2	3	4	5 Maximal depth 6	7	8	9	10

  UpdateImplicates(Φ, M, U, A, Π), 41 UpdateImplicatesLocal(Φ, M, A, Π),

	Gen, 125	program, 61
	atomic generalization function, 125	P | , 64
	functional, 122	locs(), 63
	generalization relation, 122	rmLoops(P ), 63
	well-founded, 122	sp(φ, P ), 65
	generalization partition, 127	P [ : ] , 64
	generalization sequence, 123	wp(ψ, P ), 65
	order, 123	assertion, 61
	prefix, 123	assumption, 61
	t I,I v , 5 ⊥, 4 fix(, , ), 30 Lits(), 8 S-sequence, 122 active formula, 122 base formula, 122 concatenation, 123 prex, 132 suffix, 123 guide formula, 56 Guide(), 56 implicant, 9 A-implicant, 11 (T , A)-implicant, 11 prime implicant, 9 implicate, 9 I T ,A (Φ), 11 slex, 134 syex, 139 σ, 3 A I [l], 34 A[l], 34 ∼ T , 10 I(), 29 I 41 T -equivalence, 10 A-implicate, 11 , 4 U * (T , A)-implicate, 11 T ,M,A,U (Φ), 36 clear(, ), 48 SMT-solver, 12 incremental, 13 A-trie, 45 ⊥, 45 del, 47 insert(, ), 46 S(), 45 empty leaf, 45 local implicates, 29 prime implicate, 9 interpretation, 5 partial, 6 total, 6 variables, 5 literal, 4 A-reason, 41 Φ-compatible, 34 logical consequence, see entailment abducible, 11 loop invariant, 62 abducible literal, see abducible candidate, 62 arity, 3 atom, 4 model, 6, 7	instruction at location, 64 H A (Φ, M ), 43 location, 63 U T ,Φ,M , 35 loop, 61 U T ,M [U ](Φ), 35 empty clause, 8 unit clause, 8 clean representation, 128 strongest postcondition, subprogram, 64 weakest precondition, complement, 4 representation function, 124 φ, 4 monotonous, 124 constant, 3 representation set, 124 ⊗, 126 decidability, 12 decision procedure, 12 entailement, 7 |= T , 7 ||=, 9 Iextract, 125 formula, 124 generalization, 126 implicant, 124 implicant extractor, 125 ||= T , 9 merge, 126 strong entailement, 9 strict generalization, entailment, 7 |=, 7 SubMin T (), 10 SubMin(), 10 entailment minimal equivalent, 10 evaluation, 5 satisfiability, 6, 7, 12 separation logic, 132 antiframe, 135 biabduction, 135 conclusion, 135 disjoint heap, 133 φ I,I v , 5 disjoint union, 133 φ I , 5 evaluation, 133 formula, 5 formula, 132 term, 5 frame, 135 formula, 4 interpretation, 133 conjunctive normal form, 39 model, 133 function, 3 problem constraint, 135 parameter, 3 satisfiability, 134
	boolean sort, 3 |=, 6	return type, 3 signature, 3
	clause, 8 minimal, 40	generalization, 122 sort, 3
	ρ M (l), 42 predicate	→ g tautology, 7 * , 125
	⊥, 8 filtering predicate, 37	→ g term, 3 + , 125

* (), 29 I * T ,A (Φ), 11

Note in particular that S(∅) = ∅. Intuitively an A-trie may be seen as a tree in which the edges are labeled by literals and the leaves are labeled by ∅ or ⊥, and represents a set of clauses corresponding to paths from the root to ⊥.

Note that we delegate the computation of the possible strengthenings to an abduction algorithm Line 7. This abduction algorithm is presented in Algorithm 5. 3. It starts by recovering the verification condition it should perform abduction on (Line 1). Assuming it can obtain a relevant set of abducible literals (we will detail methods to do that in Chapters 6.4 and 8) and a filtering predicate if necessary, it will then invoke the ImpGen-PiD algorithm to compute the prime implicates of the formula (Line 4). Once obtained, we can update this initial result set of implicants, typically by constructing disjunctions of the ones we recovered from the call to ImpGen-PiD. We present this Line 5 in the form of a call to a procedure UpdateImplicants left unspecified. It is assumed to update the initial set of implicants by either removing some it deemed irrelevant or by adding new ones it is able to construct (such as disjunctions of the previous ones). Finally, as what we currently have is a set of implicants for the formula obtained by applying a verification condition generator, we need to translate these implicants into valid strengthenings for the selected guide formula. This is what we do Line 6. We will generally assume that we have selected our abducible literals such that we can ensure that we have Ξ ⊂ Dom(υ -1 | i ).

Algorithm 5.3: IlinvaAbduce(P, j, i)

1 let φ ←-VCGen j (P )(Guides(P )) ; 2 let A a set of abducible literals for φ ; 3 let P a literal set predicate filter for φ ; 4 let Ξ ←-I I ∈ ImpGen-PiD(φ, ∅, A, P) ; 5 UpdateImplicants(Ξ) ;

Theorem 125. Let P be a verification structure. If Ilinva(P ) terminates and if we have Ilinva(P ) = failure, then Ilinva(P ) ∼ P and Ilinva(P ) is satisfied. contain any subset that is unsatisfiable. If it is deactivated in other cases, some of implicates generated by the GPiD tool may be inconsistent. One can also configure the engine to skip hypotheses containing more than a fixed, given number of abducible literals, or to stop after the system has generated a given number of implicates. We also offer the possibility to add additional SMT-solver checks to prune abducible literals that are consequences of the current hypothesis. Finally, both global timeouts and local SMT-solver checks timeouts can be set.

The tool can be tried with the test executables provided through the implemented solver interfaces described in Chapter 8. Given one of those interfaces solver, a problem file accepted by the chosen SMT-solver problem.sdt, and a file containing abducible literals abducibles.abd, the generation of prime implicates can be launched with the command gpid-solver -i problem.sdt -l abducibles.abd -p. A complete description of the command line options to configure the execution as wanted is provided in Appendix C.

Implementation of Ilinva

In this section, we describe the implementation of the problem strengthener presented in Chapter 5, which we named Ilinva. A graphical description of its structure is provided in Figure 7. 5. It is also presented as a generic system that will be instantiated with an interface for a program prover, that is, a system that generates the verification condition and manage the guide formula for a class of verification structures. The implementation of the interface for program verification and loop invariant generation will be described in Chapter 8.

We present the Ilinva tool within its interface, which takes as an input a problem we know how to convert into a verification structure and that can be solved by a given tool. The interface also accepts additional information for the generation of the strengthenings invariants (such as a core set of abducible elements linked to the problem at hand). We Algorithm 7. ( s i z e auto ) ( lambda eq ( l r ) (= l r ) ) ( lambda neq ( l r ) ( d i s t i n c t l r ) ) ( lambda l e ( l r ) (<= l r ) ) ( lambda l t ( l r ) (< l r ) ) ( d e c l a r e t as i n t ) ( d e c l a r e 0 10 as i n t ) ( r e f e r e n c e t ) ( apply eq ( o v e r i n t i n t ) b f symmetric ) ( apply neq ( o v e r i n t i n t ) b f symmetric ) ( apply l e ( o v e r i n t i n t ) b f n o n s e l f ) ( apply l t ( o v e r i n t i n t ) b f n o n s e l f ) ( extend b f ) Figure 8.3: Abducible file for the WhyML program of Figure 8.2 l e t main ( ) : u n i t d i v e r g e s = l e t t = r e f 0 i n w h i l e ! t < 10 do i n v a r i a n t { ! t <= 10 } t := ! t + 1 done ; a s s e r t { ! t = 10 } Figure 8.4: Simple WhyML loop with a valid loop invariant such as (< t 10) and (<= t 10). The conversion toolbox will be able to translate these implicants back to syntactically valid WhyML conditions: !t < 10 and !t <= 10 (note the reintroduction of the derefencing operator !, induced by the content of the abducible file and required because t is a reference variable).

As the first implicant does not propagate (and cannot be strengthened to propagate), the tool will backtrack and try with the second implicant generated by GPiD, which happens to be a valid loop invariant for problem. Ilinva will thus return the updated WhyML program (Figure 8.4).

If

MinimalPart(ψ, Gen, W, Sup) terminates, then MinimalPart(ψ, Gen, W, Sup) ⊗ Sup |= ψ . Proof. First, we notice that the first and second parameters of MinimalPart do not change in any recursive call, which justifies the fact that we keep the notations ψ and Gen within this proof.

We are going to prove the two points simultaneously by induction on the number of recursive calls, as a pre (1) and post (2) condition.

(2) holds if we are in one of the following base cases of the algorithm. If we return at line 3, 5 or 10, we are actually returning Clean[Sup](W ) where W is the entry parameter of the algorithm. Proposition 186 gives us that Clean[Sup](W ) ⊗ Sup = W ⊗ Sup. This allows us to conclude that (2) holds using our initial hypothesis.

For all the other cases, let us assume as an induction hypothesis (*) that (2) holds for any recursive call MinimalPart(ψ, Gen, W , Sup ) verifying (1) : W ⊗ Sup |= ψ.

If we happen to return from line 8 or line 14, (1) is ensured by the tests preceding these invocations (line 7 and line 13 respectively). Applying the induction hypothesis (*), we can conclude that (1) holds for these two cases.

This leaves us with the partition case. Let W 1 , . . . , W n be our initial generalization partition of W . As ⊗ is associative and commutative (Proposition 182), we have that

This implies (1) as a consequence of our initial hypothesis and Proposition 186.

Applying our induction hypothesis (*), we deduce that W 1 ⊗(Sup⊗ j∈ 2,n ,j =1 W j ) |= ψ. We reapply the same process for every part of the generalization partition, replacing each time W in the reasoning by i∈ 1,n W i for which the implicant property has been obtained in the previous step. This allows to conclude that, at the end of the partitioning loop, we have Sup ⊗ i∈ 1,n W i |= ψ, which proves point (2) for the return at line 21. This completes the proof of the initial lemma by induction.

Lemma 188. For any formula ψ, atomic generalization function Gen, representation sets W, Sup, such that W ⊗ Sup |= ψ, MinimalPart(ψ, Gen, W, Sup) terminates.

Proof. Termination comes from the well-founded order used by → g . We prove that any recursive call made to MinimalPart uses as its representation set a strict generalization of the previous parameters. Because ≺ Gen is well-founded, this ensures that we can only make a finite number of recursive calls before falling in a base case. This is trivial for the recursive call at line 8 as Gen(W, s) ≺ Gen W for any representation set W and any s ∈ W by construction.

For the recursive call of line 14, this property is ensured by construction as a restriction on the block hypothesis allowed to be tried (see the condition in the loop line 12).

Finally, for the recursive call at line 19, this property is ensured by the Definition (183) of the generalization partition.

Lemma 189. Let ψ ∈ S, Gen be an atomic generalization function and let W, Sup be two representation sets such that W ⊗ Sup |= ψ.

We will thus consider in this part that S is the set of separation logic formulas. We also define:

Definition 195. We call a tuple (D, s, h) an interpretation for separation logic when D is a countable set, s is a total function mapping variables to elements of D and h is a partial function from D to D n . Definition 196. Let (D, s, h) be an interpretation for separation logic.

Given a variable v in the domain of s, we call

Given φ an equality (resp. disequality) between two variables v 1 and v 2 of s, we call

Definition 197. Let D be a countable set and h 1 , h 2 be two partial functions from D to D n . We say that h 1 and h 2 are disjoint (and write

Definition 198. Let D be a countable set and h 1 , h 2 be two disjoint functions of elements of D to tuple of elements of D. We define the disjoint union of h 1 and h 2 and denote by h 1 * h 2 the function from D to D n such that we have all the following:

Definition 199. Let P be a separation logic formula. Let (D, s, h) be an interpretation for separation logic. We define the satisfaction relation between interpretations and formulas as follows: we say that (D, s, h) is a model of P and write (D, s, h) |= P if one of the following holds:

5.

If v 1 and v 2 are variables, v 1 = v 2 → g . 6. Other elements are not in relation.

Justification. We first notice that any formula added in the first representation set by our extractor slex is indeed generalizable with this generalization relation. Second, the associated order is well founded (any generalizable formula can be reduced to one of the base cases).

To obtain the associated atomic generalization function Gen, we still need to define its domain.

Definition 205. Let W be a representation set and s ∈ W . (W, s) ∈ Dom(Gen) if and only if at least one of the following is verified:

We can then apply the framework of Section 10.1 to minimize separation logic implicants. 10.4 Applying this algorithm as a subservient tool for bi-abduction in separation logic Definition 206. Given a separation logic formula P that we call problem constraint and a separation logic formula Q that we call conclusion such that P |= Q, the bi-abduction problem consists in constructing missing hypotheses F (also called the antiframe) and/or missing conclusions G (also called the frame)

Those will represent the missing preconditions in memory (antiframe) to ensure the conclusion holds as well as information on parts of the memory unaffected by it (frame). In the context of program verification, antiframes are usually used to express the necessary conditions on the initial state of the memory and the frames are used to infer which memory cells are left unchanged by the program. In this work, we will only develop the computation of antiframes, that is, the computation of missing hypotheses F such that P * F |= Q. Intuitively, the idea we explore is to generalize an intuitive solution of this problem.

Proposition 207. Given two separation logic formulas P, Q, the formula F = P - * Q ∧ ¬(P - * ⊥) satisfies P * F |= Q.

Chapter 11 A simple implementation and evaluation of the minimization algorithm and of its use for abduction in separation logic

This chapter presents an implementation and an experimental evaluation of the implicant minimization algorithm and of the separation logic abduction algorithm we developed in Chapter 10. As we will see, the efficiency of the separation logic checkers and the complexity of the formulas we generate make it difficult for the general bi-abduction algorithm to work efficiently. This lack of efficiency makes it difficult to evaluate the minimization algorithm itself directly from its instantiation in separation logic. In order to evaluate the minimization algorithm itself, before considering its practical use in separation logic, we will define an alternative instantiation, the only purpose of which is the evaluation of the algorithm.

A instantiation for evaluating the minimization algorithm

As the MinimalPart algorithm is defined for minimizing implicants independently of the concrete definition of the interpretations of the formulas, it is clear that the computation cost of a minimization execution heavily depends on the definition used. In particular, the complexity of the operation verifying if the current generalization still entails the original formula impacts on the efficiency the instantiated algorithm. In order to evaluate the efficiency of MinimalPart independently of this external cost, we devise an instantiation for which this verification can be done easily.

Example 210. Consider a sequence of stacks of tokens, such as the one represented on Figure 11.1. Now assume that, for some reason, we want to reproduce this sequence but that the only information we can access is whether all the stacks of our representation contain less tokens than their counterpart in the source sequence.

To solve this problem, we may use the MinimalPart algorithm. Intuitively, we can first represent each stack by a formula of which the successive generalization represent the third one, which is not possible, and finish by minimizing the last stack as much as possible (f). Finally, the algorithm will backtrack its splits and reconstruct the sequence of stacks of tokens that was proposed in Figure 11. 1. We will use this simple application to evaluate our implicant minimization algorithm. Therefore, we provide below the formal definition of the related instantiation.

Definition 211. Given a finite sequence of symbols Y and a depth limit n ∈ N, we call token-stack formula all the elements of the following set:

Similarly to what we did in propositional logic, we will use S :

Example 212. Given a sequence of symbols Y = 1, 2, 3, 4 , the example of Figure 11.1 could be represented by the token-stack formula

Definition 213. Given a sequence of symbols Y, a depth limit n ∈ N and a token-stack formula, we define an interpretation of the symbols as a sequence I of natural integers indexed by the symbols of Y.

Definition 214. Given a sequence of symbols Y = y 1 , . . . , y k , a token-stack formula f and an interpretation of the symbols I = n 1 , . . . , n k , we define f I the evaluation of f in I inductively as follows:

Definition 215. Given an interpretation of the symbols I and a token-stack formula f, we say that I is a model of f if f I = .

We say that a token-stack formula f is satisfiable if it admits a model. Given two set-symbols-formulas f 1 and f 2 , we say that f 2 is a logical consequence of f 1 if all the models of f 1 are also models of f 2 .

Example 216. Consider again the token-stack formula 1 3 ∧ 2 2 ∧ 3 1 ∧ 4 2 representing the example of Figure 11.1. The sequence 2, 2, 1, 1 is a model of this formula while the sequence 3, 2, 1, 3 is not. Thus, we can write

Proposition 217. Let f be a token-stack formula. The sequence 0 | y ∈ Y is a model of f. Definition 218. Let f be a token-stack formula and I a model of f. We consider the implicant extractor syex defined as follows:

Testing the model minimization algorithm

We now present an experimental evaluation of the MinimalPart algorithm through this implementation framework. The experimental infrastructure is the same as the one presented in Chapter 9. In this first section, we evaluate the minimization algorithm using its token-stack formulas instantiation. As measuring an execution time is of no interest in this context, we will rather count the number of modelling tests that are made, as this is expected to be the most costly operation within the framework.

Throughout the section, the examples for which we look for a minimal model are randomly generated using the following process: we start by defining a set of symbols (of which we will abstract the content and give the size) and a depth limit, then we generate a formula containing all the provided symbols with a random generalization depth taken between zero and the depth limit. In all the examples, it has always been verified that the minimal model returned by the experiment was indeed equal to the randomly generated problem.

Shape of the problem

In Figure 11.4, we present the evolution of the number of satisfiability tests required to solve the minimization problem as a function of the size of the initial formula (as in the size of the initial representation set) when the depth limit is 10, the size of the partition 2 and the depth of atomic generalization function application 1. In Figure 11.5, we present the same value as a function of the depth limit when the size of the input formula is 100, the size of the partition 2 and the depth of atomic generalization function application 1. For all inputs, the experiments has been run on a 100 random problems of which the distribution is drawn. Note also that the partitions were generated using the most simple heuristic: separating the set into the given number of equally sized generalized sets. The theoretical mean number of satisfiability tests required by the naive method to solve the same problem with the given inputs is also represented in the figures, in the form of blue crosses. This naive method is recalled in Algorithm 11.2.

Algorithm 11.2: M inimize(f, Y) The results show that the MinimalPart algorithm is more efficient whenever the number of possible generalizations for a component is high. It also shows that the number of satisfiability tests it requires increases less than the ones of the naive algorithm ( d e c l a r e -fun c o n t e n t s ( ty u n i ) u n i )

; ; c o n t e n t s _ s o r t ( a s s e r t ( f o r a l l ( ( a ty ) ) ( f o r a l l ( ( x u n i ) ) ( s o r t a ( c o n t e n t s a x ) ) ) ) )

; ; c o n t e n t s _ d e f ( a s s e r t ( f o r a l l ( ( a ty ) ) ( f o r a l l ( ( u u n i ) ) (=> ( s o r t a u ) (= ( c o n t e n t s a ( mk_ref a u ) ) u ) ) ) ) )

; ; r e f _ i n v e r s i o n ( a s s e r t ( f o r a l l ( ( a ty ) ) ( f o r a l l ( ( u u n i ) ) (=> ( s o r t ( r e f a ) u ) (= u ( mk_ref a ( c o n t e n t s a u ) ) ) ) ) ) )

( d e c l a r e -fun t ( ) I n t )

; ; H ( a s s e r t ( not (< t 1 0 ) ) ) ( a s s e r t ; ; VC_main

Appendix C

User manual for the implementation

C.1 Distribution

The Abdulot framework contains the implementation of all the algorithms that are presented in this thesis, as well as the additional libraries, tools and interfaces necessary to compile it and plug it to SMT-solvers and to the Why3 platform. It is publicly available on GitHub (https://github.com/sellamiy/GPiD-Framework) under the BSD 3cl licence. This appendix describes all the information necessary to compile it and make it run on some minimal examples.

C.2 Structure of the repository

We detail in this section the content of the directories the sources of the Abdulot framework contain.

C.2.1 Directories

• cmake/include : Local CMake sources to help in the global compilation structure.

• cmake/modules : Additional CMake sources to detect and configure external tools such as SMT-solvers.

• cmake/patches : MiniSAT patches necessary for building the MiniSAT solver interface.

• framework : Sources of the structures and algorithms of the geneiric prime implicate generator and loop invariant generator.

• iphandle : Sources of the program abstraction interfaces.

• iphandle/why3-wrapped : Sources of the Why3 interface.

• lib/antlr4 : CMake sources for recovering and compiling ANTLR [START_REF] Parr | The Definitive ANTLR 4 Reference. Pragmatic Bookshelf[END_REF].

• lib/cxxopts : CMake sources for recovering and compiling CxxOpts (https: //github.com/jarro2783/cxxopts).

• lib/lcdot : Graph library, used for drawing execution search trees.

• lib/lisptp : Lisp parser, used in particular to parse SMT-lib and abducible files.

• lib/minpart : Implementation of the MinimalPart algorithm and of its associated structures.

• lib/smtlib2tools : Set of tools for handling SMT-lib problems.

• lib/snlog : Logging library.

• lib/starray : Static emptyable arrays library (see also [START_REF] Sellami | A dpll-based approach to prime implicate generation[END_REF]).

• lib/stdutils : Miscellaneous C++ 11 utilities.

• lib/ugly : Miscellaneous algorithms.

• lib/why3cpp : Set of tools for handling Why3 calls and WhyML programs.

• mpcontext : Sources of context components for the minpart algorithm.

• mpcontext/prop-minisat : Sources of propositional minpart context.

• mpcontext/sl-cvc4 : Sources of separation logic minpart context.

• solvers : Sources of the solver interfaces.

• test : Some tests.

• tools : Sources of the example executables used for the evaluation.

• utils : Miscellaneous scripts, used in particular to configure the solver interfaces during the compilation.

C.2.2 Compiling

The compilation is performed via CMake. The configuration accepts the following options:

• BUILD_TESTS (default ON) : Build the executables performing tests on the algorithms of the framework.

• INSTRUMENTATION (default OFF) : Build the framework with instrumentation instructions that allow to draw the exploration graphs of the algorithms and permit to verify the intermediate results of the computation. Can also significantly reduce the execution speed.

• BUILD_GPID (default ON) : Build the prime implicate generator executables.

• BUILD_ILINVA (default ON) : Build the loop invariant generator executables. the use of the option BUILD_GPID=ON is mandatory when if BUILD_ILINVA is set.

• BUILD_MINPART (default ON) : Build the contextualized implicant minimizer based on minpart.

• SKIP_SOLVER_INTERFACE (list of interfaces) : Allows one to skip the compilation and generation of a given solver interface (as well as of the corresponding executables). For instance, to skip the generation of the Z3 interface, one can add the configuration option -SKIP_SOLVER_INTERFACE=z3. Note that when an SMTsolver is not present in the system, the generation of the corresponding interfaces is automatically skipped.

• SKIP_ILINVA_HANDLER (list of interfaces) : Identical to the previous option but for the program representation interfaces of the loop invariant generator.

• SKIP_MINPART_CONTEXT (list of interfaces) : Identical to the previous option but for the minpart context components.

All the libraries of the framework are built in the lib directory of the build directory. Similarly, all the executables are built in the bin directory of the build directory.

C.2.3 Configuring Why3

The Ilinva test executable of the Abdulot uses the Why3 platform to generate and check the verification conditions of programs. This requires that the Why3 platform is installed and correctly configured before starting the compilation of the tool. Why3 can be installed via the OCaml package manager OPAM. Before compiling its Ilinva interface, it is also mandatory to make sure that Why3 can use at least one SMT-solver on the system and that it has been configured for it (by running Why3 config once).

C.2.4 Executables

The sample executables that are generated by the compilation of the while framework are listed below. Their correspondence to the algorithms presented in this thesis are also mentioned.

• abdulot-parser : Executable to parse and check abducible files.

• gpid-lcvc4 : GPiD algorithm plugged to the C++ library version of CVC4.

• gpid-ccvc4 : GPiD algorithm plugged to the SMT-lib interface of CVC4.

• gpid-verit : GPiD algorithm plugged to the SMT-lib interface of VeriT.

• gpid-lz3 : GPiD algorithm plugged to the C++ library version of Z3.

• gpid-cz3 : GPiD algorithm plugged to the SMT-lib interface of Z3.

• gpid-saltergo : GPiD algorithm plugged to the SMT-lib interface of Alt-Ergo.

• gpid-minisatp : GPiD algorithm plugged to the C++ library of MiniSAT.

• gpid-tisi : Compilation artifact; do not use.

• gpid : GPiD algorithm plugged to all the available interfaces. The interface to use has to be selected through a command-line option.

• smt2abduce : Script wrapping to help the generation of abducible literals.

• ilinva-why3-wrapped : Ilinva algorithm plugged to Why3.

• smtlib2-tools : Miscellaneous fun command line utilities to use on SMT-lib files.

• why3-tools : Miscellaneous fun but hard to use command line helpers to use on WhyML files.

• minpart-lits : minpart algorithm instantiation used to minimize a random tokenset-formula.

• minpart-prop-minisat : minpart algorithm instantiation used to minimize propositional models.

• minpart-sl-cvc4 : minpart algorithm instantiation used to minimize separation logic formulas.

• abdulot-select : High-level framework wrapper to use to encapsulate calls to any of the executables of the Abdulot framework. May also be configured by CMake to encapsulate a single Abdulot executable. May be a Bash script or a Python3 script depending on the system and on the configuration.

C.3 Running simple examples

We present in this section simple command-line examples to use the executables of the framework to perform some very simple, non-configured, tasks.

C.3.1 Generate propositional logic implicates

To generate the implicates of a propositional logic formula (assuming it is in the Dimacs format and can be parsed by MiniSAT), one can use the gpid-minisatp tool.

Assuming the Dimacs problem is called problem.dimacs, one can run gpid-minisatp -i problem.dimacs -autogen-abducibles all -P to generate all the prime implicates of the problem and print them on the terminal.

C.3.2 Generate the implicates of an SMT-lib file