mirror of
https://github.com/c-cube/sidekick.git
synced 2025-12-06 03:05:31 -05:00
258 lines
6.6 KiB
OCaml
258 lines
6.6 KiB
OCaml
(* pure SAT solver *)
|
|
|
|
open Sidekick_core
|
|
module E = CCResult
|
|
module SS = Sidekick_sat
|
|
|
|
(* FIXME
|
|
(* TODO: on the fly compression *)
|
|
module Proof : sig
|
|
include module type of struct
|
|
include Proof_trace
|
|
end
|
|
|
|
type in_memory
|
|
|
|
val create_in_memory : unit -> t * in_memory
|
|
val to_string : in_memory -> string
|
|
val to_chan : out_channel -> in_memory -> unit
|
|
val create_to_file : string -> t
|
|
val close : t -> unit
|
|
|
|
type event = Sidekick_bin_lib.Drup_parser.event =
|
|
| Input of int list
|
|
| Add of int list
|
|
| Delete of int list
|
|
|
|
val iter_events : in_memory -> event Iter.t
|
|
end = struct
|
|
include Proof_trace
|
|
module PT = Proof_term
|
|
|
|
let bpf = Printf.bprintf
|
|
let fpf = Printf.fprintf
|
|
|
|
type lit = Lit.t
|
|
type in_memory = Buffer.t
|
|
|
|
let to_string = Buffer.contents
|
|
|
|
(*
|
|
type t =
|
|
| Dummy
|
|
| Inner of in_memory
|
|
| Out of { oc: out_channel; close: unit -> unit }
|
|
*)
|
|
|
|
let[@inline] emit_lits_buf_ buf lits = lits (fun i -> bpf buf "%d " i)
|
|
let[@inline] emit_lits_out_ oc lits = lits (fun i -> fpf oc "%d " i)
|
|
|
|
let create_in_memory () =
|
|
let buf = Buffer.create 1_024 in
|
|
let pr =
|
|
(module struct
|
|
let enabled () = true
|
|
let add_step s = assert false
|
|
|
|
(* TODO: helper to flatten?
|
|
let pt : PT.t = s () in
|
|
match pt.
|
|
*)
|
|
|
|
(* TODO *)
|
|
let add_unsat _ = ()
|
|
|
|
(* TODO *)
|
|
let delete _ = ()
|
|
end : DYN)
|
|
in
|
|
pr, buf
|
|
|
|
(*
|
|
module Rule = struct
|
|
type nonrec lit = lit
|
|
type nonrec rule = rule
|
|
type nonrec step_id = step_id
|
|
|
|
let sat_input_clause lits self =
|
|
match self with
|
|
| Dummy -> ()
|
|
| Inner buf ->
|
|
bpf buf "i ";
|
|
emit_lits_buf_ buf lits;
|
|
bpf buf "0\n"
|
|
| Out { oc; _ } ->
|
|
fpf oc "i ";
|
|
emit_lits_out_ oc lits;
|
|
fpf oc "0\n"
|
|
|
|
let sat_redundant_clause lits ~hyps:_ self =
|
|
match self with
|
|
| Dummy -> ()
|
|
| Inner buf ->
|
|
bpf buf "r ";
|
|
emit_lits_buf_ buf lits;
|
|
bpf buf "0\n"
|
|
| Out { oc; _ } ->
|
|
fpf oc "r ";
|
|
emit_lits_out_ oc lits;
|
|
fpf oc "0\n"
|
|
|
|
let sat_unsat_core _ _ = ()
|
|
end
|
|
|
|
let del_clause () lits self =
|
|
match self with
|
|
| Dummy -> ()
|
|
| Inner buf ->
|
|
bpf buf "d ";
|
|
emit_lits_buf_ buf lits;
|
|
bpf buf "0\n"
|
|
| Out { oc; _ } ->
|
|
fpf oc "d ";
|
|
emit_lits_out_ oc lits;
|
|
fpf oc "0\n"
|
|
|
|
|
|
let create_in_memory () : t * in_memory =
|
|
let buf = Buffer.create 1_024 in
|
|
Inner buf, buf
|
|
|
|
let create_to_file file =
|
|
let oc, close =
|
|
match Filename.extension file with
|
|
| ".gz" ->
|
|
let cmd = Printf.sprintf "gzip -c - > \"%s\"" (String.escaped file) in
|
|
Log.debugf 1 (fun k -> k "proof file: command is %s" cmd);
|
|
let oc = Unix.open_process_out cmd in
|
|
oc, fun () -> ignore (Unix.close_process_out oc : Unix.process_status)
|
|
| ".drup" ->
|
|
let oc = open_out_bin file in
|
|
oc, fun () -> close_out_noerr oc
|
|
| s -> Error.errorf "unknown file extension '%s'" s
|
|
in
|
|
Out { oc; close }
|
|
|
|
let close = function
|
|
| Dummy | Inner _ -> ()
|
|
| Out { close; oc } ->
|
|
flush oc;
|
|
close ()
|
|
|
|
let to_string = Buffer.contents
|
|
let to_chan = Buffer.output_buffer
|
|
|
|
module DP = Sidekick_bin_lib.Drup_parser
|
|
|
|
type event = DP.event =
|
|
| Input of int list
|
|
| Add of int list
|
|
| Delete of int list
|
|
|
|
(* parse the proof back *)
|
|
let iter_events (self : in_memory) : DP.event Iter.t =
|
|
let dp = DP.create_string (to_string self) in
|
|
DP.iter dp
|
|
|
|
*)
|
|
end
|
|
*)
|
|
|
|
module I_const : sig
|
|
val make : Term.store -> int -> Lit.t
|
|
end = struct
|
|
type Const.view += I of int
|
|
|
|
let ops =
|
|
(module struct
|
|
let equal a b =
|
|
match a, b with
|
|
| I a, I b -> a = b
|
|
| _ -> false
|
|
|
|
let hash = function
|
|
| I i -> Hash.int i
|
|
| _ -> assert false
|
|
|
|
let pp out = function
|
|
| I i -> Fmt.int out i
|
|
| _ -> assert false
|
|
end : Const.DYN_OPS)
|
|
|
|
let make tst i : Lit.t =
|
|
let t = Term.const tst @@ Const.make (I (abs i)) ops ~ty:(Term.bool tst) in
|
|
Lit.atom ~sign:(i > 0) t
|
|
end
|
|
|
|
module SAT = Sidekick_sat
|
|
|
|
module Dimacs = struct
|
|
open Sidekick_base
|
|
module BL = Sidekick_bin_lib
|
|
module T = Term
|
|
|
|
let parse_file (solver : SAT.t) (tst : Term.store) (file : string) :
|
|
(unit, string) result =
|
|
try
|
|
CCIO.with_in file (fun ic ->
|
|
let p = BL.Dimacs_parser.create ic in
|
|
BL.Dimacs_parser.iter p (fun c ->
|
|
(* convert on the fly *)
|
|
let c = List.map (I_const.make tst) c in
|
|
SAT.add_input_clause solver c);
|
|
Ok ())
|
|
with e -> E.of_exn_trace e
|
|
end
|
|
|
|
(* FIXME
|
|
let check_proof (proof : Proof.in_memory) : bool =
|
|
Profile.with_ "pure-sat.check-proof" @@ fun () ->
|
|
let module SDRUP = Sidekick_drup.Make () in
|
|
let store = SDRUP.Clause.create () in
|
|
let checker = SDRUP.Checker.create store in
|
|
let ok = ref true in
|
|
|
|
let tr_clause c =
|
|
let c = List.rev_map SDRUP.Atom.of_int_dimacs c in
|
|
SDRUP.Clause.of_list store c
|
|
in
|
|
|
|
Proof.iter_events proof (function
|
|
| Proof.Input c ->
|
|
let c = tr_clause c in
|
|
SDRUP.Checker.add_clause checker c
|
|
| Proof.Add c ->
|
|
let c = tr_clause c in
|
|
if not (SDRUP.Checker.is_valid_drup checker c) then ok := false;
|
|
SDRUP.Checker.add_clause checker c
|
|
| Proof.Delete c ->
|
|
let c = tr_clause c in
|
|
SDRUP.Checker.del_clause checker c);
|
|
!ok
|
|
*)
|
|
|
|
let start = Sys.time ()
|
|
|
|
let solve ?(check = false) ?in_memory_proof (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;
|
|
(match res with
|
|
| SAT.Sat _ ->
|
|
let t3 = Sys.time () in
|
|
Format.printf "Sat (%.3f/%.3f)@." (t2 -. start) (t3 -. t2)
|
|
| SAT.Unsat _ ->
|
|
if check then (
|
|
match in_memory_proof with
|
|
| None ->
|
|
Error.errorf "Cannot validate proof, no in-memory proof provided"
|
|
| Some _proof ->
|
|
let ok = true (* FIXME check_proof proof *) in
|
|
if not ok then Error.errorf "Proof validation failed"
|
|
);
|
|
|
|
let t3 = Sys.time () in
|
|
Format.printf "Unsat (%.3f/%.3f)@." (t2 -. start) (t3 -. t2));
|
|
Ok ()
|