• Aucun résultat trouvé

4.2 Optimisations

4.2.3 Instantiation efficace

Il est tout à fait concevable d’utiliser les mécanismes d’instantiation de quantificateurs internes aux solveurs SMT pour décharger les tests de points fixes. Traditionnellement, ces solveurs utilisent des déclencheurs pour filtrer les formules closes du contexte et obtenir des substitutions des variables quantifiées vers des termes clos. Ce filtrage est réalisé modulo la théorie de l’égalité libre [125] et chaque tour d’instantiation peut générer des termes de plus en plus gros et des instances de plus en plus nombreuses. Bien que ce mécanisme soit contrôlé par des stratégies limitant les instances possibles et des heuristiques favorisant certains termes pour le filtrage, cette technique d’instantiation reste incomplète et souvent peu efficace. Elle peut toutefois donner des résultats intéressants sur des problèmes dont le contexte (souvent composé d’axiomes avec quantificateurs universels) n’est pas trop important. C’est le cas par exemple des obligations de preuves venant de la vérification déductive de programmes. En revanche, les problèmes qui constituent nos tests de points fixes contiennent souvent plusieurs milliers de formules quantifiées ce qui en fait des candidats difficiles même pour les solveurs les plus modernes.

Il existe des théories axiomatiques pour lesquelles il est possible de calculer les dé-clencheurs des axiomes de façon à rendre l’instantiation par filtrage complète [60]. La preuve de complétude de la théorie devant être effectuée à chaque nouvelle théorie, il n’est pas possible de calculer automatiquement les déclencheurs pour chaque point fixe dans notre cas. Certains solveurs SMT comme Z3 utilisent une forme d’instantiation à partir de modèles [73] en complément des techniques classiques à déclencheurs. Cette approche permet de rendre le solveur plus complet mais n’améliore pas ses performances sur les exemples où le filtrage est suffisant.

Le principal problème rencontré dans Cubicle est en réalité l’efficacité des procédures d’instantiation. En effet, la restriction imposée sur les théories supportées par le model checker et la forme particulière des tests logiques nous permet de connaître toutes les instances à faire, grâce à l’algorithme 5 par exemple. Comme montré précédemment, c’est leur nombre qui devient rapidement rédhibitoire. On explique ici comment restreindre ce nombre de manière dramatique pour n’envoyer au solveur que les instances qui lui seront potentiellement utiles.

4.2 Optimisations insatisfiable : ∆(#i) ∧ F (#i) ∧ ^ 0≤k≤|V | ^ σ ∈Σk ¬(∆(jk)σ ∧ (Fk)σ )

Pour réaliser ce test le plus efficacement possible il faut trouver quel est l’ensemble des instances des formules de V qui contredit ∆(#i) ∧ F (#i). En général si on sait que pour deux formules F et G, F ∧ G est insatisifiable, alors la formule F ∧ ¬G est satisfiable ssi F est satisfiable. Intuitivement, G n’apporte rien pour montrer l’insatisfiabilité de F ∧ ¬G ∧ . . .. Dans notre cas, l’instance σ : {jk} 7→ {#i}n’est pas utile si ∆(#i) ∧ F (#i) ∧ ¬(∆(jk)σ ∧ (Fk)σ ) est insatisfiable.

F et Fk sont des conjonctions de littéraux F = l1∧ . . . ∧ln, Fk = k1∧ . . . ∧km. Sans perte de généralité on peut supposer que F et Fk sont chacune cohérentes de leur côté. Il suffit alors que deux littéraux li∧kj soient insatisfiables pour rendre ∆ ∧ F ∧ ∆ ∧ Fk insatisfiables. De plus, lorsque deux littéraux li∧kj sont insatisfiables, un test syntaxique permet souvent de détecter cette insatisfiabilité. Par exemple, si li ≡ x (#1) = 1 et que kj ≡ x (#1) , 1, syntaxiquement li = ¬kj. Dans d’autres cas, un raisonnement simple modulo théorie est aussi possible et très peu coûteux. Par exemple, si li ≡ x (#1) = 1 et que kj ≡ x (#1) = 2, comme la théorie de l’arithmétique nous dit que 1 , 2 on peut trivialement déduire par simple transitivité de l’égalité que li∧kj est insatisfiable.

Ces premiers tests simples sur les littéraux des cubes instantiés nous permettent d’en éliminer une bonne partie. On doit tout de même, pour chaque cube de V, construire toutes ses instances en appliquant les substitutions correspondantes. Cette opération est coûteuse car créer une instance demande d’allouer de la mémoire. En réalité, il est possible de faire ces tests avant même de construire les instances. Pour chaque cube ∃jk.∆(jk) ∧ Fk, on peut à moindre coût calculer l’ensemble Σ

k ⊆ Σk des substitutions correspondant aux instances potentiellement utiles pour le test de satisfiabilité qui nous intéresse. Pour cela, on calcule la substitution (partielle) obligatoire, et l’ensemble des substitutions impossibles.

On note Obvk la permutation obligatoire. S’il existe une variable globale x telle que le littéral x = #iapparaît dans F et x = j dans Fk alors (j 7→ #i) ∈ Obvk.

On note Imposk l’ensemble des substitutions impossibles. Soit un symbole A d’arité non nulle p, une constante C (constructeur d’un type énuméré, constante entière, . . . ) et une variable globale x. Le tableau suivant donne les conditions pour que {j

1 7→ #

1, . . . ,jp 7→ #

littéral apparaît dans Fk littéral apparaît dans F conditions A(j1, . . . ,jp) = t A(#1, . . . ,# p) , t ou A(# 1, . . . ,# p) < t ou A(# 1, . . . ,# p) > t

quelque soit le terme t A(j1, . . . ,jp) , t ou A(j 1, . . . ,jp) < t ou A(j 1, . . . ,jp) > t A(#1, . . . ,#

p) = t quelque soit le terme t

A(j1, . . . ,jp) = C1 A(#1, . . . ,# p) = C2

C1 ,C2

et C1 et C2 sont des constantes (construc-teurs d’un type énuméré, constantes entières, . . . )

On définit ensuite l’ensemble des substitutions intéressantes :

Σk =       σ ∈ Σk ∀j 7→ # ∈ Obvk. j 7→ #∈Obvk =⇒ # = # Obvk ⊆σ ∀σI ∈ImposkI *Obvk ∀σI ∈ImposkI *σ      

Remarque. On détecte aussi les incohérences triviales entre les littéraux qui n’ont aucune variable quantifiée. Si pour un cube de V, ∃jk.∆(jk) ∧ Fk avec jk non vide, alors lorsque Σk est vide cela signifie qu’aucune instance de ce cube n’est intéressante. Ce cube ne sera donc même pas considéré dans le test de point fixe.

L’ensemble des substitutions intéressantes Σ

k est calculé par la fonction relevant du moduleInstantiationde la figure 4.1. La satisfiabilité de la formule du test de point fixe est équivalente à celle-ci : ∆(#i) ∧ F (#i) ∧ ^ 0≤k≤|V | ^ σ ∈Σk ¬(∆(jk)σ ∧ (Fk)σ )

De cette façon on envoie au solveur SMT seulement les instances des cubes de V qui seront potentiellement utiles pour décharger le test de point fixe. On applique également un raisonnement similaire pour découvrir immédiatement parmi ces instances, s’il en existe une qui est trivialement impliquée par le cube considéré.

Remarque. Une technique d’instantiation similaire est utilisée dans mcmt [76]. Les auteurs appellent cette technique un « filtrage modulo types énumérés ». D’autres heuristiques sont également mises en œuvre dans mcmt mais pas par Cubicle. Par exemple leur test de