Interpolation and Symbol Elimination Note: special thanks are to Laura Kovacs who contributed both to the work described in this page and the page content. Vampire implements two new features: interpolation and symbol elimination
described in the following papers. Both features have been implemented using colored symbols and colored formulas,
explained below. Interpolation In the original definition of Craig, an interpolant of
two formulas L and R is any
formula I such that - both ⊨ L ⊃ I
and ⊨ I ⊃ R (that is,
I is implied by L
and implies R).
- Every symbol occurring in I also occurs both in
L and R.
Craig proved that, if R is implied by
L, then such an interpolant exists. However, for applications in verification and invariant generation this definition
is too restrictive. Firstly, we are normally interested in reasoning modulo a theory
T (for simplicity we assume that a
theory any set of formulas).
Secondly, we may allow theory symbols and some other symbols occur in the
interpolant. We capture this more general notion of interpolant by using logical consequence
modulo theory and by coloring symbols. We assume to have
two colors, the left
and the right color. Some symbols may be colored in
left and some in right (but
not in both), and some symbols may be transparent, that is,
have no color. We assume the following properties: - symbols colored in left may only occur in
L;
- symbols colored in right may only occur in
R;
- all symbols occurring in the theory are transparent
We call an interpolant of L and
R any formula I such that - both ⊨T L ⊃ I
and ⊨T I ⊃ R.
- I is transparent, that is, consists only of transparent
symbols.
It is easy to see that an interpolant in the sense of Craig is captured by this
definition: to this end make the theory empty, color all symbols occurring in
L in left and all symbols
occurring in R in right. There is a similar notion of reverse interpolant
of L: it is any formula I such that - both ⊨T L ⊃ I
and ⊨T I & R ⊃ ⊥.
- I is transparent, that is, consists only of transparent
symbols.
Closely related to our definitions is a concept of a
well-colored derivation: this is a derivation in which no
inference contains clauses of both colors. Paper [2] gives an algorithm for building
an interpolant of L and R
from a well-colored proof of L ⊃ R. Vampire implements
well-colored proofs and generation of interpolants from such proofs. To make Vampire generate a well-colored proof and compute an interpolant we should
be able to define the following: - symbol colors
- which part of the input relates respectively to L,
R, and the theory T.
Example 1 The following examples shows how we can request Vampire generate well-colored
proofs and interpolants using Vampire-specific extensions
to the TPTP syntax. In this example we ask Vampire to generate an interpolant for
q(f(a)) & ¬q(f(b)) ⊃ ∃v(v ≠ c).
We use TPTP comments (beginning with the symbol
"") to explain the input. vampire(option,show_interpolant,on).
vampire(symbol,predicate,q,1,left). vampire(symbol,function,f,1,left). vampire(symbol,function,a,0,left). vampire(symbol,function,b,0,left). vampire(symbol,function,c,0,right).
vampire(left_formula). fof(fA,axiom, q(f(a)) & ~q(f(b)) ). vampire(end_formula).
vampire(right_formula). fof(fB,conjecture, ?[V]: V != c). vampire(end_formula).
Vampire outputs the following: 17. $false (2:0) [resolution 16,5] 5. q(f(a)) (0:3) [CNF transformation 3] 16. ~q(f(X0)) (2:3) [superposition 6,8] 8. X0 = X1 (1:3) [superposition 7,7] 7. c = X0 (0:3) [CNF transformation 4] 6. ~q(f(b)) (0:3) [CNF transformation 3] 4. ! [X0] : c = X0 [ennf transformation 2] 2. ~? [X0] : c != X0 [negated conjecture] 3. q(f(a)) & ~q(f(b)) [ennf transformation 1] 1. q(f(a)) & ~q(f(b)) [input] Interpolant: ~! [X1,X0] : X0 = X1 That is, it finds the interpolant
¬∀x∀y(x=y).
Note that if we remove color declarations from the input, then Vampire
will generate a different refutation: fof(fA,axiom, q(f(a)) & ~q(f(b)) ). fof(fB,conjecture, ?[V]: V != c). 10. $false (0:0) [subsumption resolution 9,8] 8. q(c) (0:2) [forward demodulation 5,7] 7. c = X0 (0:3) [CNF transformation 4] 5. q(f(a)) (0:3) [CNF transformation 3] 9. ~q(c) (0:2) [forward demodulation 6,7] 6. ~q(f(b)) (0:3) [CNF transformation 3] 3. q(f(a)) & ~q(f(b)) [ennf transformation 1] 1. q(f(a)) & ~q(f(b)) [input] 4. ! [X0] : c = X0 [ennf transformation 2] 2. ~? [X0] : c != X0 [negated conjecture] Example 2 This example uses a theory: a simple axiomatisation of arithmetic with the greater-than
relation greater and successor function s. Essentially, in this example
L is q ≥ c ≥ p & f(c)=1
and R is p ≥ d ≥ q & f(d)=0 vampire(option,show_interpolant,on).
vampire(symbol,function,c,0,left). vampire(symbol,function,d,0,right).
fof(greater1,axiom, greater(s(X),X)). fof(greater2,axiom, greater(X,Y) => X != Y). fof(greater3,axiom, ~greater(X,Y) => (greater(Y,X) | X = Y) ). fof(greater_transitive1,axiom, greater(X,Y) & greater(Y,Z) => greater(X,Z)). fof(greater_transitive2,axiom, ~greater(X,Y) & ~greater(Y,Z) => ~greater(X,Z)).
vampire(left_formula). fof(fA,hypothesis, ~greater(p,c) & ~greater(c,q) & f(c) = s(zero) ). vampire(end_formula).
vampire(right_formula). fof(fB,hypothesis, ~greater(q,d) & ~greater(d,p) & f(d) = zero ). vampire(end_formula).
Vampire generates the following interpolant. (~greater(p,q) | ~greater(p,q)) & (~greater(p,q) | ~greater(p,q)) & (~greater(p,q) | ~greater(p,q)) & (~greater(p,q) | ~greater(p,q)) & (greater(q,p) | s(zero) = f(p)) & (~greater(p,q) | ~greater(p,q)) & (~greater(p,q) | ~greater(p,q)) & (~greater(p,q) | ~greater(p,q)) & (~greater(p,q) | ~greater(p,q)) & (greater(q,p) | s(zero) = f(p)) & (~greater(p,q) | ~greater(p,q)) & (~greater(p,q) | ~greater(p,q)) & (~greater(p,q) | ~greater(p,q)) & (~greater(p,q) | ~greater(p,q)) & (greater(q,p) | s(zero) = f(p)) This interpolant is equivalent to the formula
q ≥ p & f(p)=1. More Examples More examples on computing interpolants with Vampire can be found here. Each example is given in the TPTP syntax, and hence can be
immediately fed into Vampire. Symbol Elimination Symbol elimination can be used to generate loop invariants automatically, as described
in paper [1]. The idea of invariant generation is as follows. - We generate loop properties using a language that contains program variables
and some additional symbols. These symbols are required to express loop properties
that are not expressible using loop variables. For example, we may introduce
the loop counter as an additional constant.
- We run a saturation theorem prover to eliminate the extra symbols. That is,
the prover should generate consequences of the initial formulas not containing
extra symbols. These consequences are loop invariants.
To make Vampire eliminate symbols, we run it in the
symbol-eliminating mode. We declare the symbols to be
eliminated colored. For the
purpose of symbol elimination, a single color is sufficient. Here is an example
showing how to make Vampire eliminate symbols.
vampire(option,show_symbol_elimination,on).
vampire(option,naming,32000). vampire(option,splitting,off). vampire(option,time_limit,10).
vampire(symbol,function,n,0,left). vampire(symbol,function,b,1,left). vampire(symbol,function,a,1,left). vampire(symbol,function,aa,2,left). vampire(symbol,predicate,updA,2,left). vampire(symbol,predicate,updA,3,left). vampire(symbol,predicate,iter,1,left).
vampire(symbol,predicate,geq,2,skip). vampire(symbol,predicate,greater,2,skip). vampire(symbol,function,s,1,skip). vampire(symbol,function,zero,0,skip). vampire(symbol,function,a,0,skip). vampire(symbol,function,b,0,skip). vampire(symbol,function,m,0,skip).
fof(geq1,axiom, geq(X,Y) <=> greater(X,Y) | X = Y). fof(geq2,axiom, greater(X,Y) => X != Y). fof(geq_transitive,axiom, geq(X,Y) & geq(Y,Z) => geq(X,Z)). fof(greater1,axiom, greater(s(X),X)). fof(greater2,axiom, geq(X,s(Y)) <=> greater(X,Y)). fof(recurrence1,hypothesis, a(I) = I). fof(recurrence2,hypothesis, b(I) = I). fof(recurrence3,hypothesis, geq(m,b) | greater(zero,m)). fof(poly,hypothesis, a = b). fof(recurrence3,hypothesis, geq(a,zero)). fof(recurrence4,hypothesis, geq(b,zero)). fof(recurrence5,hypothesis, geq(m,b)). fof(recurrence6,hypothesis, geq(m,a)). fof(ini_a,hypothesis, a(zero) = zero). fof(ini_b,hypothesis, b(zero) = zero). fof(final_a,hypothesis, a(n) = a). fof(final_b,hypothesis, b(n) = b). fof(ini_aa,hypothesis, aa(zero) = aa0). fof(final_aa,hypothesis, aa(n,P) = aa(P)). fof(def_update_predicate_A1,hypothesis, updA(I,P) <=> (iter(I) & P = a(I) & greater(m,b(I)))). fof(def_update_predicate_A2,hypothesis, updA(I,P,V) <=> (iter(I) & P = a(I) & greater(m,b(I)) & V = bb(b(I))) ). fof(stability_A,hypothesis, ! [I] : (iter(I) => ~updA(I,P)) => aa(P) = aa0(P)). fof(last_update_A,hypothesis, updA(I,P,V) & ! [J] : (greater(J,I) => ~updA(J,P)) => aa(P) = V). fof(iter_definition,axiom, ! [I] : (iter(I) <=> ( geq(I,zero) & greater(n,I) ))). fof(gas,hypothesis, ! [I] : (iter(I) & greater(m,b(I))) => (aa(s(I),a(I)) = bb(b(I)) & a(s(I)) = s(a(I)) & b(s(I)) = s(b(I)) )).
More Examples More examples on symbol elimination with Vampire can be found here. For each example, we list its source code (in C), its encoding in TPTP,
the obtained set of symbol eliminating inferences, and a minimised
set of symbol eliminating inferences. |