<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://www.thattommyhall.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://www.thattommyhall.com/" rel="alternate" type="text/html" /><updated>2025-09-24T23:33:22+03:00</updated><id>https://www.thattommyhall.com/feed.xml</id><title type="html">A Random Walk Through Ideaspace</title><subtitle>thattommyhall&apos;s blog</subtitle><author><name>Tom Hall</name></author><entry><title type="html">What Even Is Time?</title><link href="https://www.thattommyhall.com/2025/09/24/what-even-is-time/" rel="alternate" type="text/html" title="What Even Is Time?" /><published>2025-09-24T00:00:00+03:00</published><updated>2025-09-24T00:00:00+03:00</updated><id>https://www.thattommyhall.com/2025/09/24/what-even-is-time</id><content type="html" xml:base="https://www.thattommyhall.com/2025/09/24/what-even-is-time/"><![CDATA[<p>It’s been a while since I blogged, so long that the old version of
<a href="https://middlemanapp.com/">middleman</a> I was using could not run in any version
of Ruby that <a href="https://mise.jdx.dev/">mise</a> could install on my machine and
moving off middleman seemed less work than dealing with that.</p>

<p>I don’t even remember moving to middleman from
<a href="https://octopress.org/">octopress</a> but now I am back on
<a href="https://jekyllrb.com/">jekyll</a>.</p>

<p>In what is probably quite an on-brand move I have decided to use the <a href="https://edwardtufte.github.io/tufte-css/">Tufte
CSS</a> theme that was cool 10 years ago.
<label for="use-of-sidenotes" class="margin-toggle sidenote-number"></label><input type="checkbox" id="use-of-sidenotes" class="margin-toggle" checked="" /><span class="sidenote">Which is odd as Im not <em>that</em> into sidenotes
really</span></p>

<p>A fair bit has happened that I will write more about soon but as a quick summary:</p>

<ul>
  <li>Moved to Malta during covid</li>
  <li>Got Married</li>
  <li>Learned to sail</li>
  <li>Had a kid (Izzy, nearly 3 now)</li>
  <li>Moved back to the UK</li>
  <li>Did a batch at <a href="https://www.recurse.com/">the Recurse Center</a> <label for="rc" class="margin-toggle sidenote-number"></label><input type="checkbox" id="rc" class="margin-toggle" checked="" /><span class="sidenote">Probably the main reason I wanted to reboot my blog was being inspired by the RC alum feed</span></li>
</ul>

<p>I also just bought a house near where I am from on <a href="https://www.visitwirral.com/">The
Wirral</a> in the northwest of the UK and we went for
some <del>Digital Nomad</del> Analogue Hobo Family time in Porto and then Syros with
<a href="https://www.boundless.life/syros-greece">Boundless Life</a> while the paperwork
went through.</p>

<p>I am currently in my wife’s home town of
<a href="https://en.wikipedia.org/wiki/Ia%C8%99i">Iași</a> in the east of Romania for a few
more weeks and then return to the UK mid October.</p>

<p>TTFN <label for="ttfn" class="margin-toggle sidenote-number"></label><input type="checkbox" id="ttfn" class="margin-toggle" checked="" /><span class="sidenote">ta ta for now (ie <em>goodbye</em>), which I know from Tigger in the 1968 Disney Winnie the Pooh but apparently <a href="https://en.wikipedia.org/wiki/TTFN">started in WW2</a></span></p>]]></content><author><name>Tom Hall</name></author><summary type="html"><![CDATA[It’s been a while since I blogged, so long that the old version of middleman I was using could not run in any version of Ruby that mise could install on my machine and moving off middleman seemed less work than dealing with that.]]></summary></entry><entry><title type="html">Forcing VGA output over Mini DisplayPort in Linux</title><link href="https://www.thattommyhall.com/2016/02/22/forcing-vga-output-in-linux/" rel="alternate" type="text/html" title="Forcing VGA output over Mini DisplayPort in Linux" /><published>2016-02-22T20:23:00+02:00</published><updated>2016-02-22T20:23:00+02:00</updated><id>https://www.thattommyhall.com/2016/02/22/forcing-vga-output-in-linux</id><content type="html" xml:base="https://www.thattommyhall.com/2016/02/22/forcing-vga-output-in-linux/"><![CDATA[<p>For a long time adding multiple monitors to my laptop has
JustWorked™ and have been a bit complacent about assuming that
plugging into a random projector would be fine, but recently a VGA
projector attached to the mini-display port was not detected (I think
because it was attached to a VGA switch)</p>

<p>The below did allow me to force VGA output (even though <code class="language-plaintext highlighter-rouge">xrandr</code> never
saw the VGA device)</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xrandr <span class="nt">--output</span> eDP1 <span class="nt">--mode</span> 1024x768
xrandr <span class="nt">--addmode</span> DP1 1024x768
xrandr <span class="nt">--output</span> DP1 <span class="nt">--mode</span> 1024x768 <span class="nt">--same-as</span> eDP1
</code></pre></div></div>

<p>The graphics card is an Intel and I have the latest i915 drivers from <a href="https://01.org/linuxgraphics">01.org</a></p>

<p>The <code class="language-plaintext highlighter-rouge">xrandr</code> output was</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Screen 0: minimum 8 x 8, current 1920 x 1080, maximum 32767 x 32767
eDP1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 294mm x 165mm
   1920x1080     59.93*+  59.93
   1680x1050     59.95    59.88
   1600x1024     60.17
   1400x1050     59.98
   1600x900      60.00
   1280x1024     60.02
   1440x900      59.89
   1280x960      60.00
   1368x768      60.00
   1360x768      59.80    59.96
   1152x864      60.00
   1280x720      60.00
   1024x768      60.00
   1024x576      60.00
   960x540       60.00
   800x600       60.32    56.25
   864x486       60.00
   640x480       59.94
   720x405       60.00
   640x360       60.00
DP1 disconnected (normal left inverted right x axis y axis)
HDMI1 disconnected (normal left inverted right x axis y axis)
VIRTUAL1 disconnected (normal left inverted right x axis y axis)
</code></pre></div></div>]]></content><author><name>Tom Hall</name></author><category term="linux" /><summary type="html"><![CDATA[For a long time adding multiple monitors to my laptop has JustWorked™ and have been a bit complacent about assuming that plugging into a random projector would be fine, but recently a VGA projector attached to the mini-display port was not detected (I think because it was attached to a VGA switch)]]></summary></entry><entry><title type="html">Getting Wii Classic Controller Working in Steam Using xboxdrv</title><link href="https://www.thattommyhall.com/2015/12/12/getting-wii-classic-controller-working-under-xboxdrv/" rel="alternate" type="text/html" title="Getting Wii Classic Controller Working in Steam Using xboxdrv" /><published>2015-12-12T20:08:00+02:00</published><updated>2015-12-12T20:08:00+02:00</updated><id>https://www.thattommyhall.com/2015/12/12/getting-wii-classic-controller-working-under-xboxdrv</id><content type="html" xml:base="https://www.thattommyhall.com/2015/12/12/getting-wii-classic-controller-working-under-xboxdrv/"><![CDATA[<p>For a while I have been meaning to play some modern indie platformers
from Steam (like <a href="http://supermeatboy.com/">Super Meat Boy</a>, <a href="http://braid-game.com/">Braid</a> and <a href="http://store.steampowered.com/app/48000/">Limbo</a>).</p>

<p>I have been pretty happy with the
<a href="http://www.amazon.co.uk/gp/product/B002TLTBN0/ref=as_li_tl?ie=UTF8&amp;camp=1634&amp;creative=19450&amp;creativeASIN=B002TLTBN0&amp;linkCode=as2&amp;tag=tomsblog-21">Wii Classic</a>
controller for playing games on a SNES emulator but it didnt work with
Steam straight off.</p>

<p><a rel="nofollow" href="http://www.amazon.co.uk/gp/product/B002TLTBN0/ref=as_li_tl?ie=UTF8&amp;camp=1634&amp;creative=19450&amp;creativeASIN=B002TLTBN0&amp;linkCode=as2&amp;tag=tomsblog-21"><img border="0" src="http://ws-eu.amazon-adsystem.com/widgets/q?_encoding=UTF8&amp;ASIN=B002TLTBN0&amp;Format=_SL250_&amp;ID=AsinImage&amp;MarketPlace=GB&amp;ServiceVersion=20070822&amp;WS=1&amp;tag=tomsblog-21" /></a><img src="http://ir-uk.amazon-adsystem.com/e/ir?t=tomsblog-21&amp;l=as2&amp;o=2&amp;a=B002TLTBN0" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" /></p>

<p>Using this awesome
<a href="https://aweirdimagination.net/2015/04/06/emulating-xbox-controllers-on-linux/">python script</a>
from Daniel Perelman I was able to get it working via xboxdrv.</p>

<p>Here are the correct settings:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>xboxdrv --evdev "/dev/input/event7" --evdev-keymap "BTN_THUMB2=a,BTN_PINKIE=rt,BTN_DEAD=dl,BTN_THUMB=b,BTN_BASE=lb,KEY_#302=dd,BTN_BASE3=back,BTN_BASE4=start,BTN_TOP2=lt,BTN_BASE2=rb,BTN_JOYSTICK=y,BTN_TOP=x,KEY_#300=du,KEY_#301=dr,BTN_BASE5=guide" --evdev-absmap "ABS_Y=y1,ABS_Z=x2,ABS_X=x1,ABS_RZ=y2" --axismap "-y1=y1,-y2=y2 --mimic-xpad --silent --quiet"
</code></pre></div></div>

<p>My controller is now at <code class="language-plaintext highlighter-rouge">/dev/input/event7</code>, you can find out where
yours is by running <code class="language-plaintext highlighter-rouge">evtest /dev/input/eventX</code> (if you just plugged it
in it’s likely to be the highest numbered input device)</p>]]></content><author><name>Tom Hall</name></author><category term="games,steam" /><summary type="html"><![CDATA[For a while I have been meaning to play some modern indie platformers from Steam (like Super Meat Boy, Braid and Limbo).]]></summary></entry><entry><title type="html">SICP Distilled Now Public</title><link href="https://www.thattommyhall.com/2015/09/06/sicp-distilled-now-public/" rel="alternate" type="text/html" title="SICP Distilled Now Public" /><published>2015-09-06T19:18:00+03:00</published><updated>2015-09-06T19:18:00+03:00</updated><id>https://www.thattommyhall.com/2015/09/06/sicp-distilled-now-public</id><content type="html" xml:base="https://www.thattommyhall.com/2015/09/06/sicp-distilled-now-public/"><![CDATA[<p>I have made the <a href="http://www.sicpdistilled.com/">SICP Distilled</a> site
public.</p>

<p>It is now a year since the SICP Distilled Kickstarter was funded, I
originally thought it would take 5 months to complete and had a
slightly different vision for what it would look like, massive thanks
to all of the supporters for their patience and understanding.</p>

<p>I originally thought an accompaniment to the original book but it has
wound up being more like a rewrite, fortunately the original text is
under a Creative Commons
<a href="https://creativecommons.org/licenses/by-sa/4.0/">Attribution-ShareAlike 4.0</a>
License so I can ‘remix’ it without getting into copyright issues if I
have the same licence.</p>

<p>It is not complete yet, but I think I now have good explanations of:</p>

<ul>
  <li><a href="http://www.sicpdistilled.com/section/1.3-higher-order">Higher Order Functions</a></li>
  <li><a href="http://www.sicpdistilled.com/section/2-escher">Embedded DSLs and stratified design</a></li>
  <li><a href="http://www.sicpdistilled.com/section/4.1">Building an interpreter</a></li>
</ul>

<p>Which really are (for me at least) the highlights of the book.</p>

<p>I think the projects make it easier to engage with the ideas than the
book’s exercises. The content from Ch1 is complete (I may add another
couple of projects). Have a look at
<a href="http://www.sicpdistilled.com/section/1-distilled">Ch1 Distilled</a> for
more on what is different from the original.</p>

<p>I have just published a straight translation of the rational number
example from Ch2, in the SICP style. I will publish a more idiomatic
Clojure version of the example and go on to implementing sets and the
encoding trees more idiomatically too. Again
<a href="http://www.sicpdistilled.com/section/2-distilled">Ch2 Distilled</a> goes
into more detail.</p>

<p>Ch3 I am still not totally settled on what to do, probably just a
standard description of how Clojure handles state, talk about
concurrency vs parallelism and do a project based on it. I think SICP
accepts the importance of concurrency but we just didn’t have as good
techniques to handle it then.</p>

<p>I am pleased that I was able to do a
<a href="http://www.sicpdistilled.com/section/4.1">purely functional interpreter</a>
for Ch4, I will add a section on making it lazy (and getting streams
for free then, important as I am not including them as part of
Ch3). The logic programming section might use
<a href="http://webyrd.net/scheme-2013/papers/HemannMuKanren2013.pdf">μkanren</a>
rather than translate SICP’s.</p>

<p>I have avoiding thinking about Ch5 too much till I pin everything else
down, I have jumped around the book too much already and people that
needed the simpler material at the beginning have waited longer than
they should have. I still like the idea of doing a very basic LLVM
compiler though.</p>

<p>Since starting the project, I found
<a href="http://www.composingprograms.com/">Composing Programs</a> a re-imagining
of SICP in Python. It is great and I think complementary to SICP
Distilled, they have interesting additions to and selections from the
text. I plan to write an interpreter for a subset of Python in Clojure
using <a href="https://github.com/Engelberg/instaparse">Instaparse</a> which will
complement their
<a href="http://inst.eecs.berkeley.edu/~cs61a/fa13/proj/scheme/scheme.html">Scheme in Python</a>.</p>

<p>I hope you enjoy what is there, any issues with the content please
<a href="https://gitter.im/SICPDistilled">ask on gitter</a> or raise an issue on
<a href="https://github.com/orgs/SICPDistilled/">github</a></p>]]></content><author><name>Tom Hall</name></author><category term="clojure,sicp" /><summary type="html"><![CDATA[I have made the SICP Distilled site public.]]></summary></entry><entry><title type="html">Transducers in SICP</title><link href="https://www.thattommyhall.com/2014/10/09/transducers-in-sicp/" rel="alternate" type="text/html" title="Transducers in SICP" /><published>2014-10-09T09:16:00+03:00</published><updated>2014-10-09T09:16:00+03:00</updated><id>https://www.thattommyhall.com/2014/10/09/transducers-in-sicp</id><content type="html" xml:base="https://www.thattommyhall.com/2014/10/09/transducers-in-sicp/"><![CDATA[<p>I was re-reading the first two chapters of SICP at the weekend as I am starting to prepare <a href="https://www.kickstarter.com/projects/1751759988/sicp-distilled">SICP Distilled</a> and I was pleased to see:</p>

<blockquote>
  <p>The value of expressing programs as sequence operations is that this helps us make program designs that are modular, that is, designs that are constructed by combining relatively independent pieces. We can encourage modular design by providing a library of standard components together with a conventional interface for connecting the components in flexible ways.</p>
</blockquote>

<blockquote>
  <p>Modular construction is a powerful strategy for controlling complexity in engineering design. In real signal-processing applications, for example, designers regularly build systems by cascading elements selected from standardized families of filters and <em>transducers</em>. Similarly, sequence operations provide a library of standard program elements that we can mix and match.</p>
</blockquote>

<p>While we know Rich finds his words in an etymology dictionary I thought it interesting to see someone else arrive at the same word for a similar concept.</p>

<p>If you have not seen Rich’s into to transducers please <a href="https://www.youtube.com/watch?v=6mTbuzafcII">do so</a>, it’s excellent.</p>]]></content><author><name>Tom Hall</name></author><category term="clojure,sicp" /><summary type="html"><![CDATA[I was re-reading the first two chapters of SICP at the weekend as I am starting to prepare SICP Distilled and I was pleased to see:]]></summary></entry><entry><title type="html">SICP Distilled</title><link href="https://www.thattommyhall.com/2014/08/27/sicp-distilled/" rel="alternate" type="text/html" title="SICP Distilled" /><published>2014-08-27T23:49:00+03:00</published><updated>2014-08-27T23:49:00+03:00</updated><id>https://www.thattommyhall.com/2014/08/27/sicp-distilled</id><content type="html" xml:base="https://www.thattommyhall.com/2014/08/27/sicp-distilled/"><![CDATA[<p>I launched a <a href="https://www.kickstarter.com/projects/1751759988/sicp-distilled">Kickstarter project</a> yesterday to do an idiosyncratic tour of the best of Structure and Interpretation of Computer Programs in Clojure</p>

<h2 id="please-sign-up-if-you-are-interested-below-is-copied-from-kickstarter">Please sign up if you are interested (below is copied from Kickstarter)</h2>

<h1 id="sicp">SICP?</h1>
<p>It is a great introduction to computation, Peter Norvig probably <a href="http://www.amazon.com/review/R403HR4VL71K8/">said it best</a>:</p>

<blockquote>
  <p>To use an analogy, if SICP were about automobiles, it would be for the person who wants to know how cars work, how they are built, and how one might design fuel-efficient, safe, reliable vehicles for the 21st century. The people who hate SICP are the ones who just want to know how to drive their car on the highway, just like everyone else.</p>
</blockquote>

<p>I was going to write more about why one should study SICP, but Kai Wu of Hacker Retreat did a stellar job <a href="http://hackerretreat.com/why-how-start-sicp/">here</a></p>

<h1 id="distilled">Distilled?</h1>

<p>It’s a long book, with lots of exercises and lots of people I know have started, loved it, but somehow not finished.</p>

<p>Abelson and Sussman themselves highlight the important lessons of SICP in their paper <a href="http://dspace.mit.edu/bitstream/handle/1721.1/6064/AIM-986.pdf?sequence=2">Lisp: A Language For Stratified Design</a> and I have my own favourite bits.</p>

<p>As the book itself is available <a href="http://sicpebook.wordpress.com/">online for free</a> I want to make the perfect accompaniment to it - an ebook summarising the key ideas, short videos describing them, screencasts of solving some of the exercises, translation of the examples into Clojure, example projects, partial solutions for you to complete (similar to <a href="http://www.4clojure.com/problem/178">4clojure</a> and <a href="http://clojurekoans.com/">Clojure koans</a>) and a place to discuss solving them with people.</p>

<p>Something more like the exercises for the Feynman Lectures on Physics, to be enjoyed alongside SICP, rather than completely replace it.</p>

<p>Maybe some ideas come out a little different in Clojure, or I take a slightly novel approach (hence idiosyncratic), maybe I miss something out (hence tour, sorry), but I hope we can have some fun along the way.</p>

<p>I’ve surveyed friends and people who signed up early about which bits they enjoyed, where they got stuck and how best to approach it.</p>

<p>People that join in on the Kickstarter get a reduced price and a chance to affect the direction of the project (and, let’s be honest, be test subjects)</p>

<h1 id="why-clojure">Why Clojure?</h1>

<ul>
  <li>A modern take on Lisp</li>
  <li>Slightly less parens (though obviously you will come to love them anyway)</li>
  <li>More immutability! (SICP gets as far as possible without mutation and quite rightly warns you to be careful when you start)</li>
  <li>Target JVM or Javascript, and use their libraries</li>
  <li>An <a href="https://github.com/Engelberg/instaparse">excellent parser library</a></li>
  <li>A more fully featured <a href="https://github.com/clojure/core.logic">logic engine</a> for us to peek at</li>
  <li>Different concurrency models</li>
</ul>

<h1 id="what-will-i-do">What will I do?</h1>

<p>You will:</p>

<ul>
  <li>Come to appreciate and use higher order functions</li>
  <li>Build everything from (almost) nothing</li>
  <li>Deeply embed DSLs into Clojure</li>
  <li>Draw Escher pictures</li>
  <li>Create datastructures</li>
  <li>Learn why <a href="http://vimeo.com/6624203">reduce is considered harmful</a>  (not SICP but I have some fun exercises planned)</li>
  <li>understand iteration and recursion</li>
  <li>Create an object system</li>
  <li>Make a compiler</li>
  <li>Build a Lisp interpreter (or a mini version of your other favourite language)</li>
  <li>Do some logic programming</li>
</ul>

<p>Plus more!</p>

<h1 id="why-kickstarter">Why Kickstarter?</h1>
<p>Having the money up front allows me to judge interest, spend more on post-production of the videos, devote more time to it and create a way for people to collaborate and help each other along the way.</p>

<h1 id="i-want-it-to-be-free">I want it to be free!</h1>

<p>So do I! If I was independently wealthy I would love to spend all my days on this, but alas I am not. I do believe in freedom though, and promise to make all the resources free after 12 months.</p>

<p>To quote RMS:</p>

<blockquote>
  <p>The copyright system works by providing privileges and thus benefits to publishers and authors; but it does not do this for their sake. Rather, it does this to modify their behaviour: to provide an incentive for authors to write more and publish more. In effect, the government spends the public’s natural rights, on the public’s behalf, as part of a deal to bring the public more published works</p>
</blockquote>

<h1 id="how-long-will-it-take">How long will it take?</h1>

<p>I will roughly follow the books 5 chapters, one a month, that gives enough time for people to follow along. If we have a bunch of people going through at the same time we will be able to benefit from interactions within the group as well.</p>

<p>However I am often put off by artificial deadlines in MOOCs so want the material to stand alone (well at least alongside the SICP text) for someone doing it by themselves at whatever pace they like.</p>]]></content><author><name>Tom Hall</name></author><category term="clojure" /><summary type="html"><![CDATA[I launched a Kickstarter project yesterday to do an idiosyncratic tour of the best of Structure and Interpretation of Computer Programs in Clojure]]></summary></entry><entry><title type="html">101 Goals Day 200 Update</title><link href="https://www.thattommyhall.com/2014/02/24/101-goals-day-200-update/" rel="alternate" type="text/html" title="101 Goals Day 200 Update" /><published>2014-02-24T12:00:00+02:00</published><updated>2014-02-24T12:00:00+02:00</updated><id>https://www.thattommyhall.com/2014/02/24/101-goals-day-200-update</id><content type="html" xml:base="https://www.thattommyhall.com/2014/02/24/101-goals-day-200-update/"><![CDATA[<p>This is my (month late) day 200 update of my second 101 Goals in 1001 days</p>

<h2 id="completed">Completed</h2>

<h3 id="43---build-a-robot">43 - Build a robot</h3>
<p>Did my raspirobot at the weekend at <a href="http://www.meetup.com/NodeBots-of-London/">NodeBots of London</a>.</p>

<h3 id="59---finish-4clojure">59 - Finish 4clojure</h3>
<p><img src="/images/post/4clojure.png" /></p>

<p>Finished the final few over Christmas.</p>

<h2 id="in-progress">In Progress</h2>

<h3 id="41---reasoned-schemer">41 - Reasoned Schemer</h3>
<p><a href="http://www.amazon.co.uk/gp/product/0262562146?ie=UTF8&amp;camp=3194&amp;creative=21330&amp;creativeASIN=0262562146&amp;linkCode=shr&amp;tag=tomsblog-21"><img src="/images/post/reasonedschemer.jpg" /></a></p>

<p>Loving it, on chapter 8. 2014 is looking like the year of logic for me.</p>

<h3 id="89---walk-capital-ring">89 - Walk Capital Ring</h3>
<p>Petra and I have decided to do it together, we did section 10 as it goes past our place.
<a href="http://www.walklondon.org.uk/uploads/File/leaflets/overview_capital_ring_30062010112207.pdf"><img src="/images/post/ring.png" /></a></p>

<h2 id="planning">Planning</h2>
<p>I now have a <a href="https://trello.com/b/BtkMg23I/101-next">Trello Board </a> for planning. Mostly need to get cracking cycling, walking and swimming :-)</p>

<p>Check out <a href="/2013/07/11/101-goals-in-1001-days-ii/">the full list</a> and let me know if you want to join in any.</p>]]></content><author><name>Tom Hall</name></author><category term="101v2,life" /><summary type="html"><![CDATA[This is my (month late) day 200 update of my second 101 Goals in 1001 days]]></summary></entry><entry><title type="html">Concurrency and Parallelism in Clojure</title><link href="https://www.thattommyhall.com/2014/02/24/concurrency-and-parallelism-in-clojure/" rel="alternate" type="text/html" title="Concurrency and Parallelism in Clojure" /><published>2014-02-24T05:31:00+02:00</published><updated>2014-02-24T05:31:00+02:00</updated><id>https://www.thattommyhall.com/2014/02/24/concurrency-and-parallelism-in-clojure</id><content type="html" xml:base="https://www.thattommyhall.com/2014/02/24/concurrency-and-parallelism-in-clojure/"><![CDATA[<p>I was pleased to be speaking at the <a href="http://skillsmatter.com/event/java-jee/clojure-exchange-2013">Clojure Exchange</a> recently (at least it was recently when I started writing this blog post). I suggested to <a href="https://twitter.com/otfrom">Bruce</a> that a talk on concurrency and parallelism would be good because since most of the books were published <a href="http://clojure.com/blog/2012/05/08/reducers-a-library-and-model-for-collection-processing.html">reducers</a> and <a href="http://clojure.com/blog/2013/06/28/clojure-core-async-channels.html">core.async</a> have appeared giving us even more options in Clojure and we have a new runtime in Clojurescript (I also ranted that our books get it a bit wrong).</p>

<p>The goals of the talk were:</p>

<ul>
  <li>Give people solid working definitions of concurrency and parallelism</li>
  <li>Refresher on reference types (and that you don’t automatically get parallelism with them)</li>
  <li>Show some easy ways to get parallelism in your programs</li>
  <li>Demo a nice pattern serialising access to something non-threadsafe with an agent</li>
  <li>Explain Reducers as a way of getting parallelism (and the idea reduce/fold itself is no good for it)</li>
  <li>Introduce CSP via core.async as a way of programming concurrently (that sometimes runs in parallel)</li>
  <li>Point people at people way smarter than me talking for a bit longer than I had about just one of the things I tried to</li>
</ul>

<p>Slides are <a href="http://www.thattommyhall.com/clojurex2013">here</a>, video <a href="http://skillsmatter.com/podcast/java-jee/you-came-for-the-concurrency-right">here</a> but I will expand on a few ideas here too</p>

<h2 id="concurrency-is-not-parallelism">Concurrency is not parallelism</h2>
<p>It has been said better by Rob Pike in <a href="http://vimeo.com/49718712">this talk</a> but the definition is:</p>

<blockquote>
  <p>Concurrency is the composition of independently executing ‘processes’</p>
</blockquote>

<blockquote>
  <p>Parallelism is the simultaneous execution of (possibly related) computations</p>
</blockquote>

<p>So:</p>

<blockquote>
  <p>Concurrency is about the way we structure programs</p>
</blockquote>

<blockquote>
  <p>Parallelism is about the way they run</p>
</blockquote>

<p>The nice thing about this definition is it’s then easy to find examples of concurrent but not parallel (running multiple threads on a single core) and parallel but not concurrent (instruction-level parallelism, data parallelism), and even when concurrency and parallelism are both present but to a different extent (running 50 threads multiplexed across 4 cores).</p>

<h3 id="wikipedia">Wikipedia</h3>
<p>Is correct</p>

<p><img src="/images/post/CvPwikipedia.png" width="700" />
<img src="/images/post/citationneeded.png" width="700" /></p>

<h3 id="joe-armstrong-in-programming-erlang">Joe Armstrong in Programming Erlang</h3>
<p><img src="/images/post/armstrong.png" width="700" /></p>

<h3 id="c2-wiki">C2 Wiki</h3>
<p>I like this one as it brings out the two main ways of doing concurrency, either by message passing with no shared state or by managing access to the shared state.
<img src="/images/post/c2concurrency.png" width="700" />
<img src="/images/post/c2concurrency2.png" width="700" /></p>

<p>I have the three main books on Clojure so took a look at how they introduced the idea</p>

<h3 id="clojure-programming">Clojure Programming</h3>
<p><img src="/images/post/PvCCP.png" width="700" /></p>

<p>Both definitions assume shared state, though it captures the idea that parallel means running at the same time and that to get the most from your hardware you want to avoid coordination overhead.</p>

<h3 id="joy-of-clojure">Joy Of Clojure</h3>
<p><img src="/images/post/PvCjoy.png" width="500" /></p>

<p>I don’t like ‘roughly the same time’ here, and again seems to presume shared state.</p>

<h3 id="programming-clojure">Programming Clojure</h3>
<p><img src="/images/post/PvCPC.png" width="700" /></p>

<p>I think that saying parallel programs execute concurrently is wrong (replace it with ‘at the same time’ and I think it is right) and the first bullet misuses ‘concurrent’ at least once.</p>

<p>This is not to say it is a massive deal and stops people understanding and using the features of Clojure the books go on to explain, just that until seeing Rob’s talk I don’t think I could have given a clear definition of what the terms mean.</p>

<h2 id="reference-types">Reference types</h2>
<p>Again this was just a refresher and has probably been done better elsewhere.</p>

<p>All of the reference types hold a value and are updated by functions with the same signature</p>

<p><code class="language-plaintext highlighter-rouge">(&lt;changer&gt; reference f [args*])</code></p>

<p>All can be derefed with <code class="language-plaintext highlighter-rouge">@reference</code> or <code class="language-plaintext highlighter-rouge">(deref reference)</code></p>

<p>The main difference between them if they are synchronous or asynchronous, coordinated or uncoordinated.</p>

<ul>
  <li>Synchronisation - Does the operation block?</li>
  <li>Coordination - Can multiple operations be combined in a transaction?</li>
</ul>

<h2 id="atoms-synchronousuncoordinated">Atoms (Synchronous,Uncoordinated)</h2>

<h3 id="swap">swap!</h3>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">swap!</span><span class="w"> </span><span class="n">atom</span><span class="w"> </span><span class="n">f</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">swap!</span><span class="w"> </span><span class="n">atom</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">swap!</span><span class="w"> </span><span class="n">atom</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="n">args</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<h3 id="compare-and-set">compare-and-set!</h3>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">compare-and-set!</span><span class="w"> </span><span class="n">atom</span><span class="w"> </span><span class="n">oldval</span><span class="w"> </span><span class="n">newval</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<h3 id="reset">reset!</h3>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nf">reset!</span><span class="w"> </span><span class="n">atom</span><span class="w"> </span><span class="n">newval</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<h2 id="refs-synchronouscoordinated">Refs (Synchronous,Coordinated)</h2>
<p>(Must be inside a <code class="language-plaintext highlighter-rouge">dosync</code> transaction)</p>

<h3 id="ref-set">ref-set</h3>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">ref-set</span><span class="w"> </span><span class="nb">ref</span><span class="w"> </span><span class="nb">val</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<h3 id="alter">alter</h3>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">alter</span><span class="w"> </span><span class="nb">ref</span><span class="w"> </span><span class="n">fun</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="n">args</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<h3 id="commute">commute</h3>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">commute</span><span class="w"> </span><span class="nb">ref</span><span class="w"> </span><span class="n">fun</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="n">args</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<h2 id="agents-asynchronousuncoordinated">Agents (Asynchronous,Uncoordinated)</h2>

<h3 id="send-executed-on-a-bounded-thread-pool">send (executed on a bounded thread pool)</h3>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">send</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="n">args</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<h3 id="send-off-executed-on-an-unbounded-thread-pool">send-off (executed on an unbounded thread pool)</h3>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="nb">send-off</span><span class="w"> </span><span class="n">a</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="n">args</span><span class="p">)</span><span class="w">
</span></code></pre></div></div>

<h2 id="using-agents-to-serialise-access-to-non-threadsafe-resources">Using agents to serialise access to non-threadsafe resources</h2>
<p>If we start multiple threads and start writing to the console with println from them, very quickly you start to get overlapping writes.</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">start-thread</span><span class="w">
  </span><span class="p">[</span><span class="k">fn</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="nf">.start</span><span class="w">
   </span><span class="p">(</span><span class="nf">Thread.</span><span class="w"> </span><span class="k">fn</span><span class="p">)))</span><span class="w">

</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">loop-print</span><span class="w">
  </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">line</span><span class="w"> </span><span class="p">(</span><span class="nb">str</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="s">":**********"</span><span class="p">)]</span><span class="w">
    </span><span class="p">(</span><span class="nb">println</span><span class="w"> </span><span class="n">line</span><span class="p">)</span><span class="w">
    </span><span class="p">(</span><span class="nf">Thread/sleep</span><span class="w"> </span><span class="p">(</span><span class="nb">rand</span><span class="w"> </span><span class="mi">5</span><span class="p">))</span><span class="w">
    </span><span class="p">(</span><span class="nf">recur</span><span class="w"> </span><span class="n">n</span><span class="p">)))</span><span class="w">

</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">-main</span><span class="w"> </span><span class="p">[]</span><span class="w">
  </span><span class="p">(</span><span class="nb">dotimes</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="w"> </span><span class="mi">50</span><span class="p">]</span><span class="w">
    </span><span class="p">(</span><span class="nf">start-thread</span><span class="w"> </span><span class="o">#</span><span class="p">(</span><span class="nf">loop-print</span><span class="w"> </span><span class="n">n</span><span class="p">))))</span><span class="w">
</span></code></pre></div></div>

<p>One way around it is to wrap the contested resource in an agent</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">write</span><span class="w"> </span><span class="p">[</span><span class="n">w</span><span class="w"> </span><span class="n">content</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="nb">doto</span><span class="w"> </span><span class="n">w</span><span class="w">
    </span><span class="p">(</span><span class="nf">.write</span><span class="w"> </span><span class="n">w</span><span class="w"> </span><span class="n">content</span><span class="p">)</span><span class="w">
    </span><span class="p">(</span><span class="nf">.write</span><span class="w"> </span><span class="s">"\n"</span><span class="p">)</span><span class="w">
    </span><span class="n">.flush</span><span class="p">))</span><span class="w">

</span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">console</span><span class="w"> </span><span class="p">(</span><span class="nb">agent</span><span class="w">  </span><span class="n">*out*</span><span class="p">))</span><span class="w">

</span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">log-file</span><span class="w"> </span><span class="p">(</span><span class="nb">agent</span><span class="w"> </span><span class="p">(</span><span class="nf">io/writer</span><span class="w"> </span><span class="s">"LOG"</span><span class="w"> </span><span class="no">:append</span><span class="w"> </span><span class="n">true</span><span class="p">)))</span><span class="w">

</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">loop-print</span><span class="w">
  </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">line</span><span class="w"> </span><span class="p">(</span><span class="nb">str</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="s">":**********"</span><span class="p">)</span><span class="w">
        </span><span class="n">sleep-time</span><span class="w"> </span><span class="p">(</span><span class="nb">rand</span><span class="w"> </span><span class="mi">5</span><span class="p">)]</span><span class="w">
    </span><span class="p">(</span><span class="nf">Thread/sleep</span><span class="w"> </span><span class="n">sleep-time</span><span class="p">)</span><span class="w">
    </span><span class="p">(</span><span class="nb">send-off</span><span class="w"> </span><span class="n">console</span><span class="w"> </span><span class="n">write</span><span class="w"> </span><span class="p">(</span><span class="nb">str</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="s">":*********"</span><span class="p">))</span><span class="w">
    </span><span class="p">(</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="mi">50</span><span class="p">)</span><span class="w">
      </span><span class="c1">;; We have a separate file log for the 50th thread</span><span class="w">
      </span><span class="p">(</span><span class="nb">send-off</span><span class="w"> </span><span class="n">log-file</span><span class="w"> </span><span class="n">write</span><span class="w"> </span><span class="p">(</span><span class="nb">str</span><span class="w"> </span><span class="s">"sleeping for"</span><span class="w"> </span><span class="n">sleep-time</span><span class="p">)))</span><span class="w">
    </span><span class="p">(</span><span class="nf">recur</span><span class="w"> </span><span class="n">n</span><span class="p">)))</span><span class="w">

</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">-main</span><span class="w"> </span><span class="p">[]</span><span class="w">
  </span><span class="p">(</span><span class="nb">dotimes</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="w"> </span><span class="mi">100</span><span class="p">]</span><span class="w">
    </span><span class="p">(</span><span class="nf">start-thread</span><span class="w"> </span><span class="o">#</span><span class="p">(</span><span class="nf">loop-print</span><span class="w"> </span><span class="n">n</span><span class="p">))))</span><span class="w">
</span></code></pre></div></div>

<p>Here the <code class="language-plaintext highlighter-rouge">write</code> function takes something writeable and a string, writes the string to it with a newline at the end and then (importantly) returns the object (this is the behaviour of <code class="language-plaintext highlighter-rouge">doto</code>). This allows it to be passed to an agent, this way the value of the agent is always the writer and as the agent serialises application of the functions passed into it the writer is only written by one function at a time.</p>

<p>The guidance for whether to send or send-off to an agent is if the function does any IO or not, send-off is for IO operations and is on an unbounded pool whereas send is for CPU bound operations and is on a fixed-size pool. Either way the message queue is unbounded and you might eventually suffer memory issues (this is one of the reasons core.aync and CSP are better as they provide back-pressure and make you think up front about buffering and queue size)</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded
java.lang.OutOfMemoryError: GC overhead limit exceeded
java.lang.RuntimeException: Agent is failed, needs restart
	at clojure.lang.Util.runtimeException(Util.java:223)
	at clojure.lang.Agent.dispatch(Agent.java:238)
	at clojure.core$send_via.doInvoke(core.clj:1915)
	at clojure.lang.RestFn.applyTo(RestFn.java:146)
	at clojure.core$apply.invoke(core.clj:623)
	at clojure.core$send_off.doInvoke(core.clj:1937)
	at clojure.lang.RestFn.invoke(RestFn.java:442)
	at clojure_exchange.agents$loop_print.invoke(agents.clj:24)
	at clojure_exchange.agents$_main$fn__34.invoke(agents.clj:31)
	at clojure.lang.AFn.run(AFn.java:24)
	at java.lang.Thread.run(Thread.java:724)
Caused by: java.lang.OutOfMemoryError: GC overhead limit exceeded
</code></pre></div></div>

<h3 id="agents-and-stm">Agents and STM</h3>
<p>Thanks to <a href="http://www.philandstuff.com/">Philip Potter</a> for reminding me to mention that agents are integrated with STM, any dispatches made in a transaction are held until it commits, and are discarded if it is retried or aborted so you can use them to safely trigger side-effects from within transactions. See <a href="http://clojure.org/agents">the docs</a> for more.</p>

<h2 id="delays-and-futures">Delays and futures</h2>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">&gt;</span><span class="w"> </span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">slow-inc</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w">
   </span><span class="p">(</span><span class="nf">Thread/sleep</span><span class="w"> </span><span class="mi">1000</span><span class="p">)</span><span class="w">
   </span><span class="p">(</span><span class="nb">inc</span><span class="w"> </span><span class="n">n</span><span class="p">))</span><span class="w">
</span></code></pre></div></div>

<h3 id="delays">Delays</h3>
<ul>
  <li>runs code on deref, blocks</li>
</ul>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">&gt;</span><span class="w"> </span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">d</span><span class="w"> </span><span class="p">(</span><span class="nf">delay</span><span class="w"> </span><span class="p">(</span><span class="nf">slow-inc</span><span class="w"> </span><span class="mi">5</span><span class="p">)))</span><span class="w">
</span><span class="c1">;; Returns immediately</span><span class="w">

</span><span class="nb">&gt;</span><span class="w"> </span><span class="o">@</span><span class="n">d</span><span class="w">
</span><span class="c1">;; Will take a second as this is when 'slow-inc' will run</span><span class="w">
</span><span class="mi">6</span><span class="w">
</span></code></pre></div></div>

<h3 id="futures">Futures</h3>
<ul>
  <li>runs code in another thread (from a pool)</li>
  <li>blocks on deref (till ready)</li>
</ul>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">&gt;</span><span class="w"> </span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="p">(</span><span class="nf">future</span><span class="w"> </span><span class="p">(</span><span class="nf">slow-inc</span><span class="w"> </span><span class="mi">5</span><span class="p">)))</span><span class="w">
</span><span class="c1">;; Returns immediately as delay did but is already running slow-inc</span><span class="w">

</span><span class="nb">&gt;</span><span class="w"> </span><span class="o">@</span><span class="n">f</span><span class="w">
</span><span class="c1">;; Depends how quickly you can type</span><span class="w">
</span><span class="c1">;; but if you took longer than a second it will be ready to return,</span><span class="w">
</span><span class="c1">;; if not it will block till it is ready</span><span class="w">
</span><span class="mi">6</span><span class="w">
</span></code></pre></div></div>
<p>So now we have a chance at some parallelism!</p>

<p>We can use future as a way to just kick off new threads, so we can use <code class="language-plaintext highlighter-rouge">future</code> where we had <code class="language-plaintext highlighter-rouge">start-thread</code> (and we gain a bounded thread pool to run them on)</p>

<h2 id="pmap-and-friends">pmap and friends</h2>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">;; Make a sequence of futures</span><span class="w">
</span><span class="nb">&gt;</span><span class="w"> </span><span class="p">(</span><span class="k">def</span><span class="w"> </span><span class="n">futures</span><span class="w"> </span><span class="p">(</span><span class="nb">doall</span><span class="w"> </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="o">#</span><span class="p">(</span><span class="nf">future</span><span class="w"> </span><span class="p">(</span><span class="nf">slow-inc</span><span class="w"> </span><span class="n">%</span><span class="p">))</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="mi">4</span><span class="w"> </span><span class="mi">5</span><span class="p">])))</span><span class="w">
</span><span class="c1">;; Returns immediately (we have to use doall to force evaluation as map is lazy)</span><span class="w">

</span><span class="c1">;; Now to deref them</span><span class="w">
</span><span class="nb">&gt;</span><span class="w"> </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">deref</span><span class="w"> </span><span class="n">futures</span><span class="p">)</span><span class="w">
</span><span class="p">(</span><span class="nf">2</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="mi">4</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="mi">6</span><span class="p">)</span><span class="w">
</span><span class="c1">;; Again should return pretty rapidly but at most a second</span><span class="w">
</span></code></pre></div></div>

<h3 id="pmap">pmap</h3>
<p>Here is a version of a function called pmap that captures that idea</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">pmap</span><span class="w"> </span><span class="p">[</span><span class="n">f</span><span class="w"> </span><span class="n">col</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">futures</span><span class="w"> </span><span class="p">(</span><span class="nb">doall</span><span class="w"> </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="o">#</span><span class="p">(</span><span class="nf">future</span><span class="w"> </span><span class="p">(</span><span class="nf">f</span><span class="w"> </span><span class="n">%</span><span class="p">))</span><span class="w"> </span><span class="n">col</span><span class="p">))]</span><span class="w">
    </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">deref</span><span class="w"> </span><span class="n">futures</span><span class="p">)))</span><span class="w">
</span></code></pre></div></div>
<p>So we can do</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">&gt;</span><span class="w"> </span><span class="p">(</span><span class="nf">pmap</span><span class="w"> </span><span class="n">slow-inc</span><span class="w"> </span><span class="p">[</span><span class="mi">1</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="mi">3</span><span class="w"> </span><span class="mi">4</span><span class="w"> </span><span class="mi">5</span><span class="p">])</span><span class="w">
</span></code></pre></div></div>
<p>and it will take 1s or thereabouts.</p>

<p>The actual pmap looks like this, notice the warning that f needs to be expensive enough to justify the overhead</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">pmap</span><span class="w">
  </span><span class="s">"Like map, except f is applied in parallel. Semi-lazy in that the
  parallel computation stays ahead of the consumption, but doesn't
  realize the entire result unless required. Only useful for
  computationally intensive functions where the time of f dominates
  the coordination overhead."</span><span class="w">
  </span><span class="p">{</span><span class="no">:added</span><span class="w"> </span><span class="s">"1.0"</span><span class="w">
   </span><span class="no">:static</span><span class="w"> </span><span class="n">true</span><span class="p">}</span><span class="w">
  </span><span class="p">([</span><span class="n">f</span><span class="w"> </span><span class="n">coll</span><span class="p">]</span><span class="w">
   </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="w"> </span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="p">(</span><span class="nb">..</span><span class="w"> </span><span class="n">Runtime</span><span class="w"> </span><span class="n">getRuntime</span><span class="w"> </span><span class="n">availableProcessors</span><span class="p">))</span><span class="w">
         </span><span class="n">rets</span><span class="w"> </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="o">#</span><span class="p">(</span><span class="nf">future</span><span class="w"> </span><span class="p">(</span><span class="nf">f</span><span class="w"> </span><span class="n">%</span><span class="p">))</span><span class="w"> </span><span class="n">coll</span><span class="p">)</span><span class="w">
         </span><span class="n">step</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">step</span><span class="w"> </span><span class="p">[[</span><span class="n">x</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="n">xs</span><span class="w"> </span><span class="no">:as</span><span class="w"> </span><span class="n">vs</span><span class="p">]</span><span class="w"> </span><span class="n">fs</span><span class="p">]</span><span class="w">
                </span><span class="p">(</span><span class="nf">lazy-seq</span><span class="w">
                 </span><span class="p">(</span><span class="nb">if-let</span><span class="w"> </span><span class="p">[</span><span class="n">s</span><span class="w"> </span><span class="p">(</span><span class="nb">seq</span><span class="w"> </span><span class="n">fs</span><span class="p">)]</span><span class="w">
                   </span><span class="p">(</span><span class="nb">cons</span><span class="w"> </span><span class="p">(</span><span class="nb">deref</span><span class="w"> </span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nf">step</span><span class="w"> </span><span class="n">xs</span><span class="w"> </span><span class="p">(</span><span class="nb">rest</span><span class="w"> </span><span class="n">s</span><span class="p">)))</span><span class="w">
                   </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">deref</span><span class="w"> </span><span class="n">vs</span><span class="p">))))]</span><span class="w">
     </span><span class="p">(</span><span class="nf">step</span><span class="w"> </span><span class="n">rets</span><span class="w"> </span><span class="p">(</span><span class="nb">drop</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="n">rets</span><span class="p">))))</span><span class="w">
  </span><span class="p">([</span><span class="n">f</span><span class="w"> </span><span class="n">coll</span><span class="w"> </span><span class="o">&amp;</span><span class="w"> </span><span class="n">colls</span><span class="p">]</span><span class="w">
   </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">step</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">step</span><span class="w"> </span><span class="p">[</span><span class="n">cs</span><span class="p">]</span><span class="w">
                </span><span class="p">(</span><span class="nf">lazy-seq</span><span class="w">
                 </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">ss</span><span class="w"> </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">seq</span><span class="w"> </span><span class="n">cs</span><span class="p">)]</span><span class="w">
                   </span><span class="p">(</span><span class="nb">when</span><span class="w"> </span><span class="p">(</span><span class="nb">every?</span><span class="w"> </span><span class="nb">identity</span><span class="w"> </span><span class="n">ss</span><span class="p">)</span><span class="w">
                     </span><span class="p">(</span><span class="nb">cons</span><span class="w"> </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">first</span><span class="w"> </span><span class="n">ss</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nf">step</span><span class="w"> </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">rest</span><span class="w"> </span><span class="n">ss</span><span class="p">)))))))]</span><span class="w">
     </span><span class="p">(</span><span class="nf">pmap</span><span class="w"> </span><span class="o">#</span><span class="p">(</span><span class="nb">apply</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="n">%</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nf">step</span><span class="w"> </span><span class="p">(</span><span class="nb">cons</span><span class="w"> </span><span class="n">coll</span><span class="w"> </span><span class="n">colls</span><span class="p">))))))</span><span class="w">
</span></code></pre></div></div>
<p>It also has a few friends</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">pcalls</span><span class="w">
  </span><span class="s">"Executes the no-arg fns in parallel, returning a lazy sequence of
  their values"</span><span class="w">
  </span><span class="p">{</span><span class="no">:added</span><span class="w"> </span><span class="s">"1.0"</span><span class="w">
   </span><span class="no">:static</span><span class="w"> </span><span class="n">true</span><span class="p">}</span><span class="w">
  </span><span class="p">[</span><span class="o">&amp;</span><span class="w"> </span><span class="n">fns</span><span class="p">]</span><span class="w"> </span><span class="p">(</span><span class="nf">pmap</span><span class="w"> </span><span class="o">#</span><span class="p">(</span><span class="nf">%</span><span class="p">)</span><span class="w"> </span><span class="n">fns</span><span class="p">))</span><span class="w">

</span><span class="nb">&gt;</span><span class="w"> </span><span class="p">(</span><span class="nf">pcalls</span><span class="w"> </span><span class="n">function-1</span><span class="w"> </span><span class="n">function-2</span><span class="w"> </span><span class="n">...</span><span class="p">)</span><span class="w">

</span><span class="p">(</span><span class="k">defmacro</span><span class="w"> </span><span class="n">pvalues</span><span class="w">
  </span><span class="s">"Returns a lazy sequence of the values of the exprs, which are
  evaluated in parallel"</span><span class="w">
  </span><span class="p">{</span><span class="no">:added</span><span class="w"> </span><span class="s">"1.0"</span><span class="w">
   </span><span class="no">:static</span><span class="w"> </span><span class="n">true</span><span class="p">}</span><span class="w">
  </span><span class="p">[</span><span class="o">&amp;</span><span class="w"> </span><span class="n">exprs</span><span class="p">]</span><span class="w">
  </span><span class="o">`</span><span class="p">(</span><span class="nf">pcalls</span><span class="w"> </span><span class="o">~@</span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="o">#</span><span class="p">(</span><span class="nb">list</span><span class="w"> </span><span class="o">`</span><span class="k">fn</span><span class="w"> </span><span class="p">[]</span><span class="w"> </span><span class="n">%</span><span class="p">)</span><span class="w"> </span><span class="n">exprs</span><span class="p">)))</span><span class="w">

</span><span class="nb">&gt;</span><span class="w"> </span><span class="p">(</span><span class="nf">pvalues</span><span class="w"> </span><span class="p">(</span><span class="nf">expensive-calc-1</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nf">expensive-calc-2</span><span class="p">))</span><span class="w">
</span></code></pre></div></div>

<h2 id="waiting-for-futures">Waiting for futures</h2>
<p>You need to call <code class="language-plaintext highlighter-rouge">shutdown-agents</code> to exit when the agents/futures are done.</p>

<p>(taken from <a href="http://clojuredocs.org/clojure_core/clojure.core/future">clojuredocs</a> )</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>;; Note: If you leave out the call to (shutdown-agents), the program will on
;; most (all?) OS/JVM combinations "hang" for 1 minute before the process exits.
;; It is simply waiting for background threads, created by the future call, to
;; be shut down.  shutdown-agents will shut them down immediately, or
;; (System/exit &lt;exit-status&gt;) will exit immediately without waiting for them
;; to shut down.

;; This wait occurs even if you use futures indirectly through some other Clojure
;; functions that use them internally, such as pmap or clojure.java.shell/sh
</code></pre></div></div>

<h2 id="code">Code</h2>
<p>Just pushed the bits I was playing with up to <a href="https://github.com/thattommyhall/clojure-exchange">github</a></p>

<h2 id="next-time">Next time</h2>
<p>I hope that was interesting, I am going to stop for now as it has already taken 2 months to write this. I have already described CSP and core.async <a href="/2013/10/27/async-csp-resources/">here</a> and <a href="/2013/10/27/async-game-of-life/">here</a> so won’t cover that again but I will try and describe reducers (and why reduce is considered harmful) but to be honest you would probably be better just looking at my <a href="http://www.thattommyhall.com/clojurex2013/#53">references</a> from the talk (especially the Guy Steel talk)</p>]]></content><author><name>Tom Hall</name></author><category term="clojurescript,clojure" /><summary type="html"><![CDATA[I was pleased to be speaking at the Clojure Exchange recently (at least it was recently when I started writing this blog post). I suggested to Bruce that a talk on concurrency and parallelism would be good because since most of the books were published reducers and core.async have appeared giving us even more options in Clojure and we have a new runtime in Clojurescript (I also ranted that our books get it a bit wrong).]]></summary></entry><entry><title type="html">101 Goals Day 100 Update</title><link href="https://www.thattommyhall.com/2013/12/14/101-goals-day-100-update/" rel="alternate" type="text/html" title="101 Goals Day 100 Update" /><published>2013-12-14T23:46:00+02:00</published><updated>2013-12-14T23:46:00+02:00</updated><id>https://www.thattommyhall.com/2013/12/14/101-goals-day-100-update</id><content type="html" xml:base="https://www.thattommyhall.com/2013/12/14/101-goals-day-100-update/"><![CDATA[<p>In the middle of the year I set myself another <a href="/2013/07/11/101-goals-in-1001-days-ii/">101 Goals in 1001 days</a> and added into my calender reminders to do updates every 100 days (this was due October 19th actually)</p>

<h2 id="completed">Completed</h2>

<h3 id="4---read-beowulf">4 - Read Beowulf</h3>
<p>I finally read all of Seamus Heaney’s translation, shortly after he died.</p>

<audio controls=""><source src="http://www.wwnorton.com/college/english/nael/noa/mp3/audio_ma_01.mp3" /></audio>

<pre><code class="language-nohighlight">So. The Spear-Danes in days gone by
and the kings who ruled them had courage and greatness.
We have heard of those princes’ heroic campaigns.

There was Shield Sheafson, scourge of many tribes,
a wrecker of mead-benches, rampaging among foes.
This terror of the hall-troops had come far.
A foundling to start with, he would flourish later on
as his powers waxed and his worth was proved.
In the end each clan on the outlying coasts
beyond the whale-road had to yield to him
and begin to pay tribute.

Afterwards a boy-child was born to Shield,
a cub in the yard, a comfort sent
by God to that nation, He knew what they had tholed,
by long times and troubles they'd come through
without a leader; so the Lord of Life,
the glorious Almighty, made this man renowned.
Shield had fathered a famous son:
Beow's name was known through the north.
And a young prince must be prudent like that,
giving freely while his father lives
so that afterwards in age when fighting starts
steadfast companions will stand by him
and hold the line. Behaviour that's admired
is the path to power among people everywhere.

Shield was still thriving when his time came
and he crossed over into the Lord's keeping.
His warrior band did what he bade them
when he laid down the law among the Danes:
they shouldered him out to the sea's flood,
a chief they revered who had long ruled them.
A ring-whorled prow rode in the harbour,
ice clad, outbound, a craft for their prince.
They stretched their beloved lord in his boat,
laid out by the mast, amidships,
the great ring-giver. Far-fetched treasures
were piled upon him, and precious gear.
I have never heard before of a ship so well furbished
with battle tackle, bladed weapons
and coats of mail. The massed treasure
was loaded on top of him: it would travel far
on out into the ocean's sway.
They decked his body no less bountifully
with offerings than those first ones did
who cast him away when he was a child
and launched him alone out oer the waves.
And they set a gold standard up
high above his head and let him drift
to wind and tide, bewailing him
and mourning their loss. No man can tell,
no wise man in hall or weathered veteran
knows for certain who salvaged that load.
</code></pre>

<p>Goal 5 is to memorise the opening so I chose the above extract (not quite done it yet)</p>

<p>####The Fight With Grendel</p>

<audio controls=""><source src="http://www.wwnorton.com/college/english/nael/noa/mp3/audio_ma_01a.mp3" /></audio>

<p>####The Last Survivor’s Speech</p>
<audio controls=""><source src="http://www.wwnorton.com/college/english/nael/noa/mp3/audio_ma_01b.mp3" /></audio>

<p>####Beowulf’s Funeral</p>
<audio controls=""><source src="http://www.wwnorton.com/college/english/nael/noa/mp3/audio_ma_01c.mp3" /></audio>

<p>These and other Old English readings are available at <a href="http://www.wwnorton.com/college/english/nael/noa/audio.htm">The Norton Anthology Of English Literature</a></p>

<h4 id="heaneys-own-reading">Heaney’s own reading</h4>

<iframe width="560" height="315" src="//www.youtube.com/v/AaB0trCztM0&amp;autoplay=0" frameborder="0" allowfullscreen="">
</iframe>

<iframe width="560" height="315" src="//www.youtube.com/v/Zsxxg5P-DnY&amp;autoplay=0 " frameborder="0" allowfullscreen=""></iframe>

<p>His <a href="http://www.wwnorton.com/college/english/nael/beowulf/introbeowulf.htm">introduction</a> is also online.</p>

<h4 id="nobel-lecture">Nobel Lecture</h4>
<iframe width="420" height="315" src="//www.youtube.com/v/P7KzfqtL5qY&amp;autoplay=0" frameborder="0" allowfullscreen=""></iframe>

<h4 id="dramatic-reading-of-the-original">Dramatic reading of the original</h4>
<iframe width="420" height="315" src="//www.youtube.com/v/Y13cES7MMd8&amp;autoplay=0" frameborder="0" allowfullscreen=""></iframe>

<h3 id="58--swim-100m">58 -Swim 100m</h3>
<p>Sounds easy but I have not really swam for 20 years, managed to remember to breath enough to do this while on holiday in Greece in July. Some more swimming goals to come.</p>

<h3 id="50---take-part-in-lisp-in-summer-projects">50 - Take part in Lisp In Summer Projects</h3>
<p>I wanted to do an alife sim using Genetic Programming, while the sim itself is a bit raw I blogged about <a href="/2013/08/23/genetic-programming-in-clojure-with-zippers/">Genetic Programming</a> and <a href="/2013/07/07/evolving-cellular-automata-the-code/">Cellular Automata</a> work I did along the way. I loved the ‘hack month’ style of the contest, giving longer than the typical weekend to comeplete it.</p>

<h3 id="44---go-ai-with-monte-carlo-tree-search">44 - Go AI with Monte Carlo Tree Search</h3>
<p>For the Clojure Cup, <a href="http://scattered-thoughts.net/about.html">Jamie</a> and I did one in the browser in Clojurescript. I am afraid I leaned on him quite a bit as I had to disappear and do the Shine London nighttime walking marathon. He <a href="http://scattered-thoughts.net/blog/2013/10/06/hugo-a-go-go/">bloged about it</a> and later <a href="http://scattered-thoughts.net/blog/2013/11/24/hugo-a-go-go-optimisation/">some optimisations</a>.</p>

<p>I don’t think I am done with MCTS as it seems to be used in <a href="http://ccg.doc.gold.ac.uk/index.html">Computational Creativity</a> and is in Coursera’s <a href="https://www.coursera.org/course/ggp">General Game Playing</a> course.</p>

<h3 id="45---start-using-paredit">45 - Start using Paredit</h3>
<p>Trivial really but I just needed to sit down and do it at some point. Long overdue and if you paren and dont use it, you should, it’s <a href="http://www.youtube.com/watch?v=D6h5dFyyUX0">awesome</a></p>

<h3 id="40---seasoned-schemer">40 - Seasoned Schemer</h3>

<p>Great book, I just wish I came to it sooner as not much was new to me.</p>

<p><a href="http://www.amazon.co.uk/gp/product/026256100X?ie=UTF8&amp;camp=3194&amp;creative=21330&amp;creativeASIN=026256100X&amp;linkCode=shr&amp;tag=tomsblog-21">&lt;img src=”/images/The_Seasoned_Schemer.jpg&gt;</a></p>

<h2 id="in-progress">In Progress</h2>

<h3 id="43---build-a-robot">43 - Build a robot</h3>
<p>I decided to make my Raspberry Pi the brain of a car.
I did a bit of research and found I needed to get a <a href="https://github.com/simonmonk/raspirobotboard/wiki">RasPiRobot</a> to drive motors so I got one and did my first bit of soldering in years. Simon Monks <a href="http://www.amazon.co.uk/gp/product/0071807837?ie=UTF8&amp;camp=3194&amp;creative=21330&amp;creativeASIN=0071807837&amp;linkCode=shr&amp;tag=tomsblog-21&amp;qid=1387111063&amp;sr=8-3&amp;keywords=simon+monk">book</a> is excellent and describes pretty well how to build a robot with the Magician Chassis</p>

<p>&lt;img src=”/images/post/magician.jpg&gt;</p>

<p>Get it from <a href="http://proto-pic.co.uk/magician-chassis/">Proto-pic</a> in the UK.</p>

<p>I actually went for a <a href="http://www.hobbytronics.co.uk/robotics/4wd-chassis-kit">4WD Chassis</a></p>

<p>&lt;img src=”/images/post/4wd.jpg&gt;</p>

<p>&lt;img src=”/images/post/car1.jpg&gt;</p>

<p>&lt;img src=”/images/post/car2.jpg&gt;</p>

<p>&lt;img src=”/images/post/car3.jpg&gt;</p>

<p>I went to <a href="http://www.meetup.com/NodeBots-of-London/">NodeBots of London</a> and it was an amazing day, the venue and the people were great. I arrived late so only had time to do the soldering of the RasPiRobot but did later get it hooked up to the Pi. I was lucky I bought both kits as the battery thing from the 4WD does not work with the RasPiRobot so I had to use the magician one.</p>

<p>Last week I joined the <a href="https://london.hackspace.org.uk/">London Hackspace</a> so should get this finished and be up to more roboty stuff in future.</p>

<h3 id="39---finish-4clojure">39 - Finish 4clojure</h3>
<p>I think Christmas 2011 I did my first ‘hard’ problem after getting bored of the easy ones, took me an entire day to do it. I did it intermittently in 2012 and had ~30 left coming up to Christmas, I got it to 25 by December 1st so I could do it as an advent calender and got down to (I think) 6 left by the new year. Some have since been added and I had another push last month so I am down to 2 and have finally caught up with <a href="http://www.4clojure.com/user/jsmith145">Jen</a> (who had completed them all until the recent additions). I think this Christmas it’s getting done at last!!!</p>

<h3 id="57---quarterly-wild-swim">57 - Quarterly Wild Swim</h3>
<p>I swam in the sea in Greece, bit scary after having only just swam again for first time in ages</p>

<h3 id="5---memorise-beowulf-opening">5 - Memorise Beowulf Opening</h3>
<p>As discussed above</p>

<h3 id="28---watch-all-teaching-company-linguistics-courses">28 - Watch all Teaching Company linguistics courses</h3>
<p>Looking at the <a href="http://www.thegreatcourses.com/tgc/courses/courses.aspx?s=811&amp;ps=905">list</a> there are even more than when I decided to do this.
I am half way through <a href="http://www.thegreatcourses.com/tgc/courses/course_detail.aspx?cid=2270">Understanding Linguistics: The Science of Language</a>, it is superb and I am very happy to see John McWhorter has 2 more new courses available.</p>

<h3 id="27---read-a-students-introduction-to-english-grammar">27 - Read “A Student’s Introduction To English Grammar”</h3>
<p>I did start this but abandoned it as I was too tired to really take it in (a common feeling for me this year)</p>

<h3 id="29---finish-10-online-courses">29 - Finish 10 Online Courses</h3>
<p>Well I did lots of Coursera’s <a href="https://www.coursera.org/course/intrologic">Logic</a> one, all of the <a href="https://class.coursera.org/algo-004/class">Algorithms</a> one most of the EdX <a href="https://www.edx.org/course/uc-berkeleyx/uc-berkeleyx-cs-191x-quantum-mechanics-1033">Quantum Computation</a> one and all of their <a href="https://www.edx.org/course/uc-berkeleyx/uc-berkeleyx-cs188-1x-artificial-579">AI</a> one. Both the EdX courses were <em>excellent</em></p>

<p>I have pretty much come to the conclusion that till I have more time I just cannot keep up with their artificial deadlines so have taken to watching them at my own pace. I don’t get much value from the ‘massiveness’ of MOOCs (typically ‘there is a forum over there and deadlines every week’) and lots of them I would learn more just spending my time reading as the videos are not particularly good. I do think it is worth finding the real gems though.</p>

<h3 id="42---artificial-intellegence---a-modern-approach-in-clojure">42 - ‘Artificial Intellegence - A Modern Approach’ in Clojure</h3>
<p>I <a href="https://github.com/thattommyhall/aima-clojure">started this</a> a year ago, translating the Python and Common Lisp code examples into Clojure. I think having done the AI course I now know a lot more of the content of the book so I should revisit it soon.</p>

<h3 id="17---100-pressups">17 - 100 Pressups</h3>
<p>As I could not do one after breaking both my elbows I am pleased I can now do 20</p>

<h2 id="planning">Planning</h2>

<h3 id="65---play-harmonica">65 - Play Harmonica</h3>
<p>Well, I say ‘planning’ - my sister bought me one at least ;-)</p>

<h3 id="81---multi-day-canoe-trip">81 - Multi-day Canoe Trip</h3>
<p>Keeping it simple for a first trip I will probably do the <a href="http://greatglencanoetrail.info/useful-services/paddling-activity-providers1/hire1/">Great Glen Canoe Trail</a> next year.</p>

<h3 id="31---learn-to-dance">31 - Learn to dance</h3>
<p>I got Petra and I swing lessons for her birthday, if my ankle is up for it that’s happening in Jan</p>

<h2 id="changing">Changing</h2>
<p>I am swapping a few goals, I have been doing kettlebell training lately so am swapping a few goals from Olympic lift ones.</p>

<h3 id="14---squat-150kg---snatch-2x32kg-bells-simultaneously">14 - Squat 150kg -&gt; Snatch 2x32kg Bells (simultaneously)</h3>

<h3 id="16---press-150kg---snatch-24kg-200-times-in-10-mins">16 - Press 150kg -&gt; Snatch 24kg 200 times in 10 mins</h3>

<h3 id="15---deadlift-150kg---farmers-carry-60kg-each-arm">15 - Deadlift 150kg -&gt; Farmers Carry 60kg each arm</h3>

<h1 id="whats-next">What’s next?</h1>
<p>Take a look at <a href="/2013/07/11/101-goals-in-1001-days-ii/">the full list</a>, if you fancy any let me know.</p>]]></content><author><name>Tom Hall</name></author><category term="101v2,life" /><summary type="html"><![CDATA[In the middle of the year I set myself another 101 Goals in 1001 days and added into my calender reminders to do updates every 100 days (this was due October 19th actually)]]></summary></entry><entry><title type="html">Hackercup 2014 - Qualifier</title><link href="https://www.thattommyhall.com/2013/11/25/facebook-hackercup-2014-1/" rel="alternate" type="text/html" title="Hackercup 2014 - Qualifier" /><published>2013-11-25T21:30:00+02:00</published><updated>2013-11-25T21:30:00+02:00</updated><id>https://www.thattommyhall.com/2013/11/25/facebook-hackercup-2014-1</id><content type="html" xml:base="https://www.thattommyhall.com/2013/11/25/facebook-hackercup-2014-1/"><![CDATA[<p>I had some fun doing it
<a href="/2013/02/04/facebook-hacker-cup-2013/">last year</a> so I thought I
would have a go again. This weekend was the qualifier. You can see the
questions
<a href="https://www.facebook.com/hackercup/problems.php?pid=318555664954399&amp;round=598486203541358">here</a></p>

<h3 id="square-detector">Square Detector</h3>

<pre><code class="language-nohighlight">You want to write an image detection system that is able to
recognise different geometric shapes. In the first version of the
system you settled with just being able to detect filled squares on a
grid. You are given a grid of N×N square cells. Each cell is either
white or black.  Your task is to detect whether all the black cells
form a square shape.

  ..##
  ..##
  ....
  ....    =&gt; TRUE

  ..##
  ..##
  #...
  ....    =&gt; FALSE

</code></pre>

<p>We basically find the bottom leftmost and top rightmost black cell and check that the count of black cells is the same as the area of the square they describe</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">square?</span><span class="w"> </span><span class="p">[</span><span class="n">s</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">size</span><span class="w"> </span><span class="p">(</span><span class="nb">count</span><span class="w"> </span><span class="n">s</span><span class="p">)</span><span class="w">
        </span><span class="n">black-cells</span><span class="w"> </span><span class="p">(</span><span class="k">for</span><span class="w"> </span><span class="p">[</span><span class="n">y</span><span class="w"> </span><span class="p">(</span><span class="nb">range</span><span class="w"> </span><span class="n">size</span><span class="p">)</span><span class="w">
                     </span><span class="n">x</span><span class="w"> </span><span class="p">(</span><span class="nb">range</span><span class="w"> </span><span class="n">size</span><span class="p">)</span><span class="w">
                     </span><span class="no">:when</span><span class="w">  </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="sc">\#</span><span class="w"> </span><span class="p">(</span><span class="nb">nth</span><span class="w"> </span><span class="p">(</span><span class="nb">nth</span><span class="w"> </span><span class="n">s</span><span class="w"> </span><span class="n">y</span><span class="p">)</span><span class="w">
                                       </span><span class="n">x</span><span class="p">))]</span><span class="w">
                 </span><span class="p">[</span><span class="n">y</span><span class="w"> </span><span class="n">x</span><span class="p">])</span><span class="w">
        </span><span class="n">ys</span><span class="w"> </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">first</span><span class="w"> </span><span class="n">black-cells</span><span class="p">)</span><span class="w">
        </span><span class="n">xs</span><span class="w"> </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">second</span><span class="w"> </span><span class="n">black-cells</span><span class="p">)</span><span class="w">
        </span><span class="n">x-min</span><span class="w"> </span><span class="p">(</span><span class="nb">apply</span><span class="w"> </span><span class="nb">min</span><span class="w"> </span><span class="n">xs</span><span class="p">)</span><span class="w">
        </span><span class="n">x-max</span><span class="w"> </span><span class="p">(</span><span class="nb">apply</span><span class="w"> </span><span class="nb">max</span><span class="w"> </span><span class="n">xs</span><span class="p">)</span><span class="w">
        </span><span class="n">y-min</span><span class="w"> </span><span class="p">(</span><span class="nb">apply</span><span class="w"> </span><span class="nb">min</span><span class="w"> </span><span class="n">ys</span><span class="p">)</span><span class="w">
        </span><span class="n">y-max</span><span class="w"> </span><span class="p">(</span><span class="nb">apply</span><span class="w"> </span><span class="nb">max</span><span class="w"> </span><span class="n">ys</span><span class="p">)</span><span class="w">
        </span><span class="n">y-edge</span><span class="w"> </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="n">y-max</span><span class="w"> </span><span class="p">(</span><span class="nb">dec</span><span class="w"> </span><span class="n">y-min</span><span class="p">))</span><span class="w">
        </span><span class="n">x-edge</span><span class="w"> </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="n">x-max</span><span class="w"> </span><span class="p">(</span><span class="nb">dec</span><span class="w"> </span><span class="n">x-min</span><span class="p">))</span><span class="w">
        </span><span class="n">square-size</span><span class="w"> </span><span class="p">(</span><span class="nb">*</span><span class="w"> </span><span class="n">y-edge</span><span class="w"> </span><span class="n">x-edge</span><span class="p">)]</span><span class="w">
    </span><span class="p">(</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nb">and</span><span class="w"> </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="n">x-edge</span><span class="w"> </span><span class="n">y-edge</span><span class="p">)</span><span class="w">
             </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="p">(</span><span class="nb">count</span><span class="w"> </span><span class="n">black-cells</span><span class="p">)</span><span class="w"> </span><span class="n">square-size</span><span class="p">))</span><span class="w">
      </span><span class="s">"YES"</span><span class="w">
      </span><span class="s">"NO"</span><span class="p">)))</span><span class="w">
</span></code></pre></div></div>

<p>If the input was bigger then I would have found min/max in a single reduce but I like the clarity here and naming things is good right?</p>

<h3 id="basketball-game">Basketball Game</h3>

<pre><code class="language-nohighlight">A group of N high school students wants to play a basketball game.
To divide themselves into two teams they first rank all the players in the
following way:

Players with a higher shot percentage are rated higher than players with a lower
shot percentage.
If two players have the same shot percentage, the taller player is rated higher.
Luckily there are no two players with both the same shot percentage and height
so they are able to order themselves in an unambiguous way. Based on that
ordering each player is assigned a draft number from the range [1..N], where the
highest-rated player gets the number 1, the second highest-rated gets the number
2, and so on. Now the first team contains all the players with the odd draft
numbers and the second team all the players with the even draft numbers.

Each team can only have P players playing at a time, so to ensure that everyone
gets similar time on the court both teams will rotate their players according to
the following algorithm:

Each team starts the game with the P players who have the lowest draft numbers.
If there are more than P players on a team after each minute of the game the
player with the highest total time played leaves the playing field. Ties are
broken by the player with the higher draft number leaving first.
To replace her the player on the bench with the lowest total time played joins
the game. Ties are broken by the player with the lower draft number entering
first.
The game has been going on for M minutes now. Your task is to print out the
names of all the players currently on the field, (that is after M rotations).

Eg:
M = 3
P = 2
Wai 99 131
Weiyan 81 155
Lin 80 100
Purav 86 198
Slawek 80 192
Meihong 44 109

Sort all the players by their shot percentage you
get the list: [Wai, Purav, Weiyan, Slawek, Lin, Meihong]. This makes the two
teams:
[Wai, Weiyan, Lin]
[Purav, Slawek, Meihong]
The game starts with Lin and Meihong sitting on the bench in their respective
teams. After the first minute passes it's time for Weiyan and Slawek to sit out
since they have the highest draft numbers of the people who played. After the
second minute passes Lin and Meihong will keep playing since they only played
one minute so far and it's Wai and Purav who have to sit out.

Finally after the third minute Lin and Maihong go back to the bench and all the
players currently playing again are:
Purav Slawek Wai Weiyan
</code></pre>

<p>Here we sort the players according to the rule, get the two teams using take-nth starting at the first or second.
The order the players come onto the pitch is a bit tricky, the ones with lowest draft numbers are on first but then they leave in order of highest first then the people on the bench come on lowest first, so the list of players in the order they come on the pitch is <code class="language-plaintext highlighter-rouge">(concat (reverse (take p team)) (drop p team))</code> which we cycle so it’s infinite then use <code class="language-plaintext highlighter-rouge">(partition p 1 cycled-team-list)</code> to get a sliding window of P players moving up in ones. A speedup I did not do would have been using modular arithmetic for large m (both cycles repeat in the team size so we could replace m with their LCM rather then taking the mth of the infinite list directly)</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">compare-players</span><span class="w">
  </span><span class="p">[[</span><span class="nb">name</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="n">height</span><span class="p">]</span><span class="w"> </span><span class="p">[</span><span class="nb">name</span><span class="o">'</span><span class="w"> </span><span class="n">p</span><span class="o">'</span><span class="w"> </span><span class="n">height</span><span class="o">'</span><span class="p">]]</span><span class="w">
  </span><span class="p">(</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="n">p</span><span class="o">'</span><span class="p">)</span><span class="w">
    </span><span class="p">(</span><span class="nb">&gt;</span><span class="w"> </span><span class="n">height</span><span class="w"> </span><span class="n">height</span><span class="o">'</span><span class="p">)</span><span class="w">
    </span><span class="p">(</span><span class="nb">&gt;</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="n">p</span><span class="o">'</span><span class="p">)))</span><span class="w">

</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">sort-players</span><span class="w"> </span><span class="p">[</span><span class="n">players</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="nb">first</span><span class="w">
       </span><span class="p">(</span><span class="nb">apply</span><span class="w"> </span><span class="n">sorted-set-by</span><span class="w">
              </span><span class="n">compare-players</span><span class="w">
              </span><span class="n">players</span><span class="p">)))</span><span class="w">

</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">f</span><span class="w"> </span><span class="p">[[</span><span class="n">m</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="n">players</span><span class="p">]]</span><span class="w">
  </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">players</span><span class="w"> </span><span class="p">(</span><span class="nf">sort-players</span><span class="w"> </span><span class="p">(</span><span class="nb">map</span><span class="w"> </span><span class="n">parse-player</span><span class="w"> </span><span class="n">players</span><span class="p">))</span><span class="w">
        </span><span class="n">team1</span><span class="w"> </span><span class="p">(</span><span class="nb">take-nth</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="n">players</span><span class="p">)</span><span class="w">
        </span><span class="n">team2</span><span class="w"> </span><span class="p">(</span><span class="nb">take-nth</span><span class="w"> </span><span class="mi">2</span><span class="w"> </span><span class="p">(</span><span class="nb">rest</span><span class="w"> </span><span class="n">players</span><span class="p">))</span><span class="w">
        </span><span class="n">mth</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="n">team</span><span class="p">]</span><span class="w">
              </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">team-size</span><span class="w"> </span><span class="p">(</span><span class="nb">count</span><span class="w"> </span><span class="n">team</span><span class="p">)</span><span class="w">
                    </span><span class="n">cycled-team-list</span><span class="w"> </span><span class="p">(</span><span class="nb">cycle</span><span class="w"> </span><span class="p">(</span><span class="nb">concat</span><span class="w"> </span><span class="p">(</span><span class="nb">reverse</span><span class="w"> </span><span class="p">(</span><span class="nb">take</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="n">team</span><span class="p">))</span><span class="w">
                                                    </span><span class="p">(</span><span class="nb">drop</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="n">team</span><span class="p">)))]</span><span class="w">
                </span><span class="p">(</span><span class="nb">nth</span><span class="w"> </span><span class="p">(</span><span class="nf">partition</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">cycled-team-list</span><span class="p">)</span><span class="w"> </span><span class="n">m</span><span class="p">)))]</span><span class="w">
    </span><span class="p">(</span><span class="nf">str/join</span><span class="w"> </span><span class="s">" "</span><span class="w"> </span><span class="p">(</span><span class="nb">sort</span><span class="w"> </span><span class="p">(</span><span class="nb">concat</span><span class="w"> </span><span class="p">(</span><span class="nf">mth</span><span class="w"> </span><span class="n">team1</span><span class="p">)</span><span class="w">
                                </span><span class="p">(</span><span class="nf">mth</span><span class="w"> </span><span class="n">team2</span><span class="p">))))))</span><span class="w">
</span></code></pre></div></div>

<h3 id="tennison">Tennison</h3>

<pre><code class="language-nohighlight">You may be familiar with the works of Alfred Lord Tennyson, the famous English
poet. In this problem we will concern ourselves with Tennison, the less famous
English tennis player. As you know, tennis is not so much a game of skill as
a game of luck and weather patterns. The goal of tennis is to win K sets before
the other player. However, the chance of winning a set is largely dependent on
whether or not there is weather.

Tennison plays best when it's sunny, but sometimes of course, it rains. Tennison
wins a set with probability ps when it's sunny, and with probability pr when it's
raining. The chance that there will be sun for the first set is pi. Luckily for
Tennison, whenever he wins a set, the probability that there will be sun increases
by pu with probability pw. Unfortunately, when Tennison loses a set, the probability
of sun decreases by pd with probability pl. What is the chance that Tennison will
be successful in his match?

Rain and sun are the only weather conditions, so P(rain) = 1 - P(sun) at all
times. Also, probabilities always stay in the range [0, 1]. If P(sun) would ever
be less than 0, it is instead 0. If it would ever be greater than 1, it is instead 1.
</code></pre>

<p>I did not get this one right, I thought the tree was too big to actually sum all of the different ways Tennison can win so tried a Monte Carlo approach which works but is too slow to converge on the precision required.</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">normalise</span><span class="w"> </span><span class="p">[</span><span class="n">p</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">cond</span><span class="w"> </span><span class="p">(</span><span class="nb">&lt;</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="mf">0.0</span><span class="p">)</span><span class="w">
        </span><span class="mf">0.0</span><span class="w">
        </span><span class="p">(</span><span class="nb">&gt;</span><span class="w"> </span><span class="n">p</span><span class="w"> </span><span class="mf">1.0</span><span class="p">)</span><span class="w">
        </span><span class="mf">1.0</span><span class="w">
        </span><span class="no">:else</span><span class="w">
        </span><span class="n">p</span><span class="p">))</span><span class="w">

</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">sim</span><span class="w">
  </span><span class="p">([</span><span class="n">k</span><span class="w"> </span><span class="n">ps</span><span class="w"> </span><span class="nb">pr</span><span class="w"> </span><span class="n">pi</span><span class="w"> </span><span class="n">pu</span><span class="w"> </span><span class="n">pw</span><span class="w"> </span><span class="n">pd</span><span class="w"> </span><span class="n">pl</span><span class="p">]</span><span class="w">
     </span><span class="p">(</span><span class="nf">sim</span><span class="w"> </span><span class="p">(</span><span class="nb">int</span><span class="w"> </span><span class="n">k</span><span class="p">)</span><span class="w"> </span><span class="n">ps</span><span class="w"> </span><span class="nb">pr</span><span class="w"> </span><span class="n">pi</span><span class="w"> </span><span class="n">pu</span><span class="w"> </span><span class="n">pw</span><span class="w"> </span><span class="n">pd</span><span class="w"> </span><span class="n">pl</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="mi">0</span><span class="p">))</span><span class="w">
  </span><span class="p">([</span><span class="n">k</span><span class="w"> </span><span class="n">ps</span><span class="w"> </span><span class="nb">pr</span><span class="w"> </span><span class="n">pi</span><span class="w"> </span><span class="n">pu</span><span class="w"> </span><span class="n">pw</span><span class="w"> </span><span class="n">pd</span><span class="w"> </span><span class="n">pl</span><span class="w"> </span><span class="n">wins</span><span class="w"> </span><span class="n">losses</span><span class="p">]</span><span class="w">
     </span><span class="p">(</span><span class="k">cond</span><span class="w"> </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="n">k</span><span class="w"> </span><span class="n">wins</span><span class="p">)</span><span class="w">
           </span><span class="mf">1.0</span><span class="w">

           </span><span class="p">(</span><span class="nb">=</span><span class="w"> </span><span class="n">k</span><span class="w"> </span><span class="n">losses</span><span class="p">)</span><span class="w">
           </span><span class="mf">0.0</span><span class="w">
           </span><span class="c1">;; ps sunny win</span><span class="w">
           </span><span class="c1">;; pr rain win</span><span class="w">
           </span><span class="c1">;; pi chance of sun</span><span class="w">
           </span><span class="c1">;; wins: +pu with prob pw</span><span class="w">
           </span><span class="c1">;; lose: -pd with prob pl</span><span class="w">

           </span><span class="no">:else</span><span class="w">
           </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">pwin</span><span class="w"> </span><span class="p">(</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="nb">&lt;</span><span class="w"> </span><span class="p">(</span><span class="nb">rand</span><span class="p">)</span><span class="w"> </span><span class="n">pi</span><span class="p">)</span><span class="w"> </span><span class="n">ps</span><span class="w"> </span><span class="nb">pr</span><span class="p">)</span><span class="w">
                 </span><span class="n">won?</span><span class="w"> </span><span class="p">(</span><span class="nb">&lt;</span><span class="w"> </span><span class="p">(</span><span class="nb">rand</span><span class="p">)</span><span class="w"> </span><span class="n">pwin</span><span class="p">)]</span><span class="w">
             </span><span class="p">(</span><span class="k">if</span><span class="w"> </span><span class="n">won?</span><span class="w">
               </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">increase?</span><span class="w"> </span><span class="p">(</span><span class="nb">&lt;</span><span class="w"> </span><span class="p">(</span><span class="nb">rand</span><span class="p">)</span><span class="w"> </span><span class="n">pw</span><span class="p">)</span><span class="w">
                     </span><span class="n">delta</span><span class="w"> </span><span class="p">(</span><span class="k">if</span><span class="w"> </span><span class="n">increase?</span><span class="w"> </span><span class="n">pu</span><span class="w"> </span><span class="mi">0</span><span class="p">)]</span><span class="w">
                 </span><span class="p">(</span><span class="nf">recur</span><span class="w"> </span><span class="n">k</span><span class="w"> </span><span class="n">ps</span><span class="w"> </span><span class="nb">pr</span><span class="w"> </span><span class="p">(</span><span class="nb">min</span><span class="w"> </span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="n">delta</span><span class="w"> </span><span class="n">pi</span><span class="p">)</span><span class="w"> </span><span class="mi">1</span><span class="p">)</span><span class="w"> </span><span class="n">pu</span><span class="w"> </span><span class="n">pw</span><span class="w"> </span><span class="n">pd</span><span class="w"> </span><span class="n">pl</span><span class="w"> </span><span class="p">(</span><span class="nb">inc</span><span class="w"> </span><span class="n">wins</span><span class="p">)</span><span class="w"> </span><span class="n">losses</span><span class="p">))</span><span class="w">
               </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">decrease?</span><span class="w"> </span><span class="p">(</span><span class="nb">&lt;</span><span class="w"> </span><span class="p">(</span><span class="nb">rand</span><span class="p">)</span><span class="w"> </span><span class="n">pl</span><span class="p">)</span><span class="w">
                     </span><span class="n">delta</span><span class="w"> </span><span class="p">(</span><span class="k">if</span><span class="w"> </span><span class="n">decrease?</span><span class="w"> </span><span class="n">pd</span><span class="w"> </span><span class="mi">0</span><span class="p">)]</span><span class="w">
                 </span><span class="p">(</span><span class="nf">recur</span><span class="w"> </span><span class="n">k</span><span class="w"> </span><span class="n">ps</span><span class="w"> </span><span class="nb">pr</span><span class="w"> </span><span class="p">(</span><span class="nb">max</span><span class="w"> </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="n">pi</span><span class="w"> </span><span class="n">delta</span><span class="p">)</span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="n">pu</span><span class="w"> </span><span class="n">pw</span><span class="w"> </span><span class="n">pd</span><span class="w"> </span><span class="n">pl</span><span class="w"> </span><span class="n">wins</span><span class="w"> </span><span class="p">(</span><span class="nb">inc</span><span class="w"> </span><span class="n">losses</span><span class="p">))))))))</span><span class="w">

</span><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">win-probability</span><span class="w"> </span><span class="p">[</span><span class="o">&amp;</span><span class="w"> </span><span class="n">args</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="w"> </span><span class="mi">1000000</span><span class="w">
        </span><span class="n">won</span><span class="w"> </span><span class="p">(</span><span class="nb">reduce</span><span class="w"> </span><span class="nb">+</span><span class="w">
                    </span><span class="p">(</span><span class="nf">pmap</span><span class="w"> </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="p">[</span><span class="n">n</span><span class="p">]</span><span class="w">
                            </span><span class="p">(</span><span class="nb">apply</span><span class="w"> </span><span class="n">sim</span><span class="w"> </span><span class="n">args</span><span class="p">))</span><span class="w">
                          </span><span class="p">(</span><span class="nb">range</span><span class="w"> </span><span class="n">n</span><span class="p">)))]</span><span class="w">
    </span><span class="p">(</span><span class="nb">/</span><span class="w"> </span><span class="n">won</span><span class="w"> </span><span class="n">n</span><span class="p">)))</span><span class="w">

</span></code></pre></div></div>

<p>After looking at <a href="http://www.facebook.com/notes/facebook-hacker-cup/2014-qualification-round-solutions/775180192497884">the solutions</a> they suggest a nice dynamic programming approach, but still they do calculate every way tennison can win, here is a clojure version that I think is still a bit slow on the input. I could not find a way to use the <code class="language-plaintext highlighter-rouge">memoize</code> function for the recursive function.</p>

<div class="language-clojure highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">(</span><span class="k">defn</span><span class="w"> </span><span class="n">win-probability2</span><span class="w"> </span><span class="p">[</span><span class="n">k</span><span class="w"> </span><span class="n">ps</span><span class="w"> </span><span class="nb">pr</span><span class="w"> </span><span class="n">pi</span><span class="w"> </span><span class="n">pu</span><span class="w"> </span><span class="n">pw</span><span class="w"> </span><span class="n">pd</span><span class="w"> </span><span class="n">pl</span><span class="p">]</span><span class="w">
  </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">lookup</span><span class="w"> </span><span class="p">(</span><span class="nf">atom</span><span class="w"> </span><span class="p">{})</span><span class="w">
        </span><span class="n">F</span><span class="w">
        </span><span class="p">(</span><span class="k">fn</span><span class="w"> </span><span class="n">F</span><span class="w">  </span><span class="p">[</span><span class="n">w</span><span class="w"> </span><span class="n">l</span><span class="w"> </span><span class="n">p</span><span class="p">]</span><span class="w">
          </span><span class="p">(</span><span class="k">cond</span><span class="w"> </span><span class="p">(</span><span class="nb">==</span><span class="w"> </span><span class="n">w</span><span class="w"> </span><span class="n">k</span><span class="p">)</span><span class="w">
                </span><span class="mi">1</span><span class="w">
                </span><span class="p">(</span><span class="nb">==</span><span class="w"> </span><span class="n">l</span><span class="w"> </span><span class="n">k</span><span class="p">)</span><span class="w">
                </span><span class="mi">0</span><span class="w">
                </span><span class="no">:else</span><span class="w">
                </span><span class="p">(</span><span class="nb">if-let</span><span class="w"> </span><span class="p">[</span><span class="n">cached</span><span class="w"> </span><span class="p">(</span><span class="o">@</span><span class="n">lookup</span><span class="w"> </span><span class="p">[</span><span class="n">w</span><span class="w"> </span><span class="n">l</span><span class="w"> </span><span class="n">p</span><span class="p">])]</span><span class="w">
                  </span><span class="n">cached</span><span class="w">
                  </span><span class="p">(</span><span class="k">let</span><span class="w"> </span><span class="p">[</span><span class="n">answer</span><span class="w">
                        </span><span class="p">(</span><span class="nb">+</span><span class="w">
                         </span><span class="p">(</span><span class="nb">*</span><span class="w"> </span><span class="p">(</span><span class="nf">normalise</span><span class="w"> </span><span class="n">p</span><span class="p">)</span><span class="w"> </span><span class="n">ps</span><span class="w"> </span><span class="n">pw</span><span class="w"> </span><span class="p">(</span><span class="nf">F</span><span class="w"> </span><span class="p">(</span><span class="nb">inc</span><span class="w"> </span><span class="n">w</span><span class="p">)</span><span class="w"> </span><span class="n">l</span><span class="w"> </span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="p">(</span><span class="nf">normalise</span><span class="w"> </span><span class="n">p</span><span class="p">)</span><span class="w"> </span><span class="n">pu</span><span class="p">)))</span><span class="w">
                         </span><span class="p">(</span><span class="nb">*</span><span class="w"> </span><span class="p">(</span><span class="nf">normalise</span><span class="w"> </span><span class="n">p</span><span class="p">)</span><span class="w"> </span><span class="n">ps</span><span class="w"> </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">pw</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nf">F</span><span class="w"> </span><span class="p">(</span><span class="nb">inc</span><span class="w"> </span><span class="n">w</span><span class="p">)</span><span class="w"> </span><span class="n">l</span><span class="w"> </span><span class="p">(</span><span class="nf">normalise</span><span class="w"> </span><span class="n">p</span><span class="p">)))</span><span class="w">
                         </span><span class="p">(</span><span class="nb">*</span><span class="w">  </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">ps</span><span class="p">)</span><span class="w"> </span><span class="n">pl</span><span class="w"> </span><span class="p">(</span><span class="nf">F</span><span class="w"> </span><span class="n">w</span><span class="w"> </span><span class="p">(</span><span class="nb">inc</span><span class="w"> </span><span class="n">l</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="p">(</span><span class="nf">normalise</span><span class="w"> </span><span class="n">p</span><span class="p">)</span><span class="w"> </span><span class="n">pd</span><span class="p">)))</span><span class="w">
                         </span><span class="p">(</span><span class="nb">*</span><span class="w"> </span><span class="p">(</span><span class="nf">normalise</span><span class="w"> </span><span class="n">p</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">ps</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">pl</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nf">F</span><span class="w"> </span><span class="n">w</span><span class="w"> </span><span class="p">(</span><span class="nb">inc</span><span class="w"> </span><span class="n">l</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="p">(</span><span class="nf">normalise</span><span class="w"> </span><span class="n">p</span><span class="p">)</span><span class="w"> </span><span class="n">pu</span><span class="p">)))</span><span class="w">
                         </span><span class="p">(</span><span class="nb">*</span><span class="w"> </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">(</span><span class="nf">normalise</span><span class="w"> </span><span class="n">p</span><span class="p">))</span><span class="w"> </span><span class="nb">pr</span><span class="w"> </span><span class="n">pw</span><span class="w"> </span><span class="p">(</span><span class="nf">F</span><span class="w"> </span><span class="p">(</span><span class="nb">inc</span><span class="w"> </span><span class="n">w</span><span class="p">)</span><span class="w"> </span><span class="n">l</span><span class="w"> </span><span class="p">(</span><span class="nb">+</span><span class="w"> </span><span class="p">(</span><span class="nf">normalise</span><span class="w"> </span><span class="n">p</span><span class="p">)</span><span class="w"> </span><span class="n">pu</span><span class="p">)))</span><span class="w">
                         </span><span class="p">(</span><span class="nb">*</span><span class="w"> </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">(</span><span class="nf">normalise</span><span class="w"> </span><span class="n">p</span><span class="p">))</span><span class="w"> </span><span class="nb">pr</span><span class="w"> </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">pw</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nf">F</span><span class="w"> </span><span class="p">(</span><span class="nb">inc</span><span class="w"> </span><span class="n">w</span><span class="p">)</span><span class="w"> </span><span class="n">l</span><span class="w"> </span><span class="p">(</span><span class="nf">normalise</span><span class="w"> </span><span class="n">p</span><span class="p">)))</span><span class="w">
                         </span><span class="p">(</span><span class="nb">*</span><span class="w"> </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">(</span><span class="nf">normalise</span><span class="w"> </span><span class="n">p</span><span class="p">))</span><span class="w"> </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="nb">pr</span><span class="p">)</span><span class="w"> </span><span class="n">pl</span><span class="w"> </span><span class="p">(</span><span class="nf">F</span><span class="w"> </span><span class="n">w</span><span class="w"> </span><span class="p">(</span><span class="nb">inc</span><span class="w"> </span><span class="n">l</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="p">(</span><span class="nf">normalise</span><span class="w"> </span><span class="n">p</span><span class="p">)</span><span class="w"> </span><span class="n">pd</span><span class="p">)))</span><span class="w">
                         </span><span class="p">(</span><span class="nb">*</span><span class="w"> </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="p">(</span><span class="nf">normalise</span><span class="w"> </span><span class="n">p</span><span class="p">))</span><span class="w"> </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="nb">pr</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nb">-</span><span class="w"> </span><span class="mi">1</span><span class="w"> </span><span class="n">pl</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nf">F</span><span class="w"> </span><span class="n">w</span><span class="w"> </span><span class="p">(</span><span class="nb">inc</span><span class="w"> </span><span class="n">l</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="nf">normalise</span><span class="w"> </span><span class="n">p</span><span class="p">))))]</span><span class="w">
                    </span><span class="p">(</span><span class="nf">swap!</span><span class="w"> </span><span class="n">lookup</span><span class="w"> </span><span class="nb">assoc</span><span class="w"> </span><span class="p">[</span><span class="n">w</span><span class="w"> </span><span class="n">l</span><span class="w"> </span><span class="n">p</span><span class="p">]</span><span class="w"> </span><span class="n">answer</span><span class="p">)</span><span class="w">
                    </span><span class="n">answer</span><span class="p">))))]</span><span class="w">
    </span><span class="p">(</span><span class="nf">F</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="mi">0</span><span class="w"> </span><span class="n">pi</span><span class="p">)))</span><span class="w">
</span></code></pre></div></div>

<p>Please let me know any improvements to tennison you can think of, code is <a href="https://github.com/thattommyhall/hackercup2014/tree/master/src/hackercup2014">on github</a></p>]]></content><author><name>Tom Hall</name></author><category term="clojure" /><summary type="html"><![CDATA[I had some fun doing it last year so I thought I would have a go again. This weekend was the qualifier. You can see the questions here]]></summary></entry></feed>