<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" version="2.0">

<channel>
	<title>Clojure and me</title>
	
	<link>http://clj-me.cgrand.net</link>
	<description>When the pupil is ready to learn, a teacher will appear.</description>
	<lastBuildDate>Wed, 10 Feb 2010 10:04:14 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/ClojureAndMe" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="clojureandme" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>The reasons why Enlive templates return seqs of strings</title>
		<link>http://clj-me.cgrand.net/2010/02/10/why-enlive-templates-return-seqs-of-strings/</link>
		<comments>http://clj-me.cgrand.net/2010/02/10/why-enlive-templates-return-seqs-of-strings/#comments</comments>
		<pubDate>Wed, 10 Feb 2010 10:03:29 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=276</guid>
		<description><![CDATA[The main reasons behind Enlive templates returning seqs of strings are:

Ring does not expose the output stream (and I think it is a good thing)
I don&#8217;t want to allocate the whole response as a single string

 Hence it seemed to me the simplest thing to do. (Simpler than implementing InputStream or making templates and Ring [...]]]></description>
			<content:encoded><![CDATA[<p>The main reasons behind Enlive templates returning seqs of strings are:
<ul>
<li><a href="http://github.com/mmcgrana/ring/blob/master/SPEC">Ring</a> does not expose the output stream (and I think it is a good thing)</li>
<li>I don&#8217;t want to allocate the whole response as a single string</li>
</ul>
<p> Hence it seemed to me the simplest thing to do. (Simpler than implementing InputStream or making templates and Ring to communicate through a kind of reduce-based IO.)</p>
<p>Nodes serializations are cached when the source of the template is read:
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">deftemplate</span> <span class="nv">hello</span> <span class="p">(</span><span class="nb">-&gt; </span><span class="s">&quot;&lt;h1&gt;This is a static title&lt;h2&gt;This is a dynamic title&quot;</span> <span class="nv">java</span><span class="o">.</span><span class="nv">io</span><span class="o">.</span><span class="nv">StringReader</span><span class="o">.</span> <span class="nv">html-resource</span><span class="p">)</span> <span class="p">[</span><span class="nv">name</span><span class="p">]</span> <span class="p">[</span><span class="nv">:h2</span><span class="p">]</span> <span class="p">(</span><span class="nf">content</span> <span class="nv">name</span><span class="p">))</span>
<span class="o">#</span><span class="ss">&#39;user/hello</span>
<span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">hello</span> <span class="s">&quot;Replaced dynamic title&quot;</span><span class="p">)</span>
<span class="p">(</span><span class="s">&quot;&lt;html&gt;&quot;</span> <span class="s">&quot;&lt;body&gt;&quot;</span> <span class="s">&quot;&lt;h1&gt;This is a static title&lt;/h1&gt;&quot;</span> <span class="s">&quot;&lt;h2&gt;&quot;</span> <span class="s">&quot;Replaced dynamic title&quot;</span> <span class="s">&quot;&lt;/h2&gt;&quot;</span> <span class="s">&quot;&lt;/body&gt;&quot;</span> <span class="s">&quot;&lt;/html&gt;&quot;</span><span class="p">)</span>
<span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">hello</span> <span class="s">&quot;Replaced dynamic title II&quot;</span><span class="p">)</span>
<span class="p">(</span><span class="s">&quot;&lt;html&gt;&quot;</span> <span class="s">&quot;&lt;body&gt;&quot;</span> <span class="s">&quot;&lt;h1&gt;This is a static title&lt;/h1&gt;&quot;</span> <span class="s">&quot;&lt;h2&gt;&quot;</span> <span class="s">&quot;Replaced dynamic title II&quot;</span> <span class="s">&quot;&lt;/h2&gt;&quot;</span> <span class="s">&quot;&lt;/body&gt;&quot;</span> <span class="s">&quot;&lt;/html&gt;&quot;</span><span class="p">)</span>
<span class="nv">user=&gt;</span> <span class="p">(</span><span class="nb">map </span><span class="nv">identical?</span> <span class="nv">*1</span> <span class="nv">*2</span><span class="p">)</span>
<span class="p">(</span><span class="nf">true</span> <span class="nv">true</span> <span class="nv">true</span> <span class="nv">true</span> <span class="nv">false</span> <span class="nv">true</span> <span class="nv">true</span> <span class="nv">true</span><span class="p">)</span></pre>
<p>Thus no string allocation except for the dynamic parts but the real <i>raison d&#8217;être</i> of the static nodes serializations cache is to reduce the time spent traversing the tree and the number of allocated Cons (since the strings are longer).</p>
<p>Even without this cache there&#8217;s no String allocation when serializing a tree (but many Cons instances are allocated):
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">x</span> <span class="p">{</span><span class="nv">:tag</span> <span class="nv">:html</span> <span class="nv">:content</span> <span class="p">[{</span><span class="nv">:tag</span> <span class="nv">:body</span> <span class="nv">:content</span> <span class="p">[{</span><span class="nv">:tag</span> <span class="nv">:h1</span> <span class="nv">:content</span> <span class="p">[</span><span class="s">&quot;This is a static title&quot;</span><span class="p">]}</span> <span class="p">{</span><span class="nv">:tag</span> <span class="nv">:h2</span> <span class="nv">:content</span> <span class="p">[</span><span class="s">&quot;This is a dynamic title&quot;</span><span class="p">]}]}]}]</span>
         <span class="p">(</span><span class="nb">every? </span><span class="p">(</span><span class="nb">partial </span><span class="nv">apply</span> <span class="nv">identical?</span><span class="p">)</span> <span class="p">(</span><span class="nb">map </span><span class="nv">vector</span> <span class="p">(</span><span class="nf">emit*</span> <span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="nf">emit*</span> <span class="nv">x</span><span class="p">))))</span>
<span class="nv">true</span></pre>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/8ctrzS2Cpnc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2010/02/10/why-enlive-templates-return-seqs-of-strings/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Clojure refactoring: flattening reduces</title>
		<link>http://clj-me.cgrand.net/2010/01/19/clojure-refactoring-flattening-reduces/</link>
		<comments>http://clj-me.cgrand.net/2010/01/19/clojure-refactoring-flattening-reduces/#comments</comments>
		<pubDate>Tue, 19 Jan 2010 10:48:51 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[mistakes]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=270</guid>
		<description><![CDATA[This morning I wrote some code which looked like:
(reduce (fn [acc x]
          (reduce (fn [acc y]
                    (reduce f acc y)) acc x)) init xs)
 (it was slightly [...]]]></description>
			<content:encoded><![CDATA[<p>This morning I wrote some code which looked like:
<pre class="highlight"><span class="p">(</span><span class="nb">reduce </span><span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">acc</span> <span class="nv">x</span><span class="p">]</span>
          <span class="p">(</span><span class="nb">reduce </span><span class="p">(</span><span class="k">fn </span><span class="p">[</span><span class="nv">acc</span> <span class="nv">y</span><span class="p">]</span>
                    <span class="p">(</span><span class="nb">reduce </span><span class="nv">f</span> <span class="nv">acc</span> <span class="nv">y</span><span class="p">))</span> <span class="nv">acc</span> <span class="nv">x</span><span class="p">))</span> <span class="nv">init</span> <span class="nv">xs</span><span class="p">)</span></pre>
<p> (it was slightly more complex with some filtering and destructuring thrown in for good measure).</p>
<p>I wasn&#8217;t happy with those nested reduces and it occured to me that I could refactor it to use a single one:
<pre class="highlight"><span class="p">(</span><span class="nb">reduce </span><span class="nv">f</span> <span class="nv">init</span> <span class="p">(</span><span class="k">for </span><span class="p">[</span><span class="nv">x</span> <span class="nv">xs,</span> <span class="nv">y</span> <span class="nv">x,</span> <span class="nv">z</span> <span class="nv">y</span><span class="p">]</span> <span class="nv">z</span><span class="p">))</span></pre>
<p> Now that reads better!</p>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/fi1UN6QlmCI" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2010/01/19/clojure-refactoring-flattening-reduces/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Graph Structured Stacks in Clojure</title>
		<link>http://clj-me.cgrand.net/2010/01/16/graph-structured-stacks-in-clojure/</link>
		<comments>http://clj-me.cgrand.net/2010/01/16/graph-structured-stacks-in-clojure/#comments</comments>
		<pubDate>Sat, 16 Jan 2010 15:41:41 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[pondering]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=257</guid>
		<description><![CDATA[I am currently pondering how best to represent Graph Structured Stacks in Clojure. My first idea was to use maps.

So this GSS would be represented as:
{7 {3 {1 {0 {}}},
    4 {1 {0 {}}},
    5 {2 {0 {}}}},
 8 {6 {2 {0 {}}}}}
 Please note that repeated maps in [...]]]></description>
			<content:encoded><![CDATA[<p>I am currently pondering how best to represent <a href="http://en.wikipedia.org/wiki/Graph-structured_stack">Graph Structured Stacks</a> in Clojure. My first idea was to use maps.</p>
<p><img class="alignleft" title="An example of a graph-structured stack" src="http://upload.wikimedia.org/wikipedia/en/c/cd/Graphstructuredstack_jaredwf.png" alt="" width="251" height="209" /></p>
<p>So this GSS would be represented as:
<pre class="highlight"><span class="p">{</span><span class="mi">7</span> <span class="p">{</span><span class="mi">3</span> <span class="p">{</span><span class="mi">1</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}</span><span class="o">,</span>
    <span class="mi">4</span> <span class="p">{</span><span class="mi">1</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}</span><span class="o">,</span>
    <span class="mi">5</span> <span class="p">{</span><span class="mi">2</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}}</span><span class="o">,</span>
 <span class="mi">8</span> <span class="p">{</span><span class="mi">6</span> <span class="p">{</span><span class="mi">2</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}}}</span></pre>
<p> Please note that repeated maps in this representation would be shared by construction.</p>
<p>It is all well and good this representation allow me to easily perform stack ops but I want to also be able to traverse the stacks from the bottom. This means to make the graph cyclic so I thought that I need an <a href="http://en.wikipedia.org/wiki/Adjacency_list">adjency list</a> or, more realistically, two indexed versions (maps of sets) of this list to be able to traverse the GSS in any direction. Or the map-based representation for direct traversal and an adjency map for reverse traversal.</p>
<p>To me the more boring part with this adjency lists is that I  have to name the GSS nodes. Wait! There are natural identifiers for these nodes: their key-value pairs in the map-based representation! <code class="highlight"><span class="p">[</span><span class="mi">2</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}]</span></code> is a natural identifier for node #2 and <code class="highlight"><span class="p">[</span><span class="mi">2</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}]</span></code> the one for node #7.</p>
<p>Now I&#8217;m able to represent the GSS as:
<pre class="highlight"><span class="p">[</span><span class="c1">;; direct representation</span>
 <span class="p">{</span><span class="mi">7</span> <span class="p">{</span><span class="mi">3</span> <span class="p">{</span><span class="mi">1</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}</span><span class="o">,</span>
     <span class="mi">4</span> <span class="p">{</span><span class="mi">1</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}</span><span class="o">,</span>
     <span class="mi">5</span> <span class="p">{</span><span class="mi">2</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}}</span><span class="o">,</span>
  <span class="mi">8</span> <span class="p">{</span><span class="mi">6</span> <span class="p">{</span><span class="mi">2</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}}}</span>
 <span class="c1">;; adjency map for reverse traversal</span>
 <span class="p">{</span><span class="nv">nil</span> <span class="o">#</span><span class="p">{[</span><span class="mi">0</span> <span class="p">{}]}</span><span class="o">,</span>
  <span class="p">[</span><span class="mi">0</span> <span class="p">{}]</span> <span class="o">#</span><span class="p">{[</span><span class="mi">1</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}]</span>
           <span class="p">[</span><span class="mi">2</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}]}</span><span class="o">,</span>
  <span class="p">[</span><span class="mi">1</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}]</span> <span class="o">#</span><span class="p">{[</span><span class="mi">3</span> <span class="p">{</span><span class="mi">1</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}]</span>
               <span class="p">[</span><span class="mi">4</span> <span class="p">{</span><span class="mi">1</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}]}</span><span class="o">,</span>
  <span class="p">[</span><span class="mi">2</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}]</span> <span class="o">#</span><span class="p">{[</span><span class="mi">5</span> <span class="p">{</span><span class="mi">2</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}]</span>
               <span class="p">[</span><span class="mi">6</span> <span class="p">{</span><span class="mi">2</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}]}</span><span class="o">,</span>
  <span class="p">[</span><span class="mi">3</span> <span class="p">{</span><span class="mi">1</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}]</span> <span class="o">#</span><span class="p">{[</span><span class="mi">7</span> <span class="p">{</span><span class="mi">3</span> <span class="p">{</span><span class="mi">1</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}</span><span class="o">,</span>
                       <span class="mi">4</span> <span class="p">{</span><span class="mi">1</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}</span><span class="o">,</span>
                       <span class="mi">5</span> <span class="p">{</span><span class="mi">2</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}}]}</span><span class="o">,</span>
  <span class="p">[</span><span class="mi">4</span> <span class="p">{</span><span class="mi">1</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}]</span> <span class="o">#</span><span class="p">{[</span><span class="mi">7</span> <span class="p">{</span><span class="mi">3</span> <span class="p">{</span><span class="mi">1</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}</span><span class="o">,</span>
                       <span class="mi">4</span> <span class="p">{</span><span class="mi">1</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}</span><span class="o">,</span>
                       <span class="mi">5</span> <span class="p">{</span><span class="mi">2</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}}]}</span><span class="o">,</span>
  <span class="p">[</span><span class="mi">5</span> <span class="p">{</span><span class="mi">2</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}]</span> <span class="o">#</span><span class="p">{[</span><span class="mi">7</span> <span class="p">{</span><span class="mi">3</span> <span class="p">{</span><span class="mi">1</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}</span><span class="o">,</span>
                       <span class="mi">4</span> <span class="p">{</span><span class="mi">1</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}</span><span class="o">,</span>
                       <span class="mi">5</span> <span class="p">{</span><span class="mi">2</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}}]}</span><span class="o">,</span>
  <span class="p">[</span><span class="mi">6</span> <span class="p">{</span><span class="mi">2</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}]</span> <span class="o">#</span><span class="p">{[</span><span class="mi">8</span> <span class="p">{</span><span class="mi">6</span> <span class="p">{</span><span class="mi">2</span> <span class="p">{</span><span class="mi">0</span> <span class="p">{}}}}]}}]</span></pre>
<p> Granted the serialization is verbose but all nodes are shared in memory by construction and I find this model rather simple.</p>
<p>Does anyone have other ideas on how to functionally implement such a structure?</p>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/Ti1-Xs9hGv4" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2010/01/16/graph-structured-stacks-in-clojure/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Are pipe dreams made of promises?</title>
		<link>http://clj-me.cgrand.net/2009/11/18/are-pipe-dreams-made-of-promises/</link>
		<comments>http://clj-me.cgrand.net/2009/11/18/are-pipe-dreams-made-of-promises/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 17:32:23 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=242</guid>
		<description><![CDATA[(defn pipe
 &#34;Returns a pair: a seq (the read end) and a function (the write end).
  The function can takes either no arguments to close the pipe 
  or one argument which is appended to the seq. Read is blocking.&#34;
 []
  (let [promises (atom (repeatedly promise))
       [...]]]></description>
			<content:encoded><![CDATA[<pre class="highlight"><span class="p">(</span><span class="k">defn </span><span class="nv">pipe</span>
 <span class="s">&quot;Returns a pair: a seq (the read end) and a function (the write end).</span>
<span class="s">  The function can takes either no arguments to close the pipe </span>
<span class="s">  or one argument which is appended to the seq. Read is blocking.&quot;</span>
 <span class="p">[]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">promises</span> <span class="p">(</span><span class="nf">atom</span> <span class="p">(</span><span class="nf">repeatedly</span> <span class="nv">promise</span><span class="p">))</span>
        <span class="nv">p</span> <span class="p">(</span><span class="nb">second </span><span class="nv">@promises</span><span class="p">)]</span>
    <span class="p">[(</span><span class="nf">lazy-seq</span> <span class="nv">@p</span><span class="p">)</span>
     <span class="p">(</span><span class="k">fn </span>
       <span class="p">([]</span> <span class="c1">;close the pipe</span>
         <span class="p">(</span><span class="k">let </span><span class="p">[[</span><span class="nv">a</span><span class="p">]</span> <span class="p">(</span><span class="nf">swap!</span> <span class="nv">promises</span> <span class="o">#</span><span class="p">(</span><span class="nv">vector</span> <span class="p">(</span><span class="nb">second </span><span class="nv">%</span><span class="p">)))]</span>
           <span class="p">(</span><span class="k">if </span><span class="nv">a</span>
             <span class="p">(</span><span class="nf">deliver</span> <span class="nv">a</span> <span class="nv">nil</span><span class="p">)</span>
             <span class="p">(</span><span class="nf">throw</span> <span class="p">(</span><span class="nf">Exception</span><span class="o">.</span> <span class="s">&quot;Pipe already closed&quot;</span><span class="p">)))))</span>
       <span class="p">([</span><span class="nv">x</span><span class="p">]</span> <span class="c1">;enqueue x</span>
         <span class="p">(</span><span class="k">let </span><span class="p">[[</span><span class="nv">a</span> <span class="nv">b</span><span class="p">]</span> <span class="p">(</span><span class="nf">swap!</span> <span class="nv">promises</span> <span class="nv">next</span><span class="p">)]</span>
           <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">and </span><span class="nv">a</span> <span class="nv">b</span><span class="p">)</span>
             <span class="p">(</span><span class="nf">do</span>
               <span class="p">(</span><span class="nf">deliver</span> <span class="nv">a</span> <span class="p">(</span><span class="nb">cons </span><span class="nv">x</span> <span class="p">(</span><span class="nf">lazy-seq</span> <span class="nv">@b</span><span class="p">)))</span>
               <span class="nv">x</span><span class="p">)</span>
             <span class="p">(</span><span class="nf">throw</span> <span class="p">(</span><span class="nf">Exception</span><span class="o">.</span> <span class="s">&quot;Pipe already closed&quot;</span><span class="p">))))))]))</span></pre>
<p>Beware of not printing the seq while the pipe is still open!</p>
<pre class="highlight"><span class="p">(</span><span class="k">let </span><span class="p">[[</span><span class="nv">q</span> <span class="nv">f</span><span class="p">]</span> <span class="p">(</span><span class="nf">pipe</span><span class="p">)]</span>
  <span class="p">(</span><span class="nf">future</span> <span class="p">(</span><span class="nb">doseq </span><span class="p">[</span><span class="nv">x</span> <span class="nv">q</span><span class="p">]</span> <span class="p">(</span><span class="nb">println </span><span class="nv">x</span><span class="p">))</span> <span class="p">(</span><span class="nb">println </span><span class="s">&quot;that&#39;s all folks!&quot;</span><span class="p">))</span>
  <span class="p">(</span><span class="nb">doseq </span><span class="p">[</span><span class="nv">x</span> <span class="p">(</span><span class="nb">range </span><span class="mi">10</span><span class="p">)]</span>
    <span class="p">(</span><span class="nf">f</span> <span class="nv">x</span><span class="p">))</span>
  <span class="p">(</span><span class="nf">f</span><span class="p">))</span> <span class="c1">;close the pipe</span></pre>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/COK5FHhUwqc" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2009/11/18/are-pipe-dreams-made-of-promises/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>An optimization job is never done</title>
		<link>http://clj-me.cgrand.net/2009/11/18/an-optimization-job-is-never-done/</link>
		<comments>http://clj-me.cgrand.net/2009/11/18/an-optimization-job-is-never-done/#comments</comments>
		<pubDate>Wed, 18 Nov 2009 10:26:01 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[optimization]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=230</guid>
		<description><![CDATA[&#8230; when you don&#8217;t set measurable goals.
Yesterday, in Life of Brian I showed several tricks to make an implementation of Brian&#8217;s Brain faster. I tought it was enough but since some disagree here comes another perf boost.
Repetitive lookups
In neighbours-count the first arg (which happens to be a seq of 3 items) is destructured:
(defn neighbours-count [[above [...]]]></description>
			<content:encoded><![CDATA[<p>&hellip; when you don&#8217;t set measurable goals.</p>
<p>Yesterday, in <a href="http://clj-me.cgrand.net/2009/11/17/life-of-brian/">Life of Brian</a> I showed several tricks to make an implementation of <a href="http://en.wikipedia.org/wiki/Brian's_Brain">Brian&#8217;s Brain</a> faster. I tought it was enough but since some disagree here comes another perf boost.</p>
<h2>Repetitive lookups</h2>
<p>In <code class="highlight"><span class="nv">neighbours-count</span></code> the first arg (which happens to be a seq of 3 items) is destructured:</p>
<pre class="highlight"><span class="p">(</span><span class="k">defn </span><span class="nv">neighbours-count</span> <span class="p">[[</span><span class="nv">above</span> <span class="nv">current</span> <span class="nv">below</span><span class="p">]</span> <span class="nv">i</span> <span class="nv">w</span><span class="p">]</span></pre>
<p>which means that there&#8217;s 3 lookups per <code class="highlight"><span class="nv">:off</span></code> cell while these lookups results are constant for a given row!</p>
<p>So let&#8217;s move these lookups in step1:</p>
<pre class="highlight"><span class="p">(</span><span class="k">defn </span><span class="nv">neighbours-count</span> <span class="p">[</span><span class="nv">above</span> <span class="nv">current</span> <span class="nv">below</span> <span class="nv">i</span> <span class="nv">w</span><span class="p">]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">j</span> <span class="p">(</span><span class="nf">mod</span> <span class="p">(</span><span class="nb">inc </span><span class="nv">i</span><span class="p">)</span> <span class="nv">w</span><span class="p">)</span>
        <span class="nv">k</span> <span class="p">(</span><span class="nf">mod</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">i</span><span class="p">)</span> <span class="nv">w</span><span class="p">)</span>
        <span class="nv">s</span> <span class="o">#</span><span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">= </span><span class="p">(</span><span class="nb">aget </span><span class="o">#</span><span class="nv">^objects</span> <span class="nv">%1</span> <span class="p">(</span><span class="nb">int </span><span class="nv">%2</span><span class="p">))</span> <span class="nv">:on</span><span class="p">)</span> <span class="mi">1</span> <span class="mi">0</span><span class="p">)]</span>
    <span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nf">s</span> <span class="nv">above</span> <span class="nv">j</span><span class="p">)</span> <span class="p">(</span><span class="nf">s</span> <span class="nv">above</span> <span class="nv">i</span><span class="p">))</span>
         <span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nf">s</span> <span class="nv">above</span> <span class="nv">k</span><span class="p">)</span> <span class="p">(</span><span class="nf">s</span> <span class="nv">current</span> <span class="nv">j</span><span class="p">)))</span>
      <span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nf">s</span> <span class="nv">current</span> <span class="nv">k</span><span class="p">)</span> <span class="p">(</span><span class="nf">s</span> <span class="nv">below</span> <span class="nv">j</span><span class="p">))</span>
        <span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nf">s</span> <span class="nv">below</span> <span class="nv">i</span><span class="p">)</span> <span class="p">(</span><span class="nf">s</span> <span class="nv">below</span> <span class="nv">k</span><span class="p">))))))</span>

<span class="p">(</span><span class="k">defn </span><span class="nv">step1</span> <span class="p">[[</span><span class="nv">above</span> <span class="o">#</span><span class="nv">^objects</span> <span class="nv">current</span> <span class="nv">below</span><span class="p">]]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">w</span> <span class="p">(</span><span class="nb">count </span><span class="nv">current</span><span class="p">)]</span>
    <span class="p">(</span><span class="nb">loop </span><span class="p">[</span><span class="nv">i</span> <span class="p">(</span><span class="nb">int </span><span class="p">(</span><span class="nb">dec </span><span class="nv">w</span><span class="p">))</span><span class="o">,</span> <span class="o">#</span><span class="nv">^objects</span> <span class="nv">row</span> <span class="p">(</span><span class="nf">aclone</span> <span class="nv">current</span><span class="p">)]</span>
      <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">neg? </span><span class="nv">i</span><span class="p">)</span>
        <span class="nv">row</span>
        <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">c</span> <span class="p">(</span><span class="nb">aget </span><span class="nv">current</span> <span class="nv">i</span><span class="p">)]</span>
          <span class="p">(</span><span class="nf">cond</span>
            <span class="p">(</span><span class="nb">= </span><span class="nv">c</span> <span class="nv">:on</span><span class="p">)</span>
              <span class="p">(</span><span class="nf">recur</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">i</span><span class="p">)</span> <span class="p">(</span><span class="nb">doto </span><span class="nv">row</span> <span class="p">(</span><span class="nb">aset </span><span class="nv">i</span> <span class="nv">:dying</span><span class="p">)))</span>
            <span class="p">(</span><span class="nb">= </span><span class="nv">c</span> <span class="nv">:dying</span><span class="p">)</span>
              <span class="p">(</span><span class="nf">recur</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">i</span><span class="p">)</span> <span class="p">(</span><span class="nb">doto </span><span class="nv">row</span> <span class="p">(</span><span class="nb">aset </span><span class="nv">i</span> <span class="nv">:off</span><span class="p">)))</span>
            <span class="p">(</span><span class="nb">= </span><span class="mi">2</span> <span class="p">(</span><span class="nf">neighbours-count</span> <span class="nv">above</span> <span class="nv">current</span> <span class="nv">below</span> <span class="nv">i</span> <span class="nv">w</span><span class="p">))</span>
              <span class="p">(</span><span class="nf">recur</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">i</span><span class="p">)</span> <span class="p">(</span><span class="nb">doto </span><span class="nv">row</span> <span class="p">(</span><span class="nb">aset </span><span class="nv">i</span> <span class="nv">:on</span><span class="p">)))</span>
            <span class="nv">:else</span>
              <span class="p">(</span><span class="nf">recur</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">i</span><span class="p">)</span> <span class="nv">row</span><span class="p">)))))))</span></pre>
<p>Benchmark:</p>
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">do</span>  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">b</span> <span class="p">(</span><span class="nf">rand-board</span> <span class="mi">80</span> <span class="mi">80</span><span class="p">)]</span> <span class="p">(</span><span class="nb">time </span><span class="p">((</span><span class="nb">apply </span><span class="nv">comp</span> <span class="p">(</span><span class="nb">repeat </span><span class="mi">1000</span> <span class="nv">step</span><span class="p">))</span> <span class="nv">b</span><span class="p">)))</span> <span class="nv">nil</span><span class="p">)</span>
<span class="s">&quot;Elapsed time: 2058.372014 msecs&quot;</span>
<span class="nv">nil</span>
<span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">do</span>  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">b</span> <span class="p">(</span><span class="nf">rand-board</span> <span class="mi">200</span> <span class="mi">200</span><span class="p">)]</span> <span class="p">(</span><span class="nb">time </span><span class="p">((</span><span class="nb">apply </span><span class="nv">comp</span> <span class="p">(</span><span class="nb">repeat </span><span class="mi">100</span> <span class="nv">step</span><span class="p">))</span> <span class="nv">b</span><span class="p">)))</span> <span class="nv">nil</span><span class="p">)</span>
<span class="s">&quot;Elapsed time: 1105.499303 msecs&quot;</span>
<span class="nv">nil</span></pre>
<p>Wow, twice as fast! Again. 2.1ms/step on a 80*80 board, <strong>11.1ms/step on a 200*200 board</strong>.</p>
<p><a href="http://gist.github.com/237700">This version</a> on a 200*200 board is then nearly 10x faster than my first one!</p>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/jxvx26Wv8Vk" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2009/11/18/an-optimization-job-is-never-done/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Life of Brian</title>
		<link>http://clj-me.cgrand.net/2009/11/17/life-of-brian/</link>
		<comments>http://clj-me.cgrand.net/2009/11/17/life-of-brian/#comments</comments>
		<pubDate>Tue, 17 Nov 2009 11:24:43 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[optimization]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=181</guid>
		<description><![CDATA[Some weeks ago, Lau Jensen implemented Brian&#8217;s Brain but gave up making it go faster. He reached for my advice but I was swamped in work.
First cut
Here is my take:
(defn neighbours-count [rows i w]
  (count (for [j [(mod (inc i) w) i (mod (dec i) w)]
         [...]]]></description>
			<content:encoded><![CDATA[<p>Some weeks ago, <a href="http://www.bestinclass.dk/index.php/2009/10/brians-brain-echoes-from-the-web/">Lau Jensen implemented Brian&#8217;s Brain</a> but gave up making it go faster. He reached for my advice but I was swamped in work.</p>
<h2>First cut</h2>
<p>Here is my take:</p>
<pre class="highlight"><span class="p">(</span><span class="k">defn </span><span class="nv">neighbours-count</span> <span class="p">[</span><span class="nv">rows</span> <span class="nv">i</span> <span class="nv">w</span><span class="p">]</span>
  <span class="p">(</span><span class="nb">count </span><span class="p">(</span><span class="k">for </span><span class="p">[</span><span class="nv">j</span> <span class="p">[(</span><span class="nf">mod</span> <span class="p">(</span><span class="nb">inc </span><span class="nv">i</span><span class="p">)</span> <span class="nv">w</span><span class="p">)</span> <span class="nv">i</span> <span class="p">(</span><span class="nf">mod</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">i</span><span class="p">)</span> <span class="nv">w</span><span class="p">)]</span>
               <span class="nv">r</span> <span class="nv">rows</span> <span class="nv">:when</span> <span class="p">(</span><span class="nb">= </span><span class="nv">:on</span> <span class="p">(</span><span class="nf">r</span> <span class="nv">j</span><span class="p">))]</span> <span class="nv">r</span><span class="p">)))</span>

<span class="p">(</span><span class="k">defn </span><span class="nv">step1</span> <span class="p">[</span><span class="nv">rows</span><span class="p">]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">current</span> <span class="p">(</span><span class="nb">second </span><span class="nv">rows</span><span class="p">)</span>
        <span class="nv">w</span> <span class="p">(</span><span class="nb">count </span><span class="nv">current</span><span class="p">)]</span>
    <span class="p">(</span><span class="nb">loop </span><span class="p">[</span><span class="nv">i</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">w</span><span class="p">)</span><span class="o">,</span> <span class="nv">row</span> <span class="p">(</span><span class="nf">transient</span> <span class="nv">current</span><span class="p">)]</span>
      <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">neg? </span><span class="nv">i</span><span class="p">)</span>
        <span class="p">(</span><span class="nf">persistent!</span> <span class="nv">row</span><span class="p">)</span>
        <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">c</span> <span class="p">(</span><span class="nf">current</span> <span class="nv">i</span><span class="p">)]</span>
          <span class="p">(</span><span class="nf">cond</span>
            <span class="p">(</span><span class="nb">= </span><span class="nv">c</span> <span class="nv">:on</span><span class="p">)</span>
              <span class="p">(</span><span class="nf">recur</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">i</span><span class="p">)</span> <span class="p">(</span><span class="nf">assoc!</span> <span class="nv">row</span> <span class="nv">i</span> <span class="nv">:dying</span><span class="p">))</span>
            <span class="p">(</span><span class="nb">= </span><span class="nv">c</span> <span class="nv">:dying</span><span class="p">)</span>
              <span class="p">(</span><span class="nf">recur</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">i</span><span class="p">)</span> <span class="p">(</span><span class="nf">assoc!</span> <span class="nv">row</span> <span class="nv">i</span> <span class="nv">:off</span><span class="p">))</span>
            <span class="p">(</span><span class="nb">= </span><span class="mi">2</span> <span class="p">(</span><span class="nf">neighbours-count</span> <span class="nv">rows</span> <span class="nv">i</span> <span class="nv">w</span><span class="p">))</span>
              <span class="p">(</span><span class="nf">recur</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">i</span><span class="p">)</span> <span class="p">(</span><span class="nf">assoc!</span> <span class="nv">row</span> <span class="nv">i</span> <span class="nv">:on</span><span class="p">))</span>
            <span class="nv">:else</span>
              <span class="p">(</span><span class="nf">recur</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">i</span><span class="p">)</span> <span class="nv">row</span><span class="p">)))))))</span>

<span class="p">(</span><span class="k">defn </span><span class="nv">step</span> <span class="p">[</span><span class="nv">board</span><span class="p">]</span>
  <span class="p">(</span><span class="nf">vec</span> <span class="p">(</span><span class="nb">map </span><span class="nv">step1</span>
         <span class="p">(</span><span class="nf">partition</span> <span class="mi">3</span> <span class="mi">1</span> <span class="p">(</span><span class="nb">concat </span><span class="p">[(</span><span class="nb">peek </span><span class="nv">board</span><span class="p">)]</span> <span class="nv">board</span> <span class="p">[(</span><span class="nb">first </span><span class="nv">board</span><span class="p">)])))))</span></pre>
<p>A board is a vector of vectors (rows) containing either <code class="highlight"><span class="nv">:on</span></code>, <code class="highlight"><span class="nv">:dying</span></code> or <code class="highlight"><span class="nv">:off</span></code>.</p>
<p>If you look closely at <code class="highlight"><span class="nv">step</span></code> you should recognize <code class="highlight"><span class="nv">torus-window</span></code> from Lau&#8217;s <a href="http://www.bestinclass.dk/index.php/2009/10/brians-functional-brain/">Brians functional brain</a>. I must confess I am the one who gave Lau the idea of the seq-heavy implementation &mdash; just to prove it was doable without indices.<br />
This is why I chose to keep a clear, functional, indexless processing at the row level. It is only the cell level that is worth optimizing.</p>
<p><code class="highlight"><span class="nv">step1</span></code> steps a single row. It takes as only argument a seq of 3 rows (above, current and below) and use a transient vector to compute the next state of the current row. I tried to keep <code class="highlight"><span class="nv">neighbours-count</span></code> simple while reducing the number of intermediate seqs (less alloc, less GC, faster code) by using a seq comprehension (<code class="highlight"><span class="nv">for</span></code>) rather than several higher-order functions.</p>
<h3>How does it run?</h3>
<p>First a little utility to create random boards (with one third of <code class="highlight"><span class="nv">:on</span></code> cells):</p>
<pre class="highlight"><span class="p">(</span><span class="k">defn </span><span class="nv">rand-board</span> <span class="p">[</span><span class="nv">w</span> <span class="nv">h</span><span class="p">]</span>
  <span class="p">(</span><span class="nf">vec</span> <span class="p">(</span><span class="nb">map </span><span class="nv">vec</span> <span class="p">(</span><span class="nf">partition</span> <span class="nv">w</span> <span class="p">(</span><span class="nb">take </span><span class="p">(</span><span class="nb">* </span><span class="nv">w</span> <span class="nv">h</span><span class="p">)</span> <span class="p">(</span><span class="nf">repeatedly</span> <span class="o">#</span><span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">zero? </span><span class="p">(</span><span class="nb">rand-int </span><span class="mi">3</span><span class="p">))</span> <span class="nv">:on</span> <span class="nv">:off</span><span class="p">)))))))</span></pre>
<p>Then the actual benchmark:</p>
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">do</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">b</span> <span class="p">(</span><span class="nf">rand-board</span> <span class="mi">80</span> <span class="mi">80</span><span class="p">)]</span> <span class="p">(</span><span class="nb">time </span><span class="p">((</span><span class="nb">apply </span><span class="nv">comp</span> <span class="p">(</span><span class="nb">repeat </span><span class="mi">1000</span> <span class="nv">step</span><span class="p">))</span> <span class="nv">b</span><span class="p">)))</span> <span class="nv">nil</span><span class="p">)</span>
<span class="s">&quot;Elapsed time: 16734.609776 msecs&quot;</span>
<span class="nv">nil</span>
<span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">do</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">b</span> <span class="p">(</span><span class="nf">rand-board</span> <span class="mi">200</span> <span class="mi">200</span><span class="p">)]</span> <span class="p">(</span><span class="nb">time </span><span class="p">((</span><span class="nb">apply </span><span class="nv">comp</span> <span class="p">(</span><span class="nb">repeat </span><span class="mi">100</span> <span class="nv">step</span><span class="p">))</span> <span class="nv">b</span><span class="p">)))</span> <span class="nv">nil</span><span class="p">)</span>
<span class="s">&quot;Elapsed time: 10200.273708 msecs&quot;</span>
<span class="nv">nil</span></pre>
<p> So I get <strong>16.7ms/step on a 80*80 board</strong> (where Lau was stuck at 200ms on his box) and 102ms/step on a 200*200 board.</p>
<h2>Optimizations</h2>
<h3>Unrolling <code class="highlight"><span class="nv">neighbours-count</span></code></h3>
<p><code class="highlight"><span class="nv">neighbours-count</span></code> is called once for each <code class="highlight"><span class="nv">:off</span></code> cell and is rather complex so making it go faster should yield sensible gains this is why I unrolled it:</p>
<pre class="highlight"><span class="p">(</span><span class="k">defn </span><span class="nv">neighbours-count</span> <span class="p">[[</span><span class="nv">above</span> <span class="nv">current</span> <span class="nv">below</span><span class="p">]</span> <span class="nv">i</span> <span class="nv">w</span><span class="p">]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">j</span> <span class="p">(</span><span class="nf">mod</span> <span class="p">(</span><span class="nb">inc </span><span class="nv">i</span><span class="p">)</span> <span class="nv">w</span><span class="p">)</span>
        <span class="nv">k</span> <span class="p">(</span><span class="nf">mod</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">i</span><span class="p">)</span> <span class="nv">w</span><span class="p">)</span>
        <span class="nv">s</span> <span class="o">#</span><span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">= </span><span class="p">(</span><span class="nf">%1</span> <span class="nv">%2</span><span class="p">)</span> <span class="nv">:on</span><span class="p">)</span> <span class="mi">1</span> <span class="mi">0</span><span class="p">)]</span>
    <span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nf">s</span> <span class="nv">above</span> <span class="nv">j</span><span class="p">)</span> <span class="p">(</span><span class="nf">s</span> <span class="nv">above</span> <span class="nv">i</span><span class="p">))</span>
         <span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nf">s</span> <span class="nv">above</span> <span class="nv">k</span><span class="p">)</span> <span class="p">(</span><span class="nf">s</span> <span class="nv">current</span> <span class="nv">j</span><span class="p">)))</span>
      <span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nf">s</span> <span class="nv">current</span> <span class="nv">k</span><span class="p">)</span> <span class="p">(</span><span class="nf">s</span> <span class="nv">below</span> <span class="nv">j</span><span class="p">))</span>
        <span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nf">s</span> <span class="nv">below</span> <span class="nv">i</span><span class="p">)</span> <span class="p">(</span><span class="nf">s</span> <span class="nv">below</span> <span class="nv">k</span><span class="p">))))))</span></pre>
<p>I paired the sum terms because currently only math ops with two args are inlined.</p>
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">do</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">b</span> <span class="p">(</span><span class="nf">rand-board</span> <span class="mi">80</span> <span class="mi">80</span><span class="p">)]</span> <span class="p">(</span><span class="nb">time </span><span class="p">((</span><span class="nb">apply </span><span class="nv">comp</span> <span class="p">(</span><span class="nb">repeat </span><span class="mi">1000</span> <span class="nv">step</span><span class="p">))</span> <span class="nv">b</span><span class="p">)))</span> <span class="nv">nil</span><span class="p">)</span>
<span class="s">&quot;Elapsed time: 7880.492493 msecs&quot;</span>
<span class="nv">nil</span>
<span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">do</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">b</span> <span class="p">(</span><span class="nf">rand-board</span> <span class="mi">200</span> <span class="mi">200</span><span class="p">)]</span> <span class="p">(</span><span class="nb">time </span><span class="p">((</span><span class="nb">apply </span><span class="nv">comp</span> <span class="p">(</span><span class="nb">repeat </span><span class="mi">100</span> <span class="nv">step</span><span class="p">))</span> <span class="nv">b</span><span class="p">)))</span> <span class="nv">nil</span><span class="p">)</span>
<span class="s">&quot;Elapsed time: 4679.679401 msecs&quot;</span>
<span class="nv">nil</span></pre>
<p><strong>More than twice as fast!</strong> 7.9ms/step for a 80*80 board and 46.8ms/step for a 200*200 one.</p>
<h3>Using java arrays</h3>
<p>Since there is little sharing between two iterations, vectors are not that useful so why not to try using arrays to represent rows? The board is then a vector of arrays:</p>
<pre class="highlight"><span class="p">(</span><span class="k">defn </span><span class="nv">neighbours-count</span> <span class="p">[[</span><span class="nv">above</span> <span class="nv">current</span> <span class="nv">below</span><span class="p">]</span> <span class="nv">i</span> <span class="nv">w</span><span class="p">]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">j</span> <span class="p">(</span><span class="nf">mod</span> <span class="p">(</span><span class="nb">inc </span><span class="nv">i</span><span class="p">)</span> <span class="nv">w</span><span class="p">)</span>
        <span class="nv">k</span> <span class="p">(</span><span class="nf">mod</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">i</span><span class="p">)</span> <span class="nv">w</span><span class="p">)</span>
        <span class="nv">s</span> <span class="o">#</span><span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">= </span><span class="p">(</span><span class="nb">aget </span><span class="o">#</span><span class="nv">^objects</span> <span class="nv">%1</span> <span class="p">(</span><span class="nb">int </span><span class="nv">%2</span><span class="p">))</span> <span class="nv">:on</span><span class="p">)</span> <span class="mi">1</span> <span class="mi">0</span><span class="p">)]</span>
    <span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nf">s</span> <span class="nv">above</span> <span class="nv">j</span><span class="p">)</span> <span class="p">(</span><span class="nf">s</span> <span class="nv">above</span> <span class="nv">i</span><span class="p">))</span>
         <span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nf">s</span> <span class="nv">above</span> <span class="nv">k</span><span class="p">)</span> <span class="p">(</span><span class="nf">s</span> <span class="nv">current</span> <span class="nv">j</span><span class="p">)))</span>
      <span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nf">s</span> <span class="nv">current</span> <span class="nv">k</span><span class="p">)</span> <span class="p">(</span><span class="nf">s</span> <span class="nv">below</span> <span class="nv">j</span><span class="p">))</span>
        <span class="p">(</span><span class="nb">+ </span><span class="p">(</span><span class="nf">s</span> <span class="nv">below</span> <span class="nv">i</span><span class="p">)</span> <span class="p">(</span><span class="nf">s</span> <span class="nv">below</span> <span class="nv">k</span><span class="p">))))))</span>

<span class="p">(</span><span class="k">defn </span><span class="nv">step1</span> <span class="p">[</span><span class="nv">rows</span><span class="p">]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="o">#</span><span class="nv">^objects</span> <span class="nv">current</span> <span class="p">(</span><span class="nb">second </span><span class="nv">rows</span><span class="p">)</span>
        <span class="nv">w</span> <span class="p">(</span><span class="nb">count </span><span class="nv">current</span><span class="p">)]</span>
    <span class="p">(</span><span class="nb">loop </span><span class="p">[</span><span class="nv">i</span> <span class="p">(</span><span class="nb">int </span><span class="p">(</span><span class="nb">dec </span><span class="nv">w</span><span class="p">))</span><span class="o">,</span> <span class="o">#</span><span class="nv">^objects</span> <span class="nv">row</span> <span class="p">(</span><span class="nf">aclone</span> <span class="nv">current</span><span class="p">)]</span>
      <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">neg? </span><span class="nv">i</span><span class="p">)</span>
        <span class="nv">row</span>
        <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">c</span> <span class="p">(</span><span class="nb">aget </span><span class="nv">current</span> <span class="nv">i</span><span class="p">)]</span>
          <span class="p">(</span><span class="nf">cond</span>
            <span class="p">(</span><span class="nb">= </span><span class="nv">c</span> <span class="nv">:on</span><span class="p">)</span>
              <span class="p">(</span><span class="nf">recur</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">i</span><span class="p">)</span> <span class="p">(</span><span class="nb">doto </span><span class="nv">row</span> <span class="p">(</span><span class="nb">aset </span><span class="nv">i</span> <span class="nv">:dying</span><span class="p">)))</span>
            <span class="p">(</span><span class="nb">= </span><span class="nv">c</span> <span class="nv">:dying</span><span class="p">)</span>
              <span class="p">(</span><span class="nf">recur</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">i</span><span class="p">)</span> <span class="p">(</span><span class="nb">doto </span><span class="nv">row</span> <span class="p">(</span><span class="nb">aset </span><span class="nv">i</span> <span class="nv">:off</span><span class="p">)))</span>
            <span class="p">(</span><span class="nb">= </span><span class="mi">2</span> <span class="p">(</span><span class="nf">neighbours-count</span> <span class="nv">rows</span> <span class="nv">i</span> <span class="nv">w</span><span class="p">))</span>
              <span class="p">(</span><span class="nf">recur</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">i</span><span class="p">)</span> <span class="p">(</span><span class="nb">doto </span><span class="nv">row</span> <span class="p">(</span><span class="nb">aset </span><span class="nv">i</span> <span class="nv">:on</span><span class="p">)))</span>
            <span class="nv">:else</span>
              <span class="p">(</span><span class="nf">recur</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">i</span><span class="p">)</span> <span class="nv">row</span><span class="p">)))))))</span>

<span class="p">(</span><span class="k">defn </span><span class="nv">step</span> <span class="p">[</span><span class="nv">board</span><span class="p">]</span>
  <span class="p">(</span><span class="nf">vec</span> <span class="p">(</span><span class="nb">map </span><span class="nv">step1</span>
         <span class="p">(</span><span class="nf">partition</span> <span class="mi">3</span> <span class="mi">1</span> <span class="p">(</span><span class="nb">concat </span><span class="p">[(</span><span class="nb">peek </span><span class="nv">board</span><span class="p">)]</span> <span class="nv">board</span> <span class="p">[(</span><span class="nb">first </span><span class="nv">board</span><span class="p">)])))))</span>

<span class="p">(</span><span class="k">defn </span><span class="nv">rand-board</span> <span class="p">[</span><span class="nv">w</span> <span class="nv">h</span><span class="p">]</span>
  <span class="p">(</span><span class="nf">vec</span> <span class="p">(</span><span class="nb">map </span><span class="o">#</span><span class="p">(</span><span class="nv">into-array</span> <span class="nv">Object</span> <span class="nv">%</span><span class="p">)</span> <span class="p">(</span><span class="nf">partition</span> <span class="nv">w</span> <span class="p">(</span><span class="nb">take </span><span class="p">(</span><span class="nb">* </span><span class="nv">w</span> <span class="nv">h</span><span class="p">)</span> <span class="p">(</span><span class="nf">repeatedly</span> <span class="o">#</span><span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">zero? </span><span class="p">(</span><span class="nb">rand-int </span><span class="mi">3</span><span class="p">))</span> <span class="nv">:on</span> <span class="nv">:off</span><span class="p">)))))))</span></pre>
<p>Benchmark numbers:</p>
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">do</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">b</span> <span class="p">(</span><span class="nf">rand-board</span> <span class="mi">80</span> <span class="mi">80</span><span class="p">)]</span> <span class="p">(</span><span class="nb">time </span><span class="p">((</span><span class="nb">apply </span><span class="nv">comp</span> <span class="p">(</span><span class="nb">repeat </span><span class="mi">1000</span> <span class="nv">step</span><span class="p">))</span> <span class="nv">b</span><span class="p">)))</span> <span class="nv">nil</span><span class="p">)</span>
<span class="s">&quot;Elapsed time: 5155.422268 msecs&quot;</span>
<span class="nv">nil</span>
<span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">do</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">b</span> <span class="p">(</span><span class="nf">rand-board</span> <span class="mi">200</span> <span class="mi">200</span><span class="p">)]</span> <span class="p">(</span><span class="nb">time </span><span class="p">((</span><span class="nb">apply </span><span class="nv">comp</span> <span class="p">(</span><span class="nb">repeat </span><span class="mi">100</span> <span class="nv">step</span><span class="p">))</span> <span class="nv">b</span><span class="p">)))</span> <span class="nv">nil</span><span class="p">)</span>
<span class="s">&quot;Elapsed time: 2964.524262 msecs&quot;</span>
<span class="nv">nil</span></pre>
<p>Arrays cut one third of the runtime: we are down to 5.2ms/step for a 80*80 board and 29.6ms/step for a 200*200 one. This means <strong>the overall speedup is greater than 3x</strong>!</p>
<h2>Adding a swing frontend</h2>
<p>I decoupled the rendering from the computation: 25 fps no matter how many steps are really computed. If the computation is fast not all steps are rendered (eg for a 80*80 board at 200 sps only one step out of eight is rendered to screen).</p>
<pre class="highlight"><span class="p">(</span><span class="nb">import </span><span class="o">&#39;</span><span class="p">(</span><span class="nv">javax</span><span class="o">.</span><span class="nv">swing</span> <span class="nv">JFrame</span> <span class="nv">JPanel</span><span class="p">)</span>
        <span class="o">&#39;</span><span class="p">(</span><span class="nv">java</span><span class="o">.</span><span class="nv">awt</span> <span class="nv">Color</span> <span class="nv">Graphics2D</span><span class="p">))</span>

<span class="p">(</span><span class="k">defn </span><span class="nv">dims</span> <span class="p">[[</span><span class="nv">row</span> <span class="nv">:as</span> <span class="nv">board</span><span class="p">]]</span> <span class="p">[(</span><span class="nb">count </span><span class="nv">row</span><span class="p">)</span> <span class="p">(</span><span class="nb">count </span><span class="nv">board</span><span class="p">)])</span>

<span class="p">(</span><span class="k">defn </span><span class="nv">render-board</span> <span class="p">[</span><span class="nv">board</span> <span class="o">#</span><span class="nv">^Graphics2D</span> <span class="nv">g</span> <span class="nv">cell-size</span><span class="p">]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[[</span><span class="nv">w</span> <span class="nv">h</span><span class="p">]</span> <span class="p">(</span><span class="nf">dims</span> <span class="nv">board</span><span class="p">)]</span>
    <span class="p">(</span><span class="nb">doto </span><span class="nv">g</span>
      <span class="p">(</span><span class="o">.</span><span class="nv">setColor</span> <span class="nv">Color/BLACK</span><span class="p">)</span>
      <span class="p">(</span><span class="o">.</span><span class="nv">scale</span> <span class="nv">cell-size</span> <span class="nv">cell-size</span><span class="p">)</span>
      <span class="p">(</span><span class="o">.</span><span class="nv">fillRect</span> <span class="mi">0</span> <span class="mi">0</span> <span class="nv">w</span> <span class="nv">h</span><span class="p">))</span>
    <span class="p">(</span><span class="nb">doseq </span><span class="p">[</span><span class="nv">i</span> <span class="p">(</span><span class="nb">range </span><span class="nv">h</span><span class="p">)</span> <span class="nv">j</span> <span class="p">(</span><span class="nb">range </span><span class="nv">w</span><span class="p">)]</span>
      <span class="p">(</span><span class="nb">when-let </span><span class="p">[</span><span class="nv">color</span> <span class="p">({</span><span class="nv">:on</span> <span class="nv">Color/WHITE</span> <span class="nv">:dying</span> <span class="nv">Color/GRAY</span><span class="p">}</span> <span class="p">((</span><span class="nf">board</span> <span class="nv">i</span><span class="p">)</span> <span class="nv">j</span><span class="p">))]</span>
        <span class="p">(</span><span class="nb">doto </span><span class="nv">g</span>
          <span class="p">(</span><span class="o">.</span><span class="nv">setColor</span> <span class="nv">color</span><span class="p">)</span>
          <span class="p">(</span><span class="o">.</span><span class="nv">fillRect</span> <span class="nv">j</span> <span class="nv">i</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">))))))</span>

<span class="p">(</span><span class="k">defn </span><span class="nv">start-brian</span> <span class="p">[</span><span class="nv">board</span> <span class="nv">cell-size</span><span class="p">]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[[</span><span class="nv">w</span> <span class="nv">h</span><span class="p">]</span> <span class="p">(</span><span class="nf">dims</span> <span class="nv">board</span><span class="p">)</span>
        <span class="nv">switch</span> <span class="p">(</span><span class="nf">atom</span> <span class="nv">true</span><span class="p">)</span>
        <span class="nv">board</span> <span class="p">(</span><span class="nf">atom</span> <span class="nv">board</span><span class="p">)</span>
        <span class="nv">panel</span> <span class="p">(</span><span class="nb">doto </span><span class="p">(</span><span class="nb">proxy </span><span class="p">[</span><span class="nv">JPanel</span><span class="p">]</span> <span class="p">[]</span>
                      <span class="p">(</span><span class="nf">paint</span> <span class="p">[</span><span class="nv">g</span><span class="p">]</span> <span class="p">(</span><span class="nf">render-board</span> <span class="nv">@board</span> <span class="nv">g</span> <span class="nv">cell-size</span><span class="p">)))</span>
                <span class="p">(</span><span class="o">.</span><span class="nv">setDoubleBuffered</span> <span class="nv">true</span><span class="p">))]</span>
    <span class="p">(</span><span class="nb">doto </span><span class="p">(</span><span class="nf">JFrame</span><span class="o">.</span><span class="p">)</span>
      <span class="p">(</span><span class="o">.</span><span class="nv">addWindowListener</span> <span class="p">(</span><span class="nb">proxy </span><span class="p">[</span><span class="nv">java</span><span class="o">.</span><span class="nv">awt</span><span class="o">.</span><span class="nv">event</span><span class="o">.</span><span class="nv">WindowAdapter</span><span class="p">]</span> <span class="p">[]</span>
                            <span class="p">(</span><span class="nf">windowClosing</span> <span class="p">[</span><span class="nv">_</span><span class="p">]</span> <span class="p">(</span><span class="nf">reset!</span> <span class="nv">switch</span> <span class="nv">false</span><span class="p">))))</span>
      <span class="p">(</span><span class="o">.</span><span class="nv">setSize</span> <span class="p">(</span><span class="nb">* </span><span class="nv">w</span> <span class="nv">cell-size</span><span class="p">)</span> <span class="p">(</span><span class="nb">* </span><span class="nv">h</span> <span class="nv">cell-size</span><span class="p">))</span>
      <span class="p">(</span><span class="o">.</span><span class="nv">add</span> <span class="nv">panel</span><span class="p">)</span>
      <span class="o">.</span><span class="nv">show</span><span class="p">)</span>
    <span class="p">(</span><span class="nf">future</span> <span class="p">(</span><span class="nf">while</span> <span class="nv">@switch</span> <span class="p">(</span><span class="nf">swap!</span> <span class="nv">board</span> <span class="nv">step</span><span class="p">)))</span>
    <span class="p">(</span><span class="nf">future</span> <span class="p">(</span><span class="nf">while</span> <span class="nv">@switch</span> <span class="p">(</span><span class="o">.</span><span class="nv">repaint</span> <span class="nv">panel</span><span class="p">)</span> <span class="p">(</span><span class="nf">Thread/sleep</span> <span class="mi">40</span><span class="p">)))))</span>

<span class="p">(</span><span class="nf">start-brian</span> <span class="p">(</span><span class="nf">rand-board</span> <span class="mi">200</span> <span class="mi">200</span><span class="p">)</span> <span class="mi">5</span><span class="p">)</span></pre>
<p>The rendering code is slightly different when using arrays:</p>
<pre class="highlight"><span class="p">(</span><span class="k">defn </span><span class="nv">render-board</span> <span class="p">[</span><span class="nv">board</span> <span class="o">#</span><span class="nv">^Graphics2D</span> <span class="nv">g</span> <span class="nv">cell-size</span><span class="p">]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[[</span><span class="nv">w</span> <span class="nv">h</span><span class="p">]</span> <span class="p">(</span><span class="nf">dims</span> <span class="nv">board</span><span class="p">)]</span>
    <span class="p">(</span><span class="nb">doto </span><span class="nv">g</span>
      <span class="p">(</span><span class="o">.</span><span class="nv">setColor</span> <span class="nv">Color/BLACK</span><span class="p">)</span>
      <span class="p">(</span><span class="o">.</span><span class="nv">scale</span> <span class="nv">cell-size</span> <span class="nv">cell-size</span><span class="p">)</span>
      <span class="p">(</span><span class="o">.</span><span class="nv">fillRect</span> <span class="mi">0</span> <span class="mi">0</span> <span class="nv">w</span> <span class="nv">h</span><span class="p">))</span>
    <span class="p">(</span><span class="nb">doseq </span><span class="p">[</span><span class="nv">i</span> <span class="p">(</span><span class="nb">range </span><span class="nv">h</span><span class="p">)</span> <span class="nv">j</span> <span class="p">(</span><span class="nb">range </span><span class="nv">w</span><span class="p">)]</span>
      <span class="p">(</span><span class="nb">when-let </span><span class="p">[</span><span class="nv">color</span> <span class="p">({</span><span class="nv">:on</span> <span class="nv">Color/WHITE</span> <span class="nv">:dying</span> <span class="nv">Color/GRAY</span><span class="p">}</span> <span class="p">(</span><span class="nb">aget </span><span class="o">#</span><span class="nv">^objects</span> <span class="p">(</span><span class="nf">board</span> <span class="nv">i</span><span class="p">)</span> <span class="p">(</span><span class="nb">int </span><span class="nv">j</span><span class="p">)))]</span>
        <span class="p">(</span><span class="nb">doto </span><span class="nv">g</span>
          <span class="p">(</span><span class="o">.</span><span class="nv">setColor</span> <span class="nv">color</span><span class="p">)</span>
          <span class="p">(</span><span class="o">.</span><span class="nv">fillRect</span> <span class="nv">j</span> <span class="nv">i</span> <span class="mi">1</span> <span class="mi">1</span><span class="p">))))))</span></pre>
<h2>Putting all cores to work</h2>
<p>The first attempt to parallelizing is to replace <code class="highlight"><span class="nv">map</span></code> by <code class="highlight"><span class="nv">pmap</span></code> in <code class="highlight"><span class="nv">step</span></code>.</p>
<pre class="highlight"><span class="p">(</span><span class="k">defn </span><span class="nv">step</span> <span class="p">[</span><span class="nv">board</span><span class="p">]</span>
  <span class="p">(</span><span class="nf">vec</span> <span class="p">(</span><span class="nf">pmap</span> <span class="nv">step1</span>
         <span class="p">(</span><span class="nf">partition</span> <span class="mi">3</span> <span class="mi">1</span> <span class="p">(</span><span class="nb">concat </span><span class="p">[(</span><span class="nb">peek </span><span class="nv">board</span><span class="p">)]</span> <span class="nv">board</span> <span class="p">[(</span><span class="nb">first </span><span class="nv">board</span><span class="p">)])))))</span></pre>
<p>This does not yield such a gain:</p>
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">do</span>  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">b</span> <span class="p">(</span><span class="nf">rand-board</span> <span class="mi">80</span> <span class="mi">80</span><span class="p">)]</span> <span class="p">(</span><span class="nb">time </span><span class="p">((</span><span class="nb">apply </span><span class="nv">comp</span> <span class="p">(</span><span class="nb">repeat </span><span class="mi">1000</span> <span class="nv">step</span><span class="p">))</span> <span class="nv">b</span><span class="p">)))</span> <span class="nv">nil</span><span class="p">)</span>
<span class="s">&quot;Elapsed time: 5624.407083 msecs&quot;</span>
<span class="nv">nil</span>
<span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">do</span>  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">b</span> <span class="p">(</span><span class="nf">rand-board</span> <span class="mi">200</span> <span class="mi">200</span><span class="p">)]</span> <span class="p">(</span><span class="nb">time </span><span class="p">((</span><span class="nb">apply </span><span class="nv">comp</span> <span class="p">(</span><span class="nb">repeat </span><span class="mi">100</span> <span class="nv">step</span><span class="p">))</span> <span class="nv">b</span><span class="p">)))</span> <span class="nv">nil</span><span class="p">)</span>
<span class="s">&quot;Elapsed time: 2778.74241 msecs&quot;</span>
<span class="nv">nil</span></pre>
<p>Performances are slighlty worse on the 80*80 board and slightly better on the 200*200. The reason is that the processing of a single row is not computationally intense enough compared to the parallelization overhead. So I have to send each core more stuff at once.</p>
<p>Rich is working on some cool features in the <a href="http://github.com/richhickey/clojure/commits/par">par branch</a> that will make such parallelization a breeze meanwhile I am going to show how to <em>manually</em> parallelize <code class="highlight"><span class="nv">step</span></code>.</p>
<p>The idea is simply to split the vector in N chunks where N is the number of cores.</p>
<pre class="highlight"><span class="p">(</span><span class="k">defn </span><span class="nv">step</span> <span class="p">[</span><span class="nv">board</span><span class="p">]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">n</span> <span class="p">(</span><span class="o">.</span><span class="nv">availableProcessors</span> <span class="p">(</span><span class="nf">Runtime/getRuntime</span><span class="p">))</span>
        <span class="nv">l</span> <span class="p">(</span><span class="nb">count </span><span class="nv">board</span><span class="p">)</span>
        <span class="nv">bounds</span> <span class="p">(</span><span class="nb">map </span><span class="nv">int</span> <span class="p">(</span><span class="nb">range </span><span class="mi">0</span> <span class="p">(</span><span class="nb">inc </span><span class="nv">l</span><span class="p">)</span> <span class="p">(</span><span class="nb">/ </span><span class="nv">l</span> <span class="nv">n</span><span class="p">)))]</span>
    <span class="p">(</span><span class="nb">apply </span><span class="nv">into</span>
      <span class="p">(</span><span class="nf">pmap</span> <span class="o">#</span><span class="p">(</span><span class="nv">vec</span> <span class="p">(</span><span class="nb">map </span><span class="nv">step1</span> <span class="p">(</span><span class="nf">partition</span> <span class="mi">3</span> <span class="mi">1</span>
               <span class="p">(</span><span class="nb">concat </span><span class="p">[(</span><span class="nf">board</span> <span class="p">(</span><span class="nf">mod</span> <span class="p">(</span><span class="nb">dec </span><span class="nv">%1</span><span class="p">)</span> <span class="nv">l</span><span class="p">))]</span>
                 <span class="p">(</span><span class="nb">subvec </span><span class="nv">board</span> <span class="nv">%1</span> <span class="nv">%2</span><span class="p">)</span>
                 <span class="p">[(</span><span class="nf">board</span> <span class="p">(</span><span class="nf">mod</span> <span class="nv">%2</span> <span class="nv">l</span><span class="p">))]))))</span>
        <span class="nv">bounds</span> <span class="p">(</span><span class="nb">rest </span><span class="nv">bounds</span><span class="p">)))))</span></pre>
<p>How does it fare?</p>
<pre class="highlight"><span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">do</span>  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">b</span> <span class="p">(</span><span class="nf">rand-board</span> <span class="mi">80</span> <span class="mi">80</span><span class="p">)]</span> <span class="p">(</span><span class="nb">time </span><span class="p">((</span><span class="nb">apply </span><span class="nv">comp</span> <span class="p">(</span><span class="nb">repeat </span><span class="mi">1000</span> <span class="nv">step</span><span class="p">))</span> <span class="nv">b</span><span class="p">)))</span> <span class="nv">nil</span><span class="p">)</span>
<span class="s">&quot;Elapsed time: 3672.935876 msecs&quot;</span>
<span class="nv">nil</span>
<span class="nv">user=&gt;</span> <span class="p">(</span><span class="nf">do</span>  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">b</span> <span class="p">(</span><span class="nf">rand-board</span> <span class="mi">200</span> <span class="mi">200</span><span class="p">)]</span> <span class="p">(</span><span class="nb">time </span><span class="p">((</span><span class="nb">apply </span><span class="nv">comp</span> <span class="p">(</span><span class="nb">repeat </span><span class="mi">100</span> <span class="nv">step</span><span class="p">))</span> <span class="nv">b</span><span class="p">)))</span> <span class="nv">nil</span><span class="p">)</span>
<span class="s">&quot;Elapsed time: 2154.728325 msecs&quot;</span>
<span class="nv">nil</span></pre>
<p>3.7ms/step on a 80*80 board, 21.5ms/step on the 200*200 board. It is indeed better than plain pmap and cuts off 30% of the run time. Now this is nearly <strong>5 times faster than my initial attempt!</strong></p>
<p>You can view the whole source code (including variants) <a href="http://gist.github.com/236782">here</a> and follow me on Twitter <a href="http://twitter.com/cgrand">there</a>.</p>
<p>See <a href="http://clj-me.cgrand.net/2009/11/18/an-optimization-job-is-never-done/">this subsequent post</a> for more optimizations (another 2x improvement).</p>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/OiEx1-MgGA8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2009/11/17/life-of-brian/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Enlive Google group</title>
		<link>http://clj-me.cgrand.net/2009/10/15/enlive-google-group/</link>
		<comments>http://clj-me.cgrand.net/2009/10/15/enlive-google-group/#comments</comments>
		<pubDate>Thu, 15 Oct 2009 19:36:14 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=173</guid>
		<description><![CDATA[I created a google group dedicated to Enlive — my HTML/XML CSS-based transformation and extraction library.
]]></description>
			<content:encoded><![CDATA[<p>I created a <a href="http://groups.google.com/group/enlive-clj">google group</a> dedicated to <a href="http://github.com/cgrand/enlive/tree">Enlive</a> — my HTML/XML CSS-based transformation and extraction library.</p>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/lgOrlblcd4A" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2009/10/15/enlive-google-group/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Taming multidim Arrays</title>
		<link>http://clj-me.cgrand.net/2009/10/15/multidim-arrays/</link>
		<comments>http://clj-me.cgrand.net/2009/10/15/multidim-arrays/#comments</comments>
		<pubDate>Thu, 15 Oct 2009 18:04:22 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[interop]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=153</guid>
		<description><![CDATA[Utilities
(defn array? [x] (-&#62; x class .isArray))
(defn see [x] (if (array? x) (map see x) x))
Creation
Blank and rectangular:
(see (make-array Double/TYPE 3 2))
; ((0.0 0.0) (0.0 0.0) (0.0 0.0))
From a nested collection:
(see (into-array (map (partial into-array Double/TYPE) [[1 2 3 4] [5 6]])))
; ((1.0 2.0 3.0 4.0) (5.0 6.0))
Reading
A multidim array:
(def dd (make-array Double/TYPE 1000 1000))
Naive [...]]]></description>
			<content:encoded><![CDATA[<h4>Utilities</h4>
<pre class="highlight"><span class="p">(</span><span class="k">defn </span><span class="nv">array?</span> <span class="p">[</span><span class="nv">x</span><span class="p">]</span> <span class="p">(</span><span class="nb">-&gt; </span><span class="nv">x</span> <span class="nv">class</span> <span class="o">.</span><span class="nv">isArray</span><span class="p">))</span>
<span class="p">(</span><span class="k">defn </span><span class="nv">see</span> <span class="p">[</span><span class="nv">x</span><span class="p">]</span> <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nf">array?</span> <span class="nv">x</span><span class="p">)</span> <span class="p">(</span><span class="nb">map </span><span class="nv">see</span> <span class="nv">x</span><span class="p">)</span> <span class="nv">x</span><span class="p">))</span></pre>
<h4>Creation</h4>
<p>Blank and rectangular:</p>
<pre class="highlight"><span class="p">(</span><span class="nf">see</span> <span class="p">(</span><span class="nb">make-array </span><span class="nv">Double/TYPE</span> <span class="mi">3</span> <span class="mi">2</span><span class="p">))</span>
<span class="c1">; ((0.0 0.0) (0.0 0.0) (0.0 0.0))</span></pre>
<p>From a nested collection:</p>
<pre class="highlight"><span class="p">(</span><span class="nf">see</span> <span class="p">(</span><span class="nb">into-array </span><span class="p">(</span><span class="nb">map </span><span class="p">(</span><span class="nb">partial </span><span class="nv">into-array</span> <span class="nv">Double/TYPE</span><span class="p">)</span> <span class="p">[[</span><span class="mi">1</span> <span class="mi">2</span> <span class="mi">3</span> <span class="mi">4</span><span class="p">]</span> <span class="p">[</span><span class="mi">5</span> <span class="mi">6</span><span class="p">]])))</span>
<span class="c1">; ((1.0 2.0 3.0 4.0) (5.0 6.0))</span></pre>
<h4>Reading</h4>
<p>A multidim array:</p>
<pre class="highlight"><span class="p">(</span><span class="k">def </span><span class="nv">dd</span> <span class="p">(</span><span class="nb">make-array </span><span class="nv">Double/TYPE</span> <span class="mi">1000</span> <span class="mi">1000</span><span class="p">))</span></pre>
<p>Naive method:</p>
<pre class="highlight"><span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">i</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">j</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nb">aget </span><span class="nv">dd</span> <span class="nv">i</span> <span class="nv">j</span><span class="p">))))</span>
<span class="c1">; &quot;Elapsed time: 455.514388 msecs&quot;</span></pre>
<p>Step-by-step (allow inlining):</p>
<pre class="highlight"><span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">i</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">j</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nb">-&gt; </span><span class="nv">dd</span> <span class="p">(</span><span class="nb">aget </span><span class="nv">i</span><span class="p">)</span> <span class="p">(</span><span class="nb">aget </span><span class="nv">j</span><span class="p">)))))</span>
<span class="c1">; &quot;Elapsed time: 257.625829 msecs&quot;</span></pre>
<p>(Not so) Hinted step-by-step (<code class="highlight"><span class="o">#</span><span class="nv">^doubles</span></code> is ignored because of inline-expansion):</p>
<pre class="highlight"><span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">i</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">j</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nb">-&gt; </span><span class="o">#</span><span class="nv">^objects</span> <span class="nv">dd</span> <span class="p">(</span><span class="o">#</span><span class="nv">^doubles</span> <span class="nv">aget</span> <span class="nv">i</span><span class="p">)</span> <span class="p">(</span><span class="nb">aget </span><span class="nv">j</span><span class="p">)))))</span>
<span class="c1">; &quot;Elapsed time: 157.095175 msecs&quot;</span></pre>
<p>Fully hinted step-by-step:</p>
<pre class="highlight"><span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">i</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">j</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="o">#</span><span class="nv">^doubles</span> <span class="nv">a</span> <span class="p">(</span><span class="nb">aget </span><span class="o">#</span><span class="nv">^objects</span> <span class="nv">dd</span> <span class="nv">i</span><span class="p">)]</span> <span class="p">(</span><span class="nb">aget </span><span class="nv">a</span> <span class="nv">j</span><span class="p">)))))</span>
<span class="c1">; &quot;Elapsed time: 17.412548 msecs&quot;</span></pre>
<p>Let&#8217;s embody this knowledge in a nice macro:</p>
<pre class="highlight"><span class="p">(</span><span class="k">defmacro </span><span class="nv">deep-aget</span>
  <span class="p">([</span><span class="nv">hint</span> <span class="nv">array</span> <span class="nv">idx</span><span class="p">]</span>
    <span class="o">`</span><span class="p">(</span><span class="nb">aget </span><span class="nv">~</span><span class="p">(</span><span class="nf">vary-meta</span> <span class="nv">array</span> <span class="nv">assoc</span> <span class="nv">:tag</span> <span class="nv">hint</span><span class="p">)</span> <span class="nv">~idx</span><span class="p">))</span>
  <span class="p">([</span><span class="nv">hint</span> <span class="nv">array</span> <span class="nv">idx</span> <span class="nv">&amp;</span> <span class="nv">idxs</span><span class="p">]</span>
    <span class="o">`</span><span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">a</span><span class="o">#</span> <span class="p">(</span><span class="nb">aget </span><span class="nv">~</span><span class="p">(</span><span class="nf">vary-meta</span> <span class="nv">array</span> <span class="nv">assoc</span> <span class="nv">:tag</span> <span class="ss">&#39;objects</span><span class="p">)</span> <span class="nv">~idx</span><span class="p">)]</span>
       <span class="p">(</span><span class="nf">deep-aget</span> <span class="nv">~hint</span> <span class="nv">a</span><span class="o">#</span> <span class="nv">~@idxs</span><span class="p">))))</span></pre>
<p>Does it work?</p>
<pre class="highlight"><span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">i</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">j</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nf">deep-aget</span> <span class="nv">doubles</span> <span class="nv">dd</span> <span class="nv">i</span> <span class="nv">j</span><span class="p">))))</span>
<span class="c1">; &quot;Elapsed time: 16.937279 msecs&quot;</span></pre>
<h4>Updating</h4>
<p>Naive method:</p>
<pre class="highlight"><span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">i</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">j</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nb">aset </span><span class="nv">dd</span> <span class="nv">i</span> <span class="nv">j</span> <span class="mf">42.0</span><span class="p">))))</span>
<span class="c1">; &quot;Elapsed time: 13859.404896 msecs&quot;</span></pre>
<p>Partially hinted step-by-step:</p>
<pre class="highlight"><span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">i</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">j</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nb">-&gt; </span><span class="o">#</span><span class="nv">^objects</span> <span class="nv">dd</span> <span class="p">(</span><span class="nb">aget </span><span class="nv">i</span><span class="p">)</span> <span class="p">(</span><span class="nb">aset </span><span class="nv">j</span> <span class="mf">42.0</span><span class="p">)))))</span>
<span class="c1">; &quot;Elapsed time: 94.699536 msecs&quot;</span></pre>
<p>Fully hinted step-by-step (take 1):</p>
<pre class="highlight"><span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">i</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">j</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="o">#</span><span class="nv">^doubles</span> <span class="nv">a</span> <span class="p">(</span><span class="nb">aget </span><span class="o">#</span><span class="nv">^objects</span> <span class="nv">dd</span> <span class="nv">i</span><span class="p">)]</span> <span class="p">(</span><span class="nb">aset </span><span class="nv">a</span> <span class="nv">j</span> <span class="mf">42.0</span><span class="p">)))))</span>
<span class="c1">; java.lang.IllegalArgumentException: More than one matching method found: aset</span></pre>
<p>The compiler doesn&#8217;t know which aset to pick between (Object[], int, Object) and (double[], int, double) according to the hints (double[], int, Object). That&#8217;s why one needs to hint 42.0:</p>
<pre class="highlight"><span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">i</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">j</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="o">#</span><span class="nv">^doubles</span> <span class="nv">a</span> <span class="p">(</span><span class="nb">aget </span><span class="o">#</span><span class="nv">^objects</span> <span class="nv">dd</span> <span class="nv">i</span><span class="p">)]</span> <span class="p">(</span><span class="nb">aset </span><span class="nv">a</span> <span class="nv">j</span> <span class="p">(</span><span class="nb">double </span><span class="mf">42.0</span><span class="p">))))))</span>
<span class="c1">; &quot;Elapsed time: 19.561983 msecs&quot;</span></pre>
<p>A nice macro to abstract away:</p>
<pre class="highlight"><span class="p">(</span><span class="k">defmacro </span><span class="nv">deep-aset</span> <span class="p">[</span><span class="nv">hint</span> <span class="nv">array</span> <span class="nv">&amp;</span> <span class="nv">idxsv</span><span class="p">]</span>
  <span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">hints</span> <span class="o">&#39;</span><span class="p">{</span><span class="nv">doubles</span> <span class="nv">double</span> <span class="nv">ints</span> <span class="nv">int</span><span class="p">}</span> <span class="c1">; writing a comprehensive map is left as an exercise to the reader</span>
        <span class="p">[</span><span class="nv">v</span> <span class="nv">idx</span> <span class="nv">&amp;</span> <span class="nv">sxdi</span><span class="p">]</span> <span class="p">(</span><span class="nb">reverse </span><span class="nv">idxsv</span><span class="p">)</span>
        <span class="nv">idxs</span> <span class="p">(</span><span class="nb">reverse </span><span class="nv">sxdi</span><span class="p">)</span>
        <span class="nv">v</span> <span class="p">(</span><span class="nb">if-let </span><span class="p">[</span><span class="nv">h</span> <span class="p">(</span><span class="nf">hints</span> <span class="nv">hint</span><span class="p">)]</span> <span class="p">(</span><span class="nb">list </span><span class="nv">h</span> <span class="nv">v</span><span class="p">)</span> <span class="nv">v</span><span class="p">)</span>
        <span class="nv">nested-array</span> <span class="p">(</span><span class="k">if </span><span class="p">(</span><span class="nb">seq </span><span class="nv">idxs</span><span class="p">)</span>
                       <span class="o">`</span><span class="p">(</span><span class="nf">deep-aget</span> <span class="nv">~</span><span class="ss">&#39;objects</span> <span class="nv">~array</span> <span class="nv">~@idxs</span><span class="p">)</span>
                        <span class="nv">array</span><span class="p">)</span>
        <span class="nv">a-sym</span> <span class="p">(</span><span class="nb">with-meta </span><span class="p">(</span><span class="nb">gensym </span><span class="s">&quot;a&quot;</span><span class="p">)</span> <span class="p">{</span><span class="nv">:tag</span> <span class="nv">hint</span><span class="p">})]</span>
      <span class="o">`</span><span class="p">(</span><span class="k">let </span><span class="p">[</span><span class="nv">~a-sym</span> <span class="nv">~nested-array</span><span class="p">]</span>
         <span class="p">(</span><span class="nb">aset </span><span class="nv">~a-sym</span> <span class="nv">~idx</span> <span class="nv">~v</span><span class="p">))))</span></pre>
<p>Does it work?</p>
<pre class="highlight"><span class="p">(</span><span class="nb">time </span><span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">i</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nb">dotimes </span><span class="p">[</span><span class="nv">j</span> <span class="mi">1000</span><span class="p">]</span> <span class="p">(</span><span class="nf">deep-aset</span> <span class="nv">doubles</span> <span class="nv">dd</span> <span class="nv">i</span> <span class="nv">j</span> <span class="mf">42.0</span><span class="p">))))</span>
<span class="c1">; &quot;Elapsed time: 19.439133 msecs&quot;</span></pre>
<p>(All tests run on jdk 1.6.0_14 32bit, options <code>-server -XX:+DoEscapeAnalysis</code> on a processor with a 6MB L2 cache.)</p>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/C-Ml8bI5mOA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2009/10/15/multidim-arrays/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Clojure and Me has moved</title>
		<link>http://clj-me.cgrand.net/2009/09/26/clojure-and-me-has-moved/</link>
		<comments>http://clj-me.cgrand.net/2009/09/26/clojure-and-me-has-moved/#comments</comments>
		<pubDate>Sat, 26 Sep 2009 14:04:16 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/?p=144</guid>
		<description><![CDATA[I&#8217;m sorry if my previous posts reappeared in your RSS reader. I just moved Clojure and me from blogger to cgrand.net.
]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m sorry if my previous posts reappeared in your RSS reader. I just moved <a href="clj-me.cgrand.net">Clojure and me</a> from <a href="clj-me.blogpsot.com">blogger</a> to <a href="clj-me.cgrand.net">cgrand.net</a>.</p>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/0mdWKb3g_W8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2009/09/26/clojure-and-me-has-moved/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>About the subtitle</title>
		<link>http://clj-me.cgrand.net/2009/08/13/about-the-subtitle/</link>
		<comments>http://clj-me.cgrand.net/2009/08/13/about-the-subtitle/#comments</comments>
		<pubDate>Thu, 13 Aug 2009 08:54:00 +0000</pubDate>
		<dc:creator>cgrand</dc:creator>
				<category><![CDATA[unsorted]]></category>

		<guid isPermaLink="false">http://clj-me.cgrand.net/2009/08/13/about-the-subtitle/</guid>
		<description><![CDATA[The subtitle for this blog may be misleading. Actually it reads &#8220;When the pupil is ready to learn, a teacher will appear.&#8221; I picked this Zen proverb because in early 2008 I was looking for a language with the following requirements: strong metaprogrammability, strong concurrency support, strong functional bias and bonus points for running on [...]]]></description>
			<content:encoded><![CDATA[<p>The subtitle for this blog may be misleading. Actually it reads &#8220;When the pupil is ready to learn, a teacher will appear.&#8221; <br />I picked this Zen proverb because in early 2008 I was looking for a language with the following requirements: strong metaprogrammability, strong concurrency support, strong functional bias and bonus points for running on the JVM. I had prepared myself to not find the rare bird when I met Clojure (and it was nearly love at first sight).<br />So in that perspective I am the pupil and Clojure (the language, Rich Hickey and the whole community) the teacher.</p>
<img src="http://feeds.feedburner.com/~r/ClojureAndMe/~4/nlV0hiUveXM" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://clj-me.cgrand.net/2009/08/13/about-the-subtitle/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
