Partie 1 : SAT solveur

publicité
Partie 1 : SAT solveur
François Thiré
January 16, 2017
1
Introduction
Le projet logique de cette année va se découper en trois parties plus ou moins
indépendantes. L’objectif est à chaque fois de vous faire découvrir comment la
logique peut-être utilisée pour résoudre des problèmes. Il existe de nombreuses
façon différentes d’utiliser la logique et il n’est pas possible en un semestre de
présenter toutes ces façons. Cependant, voici 5 grandes catégories1 :
• Les SAT solveurs
• Les SMT solveurs
• Les démonstrateurs automatiques
• Les assistants de preuve
• La programmation logique
Les SAT solveurs : ce sont des outils qui permettent de répondre au problème de la satisfiabilité d’une formule exprimée en logique propositionnelle. La
première partie du projet s’intéresse à cette catégorie et elle sera donc détaillée
ci-dessous.
Les SMT solveurs : ces outils sont également des solveurs mais cette fois
du premier ordre auquel on a rajouté des théories. Des théories, il en existe des
dizaines, mais on peut notamment citer :
• l’arithmétique
• l’arithmétique linéaire (sans la multiplication)
• les nombre flottants
1 les
points soulignés en gras sont ceux qui vont nous concerner
1
Les SMT solveurs sont en général basés sur un SAT solveur auquel on
a rajouté une procédure de décision pour chaque théorie. Dans le cas de
l’arithmétique linéaire par exemple, cette procédure est généralement l’algorithme
du simplex que vous verrez si vous faites le cours Algorithmique 2. En se plaçant
dans cette théorie, par exemple vous pouvez donner la formule suivante à un
SMT solveur :
∀x, y, z, 2x ≥ y + 4z ∨ 2x + 3z ≥ 3(y + 1) ∨ 7y + 3 ≥ 6x + 4z
et il vous répondra que c’est effectivement un théorème (était-ce évident ?).
Le problème aussi bien avec les SAT solveurs que les SMT solveurs, c’est
qu’ils intègrent seulement une procédure de décision. Autrement dit leur réponse
peut-être :
• Oui
• Non
• Je ne sais pas
Mais imaginez que le SMT solveur ait un bug dans son code et qu’une fois
de temps en temps il se trompe, comment peut-on le savoir ? Afin d’augmenter
notre degré de confiance il peut-être plus intéressant de fournir une preuve (ou un
trace de preuve) dudit théorème. C’est l’objet des démonstrateurs automatiques.
Les démonstrateurs automatiques : ce sont des outils qui à l’instar des
SMT solveurs prennent en entrée un énoncé mathématique mais cette fois essayent aussi de trouver une preuve (voir un contre-exemple). La contre-partie
c’est que trouver la preuve d’un énoncé peut prendre beaucoup plus de temps
que les procédures de décision que l’on trouve dans un SMT solveur.
Les assistants de preuve : ce sont des outils qui comme les démonstrateurs
automatiques construisent des preuves mais non plus de façon automatique mais
en interagissant avec un utilisateur. On ne peut pas attendre (en tout cas
aujourd’hui) des démonstrateurs automatiques de trouver des preuves de gros
théorèmes (petit théorème de Fermat, théorème de Feit-Thompson, théorème de
Fermat-Wiles). Heureusement, il est cependant possible d’écrire cette preuve
formellement et d’avoir un outil qui vérifie si la preuve est correct. C’est ce
qu’on étudiera dans la seconde partie de ce projet.
La programmation logique : c’est un autre paradigme de programmation
qui est très intéressant car il contient intrinsèquement du non-déterminisme.
Autrement dit, on a gratuitement un algorithme qui permet de faire du backtracking (ce dont on avait besoin pour le solveur du projet Fling par exemple).
Ce paradigme permet ainsi d’écrire en très peu de code des solveurs basiques
pour de nombreux problèmes (notamment tous les problèmes logiques comme
le sudoku, les dérivés de carrés latins, ...). Mais il est aussi utilisé en bioinformatique ou bien en traitement automatique de la langue. C’est ce qu’on
verra dans la dernière partie de ce cours.
2
2
Description du projet
Cette partie s’intéresse aux SAT solveurs. Un SAT solveur est un outil qui
prend en entrée une formule exprimée en logique propositionnelle et renvoie une
réponse :
• SAT si la formule est satisfiable (accompagné généralement d’un environnement qui satisfasse la formule)
• UNSAT si la formule est insatisfiable (parfois avec une trace de preuve)
Ce projet va se découper en trois phases:
• Implémenter une procédure de décision correcte et complète (DPLL) pour
le problème
• Tester cette implémentation sur un ou plusieurs problèmes
• Comparer les performances avec les outils actuellement sur le marché
3
Consignes
Pour ce projet, le langage n’est pas imposé. Par contre, si vous souhaitez utiliser
un autre langage qu’Ocaml, prévenez-moi avant afin que je donne mon aval.
Cependant, je vous recommande d’utiliser Ocaml qui est tout à fait adapté pour
ce projet. Le sujet est volontairement succint et peu détaillé afin que vous soyez
un maximum libre dans vos choix.
4
Un solveur naïf
Avant d’implémenter l’algorithme DPLL, je vous conseille d’abord de faire un
solveur très naïf afin de se mettre en jambe. Ce dernier pour résoudre une
formule propositionnelle portant sur un ensemble de variables X va énumérer
toutes les fonctions possibles de X 7→ B tant qu’il n’a pas trouvé un modèle.
Ce solveur s’avèrera très vite inefficace mais il pourra être utile pour déboguer
DPLL ainsi que pour faire des comparaisons dans la dernière partie. Cependant,
je vous conseille de ne pas passer plus d’une séance sur ce solveur, c’est juste
histoire de s’échauffer un peu.
Bonus: Si vous cherchez un peu de challenge, je vous invite à implémenter
ce solveur avec seulement des fonctions récursives terminales (et évidemment de
façon purement fonctionnelle).
En testant rapidement le solveur naïf, on se rend compte qu’il n’est pas
possible d’aller très loin. On va donc maintenant voir comment implémenter un
algorithme un peu plus malin que le solveur précédent.
3
5
Vers un solveur un peu plus malin : DPLL
L’algorithme DPLL2 a été publié pour la première fois en 1962 et reste un élément essentiel dans les implémentations des SAT-solveurs aujourd’hui. L’efficacité
de cet algorithme repose sur trois critères simples appliqués aux formules en
forme normale conjonctive3 . Ces critères sont :
• Si la formule cnf contient une clause vide, alors la formule est insatisfiable
• Si la formule cnf contient une clause contenant un unique littéral, alors la
valeur de ce littéral est déterminée pour la suite de la recherche
• Si la formule cnf contient une variable qui apparait uniquement positivement ou uniquement négativement, alors on peut supprimer toutes les
clauses où cette variable apparaît.
Si aucun de ces critères n’est applicable, il faut revenir à une méthode naïve.
Pour cela l’algorithme est paramétré par une méthode choose_variable qui
choisit une variable sur laquelle on branche:
• Premier cas on met la valeur de cette variable à true et on simplifie selon
les critères ci-dessus
• De même, en mettant la valeur de la variable à false
A vous de jouer maintenant. Si vous souhaitez tester votre programme,
je vous conseille d’implémenter le format DIMACS4 . Vous trouverez pléthore
d’exemples dans ce format.
6
Transformer un problème en une formule propositionnelle
Dans le monde académique, afin de tester la rapidité des solveurs SAT, il existe
des concours pour comparer les meilleurs solveurs existants. Cependant, avec
notre algorithme très simple on n’ira pas très loin dans ce genre de concours.
Je vous propose donc dans cette partie de créer d’autres exemples afin de comparer vos solveurs. Pour cela on va prendre des problèmes logiques que l’on va
transformer en une formule propositionnelle de telle sorte que le problème a une
solution si et seulement si la formule propositionnelle est satisfiable. Je vous
propose dans cette partie plusieurs idées de problèmes qui peuvent être intéressants à regarder. Je vous demande d’en implémenter un. L’idéal, serait que
vous vous répartissiez les problèmes afin que l’on puisse comparer les résultats
à la fin. Les étoiles sont une indication du temps à y passer.
• Eternity II (***,*,-)
2 https://en.wikipedia.org/wiki/DPLL_algorithm
3 https://en.wikipedia.org/wiki/Conjunctive_normal_form
4 http://people.sc.fsu.edu/~jburkardt/data/cnf/cnf.html
4
• Sudoku (*,*,**)
• Démineur (*,*,-)
• Picross (***,*,**)
• Alcazar (***,**,**)
• Towers (*,*,-)
• Loopy (**,**,**)
• Tents (**,*,**)
• Tracks (**,**,**)
Pour chacun de ces problèmes, il y a deux tâches à faire plus une optionnelle
(bonus) :
• Encoder le problème vers une formule SAT
• Générer aléatoirement des instances du problème (cela peut nécessiter la
partie une)
• Vérifier l’unicité de la solution
Les étoiles indiquent la difficulté (ou plutôt) le temps nécessaire que j’estime
pour chacune de ces trois tâches. Ce n’est qu’une idée car je n’ai pas implémenté
tous ces problèmes. Evidemment, si vous vous attaquez à des problèmes plus
compliqués, cela influera positivement sur votre note (si vous arrivez à la fin).
7
Benchmark
Lorsqu’on a implémenté DPLL, on a vu qu’on pouvait paramétriser l’algorithme
par le choix d’une variable. Il serait intéressant que vous implémentiez plusieurs
choix5 afin de voir les différences :
• littéral le plus présent
• littéral le plus présent dans une clause minimale
• UP/GUP/SUP
• JW rule
Pour ces différents algorithmes + l’algorithme naïf, je vous demande de faire
tourner vos programmes sur les exemples générés à la partie 2 et de faire une
comparaison (idéalement dans un tableau). N’hésitez-pas à laisser des commentaires pour expliquer ce que vous observez si vous le pouvez. N’hésitez-pas non
plus à comparer vos solveurs. Cependant, ceci est pertinent seulement si vous
utilisez le même langage et le même compilateur.
5 https://www.cs.ubc.ca/~hutter/EARG.shtml/earg/papers07/lagoudakis01learning.
pdf
5
Téléchargement