(* TEST *) (** This test weak table by application to the memoization of collatz (also known as syracuse) algorithm suite computation *) (** We use Int64 because they are boxed *) (** number of element of the suite to compute (more are computed) *) let n = 1000 let two = Int64.of_int 2 let three = Int64.of_int 3 let collatz x = if Int64.equal (Int64.rem x two) Int64.zero then Int64.div x two else Int64.succ (Int64.mul x three) module S = struct include Int64 let hash (x:t) = Hashtbl.hash x end let pp = Int64.to_string module HW = Ephemeron.K1.Make(S) module SW = Weak.Make(S) let sw = SW.create n let hashcons x = SW.merge sw x let hw = HW.create n let rec fill_hw x = if not (HW.mem hw x) then begin let y = hashcons (collatz x) in HW.add hw x y; fill_hw y end exception InvariantBroken of string let test b = Printf.ksprintf (fun s -> if not b then raise (InvariantBroken s)) let rec check_hw_aux cache x = (** We use int so that the cache doesn't make x alive *) if not (Hashtbl.mem cache (Int64.to_int x)) then begin test (HW.mem hw x) "missing %s%!" (pp x); let y = try HW.find hw x with Not_found -> test (not (HW.mem hw x)) "key in the table but data missing %s!%!" (pp x); test false "missing %s%!" (pp x); assert false in let y' = collatz x in test (Int64.equal y y') "bad result for %s: %s instead of %s%!" (pp x) (pp y) (pp y'); let y'' = hashcons y' in test (y == y'') "bad result for %s: not physically equal%!" (pp x); Hashtbl.add cache (Int64.to_int x) (); check_hw_aux cache y end let check_hw iter = let cache = Hashtbl.create n in iter (fun x -> check_hw_aux cache x) (** tests *) let run ~next ~check = HW.reset hw; SW.clear sw; (* Gc.full_major (); *) for x=0 to n do let x' = next x in fill_hw x'; check x; done; Gc.full_major (); HW.clean hw; Printf.printf "length: %i\n%!" (HW.length hw) let print_stats () = let print_stats name stats = Printf.printf "%s (%3i,%3i,%3i): %!" name stats.Hashtbl.num_bindings stats.Hashtbl.num_buckets stats.Hashtbl.max_bucket_length; Array.iteri (fun i n -> Printf.printf "%i: %i, %!" i n) stats.Hashtbl.bucket_histogram; Printf.printf "\n%!"; in print_stats "stats : " (HW.stats hw); print_stats "stats_alive: " (HW.stats_alive hw) let test_keep_last d d' = Printf.printf "## Keep last %i alive, check each %i ##\n%!" (n/d) (n/d'); let keep_alive = Array.make (n/d) Int64.zero in let next x = let x' = hashcons (Int64.of_int x) in Array.set keep_alive (x mod (n/d)) x'; x' in let check x = if x mod (n/d') = 0 || x = n then begin check_hw (fun f -> Array.iter f keep_alive) end in run ~next ~check; (** keep the array alive until the end *) let s = Array.fold_left (fun acc x -> Int64.add x acc) Int64.zero keep_alive in Printf.printf "sum of kept alive %s\n%!" (pp s); print_stats (); Printf.printf "\n%!" let () = test_keep_last 1 10; test_keep_last 50 10; test_keep_last 100 2