1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
open Hc type var = int type hidden = view hash_consed and view = True | False | Node of var * hidden * hidden module HashedT = struct type t = view let equal x y = match (x, y) with | True, True | False, False -> true | Node (v1, l1, r1), Node (v2, l2, r2) -> v1 = v2 && l1 == l2 && r1 == r2 | _ -> false let hash = function | True -> 1 | False -> 0 | Node (v, l, r) -> (19 * ((19 * v) + l.tag)) + r.tag + 2 end module Hbdd = Hc.Make (HashedT) module Hash = struct type t = hidden let equal = ( == ) let hash b = b.tag end let hc = Hbdd.hashcons let view x = x.node module Mem = Memo.MakeWeak (Hash) let true_bdd = hc True let false_bdd = hc False let get_order bdd = match view bdd with True | False -> -1 | Node (v, _, _) -> v let node v l h = if v <= get_order l || v <= get_order h then invalid_arg "node" ; if Hash.equal l h then l else hc (Node (v, l, h)) let var_bdd v = node v false_bdd true_bdd let rec fprintf fmt bdd = match view bdd with | True -> Format.fprintf fmt "true" | False -> Format.fprintf fmt "false" | Node (v, l, h) -> Format.fprintf fmt "%d ? (%a) : (%a)" v fprintf h fprintf l let to_string bdd = let buff = Buffer.create 512 in let fmt = Format.formatter_of_buffer buff in fprintf fmt bdd ; Format.pp_print_flush fmt () ; Buffer.contents buff let of_bool = function true -> true_bdd | false -> false_bdd let neg x = Mem.memo (fun neg x -> match view x with | True -> false_bdd | False -> true_bdd | Node (var, low, high) -> node var (neg low) (neg high)) x (* TODO: memo 2 ? *) let rec comb_comm op n1 n2 = let comb_comm = comb_comm op in match (view n1, view n2) with | Node (v1, l1, h1), Node (v2, l2, h2) when v1 = v2 -> node v1 (comb_comm l1 l2) (comb_comm h1 h2) | Node (v1, l1, h1), Node (v2, _, _) when v1 < v2 -> node v1 (comb_comm l1 n2) (comb_comm h1 n2) | Node (_, _, _), Node (v2, l2, h2) -> node v2 (comb_comm n1 l2) (comb_comm n1 h2) | True, Node (v, l, h) | Node (v, l, h), True -> node v (comb_comm l true_bdd) (comb_comm h true_bdd) | False, Node (v, l, h) | Node (v, l, h), False -> node v (comb_comm l false_bdd) (comb_comm h false_bdd) | False, False -> of_bool (op false false) | False, True | True, False -> of_bool (op true false) | True, True -> of_bool (op true true) (* TODO: memo2 ? *) let rec comb op n1 n2 = let comb = comb op in match (view n1, view n2) with | Node (v1, l1, h1), Node (v2, l2, h2) when v1 = v2 -> node v1 (comb l1 l2) (comb h1 h2) | Node (v1, l1, h1), Node (v2, _, _) when v1 < v2 -> node v1 (comb l1 n2) (comb h1 n2) | Node (_, _, _), Node (v2, l2, h2) -> node v2 (comb n1 l2) (comb n1 h2) | True, Node (v, l, h) -> node v (comb true_bdd l) (comb true_bdd h) | Node (v, l, h), True -> node v (comb l true_bdd) (comb h true_bdd) | False, Node (v, l, h) -> node v (comb false_bdd l) (comb false_bdd h) | Node (v, l, h), False -> node v (comb l false_bdd) (comb h false_bdd) | False, False -> of_bool (op false false) | False, True -> of_bool (op false true) | True, False -> of_bool (op true false) | True, True -> of_bool (op true true) let conj = comb_comm (fun x y -> x && y) let disj = comb_comm (fun x y -> x || y) let imp = comb (fun x y -> (not x) || y) let eq = comb_comm (fun x y -> x = y) let compute tbl = let rec compute_aux bdd = match view bdd with | False -> false_bdd | True -> true_bdd | Node (v, l, h) -> ( match Hashtbl.find tbl v with | exception Not_found -> node v (compute_aux l) (compute_aux h) | true -> compute_aux h | false -> compute_aux l ) in compute_aux let size = (* TODO *) let module H = Hashtbl.Make (struct type t = Hash.t let equal = ( == ) let hash = Hashtbl.hash (* TODO *) end) in let tbl = H.create 512 in let rec size bdd = match view bdd with | False | True -> 0 | _ when H.mem tbl bdd -> 0 | Node (_, l, h) -> H.add tbl bdd () ; 1 + size l + size h in size let is_sat bdd = match view bdd with False -> false | _ -> true let count_sat card = let count = Mem.memo (fun count bdd -> match view bdd with | False -> 0 | True -> 1 | Node (v, l, h) -> assert (0 <= v && v < card) ; let count_side s = count s lsl (v - get_order s - 1) in count_side h + count_side l) in fun bdd -> count bdd lsl (card - get_order bdd - 1) let any_sat = let rec aux assign bdd = match view bdd with | False -> None | True -> Some assign | Node (v, l, h) -> ( match aux assign l with | None -> aux ((v, true) :: assign) h | Some assign -> Some ((v, false) :: assign) ) in aux [] let all_sat bdd = let add_assign v b = function | None -> None | Some assign -> Some ((v, b) :: assign) in let rec aux assign bdd = match view bdd with | False -> [None] | True -> [Some assign] | Node (v, l, h) -> let add_assign = add_assign v in let aux = aux assign in List.map (add_assign false) (aux l) @ List.map (add_assign true) (aux h) in List.fold_left (fun acc -> function None -> acc | Some assign -> assign :: acc) [] (aux [] bdd) (* TODO: in each assign, add all the unused vars. ? *) let random_sat _ = (* let _ = count_sat maxn in *) let rec aux assign bdd = match view bdd with | False -> None | True -> Some assign | Node (v, l, h) -> ( if is_sat l && is_sat h then if true (* TODO *) then aux ((v, false) :: assign) h else aux ((v, true) :: assign) l else match aux assign l with | None -> aux ((v, true) :: assign) h | Some assign -> Some ((v, false) :: assign) ) in aux []