mirror of
https://github.com/c-cube/sidekick.git
synced 2025-12-07 03:35:38 -05:00
155 lines
3.3 KiB
OCaml
155 lines
3.3 KiB
OCaml
(*
|
|
MSAT is free software, using the Apache license, see file LICENSE
|
|
Copyright 2014 Guillaume Bury
|
|
Copyright 2014 Simon Cruanes
|
|
*)
|
|
|
|
module Fsmt = struct
|
|
|
|
exception Invalid_var
|
|
|
|
type var = string
|
|
type t =
|
|
| Fresh of int
|
|
| Equal of var * var
|
|
| Distinct of var * var
|
|
|
|
let dummy = Fresh 0
|
|
|
|
let max_fresh = ref 0
|
|
let fresh () =
|
|
incr max_fresh;
|
|
Fresh !max_fresh
|
|
|
|
let mk_var i =
|
|
if i <> "" then
|
|
i
|
|
else
|
|
raise Invalid_var
|
|
|
|
let mk_eq i j = Equal (mk_var i, mk_var j)
|
|
let mk_neq i j = Distinct (mk_var i, mk_var j)
|
|
|
|
let neg = function
|
|
| Fresh i -> Fresh (-i)
|
|
| Equal (a, b) -> Distinct (a, b)
|
|
| Distinct (a, b) -> Equal (a, b)
|
|
|
|
let norm = function
|
|
| Fresh i -> Fresh (abs i), i < 0
|
|
| Equal (a, b) -> Equal (min a b, max a b), false
|
|
| Distinct (a, b) -> Equal (min a b, max a b), true
|
|
|
|
(* Only used after normalisation, so usual functions should work *)
|
|
let hash = Hashtbl.hash
|
|
let equal = (=)
|
|
let compare = Pervasives.compare
|
|
|
|
let s = Hstring.make ""
|
|
let label _ = s
|
|
let add_label _ _ = ()
|
|
|
|
let print fmt = function
|
|
| Fresh i -> Format.fprintf fmt "%sv%d" (if i < 0 then "¬ " else "") (abs i)
|
|
| Equal (a, b) -> Format.fprintf fmt "%s = %s" a b
|
|
| Distinct (a, b) -> Format.fprintf fmt "%s <> %s" a b
|
|
|
|
end
|
|
|
|
module Tseitin = Tseitin.Make(Fsmt)
|
|
|
|
module Tsmt = struct
|
|
|
|
module U = Unionfind.Make(String)
|
|
|
|
type formula = Fsmt.t
|
|
type proof = unit
|
|
type slice = {
|
|
start : int;
|
|
length : int;
|
|
get : int -> formula;
|
|
push : formula -> formula list -> proof -> unit;
|
|
}
|
|
type level = U.t
|
|
|
|
type res =
|
|
| Sat of level
|
|
| Unsat of formula list * proof
|
|
|
|
let dummy = U.empty
|
|
|
|
let env = ref U.empty
|
|
|
|
let current_level () = !env
|
|
|
|
let temp = ref []
|
|
|
|
let assume s =
|
|
try
|
|
for i = s.start to s.start + s.length - 1 do
|
|
match s.get i with
|
|
| Fsmt.Fresh _ -> ()
|
|
| Fsmt.Equal (i, j) as f ->
|
|
temp := f :: !temp;
|
|
env := U.union !env i j
|
|
| Fsmt.Distinct (i, j) as f ->
|
|
temp := f :: !temp;
|
|
env := U.forbid !env i j
|
|
| _ -> assert false
|
|
done;
|
|
Sat (current_level ())
|
|
with U.Unsat ->
|
|
match !temp with
|
|
| _ :: _ -> Unsat (List.rev_map Fsmt.neg !temp, ())
|
|
| _ -> assert false
|
|
|
|
let backtrack l = env := l
|
|
|
|
end
|
|
|
|
module Make(Dummy:sig end) = struct
|
|
module SmtSolver = Solver.Make(Fsmt)(Tsmt)
|
|
|
|
type atom = Fsmt.t
|
|
type clause = SmtSolver.St.clause
|
|
type proof = SmtSolver.Proof.proof
|
|
|
|
type res =
|
|
| Sat
|
|
| Unsat
|
|
|
|
let _i = ref 0
|
|
|
|
let make_eq = Fsmt.mk_eq
|
|
let make_neq = Fsmt.mk_neq
|
|
|
|
let neg = Fsmt.neg
|
|
|
|
let hash = Fsmt.hash
|
|
let equal = Fsmt.equal
|
|
let compare = Fsmt.compare
|
|
|
|
let solve () =
|
|
try
|
|
SmtSolver.solve ();
|
|
Sat
|
|
with SmtSolver.Unsat -> Unsat
|
|
|
|
let assume l =
|
|
incr _i;
|
|
try
|
|
SmtSolver.assume l !_i
|
|
with SmtSolver.Unsat -> ()
|
|
|
|
let get_proof () =
|
|
SmtSolver.Proof.learn (SmtSolver.history ());
|
|
match SmtSolver.unsat_conflict () with
|
|
| None -> assert false
|
|
| Some c -> SmtSolver.Proof.prove_unsat c
|
|
|
|
let unsat_core = SmtSolver.Proof.unsat_core
|
|
|
|
let print_atom = Fsmt.print
|
|
let print_clause = SmtSolver.St.print_clause
|
|
let print_proof = SmtSolver.Proof.print_dot
|
|
end
|