mirror of
https://github.com/c-cube/sidekick.git
synced 2025-12-10 05:03:59 -05:00
wip: remove push/pop
This commit is contained in:
parent
f3488d68db
commit
1136416a7c
3 changed files with 113 additions and 223 deletions
|
|
@ -54,7 +54,6 @@ module Make(Plugin : PLUGIN)
|
|||
|
||||
and clause = {
|
||||
name : int;
|
||||
tag : int option; (* TODO remove *)
|
||||
atoms : atom array;
|
||||
mutable cpremise : premise;
|
||||
mutable activity : float;
|
||||
|
|
@ -71,7 +70,6 @@ module Make(Plugin : PLUGIN)
|
|||
for pure SAT, [reason] is sufficient *)
|
||||
and premise =
|
||||
| Hyp
|
||||
| Local
|
||||
| Lemma of lemma
|
||||
| History of clause list
|
||||
|
||||
|
|
@ -114,7 +112,6 @@ module Make(Plugin : PLUGIN)
|
|||
|
||||
let name_of_clause c = match c.cpremise with
|
||||
| Hyp -> "H" ^ string_of_int c.name
|
||||
| Local -> "L" ^ string_of_int c.name
|
||||
| Lemma _ -> "T" ^ string_of_int c.name
|
||||
| History _ -> "C" ^ string_of_int c.name
|
||||
|
||||
|
|
@ -333,25 +330,23 @@ module Make(Plugin : PLUGIN)
|
|||
|
||||
let make_a =
|
||||
let n = ref 0 in
|
||||
fun ?tag atoms premise ->
|
||||
fun atoms premise ->
|
||||
let name = !n in
|
||||
incr n;
|
||||
{ name;
|
||||
tag = tag;
|
||||
atoms = atoms;
|
||||
visited = false;
|
||||
attached = false;
|
||||
activity = 0.;
|
||||
cpremise = premise}
|
||||
|
||||
let make ?tag l premise = make_a ?tag (Array.of_list l) premise
|
||||
let make l premise = make_a (Array.of_list l) premise
|
||||
|
||||
let empty = make [] (History [])
|
||||
let name = name_of_clause
|
||||
let[@inline] equal c1 c2 = c1==c2
|
||||
let[@inline] atoms c = c.atoms
|
||||
let[@inline] atoms_l c = Array.to_list c.atoms
|
||||
let[@inline] tag c = c.tag
|
||||
let hash cl = Array.fold_left (fun i a -> Hashtbl.hash (a.aid, i)) 0 cl.atoms
|
||||
|
||||
let[@inline] premise c = c.cpremise
|
||||
|
|
@ -377,7 +372,6 @@ module Make(Plugin : PLUGIN)
|
|||
|
||||
let debug_premise out = function
|
||||
| Hyp -> Format.fprintf out "hyp"
|
||||
| Local -> Format.fprintf out "local"
|
||||
| Lemma _ -> Format.fprintf out "th_lemma"
|
||||
| History v ->
|
||||
List.iter (fun c -> Format.fprintf out "%s,@ " (name_of_clause c)) v
|
||||
|
|
@ -551,8 +545,6 @@ module Make(Plugin : PLUGIN)
|
|||
{conclusion; step = Lemma l; }
|
||||
| Hyp ->
|
||||
{ conclusion; step = Hypothesis; }
|
||||
| Local ->
|
||||
{ conclusion; step = Assumption; }
|
||||
| History [] ->
|
||||
Log.debugf 0 (fun k -> k "Empty history for clause: %a" Clause.debug conclusion);
|
||||
raise (Resolution_error "Empty history")
|
||||
|
|
@ -602,7 +594,7 @@ module Make(Plugin : PLUGIN)
|
|||
if not c.visited then (
|
||||
c.visited <- true;
|
||||
match c.cpremise with
|
||||
| Hyp | Local | Lemma _ -> aux (c :: res) acc r
|
||||
| Hyp | Lemma _ -> aux (c :: res) acc r
|
||||
| History h ->
|
||||
let l = List.fold_left (fun acc c ->
|
||||
if not c.visited then c :: acc else acc) r h in
|
||||
|
|
@ -662,8 +654,15 @@ module Make(Plugin : PLUGIN)
|
|||
let set_idx = Elt.set_idx
|
||||
end)
|
||||
|
||||
(* cause of "unsat", possibly conditional to local assumptions *)
|
||||
type unsat_cause =
|
||||
| US_local of {
|
||||
core: atom list;
|
||||
}
|
||||
| US_false of clause (* true unsat *)
|
||||
|
||||
exception E_sat
|
||||
exception E_unsat
|
||||
exception E_unsat of unsat_cause
|
||||
exception UndecidedLit
|
||||
exception Restart
|
||||
exception Conflict of clause
|
||||
|
|
@ -699,19 +698,13 @@ module Make(Plugin : PLUGIN)
|
|||
(* clauses added by the user *)
|
||||
clauses_learnt : clause Vec.t;
|
||||
(* learnt clauses (tautologies true at any time, whatever the user level) *)
|
||||
(* TODO: remove, replace by vec of assumptions *)
|
||||
clauses_temp : clause Vec.t;
|
||||
(* Temp clauses, corresponding to the local assumptions. This vec is used
|
||||
only to have an efficient way to access the list of local assumptions. *)
|
||||
|
||||
clauses_root : clause Stack.t;
|
||||
(* Clauses that should propagate at level 0, but couldn't *)
|
||||
clauses_to_add : clause Stack.t;
|
||||
(* Clauses either assumed or pushed by the theory, waiting to be added. *)
|
||||
|
||||
mutable unsat_at_0: clause option;
|
||||
(* conflict at level 0, if any *)
|
||||
|
||||
mutable unsat_conflict : clause option;
|
||||
(* conflict clause at [base_level], if any *)
|
||||
mutable next_decision : atom option;
|
||||
(* When the last conflict was a semantic one, this stores the next decision to make *)
|
||||
|
||||
|
|
@ -723,9 +716,8 @@ module Make(Plugin : PLUGIN)
|
|||
th_levels : Plugin.level Vec.t;
|
||||
(* theory states corresponding to elt_levels *)
|
||||
|
||||
(* TODO: remove *)
|
||||
user_levels : int Vec.t;
|
||||
(* user levels in [clauses_temp] *)
|
||||
mutable assumptions: atom Vec.t;
|
||||
(* current assumptions *)
|
||||
|
||||
mutable th_head : int;
|
||||
(* Start offset in the queue {!trail} of
|
||||
|
|
@ -758,25 +750,18 @@ module Make(Plugin : PLUGIN)
|
|||
mutable learntsize_factor : float;
|
||||
(* initial limit for the number of learnt clauses, 1/3 of initial
|
||||
number of clauses by default *)
|
||||
|
||||
(* TODO: remove *)
|
||||
mutable dirty: bool;
|
||||
(* is there a [pop()] on top of the stack for examining
|
||||
current model/proof? *)
|
||||
}
|
||||
type solver = t
|
||||
|
||||
(* Starting environment. *)
|
||||
let create_ ~st (th:theory) : t = {
|
||||
st; th;
|
||||
unsat_conflict = None;
|
||||
unsat_at_0=None;
|
||||
next_decision = None;
|
||||
|
||||
clauses_hyps = Vec.create();
|
||||
clauses_learnt = Vec.create();
|
||||
clauses_temp = Vec.create();
|
||||
|
||||
clauses_root = Stack.create ();
|
||||
clauses_to_add = Stack.create ();
|
||||
|
||||
th_head = 0;
|
||||
|
|
@ -785,7 +770,7 @@ module Make(Plugin : PLUGIN)
|
|||
trail = Vec.create ();
|
||||
elt_levels = Vec.create();
|
||||
th_levels = Vec.create();
|
||||
user_levels = Vec.create();
|
||||
assumptions= Vec.create();
|
||||
|
||||
order = H.create();
|
||||
|
||||
|
|
@ -795,7 +780,6 @@ module Make(Plugin : PLUGIN)
|
|||
restart_first = 100;
|
||||
|
||||
learntsize_factor = 1. /. 3. ;
|
||||
dirty=false;
|
||||
}
|
||||
|
||||
let create ?(size=`Big) (th:theory) : t =
|
||||
|
|
@ -811,13 +795,12 @@ module Make(Plugin : PLUGIN)
|
|||
(* let nb_vars () = St.nb_elt () *)
|
||||
|
||||
let[@inline] decision_level st = Vec.size st.elt_levels
|
||||
let[@inline] base_level st = Vec.size st.user_levels
|
||||
|
||||
(* Are the assumptions currently unsat ? *)
|
||||
let[@inline] is_unsat st =
|
||||
match st.unsat_conflict with
|
||||
| Some _ -> true
|
||||
| None -> false
|
||||
(* Do we have a level-0 empty clause? *)
|
||||
let[@inline] check_unsat_ st =
|
||||
match st.unsat_at_0 with
|
||||
| Some c -> raise (E_unsat (US_false c))
|
||||
| None -> ()
|
||||
|
||||
(* Iteration over subterms.
|
||||
When incrementing activity, we want to be able to iterate over
|
||||
|
|
@ -875,7 +858,7 @@ module Make(Plugin : PLUGIN)
|
|||
let l = Lit.make st.st t in
|
||||
insert_var_order st (E_lit l)
|
||||
|
||||
let make_atom_ st (p:formula) : atom =
|
||||
let make_atom st (p:formula) : atom =
|
||||
let a = mk_atom st p in
|
||||
insert_var_order st (E_var a.var);
|
||||
a
|
||||
|
|
@ -1056,7 +1039,7 @@ module Make(Plugin : PLUGIN)
|
|||
i.e we want to go back to the state the solver was in
|
||||
when decision level [lvl] was created. *)
|
||||
let cancel_until st lvl =
|
||||
assert (lvl >= base_level st);
|
||||
assert (lvl >= 0);
|
||||
(* Nothing to do if we try to backtrack to a non-existent level. *)
|
||||
if decision_level st <= lvl then (
|
||||
Log.debugf debug (fun k -> k "Already at level <= %d" lvl)
|
||||
|
|
@ -1111,12 +1094,22 @@ module Make(Plugin : PLUGIN)
|
|||
assert (Vec.size st.elt_levels = Vec.size st.th_levels);
|
||||
()
|
||||
|
||||
let pp_unsat_cause out = function
|
||||
| US_local {core} ->
|
||||
Format.fprintf out "false assumptions (@[core %a@])"
|
||||
(Format.pp_print_list Atom.pp) core
|
||||
| US_false c ->
|
||||
Format.fprintf out "false %a" Clause.debug c
|
||||
|
||||
(* Unsatisfiability is signaled through an exception, since it can happen
|
||||
in multiple places (adding new clauses, or solving for instance). *)
|
||||
let report_unsat st confl : _ =
|
||||
Log.debugf info (fun k -> k "@[Unsat conflict: %a@]" Clause.debug confl);
|
||||
st.unsat_conflict <- Some confl;
|
||||
raise E_unsat
|
||||
let report_unsat st (us:unsat_cause) : _ =
|
||||
Log.debugf info (fun k -> k "@[Unsat conflict: %a@]" pp_unsat_cause us);
|
||||
begin match us with
|
||||
| US_false c -> st.unsat_at_0 <- Some c;
|
||||
| _ -> ()
|
||||
end;
|
||||
raise (E_unsat us)
|
||||
|
||||
(* Simplification of boolean propagation reasons.
|
||||
When doing boolean propagation *at level 0*, it can happen
|
||||
|
|
@ -1245,18 +1238,18 @@ module Make(Plugin : PLUGIN)
|
|||
and a boolean stating whether it is
|
||||
a UIP ("Unique Implication Point")
|
||||
precond: the atom list is sorted by decreasing decision level *)
|
||||
let backtrack_lvl st : atom list -> int * bool = function
|
||||
let backtrack_lvl _st : atom list -> int * bool = function
|
||||
| [] | [_] ->
|
||||
0, true
|
||||
| a :: b :: _ ->
|
||||
assert(a.var.v_level > base_level st);
|
||||
assert(a.var.v_level > 0);
|
||||
if a.var.v_level > b.var.v_level then (
|
||||
(* backtrack below [a], so we can propagate [not a] *)
|
||||
b.var.v_level, true
|
||||
) else (
|
||||
assert (a.var.v_level = b.var.v_level);
|
||||
assert (a.var.v_level >= base_level st);
|
||||
max (a.var.v_level - 1) (base_level st), false
|
||||
assert (a.var.v_level >= 0);
|
||||
max (a.var.v_level - 1) 0, false
|
||||
)
|
||||
|
||||
(* result of conflict analysis, containing the learnt clause and some
|
||||
|
|
@ -1303,7 +1296,7 @@ module Make(Plugin : PLUGIN)
|
|||
Log.debugf debug (fun k->k" Resolving clause: %a" Clause.debug clause);
|
||||
begin match clause.cpremise with
|
||||
| History _ -> clause_bump_activity st clause
|
||||
| Hyp | Local | Lemma _ -> ()
|
||||
| Hyp | Lemma _ -> ()
|
||||
end;
|
||||
history := clause :: !history;
|
||||
(* visit the current predecessors *)
|
||||
|
|
@ -1384,9 +1377,10 @@ module Make(Plugin : PLUGIN)
|
|||
begin match cr.cr_learnt with
|
||||
| [] -> assert false
|
||||
| [fuip] ->
|
||||
assert (cr.cr_backtrack_lvl = 0);
|
||||
assert (cr.cr_backtrack_lvl = 0 && decision_level st = 0);
|
||||
if fuip.neg.is_true then (
|
||||
report_unsat st confl
|
||||
(* incompatible at level 0 *)
|
||||
report_unsat st (US_false confl)
|
||||
) else (
|
||||
let uclause = Clause.make cr.cr_learnt (History cr.cr_history) in
|
||||
Vec.push st.clauses_learnt uclause;
|
||||
|
|
@ -1415,26 +1409,25 @@ module Make(Plugin : PLUGIN)
|
|||
let add_boolean_conflict st (confl:clause): unit =
|
||||
Log.debugf info (fun k -> k "Boolean conflict: %a" Clause.debug confl);
|
||||
st.next_decision <- None;
|
||||
assert (decision_level st >= base_level st);
|
||||
if decision_level st = base_level st ||
|
||||
Array.for_all (fun a -> a.var.v_level <= base_level st) confl.atoms then (
|
||||
assert (decision_level st >= 0);
|
||||
if decision_level st = 0 ||
|
||||
Array.for_all (fun a -> a.var.v_level <= 0) confl.atoms then (
|
||||
(* Top-level conflict *)
|
||||
report_unsat st confl;
|
||||
report_unsat st (US_false confl);
|
||||
);
|
||||
let cr = analyze st confl in
|
||||
cancel_until st (max cr.cr_backtrack_lvl (base_level st));
|
||||
cancel_until st (max cr.cr_backtrack_lvl 0);
|
||||
record_learnt_clause st confl cr
|
||||
|
||||
(* Get the correct vector to insert a clause in. *)
|
||||
let clause_vector st c =
|
||||
match c.cpremise with
|
||||
| Hyp -> st.clauses_hyps
|
||||
| Local -> st.clauses_temp
|
||||
| Lemma _ | History _ -> st.clauses_learnt
|
||||
|
||||
(* Add a new clause, simplifying, propagating, and backtracking if
|
||||
the clause is false in the current trail *)
|
||||
let add_clause st (init:clause) : unit =
|
||||
let add_clause_ st (init:clause) : unit =
|
||||
Log.debugf debug (fun k -> k "Adding clause: @[<hov>%a@]" Clause.debug init);
|
||||
(* Insertion of new lits is done before simplification. Indeed, else a lit in a
|
||||
trivial clause could end up being not decided on, which is a bug. *)
|
||||
|
|
@ -1456,29 +1449,14 @@ module Make(Plugin : PLUGIN)
|
|||
Log.debugf info (fun k->k "New clause: @[<hov>%a@]" Clause.debug clause);
|
||||
match atoms with
|
||||
| [] ->
|
||||
(* Report_unsat will raise, and the current clause will be lost if we do not
|
||||
store it somewhere. Since the proof search will end, any of env.clauses_to_add
|
||||
or env.clauses_root is adequate. *)
|
||||
Stack.push clause st.clauses_root;
|
||||
report_unsat st clause
|
||||
report_unsat st @@ US_false clause
|
||||
| [a] ->
|
||||
cancel_until st (base_level st);
|
||||
cancel_until st 0;
|
||||
if a.neg.is_true then (
|
||||
(* Since we cannot propagate the atom [a], in order to not lose
|
||||
the information that [a] must be true, we add clause to the list
|
||||
of clauses to add, so that it will be e-examined later. *)
|
||||
Log.debug debug "Unit clause, adding to clauses to add";
|
||||
Stack.push clause st.clauses_to_add;
|
||||
report_unsat st clause
|
||||
(* cannot recover from this *)
|
||||
report_unsat st @@ US_false clause
|
||||
) else if a.is_true then (
|
||||
(* If the atom is already true, then it should be because of a local hyp.
|
||||
However it means we can't propagate it at level 0. In order to not lose
|
||||
that information, we store the clause in a stack of clauses that we will
|
||||
add to the solver at the next pop. *)
|
||||
Log.debug debug "Unit clause, adding to root clauses";
|
||||
assert (0 < a.var.v_level && a.var.v_level <= base_level st);
|
||||
Stack.push clause st.clauses_root;
|
||||
()
|
||||
() (* atom is already true, nothing to do *)
|
||||
) else (
|
||||
Log.debugf debug (fun k->k "Unit clause, propagating: %a" Atom.debug a);
|
||||
Vec.push vec clause;
|
||||
|
|
@ -1496,7 +1474,7 @@ module Make(Plugin : PLUGIN)
|
|||
attach_clause clause;
|
||||
if b.neg.is_true && not a.is_true && not a.neg.is_true then (
|
||||
let lvl = List.fold_left (fun m a -> max m a.var.v_level) 0 atoms in
|
||||
cancel_until st (max lvl (base_level st));
|
||||
cancel_until st lvl;
|
||||
enqueue_bool st a ~level:lvl (Bcp clause)
|
||||
)
|
||||
)
|
||||
|
|
@ -1508,7 +1486,7 @@ module Make(Plugin : PLUGIN)
|
|||
if not (Stack.is_empty st.clauses_to_add) then (
|
||||
while not (Stack.is_empty st.clauses_to_add) do
|
||||
let c = Stack.pop st.clauses_to_add in
|
||||
add_clause st c
|
||||
add_clause_ st c
|
||||
done
|
||||
)
|
||||
|
||||
|
|
@ -1723,6 +1701,7 @@ module Make(Plugin : PLUGIN)
|
|||
enqueue_bool st atom ~level:current_level Decision
|
||||
)
|
||||
|
||||
(* FIXME: add assumptions first, add analyze_final *)
|
||||
and pick_branch_lit st =
|
||||
match st.next_decision with
|
||||
| Some atom ->
|
||||
|
|
@ -1741,7 +1720,7 @@ module Make(Plugin : PLUGIN)
|
|||
)
|
||||
| E_var v ->
|
||||
pick_branch_aux st v.pa
|
||||
| exception Not_found -> raise E_sat
|
||||
| exception Not_found -> raise_notrace E_sat
|
||||
end
|
||||
|
||||
(* do some amount of search, until the number of conflicts or clause learnt
|
||||
|
|
@ -1759,22 +1738,23 @@ module Make(Plugin : PLUGIN)
|
|||
if confl.attached then
|
||||
add_boolean_conflict st confl
|
||||
else
|
||||
add_clause st confl
|
||||
add_clause_ st confl
|
||||
|
||||
| None -> (* No Conflict *)
|
||||
assert (st.elt_head = Vec.size st.trail);
|
||||
assert (st.elt_head = st.th_head);
|
||||
if Vec.size st.trail = nb_elt st.st then raise E_sat;
|
||||
if Vec.size st.trail = nb_elt st.st then raise_notrace E_sat;
|
||||
if n_of_conflicts > 0 && !conflictC >= n_of_conflicts then (
|
||||
Log.debug info "Restarting...";
|
||||
cancel_until st (base_level st);
|
||||
raise Restart
|
||||
cancel_until st 0;
|
||||
raise_notrace Restart
|
||||
);
|
||||
(* if decision_level() = 0 then simplify (); *)
|
||||
|
||||
if n_of_learnts >= 0 &&
|
||||
Vec.size st.clauses_learnt - Vec.size st.trail >= n_of_learnts
|
||||
then reduce_db();
|
||||
Vec.size st.clauses_learnt - Vec.size st.trail >= n_of_learnts then (
|
||||
reduce_db();
|
||||
);
|
||||
|
||||
pick_branch_lit st
|
||||
done
|
||||
|
|
@ -1792,7 +1772,7 @@ module Make(Plugin : PLUGIN)
|
|||
|
||||
let[@inline] eval st lit = fst @@ eval_level st lit
|
||||
|
||||
let[@inline] unsat_conflict st = st.unsat_conflict
|
||||
let[@inline] unsat_conflict st = st.unsat_at_0
|
||||
|
||||
let model (st:t) : (term * term) list =
|
||||
let opt = function Some a -> a | None -> assert false in
|
||||
|
|
@ -1804,9 +1784,9 @@ module Make(Plugin : PLUGIN)
|
|||
|
||||
(* fixpoint of propagation and decisions until a model is found, or a
|
||||
conflict is reached *)
|
||||
let solve (st:t) : unit =
|
||||
let solve_ (st:t) : unit =
|
||||
Log.debug 5 "solve";
|
||||
if is_unsat st then raise E_unsat;
|
||||
check_unsat_ st;
|
||||
let n_of_conflicts = ref (to_float st.restart_first) in
|
||||
let n_of_learnts = ref ((to_float (nb_clauses st)) *. st.learntsize_factor) in
|
||||
try
|
||||
|
|
@ -1827,67 +1807,26 @@ module Make(Plugin : PLUGIN)
|
|||
Log.debugf info (fun k -> k "Theory conflict clause: %a" Clause.debug c);
|
||||
Stack.push c st.clauses_to_add
|
||||
end;
|
||||
if Stack.is_empty st.clauses_to_add then raise E_sat
|
||||
if Stack.is_empty st.clauses_to_add then raise_notrace E_sat
|
||||
end
|
||||
done
|
||||
with E_sat -> ()
|
||||
|
||||
let assume st ?tag cnf =
|
||||
let assume st cnf =
|
||||
List.iter
|
||||
(fun l ->
|
||||
let atoms = List.rev_map (mk_atom st) l in
|
||||
let c = Clause.make ?tag atoms Hyp in
|
||||
let c = Clause.make atoms Hyp in
|
||||
Log.debugf debug (fun k -> k "Assuming clause: @[<hov 2>%a@]" Clause.debug c);
|
||||
Stack.push c st.clauses_to_add)
|
||||
cnf
|
||||
|
||||
(* create a factice decision level for local assumptions *)
|
||||
let push st : unit =
|
||||
Log.debug debug "Pushing a new user level";
|
||||
match st.unsat_conflict with
|
||||
| Some _ -> raise E_unsat
|
||||
| None ->
|
||||
cancel_until st (base_level st);
|
||||
Log.debugf debug
|
||||
(fun k -> k "@[<v>Status:@,@[<hov 2>trail: %d - %d@,%a@]"
|
||||
st.elt_head st.th_head (Vec.pp ~sep:"" Trail_elt.debug) st.trail);
|
||||
begin match propagate st with
|
||||
| Some confl ->
|
||||
report_unsat st confl
|
||||
| None ->
|
||||
Log.debugf debug
|
||||
(fun k -> k "@[<v>Current trail:@,@[<hov>%a@]@]"
|
||||
(Vec.pp ~sep:"" Trail_elt.debug) st.trail);
|
||||
Log.debug info "Creating new user level";
|
||||
new_decision_level st;
|
||||
Vec.push st.user_levels (Vec.size st.clauses_temp);
|
||||
assert (decision_level st = base_level st)
|
||||
end
|
||||
|
||||
(* pop the last factice decision level *)
|
||||
let pop st : unit =
|
||||
if base_level st = 0 then
|
||||
Log.debug warn "Cannot pop (already at level 0)"
|
||||
else (
|
||||
Log.debug info "Popping user level";
|
||||
assert (base_level st > 0);
|
||||
st.unsat_conflict <- None;
|
||||
let n = Vec.pop st.user_levels in (* before the [cancel_until]! *)
|
||||
(* Add the root clauses to the clauses to add *)
|
||||
Stack.iter (fun c -> Stack.push c st.clauses_to_add) st.clauses_root;
|
||||
Stack.clear st.clauses_root;
|
||||
(* remove from env.clauses_temp the now invalid caluses. *)
|
||||
Vec.shrink st.clauses_temp n;
|
||||
assert (Vec.for_all (fun c -> Array.length c.atoms = 1) st.clauses_temp);
|
||||
assert (Vec.for_all (fun c -> c.atoms.(0).var.v_level <= base_level st) st.clauses_temp);
|
||||
cancel_until st (base_level st)
|
||||
)
|
||||
|
||||
(* TODO: remove
|
||||
(* Add local hyps to the current decision level *)
|
||||
let local (st:t) (l:atom list) : unit =
|
||||
let aux a =
|
||||
Log.debugf info (fun k-> k "Local assumption: @[%a@]" Atom.debug a);
|
||||
assert (decision_level st = base_level st);
|
||||
assert (decision_level st = st);
|
||||
if not a.is_true then (
|
||||
let c = Clause.make [a] Local in
|
||||
Log.debugf debug (fun k -> k "Temp clause: @[%a@]" Clause.debug c);
|
||||
|
|
@ -1910,6 +1849,7 @@ module Make(Plugin : PLUGIN)
|
|||
List.iter aux l
|
||||
| Some _ ->
|
||||
Log.debug warn "Cannot add local assumption (already unsat)"
|
||||
*)
|
||||
|
||||
(* Check satisfiability *)
|
||||
let check_clause c =
|
||||
|
|
@ -1937,10 +1877,8 @@ module Make(Plugin : PLUGIN)
|
|||
|
||||
let check st : bool =
|
||||
Stack.is_empty st.clauses_to_add &&
|
||||
check_stack st.clauses_root &&
|
||||
check_vec st.clauses_hyps &&
|
||||
check_vec st.clauses_learnt &&
|
||||
check_vec st.clauses_temp
|
||||
check_vec st.clauses_learnt
|
||||
|
||||
(* Unsafe access to internal data *)
|
||||
|
||||
|
|
@ -1948,23 +1886,20 @@ module Make(Plugin : PLUGIN)
|
|||
|
||||
let history env = env.clauses_learnt
|
||||
|
||||
let temp env = env.clauses_temp
|
||||
|
||||
let trail env = env.trail
|
||||
|
||||
(* Result type *)
|
||||
type res =
|
||||
| Sat of (term,atom) Solver_intf.sat_state
|
||||
| Unsat of (clause,Proof.t) Solver_intf.unsat_state
|
||||
| Unsat of (atom,clause,Proof.t) Solver_intf.unsat_state
|
||||
|
||||
let pp_all st lvl status =
|
||||
Log.debugf lvl
|
||||
(fun k -> k
|
||||
"@[<v>%s - Full resume:@,@[<hov 2>Trail:@\n%a@]@,\
|
||||
@[<hov 2>Temp:@\n%a@]@,@[<hov 2>Hyps:@\n%a@]@,@[<hov 2>Lemmas:@\n%a@]@,@]@."
|
||||
@[<hov 2>Hyps:@\n%a@]@,@[<hov 2>Lemmas:@\n%a@]@,@]@."
|
||||
status
|
||||
(Vec.pp ~sep:"" Trail_elt.debug) (trail st)
|
||||
(Vec.pp ~sep:"" Clause.debug) (temp st)
|
||||
(Vec.pp ~sep:"" Clause.debug) (hyps st)
|
||||
(Vec.pp ~sep:"" Clause.debug) (history st)
|
||||
)
|
||||
|
|
@ -1985,60 +1920,43 @@ module Make(Plugin : PLUGIN)
|
|||
model = (fun () -> model st);
|
||||
}
|
||||
|
||||
let mk_unsat (st:t) : (_,_) Solver_intf.unsat_state =
|
||||
let mk_unsat (st:t) (us: unsat_cause) : _ Solver_intf.unsat_state =
|
||||
pp_all st 99 "UNSAT";
|
||||
let unsat_conflict () =
|
||||
match unsat_conflict st with
|
||||
| None -> assert false
|
||||
| Some c -> c
|
||||
let unsat_assumptions () = match us with
|
||||
| US_local {core} -> core
|
||||
| _ -> []
|
||||
in
|
||||
let unsat_conflict = match us with
|
||||
| US_false c -> fun() -> c
|
||||
| US_local {core} ->
|
||||
let c = lazy (
|
||||
let hist = [] in (* FIXME *)
|
||||
Clause.make (List.map Atom.neg core) (History hist)
|
||||
) in
|
||||
fun () -> Lazy.force c
|
||||
in
|
||||
let get_proof () =
|
||||
let c = unsat_conflict () in
|
||||
Proof.prove_unsat c
|
||||
Proof.prove c
|
||||
in
|
||||
{ Solver_intf.unsat_conflict; get_proof; }
|
||||
|
||||
(* clean local state *)
|
||||
let[@inline] cleanup_ (st:t) : unit =
|
||||
if st.dirty then (
|
||||
pop st; (* reset *)
|
||||
st.dirty <- false;
|
||||
)
|
||||
|
||||
(* Wrappers around internal functions*)
|
||||
let[@inline] assume st ?tag cls : unit =
|
||||
cleanup_ st;
|
||||
assume st ?tag cls
|
||||
{ Solver_intf.unsat_conflict; get_proof; unsat_assumptions; }
|
||||
|
||||
let[@inline] add_clause_a st c : unit =
|
||||
let c = Clause.make_a c Hyp in
|
||||
add_clause st c
|
||||
add_clause_ st c
|
||||
|
||||
let[@inline] add_clause st ?tag c : unit =
|
||||
cleanup_ st;
|
||||
let c = Clause.make ?tag c Hyp in
|
||||
add_clause st c
|
||||
let[@inline] add_clause st c : unit =
|
||||
let c = Clause.make c Hyp in
|
||||
add_clause_ st c
|
||||
|
||||
let solve (st:t) ?(assumptions=[]) () =
|
||||
cleanup_ st;
|
||||
Vec.clear st.assumptions;
|
||||
List.iter (Vec.push st.assumptions) assumptions;
|
||||
try
|
||||
push st;
|
||||
st.dirty <- true; (* to call [pop] before any other action *)
|
||||
local st assumptions;
|
||||
solve st;
|
||||
solve_ st;
|
||||
Sat (mk_sat st)
|
||||
with E_unsat ->
|
||||
Unsat (mk_unsat st)
|
||||
|
||||
let[@inline] push st =
|
||||
cleanup_ st;
|
||||
push st
|
||||
|
||||
let[@inline] pop st =
|
||||
cleanup_ st;
|
||||
pop st
|
||||
|
||||
let unsat_core = Proof.unsat_core
|
||||
with E_unsat us ->
|
||||
Unsat (mk_unsat st us)
|
||||
|
||||
let true_at_level0 st a =
|
||||
try
|
||||
|
|
@ -2046,22 +1964,10 @@ module Make(Plugin : PLUGIN)
|
|||
b && lev = 0
|
||||
with UndecidedLit -> false
|
||||
|
||||
(* TODO: remove *)
|
||||
let get_tag cl = cl.tag
|
||||
|
||||
let[@inline] new_lit st t =
|
||||
cleanup_ st;
|
||||
new_lit st t
|
||||
|
||||
let[@inline] make_atom st a =
|
||||
cleanup_ st;
|
||||
make_atom_ st a
|
||||
|
||||
let export (st:t) : clause Solver_intf.export =
|
||||
let hyps = hyps st in
|
||||
let history = history st in
|
||||
let local = temp st in
|
||||
{Solver_intf.hyps; history; local}
|
||||
{Solver_intf.hyps; history; }
|
||||
end
|
||||
[@@inline][@@specialise]
|
||||
|
||||
|
|
|
|||
|
|
@ -18,14 +18,14 @@ type ('term, 'form) sat_state = ('term, 'form) Solver_intf.sat_state = {
|
|||
model : unit -> ('term * 'term) list;
|
||||
}
|
||||
|
||||
type ('clause, 'proof) unsat_state = ('clause, 'proof) Solver_intf.unsat_state = {
|
||||
type ('atom,'clause, 'proof) unsat_state = ('atom,'clause, 'proof) Solver_intf.unsat_state = {
|
||||
unsat_conflict : unit -> 'clause;
|
||||
get_proof : unit -> 'proof;
|
||||
unsat_assumptions: unit -> 'atom list;
|
||||
}
|
||||
type 'clause export = 'clause Solver_intf.export = {
|
||||
hyps : 'clause Vec.t;
|
||||
history : 'clause Vec.t;
|
||||
local : 'clause Vec.t;
|
||||
}
|
||||
type ('formula, 'proof) th_res = ('formula, 'proof) Solver_intf.th_res =
|
||||
| Th_sat
|
||||
|
|
|
|||
|
|
@ -32,18 +32,19 @@ type ('term, 'form) sat_state = {
|
|||
}
|
||||
(** The type of values returned when the solver reaches a SAT state. *)
|
||||
|
||||
type ('clause, 'proof) unsat_state = {
|
||||
type ('atom, 'clause, 'proof) unsat_state = {
|
||||
unsat_conflict : unit -> 'clause;
|
||||
(** Returns the unsat clause found at the toplevel *)
|
||||
get_proof : unit -> 'proof;
|
||||
(** returns a persistent proof of the empty clause from the Unsat result. *)
|
||||
unsat_assumptions: unit -> 'atom list;
|
||||
(** Subset of assumptions responsible for "unsat" *)
|
||||
}
|
||||
(** The type of values returned when the solver reaches an UNSAT state. *)
|
||||
|
||||
type 'clause export = {
|
||||
hyps: 'clause Vec.t;
|
||||
history: 'clause Vec.t;
|
||||
local: 'clause Vec.t;
|
||||
}
|
||||
(** Export internal state *)
|
||||
|
||||
|
|
@ -365,7 +366,6 @@ module type S = sig
|
|||
|
||||
val atoms : t -> atom array
|
||||
val atoms_l : t -> atom list
|
||||
val tag : t -> int option
|
||||
val equal : t -> t -> bool
|
||||
val name : t -> string
|
||||
|
||||
|
|
@ -396,7 +396,7 @@ module type S = sig
|
|||
(** Result type for the solver *)
|
||||
type res =
|
||||
| Sat of (term,atom) sat_state (** Returned when the solver reaches SAT, with a model *)
|
||||
| Unsat of (clause,Proof.t) unsat_state (** Returned when the solver reaches UNSAT, with a proof *)
|
||||
| Unsat of (atom,clause,Proof.t) unsat_state (** Returned when the solver reaches UNSAT, with a proof *)
|
||||
|
||||
exception UndecidedLit
|
||||
(** Exception raised by the evaluating functions when a literal
|
||||
|
|
@ -404,11 +404,11 @@ module type S = sig
|
|||
|
||||
(** {2 Base operations} *)
|
||||
|
||||
val assume : t -> ?tag:int -> formula list list -> unit
|
||||
val assume : t -> formula list list -> unit
|
||||
(** Add the list of clauses to the current set of assumptions.
|
||||
Modifies the sat solver state in place. *)
|
||||
|
||||
val add_clause : t -> ?tag:int -> atom list -> unit
|
||||
val add_clause : t -> atom list -> unit
|
||||
(** Lower level addition of clauses *)
|
||||
|
||||
val add_clause_a : t -> atom array -> unit
|
||||
|
|
@ -430,26 +430,10 @@ module type S = sig
|
|||
This formula will be decided on at some point during solving,
|
||||
wether it appears in clauses or not. *)
|
||||
|
||||
val unsat_core : Proof.t -> clause list
|
||||
(** Returns the unsat core of a given proof, ie a subset of all the added
|
||||
clauses that is sufficient to establish unsatisfiability. *)
|
||||
|
||||
val true_at_level0 : t -> atom -> bool
|
||||
(** [true_at_level0 a] returns [true] if [a] was proved at level0, i.e.
|
||||
it must hold in all models *)
|
||||
|
||||
val get_tag : clause -> int option
|
||||
(** Recover tag from a clause, if any *)
|
||||
|
||||
val push : t -> unit
|
||||
(** Push a new save point. Clauses added after this call to [push] will
|
||||
be added as normal, but the corresponding call to [pop] will
|
||||
remove these clauses. *)
|
||||
|
||||
val pop : t -> unit
|
||||
(** Return to last save point, discarding clauses added since last
|
||||
call to [push] *)
|
||||
|
||||
val export : t -> clause export
|
||||
end
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue