wip: clause pools

This commit is contained in:
Simon Cruanes 2021-08-31 09:30:28 -04:00
parent 4a2367b1bd
commit 16bb65ebfa
No known key found for this signature in database
GPG key ID: 4AC01D0849AA62B6
5 changed files with 92 additions and 44 deletions

View file

@ -645,6 +645,7 @@ module type SOLVER_INTERNAL = sig
type term = T.Term.t type term = T.Term.t
type term_store = T.Term.store type term_store = T.Term.store
type ty_store = T.Ty.store type ty_store = T.Ty.store
type clause_pool
type proof type proof
type dproof = proof -> unit type dproof = proof -> unit
(** Delayed proof. This is used to build a proof step on demand. *) (** Delayed proof. This is used to build a proof step on demand. *)

View file

@ -27,11 +27,6 @@ let pp_lbool out = function
| L_false -> Format.fprintf out "false" | L_false -> Format.fprintf out "false"
| L_undefined -> Format.fprintf out "undefined" | L_undefined -> Format.fprintf out "undefined"
type 'a clause_lifetime = 'a Solver_intf.clause_lifetime =
| CL_keep
| CL_can_gc
| CL_use_allocator of 'a
exception No_proof = Solver_intf.No_proof exception No_proof = Solver_intf.No_proof
module Solver = Solver module Solver = Solver

View file

@ -621,7 +621,7 @@ module Make(Plugin : PLUGIN)
and clause_pool = and clause_pool =
| CP_gc of { | CP_gc of {
size: int; size: int;
clauses: CVec.t; clauses: clause Vec.t; (* TODO: when we can sort CVec.t, come back *)
descr: string; descr: string;
} }
| CP_scoped of { | CP_scoped of {
@ -710,9 +710,9 @@ module Make(Plugin : PLUGIN)
let descr = function let descr = function
| CP_gc {descr; _} | CP_scoped {descr; _} -> descr | CP_gc {descr; _} | CP_scoped {descr; _} -> descr
let gc (solver:solver) (self:t) : unit = let gc (_solver:solver) (self:t) : unit =
match self with match self with
| CP_gc {clauses; size; descr} -> | CP_gc {clauses=_; size=_; descr} ->
Log.debugf 10 (fun k->k"(@[clause-pool.gc@ %s@])" descr); Log.debugf 10 (fun k->k"(@[clause-pool.gc@ %s@])" descr);
() (* FIXME *) () (* FIXME *)
| CP_scoped _ -> () | CP_scoped _ -> ()
@ -741,16 +741,16 @@ module Make(Plugin : PLUGIN)
let add solver (self:t) (c:clause) = let add solver (self:t) (c:clause) =
match self with match self with
| CP_gc { clauses; size; descr=_} -> | CP_gc { clauses; size; descr=_} ->
if CVec.size clauses >= size then ( if Vec.size clauses >= size then (
gc solver self; gc solver self;
); );
CVec.push clauses c Vec.push clauses c
| CP_scoped {clauses; _} -> | CP_scoped {clauses; _} ->
CVec.push clauses c CVec.push clauses c
let iter self ~f = match self with let iter self ~f = match self with
| CP_gc {clauses; _} | CP_scoped {clauses; _} -> | CP_gc {clauses; _} -> Vec.iter f clauses
CVec.iter clauses ~f | CP_scoped {clauses; _} -> CVec.iter ~f clauses
end end
let[@inline] decision_level st = VecI32.size st.var_levels let[@inline] decision_level st = VecI32.size st.var_levels
@ -1266,9 +1266,22 @@ module Make(Plugin : PLUGIN)
cr_is_uip = is_uip; cr_is_uip = is_uip;
} }
(* FIXME: take clause pool *) (* Get the correct vector to insert a clause in. *)
let[@inline] add_clause_to_vec_ ?pool self c =
if Clause.removable self.store c && Clause.n_atoms self.store c > 2 then (
(* add clause to some pool/set of clauses *)
begin match pool with
| Some pool ->
Clause_pool.add self pool c
| None ->
Vec.push self.clauses_learnt c
end
) else (
CVec.push self.clauses_hyps c
)
(* add the learnt clause to the clause database, propagate, etc. *) (* add the learnt clause to the clause database, propagate, etc. *)
let record_learnt_clause (self:t) (confl:clause) (cr:conflict_res): unit = let record_learnt_clause (self:t) ?pool (confl:clause) (cr:conflict_res): unit =
let store = self.store in let store = self.store in
begin match cr.cr_learnt with begin match cr.cr_learnt with
| [| |] -> assert false | [| |] -> assert false
@ -1289,9 +1302,8 @@ module Make(Plugin : PLUGIN)
| _ -> | _ ->
let fuip = cr.cr_learnt.(0) in let fuip = cr.cr_learnt.(0) in
let lclause = Clause.make_a store ~removable:true cr.cr_learnt in let lclause = Clause.make_a store ~removable:true cr.cr_learnt in
if Clause.n_atoms store lclause > 2 then (
CVec.push self.clauses_learnt lclause; (* potentially gc'able *) add_clause_to_vec_ ?pool self lclause;
);
attach_clause self lclause; attach_clause self lclause;
clause_bump_activity self lclause; clause_bump_activity self lclause;
(match self.on_learnt with Some f -> f self lclause | None -> ()); (match self.on_learnt with Some f -> f self lclause | None -> ());
@ -1322,17 +1334,9 @@ module Make(Plugin : PLUGIN)
cancel_until self (max cr.cr_backtrack_lvl 0); cancel_until self (max cr.cr_backtrack_lvl 0);
record_learnt_clause self confl cr record_learnt_clause self confl cr
(* Get the correct vector to insert a clause in. *)
let[@inline] add_clause_to_vec self c =
if Clause.removable self.store c then (
Vec.push self.clauses_learnt c
) else (
Vec.push self.clauses_hyps c
)
(* Add a new clause, simplifying, propagating, and backtracking if (* Add a new clause, simplifying, propagating, and backtracking if
the clause is false in the current trail *) the clause is false in the current trail *)
let add_clause_ (self:t) (init:clause) : unit = let add_clause_ (self:t) ?pool (init:clause) : unit =
let store = self.store in let store = self.store in
Log.debugf 30 (fun k -> k "(@[sat.add-clause@ @[<hov>%a@]@])" (Clause.debug store) init); Log.debugf 30 (fun k -> k "(@[sat.add-clause@ @[<hov>%a@]@])" (Clause.debug store) init);
(* Insertion of new lits is done before simplification. Indeed, else a lit in a (* Insertion of new lits is done before simplification. Indeed, else a lit in a
@ -1368,11 +1372,11 @@ module Make(Plugin : PLUGIN)
) else ( ) else (
Log.debugf 40 Log.debugf 40
(fun k->k "(@[sat.add-clause.unit-clause@ :propagating %a@])" (Atom.debug store) a); (fun k->k "(@[sat.add-clause.unit-clause@ :propagating %a@])" (Atom.debug store) a);
add_clause_to_vec self clause; add_clause_to_vec_ ?pool self clause;
enqueue_bool self a ~level:0 (Bcp clause) enqueue_bool self a ~level:0 (Bcp clause)
) )
| a::b::_ -> | a::b::_ ->
add_clause_to_vec self clause; add_clause_to_vec_ ?pool self clause;
if Atom.is_false store a then ( if Atom.is_false store a then (
(* Atom need to be sorted in decreasing order of decision level, (* Atom need to be sorted in decreasing order of decision level,
or we might watch the wrong literals. *) or we might watch the wrong literals. *)
@ -1499,7 +1503,9 @@ module Make(Plugin : PLUGIN)
Proof.with_proof self.proof dp; Proof.with_proof self.proof dp;
Log.debugf 5 (fun k->k "(@[sat.th.add-clause-in-pool@ %a@ :pool %s@])" Log.debugf 5 (fun k->k "(@[sat.th.add-clause-in-pool@ %a@ :pool %s@])"
(Clause.debug self.store) c (Clause_pool.descr pool)); (Clause.debug self.store) c (Clause_pool.descr pool));
Clause_pool.add pool c (* FIXME: a way to use [self.clauses_to_add] but with a
pool, to avoid loops *)
add_clause_ self ~pool c
let acts_add_decision_lit (self:t) (f:lit) (sign:bool) : unit = let acts_add_decision_lit (self:t) (f:lit) (sign:bool) : unit =
let store = self.store in let store = self.store in
@ -1582,6 +1588,7 @@ module Make(Plugin : PLUGIN)
let[@inline] current_slice st : _ Solver_intf.acts = let[@inline] current_slice st : _ Solver_intf.acts =
let module M = struct let module M = struct
type nonrec proof = proof type nonrec proof = proof
type nonrec clause_pool = clause_pool
type dproof = proof -> unit type dproof = proof -> unit
type nonrec lit = lit type nonrec lit = lit
let iter_assumptions=acts_iter st ~full:false st.th_head let iter_assumptions=acts_iter st ~full:false st.th_head
@ -1600,11 +1607,13 @@ module Make(Plugin : PLUGIN)
let module M = struct let module M = struct
type nonrec proof = proof type nonrec proof = proof
type dproof = proof -> unit type dproof = proof -> unit
type nonrec clause_pool = clause_pool
type nonrec lit = lit type nonrec lit = lit
let iter_assumptions=acts_iter st ~full:true st.th_head let iter_assumptions=acts_iter st ~full:true st.th_head
let eval_lit= acts_eval_lit st let eval_lit= acts_eval_lit st
let add_lit=acts_add_lit st let add_lit=acts_add_lit st
let add_clause = acts_add_clause st let add_clause = acts_add_clause st
let add_clause_in_pool = acts_add_clause_in_pool st
let propagate = acts_propagate st let propagate = acts_propagate st
let raise_conflict c pr=acts_raise st c pr let raise_conflict c pr=acts_raise st c pr
let add_decision_lit=acts_add_decision_lit st let add_decision_lit=acts_add_decision_lit st
@ -1691,6 +1700,25 @@ module Make(Plugin : PLUGIN)
(Format.pp_print_list (Atom.debug store)) !core); (Format.pp_print_list (Atom.debug store)) !core);
!core !core
(*
module Clause_gc = struct
type state = {
solver: solver;
dirty_atoms: Atom.V
}
end
*)
(* FIXME: also handle clause pools.
- pools should probably have a "needs_gc" flag instead of doing GC
themselves
- each pool GC's itself by moving clauses into self.clauses_dead
- then all dead clauses are detached (+ dirty atoms marked),
we clean dirty atoms' watchlists, and finally remove clause.
*)
(* GC: remove some learnt clauses. (* GC: remove some learnt clauses.
This works even during the proof with a non empty trail. *) This works even during the proof with a non empty trail. *)
let reduce_clause_db (self:t) (n_of_learnts: int) : unit = let reduce_clause_db (self:t) (n_of_learnts: int) : unit =
@ -1999,22 +2027,30 @@ module Make(Plugin : PLUGIN)
end in end in
(module M) (module M)
let add_clause_atoms_ self (c:atom array) dp : unit = let add_clause_atoms_ self ?pool ~removable (c:atom array) dp : unit =
try try
let c = Clause.make_a self.store ~removable:false c in let c = Clause.make_a self.store ~removable c in
Proof.with_proof self.proof dp; Proof.with_proof self.proof dp;
add_clause_ self c add_clause_ ?pool self c
with with
| E_unsat (US_false c) -> | E_unsat (US_false c) ->
self.unsat_at_0 <- Some c self.unsat_at_0 <- Some c
let add_clause_a self c dp : unit = let add_clause_a self c dp : unit =
let c = Array.map (make_atom_ self) c in let c = Array.map (make_atom_ self) c in
add_clause_atoms_ self c dp add_clause_atoms_ ~removable:false self c dp
let add_clause self (c:lit list) dp : unit = let add_clause self (c:lit list) dp : unit =
let c = Util.array_of_list_map (make_atom_ self) c in let c = Util.array_of_list_map (make_atom_ self) c in
add_clause_atoms_ self c dp add_clause_atoms_ ~removable:false self c dp
let add_clause_a_in_pool self ~pool c dp : unit =
let c = Array.map (make_atom_ self) c in
add_clause_atoms_ ~pool ~removable:true self c dp
let add_clause_in_pool self ~pool (c:lit list) dp : unit =
let c = Util.array_of_list_map (make_atom_ self) c in
add_clause_atoms_ ~pool ~removable:true self c dp
let add_input_clause self (c:lit list) = let add_input_clause self (c:lit list) =
let dp = Proof.emit_input_clause (Iter.of_list c) in let dp = Proof.emit_input_clause (Iter.of_list c) in
@ -2024,6 +2060,16 @@ module Make(Plugin : PLUGIN)
let dp = Proof.emit_input_clause (Iter.of_array c) in let dp = Proof.emit_input_clause (Iter.of_array c) in
add_clause_a self c dp add_clause_a self c dp
let new_clause_pool_gc_fixed_size ~descr ~size (self:t) : clause_pool =
let p = CP_gc {clauses=Vec.create(); size; descr} in
Vec.push self.clause_pools p;
p
let new_clause_pool_scoped ~descr (self:t) : clause_pool =
let p = CP_scoped {clauses=CVec.create(); levels=VecI32.create(); descr} in
Vec.push self.clause_pools p;
p
let solve ?(assumptions=[]) (self:t) : res = let solve ?(assumptions=[]) (self:t) : res =
cancel_until self 0; cancel_until self 0;
AVec.clear self.assumptions; AVec.clear self.assumptions;

View file

@ -341,21 +341,21 @@ module type S = sig
val add_clause : t -> lit list -> dproof -> unit val add_clause : t -> lit list -> dproof -> unit
(** Lower level addition of clauses *) (** Lower level addition of clauses *)
val add_input_clause : t -> lit list -> unit
(** Like {!add_clause} but with the justification of being an input clause *)
val add_clause_a : t -> lit array -> dproof -> unit val add_clause_a : t -> lit array -> dproof -> unit
(** Lower level addition of clauses *) (** Lower level addition of clauses *)
val add_clause_in_pool : t -> pool:clause_pool -> lit list -> unit val add_input_clause : t -> lit list -> unit
(** Like {!add_clause} but using a specific clause pool *) (** Like {!add_clause} but with the justification of being an input clause *)
val add_clause_a_in_pool : t -> pool:clause_pool -> lit array -> unit
(** Like {!add_clause_a} but using a specific clause pool *)
val add_input_clause_a : t -> lit array -> unit val add_input_clause_a : t -> lit array -> unit
(** Like {!add_clause_a} but with justification of being an input clause *) (** Like {!add_clause_a} but with justification of being an input clause *)
val add_clause_in_pool : t -> pool:clause_pool -> lit list -> dproof -> unit
(** Like {!add_clause} but using a specific clause pool *)
val add_clause_a_in_pool : t -> pool:clause_pool -> lit array -> dproof -> unit
(** Like {!add_clause_a} but using a specific clause pool *)
(* TODO: API to push/pop/clear assumptions from an inner vector *) (* TODO: API to push/pop/clear assumptions from an inner vector *)
val solve : val solve :

View file

@ -90,6 +90,7 @@ module Make(A : ARG)
type ty = Ty.t type ty = Ty.t
type lit = Lit.t type lit = Lit.t
type term_store = Term.store type term_store = Term.store
type clause_pool
type ty_store = Ty.store type ty_store = Ty.store
type th_states = type th_states =
@ -235,10 +236,15 @@ module Make(A : ARG)
let[@inline] propagate_l self acts p cs proof : unit = let[@inline] propagate_l self acts p cs proof : unit =
propagate self acts p ~reason:(fun()->cs,proof) propagate self acts p ~reason:(fun()->cs,proof)
let add_sat_clause_ self (acts:theory_actions) ~lifetime lits (proof:dproof) : unit = let add_sat_clause_ self (acts:theory_actions) ~keep lits (proof:dproof) : unit =
let (module A) = acts in let (module A) = acts in
Stat.incr self.count_axiom; Stat.incr self.count_axiom;
A.add_clause ~lifetime lits proof A.add_clause ~keep lits proof
let add_sat_clause_pool_ self (acts:theory_actions) ~pool lits (proof:dproof) : unit =
let (module A) = acts in
Stat.incr self.count_axiom;
A.add_clause_in_pool ~pool lits proof
let add_sat_lit _self ?default_pol (acts:theory_actions) (lit:Lit.t) : unit = let add_sat_lit _self ?default_pol (acts:theory_actions) (lit:Lit.t) : unit =
let (module A) = acts in let (module A) = acts in