use a pure sat solver for cnf files

This commit is contained in:
Simon Cruanes 2021-07-18 02:46:04 -04:00
parent 4cb8887639
commit 1aa160fe56
10 changed files with 124 additions and 79 deletions

View file

@ -14,7 +14,6 @@ depends: [
"dune" { >= "1.1" } "dune" { >= "1.1" }
"containers" { >= "3.0" & < "4.0" } "containers" { >= "3.0" & < "4.0" }
"iter" { >= "1.0" & < "2.0" } "iter" { >= "1.0" & < "2.0" }
"msat" { >= "0.9" < "0.10" }
"ocaml" { >= "4.04" } "ocaml" { >= "4.04" }
"alcotest" {with-test} "alcotest" {with-test}
"odoc" {with-doc} "odoc" {with-doc}

View file

@ -36,15 +36,15 @@ module Default(S : Sidekick_sat.S) = struct
let hyp_info c = let hyp_info c =
"hypothesis", Some "LIGHTBLUE", "hypothesis", Some "LIGHTBLUE",
[ fun fmt () -> Format.fprintf fmt "%s" @@ Clause.name c] [ fun fmt () -> Format.fprintf fmt "%s" @@ Clause.short_name c]
let lemma_info c = let lemma_info c =
"lemma", Some "BLUE", "lemma", Some "BLUE",
[ fun fmt () -> Format.fprintf fmt "%s" @@ Clause.name c] [ fun fmt () -> Format.fprintf fmt "%s" @@ Clause.short_name c]
let assumption_info c = let assumption_info c =
"assumption", Some "PURPLE", "assumption", Some "PURPLE",
[ fun fmt () -> Format.fprintf fmt "%s" @@ Clause.name c] [ fun fmt () -> Format.fprintf fmt "%s" @@ Clause.short_name c]
end end
@ -57,7 +57,7 @@ module Make(S : Sidekick_sat.S)(A : Arg with type atom := S.atom
module Clause = S.Clause module Clause = S.Clause
module P = S.Proof module P = S.Proof
let node_id n = Clause.name n.P.conclusion let node_id n = Clause.short_name n.P.conclusion
let proof_id p = node_id (P.expand p) let proof_id p = node_id (P.expand p)
let res_nn_id n1 n2 = node_id n1 ^ "_" ^ node_id n2 ^ "_res" let res_nn_id n1 n2 = node_id n1 ^ "_" ^ node_id n2 ^ "_res"
let res_np_id n1 n2 = node_id n1 ^ "_" ^ proof_id n2 ^ "_res" let res_np_id n1 n2 = node_id n1 ^ "_" ^ proof_id n2 ^ "_res"

View file

@ -4,7 +4,7 @@
(name main) (name main)
(public_name sidekick) (public_name sidekick)
(package sidekick-bin) (package sidekick-bin)
(libraries containers iter result msat sidekick.core sidekick-base (libraries containers iter result sidekick.sat sidekick.core sidekick-base
sidekick.msat-solver sidekick-bin.smtlib sidekick.tef) sidekick.msat-solver sidekick-bin.smtlib sidekick.tef)
(flags :standard -safe-string -color always -open Sidekick_util)) (flags :standard -safe-string -color always -open Sidekick_util))

View file

@ -4,14 +4,14 @@ Copyright 2014 Guillaume Bury
Copyright 2014 Simon Cruanes Copyright 2014 Simon Cruanes
*) *)
open CCResult.Infix
module E = CCResult module E = CCResult
module Fmt = CCFormat module Fmt = CCFormat
module Term = Sidekick_base.Term module Term = Sidekick_base.Term
module Solver = Sidekick_smtlib.Solver module Solver = Sidekick_smtlib.Solver
module Process = Sidekick_smtlib.Process module Process = Sidekick_smtlib.Process
open E.Infix
type 'a or_error = ('a, string) E.t type 'a or_error = ('a, string) E.t
exception Out_of_time exception Out_of_time
@ -87,39 +87,6 @@ let argspec = Arg.align [
"--debug", Arg.Int Msat.Log.set_debug, "<lvl> sets the debug verbose level"; "--debug", Arg.Int Msat.Log.set_debug, "<lvl> sets the debug verbose level";
] |> List.sort compare ] |> List.sort compare
module Dimacs = struct
open Sidekick_base
module T = Term
let parse_file tst (file:string) : Statement.t list or_error =
let atoms = Util.Int_tbl.create 32 in
let get_lit i =
let v =
match Util.Int_tbl.find atoms (abs i) with
| x -> Term.const tst x
| exception Not_found ->
let f = Sidekick_base.Fun.mk_undef_const
(ID.makef "%d" (abs i)) (Ty.bool()) in
Util.Int_tbl.add atoms (abs i) f;
Term.const tst f
in
if i<0 then Term.not_ tst v else v
in
try
CCIO.with_in file
(fun ic ->
let p = Dimacs_parser.create ic in
let stmts = ref [] in
Dimacs_parser.iter p
(fun c ->
let lits = List.rev_map get_lit c in
stmts := Statement.Stmt_assert_clause lits :: !stmts);
stmts := Statement.Stmt_check_sat [] :: !stmts;
Ok (List.rev !stmts))
with e ->
E.of_exn_trace e
end
(* Limits alarm *) (* Limits alarm *)
let check_limits () = let check_limits () =
let t = Sys.time () in let t = Sys.time () in
@ -130,25 +97,12 @@ let check_limits () =
else if s > !size_limit then else if s > !size_limit then
raise Out_of_space raise Out_of_space
let main () = let main_smt ~dot_proof () : _ result =
Sidekick_tef.setup();
at_exit Sidekick_tef.teardown;
CCFormat.set_color_default true;
(* Administrative duties *)
Arg.parse argspec input_file usage;
if !file = "" then (
Arg.usage argspec usage;
exit 2
);
let dot_proof = if !p_dot_proof = "" then None else Some !p_dot_proof in
check := !check || CCOpt.is_some dot_proof; (* dot requires a proof *)
let al = Gc.create_alarm check_limits in
Util.setup_gc();
let tst = Term.create ~size:4_096 () in let tst = Term.create ~size:4_096 () in
let is_cnf = Filename.check_suffix !file ".cnf" in
let solver = let solver =
let theories = let theories =
if is_cnf then [] else [ (* TODO: probes, to load only required theories *)
[
Process.th_bool; Process.th_bool;
Process.th_data; Process.th_data;
Process.th_lra; Process.th_lra;
@ -163,8 +117,7 @@ let main () =
Solver.add_theory solver Process.Check_cc.theory; Solver.add_theory solver Process.Check_cc.theory;
); );
begin begin
if is_cnf then Dimacs.parse_file tst !file Sidekick_smtlib.parse tst !file
else Sidekick_smtlib.parse tst !file
end end
>>= fun input -> >>= fun input ->
(* process statements *) (* process statements *)
@ -186,6 +139,35 @@ let main () =
if !p_stat then ( if !p_stat then (
Format.printf "%a@." Solver.pp_stats solver; Format.printf "%a@." Solver.pp_stats solver;
); );
res
let main_cnf () : _ result =
let solver = Pure_sat_solver.SAT.create ~size:`Big () in
Pure_sat_solver.Dimacs.parse_file solver !file >>= fun () ->
Pure_sat_solver.solve solver
let main () =
Sidekick_tef.setup();
at_exit Sidekick_tef.teardown;
CCFormat.set_color_default true;
(* Administrative duties *)
Arg.parse argspec input_file usage;
if !file = "" then (
Arg.usage argspec usage;
exit 2
);
let dot_proof = if !p_dot_proof = "" then None else Some !p_dot_proof in
check := !check || CCOpt.is_some dot_proof; (* dot requires a proof *)
let al = Gc.create_alarm check_limits in
Util.setup_gc();
let is_cnf = Filename.check_suffix !file ".cnf" in
let res =
if is_cnf then (
main_cnf ()
) else (
main_smt ~dot_proof ()
)
in
if !p_gc_stat then ( if !p_gc_stat then (
Printf.printf "(gc_stats\n%t)\n" Gc.print_stat; Printf.printf "(gc_stats\n%t)\n" Gc.print_stat;
); );

View file

@ -0,0 +1,58 @@
(* pure SAT solver *)
module E = CCResult
module SS = Sidekick_sat
module Arg = struct
module Formula = struct
type t = int
let norm t = if t>0 then t, SS.Same_sign else -t, SS.Negated
let abs = abs
let sign t = t>0
let equal = CCInt.equal
let hash = CCHash.int
let neg x = -x
let pp = Fmt.int
end
type proof=unit
end
module SAT = Sidekick_sat.Make_pure_sat(Arg)
module Dimacs = struct
open Sidekick_base
module T = Term
let parse_file (solver:SAT.t) (file:string) : (unit, string) result =
let get_lit i : SAT.atom = SAT.make_atom solver i in
try
CCIO.with_in file
(fun ic ->
let p = Dimacs_parser.create ic in
Dimacs_parser.iter p
(fun c ->
let atoms = List.rev_map get_lit c in
SAT.add_clause solver atoms ());
Ok ())
with e ->
E.of_exn_trace e
end
let solve (solver:SAT.t) : (unit, string) result =
let res =
Profile.with_ "solve" (fun () -> SAT.solve solver)
in
let t2 = Sys.time () in
Printf.printf "\r"; flush stdout;
begin match res with
| SAT.Sat _ ->
let t3 = Sys.time () -. t2 in
Format.printf "Sat (%.3f/%.3f)@." t2 t3;
| SAT.Unsat _ ->
let t3 = Sys.time () -. t2 in
Format.printf "Unsat (%.3f/%.3f)@." t2 t3;
end;
Ok ()

View file

@ -54,4 +54,6 @@ let pp_lbool out = function
exception No_proof = Solver_intf.No_proof exception No_proof = Solver_intf.No_proof
module Solver = Solver
module Make_cdcl_t = Solver.Make_cdcl_t module Make_cdcl_t = Solver.Make_cdcl_t
module Make_pure_sat = Solver.Make_pure_sat

View file

@ -1,8 +1,8 @@
module type PLUGIN = sig module type PLUGIN = sig
val has_theory : bool val has_theory : bool
(** Is this a CDCL(T) plugin or mcsat plugin? (** [true] iff the solver is parametrized by a theory, not just
i.e does it have theories *) pure SAT. *)
include Solver_intf.PLUGIN_CDCL_T include Solver_intf.PLUGIN_CDCL_T
end end
@ -11,7 +11,7 @@ module type S = Solver_intf.S
module type PLUGIN_CDCL_T = Solver_intf.PLUGIN_CDCL_T module type PLUGIN_CDCL_T = Solver_intf.PLUGIN_CDCL_T
let invalid_argf fmt = let invalid_argf fmt =
Format.kasprintf (fun msg -> invalid_arg ("msat: " ^ msg)) fmt Format.kasprintf (fun msg -> invalid_arg ("sidekick.sat: " ^ msg)) fmt
module Make(Plugin : PLUGIN) module Make(Plugin : PLUGIN)
= struct = struct
@ -66,6 +66,8 @@ module Make(Plugin : PLUGIN)
(* Constructors *) (* Constructors *)
module MF = Hashtbl.Make(Formula) module MF = Hashtbl.Make(Formula)
(* state for variables. declared separately because it simplifies our
life below, as it's required to construct new atoms/variables *)
type st = { type st = {
f_map: var MF.t; f_map: var MF.t;
vars: var Vec.t; vars: var Vec.t;
@ -89,12 +91,12 @@ module Make(Plugin : PLUGIN)
let get_elt st i = Vec.get st.vars i let get_elt st i = Vec.get st.vars i
let iter_elt st f = Vec.iter f st.vars let iter_elt st f = Vec.iter f st.vars
let name_of_clause c = match c.cpremise with let kind_of_clause c = match c.cpremise with
| Hyp _ -> "H" ^ string_of_int c.cid | Hyp _ -> "H"
| Lemma _ -> "T" ^ string_of_int c.cid | Lemma _ -> "T"
| Local -> "L" ^ string_of_int c.cid | Local -> "L"
| History _ -> "C" ^ string_of_int c.cid | History _ -> "C"
| Empty_premise -> string_of_int c.cid | Empty_premise -> ""
(* some boolean flags for variables, used as masks *) (* some boolean flags for variables, used as masks *)
let seen_var = 0b1 let seen_var = 0b1
@ -224,7 +226,7 @@ module Make(Plugin : PLUGIN)
| n, Some Decision -> | n, Some Decision ->
Format.fprintf fmt "@@%d" n Format.fprintf fmt "@@%d" n
| n, Some Bcp c -> | n, Some Bcp c ->
Format.fprintf fmt "->%d/%s" n (name_of_clause c) Format.fprintf fmt "->%d/%s/%d" n (kind_of_clause c) c.cid
| n, Some (Bcp_lazy _) -> | n, Some (Bcp_lazy _) ->
Format.fprintf fmt "->%d/<lazy>" n Format.fprintf fmt "->%d/<lazy>" n
@ -268,7 +270,6 @@ module Make(Plugin : PLUGIN)
let make ~flags l premise = make_a ~flags (Array.of_list l) premise let make ~flags l premise = make_a ~flags (Array.of_list l) premise
let empty = make [] (History []) let empty = make [] (History [])
let name = name_of_clause
let[@inline] equal c1 c2 = c1.cid = c2.cid let[@inline] equal c1 c2 = c1.cid = c2.cid
let[@inline] hash c = Hashtbl.hash c.cid let[@inline] hash c = Hashtbl.hash c.cid
let[@inline] atoms c = c.atoms let[@inline] atoms c = c.atoms
@ -311,20 +312,24 @@ module Make(Plugin : PLUGIN)
let equal = equal let equal = equal
end) end)
let short_name c = Printf.sprintf "%s%d" (kind_of_clause c) c.cid
let pp fmt c = let pp fmt c =
Format.fprintf fmt "%s : %a" (name c) Atom.pp_a c.atoms Format.fprintf fmt "(cl[%s%d] : %a" (kind_of_clause c) c.cid Atom.pp_a c.atoms
let debug_premise out = function let debug_premise out = function
| Hyp _ -> Format.fprintf out "hyp" | Hyp _ -> Format.fprintf out "hyp"
| Lemma _ -> Format.fprintf out "th_lemma" | Lemma _ -> Format.fprintf out "th_lemma"
| Local -> Format.fprintf out "local" | Local -> Format.fprintf out "local"
| History v -> | History v ->
List.iter (fun c -> Format.fprintf out "%s,@ " (name_of_clause c)) v Format.fprintf out "(@[res";
| Empty_premise -> Format.fprintf out "<no premise>" List.iter (fun c -> Format.fprintf out "@ %s%d," (kind_of_clause c) c.cid) v;
Format.fprintf out "@])"
| Empty_premise -> Format.fprintf out "none"
let debug out ({atoms=arr; cpremise=cp;_}as c) = let debug out ({atoms=arr; cpremise=cp;_}as c) =
Format.fprintf out "%s@[<hov>{@[<hov>%a@]}@ cpremise={@[<hov>%a@]}@]" Format.fprintf out
(name c) Atom.debug_a arr debug_premise cp "(@[cl[%s%d]@ {@[<hov>%a@]}@ :premise %a@])"
(kind_of_clause c) c.cid Atom.debug_a arr debug_premise cp
end end
module Proof = struct module Proof = struct
@ -774,7 +779,6 @@ module Make(Plugin : PLUGIN)
st.on_conflict <- on_conflict; st.on_conflict <- on_conflict;
st st
let[@inline] st t = t.st
let[@inline] nb_clauses st = Vec.size st.clauses_hyps let[@inline] nb_clauses st = Vec.size st.clauses_hyps
let[@inline] decision_level st = Vec.size st.var_levels let[@inline] decision_level st = Vec.size st.var_levels

View file

@ -341,8 +341,8 @@ module type S = sig
val atoms : t -> atom array val atoms : t -> atom array
val atoms_l : t -> atom list val atoms_l : t -> atom list
val equal : t -> t -> bool val equal : t -> t -> bool
val name : t -> string
val short_name : t -> string
val pp : t printer val pp : t printer
module Tbl : Hashtbl.S with type key = t module Tbl : Hashtbl.S with type key = t

View file

@ -1,7 +1,7 @@
(library (library
(name sidekick_smtlib) (name sidekick_smtlib)
(public_name sidekick-bin.smtlib) (public_name sidekick-bin.smtlib)
(libraries containers zarith msat sidekick.core sidekick.util (libraries containers zarith sidekick.core sidekick.util
sidekick-base sidekick-base.solver sidekick-base sidekick-base.solver
msat.backend smtlib-utils msat.backend smtlib-utils
sidekick.tef) sidekick.tef)

View file

@ -1,4 +1,4 @@
(library (library
(name sidekick_util) (name sidekick_util)
(public_name sidekick.util) (public_name sidekick.util)
(libraries containers iter msat sidekick.sigs)) (libraries containers iter sidekick.sigs))