wip: proof production

This commit is contained in:
Simon Cruanes 2021-10-09 00:51:15 -04:00
parent d3537f2c3f
commit 0550f6fcfa
No known key found for this signature in database
GPG key ID: 4AC01D0849AA62B6
3 changed files with 76 additions and 53 deletions

View file

@ -786,6 +786,9 @@ module type SOLVER_INTERNAL = sig
module type PREPROCESS_ACTS = sig module type PREPROCESS_ACTS = sig
val proof : proof val proof : proof
val mk_lit_nopreproc : ?sign:bool -> term -> lit
(** [mk_lit t] creates a new literal for a boolean term [t]. *)
val mk_lit : ?sign:bool -> term -> lit * proof_step option val mk_lit : ?sign:bool -> term -> lit * proof_step option
(** [mk_lit t] creates a new literal for a boolean term [t]. (** [mk_lit t] creates a new literal for a boolean term [t].
Also returns an optional proof of preprocessing, which if present Also returns an optional proof of preprocessing, which if present

View file

@ -187,6 +187,7 @@ module Make(A : ARG)
module type PREPROCESS_ACTS = sig module type PREPROCESS_ACTS = sig
val proof : proof val proof : proof
val mk_lit_nopreproc : ?sign:bool -> term -> lit
val mk_lit : ?sign:bool -> term -> lit * proof_step option val mk_lit : ?sign:bool -> term -> lit * proof_step option
val add_clause : lit list -> proof_step -> unit val add_clause : lit list -> proof_step -> unit
val add_lit : ?default_pol:bool -> lit -> unit val add_lit : ?default_pol:bool -> lit -> unit
@ -282,7 +283,7 @@ module Make(A : ARG)
this calls all the preprocessing hooks on subterms, ensuring this calls all the preprocessing hooks on subterms, ensuring
a fixpoint. *) a fixpoint. *)
let preprocess_term_ (self:t) (module A0:PREPROCESS_ACTS) (t:term) : term * proof_step option = let preprocess_term_ (self:t) (module A0:PREPROCESS_ACTS) (t:term) : term * proof_step option =
let mk_lit_nopreproc t = Lit.atom self.tst t in (* no further simplification *) let mk_lit_nopreproc ?sign t = Lit.atom ?sign self.tst t in (* no further simplification *)
(* compute and cache normal form [u] of [t]. (* compute and cache normal form [u] of [t].
@ -384,10 +385,13 @@ module Make(A : ARG)
and pacts = lazy ( and pacts = lazy (
(module struct (module struct
let proof = A0.proof let proof = A0.proof
let add_lit ?default_pol lit = let add_lit ?default_pol lit =
(* just drop the proof *) (* just drop the proof *)
(* TODO: add a clause instead [lit => preprocess(lit)]? *)
let lit = preprocess_lit ~steps:(ref []) lit in let lit = preprocess_lit ~steps:(ref []) lit in
A0.add_lit ?default_pol lit A0.add_lit ?default_pol lit
let add_clause c pr_c = let add_clause c pr_c =
Stat.incr self.count_preprocess_clause; Stat.incr self.count_preprocess_clause;
let steps = ref [] in let steps = ref [] in
@ -398,6 +402,8 @@ module Make(A : ARG)
in in
A0.add_clause c' pr_c' A0.add_clause c' pr_c'
let mk_lit_nopreproc = mk_lit_nopreproc
let mk_lit = mk_lit let mk_lit = mk_lit
end : PREPROCESS_ACTS) end : PREPROCESS_ACTS)
) in ) in
@ -441,6 +447,7 @@ module Make(A : ARG)
let preprocess_acts_of_acts (self:t) (acts:theory_actions) : preprocess_actions = let preprocess_acts_of_acts (self:t) (acts:theory_actions) : preprocess_actions =
(module struct (module struct
let proof = self.proof let proof = self.proof
let mk_lit_nopreproc ?sign t = Lit.atom self.tst ?sign t
let mk_lit ?sign t = Lit.atom self.tst ?sign t, None let mk_lit ?sign t = Lit.atom self.tst ?sign t, None
let add_clause = add_clause_ self acts let add_clause = add_clause_ self acts
let add_lit = add_lit self acts let add_lit = add_lit self acts
@ -693,6 +700,7 @@ module Make(A : ARG)
(self:t) : (module Solver_internal.PREPROCESS_ACTS) = (self:t) : (module Solver_internal.PREPROCESS_ACTS) =
(module struct (module struct
let proof = self.proof let proof = self.proof
let mk_lit_nopreproc ?sign t = Lit.atom ?sign self.si.tst t
let mk_lit ?sign t = Lit.atom ?sign self.si.tst t, None let mk_lit ?sign t = Lit.atom ?sign self.si.tst t, None
let add_lit ?default_pol lit = let add_lit ?default_pol lit =
Sat_solver.add_lit self.solver ?default_pol lit Sat_solver.add_lit self.solver ?default_pol lit

View file

@ -126,7 +126,7 @@ module Make(A : ARG) : S with module A = A = struct
in in
(* proof is [t <=> u] *) (* proof is [t <=> u] *)
let ret_bequiv t1 u = let ret_bequiv t1 u =
add_step_ @@ SI.Simplify.with_proof simp (A.lemma_bool_equiv t1 u); add_step_ @@ A.lemma_bool_equiv t1 u @@ SI.Simplify.proof simp;
ret u ret u
in in
@ -152,13 +152,13 @@ module Make(A : ARG) : S with module A = A = struct
(* directly simplify [a] so that maybe we never will simplify one (* directly simplify [a] so that maybe we never will simplify one
of the branches *) of the branches *)
let a, prf_a = SI.Simplify.normalize_t simp a in let a, prf_a = SI.Simplify.normalize_t simp a in
Iter.iter add_step_ prf_a; CCOpt.iter add_step_ prf_a;
begin match A.view_as_bool a with begin match A.view_as_bool a with
| B_bool true -> | B_bool true ->
add_step_ @@ SI.Simplify.with_proof simp (A.lemma_ite_true ~a ~ite:t); add_step_ @@ A.lemma_ite_true ~a ~ite:t @@ SI.Simplify.proof simp;
ret b ret b
| B_bool false -> | B_bool false ->
add_step_ @@ SI.Simplify.with_proof simp (A.lemma_ite_false ~a ~ite:t); add_step_ @@ A.lemma_ite_false ~a ~ite:t @@ SI.Simplify.proof simp;
ret c ret c
| _ -> | _ ->
None None
@ -189,13 +189,10 @@ module Make(A : ARG) : S with module A = A = struct
let proxy = fresh_term ~for_t ~pre self (Ty.bool self.ty_st) in let proxy = fresh_term ~for_t ~pre self (Ty.bool self.ty_st) in
proxy, mk_lit proxy proxy, mk_lit proxy
let p1_opt s1 s2 p : SI.proof_step = let pr_p1_opt p s1 s2 : SI.proof_step =
let s2 = s2 p in
CCOpt.map_or ~default:s2 (fun s1 -> SI.P.proof_p1 s1 s2 p) s1 CCOpt.map_or ~default:s2 (fun s1 -> SI.P.proof_p1 s1 s2 p) s1
let p1_map s1 s2 p = let pr_p1 p s1 s2 = SI.P.proof_p1 s1 s2 p
let s2 = s2 p in
SI.P.proof_p1 s1 s2 p
(* preprocess "ite" away *) (* preprocess "ite" away *)
let preproc_ite self si (module PA:SI.PREPROCESS_ACTS) (t:T.t) : (T.t * SI.proof_step Iter.t) option = let preproc_ite self si (module PA:SI.PREPROCESS_ACTS) (t:T.t) : (T.t * SI.proof_step Iter.t) option =
@ -211,60 +208,66 @@ module Make(A : ARG) : S with module A = A = struct
begin match A.view_as_bool a' with begin match A.view_as_bool a' with
| B_bool true -> | B_bool true ->
(* [a=true |- ite a b c=b], [|- a=true] ==> [|- t=b] *) (* [a=true |- ite a b c=b], [|- a=true] ==> [|- t=b] *)
add_step_ @@ SI.with_proof si (A.lemma_ite_true ~a:a' ~ite:t); add_step_ @@ A.lemma_ite_true ~a:a' ~ite:t PA.proof;
ret b ret b
| B_bool false -> | B_bool false ->
(* [a=false |- ite a b c=c], [|- a=false] ==> [|- t=c] *) (* [a=false |- ite a b c=c], [|- a=false] ==> [|- t=c] *)
add_step_ @@ SI.with_proof si (A.lemma_ite_false ~a:a' ~ite:t); add_step_ @@ A.lemma_ite_false ~a:a' ~ite:t PA.proof;
ret c ret c
| _ -> | _ ->
let t_ite = fresh_term self ~for_t:t ~pre:"ite" (T.ty b) in let t_ite = fresh_term self ~for_t:t ~pre:"ite" (T.ty b) in
SI.define_const si ~const:t_ite ~rhs:t; SI.define_const si ~const:t_ite ~rhs:t;
let pr_def = SI.with_proof si (SI.P.define_term t_ite t) in let pr_def = SI.P.define_term t_ite t PA.proof in
let lit_a = PA.mk_lit a' in let lit_a = PA.mk_lit_nopreproc a' in
(* TODO: use unit paramod on each clause with side t=t_ite and on a=a' *) (* TODO: use unit paramod on each clause with side t=t_ite and on a=a' *)
PA.add_clause [Lit.neg lit_a; PA.mk_lit (eq self.tst t_ite b)] PA.add_clause [Lit.neg lit_a; PA.mk_lit_nopreproc (eq self.tst t_ite b)]
(p1_map pr_def @@ p1_opt pr_a (A.lemma_ite_true ~a:a' ~ite:t)); (pr_p1 PA.proof pr_def @@ pr_p1_opt PA.proof pr_a @@
PA.add_clause [lit_a; PA.mk_lit (eq self.tst t_ite c)] A.lemma_ite_true ~a:a' ~ite:t PA.proof);
(p1_map pr_def @@ p1_opt pr_a (A.lemma_ite_false ~a:a' ~ite:t)); PA.add_clause [lit_a; PA.mk_lit_nopreproc (eq self.tst t_ite c)]
(pr_p1 PA.proof pr_def @@ pr_p1_opt PA.proof pr_a @@
A.lemma_ite_false ~a:a' ~ite:t PA.proof);
ret t_ite ret t_ite
end end
| _ -> None | _ -> None
(* TODO: polarity? *) (* TODO: polarity? *)
let cnf (self:state) (si:SI.t) (module PA:SI.PREPROCESS_ACTS) (t:T.t) : T.t option = let cnf (self:state) (si:SI.t) (module PA:SI.PREPROCESS_ACTS)
(t:T.t) : (T.t * _ Iter.t) option =
Log.debugf 50 (fun k->k"(@[th-bool.cnf@ %a@])" T.pp t); Log.debugf 50 (fun k->k"(@[th-bool.cnf@ %a@])" T.pp t);
let steps = ref [] in
let mk_lit = PA.mk_lit in let[@inline] add_step s = steps := s :: !steps in
(* handle boolean equality *) (* handle boolean equality *)
let equiv_ si ~is_xor ~for_t t_a t_b : Lit.t = let equiv_ si ~is_xor ~for_t t_a t_b : Lit.t =
let a = mk_lit t_a in let a = PA.mk_lit_nopreproc t_a in
let b = mk_lit t_b in let b = PA.mk_lit_nopreproc t_b in
let a = if is_xor then Lit.neg a else a in (* [a xor b] is [(¬a) = b] *) let a = if is_xor then Lit.neg a else a in (* [a xor b] is [(¬a) = b] *)
let t_proxy, proxy = fresh_lit ~for_t ~mk_lit:PA.mk_lit ~pre:"equiv_" self in let t_proxy, proxy = fresh_lit ~for_t ~mk_lit:PA.mk_lit_nopreproc ~pre:"equiv_" self in
SI.define_const si ~const:t_proxy ~rhs:for_t; SI.define_const si ~const:t_proxy ~rhs:for_t;
let pr_def = SI.with_proof si (SI.P.define_term t_proxy for_t) in let pr_def = SI.P.define_term t_proxy for_t PA.proof in
add_step pr_def;
let add_clause c pr = let[@inline] add_clause c pr = PA.add_clause c pr in
PA.add_clause c pr
in
(* proxy => a<=> b, (* proxy => a<=> b,
¬proxy => a xor b *) ¬proxy => a xor b *)
add_clause [Lit.neg proxy; Lit.neg a; b] add_clause [Lit.neg proxy; Lit.neg a; b]
(if is_xor then A.lemma_bool_c "xor-e+" [t_proxy] (pr_p1 PA.proof pr_def @@
else A.lemma_bool_c "eq-e" [t_proxy; t_a]); if is_xor then A.lemma_bool_c "xor-e+" [for_t] PA.proof
else A.lemma_bool_c "eq-e" [for_t; t_a] PA.proof);
add_clause [Lit.neg proxy; Lit.neg b; a] add_clause [Lit.neg proxy; Lit.neg b; a]
(if is_xor then A.lemma_bool_c "xor-e-" [t_proxy] (pr_p1 PA.proof pr_def @@
else A.lemma_bool_c "eq-e" [t_proxy; t_b]); if is_xor then A.lemma_bool_c "xor-e-" [for_t] PA.proof
else A.lemma_bool_c "eq-e" [for_t; t_b] PA.proof);
add_clause [proxy; a; b] add_clause [proxy; a; b]
(if is_xor then A.lemma_bool_c "xor-i" [t_proxy; t_a] (pr_p1 PA.proof pr_def @@
else A.lemma_bool_c "eq-i+" [t_proxy]); if is_xor then A.lemma_bool_c "xor-i" [for_t; t_a] PA.proof
else A.lemma_bool_c "eq-i+" [for_t] PA.proof);
add_clause [proxy; Lit.neg a; Lit.neg b] add_clause [proxy; Lit.neg a; Lit.neg b]
(if is_xor then A.lemma_bool_c "xor-i" [t_proxy; t_b] (pr_p1 PA.proof pr_def @@
else A.lemma_bool_c "eq-i-" [t_proxy]); if is_xor then A.lemma_bool_c "xor-i" [for_t; t_b] PA.proof
else A.lemma_bool_c "eq-i-" [for_t] PA.proof);
proxy proxy
in in
@ -279,57 +282,66 @@ module Make(A : ARG) : S with module A = A = struct
| B_and l -> | B_and l ->
let t_subs = Iter.to_list l in let t_subs = Iter.to_list l in
let subs = List.map mk_lit t_subs in let subs = List.map PA.mk_lit_nopreproc t_subs in
let t_proxy, proxy = fresh_lit ~for_t:t ~mk_lit:PA.mk_lit ~pre:"and_" self in let t_proxy, proxy = fresh_lit ~for_t:t ~mk_lit:PA.mk_lit_nopreproc ~pre:"and_" self in
SI.define_const si ~const:t_proxy ~rhs:t; SI.define_const si ~const:t_proxy ~rhs:t;
SI.with_proof si (SI.P.define_term t_proxy t); let pr_def = SI.P.define_term t_proxy t PA.proof in
add_step pr_def;
(* add clauses *) (* add clauses *)
List.iter2 List.iter2
(fun t_u u -> (fun t_u u ->
PA.add_clause PA.add_clause
[Lit.neg proxy; u] [Lit.neg proxy; u]
(A.lemma_bool_c "and-e" [t_proxy; t_u])) (pr_p1 PA.proof pr_def @@ A.lemma_bool_c "and-e" [t; t_u] PA.proof))
t_subs subs; t_subs subs;
PA.add_clause (proxy :: List.map Lit.neg subs) PA.add_clause (proxy :: List.map Lit.neg subs)
(A.lemma_bool_c "and-i" [t_proxy]); (pr_p1 PA.proof pr_def @@ A.lemma_bool_c "and-i" [t] PA.proof);
Some proxy Some proxy
| B_or l -> | B_or l ->
let t_subs = Iter.to_list l in let t_subs = Iter.to_list l in
let subs = List.map mk_lit t_subs in let subs = List.map PA.mk_lit_nopreproc t_subs in
let t_proxy, proxy = fresh_lit ~for_t:t ~mk_lit:PA.mk_lit ~pre:"or_" self in let t_proxy, proxy = fresh_lit ~for_t:t ~mk_lit:PA.mk_lit_nopreproc ~pre:"or_" self in
SI.define_const si ~const:t_proxy ~rhs:t; SI.define_const si ~const:t_proxy ~rhs:t;
SI.with_proof si (SI.P.define_term t_proxy t); let pr_def = SI.P.define_term t_proxy t PA.proof in
add_step pr_def;
(* add clauses *) (* add clauses *)
List.iter2 List.iter2
(fun t_u u -> (fun t_u u ->
PA.add_clause [Lit.neg u; proxy] PA.add_clause [Lit.neg u; proxy]
(A.lemma_bool_c "or-i" [t_proxy; t_u])) (pr_p1 PA.proof pr_def @@
A.lemma_bool_c "or-i" [t; t_u] PA.proof))
t_subs subs; t_subs subs;
PA.add_clause (Lit.neg proxy :: subs) PA.add_clause (Lit.neg proxy :: subs)
(A.lemma_bool_c "or-e" [t_proxy]); (pr_p1 PA.proof pr_def @@ A.lemma_bool_c "or-e" [t] PA.proof);
Some proxy Some proxy
| B_imply (t_args, t_u) -> | B_imply (t_args, t_u) ->
(* transform into [¬args \/ u] on the fly *) (* transform into [¬args \/ u] on the fly *)
let t_args = Iter.to_list t_args in let t_args = Iter.to_list t_args in
let args = List.map (fun t -> Lit.neg (mk_lit t)) t_args in let args = List.map (fun t -> Lit.neg (PA.mk_lit_nopreproc t)) t_args in
let u = mk_lit t_u in let u = PA.mk_lit_nopreproc t_u in
let subs = u :: args in let subs = u :: args in
(* now the or-encoding *) (* now the or-encoding *)
let t_proxy, proxy = fresh_lit ~for_t:t ~mk_lit:PA.mk_lit ~pre:"implies_" self in let t_proxy, proxy =
fresh_lit ~for_t:t ~mk_lit:PA.mk_lit_nopreproc ~pre:"implies_" self in
SI.define_const si ~const:t_proxy ~rhs:t; SI.define_const si ~const:t_proxy ~rhs:t;
SI.with_proof si (SI.P.define_term t_proxy t); let pr_def = SI.P.define_term t_proxy t PA.proof in
add_step pr_def;
(* add clauses *) (* add clauses *)
List.iter2 List.iter2
(fun t_u u -> (fun t_u u ->
PA.add_clause [Lit.neg u; proxy] PA.add_clause [Lit.neg u; proxy]
(A.lemma_bool_c "imp-i" [t_proxy; t_u])) (pr_p1 PA.proof pr_def @@
A.lemma_bool_c "imp-i" [t_proxy; t_u] PA.proof))
(t_u::t_args) subs; (t_u::t_args) subs;
PA.add_clause (Lit.neg proxy :: subs) PA.add_clause (Lit.neg proxy :: subs)
(A.lemma_bool_c "imp-e" [t_proxy]); (pr_p1 PA.proof pr_def @@
A.lemma_bool_c "imp-e" [t_proxy] PA.proof);
Some proxy Some proxy
| B_ite _ | B_eq _ | B_neq _ -> None | B_ite _ | B_eq _ | B_neq _ -> None
@ -344,7 +356,7 @@ module Make(A : ARG) : S with module A = A = struct
let u = Lit.term lit in let u = Lit.term lit in
(* put sign back as a "not" *) (* put sign back as a "not" *)
let u = if Lit.sign lit then u else A.mk_bool self.tst (B_not u) in let u = if Lit.sign lit then u else A.mk_bool self.tst (B_not u) in
if T.equal u t then None else Some u if T.equal u t then None else Some (u, Iter.of_list !steps)
end end
(* check if new terms were added to the congruence closure, that can be turned (* check if new terms were added to the congruence closure, that can be turned