open Format
type ident =
{
iname : Hstring.t;
mask : int;
mutable ivalues : (atom * int) Vec.t;
ivars : var Vec.t;
}
and var =
{ vid : int;
ident : ident;
pa : atom;
na : atom;
mutable weight : float;
mutable seen : bool;
mutable level : int;
mutable reason: reason;
mutable vpremise : premise}
and atom =
{ aid : int;
var : var;
value : int;
neg : atom;
mutable is_true : bool;
mutable watched : clause Vec.t;}
and clause =
{ name : string;
mutable atoms : atom Vec.t ;
mutable activity : float;
mutable removed : bool;
learnt : bool;
cpremise : premise }
and reason = clause option
and premise = clause list
let dummy_value = -1
let rec dummy_ident =
{ iname = Hstring.make "";
mask = 2;
ivalues = {Vec.dummy=dummy_atom, dummy_value; data=[||]; sz=0};
ivars = {Vec.dummy=dummy_var; data=[||]; sz=0};
}
and dummy_var =
{ vid = -101;
ident = dummy_ident;
pa = dummy_atom;
na = dummy_atom;
weight = -1.;
seen = false;
level = -1;
reason = None;
vpremise = []}
and dummy_atom =
{ aid = -202;
var = dummy_var;
value = dummy_value;
neg = dummy_atom;
watched = {Vec.dummy=dummy_clause; data=[||]; sz=0};
is_true = false;}
and dummy_clause =
{ name = "";
atoms = {Vec.dummy=dummy_atom; data=[||]; sz=0};
activity = -1.;
removed = false;
learnt = false;
cpremise = [] }
module Debug = struct
let sign a = if a==a.var.pa then "" else "-"
let level a =
match a.var.level, a.var.reason with
| n, _ when n < 0 -> assert false
| 0, Some c -> sprintf "->0/%s" c.name
| 0, None -> "@0"
| n, Some c -> sprintf "->%d/%s" n c.name
| n, None -> sprintf "@@%d" n
let value a =
if a.is_true then sprintf "[T%s]" (level a)
else if a.neg.is_true then sprintf "[F%s]" (level a)
else ""
let value_ms_like a =
if a.is_true then sprintf ":1%s" (level a)
else if a.neg.is_true then sprintf ":0%s" (level a)
else ":X"
let premise fmt v =
List.iter (fun {name=name} -> fprintf fmt "%s," name) v
let atom fmt a =
fprintf fmt "%s%d%s [%a = %d]"
(sign a) (a.var.vid+1) (value a) Hstring.print a.var.ident.iname
( a.value)
let atoms_list fmt l = List.iter (fprintf fmt "%a ; " atom) l
let atoms_array fmt arr = Array.iter (fprintf fmt "%a ; " atom) arr
let atoms_vec fmt vec =
for i = 0 to Vec.size vec - 1 do
fprintf fmt "%a ; " atom (Vec.get vec i)
done
let clause fmt {name=name; atoms=arr; cpremise=cp} =
fprintf fmt "%s:{ %a}" name atoms_vec arr
end
module HA = Hashtbl.Make (struct
type t = Hstring.t * int
let equal (n1, v1) (n2, v2) = Hstring.equal n1 n2 && v1 = v2
let hash (n, v) = Hstring.hash n * v
end)
module HI = Hstring.H
let cpt_mk_var = ref 0
let ha = HA.create 2001
let hi = HI.create 2001
let is_top a = a.var.ident.mask = a.value
let is_bottom a = a.value = 0
let fresh_lname =
let cpt = ref 0 in
fun () -> incr cpt; "L" ^ (string_of_int !cpt)
let fresh_dname =
let cpt = ref 0 in
fun () -> incr cpt; "D" ^ (string_of_int !cpt)
let fresh_ename =
let cpt = ref 0 in
fun () -> incr cpt; "E" ^ (string_of_int !cpt)
let fresh_name =
let cpt = ref 0 in
fun () -> incr cpt; "C" ^ (string_of_int !cpt)
let make_clause name ali sz_ali is_learnt premise =
let atoms = Vec.from_list ali sz_ali dummy_atom in
{ name = name;
atoms = atoms;
removed = false;
learnt = is_learnt;
activity = 0.;
cpremise = premise}
let mkident vname mask =
try HI.find hi vname
with Not_found ->
let vec = Vec.make 10 (dummy_atom, dummy_value) in
Vec.push vec (dummy_atom, mask);
let i =
{ iname = vname;
mask = mask;
ivalues = vec;
ivars = Vec.make 10 dummy_var;
}
in HI.add hi vname i;
i
let make_bottom_clause l a j =
let v = a.var.ident.ivalues in
assert (Vec.size v > 1);
let c = ref [a.neg] in
for i = 1 to j do
c := (fst (Vec.get v i)).neg :: !c
done;
let c = make_clause (fresh_ename ()) !c (j+1) true [] in
l := (a.neg, c, (fst (Vec.last v)).var.level) :: !l;
raise Exit
exception Found of (atom * clause * int)
let new_implied_facts l v =
let vals = v.ident.ivalues in
let vpa = v.pa.value in
let vna = v.na.value in
try
for i = 1 to Vec.size vals - 1 do
let x = snd (Vec.get vals i) in
if x land vpa = 0 then make_bottom_clause l v.pa i;
if x land vna = 0 then make_bottom_clause l v.na i;
done
with Exit -> ()
let add_atom implied (vname, value, mask) =
try HA.find ha (vname,value)
with Not_found ->
let cpt_fois_2 = !cpt_mk_var lsl 1 in
let ident = mkident vname mask in
let neg_value = ident.mask land (lnot value) in
let rec var =
{ vid = !cpt_mk_var ;
ident = ident;
pa = pa;
na = na;
level = -1;
reason = None;
seen = false;
vpremise = [];
weight = 0.;}
and pa =
{ aid = cpt_fois_2;
var = var;
neg = na;
value = value;
is_true = false;
watched = Vec.make 10 dummy_clause;
}
and na =
{ aid = cpt_fois_2 + 1;
var = var;
neg = pa;
value = neg_value;
is_true = false;
watched = Vec.make 10 dummy_clause;
}
in
Vec.push ident.ivars var;
if is_top pa then begin
pa.is_true <- true;
pa.var.level <- 0;
end;
if is_bottom pa then begin
na.is_true <- true;
na.var.level <- 0;
end;
HA.add ha (vname, value) pa;
HA.add ha (vname, neg_value) na;
incr cpt_mk_var;
new_implied_facts implied var;
pa
let made_vars_info () = !cpt_mk_var, HA.fold (fun _ a acc -> a :: acc) ha []
module Clause = struct
let size c = Vec.size c.atoms
let pop c = Vec.pop c.atoms
let shrink c i = Vec.shrink c.atoms i
let last c = Vec.last c.atoms
let get c i = Vec.get c.atoms i
let set c i v = Vec.set c.atoms i v
end
let to_float i = float_of_int i
let to_int f = int_of_float f
let clear () =
cpt_mk_var := 0;
HA.clear ha;
HI.clear hi
let same_ident a b = Hstring.equal a.var.ident.iname b.var.ident.iname
let is_bottom a =
a.neg.is_true ||
(snd (Vec.last a.var.ident.ivalues)) land a.value = 0
let check_bottom_clause a =
let v = a.var.ident.ivalues in
if not (is_bottom a) then None
else begin
assert (Vec.size v > 1);
let size = ref 1 in
let c = ref [a.neg] in
for i = 1 to Vec.size v - 1 do
let b = (fst (Vec.get v i)) in
if b.var.level > 0 then begin
c := b.neg :: !c;
incr size
end
done;
let cl = make_clause (fresh_ename ()) !c !size true [] in
Some cl
end
let is_attached c =
let w0 = (Vec.get c.atoms 0).neg.watched in
let w1 = (Vec.get c.atoms 1).neg.watched in
let f w =
try
for i = 0 to Vec.size w - 1 do
if Vec.get w i == c then raise Exit
done;
false
with Exit -> true
in
f w0 && f w1
let enqueue_ident a =
let values = a.var.ident.ivalues in
Vec.push values (a, ((snd (Vec.last values)) land a.value));
let l = ref [] in
let ivars = a.var.ident.ivars in
let lvl = a.var.level in
for i = 0 to Vec.size ivars - 1 do
let v = Vec.get ivars i in
if v.level < 0 then
match check_bottom_clause v.pa with
| Some c ->
l := (v.na, c, lvl) :: !l
| None ->
match check_bottom_clause v.na
with
| Some c ->
l := (v.pa, c, lvl) :: !l
| None -> ()
done;
!l
let pop_ident a = Vec.pop a.var.ident.ivalues;
assert (Vec.size a.var.ident.ivalues > 0)