Fix mcsat conflict analysis

When analyzing an mcst conflict clause and looking at a semantic
propagation in the trail, the last resolved clause was looked at again,
which caused an invalid history to be generated (the computation of the
backtrack clause was not affected because the second resolution of the clause
was basically a no-op thanks to the 'seen' field), thus it did not
introduce any soundness bug, just a faulty clause history which was
caught during proof expansion.
This commit is contained in:
Guillaume Bury 2017-08-25 18:33:42 +02:00
parent 8eee822ad6
commit 4989026f06

View file

@ -617,22 +617,29 @@ module Make
let cond = ref true in let cond = ref true in
let blevel = ref 0 in let blevel = ref 0 in
let seen = ref [] in let seen = ref [] in
let c = ref c_clause in let c = ref (Some c_clause) in
let tr_ind = ref (Vec.size env.elt_queue - 1) in let tr_ind = ref (Vec.size env.elt_queue - 1) in
let history = ref [] in let history = ref [] in
assert (decision_level () > 0); assert (decision_level () > 0);
let conflict_level = let conflict_level =
Array.fold_left (fun acc p -> max acc p.var.v_level) 0 c_clause.atoms Array.fold_left (fun acc p -> max acc p.var.v_level) 0 c_clause.atoms
in in
Log.debugf debug "Analyzing conflict (%d): %a"
(fun k -> k conflict_level St.pp_clause c_clause);
while !cond do while !cond do
begin match !c.cpremise with begin match !c with
| History _ -> clause_bump_activity !c | None ->
Log.debugf debug " skipping resolution for semantic propagation" (fun k->k)
| Some clause ->
Log.debugf debug " Resolving clause: %a" (fun k->k St.pp_clause clause);
begin match clause.cpremise with
| History _ -> clause_bump_activity clause
| Hyp | Local | Lemma _ -> () | Hyp | Local | Lemma _ -> ()
end; end;
history := !c :: !history; history := clause :: !history;
(* visit the current predecessors *) (* visit the current predecessors *)
for j = 0 to Array.length !c.atoms - 1 do for j = 0 to Array.length clause.atoms - 1 do
let q = !c.atoms.(j) in let q = clause.atoms.(j) in
assert (q.is_true || q.neg.is_true && q.var.v_level >= 0); (* unsure? *) assert (q.is_true || q.neg.is_true && q.var.v_level >= 0); (* unsure? *)
if q.var.v_level <= 0 then begin if q.var.v_level <= 0 then begin
assert (q.neg.is_true); assert (q.neg.is_true);
@ -653,11 +660,14 @@ module Make
end end
end end
end end
done; done
end;
(* look for the next node to expand *) (* look for the next node to expand *)
while while
match Vec.get env.elt_queue !tr_ind with let a = Vec.get env.elt_queue !tr_ind in
Log.debugf debug " looking at: %a" (fun k -> k St.pp a);
match a with
| Atom q -> | Atom q ->
(not (q.var.seen = Both)) || (not (q.var.seen = Both)) ||
(q.var.v_level < conflict_level) (q.var.v_level < conflict_level)
@ -674,11 +684,12 @@ module Make
learnt := p.neg :: (List.rev !learnt) learnt := p.neg :: (List.rev !learnt)
| n, Some Semantic -> | n, Some Semantic ->
assert (n > 0); assert (n > 0);
learnt := p.neg :: !learnt learnt := p.neg :: !learnt;
c := None
| n, Some Bcp cl -> | n, Some Bcp cl ->
assert (n > 0); assert (n > 0);
assert (p.var.v_level >= conflict_level); assert (p.var.v_level >= conflict_level);
c := cl c := Some cl
| n, _ -> assert false | n, _ -> assert false
done; done;
List.iter (fun q -> clear q.var) !seen; List.iter (fun q -> clear q.var) !seen;