feat: basic proof production for QF_UF (wip)

This commit is contained in:
Simon Cruanes 2021-04-04 18:50:23 -04:00
parent fbc3ec7ed6
commit 57bf44dfb9
7 changed files with 63 additions and 29 deletions

View file

@ -373,14 +373,14 @@ module Make (A: CC_ARG)
n.n_expl <- FL_none; n.n_expl <- FL_none;
end end
let raise_conflict (cc:t) ~th (acts:actions) (e:lit list) : _ = let raise_conflict_ (cc:t) ~th (acts:actions) (e:lit list) p : _ =
Profile.instant "cc.conflict"; Profile.instant "cc.conflict";
(* clear tasks queue *) (* clear tasks queue *)
Vec.clear cc.pending; Vec.clear cc.pending;
Vec.clear cc.combine; Vec.clear cc.combine;
List.iter (fun f -> f cc ~th e) cc.on_conflict; List.iter (fun f -> f cc ~th e) cc.on_conflict;
Stat.incr cc.count_conflict; Stat.incr cc.count_conflict;
Actions.raise_conflict acts e P.default Actions.raise_conflict acts e p
let[@inline] all_classes cc : repr Iter.t = let[@inline] all_classes cc : repr Iter.t =
T_tbl.values cc.tbl T_tbl.values cc.tbl
@ -652,7 +652,14 @@ module Make (A: CC_ARG)
let lits = explain_decompose cc ~th [] e_ab in let lits = explain_decompose cc ~th [] e_ab in
let lits = explain_pair cc ~th lits a ra in let lits = explain_pair cc ~th lits a ra in
let lits = explain_pair cc ~th lits b rb in let lits = explain_pair cc ~th lits b rb in
raise_conflict cc ~th:!th acts (List.rev_map Lit.neg lits) let proof =
let lits =
Iter.of_list lits
|> Iter.map (fun lit -> Lit.term lit, Lit.sign lit)
in
P.make_cc lits
in
raise_conflict_ cc ~th:!th acts (List.rev_map Lit.neg lits) proof
); );
(* We will merge [r_from] into [r_into]. (* We will merge [r_from] into [r_into].
we try to ensure that [size ra <= size rb] in general, but always we try to ensure that [size ra <= size rb] in general, but always
@ -833,7 +840,14 @@ module Make (A: CC_ARG)
let th = ref true in let th = ref true in
let lits = explain_decompose cc ~th [] expl in let lits = explain_decompose cc ~th [] expl in
let lits = List.rev_map Lit.neg lits in let lits = List.rev_map Lit.neg lits in
raise_conflict cc ~th:!th acts lits let proof =
let lits =
Iter.of_list lits
|> Iter.map (fun lit -> Lit.term lit, Lit.sign lit)
in
P.make_cc lits
in
raise_conflict_ cc ~th:!th acts lits proof
let merge cc n1 n2 expl = let merge cc n1 n2 expl =
Log.debugf 5 Log.debugf 5

View file

@ -146,10 +146,11 @@ module type TERM = sig
end end
module type PROOF = sig module type PROOF = sig
type term
type t type t
val pp : t Fmt.printer val pp : t Fmt.printer
val default : t val default : t
val make_cc : (term*bool) Iter.t -> t
end end
(** Literals (** Literals
@ -192,9 +193,10 @@ end
is inconsistent *) is inconsistent *)
module type CC_ACTIONS = sig module type CC_ACTIONS = sig
module T : TERM module T : TERM
module P : PROOF
module Lit : LIT with module T = T module Lit : LIT with module T = T
module P : PROOF with type term = T.Term.t
type t type t
(** An action handle. It is used by the congruence closure (** An action handle. It is used by the congruence closure
to perform the actions below. How it performs the actions to perform the actions below. How it performs the actions
@ -220,7 +222,7 @@ end
(** Arguments to a congruence closure's implementation *) (** Arguments to a congruence closure's implementation *)
module type CC_ARG = sig module type CC_ARG = sig
module T : TERM module T : TERM
module P : PROOF module P : PROOF with type term = T.Term.t
module Lit : LIT with module T = T module Lit : LIT with module T = T
module Actions : CC_ACTIONS with module T=T and module P = P and module Lit = Lit module Actions : CC_ACTIONS with module T=T and module P = P and module Lit = Lit
@ -231,7 +233,7 @@ end
(** Signature of the congruence closure *) (** Signature of the congruence closure *)
module type CC_S = sig module type CC_S = sig
module T : TERM module T : TERM
module P : PROOF module P : PROOF with type term = T.Term.t
module Lit : LIT with module T = T module Lit : LIT with module T = T
module Actions : CC_ACTIONS with module T = T and module Lit = Lit and module P = P module Actions : CC_ACTIONS with module T = T and module Lit = Lit and module P = P
type term_state = T.Term.state type term_state = T.Term.state
@ -491,7 +493,7 @@ end
new lemmas, propagate literals, access the congruence closure, etc. *) new lemmas, propagate literals, access the congruence closure, etc. *)
module type SOLVER_INTERNAL = sig module type SOLVER_INTERNAL = sig
module T : TERM module T : TERM
module P : PROOF module P : PROOF with type term = T.Term.t
type ty = T.Ty.t type ty = T.Ty.t
type term = T.Term.t type term = T.Term.t
@ -728,7 +730,8 @@ end
Theory implementors will mostly interact with {!SOLVER_INTERNAL}. *) Theory implementors will mostly interact with {!SOLVER_INTERNAL}. *)
module type SOLVER = sig module type SOLVER = sig
module T : TERM module T : TERM
module P : PROOF module P : PROOF with type term = T.Term.t
module Lit : LIT with module T = T module Lit : LIT with module T = T
module Solver_internal module Solver_internal
@ -854,6 +857,7 @@ module type SOLVER = sig
type t type t
val check : t -> unit val check : t -> unit
val pp_dot : t Fmt.printer val pp_dot : t Fmt.printer
val pp : t Fmt.printer
end end
type proof = Proof.t type proof = Proof.t

View file

@ -21,7 +21,7 @@ exception Out_of_space
let file = ref "" let file = ref ""
let p_cnf = ref false let p_cnf = ref false
let p_dot_proof = ref "" let p_dot_proof = ref ""
let p_proof_print = ref false let p_proof = ref false
let p_model = ref false let p_model = ref false
let check = ref false let check = ref false
let time_limit = ref 300. let time_limit = ref 300.
@ -71,6 +71,8 @@ let argspec = Arg.align [
"--no-restarts", Arg.Clear restarts, " disable restarts"; "--no-restarts", Arg.Clear restarts, " disable restarts";
"--dot", Arg.Set_string p_dot_proof, " if provided, print the dot proof in the given file"; "--dot", Arg.Set_string p_dot_proof, " if provided, print the dot proof in the given file";
"--stat", Arg.Set p_stat, " print statistics"; "--stat", Arg.Set p_stat, " print statistics";
"--proof", Arg.Set p_proof, " print proof";
"--no-proof", Arg.Clear p_proof, " do not print proof";
"--model", Arg.Set p_model, " print model"; "--model", Arg.Set p_model, " print model";
"--no-model", Arg.Clear p_model, " do not print model"; "--no-model", Arg.Clear p_model, " do not print model";
"--gc-stat", Arg.Set p_gc_stat, " outputs statistics about the GC"; "--gc-stat", Arg.Set p_gc_stat, " outputs statistics about the GC";
@ -151,7 +153,8 @@ let main () =
Process.th_lra; Process.th_lra;
] ]
in in
Process.Solver.create ~store_proof:!check ~theories tst () () let store_proof = !check || !p_proof in
Process.Solver.create ~store_proof ~theories tst () ()
in in
if !check then ( if !check then (
(* might have to check conflicts *) (* might have to check conflicts *)
@ -171,7 +174,8 @@ let main () =
Process.process_stmt Process.process_stmt
~hyps ~gc:!gc ~restarts:!restarts ~pp_cnf:!p_cnf ~hyps ~gc:!gc ~restarts:!restarts ~pp_cnf:!p_cnf
~time:!time_limit ~memory:!size_limit ~time:!time_limit ~memory:!size_limit
?dot_proof ~pp_model:!p_model ~check:!check ~progress:!p_progress ?dot_proof ~pp_proof:!p_proof ~pp_model:!p_model
~check:!check ~progress:!p_progress
solver) solver)
() input () input
with Exit -> with Exit ->

View file

@ -13,7 +13,7 @@ module Log = Msat.Log
module type ARG = sig module type ARG = sig
open Sidekick_core open Sidekick_core
module T : TERM module T : TERM
module P : PROOF module P : PROOF with type term = T.Term.t
val cc_view : T.Term.t -> (T.Fun.t, T.Term.t, T.Term.t Iter.t) CC_view.t val cc_view : T.Term.t -> (T.Fun.t, T.Term.t, T.Term.t Iter.t) CC_view.t
@ -435,6 +435,7 @@ module Make(A : ARG)
include Sat_solver.Proof include Sat_solver.Proof
module Dot = Msat_backend.Dot.Make(Sat_solver)(Msat_backend.Dot.Default(Sat_solver)) module Dot = Msat_backend.Dot.Make(Sat_solver)(Msat_backend.Dot.Default(Sat_solver))
let pp_dot = Dot.pp let pp_dot = Dot.pp
let pp out (_self:t) = Fmt.string out "<Proof>" (* TODO *)
end end
type proof = Proof.t type proof = Proof.t

View file

@ -17,11 +17,7 @@ module Solver_arg = struct
let cc_view = Term.cc_view let cc_view = Term.cc_view
let is_valid_literal _ = true let is_valid_literal _ = true
module P = struct module P = Proof
type t = Default
let default=Default
let pp out _ = Fmt.string out "default"
end
end end
module Solver = Sidekick_msat_solver.Make(Solver_arg) module Solver = Sidekick_msat_solver.Make(Solver_arg)
@ -147,6 +143,7 @@ let solve
?gc:_ ?gc:_
?restarts:_ ?restarts:_
?dot_proof ?dot_proof
?(pp_proof=false)
?(pp_model=false) ?(pp_model=false)
?(check=false) ?(check=false)
?time:_ ?memory:_ ?(progress=false) ?time:_ ?memory:_ ?(progress=false)
@ -179,12 +176,19 @@ let solve
let t3 = Sys.time () -. t2 in let t3 = Sys.time () -. t2 in
Format.printf "Sat (%.3f/%.3f/%.3f)@." t1 (t2-.t1) t3; Format.printf "Sat (%.3f/%.3f/%.3f)@." t1 (t2-.t1) t3;
| Solver.Unsat {proof;_} -> | Solver.Unsat {proof;_} ->
let proof_opt =
if check||pp_proof then Lazy.force proof
else None
in
if check then ( if check then (
match proof with match proof_opt with
| lazy (Some p) -> | Some p ->
Profile.with_ "unsat.check" (fun () -> Solver.Proof.check p); Profile.with_ "unsat.check" (fun () -> Solver.Proof.check p);
| _ -> () | _ -> ()
); );
begin match dot_proof, proof with begin match dot_proof, proof with
| None, _ -> () | None, _ -> ()
| Some file, lazy (Some p) -> | Some file, lazy (Some p) ->
@ -197,8 +201,18 @@ let solve
Format.pp_print_flush fmt (); flush oc) Format.pp_print_flush fmt (); flush oc)
| _ -> () | _ -> ()
end; end;
let t3 = Sys.time () -. t2 in let t3 = Sys.time () -. t2 in
Format.printf "Unsat (%.3f/%.3f/%.3f)@." t1 (t2-.t1) t3; Format.printf "Unsat (%.3f/%.3f/%.3f)@." t1 (t2-.t1) t3;
(* TODO: allow to print proof into a file, more realistic for checking *)
if pp_proof then (
match proof_opt with
| None -> Error.errorf "cannot print proof, none was generated"
| Some p ->
Fmt.printf "(@[proof@ %a@])@." Solver.Proof.pp p;
);
| Solver.Unknown reas -> | Solver.Unknown reas ->
Format.printf "Unknown (:reason %a)" Solver.Unknown.pp reas Format.printf "Unknown (:reason %a)" Solver.Unknown.pp reas
end end
@ -206,7 +220,7 @@ let solve
(* process a single statement *) (* process a single statement *)
let process_stmt let process_stmt
?hyps ?hyps
?gc ?restarts ?(pp_cnf=false) ?dot_proof ?pp_model ?(check=false) ?gc ?restarts ?(pp_cnf=false) ?dot_proof ?pp_proof ?pp_model ?(check=false)
?time ?memory ?progress ?time ?memory ?progress
(solver:Solver.t) (solver:Solver.t)
(stmt:Statement.t) : unit or_error = (stmt:Statement.t) : unit or_error =
@ -240,7 +254,8 @@ let process_stmt
List.map (fun (sign,t) -> Solver.mk_atom_t solver ~sign t) l List.map (fun (sign,t) -> Solver.mk_atom_t solver ~sign t) l
in in
solve solve
?gc ?restarts ?dot_proof ~check ?pp_model ?time ?memory ?progress ?gc ?restarts ?dot_proof ~check ?pp_proof ?pp_model
?time ?memory ?progress
~assumptions ?hyps ~assumptions ?hyps
solver; solver;
E.return() E.return()

View file

@ -25,6 +25,7 @@ val process_stmt :
?restarts:bool -> ?restarts:bool ->
?pp_cnf:bool -> ?pp_cnf:bool ->
?dot_proof:string -> ?dot_proof:string ->
?pp_proof:bool ->
?pp_model:bool -> ?pp_model:bool ->
?check:bool -> ?check:bool ->
?time:float -> ?time:float ->

View file

@ -1,7 +1,6 @@
(** {1 Process Statements} *) (** {1 Process Statements} *)
module ID = Sidekick_base_term.ID module ID = Sidekick_base_term.ID
module Fmt = CCFormat
module E = CCResult module E = CCResult
module Loc = Smtlib_utils.V_2_6.Loc module Loc = Smtlib_utils.V_2_6.Loc
module Parse_ast = Smtlib_utils.V_2_6.Ast module Parse_ast = Smtlib_utils.V_2_6.Ast
@ -9,11 +8,7 @@ module Process = Process
module Solver = Process.Solver module Solver = Process.Solver
module Term = Sidekick_base_term.Term module Term = Sidekick_base_term.Term
module Stmt = Sidekick_base_term.Statement module Stmt = Sidekick_base_term.Statement
module Proof = Proof
module Proof = struct
type t = Proof_default
let default = Proof_default
end
type 'a or_error = ('a, string) CCResult.t type 'a or_error = ('a, string) CCResult.t