mirror of
https://github.com/c-cube/sidekick.git
synced 2025-12-07 11:45:41 -05:00
Fix for semantic conflict and decision levels
When faced with a semantic conflict, a new decision must be made to solve the conflict, however, because we just backtracked, it is not ensured that the solver is in a correct state to add a new level, so the decision is now delayed until propagation has been done.
This commit is contained in:
parent
df1f28ccb1
commit
a21807c624
1 changed files with 106 additions and 93 deletions
|
|
@ -40,8 +40,8 @@ module Make
|
||||||
|
|
||||||
mutable unsat_conflict : clause option;
|
mutable unsat_conflict : clause option;
|
||||||
(* conflict clause at decision level 0, if any *)
|
(* conflict clause at decision level 0, if any *)
|
||||||
|
mutable next_decision : atom option;
|
||||||
|
(* When the last conflict was a semantic one, this stores the next decision to make *)
|
||||||
|
|
||||||
elt_queue : t Vec.t;
|
elt_queue : t Vec.t;
|
||||||
(* decision stack + propagated elements (atoms or assignments) *)
|
(* decision stack + propagated elements (atoms or assignments) *)
|
||||||
|
|
@ -110,6 +110,7 @@ module Make
|
||||||
|
|
||||||
let env = {
|
let env = {
|
||||||
unsat_conflict = None;
|
unsat_conflict = None;
|
||||||
|
next_decision = None;
|
||||||
|
|
||||||
clauses_hyps = Vec.make 0 dummy_clause;
|
clauses_hyps = Vec.make 0 dummy_clause;
|
||||||
clauses_learnt = Vec.make 0 dummy_clause;
|
clauses_learnt = Vec.make 0 dummy_clause;
|
||||||
|
|
@ -158,13 +159,14 @@ module Make
|
||||||
nb_init_clauses = 0;
|
nb_init_clauses = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_unsat () = match env.unsat_conflict with Some _ -> true | None -> false
|
let is_unsat () =
|
||||||
|
match env.unsat_conflict with
|
||||||
|
| Some _ -> true
|
||||||
|
| None -> false
|
||||||
|
|
||||||
(* Level for push/pop operations *)
|
(* Level for push/pop operations *)
|
||||||
type level = int
|
type level = int
|
||||||
|
|
||||||
let base_level = 0
|
let base_level = 0
|
||||||
|
|
||||||
let current_level () = Vec.size env.user_levels
|
let current_level () = Vec.size env.user_levels
|
||||||
|
|
||||||
(* Iteration over subterms *)
|
(* Iteration over subterms *)
|
||||||
|
|
@ -253,6 +255,67 @@ module Make
|
||||||
let nb_learnts () = Vec.size env.clauses_learnt
|
let nb_learnts () = Vec.size env.clauses_learnt
|
||||||
let nb_vars () = St.nb_elt ()
|
let nb_vars () = St.nb_elt ()
|
||||||
|
|
||||||
|
(* Simplify clauses *)
|
||||||
|
exception Trivial
|
||||||
|
|
||||||
|
let simplify_zero atoms level0 =
|
||||||
|
(* Eliminates dead litterals from clauses when at decision level 0 *)
|
||||||
|
assert (decision_level () = 0);
|
||||||
|
let aux (atoms, init, lvl) a =
|
||||||
|
if a.is_true then raise Trivial;
|
||||||
|
if a.neg.is_true then begin
|
||||||
|
match a.var.reason with
|
||||||
|
| Bcp (Some cl) -> atoms, false, max lvl cl.c_level
|
||||||
|
| Semantic 0 -> atoms, init, lvl
|
||||||
|
| _ ->
|
||||||
|
L.debug 0 "Unexpected semantic propagation at level 0: %a" St.pp_atom a;
|
||||||
|
assert false
|
||||||
|
end else
|
||||||
|
a::atoms, init, lvl
|
||||||
|
in
|
||||||
|
let atoms, init, lvl = List.fold_left aux ([], true, level0) atoms in
|
||||||
|
List.fast_sort (fun a b -> a.var.vid - b.var.vid) atoms, init, lvl
|
||||||
|
|
||||||
|
let partition atoms init0 =
|
||||||
|
(* Parittion litterals for new clauses *)
|
||||||
|
let rec partition_aux trues unassigned falses init lvl = function
|
||||||
|
| [] -> trues @ unassigned @ falses, init, lvl
|
||||||
|
| a :: r ->
|
||||||
|
if a.is_true then
|
||||||
|
if a.var.level = 0 then raise Trivial
|
||||||
|
else (a::trues) @ unassigned @ falses @ r, init, lvl
|
||||||
|
else if a.neg.is_true then
|
||||||
|
if a.var.level = 0 then begin
|
||||||
|
match a.var.reason with
|
||||||
|
| Bcp (Some cl) ->
|
||||||
|
partition_aux trues unassigned falses false (max lvl cl.c_level) r
|
||||||
|
| Semantic 0 ->
|
||||||
|
partition_aux trues unassigned falses init lvl r
|
||||||
|
| _ -> assert false
|
||||||
|
end else
|
||||||
|
partition_aux trues unassigned (a::falses) init lvl r
|
||||||
|
else
|
||||||
|
partition_aux trues (a::unassigned) falses init lvl r
|
||||||
|
in
|
||||||
|
if decision_level () = 0 then
|
||||||
|
simplify_zero atoms init0
|
||||||
|
else
|
||||||
|
partition_aux [] [] [] false init0 atoms
|
||||||
|
|
||||||
|
(* Compute a progess estimate *)
|
||||||
|
let progress_estimate () =
|
||||||
|
let prg = ref 0. in
|
||||||
|
let nbv = to_float (nb_vars()) in
|
||||||
|
let lvl = decision_level () in
|
||||||
|
let _F = 1. /. nbv in
|
||||||
|
for i = 0 to lvl do
|
||||||
|
let _beg = if i = 0 then 0 else Vec.get env.elt_levels (i-1) in
|
||||||
|
let _end = if i=lvl then Vec.size env.elt_queue else Vec.get env.elt_levels i in
|
||||||
|
prg := !prg +. _F**(to_float i) *. (to_float (_end - _beg))
|
||||||
|
done;
|
||||||
|
!prg /. nbv
|
||||||
|
|
||||||
|
|
||||||
(* Manipulating decision levels *)
|
(* Manipulating decision levels *)
|
||||||
let new_decision_level() =
|
let new_decision_level() =
|
||||||
assert (env.th_head = Vec.size env.elt_queue);
|
assert (env.th_head = Vec.size env.elt_queue);
|
||||||
|
|
@ -493,15 +556,14 @@ module Make
|
||||||
if is_uip then
|
if is_uip then
|
||||||
enqueue_bool fuip blevel (Bcp (Some lclause))
|
enqueue_bool fuip blevel (Bcp (Some lclause))
|
||||||
else begin
|
else begin
|
||||||
env.decisions <- env.decisions + 1;
|
env.next_decision <- Some fuip.neg
|
||||||
new_decision_level();
|
|
||||||
enqueue_bool fuip.neg (decision_level ()) (Bcp None)
|
|
||||||
end
|
end
|
||||||
end;
|
end;
|
||||||
var_decay_activity ();
|
var_decay_activity ();
|
||||||
clause_decay_activity ()
|
clause_decay_activity ()
|
||||||
|
|
||||||
let add_boolean_conflict confl =
|
let add_boolean_conflict confl =
|
||||||
|
env.next_decision <- None;
|
||||||
env.conflicts <- env.conflicts + 1;
|
env.conflicts <- env.conflicts + 1;
|
||||||
if decision_level() = 0 || Vec.for_all (fun a -> a.var.level = 0) confl.atoms then
|
if decision_level() = 0 || Vec.for_all (fun a -> a.var.level = 0) confl.atoms then
|
||||||
report_unsat confl; (* Top-level conflict *)
|
report_unsat confl; (* Top-level conflict *)
|
||||||
|
|
@ -510,50 +572,6 @@ module Make
|
||||||
record_learnt_clause confl blevel learnt (History history) is_uip lvl
|
record_learnt_clause confl blevel learnt (History history) is_uip lvl
|
||||||
|
|
||||||
(* Add a new clause *)
|
(* Add a new clause *)
|
||||||
exception Trivial
|
|
||||||
|
|
||||||
let simplify_zero atoms level0 =
|
|
||||||
assert (decision_level () = 0);
|
|
||||||
let aux (atoms, init, lvl) a =
|
|
||||||
if a.is_true then raise Trivial;
|
|
||||||
if a.neg.is_true then begin
|
|
||||||
match a.var.reason with
|
|
||||||
| Bcp (Some cl) -> atoms, false, max lvl cl.c_level
|
|
||||||
| Semantic 0 -> atoms, init, lvl
|
|
||||||
| _ ->
|
|
||||||
L.debug 0 "Unexpected semantic propagation at level 0: %a" St.pp_atom a;
|
|
||||||
assert false
|
|
||||||
end else
|
|
||||||
a::atoms, init, lvl
|
|
||||||
in
|
|
||||||
let atoms, init, lvl = List.fold_left aux ([], true, level0) atoms in
|
|
||||||
List.fast_sort (fun a b -> a.var.vid - b.var.vid) atoms, init, lvl
|
|
||||||
|
|
||||||
let partition atoms init0 =
|
|
||||||
let rec partition_aux trues unassigned falses init lvl = function
|
|
||||||
| [] -> trues @ unassigned @ falses, init, lvl
|
|
||||||
| a :: r ->
|
|
||||||
if a.is_true then
|
|
||||||
if a.var.level = 0 then raise Trivial
|
|
||||||
else (a::trues) @ unassigned @ falses @ r, init, lvl
|
|
||||||
else if a.neg.is_true then
|
|
||||||
if a.var.level = 0 then begin
|
|
||||||
match a.var.reason with
|
|
||||||
| Bcp (Some cl) ->
|
|
||||||
partition_aux trues unassigned falses false (max lvl cl.c_level) r
|
|
||||||
| Semantic 0 ->
|
|
||||||
partition_aux trues unassigned falses init lvl r
|
|
||||||
| _ -> assert false
|
|
||||||
end else
|
|
||||||
partition_aux trues unassigned (a::falses) init lvl r
|
|
||||||
else
|
|
||||||
partition_aux trues (a::unassigned) falses init lvl r
|
|
||||||
in
|
|
||||||
if decision_level () = 0 then
|
|
||||||
simplify_zero atoms init0
|
|
||||||
else
|
|
||||||
partition_aux [] [] [] false init0 atoms
|
|
||||||
|
|
||||||
let add_clause ?(force=false) init0 =
|
let add_clause ?(force=false) init0 =
|
||||||
let vec = match init0.cpremise with
|
let vec = match init0.cpremise with
|
||||||
| Lemma _ -> env.clauses_learnt
|
| Lemma _ -> env.clauses_learnt
|
||||||
|
|
@ -592,18 +610,6 @@ module Make
|
||||||
enqueue_bool a 0 (Bcp (Some init0))
|
enqueue_bool a 0 (Bcp (Some init0))
|
||||||
with Trivial -> L.debug 5 "Trivial clause ignored : %a" St.pp_clause init0
|
with Trivial -> L.debug 5 "Trivial clause ignored : %a" St.pp_clause init0
|
||||||
|
|
||||||
let progress_estimate () =
|
|
||||||
let prg = ref 0. in
|
|
||||||
let nbv = to_float (nb_vars()) in
|
|
||||||
let lvl = decision_level () in
|
|
||||||
let _F = 1. /. nbv in
|
|
||||||
for i = 0 to lvl do
|
|
||||||
let _beg = if i = 0 then 0 else Vec.get env.elt_levels (i-1) in
|
|
||||||
let _end = if i=lvl then Vec.size env.elt_queue else Vec.get env.elt_levels i in
|
|
||||||
prg := !prg +. _F**(to_float i) *. (to_float (_end - _beg))
|
|
||||||
done;
|
|
||||||
!prg /. nbv
|
|
||||||
|
|
||||||
let propagate_in_clause a c i watched new_sz =
|
let propagate_in_clause a c i watched new_sz =
|
||||||
let atoms = c.atoms in
|
let atoms = c.atoms in
|
||||||
let first = Vec.get atoms 0 in
|
let first = Vec.get atoms 0 in
|
||||||
|
|
@ -741,6 +747,7 @@ module Make
|
||||||
| _ -> !res
|
| _ -> !res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
(*
|
||||||
(* heuristic comparison between clauses, by their size (unary/binary or not)
|
(* heuristic comparison between clauses, by their size (unary/binary or not)
|
||||||
and activity *)
|
and activity *)
|
||||||
let f_sort_db c1 c2 =
|
let f_sort_db c1 c2 =
|
||||||
|
|
@ -762,6 +769,7 @@ module Make
|
||||||
| _ -> false
|
| _ -> false
|
||||||
) env.vars
|
) env.vars
|
||||||
*)
|
*)
|
||||||
|
*)
|
||||||
|
|
||||||
(* remove some learnt clauses *)
|
(* remove some learnt clauses *)
|
||||||
let reduce_db () = () (*
|
let reduce_db () = () (*
|
||||||
|
|
@ -794,9 +802,6 @@ module Make
|
||||||
if satisfied c then remove_clause c
|
if satisfied c then remove_clause c
|
||||||
done
|
done
|
||||||
|
|
||||||
module HUC = Hashtbl.Make
|
|
||||||
(struct type t = clause let equal = (==) let hash = Hashtbl.hash end)
|
|
||||||
|
|
||||||
let simplify () =
|
let simplify () =
|
||||||
assert (decision_level () = 0);
|
assert (decision_level () = 0);
|
||||||
if is_unsat () then raise Unsat;
|
if is_unsat () then raise Unsat;
|
||||||
|
|
@ -814,32 +819,40 @@ module Make
|
||||||
end
|
end
|
||||||
|
|
||||||
(* Decide on a new litteral *)
|
(* Decide on a new litteral *)
|
||||||
let rec pick_branch_lit () =
|
let rec pick_branch_aux atom =
|
||||||
let max = Iheap.remove_min f_weight env.order in
|
let v = atom.var in
|
||||||
destruct_elt (St.get_elt max)
|
if v.level >= 0 then begin
|
||||||
(fun v ->
|
assert (v.pa.is_true || v.na.is_true);
|
||||||
if v.level >= 0 then
|
pick_branch_lit ()
|
||||||
pick_branch_lit ()
|
end else match Th.eval atom.lit with
|
||||||
else begin
|
| Th.Unknown ->
|
||||||
let value = Th.assign v.term in
|
env.decisions <- env.decisions + 1;
|
||||||
env.decisions <- env.decisions + 1;
|
new_decision_level();
|
||||||
new_decision_level();
|
let current_level = decision_level () in
|
||||||
let current_level = decision_level () in
|
enqueue_bool atom current_level (Bcp None)
|
||||||
enqueue_assign v value current_level
|
| Th.Valued (b, lvl) ->
|
||||||
end)
|
let a = if b then atom else atom.neg in
|
||||||
(fun v ->
|
enqueue_bool a lvl (Semantic lvl)
|
||||||
if v.level >= 0 then begin
|
|
||||||
assert (v.pa.is_true || v.na.is_true);
|
and pick_branch_lit () =
|
||||||
pick_branch_lit ()
|
match env.next_decision with
|
||||||
end else match Th.eval v.pa.lit with
|
| Some atom ->
|
||||||
| Th.Unknown ->
|
env.next_decision <- None;
|
||||||
env.decisions <- env.decisions + 1;
|
pick_branch_aux atom
|
||||||
new_decision_level();
|
| None ->
|
||||||
let current_level = decision_level () in
|
destruct_elt (
|
||||||
enqueue_bool v.pa current_level (Bcp None)
|
St.get_elt @@ Iheap.remove_min f_weight env.order)
|
||||||
| Th.Valued (b, lvl) ->
|
(fun v ->
|
||||||
let a = if b then v.pa else v.na in
|
if v.level >= 0 then
|
||||||
enqueue_bool a lvl (Semantic lvl))
|
pick_branch_lit ()
|
||||||
|
else begin
|
||||||
|
let value = Th.assign v.term in
|
||||||
|
env.decisions <- env.decisions + 1;
|
||||||
|
new_decision_level();
|
||||||
|
let current_level = decision_level () in
|
||||||
|
enqueue_assign v value current_level
|
||||||
|
end)
|
||||||
|
(fun v -> pick_branch_aux v.pa)
|
||||||
|
|
||||||
let search n_of_conflicts n_of_learnts =
|
let search n_of_conflicts n_of_learnts =
|
||||||
let conflictC = ref 0 in
|
let conflictC = ref 0 in
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue