type bdd = One | Zero | Node of bdd * int * int * bdd let rec eval bdd vars = match bdd with Zero -> false | One -> true | Node(l, v, _, h) -> if vars.(v) then eval h vars else eval l vars let getId bdd = match bdd with Node(_,_,id,_) -> id | Zero -> 0 | One -> 1 let initSize_1 = 8*1024 - 1 let nodeC = ref 1 let sz_1 = ref initSize_1 let htab = ref(Array.create (!sz_1+1) []) let n_items = ref 0 let hashVal x y v = x lsl 1 + y + v lsl 2 let resize newSize = let arr = !htab in let newSz_1 = newSize-1 in let newArr = Array.create newSize [] in let rec copyBucket bucket = match bucket with [] -> () | n ::ns -> match n with Node(l,v,_,h) -> let ind = hashVal (getId l) (getId h) v land newSz_1 in newArr.(ind) <- (n :: newArr.(ind)); copyBucket ns in for n = 0 to !sz_1 do copyBucket(arr.(n)) done; htab := newArr; sz_1 := newSz_1 let rec insert idl idh v ind bucket newNode = if !n_items <= !sz_1 then ( (!htab).(ind) <- (newNode :: bucket); incr n_items ) else ( resize(!sz_1 + !sz_1 + 2); let ind = hashVal idl idh v land (!sz_1) in (!htab).(ind) <- newNode :: (!htab).(ind) ) let resetUnique () = ( sz_1 := initSize_1; htab := Array.create (!sz_1+1) []; n_items := 0; nodeC := 1 ) let mkNode low v high = let idl = getId low in let idh = getId high in if idl = idh then low else let ind = hashVal idl idh v land (!sz_1) in let bucket = (!htab).(ind) in let rec lookup b = match b with [] -> let n = Node(low, v, (incr nodeC; !nodeC), high) in insert (getId low) (getId high) v ind bucket n; n | n :: ns -> match n with Node(l,v',id,h) -> if v=v' & idl=getId l & idh=getId h then n else lookup ns in lookup bucket type ordering = LESS | EQUAL | GREATER let cmpVar (x:int) (y:int) = if xy then GREATER else EQUAL let zero = Zero let one = One let mkVar x = mkNode zero x one let cacheSize = 1999 let andslot1 = Array.create cacheSize 0 let andslot2 = Array.create cacheSize 0 let andslot3 = Array.create cacheSize zero let xorslot1 = Array.create cacheSize 0 let xorslot2 = Array.create cacheSize 0 let xorslot3 = Array.create cacheSize zero let notslot1 = Array.create cacheSize 0 let notslot2 = Array.create cacheSize one let hash x y = ((x lsl 1)+y) mod cacheSize let rec not n = match n with Zero -> One | One -> Zero | Node(l, v, id, r) -> let h = id mod cacheSize in if id=notslot1.(h) then notslot2.(h) else let f = mkNode (not l) v (not r) in notslot1.(h) <- id; notslot2.(h) <- f; f let rec and2 n1 n2 = match n1 with Node(l1, v1, i1, r1) -> (match n2 with Node(l2, v2, i2, r2) -> let h = hash i1 i2 in if i1=andslot1.(h) & i2=andslot2.(h) then andslot3.(h) else let f = match cmpVar v1 v2 with EQUAL -> mkNode (and2 l1 l2) v1 (and2 r1 r2) | LESS -> mkNode (and2 l1 n2) v1 (and2 r1 n2) | GREATER -> mkNode (and2 n1 l2) v2 (and2 n1 r2) in andslot1.(h) <- i1; andslot2.(h) <- i2; andslot3.(h) <- f; f | Zero -> Zero | One -> n1) | Zero -> Zero | One -> n2 let rec xor n1 n2 = match n1 with Node(l1, v1, i1, r1) -> (match n2 with Node(l2, v2, i2, r2) -> let h = hash i1 i2 in if i1=andslot1.(h) & i2=andslot2.(h) then andslot3.(h) else let f = match cmpVar v1 v2 with EQUAL -> mkNode (xor l1 l2) v1 (xor r1 r2) | LESS -> mkNode (xor l1 n2) v1 (xor r1 n2) | GREATER -> mkNode (xor n1 l2) v2 (xor n1 r2) in andslot1.(h) <- i1; andslot2.(h) <- i2; andslot3.(h) <- f; f | Zero -> n1 | One -> not n1) | Zero -> n2 | One -> not n2 let hwb n = let rec h i j = if i=j then mkVar i else xor (and2 (not(mkVar j)) (h i (j-1))) (and2 (mkVar j) (g i (j-1))) and g i j = if i=j then mkVar i else xor (and2 (not(mkVar i)) (h (i+1) j)) (and2 (mkVar i) (g (i+1) j)) in h 1 n (* Testing *) let seed = ref 0 let random() = seed := !seed * 25173 + 17431; !seed land 1 > 0 let random_vars n = let vars = Array.create n false in for i = 0 to n - 1 do vars.(i) <- random() done; vars let test_hwb bdd vars = (* We should have eval bdd vars = vars.(n) if n > 0 eval bdd vars = 0 if n = 0 where n is the number of "true" elements in vars. *) let ntrue = ref 0 in for i = 0 to Array.length vars - 1 do if vars.(i) then incr ntrue done; eval bdd vars = (if !ntrue > 0 then vars.(!ntrue) else false) let main () = let n = if Array.length Sys.argv >= 2 then int_of_string Sys.argv.(1) else 20 in let ntests = if Array.length Sys.argv >= 3 then int_of_string Sys.argv.(2) else 50 in let bdd = hwb n in let succeeded = ref true in for i = 1 to ntests do succeeded := !succeeded || test_hwb bdd (random_vars n) done; if !succeeded then print_string "OK\n" else print_string "FAILED\n"; exit 0 let _ = main()