<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Heap Heap Array! &#187; Project Euler</title>
	<atom:link href="http://siwoti.com/blog/category/project-euler/feed/" rel="self" type="application/rss+xml" />
	<link>http://siwoti.com/blog</link>
	<description>Putting the &#039;dys&#039; in &#039;functional programming&#039;.</description>
	<lastBuildDate>Fri, 03 Sep 2010 03:05:51 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Project Euler Problem 14</title>
		<link>http://siwoti.com/blog/2009/12/project-euler-problem-14/</link>
		<comments>http://siwoti.com/blog/2009/12/project-euler-problem-14/#comments</comments>
		<pubDate>Mon, 07 Dec 2009 05:24:47 +0000</pubDate>
		<dc:creator>Benjamin Geiger</dc:creator>
				<category><![CDATA[F#]]></category>
		<category><![CDATA[Functional Programming]]></category>
		<category><![CDATA[Project Euler]]></category>

		<guid isPermaLink="false">http://siwoti.com/blog/?p=74</guid>
		<description><![CDATA[For the last 36 hours, off and on, I&#8217;ve been working on solutions to Project Euler problems, just to learn some F#. I started at the beginning and have been working my way up, as the difficulty increases. So far, I&#8217;ve solved problems 1-10, 14, 47, and 243. Problem 9 doesn&#8217;t really count as I [...]]]></description>
			<content:encoded><![CDATA[<p>For the last 36 hours, off and on, I&#8217;ve been working on solutions to <a href="http://projecteuler.net/" onclick="pageTracker._trackPageview('/outgoing/projecteuler.net/?referer=');">Project Euler</a> problems, just to learn some F#. I started at the beginning and have been working my way up, as the difficulty increases.</p>
<p>So far, I&#8217;ve solved problems 1-10, 14, 47, and 243. Problem 9 doesn&#8217;t really count as I basically borrowed the code verbatim from <a href="http://diditwith.net/2009/03/09/YAPESProblemNine.aspx" onclick="pageTracker._trackPageview('/outgoing/diditwith.net/2009/03/09/YAPESProblemNine.aspx?referer=');">another site</a>, and problem 5 almost doesn&#8217;t as I solved it with pencil and paper.</p>
<p>I may cover a few of the others later, but for now I&#8217;ll focus on 14.</p>
<p><span id="more-74"></span></p>
<p><a href="http://projecteuler.net/index.php?section=problems&#038;id=14" onclick="pageTracker._trackPageview('/outgoing/projecteuler.net/index.php?section=problems_038_id=14&amp;referer=');">Problem 14</a> was a bit trickier than it looked. I knew from the start that I&#8217;d have to resort to some sort of memoization to get runtime down to a reasonable level. As noted on the Project Euler site:</p>
<blockquote><p>
Each problem has been designed according to a &#8220;one-minute rule&#8221;, which means that although it may take several hours to design a successful algorithm with more difficult problems, an efficient implementation will allow a solution to be obtained on a modestly powered computer in less than one minute.
</p></blockquote>
<p>A brute-force solution without memoization took way too long on the virtual machine I use to run Visual Studio 2010. (I don&#8217;t know how long, because I killed it after about ten minutes.) So, I borrowed some code from <cite>Programming F#</cite> (page 199):</p>
<pre class="brush: fsharp; title: ; notranslate">
open System.Collections.Generic

let memoize (f : 'a -&gt; 'b) =
    let dict = new Dictionary&lt;'a, 'b&gt;()

    let memoizedFunc (input : 'a) =
        match dict.TryGetValue(input) with
        | true, x -&gt; x
        | false, _ -&gt;
            let answer = f input
            dict.Add(input, answer)
            answer

    memoizedFunc
</pre>
<p>The project statement uses a starting point of 13, and gives a sequence length of 10; I realized that if the sequence ever reached 13, for instance, it would always be at 1 ten iterations later. My first attempt at a solution copied around the actual sequence of numbers for each starting point. Ideally, if I always tacked the new number on as the head, the tail would eventually be a list that had already been generated, and wouldn&#8217;t need to be recreated or even copied, as the new list could just point to the old one.</p>
<p>While this wasn&#8217;t a horrible idea, it seemed a lot slower than I&#8217;d like. So, I switched to a simple tally of sequence length. Still slow.</p>
<p>After I let the program run all the way through, I realized my problem: the debugging output. What started as a ten-minute process shortened itself to about ten seconds when I removed the printfn from the inner function. I probably could have kept the sequence after all.</p>
<pre class="brush: fsharp; title: ; notranslate">
let rec collatz =
    // The only reason to create an inner function here
    // is to memoize it. You have to call the outer
    // function recursively or the memoize function
    // won't catch it.
    let collatz_ (x : int64) =
        if x = 1L then 0
        elif x % 2L = 0L then
            1 + collatz (x / 2L)
        else
            1 + collatz (3L * x + 1L)

    memoize collatz_

// Candidates
[ 1L..999999L ]
    // Calculate path length for each, decorate
    |&gt; List.map (fun x -&gt; (collatz x, x))
    // Sort by path length...
    |&gt; List.sortBy fst
    // ... long paths first
    |&gt; List.rev
    // Give me just the longest path
    |&gt; List.head
    // Give me just the starting point
    |&gt; snd;;
</pre>
<p>PS: <a href="http://en.wikipedia.org/wiki/Collatz_conjecture" onclick="pageTracker._trackPageview('/outgoing/en.wikipedia.org/wiki/Collatz_conjecture?referer=');">if you&#8217;re asking why it&#8217;s called &#8220;collatz&#8221;?</a></p>
<p>So, what did I learn?</p>
<p>I learned that console output is <em>slow</em>. I also learned that decorating an input list with tuples (a la the &#8220;Schwartzian Transform&#8221;) is a useful technique in F#. Function pipelining is incredibly handy. And I&#8217;m addicted to Project Euler.</p>
]]></content:encoded>
			<wfw:commentRss>http://siwoti.com/blog/2009/12/project-euler-problem-14/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

