From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.1.3 (2006-06-01) on yquem.inria.fr X-Spam-Level: * X-Spam-Status: No, score=1.3 required=5.0 tests=SPF_FAIL autolearn=disabled version=3.1.3 Received: from mail3-relais-sop.national.inria.fr (mail3-relais-sop.national.inria.fr [192.134.164.104]) by yquem.inria.fr (Postfix) with ESMTP id 7F229BC6B for ; Thu, 29 Nov 2007 04:17:46 +0100 (CET) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AgAAADa+TUfAXQInh2dsb2JhbACPRQEBAQgKKQ X-IronPort-AV: E=Sophos;i="4.23,226,1194217200"; d="scan'208";a="6293795" Received: from concorde.inria.fr ([192.93.2.39]) by mail3-smtp-sop.national.inria.fr with ESMTP; 29 Nov 2007 04:17:46 +0100 Received: from mail4-relais-sop.national.inria.fr (mail4-relais-sop.national.inria.fr [192.134.164.105]) by concorde.inria.fr (8.13.6/8.13.6) with ESMTP id lAT3HjDQ010508 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=OK) for ; Thu, 29 Nov 2007 04:17:45 +0100 X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AgAAAPq9TUfRVaK0kmdsb2JhbACPRQEBAQEHAgYp X-IronPort-AV: E=Sophos;i="4.23,226,1194217200"; d="scan'208";a="19792573" Received: from el-out-1112.google.com ([209.85.162.180]) by mail4-smtp-sop.national.inria.fr with ESMTP; 29 Nov 2007 04:17:44 +0100 Received: by el-out-1112.google.com with SMTP id m34so902033ele for ; Wed, 28 Nov 2007 19:17:43 -0800 (PST) Received: by 10.142.114.15 with SMTP id m15mr1762803wfc.1196306262111; Wed, 28 Nov 2007 19:17:42 -0800 (PST) Received: by 10.142.226.14 with HTTP; Wed, 28 Nov 2007 19:17:42 -0800 (PST) Message-ID: Date: Wed, 28 Nov 2007 19:17:42 -0800 From: "Evan Klitzke" To: caml-list@inria.fr Subject: Help with simple ocaml memoization problem MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit Content-Disposition: inline X-Miltered: at concorde with ID 474E2F59.000 by Joe's j-chkmail (http://j-chkmail . ensmp . fr)! X-Spam: no; 0.00; ocaml:01 memoization:01 ocaml:01 memoize:01 computed:01 ocamlopt:01 pointers:01 sig:01 val:01 struct:01 hash:01 memoized:01 mult:01 memoization:01 computed:01 Hi everyone, I'm learning Ocaml and I'm trying to figure out why the code I've written is so slow (and not working). I'm trying to learn Ocaml by implementing the Project Euler problems in Ocaml, and I'm stuck on problem 14 (http://projecteuler.net/index.php?section=problems&id=14). Basically I'm doing the 3*n+1 problem and I need to memoize values that I've already computed if the function is going to finish in a reasonable amount of time. I wrote a really short prototype of what I want to do in Python, and that code is really short and runs quickly (11 seconds); if you're interested you can see the prototype at http://static.eklitzke.org/collatz.py You can see my Ocaml attempt at http://static.eklitzke.org/problem14.ml . As you can see, it's a _lot_ more code, which alone leads me to think that I'm probably not doing this idiomatically. When I run it (compiled with ocamlopt, ocaml 3.10 on Linux), the memory usage climbs and after it reaches about 128 MB (after about 30 seconds) I get the error: Fatal error: exception Stack_overflow I think I could use some help with this problem. Maybe I just need to increase the stack size (how do I do that?) -- the Python version gets to about the same size right before finishing, so this seems like a reasonable amount of memory to use -- but I'm concerned that maybe I'm doing something else wrong, because I'd expect the Ocaml version to run much more quickly given that it is compiled to native code. I would appreciate any pointers for things that I'm doing wrong or awkwardly. Thanks in advance! I'm going to include the text of my ocaml version inline below, but due to the long lines in the program it will likely end up mangled :-/ module type INT = sig type t = int val compare : t -> t-> int end;; module Int : INT = struct type t = int let compare i j = if i < j then -1 else if i = j then 0 else 1 end;; open Big_int open Map (* A hash table for ints *) module IntMap = Map.Make(Int);; (* This is where we're going to store memoized values for find_collatz_len *) let ann = ref IntMap.empty;; (* Find the length of the chain for the int n *) let find_collatz_len (n:int) = (* This is the definition of the collatz map for big_ints *) let collatz (n:big_int) = let two_big_int = succ_big_int unit_big_int in if eq_big_int (mod_big_int n two_big_int) zero_big_int then div_big_int n two_big_int else succ_big_int(mult_int_big_int 3 n) (* Tries to find the value of key `k' in the map m, or 0 if not found *) and find_safe m k = try IntMap.find k m with Not_found -> 0 in (* Helper function that accepts big_ints; t is the term that we're finding the length of *) let rec aux_collatz_len (t:big_int) = (* We use memoization for terms small enough to fit in an int *) if is_int_big_int t then let t_int = int_of_big_int t in let v = find_safe !ann t_int in if v <> 0 then v (* Cache hit -- we've already computed aux_collatz_len for this value of t *) else if eq_big_int t unit_big_int then 1 else let v' = 1 + aux_collatz_len (collatz t) in ann := IntMap.add t_int v' !ann ; v' else 1 + aux_collatz_len (collatz t) in aux_collatz_len (big_int_of_int n);; (* Makes the list [1..n] *) let nats n = let rec rnats m = if m = 0 then [] else m :: (rnats (m - 1)) in List.rev (rnats n) ;; let biggest_int l = let rec aux l (num, len) = if l = [] then num else let (a, b) = List.hd l and t = List.tl l in if b > len then aux t (a, b) else aux t (num, len) in aux l (List.hd l) ;; let solution = biggest_int (List.map (fun x -> (x, find_collatz_len x)) (nats 999999)) ;; print_endline (string_of_int solution) -- Evan Klitzke