mirror of
https://github.com/c-cube/sidekick.git
synced 2025-12-06 11:15:43 -05:00
wip: trace checking
- continue Drup checker - create sidekick-bin.lib to share parsers - parse problem+proof for sidekick-check
This commit is contained in:
parent
ec6fb0d5e1
commit
bef0c810d3
13 changed files with 266 additions and 33 deletions
20
src/bin-lib/Drup_lexer.mll
Normal file
20
src/bin-lib/Drup_lexer.mll
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
|
||||||
|
{
|
||||||
|
type token = EOF | ZERO | LIT of int | D
|
||||||
|
}
|
||||||
|
|
||||||
|
let number = ['1' - '9'] ['0' - '9']*
|
||||||
|
|
||||||
|
rule token = parse
|
||||||
|
| eof { EOF }
|
||||||
|
| "c" { comment lexbuf }
|
||||||
|
| [' ' '\t' '\r'] { token lexbuf }
|
||||||
|
| "d" { D }
|
||||||
|
| '\n' { Lexing.new_line lexbuf; token lexbuf }
|
||||||
|
| '0' { ZERO }
|
||||||
|
| '-'? number { LIT (int_of_string (Lexing.lexeme lexbuf)) }
|
||||||
|
| _ { Error.errorf "dimacs.lexer: unexpected char `%s`" (Lexing.lexeme lexbuf) }
|
||||||
|
|
||||||
|
and comment = parse
|
||||||
|
| '\n' { Lexing.new_line lexbuf; token lexbuf }
|
||||||
|
| [^'\n'] { comment lexbuf }
|
||||||
41
src/bin-lib/Drup_parser.ml
Normal file
41
src/bin-lib/Drup_parser.ml
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
|
||||||
|
module L = Drup_lexer
|
||||||
|
|
||||||
|
type event =
|
||||||
|
| Add of int list
|
||||||
|
| Delete of int list
|
||||||
|
|
||||||
|
type t = {
|
||||||
|
buf: Lexing.lexbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
let create (ic:in_channel) : t =
|
||||||
|
let buf = Lexing.from_channel ic in
|
||||||
|
{buf; }
|
||||||
|
|
||||||
|
let next self : _ option =
|
||||||
|
let rec get_clause acc = match L.token self.buf with
|
||||||
|
| L.EOF -> Error.errorf "unexpected EOF in a clause"
|
||||||
|
| L.ZERO -> List.rev acc
|
||||||
|
| L.LIT i -> get_clause (i::acc)
|
||||||
|
| _ -> Error.errorf "expected clause"
|
||||||
|
in
|
||||||
|
begin match L.token self.buf with
|
||||||
|
| L.EOF -> None
|
||||||
|
| L.D ->
|
||||||
|
let c = get_clause [] in
|
||||||
|
Some (Delete c)
|
||||||
|
| L.ZERO -> Some (Add [])
|
||||||
|
| L.LIT i ->
|
||||||
|
let c = get_clause [i] in
|
||||||
|
Some (Add c)
|
||||||
|
end
|
||||||
|
|
||||||
|
let iter self k =
|
||||||
|
let rec loop () =
|
||||||
|
match next self with
|
||||||
|
| None -> ()
|
||||||
|
| Some ev -> k ev; loop ()
|
||||||
|
in
|
||||||
|
loop ()
|
||||||
|
|
||||||
16
src/bin-lib/Drup_parser.mli
Normal file
16
src/bin-lib/Drup_parser.mli
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
|
||||||
|
(** {1 DRUP parser} *)
|
||||||
|
|
||||||
|
type t
|
||||||
|
|
||||||
|
type event =
|
||||||
|
| Add of int list
|
||||||
|
| Delete of int list
|
||||||
|
|
||||||
|
val create : in_channel -> t
|
||||||
|
|
||||||
|
val next : t -> event option
|
||||||
|
|
||||||
|
val iter : t -> event Iter.t
|
||||||
|
|
||||||
|
|
||||||
8
src/bin-lib/Sidekick_bin_lib.ml
Normal file
8
src/bin-lib/Sidekick_bin_lib.ml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
|
||||||
|
(** Library for the Sidekick executables *)
|
||||||
|
|
||||||
|
module Dimacs_lexer = Dimacs_lexer
|
||||||
|
module Dimacs_parser = Dimacs_parser
|
||||||
|
|
||||||
|
module Drup_lexer = Drup_lexer
|
||||||
|
module Drup_parser = Drup_parser
|
||||||
9
src/bin-lib/dune
Normal file
9
src/bin-lib/dune
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
|
||||||
|
(library
|
||||||
|
(name sidekick_bin_lib)
|
||||||
|
(public_name sidekick-bin.lib)
|
||||||
|
(synopsis "Utils for the sidekick binaries")
|
||||||
|
(libraries containers sidekick.util)
|
||||||
|
(flags :standard -warn-error -a+8 -open Sidekick_util))
|
||||||
|
|
||||||
|
(ocamllex (modules Dimacs_lexer Drup_lexer))
|
||||||
|
|
@ -3,5 +3,6 @@
|
||||||
(name main)
|
(name main)
|
||||||
(public_name sidekick-checker)
|
(public_name sidekick-checker)
|
||||||
(package sidekick-bin)
|
(package sidekick-bin)
|
||||||
(libraries containers sidekick.util sidekick.drup)
|
(libraries containers sidekick-bin.lib
|
||||||
|
sidekick.util sidekick.drup)
|
||||||
(flags :standard -warn-error -a+8 -open Sidekick_util))
|
(flags :standard -warn-error -a+8 -open Sidekick_util))
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,81 @@
|
||||||
|
|
||||||
|
module BL = Sidekick_bin_lib
|
||||||
|
module SDrup = Sidekick_drup
|
||||||
|
|
||||||
|
let clause_of_int_l atoms : SDrup.clause =
|
||||||
|
Array.of_list atoms
|
||||||
|
|> Array.map SDrup.Atom.of_int
|
||||||
|
|> SDrup.Clause.of_array
|
||||||
|
|
||||||
|
let check ?pb proof : bool =
|
||||||
|
let trace = SDrup.Trace.create() in
|
||||||
|
|
||||||
|
(* add problem to trace, if provided *)
|
||||||
|
begin match pb with
|
||||||
|
| None -> ()
|
||||||
|
| Some f when Filename.extension f = ".cnf" ->
|
||||||
|
CCIO.with_in f
|
||||||
|
(fun ic ->
|
||||||
|
let parser_ = BL.Dimacs_parser.create ic in
|
||||||
|
BL.Dimacs_parser.iter parser_
|
||||||
|
(fun atoms ->
|
||||||
|
let c = clause_of_int_l atoms in
|
||||||
|
SDrup.Trace.add_input_clause trace c))
|
||||||
|
| Some f ->
|
||||||
|
(* TODO: handle .cnf.gz *)
|
||||||
|
Error.errorf "unknown problem file extension '%s'" (Filename.extension f)
|
||||||
|
end;
|
||||||
|
|
||||||
|
(* add proof to trace *)
|
||||||
|
begin match proof with
|
||||||
|
| f when Filename.extension f = ".drup" ->
|
||||||
|
CCIO.with_in f
|
||||||
|
(fun ic ->
|
||||||
|
let p = BL.Drup_parser.create ic in
|
||||||
|
BL.Drup_parser.iter p
|
||||||
|
(function
|
||||||
|
| BL.Drup_parser.Add c ->
|
||||||
|
let c = clause_of_int_l c in
|
||||||
|
SDrup.Trace.add_clause trace c
|
||||||
|
| BL.Drup_parser.Delete c ->
|
||||||
|
let c = clause_of_int_l c in
|
||||||
|
SDrup.Trace.del_clause trace c))
|
||||||
|
| f ->
|
||||||
|
(* TODO: handle .drup.gz *)
|
||||||
|
Error.errorf "unknown proof file extension '%s'" (Filename.extension f)
|
||||||
|
end;
|
||||||
|
|
||||||
|
(* check proof *)
|
||||||
|
Log.debugf 1 (fun k->k"checking proof (%d steps)" (SDrup.Trace.size trace));
|
||||||
|
begin match SDrup.Fwd_check.check trace with
|
||||||
|
| Ok () -> true
|
||||||
|
| Error bad ->
|
||||||
|
assert (VecI32.size bad > 0);
|
||||||
|
let n0 = VecI32.get bad 0 in
|
||||||
|
Format.eprintf
|
||||||
|
"checking failed on %d events.@.@[<2>First failure is event[%d]:@ %a@]@."
|
||||||
|
(VecI32.size bad) n0
|
||||||
|
SDrup.Trace.pp_event (SDrup.Trace.get trace n0);
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
let () =
|
let () =
|
||||||
assert false
|
let files = ref [] in
|
||||||
|
let opts = [
|
||||||
|
"-d", Arg.Int Log.set_debug, " set debug level";
|
||||||
|
] |> Arg.align in
|
||||||
|
Printexc.record_backtrace true;
|
||||||
|
|
||||||
|
Arg.parse opts (fun f -> files := f :: !files) "checker [opt]* [file]+";
|
||||||
|
|
||||||
|
begin match List.rev !files with
|
||||||
|
| [pb; proof] ->
|
||||||
|
Log.debugf 1 (fun k->k"checker: problem `%s`, proof `%s`" pb proof);
|
||||||
|
let ok = check ~pb proof in
|
||||||
|
if not ok then exit 1
|
||||||
|
| [proof] ->
|
||||||
|
Log.debugf 1 (fun k->k"checker: proof `%s`" proof);
|
||||||
|
let ok = check ?pb:None proof in
|
||||||
|
if not ok then exit 1
|
||||||
|
| _ -> failwith "expected <problem>? <proof>"
|
||||||
|
end
|
||||||
|
|
|
||||||
|
|
@ -33,12 +33,22 @@ end = struct
|
||||||
end
|
end
|
||||||
type atom = Atom.t
|
type atom = Atom.t
|
||||||
|
|
||||||
type clause = atom array
|
module Clause : sig
|
||||||
module Clause = struct
|
type t
|
||||||
type t = clause
|
val size : t -> int
|
||||||
|
val get : t -> int -> atom
|
||||||
|
val iter : f:(atom -> unit) -> t -> unit
|
||||||
|
val pp : t Fmt.printer
|
||||||
|
val of_array : atom array -> t
|
||||||
|
end = struct
|
||||||
|
type t = atom array
|
||||||
|
let size = Array.length
|
||||||
|
let get = Array.get
|
||||||
let iter ~f c = Array.iter f c
|
let iter ~f c = Array.iter f c
|
||||||
let pp out (self:t) = Fmt.Dump.array Atom.pp out self
|
let pp out (self:t) = Fmt.Dump.array Atom.pp out self
|
||||||
|
let of_array a = a
|
||||||
end
|
end
|
||||||
|
type clause = Clause.t
|
||||||
|
|
||||||
module Trace : sig
|
module Trace : sig
|
||||||
type t
|
type t
|
||||||
|
|
@ -46,7 +56,7 @@ module Trace : sig
|
||||||
val create : unit -> t
|
val create : unit -> t
|
||||||
|
|
||||||
val add_clause : t -> clause -> unit
|
val add_clause : t -> clause -> unit
|
||||||
|
val add_input_clause : t -> clause -> unit
|
||||||
val del_clause : t -> clause -> unit
|
val del_clause : t -> clause -> unit
|
||||||
|
|
||||||
type event =
|
type event =
|
||||||
|
|
@ -56,6 +66,8 @@ module Trace : sig
|
||||||
|
|
||||||
val iteri : t -> f:(int -> event -> unit) -> unit
|
val iteri : t -> f:(int -> event -> unit) -> unit
|
||||||
val events : t -> event Iter.t
|
val events : t -> event Iter.t
|
||||||
|
val size : t -> int
|
||||||
|
val get : t -> int -> event
|
||||||
|
|
||||||
val pp_event : event Fmt.printer
|
val pp_event : event Fmt.printer
|
||||||
|
|
||||||
|
|
@ -74,18 +86,21 @@ end = struct
|
||||||
{ evs=Vec.create() }
|
{ evs=Vec.create() }
|
||||||
|
|
||||||
let add_clause self c = Vec.push self.evs (A c)
|
let add_clause self c = Vec.push self.evs (A c)
|
||||||
|
let add_input_clause self c = Vec.push self.evs (I c)
|
||||||
let del_clause self c = Vec.push self.evs (D c)
|
let del_clause self c = Vec.push self.evs (D c)
|
||||||
|
let get self i = Vec.get self.evs i
|
||||||
|
let size self = Vec.size self.evs
|
||||||
let events self = Vec.to_seq self.evs
|
let events self = Vec.to_seq self.evs
|
||||||
let iteri self ~f = Vec.iteri f self.evs
|
let iteri self ~f = Vec.iteri f self.evs
|
||||||
|
|
||||||
let pp_event out = function
|
let pp_event out = function
|
||||||
| I c -> Fmt.fprintf out "(@[input %a@])" Clause.pp c
|
| I c -> Fmt.fprintf out "(@[Input %a@])" Clause.pp c
|
||||||
| A c -> Fmt.fprintf out "(@[add %a@])" Clause.pp c
|
| A c -> Fmt.fprintf out "(@[Add %a@])" Clause.pp c
|
||||||
| D c -> Fmt.fprintf out "(@[del %a@])" Clause.pp c
|
| D c -> Fmt.fprintf out "(@[Del %a@])" Clause.pp c
|
||||||
|
|
||||||
let dump oc self : unit =
|
let dump oc self : unit =
|
||||||
let fpf = Printf.fprintf in
|
let fpf = Printf.fprintf in
|
||||||
let pp_c out c = Array.iter (fun a -> fpf oc "%d " (Atom.to_int a)) c; in
|
let pp_c out c = Clause.iter c ~f:(fun a -> fpf oc "%d " (Atom.to_int a)); in
|
||||||
Vec.iter
|
Vec.iter
|
||||||
(function
|
(function
|
||||||
| I c -> fpf oc "i %a0\n" pp_c c;
|
| I c -> fpf oc "i %a0\n" pp_c c;
|
||||||
|
|
@ -95,6 +110,20 @@ end = struct
|
||||||
self.evs
|
self.evs
|
||||||
end
|
end
|
||||||
|
|
||||||
|
(*
|
||||||
|
module Checker : sig
|
||||||
|
type t
|
||||||
|
|
||||||
|
val create : unit -> t
|
||||||
|
|
||||||
|
val add_clause : t -> clause -> unit
|
||||||
|
val remove_clause : t -> clause -> unit
|
||||||
|
end = struct
|
||||||
|
type t = {
|
||||||
|
clauses: unit Clause.Tbl.t;
|
||||||
|
}
|
||||||
|
*)
|
||||||
|
|
||||||
(** Forward checking.
|
(** Forward checking.
|
||||||
|
|
||||||
Each event is checked by reverse-unit propagation on previous events. *)
|
Each event is checked by reverse-unit propagation on previous events. *)
|
||||||
|
|
@ -129,15 +158,16 @@ end = struct
|
||||||
|
|
||||||
let ensure_atom_ self (a:atom) =
|
let ensure_atom_ self (a:atom) =
|
||||||
Bitvec.ensure_size self.assign (a:atom:>int);
|
Bitvec.ensure_size self.assign (a:atom:>int);
|
||||||
Vec.ensure_size self.watches ISet.empty (a:atom:>int);
|
(* size: 2+atom, because: 1+atom makes atom valid, and if it's positive,
|
||||||
|
2+atom is (¬atom)+1 *)
|
||||||
|
Vec.ensure_size self.watches ISet.empty (2+(a:atom:>int));
|
||||||
()
|
()
|
||||||
|
|
||||||
let[@inline] is_true self (a:atom) : bool =
|
let[@inline] is_true self (a:atom) : bool =
|
||||||
Bitvec.get self.assign (a:atom:>int)
|
Bitvec.get self.assign (a:atom:>int)
|
||||||
let[@inline] is_false self (a:atom) : bool = is_true self (Atom.neg a)
|
|
||||||
let[@inline] set_true self (a:atom) : unit =
|
|
||||||
Bitvec.set self.assign (a:atom:>int) true
|
|
||||||
|
|
||||||
|
let[@inline] is_false self (a:atom) : bool =
|
||||||
|
is_true self (Atom.neg a)
|
||||||
|
|
||||||
let add_watch_ self (a:atom) cid =
|
let add_watch_ self (a:atom) cid =
|
||||||
let set = Vec.get self.watches (a:atom:>int) in
|
let set = Vec.get self.watches (a:atom:>int) in
|
||||||
|
|
@ -149,6 +179,19 @@ end = struct
|
||||||
|
|
||||||
exception Conflict
|
exception Conflict
|
||||||
|
|
||||||
|
let raise_conflict_ self a =
|
||||||
|
Log.debugf 5 (fun k->k"conflict on atom %a" Atom.pp a);
|
||||||
|
raise Conflict
|
||||||
|
|
||||||
|
(* set atom to true *)
|
||||||
|
let set_atom_true (self:t) (a:atom) : unit =
|
||||||
|
if is_true self a then ()
|
||||||
|
else if is_false self a then raise_conflict_ self a
|
||||||
|
else (
|
||||||
|
Bitvec.set self.assign (a:atom:>int) true;
|
||||||
|
VecI32.push self.trail (a:atom:>int)
|
||||||
|
)
|
||||||
|
|
||||||
(* TODO *)
|
(* TODO *)
|
||||||
let propagate_in_clause_ (self:t) (cid:int) : unit =
|
let propagate_in_clause_ (self:t) (cid:int) : unit =
|
||||||
()
|
()
|
||||||
|
|
@ -169,20 +212,31 @@ end = struct
|
||||||
let with_restore_trail_ self f =
|
let with_restore_trail_ self f =
|
||||||
let trail_size0 = VecI32.size self.trail in
|
let trail_size0 = VecI32.size self.trail in
|
||||||
let ptr = self.trail_ptr in
|
let ptr = self.trail_ptr in
|
||||||
CCFun.finally
|
|
||||||
~h:(fun () ->
|
let restore () =
|
||||||
VecI32.shrink self.trail trail_size0;
|
(* unassign new literals *)
|
||||||
self.trail_ptr <- ptr)
|
for i=trail_size0 to VecI32.size self.trail - 1 do
|
||||||
~f
|
let a = Atom.of_int_unsafe (VecI32.get self.trail i) in
|
||||||
|
assert (is_true self a);
|
||||||
|
Bitvec.set self.assign (a:atom:>int) false;
|
||||||
|
done;
|
||||||
|
|
||||||
|
(* remove literals from trail *)
|
||||||
|
VecI32.shrink self.trail trail_size0;
|
||||||
|
self.trail_ptr <- ptr
|
||||||
|
in
|
||||||
|
|
||||||
|
CCFun.finally ~h:restore ~f
|
||||||
|
|
||||||
(* check event, return [true] if it's valid *)
|
(* check event, return [true] if it's valid *)
|
||||||
let check_ev (self:t) (ev:Trace.event) : bool =
|
let check_ev (self:t) i (ev:Trace.event) : bool =
|
||||||
Log.debugf 20 (fun k->k"(@[check-ev@ %a@])" Trace.pp_event ev);
|
Log.debugf 20 (fun k->k"(@[check-ev[%d]@ %a@])" i Trace.pp_event ev);
|
||||||
|
|
||||||
(* add clause to the state *)
|
(* add clause to the state *)
|
||||||
let add_c_ c =
|
let add_c_ (c:Clause.t) =
|
||||||
Array.iter (ensure_atom_ self) c;
|
Clause.iter c ~f:(ensure_atom_ self);
|
||||||
|
|
||||||
|
(* allocate clause *)
|
||||||
let cid =
|
let cid =
|
||||||
match Vec.pop_exn self.cs_recycle with
|
match Vec.pop_exn self.cs_recycle with
|
||||||
| cid ->
|
| cid ->
|
||||||
|
|
@ -193,8 +247,15 @@ end = struct
|
||||||
Vec.push self.cs c;
|
Vec.push self.cs c;
|
||||||
cid
|
cid
|
||||||
in
|
in
|
||||||
add_watch_ self (Atom.neg c.(0)) cid;
|
|
||||||
add_watch_ self (Atom.neg c.(1)) cid;
|
begin match Clause.size c with
|
||||||
|
| 0 -> ()
|
||||||
|
| 1 ->
|
||||||
|
set_atom_true self (Clause.get c 0);
|
||||||
|
| _ ->
|
||||||
|
add_watch_ self (Atom.neg (Clause.get c 0)) cid;
|
||||||
|
add_watch_ self (Atom.neg (Clause.get c 1)) cid;
|
||||||
|
end;
|
||||||
propagate_in_clause_ self cid; (* make sure watches are valid *)
|
propagate_in_clause_ self cid; (* make sure watches are valid *)
|
||||||
()
|
()
|
||||||
in
|
in
|
||||||
|
|
@ -216,8 +277,7 @@ end = struct
|
||||||
if is_true self a then raise_notrace Conflict; (* tautology *)
|
if is_true self a then raise_notrace Conflict; (* tautology *)
|
||||||
let a' = Atom.neg a in
|
let a' = Atom.neg a in
|
||||||
if is_true self a' then () else (
|
if is_true self a' then () else (
|
||||||
VecI32.push self.trail (a':atom:>int);
|
set_atom_true self a'
|
||||||
set_true self a'
|
|
||||||
));
|
));
|
||||||
propagate_ self;
|
propagate_ self;
|
||||||
false
|
false
|
||||||
|
|
@ -237,9 +297,10 @@ end = struct
|
||||||
(* check each event in turn *)
|
(* check each event in turn *)
|
||||||
Trace.iteri trace
|
Trace.iteri trace
|
||||||
~f:(fun i ev ->
|
~f:(fun i ev ->
|
||||||
let ok = check_ev self ev in
|
let ok = check_ev self i ev in
|
||||||
if not ok then (
|
if not ok then (
|
||||||
Log.debugf 10 (fun k->k"(@[check.step.fail@ :n %d@ %a@])" i Trace.pp_event ev);
|
Log.debugf 10
|
||||||
|
(fun k->k"(@[check.step.fail@ event[%d]@ :def %a@])" i Trace.pp_event ev);
|
||||||
VecI32.push self.errors i
|
VecI32.push self.errors i
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
(modes native)
|
(modes native)
|
||||||
(libraries containers iter result sidekick.sat 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
|
||||||
sidekick.memtrace)
|
sidekick.memtrace sidekick-bin.lib)
|
||||||
(flags :standard -safe-string -color always -open Sidekick_util))
|
(flags :standard -safe-string -color always -open Sidekick_util))
|
||||||
|
|
||||||
(rule
|
(rule
|
||||||
|
|
@ -18,4 +18,3 @@
|
||||||
(with-stdout-to %{targets}
|
(with-stdout-to %{targets}
|
||||||
(echo "let version = {git|%{version:sidekick}|git}"))))
|
(echo "let version = {git|%{version:sidekick}|git}"))))
|
||||||
|
|
||||||
(ocamllex (modules Dimacs_lexer))
|
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ module SAT = Sidekick_sat.Make_pure_sat(Arg)
|
||||||
|
|
||||||
module Dimacs = struct
|
module Dimacs = struct
|
||||||
open Sidekick_base
|
open Sidekick_base
|
||||||
|
module BL = Sidekick_bin_lib
|
||||||
module T = Term
|
module T = Term
|
||||||
|
|
||||||
let parse_file (solver:SAT.t) (file:string) : (unit, string) result =
|
let parse_file (solver:SAT.t) (file:string) : (unit, string) result =
|
||||||
|
|
@ -30,8 +31,8 @@ module Dimacs = struct
|
||||||
try
|
try
|
||||||
CCIO.with_in file
|
CCIO.with_in file
|
||||||
(fun ic ->
|
(fun ic ->
|
||||||
let p = Dimacs_parser.create ic in
|
let p = BL.Dimacs_parser.create ic in
|
||||||
Dimacs_parser.iter p
|
BL.Dimacs_parser.iter p
|
||||||
(fun c ->
|
(fun c ->
|
||||||
let atoms = List.rev_map get_lit c in
|
let atoms = List.rev_map get_lit c in
|
||||||
SAT.add_clause solver atoms ());
|
SAT.add_clause solver atoms ());
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue