<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7056990295646173627</id><updated>2012-01-18T04:44:23.787Z</updated><title type='text'>Learning Clojure</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.learningclojure.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>92</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-4090112944109615469</id><published>2011-09-22T13:28:00.000+01:00</published><updated>2011-09-22T21:42:15.013+01:00</updated><title type='text'>Clojure Setup Tutorial with EMACS: clojure, clojure.contrib, swank, slime, maven and maven-clojure-plugin in a couple of seconds</title><content type='html'>&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;As of 22nd September 2011, this is still working fine, this time on Fedora 14 (substituting yum for apt-get, but that's the only difference) &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;------------------------------------------------------------------------------------------------------------------------------------ &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;I've just (15th February 2011) had to set this up again for someone on an Ubuntu 10.10 box.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;And to my speechless amazement (16th February 2011), it worked absolutely the same way on Radek Ostrowski (a complete stranger) 's mac at dev8d, thus condemning him to years of suffering at the hands of Aquamacs. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;This method is still my favourite, still the one I actually use in practice, and still the easiest, and it's been stable for about a year now. &lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Since I've just confirmed that it still works, I've moved it back to the top.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;hr /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Install maven:&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;b&gt;$sudo apt-get install maven2&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Then create a &lt;b&gt;pom.x&lt;/b&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;b&gt;ml&lt;/b&gt; file to tell maven which repositories to use. There's an example below to copy and paste.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Once you've got maven installed, and made a pom.xml file, then:&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;b&gt;$mvn clojure:repl&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;Will start a REPL with clojure 1.2 and clojure-contrib 1.2 on the classpath. The REPL should use jLine to give it editing and history on all platforms.&lt;br /&gt;&lt;br /&gt;If you like to use EMACS instead, then&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;b&gt;$mvn clojure:swank&lt;/b&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="cssButtonOuter"&gt;&lt;div class="cssButtonMiddle"&gt;&lt;div class="cssButtonInner"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Will start a swank server, which you can connect to with &lt;b&gt;M-x slime-connect&lt;/b&gt;.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;That's it from the clojure side.&lt;/span&gt;&lt;br /&gt;&lt;hr /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;To set up emacs, and equip it to talk to the clojure swank server:&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;b&gt;$sudo apt-get install emacs&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Then install the emacs lisp package archive (see&amp;nbsp;&lt;/span&gt;http://tromey.com/elpa/)&amp;nbsp;by evaluating this code:&lt;br /&gt;&lt;br /&gt;&amp;nbsp;(cut and paste it into the scratch buffer, put the cursor in the middle, and use &lt;b&gt;M-C-x&lt;/b&gt;):&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;--emacs lisp to install elpa---------------&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;(let ((buffer (url-retrieve-synchronously&lt;br /&gt;        "http://tromey.com/elpa/package-install.el")))&lt;br /&gt;  (save-excursion&lt;br /&gt;    (set-buffer buffer)&lt;br /&gt;    (goto-char (point-min))&lt;br /&gt;    (re-search-forward "^$" nil 'move)&lt;br /&gt;    (eval-region (point) (point-max))&lt;br /&gt;    (kill-buffer (current-buffer))))&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;---end of emacs lisp to install elpa-------------&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Now use &lt;b&gt;M-x package-list-packages&lt;/b&gt; to bring up the list of packages, and use &lt;b&gt;i&lt;/b&gt; and then &lt;b&gt;x&lt;/b&gt;&amp;nbsp;to mark and then install&amp;nbsp;&lt;/span&gt;&lt;b&gt;slime&lt;/b&gt;, &lt;b&gt;slime-repl&lt;/b&gt;, and &lt;b&gt;clojure-mode&lt;/b&gt;.&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Then connect emacs to the already running clojure image with &lt;b&gt;M-x slime-connect&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;That should be it. You should now be at a running clojure 1.2 repl inside emacs.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;hr /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;Here's an example of a pom.xml file that pulls in clojure and clojure-contrib 1.2 . Just cut and paste it.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;div style="margin: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;As well as the essentials, I've also added: the &lt;b&gt;clojars.org&lt;/b&gt; repository, where many useful clojure packages live;&amp;nbsp; the &lt;b&gt;maven versions plugin&lt;/b&gt;, which helps with keeping everything cutting edge; and &lt;b&gt;jline&lt;/b&gt; so that command line repls work better (mvn clojure:repl)&lt;/span&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;I like to have my startup repls conditioned a little, so if you have a startup script that you always want to run, add this snippet&lt;/span&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;div style="margin: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;lt;configuration&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;div style="margin: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;lt;replScript&amp;gt;startup.clj&amp;lt;/replScript&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;div style="margin: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;lt;/configuration&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;div style="margin: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;div style="margin: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;to the clojure-maven-plugin section so that when maven starts a repl, the code in startup.clj is loaded as the first action. This is a good place to set print-length and print-level, so that they will be set before the swank server starts, which means that you won't hang emacs by evaluating an infinite sequence.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;I also like to &lt;b&gt;require&lt;/b&gt; everything on the classpath, so that I can use things like &lt;b&gt;find-doc&lt;/b&gt; to find out about everything.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;b&gt;pom.xml&lt;/b&gt; files look terrifying, but they're really not. It's just that xml is such a godawful verbose way to write things out.&lt;br /&gt;&lt;br /&gt;It contains: the addresses of three repositories which hold vital code; the names and versions of four vital jar files that you need; and the names and versions of two helpful maven plugins.&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;b&gt;pom.xml&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;style type="text/css"&gt;    &lt;!--      .xml-body {        color: #ffffff;        background-color: #000000;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;br /&gt;&lt;pre class="xml-body"&gt;&amp;lt;&lt;span class="function-name"&gt;project&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;modelVersion&lt;/span&gt;&amp;gt;4.0.0&amp;lt;/&lt;span class="function-name"&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;com.example&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;hello-maven-clojure-swank&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;1.0-SNAPSHOT&amp;lt;/&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;name&lt;/span&gt;&amp;gt;hello-maven&amp;lt;/&lt;span class="function-name"&gt;name&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;description&lt;/span&gt;&amp;gt;maven, clojure, emacs: together at last&amp;lt;/&lt;span class="function-name"&gt;description&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;repositories&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;repository&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;id&lt;/span&gt;&amp;gt;clojars&amp;lt;/&lt;span class="function-name"&gt;id&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;url&lt;/span&gt;&amp;gt;http://clojars.org/repo/&amp;lt;/&lt;span class="function-name"&gt;url&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;repository&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;repository&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;id&lt;/span&gt;&amp;gt;clojure&amp;lt;/&lt;span class="function-name"&gt;id&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;url&lt;/span&gt;&amp;gt;http://build.clojure.org/releases&amp;lt;/&lt;span class="function-name"&gt;url&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;repository&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;repository&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;id&lt;/span&gt;&amp;gt;central&amp;lt;/&lt;span class="function-name"&gt;id&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;url&lt;/span&gt;&amp;gt;http://repo1.maven.org/maven2&amp;lt;/&lt;span class="function-name"&gt;url&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;repository&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/&lt;span class="function-name"&gt;repositories&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;dependencies&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;org.clojure&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;clojure&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;1.2.0&amp;lt;/&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;org.clojure&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;clojure-contrib&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;1.2.0&amp;lt;/&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;jline&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;jline&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;0.9.94&amp;lt;/&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;swank-clojure&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;swank-clojure&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;1.2.1&amp;lt;/&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/&lt;span class="function-name"&gt;dependencies&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;build&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;plugins&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;plugin&lt;/span&gt;&amp;gt;&lt;br /&gt;         &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;com.theoryinpractise&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;            &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;clojure-maven-plugin&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;         &amp;lt;&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;1.3.3&amp;lt;/&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;/&lt;span class="function-name"&gt;plugin&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;plugin&lt;/span&gt;&amp;gt;&lt;br /&gt;        &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;org.codehaus.mojo&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;          &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;versions-maven-plugin&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;        &amp;lt;&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;1.2&amp;lt;/&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;/&lt;span class="function-name"&gt;plugin&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;plugins&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;/&lt;span class="function-name"&gt;build&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;/&lt;span class="function-name"&gt;project&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;pre class="xml-body"&gt;&lt;/pre&gt;&lt;pre class="xml_body"&gt;&lt;/pre&gt;&lt;pre class="xml_body"&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-4090112944109615469?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/4090112944109615469/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2010/08/clojure-emacs-swank-slime-maven-maven.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/4090112944109615469'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/4090112944109615469'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2010/08/clojure-emacs-swank-slime-maven-maven.html' title='Clojure Setup Tutorial with EMACS: clojure, clojure.contrib, swank, slime, maven and maven-clojure-plugin in a couple of seconds'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-689985051107678589</id><published>2011-05-29T00:28:00.002+01:00</published><updated>2011-05-29T00:28:25.898+01:00</updated><title type='text'>Numerical Integration: Better Refinements?</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;pre class="clojure-body"&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Numerical Integration: Better Refinements?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Here are some very simple functions which we might want to test integration&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;methods on:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;square&lt;/span&gt;  [x] (&lt;span class="builtin"&gt;*&lt;/span&gt; x x))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;sine&lt;/span&gt;    [x] (Math/sin x))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;step&lt;/span&gt;    [x] (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;&amp;lt;&lt;/span&gt; x 1/2) 0.0 1.0))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;inverse&lt;/span&gt; [x] (&lt;span class="builtin"&gt;/&lt;/span&gt; x))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Here are some Newton-Cotes formulae for approximate integration:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;trapezium-rule&lt;/span&gt; [f a b]&lt;br /&gt;  (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/2 (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;+&lt;/span&gt; (f a) (f b))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;simpson-rule&lt;/span&gt; [f a b]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [midpoint (&lt;span class="builtin"&gt;+&lt;/span&gt; a (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) 2))]&lt;br /&gt;    (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/6 (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;+&lt;/span&gt; (f a) (&lt;span class="builtin"&gt;*&lt;/span&gt; 4 (f midpoint)) (f b)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;simpson38-rule&lt;/span&gt; [f a b]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [midpoint1 (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a a b) 3)&lt;br /&gt;        midpoint2 (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a b b) 3)]&lt;br /&gt;    (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/8 (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;+&lt;/span&gt; (f a) (&lt;span class="builtin"&gt;*&lt;/span&gt; 3 (f midpoint1)) (&lt;span class="builtin"&gt;*&lt;/span&gt; 3 (f midpoint2)) (f b)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;booles-rule&lt;/span&gt; [f a b]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [midpoint1 (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a a a b) 4)&lt;br /&gt;        midpoint2 (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a a b b) 4)&lt;br /&gt;        midpoint3 (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a b b b) 4)]&lt;br /&gt;    (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/90 (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;+&lt;/span&gt; (&lt;span class="builtin"&gt;*&lt;/span&gt; 7 (f a)) (&lt;span class="builtin"&gt;*&lt;/span&gt; 32 (f midpoint1)) (&lt;span class="builtin"&gt;*&lt;/span&gt; 12 (f midpoint2)) (&lt;span class="builtin"&gt;*&lt;/span&gt; 32 (f midpoint3)) (&lt;span class="builtin"&gt;*&lt;/span&gt; 7 (f b))))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can use any of these rules to get estimate of the integral of a function over an interval:&lt;br /&gt;&lt;/span&gt;(simpson-rule inverse 1 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;10/9&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If we halve the interval and use the rule over both halves, then we can use the rule to&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;get a better estimate by adding the estimates for the half-intervals&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;+&lt;/span&gt;&lt;br /&gt; (simpson-rule inverse 1 2)&lt;br /&gt; (simpson-rule inverse 2 3)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;11/10&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can guess at the error involved in the estimate by taking the difference&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;between these two estimates, on the basis that splitting the interval usually&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;makes most of the error go away.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;-&lt;/span&gt; (simpson-rule inverse 1 3)&lt;br /&gt;   (&lt;span class="builtin"&gt;+&lt;/span&gt;&lt;br /&gt;    (simpson-rule inverse 1 2)&lt;br /&gt;    (simpson-rule inverse 2 3))) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1/90&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So we'd expect that the first estimate is out by a bit more than 1/90, and&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;that the second is out by rather less than 1/90&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;For the inverse function, which can be integrated symbolically, we know the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;true answer:&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;-&lt;/span&gt; (Math/log 3) (Math/log 1)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.0986122886681098&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;/&lt;/span&gt; 10.0 9) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.1111111111111112&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;/&lt;/span&gt; 11.0 10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.1&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So the errors are really:&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;-&lt;/span&gt; 1.0986122 10/9)  &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;-0.0124989111111109  ; which is ~ 1/90&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;-&lt;/span&gt; 1.0986122 11/10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;-0.00138780000000005 ; which is ~ 1/900&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;This method of guessing the error is deeply suspect, and can go wrong, but I&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;won't go into details.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I think it's good enough for our purposes as long as the functions we want to&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;integrate are reasonably well behaved and we take small enough intervals.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So we can easily make a function which gives us the more refined of the two&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;estimates, together with a guess as to how close it is to the truth.&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;approx-with-error&lt;/span&gt;[rule f a b]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [guess (rule f a b)&lt;br /&gt;        midpoint (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a b) 2)&lt;br /&gt;        better-guess (&lt;span class="builtin"&gt;+&lt;/span&gt; (rule f a midpoint) (rule f midpoint b))&lt;br /&gt;        error-estimate (&lt;span class="builtin"&gt;-&lt;/span&gt; guess better-guess)&lt;br /&gt;        abs-error-estimate (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; error-estimate 0) error-estimate (&lt;span class="builtin"&gt;-&lt;/span&gt; error-estimate))]&lt;br /&gt;    [better-guess abs-error-estimate]))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's try it out on a few cases, on the particularly nasty integral of 1/x over [0.01,100]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;This is the true answer&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;-&lt;/span&gt; (Math/log 100) (Math/log 0.01)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.210340371976184&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(approx-with-error trapezium-rule inverse 0.01 100) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[2500.999775019998 2499.000174980002]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We guess 2500, and we think we're out by at most 2499, which is just true&lt;br /&gt;&lt;/span&gt;(approx-with-error simpson-rule inverse 0.01 100) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[835.4437770204454 832.5559396728856]&lt;br /&gt;&lt;/span&gt;(approx-with-error simpson38-rule inverse 0.01 100) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[627.4427811912234 624.2442845054817]&lt;br /&gt;&lt;/span&gt;(approx-with-error booles-rule inverse 0.01 100) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[391.7824297523125 388.1576179566068]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;When we split the interval into two halves [0.01, 50.05] [50.05,100]&lt;br /&gt;&lt;/span&gt;(approx-with-error trapezium-rule inverse 0.01 50.05) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[1252.2495505293746 1250.2503495705255]&lt;br /&gt;&lt;/span&gt;(approx-with-error trapezium-rule inverse 50.05 100) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[0.7072645364881702 0.041486462512828726]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Our guess tells us that the great majority of the error is in the first sub interval&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We might want to refine that first, before bothering with the other one:&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We'll now split [0.01, 25.025][25.025,50.05][50.05,100]&lt;br /&gt;&lt;/span&gt;(approx-with-error trapezium-rule inverse 0.01 25.025) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[626.6241012183343 624.6256989814656]&lt;br /&gt;&lt;/span&gt;(approx-with-error trapezium-rule inverse 25.025 50.05) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[0.7083333333333333 0.04166666666666663]&lt;br /&gt;&lt;/span&gt;(approx-with-error trapezium-rule inverse 50.05 100) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[0.7072645364881702 0.041486462512828726]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Again, one subinterval seems to be responsible for the majority of our errors.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We could keep a list of intervals, sorted by the estimated error, and always refine the one&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;with the largest guessed error.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;interval-&amp;gt;errorstruct&lt;/span&gt; [rule f [a b]]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [[guess error-guess] (approx-with-error rule f a b)]&lt;br /&gt;    [error-guess, guess, [a,b]]))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;errorstructs&lt;/span&gt; (&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; interval-&amp;gt;errorstruct trapezium-rule inverse)&lt;br /&gt;                       [[0.01,25.025][25.025 50.05][50.05 100]]))&lt;br /&gt;&lt;br /&gt;errorstructs&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;([624.6256989814656 626.6241012183343     [0.01   25.025]]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;[0.04166666666666663 0.7083333333333333  [25.025 50.05]]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;[0.041486462512828726 0.7072645364881702 [50.05  100]])&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And now we need a function to refine the interval with the largest error&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;refine&lt;/span&gt;[rule f errorstructs]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [sortedstructs (&lt;span class="builtin"&gt;reverse&lt;/span&gt; (&lt;span class="builtin"&gt;sort&lt;/span&gt; errorstructs))&lt;br /&gt;        [_ _ [a b]] (&lt;span class="builtin"&gt;first&lt;/span&gt; sortedstructs)&lt;br /&gt;        remains (&lt;span class="builtin"&gt;rest&lt;/span&gt; sortedstructs)&lt;br /&gt;        midpoint (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a b) 2)&lt;br /&gt;        subinterval1 (interval-&amp;gt;errorstruct rule f [a midpoint])&lt;br /&gt;        subinterval2 (interval-&amp;gt;errorstruct rule f [midpoint b])] &lt;br /&gt;        (&lt;span class="builtin"&gt;cons&lt;/span&gt; subinterval1 (&lt;span class="builtin"&gt;cons&lt;/span&gt; subinterval2 remains))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Now with every call to refine, we refine the interval with the largest error estimate&lt;br /&gt;&lt;/span&gt;(refine trapezium-rule inverse errorstructs)&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;([311.93889676733556 313.93570379188156 [0.01 12.5175]]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;[0.04159457274964806 0.7079060863675477 [12.5175 25.025]]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;[0.04166666666666663 0.7083333333333333 [25.025 50.05]]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;[0.041486462512828726 0.7072645364881702 [50.05 100]])&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;successive-trapezium-refinements&lt;/span&gt; (&lt;span class="builtin"&gt;iterate&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; refine trapezium-rule inverse) errorstructs))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Here's what it looks like after a few iterations&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;nth&lt;/span&gt; successive-trapezium-refinements 5)&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;([18.81475746721543 20.764864658796014 [0.01 0.7917187499999999]]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;[0.040533241059784286 0.7015625070966475 [0.7917187499999999 1.5734374999999998]]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;[0.04109463731966401 0.7049306354620377 [1.5734374999999998 3.136875]]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;[0.041379306898238544 0.7066276281534741 [3.136875 6.26375]]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;[0.04152264848816445 0.7074793872568832 [6.26375 12.5175]]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;[0.04159457274964806 0.7079060863675477 [12.5175 25.025]]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;[0.04166666666666663 0.7083333333333333 [25.025 50.05]]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;[0.041486462512828726 0.7072645364881702 [50.05 100]])&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;        &lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can get our best guess for the whole thing and our total error estimate&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;by reducing this list&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; first  (&lt;span class="builtin"&gt;nth&lt;/span&gt; successive-trapezium-refinements 5))) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;19.104035002910425&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; second (&lt;span class="builtin"&gt;nth&lt;/span&gt; successive-trapezium-refinements 5))) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;25.708968772954105&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;After a hundred refinements..&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; first  (&lt;span class="builtin"&gt;nth&lt;/span&gt; successive-trapezium-refinements 100))) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.010431101535137086&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; second (&lt;span class="builtin"&gt;nth&lt;/span&gt; successive-trapezium-refinements 100))) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.213824736866899&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;After a thousand refinements..&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; first  (&lt;span class="builtin"&gt;nth&lt;/span&gt; successive-trapezium-refinements 1000))) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.0913238861095381E-4&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; second (&lt;span class="builtin"&gt;nth&lt;/span&gt; successive-trapezium-refinements 1000))) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.210376750235199&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;That's not bad, (the real answer is 9.210340371976184), but it's running very slowly.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We could try with a higher order rule&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;successive-boole-refinements&lt;/span&gt; (&lt;span class="builtin"&gt;iterate&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; refine booles-rule inverse) errorstructs))&lt;br /&gt;(&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; first   (&lt;span class="builtin"&gt;nth&lt;/span&gt; successive-boole-refinements 1000))) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;4.420942778526893E-15&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; second  (&lt;span class="builtin"&gt;nth&lt;/span&gt; successive-boole-refinements 1000))) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.210340371976176&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In this case, that seems to work very well, but the run time is appalling.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The problem is that we have a longer and longer list of intervals at every&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;step, and every step, we have to sort this list. That's an n^2 algorithm,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;which won't scale well.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What we should do here is use a priority queue. Clojure doesn't have an&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;immutable version, although it's possible to fake one with a sorted map.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But rather than do that, I'm going to drop out of the functional paradigm&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;altogther, and use the heap implementation from Java in a mutable fashion,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;looping and popping and adding.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;improve-loop&lt;/span&gt; [rule f a b count]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [pq (java.util.PriorityQueue. count (&lt;span class="builtin"&gt;comparator&lt;/span&gt; (&lt;span class="builtin"&gt;fn&lt;/span&gt;[a b](&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; (&lt;span class="builtin"&gt;first&lt;/span&gt; a)(&lt;span class="builtin"&gt;first&lt;/span&gt; b)))))]&lt;br /&gt;    (.add pq (interval-&amp;gt;errorstruct rule f [a b]))&lt;br /&gt;    (&lt;span class="keyword"&gt;loop&lt;/span&gt; [pq pq count count]&lt;br /&gt;      (&lt;span class="keyword"&gt;if&lt;/span&gt; (zero? count) pq&lt;br /&gt;          (&lt;span class="keyword"&gt;let&lt;/span&gt; [[err val [a b]] (.poll pq)&lt;br /&gt;                midpoint (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a b) 2)&lt;br /&gt;                aa (interval-&amp;gt;errorstruct rule f [a midpoint])&lt;br /&gt;                bb (interval-&amp;gt;errorstruct rule f [midpoint b])]&lt;br /&gt;            (&lt;span class="keyword"&gt;doto&lt;/span&gt; pq&lt;br /&gt;              (.add aa)&lt;br /&gt;              (.add bb))&lt;br /&gt;            (&lt;span class="keyword"&gt;recur&lt;/span&gt; pq (&lt;span class="builtin"&gt;dec&lt;/span&gt; count)))))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Now we can do our calculation much faster&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;integrate&lt;/span&gt; [rule f a b count]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [pq (improve-loop rule f a b count)]&lt;br /&gt;    [(&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; first pq))&lt;br /&gt;     (&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; second pq))]))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We'll ask for a thousand refinements, and get back the error estimate, and the answer.&lt;br /&gt;&lt;/span&gt;(integrate booles-rule inverse 0.01 100 1000) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[4.455637248046429E-15 9.21034037197618]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's try the same integral over the very nasty range [0.0000001, 10000000] which caused serious&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;problems for our previous methods.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The real answer is&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;-&lt;/span&gt; (Math/log 10000000) (Math/log 0.00000001)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;34.538776394910684&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And our approximations are:&lt;br /&gt;&lt;/span&gt;(integrate booles-rule inverse 0.00000001 10000000 10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[3.797743055486256E10 3.797743056542089E10]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule inverse 0.00000001 10000000 100) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[3.3430724324184924E-5 34.53877704296225]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule inverse 0.00000001 10000000 1000) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[4.549938203979309E-11 34.53877639491147]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule inverse 0.00000001 10000000 10000) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[9.361001557239845E-16 34.53877639491065]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;For the non-stiff integrals that we started playing with, Boole's rule is great:&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It's exact for quadratics, and several higher powers&lt;br /&gt;&lt;/span&gt;(integrate booles-rule square 0 2 10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[0 8/3]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule (&lt;span class="builtin"&gt;fn&lt;/span&gt;[x] (&lt;span class="builtin"&gt;*&lt;/span&gt; x x x x)) 0 2 10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[0 32/5]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule (&lt;span class="builtin"&gt;fn&lt;/span&gt;[x] (&lt;span class="builtin"&gt;*&lt;/span&gt; x x x x x)) 0 2 10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[0 32/3]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and very good for higher powers, even with very few refinements&lt;br /&gt;&lt;/span&gt;(integrate booles-rule (&lt;span class="builtin"&gt;fn&lt;/span&gt;[x] (&lt;span class="builtin"&gt;*&lt;/span&gt; x x x x x x)) 0 2 10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[969/8589934592 471219269093/25769803776]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule (&lt;span class="builtin"&gt;fn&lt;/span&gt;[x] (&lt;span class="builtin"&gt;*&lt;/span&gt; x x x x x x)) 0 2 20) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[2127/1099511627776 60316066438099/3298534883328]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;convergence is great for sine&lt;br /&gt;&lt;/span&gt;(integrate booles-rule sine 0 Math/PI 10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[1.7383848804897184E-9 1.9999999999725113]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule sine 0 Math/PI 100) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[3.1931922384043077E-15 1.9999999999999991]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule sine 0 Math/PI 1000) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[2.526233413538588E-17 1.999999999999999]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule sine 0 Math/PI 10000) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[6.32722651455846E-18 2.0]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But I'm still quite worried about the error estimate that we made. It's only&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;a guess, and it can be a bad guess.  Here are some functions that are&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;deliberately designed to screw things up.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;This function is extremely vibratey near the origin.&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;sineinverse&lt;/span&gt;[x] (Math/sin (&lt;span class="builtin"&gt;/&lt;/span&gt; x)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The error estimates are clearly wrong here, but the answers seem to settle down to something that looks plausible.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(integrate booles-rule sineinverse 0.001 10 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[0.09752245288534744 3.189170812427795]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule sineinverse 0.001 10 10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[0.014802407142066881 2.725700351059874]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule sineinverse 0.001 10 100) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[2.666579898821515E-4 2.7262259059929814]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule sineinverse 0.001 10 1000) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[7.84363268117651E-9 2.7262019887881457]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule sineinverse 0.001 10 10000) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[8.311387750656713E-15 2.726201989096135]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I'm slightly reassured that if we use the trapezium rule, which should be&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;slower converging but less sensitive to high derivatives, we seem to settle down to the same thing:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(integrate trapezium-rule sineinverse 0.001 10 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[0.3493754261290617 2.9603246206316127]&lt;br /&gt;&lt;/span&gt;(integrate trapezium-rule sineinverse 0.001 10 10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[0.12037643221528535 2.759621850911819]&lt;br /&gt;&lt;/span&gt;(integrate trapezium-rule sineinverse 0.001 10 100) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[0.011584111090323689 2.728470051290524]&lt;br /&gt;&lt;/span&gt;(integrate trapezium-rule sineinverse 0.001 10 1000) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[7.174438961790802E-4 2.7265014884997414]&lt;br /&gt;&lt;/span&gt;(integrate trapezium-rule sineinverse 0.001 10 10000) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[1.0854830311799172E-5 2.7262023437746654]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Since I don't actually know what the integral of sin(1/x) is, I've no idea&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;whether this answer is correct. Since both rules seem to settle down to the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;same answer, I tend to believe that it is.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Here's a weird function, which looks like it should be even worse that sin(1/x) on its own&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;strange&lt;/span&gt;[x] (&lt;span class="builtin"&gt;-&lt;/span&gt; (Math/sin (&lt;span class="builtin"&gt;/&lt;/span&gt; x)) (&lt;span class="builtin"&gt;/&lt;/span&gt; (Math/cos (&lt;span class="builtin"&gt;/&lt;/span&gt; x)) x)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In fact it's the derivative of x sin(1/x), so we can calculate the real answer over [0.001, 10]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;which should be:&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;-&lt;/span&gt; (&lt;span class="builtin"&gt;*&lt;/span&gt; 10 (Math/sin 1/10)) (&lt;span class="builtin"&gt;*&lt;/span&gt; 0.001 (Math/sin 1000))) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.9975072869277496&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Interestingly, the error estimates look sound for this one:&lt;br /&gt;&lt;/span&gt;(integrate booles-rule strange 0.001 10 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[109.91706304856582 -108.12753277035351]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule strange 0.001 10 10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[0.07641821305025362 -1.0276123964492345]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule strange 0.001 10 100) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[0.0798435700032961 1.0469088424961843]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule strange 0.001 10 1000) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[2.0359056110968434E-6 0.9975072871949854]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule strange 0.001 10 10000) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[1.9224976990340685E-12 0.997507286927752]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Since we seem to have dealt well with some nasty functions, we might be&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;getting confident in our rule. I know I was!&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But this innocuous looking function&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;sine80squared&lt;/span&gt;[x] (square (Math/sin (&lt;span class="builtin"&gt;*&lt;/span&gt; x 80))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Is a complete nightmare. It looks as though the method is converging well:&lt;br /&gt;&lt;/span&gt;(integrate booles-rule sine80squared 0 Math/PI 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[1.1091279850485843E-28 3.7074689566598855E-28]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule sine80squared 0 Math/PI 10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[0.013089969389960716 0.7853981633974437]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule sine80squared 0 Math/PI 100) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[1.7991469747360833E-12 0.7853981633974478]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule sine80squared 0 Math/PI 1000) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[3.207733520089899E-13 0.7853981633974484]&lt;br /&gt;&lt;/span&gt;(integrate booles-rule sine80squared 0 Math/PI 10000) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[3.1095566849572033E-15 0.7853981633974481]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But if we use a different rule, it also seems to converge, but to a completely different answer&lt;br /&gt;&lt;/span&gt;(integrate trapezium-rule sine80squared 0 Math/PI 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[3.226319244612108E-28 4.262878793991289E-28]&lt;br /&gt;&lt;/span&gt;(integrate trapezium-rule sine80squared 0 Math/PI 10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[0.01573134053904405 0.19774924859401588]&lt;br /&gt;&lt;/span&gt;(integrate trapezium-rule sine80squared 0 Math/PI 100) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[5.4528883422580115E-5 0.19634904414812832]&lt;br /&gt;&lt;/span&gt;(integrate trapezium-rule sine80squared 0 Math/PI 1000) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[4.6327740574637914E-7 0.19634954102557595]&lt;br /&gt;&lt;/span&gt;(integrate trapezium-rule sine80squared 0 Math/PI 10000) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;[5.200068066397881E-9 0.19634954084967793]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In fact both answers are wrong. We can calculate the real integral of this&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;function over the interval [0,pi] which should be:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;/&lt;/span&gt; (Math/PI) 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.5707963267948966&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In fact if we use our much earlier 'divide every interval evenly' algorithm:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;iterated-rule&lt;/span&gt; [rule f a b N]&lt;br /&gt;  (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; N 0)&lt;br /&gt;    (rule f a b)&lt;br /&gt;    (&lt;span class="keyword"&gt;let&lt;/span&gt; [midpoint (&lt;span class="builtin"&gt;+&lt;/span&gt; a (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) 2))]&lt;br /&gt;      (&lt;span class="builtin"&gt;+&lt;/span&gt; (iterated-rule rule f a midpoint (&lt;span class="builtin"&gt;dec&lt;/span&gt; N))&lt;br /&gt;         (iterated-rule rule f midpoint b (&lt;span class="builtin"&gt;dec&lt;/span&gt; N))))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We very quickly get surprisingly good answers:&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule sine80squared 0 Math/PI 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.13079223568638E-28&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule sine80squared 0 Math/PI 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;4.262878793991289E-28&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule sine80squared 0 Math/PI 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;3.5626606693542546E-28&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule sine80squared 0 Math/PI 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;3.6535380881685736E-28&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule sine80squared 0 Math/PI 5) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.5707963267948966&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule sine80squared 0 Math/PI 6) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.570796326794897&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule sine80squared 0 Math/PI 7) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.5707963267948972&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule sine80squared 0 Math/PI 8) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.5707963267948966&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule sine80squared 0 Math/PI 9) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.5707963267948957&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule sine80squared 0 Math/PI 10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.5707963267948963&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;With Booles' rule the story is the same:&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine80squared 0 Math/PI 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;3.1974110932118413E-28&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine80squared 0 Math/PI 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;3.7074689566598855E-28&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine80squared 0 Math/PI 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.2340214425527414&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine80squared 0 Math/PI 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.5358897417550046&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine80squared 0 Math/PI 5) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.570796326794895&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine80squared 0 Math/PI 6) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.5707963267948961&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine80squared 0 Math/PI 7) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.5707963267948966&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine80squared 0 Math/PI 8) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.5707963267948968&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine80squared 0 Math/PI 9) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.5707963267948963&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So the nice rule that we'd come up with, which worked so well for the stiff problem&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;of integrating 1/x near the origin, is completely broken on something that the obvious&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;recursion integrates (suspiciously) well.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The problem is that we used an error estimate that we can't trust to control&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;the refinement process.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If we guess that a certain interval contains hardly any error, then it will&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;never get refined at all, so we'll never find out that our guess is wrong.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-689985051107678589?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/689985051107678589/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/05/numerical-integration-better_29.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/689985051107678589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/689985051107678589'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/05/numerical-integration-better_29.html' title='Numerical Integration: Better Refinements?'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-646447759657245210</id><published>2011-05-26T01:51:00.002+01:00</published><updated>2011-05-26T01:51:55.273+01:00</updated><title type='text'>Numerical Integration: Better Refinements?</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;pre class="clojure-body"&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Numerical Integration: Better Refinements?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Here are some Newton-Cotes formulae for approximate integration:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;trapezium-rule&lt;/span&gt; [f a b]&lt;br /&gt;  (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/2 (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;+&lt;/span&gt; (f a) (f b))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;simpson-rule&lt;/span&gt; [f a b]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [midpoint (&lt;span class="builtin"&gt;+&lt;/span&gt; a (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) 2))]&lt;br /&gt;    (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/6 (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;+&lt;/span&gt; (f a) (&lt;span class="builtin"&gt;*&lt;/span&gt; 4 (f midpoint)) (f b)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;simpson38-rule&lt;/span&gt; [f a b]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [midpoint1 (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a a b) 3)&lt;br /&gt;        midpoint2 (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a b b) 3)]&lt;br /&gt;    (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/8 (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;+&lt;/span&gt; (f a) (&lt;span class="builtin"&gt;*&lt;/span&gt; 3 (f midpoint1)) (&lt;span class="builtin"&gt;*&lt;/span&gt; 3 (f midpoint2)) (f b)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;booles-rule&lt;/span&gt; [f a b]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [midpoint1 (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a a a b) 4)&lt;br /&gt;        midpoint2 (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a a b b) 4)&lt;br /&gt;        midpoint3 (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a b b b) 4)]&lt;br /&gt;    (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/90 (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;+&lt;/span&gt; (&lt;span class="builtin"&gt;*&lt;/span&gt; 7 (f a)) (&lt;span class="builtin"&gt;*&lt;/span&gt; 32 (f midpoint1)) (&lt;span class="builtin"&gt;*&lt;/span&gt; 12 (f midpoint2)) (&lt;span class="builtin"&gt;*&lt;/span&gt; 32 (f midpoint3)) (&lt;span class="builtin"&gt;*&lt;/span&gt; 7 (f b))))))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And here is a way to apply them to (power 2 N) subintervals&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;iterated-rule&lt;/span&gt; [rule f a b N]&lt;br /&gt;  (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; N 0)&lt;br /&gt;    (rule f a b)&lt;br /&gt;    (&lt;span class="keyword"&gt;let&lt;/span&gt; [midpoint (&lt;span class="builtin"&gt;+&lt;/span&gt; a (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) 2))]&lt;br /&gt;      (&lt;span class="builtin"&gt;+&lt;/span&gt; (iterated-rule rule f a midpoint (&lt;span class="builtin"&gt;dec&lt;/span&gt; N))&lt;br /&gt;         (iterated-rule rule f midpoint b (&lt;span class="builtin"&gt;dec&lt;/span&gt; N))))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Here are some very simple functions which we might want to test integration&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;methods on:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;square&lt;/span&gt;  [x] (&lt;span class="builtin"&gt;*&lt;/span&gt; x x))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;sine&lt;/span&gt;    [x] (Math/sin x))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;step&lt;/span&gt;    [x] (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;&amp;lt;&lt;/span&gt; x 1/2) 0.0 1.0))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;inverse&lt;/span&gt; [x] (&lt;span class="builtin"&gt;/&lt;/span&gt; x))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We might notice that with our Newton-Cotes formulae, the change in the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;estimate when we make a refinement is often around the same size as the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;actual error.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's try using that to produce a method where we can say what error we'd&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;like, and if the change from refining the guess is too big, we should refine&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;more. And if we do refine more, we'll ask for half the desired error on each&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;of the two subintervals, which should mean that the total error is at least&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;comparable to the error we asked for!&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;adaptive-rule-recurse&lt;/span&gt; [rule f a b desired-error]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [guess (rule f a b)&lt;br /&gt;        midpoint (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a b) 2)&lt;br /&gt;        better-guess (&lt;span class="builtin"&gt;+&lt;/span&gt; (rule f a midpoint) (rule f midpoint b))&lt;br /&gt;        error-estimate (&lt;span class="builtin"&gt;-&lt;/span&gt; guess better-guess)&lt;br /&gt;        abs-error-estimate (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;&amp;gt;&lt;/span&gt; error-estimate 0) error-estimate (&lt;span class="builtin"&gt;-&lt;/span&gt; error-estimate))]&lt;br /&gt;    (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;&amp;lt;&lt;/span&gt; abs-error-estimate desired-error) better-guess&lt;br /&gt;        (&lt;span class="keyword"&gt;let&lt;/span&gt; [half-desired-error (&lt;span class="builtin"&gt;/&lt;/span&gt; desired-error 2)]&lt;br /&gt;          (&lt;span class="builtin"&gt;+&lt;/span&gt; (adaptive-rule-recurse rule f a midpoint half-desired-error)&lt;br /&gt;             (adaptive-rule-recurse rule f midpoint b half-desired-error))))))&lt;br /&gt;&lt;br /&gt;(adaptive-rule-recurse trapezium-rule square 0. 2 0.1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.6875&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse trapezium-rule square 0. 2 0.01) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.66796875&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse trapezium-rule square 0. 2 0.001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.6669921875&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(adaptive-rule-recurse trapezium-rule step 0.0001 1 0.1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse trapezium-rule step 0.0001 1 0.01) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse trapezium-rule step 0.0001 1 0.001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse trapezium-rule step 0.0001 1 0.0001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Here we're using the trapezium rule on the integral that we were previously unable to get&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;a good answer for: remember that the correct answer is 9.210340371976182&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(adaptive-rule-recurse trapezium-rule inverse 0.0001 1 0.1)    &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.234002964342716&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse trapezium-rule inverse 0.0001 1 0.01)   &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.211881820961814&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse trapezium-rule inverse 0.0001 1 0.001)  &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.210518109406467&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse trapezium-rule inverse 0.0001 1 0.0001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.210358164670637&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;At this point, we're getting much better answers than we ever got before, but they've started&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;taking noticeable time to compute.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;However, we still retain the option of using the higher order formulae:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(adaptive-rule-recurse booles-rule inverse 0.0001 1 0.1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.210347324857782&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse booles-rule inverse 0.0001 1 0.01) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.210345994304586&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse booles-rule inverse 0.0001 1 0.001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.210344014376869&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse booles-rule inverse 0.0001 1 0.0001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.21034116413936&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse booles-rule inverse 0.0001 1 0.00001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.210340404907965&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse booles-rule inverse 0.0001 1 0.000001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.210340376142819&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse booles-rule inverse 0.0001 1 0.0000001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.210340372376441&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse booles-rule inverse 0.0001 1 0.00000001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.210340372016345&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse booles-rule inverse 0.0001 1 0.000000001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.21034037198001&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse booles-rule inverse 0.0001 1 0.0000000001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.210340371976589&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse booles-rule inverse 0.0001 1 0.00000000001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.210340371976214&lt;br /&gt;&lt;/span&gt;(adaptive-rule-recurse booles-rule inverse 0.0001 1 0.000000000001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.210340371976185&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;These answers come back instantaneously, even when we're calculating the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;previously impossible answer to the question to 12 decimal places.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But beware! If we ask for too much accuracy, then the effect of floating&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;point noise means that our recursion may never terminate:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(adaptive-rule-recurse booles-rule inverse 0.0001 1 0.0000000000001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;freezes REPL!&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;At this point, I'm very tempted to say:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;integrate&lt;/span&gt; [f a b]&lt;br /&gt;  (adaptive-rule-recurse booles-rule f a b 0.00000001))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Famously, the integral of 1/x diverges (very slowly) as x gets large&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;which makes it quite difficult to calculate for large intervals without using special tricks.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The integral from 1 to 1000000 of 1/x is log 1000000 - log 1&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;-&lt;/span&gt; (Math/log 1000000) (Math/log 1)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;13.815510557964274&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's try calculating that with our new integrate function:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;time&lt;/span&gt;&lt;br /&gt; (integrate (&lt;span class="builtin"&gt;fn&lt;/span&gt;[x] (&lt;span class="builtin"&gt;/&lt;/span&gt; 1.0 x)) 1 1000000))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;"Elapsed time: 293.219062 msecs"&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;13.81551055800455&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I think that's pretty good.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Unfortunately, we can still lock up the computer by asking the wrong question&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;-&lt;/span&gt; (Math/log 100000000) (Math/log 1)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;18.420680743952367&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;but:&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;time&lt;/span&gt;&lt;br /&gt; (integrate (&lt;span class="builtin"&gt;fn&lt;/span&gt;[x] (&lt;span class="builtin"&gt;/&lt;/span&gt; 1.0 x)) 1 100000000)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;Freezes REPL&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Can you work out what's going on and what we could do about it?&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-646447759657245210?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/646447759657245210/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/05/numerical-integration-better_26.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/646447759657245210'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/646447759657245210'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/05/numerical-integration-better_26.html' title='Numerical Integration: Better Refinements?'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-3828516715693005805</id><published>2011-05-26T00:27:00.001+01:00</published><updated>2011-05-26T00:28:22.967+01:00</updated><title type='text'>Numerical Integration: Better Rules?</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;pre class="clojure-body"&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Numerical Integration: Better Rules?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So far we've found a couple of approximations to 'the area under a graph'.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;trapezium-rule&lt;/span&gt; [f a b]&lt;br /&gt;  (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/2 (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;+&lt;/span&gt; (f a) (f b))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;simpson-rule&lt;/span&gt; [f a b]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [midpoint (&lt;span class="builtin"&gt;+&lt;/span&gt; a (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) 2))]&lt;br /&gt;    (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/6 (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;+&lt;/span&gt; (f a) (&lt;span class="builtin"&gt;*&lt;/span&gt; 4 (f midpoint)) (f b)))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And a way of repeatedly splitting intervals and applying the rules to the sub-intervals&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;to produce better and better approximations.&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;iterated-rule&lt;/span&gt; [rule f a b N]&lt;br /&gt;  (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; N 0)&lt;br /&gt;    (rule f a b)&lt;br /&gt;    (&lt;span class="keyword"&gt;let&lt;/span&gt; [midpoint (&lt;span class="builtin"&gt;+&lt;/span&gt; a (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) 2))]&lt;br /&gt;      (&lt;span class="builtin"&gt;+&lt;/span&gt; (iterated-rule rule f a midpoint (&lt;span class="builtin"&gt;dec&lt;/span&gt; N))&lt;br /&gt;         (iterated-rule rule f midpoint b (&lt;span class="builtin"&gt;dec&lt;/span&gt; N))))))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;For these two functions, which are nice and smooth, with derivatives that&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;don't get too large, these rules produce good approximations&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;square&lt;/span&gt;[x] (&lt;span class="builtin"&gt;*&lt;/span&gt; x x))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;sine&lt;/span&gt; [x] (Math/sin x))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;For this one, which isn't smooth, the approximations converge slowly:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;step&lt;/span&gt; [x]  (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;&amp;lt;&lt;/span&gt; x 1/2) 0.0 1.0))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;For this, which is smooth, but which blows up near 0, the approximations are bad&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;inverse&lt;/span&gt; [x] (&lt;span class="builtin"&gt;/&lt;/span&gt; x))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;One approach which is often taken is to use 'more accurate' rules.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The trapezium rule and Simpson's rule are members of a family called 'Newton-Cotes' formulas.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The more complicated a Newton-Cotes formula is, the more polynomials it can integrate exactly.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But in fact, for nice smooth functions, they tend to be more accurate the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;more polynomials they can integrate exactly.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Here are two more examples, and their estimates for the integral of sine over&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;a half circle (which should be exactly 2):&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;simpson38-rule&lt;/span&gt; [f a b]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [midpoint1 (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a a b) 3)&lt;br /&gt;        midpoint2 (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a b b) 3)]&lt;br /&gt;    (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/8 (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;+&lt;/span&gt; (f a) (&lt;span class="builtin"&gt;*&lt;/span&gt; 3 (f midpoint1)) (&lt;span class="builtin"&gt;*&lt;/span&gt; 3 (f midpoint2)) (f b)))))&lt;br /&gt;&lt;br /&gt;(simpson38-rule sine 0 Math/PI) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.040524284763495&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;booles-rule&lt;/span&gt; [f a b]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [midpoint1 (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a a a b) 4)&lt;br /&gt;        midpoint2 (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a a b b) 4)&lt;br /&gt;        midpoint3 (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;+&lt;/span&gt; a b b b) 4)]&lt;br /&gt;    (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/90 (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;+&lt;/span&gt; (&lt;span class="builtin"&gt;*&lt;/span&gt; 7 (f a)) (&lt;span class="builtin"&gt;*&lt;/span&gt; 32 (f midpoint1)) (&lt;span class="builtin"&gt;*&lt;/span&gt; 12 (f midpoint2)) (&lt;span class="builtin"&gt;*&lt;/span&gt; 32 (f midpoint3)) (&lt;span class="builtin"&gt;*&lt;/span&gt; 7 (f b))))))&lt;br /&gt;&lt;br /&gt;(booles-rule sine 0 Math/PI) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.9985707318238355&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can use the same approach to getting better estimates by subdividing: For&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;sine, as well as getting better estimates to start with, these rules have&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;high rates of convergence. It doesn't take many subdivisions before we start&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;to run into the limits of floating point accuracy.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(iterated-rule booles-rule sine 0 Math/PI 0) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.9985707318238355&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine 0 Math/PI 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.9999831309459855&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine 0 Math/PI 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.9999997524545716&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine 0 Math/PI 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.9999999961908446&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine 0 Math/PI 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.9999999999407074&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine 0 Math/PI 5) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.999999999999074&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine 0 Math/PI 6) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.9999999999999853&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine 0 Math/PI 7) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.9999999999999993&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine 0 Math/PI 8) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.9999999999999998&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule sine 0 Math/PI 9) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.9999999999999998&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(iterated-rule simpson38-rule sine 0 Math/PI 0) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.040524284763495&lt;br /&gt;&lt;/span&gt;(iterated-rule simpson38-rule sine 0 Math/PI 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.002009846628558&lt;br /&gt;&lt;/span&gt;(iterated-rule simpson38-rule sine 0 Math/PI 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.000119386415226&lt;br /&gt;&lt;/span&gt;(iterated-rule simpson38-rule sine 0 Math/PI 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.000007370036249&lt;br /&gt;&lt;/span&gt;(iterated-rule simpson38-rule sine 0 Math/PI 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.000000459216732&lt;br /&gt;&lt;/span&gt;(iterated-rule simpson38-rule sine 0 Math/PI 5) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.0000000286790867&lt;br /&gt;&lt;/span&gt;(iterated-rule simpson38-rule sine 0 Math/PI 6) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.0000000017921&lt;br /&gt;&lt;/span&gt;(iterated-rule simpson38-rule sine 0 Math/PI 7) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.000000000112001&lt;br /&gt;&lt;/span&gt;(iterated-rule simpson38-rule sine 0 Math/PI 8) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.0000000000069997&lt;br /&gt;&lt;/span&gt;(iterated-rule simpson38-rule sine 0 Math/PI 9) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.000000000000438&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;For the step function, however, boole's rule isn't really that much better&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;than the trapezium rule&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(iterated-rule booles-rule step 0 1 0) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5666666666666667&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule step 0 1 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5388888888888889&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule step 0 1 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5194444444444445&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule step 0 1 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5097222222222222&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule step 0 1 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5048611111111111&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule step 0 1 5) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5024305555555555&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule step 0 1 6) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5012152777777777&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule step 0 1 7) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5006076388888889&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule step 0 1 8) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5003038194444445&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule step 0 1 9) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5001519097222222&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Both seem to need double the number of points to halve their error.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(iterated-rule trapezium-rule step 0 1 0) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule step 0 1 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.75&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule step 0 1 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.625&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule step 0 1 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5625&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule step 0 1 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.53125&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule step 0 1 5) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.515625&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule step 0 1 6) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5078125&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule step 0 1 7) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.50390625&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule step 0 1 8) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.501953125&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule step 0 1 9) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.5009765625&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Performance is similarly bad for boole's rule on the inverse function&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(iterated-rule booles-rule inverse 0.0001 1 0) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;779.9400477089192&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule inverse 0.0001 1 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;391.7824297523124&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule inverse 0.0001 1 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;198.04899407170583&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule inverse 0.0001 1 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;101.52648013049377&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule inverse 0.0001 1 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;53.607079025964396&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule inverse 0.0001 1 5) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;29.984599583713347&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule inverse 0.0001 1 6) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;18.501553032592827&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule inverse 0.0001 1 7) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;13.071085113384171&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule inverse 0.0001 1 8) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;10.635953348374398&lt;br /&gt;&lt;/span&gt;(iterated-rule booles-rule inverse 0.0001 1 9) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.647557264415854&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(iterated-rule trapezium-rule inverse 0.0001 1 0) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;4999.99995&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule inverse 0.0001 1 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2500.9997750199977&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule inverse 0.0001 1 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1251.8327765203333&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule inverse 0.0001 1 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;627.5916420975113&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule inverse 0.0001 1 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;315.8156999790102&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule inverse 0.0001 1 5) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;160.27209317742054&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule inverse 0.0001 1 6) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;82.84288624590312&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule inverse 0.0001 1 7) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;44.46707207824598&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule inverse 0.0001 1 8) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;25.61044440290146&lt;br /&gt;&lt;/span&gt;(iterated-rule trapezium-rule inverse 0.0001 1 9) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;16.499072595032356&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So although it seems these higher order Newton-Cotes formulae are much more&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;accurate and faster converging on well behaved functions, they don't seem to&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;help much in integrating anything tricky.&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-3828516715693005805?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/3828516715693005805/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/05/numerical-integration-better-rules.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/3828516715693005805'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/3828516715693005805'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/05/numerical-integration-better-rules.html' title='Numerical Integration: Better Rules?'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-421188370810983405</id><published>2011-05-25T23:26:00.001+01:00</published><updated>2011-05-25T23:26:03.133+01:00</updated><title type='text'>Numerical Integration: Harder Functions</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;pre class="clojure-body"&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Numerical Integration: Harder Functions&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So far we've found a couple of approximations to 'the area under a graph'.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;trapezium-rule&lt;/span&gt; [f a b]&lt;br /&gt;  (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/2 (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;+&lt;/span&gt; (f a) (f b))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;simpson-rule&lt;/span&gt; [f a b]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [midpoint (&lt;span class="builtin"&gt;+&lt;/span&gt; a (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) 2))]&lt;br /&gt;    (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/6 (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;+&lt;/span&gt; (f a) (&lt;span class="builtin"&gt;*&lt;/span&gt; 4 (f midpoint)) (f b)))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And a way of repeatedly splitting intervals and applying the rules to the sub-intervals&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;to produce better and better approximations.&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;iterated-rule&lt;/span&gt; [rule f a b N]&lt;br /&gt;  (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; N 0)&lt;br /&gt;    (rule f a b)&lt;br /&gt;    (&lt;span class="keyword"&gt;let&lt;/span&gt; [midpoint (&lt;span class="builtin"&gt;+&lt;/span&gt; a (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) 2))]&lt;br /&gt;      (&lt;span class="builtin"&gt;+&lt;/span&gt; (iterated-rule rule f a midpoint (&lt;span class="builtin"&gt;dec&lt;/span&gt; N))&lt;br /&gt;         (iterated-rule rule f midpoint b (&lt;span class="builtin"&gt;dec&lt;/span&gt; N))))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We know that Simpson's rule is exact for our original function&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;square&lt;/span&gt;[x] (&lt;span class="builtin"&gt;*&lt;/span&gt; x x))&lt;br /&gt;&lt;br /&gt;(simpson-rule square 0 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;8/3&lt;br /&gt;&lt;/span&gt;(iterated-rule simpson-rule square 0 2 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;8/3&lt;br /&gt;&lt;/span&gt;(iterated-rule simpson-rule square 0 2 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;8/3&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;How do we do with some other functions?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Another function where we can calculate the answer directly is sine&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;sine&lt;/span&gt; [x] (Math/sin x))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The integral of sine over a half-turn (i.e. over the interval [0,pi]) is exactly 2.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;here are the first few approximations with the trapezium rule:&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; iterated-rule trapezium-rule sine 0 Math/PI) (&lt;span class="builtin"&gt;iterate&lt;/span&gt; inc 0)))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(1.9236706937217898E-16 1.5707963267948968 1.8961188979370398&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;1.9742316019455508 1.993570343772339 1.9983933609701445 1.9995983886400377&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;1.9998996001842024 1.9999749002350526 1.9999937250705755)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;After an inauspicious start, the answer is clearly settling down to 2.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Simpson's rule also settles down to 2, but it's much quicker.&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; iterated-rule simpson-rule sine 0 Math/PI) (&lt;span class="builtin"&gt;iterate&lt;/span&gt; inc 0)))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(2.094395102393196 2.0045597549844216 2.000269169948388 2.0000165910479364&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;2.000001033369414 2.0000000645300027 2.000000004032258 2.000000000252003&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;2.000000000015751 2.000000000000985)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So it looks like we're onto a winner so far.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Another type of function that doesn't do so well is:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;step&lt;/span&gt; [x]  (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;&amp;lt;&lt;/span&gt; x 1/2) 0 1))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It should be fairly obvious that the integral of this over [0,1] is 0.5, but&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;in fact the convergence of the methods is very slow compared to what we had&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;for sine or square.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; iterated-rule trapezium-rule step 0. 1) (&lt;span class="builtin"&gt;iterate&lt;/span&gt; inc 0)))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(0.5 0.75 0.625 0.5625 0.53125 0.515625 0.5078125 0.50390625 0.501953125 ...&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; iterated-rule simpson-rule step 0. 1) (&lt;span class="builtin"&gt;iterate&lt;/span&gt; inc 0)))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(0.8333333333333336 0.5833333333333335 0.5416666666666667 0.5208333333333335&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.5104166666666667 0.5052083333333335 0.5026041666666667 0.5013020833333335&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.5006510416666667 0.5003255208333335 )&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Notice how if we make the tiniest possible change to the function, which doesn't change the integral at all:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;evil-step&lt;/span&gt; [x]  (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;&amp;lt;=&lt;/span&gt; x 1/2) 0 1))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;the approximations are all changed quite a lot, although they do seem to&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;still converge to the correct answer.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; iterated-rule trapezium-rule evil-step 0. 1) (&lt;span class="builtin"&gt;iterate&lt;/span&gt; inc 0)))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(0.5 0.25 0.375 0.4375 0.46875 0.484375 0.4921875 0.49609375 0.498046875 0.4990234375)&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; iterated-rule simpson-rule evil-step 0. 1) (&lt;span class="builtin"&gt;iterate&lt;/span&gt; inc 0)))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(0.1666666666666667 0.4166666666666668 0.4583333333333335 0.4791666666666668&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.4895833333333335 0.4947916666666668 0.4973958333333335 0.4986979166666668&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.4993489583333335 0.4996744791666668)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What about if we're integrating a (moderately) badly behaved function?:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;inverse&lt;/span&gt; [x] (&lt;span class="builtin"&gt;/&lt;/span&gt; x))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;the real answer, by devious mathematical trickery is (log a) - (log b)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So if we integrate over the region [0.0001, 1], where the values of 1/x are&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;sometimes very large, we should get:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;-&lt;/span&gt; (Math/log 1) (Math/log 0.0001)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.210340371976182&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; iterated-rule trapezium-rule inverse 0.0001 1) (&lt;span class="builtin"&gt;iterate&lt;/span&gt; inc 0)))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(4999.99995 2500.9997750199977 1251.8327765203333 627.5916420975113&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;315.8156999790102 160.27209317742054 82.84288624590312 44.46707207824598&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;25.61044440290146 16.499072595032356)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; iterated-rule simpson-rule inverse 0.0001 1) (&lt;span class="builtin"&gt;iterate&lt;/span&gt; inc 0)))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(1667.9997166933313 835.4437770204453 419.5112639565708 211.89038593950997&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;108.42422424355732 57.03315060206397 31.67513402236028 19.324901844453297&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;13.461948659075995 10.812578055293251)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It looks like both the rules, after starting off with appalling first&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;guesses, are converging to something, and maybe even to the right answer, but&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;the convergence is very slow.  Remember that to get the tenth element of this&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;sequence we're splitting the interval up into 1024 pieces, and we haven't&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;even got the answer right to one significant figure.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Numerical Integration can give very misleading answers if it's used naively.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Quite often, the results of a careless numerical simulation will just 'look&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;wrong' to a trained eye, and in those cases it's usually the eye that's in&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;the right.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;One way to be reassured that your answer is roughly correct is to alter&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;expected degree of accuracy of the method, and to check that the answer&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;doesn't change by much!&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-421188370810983405?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/421188370810983405/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/05/numerical-integration-harder-functions.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/421188370810983405'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/421188370810983405'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/05/numerical-integration-harder-functions.html' title='Numerical Integration: Harder Functions'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-2338549771258159451</id><published>2011-05-25T22:37:00.002+01:00</published><updated>2011-05-25T22:37:38.759+01:00</updated><title type='text'>Numerical Integration: Better Approximations</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;pre class="clojure-body"&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Numerical Integration: Better Approximations&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Remember our example function:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;square&lt;/span&gt;[x] (&lt;span class="builtin"&gt;*&lt;/span&gt; x x))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We're trying to find ways to calculate the 'area under its graph between 0&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and 2', or the 'integral over the interval [0,2]'&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;A better estimate of this area under the graph is to imagine a trapezium&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;which has its base corners at (0,0) and (2,0), and the top corners at&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(0,(square 0)) (2, (square 2)), and calculate the area of that.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;More generally, if the interval we're interested is [a,b], and the function's&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;values there are fa and fb, then the area of the trapezium will just be:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;trapezium&lt;/span&gt; [a fa b fb]&lt;br /&gt;  (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/2 (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;+&lt;/span&gt; fa fb)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Another way to think about that is that it's the length of the interval&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;multiplied by the average of the values of the function at the ends.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So another approximation to the integral of f over [a,b] is:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;trapezium-rule&lt;/span&gt; [f a b]&lt;br /&gt;  (trapezium a (f a) b (f b)))&lt;br /&gt;&lt;br /&gt;(trapezium-rule square 0 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;4&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can make another approximation by using the trapezium rule on the two&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;subintervals [0,1] and [1,2] and adding the results&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;+&lt;/span&gt; (trapezium-rule square 0 1)&lt;br /&gt;   (trapezium-rule square 1 2)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;3&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And an even better one by splitting those subintervals in half&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;+&lt;/span&gt; (trapezium-rule square 0 1/2)&lt;br /&gt;   (trapezium-rule square 1/2 1)&lt;br /&gt;   (trapezium-rule square 1 3/2)&lt;br /&gt;   (trapezium-rule square 3/2 2)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;11/4&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And so on...&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;iterated-rule&lt;/span&gt; [rule f a b N]&lt;br /&gt;  (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; N 0)&lt;br /&gt;    (rule f a b)&lt;br /&gt;    (&lt;span class="keyword"&gt;let&lt;/span&gt; [midpoint (&lt;span class="builtin"&gt;+&lt;/span&gt; a (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) 2))]&lt;br /&gt;      (&lt;span class="builtin"&gt;+&lt;/span&gt; (iterated-rule rule f a midpoint (&lt;span class="builtin"&gt;dec&lt;/span&gt; N))&lt;br /&gt;         (iterated-rule rule f midpoint b (&lt;span class="builtin"&gt;dec&lt;/span&gt; N))))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;This converges fairly nicely:&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; iterated-rule trapezium-rule square 0 2) (&lt;span class="builtin"&gt;range&lt;/span&gt; 10))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(4 3 11/4 43/16 171/64 683/256 2731/1024 10923/4096 43691/16384 174763/65536)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; - 8/3)&lt;br /&gt;     (&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; iterated-rule trapezium-rule square 0 2) (&lt;span class="builtin"&gt;range&lt;/span&gt; 10)))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(-4/3 -1/3 -1/12 -1/48 -1/192 -1/768 -1/3072 -1/12288 -1/49152 -1/196608)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We now only need a thousand samples of the function to get the answer&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;accurate to one part in 100000.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But an even nicer approximation is Simpson's rule, which involves fitting a&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;parabola to the two end points and the midpoint, and calculating the area&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;under that.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;That's equivalent to taking a weighted sum of the values of f at the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;beginning, midpoint, and end of the interval, with weights 1:4:1&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;simpson-rule&lt;/span&gt; [f a b]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [midpoint (&lt;span class="builtin"&gt;+&lt;/span&gt; a (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) 2))]&lt;br /&gt;    (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/6 (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;+&lt;/span&gt; (f a) (&lt;span class="builtin"&gt;*&lt;/span&gt; 4 (f midpoint)) (f b)))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;For the square function, which is itself a parabola, this rule actually&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;calculates the area exactly!&lt;br /&gt;&lt;/span&gt;(simpson-rule square 0 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;8/3&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;That about wraps it up for numerical approximations to the integrals of&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;quadratics, but they are easy to calculate exactly anyway.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-2338549771258159451?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/2338549771258159451/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/05/numerical-integration-better.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/2338549771258159451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/2338549771258159451'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/05/numerical-integration-better.html' title='Numerical Integration: Better Approximations'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-8482838723313979031</id><published>2011-05-25T22:07:00.001+01:00</published><updated>2011-05-25T23:41:54.250+01:00</updated><title type='text'>Numerical Integration: What is an Integral?</title><content type='html'>I've found myself needing to take a few difficult integrals recently, as part of some machine learning algorithms, and I ended up calculating them with numerical approximations.&lt;br /&gt;&lt;br /&gt;Frustration at the amount of time they were taking lead me to progressively improve my methods, which got very much faster as I played with them.&lt;br /&gt;&lt;br /&gt;Weirdly, my initial instincts had been to translate my programs into either C or Java, which might well have resulted in 100x speed ups over the obvious implementations in Clojure, but in fact the clarity of expression afforded by writing in a language where recursion is a natural thing to do lead me, by making fairly obvious changes, to some very fast algorithms.&lt;br /&gt;&lt;br /&gt;Of course, I could still translate them to C or Java, or optimized Clojure, and they'd still get a lot faster, but it hardly seems worth the bother now.&lt;br /&gt;&lt;br /&gt;&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;br /&gt;&lt;pre class="clojure-body"&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Numerical Integration I: What is an integral, anyway?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What does it mean to 'evaluate the integral' of a function over an interval?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's take an example function&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;square&lt;/span&gt;[x] (&lt;span class="builtin"&gt;*&lt;/span&gt; x x))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We could evaluate it at a few input values:&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; square [0 1 2]) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(0 1 4)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The integral of a function over an interval is a sort of&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;'average sum over all the possible values in the interval'.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;A first approximation to the integral of square over the interval [0,2]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;would be to say:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's pretend that the value of square between 0 and 1 is like (square 0)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and the value between 1 and 2 is like (square 1)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So to find our approximation we add (square 0) to (square 1):&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; square [0 1])) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Another approximation, equally valid, would be to say that the value between&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0 and 1 is like (square 1) so we could equally well add the value at 1 to the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;value at 2&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; square [1 2])) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;5&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;These answers are quite different! One is too low, because we paid too much&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;attention to the numbers at the start of the sub-ranges. One is too high,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;because we added up numbers from the ends.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can make both answers more accurate by sampling the function at more&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;points, and dividing the sum by an appropriate factor to make up for having&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;more points.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; square [0 1/2 1 3/2]  )) 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;7/4&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; square   [1/2 1 3/2 2])) 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;15/4&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can continue the procedure, sampling the function at twice as many points again:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; square [0 1/4 1/2 3/4 1 5/4 6/4 7/4]  )) 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;35/16&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; square   [1/4 1/2 3/4 1 5/4 6/4 7/4 2])) 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;51/16&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It's clear that these values will get closer to one another the more points&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;we sample at&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If we continue the procedure indefinitely:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;riemann-lower-sum&lt;/span&gt; [f a b N]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [points (&lt;span class="builtin"&gt;range&lt;/span&gt; a b (&lt;span class="builtin"&gt;/&lt;/span&gt; N))]&lt;br /&gt;    (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; f points)) N)))&lt;br /&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; riemann-lower-sum square 0 2) (&lt;span class="builtin"&gt;iterate&lt;/span&gt; inc 1)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(1 7/4 55/27 35/16 57/25 253/108 ...)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We find that the answers settle down to a particular number, and in this case&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;it looks like they're settling down to 8/3&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;However we do need to take quite a lot of samples to make the approximation get close!&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;take&lt;/span&gt; 15 (&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; - 8/3)&lt;br /&gt;              (&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; riemann-lower-sum square 0 2)&lt;br /&gt;                   (&lt;span class="builtin"&gt;iterate&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; * 2) 1))))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(5/3 11/12 23/48 47/192 95/768 191/3072 383/12288 767/49152 1535/196608&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;3071/786432 6143/3145728 12287/12582912 24575/50331648 49151/201326592&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;98303/805306368)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The last number here is what we get if we keep splitting our sub-intervals in&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;half fifteen times, and that's quite a lot of sub-intervals. (1, 2, 4, 8, 16 ...)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Strictly speaking, the riemann lower sum is a sum of the lowest values of&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;the function on the subintervals, but because the square function is&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;monotonically increasing over our range, the function as we defined it has&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;the same value.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If this procedure has a limit, then the integral is defined as this limit.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;For well behaved functions, this limit will exist.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The limit can be thought of as the area under the graph of f from a to b.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;At school we learn to calculate this limit by finding an antiderivative to&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;the original function, and calculating how much it changes over the interval.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;An antiderivative of (fn[x] (* x x)) is (fn[x] (* 1/3 x x x))&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;let&lt;/span&gt; [anti (&lt;span class="builtin"&gt;fn&lt;/span&gt;[x] (&lt;span class="builtin"&gt;*&lt;/span&gt; 1/3 x x x))]&lt;br /&gt;  (&lt;span class="builtin"&gt;-&lt;/span&gt; (anti 2) (anti 0))) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;8/3&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Although this is clearly a much better way to calculate integrals than by&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;taking millions of function samples and adding them up, it's often quite hard&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;to find antiderivatives even for quite simple functions, and for some quite&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;simple functions, no easily expressible antiderivative exists.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So we quite often find ourselves needing to calculate approximations by computer,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and this is called numerical integration.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-8482838723313979031?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/8482838723313979031/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/05/numerical-integration-what-is-integral.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/8482838723313979031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/8482838723313979031'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/05/numerical-integration-what-is-integral.html' title='Numerical Integration: What is an Integral?'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-8149809029024763110</id><published>2011-05-04T01:06:00.000+01:00</published><updated>2011-05-04T01:06:26.248+01:00</updated><title type='text'>Clojure Inference (reduce, cl-format, Poisson distribution, Bayes)</title><content type='html'>Apologies for the mathematical nature of this post.&amp;nbsp;It's just what I happen to be thinking about at the moment.&lt;br /&gt;&lt;br /&gt;Although actually apart from the formula for a Poisson distribution, it's all just philosophy and counting and adding up and taking averages.&lt;br /&gt;&lt;br /&gt;I published it here because:&lt;br /&gt;(a) It's a nice example of how lovely a language clojure is for exploring mathematics.&lt;br /&gt;(b) It's got reduce in it. a lot.&lt;br /&gt;(c) I use cl-format to print lists of lists of floats, and I had to look through the common lisp docs to remember how to do that. I couldn't find any nice clojure examples to crib from.    &lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      .string {        /* font-lock-string-face */        color: #ffa500;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;br /&gt;&lt;br /&gt;&lt;pre class="clojure-body"&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;A Poisson Process&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Imagine a very lot of things, each of which has a very small chance of&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;happening, so that on average, only a few things happen every second.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;A classic case is radioactivity, where we've got a very large number of&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;atoms, each of which has a very small chance of exploding in any given&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;second.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We might know the average number of decays per second without having the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;slightest idea what the large number or the small chance are.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Alternatively, we might just know what the sample did over a one second&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;period, and be trying to guess what the constant is.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In probability, we model this situation with a Poisson process.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;This cryptic function gives the probabilities, for a given decay rate l&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;of each of the numbers we might read on our Geiger counter.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I'm ashamed to say that although I wrote this function and can prove these&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;are the probabilities, I can't come up with an easy way to explain why it&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;gives the right answers. You have to imagine what the probabilities are for&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;larger and larger numbers but smaller and smaller chances, keeping the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;average the same, and notice that they settle down as the numbers get&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;bigger. These are the limits:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;poisson&lt;/span&gt; [l]&lt;br /&gt;  (&lt;span class="builtin"&gt;map&lt;/span&gt; first&lt;br /&gt;       (&lt;span class="builtin"&gt;iterate&lt;/span&gt;&lt;br /&gt;        (&lt;span class="builtin"&gt;fn&lt;/span&gt; [[a c]] [(&lt;span class="builtin"&gt;/&lt;/span&gt;(&lt;span class="builtin"&gt;*&lt;/span&gt; a l) (&lt;span class="builtin"&gt;inc&lt;/span&gt; c)) (&lt;span class="builtin"&gt;inc&lt;/span&gt; c)])&lt;br /&gt;        [(Math/exp (&lt;span class="builtin"&gt;-&lt;/span&gt; l)) 0])))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So let's just take this as the definition of a Poisson process, and have a&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;look at what it means.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Clojure has inherited common lisp's excellent format function, so by casting&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;one cryptic spell we can print out the probabilities for the first few geiger&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;counter readings, if the average decay rate is one click/second.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(clojure.pprint/cl-format nil &lt;span class="string"&gt;"~{~$~^, ~}"&lt;/span&gt; (&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (poisson 1)))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;"0.37, 0.37, 0.18, 0.06, 0.02, 0.00, 0.00, 0.00, 0.00, 0.00"&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;One way of looking at this is to say that if we ran the experiment one&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;hundred times, then we'd expect that 37 times we'd hear no clicks, 37 times&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;we'd get one click, 18 times we'd get two, 6 times we'd get three, and twice&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;we'd get four. Sort of. Although actually we'd be quite surprised if that&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;happened.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;As a sanity check, let's work out what our expected number of clicks is here.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We know it should be one.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(reductions +&lt;br /&gt;            (&lt;span class="builtin"&gt;map&lt;/span&gt; *&lt;br /&gt;                 (poisson 1)&lt;br /&gt;                 (&lt;span class="builtin"&gt;range&lt;/span&gt;)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(0.0 0.36787944117144233 0.7357588823428847 0.9196986029286058 0.9810118431238463 0.9963401531726563 0.9994058151824183 0.999916758850712 0.9999897508033253 0.999998874797402 0.9999998885745216 0.9999999899522336 0.9999999991683892 0.9999999999364022 0.9999999999954802 0.9999999999997 0.9999999999999813 0.9999999999999989 0.9999999999999999 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 ...)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If we include enough terms we do indeed get one.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I enjoyed that. Let's try it again for a process with constant 7.5&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(reductions +&lt;br /&gt;            (&lt;span class="builtin"&gt;map&lt;/span&gt; *&lt;br /&gt;                 (poisson 7.5)&lt;br /&gt;                 (&lt;span class="builtin"&gt;range&lt;/span&gt;)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;(0.0 0.0041481327761087525 0.0352591285969244 0.15192536292498304 0.44359094874512967 0.9904639221579046 1.810773382277067 2.83616020742602 3.934788948657041 4.964753393561123 5.823057097647858 6.46678487571291 6.905690178939081 7.180005993455438 7.338265117214875 7.4230467906574304 7.465437627378708 7.485308332091806 7.494074819465232 7.497727522537493 7.499169379013385 7.499710075191845 7.499903180969866 7.499969012485101 7.4999904792835475 7.499997187658062 7.499999200170416 7.499999780702826 7.499999941961828 7.4999999851562045 7.499999996327164 7.499999999119903 7.499999999795566 7.499999999953925 7.499999999989916 7.499999999997855 7.499999999999556 7.49999999999991 7.499999999999982 7.4999999999999964 7.499999999999999 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 7.5 ...)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Neat huh?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The philosophical foundations of probability theory are completely incoherent&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;as far as I can tell, so I've always felt free to believe whatever I like as&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;long as it means my intuition leads me to the right answers.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I've found that for me, intuition is best served by imagining that we have a&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;vast number of parallel universes, and in them the results of the experiments&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;are spread out in the proportions given by the formula.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It's fair to say that this position is controversial.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If we take the numbers to three significant figures:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(clojure.pprint/cl-format nil &lt;span class="string"&gt;"~{~3$~^, ~}"&lt;/span&gt; (&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (poisson 1)))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;"0.368, 0.368, 0.184, 0.061, 0.015, 0.003, 0.001, 0.000, 0.000, 0.000"&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Then we'll notice that there are some very rare universes where we get five&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;clicks, or even six from a process where the average number of clicks/second&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;is one.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In fact none of the numbers is really zero. There will be some universes&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;where the whole radioactive sample decays at once.  It's probably best not to&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;be near the sample in those universes, but fortunately they're very rare.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(clojure.pprint/cl-format nil &lt;span class="string"&gt;"~{~6$~^, ~}"&lt;/span&gt; (&lt;span class="builtin"&gt;take&lt;/span&gt; 0 (poisson 1)))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;"0.367879, 0.367879, 0.183940, 0.061313, 0.015328, 0.003066, 0.000511, 0.000073, 0.000009, 0.000001"&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It turns out we need to sift through a million universes to have a good&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;chance of finding one where nine decays happen in one second. It would be a&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;cold day in hell before you found one where there were twenty.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Imagine that we're pointing a photon detector at a distant star, and we want&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;to make a guess at how bright it is.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Photons happening to hit your detector is very much the same sort of problem&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;as radioactive decays hitting your geiger counter.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's imagine that we've got an absolute stack of parallel universes.  In&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;some of them, the constant for the star is 1, in some it's 2, etc, right up&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;to 20, and those constants are all equally likely&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can calculate the proportions of those universes where we see all the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;different numbers of photons.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Photons across the top, 0-9. Star types down the side, 1-20.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(clojure.pprint/cl-format nil &lt;span class="string"&gt;"~{~{~$~^,~}~% ~}"&lt;/span&gt; (&lt;span class="builtin"&gt;map&lt;/span&gt; #(&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (poisson %)) (&lt;span class="builtin"&gt;range&lt;/span&gt; 1 21)))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.37,0.37,0.18,0.06,0.02,0.00,0.00,0.00,0.00,0.00&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.14,0.27,0.27,0.18,0.09,0.04,0.01,0.00,0.00,0.00&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.05,0.15,0.22,0.22,0.17,0.10,0.05,0.02,0.01,0.00&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.02,0.07,0.15,0.20,0.20,0.16,0.10,0.06,0.03,0.01&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.01,0.03,0.08,0.14,0.18,0.18,0.15,0.10,0.07,0.04&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.00,0.01,0.04,0.09,0.13,0.16,0.16,0.14,0.10,0.07&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.00,0.01,0.02,0.05,0.09,0.13,0.15,0.15,0.13,0.10&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.00,0.00,0.01,0.03,0.06,0.09,0.12,0.14,0.14,0.12&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.00,0.00,0.00,0.01,0.03,0.06,0.09,0.12,0.13,0.13&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.00,0.00,0.00,0.01,0.02,0.04,0.06,0.09,0.11,0.13&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.00,0.00,0.00,0.00,0.01,0.02,0.04,0.06,0.09,0.11&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.00,0.00,0.00,0.00,0.01,0.01,0.03,0.04,0.07,0.09&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.00,0.00,0.00,0.00,0.00,0.01,0.02,0.03,0.05,0.07&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.00,0.00,0.00,0.00,0.00,0.00,0.01,0.02,0.03,0.05&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.01,0.02,0.03&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.01,0.01,0.02&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.01,0.01&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.01&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The way I read this table is:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We had a look in several hundred parallel universes where we did the experiment.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In thirty seven of them, the star constant was one, and we saw no photons in our detector.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In another thirty seven, the star constant was one, but we saw one photon.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;There were four universes where the star constant was five, and we saw nine photons.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So what should we believe if we point a photodetector at a star and detect 9&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;photons in one second?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Well, what we're trying to do is work out what the star constant is.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And what we know is that we're in one of the universes where we counted nine photons.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I.e. we know that we're in the last row of the table.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's have a look at that last row:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(clojure.pprint/cl-format nil &lt;span class="string"&gt;"~{~$~^,~}"&lt;/span&gt; (&lt;span class="builtin"&gt;map&lt;/span&gt; #(&lt;span class="builtin"&gt;nth&lt;/span&gt; (poisson %) 9) (&lt;span class="builtin"&gt;range&lt;/span&gt; 1 21)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;"0.00,0.00,0.00,0.01,0.04,0.07,0.10,0.12,0.13,0.13,0.11,0.09,0.07,0.05,0.03,0.02,0.01,0.01,0.00,0.00"&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What is the total number of the universes that we could be in?&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; #(&lt;span class="builtin"&gt;nth&lt;/span&gt; (poisson %) 9) (&lt;span class="builtin"&gt;range&lt;/span&gt; 1 21)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0.9963258860986628&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Call it 100&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Counting along, we see that there's about a 13% chance that we're in a&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;universe where the constant is 9&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And about a 13% chance that the constant is 10&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And a one percent chance that the constant is 4 and that was a particularly lucky second to measure.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And a one percent chance that the constant is 18 and it was a particularly bad second to measure in.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We might even want to say that there's an 88% chance that the constant is between 6 and 14.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Or a half chance that it's 8, 9, 10, or 11&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;As you might have guessed in advance, nine, the number of photons that we&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;actually saw in a second, is probably our best guess at the average number of&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;photons we'll see per second from now on. In classical statistics we'd call&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;that the maximum likelihood estimator, or an unbiased estimator, but in fact&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;there's only a 13% chance that it's the right answer.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Probably better just to keep the distribution above in mind.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What's the expected number of photons per second we'll see if we now run our&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;counter for a while?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Remember that we're assuming that stars come in discrete varieties 1-20&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and that we saw 9 photons.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;expected-rate&lt;/span&gt; [ stars photons ]&lt;br /&gt;  (&lt;span class="builtin"&gt;/&lt;/span&gt; &lt;br /&gt;   (&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; *&lt;br /&gt;                  stars&lt;br /&gt;                  (&lt;span class="builtin"&gt;map&lt;/span&gt; #(&lt;span class="builtin"&gt;nth&lt;/span&gt; (poisson %) photons) stars)))&lt;br /&gt;   (&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; #(&lt;span class="builtin"&gt;nth&lt;/span&gt; (poisson %) photons) stars))))&lt;br /&gt;&lt;br /&gt;(expected-rate (&lt;span class="builtin"&gt;map&lt;/span&gt; inc (&lt;span class="builtin"&gt;range&lt;/span&gt; 20)) 9) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.955123984139409&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;This strikes me as very weird.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We've seen 9 photons. Surely, given no more information than that, our best&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;guess should be that we'll see 9 photons/second?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Consider some edge cases.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What about if the stars are only ever of brightness one?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(expected-rate '(1) 9) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.0&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;That's definitely right. We must have just been really lucky to catch nine&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;photons at once. Since we're *sure* that the star is brightness one, the long&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;term estimate has to be one.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Here we're in complete agreement with the maximum likelihood estimator, and&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;disagree violently with the unbiased estimator.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What about if stars come in brightnesses 1 or 10?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(expected-rate '(1 10) 9) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.999927072835586&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Again, fair enough. Chances are it was a brightness 10 star behaving&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;normally, but there's a very small chance that it was a brightness 1 star&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;having a very good second.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If we run our experiment often enough, the average value will be pulled down&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;a tiny bit by those cases.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What if we saw 5 photons?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(expected-rate '(1 10) 5) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.325386911283335&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Pretty much the same. But now we have to take more seriously the chance now&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;that it was a weak star having a field day rather than a bright star having a&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;half-hearted go.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If you're having to budget for photons for some reason, then 9.32 is an&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;unbelievably bad answer. Your budget is going to need to be 10 or 1 exactly.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But if you're placing a bet at a bookmaker's, or buying photon insurance from&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;a company with a presence in lots of parallel universes, then 9.33 might well&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;be a fair price. Everyone's got to make a profit.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(expected-rate '(1 10) 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.1097148350481423&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Same sort of thing. About one time in a hundred, two photons will have been&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;emitted by a brightness 10 star rather than a brightness 1 star. However that&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;occasional much brighter star will skew the results noticeably.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;These answers all look about right to me:&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; expected-rate '(1 10)) (&lt;span class="builtin"&gt;range&lt;/span&gt; 20)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(1.001110551183876 1.0110931922809403 1.1097148350481423 1.9886759335192858 5.97152862794323 9.325386911283335 9.927658434429095 9.992713129077847 9.999270781535703 9.999927072835586 9.999992707230374 9.999999270722506 9.999999927072245 9.999999992707224 9.999999999270722 9.999999999927073 9.999999999992706 9.999999999999272 9.999999999999927 9.999999999999993)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The dodgy case is when we see 4 photons.  Brightness one stars have about a&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;2% chance of producing 4 photons, and brightness ten stars have about a 2%&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;chance as well.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So half the time, we've got a 1, and half the time, we've got a 10.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So we're expecting to get a long term average of 10 half the time, and 1 the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;other half.  And therefore we expect to see around 5.5 photons/second if we&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;add up all our experiments.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But I still find this weird:&lt;br /&gt;&lt;/span&gt;(expected-rate (&lt;span class="builtin"&gt;map&lt;/span&gt; inc (&lt;span class="builtin"&gt;range&lt;/span&gt; 20)) 9) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;9.955123984139409&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;However the whole range of photons that we can receive behaves correctly:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; expected-rate (&lt;span class="builtin"&gt;map&lt;/span&gt; inc (&lt;span class="builtin"&gt;range&lt;/span&gt; 20))) (&lt;span class="builtin"&gt;range&lt;/span&gt; 40) ) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(1.5819766656462542 2.163952866521654 3.0148662995404725 3.9961819317191947 4.9990309464433125 5.9993253251689005 6.997434541967013 7.992370962274987 8.980384871785288 9.955123984139409 10.90739733739242 11.825629164415346 12.697213993063654 13.510414954047969 14.256168445529575 14.92921796885468 15.52834070305211 16.055807374000462 16.516421661779617 16.916484374585746 17.262908595847506 17.562577608383947 17.821943140115458 18.04681608289834 18.242291371716 18.412756086521956 18.56194298618969 18.69300434170798 18.808590810798304 18.910926944365613 19.00187928605607 19.08301562443344 19.15565538916098 19.22091189359721 19.27972741592878 19.332902168984916 19.381118149636865 19.424958748228278 19.464924873069005 19.501448223241248)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If we get no photons at all, then we've probably got a low brightness star.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It'll most likely be a one, might well be a two, could be a three, and so on.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So we know the mean *must* be bigger than one.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Lots of photons is telling us that we've probably got a twenty, but might&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;have a 19, and could have an 18, so the mean should be less than 20.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;That's enough evidence of correctness that I believe my calculation, even&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;though at first I was pretty sure that I'd made an off-by-one error&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;somewhere.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If anyone's still reading, can they see whether I got it right or not?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;This way of calculating things is called Bayesian Statistics, after the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Reverend Thomas Bayes.  It's very general, but was considered to be just a&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;curiosity until computers came along and made it possible to do these&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;calculations on real problems.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Poisson processes are a nice simple case that I happened to be thinking about&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;as a result of reading David Mackay's beautiful book Information Theory,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Inference, and Learning Algorithms. The nice thing is that the techniques&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;work for any distributions or sets of models at all.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;This half-witted way of thinking about what the calculations mean is my own,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and I don't want to blame it on Bayes or anyone else. But it works for me.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt; &lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;This is a more conventional way to calculate the chance of a Poisson&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;distribution with constant 9 producing 7 events:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;/&lt;/span&gt;&lt;br /&gt; (&lt;span class="builtin"&gt;*&lt;/span&gt; (Math/exp -9)&lt;br /&gt;    (&lt;span class="builtin"&gt;reduce&lt;/span&gt; * (&lt;span class="builtin"&gt;repeat&lt;/span&gt; 7 9)))&lt;br /&gt; (&lt;span class="builtin"&gt;reduce&lt;/span&gt; * (&lt;span class="builtin"&gt;map&lt;/span&gt; inc (&lt;span class="builtin"&gt;range&lt;/span&gt; 7)))) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.11711612445290907&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But it produces the same answer as mine.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;nth&lt;/span&gt; (poisson 9) 7) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.11711612445290907&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Proof by it totally works on this example.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-8149809029024763110?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/8149809029024763110/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/05/clojure-inference-reduce-cl-format.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/8149809029024763110'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/8149809029024763110'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/05/clojure-inference-reduce-cl-format.html' title='Clojure Inference (reduce, cl-format, Poisson distribution, Bayes)'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-391854852453159678</id><published>2011-04-06T21:01:00.002+01:00</published><updated>2011-11-21T14:02:58.257Z</updated><title type='text'>Favourite keys for EMACS and SLIME</title><content type='html'>&lt;div style="color: black;"&gt;&lt;span class="Apple-style-span"&gt;I made this post about two years ago. It's been really useful to me, and over the years I've added more commands. These are all the things that make emacs a joy and a horror for clojure editing for me.&lt;/span&gt;&lt;/div&gt;&lt;div style="color: black;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="color: black;"&gt;&lt;span class="Apple-style-span"&gt;Emacs is weird. I often hate it for how much it distracts me from what I'm actually trying to do. And yet when I try to use any other editor, I find myself missing emacs features so much that I end up going back to it. And the more you learn about it, the more addicted you get.&lt;/span&gt;&lt;/div&gt;&lt;div style="color: black;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="color: black;"&gt;&lt;span class="Apple-style-span"&gt;I think that there are fundamental usability mistakes in emacs, mostly to do with its habit of rearranging your windows. It was a great relief when I found out that you can store the window arrangement in a register, and then create a key that says 'put it all back! (you bastard)'. I dream of an editor as powerful as emacs but with a sanely designed UI that obeys modern conventions.&lt;/span&gt;&lt;/div&gt;&lt;div style="color: black;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="color: black;"&gt;&lt;span class="Apple-style-span"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="color: black;"&gt;&lt;span class="Apple-style-span"&gt;In a very real sense, an editor that is to emacs as clojure is to common lisp. What would be wonderful is if it lived in clojure's standard library like idle does for python.&lt;/span&gt;&lt;/div&gt;&lt;div style="color: black;"&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="color: black;"&gt;&lt;span class="Apple-style-span"&gt;On the other hand, having got the hang of emacs for clojure editing, it very rarely distracts me these days, and in that mode it's a pure joy. I wouldn't use any other tool. It mainly drives me up the wall now when I'm trying to use it to program in some other language.&lt;/span&gt;&lt;/div&gt;&lt;div style="color: black;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="color: black;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="color: black;"&gt;&lt;span class="Apple-style-span"&gt;&lt;span style="color: red;"&gt;(Latest: It was an even greater relief when I found winner-mode, which gives you a key for 'put them back the way they were just now, you stupid bastard'. In fact it gives you an undo history.&amp;nbsp; I've been using that for a while now, and it's great.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="color: black;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="color: black;"&gt;&lt;span class="Apple-style-span"&gt;&lt;span style="color: red;"&gt;I do wonder if the very fact that you can eventually hack the damned thing around so much that it stops being annoying is what has prevented people from starting the programmable editor project again from scratch but starting with something a bit more modern. )&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="color: black;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;the Editor for Middle Aged Computer Scientists &lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Is a very good way of editing Clojure, once you have slime and swank installed.&lt;br /&gt;&lt;br /&gt;However, the key combinations don't stay in the brain very well if you don't use it all the time, so I thought I'd write down my favourite keys for Clojure editing whilst I'm using it every day, to serve as a cheat sheet for others, and for me in a few months time.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;General Editing Keys&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;C-h m&lt;br /&gt;describe the mode you're in&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;C-/&lt;br /&gt;Incomprehensible undo&lt;br /&gt;&lt;br /&gt;C-w&amp;nbsp;&amp;nbsp;&amp;nbsp; cut&lt;br /&gt;M-w&amp;nbsp;&amp;nbsp; copy&lt;br /&gt;C-y&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; paste&lt;br /&gt;M-y&amp;nbsp;&amp;nbsp;&amp;nbsp; paste the next most recent thing instead&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;C-x 0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; kill this window&lt;br /&gt;C-x 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; make this window the only window&lt;br /&gt;&lt;br /&gt;C-x 2&lt;br /&gt;C-x 3&amp;nbsp; split the window (vertically and horizontally)&lt;br /&gt;&lt;br /&gt;C-x o&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; go to other window&lt;br /&gt;&lt;br /&gt;M-g M-g&amp;nbsp;&amp;nbsp;&amp;nbsp; go to a particular line by number&lt;br /&gt;&lt;br /&gt;C-x h &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; mark whole buffer&lt;br /&gt;&lt;br /&gt;M-q &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; reformat paragraph. good for long comments&lt;br /&gt;&lt;br /&gt;M-&amp;lt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; beginning&lt;br /&gt;M-&amp;gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; and end of file&lt;br /&gt;&lt;br /&gt;C-x C-+&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; adjust the font size (nice repeating behaviour, try C-x C-+ C-+)&lt;br /&gt;C-x C- -&lt;br /&gt;&lt;br /&gt;There's a nice list of useful keys at&lt;br /&gt;&lt;a href="http://www.math.uh.edu/%7Ebgb/emacs_keys.html"&gt;http://www.math.uh.edu/~bgb/emacs_keys.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And this is a nice guide &lt;br /&gt;&lt;a href="http://www.gnu.org/software/emacs/tour/%20"&gt;http://www.gnu.org/software/emacs/tour/ &lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Keyboard Macros&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;C-x (&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; start recording&lt;br /&gt;C-x )&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; stop&lt;br /&gt;&lt;br /&gt;C-x e&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; execute (then e to reexecute immediately)&lt;br /&gt;C-u 10 C-x e&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; execute 10 times&lt;br /&gt;&lt;br /&gt;C-x C-k C-p &amp;nbsp; move backwards&lt;br /&gt;C-x C-k C-n &amp;nbsp; and forwards in the macro ring &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Also see: &lt;a href="http://www.emacswiki.org/emacs/KeyboardMacros"&gt;http://www.emacswiki.org/emacs/KeyboardMacros&lt;/a&gt;&lt;br /&gt;and: &lt;a href="http://www.gnu.org/software/emacs/manual/html_node/emacs/Keyboard-Macros.html#Keyboard-Macros"&gt;http://www.gnu.org/software/emacs/manual/html_node/emacs/Keyboard-Macros.html#Keyboard-Macros&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Search&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;C-s forward and reverse incremental search&lt;br /&gt;C-r&lt;br /&gt;&lt;br /&gt;Afterwards RET drops you in the buffer, then C-x C-x should get you back because mark was set at the start of the search!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Slimey stuff &lt;/b&gt;&lt;br /&gt;&lt;br /&gt;M-x slime &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; start slime and a clojure instance&lt;br /&gt;M-x slime-connect&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; start slime, connect to a running swank server&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;F12&amp;gt; r &amp;nbsp; find the slime REP&lt;br /&gt;&amp;lt;F12&amp;gt; j &amp;nbsp;&amp;nbsp; find the clojure buffers&lt;br /&gt;(well, that's what it means once you've made this hack in your .emacs file)&lt;br /&gt;&lt;div&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;;;bind the slime selector to f12 and add a method for finding clojure buffers&lt;br /&gt;(define-key global-map (kbd "&amp;lt;f12&amp;gt;") 'slime-selector)&lt;br /&gt;(def-slime-selector-method ?j&lt;br /&gt;&amp;nbsp; "most recently visited clojure-mode buffer."&lt;br /&gt;&amp;nbsp; (slim&lt;/code&gt;e-recently-visited-buffer 'clojure-mode))&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Completion of Symbols&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;C-c TAB slime-complete-symbol&lt;br /&gt;M-/&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Switching Namespace&lt;/b&gt;&lt;br /&gt;C-c M-p&lt;br /&gt;&lt;br /&gt;&lt;b&gt;At the REPL&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;M-p M-n&amp;nbsp;&amp;nbsp; previous and next in history&lt;br /&gt;&lt;br /&gt;C-x C-o &amp;nbsp; &amp;nbsp; flush the last output &lt;br /&gt;C-x M-o&amp;nbsp;&amp;nbsp;&amp;nbsp; flush the whole REPL buffer&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Lisp editing and evaluating keys&amp;nbsp; &lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Note that in Gnome, Ctrl-Alt-D is 'show desktop', Ctrl-Alt-L is'lock', and so on.&lt;br /&gt;I turn all those off so that I can edit LISP codeeasily.&lt;br /&gt;Use System/Preferences/Keyboard Shortcuts)&lt;br /&gt;&lt;br /&gt;C-M-x&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; evaluate this top-level expression&lt;br /&gt;&lt;br /&gt;C-x C-e&amp;nbsp; evaluate the expression behind the cursor&lt;br /&gt;&lt;br /&gt;C-u C-x C-e evaluate the expression and paste the result into the buffer!&lt;br /&gt;&lt;br /&gt;C-c C-k save compile and load this buffer&lt;br /&gt;&lt;br /&gt;M-.&lt;br /&gt;M-,&lt;br /&gt;go to the definition of the expression under the cursor&lt;br /&gt;come back from it&lt;br /&gt;&lt;br /&gt;C-c C-d C-d&lt;br /&gt;describe symbol under cursor&lt;br /&gt;&lt;br /&gt;C-M-k&lt;br /&gt;kill by s-expression&lt;br /&gt;&lt;br /&gt;C-M-h&lt;br /&gt;mark this top-level s-expression&lt;br /&gt;&lt;br /&gt;C-M-@&lt;br /&gt;mark next s-expression&lt;br /&gt;&lt;br /&gt;(these last three repeat nicely. C-M-h C-M-h marks the next two top-level expressions)&lt;br /&gt;&lt;br /&gt;C-M-q&lt;br /&gt;reindent the s-expression&lt;br /&gt;&lt;br /&gt;C-M-t&lt;br /&gt;transpose s-expressions (weirdly useful)&lt;br /&gt;repeated presses move an s-expression along inside a larger one.&lt;br /&gt;&lt;br /&gt;C-M-a&lt;br /&gt;C-M-e&lt;br /&gt;beginning and end of top level s-expressions (defn ....)&lt;br /&gt;&lt;br /&gt;C-M-f&lt;br /&gt;C-M-b&lt;br /&gt;C-M-p&lt;br /&gt;C-M-n&lt;br /&gt;backwards and forwards by list, previous and next s-expression&lt;br /&gt;(the difference is subtle and not terribly important)&lt;br /&gt;&lt;br /&gt;C-M-u&lt;br /&gt;C-M-d&lt;br /&gt;up and down list nest levels&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin: 0px;"&gt;&lt;b&gt;Desktops and Windows&lt;/b&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;a desktop is a list of buffers, places in buffers, etc.&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;M-: (desktop-read "~/data/dir") will read a desktop file from an arbitrary place&lt;/div&gt;&lt;div style="margin: 0px;"&gt;M-x desktop-save will put one down&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;window arrangements (the layout of the screen) can be saved in registers&lt;/div&gt;&lt;div style="margin: 0px;"&gt;&lt;br /&gt;&lt;div style="margin: 0px;"&gt;C-x&amp;nbsp; rfa&amp;nbsp;&amp;nbsp;&amp;nbsp; store window layout ( in register a , you can use other registers too)&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="margin: 0px;"&gt;C-x&amp;nbsp; rja&amp;nbsp;&amp;nbsp;&amp;nbsp; restore it&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Other commands&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;M-x htmlize-file is great for saving files with their syntax highlighting in html.&lt;br /&gt;&lt;br /&gt;M-x kill-rectangle, yank-rectangle and string-rectangle&lt;br /&gt;&lt;br /&gt;Not an emacs command, but I have Alt-F11 bound to full-screen windows in GNOME.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;A useful keyboard macro&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;In clojure-mode, trying to make a keyboard macro to paste results into the buffer&lt;br /&gt;always seems to go horribly wrong. But this particular sequence works to write the result of an expression into the buffer above the expression itself. Place the cursor at the start of the expression.&lt;br /&gt;&lt;br /&gt;If you do it by hand, the result ends up under the expression. If you record it and play it back, the result is over. No idea why, but this is a lot less haywire than every other time I've tried to do this.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;M-C-f&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;;; forward-sexp&lt;br /&gt;C-u C-x C-e&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;  &lt;/span&gt;;; slime-eval-last-expression&lt;br /&gt;M-C-b&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;;; backward-sexp&lt;br /&gt;RET&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;;; reindent-then-newline-and-indent&lt;br /&gt;&amp;lt;up&amp;gt;&lt;span class="Apple-tab-span" style="white-space: pre;"&gt;   &lt;/span&gt;;; previous-line&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Bookmarks&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;C-x r m&amp;nbsp; make bookmark&lt;br /&gt;C-x r b&amp;nbsp;&amp;nbsp; jump to bookmark&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-391854852453159678?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/391854852453159678/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2009/12/favourite-keys-for-emacs-and-slime.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/391854852453159678'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/391854852453159678'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2009/12/favourite-keys-for-emacs-and-slime.html' title='Favourite keys for EMACS and SLIME'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-8819936782728829392</id><published>2011-03-23T01:11:00.001Z</published><updated>2011-03-23T01:18:36.301Z</updated><title type='text'>Hello Web : Dynamic Compojure Web Development at the REPL</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      .string {        /* font-lock-string-face */        color: #ffa500;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;br /&gt;&lt;pre class="clojure-body"&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In an article which convinced many people to have a look at LISP&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;http://www.paulgraham.com/avg.html&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Paul Graham wrote about how nice it was to write a web application from an&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;environment where everything was controllable from the REPL.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Here's how to create a web server at the REPL&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;First we'll need a function to generate a simple web page&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;yo&lt;/span&gt; [] &lt;span class="string"&gt;"Hello"&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Now we attach that to /&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;use&lt;/span&gt; 'compojure.core)&lt;br /&gt;(defroutes main-routes (GET &lt;span class="string"&gt;"/"&lt;/span&gt; [] (yo)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We should wrap our routing table in a handler (note the #')&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;use&lt;/span&gt; 'compojure.handler)&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;app&lt;/span&gt; (site #'main-routes))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And then we can run it with jetty (again note the #')&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;use&lt;/span&gt; 'ring.adapter.jetty)&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;server&lt;/span&gt; (run-jetty #'app {&lt;span class="builtin"&gt;:port&lt;/span&gt; 8080 &lt;span class="builtin"&gt;:join?&lt;/span&gt; false}))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So now we're serving web pages. Go look at http://localhost:8080/&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The web browser of the gods:&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;$ watch -d -n 1 curl -sv http://localhost:8080/ &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can stop the server&lt;br /&gt;&lt;/span&gt;(.stop server)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And restart it:&lt;br /&gt;&lt;/span&gt;(.start server)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can redefine those functions, and the change takes effect immediately:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;yo&lt;/span&gt; [] &lt;span class="string"&gt;"&amp;lt;h1&amp;gt;Hello&amp;lt;h1/&amp;gt;"&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(you will need to refresh the page, unless you use twbotg)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;HTML is a bit of a pain. We already have a syntax for tree-structured data:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;use&lt;/span&gt; 'hiccup.page-helpers)&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;yo&lt;/span&gt; []      &lt;br /&gt;  (html5 [&lt;span class="builtin"&gt;:head&lt;/span&gt;&lt;br /&gt;          [&lt;span class="builtin"&gt;:title&lt;/span&gt; &lt;span class="string"&gt;"Hello World"&lt;/span&gt;]]&lt;br /&gt;         [&lt;span class="builtin"&gt;:body&lt;/span&gt;&lt;br /&gt;          [&lt;span class="builtin"&gt;:h1&lt;/span&gt; &lt;span class="string"&gt;"Lisp is the future"&lt;/span&gt;]]))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I'm confused: see http://stackoverflow.com/questions/5398569/can-clojure-be-made-dynamic&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The reason for the #' above is to make sure that we can redefine main-routes&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and app at runtime. Without the indirection, the changes don't seem to get picked up.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And yet they do get picked up when you redefine yo.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I do not understand what is going on here. Any explanation would be welcome!&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To start a REPL with the necessary libraries available, you can use maven.&lt;br /&gt;&lt;br /&gt;To install maven on ubuntu:&lt;br /&gt;$ &lt;b&gt;sudo apt-get install maven2 &lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Put this xml in a file named pom.xml, and then type&lt;br /&gt;$ &lt;b&gt;mvn clojure:repl&lt;/b&gt;&lt;br /&gt;in the same directory.For a swank server that you can use with emacs, use&lt;br /&gt;$ &lt;b&gt;mvn clojure:swank    &lt;/b&gt;&lt;style type="text/css"&gt;    &lt;!--      .xml-body {        color: #fff8dc;        background-color: #000000;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;br /&gt;&lt;br /&gt;The first time you run it it will do an incredible amount of downloading to get all the necessary bits, but after that it's fairly speedy.&lt;br /&gt;&lt;br /&gt;&lt;pre class="xml-body"&gt;&amp;lt;&lt;span class="function-name"&gt;project&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;modelVersion&lt;/span&gt;&amp;gt;4.0.0&amp;lt;/&lt;span class="function-name"&gt;modelVersion&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;com.aspden&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;hello-compojure&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;0.1-SNAPSHOT&amp;lt;/&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;name&lt;/span&gt;&amp;gt;hello-compojure&amp;lt;/&lt;span class="function-name"&gt;name&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;description&lt;/span&gt;&amp;gt;maven, clojure, emacs, swank, compojure: together at last&amp;lt;/&lt;span class="function-name"&gt;description&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;url&lt;/span&gt;&amp;gt;http://www.learningclojure.com&amp;lt;/&lt;span class="function-name"&gt;url&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="comment-delimiter"&gt;&amp;lt;!-- &lt;/span&gt;&lt;span class="comment"&gt;repositories &lt;/span&gt;&lt;span class="comment-delimiter"&gt;--&amp;gt;&lt;/span&gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;repositories&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;repository&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;id&lt;/span&gt;&amp;gt;clojars&amp;lt;/&lt;span class="function-name"&gt;id&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;url&lt;/span&gt;&amp;gt;http://clojars.org/repo/&amp;lt;/&lt;span class="function-name"&gt;url&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;repository&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;repository&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;id&lt;/span&gt;&amp;gt;clojure&amp;lt;/&lt;span class="function-name"&gt;id&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;url&lt;/span&gt;&amp;gt;http://build.clojure.org/releases&amp;lt;/&lt;span class="function-name"&gt;url&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;repository&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;repository&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;id&lt;/span&gt;&amp;gt;central&amp;lt;/&lt;span class="function-name"&gt;id&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;url&lt;/span&gt;&amp;gt;http://repo1.maven.org/maven2&amp;lt;/&lt;span class="function-name"&gt;url&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;repository&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/&lt;span class="function-name"&gt;repositories&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="comment-delimiter"&gt;&amp;lt;!-- &lt;/span&gt;&lt;span class="comment"&gt;libraries &lt;/span&gt;&lt;span class="comment-delimiter"&gt;--&amp;gt;&lt;/span&gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;dependencies&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;compojure&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;compojure&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;0.6.2&amp;lt;/&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;hiccup&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;hiccup&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;0.3.4&amp;lt;/&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;ring&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;ring-jetty-adapter&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;0.3.7&amp;lt;/&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;org.clojure&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;clojure&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;1.2.0&amp;lt;/&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;org.clojure&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;clojure-contrib&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;1.2.0&amp;lt;/&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;jline&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;jline&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;0.9.94&amp;lt;/&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;swank-clojure&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;swank-clojure&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;1.2.1&amp;lt;/&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;dependency&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/&lt;span class="function-name"&gt;dependencies&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;br /&gt;  &amp;lt;&lt;span class="function-name"&gt;build&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;&lt;span class="function-name"&gt;plugins&lt;/span&gt;&amp;gt;&lt;br /&gt;      &lt;span class="comment-delimiter"&gt;&amp;lt;!-- &lt;/span&gt;&lt;span class="comment"&gt;talios' clojure-maven-plugin provides mvn clojure:swank etc &lt;/span&gt;&lt;span class="comment-delimiter"&gt;--&amp;gt;&lt;/span&gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;plugin&lt;/span&gt;&amp;gt;&lt;br /&gt;        &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;com.theoryinpractise&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;        &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;clojure-maven-plugin&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;        &amp;lt;&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;1.3.2&amp;lt;/&lt;span class="function-name"&gt;version&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;/&lt;span class="function-name"&gt;plugin&lt;/span&gt;&amp;gt;&lt;br /&gt;      &lt;span class="comment-delimiter"&gt;&amp;lt;!-- &lt;/span&gt;&lt;span class="comment"&gt;The versions plugin allows you to find out what you can upgrade &lt;/span&gt;&lt;span class="comment-delimiter"&gt;--&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="comment-delimiter"&gt;&amp;lt;!-- &lt;/span&gt;&lt;span class="comment"&gt;mvn versions:help &lt;/span&gt;&lt;span class="comment-delimiter"&gt;--&amp;gt;&lt;/span&gt;&lt;br /&gt;      &lt;span class="comment-delimiter"&gt;&amp;lt;!-- &lt;/span&gt;&lt;span class="comment"&gt;mvn versions:display-dependency-updates &lt;/span&gt;&lt;span class="comment-delimiter"&gt;--&amp;gt;&lt;/span&gt;&lt;br /&gt;      &amp;lt;&lt;span class="function-name"&gt;plugin&lt;/span&gt;&amp;gt;&lt;br /&gt;        &amp;lt;&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;org.codehaus.mojo&amp;lt;/&lt;span class="function-name"&gt;groupId&lt;/span&gt;&amp;gt;&lt;br /&gt;        &amp;lt;&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;versions-maven-plugin&amp;lt;/&lt;span class="function-name"&gt;artifactId&lt;/span&gt;&amp;gt;&lt;br /&gt;      &amp;lt;/&lt;span class="function-name"&gt;plugin&lt;/span&gt;&amp;gt;&lt;br /&gt;    &amp;lt;/&lt;span class="function-name"&gt;plugins&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;/&lt;span class="function-name"&gt;build&lt;/span&gt;&amp;gt;&lt;br /&gt;  &lt;br /&gt;&lt;br /&gt;&amp;lt;/&lt;span class="function-name"&gt;project&lt;/span&gt;&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-8819936782728829392?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/8819936782728829392/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/03/hello-web-dynamic-compojure-web.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/8819936782728829392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/8819936782728829392'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/03/hello-web-dynamic-compojure-web.html' title='Hello Web : Dynamic Compojure Web Development at the REPL'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-1727259420776981425</id><published>2011-02-23T16:50:00.002Z</published><updated>2011-02-25T00:33:50.146Z</updated><title type='text'>Advice to a Newbie</title><content type='html'>Someone wrote to me the other day asking me to teach him Clojure over Skype.&lt;br /&gt;&lt;br /&gt;Well, I am sceptical of the feasibility of this scheme, but it is well known that the words "£50/hour" ring pleasantly in my ears, although in fact for this kind of one-hour every so often-type piecework it might be truer to say that the real figure is rather higher, but what the hell, this guy is a beginner interested in lisp, so I can cut him some slack....&lt;br /&gt;&lt;br /&gt;However it occurs to me that he doesn't really need me, and as a very wise man once pointed out to me, my clients pay me for my advice, rather than for my typing.&lt;br /&gt;&lt;br /&gt;So this is my reply:&lt;br /&gt;&lt;br /&gt;I have removed any identifying details from it, I hope, but if the guy in question wishes to out himself here, then that is perfectly fine, and maybe he will find a study partner who lives somewhere in his area.&lt;br /&gt;&lt;br /&gt;And if anyone reading this would like to recommend their own route in, or just flame me for being so utterly ignorant and old-fashioned, then feel free to leave long comments, at the risk that I may use them as material for further posts.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;Dear .......,&lt;br /&gt;&lt;br /&gt;I'm sorry I haven't replied for so long. I've been rushed off my feet, but I was very flattered by your offer.&lt;br /&gt;&lt;br /&gt;Clojure's exceedingly cool, but to understand it you need to speak lisp. (Scheme is the purest and easiest lisp to understand).&lt;br /&gt;&lt;br /&gt;I'd recommend the route I took into all that sort of thing, the excellent series of lectures given to first years at MIT, and filmed here as given to a load of HP execs by the original lecturers.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://groups.csail.mit.edu/mac/classes/6.001/abelson-sussman-lectures/"&gt;http://groups.csail.mit.edu/mac/classes/6.001/abelson-sussman-lectures/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You should get the excellent PLT Racket (which used to be called PLT Scheme),&lt;br /&gt;&lt;br /&gt;&lt;a href="http://racket-lang.org/"&gt;http://racket-lang.org/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;which has a superb beginners' scheme editor and environment, called DrScheme (or these days I presume DrRacket)&lt;br /&gt;and set the required language to Scheme R4RS or R5RS (not modern racket, which is a similar but different language to the one used in the book).&lt;br /&gt;&lt;br /&gt;That way you won't have to deal with the incomprehensibly weird emacs at the same time as learning lisp.&lt;br /&gt;&lt;br /&gt;When they write anything on the board in the videos, stop the lecture and try it out in DrRacket.&lt;br /&gt;&lt;br /&gt;There's also the excellent companion textbook:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://mitpress.mit.edu/sicp/full-text/book/book.html"&gt;http://mitpress.mit.edu/sicp/full-text/book/book.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;which has been used as an introductory CompSci text for many years.&lt;br /&gt;&lt;br /&gt;I seriously recommend you to do *all* the exercises in the book. Even the ones that look boring are in fact spectacularly well chosen and interesting once you start, and each one will teach you something new.&lt;br /&gt;&lt;br /&gt;Until you've done them all, you won't understand the material well enough to be able to go onto the next chapter.&lt;br /&gt;&lt;br /&gt;You will of course ignore this advice. I know I would.&lt;br /&gt;&lt;br /&gt;When you are half way through Chapter 2, and a bit bewildered and wondering if you are not clever enough, or why anyone should be interested in this weird and incomprehensible way of doing simple things, remember the advice and go back and do all the exercises in Chapter 1.&lt;br /&gt;&lt;br /&gt;Be aware that this is a very long process. Reckon on being able to do one exercise per day, and if you're treating it as a hobby, reckon on taking a year to understand the whole book.&lt;br /&gt;&lt;br /&gt;But it's also terrific fun, and you'll get regular rewards of small doses of enlightenment throughout.&lt;br /&gt;&lt;br /&gt;I actually did all this. I've never been to any sort of computer training. I learned lisp from that wonderful book, those wonderful lectures, and DrScheme.&lt;br /&gt;&lt;br /&gt;It really is the easiest way in. That's where all the smuggest lisp weenies come from, or go eventually.&lt;br /&gt;&lt;br /&gt;And once you've learned scheme (or more accurately, once you've learned all the new ways of thinking that Abelson and Sussman demonstrate), you'll look at clojure and think:&lt;br /&gt;&lt;br /&gt;'Oh yes, that's nice... I see...'&lt;br /&gt;&lt;br /&gt;-----&lt;br /&gt;&lt;br /&gt;That said, I am a complete slut, and amongst the things I am prepared to do for £50 an hour is to try to teach someone Clojure over Skype.&lt;br /&gt;&lt;br /&gt;But I really think that you'll get on better with the video lectures.&lt;br /&gt;&lt;br /&gt;Also, even though I am rather busy at the moment, I am not entirely without public spiritedness.&lt;br /&gt;&lt;br /&gt;If you read the first chapter of SICP, and watch the associated lectures, and have an honest go at doing all the exercises in chapter one,&amp;nbsp;then you can skype me and I'll spend a couple of hours leading you through any exercises you had difficulty with for free.&lt;br /&gt;&lt;br /&gt;Cheers, John.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;P.S. I find that I have just written a fine blog post, which I will publish. I will remove your name.&lt;br /&gt;&lt;br /&gt;P.P.S. Hypocrite note. I never did get round to chapter 5 of SICP. I intend to one day.&lt;br /&gt;&lt;br /&gt;P.P.P.S. In fact, you can probably get away with just reading the first three before you can understand clojure.&amp;nbsp;But chapter 4 is definitely the best of the first four, so it would be a shame to stop there.&lt;br /&gt;And you won't understand the why of lisp until you've read chapter 4.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-1727259420776981425?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/1727259420776981425/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/02/advice-to-newbie.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/1727259420776981425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/1727259420776981425'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/02/advice-to-newbie.html' title='Advice to a Newbie'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-4752205248188349525</id><published>2011-02-16T16:45:00.000Z</published><updated>2011-02-16T16:44:57.545Z</updated><title type='text'>Clojure Dojo 4: Symbolic Differentiation</title><content type='html'>We've written a fairly good Newton-Raphson solver, but it's a bit hacky to do numerical differentiation when differentiation is so easy by hand.&lt;br /&gt;&lt;br /&gt;Here I've tried to create the simplest possible symbolic differentiator.&lt;br /&gt;&lt;br /&gt;It relies on four basic rules:&lt;br /&gt;&lt;br /&gt;The derivative of a constant is 0.&lt;br /&gt;The derivative of a variable is 1 with respect to itself, 0 with respect to a different variable.&lt;br /&gt;The derivative of a sum is the sum of the derivatives of the parts.&lt;br /&gt;The derivative of a product is the sum of the derivative of the first part times the second part and the first part times the derivative of the second part.&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      .string {        /* font-lock-string-face */        color: #ffa500;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;&lt;br /&gt;&lt;br /&gt;If you tell the computer this then it can differentiate polynomials like&lt;br /&gt;x^5+x^2+2x+3 as long as you express them in terms of binary operators. &lt;br /&gt;&lt;pre&gt;(+ (+ (* x (* x x)) (* 2 (* x x))) 1)&lt;/pre&gt;&lt;br /&gt;It's easily extended to deal with arbitrary operators like (* x y z 2), and with functions like sin and cos.&lt;br /&gt;&lt;br /&gt;A routine to simplify the answers would also be nice, so that (+ (* 0 (* (* x x) x)) (* x 1)) might be more readably represented as x.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="clojure-body"&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The simplest possible symbolic differentiator&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Functions to create and unpack additions like (+ 1 2)&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-add&lt;/span&gt; [ a b ] (list '+ a b))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;addition?&lt;/span&gt; [x] (&lt;span class="keyword"&gt;and&lt;/span&gt; (=(&lt;span class="builtin"&gt;count&lt;/span&gt; x) 3) (= (&lt;span class="builtin"&gt;first&lt;/span&gt; x) '+)))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;add1&lt;/span&gt;   [x] (second x))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;add2&lt;/span&gt;   [x] (second (&lt;span class="builtin"&gt;rest&lt;/span&gt; x)))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Similar for multiplications (* 1 2)&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-mul&lt;/span&gt; [ a b ] (list '* a b))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;multiplication?&lt;/span&gt; [x] (&lt;span class="keyword"&gt;and&lt;/span&gt; (=(&lt;span class="builtin"&gt;count&lt;/span&gt; x) 3) (= (&lt;span class="builtin"&gt;first&lt;/span&gt; x) '*)))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;mul1&lt;/span&gt;   [x] (second x))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;mul2&lt;/span&gt;   [x] (second (&lt;span class="builtin"&gt;rest&lt;/span&gt; x)))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Differentiation. &lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;deriv&lt;/span&gt; [exp var]&lt;br /&gt;  (&lt;span class="keyword"&gt;cond&lt;/span&gt; (number? exp) 0                                                              &lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;d/dx c -&amp;gt; 0&lt;br /&gt;&lt;/span&gt;        (&lt;span class="builtin"&gt;symbol?&lt;/span&gt; exp) (&lt;span class="keyword"&gt;if&lt;/span&gt; (= exp var) 1 0)                                           &lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;d/dx x -&amp;gt; 1, d/dx y -&amp;gt; 0&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;        (addition? exp) (make-add (deriv (add1 exp) var) (deriv (add2 exp) var))     &lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;d/dx a+b -&amp;gt; d/dx a + d/dx b&lt;br /&gt;&lt;/span&gt;        (multiplication? exp) (make-add (make-mul (deriv (mul1 exp) var) (mul2 exp)) &lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;d/dx a*b -&amp;gt; d/dx a * b + a * d/dx b&lt;br /&gt;&lt;/span&gt;                                        (make-mul (mul1 exp) (deriv (mul2 exp) var)))&lt;br /&gt;        &lt;span class="builtin"&gt;:else&lt;/span&gt; &lt;span class="builtin"&gt;:error&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;an example of use: create the function x -&amp;gt; x^3 + 2x^2 + 1 and its derivative &lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;poly&lt;/span&gt; '(+ (+ (* x (* x x)) (* 2 (* x x))) 1))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;poly-&amp;gt;fnform&lt;/span&gt; [poly] (list 'fn '[x] poly))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;polyfn&lt;/span&gt;  (eval (poly-&amp;gt;fnform poly)))&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;dpolyfn&lt;/span&gt; (eval (poly-&amp;gt;fnform (deriv poly 'x))))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;tests&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(use 'clojure.test)&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;deftest&lt;/span&gt; &lt;span class="function-name"&gt;deriv-test&lt;/span&gt;&lt;br /&gt;  (testing &lt;span class="string"&gt;"binary operators"&lt;/span&gt;&lt;br /&gt;    (is (= (&lt;span class="keyword"&gt;let&lt;/span&gt; [m '(* a b)] [(multiplication? m) (make-mul (mul1 m) (mul2 m))]) [true  '(* a b)]))&lt;br /&gt;    (is (= (&lt;span class="keyword"&gt;let&lt;/span&gt; [m '(* a b)] [(addition? m)       (make-add (add1 m) (add2 m))]) [false '(+ a b)])))&lt;br /&gt;  (testing &lt;span class="string"&gt;"derivative function"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    (is (= (deriv '0 'x)               '0))&lt;br /&gt;    (is (= (deriv '1 'x)               '0))&lt;br /&gt;    (is (= (deriv 'x 'x)               '1))&lt;br /&gt;    (is (= (deriv 'y 'x)               '0))&lt;br /&gt;    (is (= (deriv '(+ x x) 'x)         '(+ 1 1)))&lt;br /&gt;    (is (= (deriv '(* x x) 'x)         '(+ (* 1 x) (* x 1))))&lt;br /&gt;    (is (= (deriv '(* x x) 'y)         '(+ (* 0 x) (* x 0))))&lt;br /&gt;    (is (= (deriv '(* x (* x x)) 'x)   '(+ (* 1 (* x x)) (* x (+ (* 1 x) (* x 1)))))))&lt;br /&gt;  (testing &lt;span class="string"&gt;"function creation: d/dx (x^3 + 2x^2 + 1) = 3x^2 + 4x "&lt;/span&gt;&lt;br /&gt;    (&lt;span class="keyword"&gt;let&lt;/span&gt; [poly '(+ (+ (* x (* x x)) (* 2 (* x x))) 1)]&lt;br /&gt;      (is (= ((eval (poly-&amp;gt;fnform poly)) 3) 46))&lt;br /&gt;      (is (= ((eval (poly-&amp;gt;fnform (deriv poly 'x))) 3))))))&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-4752205248188349525?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/4752205248188349525/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2010/02/clojure-dojo-4-symbolic-differentiation.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/4752205248188349525'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/4752205248188349525'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2010/02/clojure-dojo-4-symbolic-differentiation.html' title='Clojure Dojo 4: Symbolic Differentiation'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-4583756468249093156</id><published>2011-02-16T16:41:00.000Z</published><updated>2011-02-16T16:43:56.763Z</updated><title type='text'>Clojure Dojo 3: From Heron to Newton-Raphson</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;&lt;pre class="clojure-body"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We've so far written a square root solver using Heron's method&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;average&lt;/span&gt; [a b] &lt;br /&gt;  (/ (+ a b) 2))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;abs&lt;/span&gt;[x] &lt;br /&gt;  (&lt;span class="keyword"&gt;if&lt;/span&gt; (&amp;lt; x 0) (- x) x))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-good-enough?&lt;/span&gt; [n]&lt;br /&gt;  (&lt;span class="keyword"&gt;fn&lt;/span&gt; [guess] (&amp;lt; (abs (- n (* guess guess))) 1e-6)))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-improver&lt;/span&gt; [n]&lt;br /&gt;  (&lt;span class="keyword"&gt;fn&lt;/span&gt; [guess] (average guess (/ n guess))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;iterative-improve&lt;/span&gt; [x improve good?]&lt;br /&gt;  (&lt;span class="keyword"&gt;if&lt;/span&gt; (good? x) x&lt;br /&gt;      (iterative-improve (improve x) improve good?)))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;square-root&lt;/span&gt; [n]&lt;br /&gt;     (iterative-improve 1.0 (make-improver n) (make-good-enough? n)))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Now in fact, Heron's method turns out to be only a simple example of a more general method of root finding known as Newton-Raphson.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Their great idea was to use the derivative of a function to help find its roots.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Finding Derivatives (by cheating)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Suppose we've got a function, say cube&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;cube&lt;/span&gt; [x] (* x x x))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And we want to find out what its derivative is, i.e. how much it changes when you change the argument.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(cube 4)        &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;i s 64&lt;br /&gt;&lt;/span&gt;(cube 4.000001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;is 64.000048000012&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In other words, if we add 0.000001 to x, then (cube x) goes up by 0.00004800..... which is about 48 times as much.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We say that the derivative of cube at 4 is (about) 48.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It's different in different places.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(cube 3)        &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;is 27&lt;br /&gt;&lt;/span&gt;(cube 3.000001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;is 27.000027000009005&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So the rate of change of cube at 3 is (about) 27.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;In general, we want a function that takes a function, and gives back a function that tells us how much it changes if you add a tiny bit to its argument.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;deriv&lt;/span&gt; [f]&lt;br /&gt;  (&lt;span class="keyword"&gt;fn&lt;/span&gt; [x] (/ &lt;br /&gt;           (- &lt;br /&gt;            (f (+ x 0.000001)) &lt;br /&gt;            (f x))&lt;br /&gt;           0.000001)))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's try that out:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;((deriv cube) 4)       48.00001200067072&lt;br /&gt;((deriv cube) 3)       27.00000900546229&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Notice what we did here! This is a function which takes a function and gives back a function.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We could name the answer!&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;dcube&lt;/span&gt; (deriv cube))&lt;br /&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; dcube (&lt;span class="builtin"&gt;range&lt;/span&gt; 10))        &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;(1.0E-12 3.0000029997978572 12.000006002210739 27.00000900546229 48.00001200067072 75.00001501625775 108.00001800248538 147.00002100198617 192.00002384422987 243.0000268986987)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So now we know how to calculate (a good approximation to) the derivative of any function.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Newton Raphson&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Imagine that we wanted to find the cube root of 100.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;That's the same as finding a number which, when you cube it and subtract 100, gives you zero&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So we should take as our equation to solve: (cube x) - 100 = 0&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;or (f x) = 0 where f is &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;f&lt;/span&gt;[x] (- (* x x x) 100))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Isaac Newton told us that if you have an equation like that, and you have a guess at a number&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;which will make it zero, then you can find a much better guess if you know the derivative.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;df&lt;/span&gt; (deriv f))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Newton said: Suppose that I guess that 4 is the cube root of 100.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Then I try it (f 4) = -36&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;That's not so close. What's the derivative there?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(df 4) 48.00001200067072&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What that means is that when we raise x by a tiny amount, say 4.0000001, then (f x) goes up by about 48 times that.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So Newton tells us:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The function is too low by 36.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If we make the guess a bit larger, then the function will go up by ~ 48 times as much.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We should try adding 36/48 as our next guess.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's try&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(+ 4.0 (/ 36 48)) &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;4.75&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;(f 4.75)          &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;7.171875&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;ok, better. We were under by 36, now we're over by 7. 4.75 is too high!&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Take the derivative again:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(df 4.75) &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;67.68751426022845&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;Divide the amount we're off by the derivative&lt;br /&gt;&lt;/span&gt;(/ (f 4.75) (df 4.75)) &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;0.10595565634789487&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So our next guess should be (- 4.75 0.10595565634789487) , which is 4.644044343652105&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's try 4.644 :&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(f 4.644) &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;0.15592198400001678 ...homing in...&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(- 4.644 (/ (f 4.644) (df 4.644)))  &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;4.641590085793267&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(f 4.64159) &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;7.538717167676623E-5 ...very good...&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Obviously we've got another guess-improving function here&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;improve-cbrt100&lt;/span&gt; [guess]&lt;br /&gt;  (- guess (/ (f guess) (df guess))))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(improve-cbrt100 4.0)     4.749999812489567&lt;br /&gt;(improve-cbrt100 (improve-cbrt100 4.0)) 4.644044335287887&lt;br /&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (&lt;span class="builtin"&gt;iterate&lt;/span&gt; improve-cbrt100 4.0))   &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(4.0 4.749999812489567 4.644044335287887 4.6415901322397985 4.641588833613422 4.641588833612778 4.641588833612778 4.641588833612778 4.641588833612778 4.641588833612778)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's try 4.641588833612778, which seems to be about as good as floating point arithmetic can get us.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(f 4.641588833612778)      &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;-2.8421709430404007E-14&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(cube 4.641588833612778)   &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;99.99999999999997&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Pretty good for only 5 steps!&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What about a good-enough function to tell us when to stop iterating?&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;good-enough-cbrt100?&lt;/span&gt; [x]&lt;br /&gt;  (&amp;lt; (abs (f x)) 0.0000001))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Now we can plug the improver and the good enough function into iterative-improve, as before. We'll use 1.0 as our initial guess again.&lt;br /&gt;&lt;/span&gt;(iterative-improve 1.0 improve-cbrt100 good-enough-cbrt100?) &lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;4.641588833613406&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(cube 4.641588833613406)   &lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;100.00000000004056&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But of course, nothing we did depended on (f x) being (- (cube x) 100)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can make a guess-improver for any function&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-improver&lt;/span&gt; [f]&lt;br /&gt;  (&lt;span class="keyword"&gt;fn&lt;/span&gt; [guess] (- guess (/ (f guess) ((deriv f) guess)))))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and a function to tell us whether it's good enough&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-good-enough&lt;/span&gt; [f]&lt;br /&gt;  (&lt;span class="keyword"&gt;fn&lt;/span&gt; [guess] (&amp;lt; (abs (f guess)) 0.0000001)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What if we'd like to solve the equation x^3 + x^2 + x + 1 = 0 ?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;solve&lt;/span&gt; [f guess]&lt;br /&gt;  (iterative-improve guess (make-improver f) (make-good-enough f)))&lt;br /&gt;&lt;br /&gt;(solve (&lt;span class="keyword"&gt;fn&lt;/span&gt; [x] (+ (* x x x) (* x x) x 1)) 1.0) &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;-1.0000000235152005&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's see how good an answer that is.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;((&lt;span class="keyword"&gt;fn&lt;/span&gt; [x] (+ (* x x x) (* x x) x 1)) -1.0000000235152005) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;-4.703040201725628E-8&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Newton Raphson Solver&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Here's the whole of our general function solver, but let's make the two 'magic numbers' into variables too.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;deriv&lt;/span&gt; [f dx]&lt;br /&gt;  (&lt;span class="keyword"&gt;fn&lt;/span&gt; [x] (/  (- (f (+ x dx)) (f x) )  dx)))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-improver&lt;/span&gt; [f dx]&lt;br /&gt;  (&lt;span class="keyword"&gt;fn&lt;/span&gt; [guess] (- guess (/ (f guess) ((deriv f dx) guess)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-good-enough&lt;/span&gt; [f tolerance]&lt;br /&gt;  (&lt;span class="keyword"&gt;fn&lt;/span&gt; [guess] (&amp;lt; (abs (f guess)) tolerance)))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;iterative-improve&lt;/span&gt; [x improve good?]&lt;br /&gt;  (&lt;span class="keyword"&gt;if&lt;/span&gt; (good? x) x&lt;br /&gt;      (iterative-improve (improve x) improve good?)))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;solve&lt;/span&gt; [f guess dx tolerance]&lt;br /&gt;  (iterative-improve guess (make-improver f dx) (make-good-enough f tolerance)))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Some applications&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;usually we'll want an initial guess of 1.0, a tolerance of 0.0000001 and a dx of 0.0000001&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;solve-it&lt;/span&gt; [f] &lt;br /&gt;  (solve f 1.0 0.000001 0.000001))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Square roots are the solutions of (- (* x x) n) = 0&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;sqrt&lt;/span&gt; [n] &lt;br /&gt;  (solve-it &lt;br /&gt;   (&lt;span class="keyword"&gt;fn&lt;/span&gt; [x] (- (* x x) n))))&lt;br /&gt;&lt;br /&gt;(sqrt 2) &lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Cube roots are the solutions of (- (* x x x) n) = 0&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;cubert&lt;/span&gt; [n] &lt;br /&gt;  (solve-it &lt;br /&gt;   (fn[x] (- (* x x x) n))))&lt;br /&gt;&lt;br /&gt;(cubert 2)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;General positive integer powers can be expressed recursively:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;pow&lt;/span&gt; [x m]&lt;br /&gt;  (&lt;span class="keyword"&gt;if&lt;/span&gt; (= m 0) 1&lt;br /&gt;      (* x (pow x (- m 1)))))&lt;br /&gt;&lt;br /&gt;(pow 2 3) &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;8&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And if we can express them, we can use our method to find mth roots.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;mthrt&lt;/span&gt; [m n] &lt;br /&gt;  (solve-it &lt;br /&gt;   (fn[x] (- (pow x m) n))))&lt;br /&gt;&lt;br /&gt;(mthrt 4 10000) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;10.0&lt;br /&gt;&lt;/span&gt;(mthrt 123 234) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.045350466874579&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(pow 1.045350466874579 123) &lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;234.0000000243792&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But of course, we can solve any equation which is amenable to Newton's method.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What number, when multiplied by itself 5 times, and added to its cube, is equal to 700?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(solve-it (fn[x] (+ (* x x x x x) (* x x x) (- 700))))         &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;3.653807138770812&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;((fn[x] (+ (* x x x x x) (* x x x))) 3.653807138770812) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;700.0000003041337&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And if we'd like a better answer, we can tighten the tolerances&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(solve (fn[x] (+ (* x x x x x) (* x x x) (- 700))) 1.0 0.0001 0.0000000001) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;3.6538071384442974&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;((fn[x] (+ (* x x x x x) (* x x x))) 3.6538071384442974) &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;700.0000000000817&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In theory, we'd be able to use exact arithmetic to get arbitrarily accurate answers.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Unfortunately, there's a problem:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;it&lt;/span&gt; (make-improver (fn[x] (+ (* x x x x x) (* x x x) (- 700))) 1/1000000)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;let's use an exact number for the derivative approximation&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and start with an exact guess&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(it 1)                  &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;706000013000011000005000001/8000013000011000005000001&lt;br /&gt;&lt;/span&gt;(it (it 1))             &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;701635321996143769309418549344377227910245191235491382603948489939699061403896688219959595828904782223381164841011935230760200930031084004228000441000030000001/9938320550977024134920249980653903204519665284470123223646489755187942893061019955878983167997749088761731121640594804980166030029688004228000441000030000001&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;(it (it (it 1)))        &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;680237917441885524336418138840317390387477847859858876595840234272149425820646224687954143292874376454521646334951672503154114880181300843385953617515081285781202235479686701822851428206060076054501437170597117295185786622448092483300621863099620331252416621986363001610323019591307968502301991515214451683404838437583955509995832608492690263029459069929976980341191436712932448855080982518511841862770021155980758185192008036141486759432138585947862423162360655529584841649322416573707879742014567586254212003318865179086757633089843219756812844011861068141391297639719428726706532258163565342026653477095733524189143027946838723155848407864793520497990564324241350635343653518356286709120797176348156180962741126448716721627967605789740379911361208362221973935469409915879343921377079168493057613428011966000155000001/12044286332140129752156903683583126447244938902908926261607579552042467607850219073475448382767207875539137993119265514088232278316554495937166615076210884321449749330293196083213705419806298445939325718843197812663753008605821508903073125871316024961234609794639656768170967982087039663880189123415565181043003755509161080647377737131911463013608843269269085395872146930064532858794789612245264182978492519500766787287053880913766446555513734299742826803443919934807497308923876636662216418140448109767596616697192628702623509472332595967524822599329261416093615390398256303064181652715052013431614546617380753560488219680455031256525883523608904103537508019124887595921116604264464741508409082509232101707795378534258208496424946224563887570504744604783840489200142804159760458106765068490963613428011966000155000001&lt;br /&gt;&lt;/span&gt;(it (it (it (it 1))))   &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;582683064888886254627237413128914355133205070107730345306566818667169839077043977063385150567627868898954627396888803873298542915735291068231854737660749871284970969691761755237023440170586132711096078205774661890184691373273510273283202351760392701768411497903999874829223861118399238720882465581354352630000971969184626801423877016182068328118391265021597001152296290812122250720956031547021906861678543752400823983366892551426008467510890046723277161664312028285174276774217375277065253742530859064530016440400316790801769530544371284081707010989839631883556283241113998175234840943170722268328720701199347867588322060049770935643979286527454236006759544836737208537749694757872416290454093930058675287658912516799102545283953465977040744182800487171767210596289815719837983663631950117171893161135122746529146479448859227394441049923190055342857801930221659120398700765917475396756356933748228771216329690971598121024906393909199740001655437226675292089740865401850681717862593295044249444227096530596676969537355119944076825364494231692463504463385356777816358752007019352340833078969061391374565063342370784189339508167803312120387247644380450529051088582048118902223778854166538058459895429188150443034952695968773967230092326545545925098065274390529306120532407597280407465373342806740914557404279803404281875098412568052206856189504731510965158306039056809060766012400914292618679128113015139253847973084750652345634913827827043851034605686643123187076375915598639958363937697829956243245104853978610467265918061529051311071288413580756443693449482971629647374397753310557728689142976074021187362385338932147567642210185904671961035565315840293902065425141448705637965586698203041117408261444705945865047531954486514780505078832025358426644461672866572253641788067682868313500867194340509941792198538459647737009443599755837217723308620719398896201880698984796565219264280137596609642845400547125754456209756196169964659473873586279764214453671645956003619308063592648337612774637171241884690676604002029522916589191903605327335495103912144305652194435971484948567480613108531306049822517644426959900990535402937677569195079220088350105434599994075059763835418492356744894787315782423704801923419774013400657508864679447262609755156219146757585536473633170206959340454211578712959760853352548696411404380901268846622462357056396277653709161131992015278410666198586576834004214031859566710336893361077448333057320403538099709665120727817043295276197596679826722665947871368777705493013687853852488123574246109063974638016285172124627788918704893034469219280568313768497634816004319733836637800496141268248807282891107795078010343054429751145414810367778479411850027960387501665140659520089944949565082934980430105203072555206594274562501052867096198848952152330124216130716659045181152784334507386057959224529758674635647399911089583876402241119812642070687710563501331168402312038757841360479166547376873053789334438351535437225196907596309808445013472858435271020713482531473249425954713138213993853690048279402486411516169465400907740591254918376665681348518024822387460412485718766760961958943780464278973812982576607564820484862661878406223946061213224303753767486290224002094709777464746472645414893385625996401380435392614667079096134453611792569645198318837308794387253480934803497220222891193495355138449277282306273087395040974247699578508944806995861199096983093778899088019827135297023837526798957092191839173362464128894165682017815738236599955940542605196688759536725013516191327597134380086354086023426735965448551045630879574037331690144148829216502025494635660367861837832650027912461998002111883455796634997105423180569440930861025594379890711775754266620157029760796036618547810092105837604672377921726136778076482261042587195382143724289727648562704136017853509498366890447377518135820019350488687720760940855188770925017427141691614329578171795155245502836823003566045473401512439769020488822239922252814521793930372045109677392922267054560823873124298362347797278136358895228352710628394677753104291145730759681035568127201415728926581298819651031969039124011747083909428303966000780000001/12896626453600069493698610007462574074360012803192517550652653321288458704437628147812351238096058570880646809642684891850066999395344051036048084092196565019966845694603226043392692831832408470853928980193581747252243200468103361176860667342346033755639391767792595834026685821301417812313001324714923798171069125692865759809093740132786844460822717151100184874113026243342113737733017773505307764700961069595789996009548181632271209787338405203417470570243624108296656484641803537134016638223204512186999071878554046958682488174902216383193717986143532189831044292308519842126873269313853560876247133978458353574480851312759631684358889032900084642745496288725888743073969677137896558829603592262230802522695739419744389018487062275548598153935413565238867472051597918163575900094811377931457308002870398147828447466466856465628782660404829455110767346686507193439951612181709790999494520905843712219628937059390531846716829881905679762662797797772057202910931972704357372155619580235092749976889122762716133368842037661984150683629394903567236216963194674605967568392431208794043431169892910445094675188563758743114907987788746591274250207082015901133815715910101081963885658315948409184499380715077775262542275170959223244947248063594716133379982128239636514206935394270725149984811164184816315321673225284930879745768846720157626335366782084507443322775922411153536241445645457909068808146547276992161599402164331016798612763537783551540734336332823264126557187267639802943507420912300582217231591699364446110633032192667875702437386209756724502546707178905247996448449229725676664533990896268840252253987954869584921155755185596659051602784734099723461617865205317857691298850939510647703168248071840078142301962876095991821410664592847145496334778994271130316719075179553320153706951867058953414639227099786449755622188371176105537376510675813747465892564129310902573333355338988514058192477421861710533925137494638802746649014987114280003213204406857866359359280991867594433240560958642355778026603456310571266226381230212501928363154073509767737834411081511741666078389988426255700754713921887266615912226559289922110288321637513352794999588449807206908304314944589521175612052878625277657474456489493344970961101196034555416517832906272790448598835563702334203053761460216483188413922273789078424479313993102344574019369085117678979346999182040112416824764512591041037973913657403354399232242224999268943921208792520828958494399634230250208344108593016608457066759423447434130404474515620954899757483291938447043440289286090559545316946393298710577732756942628616513884579585056022530728783711122920500882377115985715201353863643271746094708630198929184352363067785421438134909914864758356500163689964428638647687495591442052889991128729671129301459039511338151733777970655351650119214267552140948065933092934877227143743916767768243644993862805442252649852133799824872693054837337674268061282267623038576543034125243858631285899198303109966963172209152874196720199801119238717086988413507996967711063340008844027377086930137204987454203538469697377749646520851213248589905149021586496254737543585289159013650128559023578482611563124559893592352427180734048684239663086639329223310790701294430611951452851943347414551549066596198403402509218874978312155181397196069302152786264584396523101878569322693955950044160266238264131771759791930583114290189937813208245285469977694328792320835576523730805116731577483465467653183154605688937756438221438317995677209102959548247744261605934633001969642392983652820479907300076279299375999438660224810860948463249531812666274785951673129729793010427319485797202888099118900435857053255162204718549364268309991788374329365868674979202327345545939405245168318555414785299112969636869024689405450765132794123797478424267092928772922594681937404357022580366085874534312247818159047202717252632019175403527618827567476810823460590807535175349230955481084676292524894761199878853286342204470938790343375932066863536221551379561495530913704293344747209001634639584668143339854848154541379814946625988808902291845280350306322621482114145676960211744291909428303966000780000001&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;after 4 iterations we've got 8000 digits in our fraction! It might take a while to calculate each step.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It's possible to control this crazed exponentiation of digits. &lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I leave the problem of modifying the method to produce arbitrarily accurate answers as a problem to the reader.&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-4583756468249093156?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/4583756468249093156/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2010/02/clojure-dojo-3-from-heron-to-newton.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/4583756468249093156'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/4583756468249093156'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2010/02/clojure-dojo-3-from-heron-to-newton.html' title='Clojure Dojo 3: From Heron to Newton-Raphson'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-8195927066663962921</id><published>2011-02-16T16:40:00.000Z</published><updated>2011-02-16T16:47:00.747Z</updated><title type='text'>Clojure Dojo 2: What about numbers that aren't 10?</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;pre class="clojure-body"&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We've so far implemented Heron's method for finding the square root of&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;the number 10. The program looks like this:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;average&lt;/span&gt; [a b] &lt;br /&gt;  (/ (+ a b) 2))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;improve-guess&lt;/span&gt; [guess]&lt;br /&gt;  (average guess (/ 10 guess)))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;abs&lt;/span&gt;[x] &lt;br /&gt;  (&lt;span class="keyword"&gt;if&lt;/span&gt; (&amp;lt; x 0) (- x) x))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;good-enough?&lt;/span&gt; [guess] &lt;br /&gt;  (&amp;lt; (abs (- 10 (* guess guess))) 1e-6))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;good-enough-guess&lt;/span&gt; [x]&lt;br /&gt;  (&lt;span class="keyword"&gt;if&lt;/span&gt; (good-enough? x) x&lt;br /&gt;      (good-enough-guess (improve-guess x))))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;At this point, it might be a good idea to put the functions in a file. &lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If we use a lisp-conscious IDE (EMACS, the Editor for Middle Aged Computer Scientists, is my favourite)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Then we can carry on our conversational style of development.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In fact, this program is easily generalized. Our first task is to make a more general&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;iterative-improve function.  This function should take a guess, a function to improve guesses,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and a function to tell when guesses are good enough, and return an answer which is good enough,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;which it should find by repeatedly improving the guesses.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We almost have this function already. We just need to make the constants in good-enough-guess into arguments.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;iterative-improve&lt;/span&gt; [x improve good?]&lt;br /&gt;  (&lt;span class="keyword"&gt;if&lt;/span&gt; (good? x) x&lt;br /&gt;      (iterative-improve (improve x) improve good?)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's test that: (In emacs, put the cursor at the end of the expression and type C-x C-e to evaluate the expression)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(iterative-improve 1.0 improve-guess good-enough?)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Or in fact, we can use C-u C-x C-e to evaluate it and paste it into the buffer.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(iterative-improve 1.0 improve-guess good-enough?)&lt;br /&gt;3.162277665175675&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(* 3.162277665175675 3.162277665175675) is 10.000000031668918, so we haven't broken our method.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Of course to find the square roots of numbers other than 10, we need functions that will make our guesses closer and tell whether the answers are good enough.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It would be a terrible thing to have to hand code them every time. But we can make functions which make functions:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-improver&lt;/span&gt; [n]&lt;br /&gt;  (&lt;span class="keyword"&gt;fn&lt;/span&gt; [guess] (average guess (/ n guess))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;f&lt;/span&gt; (make-improver 25))&lt;br /&gt;&lt;br /&gt;(f 1.0)                                 &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;13.0&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;(f (f 1.0))                             &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;7.461538461538462&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (&lt;span class="builtin"&gt;iterate&lt;/span&gt; f 1.0))               &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;(1.0 13.0 7.461538461538462 5.406026962727994 5.015247601944898 5.000023178253949 5.000000000053722 5.0 5.0 5.0)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-good-enough?&lt;/span&gt; [n]&lt;br /&gt;  (&lt;span class="keyword"&gt;fn&lt;/span&gt; [guess] (&amp;lt; (abs (- n (* guess guess))) 1e-6)))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;g?&lt;/span&gt; (make-good-enough? 25))&lt;br /&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (&lt;span class="builtin"&gt;map&lt;/span&gt; g? (&lt;span class="builtin"&gt;iterate&lt;/span&gt; f 1.0)))      &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;(false false false false false false true true true true)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(iterative-improve 1.0 f g?)            &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;5.000000000053722&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So now we can find arbitrary square roots&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;square-root&lt;/span&gt; [n]&lt;br /&gt;     (iterative-improve 1.0 (make-improver n) (make-good-enough? n)))&lt;br /&gt;&lt;br /&gt;(square-root 2)                         &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;1.4142135623746899&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-8195927066663962921?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/8195927066663962921/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2010/02/clojure-dojo-2-what-about-numbers-that.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/8195927066663962921'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/8195927066663962921'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2010/02/clojure-dojo-2-what-about-numbers-that.html' title='Clojure Dojo 2: What about numbers that aren&apos;t 10?'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-7630583826707299285</id><published>2011-02-16T16:39:00.002Z</published><updated>2011-02-17T11:09:47.879Z</updated><title type='text'>Clojure Dojo: The method of Heron of Alexandria</title><content type='html'>To my further surprise, I was asked to give this talk again this year, only twice. So I've moved this back up to the top in case anyone who was there wants to read through the original draft.&lt;hr/&gt;Somewhat to my surprise, I've been asked to give a talk on Clojure in London in a few weeks. &lt;a href="http://wiki.2010.dev8d.org/w/Clojure_Lab"&gt;http://wiki.2010.dev8d.org/w/Clojure_Lab&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It will be for an audience of people who don't have LISP experience, and it has to be in the form of a 'programming dojo', where people take turns to write real code.&lt;br /&gt;&lt;br /&gt;I decided that talking about all the things that make Clojure the best new LISP for 30 years would maybe be a bit redundant with such an audience, so instead I thought I'd try and go through the example that got me hooked on LISP, the generalized iterative improver from Structure and Interpretation of Computer Programs.&lt;br /&gt;&lt;br /&gt;Here's a draft of the first half. I don't actually expect to get any further than this in two hours,but just in case, there's also a second half that will turn this into a Newton-Raphson solver, and then go on to symbolic differentiation of functions.&lt;br /&gt;&lt;br /&gt;&lt;style type="text/css"&gt;    &lt;!--      .clojure-text {        color: #fff8dc;        background-color: #000000;        overflow: auto;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      .string {        /* font-lock-string-face */        color: #ffa500;      }    --&gt;&lt;/style&gt;&lt;br /&gt;&lt;pre class="clojure-text"&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;When we write lisp, we have magic powers, and the reason is that our code is in a form that is&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;easy to manipulate programmatically.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Like all magic, there is a price to pay.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The price is that we have to rip the front end off our compiler.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The front end is the thing that takes 1*2+3*5 and says:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;1 is valid but 1* isn't, * is an operator, and so on, so that must really be 1 * 2 + 3 * 5 , and&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;* binds tighter than +, so that's really ( ( 1 * 2 ) + ( 3 * 5 ) ) Which is really a tree:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;             (+ &lt;br /&gt;              (* 5 3)&lt;br /&gt;              (* 1 2))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Meaning take 1 and 2 and multiply them, take 5 and 3 and multiply them. Add the results.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;This is clearly seriously annoying, and like monads in Haskell, it's the first thing you hit when&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;you learn lisp, but I promise that after a month or so of using it you stop noticing it, and&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;although it's never quite as good for actual arithmetic, it's actually much nicer as a notation&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;for a generalized function call.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;More importantly, it allows us to treat all functions uniformly, including the ones we define&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;ourselves. And this is the source of the magic.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If we do well today we'll be able to symbolically differentiate a function.  Using a very short&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;program. And that's hard in a language with a syntax.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So my aim for today is to get us used to the (lack of) syntax of lisp.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We're going to use clojure, which is a modern member of the LISP family, in the same sense that&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Java is a member of the ALGOL family.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Clojure's a wonderful language, which uses Java bytecode as its machine language, and runs on the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;JVM, and so has easy natural access to all the libraries that Java has.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;My friends at the Chemistry department in Cambridge are using it because they've written a lot of&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Java over the years, and while they like it for all sorts of reasons, they've found that Clojure&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;is an easier way to write Java than Java is.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It has pervasive laziness throughout the language, which allows us to disconnect the things that&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;need to be done from the order they need to be done in.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It has extraordinary pure-functional data structures, and baked-in software transactional memory,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;which together make for a style of programming that can run in parallel on many cores.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It has maps and sets and vectors and regular expressions built right into the language, and so&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;natural to use that they're everyday objects like they are for PERL and Python people.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But I'm going to ignore all of that, and we're going to get over the pons asinorum of lisp, which&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;is all those damned brackets.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We're going to write a program that you could have written in LISP forty years ago, when the&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;newest member of the ALGOL family was ALGOL itself.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;-------------------------------------------------------------------------------------------------&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The method of Heron of Alexandria&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;---------------------------------&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I don't know if any of you remember not having a calculator.  Once upon a time they didn't even&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;have mathematical tables, and so they had to calculate things like square roots by hand.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;One popular method of calculating a square root is due to Hero(n) of Alexandria, who also&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;invented steam power, the windmill, the syringe and the vending machine.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What Heron said to do was this:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Suppose you have a number that you want to find the square root of, let's say 10.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And suppose you have a guess for where that square root might be, let's say 1.  It's not a very&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;good guess, because the square of 1 is 1, not ten, but it will do to get started.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So Heron tells us, if we know the square root, then if we divide 10 by it, we'll get it back.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Like say the square root of 4 is 2, and if we divide 4 by 2, then we get 2.  And that's what it&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;means to *be* a square root.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But if we guessed too low, then the thing we get back will be too high.  And if it's too high,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;then the thing that we get back will be too low.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So Heron says to take the average of what we have and what we get back when we do this division,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and he promises us that will be a better guess.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's try that, for our problem number 10, and our guess 1&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;user&amp;gt; (/ 10 1)&lt;br /&gt;10&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We guessed 1, we divided 10 by 1, we got back 10.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What's the average?&lt;br /&gt;&lt;/span&gt;user&amp;gt; (/ (+ 10 1) 2)&lt;br /&gt;11/2 &lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Or if we do the whole calculation at once, it looks like:&lt;br /&gt;&lt;/span&gt;user&amp;gt; (/ (+ (/ 10 1) 1) 2)&lt;br /&gt;11/2&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;That's getting a bit hard to read, so we should define a function to give us averages:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;user&amp;gt; (&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;average&lt;/span&gt; [a b] (/ (+ a b) 2))&lt;br /&gt;#'user/average&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can test it:&lt;br /&gt;&lt;/span&gt;user&amp;gt; (average 10 1)&lt;br /&gt;11/2&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So our old calculation goes like:&lt;br /&gt;&lt;/span&gt;user&amp;gt; (average (/ 10 1) 1)&lt;br /&gt;11/2&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We might as well make another function which just makes our guesses better.&lt;br /&gt;&lt;/span&gt;user&amp;gt; (&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;improve-guess&lt;/span&gt; [guess] (average guess (/ 10 guess)))&lt;br /&gt;#'user/improve-guess&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's try that:&lt;br /&gt;&lt;/span&gt;user&amp;gt; (improve-guess 1)&lt;br /&gt;11/2&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Of course, a better guess can also be improved.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;user&amp;gt; (improve-guess (improve-guess 1))&lt;br /&gt;161/44&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And improved again.&lt;br /&gt;&lt;/span&gt;user&amp;gt; (improve-guess (improve-guess (improve-guess 1)))&lt;br /&gt;45281/14168&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Now you'll notice that clojure is doing exact arithmetic, and giving us back a fraction, just&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;like a human being would do.  &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But if we start it off with an inexact guess, a decimal rather than a ratio, &lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;say 1.0 rather than 1, then every answer we get back will be a decimal.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;  &lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Because you can't make an exact answer from an inexact input.&lt;br /&gt;&lt;/span&gt;user&amp;gt; (improve-guess (improve-guess (improve-guess 1.0)))&lt;br /&gt;3.196005081874647&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Inexactness is contagious.&lt;br /&gt;&lt;/span&gt;user&amp;gt; (+ 1 2)&lt;br /&gt;3&lt;br /&gt;user&amp;gt; (+ 1.0 2)&lt;br /&gt;3.0&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's go on a bit of a side-track now and look at just how good Heron's idea was.  We can&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;use a magic function called iterate to make an infinite sequence of guesses.  It's best only to&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;look at the first bit of an infinite sequence.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Otherwise, like with the Medusa of Greek myth, the REPL turns to stone.  Let's look at the first&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;five values in our sequence.&lt;br /&gt;&lt;/span&gt;user&amp;gt; (&lt;span class="builtin"&gt;take&lt;/span&gt; 5 (&lt;span class="builtin"&gt;iterate&lt;/span&gt; improve-guess 1))&lt;br /&gt;(1 11/2 161/44 45281/14168 4057691201/1283082416)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We get a better idea of what's going on here if we use decimal fractions&lt;br /&gt;&lt;/span&gt;user&amp;gt; (&lt;span class="builtin"&gt;take&lt;/span&gt; 5 (&lt;span class="builtin"&gt;iterate&lt;/span&gt; improve-guess 1.))&lt;br /&gt;(1.0 5.5 3.659090909090909 3.196005081874647 3.16245562280389)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It only takes a few iterations before we've hit the limit of floating-point accuracy&lt;br /&gt;&lt;/span&gt;user&amp;gt; (&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (&lt;span class="builtin"&gt;iterate&lt;/span&gt; improve-guess 1.))&lt;br /&gt;(1.0 5.5 3.659090909090909 3.196005081874647 3.16245562280389 3.162277665175675 3.162277660168379 3.162277660168379 3.162277660168379 3.162277660168379)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's look at the squares of the values in our sequence:&lt;br /&gt;&lt;/span&gt;user&amp;gt; (&lt;span class="builtin"&gt;map&lt;/span&gt; (fn[x](* x x)) (&lt;span class="builtin"&gt;iterate&lt;/span&gt; improve-guess 1.))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;...time passes...&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Oops. We looked at the medusa! &lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In some environments the REPL is smart enough to print out the values one-by-one, &lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;but here, it's trying to do the whole thing before printing anything.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Ctrl-C will stop the calculation and restore the REPL.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Try again:&lt;br /&gt;&lt;/span&gt;user&amp;gt; (&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (&lt;span class="builtin"&gt;map&lt;/span&gt; (fn[x](* x x)) (&lt;span class="builtin"&gt;iterate&lt;/span&gt; improve-guess 1.)))&lt;br /&gt;(1.0 30.25 13.388946280991735 10.21444848336857 10.001125566203939 10.000000031668918 9.999999999999998 9.999999999999998 9.999999999999998 9.999999999999998)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Iterate and map are magic functions, so let's not worry too much about them yet, &lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;but the magic goes away once you know how it's done.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If they weren't built into the language we could write our own versions.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;They're one liners.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Later I'll show you how they work.  &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;How do we know when to stop improving our guesses?&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;        &lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;First off, we'd like a definition of when our guess is good enough.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;How about, square it and if the answer's close to 10 then that goes?&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;How good a guess is 3.19?&lt;br /&gt;&lt;/span&gt;user&amp;gt; (- 10 (* 3.19 3.19))&lt;br /&gt;-0.17609999999999992&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Rats, we need an absolute value function&lt;br /&gt;&lt;/span&gt;user&amp;gt; (&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;abs&lt;/span&gt;[x] (&lt;span class="keyword"&gt;if&lt;/span&gt; (&amp;lt; x 0) -x x))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;Barf....&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;Sigh. *Every* function needs the same call syntax. Unary minus is a function just like anything else.&lt;br /&gt;&lt;/span&gt;user&amp;gt; (&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;abs&lt;/span&gt;[x] (&lt;span class="keyword"&gt;if&lt;/span&gt; (&amp;lt; x 0) (- x) x))&lt;br /&gt;#'user/abs&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;Let's use map to test the function.&lt;br /&gt;&lt;/span&gt;user&amp;gt; (&lt;span class="builtin"&gt;map&lt;/span&gt; abs (list -1 1 0))&lt;br /&gt;(1 1 0)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So:&lt;br /&gt;&lt;/span&gt;user&amp;gt; (abs (- 10 (* 3.19 3.19)))&lt;br /&gt;0.17609999999999992&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What's good enough? Let's say we're happy if the difference is less than 1/10^6, or 1e-6&lt;br /&gt;&lt;/span&gt;user&amp;gt; 1e-6&lt;br /&gt;1.0E-6&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Here's our good-enough test&lt;br /&gt;&lt;/span&gt;user&amp;gt; (&amp;lt; (abs (- 10 (* 3.19 3.19))) 1e-6)&lt;br /&gt;false&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;3.19 isn't good enough&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Wrap the test up&lt;br /&gt;&lt;/span&gt;user&amp;gt; (&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;good-enough?&lt;/span&gt; [guess] (&amp;lt; (abs (- 10 (* guess guess))) 1e-6))&lt;br /&gt;#'user/good-enough?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's see whether the first five values are good enough&lt;br /&gt;&lt;/span&gt;user&amp;gt; (&lt;span class="builtin"&gt;take&lt;/span&gt; 5 (&lt;span class="builtin"&gt;map&lt;/span&gt; good-enough? (&lt;span class="builtin"&gt;iterate&lt;/span&gt; improve-guess 1.)))&lt;br /&gt;(false false false false false)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What about the first ten?&lt;br /&gt;&lt;/span&gt;user&amp;gt; (&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (&lt;span class="builtin"&gt;map&lt;/span&gt; good-enough? (&lt;span class="builtin"&gt;iterate&lt;/span&gt; improve-guess 1.)))&lt;br /&gt;(false false false false false true true true true true)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What were those answers again?&lt;br /&gt;&lt;/span&gt;user&amp;gt; (&lt;span class="builtin"&gt;take&lt;/span&gt; 10 (&lt;span class="builtin"&gt;iterate&lt;/span&gt; improve-guess 1.))&lt;br /&gt;(1.0 5.5 3.659090909090909 3.196005081874647 3.16245562280389 3.162277665175675 3.162277660168379 3.162277660168379 3.162277660168379 3.162277660168379)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So what if we just want a function that will give us an answer that is good enough?  We'll call&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;it good-enough-guess. &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We give it a guess. If that guess is good enough, then it gives us it back.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If it's not, then it makes it better, and tries again.&lt;br /&gt;&lt;/span&gt;user&amp;gt; (&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;good-enough-guess&lt;/span&gt; [x]&lt;br /&gt;        (&lt;span class="keyword"&gt;if&lt;/span&gt; (good-enough? x) x&lt;br /&gt;            (good-enough-guess (improve-guess x))))&lt;br /&gt;#'user/good-enough-guess&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It doesn't really matter what our initial guess is. Anything will work.&lt;br /&gt;&lt;/span&gt;user&amp;gt; (good-enough-guess 1.0)&lt;br /&gt;3.162277665175675&lt;br /&gt;&lt;br /&gt;user&amp;gt; (good-enough-guess 3.0)&lt;br /&gt;3.162277660169842&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;How good is that guess?&lt;br /&gt;&lt;/span&gt;user&amp;gt; (* (good-enough-guess 3.0)(good-enough-guess 3.0))&lt;br /&gt;10.00000000000925&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Sweet. Here endeth the method of Heron of Alexandria for finding the square root of 10.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's have a look at our program in its entirety&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;average&lt;/span&gt; [a b] &lt;br /&gt;  (/ (+ a b) 2))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;improve-guess&lt;/span&gt; [guess]&lt;br /&gt;  (average guess (/ 10 guess)))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;abs&lt;/span&gt;[x] &lt;br /&gt;  (&lt;span class="keyword"&gt;if&lt;/span&gt; (&amp;lt; x 0) (- x) x))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;good-enough?&lt;/span&gt; [guess] &lt;br /&gt;  (&amp;lt; (abs (- 10 (* guess guess))) 1e-6))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;good-enough-guess&lt;/span&gt; [x]&lt;br /&gt;  (&lt;span class="keyword"&gt;if&lt;/span&gt; (good-enough? x) x&lt;br /&gt;      (good-enough-guess (improve-guess x))))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-7630583826707299285?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/7630583826707299285/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2010/01/clojure-dojo-method-of-heron-of.html#comment-form' title='14 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/7630583826707299285'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/7630583826707299285'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2010/01/clojure-dojo-method-of-heron-of.html' title='Clojure Dojo: The method of Heron of Alexandria'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>14</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-5887133640716036601</id><published>2011-02-08T22:24:00.003Z</published><updated>2011-02-08T22:27:42.168Z</updated><title type='text'>RabbitMQ &amp; Clojure: Hello World</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      .string {        /* font-lock-string-face */        color: #ffa500;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;pre class="clojure-body"&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;RabbitMQ is a way for different processes to talk to one another.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Here we're going to start a process and get it to send messages to itself via&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;rabbitMQ.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;First we need to install rabbitmq. I'm using Ubuntu 10.10, so that's:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;$ sudo apt-get install rabbitmq-server&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Unfortunately Ubuntu has an old version, which the current client library is&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;unable to talk to.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Since the protocol has changed, it seems silly to use the old version,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;especially since rabbit provide a debian package which seems to work fine:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;To install the latest rabbitmq release (2.3.1 at time of writing)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;$ wget http://www.rabbitmq.com/releases/rabbitmq-server/v2.3.1/rabbitmq-server_2.3.1-1_all.deb&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;$ sudo dpkg -i rabbitmq-server_2.3.1-1_all.deb&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I installed this over the top of the default ubuntu installation and this&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;seems to work.  I don't know what happens if you install it&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;out-of-the-blue. Things may not get set up right, although the rabbitmq&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;website seems to indicate that it will be ok.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;You can check that rabbitMQ is working (woc-desktop is the name of my&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;machine, don't ask..) with&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;$ sudo rabbitmqctl -n rabbit@woc-desktop status&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Which should respond:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Status of node 'rabbit@woc-desktop' ...&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;[{running_applications,[{rabbit,"RabbitMQ","2.3.1"},&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;                         &lt;/span&gt;&lt;span class="comment"&gt;{mnesia,"MNESIA  CXC 138 12","4.4.12"},&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;                         &lt;/span&gt;&lt;span class="comment"&gt;{os_mon,"CPO  CXC 138 46","2.2.4"},&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;                         &lt;/span&gt;&lt;span class="comment"&gt;{sasl,"SASL  CXC 138 11","2.1.8"},&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;                         &lt;/span&gt;&lt;span class="comment"&gt;{stdlib,"ERTS  CXC 138 10","1.16.4"},&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;                         &lt;/span&gt;&lt;span class="comment"&gt;{kernel,"ERTS  CXC 138 10","2.13.4"}]},&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;{nodes,[{disc,['rabbit@woc-desktop']}]},&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;{running_nodes,['rabbit@woc-desktop']}]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The corresponding java client library is in the central maven repository so&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;you should add this snippet to your pom.xml or the corresponding incantation&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;to your project.clj if you use leiningen:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;    &lt;/span&gt;&lt;span class="comment"&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;      &lt;/span&gt;&lt;span class="comment"&gt;&amp;lt;groupId&amp;gt;com.rabbitmq&amp;lt;/groupId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;      &lt;/span&gt;&lt;span class="comment"&gt;&amp;lt;artifactId&amp;gt;amqp-client&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;      &lt;/span&gt;&lt;span class="comment"&gt;&amp;lt;version&amp;gt;2.3.1&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;    &lt;/span&gt;&lt;span class="comment"&gt;&amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;First we have to import the classes from the java library.&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;import&lt;/span&gt; (com.rabbitmq.client ConnectionFactory Connection Channel QueueingConsumer))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And then we have to translate the equivalent java hello world program using&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Clojure's excellent interop.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It feels very strange writing this sort of ceremony-oriented imperative code&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;in Clojure:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Make a connection factory on the local host&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;connection-factory&lt;/span&gt;&lt;br /&gt;     (&lt;span class="keyword"&gt;doto&lt;/span&gt; (ConnectionFactory.)&lt;br /&gt;       (.setHost &lt;span class="string"&gt;"localhost"&lt;/span&gt;)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and get it to make you a connection&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;connection&lt;/span&gt; (.newConnection connection-factory))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;get that to make you a channel&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;channel&lt;/span&gt; (&lt;span class="keyword"&gt;.&lt;/span&gt; connection createChannel))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And on that channel, create (or at least ensure the existence of) a queue,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;named "hello", which is neither durable nor exclusive nor auto-deleted:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;.&lt;/span&gt; channel queueDeclare &lt;span class="string"&gt;"hello"&lt;/span&gt; false false false nil)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Now we'll send ten messages to that queue:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;dotimes&lt;/span&gt; [ i 10 ]&lt;br /&gt;  (&lt;span class="keyword"&gt;.&lt;/span&gt; channel basicPublish &lt;span class="string"&gt;""&lt;/span&gt; &lt;span class="string"&gt;"hello"&lt;/span&gt; nil (&lt;span class="keyword"&gt;.&lt;/span&gt; (&lt;span class="builtin"&gt;format&lt;/span&gt; &lt;span class="string"&gt;"Hello World! (%d)"&lt;/span&gt; i) getBytes)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Strictly we're sending the messages to the default exchange "", using the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;routing key "hello"&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Now we want to retrieve our messages from the queue.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We create a consumer&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;consumer&lt;/span&gt; (new QueueingConsumer channel))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And attach it to the channel&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;.&lt;/span&gt; channel basicConsume &lt;span class="string"&gt;"hello"&lt;/span&gt; true consumer)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;consumer.nextDelivery() will block waiting for a message to arrive in the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;queue, so we can just keep looping&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;loop&lt;/span&gt; []&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [delivery (&lt;span class="keyword"&gt;.&lt;/span&gt; consumer nextDelivery)&lt;br /&gt;        str (String. (&lt;span class="keyword"&gt;.&lt;/span&gt; delivery getBody))]&lt;br /&gt;          (&lt;span class="builtin"&gt;println&lt;/span&gt; str)&lt;br /&gt;          (&lt;span class="keyword"&gt;recur&lt;/span&gt;)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The fun part is that we could run several copies of this program simultaneously&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If you're using the maven-clojure-plugin, then the command to run this script&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;from the command line is:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;$ mvn -Dclojure.script=rabbitmq.clj clojure:run&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So you can run it on various separate terminals at once.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The first one you run will just send messages to itself and print them out.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Later copies will send messages over which earlier ones will fight. It's most entertaining!&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-5887133640716036601?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/5887133640716036601/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/02/rabbitmq-clojure-hello-world.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/5887133640716036601'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/5887133640716036601'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/02/rabbitmq-clojure-hello-world.html' title='RabbitMQ &amp; Clojure: Hello World'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-4294998239374329516</id><published>2011-01-30T22:21:00.002Z</published><updated>2011-01-30T22:21:12.071Z</updated><title type='text'>Turning Exceptions into Return Values</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      .string {        /* font-lock-string-face */        color: #ffa500;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;pre class="clojure-body"&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I often find that the default behaviour of exceptions in emacs/slime is a bit&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;annoying.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Up pops up a debugger window, but that moves the focus away from where&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;you're working, and the new window then needs dismissing, and has often&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;buggered up the size of other windows, etc...&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Also when playing with experimental clojure versions, the behaviour is a bit&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;random, and often the expression just gets swallowed, with no clue as to what&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;it was:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Anyway I wrote this little macro, which turns an exception into a return value:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defmacro&lt;/span&gt; &lt;span class="function-name"&gt;tryc&lt;/span&gt;[ &amp;amp; e]&lt;br /&gt;  `(&lt;span class="keyword"&gt;try&lt;/span&gt; ~@e&lt;br /&gt;       (&lt;span class="keyword"&gt;catch&lt;/span&gt; Exception a# a#)))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(tryc (java.io.File &lt;span class="string"&gt;"."&lt;/span&gt;)) &lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;#&amp;lt;ClassCastException java.lang.ClassCastException: java.lang.Class cannot be cast to clojure.lang.IFn&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Obviously you should only use this at the top level!&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I find I'm using it all the time when writing code in emacs&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-4294998239374329516?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/4294998239374329516/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/01/turning-exceptions-into-return-values.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/4294998239374329516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/4294998239374329516'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/01/turning-exceptions-into-return-values.html' title='Turning Exceptions into Return Values'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-7715404504460576126</id><published>2011-01-30T21:24:00.003Z</published><updated>2011-01-30T21:25:13.965Z</updated><title type='text'>Finding Something in a Vector, Parsing CSV Files</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      .string {        /* font-lock-string-face */        color: #ffa500;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;pre class="clojure-body"&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Indexing Into a Vector: A Sequence of Answers&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The other day, I had a csv file to read (csv files are comma-separated&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;values, often produced by exporting spreadsheets, or a reasonably standard&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;human-readable format for grids of data)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;There's a lovely library which takes all the hard work out of reading csv&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;files&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The library's on clojars, so you use it by adding this to your maven pom.xml&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;&amp;lt;dependency&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;   &lt;/span&gt;&lt;span class="comment"&gt;&amp;lt;groupId&amp;gt;clojure-csv&amp;lt;/groupId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;   &lt;/span&gt;&lt;span class="comment"&gt;&amp;lt;artifactId&amp;gt;clojure-csv&amp;lt;/artifactId&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;   &lt;/span&gt;&lt;span class="comment"&gt;&amp;lt;version&amp;gt;1.2.0&amp;lt;/version&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;&amp;lt;/dependency&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and then you can use clojure-csv.core/parse-csv to read your file in as a&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;sequence.  It seems to magically handle all the intricies of all the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;different possible csv file arrangements.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Thankyou David Santiago, it works like a charm.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But then I hit a problem: I wanted to read the email-addresses from every&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;record.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I've rather simplified here, but let's imagine that the data after parsing&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;looked like this:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;csv-data&lt;/span&gt;&lt;br /&gt;     [[&lt;span class="string"&gt;"Name"&lt;/span&gt; &lt;span class="string"&gt;"E-mail 1"&lt;/span&gt; &lt;span class="string"&gt;"Address"&lt;/span&gt; &lt;span class="string"&gt;"E-mail 2"&lt;/span&gt; &lt;span class="string"&gt;"E-mail 3"&lt;/span&gt;]&lt;br /&gt;      [&lt;span class="string"&gt;"John"&lt;/span&gt; &lt;span class="string"&gt;"john@mailinator.com"&lt;/span&gt; &lt;span class="string"&gt;"3 Church St"&lt;/span&gt; &lt;span class="string"&gt;"xyz@learnclojure.com"&lt;/span&gt; &lt;span class="string"&gt;""&lt;/span&gt;]&lt;br /&gt;      [&lt;span class="string"&gt;"Fred"&lt;/span&gt; &lt;span class="string"&gt;"fred@mailinator.com"&lt;/span&gt; &lt;span class="string"&gt;"7 Park Street"&lt;/span&gt; &lt;span class="string"&gt;"fred@gmail.com"&lt;/span&gt; &lt;span class="string"&gt;"fred@googlemail.com"&lt;/span&gt; ]])&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;header&lt;/span&gt; (&lt;span class="builtin"&gt;first&lt;/span&gt; csv-data))&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;data&lt;/span&gt;   (&lt;span class="builtin"&gt;rest&lt;/span&gt; csv-data))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;As it happened, most of the email-addresses were stored in the second column,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;but some records had two or even three addresses, and it looked as though the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;generating program might be labelling its columns according to the number of&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;e-mail addresses it needed to output.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It seemed very likely that another data set might have an "E-mail 4" column,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and it seemed unwise to rely on the needed columns always being 1,3,4 and&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;possibly 5. What if the program introduced another field entirely?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So obviously I needed a function to look up things in the header row somehow.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And there didn't seem to be one, although there were the interesting&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;functions keep-indexed and map-indexed, which I hadn't noticed before.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And I couldn't find one. So I figured that I could either write one, or I&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;could ask on Stack Overflow.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And so I did both, expecting to find that I'd re-invent something in the&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;standard library, or at least in contrib, that I hadn't been able to find.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;http://stackoverflow.com/questions/4830900/how-do-i-find-the-index-of-an-item-in-a-vector&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So the function(s) I came up with were:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;indices-of&lt;/span&gt; [f coll]&lt;br /&gt;  (keep-indexed #(&lt;span class="keyword"&gt;if&lt;/span&gt; (f %2) %1 nil) coll))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;first-index-of&lt;/span&gt; [f coll]&lt;br /&gt;  (&lt;span class="builtin"&gt;first&lt;/span&gt; (indices-of f coll)))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;find-thing&lt;/span&gt; [value coll]&lt;br /&gt;  (first-index-of #(&lt;span class="builtin"&gt;=&lt;/span&gt; % value) coll))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And here are some examples:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(indices-of #(&lt;span class="builtin"&gt;=&lt;/span&gt; &lt;span class="string"&gt;"Name"&lt;/span&gt; %) header) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(0)&lt;br /&gt;&lt;/span&gt;(indices-of (&lt;span class="builtin"&gt;partial&lt;/span&gt; re-matches #&lt;span class="string"&gt;".*E-mail.*"&lt;/span&gt;) header) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(1 3 4)&lt;br /&gt;&lt;/span&gt;(first-index-of #(&lt;span class="builtin"&gt;=&lt;/span&gt; &lt;span class="string"&gt;"Name"&lt;/span&gt; %) header) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0&lt;br /&gt;&lt;/span&gt;(find-thing &lt;span class="string"&gt;"Name"&lt;/span&gt; header) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But I was a bit nervous about these solutions, because I thought I must just&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;have re-invented some sort of wheel, and also because they're happy to return&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;answers for sets and maps, where the question doesn't really make much sense&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;fine&lt;br /&gt;&lt;/span&gt;(find-thing &lt;span class="string"&gt;"two"&lt;/span&gt; [&lt;span class="string"&gt;"one"&lt;/span&gt; &lt;span class="string"&gt;"two"&lt;/span&gt; &lt;span class="string"&gt;"three"&lt;/span&gt; &lt;span class="string"&gt;"two"&lt;/span&gt;]) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1&lt;br /&gt;&lt;/span&gt;(find-thing &lt;span class="string"&gt;"two"&lt;/span&gt; '(&lt;span class="string"&gt;"one"&lt;/span&gt; &lt;span class="string"&gt;"two"&lt;/span&gt; &lt;span class="string"&gt;"three"&lt;/span&gt;)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;but these answers are a bit silly&lt;br /&gt;&lt;/span&gt;(find-thing &lt;span class="string"&gt;"two"&lt;/span&gt; #{&lt;span class="string"&gt;"one"&lt;/span&gt; &lt;span class="string"&gt;"two"&lt;/span&gt; &lt;span class="string"&gt;"three"&lt;/span&gt;}) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1&lt;br /&gt;&lt;/span&gt;(find-thing &lt;span class="string"&gt;"two"&lt;/span&gt; {&lt;span class="string"&gt;"one"&lt;/span&gt; &lt;span class="string"&gt;"two"&lt;/span&gt; &lt;span class="string"&gt;"two"&lt;/span&gt; &lt;span class="string"&gt;"three"&lt;/span&gt;}) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;nil&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But I went back to Stack Overflow, in order to answer my own question, and&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;found a couple of much better answers.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Brian Carper pointed out:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(.indexOf header &lt;span class="string"&gt;"Name"&lt;/span&gt;) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Which is clearly the answer for searching vectors.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And ponzao pointed out this lovely thing, originally due to Stuart Halloway:&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;require&lt;/span&gt; 'clojure.contrib.seq)&lt;br /&gt;(&lt;span class="builtin"&gt;first&lt;/span&gt; (clojure.contrib.seq/positions #{&lt;span class="string"&gt;"Name"&lt;/span&gt;} header)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;positions is like indices-of, but using a set as the predicate is really clever.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;anyway, now I could say:&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; #( % (.indexOf header &lt;span class="string"&gt;"Name"&lt;/span&gt;)) data) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;("John" "Fred")&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; #( % (.indexOf header &lt;span class="string"&gt;"E-mail 1"&lt;/span&gt;)) data) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;("john@mailinator.com" "fred@mailinator.com")&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Or even, for fans of terseness and crypticity (and forgive me Lord, for I am&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;such a fan), something like:&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; #(&lt;span class="builtin"&gt;vector&lt;/span&gt; (% (.indexOf header &lt;span class="string"&gt;"Name"&lt;/span&gt;))&lt;br /&gt;              (&lt;span class="keyword"&gt;for&lt;/span&gt; [i (clojure.contrib.seq/positions&lt;br /&gt;                       (&lt;span class="builtin"&gt;partial&lt;/span&gt; re-matches #&lt;span class="string"&gt;"E-mail \d+"&lt;/span&gt;) header)]&lt;br /&gt;                (% i))) data)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(["John" ("john@mailinator.com" "xyz@learnclojure.com" "")]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;["Fred" ("fred@mailinator.com" "fred@gmail.com" "fred@googlemail.com")])&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But a little later, there was another answer from cgrand, who warned me&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;against using indices on general principles. And I agree with that, so I&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;asked what I should do in the particular case of csv files. And there was an&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;answer from Alex Stoddard, which I believe is the answer to the question that&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I should have asked.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can make a map from strings to indices&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;hmap&lt;/span&gt; (zipmap header (&lt;span class="builtin"&gt;iterate&lt;/span&gt; inc 0)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And use it like this:&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; #(% (hmap &lt;span class="string"&gt;"Name"&lt;/span&gt;)) data) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;("John" "Fred")&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;or this:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;e-mails&lt;/span&gt; (&lt;span class="builtin"&gt;filter&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; re-matches #&lt;span class="string"&gt;"E-mail \d+"&lt;/span&gt;) header))&lt;br /&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; #(&lt;span class="builtin"&gt;vector&lt;/span&gt; (% (hmap &lt;span class="string"&gt;"Name"&lt;/span&gt;)) (&lt;span class="keyword"&gt;for&lt;/span&gt; [e e-mails] (% (hmap e)))) data)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;or this:&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; #(&lt;span class="builtin"&gt;vector&lt;/span&gt;&lt;br /&gt;       (% (hmap &lt;span class="string"&gt;"Name"&lt;/span&gt;))&lt;br /&gt;       (&lt;span class="keyword"&gt;for&lt;/span&gt; [e (&lt;span class="builtin"&gt;filter&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; re-matches #&lt;span class="string"&gt;"E-mail \d+"&lt;/span&gt;) header)]&lt;br /&gt;         (% (hmap e)))) data)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;to get:&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(["John" ("john@mailinator.com" "xyz@learnclojure.com" "")]&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;["Fred" ("fred@mailinator.com" "fred@gmail.com" "fred@googlemail.com")])&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;or even this (although now you do have to rely on the name coming before the e-mails):&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; #(&lt;span class="keyword"&gt;for&lt;/span&gt; [e (&lt;span class="builtin"&gt;filter&lt;/span&gt; (&lt;span class="builtin"&gt;partial&lt;/span&gt; re-matches #&lt;span class="string"&gt;"E-mail \d+|Name"&lt;/span&gt;) header)]&lt;br /&gt;        (% (hmap e)))&lt;br /&gt;     data)&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;to get:&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(("John" "john@mailinator.com" "xyz@learnclojure.com" "")&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;  &lt;/span&gt;&lt;span class="comment"&gt;("Fred" "fred@mailinator.com" "fred@gmail.com" "fred@googlemail.com"))&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;If we want to abstract out a pattern, then:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;columns&lt;/span&gt; [f header data]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [hmap (zipmap header (&lt;span class="builtin"&gt;iterate&lt;/span&gt; inc 0))&lt;br /&gt;        cols (&lt;span class="builtin"&gt;filter&lt;/span&gt; f header)&lt;br /&gt;    (&lt;span class="builtin"&gt;map&lt;/span&gt; #(&lt;span class="keyword"&gt;for&lt;/span&gt; [e cols] (% (hmap e))) data)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;allows:&lt;br /&gt;&lt;/span&gt;(columns #{&lt;span class="string"&gt;"Name"&lt;/span&gt;} header data) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(("John") ("Fred"))&lt;br /&gt;&lt;/span&gt;(columns (&lt;span class="builtin"&gt;partial&lt;/span&gt; re-matches #&lt;span class="string"&gt;"E-mail \d+"&lt;/span&gt;) header data) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(("john@mailinator.com" "xyz@learnclojure.com" "") ("fred@mailinator.com" "fred@gmail.com" "fred@googlemail.com"))&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-7715404504460576126?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/7715404504460576126/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/01/finding-something-in-vector-parsing-csv.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/7715404504460576126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/7715404504460576126'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/01/finding-something-in-vector-parsing-csv.html' title='Finding Something in a Vector, Parsing CSV Files'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-5233677146340162156</id><published>2011-01-27T20:10:00.000Z</published><updated>2011-01-27T20:10:40.290Z</updated><title type='text'>£500 if you can find me a job (version 1.0)</title><content type='html'>&lt;a href="http://www.learningclojure.com/2010/10/gis-job.html"&gt;That&lt;/a&gt;&amp;nbsp;worked a treat, £500 awarded to lucky winner who found me a fun short contract.&lt;br /&gt;&lt;br /&gt;Now I'd like another one, so I repeat the offer:&lt;br /&gt;&lt;br /&gt;If, within the next six months, I take a job which lasts longer than one month, and that is not obtained through an agency, then on the day the first cheque from that job cashes, I'll give £500 to the person who provided the crucial introduction.&lt;br /&gt;&lt;br /&gt;If there are a number of people involved somehow, then I'll apportion it fairly between them. And if the timing conditions above are not quite met, or if someone points me at a short contract which the £500 penalty makes not worth taking, then I'll do something fair and proportional anyway. (The thing Simon pointed me at only lasted three weeks and I paid him in full anyway, because it was neat.)&lt;br /&gt;&lt;br /&gt;And this offer applies even to personal friends, and to old contacts who I have not got round to calling yet, and to people who are themselves offering work, because why wouldn't it?&lt;br /&gt;&lt;br /&gt;And obviously if I find one through my own efforts then I'll keep the money. But my word is generally thought to be good, and I have made a public promise on my own blog to this effect, so if I cheat you you can blacken my name and ruin my reputation for honesty, which is worth much more to me than £500.&lt;br /&gt;&lt;br /&gt;Anyhow, my CV is at &lt;a href="http://www.aspden.com/"&gt;http://www.aspden.com&lt;/a&gt;, and any advice on how it could be improved will be gratefully received.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;I'll also repeat the original advert: (job-hunt.contrib 1.0)&lt;br /&gt;&lt;br /&gt;Anyone in Cambridge need a programmer? Obviously Clojure is a speciality, and my current obsession, but I'm also pretty good with C (especially the embedded variety), microcontrollers, and Python, and I have a particular facility with mathematical concepts and algorithms of all kinds. My obsessions can be pretty quickly changed when I need them to be.&lt;br /&gt;&lt;br /&gt;I have a (deserved) reputation for being able to produce heavily optimised but nevertheless bug-free and readable code, but I also know how to hack together sloppy, bug-ridden prototypes, and I know which style is appropriate when, and how to slide along the continuum between them.&lt;br /&gt;&lt;br /&gt;I've worked in telecoms, commercial research,&amp;nbsp;banking,&amp;nbsp;university research, a chip design company, server virtualization, a couple of startups, and occasionally completely alone.&lt;br /&gt;&lt;br /&gt;I've worked on many sizes of machine. I've written programs for tiny 8-bit microcontrollers, and once upon a time every IBM machine in one building in Imperial College was running my partial differential equation solvers in parallel in the background.&lt;br /&gt;&lt;br /&gt;I'm smart and I get things done. I'm confident enough in my own abilities that if I can't do something I admit it and find someone who can.&lt;br /&gt;&lt;br /&gt;I also have various ancient and rusty skills with things like Java, C++, R, OCaml, Common LISP, Scheme, FORTRAN and Pascal which can be brushed up if necessary. Like all lispers, I occasionally write toy interpreters for made-up languages for fun.&lt;br /&gt;&lt;br /&gt;If you're a local company using Java, who might be interested in giving Clojure a try (motivation here, in Paul Graham's classic &lt;a href="http://www.paulgraham.com/avg.html"&gt;Beating the Averages&lt;/a&gt;), I'd love to try to show you what all the fuss is about.&lt;br /&gt;&lt;br /&gt;CV here if you're interested: &lt;a href="http://www.aspden.com/"&gt;http://www.aspden.com&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I've never used a CV before, having always found work through word of mouth. So I expect that it can be improved. If anyone's got any suggestions as to how it could be better written, do please leave comments or e-mail &lt;a href="mailto:cv@aspden.com"&gt;cv@aspden.com&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-5233677146340162156?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/5233677146340162156/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/01/500-if-you-can-find-me-job-version-10.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/5233677146340162156'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/5233677146340162156'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/01/500-if-you-can-find-me-job-version-10.html' title='£500 if you can find me a job (version 1.0)'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-7203270956497988578</id><published>2011-01-25T23:37:00.000Z</published><updated>2011-01-25T23:37:32.314Z</updated><title type='text'>K-means : An Algorithm for Clustering Data</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;pre class="clojure-body"&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;K-means&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;K-means is a Clustering Algorithm.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We use it when we have some data, and we want to split the data into separate categories.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;For instance, an early biologist, let's call him Adam, might measure all&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;sorts of things about the living objects he encounters in the world.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(black, feathers, flies)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(green, tasty)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(green, slithers, poisonous)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;... and so on&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;After he collects enough data, he might go looking for structure in it.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Uninformed by theory, he might nevertheless notice that many things that do&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;not move are green, and that many things that are not green move.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;He might name these two obvious groups the Animals and the Plants.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Further analysis of the data might split the Plants into Trees and Flowers,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and the Animals into Mammals, Birds, and Fish.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Theoretically, this process could continue further, extracting 'natural&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;categories' from the observed structure of the data, without any theory about&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;how the various properties come about&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's consider a very simple clustering situation. We have some numbers,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and we'd like to see if they form groups.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Suppose we want to cluster the points 2 3 5 6 10 11 100 101 102&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;data&lt;/span&gt; '(2 3 5 6 10 11 100 101 102))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;You may be able to see some natural groupings in this data.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It's easy enough to say how far one number is from another&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;distance&lt;/span&gt;[a b] = (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;&amp;lt;&lt;/span&gt; a b) (&lt;span class="builtin"&gt;-&lt;/span&gt; b a) (&lt;span class="builtin"&gt;-&lt;/span&gt; a b)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;To do K-means, we need to start with some guesses about where the clusters are.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;They don't have to be terribly good guesses.&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;guessed-means&lt;/span&gt; '(0 10))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Given a particular point, we want to know which of our means is closest&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;closest&lt;/span&gt; [point means distance]&lt;br /&gt;  (&lt;span class="builtin"&gt;first&lt;/span&gt; (&lt;span class="builtin"&gt;sort-by&lt;/span&gt; #(distance % point) means)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In our little dataset, 2 is closest to the guess of 0, and 100 is closest to the guess of 10&lt;br /&gt;&lt;/span&gt;(closest 2   guessed-means distance) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0&lt;br /&gt;&lt;/span&gt;(closest 100 guessed-means distance) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;10&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So we can talk about the group of all points for which 0 is the best guess&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and the group of all points for which 10 is the best guess.&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;point-groups&lt;/span&gt; [means data distance]&lt;br /&gt;  (group-by #(closest % means distance) data))&lt;br /&gt;&lt;br /&gt;(point-groups guessed-means data distance) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;{0 [2 3 5], 10 [6 10 11 100 101 102]}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can take an average of a group of points&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;average&lt;/span&gt; [&amp;amp; list] (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;reduce&lt;/span&gt; + list) (&lt;span class="builtin"&gt;count&lt;/span&gt; list)))&lt;br /&gt;&lt;br /&gt;(average 6 10 11 100 101 102) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;55&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So we can take the average of each group, and use it as a new guess for where&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;the clusters are. If a mean doesn't have a group, then we'll leave it where&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;it is.&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;new-means&lt;/span&gt; [average point-groups old-means]&lt;br /&gt;  (&lt;span class="keyword"&gt;for&lt;/span&gt; [o old-means]&lt;br /&gt;    (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;contains?&lt;/span&gt; point-groups o)&lt;br /&gt;      (&lt;span class="builtin"&gt;apply&lt;/span&gt; average (&lt;span class="builtin"&gt;get&lt;/span&gt; point-groups o)) o)))&lt;br /&gt;&lt;br /&gt;(new-means average (point-groups guessed-means data distance) guessed-means) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(10/3 55)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So if we know we've got a particular set of points, and a particular idea of&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;distance, and a way of averaging things, that gives us a way of making a new&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;list of guesses from our original list of guesses&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;iterate-means&lt;/span&gt; [data distance average]&lt;br /&gt;  (&lt;span class="builtin"&gt;fn&lt;/span&gt; [means] (new-means average (point-groups means data distance) means)))&lt;br /&gt;&lt;br /&gt;((iterate-means data distance average) '(0 10)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(10/3 55)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and of course we can use that as a new guess, and improve it again.&lt;br /&gt;&lt;/span&gt;((iterate-means data distance average) '(10/3 55)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(37/6 101)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can do this repeatedly until it settles down.&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;iterate&lt;/span&gt; (iterate-means data distance average) '(0 10)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;((0 10) (10/3 55) (37/6 101) (37/6 101) .....)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;K-means with two means seems to be trying to tell us that we've got a group&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;centered around 6 and another centred around 101&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;These groups are:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;groups&lt;/span&gt; [data distance means]&lt;br /&gt;  (&lt;span class="builtin"&gt;vals&lt;/span&gt; (point-groups means data distance)))&lt;br /&gt;&lt;br /&gt;(groups data distance '(37/6 101)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;([2 3 5 6 10 11] [100 101 102])&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Ideally we'd like to iterate until the groups stop changing.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I described a function for doing this in a previous post:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;take-while-unstable&lt;/span&gt; &lt;br /&gt;  ([sq] (&lt;span class="builtin"&gt;lazy-seq&lt;/span&gt; (&lt;span class="keyword"&gt;if-let&lt;/span&gt; [sq (&lt;span class="builtin"&gt;seq&lt;/span&gt; sq)]&lt;br /&gt;                    (&lt;span class="builtin"&gt;cons&lt;/span&gt; (&lt;span class="builtin"&gt;first&lt;/span&gt; sq) (take-while-unstable (&lt;span class="builtin"&gt;rest&lt;/span&gt; sq) (&lt;span class="builtin"&gt;first&lt;/span&gt; sq))))))&lt;br /&gt;  ([sq last] (&lt;span class="builtin"&gt;lazy-seq&lt;/span&gt; (&lt;span class="keyword"&gt;if-let&lt;/span&gt; [sq (&lt;span class="builtin"&gt;seq&lt;/span&gt; sq)]&lt;br /&gt;                         (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (&lt;span class="builtin"&gt;first&lt;/span&gt; sq) last) '() (take-while-unstable sq))))))&lt;br /&gt;&lt;br /&gt;(take-while-unstable '(1 2 3 4 5 6 7 7 7 7)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(1 2 3 4 5 6 7)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(take-while-unstable (&lt;span class="builtin"&gt;map&lt;/span&gt; #(groups data distance %) (&lt;span class="builtin"&gt;iterate&lt;/span&gt; (iterate-means data distance average) '(0 10))))&lt;br /&gt;                                        &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(([2 3 5] [6 10 11 100 101 102])&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;([2 3 5 6 10 11] [100 101 102]))&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Shows that our first guesses group 2,3 and 5 (nearer to 0 than 10) vs all the rest.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;K-means modifies that instantly to separate out the large group of three.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can make a function, which takes our data, notion of distance, and notion of average,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and gives us back a function which, for a given set of initial guesses at the means,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;shows us how the group memberships change.&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;k-groups&lt;/span&gt; [data distance average]&lt;br /&gt;  (&lt;span class="builtin"&gt;fn&lt;/span&gt; [guesses]&lt;br /&gt;    (take-while-unstable&lt;br /&gt;     (&lt;span class="builtin"&gt;map&lt;/span&gt; #(groups data distance %)&lt;br /&gt;          (&lt;span class="builtin"&gt;iterate&lt;/span&gt; (iterate-means data distance average) guesses)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;grouper&lt;/span&gt; (k-groups data distance average))&lt;br /&gt;&lt;br /&gt;(grouper '(0 10))&lt;br /&gt;                                        &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(([2 3 5] [6 10 11 100 101 102])&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;([2 3 5 6 10 11] [100 101 102]))&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Nothing we said above limits us to only having two guesses&lt;br /&gt;&lt;/span&gt;(grouper '(1 2 3))&lt;br /&gt;                                        &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(([2] [3 5 6 10 11 100 101 102])&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;([2 3 5 6 10 11] [100 101 102])&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;([2 3] [5 6 10 11] [100 101 102])&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;([2 3 5] [6 10 11] [100 101 102])&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;([2 3 5 6] [10 11] [100 101 102]))&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The more means we start with, the more detailed our clustering.&lt;br /&gt;&lt;/span&gt;(grouper '(0 1 2 3 4))&lt;br /&gt;                                        &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(([2] [3] [5 6 10 11 100 101 102])&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;([2] [3 5 6 10 11] [100 101 102])&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;([2 3] [5 6 10 11] [100 101 102])&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;([2 3 5] [6 10 11] [100 101 102])&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;([2] [3 5 6] [10 11] [100 101 102])&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;([2 3] [5 6] [10 11] [100 101 102]))&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We have to be careful not to start off with too many means, or we just get our data back:&lt;br /&gt;&lt;/span&gt;(grouper (&lt;span class="builtin"&gt;range&lt;/span&gt; 200)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(([2] [3] [100] [5] [101] [6] [102] [10] [11]))&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Generalizing to Other Spaces&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In fact, nothing we said above depends on our inputs being numbers&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can use any data where we can define a distance, and a method of averaging:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;One of the easiest things to do this for would be vectors:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;vec-distance&lt;/span&gt; [a b] (&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; #(&lt;span class="builtin"&gt;*&lt;/span&gt; % %) (&lt;span class="builtin"&gt;map&lt;/span&gt; - a b))))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;vec-average&lt;/span&gt;  [&amp;amp; l] (&lt;span class="builtin"&gt;map&lt;/span&gt; #(&lt;span class="builtin"&gt;/&lt;/span&gt; % (&lt;span class="builtin"&gt;count&lt;/span&gt; l)) (&lt;span class="builtin"&gt;apply&lt;/span&gt; map + l)))&lt;br /&gt;&lt;br /&gt;(vec-distance [1 2 3][5 6 7]) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;48&lt;br /&gt;&lt;/span&gt;(vec-average  [1 2 3][5 6 7]) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(3 4 5)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Here's a little set of vectors&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;vector-data&lt;/span&gt; '( [1 2 3] [3 2 1] [100 200 300] [300 200 100] [50 50 50]))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And choosing three guesses in a fairly simple-minded manner, we can see how the algorithm&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;divides them into three different groups.&lt;br /&gt;&lt;/span&gt;((k-groups vector-data vec-distance vec-average) '([1 1 1] [2 2 2] [3 3 3]))&lt;br /&gt;                                        &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(([[1 2 3] [3 2 1]] [[100 200 300] [300 200 100] [50 50 50]])&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;([[1 2 3] [3 2 1] [50 50 50]]&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;   &lt;/span&gt;&lt;span class="comment"&gt;[[100 200 300] [300 200 100]])&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;([[1 2 3] [3 2 1]]&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;   &lt;/span&gt;&lt;span class="comment"&gt;[[100 200 300] [300 200 100]]&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;   &lt;/span&gt;&lt;span class="comment"&gt;[[50 50 50]]))&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Pedantic Footnote&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Note that the algorithm as described above isn't quite the classic K-means.&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I don't think the difference is terribly important, and I thought it would complicate the explanation to deal with it.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In the usual K-means, if you have two identical means, then you're only supposed to update one of them.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Here our two identical guesses are both getting updated&lt;br /&gt;&lt;/span&gt;(new-means average (point-groups '(0 0) '(0 1 2 3 4) distance) '(0 0)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(2 2)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Our update function:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;new-means&lt;/span&gt; [average point-groups old-means]&lt;br /&gt;  (&lt;span class="keyword"&gt;for&lt;/span&gt; [o old-means]&lt;br /&gt;    (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;contains?&lt;/span&gt; point-groups o)&lt;br /&gt;      (&lt;span class="builtin"&gt;apply&lt;/span&gt; average (&lt;span class="builtin"&gt;get&lt;/span&gt; point-groups o)) o)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Needs to be changed so that if there are two identical means only one of them will be changed:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;update-seq&lt;/span&gt; [sq f]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [freqs (frequencies sq)]&lt;br /&gt;    (&lt;span class="builtin"&gt;apply&lt;/span&gt; concat&lt;br /&gt;     (&lt;span class="keyword"&gt;for&lt;/span&gt; [[k v] freqs]&lt;br /&gt;       (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; v 1) (&lt;span class="builtin"&gt;list&lt;/span&gt; (f k))&lt;br /&gt;           (&lt;span class="builtin"&gt;cons&lt;/span&gt; (f k) (&lt;span class="builtin"&gt;repeat&lt;/span&gt; (&lt;span class="builtin"&gt;dec&lt;/span&gt; v) k)))))))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;new-means&lt;/span&gt; [average point-groups old-means]&lt;br /&gt;  (update-seq old-means (&lt;span class="builtin"&gt;fn&lt;/span&gt;[o]&lt;br /&gt;                          (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;contains?&lt;/span&gt; point-groups o)&lt;br /&gt;                            (&lt;span class="builtin"&gt;apply&lt;/span&gt; average (&lt;span class="builtin"&gt;get&lt;/span&gt; point-groups o)) o))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Now only one will get updated at once&lt;br /&gt;&lt;/span&gt;(new-means average (point-groups '(0 0) '(0 1 2 3 4) distance) '(0 0)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(2 0)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Now we don't lose groups when the means get aliased.&lt;br /&gt;&lt;/span&gt;((k-groups '(0 1 2 3 4) distance average) '(0 1)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(([0] [1 2 3 4]) ([0 1] [2 3 4]))&lt;br /&gt;&lt;/span&gt;((k-groups '(0 1 2 3 4) distance average) '(0 0)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(([0 1 2 3 4]) ([0] [1 2 3 4]) ([0 1] [2 3 4]))&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;((k-groups vector-data vec-distance vec-average) '([1 1 1] [1 1 1] [1 1 1])) &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(([[1 2 3] [3 2 1] [100 200 300] [300 200 100] [50 50 50]])&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;([[1 2 3] [3 2 1]] [[100 200 300] [300 200 100] [50 50 50]])&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;([[1 2 3] [3 2 1] [50 50 50]] [[100 200 300] [300 200 100]])&lt;br /&gt;&lt;/span&gt;                                        &lt;span class="comment-delimiter"&gt;;  &lt;/span&gt;&lt;span class="comment"&gt;([[1 2 3] [3 2 1]] [[100 200 300] [300 200 100]] [[50 50 50]]))&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Although it's still possible that a mean never acquires any points, so we can still get out fewer groups than means.&lt;br /&gt;&lt;/span&gt;((k-groups '(0 1 2 3 4) distance average) '(0 5 10)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(([0 1 2] [3 4]))&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-7203270956497988578?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/7203270956497988578/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/01/k-means-algorithm-for-clustering-data.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/7203270956497988578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/7203270956497988578'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/01/k-means-algorithm-for-clustering-data.html' title='K-means : An Algorithm for Clustering Data'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-6162659991034713859</id><published>2011-01-25T15:22:00.002Z</published><updated>2011-01-25T15:22:39.355Z</updated><title type='text'>Cleaning Old Definitions from the REPL : shred-user</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;pre class="clojure-body"&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I often find myself restarting the clojure repl in order to get rid of old&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;definitions which introduce subtle bugs.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Consider:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;factorial&lt;/span&gt; [n] (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;&amp;lt;&lt;/span&gt; n 2) 1 (&lt;span class="builtin"&gt;*&lt;/span&gt; n (factorial (&lt;span class="builtin"&gt;dec&lt;/span&gt; n))))) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;#'user/factorial&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(factorial 10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;3628800&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Suppose instead I wanted (factorial2 n) to be (* 1 2 2 2 3 2 4 .... 2 n)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;factorial2&lt;/span&gt; [n] (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;&amp;lt;&lt;/span&gt; n 2) 1 (&lt;span class="builtin"&gt;*&lt;/span&gt; 2 n (factorial (&lt;span class="builtin"&gt;dec&lt;/span&gt; n))))) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;#'user/factorial2&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;There is a subtle bug introduced by my failing to rename the recursive call&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; factorial2 '(1 2 3 4)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(1 4 24 192)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But (factorial2 4) should be (* 1 2 2 2 3 2 4) = 192&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I suspect that there is an old definition hanging around confusing matters.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;To find it, I can run the program from the command line, or restart the repl and recompile, or:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;doseq&lt;/span&gt; [s (&lt;span class="builtin"&gt;map&lt;/span&gt; first (&lt;span class="builtin"&gt;ns-interns&lt;/span&gt; 'user))](&lt;span class="builtin"&gt;ns-unmap&lt;/span&gt; 'user s)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;nil&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;factorial2&lt;/span&gt; [n] (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;&amp;lt;&lt;/span&gt; n 2) 1 (&lt;span class="builtin"&gt;*&lt;/span&gt; 2 n (factorial (&lt;span class="builtin"&gt;dec&lt;/span&gt; n))))) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;Unable to resolve symbol: factorial in this context&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Aha! &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;factorial2&lt;/span&gt; [n] (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;&amp;lt;&lt;/span&gt; n 2) 1 (&lt;span class="builtin"&gt;*&lt;/span&gt; 2 n (factorial2 (&lt;span class="builtin"&gt;dec&lt;/span&gt; n))))) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;#'user/factorial2&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(factorial2 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;192&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;For convenience I'd like to make that a function:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;shred-user&lt;/span&gt; []&lt;br /&gt;  (&lt;span class="keyword"&gt;doseq&lt;/span&gt; [s (&lt;span class="builtin"&gt;map&lt;/span&gt; first (&lt;span class="builtin"&gt;ns-interns&lt;/span&gt; 'user))] (&lt;span class="builtin"&gt;ns-unmap&lt;/span&gt; 'user s)))&lt;br /&gt;&lt;br /&gt;(shred-user) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;nil&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(shred-user) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;Unable to resolve symbol: shred-user in this context ; bugger!&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;shred-user&lt;/span&gt; []&lt;br /&gt;  (&lt;span class="keyword"&gt;doseq&lt;/span&gt; [s (&lt;span class="builtin"&gt;filter&lt;/span&gt; (&lt;span class="builtin"&gt;complement&lt;/span&gt; #{'shred-user}) (&lt;span class="builtin"&gt;map&lt;/span&gt; first (&lt;span class="builtin"&gt;ns-interns&lt;/span&gt; 'user)))] (&lt;span class="builtin"&gt;ns-unmap&lt;/span&gt; 'user s)))&lt;br /&gt;&lt;br /&gt;(shred-user) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;nil&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(shred-user) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;nil&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-6162659991034713859?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/6162659991034713859/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/01/cleaning-old-definitions-from-repl.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/6162659991034713859'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/6162659991034713859'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/01/cleaning-old-definitions-from-repl.html' title='Cleaning Old Definitions from the REPL : shred-user'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-9107219843401475775</id><published>2011-01-25T13:43:00.000Z</published><updated>2011-01-25T13:43:57.231Z</updated><title type='text'>take-while-unstable</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      .type {        /* font-lock-type-face */        color: #ffff00;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;pre class="clojure-body"&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I often find myself wanting to iterate something until it converges.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;collatz&lt;/span&gt; [n] (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;even?&lt;/span&gt; n) (&lt;span class="keyword"&gt;recur&lt;/span&gt; (&lt;span class="builtin"&gt;/&lt;/span&gt; n 2)) (&lt;span class="builtin"&gt;+&lt;/span&gt; 1 (&lt;span class="builtin"&gt;*&lt;/span&gt; 3 n))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;iterate&lt;/span&gt; collatz 100) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(100 76 58 88 34 52 40 16 4 4 4 4 4 4 ...)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And so I often find myself writing:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;take-while-unstable&lt;/span&gt;&lt;br /&gt;  ([sq] (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;empty?&lt;/span&gt; sq) '()&lt;br /&gt;            (&lt;span class="builtin"&gt;cons&lt;/span&gt; (&lt;span class="builtin"&gt;first&lt;/span&gt; sq) (#'take-while-unstable (&lt;span class="builtin"&gt;rest&lt;/span&gt; sq) (&lt;span class="builtin"&gt;first&lt;/span&gt; sq)))))&lt;br /&gt;  ([sq last] (&lt;span class="keyword"&gt;cond&lt;/span&gt; (&lt;span class="builtin"&gt;empty?&lt;/span&gt; sq) '()&lt;br /&gt;                   (&lt;span class="builtin"&gt;=&lt;/span&gt; (&lt;span class="builtin"&gt;first&lt;/span&gt; sq) last) '()&lt;br /&gt;                   &lt;span class="builtin"&gt;:else&lt;/span&gt; (&lt;span class="builtin"&gt;cons&lt;/span&gt; (&lt;span class="builtin"&gt;first&lt;/span&gt; sq) (#'take-while-unstable (&lt;span class="builtin"&gt;rest&lt;/span&gt; sq) (&lt;span class="builtin"&gt;first&lt;/span&gt; sq))))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Which allows me to stop the iteration once it's settled down.&lt;br /&gt;&lt;/span&gt;(take-while-unstable (&lt;span class="builtin"&gt;iterate&lt;/span&gt; collatz 100)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(100 76 58 88 34 52 40 16 4)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;You can see how it works here:&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;require&lt;/span&gt; 'clojure.contrib.trace)&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;binding&lt;/span&gt;  [*print-length* 20] &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;taking care not to look at the medusa&lt;br /&gt;&lt;/span&gt;  (clojure.contrib.trace/dotrace (take-while-unstable) (take-while-unstable (&lt;span class="builtin"&gt;iterate&lt;/span&gt; collatz 100))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15884: (take-while-unstable (100 76 58 88 34 52 40 16 4 4 4 4 4 4 4 4 4 4 4 4 ...))&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15885: |    (take-while-unstable (76 58 88 34 52 40 16 4 4 4 4 4 4 4 4 4 4 4 4 4 ...) 100)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15886: |    |    (take-while-unstable (58 88 34 52 40 16 4 4 4 4 4 4 4 4 4 4 4 4 4 4 ...) 76)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15887: |    |    |    (take-while-unstable (88 34 52 40 16 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 ...) 58)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15888: |    |    |    |    (take-while-unstable (34 52 40 16 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 ...) 88)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15889: |    |    |    |    |    (take-while-unstable (52 40 16 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 ...) 34)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15890: |    |    |    |    |    |    (take-while-unstable (40 16 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 ...) 52)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15891: |    |    |    |    |    |    |    (take-while-unstable (16 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 ...) 40)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15892: |    |    |    |    |    |    |    |    (take-while-unstable (4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 ...) 16)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15893: |    |    |    |    |    |    |    |    |    (take-while-unstable (4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 ...) 4)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15893: |    |    |    |    |    |    |    |    |    =&amp;gt; ()&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15892: |    |    |    |    |    |    |    |    =&amp;gt; (4)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15891: |    |    |    |    |    |    |    =&amp;gt; (16 4)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15890: |    |    |    |    |    |    =&amp;gt; (40 16 4)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15889: |    |    |    |    |    =&amp;gt; (52 40 16 4)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15888: |    |    |    |    =&amp;gt; (34 52 40 16 4)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15887: |    |    |    =&amp;gt; (88 34 52 40 16 4)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15886: |    |    =&amp;gt; (58 88 34 52 40 16 4)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15885: |    =&amp;gt; (76 58 88 34 52 40 16 4)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;TRACE t15884: =&amp;gt; (100 76 58 88 34 52 40 16 4)&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;(100 76 58 88 34 52 40 16 4)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Anyway, this function comes in so handy that I thought I'd lazyize it and give it some tests&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;use&lt;/span&gt; 'clojure.test)&lt;br /&gt;&lt;br /&gt;(&lt;span class="type"&gt;with-test&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  (&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;take-while-unstable&lt;/span&gt;&lt;br /&gt;    ([sq] (&lt;span class="builtin"&gt;lazy-seq&lt;/span&gt; (&lt;span class="keyword"&gt;if-let&lt;/span&gt; [sq (&lt;span class="builtin"&gt;seq&lt;/span&gt; sq)]&lt;br /&gt;                      (&lt;span class="builtin"&gt;cons&lt;/span&gt; (&lt;span class="builtin"&gt;first&lt;/span&gt; sq) (take-while-unstable (&lt;span class="builtin"&gt;rest&lt;/span&gt; sq) (&lt;span class="builtin"&gt;first&lt;/span&gt; sq))))))&lt;br /&gt;    ([sq last] (&lt;span class="builtin"&gt;lazy-seq&lt;/span&gt; (&lt;span class="keyword"&gt;if-let&lt;/span&gt; [sq (&lt;span class="builtin"&gt;seq&lt;/span&gt; sq)]&lt;br /&gt;                           (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (&lt;span class="builtin"&gt;first&lt;/span&gt; sq) last) '() (take-while-unstable sq))))))&lt;br /&gt;&lt;br /&gt;  (&lt;span class="type"&gt;is&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (take-while-unstable '()) '()))&lt;br /&gt;  (&lt;span class="type"&gt;is&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (take-while-unstable '(1)) '(1)))&lt;br /&gt;  (&lt;span class="type"&gt;is&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (take-while-unstable '(1 1)) '(1)))&lt;br /&gt;  (&lt;span class="type"&gt;is&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (take-while-unstable '(1 2)) '(1 2)))&lt;br /&gt;  (&lt;span class="type"&gt;is&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (take-while-unstable '(1 1 2)) '(1)))&lt;br /&gt;  (&lt;span class="type"&gt;is&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (take-while-unstable '(1 1 1)) '(1)))&lt;br /&gt;  (&lt;span class="type"&gt;is&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (take-while-unstable '(1 1 2 1)) '(1)))&lt;br /&gt;  (&lt;span class="type"&gt;is&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (take-while-unstable '(1 2 3 4 5 6 7 7 7 7)) '(1 2 3 4 5 6 7)))&lt;br /&gt;  (&lt;span class="type"&gt;is&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (&lt;span class="builtin"&gt;take&lt;/span&gt; 10000 (take-while-unstable (&lt;span class="builtin"&gt;range&lt;/span&gt;))) (&lt;span class="builtin"&gt;take&lt;/span&gt; 10000 (&lt;span class="builtin"&gt;range&lt;/span&gt;))))&lt;br /&gt;  (&lt;span class="type"&gt;is&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (take-while-unstable (&lt;span class="builtin"&gt;concat&lt;/span&gt; (&lt;span class="builtin"&gt;take&lt;/span&gt; 10000 (&lt;span class="builtin"&gt;range&lt;/span&gt;)) '(10000) (&lt;span class="builtin"&gt;drop&lt;/span&gt; 10000 (&lt;span class="builtin"&gt;range&lt;/span&gt;)))) (&lt;span class="builtin"&gt;range&lt;/span&gt; 10001)))&lt;br /&gt;  (&lt;span class="type"&gt;is&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (take-while-unstable '(nil)) '(nil)))&lt;br /&gt;  (&lt;span class="type"&gt;is&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (take-while-unstable '(nil nil)) '(nil)))&lt;br /&gt;  (&lt;span class="type"&gt;is&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (take-while-unstable '[nil nil]) '(nil)))&lt;br /&gt;  (&lt;span class="type"&gt;is&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (take-while-unstable [ &lt;span class="builtin"&gt;:a&lt;/span&gt; &lt;span class="builtin"&gt;:b&lt;/span&gt; &lt;span class="builtin"&gt;:c&lt;/span&gt; &lt;span class="builtin"&gt;:d&lt;/span&gt; &lt;span class="builtin"&gt;:d&lt;/span&gt; &lt;span class="builtin"&gt;:e&lt;/span&gt;]) '(&lt;span class="builtin"&gt;:a&lt;/span&gt; &lt;span class="builtin"&gt;:b&lt;/span&gt; &lt;span class="builtin"&gt;:c&lt;/span&gt; &lt;span class="builtin"&gt;:d&lt;/span&gt;))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="type"&gt;run-tests&lt;/span&gt;) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;{:type :summary, :test 1, :pass 14, :fail 0, :error 0}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Hopefully someone will find it useful. Can anyone break it?&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-9107219843401475775?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/9107219843401475775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/01/take-while-unstable.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/9107219843401475775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/9107219843401475775'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/01/take-while-unstable.html' title='take-while-unstable'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-3749460912029659625</id><published>2011-01-17T23:09:00.003Z</published><updated>2011-01-17T23:12:30.829Z</updated><title type='text'>A Very Gentle Introduction to Information Theory: Guessing the Entropy</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;pre class="clojure-body"&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;A Very Gentle Introduction to Information Theory : Part IV&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Entropy and Huffman Coding&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Once again, I'll keep some code from the earlier parts, without explanation&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Probability distributions&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;combine-keywords&lt;/span&gt; [&amp;amp; a] (&lt;span class="builtin"&gt;keyword&lt;/span&gt; (&lt;span class="builtin"&gt;apply&lt;/span&gt; str (&lt;span class="builtin"&gt;mapcat&lt;/span&gt; #(&lt;span class="builtin"&gt;drop&lt;/span&gt; 1 (&lt;span class="builtin"&gt;str&lt;/span&gt; %)) a))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;combine-distributions&lt;/span&gt;&lt;br /&gt;  ([P] P)&lt;br /&gt;  ([P1 P2]&lt;br /&gt;     (&lt;span class="builtin"&gt;into&lt;/span&gt; {}&lt;br /&gt;           (&lt;span class="keyword"&gt;for&lt;/span&gt; [[s1 p1] P1&lt;br /&gt;                 [s2 p2] P2]&lt;br /&gt;             [(combine-keywords s1 s2) (&lt;span class="builtin"&gt;*&lt;/span&gt; p1 p2)])))&lt;br /&gt;  ([P1 P2 &amp;amp; Plist] (&lt;span class="builtin"&gt;reduce&lt;/span&gt; combine-distributions (&lt;span class="builtin"&gt;cons&lt;/span&gt; P1 (&lt;span class="builtin"&gt;cons&lt;/span&gt; P2 Plist)))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Coding and Decoding&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;decoder&lt;/span&gt;&lt;br /&gt;  ([code-tree stream] (decoder code-tree code-tree stream))&lt;br /&gt;  ([current-code-tree code-tree stream]&lt;br /&gt;     (&lt;span class="builtin"&gt;lazy-seq&lt;/span&gt;&lt;br /&gt;        (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;keyword?&lt;/span&gt; current-code-tree)&lt;br /&gt;          (&lt;span class="builtin"&gt;cons&lt;/span&gt; current-code-tree (decoder code-tree code-tree stream))&lt;br /&gt;          (&lt;span class="keyword"&gt;if-let&lt;/span&gt; [stream (&lt;span class="builtin"&gt;seq&lt;/span&gt; stream)]&lt;br /&gt;            (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (&lt;span class="builtin"&gt;first&lt;/span&gt; stream) 1)&lt;br /&gt;              (decoder (&lt;span class="builtin"&gt;first&lt;/span&gt; current-code-tree)  code-tree (&lt;span class="builtin"&gt;rest&lt;/span&gt; stream))&lt;br /&gt;              (decoder (&lt;span class="builtin"&gt;second&lt;/span&gt; current-code-tree) code-tree (&lt;span class="builtin"&gt;rest&lt;/span&gt; stream))))))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;encoder&lt;/span&gt; [code stream] (&lt;span class="builtin"&gt;mapcat&lt;/span&gt; code stream))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-encoder&lt;/span&gt; [code]  (&lt;span class="builtin"&gt;fn&lt;/span&gt; [s] (encoder code s)))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-decoder&lt;/span&gt; [code-tree] (&lt;span class="builtin"&gt;fn&lt;/span&gt;[s] (decoder code-tree s)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Huffman encoding&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;symbols&lt;/span&gt; [prefix code-tree]&lt;br /&gt;  (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;keyword?&lt;/span&gt; code-tree) (&lt;span class="builtin"&gt;list&lt;/span&gt; prefix code-tree)&lt;br /&gt;      (&lt;span class="builtin"&gt;concat&lt;/span&gt; (symbols (&lt;span class="builtin"&gt;cons&lt;/span&gt; 1 prefix) (&lt;span class="builtin"&gt;first&lt;/span&gt; code-tree))&lt;br /&gt;              (symbols (&lt;span class="builtin"&gt;cons&lt;/span&gt; 0 prefix) (&lt;span class="builtin"&gt;second&lt;/span&gt; code-tree)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-code&lt;/span&gt; [code-tree]&lt;br /&gt;  (&lt;span class="builtin"&gt;into&lt;/span&gt; {} (&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;fn&lt;/span&gt;[[c s]][s (&lt;span class="builtin"&gt;reverse&lt;/span&gt; c)]) (&lt;span class="builtin"&gt;partition&lt;/span&gt; 2 (symbols '() code-tree)))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The original make-code-tree was very slow, because it re-sorted the list every&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;iteration. We can speed it up considerably by using a priority queue instead&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;of sorting the list every iteration. Clojure doesn't have one built in, so&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;here's a poor man's version built out of a sorted map of lists.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;madd&lt;/span&gt; [m [k p]] (&lt;span class="builtin"&gt;assoc&lt;/span&gt; m p (&lt;span class="builtin"&gt;cons&lt;/span&gt; k (m p))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;mpop&lt;/span&gt; [m]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [[k vlist] (&lt;span class="builtin"&gt;first&lt;/span&gt; m)]&lt;br /&gt;    [k (&lt;span class="builtin"&gt;first&lt;/span&gt; vlist)&lt;br /&gt;    (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;empty?&lt;/span&gt; (&lt;span class="builtin"&gt;rest&lt;/span&gt; vlist))&lt;br /&gt;      (&lt;span class="builtin"&gt;dissoc&lt;/span&gt; m k)&lt;br /&gt;      (&lt;span class="builtin"&gt;assoc&lt;/span&gt; m k (&lt;span class="builtin"&gt;rest&lt;/span&gt; vlist)))]))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;mcombine&lt;/span&gt; [m]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [[pa a pop1] (mpop m)&lt;br /&gt;        [pb b pop2] (mpop pop1)]&lt;br /&gt;    (madd pop2 [[a b] (&lt;span class="builtin"&gt;+&lt;/span&gt; pa pb)])))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-code-tree&lt;/span&gt; [P]&lt;br /&gt;  (&lt;span class="builtin"&gt;second&lt;/span&gt; (mpop&lt;br /&gt;          (&lt;span class="builtin"&gt;nth&lt;/span&gt; (&lt;span class="builtin"&gt;iterate&lt;/span&gt; mcombine (&lt;span class="builtin"&gt;reduce&lt;/span&gt; madd (&lt;span class="builtin"&gt;sorted-map&lt;/span&gt;) P)) (&lt;span class="builtin"&gt;dec&lt;/span&gt; (&lt;span class="builtin"&gt;count&lt;/span&gt; P))))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;fair-coin&lt;/span&gt; {&lt;span class="builtin"&gt;:H&lt;/span&gt; 1 &lt;span class="builtin"&gt;:T&lt;/span&gt; 1})&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unfair-coin&lt;/span&gt; {&lt;span class="builtin"&gt;:H&lt;/span&gt; 3 &lt;span class="builtin"&gt;:T&lt;/span&gt; 1})&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unfair-triples&lt;/span&gt; (combine-distributions unfair-coin unfair-coin unfair-coin))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;triple-code-tree&lt;/span&gt; (make-code-tree unfair-triples))&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;triple-code&lt;/span&gt; (make-code triple-code-tree))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We don't need to estimate the cost of a code by generating a long random stream and transmitting it.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Given a probability distribution and a code, we can just calculate the expected cost:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We make a distribution over the transmitted symbols&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;code-distribution&lt;/span&gt; [P code]  (&lt;span class="keyword"&gt;for&lt;/span&gt; [s (&lt;span class="builtin"&gt;keys&lt;/span&gt; P)] [(P s) (code s)]))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;e.g.&lt;br /&gt;&lt;/span&gt;(code-distribution unfair-triples triple-code)&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;([27 (0)] [9 (1 1 1)] [9 (1 1 0)] [3 (1 0 0 1 0)] [9 (1 0 1)] [3 (1 0 0 0 1)] [3 (1 0 0 0 0)] [1 (1 0 0 1 1)])&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And from that, it's easy to calculate the expected length of a sequence&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;expected-code-length&lt;/span&gt; [P code]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [cd (code-distribution P code)]&lt;br /&gt;    (&lt;span class="builtin"&gt;/&lt;/span&gt; (&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="keyword"&gt;for&lt;/span&gt; [[k v] cd] (&lt;span class="builtin"&gt;*&lt;/span&gt; k (&lt;span class="builtin"&gt;count&lt;/span&gt; v))))&lt;br /&gt;       (&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;map&lt;/span&gt; first cd)))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So the expected cost per symbol is:&lt;br /&gt;&lt;/span&gt;(expected-code-length unfair-triples triple-code) &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;79/32&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;or per coin-toss:&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;float&lt;/span&gt; ( / 79/32 3)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.8229167&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So we can get the noise out of our table:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;cost-for-n-code&lt;/span&gt; [ P n ]&lt;br /&gt;     (&lt;span class="keyword"&gt;let&lt;/span&gt; [Pn (&lt;span class="builtin"&gt;apply&lt;/span&gt; combine-distributions (&lt;span class="builtin"&gt;repeat&lt;/span&gt; n P))&lt;br /&gt;           code (make-code (make-code-tree Pn))]&lt;br /&gt;       (&lt;span class="builtin"&gt;float&lt;/span&gt; (&lt;span class="builtin"&gt;/&lt;/span&gt; (expected-code-length Pn code) n))))&lt;br /&gt;&lt;br /&gt;(cost-for-n-code unfair-coin 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.0&lt;br /&gt;&lt;/span&gt;(cost-for-n-code unfair-coin 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.84375&lt;br /&gt;&lt;/span&gt;(cost-for-n-code unfair-coin 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.8229167&lt;br /&gt;&lt;/span&gt;(cost-for-n-code unfair-coin 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.8183594&lt;br /&gt;&lt;/span&gt;(cost-for-n-code unfair-coin 5) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.81777346&lt;br /&gt;&lt;/span&gt;(cost-for-n-code unfair-coin 6) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.8186849&lt;br /&gt;&lt;/span&gt;(cost-for-n-code unfair-coin 7) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.81685966&lt;br /&gt;&lt;/span&gt;(cost-for-n-code unfair-coin 8) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.81575775&lt;br /&gt;&lt;/span&gt;(cost-for-n-code unfair-coin 9) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.81493336&lt;br /&gt;&lt;/span&gt;(cost-for-n-code unfair-coin 10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.8141917&lt;br /&gt;&lt;/span&gt;(cost-for-n-code unfair-coin 11) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.8137328&lt;br /&gt;&lt;/span&gt;(cost-for-n-code unfair-coin 12) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.81351095&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It looks like something is converging, although the convergence isn't monotonic. &lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I'm now revising my estimate of the cost of sending the results of a 1:3 process to be about 0.813&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But we don't know whether that's the limit of the coding process, or a property of the 1:3 distribution,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;or whether it's in some way specific to transmitting over a binary channel.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's look at some other distributions.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;For the fair coin distribution, huffman coding triples doesn't help at all.&lt;br /&gt;&lt;/span&gt;(cost-for-n-code fair-coin 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.0&lt;br /&gt;&lt;/span&gt;(cost-for-n-code fair-coin 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.0&lt;br /&gt;&lt;/span&gt;(cost-for-n-code fair-coin 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.0&lt;br /&gt;&lt;/span&gt;(cost-for-n-code fair-coin 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.0&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But for an even choice between three things, it does:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;triad&lt;/span&gt; {&lt;span class="builtin"&gt;:A&lt;/span&gt; 1 &lt;span class="builtin"&gt;:B&lt;/span&gt; 1 &lt;span class="builtin"&gt;:C&lt;/span&gt; 1})&lt;br /&gt;&lt;br /&gt;(cost-for-n-code triad 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.6666666&lt;br /&gt;&lt;/span&gt;(cost-for-n-code triad 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.6111112&lt;br /&gt;&lt;/span&gt;(cost-for-n-code triad 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.6049383&lt;br /&gt;&lt;/span&gt;(cost-for-n-code triad 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.6049383&lt;br /&gt;&lt;/span&gt;(cost-for-n-code triad 5) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.5893004&lt;br /&gt;&lt;/span&gt;(cost-for-n-code triad 6) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.5992227&lt;br /&gt;&lt;/span&gt;(cost-for-n-code triad 7) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.5895878&lt;br /&gt;&lt;/span&gt;(cost-for-n-code triad 8) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.5939262&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;For a choice between four things, it makes no difference&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;quad&lt;/span&gt; {&lt;span class="builtin"&gt;:A&lt;/span&gt; 1 &lt;span class="builtin"&gt;:B&lt;/span&gt; 1 &lt;span class="builtin"&gt;:C&lt;/span&gt; 1 &lt;span class="builtin"&gt;:D&lt;/span&gt; 1})&lt;br /&gt;&lt;br /&gt;(cost-for-n-code quad 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.0&lt;br /&gt;&lt;/span&gt;(cost-for-n-code quad 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.0&lt;br /&gt;&lt;/span&gt;(cost-for-n-code quad 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.0&lt;br /&gt;&lt;/span&gt;(cost-for-n-code quad 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.0&lt;br /&gt;&lt;/span&gt;(cost-for-n-code quad 5) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.0&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;For five it's a good thing to do&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;quint&lt;/span&gt; {&lt;span class="builtin"&gt;:A&lt;/span&gt; 1 &lt;span class="builtin"&gt;:B&lt;/span&gt; 1 &lt;span class="builtin"&gt;:C&lt;/span&gt; 1 &lt;span class="builtin"&gt;:D&lt;/span&gt; 1 &lt;span class="builtin"&gt;:E&lt;/span&gt; 1})&lt;br /&gt;&lt;br /&gt;(cost-for-n-code quint 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.4&lt;br /&gt;&lt;/span&gt;(cost-for-n-code quint 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.36&lt;br /&gt;&lt;/span&gt;(cost-for-n-code quint 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.3253334&lt;br /&gt;&lt;/span&gt;(cost-for-n-code quint 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.3404&lt;br /&gt;&lt;/span&gt;(cost-for-n-code quint 5) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.337856&lt;br /&gt;&lt;/span&gt;(cost-for-n-code quint 6) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.3252373&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And again, for the next power of two, no difference.&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;octet&lt;/span&gt; {&lt;span class="builtin"&gt;:A&lt;/span&gt; 1 &lt;span class="builtin"&gt;:B&lt;/span&gt; 1 &lt;span class="builtin"&gt;:C&lt;/span&gt; 1 &lt;span class="builtin"&gt;:D&lt;/span&gt; 1 &lt;span class="builtin"&gt;:E&lt;/span&gt; 1 &lt;span class="builtin"&gt;:F&lt;/span&gt; 1 &lt;span class="builtin"&gt;:G&lt;/span&gt; 1 &lt;span class="builtin"&gt;:H&lt;/span&gt; 1})&lt;br /&gt;&lt;br /&gt;(cost-for-n-code octet 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;3.0&lt;br /&gt;&lt;/span&gt;(cost-for-n-code octet 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;3.0&lt;br /&gt;&lt;/span&gt;(cost-for-n-code octet 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;3.0&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;I think that we might have guessed that it would take three bits to decide between&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;eight equally likely things, and two bits for four things, but what about the other numbers?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If 8 = 2*2*2 -&amp;gt; 3, and 4 = 2*2 -&amp;gt; 2, and 2 -&amp;gt; 1, what's the easiest pattern we can fit to that?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;bits&lt;/span&gt; [n] (&lt;span class="builtin"&gt;/&lt;/span&gt; (Math/log n)(Math/log 2))) &lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Also known as log2&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;map&lt;/span&gt; bits (&lt;span class="builtin"&gt;range&lt;/span&gt; 2 10)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(1.0 1.5849625007211563 2.0 2.321928094887362 2.584962500721156 2.807354922057604 3.0 3.1699250014423126)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So let's make a prediction&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;sextet&lt;/span&gt; {&lt;span class="builtin"&gt;:A&lt;/span&gt; 1 &lt;span class="builtin"&gt;:B&lt;/span&gt; 1 &lt;span class="builtin"&gt;:C&lt;/span&gt; 1 &lt;span class="builtin"&gt;:D&lt;/span&gt; 1 &lt;span class="builtin"&gt;:E&lt;/span&gt; 1 &lt;span class="builtin"&gt;:F&lt;/span&gt; 1})&lt;br /&gt;(bits 6) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.584962500721156&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(cost-for-n-code sextet 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.6666667&lt;br /&gt;&lt;/span&gt;(cost-for-n-code sextet 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.6111112&lt;br /&gt;&lt;/span&gt;(cost-for-n-code sextet 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.6049383&lt;br /&gt;&lt;/span&gt;(cost-for-n-code sextet 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.6049383&lt;br /&gt;&lt;/span&gt;(cost-for-n-code sextet 5) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.5893004&lt;br /&gt;&lt;/span&gt;(cost-for-n-code sextet 6) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.5992227&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It looks as though the cost of coding an even distribution using huffman&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;encoding of runs is pretty close to being the logarithm (to base 2) of the number of symbols.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-3749460912029659625?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/3749460912029659625/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/01/very-gently-introduction-to-information.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/3749460912029659625'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/3749460912029659625'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/01/very-gently-introduction-to-information.html' title='A Very Gentle Introduction to Information Theory: Guessing the Entropy'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-33371887474873590</id><published>2011-01-15T18:46:00.000Z</published><updated>2011-01-15T18:46:04.678Z</updated><title type='text'>A Very Gentle Introduction to Information Theory: Huffman Coding</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-1 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-2 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-3 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-4 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-5 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-6 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-7 {        /* (:foreground "purple") */        color: #a020f0;      }      .ATTRLIST-8 {        /* (:foreground "orange1") */        color: #ffa500;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      .type {        /* font-lock-type-face */        color: #ffff00;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;pre class="clojure-body"&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;A Very Gentle Introduction to Information Theory : Part III&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Entropy and Huffman Coding&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Once again, I'll keep some code from the first two parts, without explanation&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;random-stream&lt;/span&gt; [P]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [pseq (&lt;span class="builtin"&gt;vec&lt;/span&gt; (&lt;span class="builtin"&gt;mapcat&lt;/span&gt; (&lt;span class="builtin"&gt;fn&lt;/span&gt;[[k v]](&lt;span class="builtin"&gt;repeat&lt;/span&gt; v k )) P))]&lt;br /&gt;    (&lt;span class="keyword"&gt;for&lt;/span&gt; [i (&lt;span class="builtin"&gt;range&lt;/span&gt;)] (rand-nth pseq))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;cost&lt;/span&gt; [encoder decoder message]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [coded (encoder message)]&lt;br /&gt;    (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (decoder coded) message) (&lt;span class="builtin"&gt;count&lt;/span&gt; coded) &lt;span class="builtin"&gt;:fail&lt;/span&gt;)))&lt;br /&gt;&lt;br /&gt;&lt;span class="ATTRLIST-8"&gt;(&lt;/span&gt;&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;decoder&lt;/span&gt;&lt;br /&gt;  ([code-tree stream] (decoder code-tree code-tree stream))&lt;br /&gt;  ([current-code-tree code-tree stream]&lt;br /&gt;     (&lt;span class="builtin"&gt;lazy-seq&lt;/span&gt;&lt;br /&gt;        (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;keyword?&lt;/span&gt; current-code-tree)&lt;br /&gt;          (&lt;span class="builtin"&gt;cons&lt;/span&gt; current-code-tree (decoder code-tree code-tree stream))&lt;br /&gt;          (&lt;span class="keyword"&gt;if-let&lt;/span&gt; [stream (&lt;span class="builtin"&gt;seq&lt;/span&gt; stream)]&lt;br /&gt;            (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (&lt;span class="builtin"&gt;first&lt;/span&gt; stream) 1)&lt;br /&gt;              (decoder (&lt;span class="builtin"&gt;first&lt;/span&gt; current-code-tree)  code-tree (&lt;span class="builtin"&gt;rest&lt;/span&gt; stream))&lt;br /&gt;              (decoder (&lt;span class="builtin"&gt;second&lt;/span&gt; current-code-tree) code-tree (&lt;span class="builtin"&gt;rest&lt;/span&gt; stream)))))))&lt;span class="ATTRLIST-8"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;encoder&lt;/span&gt; [code stream] (&lt;span class="builtin"&gt;mapcat&lt;/span&gt; code stream))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-encoder&lt;/span&gt; [code]  (&lt;span class="builtin"&gt;fn&lt;/span&gt; [s] (encoder code s)))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-decoder&lt;/span&gt; [code-tree] (&lt;span class="builtin"&gt;fn&lt;/span&gt;[s] (decoder code-tree s)))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;combine-keywords&lt;/span&gt; [&amp;amp; a] (&lt;span class="builtin"&gt;keyword&lt;/span&gt; (&lt;span class="builtin"&gt;apply&lt;/span&gt; str (&lt;span class="builtin"&gt;mapcat&lt;/span&gt; #(&lt;span class="builtin"&gt;drop&lt;/span&gt; 1 (&lt;span class="builtin"&gt;str&lt;/span&gt; %)) a))))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;split-keyword&lt;/span&gt; [a] (&lt;span class="builtin"&gt;map&lt;/span&gt; #(&lt;span class="builtin"&gt;keyword&lt;/span&gt; (&lt;span class="builtin"&gt;str&lt;/span&gt; %)) (&lt;span class="builtin"&gt;drop&lt;/span&gt; 1 (&lt;span class="builtin"&gt;str&lt;/span&gt; a))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-combination-encoder&lt;/span&gt; [code n]&lt;br /&gt;  (&lt;span class="builtin"&gt;fn&lt;/span&gt; [s] (encoder code (&lt;span class="builtin"&gt;map&lt;/span&gt; #(&lt;span class="builtin"&gt;apply&lt;/span&gt; combine-keywords %) (&lt;span class="builtin"&gt;partition&lt;/span&gt; n s)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-combination-decoder&lt;/span&gt; [code-tree]&lt;br /&gt;  (&lt;span class="builtin"&gt;fn&lt;/span&gt; [s] (&lt;span class="builtin"&gt;mapcat&lt;/span&gt; split-keyword (decoder code-tree s))))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So far we've looked at three probability distributions:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;fair-coin&lt;/span&gt; {&lt;span class="builtin"&gt;:H&lt;/span&gt; 1 &lt;span class="builtin"&gt;:T&lt;/span&gt; 1})&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unfair-coin&lt;/span&gt; {&lt;span class="builtin"&gt;:H&lt;/span&gt; 3 &lt;span class="builtin"&gt;:T&lt;/span&gt; 1})&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unfair-pairs&lt;/span&gt; {&lt;span class="builtin"&gt;:HH&lt;/span&gt; 9, &lt;span class="builtin"&gt;:HT&lt;/span&gt; 3, &lt;span class="builtin"&gt;:TH&lt;/span&gt; 3, &lt;span class="builtin"&gt;:TT&lt;/span&gt; 1})&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And two codes:&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;fair-code-tree&lt;/span&gt; [&lt;span class="builtin"&gt;:H&lt;/span&gt; &lt;span class="builtin"&gt;:T&lt;/span&gt;])&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;fair-code&lt;/span&gt; {&lt;span class="builtin"&gt;:H&lt;/span&gt; '(1) &lt;span class="builtin"&gt;:T&lt;/span&gt; '(0)})&lt;br /&gt;     &lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unfair-code-tree&lt;/span&gt; [ &lt;span class="builtin"&gt;:HH&lt;/span&gt; [ &lt;span class="builtin"&gt;:HT&lt;/span&gt; [ &lt;span class="builtin"&gt;:TH&lt;/span&gt; &lt;span class="builtin"&gt;:TT&lt;/span&gt;]]])&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unfair-code&lt;/span&gt; {&lt;span class="builtin"&gt;:HH&lt;/span&gt; '(1) &lt;span class="builtin"&gt;:HT&lt;/span&gt; '(0 1) &lt;span class="builtin"&gt;:TH&lt;/span&gt; '(0 0 1) &lt;span class="builtin"&gt;:TT&lt;/span&gt; '(0 0 0)})&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We should add a fourth probability distribution to represent pairs of fair coin toss results&lt;br /&gt;&lt;/span&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;fair-pairs&lt;/span&gt; {&lt;span class="builtin"&gt;:HH&lt;/span&gt; 1 &lt;span class="builtin"&gt;:HT&lt;/span&gt; 1 &lt;span class="builtin"&gt;:TH&lt;/span&gt; 1 &lt;span class="builtin"&gt;:TT&lt;/span&gt; 1})&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We found that&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;estimate-cost&lt;/span&gt; [P encoder decoder]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [n 100000&lt;br /&gt;        c (cost encoder decoder (&lt;span class="builtin"&gt;take&lt;/span&gt; n (random-stream P)))]&lt;br /&gt;    (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;number?&lt;/span&gt; c) (&lt;span class="builtin"&gt;float&lt;/span&gt; (&lt;span class="builtin"&gt;/&lt;/span&gt; c n)) c)))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Using the best code we can think of for the fair coin resulted in a transmission cost of 1 (&amp;#163;/symbol)&lt;br /&gt;&lt;/span&gt;(estimate-cost fair-coin   (make-encoder fair-code) (make-decoder fair-code-tree)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.0&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And that that was also the cost for the unfair coin with this code:&lt;br /&gt;&lt;/span&gt;(estimate-cost unfair-coin (make-encoder fair-code) (make-decoder fair-code-tree)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.0&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;But that we could come up with a code for pairs of coin tosses&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;which did substantially better for pairs of unfair coin tosses&lt;br /&gt;&lt;/span&gt;(estimate-cost unfair-pairs (make-encoder unfair-code) (make-decoder unfair-code-tree)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.68338&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;but substantially worse for pairs of fair coin tosses&lt;br /&gt;&lt;/span&gt;(estimate-cost fair-pairs   (make-encoder unfair-code) (make-decoder unfair-code-tree)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.24722&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;remember that that's the transmission cost per symbol, and that each symbol represents two coin tosses&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;In case you think there's any sleight of hand going on there, here's how we'd use the pairs code to transmit&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;the original unpaired streams&lt;br /&gt;&lt;/span&gt;(estimate-cost unfair-coin  (make-combination-encoder unfair-code 2) (make-combination-decoder unfair-code-tree)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.84561&lt;br /&gt;&lt;/span&gt;(estimate-cost fair-coin    (make-combination-encoder unfair-code 2) (make-combination-decoder unfair-code-tree)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.12407&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Notice that the costs here are per-toss, showing that the unfair code is actually an improvement &lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Now it seems that, if we can send the results of unfair-coin more efficiently&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;by considering {:HH 9, :HT 3, :TH 3, :TT 1}, the distribution of pairs of&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;tosses, then we should have a look at the distribution of triples, and work out a code for that:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;combine-distributions&lt;/span&gt;&lt;br /&gt;  ([P] P)&lt;br /&gt;  ([P1 P2]&lt;br /&gt;     (&lt;span class="builtin"&gt;into&lt;/span&gt; {}&lt;br /&gt;           (&lt;span class="keyword"&gt;for&lt;/span&gt; [[s1 p1] P1&lt;br /&gt;                 [s2 p2] P2]&lt;br /&gt;             [(combine-keywords s1 s2) (&lt;span class="builtin"&gt;*&lt;/span&gt; p1 p2)])))&lt;br /&gt;  ([P1 P2 &amp;amp; Plist] (&lt;span class="builtin"&gt;reduce&lt;/span&gt; combine-distributions (&lt;span class="builtin"&gt;cons&lt;/span&gt; P1 (&lt;span class="builtin"&gt;cons&lt;/span&gt; P2 Plist)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unfair-triples&lt;/span&gt; (combine-distributions unfair-coin unfair-coin unfair-coin))&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;unfair-triples is {:HHH 27, :HHT 9, :HTH 9, :HTT 3, :THH 9, :THT 3, :TTH 3, :TTT 1}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Now how should we work out a code for this distribution?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Huffman tells us that we should combine the two lowest probability events&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;so that&lt;br /&gt;&lt;/span&gt;{&lt;span class="builtin"&gt;:HHH&lt;/span&gt; 27, &lt;span class="builtin"&gt;:HHT&lt;/span&gt; 9, &lt;span class="builtin"&gt;:HTH&lt;/span&gt; 9, &lt;span class="builtin"&gt;:HTT&lt;/span&gt; 3, &lt;span class="builtin"&gt;:THH&lt;/span&gt; 9, &lt;span class="builtin"&gt;:THT&lt;/span&gt; 3, &lt;span class="builtin"&gt;:TTH&lt;/span&gt; 3, &lt;span class="builtin"&gt;:TTT&lt;/span&gt; 1}&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;goes to&lt;br /&gt;&lt;/span&gt;{&lt;span class="builtin"&gt;:HHH&lt;/span&gt; 27, &lt;span class="builtin"&gt;:HHT&lt;/span&gt; 9, &lt;span class="builtin"&gt;:HTH&lt;/span&gt; 9, &lt;span class="builtin"&gt;:HTT&lt;/span&gt; 3, &lt;span class="builtin"&gt;:THH&lt;/span&gt; 9, &lt;span class="builtin"&gt;:THT&lt;/span&gt; 3, {&lt;span class="builtin"&gt;:TTH&lt;/span&gt; 3, &lt;span class="builtin"&gt;:TTT&lt;/span&gt; 1} 4}&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and then do it again, so that&lt;br /&gt;&lt;/span&gt;{&lt;span class="builtin"&gt;:HHH&lt;/span&gt; 27, &lt;span class="builtin"&gt;:HHT&lt;/span&gt; 9, &lt;span class="builtin"&gt;:HTH&lt;/span&gt; 9, &lt;span class="builtin"&gt;:HTT&lt;/span&gt; 3, &lt;span class="builtin"&gt;:THH&lt;/span&gt; 9, &lt;span class="builtin"&gt;:THT&lt;/span&gt; 3, {&lt;span class="builtin"&gt;:TTH&lt;/span&gt; 3, &lt;span class="builtin"&gt;:TTT&lt;/span&gt; 1} 4}&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;goes to&lt;br /&gt;&lt;/span&gt;{&lt;span class="builtin"&gt;:HHH&lt;/span&gt; 27, &lt;span class="builtin"&gt;:HHT&lt;/span&gt; 9, &lt;span class="builtin"&gt;:HTH&lt;/span&gt; 9, &lt;span class="builtin"&gt;:HTT&lt;/span&gt; 3, &lt;span class="builtin"&gt;:THH&lt;/span&gt; 9, {&lt;span class="builtin"&gt;:THT&lt;/span&gt; 3, {&lt;span class="builtin"&gt;:TTH&lt;/span&gt; 3, &lt;span class="builtin"&gt;:TTT&lt;/span&gt; 1} 4} 7}&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;and so on .....&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;huffman-combine&lt;/span&gt; [P]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [plist (&lt;span class="builtin"&gt;sort-by&lt;/span&gt; second P)&lt;br /&gt;        newelement (&lt;span class="builtin"&gt;into&lt;/span&gt; {} (&lt;span class="builtin"&gt;take&lt;/span&gt; 2 plist))]&lt;br /&gt;    (&lt;span class="builtin"&gt;into&lt;/span&gt; {} (&lt;span class="builtin"&gt;cons&lt;/span&gt; [newelement (&lt;span class="builtin"&gt;reduce&lt;/span&gt; + (&lt;span class="builtin"&gt;vals&lt;/span&gt; newelement))] (&lt;span class="builtin"&gt;drop&lt;/span&gt; 2 plist)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;nth&lt;/span&gt; (&lt;span class="builtin"&gt;iterate&lt;/span&gt; huffman-combine unfair-triples) (&lt;span class="builtin"&gt;dec&lt;/span&gt; (&lt;span class="builtin"&gt;dec&lt;/span&gt; (&lt;span class="builtin"&gt;count&lt;/span&gt; unfair-triples))))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;{{{:HHT 9, :HTH 9} 18, {:THH 9, {{:TTT 1, :HTT 3} 4, {:THT 3, :TTH 3} 6} 10} 19} 37, :HHH 27}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;At the end, we get a sort of nested binary probability distribution&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;You could think of this as being a way to generate the triples by tossing strangely biased coins!&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;From that, we can generate our code tree directly by just throwing away the numbers&lt;br /&gt;&lt;/span&gt;(&lt;span class="builtin"&gt;require&lt;/span&gt; 'clojure.walk)&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-code-tree&lt;/span&gt; [P]&lt;br /&gt;  (clojure.walk/&lt;span class="type"&gt;postwalk&lt;/span&gt; #(&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;map?&lt;/span&gt; %) (&lt;span class="builtin"&gt;into&lt;/span&gt;[] (&lt;span class="builtin"&gt;map&lt;/span&gt; first  %)) %)&lt;br /&gt;                         (&lt;span class="builtin"&gt;nth&lt;/span&gt; (&lt;span class="builtin"&gt;iterate&lt;/span&gt; huffman-combine P) (&lt;span class="builtin"&gt;dec&lt;/span&gt; (&lt;span class="builtin"&gt;dec&lt;/span&gt; (&lt;span class="builtin"&gt;count&lt;/span&gt; P))))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;triple-code-tree&lt;/span&gt; (make-code-tree unfair-triples))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;&lt;/span&gt;&lt;span class="comment"&gt;[[[:HHT :HTH] [:THH [[:TTT :HTT] [:THT :TTH]]]] :HHH]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;If we have the decoder, then we can use it to generate the coder!&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;symbols&lt;/span&gt; [prefix code-tree]&lt;br /&gt;  (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;keyword?&lt;/span&gt; code-tree) (&lt;span class="builtin"&gt;list&lt;/span&gt; prefix code-tree)&lt;br /&gt;      (&lt;span class="builtin"&gt;concat&lt;/span&gt; (symbols (&lt;span class="builtin"&gt;cons&lt;/span&gt; 1 prefix) (&lt;span class="builtin"&gt;first&lt;/span&gt; code-tree))&lt;br /&gt;              (symbols (&lt;span class="builtin"&gt;cons&lt;/span&gt; 0 prefix) (&lt;span class="builtin"&gt;second&lt;/span&gt; code-tree)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-code&lt;/span&gt; [code-tree]&lt;br /&gt;  (&lt;span class="builtin"&gt;into&lt;/span&gt; {} (&lt;span class="builtin"&gt;map&lt;/span&gt; (&lt;span class="builtin"&gt;fn&lt;/span&gt;[[c s]][s (&lt;span class="builtin"&gt;reverse&lt;/span&gt; c)]) (&lt;span class="builtin"&gt;partition&lt;/span&gt; 2 (symbols '() code-tree)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;triple-code&lt;/span&gt; (make-code triple-code-tree))&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;{:HHT (0 0 0), :HTH (0 0 1), :THH (0 1 0), :TTT (0 1 1 0 0), :HTT (0 1 1 0 1), :THT (0 1 1 1 0), :TTH (0 1 1 1 1), :HHH (1)}&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's see how this does&lt;br /&gt;&lt;/span&gt;(estimate-cost unfair-triples (make-encoder triple-code) (make-decoder triple-code-tree)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;2.4615&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;&amp;#163;2.46 per symbol, or 0.82p per toss&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So while going from single tosses to pairs allowed us to go from 1-&amp;gt;0.85, going from pairs to triples only allowed us to get from 0.85-&amp;gt;0.82.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Is there an end to this process?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;bit-rate&lt;/span&gt; [P n]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [Pn (&lt;span class="builtin"&gt;apply&lt;/span&gt; combine-distributions (&lt;span class="builtin"&gt;repeat&lt;/span&gt; n P))&lt;br /&gt;        tree (make-code-tree Pn)]&lt;br /&gt;    (&lt;span class="builtin"&gt;/&lt;/span&gt; (estimate-cost Pn (make-encoder (make-code tree)) (make-decoder tree)) n)))&lt;br /&gt;&lt;br /&gt;(bit-rate unfair-coin 1) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;1.0&lt;br /&gt;&lt;/span&gt;(bit-rate unfair-coin 2) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.844435&lt;br /&gt;&lt;/span&gt;(bit-rate unfair-coin 3) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.82466&lt;br /&gt;&lt;/span&gt;(bit-rate unfair-coin 4) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.8196275&lt;br /&gt;&lt;/span&gt;(bit-rate unfair-coin 5) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.818912&lt;br /&gt;&lt;/span&gt;(bit-rate unfair-coin 6) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.81896996&lt;br /&gt;&lt;/span&gt;(bit-rate unfair-coin 7) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.8166514&lt;br /&gt;&lt;/span&gt;(bit-rate unfair-coin 8) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.815995&lt;br /&gt;&lt;/span&gt;(bit-rate unfair-coin 9) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.81352335&lt;br /&gt;&lt;/span&gt;(bit-rate unfair-coin 10) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.81462896&lt;br /&gt;&lt;/span&gt;(bit-rate unfair-coin 11) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;0.8137691&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;To me, this is at least suggestive that there might be something fundamental&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;about a cost of 82p to transmit the result of a 3:1 random result over a&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;binary channel.&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-33371887474873590?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/33371887474873590/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/01/very-gentle-introduction-to-information_15.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/33371887474873590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/33371887474873590'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/01/very-gentle-introduction-to-information_15.html' title='A Very Gentle Introduction to Information Theory: Huffman Coding'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-66474477578976365</id><published>2011-01-14T00:57:00.000Z</published><updated>2011-01-14T00:57:32.931Z</updated><title type='text'>A Very Gentle Introduction to Information Theory : Generalizing the Encoder and Decoder</title><content type='html'>&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;    &lt;pre class="clojure-body"&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;A Very Gentle Introduction to Information Theory : Part II&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Entropy and Huffman Coding&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Here's the essential code from part I, which I'm not going to explain again:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;random-stream&lt;/span&gt; [P]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [pseq (&lt;span class="builtin"&gt;vec&lt;/span&gt; (&lt;span class="builtin"&gt;mapcat&lt;/span&gt; (&lt;span class="builtin"&gt;fn&lt;/span&gt;[[k v]](&lt;span class="builtin"&gt;repeat&lt;/span&gt; v k )) P))]&lt;br /&gt;    (&lt;span class="keyword"&gt;for&lt;/span&gt; [i (&lt;span class="builtin"&gt;range&lt;/span&gt;)] (rand-nth pseq))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;cost&lt;/span&gt; [encoder decoder message]&lt;br /&gt;  (&lt;span class="keyword"&gt;let&lt;/span&gt; [coded (encoder message)]&lt;br /&gt;    (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (decoder coded) message) (&lt;span class="builtin"&gt;count&lt;/span&gt; coded) &lt;span class="builtin"&gt;:fail&lt;/span&gt;)))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unfair-pairs&lt;/span&gt; {&lt;span class="builtin"&gt;:HH&lt;/span&gt; 9, &lt;span class="builtin"&gt;:HT&lt;/span&gt; 3, &lt;span class="builtin"&gt;:TH&lt;/span&gt; 3, &lt;span class="builtin"&gt;:TT&lt;/span&gt; 1})&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We're trying to transmit the output of the random process represented by:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;stream&lt;/span&gt; (random-stream unfair-pairs))&lt;br /&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;take&lt;/span&gt; 20 stream) &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;(:HH :HH :HH :HH :HH :HH :HH :HH :HT :HH :HH :TH :HH :HH :HH :TT :HH :HH :HT :HT)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And we're using the code HH -&amp;gt; 1, HT -&amp;gt;01 TH-&amp;gt;001, TT-&amp;gt; 000&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Our code seems to have something of a tree structure&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;1-&amp;gt; :HH&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0-&amp;gt; 1 -&amp;gt; :HT&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;     &lt;/span&gt;&lt;span class="comment"&gt;0 -&amp;gt; 1 -&amp;gt; :TH&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;;          &lt;/span&gt;&lt;span class="comment"&gt;0 -&amp;gt; :TT&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Let's see if we can find some way of expressing that, so that we don't have to hand-code a decoder&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;for every different code.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;code-tree&lt;/span&gt; [ &lt;span class="builtin"&gt;:HH&lt;/span&gt; [ &lt;span class="builtin"&gt;:HT&lt;/span&gt; [ &lt;span class="builtin"&gt;:TH&lt;/span&gt; &lt;span class="builtin"&gt;:TT&lt;/span&gt;]]])&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;decoder&lt;/span&gt;&lt;br /&gt;  ([code-tree stream] (decoder code-tree code-tree stream))&lt;br /&gt;  ([current-code-tree code-tree stream]&lt;br /&gt;     (&lt;span class="builtin"&gt;lazy-seq&lt;/span&gt;&lt;br /&gt;        (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;keyword?&lt;/span&gt; current-code-tree)&lt;br /&gt;          (&lt;span class="builtin"&gt;cons&lt;/span&gt; current-code-tree (decoder code-tree code-tree stream))&lt;br /&gt;          (&lt;span class="keyword"&gt;if-let&lt;/span&gt; [stream (&lt;span class="builtin"&gt;seq&lt;/span&gt; stream)]&lt;br /&gt;            (&lt;span class="keyword"&gt;if&lt;/span&gt; (&lt;span class="builtin"&gt;=&lt;/span&gt; (&lt;span class="builtin"&gt;first&lt;/span&gt; stream) 1)&lt;br /&gt;              (decoder (&lt;span class="builtin"&gt;first&lt;/span&gt; current-code-tree)  code-tree (&lt;span class="builtin"&gt;rest&lt;/span&gt; stream))&lt;br /&gt;              (decoder (&lt;span class="builtin"&gt;second&lt;/span&gt; current-code-tree) code-tree (&lt;span class="builtin"&gt;rest&lt;/span&gt; stream))))))))&lt;br /&gt;&lt;br /&gt;(decoder code-tree '(0 1 1 0 1 0 1 1 0 0 0)) &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;(:HT :HH :HT :HT :HH :TT)&lt;br /&gt;&lt;/span&gt;  &lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;A general encoder, by comparison, is fairly straightforward:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;code&lt;/span&gt; {&lt;span class="builtin"&gt;:HH&lt;/span&gt; '(1) &lt;span class="builtin"&gt;:HT&lt;/span&gt; '(0 1) &lt;span class="builtin"&gt;:TH&lt;/span&gt; '(0 0 1) &lt;span class="builtin"&gt;:TT&lt;/span&gt; '(0 0 0)})&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;encoder&lt;/span&gt; [code stream]&lt;br /&gt;  (&lt;span class="builtin"&gt;mapcat&lt;/span&gt; code stream))&lt;br /&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;take&lt;/span&gt; 20 (encoder code stream)) &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;(1 1 1 1 1 1 1 1 0 1 1 1 0 0 1 1 1 1 0 0)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Trying the two together:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;take&lt;/span&gt; 20  (decoder code-tree (encoder code stream))) &lt;span class="comment-delimiter"&gt;;&lt;/span&gt;&lt;span class="comment"&gt;(:HH :HH :HH :HH :HH :HH :HH :HH :HT :HH :HH :TH :HH :HH :HH :TT :HH :HH :HT :HT)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And finally:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-encoder&lt;/span&gt; [code]  (&lt;span class="builtin"&gt;fn&lt;/span&gt; [s] (encoder code s)))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-decoder&lt;/span&gt; [code-tree] (&lt;span class="builtin"&gt;fn&lt;/span&gt;[s] (decoder code-tree s)))&lt;br /&gt;&lt;br /&gt;(cost (make-encoder code) (make-decoder code-tree) (&lt;span class="builtin"&gt;take&lt;/span&gt; 10000 stream)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;&amp;#163;16992&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It costs us &amp;#163;16992 to send 10000 symbols.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can use our code to send the output from the original biased coin very easily&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unfair-coin&lt;/span&gt; {&lt;span class="builtin"&gt;:H&lt;/span&gt; 3 &lt;span class="builtin"&gt;:T&lt;/span&gt; 1})&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;unfair-stream&lt;/span&gt; (random-stream unfair-coin))&lt;br /&gt;&lt;br /&gt;(&lt;span class="builtin"&gt;take&lt;/span&gt; 20 unfair-stream) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;(:H :H :H :H :H :H :T :H :H :H :H :H :H :H :T :H :H :H :H :T)&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;combine-keywords&lt;/span&gt; [&amp;amp; a] (&lt;span class="builtin"&gt;keyword&lt;/span&gt; (&lt;span class="builtin"&gt;apply&lt;/span&gt; str (&lt;span class="builtin"&gt;mapcat&lt;/span&gt; #(&lt;span class="builtin"&gt;drop&lt;/span&gt; 1 (&lt;span class="builtin"&gt;str&lt;/span&gt; %)) a))))&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;split-keyword&lt;/span&gt; [a] (&lt;span class="builtin"&gt;map&lt;/span&gt; #(&lt;span class="builtin"&gt;keyword&lt;/span&gt; (&lt;span class="builtin"&gt;str&lt;/span&gt; %)) (&lt;span class="builtin"&gt;drop&lt;/span&gt; 1 (&lt;span class="builtin"&gt;str&lt;/span&gt; a))))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-combination-encoder&lt;/span&gt; [code n]&lt;br /&gt;  (&lt;span class="builtin"&gt;fn&lt;/span&gt; [s] (encoder code (&lt;span class="builtin"&gt;map&lt;/span&gt; #(&lt;span class="builtin"&gt;apply&lt;/span&gt; combine-keywords %) (&lt;span class="builtin"&gt;partition&lt;/span&gt; n s)))))&lt;br /&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;defn&lt;/span&gt; &lt;span class="function-name"&gt;make-combination-decoder&lt;/span&gt; [code-tree]&lt;br /&gt;  (&lt;span class="builtin"&gt;fn&lt;/span&gt; [s] (&lt;span class="builtin"&gt;mapcat&lt;/span&gt; split-keyword (decoder code-tree s))))&lt;br /&gt;&lt;br /&gt;(cost (make-combination-encoder code 2) (make-combination-decoder code-tree) (&lt;span class="builtin"&gt;take&lt;/span&gt; 10000 unfair-stream)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;&amp;#163;8460&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So our method of coding for {:HH 9, :HT 3, :TH 3, :TT 1} has given us a method of coding for {:H 3, :T 1}&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;which is 16% more efficient than the obvious one.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What if we try it on the output from the fair coin?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;(&lt;span class="keyword"&gt;def&lt;/span&gt; &lt;span class="function-name"&gt;fair-stream&lt;/span&gt; (random-stream {&lt;span class="builtin"&gt;:H&lt;/span&gt; 1 &lt;span class="builtin"&gt;:T&lt;/span&gt; 1}))&lt;br /&gt;&lt;br /&gt;(cost (make-combination-encoder code 2) (make-combination-decoder code-tree) (&lt;span class="builtin"&gt;take&lt;/span&gt; 10000 fair-stream)) &lt;span class="comment-delimiter"&gt;; &lt;/span&gt;&lt;span class="comment"&gt;&amp;#163; 11257&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Using this code on the output from an unbiased coin actually makes it more expensive to transmit!&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;To recap:&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We can transmit the output from a series of coin tosses, or other random&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;processes, down a binary channel, if we choose a code.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;The code can be trivial, like :H -&amp;gt; 0 :T -&amp;gt; 1,&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;or it can be complex, like :HH -&amp;gt; 1, :HT -&amp;gt; 01, :TH -&amp;gt;001, :TT -&amp;gt; 000&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Different codes can result in different costs of transmission for the outputs&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;of different processes&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;So far, we've seen costs of &amp;#163;1/symbol for the fair coin with the trivial code&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;or &amp;#163;1.12/symbol with the more complex code&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;And we've seen costs of &amp;#163;1/symbol and &amp;#163;0.84/symbol for the unfair coin with&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;the trivial and complex code respectively.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;It seems that choosing the right code can make transmission cheaper, and&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;choosing the wrong code can make it more expensive.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7056990295646173627-66474477578976365?l=www.learningclojure.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.learningclojure.com/feeds/66474477578976365/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.learningclojure.com/2011/01/very-gentle-introduction-to-information_14.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/66474477578976365'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7056990295646173627/posts/default/66474477578976365'/><link rel='alternate' type='text/html' href='http://www.learningclojure.com/2011/01/very-gentle-introduction-to-information_14.html' title='A Very Gentle Introduction to Information Theory : Generalizing the Encoder and Decoder'/><author><name>John Lawrence Aspden</name><uri>http://www.blogger.com/profile/02587130870181071109</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://3.bp.blogspot.com/_beguhAzru6A/SxMNUBn5_fI/AAAAAAAAAAM/GHEl64CsnxA/S220/passport_photo.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7056990295646173627.post-4526623228242834063</id><published>2011-01-13T22:46:00.002Z</published><updated>2011-01-13T23:01:45.126Z</updated><title type='text'>A Very Gentle Introduction to Information Theory : Setting the Scene</title><content type='html'>I've been reading David Mackay's wonderful book &lt;a href="http://www.inference.phy.cam.ac.uk/mackay/itila/"&gt;'Information Theory, Inference, and Learning Algorithms'&lt;/a&gt;, and writing a lot of clojure code as I go. I thought I might try to explain the concept of Entropy, or Information Content, as it's used in Communications Theory.&lt;br /&gt;&lt;style type="text/css"&gt;    &lt;!--      .clojure-body {        color: #fff8dc;        background-color: #000000;      }      .ATTRLIST {        /* (:foreground "orange1") */        color: #ffa500;      }      .ATTRLIST-1 {        /* (:foreground "yellow1") */        color: #ffff00;      }      .ATTRLIST-2 {        /* (:foreground "greenyellow") */        color: #adff2f;      }      .ATTRLIST-3 {        /* (:foreground "green1") */        color: #00ff00;      }      .ATTRLIST-4 {        /* (:foreground "springgreen1") */        color: #00ff7f;      }      .ATTRLIST-5 {        /* (:foreground "cyan1") */        color: #00ffff;      }      .ATTRLIST-6 {        /* (:foreground "slateblue1") */        color: #836fff;      }      .ATTRLIST-7 {        /* (:foreground "magenta1") */        color: #ff00ff;      }      .ATTRLIST-8 {        /* (:foreground "purple") */        color: #a020f0;      }      .builtin {        /* font-lock-builtin-face */        color: #b0c4de;      }      .comment {        /* font-lock-comment-face */        color: #ffd700;      }      .comment-delimiter {        /* font-lock-comment-delimiter-face */        color: #ffd700;      }      .function-name {        /* font-lock-function-name-face */        color: #00fa9a;      }      .keyword {        /* font-lock-keyword-face */        color: #00ffff;      }      a {        color: inherit;        background-color: inherit;        font: inherit;        text-decoration: inherit;      }      a:hover {        text-decoration: underline;      }    --&gt;    &lt;/style&gt;&lt;br /&gt;&lt;pre class="clojure-body"&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;A Very Gentle Introduction to Information Theory : Part I&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Entropy and Huffman Coding&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;What is the 'information content' of a random process?&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;We might think about a Victorian bookmaker transmitting horse racing results&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;over an expensive telegraph connection. A more modern example would be&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;streaming files over an internet connection.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;To think about the essence of these things, let us choose very simple models&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;for both the random process and the channel over which the message is to be&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;sent.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Setting up a model problem&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Our communications channel will be a device over which we can transmit either&lt;br /&gt;&lt;/span&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;0 or 1, paying a cost of £1 for every symbol.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="comment-delimiter"&gt;;; &lt;/span&gt;&lt;span class="comment"&gt;Our random num
