Files
why3/examples/prover/FormulaTransformations.mlw
2023-11-23 19:04:11 +01:00

1468 lines
67 KiB
Plaintext

module Types
use Firstorder_formula_impl.Types
use Firstorder_formula_list_impl.Types
use Firstorder_term_impl.Types
use list.List
use Functions.Func
use Firstorder_semantics.Sem
(* ghost field: explicitly to get rid of the existential. *)
type skolemization_return 'st = {
skolemized : nlimpl_fo_formula ;
skolem_bound : int ;
free_var_list : list int ;
ghost model_transformer : (model int 'st) -> (model int 'st) ;
}
type skolemization_list_return 'st = {
skolemized_l : nlimpl_fo_formula_list ;
skolem_bound_l : int ;
ghost model_transformer_l : (model int 'st) -> (model int 'st) ;
}
type skolemization_env_return 'st = {
skolemized_fv_list : nlimpl_fo_term_list ;
ghost skolem_env : (list 'st) -> (int -> 'st) ;
}
end
module Logic
use Firstorder_formula_spec.Spec
use Firstorder_term_spec.Spec
use Firstorder_symbol_spec.Spec
use Firstorder_formula_list_spec.Spec
use Functions.Func
use option.Option
use OptionFuncs.Funcs
predicate is_atom (phi:fo_formula 'ls 'b) = match phi with
| PApp _ _ -> true
| Not (PApp _ _) -> true
| _ -> false
end
(* Negational normal form. *)
predicate is_nnf (phi:fo_formula 'ls 'b) = match phi with
| Not (PApp _ _) -> true
| Not _ -> false
| PApp _ _ -> true
| And a b -> is_nnf a /\ is_nnf b
| Or a b -> is_nnf a /\ is_nnf b
| Forall a -> is_nnf a
| Exists a -> is_nnf a
| FTrue -> true
| FFalse -> true
end
predicate is_nnf_list (phis:fo_formula_list 'ls 'b) = match phis with
| FOFNil -> true
| FOFCons x q -> is_nnf x /\ is_nnf_list q
end
let rec lemma is_nnf_subst (phi:fo_formula 'ls 'b) (f:'b -> (fo_term 'ls 'c)) : unit
requires { is_nnf phi }
ensures { is_nnf (subst_fo_formula phi subst_id_symbol f) }
variant { size_fo_formula phi }
=
match phi with
| Not (PApp p l) -> assert {
subst_fo_formula phi subst_id_symbol f =
Not (subst_fo_formula (PApp p l) subst_id_symbol f) =
Not (PApp (subst_symbol p subst_id_symbol)
(subst_fo_term_list l subst_id_symbol f)) }
| Not _ -> absurd
| PApp _ _ -> ()
| And a b -> is_nnf_subst a f ; is_nnf_subst b f
| Or a b -> is_nnf_subst a f ; is_nnf_subst b f
| Forall a -> is_nnf_subst a (olifts_fo_term f) ;
assert { subst_fo_formula phi subst_id_symbol f =
Forall (subst_fo_formula a subst_id_symbol (olifts_fo_term f)) }
| Exists a -> is_nnf_subst a (olifts_fo_term f) ;
assert { subst_fo_formula phi subst_id_symbol f =
Exists (subst_fo_formula a subst_id_symbol (olifts_fo_term f)) }
| FTrue -> ()
| FFalse -> ()
end
let lemma is_nnf_renaming (phi:fo_formula 'ls 'b) (f:'b -> 'c) : unit
requires { is_nnf phi }
ensures { is_nnf (rename_fo_formula phi identity f) }
=
is_nnf_subst phi (rcompose f subst_id_fo_term)
(* Simplified formula. *)
predicate is_simpl (phi:fo_formula 'ls 'b) = match phi with
| Not u -> is_simpl u
| PApp _ _ -> true
| And a b -> is_simpl a /\ is_simpl b
| Or a b -> is_simpl a /\ is_simpl b
| Forall a -> is_simpl a
| Exists a -> is_simpl a
| FTrue -> false
| FFalse -> false
end
predicate is_simpl_list (phis:fo_formula_list 'ls 'b) = match phis with
| FOFNil -> true
| FOFCons x q -> is_simpl x /\ is_simpl_list q
end
let rec lemma is_simpl_subst (phi:fo_formula 'ls 'b) (f:'b -> (fo_term 'ls 'c)) : unit
requires { is_simpl phi }
ensures { is_simpl (subst_fo_formula phi subst_id_symbol f) }
variant { size_fo_formula phi }
=
match phi with
| Not u -> is_simpl_subst u f ;
assert { subst_fo_formula phi subst_id_symbol f =
Not (subst_fo_formula u subst_id_symbol f) }
| PApp _ _ -> ()
| And a b -> is_simpl_subst a f ; is_simpl_subst b f
| Or a b -> is_simpl_subst a f ; is_simpl_subst b f
| Forall a -> is_simpl_subst a (olifts_fo_term f) ;
assert { subst_fo_formula phi subst_id_symbol f =
Forall (subst_fo_formula a subst_id_symbol (olifts_fo_term f)) }
| Exists a -> is_simpl_subst a (olifts_fo_term f) ;
assert { subst_fo_formula phi subst_id_symbol f =
Exists (subst_fo_formula a subst_id_symbol (olifts_fo_term f)) }
| FTrue -> absurd
| FFalse -> absurd
end
let lemma is_simpl_renaming (phi:fo_formula 'ls 'b) (f:'b -> 'c) : unit
requires { is_simpl phi }
ensures { is_simpl (rename_fo_formula phi identity f) }
=
is_simpl_subst phi (rcompose f subst_id_fo_term)
(* Simplified formula, + true/false allowed at top. *)
predicate is_simpl_extended (phi:fo_formula 'ls 'b) =
is_simpl phi \/ phi = FTrue \/ phi = FFalse
lemma is_simpl_extended_renaming :
forall phi:fo_formula 'ls 'b,f:'b -> 'c.
is_simpl_extended phi -> is_simpl_extended (rename_fo_formula phi identity f)
predicate no_existential (phi:fo_formula 'ls 'b) = match phi with
| Not u -> no_existential u
| PApp _ _ -> true
| And a b -> no_existential a /\ no_existential b
| Or a b -> no_existential a /\ no_existential b
| Forall a -> no_existential a
| Exists _ -> false
| FTrue -> true
| FFalse -> true
end
predicate no_existential_list (phis:fo_formula_list 'ls 'b) = match phis with
| FOFNil -> true
| FOFCons x q -> no_existential x /\ no_existential_list q
end
let rec lemma no_existential_subst (phi:fo_formula 'ls 'b) (f:'b -> (fo_term 'ls 'c)) : unit
requires { no_existential phi }
ensures { no_existential (subst_fo_formula phi subst_id_symbol f) }
variant { size_fo_formula phi }
=
match phi with
| Not u -> no_existential_subst u f ;
assert { subst_fo_formula phi subst_id_symbol f =
Not (subst_fo_formula u subst_id_symbol f) }
| PApp _ _ -> ()
| And a b -> no_existential_subst a f ; no_existential_subst b f
| Or a b -> no_existential_subst a f ; no_existential_subst b f
| Forall a -> no_existential_subst a (olifts_fo_term f) ;
assert { subst_fo_formula phi subst_id_symbol f =
Forall (subst_fo_formula a subst_id_symbol (olifts_fo_term f)) }
| Exists _ -> absurd
| FTrue -> ()
| FFalse -> ()
end
let lemma no_existential_renaming (phi:fo_formula 'ls 'b) (f:'b -> 'c) : unit
requires { no_existential phi }
ensures { no_existential (rename_fo_formula phi identity f) }
=
no_existential_subst phi (rcompose f subst_id_fo_term)
(* Skolemization environment. *)
use Choice.Choice
use list.List
(* Hack to force possibility of instantiation of extend_env
definition axiom ! *)
function extend_env_selection (g:(list 'st) -> ('b -> 'st))
(x:'b) (y:'b) (z:'st) (q:list 'st) : 'st = if x = y then z else g q x
(* Abstraction-definition axiom :
function extend_env (g:(list 'st) -> ('b -> 'st) (y:'b) :
(list 'st) -> ('b -> 'st) =
(\ l:list 'st. (\ x:option 'b. match l with
| Cons z q -> extend_env_selection g x y z q
| Nil -> default ) ) *)
function extend_env (g:(list 'st) -> ('b -> 'st)) (y:'b) :
(list 'st) -> ('b -> 'st)
axiom extend_env_def : forall g:(list 'st) -> ('b -> 'st),y:'b,
l:list 'st,x:'b. extend_env g y l x =
match l with
| Cons z q -> extend_env_selection g x y z q
| Nil -> default
end
end
module Impl
use Types
use Logic
use Functions.Func
use import set.Set as S
use Firstorder_formula_spec.Spec
use Firstorder_formula_impl.Types
use Firstorder_formula_impl.Logic
use Firstorder_formula_impl.Impl
use Firstorder_formula_list_spec.Spec
use Firstorder_formula_list_impl.Impl
use Firstorder_formula_list_impl.Logic
use Firstorder_formula_list_impl.Types
use Firstorder_term_spec.Spec
use Firstorder_term_impl.Impl
use Firstorder_term_impl.Logic
use Firstorder_term_impl.Types
use Firstorder_symbol_spec.Spec
use Firstorder_symbol_impl.Impl
use Firstorder_symbol_impl.Logic
use Firstorder_symbol_impl.Types
use list.List
use option.Option
use OptionFuncs.Funcs
use Firstorder_semantics.Sem
use bool.Bool
use list.Mem
use int.Int
exception Unsat
let smart_and (phi1 phi2:nlimpl_fo_formula) (ghost fvp:set int) (ghost st:'st) : nlimpl_fo_formula
requires { nlimpl_fo_formula_ok phi1 }
requires { forall x:int. is_fo_term_free_var_in_fo_formula x
phi1.model_fo_formula_field -> S.mem x fvp }
requires { nlimpl_fo_formula_ok phi2 }
requires { forall x:int. is_fo_term_free_var_in_fo_formula x
phi2.model_fo_formula_field -> S.mem x fvp }
requires { is_simpl_extended phi1.model_fo_formula_field }
requires { is_simpl_extended phi2.model_fo_formula_field }
ensures { is_simpl_extended result.model_fo_formula_field }
ensures { forall m:model int 'st,rho:int -> 'st.
formula_semantic result.model_fo_formula_field m rho <->
formula_semantic phi1.model_fo_formula_field m rho /\
formula_semantic phi2.model_fo_formula_field m rho }
ensures { is_nnf phi1.model_fo_formula_field /\
is_nnf phi2.model_fo_formula_field ->
is_nnf result.model_fo_formula_field }
ensures { nlimpl_fo_formula_ok result }
ensures { forall x:int. is_fo_term_free_var_in_fo_formula x
result.model_fo_formula_field -> S.mem x fvp }
=
let phi1m = phi1.model_fo_formula_field in
let phi2m = phi2.model_fo_formula_field in
match destruct_fo_formula phi1 with
| NLC_FFalse -> phi1
| NLC_FTrue -> phi2
| _ -> assert { phi1m <> FTrue } ; assert { phi1m <> FFalse } ;
match destruct_fo_formula phi2 with
| NLC_FFalse -> phi2
| NLC_FTrue -> phi1
| _ -> assert { phi2m <> FTrue } ; assert { phi2m <> FFalse } ;
assert { is_simpl phi1m /\ is_simpl phi2m } ;
let phi0 = construct_fo_formula (NLC_And phi1 phi2) in
assert { phi0.model_fo_formula_field = And phi1m phi2m } ;
phi0
end
end
let smart_or (phi1 phi2:nlimpl_fo_formula) (ghost fvp:set int) (ghost st:'st) : nlimpl_fo_formula
requires { nlimpl_fo_formula_ok phi1 }
requires { forall x:int. is_fo_term_free_var_in_fo_formula x
phi1.model_fo_formula_field -> S.mem x fvp }
requires { nlimpl_fo_formula_ok phi2 }
requires { forall x:int. is_fo_term_free_var_in_fo_formula x
phi2.model_fo_formula_field -> S.mem x fvp }
requires { is_simpl_extended phi1.model_fo_formula_field }
requires { is_simpl_extended phi2.model_fo_formula_field }
ensures { is_simpl_extended result.model_fo_formula_field }
ensures { forall m:model int 'st,rho:int -> 'st.
formula_semantic result.model_fo_formula_field m rho <->
formula_semantic phi1.model_fo_formula_field m rho \/
formula_semantic phi2.model_fo_formula_field m rho }
ensures { is_nnf phi1.model_fo_formula_field /\
is_nnf phi2.model_fo_formula_field ->
is_nnf result.model_fo_formula_field }
ensures { nlimpl_fo_formula_ok result }
ensures { forall x:int. is_fo_term_free_var_in_fo_formula x
result.model_fo_formula_field -> S.mem x fvp }
=
let phi1m = phi1.model_fo_formula_field in
let phi2m = phi2.model_fo_formula_field in
match destruct_fo_formula phi1 with
| NLC_FTrue -> phi1
| NLC_FFalse -> phi2
| _ -> assert { phi1m <> FTrue } ; assert { phi1m <> FFalse } ;
match destruct_fo_formula phi2 with
| NLC_FTrue -> phi2
| NLC_FFalse -> phi1
| _ -> assert { phi2m <> FTrue } ; assert { phi2m <> FFalse } ;
assert { is_simpl phi1m /\ is_simpl phi2m } ;
let phi0 = construct_fo_formula (NLC_Or phi1 phi2) in
assert { phi0.model_fo_formula_field = Or phi1m phi2m } ;
phi0
end
end
let smart_forall (x:int) (phi:nlimpl_fo_formula) (ghost fvp:set int) (ghost st:'st) : nlimpl_fo_formula
requires { nlimpl_fo_formula_ok phi }
requires { forall y:int. is_fo_term_free_var_in_fo_formula y
phi.model_fo_formula_field -> S.mem y fvp \/ y = x }
requires { is_simpl_extended phi.model_fo_formula_field }
ensures { is_simpl_extended result.model_fo_formula_field }
ensures { forall m:model int 'st,rho:int -> 'st.
formula_semantic result.model_fo_formula_field m rho <->
(forall xm:'st.
let r = rcompose (some[x <- None]) (ocase rho xm) in
formula_semantic phi.model_fo_formula_field m r) }
ensures { is_nnf phi.model_fo_formula_field ->
is_nnf result.model_fo_formula_field }
ensures { nlimpl_fo_formula_ok result }
ensures { forall y:int. is_fo_term_free_var_in_fo_formula y
result.model_fo_formula_field -> S.mem y fvp }
=
let phim = phi.model_fo_formula_field in
match destruct_fo_formula phi with
| NLC_FFalse -> assert { phim = FFalse &&
forall m:model int 'st,rho:int -> 'st.
not(formula_semantic phim m rho) } ;
phi
| NLC_FTrue -> phi
| _ -> assert { phim <> FTrue /\ phim <> FFalse && is_simpl phim } ;
let phi0 = construct_fo_formula (NLC_Forall x phi) in
let phi0m = phi0.model_fo_formula_field in
let ghost phi1m = rename_fo_formula phim identity (some[x <- None]) in
assert { phi0m = Forall phi1m } ;
assert { forall xf:int.
(forall y:int. is_fo_term_free_var_in_fo_formula y phim /\
eval (some[x<-None]) y = Some xf -> y <> x &&
Some xf = Some y && xf = y) && is_fo_term_free_var_in_fo_formula xf phi0m ->
is_fo_term_free_var_in_fo_formula (Some xf) phi1m &&
(exists y:int. is_fo_term_free_var_in_fo_formula y phim /\
eval (some[x <- None]) y = Some xf) && is_fo_term_free_var_in_fo_formula xf phim
&& xf <> x && S.mem xf fvp } ;
phi0
end
let smart_exists (x:int) (phi:nlimpl_fo_formula) (ghost fvp:set int) (ghost st:'st) : nlimpl_fo_formula
requires { nlimpl_fo_formula_ok phi }
requires { forall y:int. is_fo_term_free_var_in_fo_formula y phi.model_fo_formula_field
-> S.mem y fvp \/ y = x }
requires { is_simpl_extended phi.model_fo_formula_field }
ensures { is_simpl_extended result.model_fo_formula_field }
ensures { forall m:model int 'st,rho:int -> 'st.
formula_semantic result.model_fo_formula_field m rho <->
(exists xm:'st.
let r = rcompose (some[x <- None]) (ocase rho xm) in
formula_semantic phi.model_fo_formula_field m r) }
ensures { is_nnf phi.model_fo_formula_field ->
is_nnf result.model_fo_formula_field }
ensures { nlimpl_fo_formula_ok result }
ensures { forall y:int. is_fo_term_free_var_in_fo_formula y result.model_fo_formula_field
-> S.mem y fvp }
=
let phim = phi.model_fo_formula_field in
match destruct_fo_formula phi with
| NLC_FFalse -> phi
| NLC_FTrue -> assert { phim = FTrue /\
forall m:model int 'st,rho:int -> 'st.
formula_semantic phim m rho } ;
phi
| _ -> assert { phim <> FTrue /\ phim <> FFalse && is_simpl phim } ;
let phi0 = construct_fo_formula (NLC_Exists x phi) in
let phi0m = phi0.model_fo_formula_field in
let ghost phi1m = rename_fo_formula phim identity (some[x <- None]) in
assert { phi0m = Exists phi1m } ;
assert { forall xf:int.
(forall y:int. is_fo_term_free_var_in_fo_formula y phim /\
eval (some[x<-None]) y = Some xf -> y <> x &&
Some xf = Some y && xf = y) && (is_fo_term_free_var_in_fo_formula xf phi0m ->
is_fo_term_free_var_in_fo_formula (Some xf) phi1m &&
(exists y:int. is_fo_term_free_var_in_fo_formula y phim /\
eval (some[x <- None]) y = Some xf) && is_fo_term_free_var_in_fo_formula xf phim
&& xf <> x && S.mem xf fvp) && (is_fo_term_free_var_in_fo_formula xf phi0m ->
S.mem xf fvp) } ;
phi0
end
(* Put in negational normal form and
simplify formula (e.g. true/false removal/propagation to toplevel) *)
let rec nnf_simpl (phi:nlimpl_fo_formula) (ghost fvp:set int) (ghost st:'st) : nlimpl_fo_formula
requires { nlimpl_fo_formula_ok phi }
requires { forall x:int.
is_fo_term_free_var_in_fo_formula x phi.model_fo_formula_field -> S.mem x fvp }
ensures { nlimpl_fo_formula_ok result }
ensures { forall x:int.
is_fo_term_free_var_in_fo_formula x result.model_fo_formula_field -> S.mem x fvp }
ensures { forall m:model int 'st, rho:int -> 'st.
formula_semantic phi.model_fo_formula_field m rho <->
formula_semantic result.model_fo_formula_field m rho }
ensures { is_nnf result.model_fo_formula_field }
ensures { is_simpl_extended result.model_fo_formula_field }
variant { size_fo_formula phi.model_fo_formula_field }
=
let phim = phi.model_fo_formula_field in
match destruct_fo_formula phi with
| NLC_PApp p l -> phi
| NLC_Not phi' -> assert { forall x:int.
is_fo_term_free_var_in_fo_formula x phi'.model_fo_formula_field ->
is_fo_term_free_var_in_fo_formula x phim && S.mem x fvp } ;
nnf_neg_simpl phi' fvp st
| NLC_And phi1 phi2 -> let phi'1 = nnf_simpl phi1 fvp st in
let phi'2 = nnf_simpl phi2 fvp st in
smart_and phi'1 phi'2 fvp st
| NLC_Or phi1 phi2 -> let phi'1 = nnf_simpl phi1 fvp st in
let phi'2 = nnf_simpl phi2 fvp st in
smart_or phi'1 phi'2 fvp st
| NLC_FTrue -> phi
| NLC_FFalse -> phi
| NLC_Forall x phi0 ->
let phi0m = phi0.model_fo_formula_field in
let ghost phi1m = rename_fo_formula phi0m identity (some[x<-None]) in
assert { phim = Forall phi1m } ;
assert { phi0m = rename_fo_formula phi1m identity (ocase identity x) };
let ghost fvp' = S.add x fvp in
assert { forall xf:int.
(forall y:option int. is_fo_term_free_var_in_fo_formula y phi1m /\
ocase identity x y = xf -> match y with None -> x = xf && S.mem xf fvp'
| Some y -> y = xf && is_fo_term_free_var_in_fo_formula y phim &&
S.mem xf fvp && S.mem xf fvp' end && S.mem xf fvp') &&
(is_fo_term_free_var_in_fo_formula xf phi0m ->
(exists y:option int. is_fo_term_free_var_in_fo_formula y phi1m /\
ocase identity x y = xf) && S.mem xf fvp') &&
(is_fo_term_free_var_in_fo_formula xf phi0m -> S.mem xf fvp') };
let phi' = nnf_simpl phi0 fvp' st in
let phi'' = smart_forall x phi' fvp st in
phi''
| NLC_Exists x phi0 ->
let phi0m = phi0.model_fo_formula_field in
let ghost phi1m = rename_fo_formula phi0m identity (some[x<-None]) in
assert { phim = Exists phi1m } ;
assert { phi0m = rename_fo_formula phi1m identity (ocase identity x) };
let ghost fvp' = S.add x fvp in
assert { forall xf:int.
(forall y:option int. is_fo_term_free_var_in_fo_formula y phi1m /\
ocase identity x y = xf -> match y with None -> x = xf && S.mem xf fvp'
| Some y -> y = xf && is_fo_term_free_var_in_fo_formula y phim &&
S.mem xf fvp && S.mem xf fvp' end && S.mem xf fvp') &&
(is_fo_term_free_var_in_fo_formula xf phi0m ->
(exists y:option int. is_fo_term_free_var_in_fo_formula y phi1m /\
ocase identity x y = xf) && S.mem xf fvp') &&
(is_fo_term_free_var_in_fo_formula xf phi0m -> S.mem xf fvp') };
let phi' = nnf_simpl phi0 fvp' st in
let phi'' = smart_exists x phi' fvp st in
phi''
end
with nnf_neg_simpl (phi:nlimpl_fo_formula) (ghost fvp:set int) (ghost st:'st) : nlimpl_fo_formula
requires { nlimpl_fo_formula_ok phi }
requires { forall x:int. is_fo_term_free_var_in_fo_formula x
phi.model_fo_formula_field -> S.mem x fvp }
ensures { nlimpl_fo_formula_ok result }
ensures { forall x:int. is_fo_term_free_var_in_fo_formula x
result.model_fo_formula_field -> S.mem x fvp }
ensures { forall m:model int 'st, rho:int -> 'st.
formula_semantic phi.model_fo_formula_field m rho <->
not(formula_semantic result.model_fo_formula_field m rho) }
ensures { is_nnf result.model_fo_formula_field }
ensures { is_simpl_extended result.model_fo_formula_field }
variant { size_fo_formula phi.model_fo_formula_field }
=
let phim = phi.model_fo_formula_field in
match destruct_fo_formula phi with
| NLC_PApp p l -> construct_fo_formula (NLC_Not phi)
| NLC_Not phi' -> nnf_simpl phi' fvp st
| NLC_And phi1 phi2 -> let phi'1 = nnf_neg_simpl phi1 fvp st in
let phi'2 = nnf_neg_simpl phi2 fvp st in
smart_or phi'1 phi'2 fvp st
| NLC_Or phi1 phi2 -> let phi'1 = nnf_neg_simpl phi1 fvp st in
let phi'2 = nnf_neg_simpl phi2 fvp st in
smart_and phi'1 phi'2 fvp st
| NLC_FTrue -> construct_fo_formula NLC_FFalse
| NLC_FFalse -> construct_fo_formula NLC_FTrue
| NLC_Forall x phi0 ->
let phi0m = phi0.model_fo_formula_field in
let ghost phi1m = rename_fo_formula phi0m identity (some[x<-None]) in
assert { phim = Forall phi1m } ;
assert { phi0m = rename_fo_formula phi1m identity (ocase identity x) };
let ghost fvp' = S.add x fvp in
assert { forall xf:int.
(forall y:option int. is_fo_term_free_var_in_fo_formula y phi1m /\
ocase identity x y = xf -> match y with None -> x = xf && S.mem xf fvp'
| Some y -> y = xf && is_fo_term_free_var_in_fo_formula y phim &&
S.mem xf fvp && S.mem xf fvp' end && S.mem xf fvp') &&
(is_fo_term_free_var_in_fo_formula xf phi0m ->
(exists y:option int. is_fo_term_free_var_in_fo_formula y phi1m /\
ocase identity x y = xf) && S.mem xf fvp') &&
(is_fo_term_free_var_in_fo_formula xf phi0m -> S.mem xf fvp') };
let phi' = nnf_neg_simpl phi0 fvp' st in
let phi'' = smart_exists x phi' fvp st in
phi''
| NLC_Exists x phi0 ->
let phi0m = phi0.model_fo_formula_field in
let ghost phi1m = rename_fo_formula phi0m identity (some[x<-None]) in
assert { phim = Exists phi1m } ;
assert { phi0m = rename_fo_formula phi1m identity (ocase identity x) };
let ghost fvp' = S.add x fvp in
assert { forall xf:int.
(forall y:option int. is_fo_term_free_var_in_fo_formula y phi1m /\
ocase identity x y = xf -> match y with None -> x = xf && S.mem xf fvp'
| Some y -> y = xf && is_fo_term_free_var_in_fo_formula y phim &&
S.mem xf fvp && S.mem xf fvp' end && S.mem xf fvp') &&
(is_fo_term_free_var_in_fo_formula xf phi0m ->
(exists y:option int. is_fo_term_free_var_in_fo_formula y phi1m /\
ocase identity x y = xf) && S.mem xf fvp') &&
(is_fo_term_free_var_in_fo_formula xf phi0m -> S.mem xf fvp') };
let phi' = nnf_neg_simpl phi0 fvp' st in
let phi'' = smart_forall x phi' fvp st in
phi''
end
(* gnum : take care of eliminated starting points. *)
let rec nnf_simpl_list (phis:nlimpl_fo_formula_list) (gnum:int)
(ghost fvp:set int) (ghost st:'st) : (nlimpl_fo_formula_list,int)
requires { nlimpl_fo_formula_list_ok phis }
requires { forall x:int. is_fo_term_free_var_in_fo_formula_list x
phis.model_fo_formula_list_field -> S.mem x fvp }
returns { (rs,_) -> nlimpl_fo_formula_list_ok rs }
returns { (rs,_) -> forall x:int. is_fo_term_free_var_in_fo_formula_list x
rs.model_fo_formula_list_field -> S.mem x fvp }
returns { (rs,_) -> forall m:model int 'st,rho:int -> 'st.
formula_list_conj_semantic phis.model_fo_formula_list_field m rho <->
formula_list_conj_semantic rs.model_fo_formula_list_field m rho }
returns { (rs,_) -> is_nnf_list rs.model_fo_formula_list_field }
returns { (rs,_) -> is_simpl_list rs.model_fo_formula_list_field }
raises { Unsat -> forall m:model int 'st,rho:int -> 'st.
not(formula_list_conj_semantic phis.model_fo_formula_list_field m rho) }
variant { size_fo_formula_list phis.model_fo_formula_list_field }
=
let phism = phis.model_fo_formula_list_field in
match destruct_fo_formula_list phis with
| NLC_FOFNil -> (phis,gnum)
| NLC_FOFCons phi q ->
let phim = phi.model_fo_formula_field in
let qm = q.model_fo_formula_list_field in
assert { phism = FOFCons phim qm } ;
let (q',gnum') = nnf_simpl_list q (gnum-1) fvp st in
let phi' = nnf_simpl phi fvp st in
let phi'_m = phi'.model_fo_formula_field in
let q'_m = q'.model_fo_formula_list_field in
match destruct_fo_formula phi' with
| NLC_FTrue -> (q',if gnum > 0 then gnum' else gnum'+1)
| NLC_FFalse -> raise Unsat
| _ -> assert { is_simpl phi'.model_fo_formula_field } ;
let res = construct_fo_formula_list (NLC_FOFCons phi' q') in
let resm = res.model_fo_formula_list_field in
assert { resm = FOFCons phi'_m q'_m } ;
(res,gnum'+1)
end
end
use ISet.Logic
use ISet.Impl
use Choice.Choice
let rec term_free_vars (t:nlimpl_fo_term) (ghost fvp:set int) : list int
requires { nlimpl_fo_term_ok t }
requires { forall x:int. is_fo_term_free_var_in_fo_term x t.model_fo_term_field ->
S.mem x fvp }
ensures { forall x:int.
is_fo_term_free_var_in_fo_term x t.model_fo_term_field ->
mem x result }
ensures { forall x:int. mem x result -> S.mem x fvp }
ensures { iset_ok result }
variant { size_fo_term t.model_fo_term_field }
=
match destruct_fo_term t with
| NLCVar_fo_term x -> Cons x Nil
| NLC_App _ l -> term_list_free_vars l fvp
end
with term_list_free_vars (l:nlimpl_fo_term_list) (ghost fvp:set int): list int
requires { nlimpl_fo_term_list_ok l }
requires { forall x:int.
is_fo_term_free_var_in_fo_term_list x l.model_fo_term_list_field ->
S.mem x fvp }
ensures { forall x:int.
is_fo_term_free_var_in_fo_term_list x l.model_fo_term_list_field ->
mem x result }
ensures { forall x:int. mem x result -> S.mem x fvp }
ensures { iset_ok result }
variant { size_fo_term_list l.model_fo_term_list_field }
=
match destruct_fo_term_list l with
| NLC_FONil -> Nil
| NLC_FOCons t q -> merge (term_free_vars t fvp) (term_list_free_vars q fvp)
end
let rec skolem_parameters (l:list int) (acc:skolemization_env_return 'st)
(ghost fvp:set int) : skolemization_env_return 'st
requires { iset_ok l }
requires { forall x:int. mem x l -> S.mem x fvp }
requires { nlimpl_fo_term_list_ok acc.skolemized_fv_list }
requires { forall x:int. is_fo_term_free_var_in_fo_term_list x
acc.skolemized_fv_list.model_fo_term_list_field -> S.mem x fvp }
requires { forall x:int. not(mem x l /\
is_fo_term_free_var_in_fo_term_list x
acc.skolemized_fv_list.model_fo_term_list_field) }
requires { forall x:int,m:model int 'st,rho:int -> 'st.
is_fo_term_free_var_in_fo_term_list x
acc.skolemized_fv_list.model_fo_term_list_field ->
eval acc.skolem_env (term_list_semantic
acc.skolemized_fv_list.model_fo_term_list_field m rho) x =
rho x }
requires { forall f:int. not(is_symbol_free_var_in_fo_term_list f
acc.skolemized_fv_list.model_fo_term_list_field) }
ensures { nlimpl_fo_term_list_ok result.skolemized_fv_list }
ensures { forall x:int. is_fo_term_free_var_in_fo_term_list x
result.skolemized_fv_list.model_fo_term_list_field -> S.mem x fvp }
ensures { forall x:int,m:model int 'st,rho:int -> 'st.
mem x l \/ is_fo_term_free_var_in_fo_term_list x
acc.skolemized_fv_list.model_fo_term_list_field ->
eval result.skolem_env (term_list_semantic
result.skolemized_fv_list.model_fo_term_list_field m rho) x =
rho x }
ensures { forall x:int. is_fo_term_free_var_in_fo_term_list x
result.skolemized_fv_list.model_fo_term_list_field ->
mem x l \/ is_fo_term_free_var_in_fo_term_list x
acc.skolemized_fv_list.model_fo_term_list_field }
ensures { forall f:int. not(is_symbol_free_var_in_fo_term_list f
result.skolemized_fv_list.model_fo_term_list_field) }
variant { l }
=
match l with
| Nil -> acc
| Cons x q -> let accl = acc.skolemized_fv_list in
let skenv = acc.skolem_env in
let varx = construct_fo_term (NLCVar_fo_term x) in
let accl' = construct_fo_term_list (NLC_FOCons varx accl) in
let (acclm,accl'_m) = (accl.model_fo_term_list_field ,accl'.model_fo_term_list_field) in
assert { accl'_m = FOCons (Var_fo_term x) acclm } ;
let ghost skenv' = extend_env skenv x in
let acc' = {
skolemized_fv_list = accl' ;
skolem_env = skenv'
} in
skolem_parameters q acc' fvp
end
(* Not sufficient yet. *)
let rec skolemize (phi:nlimpl_fo_formula) (skb:int) (b:bool)
(ghost fvp:set int) : skolemization_return 'st
requires { nlimpl_fo_formula_ok phi }
requires { forall x:int. is_fo_term_free_var_in_fo_formula x
phi.model_fo_formula_field -> S.mem x fvp }
requires { is_simpl phi.model_fo_formula_field }
requires { is_nnf phi.model_fo_formula_field }
requires { forall ls:int.
is_symbol_free_var_in_fo_formula ls phi.model_fo_formula_field -> ls < skb }
ensures { nlimpl_fo_formula_ok result.skolemized }
ensures { forall x:int. is_fo_term_free_var_in_fo_formula x
result.skolemized.model_fo_formula_field -> S.mem x fvp }
ensures { result.skolem_bound >= skb }
ensures { forall ls:int.
is_symbol_free_var_in_fo_formula ls result.skolemized.model_fo_formula_field ->
ls < result.skolem_bound }
ensures { is_nnf result.skolemized.model_fo_formula_field }
ensures { is_simpl result.skolemized.model_fo_formula_field }
ensures { no_existential result.skolemized.model_fo_formula_field }
ensures { forall m:model int 'st, rho:int -> 'st.
formula_semantic phi.model_fo_formula_field m rho ->
formula_semantic result.skolemized.model_fo_formula_field
(eval result.model_transformer m) rho }
(* Completeness concern.
ensures { forall m:model int 'st, rho:int -> 'st.
formula_semantic result.skolemized.model_fo_formula_field m rho ->
formula_semantic phi.model_fo_formula_field m rho
*)
ensures { forall m:model int 'st, ls:int.
ls < skb -> eval m.interp_fun ls =
eval (eval result.model_transformer m).interp_fun ls }
ensures { forall m:model int 'st.
m.interp_pred = (eval result.model_transformer m).interp_pred }
ensures { forall x:int. b = True ->
is_fo_term_free_var_in_fo_formula x result.skolemized.model_fo_formula_field ->
mem x result.free_var_list }
ensures { iset_ok result.free_var_list }
ensures { forall x:int. b = True -> mem x result.free_var_list -> S.mem x fvp }
variant { size_fo_formula phi.model_fo_formula_field }
=
let phim = phi.model_fo_formula_field in
match destruct_fo_formula phi with
| NLC_PApp _ l -> { skolemized = phi ;
skolem_bound = skb ;
model_transformer = identity ;
free_var_list = if b
then term_list_free_vars l fvp
else Nil }
| NLC_Not phi' -> let phi'_m = phi'.model_fo_formula_field in
assert { phim = Not phi'_m } ;
assert { match phi'_m with
| PApp _ _ -> true | _ -> false end } ;
{ skolemized = phi ;
skolem_bound = skb ;
model_transformer = identity ;
free_var_list = if b
then match destruct_fo_formula phi' with
| NLC_PApp _ l -> term_list_free_vars l fvp
| _ -> absurd
end
else Nil }
| NLC_And phi1 phi2 ->
let phi1m = phi1.model_fo_formula_field in
let phi2m = phi2.model_fo_formula_field in
assert { phim = And phi1m phi2m } ;
assert { forall ls:int. is_symbol_free_var_in_fo_formula ls phi1m ->
is_symbol_free_var_in_fo_formula ls phim } ;
assert { forall ls:int. is_symbol_free_var_in_fo_formula ls phi2m ->
is_symbol_free_var_in_fo_formula ls phim } ;
let res1 = skolemize phi1 skb b fvp in
let res2 = skolemize phi2 res1.skolem_bound b fvp in
let res1m = res1.skolemized.model_fo_formula_field in
let res2m = res2.skolemized.model_fo_formula_field in
let skr = construct_fo_formula (NLC_And res1.skolemized res2.skolemized) in
let skrm = skr.model_fo_formula_field in
let (res1f,res2f) = (res1.model_transformer,res2.model_transformer) in
let ghost transf = rcompose res1f res2f in
let fvlist = merge res1.free_var_list res2.free_var_list in
assert { skrm = And res1m res2m } ;
assert { forall m:model int 'st.
m.interp_pred = (res1f m).interp_pred =
(transf m).interp_pred } ;
assert { forall m:model int 'st, ls:int.
ls < skb ->
eval m.interp_fun ls = eval (res1f m).interp_fun ls
= eval (transf m).interp_fun ls } ;
assert { forall m:model int 'st,rho:int -> 'st.
formula_semantic res1m m rho <->
formula_semantic res1m (res2f m) rho } ;
assert { forall m:model int 'st,rho:int -> 'st.
formula_semantic phi2m m rho <->
formula_semantic phi2m (res1f m) rho } ;
assert { forall m:model int 'st,rho:int -> 'st.
transf m = res2f (res1f m) &&
(formula_semantic phi1m m rho ->
formula_semantic res1m (res1f m) rho &&
formula_semantic res1m (transf m) rho) /\
(formula_semantic phi2m m rho ->
formula_semantic phi2m (res1f m) rho &&
formula_semantic res2m (transf m) rho) } ;
assert { forall x:int. is_fo_term_free_var_in_fo_formula x skrm ->
(is_fo_term_free_var_in_fo_formula x res1m \/
is_fo_term_free_var_in_fo_formula x res2m) &&
S.mem x fvp } ;
{ skolemized = skr ;
skolem_bound = res2.skolem_bound ;
model_transformer = transf ;
free_var_list = fvlist }
| NLC_Or phi1 phi2 ->
let phi1m = phi1.model_fo_formula_field in
let phi2m = phi2.model_fo_formula_field in
assert { phim = Or phi1m phi2m } ;
assert { forall ls:int. is_symbol_free_var_in_fo_formula ls phi1m ->
is_symbol_free_var_in_fo_formula ls phim } ;
assert { forall ls:int. is_symbol_free_var_in_fo_formula ls phi2m ->
is_symbol_free_var_in_fo_formula ls phim } ;
let res1 = skolemize phi1 skb b fvp in
let res2 = skolemize phi2 res1.skolem_bound b fvp in
let res1m = res1.skolemized.model_fo_formula_field in
let res2m = res2.skolemized.model_fo_formula_field in
let skr = construct_fo_formula (NLC_Or res1.skolemized res2.skolemized) in
let skrm = skr.model_fo_formula_field in
let (res1f,res2f) = (res1.model_transformer,res2.model_transformer) in
let ghost transf = rcompose res1f res2f in
let fvlist = merge res1.free_var_list res2.free_var_list in
assert { skrm = Or res1m res2m } ;
assert { forall m:model int 'st.
m.interp_pred = (res1f m).interp_pred =
(transf m).interp_pred } ;
assert { forall m:model int 'st, ls:int.
ls < skb ->
eval m.interp_fun ls = eval (res1f m).interp_fun ls
= eval (transf m).interp_fun ls } ;
assert { forall m:model int 'st,rho:int -> 'st.
formula_semantic res1m m rho <->
formula_semantic res1m (res2f m) rho } ;
assert { forall m:model int 'st,rho:int -> 'st.
formula_semantic phi2m m rho <->
formula_semantic phi2m (res1f m) rho } ;
assert { forall m:model int 'st,rho:int -> 'st.
transf m = res2f (res1f m) &&
(formula_semantic phi1m m rho ->
formula_semantic res1m (res1f m) rho &&
formula_semantic res1m (transf m) rho) /\
(formula_semantic phi2m m rho ->
formula_semantic phi2m (res1f m) rho &&
formula_semantic res2m (transf m) rho) } ;
assert { forall x:int. is_fo_term_free_var_in_fo_formula x skrm ->
(is_fo_term_free_var_in_fo_formula x res1m
\/ is_fo_term_free_var_in_fo_formula x res2m) &&
S.mem x fvp } ;
{ skolemized = skr ;
skolem_bound = res2.skolem_bound ;
model_transformer = transf ;
free_var_list = fvlist }
| NLC_FTrue -> absurd
| NLC_FFalse -> absurd
| NLC_Forall x phi0 ->
let phi0m = phi0.model_fo_formula_field in
let ghost r0 = some[x <- None] in
let ghost phi1m = rename_fo_formula phi0m identity r0 in
assert { phim = Forall phi1m } ;
assert { phi0m = rename_fo_formula phi1m identity (ocase identity x) } ;
assert { forall ls:int.
(is_symbol_free_var_in_fo_formula ls phi1m <->
is_symbol_free_var_in_fo_formula ls phi0m) &&
(is_symbol_free_var_in_fo_formula ls phim <->
is_symbol_free_var_in_fo_formula ls phi0m) } ;
let ghost fvp' = S.add x fvp in
assert { forall xf:int.
(forall y:option int. is_fo_term_free_var_in_fo_formula y phi1m /\
ocase identity x y = xf -> match y with None -> x = xf && S.mem xf fvp'
| Some y -> y = xf && is_fo_term_free_var_in_fo_formula y phim &&
S.mem xf fvp && S.mem xf fvp' end && S.mem xf fvp') &&
(is_fo_term_free_var_in_fo_formula xf phi0m ->
(exists y:option int. is_fo_term_free_var_in_fo_formula y phi1m /\
ocase identity x y = xf) && S.mem xf fvp') &&
(is_fo_term_free_var_in_fo_formula xf phi0m -> S.mem xf fvp') };
let res = skolemize phi0 skb b fvp' in
let resm = res.skolemized.model_fo_formula_field in
let ghost res1m = rename_fo_formula resm identity r0 in
let skr = construct_fo_formula (NLC_Forall x res.skolemized) in
let skrm = skr.model_fo_formula_field in
let fvl = remove x res.free_var_list in
let transf = res.model_transformer in
assert { skrm = Forall res1m } ;
assert { forall ls:int.
(is_symbol_free_var_in_fo_formula ls res1m <->
(exists ls':int.
is_symbol_free_var_in_fo_formula ls' resm /\ identity ls' = ls)) &&
(is_symbol_free_var_in_fo_formula ls res1m <->
is_symbol_free_var_in_fo_formula ls resm) } ;
assert { forall m:model int 'st, rho:int -> 'st, xm:'st.
formula_semantic phi1m m (ocase rho xm) ->
formula_semantic phi0m m (rcompose r0 (ocase rho xm)) &&
formula_semantic resm (transf m) (rcompose r0 (ocase rho xm)) &&
formula_semantic res1m (transf m) (ocase rho xm)
} ;
assert { forall y:int.
is_fo_term_free_var_in_fo_formula (Some y) res1m ->
(forall z:int.
is_fo_term_free_var_in_fo_formula z resm /\ r0 z = Some y ->
z <> x && z = y ) &&
(is_fo_term_free_var_in_fo_formula y resm /\ y <> x)
&& ((b = True -> mem y fvl) /\ (S.mem y fvp' && S.mem y fvp))
} ;
{ skolemized = skr ;
skolem_bound = res.skolem_bound ;
model_transformer = transf ;
free_var_list = fvl }
| NLC_Exists x phi0 ->
let phi0m = phi0.model_fo_formula_field in
let ghost r0 = some[x <- None] in
let ghost phi1m = rename_fo_formula phi0m identity r0 in
assert { phim = Exists phi1m } ;
assert { forall ls:int.
(is_symbol_free_var_in_fo_formula ls phi1m <->
is_symbol_free_var_in_fo_formula ls phi0m) &&
(is_symbol_free_var_in_fo_formula ls phim <->
is_symbol_free_var_in_fo_formula ls phi0m) } ;
let ghost fvp' = S.add x fvp in
assert { phi0m = rename_fo_formula phi1m identity (ocase identity x) } ;
assert { forall xf:int.
(forall y:option int. is_fo_term_free_var_in_fo_formula y phi1m /\
ocase identity x y = xf -> match y with None -> x = xf && S.mem xf fvp'
| Some y -> y = xf && is_fo_term_free_var_in_fo_formula y phim &&
S.mem xf fvp && S.mem xf fvp' end && S.mem xf fvp') &&
(is_fo_term_free_var_in_fo_formula xf phi0m ->
(exists y:option int. is_fo_term_free_var_in_fo_formula y phi1m /\
ocase identity x y = xf) && S.mem xf fvp') &&
(is_fo_term_free_var_in_fo_formula xf phi0m -> S.mem xf fvp') };
let res = skolemize phi0 skb True fvp' in
let resm = res.skolemized.model_fo_formula_field in
let ghost res1m = rename_fo_formula resm identity r0 in
let fvl = res.free_var_list in
let fvl = remove x fvl in
let skb' = res.skolem_bound in
let fonil = construct_fo_term_list NLC_FONil in
assert { fonil.model_fo_term_list_field = FONil } ;
let skenv = skolem_parameters fvl { skolemized_fv_list = fonil ; skolem_env = default } fvp in
let skparams = skenv.skolemized_fv_list in
let skenv = skenv.skolem_env in
let skparamsm = skparams.model_fo_term_list_field in
assert { forall y:int.
is_fo_term_free_var_in_fo_formula (Some y) res1m ->
(forall z:int.
is_fo_term_free_var_in_fo_formula z resm /\ r0 z = Some y ->
z <> x && z = y ) &&
(is_fo_term_free_var_in_fo_formula y resm /\ y <> x) && mem y fvl } ;
let transf = skolem_model_transformer res1m skb' skparamsm skenv in
let symb = construct_symbol (NLCVar_symbol skb') in
assert { symb.model_symbol_field = Var_symbol skb' } ;
let skolemf = construct_fo_term (NLC_App symb skparams) in
let skolemfm = skolemf.model_fo_term_field in
assert { skolemfm = App (Var_symbol skb') skparamsm } ;
let phir = nlsubst_fo_term_in_fo_formula res.skolemized x skolemf in
let phirm = phir.model_fo_formula_field in
let resf = res.model_transformer in
let ghost transf2 = rcompose resf transf in
(* sat (Exists phi1m) -> sat (Exists res1m). *)
assert { forall m:model int 'st, rho:int -> 'st, xm:'st.
formula_semantic phi1m m (ocase rho xm) ->
formula_semantic phi0m m (rcompose r0 (ocase rho xm)) &&
formula_semantic resm (resf m) (rcompose r0 (ocase rho xm)) &&
formula_semantic res1m (resf m) (ocase rho xm)
} ;
assert { forall m:model int 'st, rho:int -> 'st.
formula_semantic phim m rho ->
formula_semantic (Exists res1m) (resf m) rho } ;
(* sat (Exists res1m) -> sat phir. *)
let ghost sub1 = subst_id_fo_term[x <- skolemfm] in
let ghost r1 = ocase identity x in
let ghost sub2 = ocase subst_id_fo_term skolemfm in
assert { phirm = subst_fo_formula resm subst_id_symbol sub1 } ;
assert { forall y:option int.
is_fo_term_free_var_in_fo_formula y res1m ->
(y <> Some x) && rcompose r1 sub1 y = sub2 y } ;
assert { subst_fo_formula res1m subst_id_symbol sub2 =
subst_fo_formula res1m subst_id_symbol (rcompose r1 sub1) } ;
assert { extensionalEqual (rcompose r0 r1) identity } ;
assert { phirm = subst_fo_formula res1m subst_id_symbol sub2 } ;
assert { forall m:model int 'st,rho:int -> 'st.
formula_semantic (Exists res1m) m rho ->
formula_semantic phirm (transf m) rho } ;
assert { forall y:int.
is_fo_term_free_var_in_fo_formula y phirm ->
(forall z:int.
is_fo_term_free_var_in_fo_formula z resm /\
is_fo_term_free_var_in_fo_term y (sub1 z) ->
(if z <> x then z = y && mem y fvl
else is_fo_term_free_var_in_fo_term y skolemfm &&
mem y fvl)) && mem y fvl } ;
(* Vexingly painful ! *)
assert { forall ls:int.
is_symbol_free_var_in_fo_formula ls phirm ->
is_symbol_free_var_in_fo_formula ls (subst_fo_formula resm subst_id_symbol sub1) &&
((forall z:int.
is_symbol_free_var_in_fo_formula z resm /\
is_symbol_free_var_in_symbol ls (subst_id_symbol z) ->
z = ls && z < skb' + 1 ) /\
(forall z:int.
is_fo_term_free_var_in_fo_formula z resm /\
is_symbol_free_var_in_fo_term ls (sub1 z) ->
(if z <> x then sub1 z = Var_fo_term z
else is_symbol_free_var_in_fo_term ls skolemfm &&
ls = skb' && ls < skb' + 1) && ls < skb' + 1) /\
((exists z:int.
is_symbol_free_var_in_fo_formula z resm /\
is_symbol_free_var_in_symbol ls (subst_id_symbol z)) \/
(exists z:int.
is_fo_term_free_var_in_fo_formula z resm /\
is_symbol_free_var_in_fo_term ls (sub1 z))))
&& ls < skb' + 1 } ;
(* Two point of views : either why3 do not deconstruct
records enough, either too much. *)
assert { forall m:model int 'st.
let mf = (resf m).interp_fun in
let mp = (resf m).interp_pred in
m.interp_pred = mp =
(transf ({ interp_fun = mf ; interp_pred = mp })).interp_pred
= (transf2 m).interp_pred &&
m.interp_pred = (transf2 m).interp_pred } ;
assert { forall m:model int 'st, ls:int.
ls < skb ->
let mf = (resf m).interp_fun in
let mp = (resf m).interp_pred in
eval m.interp_fun ls = eval mf ls
= eval (transf { interp_fun = mf ; interp_pred = mp }).interp_fun ls
= eval (transf2 m).interp_fun ls &&
eval m.interp_fun ls = eval (transf2 m).interp_fun ls } ;
assert { forall m:model int 'st,rho:int -> 'st.
let mf = (resf m).interp_fun in
let mp = (resf m).interp_pred in
formula_semantic phim m rho ->
formula_semantic (Exists res1m) ({ interp_fun = mf ; interp_pred = mp }) rho &&
formula_semantic phirm (transf ({ interp_fun = mf ; interp_pred = mp})) rho &&
formula_semantic phirm (transf2 m) rho } ;
{ skolemized = phir ;
skolem_bound = skb' + 1 ;
model_transformer = transf2 ;
free_var_list = fvl }
end
let rec skolemize_list (phil:nlimpl_fo_formula_list) (skb:int)
(ghost fvp:set int) : skolemization_list_return 'st
requires { nlimpl_fo_formula_list_ok phil }
requires { forall x:int. is_fo_term_free_var_in_fo_formula_list x
phil.model_fo_formula_list_field -> S.mem x fvp }
requires { is_simpl_list phil.model_fo_formula_list_field }
requires { is_nnf_list phil.model_fo_formula_list_field }
requires { forall ls:int.
is_symbol_free_var_in_fo_formula_list ls phil.model_fo_formula_list_field -> ls < skb }
ensures { nlimpl_fo_formula_list_ok result.skolemized_l }
ensures { forall x:int. is_fo_term_free_var_in_fo_formula_list x
result.skolemized_l.model_fo_formula_list_field -> S.mem x fvp }
ensures { result.skolem_bound_l >= skb }
ensures { forall ls:int.
is_symbol_free_var_in_fo_formula_list ls result.skolemized_l.model_fo_formula_list_field ->
ls < result.skolem_bound_l }
ensures { is_nnf_list result.skolemized_l.model_fo_formula_list_field }
ensures { is_simpl_list result.skolemized_l.model_fo_formula_list_field }
ensures { no_existential_list result.skolemized_l.model_fo_formula_list_field }
ensures { forall m:model int 'st, rho:int -> 'st.
formula_list_conj_semantic phil.model_fo_formula_list_field m rho ->
formula_list_conj_semantic result.skolemized_l.model_fo_formula_list_field
(eval result.model_transformer_l m) rho }
(* Completeness concern.
ensures { forall m:model int 'st, rho:int -> 'st.
formula_semantic result.skolemized.model_fo_formula_field m rho ->
formula_semantic phi.model_fo_formula_field m rho
*)
ensures { forall m:model int 'st, ls:int.
ls < skb -> eval m.interp_fun ls =
eval (eval result.model_transformer_l m).interp_fun ls }
ensures { forall m:model int 'st.
m.interp_pred = (eval result.model_transformer_l m).interp_pred }
variant { size_fo_formula_list phil.model_fo_formula_list_field }
=
let philm = phil.model_fo_formula_list_field in
match destruct_fo_formula_list phil with
| NLC_FOFNil -> { skolemized_l = phil ;
skolem_bound_l = skb ;
model_transformer_l = identity }
| NLC_FOFCons phi phiq -> let phim = phi.model_fo_formula_field in
let phiqm = phiq.model_fo_formula_list_field in
assert { philm = FOFCons phim phiqm } ;
assert { forall ls:int. is_symbol_free_var_in_fo_formula ls phim ->
is_symbol_free_var_in_fo_formula_list ls philm } ;
assert { forall ls:int. is_symbol_free_var_in_fo_formula_list ls phiqm ->
is_symbol_free_var_in_fo_formula_list ls philm } ;
let res = skolemize phi skb False fvp in
let resq = skolemize_list phiq res.skolem_bound fvp in
let resm = res.skolemized.model_fo_formula_field in
let resqm = resq.skolemized_l.model_fo_formula_list_field in
let skr = construct_fo_formula_list (NLC_FOFCons res.skolemized resq.skolemized_l) in
let skrm = skr.model_fo_formula_list_field in
let (resf,resqf) = (res.model_transformer,resq.model_transformer_l) in
let ghost transf = rcompose resf resqf in
assert { skrm = FOFCons resm resqm } ;
assert { forall m:model int 'st.
m.interp_pred = (resf m).interp_pred =
(transf m).interp_pred } ;
assert { forall m:model int 'st, ls:int.
ls < skb ->
eval m.interp_fun ls = eval (resf m).interp_fun ls
= eval (transf m).interp_fun ls } ;
assert { forall m:model int 'st,rho:int -> 'st.
formula_semantic resm m rho <->
formula_semantic resm (resqf m) rho } ;
assert { forall m:model int 'st,rho:int -> 'st.
formula_list_conj_semantic phiqm m rho <->
formula_list_conj_semantic phiqm (resf m) rho } ;
assert { forall m:model int 'st,rho:int -> 'st.
transf m = resqf (resf m) &&
(formula_semantic phim m rho ->
formula_semantic resm (resf m) rho &&
formula_semantic resm (transf m) rho) /\
(formula_list_conj_semantic phiqm m rho ->
formula_list_conj_semantic phiqm (resf m) rho &&
formula_list_conj_semantic resqm (transf m) rho) } ;
{ skolemized_l = skr ;
skolem_bound_l = resq.skolem_bound_l ;
model_transformer_l = transf }
end
(* No need for it in the logic... *)
type preprocessing_return 'st = {
preprocessed : nlimpl_fo_formula_list ;
final_goals_number : int ;
ghost model_transf : (model int 'st) -> (model int 'st) ;
}
type fvr = {
ghost sr : set int ;
lr : list int ;
}
let rec term_free_vars_noghost (t:nlimpl_fo_term) : fvr
requires { nlimpl_fo_term_ok t }
ensures { forall x:int.
is_fo_term_free_var_in_fo_term x t.model_fo_term_field ->
mem x result.lr }
ensures { iset_ok result.lr }
ensures { forall x:int. S.mem x result.sr <-> mem x result.lr }
variant { size_fo_term t.model_fo_term_field }
=
match destruct_fo_term t with
| NLCVar_fo_term x -> { sr = S.singleton x ; lr = Cons x Nil }
| NLC_App _ l -> term_list_free_vars_noghost l
end
with term_list_free_vars_noghost (l:nlimpl_fo_term_list) : fvr
requires { nlimpl_fo_term_list_ok l }
ensures { forall x:int.
is_fo_term_free_var_in_fo_term_list x l.model_fo_term_list_field ->
mem x result.lr }
ensures { forall x:int. S.mem x result.sr <-> mem x result.lr }
ensures { iset_ok result.lr }
variant { size_fo_term_list l.model_fo_term_list_field }
=
match destruct_fo_term_list l with
| NLC_FONil -> { lr = Nil ; sr = S.empty }
| NLC_FOCons t q -> let r1 = term_free_vars_noghost t in
let r2 = term_list_free_vars_noghost q in
{ lr = merge r1.lr r2.lr ; sr = S.union r1.sr r2.sr }
end
let rec collect_free_var_formula (phi:nlimpl_fo_formula) : fvr
requires { nlimpl_fo_formula_ok phi }
ensures { iset_ok result.lr }
ensures { forall x:int. is_fo_term_free_var_in_fo_formula x
phi.model_fo_formula_field -> mem x result.lr }
ensures { forall x:int. mem x result.lr <-> S.mem x result.sr }
variant { size_fo_formula phi.model_fo_formula_field }
=
let phim = phi.model_fo_formula_field in
match destruct_fo_formula phi with
| NLC_PApp p l -> let pm = p.model_symbol_field in
let lm = l.model_fo_term_list_field in
assert { phim = PApp pm lm } ;
term_list_free_vars_noghost l
| NLC_Not phi0 -> let phi0m = phi0.model_fo_formula_field in
assert { phim = Not phi0m } ;
collect_free_var_formula phi0
| NLC_And phi1 phi2 -> let phi1m = phi1.model_fo_formula_field in
let phi2m = phi2.model_fo_formula_field in
assert { phim = And phi1m phi2m } ;
let r1 = collect_free_var_formula phi1 in
let r2 = collect_free_var_formula phi2 in
{ lr = merge r1.lr r2.lr ; sr = S.union r1.sr r2.sr }
| NLC_Or phi1 phi2 -> let phi1m = phi1.model_fo_formula_field in
let phi2m = phi2.model_fo_formula_field in
assert { phim = Or phi1m phi2m } ;
let r1 = collect_free_var_formula phi1 in
let r2 = collect_free_var_formula phi2 in
{ lr = merge r1.lr r2.lr ; sr = S.union r1.sr r2.sr }
| NLC_FTrue -> { lr = Nil ; sr = S.empty }
| NLC_FFalse -> { lr = Nil ; sr = S.empty }
| NLC_Forall x phi0 -> let phi0m = phi0.model_fo_formula_field in
let ghost r0 = some[x <- None] in
let ghost phi1m = rename_fo_formula phi0m identity r0 in
assert { phim = Forall phi1m } ;
let r = collect_free_var_formula phi0 in
let res = { lr = remove x r.lr ; sr = S.remove x r.sr } in
assert { forall xf:int.
(forall y:int. is_fo_term_free_var_in_fo_formula y phi0m /\
eval (some[x<-None]) y = Some xf -> y <> x &&
Some xf = Some y && xf = y) && is_fo_term_free_var_in_fo_formula xf phim ->
is_fo_term_free_var_in_fo_formula (Some xf) phi1m &&
(exists y:int. is_fo_term_free_var_in_fo_formula y phi0m /\
eval (some[x <- None]) y = Some xf) && is_fo_term_free_var_in_fo_formula xf phi0m
&& xf <> x && mem xf res.lr } ;
res
| NLC_Exists x phi0 -> let phi0m = phi0.model_fo_formula_field in
let ghost r0 = some[x <- None] in
let ghost phi1m = rename_fo_formula phi0m identity r0 in
assert { phim = Exists phi1m } ;
let r = collect_free_var_formula phi0 in
let res = { lr = remove x r.lr ; sr = S.remove x r.sr } in
assert { forall xf:int.
(forall y:int. is_fo_term_free_var_in_fo_formula y phi0m /\
eval (some[x<-None]) y = Some xf -> y <> x &&
Some xf = Some y && xf = y) && is_fo_term_free_var_in_fo_formula xf phim ->
is_fo_term_free_var_in_fo_formula (Some xf) phi1m &&
(exists y:int. is_fo_term_free_var_in_fo_formula y phi0m /\
eval (some[x <- None]) y = Some xf) && is_fo_term_free_var_in_fo_formula xf phi0m
&& xf <> x && mem xf res.lr } ;
res
end
let rec collect_free_var_formula_list (phil:nlimpl_fo_formula_list) : fvr
requires { nlimpl_fo_formula_list_ok phil }
ensures { iset_ok result.lr }
ensures { forall x:int. is_fo_term_free_var_in_fo_formula_list x
phil.model_fo_formula_list_field -> mem x result.lr }
ensures { forall x:int. mem x result.lr <-> S.mem x result.sr }
variant { size_fo_formula_list phil.model_fo_formula_list_field }
=
match destruct_fo_formula_list phil with
| NLC_FOFNil -> { lr = Nil ; sr = S.empty }
| NLC_FOFCons phi0 q -> let fvr1 = collect_free_var_formula phi0 in
let fvr2 = collect_free_var_formula_list q in
{ lr = merge fvr1.lr fvr2.lr ;
sr = S.union fvr1.sr fvr2.sr }
end
let rec exists_quantify (l:list int) (phi:nlimpl_fo_formula) (ghost st:'st) : nlimpl_fo_formula
requires { nlimpl_fo_formula_ok phi }
requires { is_simpl phi.model_fo_formula_field }
requires { is_nnf phi.model_fo_formula_field }
requires { forall x:int. is_fo_term_free_var_in_fo_formula x
phi.model_fo_formula_field -> mem x l }
ensures { nlimpl_fo_formula_ok result }
ensures { forall x:int. not(is_fo_term_free_var_in_fo_formula x
result.model_fo_formula_field) }
ensures { forall m:model int 'st,rho:int -> 'st.
formula_semantic phi.model_fo_formula_field m rho ->
formula_semantic result.model_fo_formula_field m rho }
ensures { is_simpl result.model_fo_formula_field }
ensures { is_nnf result.model_fo_formula_field }
variant { l }
= let phim = phi.model_fo_formula_field in
match l with
| Nil -> phi
| Cons x q -> let phi' = construct_fo_formula (NLC_Exists x phi) in
let phi'_m = phi'.model_fo_formula_field in
let ghost phi1m = rename_fo_formula phim identity (some[x <- None]) in
assert { phi'_m = Exists phi1m } ;
assert { forall xf:int.
(forall y:int. is_fo_term_free_var_in_fo_formula y phim /\
eval (some[x<-None]) y = Some xf -> y <> x &&
Some xf = Some y && xf = y) && is_fo_term_free_var_in_fo_formula xf phi'_m ->
is_fo_term_free_var_in_fo_formula (Some xf) phi1m &&
(exists y:int. is_fo_term_free_var_in_fo_formula y phim /\
eval (some[x <- None]) y = Some xf) && is_fo_term_free_var_in_fo_formula xf phim
&& xf <> x && mem xf q } ;
assert { forall m:model int 'st,rho:int -> 'st.
formula_semantic phim m rho ->
let rhos = ocase rho (rho x) in
let sub = rcompose (some[x <- None]) subst_id_fo_term in
let rhos' = semantic_subst sub m rhos in
extensionalEqual rhos' rho &&
phi1m = subst_fo_formula phim subst_id_symbol (rcompose (some[x <- None]) subst_id_fo_term) &&
formula_semantic phi1m m rhos &&
(exists xm:'st. formula_semantic phi1m m (ocase rho xm)) &&
formula_semantic phi'_m m rho } ;
exists_quantify q phi' st
end
type comb_ret = {
form : nlimpl_fo_formula ;
llen : int ;
}
let rec combine_with (l:nlimpl_fo_formula_list) (phi0:nlimpl_fo_formula)
(ghost fvp:set int) (ghost st:'st) : comb_ret
requires { nlimpl_fo_formula_list_ok l }
requires { forall x:int. is_fo_term_free_var_in_fo_formula x phi0.model_fo_formula_field
-> S.mem x fvp }
requires { nlimpl_fo_formula_ok phi0 }
requires { forall x:int. is_fo_term_free_var_in_fo_formula_list x
l.model_fo_formula_list_field -> S.mem x fvp }
requires { is_simpl_list l.model_fo_formula_list_field }
requires { is_nnf_list l.model_fo_formula_list_field }
requires { is_simpl phi0.model_fo_formula_field }
requires { is_nnf phi0.model_fo_formula_field }
variant { size_fo_formula_list l.model_fo_formula_list_field }
ensures { nlimpl_fo_formula_ok result.form }
ensures { is_simpl result.form.model_fo_formula_field }
ensures { is_nnf result.form.model_fo_formula_field }
ensures { forall m:model int 'st,rho:int -> 'st.
formula_semantic result.form.model_fo_formula_field m rho <->
(formula_list_conj_semantic l.model_fo_formula_list_field m rho /\
formula_semantic phi0.model_fo_formula_field m rho) }
ensures { forall x:int. is_fo_term_free_var_in_fo_formula x
result.form.model_fo_formula_field -> S.mem x fvp }
=
let lm = l.model_fo_formula_list_field in
let phi0m = phi0.model_fo_formula_field in
match destruct_fo_formula_list l with
| NLC_FOFNil -> { form = phi0 ; llen = 1 }
| NLC_FOFCons x q -> let xm = x.model_fo_formula_field in
let qm = q.model_fo_formula_list_field in
assert { lm = FOFCons xm qm } ;
let cr = combine_with q x fvp st in
let phi' = cr.form in
let phi'_m = phi'.model_fo_formula_field in
let phir = construct_fo_formula (NLC_And phi0 phi') in
let phirm = phir.model_fo_formula_field in
assert { phirm = And phi0m phi'_m } ;
{ form = phir ; llen = cr.llen + 1 }
end
type split_ret = {
forms : nlimpl_fo_formula_list ;
total_goals : int ;
}
let rec split (phi:nlimpl_fo_formula) (l:nlimpl_fo_formula_list) (lnum:int) (gnum:int) (ghost st:'st) : split_ret
requires { nlimpl_fo_formula_ok phi }
requires { forall x:int. not(is_fo_term_free_var_in_fo_formula x
phi.model_fo_formula_field) }
requires { is_simpl phi.model_fo_formula_field }
requires { is_nnf phi.model_fo_formula_field }
requires { no_existential phi.model_fo_formula_field }
requires { nlimpl_fo_formula_list_ok l }
requires { forall x:int. not(is_fo_term_free_var_in_fo_formula_list x
l.model_fo_formula_list_field) }
requires { is_simpl_list l.model_fo_formula_list_field }
requires { is_nnf_list l.model_fo_formula_list_field }
requires { no_existential_list l.model_fo_formula_list_field }
variant { size_fo_formula phi.model_fo_formula_field }
ensures { forall m:model int 'st,rho:int -> 'st.
formula_list_conj_semantic result.forms.model_fo_formula_list_field m rho
<-> (formula_semantic phi.model_fo_formula_field m rho /\
formula_list_conj_semantic l.model_fo_formula_list_field m rho) }
ensures { nlimpl_fo_formula_list_ok result.forms }
ensures { forall x:int. not(is_fo_term_free_var_in_fo_formula_list x
result.forms.model_fo_formula_list_field) }
ensures { is_simpl_list result.forms.model_fo_formula_list_field }
ensures { is_nnf_list result.forms.model_fo_formula_list_field }
ensures { no_existential_list result.forms.model_fo_formula_list_field }
=
match destruct_fo_formula phi with
| NLC_And phi1 phi2 ->
(* gnum <> 0 : either need full count (<0),
either phi is a "goal". if lnum = 1,
then gnumcall must be updated accordingly.
if lnum <> 1 (not last of initial list),
then either gnum = 1 (last goal,do not want next count),
either it is expected. *)
let phim = phi.model_fo_formula_field in
let phi1m = phi1.model_fo_formula_field in
let phi2m = phi2.model_fo_formula_field in
assert { phim = And phi1m phi2m } ;
assert { forall x:int. is_fo_term_free_var_in_fo_formula x phi1m ->
is_fo_term_free_var_in_fo_formula x phim } ;
assert { forall x:int. is_fo_term_free_var_in_fo_formula x phi2m ->
is_fo_term_free_var_in_fo_formula x phim } ;
let gnumcall = if lnum = 1
then if gnum <> 0
then (-1)
else gnum - 1
else gnum - 1 in
let r0 = split phi2 l (lnum-1) gnumcall st in
let l0 = r0.forms in
(* need full count for r1. *)
let r1 = split phi1 l0 0 (-1) st in
let l1 = r1.forms in
{ forms = l1 ;
total_goals = if gnum <> 0
then r0.total_goals + r1.total_goals
else 0 }
| _ -> let lr = construct_fo_formula_list (NLC_FOFCons phi l) in
{ forms = lr ;
total_goals = if gnum <> 0
then 1
else 0 }
end
(* Prover preprocessing function:
From a set of formulas,
return an equi-satisfiable
(as completeness is not considered here,
it is only proved that satisfiability is preserved)
set of formulas without occurrence of true/false,
in negational normal form, without existential quantifiers.
Potentially raises an exception when the input set of formulas
was (trivially) unsatisfiable. *)
exception Sat
let preprocessing (phil:nlimpl_fo_formula_list) (gnum:int) (ghost st:'st) : preprocessing_return 'st
requires { nlimpl_fo_formula_list_ok phil }
ensures { nlimpl_fo_formula_list_ok result.preprocessed }
ensures { forall x:int. not(is_fo_term_free_var_in_fo_formula_list x
result.preprocessed.model_fo_formula_list_field) }
ensures { is_nnf_list result.preprocessed.model_fo_formula_list_field }
ensures { is_simpl_list result.preprocessed.model_fo_formula_list_field }
ensures { no_existential_list result.preprocessed.model_fo_formula_list_field }
ensures { forall m:model int 'st,rho:int -> 'st.
formula_list_conj_semantic phil.model_fo_formula_list_field m rho ->
formula_list_conj_semantic result.preprocessed.model_fo_formula_list_field
(eval result.model_transf m) rho }
raises { Unsat ->
forall m:model int 'st,rho:int -> 'st.
not(formula_list_conj_semantic phil.model_fo_formula_list_field m rho) }
raises { Sat -> forall m:model int 'st,rho:int -> 'st.
formula_list_conj_semantic phil.model_fo_formula_list_field m rho }
=
let s = collect_free_var_formula_list phil in
let fvp = s.sr in
let (phisimpl,gnum) = nnf_simpl_list phil gnum fvp st in
match destruct_fo_formula_list phisimpl with
| NLC_FOFNil -> raise Sat
| NLC_FOFCons phi0 q -> let cb = combine_with q phi0 fvp st in
let len = cb.llen in
let phicb = cb.form in
let phiex = exists_quantify s.lr phicb st in
let skr = (skolemize phiex phiex.nlfree_var_symbol_set_abstraction_fo_formula_field False S.empty:skolemization_return 'st) in
let phisk = skr.skolemized in
let tr = skr.model_transformer in
let fonil = construct_fo_formula_list NLC_FOFNil in
let spl = split phisk fonil len gnum st in
assert { forall m:model int 'st,rho:int -> 'st.
formula_list_conj_semantic phil.model_fo_formula_list_field m rho ->
formula_list_conj_semantic phisimpl.model_fo_formula_list_field m rho &&
(formula_semantic phi0.model_fo_formula_field m rho /\
formula_list_conj_semantic q.model_fo_formula_list_field m rho) &&
formula_semantic phicb.model_fo_formula_field m rho &&
formula_semantic phisk.model_fo_formula_field (tr m) rho &&
formula_list_conj_semantic fonil.model_fo_formula_list_field (tr m) rho &&
formula_list_conj_semantic spl.forms.model_fo_formula_list_field (tr m) rho } ;
{ preprocessed = spl.forms ;
final_goals_number = spl.total_goals ;
model_transf = tr }
end
(*
let preprocessing (phil:nlimpl_fo_formula_list) : preprocessing_return 'st
requires { nlimpl_fo_formula_list_ok phil }
ensures { nlimpl_fo_formula_list_ok result.preprocessed }
ensures { forall x:int. not(is_fo_term_free_var_in_fo_formula_list x
result.preprocessed.model_fo_formula_list_field) }
ensures { is_nnf_list result.preprocessed.model_fo_formula_list_field }
ensures { is_simpl_list result.preprocessed.model_fo_formula_list_field }
ensures { no_existential_list result.preprocessed.model_fo_formula_list_field }
ensures { forall m:model int 'st, rho:int -> 'st.
formula_list_conj_semantic phil.model_fo_formula_list_field m rho ->
formula_list_conj_semantic result.preprocessed.model_fo_formula_list_field
(eval result.model_transf m) rho }
raises { Unsat ->
forall m:model int 'st,rho:int -> 'st.
not(formula_list_conj_semantic phil.model_fo_formula_list_field m rho) }
=
let s = collect_free_var_formula_list in
let fvp = s.sr in
let phil' = nnf_simpl_list phil fvp in
TODO
let skr =
(skolemize_list phil' phil'.nlfree_var_symbol_set_abstraction_fo_formula_list_field fvp:
skolemization_list_return 'st) in
{ preprocessed = skr.skolemized_l ;
model_transf = skr.model_transformer_l }*)
end