mirror of
https://github.com/c-cube/sidekick.git
synced 2025-12-09 20:55:39 -05:00
sat: use an atom array for clauses again
allocator is not worth the complexity, and has a lot of double indirections anyway.
This commit is contained in:
parent
8b94e8404f
commit
3aa25cb2a2
5 changed files with 79 additions and 154 deletions
|
|
@ -114,9 +114,7 @@ module Make(Plugin : PLUGIN)
|
|||
(* variable/atom store *)
|
||||
module Store = struct
|
||||
type cstore = {
|
||||
c_allocator : VecI32.t; (* storage for clause content *)
|
||||
c_idx: VecI32.t; (* clause -> idx in [c_allocator] *)
|
||||
c_len: VecI32.t; (* clause -> number of lits *)
|
||||
c_lits: atom array Vec.t; (* storage for clause content *)
|
||||
c_activity: Vec_float.t;
|
||||
c_premise: premise Vec.t;
|
||||
c_recycle_idx: VecI32.t; (* recycle clause numbers that were GC'd *)
|
||||
|
|
@ -154,10 +152,6 @@ module Make(Plugin : PLUGIN)
|
|||
| `Tiny -> 8
|
||||
| `Small -> 16
|
||||
| `Big -> 4096
|
||||
and size_alloc = match size with
|
||||
| `Tiny -> 256
|
||||
| `Small -> 4096
|
||||
| `Big -> 4 * 1024 * 1024
|
||||
in
|
||||
{ v_of_form = Form_tbl.create size_map;
|
||||
v_level = Vec.create();
|
||||
|
|
@ -172,9 +166,7 @@ module Make(Plugin : PLUGIN)
|
|||
a_watched=Vec.create();
|
||||
a_seen=Bitvec.create();
|
||||
c_store={
|
||||
c_allocator=VecI32.create ~cap:size_alloc ();
|
||||
c_idx=VecI32.create ();
|
||||
c_len=VecI32.create ();
|
||||
c_lits=Vec.create();
|
||||
c_activity=Vec_float.create();
|
||||
c_premise=Vec.create();
|
||||
c_recycle_idx=VecI32.create ~cap:0 ();
|
||||
|
|
@ -293,8 +285,6 @@ module Make(Plugin : PLUGIN)
|
|||
val premise : store -> t -> premise
|
||||
|
||||
val n_atoms : store -> t -> int
|
||||
val atom : store -> t -> int -> atom
|
||||
val set_atom : store -> t -> int -> atom -> unit
|
||||
|
||||
val visited : store -> t -> bool
|
||||
val set_visited : store -> t -> bool -> unit
|
||||
|
|
@ -302,8 +292,10 @@ module Make(Plugin : PLUGIN)
|
|||
val set_attached : store -> t -> bool -> unit
|
||||
val removable : store -> t -> bool
|
||||
val set_removable : store -> t -> bool -> unit
|
||||
|
||||
val dead : store -> t -> bool
|
||||
val set_dead : store -> t -> bool -> unit
|
||||
val dealloc : store -> t -> unit
|
||||
(** Delete the clause *)
|
||||
|
||||
val activity : store -> t -> float
|
||||
val set_activity : store -> t -> float -> unit
|
||||
|
|
@ -313,19 +305,8 @@ module Make(Plugin : PLUGIN)
|
|||
val for_all : store -> f:(atom -> bool) -> t -> bool
|
||||
val exists : store -> f:(atom -> bool) -> t -> bool
|
||||
|
||||
module Slice : sig
|
||||
type t
|
||||
|
||||
val size : t -> int
|
||||
val get : t -> int -> atom
|
||||
val set : t -> int -> atom -> unit
|
||||
val swap : t -> int -> int -> unit
|
||||
val iteri : t -> (int -> atom -> unit) -> unit
|
||||
end
|
||||
|
||||
val atoms_a : store -> t -> atom array (* allocates *)
|
||||
val atoms_a : store -> t -> atom array
|
||||
val atoms_l : store -> t -> atom list (* allocates *)
|
||||
val atoms_slice : store -> t -> Slice.t
|
||||
val atoms_iter : store -> t -> atom Iter.t
|
||||
|
||||
val short_name : store -> t -> string
|
||||
|
|
@ -336,24 +317,22 @@ module Make(Plugin : PLUGIN)
|
|||
|
||||
(* TODO: store watch lists inside clauses *)
|
||||
|
||||
let make_ (store:store) iter_atoms n_atoms premise : t =
|
||||
let make_a (store:store) (atoms:atom array) premise : t =
|
||||
let {
|
||||
c_allocator;
|
||||
c_recycle_idx; c_idx; c_len; c_activity; c_premise;
|
||||
c_recycle_idx; c_lits; c_activity; c_premise;
|
||||
c_attached; c_dead; c_removable; c_visited;
|
||||
} = store.c_store in
|
||||
(* allocate new ID *)
|
||||
let cid =
|
||||
if VecI32.is_empty c_recycle_idx then (
|
||||
VecI32.size c_idx
|
||||
Vec.size c_lits
|
||||
) else VecI32.pop c_recycle_idx
|
||||
in
|
||||
|
||||
(* allocate space *)
|
||||
begin
|
||||
let new_len = cid + 1 in
|
||||
VecI32.ensure_size c_idx new_len;
|
||||
VecI32.ensure_size c_len new_len;
|
||||
Vec.ensure_size c_lits [||] new_len;
|
||||
Vec_float.ensure_size c_activity new_len;
|
||||
Bitvec.ensure_size c_attached new_len;
|
||||
Bitvec.ensure_size c_dead new_len;
|
||||
|
|
@ -361,51 +340,24 @@ module Make(Plugin : PLUGIN)
|
|||
Bitvec.ensure_size c_visited new_len;
|
||||
end;
|
||||
|
||||
(* copy atoms *)
|
||||
begin
|
||||
let idx0 = VecI32.size c_allocator in
|
||||
VecI32.ensure_size c_allocator (VecI32.size c_allocator + n_atoms + 1);
|
||||
VecI32.set c_idx cid idx0;
|
||||
VecI32.set c_len cid n_atoms;
|
||||
let i = ref idx0 in
|
||||
iter_atoms (fun a -> VecI32.set c_allocator !i (a:atom:>int); incr i);
|
||||
end;
|
||||
|
||||
Vec.set c_lits cid atoms;
|
||||
Vec.set c_premise cid premise;
|
||||
|
||||
let c = of_int_unsafe cid in
|
||||
c
|
||||
|
||||
let make_a store atoms premise : t =
|
||||
let n = Array.length atoms in
|
||||
make_ store (Iter.of_array atoms) n premise
|
||||
|
||||
let make_l store atoms premise : t =
|
||||
let n = List.length atoms in
|
||||
make_ store (Iter.of_list atoms) n premise
|
||||
make_a store (Array.of_list atoms) premise
|
||||
|
||||
let make_vec store atoms premise : t =
|
||||
let n = Vec.size atoms in
|
||||
make_ store (Vec.to_seq atoms) n premise
|
||||
make_a store (Vec.to_array atoms) premise
|
||||
|
||||
let[@inline] n_atoms (store:store) (c:t) : int =
|
||||
VecI32.get store.c_store.c_len (c:t:>int)
|
||||
Array.length (Vec.get store.c_store.c_lits (c:t:>int))
|
||||
|
||||
let[@inline] atom (store:store) (c:t) (i:int) : atom =
|
||||
let idx0 = VecI32.get store.c_store.c_idx (c:t:>int) in
|
||||
Atom0.of_int_unsafe (VecI32.get store.c_store.c_allocator (idx0 + i))
|
||||
|
||||
let[@inline] set_atom store c i a : unit =
|
||||
let idx0 = VecI32.get store.c_store.c_idx (c:t:>int) in
|
||||
VecI32.set store.c_store.c_allocator (idx0 + i) (a:atom:>int)
|
||||
|
||||
let iter (store:store) ~f c =
|
||||
let {c_len; c_idx; c_allocator; _} = store.c_store in
|
||||
let idx0 = VecI32.get c_idx (c:t:>int) in
|
||||
let len = VecI32.get c_len (c:t:>int) in
|
||||
for i=0 to len-1 do
|
||||
f (Atom.of_int_unsafe (VecI32.get c_allocator (idx0 + i)))
|
||||
done
|
||||
let[@inline] iter (store:store) ~f c =
|
||||
let {c_lits; _} = store.c_store in
|
||||
Array.iter f (Vec.get c_lits (c:t:>int))
|
||||
|
||||
exception Early_exit
|
||||
|
||||
|
|
@ -422,17 +374,8 @@ module Make(Plugin : PLUGIN)
|
|||
with Early_exit -> true
|
||||
|
||||
let fold (store:store) ~f acc c =
|
||||
let {c_len; c_idx; c_allocator; _} = store.c_store in
|
||||
let idx0 = VecI32.get c_idx (c:t:>int) in
|
||||
let len = VecI32.get c_len (c:t:>int) in
|
||||
let rec fold acc i =
|
||||
if i=len then acc
|
||||
else (
|
||||
let x = Atom.of_int_unsafe (VecI32.get c_allocator (idx0 + i)) in
|
||||
fold (f acc x) (i+1)
|
||||
)
|
||||
in
|
||||
fold acc 0
|
||||
let {c_lits; _} = store.c_store in
|
||||
Array.fold_left f acc (Vec.get c_lits (c:t:>int))
|
||||
|
||||
let[@inline] premise store c = Vec.get store.c_store.c_premise (c:t:>int)
|
||||
let[@inline] visited store c = Bitvec.get store.c_store.c_visited (c:t:>int)
|
||||
|
|
@ -444,6 +387,13 @@ module Make(Plugin : PLUGIN)
|
|||
let[@inline] removable store c = Bitvec.get store.c_store.c_removable (c:t:>int)
|
||||
let[@inline] set_removable store c b = Bitvec.set store.c_store.c_removable (c:t:>int) b
|
||||
|
||||
(* FIXME: actually GC the clause, recycle index, and remove it
|
||||
somehow from the watch lists *)
|
||||
let dealloc store c : unit =
|
||||
set_dead store c true;
|
||||
assert (dead store c);
|
||||
()
|
||||
|
||||
let copy_flags store c1 c2 : unit =
|
||||
set_removable store c2 (removable store c1);
|
||||
()
|
||||
|
|
@ -464,24 +414,9 @@ module Make(Plugin : PLUGIN)
|
|||
assert (not (removable store c)); (* permanent by default *)
|
||||
c
|
||||
|
||||
module Slice = struct
|
||||
include VecI32.Slice
|
||||
let[@inline] get self i = Atom.of_int_unsafe (VecI32.Slice.get self i)
|
||||
let set = (VecI32.Slice.set :> t -> int -> atom -> unit)
|
||||
|
||||
let iteri self f =
|
||||
for i=0 to size self-1 do f i (get self i) done
|
||||
end
|
||||
|
||||
let atoms_slice store c : Slice.t =
|
||||
let n = n_atoms store c in
|
||||
let idx0 = VecI32.get store.c_store.c_idx (c:t:>int) in
|
||||
VecI32.slice store.c_store.c_allocator ~off:idx0 ~len:n
|
||||
|
||||
let atoms_a store c : atom array =
|
||||
Array.init (n_atoms store c) (fun i -> atom store c i)
|
||||
let atoms_l store c : _ list =
|
||||
CCList.init (n_atoms store c) (fun i -> atom store c i)
|
||||
let[@inline] atoms_a store c : atom array =
|
||||
Vec.get store.c_store.c_lits (c:t:>int)
|
||||
let atoms_l store c : _ list = Array.to_list (atoms_a store c)
|
||||
let atoms_iter store c = fun k -> iter store c ~f:k
|
||||
|
||||
let short_name store c =
|
||||
|
|
@ -1198,8 +1133,8 @@ module Make(Plugin : PLUGIN)
|
|||
assert (not @@ Clause.attached store c);
|
||||
Log.debugf 20 (fun k -> k "(@[sat.attach-clause@ %a@])" (Clause.debug store) c);
|
||||
(* TODO: change when watchlist are updated *)
|
||||
Vec.push (Atom.watched store (Atom.neg (Clause.atom store c 0))) c;
|
||||
Vec.push (Atom.watched store (Atom.neg (Clause.atom store c 1))) c;
|
||||
Vec.push (Atom.watched store (Atom.neg (Clause.atoms_a store c).(0))) c;
|
||||
Vec.push (Atom.watched store (Atom.neg (Clause.atoms_a store c).(1))) c;
|
||||
Clause.set_attached store c true;
|
||||
()
|
||||
|
||||
|
|
@ -1348,25 +1283,25 @@ module Make(Plugin : PLUGIN)
|
|||
)
|
||||
|
||||
(* move atoms assigned at high levels first *)
|
||||
let put_high_level_atoms_first (store:store) (slice:Clause.Slice.t) : unit =
|
||||
let module CS = Clause.Slice in
|
||||
CS.iteri slice
|
||||
let put_high_level_atoms_first (store:store) (arr:atom array) : unit =
|
||||
Array.iteri
|
||||
(fun i a ->
|
||||
if i>0 && Atom.level store a > Atom.level store (CS.get slice 0) then (
|
||||
if i>0 && Atom.level store a > Atom.level store arr.(0) then (
|
||||
(* move first to second, [i]-th to first, second to [i] *)
|
||||
if i=1 then (
|
||||
CS.swap slice 0 1;
|
||||
swap_arr arr 0 1;
|
||||
) else (
|
||||
let tmp = CS.get slice 1 in
|
||||
CS.set slice 1 (CS.get slice 0);
|
||||
CS.set slice 0 (CS.get slice 1);
|
||||
CS.set slice i tmp;
|
||||
let tmp = arr.(1) in
|
||||
arr.(1) <- arr.(0);
|
||||
arr.(0) <- arr.(i);
|
||||
arr.(i) <- tmp;
|
||||
);
|
||||
) else if i>1 &&
|
||||
Atom.level store a > Atom.level store (Clause.Slice.get slice 1)
|
||||
Atom.level store a > Atom.level store arr.(1)
|
||||
then (
|
||||
Clause.Slice.swap slice 1 i;
|
||||
swap_arr arr 1 i;
|
||||
))
|
||||
arr
|
||||
|
||||
(* find which level to backtrack to, given a conflict clause
|
||||
and a boolean stating whether it is
|
||||
|
|
@ -1448,8 +1383,9 @@ module Make(Plugin : PLUGIN)
|
|||
);
|
||||
Vec.push history clause;
|
||||
(* visit the current predecessors *)
|
||||
for j = 0 to Clause.n_atoms store clause - 1 do
|
||||
let q = Clause.atom store clause j in
|
||||
let atoms = Clause.atoms_a store clause in
|
||||
for j = 0 to Array.length atoms - 1 do
|
||||
let q = atoms.(j) in
|
||||
assert (Atom.is_true store q ||
|
||||
Atom.is_false store q &&
|
||||
Atom.level store q >= 0); (* unsure? *)
|
||||
|
|
@ -1589,7 +1525,8 @@ module Make(Plugin : PLUGIN)
|
|||
let clause =
|
||||
if history = [] then (
|
||||
(* just update order of atoms *)
|
||||
List.iteri (fun i a -> Clause.set_atom store c i a) atoms;
|
||||
let c_atoms = Clause.atoms_a store c in
|
||||
List.iteri (fun i a -> c_atoms.(i) <- a) atoms;
|
||||
c
|
||||
) else (
|
||||
let proof = if self.store_proof then History (c::history) else Empty_premise in
|
||||
|
|
@ -1621,7 +1558,7 @@ module Make(Plugin : PLUGIN)
|
|||
if Atom.is_false store a then (
|
||||
(* Atom need to be sorted in decreasing order of decision level,
|
||||
or we might watch the wrong literals. *)
|
||||
put_high_level_atoms_first store (Clause.atoms_slice store clause);
|
||||
put_high_level_atoms_first store (Clause.atoms_a store clause);
|
||||
attach_clause self clause;
|
||||
add_boolean_conflict self clause
|
||||
) else (
|
||||
|
|
@ -1658,25 +1595,26 @@ module Make(Plugin : PLUGIN)
|
|||
*)
|
||||
let propagate_in_clause (self:t) (a:atom) (c:clause) (i:int): watch_res =
|
||||
let store = self.store in
|
||||
let first = Clause.atom store c 0 in
|
||||
let atoms = Clause.atoms_a store c in
|
||||
let first = atoms.(0) in
|
||||
if first = Atom.neg a then (
|
||||
(* false lit must be at index 1 *)
|
||||
Clause.set_atom store c 0 (Clause.atom store c 1);
|
||||
Clause.set_atom store c 1 first;
|
||||
atoms.(0) <- atoms.(1);
|
||||
atoms.(1) <- first
|
||||
) else (
|
||||
assert (Atom.neg a = Clause.atom store c 1)
|
||||
assert (Atom.neg a = atoms.(1))
|
||||
);
|
||||
let first = Clause.atom store c 0 in
|
||||
let first = atoms.(0) in
|
||||
if Atom.is_true store first then (
|
||||
Watch_kept (* true clause, keep it in watched *)
|
||||
) else (
|
||||
try (* look for another watch lit *)
|
||||
for k = 2 to Clause.n_atoms store c - 1 do
|
||||
let ak = Clause.atom store c k in
|
||||
for k = 2 to Array.length atoms - 1 do
|
||||
let ak = atoms.(k) in
|
||||
if not (Atom.is_false store ak) then (
|
||||
(* watch lit found: update and exit *)
|
||||
Clause.set_atom store c 1 ak;
|
||||
Clause.set_atom store c k (Atom.neg a);
|
||||
atoms.(1) <- ak;
|
||||
atoms.(k) <- Atom.neg a;
|
||||
(* remove [c] from [a.watched], add it to [ak.neg.watched] *)
|
||||
Vec.push (Atom.watched store (Atom.neg ak)) c;
|
||||
assert (Vec.get (Atom.watched store a) i == c);
|
||||
|
|
@ -1933,8 +1871,7 @@ module Make(Plugin : PLUGIN)
|
|||
while Vec.size v > n_of_learnts do
|
||||
let c = Vec.pop_exn v in
|
||||
assert (Clause.removable store c);
|
||||
Clause.set_dead store c true;
|
||||
assert (Clause.dead store c);
|
||||
Clause.dealloc store c;
|
||||
incr n_collected;
|
||||
done;
|
||||
Log.debugf 3 (fun k->k "(@[sat.gc.done :collected %d@])" !n_collected);
|
||||
|
|
|
|||
|
|
@ -45,15 +45,27 @@ let resize_ t x size =
|
|||
t.data <- arr';
|
||||
()
|
||||
|
||||
let ensure_cap_ self x n =
|
||||
if n > Array.length self.data then (
|
||||
let new_size = max n (2 * Array.length self.data) in
|
||||
resize_ self x new_size
|
||||
)
|
||||
|
||||
let ensure_size self x n =
|
||||
ensure_cap_ self x n;
|
||||
if n > self.sz then (
|
||||
self.sz <- n
|
||||
)
|
||||
|
||||
(* grow the array *)
|
||||
let[@inline never] grow_to_double_size t x : unit =
|
||||
if Array.length t.data = Sys.max_array_length then (
|
||||
failwith "vec: cannot resize";
|
||||
);
|
||||
let size =
|
||||
let new_size =
|
||||
min Sys.max_array_length (max 4 (2 * Array.length t.data))
|
||||
in
|
||||
resize_ t x size;
|
||||
if new_size = t.sz then (
|
||||
failwith "vec: cannot resize";
|
||||
);
|
||||
resize_ t x new_size;
|
||||
assert (Array.length t.data > t.sz);
|
||||
()
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,9 @@ val to_seq : 'a t -> 'a Iter.t
|
|||
val clear : 'a t -> unit
|
||||
(** Set size to 0, doesn't free elements *)
|
||||
|
||||
val ensure_size : 'a t -> 'a -> int -> unit
|
||||
(** ensure size is at least [n] *)
|
||||
|
||||
val shrink : 'a t -> int -> unit
|
||||
(** [shrink vec sz] resets size of [vec] to [sz].
|
||||
Assumes [sz >=0 && sz <= size vec] *)
|
||||
|
|
|
|||
|
|
@ -82,22 +82,6 @@ let[@inline] iteri ~f self =
|
|||
|
||||
let[@inline] to_iter self k = iter ~f:k self
|
||||
|
||||
module Slice = struct
|
||||
type t = int32arr
|
||||
|
||||
let size = A.dim
|
||||
let[@inline] get self i = Int32.to_int (A.get self i)
|
||||
let[@inline] set self i x = A.set self i (Int32.of_int x)
|
||||
let[@inline] swap self i j =
|
||||
let tmp = get self i in
|
||||
set self i (get self j);
|
||||
set self j tmp
|
||||
end
|
||||
|
||||
let[@inline] slice self ~off ~len =
|
||||
assert (off+len < self.sz);
|
||||
A.sub self.data off len
|
||||
|
||||
let pp out self =
|
||||
Format.fprintf out "[@[";
|
||||
iteri self ~f:(fun i x -> if i>0 then Format.fprintf out ",@ "; Format.pp_print_int out x);
|
||||
|
|
|
|||
|
|
@ -34,17 +34,6 @@ val shrink : t -> int -> unit
|
|||
val iter : f:(int -> unit) -> t -> unit
|
||||
val iteri : f:(int -> int -> unit) -> t -> unit
|
||||
|
||||
module Slice : sig
|
||||
type t
|
||||
|
||||
val size : t -> int
|
||||
val get : t -> int -> int
|
||||
val set : t -> int -> int -> unit
|
||||
val swap : t -> int -> int -> unit
|
||||
end
|
||||
|
||||
val slice : t -> off:int -> len:int -> Slice.t
|
||||
|
||||
val to_iter : t -> int Iter.t
|
||||
|
||||
val pp : t CCFormat.printer
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue