<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Sky Blue Trades RSS feed.</title>
        <link>http://www.skybluetrades.net</link>
        <description><![CDATA[RSS feed for the Sky Blue Trades blog.]]></description>
        <atom:link href="http://www.skybluetrades.net/rss.xml" rel="self"
                   type="application/rss+xml" />
        <lastBuildDate>No date found.</lastBuildDate>
        <item>
    <title>Introduction</title>
    <link>http://www.skybluetrades.net/posts/2011/10/09/intro.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Introduction</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2011/10/09/intro.html">Introduction</a></div>
    <div class="postdate">October  9, 2011</div>

    <p>I’ve been meaning to start a blog for some time, but couldn’t settle on a platform. I’d used Wordpress before for a <a href="http://www.skybluetrades/montpellier">little blog</a> we set up to let our friends and family know what we were up to when we moved to Montpellier, and I liked it (easy to install, easy to use). For a personal blog though, I wanted something a bit more hackable (yeah, I know, you can hack on Wordpress too, but if it’s going to be for <em>fun</em>, I want to be using something other than PHP!).</p>
<!--MORE-->

<p>I spent a bit of time writing the beginnings of a blog platform of my own in <a href="http://www.haskell.org/">Haskell</a>, using the <a href="http://happstack.com/">Happstack</a> framework. I got some way with that, but it was never really ready for primetime. Recently though, I heard about <a href="http://jaspervdj.be/hakyll/">Hakyll</a>, thought “What a great idea!” and jumped back in to getting something in shape.</p>
<p>Hakyll is a static website generator, which makes it great for situations where server resources are limited. I’m serving my site from a <a href="http://www.linode.com/">Linode VPS</a> using the <a href="http://www.cherokee-project.com/">Cherokee</a> web server, and I just don’t need the full flexibility of a general webapp for what I want to do. Hakyll seemed like an ideal solution, and it’s Haskell, so it would be fun!</p>
<p>I’ll write later about how I set Hakyll up for what I wanted, because there were a number of things I wanted to do differently to the way most Hakyll-based sites are set up, but you can see what I did <a href="http://github.com/ian-ross/blog">here</a>. The basic requirements were:</p>
<ul>
<li>Markdown syntax for posts;</li>
<li>Wordpress-style <code>YYYY/MM/DD/TITLE</code> post addresses;</li>
<li>Easy to organise posts with ancillary material (images, code, etc.);</li>
<li>Good LaTeX math support.</li>
</ul>
<p>In addition, I wanted a feature I’d implemented in my not-quite-ever-finished blog framework. This allows me to embed <a href="http://sourceforge.net/projects/pgf/">TikZ</a> code representing an image in a blog post and have it rendered as an inline SVG image in the resulting HTML. Useful? Sometimes. Cute? Well, I think so. I’ll show how I did that in a later article.</p>
<p>As for what else I’m going to write about here, it’ll be pretty eclectic. Basically, anything I find interesting. Which might range from Haskell and Common Lisp stuff, to ecology, remote sensing and vegetation modelling (my day job), book reviews, plus whatever else takes my fancy.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/colophonia.html">colophonia</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/09/intro.html</guid>
</item>
<item>
    <title>Haskell Comic Scraper: Part 1</title>
    <link>http://www.skybluetrades.net/posts/2011/10/10/haskell-comic-scraper-1/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Haskell Comic Scraper: Part 1</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2011/10/10/haskell-comic-scraper-1/index.html">Haskell Comic Scraper: Part 1</a></div>
    <div class="postdate">October 10, 2011</div>

    <p>I’m a relative beginner with <a href="http://www.haskell.org/">Haskell</a>, and like many people, to start with I was a little perplexed by the Haskell approach to I/O. A small worked example helped a lot. I was curious to see how easy it would be to do something like the webcomic scraper application implemented in <a href="http://clojure.org/">Clojure</a> <a href="http://gnuvince.wordpress.com/2008/10/31/fetching-web-comics-with-clojure-part-1/">here</a> and <a href="http://gnuvince.wordpress.com/2008/11/18/fetching-web-comics-with-clojure-part-2/">here</a>. This is a simple application, but it does do realistic I/O, downloading files from the web, writing them to disk, and also doing some computations on the file contents. Over the course of two articles, I’m going to build something comparable in Haskell. It turns out to be pretty easy!</p>
<!--MORE-->

<h2 id="the-io-problem">The I/O problem</h2>
<p>Before we get started, just why is I/O a problem in Haskell? (A problem for beginners anyway.) Haskell places great weight on purity and referential transparency, and this makes dealing with the outside world more interesting than in imperative languages. Haskell’s approach to dealing safely with impure actions with side effects is to use a monad (the <code>IO</code> monad) to segregate I/O “actions” from pure functional code. This takes a bit of getting used to.</p>
<p>The other common approach to handling I/O in pure code is exemplified by the uniqueness types of <a href="http://clean.cs.ru.nl/">Clean</a> and <a href="http://www.mercury.csse.unimelb.edu.au/">Mercury</a>, where some “world” object is threaded through purely functional code — the <em>old</em> state of the world is passed into a function that does I/O, the <em>new</em> state of the world is passed back out, and the type system of the language enforces “single-threaded” access to the state of the world (Mercury calls the input state a <em>destructive input</em> argument, and the output state a <em>unique output</em>). The same sort of threading of I/O state has to happen in the run-time system of any functional language, and Haskell’s monadic I/O syntax can be thought of as a way to hide this plumbing. Of course, monads can be used for much more than this, but I’m not going to talk about that at all. Here, I’m taking a beginner’s eye view of things, and I’m going to talk only about the I/O monad.</p>
<h2 id="getting-started">Getting started</h2>
<p>First, let’s define the problem we want to solve. We want to start with definitions of some webcomics (base page, a regular expression to use to pick out the address of the image file for the latest episode, etc.) and download the image files for the latest episode of each comic. To do this, we’ll get the base page of the webcomic, use the contents of that page to figure out the URL of the latest episode image, download that image and save it to a file. We’ll get a little more fancy about this later (saving images to directories based on today’s date and reading the comic definitions from an XML configuration file), but let’s start with this simple goal in mind. The code for this stage of the example can be found <a href="ComicScraper1.hs">here</a>.</p>
<p>We’re going to need a couple of Haskell packages that aren’t installed by default, in particular <code>Network.HTTP</code> and the Posix regular expression package <code>Text.Regex.Posix</code>. If you have <a href="http://www.haskell.org/haskellwiki/Cabal-Install">Cabal</a> set up (which you most definitely should), installing these is as simple as typing</p>
<pre><code>cabal install HTTP
cabal install regex-posix
</code></pre>
<p>Let’s start by playing a little with a function to download the contents of a URL. If we put the following into a Haskell script file, <code>tst.hs</code>, say:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">import</span> <span class="dt">Network.HTTP</span><br /><span class="ot">fetchURL </span><span class="ot">::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">String</span><br />fetchURL url <span class="fu">=</span> <span class="kw">do</span><br />  resp <span class="ot">&lt;-</span> simpleHTTP (getRequest url)<br />  <span class="fu">return</span> (getResponseBody resp)</code></pre>
<p>then we can do the following in <code>ghci</code></p>
<pre><code>Prelude&gt; :load tst.hs
*Main&gt; fetchURL &quot;http://www.xkcd.com/&quot;
</code></pre>
<p>and we get back a string containing the HTML contents of the XKCD front page. So, how does this work? First, let’s think about the type of <code>fetchURL</code>, which is <code>String -&gt; IO String</code>: it takes a single string as input (the URL we want to fetch) and returns a value of type <code>IO String</code>. This return type represents an I/O action that yields a <code>String</code> when we execute it.</p>
<p>If we think about a typical I/O action, reading a character from a file say, it’s clear why these need to be treated differently from pure functions. If we call a putative <code>getCharFromFile</code> function twice in a row, passing the same file handle as an argument, we don’t expect to get the same result from each call — the results that we get depend on the contents of the file, and in general, each call to <code>getCharFromFile</code> will yield a different result. This is quite different to the behaviour of pure functions: if we evaluate <code>head [1, 2, 3]</code>, we always get <code>1</code> as the result, independent of the state of the outside world.</p>
<p>These considerations mean that we need some framework for sequencing and executing I/O actions. In Haskell, this is provided by the <code>IO</code> monad, which the Haskell run-time system treats specially to enable this non-pure interaction with the outside world.</p>
<p>I/O actions are sequenced using Haskell’s <code>do</code> syntax, which we will examine in more detail below. For the moment, take the details of <code>fetchURL</code> on trust, and concentrate more on the similarity to a more familiar imperative way of programming displayed in the <code>do</code> block.</p>
<h2 id="data-structures">Data structures</h2>
<p>We’re going to represent the comics we want to download as simple structures, with string entries for the name of the comic, the URL of the base page, a regular expression to allow us to extract the URL of the latest story image from the base page, and a prefix to put on the front of that URL (which will probably be a relative URL) to make an absolute URL we can use to download the story image:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">Comic</span> <span class="fu">=</span> <span class="dt">Comic</span> {<span class="ot"> coName </span><span class="ot">::</span> <span class="dt">String</span>,<br /><span class="ot">                     coURL </span><span class="ot">::</span> <span class="dt">String</span>,<br /><span class="ot">                     coRegex </span><span class="ot">::</span> <span class="dt">String</span>,<br /><span class="ot">                     coPrefix </span><span class="ot">::</span> <span class="dt">String</span> }<br />             <span class="kw">deriving</span> <span class="kw">Show</span></code></pre>
<p>(The <code>Comic</code> type is defined using Haskell’s <a href="http://haskell.org/onlinereport/exps.html#field-ops">record syntax</a>.) Eventually, we’ll read a list of comics to download from a configuration file, but for now, let’s define a few comics for testing:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">comics </span><span class="ot">::</span> [<span class="dt">Comic</span>]<br />comics <span class="fu">=</span> [ <span class="dt">Comic</span> <span class="st">&quot;Girl Genius&quot;</span><br />                 <span class="st">&quot;http://www.girlgeniusonline.com/comic.php&quot;</span><br />                 <span class="st">&quot;ggmain/strips/ggmain[^']+&quot;</span><br />                 <span class="st">&quot;http://www.girlgeniusonline.com/&quot;</span>,<br />           <span class="dt">Comic</span> <span class="st">&quot;XKCD&quot;</span><br />                 <span class="st">&quot;http://www.xkcd.com/&quot;</span><br />                 <span class="st">&quot;comics/.+png&quot;</span><br />                 <span class="st">&quot;http://imgs.xkcd.com/&quot;</span>,<br />           <span class="dt">Comic</span> <span class="st">&quot;Girls With Slingshots&quot;</span><br />                 <span class="st">&quot;http://www.daniellecorsetto.com/gws.html&quot;</span><br />                 <span class="st">&quot;images/gws/GWS[^\&quot;;]+&quot;</span><br />                 <span class="st">&quot;http://www.daniellecorsetto.com/&quot;</span> ]</code></pre>
<h2 id="regular-expression-matching">Regular expression matching</h2>
<p>Given a <code>Comic</code> definition, the first thing we want to do is download the base page and extract the URL of the latest image file. We’ll write a function <code>imageURL</code> to do this. It will have type <code>Comic -&gt; IO String</code>, returning an I/O action with a <code>String</code> result (the URL we want). The result here is an I/O action because we’re interacting with the outside world: we certainly don’t expect to get the same result from <code>imageURL</code> every time we call it with the same arguments. It wouldn’t be very useful if we did… This is a good general guide for when you need to think about using actions: if a piece of code should return the same answer whenever it’s called with a given set of arguments, then it can be implemented as a pure function. Otherwise, the I/O monad is going to be involved.</p>
<p>Here’s <code>imageURL</code>:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">imageURL </span><span class="ot">::</span> <span class="dt">Comic</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">String</span><br />imageURL c <span class="fu">=</span> <span class="kw">do</span><br />  pg <span class="ot">&lt;-</span> fetchURL (coURL c)<br />  <span class="kw">let</span> re <span class="fu">=</span> pg <span class="fu">=~</span> (coRegex c)<span class="ot"> </span><span class="ot">::</span> <span class="dt">String</span><br />  <span class="kw">case</span> re <span class="kw">of</span><br />    <span class="st">&quot;&quot;</span> <span class="ot">-&gt;</span> <span class="fu">return</span> (<span class="fu">error</span> <span class="fu">$</span> <span class="st">&quot;no match for regular expression for &quot;</span> <span class="fu">++</span> coName c)<br />    <span class="fu">otherwise</span> <span class="ot">-&gt;</span> <span class="fu">return</span> (coPrefix c <span class="fu">++</span> re)</code></pre>
<p>One feature of I/O actions that distinguishes them from pure calculations is the need to impose an ordering on the execution of actions. In a pure computation, order of evaluation does not affect the result of the computation: the expression <code>a + b</code> yields the same result, regardless of which of <code>a</code> or <code>b</code> is evaluated first. Here, we need to fetch the base page for the comic, and only then can we match the regular expression that will give us the URL to get the latest story image. This sequencing is expressed using Haskell’s <code>do</code> notation<sup><a href="#fn1" class="footnoteRef" id="fnref1">1</a></sup>. Three kinds of expressions can appear within a <code>do</code> block:</p>
<ol style="list-style-type: decimal">
<li><p>Regular Haskell expressions;</p></li>
<li><p><code>let</code> forms, which bind names to pure functional expressions;</p></li>
<li><p>Expressions of the form <code>name &lt;- action</code>, which execute an I/O action and bind the result of the action to the given name.</p></li>
</ol>
<p>Our <code>imageURL</code> function contains expressions of each of these three types. First, we use the <code>fetchURL</code> function (which returns an I/O action of type <code>IO String</code>), executing the returned I/O action to retrieve the comic base page, and binding the result to the name <code>pg</code>. Subsequent lines in the <code>do</code> block can then refer to this value. This binding of names permits only a single assignment to a name: once <code>pg</code> is bound here, it may not be rebound. Next, we use a <code>let</code> expression to do regular expression pattern matching on the comic base page. The <code>=~</code> operator from the <code>Text.Regex.Posix</code> module is used (we have to give an explicit type annotation to resolve the ambiguity of the return type here). Finally, we use a simple Haskell <code>case</code> expression to decide what to return from <code>imageURL</code> on the basis of the pattern match. Note that both branches of the <code>case</code> expression contain uses of the <code>return</code> function, which has type <code>a -&gt; IO a</code> and is used to “inject” a value into the <code>IO</code> monad: it’s just a way of turning a regular <code>a</code> value into a value of type <code>IO a</code>, which is the return type we need for <code>imageURL</code>.</p>
<h2 id="retrieving-images">Retrieving images</h2>
<p>We can now use out <code>imageURL</code> function as part of a function to retrieve the latest image file for a given comic. We’ll call this <code>writeImageToFile</code>:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">writeImageToFile </span><span class="ot">::</span> <span class="dt">Comic</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> ()<br />writeImageToFile c <span class="fu">=</span> <span class="kw">do</span><br />  <span class="fu">putStrLn</span> <span class="fu">$</span> <span class="st">&quot;Retrieving: &quot;</span> <span class="fu">++</span> (coName c)<br />  url <span class="ot">&lt;-</span> imageURL c<br />  img <span class="ot">&lt;-</span> fetchURL url<br />  writeBinary (normaliseName <span class="fu">$</span> coName c <span class="fu">++</span> takeExtension url) img</code></pre>
<p>The overall type of our function here is <code>Comic -&gt; IO ()</code>, showing that the function takes a <code>Comic</code> and returns an I/O action. The <code>IO ()</code> return type means that the result of the I/O action is discarded: we are only interested in the I/O action for its side effects. Here again, we see sequencing of I/O actions using <code>do</code>. The first action writes a message to the terminal using the <code>putStrLn</code> function in the Haskell prelude (with type <code>String -&gt; IO ()</code>). Then we use our <code>imageURL</code> function to download the base URL for the comic and extract the URL of the latest image file. Next, we use the <code>fetchURL</code> function to download the contents of the image URL, binding the result to the name <code>img</code>. Finally, we write the contents of the image URL into a file with a name built from the name of the comic using the <code>normaliseName</code> function and the <code>takeExtension</code> function from the standard <code>System.FilePath</code> library. Here is the definition for <code>normaliseName</code>:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">normaliseName </span><span class="ot">::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span><br />normaliseName <span class="fu">=</span> <span class="fu">map</span> fix_spaces <span class="fu">.</span> <span class="fu">map</span> <span class="fu">toLower</span><br />  <span class="kw">where</span> fix_spaces <span class="ch">' '</span> <span class="fu">=</span> <span class="ch">'_'</span><br />        fix_spaces ch <span class="fu">=</span> ch</code></pre>
<p>We write the image data to the file using the <code>writeBinary</code> helper function, which uses some <code>System.IO</code> library functions to write the file as binary data (i.e. no text encoding, no newline conversion — Haskell strings are written using UTF–8 encoding by default, which will mess up the binary image data we’re dealing with here):</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">writeBinary </span><span class="ot">::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> ()<br />writeBinary f s <span class="fu">=</span> <span class="kw">do</span><br />  h <span class="ot">&lt;-</span> openFile f <span class="dt">WriteMode</span><br />  hSetBinaryMode h <span class="kw">True</span><br />  hPutStr h s<br />  hClose h</code></pre>
<p>The sequencing provided by <code>do</code> allows us to write this sort of I/O code in a very natural imperative-looking way. The Haskell compiler translates the <code>do</code> notation into pure code that threads the I/O state through the calls, but we don’t need to think about that to use the <code>IO</code> monad. We just need to remember two things:</p>
<ol style="list-style-type: decimal">
<li><p>To distiquish between pure functional expressions (which use <code>let</code>) and capturing the execution of I/O actions (which uses the <code>&lt;-</code> notation);</p></li>
<li><p>That all assignments are immutable — once we assign a value using <code>let</code> or <code>&lt;-</code>, that name cannot be reassigned.</p></li>
</ol>
<h2 id="putting-it-together">Putting it together</h2>
<p>Next, we want to take our <code>writeImageToFile</code> function and apply it to the list of comics defined above. We expect to do this with a function with type <code>[Comic] -&gt; IO ()</code>. We might initially be tempted to write something like <code>map writeImageToFile comics</code>, but this won’t work. To see why, consider the types of <code>map</code> and <code>writeImageToFile</code>:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="fu">map</span><span class="ot"> </span><span class="ot">::</span> (a <span class="ot">-&gt;</span> b) <span class="ot">-&gt;</span> [a] <span class="ot">-&gt;</span> [b]<br /><span class="ot">writeImageToFile </span><span class="ot">::</span> <span class="dt">Comic</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> ()</code></pre>
<p>The type of <code>map writeImageToFile</code> would then be something like <code>[Comic] -&gt; [IO ()]</code>, which is not quite what we want. Composition of I/O actions should not result in a list of I/O actions, but in a single action that performs the individual actions in sequence. A suitable mapping function that provides this sequencing functionality is provided in the <code>mapM_</code> function in the <code>Control.Monad</code> library. This library contains monadic equivalents of many common list processing functions (map, folds, etc.). Specialising to the <code>IO</code> monad, since that’s the only one we care about here, <code>mapM_</code> has type <code>(a -&gt; IO b) -&gt; [a] -&gt; IO ()</code> and applies a function with an <code>IO</code> result to a list of values, returning an I/O action that discards its result (which is what <code>IO ()</code> means).</p>
<p>We can then write a function to process all of our comics as:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">processAll </span><span class="ot">::</span> [<span class="dt">Comic</span>] <span class="ot">-&gt;</span> <span class="dt">IO</span> ()<br />processAll cs <span class="fu">=</span> <span class="fu">mapM_</span> writeImageToFile cs</code></pre>
<p>Typing <code>processAll comics</code> at the GHCi prompt results in the current story image for each of the comics in our list being downloaded and saved to a file.</p>
<h2 id="what-next">What next?</h2>
<p>In Part 2, we’ll extend what we’ve done to organise our downloaded images a little, placing all the images we download into directories with names based on the current date — this will require us to do some I/O to create the directories, but also to determine the date (how could a <code>getCurrentDate</code> function always return the same value? i.e. how could it be pure?). We’ll also write some code to read a list of comics to download from an XML configuration file.</p>
<div class="footnotes">
<hr></hr>
<ol>
<li id="fn1"><p>Expressions involving <code>do</code> are convenient syntactic sugar for expressions based on the monadic <code>&gt;&gt;=</code> operator. We don’t need to worry about this here. <a href="#fnref1" class="footnoteBackLink">↩</a></p></li>
</ol>
</div>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/haskell.html">haskell</a></span> <span class="tag"><a href="../../../../../tags/programming.html">programming</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/10/haskell-comic-scraper-1/index.html</guid>
</item>
<item>
    <title>Whaleboat Island</title>
    <link>http://www.skybluetrades.net/posts/2011/10/10/whaleboat-island/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Whaleboat Island</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2011/10/10/whaleboat-island/index.html">Whaleboat Island</a></div>
    <div class="postdate">October 10, 2011</div>

    <div class="img-right">
<img src="whaleboat-island.jpg" alt="Whaleboat Island"></img>
</div>

<p>We moved from <a href="http://en.wikipedia.org/wiki/Vancouver_Island">Vancouver Island</a> on the west coast of Canada to Montpellier in March 2011. Montpellier is not <em>so</em> bad, but there are a lot of things I miss about Canada. Our friends, for one thing. But also the wide open spaces. One of the last sea kayaking trips I took in Canada was a solo outing to a small (very small!) island in the <a href="http://en.wikipedia.org/wiki/Gulf_Islands">Gulf Islands National Park</a>.</p>
<p><a href="http://www.env.gov.bc.ca/bcparks/explore/parkpgs/whaleboat/">Whaleboat Island</a> is a marine provincial park, but it’s unmanaged, which means you are completely on your own: no campsites, no hookups, no wardens, no helpful information boards, and yes, no toilets. There’s also the minor matter that the beach only exists at low tide and you have to climb up some cliffs to find a flat spot to pitch a tent. Apart from that, it’s a perfect destination. Perfect for me anyway. I’d landed on Whaleboat once before, as a possible lunch spot, but that time no-one else seemed interested in clambering over rocks to eat their sandwiches and we ended up on an admittedly very pretty beach on Pylades Island.</p>
<p>This time though, I was on a mission. I’d bought myself a kayak a couple of days before, and was out to try it out, as well as checking out the camping possibilities on Whaleboat.</p>
<!--MORE-->

<p>I put in at <a href="http://maps.google.com/maps?q=49.116523,-123.805618">Cedar-by-the-Sea</a>, a small settlement just south of the town of Nanaimo, where there’s a boat ramp, a few houses and not much else but beautiful views of the islands. And yes, it’s <em>islands</em>. There are a lot of them (I have no idea exactly how many). On this trip, I paddled by Round Island, Mudge Island, Link Island, De Courcy Island, Ruxton Island, Whaleboat Island and Pylades Island plus countless nameless little rocks that support a couple of seals or a few birds.</p>
<p>Speaking of birds, there were a lot to see this weekend: gulls, cormorants, crows, eagles, some cute little black and white ducks, geese, plus a bunch of others. I never quite got used to seeing big bald eagles in the trees above me. They’re really surprisingly common. The other thing I never quite got used to was seeing all the marine mammals around. They’re quite skittish, and you need to make sure you keep a good distance from them, but families of seals are a regular sight (and it’s hard to avoid disturbing them sometimes as you paddle round a rock and all the seals who were happily basking in the sun decide that you’re Public Enemy #1 and they need to get in the water and look at you with accusing puppy-dog eyes until you go away). I also saw a family of otters I’d seen before, with the adults fishing and the pups “helping”. And a first for me, on the way back into Cedar, there was a big family of sea lions fishing for herring. Quite intimidating when you’re in a fragile little boat, since they’re not small animals and they get quite excitable when they’re fishing, with lots of angry-sounding honking from the big males as they herd the herring towards the other sea lions.</p>
<p>There’s always a lot of more exotic weird sea stuff to see as well. This time out, I saw lots of starfish, including the biggest one I’ve ever seen, which must have been over 50 cm across, as big as some “world record” ones… There were also millions and millions of jellyfish (they must have been spawning or whatever it is they do, but there were more of them than I have <em>ever</em> seen before), and there were some <em>really</em> weird dangly blobby things that looked like condoms, but which I think might be brown tunicates that got exposed at low tide.</p>
<p>Camping on Whaleboat Island proved possible, if slightly more amusing than most people might put up with. I though it was nice. You do need to be careful about where you put your boat overnight, since the beach disappears at high tide and you may find yourself with a tricky clamber along the cliffs to get back onto the water. Also, the “path” up the cliffs is pretty rough, and is more of a scramble than a real path. Once up on top, there are plenty of flat places to pitch a (small) tent, but you need to watch out for potentially ankle-breaking holes in among the moss-covered rocks. I didn’t explore too much of the upper part of the island because of those. I was on my own and didn’t much fancy the prospect of waiting out the night for someone to come and rescue me if I broke something.</p>
<p>But still, there was solitude and quiet, with just the sound of the wind whispering in the trees and the waves lapping on the beach to send me to sleep. What a great place. I miss it!</p>
<br />
<div class="img-full">
<img src="kayak.jpg" alt="Kayak"></img>
</div>



<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/kayaking.html">kayaking</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/10/whaleboat-island/index.html</guid>
</item>
<item>
    <title>Stanford AI Class</title>
    <link>http://www.skybluetrades.net/posts/2011/10/11/ai-class-intro.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Stanford AI Class</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2011/10/11/ai-class-intro.html">Stanford AI Class</a></div>
    <div class="postdate">October 11, 2011</div>

    <p>Along with about 160,000 other people, I’ve signed up for the <a href="http://www.ai-class.com">Stanford Introduction to Artificial Intelligence</a> course. My interest in this is two-fold: first for the material, which should be pretty cool if Peter Norvig’s <a href="http://aima.cs.berkeley.edu/">book</a> is anything to go by, but second for just how they (the two instructors plus presumably an army of TAs) are going to do this.</p>
<p>Perhaps I’m not a very good teacher in a lecture setting, but I have real trouble connecting even to a class of 90 or so students. Most effective <em>teaching</em> occurs one-on-one or in small groups in office hours. And most <em>learning</em> occurs when students are sitting quietly thinking about things themselves. How you make contact with and retain the attention of 85,000 students is a problem that boggles the mind. I’m very interested to see how it goes!</p>
<p>The first couple of modules are up on the website already, and it looks like the format of most of the course will be pretty nice and accessible. How assignments and exams will work, we’ll have to see. I really hope Stanford are supplying some additional resources to help with this project. It’s a very cool thing to be doing, and very exciting, but it has the potential to be a pretty high stress adventure for the instructors!</p>
<p>If AI doesn’t float your boat, Stanford are also running <a href="http://www.ml-class.com/">Intro to Machine Learning</a> and <a href="http://www.db-class.com/">Intro to Databases</a> courses online as well.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/artificial-intelligence.html">artificial-intelligence</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/11/ai-class-intro.html</guid>
</item>
<item>
    <title>Friday photo #1</title>
    <link>http://www.skybluetrades.net/posts/2011/10/13/friday-photo-1/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Friday photo #1</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2011/10/13/friday-photo-1/index.html">Friday photo #1</a></div>
    <div class="postdate">October 13, 2011</div>

    <a href="glanmore-lake.jpg">
<div class="img-full">
<img src="glanmore-lake-small.jpg" alt="Glanmore Lake"></img>
</div>
</a>
<p>Glanmore Lake, Beara Peninsula. On a holiday to Ireland some years ago.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/photos.html">photos</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/13/friday-photo-1/index.html</guid>
</item>
<item>
    <title>Haskell Comic Scraper: Part 2</title>
    <link>http://www.skybluetrades.net/posts/2011/10/13/haskell-comic-scraper-2/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Haskell Comic Scraper: Part 2</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2011/10/13/haskell-comic-scraper-2/index.html">Haskell Comic Scraper: Part 2</a></div>
    <div class="postdate">October 13, 2011</div>

    <p><a href="../../../../../posts/2010/10/10/haskell-comic-scraper-1">Last time</a>, we looked at the basics for a webcomic scraper. In this post, we’ll look at extending our code a little to incorporate some date handling and some simple XML processing.</p>
<!--MORE-->

<p>The second version of the code is <a href="ComicScraper2.hs">here</a>.</p>
<h2 id="date-based-output-directories">Date based output directories</h2>
<p>The first thing we’ll do is set things up so that the webcomic images we download are stored in a directory whose name is taken from today’s date. Date and time handling functions are in the <code>Data.Time</code> module, so we import that:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">import</span> <span class="dt">Data.Time</span></code></pre>
<p>Following our “does it always return the same value” heuristic, it seems pretty clear that a function to get today’s date has to live in the <code>IO</code> monad, since it wouldn’t be very useful for such a function to return the same value every time it’s called. The <code>Date.Time</code> module has a number of functions for dealing with dates and times and timezones, mostly modelled on the Unix C library functions for doing the same jobs. We can get a representation of the current date (the <code>Day</code> type is just a wrapper for an integer giving the <a href="http://en.wikipedia.org/wiki/Julian_day">modified Julian day</a>) in the local timezone using the following code:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">getToday </span><span class="ot">::</span> <span class="dt">IO</span> <span class="dt">Day</span><br />getToday <span class="fu">=</span> <span class="kw">do</span><br />  tz <span class="ot">&lt;-</span> getCurrentTimeZone<br />  tm <span class="ot">&lt;-</span> getCurrentTime<br />  <span class="fu">return</span> (localDay <span class="fu">$</span> utcToLocalTime tz tm)</code></pre>
<p>Here, both getting the current time zone and getting the current time require IO actions (the current time zone can change from time to time if the machine where our code is running is moved, for instance), and obviously the current time changes with time… All of the functions <code>getCurrentTimeZone</code>, <code>getCurrentTime</code>, <code>localDay</code> and <code>utcToLocalTime</code> are defined in the <code>Data.Time</code> module, whose documentation you can read <a href="http://haskell.org/ghc/docs/7.0-latest/html/libraries/time-1.2.0.3/Data-Time.html">here</a>.</p>
<p>Once we have a date, we’d like to turn it into a good name to use for a pathname. This a simple manipulation of the result of <code>getToday</code>, but because <code>getToday</code> is an IO action, our function to make the pathname returns an IO action too:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">makeDateName </span><span class="ot">::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">String</span><br />makeDateName base <span class="fu">=</span> <span class="kw">do</span><br />  date <span class="ot">&lt;-</span> getToday<br />  <span class="fu">return</span> (base <span class="fu">++</span> <span class="st">&quot;/&quot;</span> <span class="fu">++</span> showGregorian date)</code></pre>
<p>Here, the <code>showGregorian</code> function is a handy utility from <code>Data.Time</code> that formats a date in ISO YYYY-MM-DD format, and we pass in a “base directory” where all the webcomic download directories should go.</p>
<p>We can now modify the <code>processAll</code> function from last time. We’ll need to pass in a base directory name (parameter <code>bd</code> in the function below), plus a list of comics to get. We can determine the path to save the downloads to using <code>makeDateName</code>, and we then use the <code>createDirectoryIfMissing</code> function from <code>System.Directory</code> to make the relevant directory (the first <code>True</code> argument acts the same as the <code>-p</code> flag to <code>mkdir</code>, making parent directories as required), then change working directory to the new directory, then download the files:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">processAll </span><span class="ot">::</span> <span class="dt">String</span> <span class="ot">-&gt;</span> [<span class="dt">Comic</span>] <span class="ot">-&gt;</span> <span class="dt">IO</span> ()<br />processAll bd cs <span class="fu">=</span> <span class="kw">do</span><br />  dateDirectory <span class="ot">&lt;-</span> makeDateName bd<br />  createDirectoryIfMissing <span class="kw">True</span> dateDirectory<br />  setCurrentDirectory dateDirectory<br />  <span class="fu">mapM_</span> writeImageToFile cs</code></pre>
<p>As before, a lot of this looks just like what we would write in a traditional imperative language. The monadic structure of the code that the Haskell compiler generates from a <code>do</code> statement deals with all the details of routing the results of one step of the computation to the next in a way that preserves referential transparency.</p>
<h2 id="an-xml-configuration-file">An XML configuration file</h2>
<p>Until now, we’ve been specifying the list of comics to read directly in our code. This isn’t very convenient, so it would be good to read the comic details from a configuration file. We’ll use a simple XML file that we’ll call <code>comics.xml</code>: an example is <a href="comics.xml">here</a>.</p>
<p>Haskell has a number of <a href="http://en.wikibooks.org/wiki/Haskell/XML">very sophisticated libraries</a> for dealing with XML documents, but sometimes these are slight overkill. If all you want to do is pull some information out of an XML file without too much fuss, then the <a href="http://hackage.haskell.org/package/tagsoup">TagSoup</a> package is what you want. This has a nice simple interface for reading XML (or HTML) that may or may not be well-formed, from which you can extract the data items you need. We import the package as:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">import</span> <span class="dt">Text.HTML.TagSoup</span></code></pre>
<p>and we use it as shown in the <code>getConfig</code> function, which reads the contents of a configuration file and parses it using the <code>TagSoup</code> <code>parseTags</code> function. The result of this is a list of HTML/XML tags with attached attributes that you can process using Haskell’s usual list processing functions. Here, we first use <code>filter</code> to pick out the entry in the tag list having an open tag of <code>baseDirectory</code>, from which we extract the name attribute to use as our base directory. If that works, we pick out all the entries with an open tag of <code>comic</code> and process them with the <code>makeComic</code> function, which simply pulls the relevant items out of attributes in the comic tags.</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">getConfig </span><span class="ot">::</span> <span class="fu">FilePath</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> (<span class="dt">String</span>, [<span class="dt">Comic</span>])<br />getConfig cfg_path <span class="fu">=</span> <span class="kw">do</span><br />  fc <span class="ot">&lt;-</span> <span class="fu">readFile</span> cfg_path<br />  <span class="kw">let</span> tags <span class="fu">=</span> parseTags fc<br />  <span class="kw">let</span> bdtags <span class="fu">=</span> <span class="fu">filter</span> (isTagOpenName <span class="st">&quot;baseDirectory&quot;</span>) tags<br />  <span class="kw">case</span> bdtags <span class="kw">of</span><br />    [] <span class="ot">-&gt;</span> <span class="fu">return</span> (<span class="fu">error</span> <span class="st">&quot;baseDirectory field missing from comics.xml&quot;</span>)<br />    <span class="fu">otherwise</span> <span class="ot">-&gt;</span> <span class="kw">do</span><br />      <span class="kw">let</span> bd <span class="fu">=</span> fromAttrib <span class="st">&quot;name&quot;</span> <span class="fu">$</span> <span class="fu">head</span> bdtags<br />      <span class="kw">let</span> cs <span class="fu">=</span> <span class="fu">map</span> makeComic <span class="fu">$</span> <span class="fu">filter</span> (isTagOpenName <span class="st">&quot;comic&quot;</span>) tags<br />      <span class="fu">return</span> (bd, cs)<br />  <span class="kw">where</span> makeComic t <span class="fu">=</span> <span class="kw">if</span> n <span class="fu">==</span> <span class="st">&quot;&quot;</span> <span class="fu">||</span> u <span class="fu">==</span> <span class="st">&quot;&quot;</span> <span class="fu">||</span> r <span class="fu">==</span> <span class="st">&quot;&quot;</span> <span class="fu">||</span> p <span class="fu">==</span> <span class="st">&quot;&quot;</span> <span class="kw">then</span><br />                         <span class="fu">error</span> <span class="st">&quot;attribute missing in comic tag&quot;</span><br />                         <span class="kw">else</span> <span class="dt">Comic</span> n u r p <br />          <span class="kw">where</span> n <span class="fu">=</span> fromAttrib <span class="st">&quot;name&quot;</span> t <br />                u <span class="fu">=</span> fromAttrib <span class="st">&quot;url&quot;</span> t<br />                r <span class="fu">=</span> fromAttrib <span class="st">&quot;regex&quot;</span> t <br />                p <span class="fu">=</span> fromAttrib <span class="st">&quot;prefix&quot;</span> t</code></pre>
<p>While it’s not up to more complex XML processing tasks that require walking and transforming the tree of entries in an XML file, for this type of application, <code>TagSoup</code> is just about perfect. It’s lightweight, easy to use, and interfaces with standard ways of working with lists in Haskell in a seamless way.</p>
<p>To make use of this, we just modify our main program to read the configuration information, which we pass right along to <code>processAll</code>.</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">main </span><span class="ot">::</span> <span class="dt">IO</span> ()<br />main <span class="fu">=</span> <span class="kw">do</span><br />  (bd, cs) <span class="ot">&lt;-</span> getConfig <span class="st">&quot;comics.xml&quot;</span><br />  processAll bd cs</code></pre>
<p>Simple!</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/haskell.html">haskell</a></span> <span class="tag"><a href="../../../../../tags/programming.html">programming</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/13/haskell-comic-scraper-2/index.html</guid>
</item>
<item>
    <title>Land cover datasets</title>
    <link>http://www.skybluetrades.net/posts/2011/10/15/land-cover-comparison/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Land cover datasets</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2011/10/15/land-cover-comparison/index.html">Land cover datasets</a></div>
    <div class="postdate">October 15, 2011</div>

    <p>In my day job, I work on the ecology of Mediterranean ecosystems in southern France, and if you work on a particular type of ecosystem, the first thing you need to know is where you can find your ecosystem! Seems like a simple problem, but it’s not.</p>
<!--MORE-->

<p>How might we start? Go out and take a look? That’s fine, as far as it goes, but it’s labour-intensive and it can be tricky to compare manual observations from different time periods for changes in land cover. We’ll come back to that in a minute. What about aerial photos? They’re available for many regions of the globe, and they’ve been around a lot longer than satellite data. Here’s an aerial photo of a small region (about 8.5 km by 7 km) near an experimental station we have at <a href="http://maps.google.com/maps?q=Pu%C3%A9chabon,+France&amp;hl=en&amp;ie=UTF8&amp;ll=43.717272,3.617249&amp;spn=0.06098,0.131578&amp;sll=37.0625,-95.677068&amp;sspn=66.828216,134.736328&amp;vpsrc=6&amp;hnear=Pu%C3%A9chabon,+H%C3%A9rault,+Languedoc-Roussillon,+France&amp;t=h&amp;z=14">Puéchabon</a> in the Languedoc-Roussillon region of southern France, about 30 km from Montpellier.</p>
<div class="img-full" style="width: 45%; margin-left: auto; margin-right: auto;">
<a href="aerial-photo.png"><img src="aerial-photo.png" alt="Aerial photo"></img></a>
<p style="text-align: center;">
<em>IGN aerial photo</em>
</p>
</div>

<p>We can see a river, roads, some fields (easy to spot both because of their colour and their geometry), some areas that look less vegetated (the grey parts north of the fields), some parts that look more vegetated (mostly around the greyer parts). But can we tell which areas are predominantly covered by <em>Quercus ilex</em> (<a href="http://en.wikipedia.org/wiki/Quercus_ilex">holm oak</a>) woodlands? That’s a bit tougher. Detailed examination of high resolution images can be enough to identify vegetation assemblages, but there’s often just not enough information in a simple visible light photograph (in the usual digital rendering, just three spectral channels for red, green and blue) to pick out more subtle differences. And before the 1970s, most aerial photographs were black and white, which makes things even harder.</p>
<p>For some regions of the world, there are in fact pretty good inventories of the “go out and take a look” kind. For France, the <a href="http://www.ifn.fr/">Inventaire Forestier National</a> (IFN) collects vegetation inventory information for forestry applications. Here’s a plot of their data for the same region as shown in the aerial photo:</p>
<div>
  <div class="img2-box">
    
<a href="ifn.png"><img src="ifn.png" alt="IFN example"></img></a>
<p style="text-align: center;">
<em>IFN inventory data</em>
</p>
  </div>
  <div class="img2-box">
    
<img src="ifn-legend.png" alt="IFN legend"></img>
</div>
  <div class="img-spacer"></div>
<div>

<p>There’s a pretty good correspondence between the units from the IFN data and the units that are visible on the aerial photograph, which lends some confidence to the classification that we see. There are three problems though. First, this data has been developed for forestry use. There are large white “unclassified” areas where there is no data, because there are no economically interesting trees there. For some ecological applications, that’s not much of a hindrance, but it can be a problem for others. Second, to understand what you’re seeing in a data set like this, you need to know quite a bit about the survey method used for the inventory and the statistical methods used to interpolate to a map view. For the IFN data, this is well documented, which makes the data relatively easy to use, but that level of documentation is more the exception than the rule. And finally, this data is difficult to collect: a ground-based survey of the entire country requires a lot of resources and so it can’t be done all that often. (For some reason, Spain does very well in this regard. They have really good forestry data collected on a regular basis across the whole of the country. Good for them!)</p>
<p>What about some combination of aerial photography and ground-based observations to serve as some sort of reference? This is a good approach in many cases: it allows for a more reasonable use of resources for surveying, and it can produce new data sets as new aerial photography comes in. I use two different data sets of this type, both produced in broadly similar ways, called CORINE (which covers the whole of Europe) and OCSOL (which covers only the Languedoc-Roussillon and <a href="http://en.wikipedia.org/wiki/Provence-Alpes-C%C3%B4te_d%27Azur">PACA</a> regions of southern France). Both of these data sets use ground-based observations with contemporaneous aerial photography to construct sets of rules for classifying land cover types from photographs. The rules tend to be quite complicated, relying on both basic spectral data (trees are green, water is blue, rock is grey, that sort of thing), geometric classification (fields tend to have square boundaries, rivers are roads are mostly linear features, and so on) and a combination of the two, possibly with other factors (greenhouses are squarish shiney things that often appear in regular groups). Along with some ancillary rules to control the geometry of the resulting data set (no near singular triangles, for example), this provides a system for going from aerial photographs of a region to a data set of polygons classified by land cover type. So how well does it work? Both CORINE and OSCOL use more or less the same classification scheme, with the following classes:</p>
<div class="img-full">
  
<img src="corine-ocsol-legend.png" alt="CORINE/OCSOL legend"></img>
</div>

<p>and here is what the data looks like for the same region as shown in the aerial photo and the IFN data above:</p>
<div>
  <div class="img2-box">
    
<a href="corine.png"><img src="corine.png" alt="CORINE example"></img></a><br />
<p style="text-align:center;">
<em>CORINE land cover</em>
</p>
  </div>
  <div class="img2-box">
    
<a href="ocsol.png"><img src="ocsol.png" alt="OCSOL example"></img></a><br />
<p style="text-align:center;">
<em>OCSOL land cover</em>
</p>
  </div>
</div>

<p>Hmmm… Not so awesome. Land cover units in the data sets don’t bear a strong resemblance to the land cover units you can see in the aerial photograph, and they don’t correspond all that closely to the vegetation units in the IFN data (which is probably closer to the “truth”, since it’s survey-based everywhere, while the CORINE and OCSOL data uses rules calibrated in some parts of the region of application to determine land cover type in other parts of the region).</p>
<p>For a further comparison, we can think about what sort of remote sensing products we might try to use to determine the land cover type. With remote sensing data, we have a good chance of getting a regular time series of data (annual land cover maps from MODIS, for instance), which is harder to get via any other method. The downside? Spatial resolution is pretty terrible, and classification accuracy is patchy. Here’s the MODIS data for 2006 (same year as the CORINE data and the aerial photo) for the region we’re looking at:</p>
<div>
  <div class="img2-box">
    
<a href="modis.png"><img src="modis.png" alt="MODIS example"></img></a>
<p style="text-align: center;">
<em>MODIS land cover</em>
</p>
  </div>
  <div class="img2-box">
    
<img src="igbp-legend.png" alt="MODIS legend"></img>
</div>
  <div class="img-spacer"></div>
<div>

<p>The spatial resolution here is about 500 m, compared to about 25 m for the IFN data and whatever you want to believe for the CORINE and OCSOL vector data sets (their resolution is defined in terms of the minimum area of land cover feature that they include, rather than a regular grid-based resolution limit). It’s actually very unfair to compare MODIS data to data produced by land-based surveys, but we don’t really care too much about fair in this game: we just want good data.</p>
<p>Let’s look at a comparison between some of these data sets in a slightly more quantitative way. Eyeball is fine, but just how bad <em>is</em> the correspondence between these different data sets? Let’s compare CORINE with MODIS first. Gaze at this technicolour horror for a few seconds:</p>
<div class="img-full">
<img src="CORINE_MODIS_2006.png" alt="CORINE/MODIS comparison"></img>
</div>

<p>What this is showing is, in the vertical bar on the left, the overall classification across the whole of the Languedoc-Roussillon region, according to CORINE, and in the main part of the plot, how the portion of the land surface in each of those CORINE classes was classified according to the MODIS data. If we take a look at the two most common CORINE classes, broad-leaved and coniferous forest, we see that these are mostly, but not exclusively, classified as forest in the MODIS data, but there’s quite a lot of mixing of classifications between the different forest types. The same kind of phenomena is seen in the other classes: areas classified as urban by CORINE are about 50% classified as urban in the MODIS data and about 50% something else. One possible complaint about this comparison is of a resolution mismatch between CORINE and MODIS: the CORINE data is a vector data set with pretty high spatial resolution, while the MODIS data is on a 500 m grid (more or less). We can do a similar comparison between CORINE and OCSOL though, both of which are vector data sets, though OCSOL has a smaller minimum area for land cover units it will consider. Here’s the same sort of comparison plot as for the CORINE/MODIS comparison:</p>
<div class="img-full">
<img src="OCSOL_CORINE.png" alt="OCSOL/CORINE comparison"></img>
</div>

<p>The comparison is a little easier here, since CORINE and OCSOL use more or less the same classification so we can use the same colour scales. That means that blocks in the main part of the plot that are the same colour as the bars in the left hand part of the plot are classified consistently between the two data sets. Even though these methods ostensibly use similar methods to classify land cover, the correspondence between the two data sets is not great. For instance, of the area that is classified as coniferous forest by OCSOL, only about 40% is also classified as coniferous forest by CORINE.</p>
<p>So, what do we do? It’s difficult to come up with any concrete recommendations that aren’t very tightly tied to specific applications, since everyone’s detailed needs are different. For my work, I’m most interested in assemblages including <em>Quercus ilex</em>, <em>Quercus pubescens</em>, <em>Pinus halepensis</em> and shrub species that can be bundled up into a generic “garrigue” classification. For the individual tree species, the IFN data is very good. For identifying garrigue sites, it’s a bit less good, so I use OCSOL for that. The same goes for grasslands, when I need them.</p>
<p>It’s a bit daunting that what would appear to be the simplest possible remote sensing/geostatistical data question, that is “What’s there on the ground?” turns out to be so difficult to answer. The geography and history of this part of France does make the disposition of land cover particularly complex, but something like this problem is going to be encountered more or less anywhere in the world.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/day-job.html">day-job</a></span> <span class="tag"><a href="../../../../../tags/remote-sensing.html">remote-sensing</a></span> <span class="tag"><a href="../../../../../tags/science.html">science</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/15/land-cover-comparison/index.html</guid>
</item>
<item>
    <title>AI Class: A* Search</title>
    <link>http://www.skybluetrades.net/posts/2011/10/16/a-star-search/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | AI Class: A* Search</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2011/10/16/a-star-search/index.html">AI Class: A* Search</a></div>
    <div class="postdate">October 16, 2011</div>

    <p>The first week of the online <a href="http://www.ai-class.com/">Stanford AI class</a> has gone by. The format of the presentation is pretty good, with lots of short lecture videos chained together with little quizzes embedded. It’s really pretty neat. There are some minor errors in some of the lectures, which is normal, though in this kind of online setting, it’s more difficult for the keener students to correct the lecturer as the lecture goes along, so some people are likely to spend a bit of time confused because of that. Some people have complained on Reddit about the relatively superficial level of the coverage of the lectures, but as far as I’m concerned, that’s what the book (and papers) are for. The course is called “Introduction to Artificial Intelligence”, after all.</p>
<!--NOTEASERBEGIN-->

<h2 id="motivation-take-me-home-romanian-roads">Motivation: Take me home, Romanian roads</h2>
<!--NOTEASEREND-->

<p>The two things we covered this week were a very quick introduction to the field, then some stuff about search. Although there is a big pile of code available for download associated with Russell &amp; Norvig’s <a href="http://aima.cs.berkeley.edu/">AI book</a> which would have made playing with some of this stuff easier, I decided to write some code of my own in Haskell, mostly for my own amusement. I wanted to implement A* search, with a clean interface for setting up problems.</p>
<!--MORE-->

<p>The example used in the lectures, of finding driving routes on a simple road map of Romania, is a good simple problem to look at. I wanted the definition of this problem to look something like this:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">import</span> <span class="dt">AStar</span><br /><br /><span class="kw">import</span> <span class="dt">Data.Maybe</span><br /><span class="kw">import</span> <span class="dt">Data.List</span><br /><br /><span class="kw">data</span> <span class="dt">Rom</span> <span class="fu">=</span> <span class="dt">A</span> <span class="fu">|</span> <span class="dt">B</span> <span class="fu">|</span> <span class="dt">C</span> <span class="fu">|</span> <span class="dt">D</span> <span class="fu">|</span> <span class="dt">E</span> <span class="fu">|</span> <span class="dt">F</span> <span class="fu">|</span> <span class="dt">G</span> <span class="fu">|</span> <span class="dt">H</span> <span class="fu">|</span> <span class="dt">I</span> <span class="fu">|</span> <span class="dt">L</span> <span class="fu">|</span> <span class="dt">M</span> <span class="fu">|</span> <br />           <span class="dt">N</span> <span class="fu">|</span> <span class="dt">O</span> <span class="fu">|</span> <span class="dt">P</span> <span class="fu">|</span> <span class="dt">R</span> <span class="fu">|</span> <span class="dt">S</span> <span class="fu">|</span> <span class="dt">T</span> <span class="fu">|</span> <span class="dt">U</span> <span class="fu">|</span> <span class="dt">V</span> <span class="fu">|</span> <span class="dt">Z</span><br />         <span class="kw">deriving</span> (<span class="kw">Eq</span>, <span class="kw">Ord</span>, <span class="kw">Show</span>)<br /><br /><span class="ot">initial </span><span class="ot">::</span> <span class="dt">Rom</span><br />initial <span class="fu">=</span> <span class="dt">A</span><br /><br /><span class="ot">goal </span><span class="ot">::</span> <span class="dt">Rom</span> <span class="ot">-&gt;</span> <span class="dt">Bool</span><br />goal <span class="fu">=</span> (<span class="fu">==</span> <span class="dt">B</span>)<br /><br /><span class="ot">distances </span><span class="ot">::</span> [((<span class="dt">Rom</span>, <span class="dt">Rom</span>), <span class="dt">Int</span>)]<br />distances <span class="fu">=</span> [((<span class="dt">A</span>, <span class="dt">S</span>), <span class="dv">140</span>), ((<span class="dt">A</span>, <span class="dt">T</span>), <span class="dv">118</span>), ((<span class="dt">A</span>, <span class="dt">Z</span>), <span class="dv">75</span>), ((<span class="dt">B</span>, <span class="dt">F</span>), <span class="dv">211</span>),<br />             ((<span class="dt">B</span>, <span class="dt">G</span>), <span class="dv">90</span>), ((<span class="dt">B</span>, <span class="dt">P</span>), <span class="dv">101</span>), ((<span class="dt">B</span>, <span class="dt">U</span>), <span class="dv">85</span>), ((<span class="dt">C</span>, <span class="dt">D</span>), <span class="dv">120</span>), <br />             ((<span class="dt">C</span>, <span class="dt">P</span>), <span class="dv">138</span>), ((<span class="dt">C</span>, <span class="dt">R</span>), <span class="dv">146</span>), ((<span class="dt">D</span>, <span class="dt">M</span>), <span class="dv">75</span>), ((<span class="dt">E</span>, <span class="dt">H</span>), <span class="dv">86</span>), <br />             ((<span class="dt">F</span>, <span class="dt">S</span>), <span class="dv">99</span>), ((<span class="dt">H</span>, <span class="dt">U</span>), <span class="dv">98</span>), ((<span class="dt">I</span>, <span class="dt">N</span>), <span class="dv">87</span>), ((<span class="dt">I</span>, <span class="dt">V</span>), <span class="dv">92</span>), <br />             ((<span class="dt">L</span>, <span class="dt">M</span>), <span class="dv">70</span>), ((<span class="dt">L</span>, <span class="dt">T</span>), <span class="dv">111</span>), ((<span class="dt">O</span>, <span class="dt">S</span>), <span class="dv">151</span>), ((<span class="dt">O</span>, <span class="dt">Z</span>), <span class="dv">71</span>),<br />             ((<span class="dt">P</span>, <span class="dt">R</span>), <span class="dv">97</span>), ((<span class="dt">R</span>, <span class="dt">S</span>), <span class="dv">80</span>), ((<span class="dt">U</span>, <span class="dt">V</span>), <span class="dv">142</span>)]<br /><br /><span class="ot">euclidean </span><span class="ot">::</span> [(<span class="dt">Rom</span>, <span class="dt">Int</span>)]<br />euclidean <span class="fu">=</span> [(<span class="dt">A</span>, <span class="dv">366</span>), (<span class="dt">B</span>, <span class="dv">0</span>), (<span class="dt">C</span>, <span class="dv">160</span>), (<span class="dt">D</span>, <span class="dv">242</span>), (<span class="dt">E</span>, <span class="dv">161</span>), (<span class="dt">F</span>, <span class="dv">176</span>), <br />             (<span class="dt">G</span>, <span class="dv">77</span>), (<span class="dt">H</span>, <span class="dv">151</span>), (<span class="dt">I</span>, <span class="dv">226</span>), (<span class="dt">L</span>, <span class="dv">244</span>), (<span class="dt">M</span>, <span class="dv">241</span>), (<span class="dt">N</span>, <span class="dv">234</span>), <br />             (<span class="dt">O</span>, <span class="dv">380</span>), (<span class="dt">P</span>, <span class="dv">100</span>), (<span class="dt">R</span>, <span class="dv">193</span>), (<span class="dt">S</span>, <span class="dv">253</span>), (<span class="dt">T</span>, <span class="dv">329</span>), (<span class="dt">U</span>, <span class="dv">80</span>), <br />             (<span class="dt">V</span>, <span class="dv">199</span>), (<span class="dt">Z</span>, <span class="dv">374</span>)]<br /><br /><span class="kw">instance</span> <span class="dt">SearchState</span> <span class="dt">Rom</span> <span class="kw">where</span><br />  actions x <span class="fu">=</span> <span class="fu">map</span> <span class="fu">const</span> <span class="fu">$</span> nub <span class="fu">$</span> <span class="fu">filter</span> (<span class="fu">/=</span> x) <span class="fu">$</span> (<span class="fu">map</span> <span class="fu">fst</span> ps) <span class="fu">++</span> (<span class="fu">map</span> <span class="fu">snd</span> ps)<br />    <span class="kw">where</span> ps <span class="fu">=</span> <span class="fu">map</span> <span class="fu">fst</span> <span class="fu">$</span> <span class="fu">filter</span> (\((a, b), _) <span class="ot">-&gt;</span> a <span class="fu">==</span> x <span class="fu">||</span> b <span class="fu">==</span> x) distances<br /><br />  stepCost x y <br />    <span class="fu">|</span> x <span class="fu">&lt;</span> y <span class="fu">=</span> fromJust <span class="fu">$</span> <span class="fu">lookup</span> (x, y) distances<br />    <span class="fu">|</span> <span class="fu">otherwise</span> <span class="fu">=</span> fromJust <span class="fu">$</span> <span class="fu">lookup</span> (y, x) distances<br /><br /><span class="ot">heuristic </span><span class="ot">::</span> <span class="dt">Rom</span> <span class="ot">-&gt;</span> <span class="dt">Int</span><br />heuristic x <span class="fu">=</span> fromJust <span class="fu">$</span> <span class="fu">lookup</span> x euclidean</code></pre>
<p>Here, we define a data type <code>Rom</code> to represent Romanian cities, define an initial state and a goal function, set up a couple of data structures to record city-to-city road distances and Euclidean distances of cities from Bucharest (our goal), then define <code>Rom</code> as an instance of the type class <code>SearchState</code> which includes code to find the possible actions we can take from any state (i.e. the cities we can travel to directly from a given city) and the costs (i.e. distance) associated with going from one state to another. Finally, we define a heuristic, which just returns the Euclidean distance from a given city to the goal city. Given that definition, I wanted to be able to type something like</p>
<pre class="sourceCode"><code class="sourceCode haskell">astar initial goal heuristic</code></pre>
<p>to run an A* search for the goal state, starting at the initial state and using the given heuristic. We might also want to look at <code>astar initial goal (const 0)</code> to do a uniform cost search. I’d like to both get a result and a count of the number of search tree nodes expanded (which will allow me to see how much of a difference different heuristics make to the efficiency of the search).</p>
<h2 id="a-implementation">A* implementation</h2>
<p>To make this work, the <code>AStar</code> module is defined as follows. It’s basically one type class, some supporting scaffolding, and the <code>astar</code> search function. We need a few data structures to implement A* search efficiently, so we import, in particular, <code>Data.Set</code> for sets and <code>Data.PSQueue</code> for priority search queues (priority queues that also support fast membership testing):</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">AStar</span> <span class="kw">where</span><br /><br /><span class="kw">import</span> <span class="dt">Data.Maybe</span><br /><span class="kw">import</span> <span class="dt">Data.List</span><br /><span class="kw">import</span> <span class="dt">Data.Ord</span><br /><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Set</span> <span class="kw">as</span> <span class="dt">S</span><br /><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.PSQueue</span> <span class="kw">as</span> <span class="dt">PS</span><br /><span class="kw">import</span> <span class="dt">Debug.Trace</span></code></pre>
<p>The <code>SearchState</code> type class is defined as:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">class</span> <span class="dt">SearchState</span> a <span class="kw">where</span><br /><span class="ot">  actions </span><span class="ot">::</span> a <span class="ot">-&gt;</span> [a <span class="ot">-&gt;</span> a]<br /><span class="ot">  pathCost </span><span class="ot">::</span> [a] <span class="ot">-&gt;</span> <span class="dt">Int</span><br /><span class="ot">  stepCost </span><span class="ot">::</span> a <span class="ot">-&gt;</span> a <span class="ot">-&gt;</span> <span class="dt">Int</span><br />  stepCost _ _ <span class="fu">=</span> <span class="dv">1</span><br />  pathCost sts <span class="fu">=</span> <span class="fu">sum</span> <span class="fu">$</span> <span class="fu">zipWith</span> stepCost (<span class="fu">tail</span> sts) (<span class="fu">init</span> sts)</code></pre>
<p>First, for a given search state, we want to find the actions that we can perform from that state. The <code>actions</code> method of the type class does this, returning a list of functions that will transform one state to another — we can then just apply these functions to a state to get the result of any action. We also want to be able to calculate the costs of paths composed of states, either in one go, from a list of states, using <code>pathCost</code>, or step by step, which is what <code>stepCost</code> does. We define defaults for <code>stepCost</code> (each state change has a cost of 1) and <code>pathCost</code> (the cost of a path through a list of states is just the sum of the individual steps).</p>
<p>To maintain a record of the search tree, we need a node type, holding a state, possibly a parent (<code>Nothing</code> if this is the initial node) and the cost at this node. Note that states can nominally appear in multiple nodes if a state is reached via multiple paths in the search graph (in fact, in the search function below, we only keep the best path to any particular state, so at any time, at most one node is associated with any state). We make our nodes an instance of <code>Ord</code> so that we can put them into data structures that require comparison. We set things up so that the comparison is done on the <em>cost</em> of the nodes.</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">NodeInfo</span> a <span class="fu">=</span> <span class="dt">NodeInfo</span> {<span class="ot"> state </span><span class="ot">::</span> a,<br /><span class="ot">                             parent </span><span class="ot">::</span> <span class="dt">Maybe</span> (<span class="dt">NodeInfo</span> a), <br /><span class="ot">                             cost </span><span class="ot">::</span> <span class="dt">Int</span> } <span class="kw">deriving</span> (<span class="kw">Eq</span>, <span class="kw">Show</span>)<br /><br /><span class="kw">instance</span> <span class="kw">Eq</span> a <span class="ot">=&gt;</span> <span class="kw">Ord</span> (<span class="dt">NodeInfo</span> a) <span class="kw">where</span><br />  <span class="fu">compare</span> <span class="fu">=</span> comparing cost</code></pre>
<p>The main search function is a little complicated, but it has 7 main steps:</p>
<ol style="list-style-type: decimal">
<li>Initialise the search frontier with a node for the initial state (with no parent and zero cost).</li>
<li>If the goal has been reached, extract the path from the initial to the goal node from the search tree and return it, along with a count of the number of search tree nodes expanded to find the solution.</li>
<li>As long as there are nodes in the frontier, pick the lowest cost node for expansion (the frontier is represented using a priority search queue, so this minimum cost extraction is <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>O</mi><mo stretchy="false">(</mo><mi>l</mi><mi>o</mi><mi>g</mi><mi>n</mi><mo stretchy="false">)</mo></mrow></math> in time).</li>
<li>Add the node to be expanded to the “explored” set.</li>
<li>Determine the actions from the state of the node to be expanded, the result states of those actions and the costs of the possible result states (here, “cost” means the known path cost to the state of the node being expanded, plus the heuristic cost estimate for the result state).</li>
<li>Combine the existing frontier (minus the node being expanded) with the new states: any states not already in the frontier are added, and states that already exist in the frontier have their paths and costs updated if we have found a better path to the state than the one already recorded in the search tree.</li>
<li>Repeat from step 3.</li>
</ol>
<p>Here’s a Haskell implementation:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">astar </span><span class="ot">::</span> (<span class="kw">Show</span> a, <span class="kw">Eq</span> a, <span class="dt">SearchState</span> a, <span class="kw">Ord</span> a) <span class="ot">=&gt;</span> <br />         a <span class="ot">-&gt;</span> (a <span class="ot">-&gt;</span> <span class="dt">Bool</span>) <span class="ot">-&gt;</span> <span class="dt">Maybe</span> [a]<br />astar <span class="fu">init</span> goalTest <span class="fu">=</span> helper initFrontier S.empty<br />  <span class="kw">where</span> <span class="co">-- Initial frontier contains just the single initial node (no</span><br />        <span class="co">-- parent, zero cost).</span><br />        initFrontier <span class="fu">=</span> PS.singleton <span class="fu">init</span> (<span class="dt">NodeInfo</span> <span class="fu">init</span> <span class="kw">Nothing</span> <span class="dv">0</span>)<br /><br />        <span class="co">-- Tail recursive helper.</span><br />        helper fr ex<br />          <span class="fu">|</span> PS.null fr <span class="fu">=</span> <span class="kw">Nothing</span>   <span class="co">-- Fail if the frontier is empty.</span><br />          <span class="fu">|</span> <span class="fu">otherwise</span> <span class="fu">=</span> <span class="kw">if</span> (goalTest s) <br />                        <span class="kw">then</span> <span class="kw">Just</span> (<span class="fu">reverse</span> <span class="fu">$</span> res s p) <br />                        <span class="kw">else</span> helper fr'' ex'<br />            <span class="kw">where</span> <span class="co">-- Extract next state to expand and associated</span><br />                  <span class="co">-- information.  We produce trace output to show the</span><br />                  <span class="co">-- states on the frontier.</span><br />                  <span class="kw">Just</span> (s <span class="fu">PS.:-&gt;</span> ni<span class="fu">@</span>(<span class="dt">NodeInfo</span> _ p c), fr') <span class="fu">=</span><br />                    PS.minView (traceShow (PS.keys fr) fr)<br /><br />                  <span class="co">-- Add to explored set.</span><br />                  ex' <span class="fu">=</span> S.insert s ex<br /><br />                  <span class="co">-- Determine possible actions from this state and</span><br />                  <span class="co">-- resulting state, filtering out any in the</span><br />                  <span class="co">-- explored set.</span><br />                  rs <span class="fu">=</span> <span class="fu">filter</span> (\r <span class="ot">-&gt;</span> <span class="fu">not</span> (r <span class="ot">`S.member`</span> ex')) <span class="fu">$</span> <br />                       <span class="fu">map</span> (result s) (actions s)<br /><br />                  <span class="co">-- Calculate full costs of possible result states.</span><br />                  cs <span class="fu">=</span> <span class="fu">map</span> (\r <span class="ot">-&gt;</span> c <span class="fu">+</span> stepCost s r <span class="fu">+</span> heuristic r) rs<br /><br />                  <span class="co">-- Find which of the new states are already in the</span><br />                  <span class="co">-- queue.</span><br />                  exis <span class="fu">=</span> <span class="fu">map</span> (\n <span class="ot">-&gt;</span> PS.lookup n fr) rs<br /><br />                  <span class="co">-- Combine the existing states in the queue and the</span><br />                  <span class="co">-- new ones we've found.  Only ever keep one entry</span><br />                  <span class="co">-- in the queue for each state, the one with the</span><br />                  <span class="co">-- smallest cost.</span><br />                  toadd <span class="fu">=</span> catMaybes <span class="fu">$</span> <span class="fu">zipWith3</span> combine rs cs exis<br />                  combine r c <span class="kw">Nothing</span> <span class="fu">=</span> <span class="kw">Just</span> (r, <span class="dt">NodeInfo</span> r (<span class="kw">Just</span> ni) c)<br />                  combine r c (<span class="kw">Just</span> (<span class="dt">NodeInfo</span> _ _ c'))<br />                    <span class="fu">|</span> c <span class="fu">&lt;</span> c' <span class="fu">=</span> <span class="kw">Just</span> (r, <span class="dt">NodeInfo</span> r (<span class="kw">Just</span> ni) c)<br />                    <span class="fu">|</span> <span class="fu">otherwise</span> <span class="fu">=</span> <span class="kw">Nothing</span><br /><br />                  <span class="co">-- Insert new states into new frontier.</span><br />                  fr'' <span class="fu">=</span> <span class="fu">foldl</span> (\q (k, p) <span class="ot">-&gt;</span> PS.insert k p q) fr' toadd<br /><br />                  <span class="co">-- Build the result by following the parent links</span><br />                  <span class="co">-- through the search graph.</span><br />                  res n <span class="kw">Nothing</span> <span class="fu">=</span> [<span class="fu">init</span>]<br />                  res n (<span class="kw">Just</span> p) <span class="fu">=</span> n <span class="fu">:</span> res (state p) (parent p)</code></pre>
<p>This is a bit more verbose than the implementations in the <code>Data.Graph</code> module, but it works fine and is relatively efficient. Here’s what we get for the Romanian roads problem:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> astar initial goal (<span class="fu">const</span> <span class="dv">0</span>)<br />[<span class="dt">A</span>]<br />[<span class="dt">S</span>,<span class="dt">T</span>,<span class="dt">Z</span>]<br />[<span class="dt">O</span>,<span class="dt">S</span>,<span class="dt">T</span>]<br />[<span class="dt">L</span>,<span class="dt">O</span>,<span class="dt">S</span>]<br />[<span class="dt">F</span>,<span class="dt">L</span>,<span class="dt">O</span>,<span class="dt">R</span>]<br />[<span class="dt">F</span>,<span class="dt">L</span>,<span class="dt">R</span>]<br />[<span class="dt">C</span>,<span class="dt">F</span>,<span class="dt">L</span>,<span class="dt">P</span>]<br />[<span class="dt">C</span>,<span class="dt">F</span>,<span class="dt">M</span>,<span class="dt">P</span>]<br />[<span class="dt">B</span>,<span class="dt">C</span>,<span class="dt">M</span>,<span class="dt">P</span>]<br />[<span class="dt">B</span>,<span class="dt">C</span>,<span class="dt">D</span>,<span class="dt">P</span>]<br />[<span class="dt">B</span>,<span class="dt">C</span>,<span class="dt">D</span>]<br />[<span class="dt">B</span>,<span class="dt">D</span>]<br />[<span class="dt">B</span>]<br /><span class="kw">Just</span> ([<span class="dt">A</span>,<span class="dt">S</span>,<span class="dt">R</span>,<span class="dt">P</span>,<span class="dt">B</span>],<span class="dv">13</span>)<br /><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> astar initial goal heuristic<br />[<span class="dt">A</span>]<br />[<span class="dt">S</span>,<span class="dt">T</span>,<span class="dt">Z</span>]<br />[<span class="dt">F</span>,<span class="dt">O</span>,<span class="dt">R</span>,<span class="dt">T</span>,<span class="dt">Z</span>]<br />[<span class="dt">C</span>,<span class="dt">F</span>,<span class="dt">O</span>,<span class="dt">P</span>,<span class="dt">T</span>,<span class="dt">Z</span>]<br />[<span class="dt">B</span>,<span class="dt">C</span>,<span class="dt">O</span>,<span class="dt">P</span>,<span class="dt">T</span>,<span class="dt">Z</span>]<br />[<span class="dt">B</span>,<span class="dt">C</span>,<span class="dt">O</span>,<span class="dt">T</span>,<span class="dt">Z</span>]<br /><span class="kw">Just</span> ([<span class="dt">A</span>,<span class="dt">S</span>,<span class="dt">R</span>,<span class="dt">P</span>,<span class="dt">B</span>],<span class="dv">6</span>)<br /><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> </code></pre>
<p>First, we try the search using uniform cost search (i.e. a heuristic function of <code>(const 0)</code>). This gives us the right answer (as reported in the lectures), and expands 13 nodes in the search tree to find the solution. Then, using the Euclidean distance as a heuristic for the actual distance by road, we get the same answer (guaranteed since our heuristic is admissible, i.e. optimistic) by only expanding 6 search tree nodes. You can look at the order in which the nodes in the search tree are expanded and you’ll see that they correspond to the discussion in the lecture.</p>
<h2 id="homework-problem">Homework problem</h2>
<p>Let’s look at how to set up a couple of other problems. First, one of the homework problems dealt with a very simple setting: a 4 × 6 grid where we need to find a route from the top left to the bottom right moving only horizontally or vertically at each step, with a given heuristic function at each grid cell to estimate the remaining distance to the goal cell (numbers in the grid cells here show the heuristic value and the circles mark the initial and goal states):</p>
<object type="image/svg+xml" data="../../../../../tikzs/575c812e759f7f89c61afd43cef82c26.svg" width="260" height="182" style="display: block; margin-left: auto; margin-right: auto;"></object>

<p>In our framework, this problem looks like this:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">import</span> <span class="dt">AStar</span><br /><br /><span class="kw">data</span> <span class="dt">HWState</span> <span class="fu">=</span> <span class="dt">HWState</span> <span class="dt">Int</span> <span class="dt">Int</span><br />             <span class="kw">deriving</span> (<span class="kw">Eq</span>, <span class="kw">Ord</span>)<br /><br /><span class="kw">instance</span> <span class="kw">Show</span> <span class="dt">HWState</span> <span class="kw">where</span><br />  <span class="fu">show</span> (<span class="dt">HWState</span> r c) <span class="fu">=</span> (<span class="st">&quot;ABCD&quot;</span> <span class="fu">!!</span> (r<span class="fu">-</span><span class="dv">1</span>)) <span class="fu">:</span> (<span class="fu">show</span> c)<br /><br /><span class="kw">instance</span> <span class="dt">SearchState</span> <span class="dt">HWState</span> <span class="kw">where</span><br />  actions (<span class="dt">HWState</span> r c) <span class="fu">=</span><br />    <span class="fu">map</span> (<span class="fu">const</span> <span class="fu">.</span> <span class="fu">uncurry</span> <span class="dt">HWState</span>) <span class="fu">$</span><br />    <span class="fu">filter</span> valid [ (r<span class="fu">-</span><span class="dv">1</span>, c), (r<span class="fu">+</span><span class="dv">1</span>, c), (r, c<span class="fu">-</span><span class="dv">1</span>), (r, c<span class="fu">+</span><span class="dv">1</span>) ]<br />      <span class="kw">where</span> valid (r, c) <span class="fu">=</span> r <span class="fu">&gt;=</span> <span class="dv">1</span> <span class="fu">&amp;&amp;</span> r <span class="fu">&lt;=</span> <span class="dv">4</span> <span class="fu">&amp;&amp;</span> c <span class="fu">&gt;=</span> <span class="dv">1</span> <span class="fu">&amp;&amp;</span> c <span class="fu">&lt;=</span> <span class="dv">6</span><br /><br /><span class="ot">initial </span><span class="ot">::</span> <span class="dt">HWState</span><br />initial <span class="fu">=</span> <span class="dt">HWState</span> <span class="dv">1</span> <span class="dv">1</span><br /><br /><span class="ot">goal </span><span class="ot">::</span> <span class="dt">HWState</span> <span class="ot">-&gt;</span> <span class="dt">Bool</span><br />goal (<span class="dt">HWState</span> <span class="dv">4</span> <span class="dv">6</span>) <span class="fu">=</span> <span class="kw">True</span><br />goal (<span class="dt">HWState</span> _ _) <span class="fu">=</span> <span class="kw">False</span><br /><br /><span class="ot">heuristic </span><span class="ot">::</span> <span class="dt">HWState</span> <span class="ot">-&gt;</span> <span class="dt">Int</span><br />heuristic (<span class="dt">HWState</span> <span class="dv">4</span> _) <span class="fu">=</span> <span class="dv">1</span><br />heuristic (<span class="dt">HWState</span> _ <span class="dv">6</span>) <span class="fu">=</span> <span class="dv">1</span><br />heuristic (<span class="dt">HWState</span> <span class="dv">3</span> _) <span class="fu">=</span> <span class="dv">2</span><br />heuristic (<span class="dt">HWState</span> _ <span class="dv">5</span>) <span class="fu">=</span> <span class="dv">2</span><br />heuristic (<span class="dt">HWState</span> <span class="dv">2</span> _) <span class="fu">=</span> <span class="dv">3</span><br />heuristic (<span class="dt">HWState</span> _ <span class="dv">4</span>) <span class="fu">=</span> <span class="dv">3</span><br />heuristic (<span class="dt">HWState</span> _ _) <span class="fu">=</span> <span class="dv">4</span></code></pre>
<p>The problem state, defined by the <code>HWState</code> type, just gives the row and column where we are at this step, we define a <code>Show</code> instance for the state so we can see what’s going on, we define an initial state (top left) and a function to test whether a state is the goal state (easy here: are we at the bottom right?). Then we get to the meat of the code, which is an instance definition for the <code>SearchState</code> class (defined in the <code>AStar</code> module). Here, this just has a method to find out what possible actions we can take from a given state (moving to any of the adjacent cells, module edge effects). We use the default path cost definition from the <code>SearchState</code> type class. Finally, we have a function to calculate the suggested heuristic for a given state. This all works as expected (I’ve taken out the <code>traceShow</code> call, so we don’t see the states that are expanded at each step), although here the heuristic doesn’t seem to help at all:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> astar initial goal (<span class="fu">const</span> <span class="dv">0</span>)<br /><span class="kw">Just</span> ([<span class="dt">A1</span>,<span class="dt">A2</span>,<span class="dt">A3</span>,<span class="dt">A4</span>,<span class="dt">A5</span>,<span class="dt">A6</span>,<span class="dt">B6</span>,<span class="dt">C6</span>,<span class="dt">D6</span>],<span class="dv">24</span>)<br /><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> astar initial goal heuristic<br /><span class="kw">Just</span> ([<span class="dt">A1</span>,<span class="dt">A2</span>,<span class="dt">A3</span>,<span class="dt">A4</span>,<span class="dt">A5</span>,<span class="dt">A6</span>,<span class="dt">B6</span>,<span class="dt">C6</span>,<span class="dt">D6</span>],<span class="dv">24</span>)<br /><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> </code></pre>
<h2 id="sliding-blocks-puzzles">Sliding blocks puzzles</h2>
<p>Let’s try a more substantial example. The sliding blocks puzzles of the 15-Puzzle kind are a classic search problem. Things are quite a bit more complicated here than in the two previous examples. The boards for these puzzles look like this (for the 3 × 3 “8-puzzle” version on the left and the 4 × 4 “15-puzzle” version on the right):</p>
<object type="image/svg+xml" data="../../../../../tikzs/4b8630d42eab4b22fe6ec37a606a3852.svg" width="347" height="155" style="display: block; margin-left: auto; margin-right: auto;"></object>

<br>
<p>First we need some imports (we’ll use a map to help represent the board state, and we’ll need some random numbers to generate scrambled initial board states).</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">import</span> <span class="dt">Prelude</span> <span class="kw">hiding</span> (<span class="kw">Left</span>, <span class="kw">Right</span>)<br /><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Map</span> <span class="kw">as</span> <span class="dt">M</span><br /><span class="kw">import</span> <span class="dt">System.Random</span><br /><br /><span class="kw">import</span> <span class="dt">AStar</span></code></pre>
<p>Next, we define our board state. We need to know how big the board is (typically, we’ll consider the 3 × 3 “8-puzzle” and the 4 × 4 “15-puzzle”), and what tiles are in each position, which we represent as a map from a <code>(row, column)</code> tuple to an integer tile value. For convenience, we also record the row and column where the blank is.</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">type</span> <span class="dt">Board</span> <span class="fu">=</span> <span class="dt">M.Map</span> (<span class="dt">Int</span>, <span class="dt">Int</span>) <span class="dt">Int</span><br /><span class="kw">data</span> <span class="dt">BoardState</span> <span class="fu">=</span> <span class="dt">BoardState</span> {<span class="ot"> size </span><span class="ot">::</span> <span class="dt">Int</span>,<br /><span class="ot">                               board </span><span class="ot">::</span> <span class="dt">Board</span>,<br /><span class="ot">                               bpos </span><span class="ot">::</span> (<span class="dt">Int</span>, <span class="dt">Int</span>) } <span class="kw">deriving</span> (<span class="kw">Eq</span>, <span class="kw">Ord</span>)</code></pre>
<p>We often need to generate the list of all coordinate pairs for the board, so let’s have a helper function that does that for a given board size.</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">coords </span><span class="ot">::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> [(<span class="dt">Int</span>, <span class="dt">Int</span>)]<br />coords n <span class="fu">=</span> [(r, c) <span class="fu">|</span> r <span class="ot">&lt;-</span> [<span class="dv">1</span><span class="fu">..</span>n], c <span class="ot">&lt;-</span> [<span class="dv">1</span><span class="fu">..</span>n]]</code></pre>
<p>Moves in these puzzles are most easily thought of in terms of moving the blank, rather than moving a tile. Any single move just moves the blank by one square, either up, down, left or right. Here, if we try to apply an invalid move to a board state (e.g. moving the blank off the left hand side of the board), we define the result to be an unchanged board. This is convenient when we come to generate scrambled boards, but it’s not a problem in the A* search, since we will never try to apply invalid moves.</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">MoveDir</span> <span class="fu">=</span> <span class="dt">Up</span> <span class="fu">|</span> <span class="dt">Down</span> <span class="fu">|</span> <span class="kw">Left</span> <span class="fu">|</span> <span class="kw">Right</span><br /><br /><span class="ot">move </span><span class="ot">::</span> <span class="dt">MoveDir</span> <span class="ot">-&gt;</span> <span class="dt">BoardState</span> <span class="ot">-&gt;</span> <span class="dt">BoardState</span><br />move dir (<span class="dt">BoardState</span> n m bpos<span class="fu">@</span>(brow, bcol)) <span class="fu">=</span> <span class="dt">BoardState</span> n m'' bpos'<br />  <span class="kw">where</span> m'' <span class="fu">=</span> M.insert bpos' <span class="dv">0</span> m'<br />        m' <span class="fu">=</span> M.insert bpos (m <span class="fu">M.!</span> bpos') m<br />        bpos' <span class="fu">=</span> moveBlank dir<br />        moveBlank <span class="dt">Up</span> <span class="fu">=</span> <span class="kw">if</span> (brow <span class="fu">&gt;</span> <span class="dv">1</span>) <span class="kw">then</span> (brow<span class="fu">-</span><span class="dv">1</span>, bcol) <span class="kw">else</span> (brow, bcol)<br />        moveBlank <span class="dt">Down</span> <span class="fu">=</span> <span class="kw">if</span> (brow <span class="fu">&lt;</span> n) <span class="kw">then</span> (brow<span class="fu">+</span><span class="dv">1</span>, bcol) <span class="kw">else</span> (brow, bcol)<br />        moveBlank <span class="kw">Left</span> <span class="fu">=</span> <span class="kw">if</span> (bcol <span class="fu">&gt;</span> <span class="dv">1</span>) <span class="kw">then</span> (brow, bcol<span class="fu">-</span><span class="dv">1</span>) <span class="kw">else</span> (brow, bcol)<br />        moveBlank <span class="kw">Right</span> <span class="fu">=</span> <span class="kw">if</span> (bcol <span class="fu">&lt;</span> n) <span class="kw">then</span> (brow, bcol<span class="fu">+</span><span class="dv">1</span>) <span class="kw">else</span> (brow, bcol)</code></pre>
<p>We add a <code>Show</code> instance for the board state so that we can see what’s going on.</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">instance</span> <span class="kw">Show</span> <span class="dt">BoardState</span> <span class="kw">where</span><br />  <span class="fu">show</span> (<span class="dt">BoardState</span> n m _) <span class="fu">=</span> <br />    <span class="fu">unlines</span> <span class="fu">$</span> <span class="fu">map</span> <span class="fu">concat</span> <span class="fu">$</span> chunks n <span class="fu">$</span> <span class="fu">map</span> (format <span class="fu">.</span> (m <span class="fu">M.!</span>)) (coords n)<br />      <span class="kw">where</span> format x<br />              <span class="fu">|</span> x <span class="fu">==</span> <span class="dv">0</span> <span class="fu">=</span> <span class="st">&quot; XX&quot;</span><br />              <span class="fu">|</span> <span class="dv">1</span> <span class="fu">&lt;=</span> x <span class="fu">&amp;&amp;</span> x <span class="fu">&lt;=</span> <span class="dv">9</span> <span class="fu">=</span> <span class="st">&quot;  &quot;</span> <span class="fu">++</span> <span class="fu">show</span> x<br />              <span class="fu">|</span> <span class="fu">otherwise</span> <span class="fu">=</span> <span class="st">&quot; &quot;</span> <span class="fu">++</span> <span class="fu">show</span> x<br />            chunks _ [] <span class="fu">=</span> []<br />            chunks n xs <span class="fu">=</span> (<span class="fu">take</span> n xs) <span class="fu">:</span> chunks n (<span class="fu">drop</span> n xs)</code></pre>
<p>Then, the <code>SearchState</code> instance is a bit of an anticlimax, since all we need to do is to generate the possible valid moves given a board state. We use the default implementation of path costs from <code>SearchState</code>, with each moving having the same cost.</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">instance</span> <span class="dt">SearchState</span> <span class="dt">BoardState</span> <span class="kw">where</span><br />  actions (<span class="dt">BoardState</span> n m (brow, bcol)) <span class="fu">=</span> <span class="fu">map</span> move (lr <span class="fu">++</span> ud)<br />    <span class="kw">where</span> lr<br />            <span class="fu">|</span> bcol <span class="fu">==</span> <span class="dv">1</span> <span class="fu">=</span> [<span class="kw">Right</span>]<br />            <span class="fu">|</span> bcol <span class="fu">==</span> n <span class="fu">=</span> [<span class="kw">Left</span>]<br />            <span class="fu">|</span> <span class="fu">otherwise</span> <span class="fu">=</span> [<span class="kw">Left</span>, <span class="kw">Right</span>]<br />          ud<br />            <span class="fu">|</span> brow <span class="fu">==</span> <span class="dv">1</span> <span class="fu">=</span> [<span class="dt">Down</span>]<br />            <span class="fu">|</span> brow <span class="fu">==</span> n <span class="fu">=</span> [<span class="dt">Up</span>]<br />            <span class="fu">|</span> <span class="fu">otherwise</span> <span class="fu">=</span> [<span class="dt">Up</span>, <span class="dt">Down</span>]</code></pre>
<p>The “initial” state (we’ll actually start our searches from a scrambled state derived from this):</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">initial </span><span class="ot">::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">BoardState</span><br />initial n <span class="fu">=</span> <span class="dt">BoardState</span> n <br />            (M.fromList <span class="fu">$</span> <span class="fu">zip</span> (coords n) ([<span class="dv">1</span><span class="fu">..</span>n<span class="fu">^</span><span class="dv">2</span><span class="fu">-</span><span class="dv">1</span>] <span class="fu">++</span> [<span class="dv">0</span>])) (n, n)</code></pre>
<p>and the goal state is the same:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">goal </span><span class="ot">::</span> <span class="dt">BoardState</span> <span class="ot">-&gt;</span> <span class="dt">Bool</span><br />goal (<span class="dt">BoardState</span> n m _) <span class="fu">=</span> <span class="fu">map</span> (m <span class="fu">M.!</span>) (coords n) <span class="fu">==</span> ([<span class="dv">1</span><span class="fu">..</span>n<span class="fu">^</span><span class="dv">2</span><span class="fu">-</span><span class="dv">1</span>] <span class="fu">++</span> [<span class="dv">0</span>])</code></pre>
<p>There are two possible heuristics that were mentioned in the lectures. The first just counts the number of tiles that are not in the correct position:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">heuristic1 </span><span class="ot">::</span> <span class="dt">BoardState</span> <span class="ot">-&gt;</span> <span class="dt">Int</span><br />heuristic1 (<span class="dt">BoardState</span> n m _) <span class="fu">=</span> <span class="fu">sum</span> <span class="fu">$</span> <span class="fu">zipWith</span> <br />                                (\x y <span class="ot">-&gt;</span> <span class="kw">if</span> x <span class="fu">/=</span> y <span class="kw">then</span> <span class="dv">1</span> <span class="kw">else</span> <span class="dv">0</span>) <br />                                (<span class="fu">map</span> (m <span class="fu">M.!</span>) (<span class="fu">init</span> <span class="fu">$</span> coords n)) [<span class="dv">1</span><span class="fu">..</span>n<span class="fu">^</span><span class="dv">2</span><span class="fu">-</span><span class="dv">1</span>]</code></pre>
<p>The second measures the Manhattan distance of each tile from its correct position and uses the sum of these distances for all the tiles as the heuristic value:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">heuristic2 </span><span class="ot">::</span> <span class="dt">BoardState</span> <span class="ot">-&gt;</span> <span class="dt">Int</span><br />heuristic2 (<span class="dt">BoardState</span> n m _) <span class="fu">=</span> M.foldrWithKey folder <span class="dv">0</span> m<br />  <span class="kw">where</span> folder (r, c) v s <span class="fu">=</span> s <span class="fu">+</span> <span class="kw">if</span> (v <span class="fu">&gt;</span> <span class="dv">0</span>) <span class="kw">then</span> dist (r, c) (goodPos v) <span class="kw">else</span> <span class="dv">0</span><br />        dist (r1, c1) (r2, c2) <span class="fu">=</span> <span class="fu">abs</span> (r1 <span class="fu">-</span> r2) <span class="fu">+</span> <span class="fu">abs</span> (c1 <span class="fu">-</span> c2)<br />        goodPos v <span class="fu">=</span> ((v <span class="fu">-</span> <span class="dv">1</span>) <span class="ot">`div`</span> n <span class="fu">+</span> <span class="dv">1</span>, (v <span class="fu">-</span> <span class="dv">1</span>) <span class="ot">`rem`</span> n <span class="fu">+</span> <span class="dv">1</span>)</code></pre>
<p>Finally, we need to be able to generate scrambled starting states. This is most easily done by generating a random list of moves and applying them to the initial board state. Since we ignore invalid moves in the <code>move</code> function above, this all works fine.</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">scramble </span><span class="ot">::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> <span class="dt">BoardState</span> <span class="ot">-&gt;</span> <span class="dt">IO</span> <span class="dt">BoardState</span><br />scramble n b <span class="fu">=</span> <span class="kw">do</span><br />  g <span class="ot">&lt;-</span> getStdGen<br />  <span class="fu">return</span> <span class="fu">$</span> <span class="fu">foldl</span> (<span class="fu">flip</span> move) b (makeMoves g)<br />    <span class="kw">where</span> makeMoves gen <span class="fu">=</span> <span class="fu">map</span> ([<span class="dt">Up</span>, <span class="dt">Down</span>, <span class="kw">Left</span>, <span class="kw">Right</span>] <span class="fu">!!</span>) <br />                          (<span class="fu">take</span> n <span class="fu">$</span> randomRs (<span class="dv">0</span>,<span class="dv">3</span>)<span class="ot"> gen </span><span class="ot">::</span> [<span class="dt">Int</span>])</code></pre>
<p>And then everything works as you might expect:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> b0 <span class="ot">&lt;-</span> scramble <span class="dv">20</span> (initial <span class="dv">3</span>)<br /><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> b0<br />  <span class="dv">5</span>  <span class="dv">1</span> <span class="dt">XX</span><br />  <span class="dv">4</span>  <span class="dv">2</span>  <span class="dv">3</span><br />  <span class="dv">7</span>  <span class="dv">8</span>  <span class="dv">6</span><br /><br /><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> heuristic2 b0<br /><span class="dv">6</span><br /><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> astar b0 goal heuristic2<br /><span class="kw">Just</span> ([  <span class="dv">5</span>  <span class="dv">1</span> <span class="dt">XX</span><br />  <span class="dv">4</span>  <span class="dv">2</span>  <span class="dv">3</span><br />  <span class="dv">7</span>  <span class="dv">8</span>  <span class="dv">6</span><br />,  <span class="dv">5</span>  <span class="dv">1</span>  <span class="dv">3</span><br /><span class="fu">&lt;&lt;</span> <span class="fu">lines</span> skipped <span class="fu">&gt;&gt;</span><br />  <span class="dv">7</span> <span class="dt">XX</span>  <span class="dv">8</span><br />,  <span class="dv">1</span>  <span class="dv">2</span>  <span class="dv">3</span><br />  <span class="dv">4</span>  <span class="dv">5</span>  <span class="dv">6</span><br />  <span class="dv">7</span>  <span class="dv">8</span> <span class="dt">XX</span><br />],<span class="dv">54</span>)<br /><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> </code></pre>
<p>Here, we generate a scrambled state for the 8-puzzle from the initial “perfect” state by applying 20 randomly selected moves. We display the scrambled initial state, the value of the Manhattan distance heuristic for this state (which gives us some idea of how much effort we’ll have to expend to find a solution), then run the A* search using the Manhattan distance heuristic. The result is a list of states (some of the output snipped) and a count of the number of search tree nodes expanded (54, in this case).</p>
<p>In a post in a day or two, I’ll look a little at how much of a difference using heuristics really makes in this problem…</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/artificial-intelligence.html">artificial-intelligence</a></span> <span class="tag"><a href="../../../../../tags/haskell.html">haskell</a></span> <span class="tag"><a href="../../../../../tags/programming.html">programming</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/16/a-star-search/index.html</guid>
</item>
<item>
    <title>The City &amp; The City</title>
    <link>http://www.skybluetrades.net/posts/2011/10/17/the-city-and-the-city-review.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | The City &amp; The City</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2011/10/17/the-city-and-the-city-review.html">The City &amp; The City</a></div>
    <div class="postdate">October 17, 2011</div>

    <p><em>by China Miéville</em></p>
<p>Can you <em>unsee</em>? Can you <em>unhear</em>? If I ask you not to think of a tiny green rhinoceros wearing a straw hat, can you do it?</p>
<!--MORE-->

<p>No? Then you might not be welcome in Besźel, or Ul Qoma. Two cities, physically entwined, psychically distinct, located at the frontier between Europe and Asia. No-one knows how these twin cities, estranged at birth, came to be. No-one knows if there are only two. The shadowy interstitial force of Breach certainly exists in the gaps between the cities, the spaces unclaimed by the citizens of either Besźel or Ul Qoma. So why not a hidden third city? Or a fourth, a fifth? An infinity of fractally entangled citizenries, passing each other in their shared unshared streets, eyes sliding across the things that should not be seen, ears filtering out unbidden sounds from other countries?</p>
<p>And if you have the power to conjure such a place? What do you do with it? If you’re China Miéville, you use it as the setting for a police procedural, with a laundry list of well-worn tropes: we start with a murder scene, we have the mismatched cops from different jurisdictions forced to work together, we have mystery and slow unfolding. As a stylistic framework for a slow reveal of Besźel/Ul Qoma, it works well. The plot carries the process of discovery along, and Miéville has a light touch with the details of life in the conjoined cities.</p>
<p>There’s a pleasing thread of <em>restraint</em> all the way through the book. “Restraint” is not usually a word one might associate with China Miéville: he’s not one to shy away from the grotesque, the bizarre and the weird. Here though, it sometimes feels like he’s teasing himself and his readers, presenting opportunities to fly off into the wildest flights of fantasy but, at every step, adroitly turning away to a mundane explanation.</p>
<p>The only truly fantastic element in <em>The City &amp; The City</em> is the stability of Besźel and Ul Qoma, even in the face of encounters with the wider world. Given that, everything else follows logically. No angels, no demons, no hidden dimensions, no magic. Just a social contract construed under different parameters than our own.</p>
<p>Try unseeing: walk the streets of your town and tell yourself that you will not see anyone wearing red. It’s hard. But we know that unseeing is possible. We do it every day: the disadvantaged among us are easy to ignore, our eyes slide past theirs, we easily unhear their requests for help. Perhaps with training, we <em>could</em> live in Besźel. Or Ul Qoma, for that matter.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/book-reviews.html">book-reviews</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/17/the-city-and-the-city-review.html</guid>
</item>
<item>
    <title>Applied Spatial Data Analysis With R</title>
    <link>http://www.skybluetrades.net/posts/2011/10/19/applied-spatial-data-analysis-with-r.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Applied Spatial Data Analysis With R</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2011/10/19/applied-spatial-data-analysis-with-r.html">Applied Spatial Data Analysis With R</a></div>
    <div class="postdate">October 19, 2011</div>

    <p><em>by Roger S. Bivand, Edzer J. Pebesma &amp; Virgilio Gómez-Rubio</em></p>
<p>I recently had to do a bunch of geostatistical analysis on some climate data (to be specific, using universal kriging to interpolate a time series of solar radiation data covering the region I’m working on to a different grid). I started off trying to use the geostatistical analysis toolbox in ArcGIS, which works fine as far as it goes, but seems to be very difficult indeed to access via ArcGIS’s Python scripting interface. Since I had 36 years of daily data to process, doing it by hand was not an option.</p>
<!--MORE-->

<p>I did the job using R, eventually, more by trial and error than through any great process of inspiration. I’d never done much geostatistical processing with R before, although I use it quite a lot for “normal” statistics and data analysis. My little voyage through the land of R-GeoStatistica was quite an eye opener. You can really get a lot done this way. If you know what you’re doing. Which is where this excellent little book comes in.</p>
<p>Part of the <em>Use R!</em> series published by Springer, <em>Applied Spatial Data Analysis With R</em> is written by the authors of some of the main R geostatistical packages, in particular the <code>sp</code> package which is used for the representation of geostatistical data. The book is divided into two main parts, the first dealing with general issues related to the representation of spatial data, and the second part divided into three sections dealing with point data, interpolation and geostatistics, and areal data. The point data and areal data sections seem to be well done, but they’re about subjects I’m not too familiar with, and that I don’t really need to know about for my current work. I mostly just skimmed them, but they seem comprehensive and well-explained. The interpolation and geostatistics section was what I was really here to see, and it’s good.</p>
<p>If I’d had this book before I started, I could easily have saved myself a day or two of scrabbling around not quite knowing which packages to use or how to set things up. The examples in the book are realistic, comprehensive and clear, and they serve as a very good basis to build from. <em>Applied Spatial Data Analysis With R</em> is never going to be ranked among the greats of scientific literature, but that’s not its aim — its aim is to explain how to do spatial data analysis in R, and it does that perfectly. Highly recommended.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/book-reviews.html">book-reviews</a></span> <span class="tag"><a href="../../../../tags/day-job.html">day-job</a></span> <span class="tag"><a href="../../../../tags/r.html">r</a></span> <span class="tag"><a href="../../../../tags/gis.html">gis</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/19/applied-spatial-data-analysis-with-r.html</guid>
</item>
<item>
    <title>Here's Winnie!</title>
    <link>http://www.skybluetrades.net/posts/2011/10/19/heres-winnie/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Here's Winnie!</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2011/10/19/heres-winnie/index.html">Here's Winnie!</a></div>
    <div class="postdate">October 19, 2011</div>

    <div class="img-right">
<img src="winnie.jpg" alt="Winnie"></img>
</div>

<p>Winnie is a dog, probably half beagle, half something else. She lives with us now, but her life wasn’t always wall-to-wall belly rubs, salmon for breakfast and as much love as she can stand. We adopted her from the animal shelter where we work as volunteers on September 4, and for 3–4 months before that, she’d been cowering at the back of her cage, frightened even to show her little nose to the people outside.</p>
<p>We think Winnie was raised as a hunting dog, locked up in a kennel with other dogs and no humans to bond with, since she has a bad case of <a href="http://labradornet.com/kennelsyndrome.html">kennel syndrome</a>: she’s scared of more or less everything except other dogs, and now, us. Loud or just sudden noises, cars, bikes, trams, other people, big boxes (no idea why), and so on. All send her into a panic. We think that she probably wasn’t aggressive and confident enough to satisfy the assholes who had her before, so they abandoned her.</p>
<!--MORE-->

<p>To add injury to insult, when she was abandoned, her previous “family” decided that, in order to avoid any chance of being identified as the owners of a stray dog, they would remove Winnie’s ID tattoo. The tattoo was on her ear. So they cut it off. She was found wandering in the village of one of the other volunteers, covered in ticks, with an oozing fresh wound where her ear used to be. It’s all healed up now, and she just looks kind of funny, like she’s continually cocking her head to one side as if to say “Who? Me?”.</p>
<p>Anyway, Winnie is a little cutie, and adopting her has made our lives much richer, if rather dirtier and less well rested. She loves nothing better than running through the dewy meadow in the local park in the mornings, and it’s even better if there’s another crazy dog to chase. She sleeps on our bed, howls at the old lady who feeds the pigeons next to the dog park, loves kisses and crazy play, and is just starting to realise that not everything in the world of humans leads to pain and unpleasantness. She’s even learning that it can be fun to do what the funny two-leggers she lives with ask her to do.</p>
<p>If you ever feel the need for a dog in your life, head to your local shelter. You won’t regret it.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/dogs.html">dogs</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/19/heres-winnie/index.html</guid>
</item>
<item>
    <title>AI Class: Tile Puzzle Heuristics</title>
    <link>http://www.skybluetrades.net/posts/2011/10/20/tile-puzzle-search-heuristics/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | AI Class: Tile Puzzle Heuristics</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2011/10/20/tile-puzzle-search-heuristics/index.html">AI Class: Tile Puzzle Heuristics</a></div>
    <div class="postdate">October 20, 2011</div>

    <p>In an <a href="../../../../../posts/2011/10/16/a-star-search">earlier post</a>, I presented some code for solving tile puzzles using A* search. In the lectures, Peter Norvig talked about two different heuristics for these puzzles, one simply counting the number of misplaced tiles and the other giving the total Manhattan distance of all misplaced tiles to their correct positions. It’s interesting to find out how much of a difference using these heuristics really makes.</p>
<!--MORE-->


<h2 id="state-space-size">State space size</h2>
<p>First question: how many states do these problems actually have? For an <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>n</mi><mo>×</mo><mi>n</mi></mrow></math> puzzle, we generate an arbitrary state by placing <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mi>n</mi><mn>2</mn></msup><mo>-</mo><mn>1</mn></mrow></math> tiles into <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mi>n</mi><mn>2</mn></msup></mrow></math> positions, which means that there are, on the face of it, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mo stretchy="false">(</mo><msup><mi>n</mi><mn>2</mn></msup><mo stretchy="false">)</mo><mo>!</mo></mrow></math> possible states. However, states have a kind of parity, which means that the state space is partitioned into two mutually exclusive halves. Using only legal moves of the blank position in the puzzle, there are only <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mo stretchy="false">(</mo><msup><mi>n</mi><mn>2</mn></msup><mo stretchy="false">)</mo><mo>!</mo><mo>/</mo><mn>2</mn></mrow></math> positions accessible from the “perfect” initial state.</p>
<p>For a <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mn>3</mn><mo>×</mo><mn>3</mn></mrow></math> puzzle, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mo stretchy="false">(</mo><msup><mi>n</mi><mn>2</mn></msup><mo stretchy="false">)</mo><mo>!</mo><mo>/</mo><mn>2</mn><mo>=</mo><mn>181</mn><mo>,</mo><mn>440</mn></mrow></math> and for a <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mn>4</mn><mo>×</mo><mn>4</mn></mrow></math> puzzle, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mo stretchy="false">(</mo><msup><mi>n</mi><mn>2</mn></msup><mo stretchy="false">)</mo><mo>!</mo><mo>/</mo><mn>2</mn><mo>=</mo><mn>10</mn><mo>,</mo><mn>461</mn><mo>,</mo><mn>394</mn><mo>,</mo><mn>944</mn><mo>,</mo><mn>000</mn><mo>≈</mo><msup><mn>10</mn><mn>13</mn></msup></mrow></math>, which is a big number. In the <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mn>3</mn><mo>×</mo><mn>3</mn></mrow></math> case, we can just about imagine exploring a reasonable fraction of the full state space to find the solution. For the <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mn>4</mn><mo>×</mo><mn>4</mn></mrow></math> case, we have no hope of exploring more than a <em>tiny</em> fraction of the state space. The number of states that any particular algorithm needs to expand to find a solution will obviously depend on the starting state: some states are only a move or two away from the goal state, so solutions are easy to find, while others are “a long way away” in state space (whatever the metric is that we might define).</p>
<h2 id="what-we-do">What we do</h2>
<p>Here’s what we do: we generate a whole bunch of random start states, each a given number of “scrambling” moves from the perfect state. We try to solve each of those using uniform cost search (<em>Heuristic 0</em>, i.e. a heuristic of zero for all states), the misplaced tile count heuristic (which we’ll call <em>Heuristic 1</em>) and the total Manhattan distance heuristic (<em>Heuristic 2</em>). We record the number of search tree nodes that need to be explored to find a solution for each case (I set a ceiling of 10000 nodes just so I can finish a reasonable number of computations on my aging laptop). What we end up with is a set of tuples <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mo stretchy="false">(</mo><mi>n</mi><mo>,</mo><mi>s</mi><mo>,</mo><mi>h</mi><mo>,</mo><mi>c</mi><mo stretchy="false">)</mo></mrow></math>, where <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>n</mi></mrow></math> is the problem size (3 or 4), <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>s</mi></mrow></math> is the number of “scrambling” moves (between 10 and 100), <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>h</mi></mrow></math> is the heuristic (0, 1 or 2) and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>c</mi></mrow></math> is the cost, i.e. the number of nodes expanded. We can then look at plots of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>c</mi></mrow></math> for different combinations of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>n</mi></mrow></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>s</mi></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>h</mi></mrow></math>. Below, I’ll show results from all the heuristics and “scrambling distance” together, with one plot for each problem size.</p>
<h2 id="results">Results</h2>
<p>Let’s look at the <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mn>3</mn><mo>×</mo><mn>3</mn></mrow></math> case first. This plot shows the number of nodes expanded for a range of scrambling moves for all three heuristics. For each heuristic and each scrambling move count, the <a href="http://en.wikipedia.org/wiki/Box_and_whisker_plot">box-and-whisker</a> plots show the results of 1000 runs from random initial states:</p>
<div>
  <div class="img2-box">
    
<a href="puzzle-3.png"><img src="puzzle-3.png"></img></a>
</div>
  <div class="img2-box">
    
<a href="puzzle-4.png"><img src="puzzle-4.png"></img></a>
</div>
  <div class="img-spacer"></div>
</div>

<p>Note the log scale for the number of nodes expanded! Using heuristics really does seem to make a difference. And the heuristic that we choose also makes quite a difference — Heuristic 2 is appreciably better than Heuristic 1. The story is the same for the <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mn>4</mn><mo>×</mo><mn>4</mn></mrow></math> case. Here, I wasn’t patient enough to wait for all the uniform cost search results, since they take a <em>long</em> time. I’ve also limited the number of nodes expanded to 10,000, so things finish up in a sensible timeframe.</p>
<p>One thing that’s clear on these plots is that there’s a very big spread in the cost of starting from different states the same “scrambling distance” from the goal state. That’s expected: consider two states at a “scrambling distance” of 3 from the initial state, one of which consists of moving the blank left, right, left and the other left, up, left. The first state has two moves that are inverses of one another, so the resulting state is only one move from the goal state, while the second one requires three moves to get back to the goal state. So perhaps “scrambling distance” isn’t the best metric to use on the state space. What other metrics could we use? Well, we have two ready-made, in the form of the heuristics. As well as perhaps giving us a better view of the performance of the heuristics in terms of actually helping to solve the puzzles, plotting the node expansion costs as a function of the heuristic values will also show us how well the heuristics do at measuring how hard it is to solve from a given initial state. Here are results for the 8-puzzle:</p>
<div>
  <div class="img2-box">
    
<a href="puzzle-3-heur-1.png"><img src="puzzle-3-heur-1.png"></img></a>
</div>
  <div class="img2-box">
    
<a href="puzzle-3-heur-2.png"><img src="puzzle-3-heur-2.png"></img></a>
</div>
  <div class="img-spacer"></div>
</div>

<p>and the for 15-puzzle:</p>
<div>
  <div class="img2-box">
    
<a href="puzzle-4-heur-1.png"><img src="puzzle-4-heur-1.png"></img></a>
</div>
  <div class="img2-box">
    
<a href="puzzle-4-heur-2.png"><img src="puzzle-4-heur-2.png"></img></a>
</div>
  <div class="img-spacer"></div>
</div>

<p>Although the spread at the top range of the costs is artificially compressed because I terminate any solves that expand more than 10,000 nodes, it seems pretty clear from these plots that both heuristics do a reasonable job of approximating the likely solution cost for a given initial configuration of the board. Heuristic 2 divides states up more finely than Heuristic 1, and is definitely a more accurate heuristic, in terms of being less optimistic while still admissible.</p>
<h2 id="conclusions">Conclusions</h2>
<p>The conclusions are pretty clear: A* search with a good heuristic works much better on problems with realistically sized search spaces than a simple uniform cost search. We end up needing to explore a far smaller portion of search space to find solutions. The key thing here is that A* search is guaranteed to find the optimal solution, provided that the heuristic we use is optimistic. There is a partial order on admissible heuristics for a given problem, where we can produce heuristics that are more and more accurate, i.e. less and less optimistic, and thus produce a better and better assessment of how far a particular state is from the goal.</p>
<p>A couple of points about this example. First, we’re solving these tile puzzles in kind of a dumb way. We could introduce a much more structured way of thinking about permissible moves (we can think of “circulating” sets of tiles as a single move, for instance, which immediately allows us to jump around in state space in more interesting ways). Second, A* search runs out of memory sometimes. And in this problem, it runs out of memory unpredictably: given two initial states, both generated from the goal state by 50 scrambling moves, one may take only 500 node expansions to solve, the other may take more than 10,000. Given unlimited memory, A* search will find the solution eventually, but we keep hold of a lot of “junk” states in the search space that are really of no use at all. There are more sophisticated algorithms for this sort of search that can run in limited memory, by discarding some of those redundant states.</p>
<p>Anyway, the take home lesson is that heuristics are important for search!</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/artificial-intelligence.html">artificial-intelligence</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/20/tile-puzzle-search-heuristics/index.html</guid>
</item>
<item>
    <title>Friday photo #2</title>
    <link>http://www.skybluetrades.net/posts/2011/10/21/friday-photo-2/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Friday photo #2</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2011/10/21/friday-photo-2/index.html">Friday photo #2</a></div>
    <div class="postdate">October 21, 2011</div>

    <a href="wallace-island-sundown.jpg">
<div class="img-full">
<img src="wallace-island-sundown-small.jpg" alt="Wallace Island sundown"></img>
</div>
</a>
<p>Sundown on Wallace Island, Gulf Islands National Park. Thanksgiving weekend, 2009.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/photos.html">photos</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/21/friday-photo-2/index.html</guid>
</item>
<item>
    <title>Hakyll Setup</title>
    <link>http://www.skybluetrades.net/posts/2011/10/21/hakyll-setup.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Hakyll Setup</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2011/10/21/hakyll-setup.html">Hakyll Setup</a></div>
    <div class="postdate">October 21, 2011</div>

    <p>As blogging software, I use the really rather nice <a href="http://jaspervdj.be/hakyll/">Hakyll</a>, by Jasper Van der Jeugt. This is a static website generator written in Haskell, and it’s a great solution for smaller blogs or personal websites.</p>
<p>Hakyll works just fine out of the box, but the blog setup I wanted was a bit different from what I’ve seen other people do with it, so a bit of hacking was required. I wanted to share some of the things I’ve done, since they might be of interest to other Hakyllers (Hakyllites?). All the code is available on <a href="http://github.com/ian-ross/blog">Github</a>.</p>
<!--MORE-->

<p>I was going to write some sort of extensive description of what I’d done, but it makes more sense just to point at some places in the code. There are three source files, <a href="http://github.com/ian-ross/blog/blob/9f78b89921742b8090967e3d4946732593114117/bin/blog.hs">blog.hs</a> which has all the main Hakyll-required definitions, <a href="http://github.com/ian-ross/blog/blob/9f78b89921742b8090967e3d4946732593114117/bin/Overrides.hs">Overrides.hs</a> which contains definitions of some functions from the Hakyll libraries that I override, and <a href="https://github.com/ian-ross/blog/blob/9f78b89921742b8090967e3d4946732593114117/bin/TikZ.hs">TikZ.hs</a> which contains my slightly rough around the edges code for converting images represented as <a href="http://www.texample.net/tikz/">TikZ</a> code into SVG for inclusion in web pages.</p>
<p>Here are the “highlights”:</p>
<ul>
<li><a href="http://github.com/ian-ross/blog/blob/9f78b89921742b8090967e3d4946732593114117/bin/blog.hs">blog.hs</a> lines 109–115, and functions <code>makeIndexPages</code>, <code>makeIndexPage</code> and <code>indexNavLink</code>: most of the material for splitting articles across index pages, generating the index pages and the links between them. The only tricky bit here was figuring out just how to get the Hakyll metacompilation feature working right.</li>
<li><a href="http://github.com/ian-ross/blog/blob/9f78b89921742b8090967e3d4946732593114117/bin/blog.hs">blog.hs</a>, function <code>addTeaser</code>: this is used to generate the article extract that appears on the index pages, and is a slight elaboration of a <a href="http://groups.google.com/group/hakyll/browse_thread/thread/43dc235755da8347?pli=1">suggestion of Jasper’s</a>; the only nasty is fixing up the URLs for any images that appear in the teaser so that they refer to the right directory under the <code>posts</code> hierarchy.</li>
<li>various places in <a href="http://github.com/ian-ross/blog/blob/9f78b89921742b8090967e3d4946732593114117/bin/blog.hs">blog.hs</a> and <a href="http://github.com/ian-ross/blog/blob/9f78b89921742b8090967e3d4946732593114117/bin/Overrides.hs">Overrides.hs</a>: code to allow me to use a more “Wordpressy” article naming convention, i.e. <code>yyyy/mm/dd/title</code> instead of Hakyll’s default <code>yyyy-mm-dd-title.ext</code>. I like to keep image files and other resources next to the text of articles, and this helps me to do that.</li>
<li>everything in <a href="https://github.com/ian-ross/blog/blob/9f78b89921742b8090967e3d4946732593114117/bin/TikZ.hs">TikZ.hs</a>: a while ago, when I was trying to write my own blog framework in Haskell, I had the idea of using <a href="http://www.texample.net/tikz/">TikZ</a> to represent inline images in articles, and I cobbled up something to render TikZ code into SVG for embedding. It seemed like a good idea at the time, but I’m now undecided about it, mostly because I’ve not yet been able to get SVG font styling working properly. Getting the size of SVGs right in Chrome turns out to be a bit of a headache too. Still, the code is there: it uses <code>htlatex</code> to do the conversion, and it seems to work.</li>
</ul>
<p>I’m not exactly the world’s best Haskell programmer, and some of this stuff could do with some polishing. The <code>processTikZs</code> function in <a href="https://github.com/ian-ross/blog/blob/9f78b89921742b8090967e3d4946732593114117/bin/TikZ.hs">TikZ.hs</a> in particular is a bit grim, including a use of the pattern <code>(id &amp;&amp;&amp; f) &gt;&gt;&gt; (arr (\(x, fx) -&gt; blah x fx))</code> that I seemed to find myself using often enough that it looked like there ought to be a standard combinator for it, but for which I couldn’t find one in <code>Control.Arrow</code>. It’s the first time I’ve used <a href="http://en.wikibooks.org/wiki/Haskell/Understanding_arrows">arrows</a> though, so I was just happy to end up with something that worked!</p>
<p>For what it’s worth, all the code is free for reuse.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/colophonia.html">colophonia</a></span> <span class="tag"><a href="../../../../tags/haskell.html">haskell</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/21/hakyll-setup.html</guid>
</item>
<item>
    <title>The Zen of Car Ownership</title>
    <link>http://www.skybluetrades.net/posts/2011/10/21/modulauto/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | The Zen of Car Ownership</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2011/10/21/modulauto/index.html">The Zen of Car Ownership</a></div>
    <div class="postdate">October 21, 2011</div>

    <p>“Pour avoir une voiture, sans avoir une voiture”</p>
<p><em>To have a car, without having a car</em></p>
<!--MORE-->

<br>
<div class="img-right">
<img src="modulauto.jpg"></img>
</div>

<p>Car sharing/car club schemes are pretty common in European cities, but the one here in the south of France is the best I’ve heard of. In Montpellier, it goes by the name of <a href="http://modulauto.net/">Modulauto</a>. We pay a (small) monthly fee, can book cars from a number of parking locations online, pay an hourly charge and charge per kilometre travelled. Fuel is included in the price. One location is about 5 minutes walk from our house, more or less all of them are right at tram stops, and the people who thought this out have done a really good job of locating the cars in spots where it’s easy to navigate to and from (for North American readers, this is a non-trivial accomplishment in European cities that grew up during eras when bullock-drawn carts were high technology and have road plans of a similar vintage).</p>
<p>We have an electronic card to unlock the car (only enabled when you’ve booked the car), the keys are inside, there’s a Total charge card to refuel the thing, and a very helpful call centre when things go wrong. You can book for as short or long a time as you like, and you can arrange special deals at the office in the centre of town for longer rentals over quiet periods. It’s generally more economical than renting a car for periods of less than a few days.</p>
<p>It’s actually kind of shocking that it works <em>so</em> well. Going to be a few minutes late bringing the car back? Give the office a call, and they’ll make sure you don’t pay any late charges (they’re helpful! and efficient! in <em>France</em>!). Had to refuel somewhere other than Total? Just drop the receipt into the office and you’ll get a refund on your account in a few days.</p>
<p>More or less every time we use the system, we comment about how good it is. I am regularly left reeling by the futuristic efficiency of it all. We may not have teleporters and robot servants yet, but we <em>can</em> have cars without having cars!</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/montpellier.html">montpellier</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/21/modulauto/index.html</guid>
</item>
<item>
    <title>AI Class: Bayes Networks</title>
    <link>http://www.skybluetrades.net/posts/2011/10/23/bayes-networks/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | AI Class: Bayes Networks</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2011/10/23/bayes-networks/index.html">AI Class: Bayes Networks</a></div>
    <div class="postdate">October 23, 2011</div>

    <p>The second week of the online <a href="http://www.ai-class.com/">Stanford AI class</a> was about probability, reasoning when there is uncertainty and, more specifically <a href="http://en.wikipedia.org/wiki/Bayesian_network">Bayes networks</a>. I don’t much want to talk about the theory behind these things here since that’s covered in a lot of detail on the linked Wikipedia page, in the lectures and in <a href="http://aima.cs.berkeley.edu/">AIMA</a>.</p>
<p>Instead, I want to present a mildly amusing, although not very efficient, Haskell implementation of Bayes networks. It’s often said that if you know the full joint probability distribution function (PDF) for a system, you can calculate any marginal or conditional probabilities you want. Well, Haskell is a functional programming language, a PDF is a <em>function</em>, so can we represent the PDF explicitly and use it for calculating? The answer, of course, is yes.</p>
<!--MORE-->

<p>The idea here is to implement something that will allow us to write the two-test cancer problem from the lectures as:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">import</span> <span class="dt">BayesNet</span><br /><br /><span class="kw">data</span> <span class="dt">Event</span> <span class="fu">=</span> <span class="dt">C</span> <span class="fu">|</span> <span class="dt">T1</span> <span class="fu">|</span> <span class="dt">T2</span> <span class="kw">deriving</span> (<span class="kw">Eq</span>, <span class="kw">Ord</span>, <span class="kw">Show</span>)<br /><br />bn <span class="fu">=</span> fromList [(<span class="dt">C</span>, [], [<span class="dv">0</span><span class="fu">.</span><span class="dv">01</span>]),<br />               (<span class="dt">T1</span>, [<span class="dt">C</span>], [<span class="dv">0</span><span class="fu">.</span><span class="dv">9</span>,<span class="dv">0</span><span class="fu">.</span><span class="dv">2</span>]),<br />               (<span class="dt">T2</span>, [<span class="dt">C</span>], [<span class="dv">0</span><span class="fu">.</span><span class="dv">9</span>,<span class="dv">0</span><span class="fu">.</span><span class="dv">2</span>])]</code></pre>
<p>where the entries in the list passed to the <code>BayesNet.fromList</code> function are triples giving the label for a node in the network, a list of other nodes that it is conditional on (i.e. nodes at the other end of incoming edges) and the probability table for the node. If a node <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>A</mi></mrow></math> is conditional on nodes <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>B</mi></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>C</mi></mrow></math>, the probability table entries are stored in the order <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">∣</mo><mo>+</mo><mi>B</mi><mo>,</mo><mo>+</mo><mi>C</mi><mo stretchy="false">)</mo></mrow></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">∣</mo><mo>+</mo><mi>B</mi><mo>,</mo><mo>-</mo><mi>C</mi><mo stretchy="false">)</mo></mrow></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">∣</mo><mo>-</mo><mi>B</mi><mo>,</mo><mo>+</mo><mi>C</mi><mo stretchy="false">)</mo></mrow></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">∣</mo><mo>-</mo><mi>B</mi><mo>,</mo><mo>-</mo><mi>C</mi><mo stretchy="false">)</mo></mrow></math>. Given this definition, we can then calculate <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>C</mi><mo stretchy="false">∣</mo><mi>T</mi><mn>1</mn><mo>,</mo><mi>T</mi><mn>2</mn><mo stretchy="false">)</mo></mrow></math> as</p>
<pre class="sourceCode"><code class="sourceCode haskell">p_3_20 <span class="fu">=</span> prob bn <span class="dt">C</span> [(<span class="dt">T1</span>,<span class="kw">True</span>),(<span class="dt">T2</span>,<span class="kw">True</span>)]</code></pre>
<p>and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>C</mi><mo stretchy="false">∣</mo><mi>T</mi><mn>1</mn><mo>,</mo><mo>¬</mo><mi>T</mi><mn>2</mn><mo stretchy="false">)</mo></mrow></math> as</p>
<pre class="sourceCode"><code class="sourceCode haskell">p_3_21 <span class="fu">=</span> prob bn <span class="dt">C</span> [(<span class="dt">T1</span>,<span class="kw">True</span>),(<span class="dt">T2</span>,<span class="kw">False</span>)]</code></pre>
<h2 id="data-structures">Data structures</h2>
<p>A Bayesian network is basically just a directed acyclic graph with probability tables of the appropriate size associated with each node. In my Haskell code, I treat Bayesian networks as an abstract data type, exporting only a way to construct a network from a simple list-based description, and functions to calculate probability values given a network. (You can imagine lots of other possible things you might want to do, including updating networks, calculating conditional independence relationships, and so on, but here, we’re going to concentrate on the basics.)</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">module</span> <span class="dt">BayesNet</span>(fromList, prob, jointProb, jointProbTF) <span class="kw">where</span><br /><br /><span class="kw">import</span> <span class="kw">qualified</span> <span class="dt">Data.Map</span> <span class="kw">as</span> <span class="dt">M</span><br /><span class="kw">import</span> <span class="dt">Data.List</span></code></pre>
<p>The internal representation of a node in the network is as a list of nodes on which this node is conditional, and a probability table. Nodes are parameterised by type <code>e</code> (“event”) and the type of probability values is parameterised too, by type <code>p</code>, so that we can use, for instance, rational values if we want. (I’ll show an example of this later on, but basically, we just want to impose the type class constraint <code>Fractional p</code> everywhere to make sure that the probability values that get passed in are numbers with a fractional part.)</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">data</span> <span class="dt">BayesNode</span> e p <span class="fu">=</span> <span class="dt">BayesNode</span> {<span class="ot"> cond </span><span class="ot">::</span> [e],<span class="ot"> ps </span><span class="ot">::</span> [p] } <br />                   <span class="kw">deriving</span> (<span class="kw">Eq</span>, <span class="kw">Ord</span>, <span class="kw">Show</span>)</code></pre>
<p>A Bayesian network is then just a map from node labels to nodes.</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">newtype</span> <span class="dt">BayesNet</span> e p <span class="fu">=</span> <span class="dt">BayesNet</span> (<span class="dt">M.Map</span> e (<span class="dt">BayesNode</span> e p)) <br />                     <span class="kw">deriving</span> (<span class="kw">Eq</span>, <span class="kw">Ord</span>, <span class="kw">Show</span>)</code></pre>
<p>We can generate Bayesian network values from a simple list representation, which is a list of nodes of the form:</p>
<pre><code>  (event, conditions, probabilities)
</code></pre>
<p>where:</p>
<ul>
<li><code>event</code> is a label for the node (of type <code>e</code> in all the function type signatures here);</li>
<li><code>conditions</code> is a list of the events on which this event is conditional (i.e. a list of type <code>[e]</code>); and</li>
<li><code>probabilities</code> is a table of probability values, stored as a flat list. The type of these values (represented as type variable <code>p</code> everywhere) can be any fractional numeric type. The values are stored in lexical order of the truth value assignment to the conditions variables, where <code>True</code> sorts before <code>False</code>. For instance, if <code>conditions</code> is <code>[R,S]</code>, then the probability values are in the order <code>+R,+S</code>; <code>+R,-S</code>; <code>-R,+S</code>; <code>-R,-S</code>.</li>
</ul>
<p>Creating a network from its list representation is simple. The only small thing we need to do is to check that the probability table has the right number of entries, dependent on the number of conditional variables. It would be interesting to try to apply this constraint at the type level. No idea how to do that. It’s probably easy in something like Agda, with dependent types, or Qi, where you can write programs at the type level. In Haskell, I guess it might require Template Haskell. I don’t know though. In any case, let’s keep things simple here:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">fromList </span><span class="ot">::</span> (<span class="kw">Ord</span> e, <span class="kw">Fractional</span> p) <span class="ot">=&gt;</span> [(e, [e], [p])] <span class="ot">-&gt;</span> <span class="dt">BayesNet</span> e p<br />fromList <span class="fu">=</span> <span class="dt">BayesNet</span> <span class="fu">.</span> (<span class="fu">foldl</span> doOne M.empty)<br />  <span class="kw">where</span> doOne m (ev, cond, ps) <span class="fu">=</span> <br />          <span class="kw">if</span> (<span class="fu">length</span> ps <span class="fu">/=</span> <span class="dv">2</span><span class="fu">^</span>(<span class="fu">length</span> cond)) <br />          <span class="kw">then</span> <span class="fu">error</span> <span class="st">&quot;Invalid length for probability table&quot;</span><br />          <span class="kw">else</span> M.insert ev (<span class="dt">BayesNode</span> cond ps) m</code></pre>
<h2 id="probability-calculations">Probability calculations</h2>
<p>Given a Bayesian network, we want to use it to calculate probabilities. A couple of special cases, first the probability that a single event is true, given conditions (true or false) on a set of other events.</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">prob </span><span class="ot">::</span> (<span class="kw">Ord</span> e, <span class="kw">Fractional</span> p) <span class="ot">=&gt;</span> <span class="dt">BayesNet</span> e p <span class="ot">-&gt;</span> e <span class="ot">-&gt;</span> [(e,<span class="dt">Bool</span>)] <span class="ot">-&gt;</span> p<br />prob bn ev cond <span class="fu">=</span> jointProb bn [ev] cond</code></pre>
<p>Then, the joint probability that a set of events is true, given conditions (true or false) on a set of other events.</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">jointProb </span><span class="ot">::</span> (<span class="kw">Ord</span> e, <span class="kw">Fractional</span> p) <span class="ot">=&gt;</span> <span class="dt">BayesNet</span> e p <span class="ot">-&gt;</span> [e] <span class="ot">-&gt;</span> [(e,<span class="dt">Bool</span>)] <span class="ot">-&gt;</span> p<br />jointProb bn evs cond <span class="fu">=</span> jointProbTF bn (<span class="fu">zip</span> evs <span class="fu">$</span> <span class="fu">repeat</span> <span class="kw">True</span>) cond</code></pre>
<p>Then the general case: the probability that a set of events is true or false, as specified, given conditions (true or false) on a set of other events.</p>
<p>We do this by calculating the joint PDF of the whole network, then enumerating the possible assignments of truth values to the free variables in the numerator and denominator of the representation of <span class="math">$P(X | Y) = P(X ^ Y) / P(Y)$</span>, applying the joint PDF to each of these variable assignments, summing the results and forming the fraction representing the conditional probability.</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">jointProbTF </span><span class="ot">::</span> (<span class="kw">Ord</span> e, <span class="kw">Fractional</span> p) <span class="ot">=&gt;</span> <br />               <span class="dt">BayesNet</span> e p <span class="ot">-&gt;</span> [(e,<span class="dt">Bool</span>)] <span class="ot">-&gt;</span> [(e,<span class="dt">Bool</span>)] <span class="ot">-&gt;</span> p<br />jointProbTF bn<span class="fu">@</span>(<span class="dt">BayesNet</span> m) evs cond <span class="fu">=</span> eval (cond <span class="fu">++</span> evs) <span class="fu">/</span> eval cond<br />  <span class="kw">where</span> eval <span class="fu">=</span> <span class="fu">sum</span> <span class="fu">.</span> (<span class="fu">map</span> (jointPDF bn)) <span class="fu">.</span> (enumerate bn)</code></pre>
<p>All the work here is being done in the computation of the joint PDF, which represented just as a regular Haskell function, and the enumeration of the possibilities (remember that we’re only dealing with binary random variables throughout, just as in the lectures).</p>
<h2 id="the-joint-pdf">The joint PDF</h2>
<p>The joint PDF for the network</p>
<object type="image/svg+xml" data="../../../../../tikzs/8ffdeeb453f09a01964cd195bcbafc52.svg" width="105" height="105" style="display: block; margin-left: auto; margin-right: auto;"></object>

<p>is:</p>
<p><math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mo>,</mo><mi>E</mi><mo>,</mo><mi>A</mi><mo>,</mo><mi>J</mi><mo>,</mo><mi>M</mi><mo stretchy="false">)</mo><mo>=</mo><mi>P</mi><mo stretchy="false">(</mo><mi>B</mi><mo stretchy="false">)</mo><mi>P</mi><mo stretchy="false">(</mo><mi>E</mi><mo stretchy="false">)</mo><mi>P</mi><mo stretchy="false">(</mo><mi>A</mi><mo stretchy="false">∣</mo><mi>B</mi><mo>,</mo><mi>E</mi><mo stretchy="false">)</mo><mi>P</mi><mo stretchy="false">(</mo><mi>J</mi><mo stretchy="false">∣</mo><mi>A</mi><mo stretchy="false">)</mo><mi>P</mi><mo stretchy="false">(</mo><mi>M</mi><mo stretchy="false">∣</mo><mi>A</mi><mo stretchy="false">)</mo></mrow></math></p>
<p>where we have one factor per node in the network, each of which is conditioned on the variables in the nodes connected to the incoming edges. In the code below, the joint PDF is represented as a function that takes a map from node labels to Boolean values and returns a probability value. To calculate the joint PDF of the whole network, we form the product of the individual PDF factors for each node in the network, applying each of these factor functions to the input variable assignment, and forming the product.</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">jointPDF </span><span class="ot">::</span> (<span class="kw">Ord</span> e, <span class="kw">Fractional</span> p) <span class="ot">=&gt;</span> <span class="dt">BayesNet</span> e p <span class="ot">-&gt;</span> (<span class="dt">M.Map</span> e <span class="dt">Bool</span> <span class="ot">-&gt;</span> p)<br />jointPDF bn<span class="fu">@</span>(<span class="dt">BayesNet</span> m) <span class="fu">=</span> <br />  (\vals <span class="ot">-&gt;</span> <span class="fu">product</span> <span class="fu">$</span> <span class="fu">zipWith</span> (applyFactor vals) (M.keys m) factors)<br />  <span class="kw">where</span> factors <span class="fu">=</span> <span class="fu">map</span> (jointPDFFactor bn) (M.keys m)<br />        applyFactor vs k f <span class="fu">=</span> f (vs <span class="fu">M.!</span> k) (<span class="fu">map</span> (vs <span class="fu">M.!</span>) (cond <span class="fu">$</span> m <span class="fu">M.!</span> k))</code></pre>
<p>We then need to produce the constituent functions for the individual factors in the PDF. Thes functions, for a factor of the form <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>X</mi><mo stretchy="false">∣</mo><mi>Y</mi><mo stretchy="false">)</mo></mrow></math> are represented by a function that takes a single Boolean value representing the value of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>X</mi></mrow></math>, and a list of Boolean values representing the values of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>Y</mi></mrow></math>, and returns <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>X</mi><mo stretchy="false">∣</mo><mi>Y</mi><mo stretchy="false">)</mo></mrow></math>. To do this, we need to know the predecessors of the node in question in the graph of the network, we need to extract the correct value from the node’s probability table, and we need to deal with complementary probability values.</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">jointPDFFactor </span><span class="ot">::</span> (<span class="kw">Ord</span> e, <span class="kw">Fractional</span> p) <span class="ot">=&gt;</span> <br />                  <span class="dt">BayesNet</span> e p <span class="ot">-&gt;</span> e <span class="ot">-&gt;</span> (<span class="dt">Bool</span> <span class="ot">-&gt;</span> [<span class="dt">Bool</span>] <span class="ot">-&gt;</span> p)<br />jointPDFFactor bn<span class="fu">@</span>(<span class="dt">BayesNet</span> m) ev <span class="fu">=</span><br />  (\b bs <span class="ot">-&gt;</span> <span class="kw">let</span> pval <span class="fu">=</span> pvals <span class="fu">!!</span> (<span class="fu">length</span> pvals <span class="fu">-</span> idx <span class="fu">-</span> <span class="dv">1</span>)<br />                idx <span class="fu">=</span> <span class="fu">foldl</span> (\i b <span class="ot">-&gt;</span> (<span class="kw">if</span> b <span class="kw">then</span> <span class="dv">1</span> <span class="kw">else</span> <span class="dv">0</span>) <span class="fu">+</span> <span class="dv">2</span> <span class="fu">*</span> i) <span class="dv">0</span> bs<br />            <span class="kw">in</span> <span class="kw">if</span> b <span class="kw">then</span> pval <span class="kw">else</span> (<span class="dv">1</span> <span class="fu">-</span> pval))<br />  <span class="kw">where</span> pvals <span class="fu">=</span> ps (m <span class="fu">M.!</span> ev)</code></pre>
<h2 id="enumerating-cases">Enumerating cases</h2>
<p>The other element we need in order to calculate probabilities is to be able to enumerate the possible assignments of Boolean truth values to variables in the network, given that some variables may have their values fixed by the requirements of the calculation. Here, we assume that there are no extra <em>logical</em> constraints on the values that variables may take. In many more realistic problems, there may be consistency requirements that eliminate some possible assignments (see <em>The Wumpus World Revisited</em>, Section 13.6 of <a href="http://aima.cs.berkeley.edu/">AIMA</a> for a simple example where this is the case). Given that caveat, state enumeration is quite simple:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">enumerate </span><span class="ot">::</span> (<span class="kw">Ord</span> e, <span class="kw">Fractional</span> p) <span class="ot">=&gt;</span> <br />             <span class="dt">BayesNet</span> e p <span class="ot">-&gt;</span> [(e,<span class="dt">Bool</span>)] <span class="ot">-&gt;</span> [<span class="dt">M.Map</span> e <span class="dt">Bool</span>]<br />enumerate bn<span class="fu">@</span>(<span class="dt">BayesNet</span> m) fixed <span class="fu">=</span> <span class="fu">map</span> compose msks<br />  <span class="kw">where</span> base <span class="fu">=</span> M.fromList fixed<br />        vars <span class="fu">=</span> (M.keys m) \\ (<span class="fu">map</span> <span class="fu">fst</span> fixed)<br />        msks <span class="fu">=</span> masks (<span class="fu">length</span> vars)<br />        compose <span class="fu">=</span> (M.union base) <span class="fu">.</span> M.fromList <span class="fu">.</span> (<span class="fu">zip</span> vars)</code></pre>
<p>We have a little helper to generate combinations of Boolean values:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="ot">masks </span><span class="ot">::</span> <span class="dt">Int</span> <span class="ot">-&gt;</span> [[<span class="dt">Bool</span>]]<br />masks <span class="dv">0</span> <span class="fu">=</span> [[]]<br />masks <span class="dv">1</span> <span class="fu">=</span> [[<span class="kw">False</span>], [<span class="kw">True</span>]]<br />masks n <span class="fu">=</span> <span class="fu">map</span> (<span class="kw">False</span> <span class="fu">:</span>) xs' <span class="fu">++</span> <span class="fu">map</span> (<span class="kw">True</span> <span class="fu">:</span>) xs'<br />  <span class="kw">where</span> xs' <span class="fu">=</span> masks (n <span class="fu">-</span> <span class="dv">1</span>)</code></pre>
<h2 id="applications">Applications</h2>
<p>Given the definitions above, the two test cancer example works as expected. We can also deal with Sebastian’s happiness example. The necessary definition of the Bayes network is:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="kw">import</span> <span class="dt">BayesNet</span><br /><span class="kw">import</span> <span class="dt">Data.Ratio</span><br /><br /><span class="kw">data</span> <span class="dt">Event</span> <span class="fu">=</span> <span class="dt">S</span> <span class="fu">|</span> <span class="dt">R</span> <span class="fu">|</span> <span class="dt">H</span> <span class="kw">deriving</span> (<span class="kw">Eq</span>, <span class="kw">Ord</span>, <span class="kw">Show</span>)<br /><br />bn <span class="fu">=</span> fromList [(<span class="dt">S</span>, [], [<span class="dv">7</span> <span class="fu">%</span> <span class="dv">10</span>]),<br />               (<span class="dt">R</span>, [], [<span class="dv">1</span> <span class="fu">%</span> <span class="dv">100</span>]),<br />               (<span class="dt">H</span>, [<span class="dt">S</span>, <span class="dt">R</span>], [<span class="dv">1</span>, <span class="dv">7</span> <span class="fu">%</span> <span class="dv">10</span>, <span class="dv">9</span> <span class="fu">%</span> <span class="dv">10</span>, <span class="dv">1</span> <span class="fu">%</span> <span class="dv">10</span>])]</code></pre>
<p>Here, I’ve made the probability values in the Bayes network be rational numbers (remember that we can use any instance of typeclass <code>Fractional</code> for this). We can then answer some of the questions Sebastian posed in the lecture. First we load the definition into GHCi:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> <span class="fu">:</span>load <span class="st">&quot;happiness.hs&quot;</span><br />[<span class="dv">1</span> <span class="kw">of</span> <span class="dv">2</span>] <span class="dt">Compiling</span> <span class="dt">BayesNet</span>         ( BayesNet.hs, interpreted )<br />[<span class="dv">2</span> <span class="kw">of</span> <span class="dv">2</span>] <span class="dt">Compiling</span> <span class="dt">Main</span>             ( happiness<span class="fu">.</span>hs, interpreted )<br /><span class="dt">Ok</span>, modules loaded<span class="fu">:</span> <span class="dt">BayesNet</span>, <span class="dt">Main</span><span class="fu">.</span></code></pre>
<p>Then we ask the value for <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>R</mi><mo stretchy="false">∣</mo><mi>S</mi><mo stretchy="false">)</mo></mrow></math>:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> prob bn <span class="dt">R</span> [(<span class="dt">S</span>,<span class="kw">True</span>)]<br /><span class="dt">Loading</span> package array<span class="fu">-</span><span class="dv">0</span><span class="fu">.</span><span class="dv">3</span><span class="fu">.</span><span class="dv">0</span><span class="fu">.</span><span class="dv">2</span> <span class="fu">...</span> linking <span class="fu">...</span> done<span class="fu">.</span><br /><span class="dt">Loading</span> package containers<span class="fu">-</span><span class="dv">0</span><span class="fu">.</span><span class="dv">4</span><span class="fu">.</span><span class="dv">0</span><span class="fu">.</span><span class="dv">0</span> <span class="fu">...</span> linking <span class="fu">...</span> done<span class="fu">.</span><br /><span class="dv">1</span> <span class="fu">%</span> <span class="dv">100</span></code></pre>
<p>The answer is just <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>R</mi><mo stretchy="false">)</mo></mrow></math> because <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>R</mi></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>S</mi></mrow></math> are independent. Notice that we get the result as a rational here. What about <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>R</mi><mo stretchy="false">∣</mo><mi>H</mi><mo>,</mo><mi>S</mi><mo stretchy="false">)</mo></mrow></math>? Just as easy:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> prob bn <span class="dt">R</span> [(<span class="dt">H</span>,<span class="kw">True</span>),(<span class="dt">S</span>,<span class="kw">True</span>)]<br /><span class="dv">10</span> <span class="fu">%</span> <span class="dv">703</span><br /><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> <span class="fu">fromRational</span> <span class="fu">$</span> prob bn <span class="dt">R</span> [(<span class="dt">H</span>,<span class="kw">True</span>),(<span class="dt">S</span>,<span class="kw">True</span>)]<br /><span class="dv">1</span><span class="fu">.</span>422475106685633e<span class="fu">-</span><span class="dv">2</span></code></pre>
<p>Here, I’ve converted the result from a rational to a floating point for comparison with the next result, which is <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>R</mi><mo stretchy="false">∣</mo><mi>H</mi><mo stretchy="false">)</mo></mrow></math>:</p>
<pre class="sourceCode"><code class="sourceCode haskell"><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> prob bn <span class="dt">R</span> [(<span class="dt">H</span>,<span class="kw">True</span>)]<br /><span class="dv">97</span> <span class="fu">%</span> <span class="dv">5245</span><br /><span class="fu">*</span><span class="dt">Main</span><span class="fu">&gt;</span> <span class="fu">fromRational</span> <span class="fu">$</span> prob bn <span class="dt">R</span> [(<span class="dt">H</span>,<span class="kw">True</span>)]<br /><span class="dv">1</span><span class="fu">.</span>8493803622497616e<span class="fu">-</span><span class="dv">2</span></code></pre>
<p>Here, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>P</mi><mo stretchy="false">(</mo><mi>R</mi><mo stretchy="false">∣</mo><mi>H</mi><mo stretchy="false">)</mo><mo>&gt;</mo><mi>P</mi><mo stretchy="false">(</mo><mi>R</mi><mo stretchy="false">∣</mo><mi>H</mi><mo>,</mo><mi>S</mi><mo stretchy="false">)</mo></mrow></math>, demonstrating the “explaining away” effect.</p>
<p>For sure, you can do the homework questions using the same setup.</p>
<h2 id="conclusions">Conclusions</h2>
<p>This is <em>not</em> a good way to do probability calculations on Bayes networks in general. There are much better approaches available than enumeration. My goal here was more to investigate how easy it would be to construct an explicit programmatic representation of the full joint PDF of a Bayes network. Whether writing all this code to answer three homework problems is an efficient use of time, I’ll leave for the reader to decide…</p>
<p>The code is in: <a href="BayesNet.hs">BayesNet.hs</a>, <a href="cancer.hs">cancer.hs</a> and <a href="happiness.hs">happiness.hs</a>. There’s also code implementing the earthquake alarm example from the lectures in <a href="alarm.hs">alarm.hs</a>.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/artificial-intelligence.html">artificial-intelligence</a></span> <span class="tag"><a href="../../../../../tags/haskell.html">haskell</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/23/bayes-networks/index.html</guid>
</item>
<item>
    <title>Friday photo #3</title>
    <link>http://www.skybluetrades.net/posts/2011/10/28/friday-photo-3/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Friday photo #3</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2011/10/28/friday-photo-3/index.html">Friday photo #3</a></div>
    <div class="postdate">October 28, 2011</div>

    <a href="wallace-island-morning.jpg">
<div class="img-full">
<img src="wallace-island-morning-small.jpg" alt="Wallace Island morning"></img>
</div>
</a>
<p>Morning paddling preparations on Wallace Island, Gulf Islands National Park. Thanksgiving weekend, 2009.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/photos.html">photos</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/28/friday-photo-3/index.html</guid>
</item>
<item>
    <title>AI Class: Machine Learning</title>
    <link>http://www.skybluetrades.net/posts/2011/10/30/machine-learning/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | AI Class: Machine Learning</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2011/10/30/machine-learning/index.html">AI Class: Machine Learning</a></div>
    <div class="postdate">October 30, 2011</div>

    <p>Week 3 of the <a href="http://www.ai-class.com/">Stanford AI class</a> was about machine learning. This was kind of handy for me, since my <a href="http://arxiv.org/abs/0901.0537">PhD thesis</a> was mostly about applying some unsupervised learning techniques to dimensionality reduction for climate model output. That mean that I’ve read hundreds of papers about this stuff so the basic ideas and even quite a few of the details are already pretty familiar. However, most of what I’ve read has been aimed at applications in climate science and dynamical systems theory. Not much from the <em>huge</em> literature on clustering methods, for instance.</p>
<p>Sebastian very briefly mentioned some of the nonlinear dimensionality reduction methods that have been developed for unsupervised learning applications, but it was nothing more than a mention (no time for anything else). I can’t resist the temptation to dust off a little of this stuff from the archives.</p>
<!--MORE-->

<p>Sebastian mentioned two methods of nonlinear dimensionality reduction (the two most well known), locally linear embedding<sup><a href="#fn1" class="footnoteRef" id="fnref1">1</a></sup> and Isomap<sup><a href="#fn2" class="footnoteRef" id="fnref2">2</a></sup> (Isomap is one of the methods I used in my thesis<sup><a href="#fn3" class="footnoteRef" id="fnref3">3</a></sup>). There are dozens of other methods that have been developed, and I’d like to describe the characteristics of one of the more recent ones, called Hessian locally linear embedding (HLLE). As the name suggests, it has a lot in common with locally linear embedding, but it turns out to be easier to deal with from a theoretical point of view, and has some rather nice properties.</p>
<h2 id="the-basic-idea-of-hlle">The basic idea of HLLE</h2>
<p>HLLE<sup><a href="#fn4" class="footnoteRef" id="fnref4">4</a></sup> is a <em>manifold learning</em> method. That means that, given a set of data points lying in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>m</mi></mrow></math>-dimensional Euclidean space, it tries to find (an approximation to) a <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>p</mi></mrow></math>-dimensional manifold <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>M</mi><mo>⊂</mo><msup><mo>ℝ</mo><mi>m</mi></msup></mrow></math> close to which the data points lie. Such methods can be thought of as generalisations of <a href="http://en.wikipedia.org/wiki/Principal_component_analysis">principal components analysis</a> (PCA), where PCA finds <em>linear</em> subspaces, instead of curved manifolds. The Isomap method does this by trying to build a distance measure between the data points that approximates distances along paths in the data manifold. This distance measure can then be used to “unroll” the manifold using <a href="http://en.wikipedia.org/wiki/Multidimensional_scaling">multidimensional scaling</a>. Locally linear embedding works by using a numerical approximation of the Laplace-Beltrami operator on the data manifold (a generalisation of the usual Laplacian operator to manifolds). An eigenvalue decomposition of this numerical Laplace-Beltrami operator is then used to generate “coordinates” for the manifold<sup><a href="#fn5" class="footnoteRef" id="fnref5">5</a></sup>. HLLE works in a similar way, but uses a numerical approximation to the <em>Hessian</em> matrix on the manifold (actually a sort of coordinate-invariant operator built from the Hessian), which is a generalisation of the matrix of second partial derivatives in Euclidean spaces.</p>
<p>The key observation here is that the null space of this Hessian operator is closely related to the existence of nice “flat” coordinates for the data manifold, in a much better way than the null space of the Laplacian. (Lots of functions have zero Laplacian without being “simple”. Functions with zero Hessian have all second derivatives zero, so are just linear, i.e. very simple.)</p>
<p>The details are complicated, both from a theoretical point of view and for the numerical implementation. All of these manifold learning algorithms are relatively similar in form: calculate some sort of matrix (in Isomap, it’s a distance matrix, in LLE, the Laplace-Beltrami operator and in HLLE, the Hessian), then do some sort of eigenvalue decomposition or similar computation on it. The matrices tend to be large (typically <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>N</mi><mo>×</mo><mi>N</mi></mrow></math> for <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>N</mi></mrow></math> data points, hopefully reasonably sparse) which means that iterative methods are needed to solve the resulting eigenvalue problems. At the time I did this work, I was writing most of my working code in C++, so I made use of the wonderful <a href="http://trilinos.sandia.gov/">Trilinos project</a>, developed at Sandia. Lots of good stuff for dealing with complex matrix calculations, PDE discretisation problems, plus 101 other things. Check it out.</p>
<h2 id="application-to-some-test-data-sets">Application to some test data sets</h2>
<p>So, how does it work? The traditional way to test manifold learning methods is with simple geometrical data sets, like these (the gray surfaces are the data manifolds, and the coloured points data points randomly sampled from these manifolds, perhaps with some added noise):</p>
<div>
  <div class="img-box" style="width:33%;">
    
<a href="test-hole-plane.png"><img src="test-hole-plane.png" alt="Plane with hole"></img></a><br />
</div>
  <div class="img-box" style="width:33%;">
    
<a href="test-swiss-roll.png"><img src="test-swiss-roll.png" alt="Swiss roll"></img></a><br />
</div>
  <div class="img-box" style="width:33%;">
    
<a href="test-hole-swiss-roll.png"><img src="test-hole-swiss-roll.png" alt="Swiss roll with hole"></img></a><br />
</div>
  <div class="img-spacer"></div>
</div>

<p>Given the three-dimensional coordinates of the coloured points, can the HLLE algorithm discover the intrinsic two-dimensional manifolds? Yes, it can:</p>
<div>
  <div class="img-box" style="width:33%;">
    
<a href="hlle-hole-plane.png"><img src="hlle-hole-plane.png" alt="Plane with hole"></img></a><br />
</div>
  <div class="img-box" style="width:33%;">
    
<a href="hlle-swiss-roll.png"><img src="hlle-swiss-roll.png" alt="Swiss roll"></img></a><br />
</div>
  <div class="img-box" style="width:33%;">
    
<a href="hlle-hole-swiss-roll.png"><img src="hlle-hole-swiss-roll.png" alt="Swiss roll with hole"></img></a><br />
</div>
  <div class="img-spacer"></div>
</div>

<p>The important thing to note here, particularly in the third example (the “Swiss roll with hole”), is the lack of distortion in the “unrolling” of the manifolds to a two-dimensional representation. Compare the equivalent results from Isomap and from a neural-network nonlinear PCA method:</p>
<div>
  <div class="img2-box">
    
<a href="isomap-hole-swiss-roll.png"><img src="isomap-hole-swiss-roll.png" alt="HLLE"></img></a><br />
</div>
  <div class="img2-box">
    
<a href="nlpca-hole-swiss-roll.png"><img src="nlpca-hole-swiss-roll.png" alt="HLLE"></img></a><br />
</div>
  <div class="img-spacer"></div>
</div>


<h2 id="parameter-sensitivity">Parameter sensitivity</h2>
<p>I’ve not talked about the details of the HLLE algorithm at all, but in common with a lot of similar “computational differential geometry” algorithms, at one point, a neighbourhood calculation is required (specifically, for finding locally linear subspaces by doing a local singular value decomposition). The number of points to include in these neighbourhoods is a tunable parameter of the algorithm, and it’s interesting to observe the variations in the performance of the discovery of the intrinsic data manifold as the neighbourhood size is varied. The other important factor is the total number of data points, which we can easily vary by randomly subsampling our data set. The following image shows embeddings derived for the “Swiss roll with hole” with a small amount of Gaussian noise, for a range of total data point counts and neighbourhood size (click for a <em>really</em> big version):</p>
<div class="img-full">
  
<a href="hlle-sens-noise.png"><img src="hlle-sens-noise.png" alt="HLLE sensitivity"></img></a>
</div>

<p>There are some striking patterns in the images here. Good embeddings are those in the central part of the image (they look like a rainbow-hued square with a hole in the middle) and exist for some values of the neighbourhood size <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi></mrow></math> as long as we have enough data points (less than 1000 points and we don’t find good embeddings at all). When we don’t have enough data, embeddings for smaller <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi></mrow></math> are highly distorted while those for larger <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi></mrow></math> are degenerate, i.e. all data points are mapped to a single point. For intermediate values of the data point sampling density, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mn>1000</mn><mo>≤</mo><mi>N</mi><mo>≤</mo><mn>2750</mn></mrow></math>, there is a maximum <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi></mrow></math> value below which good embeddings are seen. This maximum <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi></mrow></math> value increases more or less linearly from <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi><mo>=</mo><mn>14</mn></mrow></math> when <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>N</mi><mo>=</mo><mn>1000</mn></mrow></math> to <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi><mo>=</mo><mn>46</mn></mrow></math> when <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>N</mi><mo>=</mo><mn>2750</mn></mrow></math>. As <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi></mrow></math> is increased above the threshold value, embeddings show increasing distortion and eventually become degenerate.</p>
<p>The upper limit on the value of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi></mrow></math> to get a good embedding is imposed by the requirement that the neighbourhoods should represent “locally linear” subsets of the data manifold. When <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi></mrow></math> becomes larger than the threshold seen here, the neighbourhoods start to cover regions of the data manifold that show significant curvature at the scale of the mean distance between data points. This means that the “locally linear” part of the HLLE algorithm breaks down. The maximum <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi></mrow></math> value depends on the data sampling density because the neighbourhood size grows linearly with <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi></mrow></math> but inversely with <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>N</mi></mrow></math> — the more data points there are, the closer together they lie both in the original data space and in the lower-dimensional data manifold, and a smaller fraction of the total data manifold is encompassed by any given neighbourhood size, based on a simple count of neighbours. At the lowest data point sampling densities examined here, the Hessian LLE method does not produce good embeddings for any choice of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi></mrow></math>.</p>
<p>There is also a <em>lower</em> limit for <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi></mrow></math> below which no good embeddings are seen. This limit also depends on the data sampling density. For <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>N</mi><mo>=</mo><mn>1500</mn></mrow></math>, the lowest neighbourhood size for which a good embedding is produced is <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi><mo>=</mo><mn>14</mn></mrow></math>, while for <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>N</mi><mo>=</mo><mn>4000</mn></mrow></math>, no good embeddings are seen for <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi><mo>&lt;</mo><mn>22</mn></mrow></math>. For values of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi></mrow></math> below the lower limit, the Hessian LLE procedure identifies a one-dimensional manifold, rather than the true two-dimensional data manifold. The reason for this lower neighbourhood size limit is that, for smaller values of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>k</mi></mrow></math>, the neighbourhoods essentially sample only the noise variability in the input data, and do not capture any of the structure of the data manifold. Interestingly, the hue assignments shown in the one-dimensional manifolds appearing in these results are consistent, i.e. hues vary smoothly from one end of the embedded manifold to the other. The one-dimensional manifolds recovered from the Hessian LLE procedure appear to capture at least some aspect of the intrinsic geometry of the input data, albeit very crudely.</p>
<h2 id="application-to-real-data">Application to real data</h2>
<p>So much for carefully controlled toy data sets. The parameter sensitivity plots above show how difficult it can be to interpret the results from this kind of algorithm even for simple data (are we really seeing something intrinsic in the data or is it just an artefact of the dimensionality reduction algorithm that will go away if we change the algorithm parameters?). This problem only gets worse when confronted with realistic data. The basic problem is that, for a lot of phenomena, linear methods like PCA do surprisingly well. In particular for the climate system, there are some quite deep underlying reasons why this should be so — Gerald North showed some time ago<sup><a href="#fn6" class="footnoteRef" id="fnref6">6</a></sup> that PCA actually calculates the normal modes of certain stochastically driven linear dynamical systems, which makes it a natural tool for investigating the dynamics of such systems. For certain conditions, the dynamics of the atmosphere (and to some extent, the coupled ocean-atmosphere system) can be approximated by the type of system considered by North, meaning that PCA can be a good fit. In such a situation, it’s a bit optimistic to expect your smart nonlinear method to do all that much better.</p>
<div class="img-right" style="width:40%;">
<a href="hlle-rot3.png"><img src="hlle-rot3.png" alt="ENSO: rotated HLLE component 3"></img></a>
</div>

<p>That said, these methods don’t necessarily do any <em>worse</em> than PCA for some climate applications. The plot to the right shows the results of applying HLLE to the analysis of interannual variability in tropical Pacific sea surface temperatures (SSTs). The two main modes of variability in this region are the annual cycle and the El Niño/Southern Oscillation (ENSO). PCA does a good job of picking out both these modes of variability, both in observational data and in the results of atmosphere-ocean general circulation models (GCMs). It turns out that HLLE can do the same (which is not something that’s immediately obvious, principally because the computation of the Hessian used in the HLLE algorithm is susceptible to problems because of numerical noise).</p>
<p>What the plots on the right actually show is the value of one of the components that comes out of the HLLE analysis, rotated into a coordinate frame that “unmixes” variations due solely to the annual cycle. The hope is that this procedure will pick out variability due to ENSO. In the plots, you can see an index of ENSO variability (in black, derived from mean SSTs over a specified region in the equatorial Pacific) and the rotated HLLE component time series in red, both for observational data and for four GCMs from the <a href="http://www-pcmdi.llnl.gov/ipcc/about_ipcc.php">CMIP3</a> ensemble. What’s quite interesting here is that the HLLE algorithm manages to pick out the ENSO (or ENSO-like) variability in both the observations and most of the model data sets, without any prompting. This is not a particularly shocking result, since PCA does the same, but it’s quite encouraging to see that these more complex methods are at least no worse that linear methods when such methods are appropriate.</p>
<p>There are situations where there definitely is a lower-dimensional nonlinear manifold to be discovered, and in these cases, algorithms like Isomap or HLLE can do a lot better than a linear method like PCA. You need to experiment to find out whether that really is the case though: it’s very easy to pick a method because it’s “fashionable” and demonstrate the existence of a “nonlinear” manifold that’s just as easily discovered using a linear method. The literature on nonlinear dimensionality reduction is littered with studies of this sort.</p>
<p>The take-home lesson? Data analysis is hard, and clever methods add a extra burden of understanding on top that’s not always justified.</p>
<div class="img-spacer"></div>































<div class="footnotes">
<hr></hr>
<ol>
<li id="fn1"><p>S. T. Roweis &amp; L. K. Saul (2000). Nonlinear dimensionality reduction by locally linear embedding. <em>Science</em> <strong>290</strong>(5500), 2323–2326. <a href="http://www.sciencemag.org/content/290/5500/2323.abstract">Link</a> <a href="#fnref1" class="footnoteBackLink">↩</a></p></li>
<li id="fn2"><p>J. B. Tenenbaum et al. (2000). A global geometric framework for nonlinear dimensionality reduction. <em>Science</em> <strong>290</strong>(5500), 2319–2323. <a href="http://www.sciencemag.org/content/290/5500/2319.abstract">Link</a> <a href="#fnref2" class="footnoteBackLink">↩</a></p></li>
<li id="fn3"><p>I. Ross et al. (2008). ENSO dynamics in current climate models: an investigation using nonlinear dimensionality reduction. <em>Nonlin. Processes Geophys.</em> <strong>15</strong>(2), 339–363. <a href="http://www.nonlin-processes-geophys.net/15/339/2008/npg-15-339-2008.html">Link</a> <a href="#fnref3" class="footnoteBackLink">↩</a></p></li>
<li id="fn4"><p>D. L. Donoho &amp; C. Grimes (2003). Hessian eigenmaps: Locally linear embedding techniques for high-dimensional data. <em>Proc. Natl. Acad. Sci. USA</em> <strong>100</strong>(10), 5591–5596. <a href="http://www.pnas.org/content/100/10/5591.abstract">Link</a> <a href="#fnref4" class="footnoteBackLink">↩</a></p></li>
<li id="fn5"><p>Furious hand waving going on here. There’s a better, but much more mathematical, explanation in Chapter 8 of my thesis… <a href="#fnref5" class="footnoteBackLink">↩</a></p></li>
<li id="fn6"><p>G. R. North (1984). Empirical orthogonal functions and normal modes. <em>J. Atmos. Sci.</em> <strong>41</strong>(5), 879–887. <a href="http://journals.ametsoc.org/doi/abs/10.1175/1520-0469%281984%29041%3C0879%3AEOFANM%3E2.0.CO%3B2">Link</a> <a href="#fnref6" class="footnoteBackLink">↩</a></p></li>
</ol>
</div>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/artificial-intelligence.html">artificial-intelligence</a></span> <span class="tag"><a href="../../../../../tags/phd.html">phd</a></span> <span class="tag"><a href="../../../../../tags/maths.html">maths</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/30/machine-learning/index.html</guid>
</item>
<item>
    <title>Calming Signals</title>
    <link>http://www.skybluetrades.net/posts/2011/10/31/calming-signals.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Calming Signals</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2011/10/31/calming-signals.html">Calming Signals</a></div>
    <div class="postdate">October 31, 2011</div>

    <p>What does it mean when your dog yawns at you? She’s tired? She’s bored? She’s embarrassed of your choice of socks? If you don’t know, you probably want to read Turid Rugaas’s <a href="http://www.amazon.com/Talking-Terms-Dogs-Calming-Signals/dp/1929242360/">book</a> about the body language signals that dogs use to display unease and to calm each other down.</p>
<!--MORE-->

<p>Yawning is a very clear sign that a dog wants people (and other dogs) to back off a little and give them some space, but other signs are more subtle. Next time you see a photograph of a dog, look carefully: is the dog licking its nose? That nose lick means that it was kind of uncomfortable with all the attention and the camera pointing at it. He’s not just buffing his nose up so it looks nice and shiny on the photo…</p>
<p>There are lots of other signs, many to do with body posture and placement, that can help you to interpret how your dog is feeling. Our dog, Winnie, is quite fearful because of maltreatment when she was little, so it’s very useful to be able to watch her and get some idea when she’s beginning to get outside her comfort zone, before she transitions into tail-between-the-legs-must-run-away-now mode.</p>
<p>And this body language is more or less universal between dogs of different breeds and sometimes radically different shapes and sizes. Floppy ears and docked tails both restrict the messages that dogs can get across, but they still seem to understand each other pretty well most of the time.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/dogs.html">dogs</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/10/31/calming-signals.html</guid>
</item>
<item>
    <title>Mathematics and Logic</title>
    <link>http://www.skybluetrades.net/posts/2011/11/03/mathematics-and-logic-review.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Mathematics and Logic</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2011/11/03/mathematics-and-logic-review.html">Mathematics and Logic</a></div>
    <div class="postdate">November  3, 2011</div>

    <p><em>by Mark Kac &amp; Stanislaw Ulam</em></p>
<p>This interesting little book, published in 1968, is the result of a collaboration between two of the great figures of 20th century mathematics. Although known mostly for his work on the Manhattan Project and later associated applied mathematics efforts (I first learnt of his work after being told to read about the Fermi-Pasta-Ulam problem by my PhD supervisor), Ulam began his career as a pure mathematician, working on problems in general topology. (His autobiography, <em>Adventures of a Mathematician</em>, is well worth a read.) Kac, best known for asking “Can one hear the shape of a drum?”, made major contributions to probability theory. Kac and Ulam got to know each other in Poland, then both made the move to the United States during the Second World War.</p>
<!--MORE-->
<p><em>Mathematics and Logic</em> was originally commissioned by the Encyclopedia Britannica as a sort of long-form article to appear as an appendix to the encyclopedia. It was only published separately a little later. It’s particularly interesting because here we have two truly great mathematicians trying to answer the question “What is mathematics?”, aiming at the broader scientific community, trying to give an impression of what it is that mathematicians do. Mostly, to be honest, they don’t do a great job of answering their question. The entertaining aspect of the book is that they seem to have realised right from the start that they’re not going to manage to answer the question they pose as the first sentence of the introduction, so they instead embark on a “show-and-tell” voyage through the world of mathematics. This ends up working well, and to be honest, it makes sense. If you want to learn about a new country, where do you turn first? The CIA World Factbook, or something by Paul Theroux? If you want the raw statistics, the former is handy, but if you want a feel for the place, to take in the sights, you want something a bit more picaresque.</p>
<p>What you end up with here is 105 pages of <em>examples</em> of mathematics, then around 60 pages that tries to synthesise these examples into a coherent picture of what mathematics <em>is</em>, to try to tease out the essence of the subject. It’s a hard task! The examples that Ulam and Kac use range from the very traditional (the infinity of the primes, the irrationality of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msqrt><mn>2</mn></msqrt></mrow></math>) through the more “modern” (transcendental numbers &amp; Cantor’s argument, for instance) to topics that would be identified as resolutely modern: groups and transformations; homology groups; transformations, flows and ergodicity. In all, they give a good idea of the vast range of material encompassed by the word “mathematics” at the time. This part of the book is satisfying, although one often feels the limitations of a short form like this — tell us the details, guys! We want the details!</p>
<p>The second part of the book, I find a little less satisfying. We step from the picaresque to the analytic, to try to pin down just what this subject is. There are some general trends that are easy to pick out, but there’s no clear overarching principle (probably because there just isn’t one). The trends:</p>
<p>First, a growth of rigour, rendering the subject more formal and inward-looking.</p>
<p>Then, axiomatisation: a focus on structures, rules, consequences. For example, and as a possible indicator of one path by which new mathematics can arise, consider the field axioms, originally for real numbers, and think about how one might apply these axioms to continuous functions with convolution as the composition rule. Same axioms, different structures, different consequences, and hence new things to think about.</p>
<p>Next, algebraisation, in particular of topology, an approach with enormous ramifications and many applications.</p>
<p>Then, controversially, the liberation from intuition. The very striking example that Kac and Ulam use is the fact that continuous functions differentiable at at least one point form set of first category in set of continuous functions, i.e. they are infinitesimally rare! In some sense, “most” continuous functions are like the <a href="http://en.wikipedia.org/wiki/Weierstrass_function">Weierstrass function</a>, differentiable nowhere.</p>
<p>And then we get to the end results of axiomatisation, Gödel’s incompleteness theorem, Turing’s work on computability and an apparent crisis in the fundamentals of the subject. (Of course, the “crisis” wasn’t too critical: Gödel’s work didn’t much difference for most working mathematicians.)</p>
<p>There’s some material about the relationships between computers and mathematics (still only nascent in the 1960s) and relations with other disciplines.</p>
<p>And then we end. Does the book answer the original question? Not as such. It <em>shows</em> the answer, but this might be the only thing that it’s <em>possible</em> to do. Successful in its aim or not, it’s an interesting book, and Kac and Ulam are charming guides to the territory.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/book-reviews.html">book-reviews</a></span> <span class="tag"><a href="../../../../tags/mathematics.html">mathematics</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/11/03/mathematics-and-logic-review.html</guid>
</item>
<item>
    <title>Hippo in da house...</title>
    <link>http://www.skybluetrades.net/posts/2011/11/04/hippo.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Hippo in da house...</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2011/11/04/hippo.html">Hippo in da house...</a></div>
    <div class="postdate">November  4, 2011</div>

    <p>I kept trying to tell Rita that a hippo would make a perfect pet. She didn’t believe me. But then she sent me <a href="http://www.wimp.com/hippohouse">this</a>. Point proven, I think you will agree…</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/11/04/hippo.html</guid>
</item>
<item>
    <title>AI Class: Teaching the horde...</title>
    <link>http://www.skybluetrades.net/posts/2011/11/06/teaching-the-horde.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | AI Class: Teaching the horde...</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2011/11/06/teaching-the-horde.html">AI Class: Teaching the horde...</a></div>
    <div class="postdate">November  6, 2011</div>

    <p>Week four of the Stanford Introduction to AI class was about, well, what was it about? It was a bit of a mish-mash. Some stuff about logic, some stuff about planning. Nothing I can really pin some experiments on, so I’ve been thinking a bit about the format of the course instead.</p>
<!--MORE-->

<p>I’m becoming less and less sure that the format that Peter and Sebastian have chosen for the course works well. First, the lecture format (hand written notes, done sort of live) is very susceptible to errors. This might be OK in a real live lecture, where the audience (if they’re paying attention) can help to correct mistakes, or can ask for clarification, but when the audience is disconnected and on the other end of an internet connection, it doesn’t work so well. I’m not quite sure why they elected to follow this route, since they have lecture slides prepared for the “real” Stanford course, which they could reuse with spoken narration.</p>
<p>Second, production values aren’t that great. Preparing e-learning materials is <em>hard</em> and always requires a lot more resources than expected. The impression that I get from looking at the course materials here is that some consultation with someone who’s worked on e-learning platforms before might have been a good idea.</p>
<p>Third, the “in video” quiz format works fine for quizzes, but it’s not that great for homeworks — too many errors and ambiguities. It seems as though the plan is to use the same format for the midterm and final, which seems like a recipe for disaster. I hope they manage to come up with an alternative.</p>
<p>I know that the course is very much an experiment, and I am 100% behind Sebastian’s desire to expand access to high-quality university teaching to as many people as possible. I just feel that the technical choices that they’ve made here don’t help them a lot.</p>
<p>I’ve heard from other people that the other Stanford engineering courses (machine learning and databases) are much more professionally produced and have had far fewer server issues. Perhaps that’s a result of the narrower focus and smaller student numbers, I don’t know.</p>
<p>All that said, I don’t really buy into the strand of complaining about things that appears in some threads on Reddit. My own experiences of teaching have given me a nice (post-traumatic…) appreciation of how hard it is to prepare <em>good</em> course materials and to really get through to students. And that’s when the students are right there in front of you. What Peter and Sebastian are trying to do is more than an order of magnitude more difficult. It’s rather tricky to assess in advance just how much resource you need for a project like this with open subscription, famous names, and very wide advertising. Expected enrollment of around 10,000 students; actual enrollment 160,000. See the problem?</p>
<p>I really believe in Sebastian’s mission, and if they can carry the experience they’re getting with this course forwards, I tihnk they could build something really worthwhile. I’m very happy indeed to be part of this experiment!</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/artificial-intelligence.html">artificial-intelligence</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/11/06/teaching-the-horde.html</guid>
</item>
<item>
    <title>Blowing Stuff Up!  For SCIENCE!!!</title>
    <link>http://www.skybluetrades.net/posts/2011/11/07/gallery-of-fluid-motion/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Blowing Stuff Up!  For SCIENCE!!!</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2011/11/07/gallery-of-fluid-motion/index.html">Blowing Stuff Up!  For SCIENCE!!!</a></div>
    <div class="postdate">November  7, 2011</div>

    <p><em>via the MIT Technology Review <a href="http://www.technologyreview.com/blog/arxiv/">Physics arXiv Blog</a></em></p>
<p>Everything’s better in slow-motion, right? And everything’s even more betterer in super-slow-slow-slow slow-mo, am I right? (You know I’m right.) It turns out that if you have a high-speed (10,000 fps!) camera and a pile of C4 explosive, you can make some pretty cool movies. You can read about it <a href="http://arxiv.org/abs/1110.3090">here</a>.</p>
<div class="img-full">
<img src="particle-jets.png" alt="Particle jets"></img>
</div>
<br>
<p>On a less explodey note, two other vids from this year’s Gallery are also pretty outstanding:</p>
<div>
  <div class="img2-box">
    
<img src="bouncing-balls.png" alt="Bouncing balls"></img>
<p style="text-align: center;">
<a href="http://arxiv.org/abs/1110.3989"><em>Bouncing balls on water!</em></a>
</p>
  </div>
  <div class="img2-box">
    
<img src="freezing-drop.png" alt="Freezing drop"></img>
<p style="text-align: center;">
<a href="http://arxiv.org/abs/1110.3698"><em>Freezey trees!</em></a>
</p>
  </div>
  <div class="img-spacer"></div>
<div>



<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/science.html">science</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/11/07/gallery-of-fluid-motion/index.html</guid>
</item>
<item>
    <title>In Defence Of Dogs</title>
    <link>http://www.skybluetrades.net/posts/2011/11/08/in-defence-of-dogs/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | In Defence Of Dogs</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2011/11/08/in-defence-of-dogs/index.html">In Defence Of Dogs</a></div>
    <div class="postdate">November  8, 2011</div>

    <div class="img-right">
<img src="science-dog.jpg" alt="Science dog"></img>
<p style="text-align: center;">
<em>Science Dog is tired</em>
</p>
</div>

<p><em>by John Bradshaw</em></p>
<p>Those of us who live with small furry friends have a vested interest in understanding what our beasties are thinking. They don’t talk, they won’t use SurveyMonkey, and they sometimes act like they’re not human at all, no matter how we might like to think of them as little people in dog costumes. But never fear. There is a whole industry out there that promises to help you interpret your dog’s slightest ear flick and nose twitch, that will allow you to correct all “undesirable” canine behaviours back to the acceptable human norms, that will turn you into a veritable <a href="http://en.wikipedia.org/wiki/Doctor_Dolittle">Dr. Dolittle</a>.</p>
<p>Just one little problem. Most of what you read is wrong, and quite a lot of it is harmful. Dominate your dog! Tame the wolf in your home! Show your pooch who’s boss! All complete crap, based on romantic story-telling and what makes good TV, rather than on decent science.</p>
<p>In <em>In Defence Of Dogs</em>, John Bradshaw, a researcher in canine behaviour at the University of Bristol (although he has appeared on TV, including The Colbert Report!) presents some of the recent thinking on dog behaviour, based on, of all things, scientific research.</p>
<!--MORE-->

<p>The first thing to know is that, despite being genetically near identical to wolves, dogs are not wolves from a behavioural point of view. A good parallel is the comparison between chimpanzees and bonobos: very similar genetically, completely different social organisation and behaviour. Dogs have been radically altered by the process of domestication, having been selected, albeit haphazardly, for sociability and friendliness to humans. From that perspective, basing dog training methods on the idea that dogs are wolves is just silly. What we really need is to understand what motivates dogs to act the way that they do, bearing in mind the long process of selection.</p>
<p>Second, the position of dogs in society has changed. Most dog breeds started out as working dogs, selected for features useful for herding or guarding or hunting. Dogs as companions, as pets, are a relatively recent development. That has two consequences: first, many dog breeds formerly spent most of their time with a human handler, working, rather than being cooped up in an apartment while their owner goes off to play their part in the knowledge economy; and second, behaviours useful for hunting, guarding or herding may not be so useful for life in the city. Dachshunds want to dig. Who knows? There <em>might</em> be badgers hiding under your tulips! Collies want to herd. Something, anything. No sheep available? No problem! Children are about the right size! Beagles love to run. Four hours, five hours, no trouble. Restrict your dog from following those inbuilt behaviours without providing some alternative outlet and they won’t be happy. And when your dog isn’t happy, you’re going to know about it pretty quickly. Gnawed furniture, holes in the garden, anxious barking, peeing and pooping misadventures, all are possible.</p>
<p>The third important thing to think about is how we might breed dogs that are better suited to this life. Current breeding strategies based on conformation to breed standards have led to terrible inbreeding and the production of dogs who, in many cases, just aren’t suited to life as domestic pets. Why breed for ear shape or coat colour when you could be breeding for even temperament, friendliness and calmness (or any other combination of desirable behavioural traits you might list)? Partially because it’s harder — you can tell quite quickly whether a puppy is going to grow up to be a good show dog, but it requires longer-term monitoring to track a dog’s personality. But there’s also a strong “nurture” aspect to the behaviour a dog exhibits as an adult. Managing that requires a lot more effort from breeders, and is likely to make commercial breeding economically unviable in most cases.</p>
<p>Bradshaw’s book is something of a (quiet, polite) call to arms, to try to establish better practices for dog breeding, to breed dogs that are more likely to be happy sharing their lives with us busy modern humans. His views are not universally shared in the dog training community (to put it mildly; some of these dog people can be a little catty), but what he says makes a lot of sense.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/book-reviews.html">book-reviews</a></span> <span class="tag"><a href="../../../../../tags/dogs.html">dogs</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/11/08/in-defence-of-dogs/index.html</guid>
</item>
<item>
    <title>Friday photo #4</title>
    <link>http://www.skybluetrades.net/posts/2011/11/11/friday-photo-4/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Friday photo #4</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2011/11/11/friday-photo-4/index.html">Friday photo #4</a></div>
    <div class="postdate">November 11, 2011</div>

    <a href="kairouan-great-mosque.jpg">
<div class="img-full">
<img src="kairouan-great-mosque-small.jpg" alt="Kairouan Great Mosque"></img>
</div>
</a>
<p>Great Mosque, Kairouan, Tunisia. April, 2005.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/photos.html">photos</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/11/11/friday-photo-4/index.html</guid>
</item>
<item>
    <title>Saturday Morning Linkfest</title>
    <link>http://www.skybluetrades.net/posts/2011/11/12/link-roundup.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Saturday Morning Linkfest</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2011/11/12/link-roundup.html">Saturday Morning Linkfest</a></div>
    <div class="postdate">November 12, 2011</div>

    <h4 id="haskell">Haskell</h4>
<p><a href="http://www.scs.stanford.edu/11au-cs240h/">Stanford CS240h: Functional Systems in Haskell</a> <br> Stanford is really pushing e-learning at the moment, what with the AI, machine learning and database classes that the engineering department is running. This is another good course with content available online.</p>
<p><a href="http://www.reddit.com/r/haskell/comments/lfwlv/what_does_your_company_use_haskell_for_ill_go/">Reddit: What does your company use Haskell for?</a> <br> What it says on the tin: quite a few people chime in. Seems like Haskell isn’t so much of an “academic-only” language any more!</p>
<p><a href="http://www.vex.net/~trebla/haskell/sicp.xhtml">Storage and Identification of Cabalized Packages</a> <br> Very helpful guide to GHC package management from Albert Lai.</p>
<p><a href="http://byorgey.wordpress.com/2011/11/05/wanted-ghc-feature-warn-about-unused-constraints/">Unused constraints in GHC</a> <br> This week, we spotted an interesting thing in some of the <a href="http://projects.haskell.org/diagrams/">diagrams</a> code. There are a bunch of places where an earlier implementation of a feature required certain type class constraints. With a more recent implementation, that requirement has now gone away, but the constraints remain in the code. That makes using these particular functions trickier than it needs to be. We’d like for the compiler to warn about these extra un-needed constraints, since otherwise they just hang around like a bad smell. Brent describes it as “a nice project for someone wanting to dig into hacking on GHC”…</p>
<h4 id="the-other-culture">The other culture</h4>
<p><a href="http://www.nakedcapitalism.com/2011/09/david-graeber-on-the-invention-of-money-%E2%80%93-notes-on-sex-adventure-monomaniacal-sociopathy-and-the-true-function-of-economics.html">Money</a> (<em>via Crooked Timber</em>) <br> Where does it come from? There’s a nice little Just-So story that money arose naturally out of barter economies as a natural consequence of Immutable Economic Laws. It’s thus slightly embarrassing that anthropologists haven’t found any evidence at all for barter economies of the required type. Cue immense academic pissing contest, of course. Read it all. It’s good.</p>
<h4 id="cool-stuff">Cool stuff</h4>
<p><a href="http://visual6502.org/welcome.html">Visual 6502</a> <br> Remember the 6502? Come on, no need to be shy. The <em>other</em> 8-bit processor from the 1980s. I was a Z80 boy myself, but I did a bit of 6502 assembler programming back in the day (for my A-Level computer studies project, I wrote a little data capture package for an infra-red spectrometer in our school’s chemistry lab using the A/D ports on a BBC Micro). Any other fans of retro 8-bit should take a look at this site. They’re building sub-gate-level simulations and visualisations of old microprocessors. The visualisations are very neat, but the way they’re doing it is the kicker — working directly from dies, they’re photographing them, doing some image analysis to get the patterns of the chip layers out and using these to build transistor-level models of the chips. Lots of fun!</p>
<p><a href="http://circos.ca/">Circos</a> <br> You may have seen those super sweet circular charts floating around in some biology papers in Nature or Science. This is where they’re made, and you can make them too.</p>
<p><a href="http://mainisusuallyafunction.blogspot.com/2011/10/quasicrystals-as-sums-of-waves-in-plane.html">Quasicrystal animations</a> <br> This is “Haskell” too, but it lives in “Cool stuff”.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/11/12/link-roundup.html</guid>
</item>
<item>
    <title>A project: Constraints</title>
    <link>http://www.skybluetrades.net/posts/2011/11/14/constraints-intro.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | A project: Constraints</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2011/11/14/constraints-intro.html">A project: Constraints</a></div>
    <div class="postdate">November 14, 2011</div>

    <p>I’ve recently started making some tiny contributions to Brent Yorgey’s Haskell <a href="http://projects.haskell.org/diagrams/">diagrams</a> library, mostly bug fixes. The bug fixes are primarily just a way of familiarising myself with the diagrams codebase though. I have my eye on a rather chunkier task in the open issues list. That’s writing a constraints solver for diagram layout. I’ve been interested in this sort of problem for some time, and have never had a good reason to get down to it, so I’m going to see what I can come up with.</p>
<p>And I’m going to try something I’ve not done before, which is to document experiments, design and development as blog articles. It may all turn out to be hideously embarrassing, it may end up that none of what I do actually makes it into the mainstream of the diagrams library, but having to write about what I’m doing will keep me honest, force me to be clear about what I’m doing, and will provide an incentive to work on this stuff.</p>
<!--MORE-->

<h1 id="constraints-101">Constraints 101</h1>
<p>OK, so what do we mean here when we talk about “constraints”? The word “constraint” is used in lots of ways: we have type class constraints in Haskell, people talk about constraint logic programming, in mechanics constraints are extra side-conditions on Newton’s equations of motions imposed by the structure of the problem we’re solving<sup><a href="#fn1" class="footnoteRef" id="fnref1">1</a></sup> (think bead-on-wire problems), and so on. Here, we’re talking about something closer to the last case. Given a bunch of geometrical objects (points, lines, polygons, circles, arcs, Bézier curves, whatever), we want to be able to specify <em>geometrical</em> relationships between our objects, for instance that the end-point of one line segment is coincident with the corner of a rectangle, or that a certain circle is tangent to a certain line segment.</p>
<p>Why do this? My first exposure to constraint-based drawing was through AutoDesk’s Mechanical Desktop, which was then part of the AutoCAD product suite<sup><a href="#fn2" class="footnoteRef" id="fnref2">2</a></sup>. This had a sketching tool that was just magical. Draw a very rough sketch of approximately what a component looked like, then say, “OK, this line should be horizontal, this one should be perpendicular to this one. This curve is a fillet and should be tangential to this line and this line. These two circles are concentric, these two lines are parallel. This point lies on this line, not quite sure where yet.” What you end up with is a drawing that has a smaller number of free parameters (usually the major dimensions of whatever part you’re designing). Specify those dimensions and the rest of your drawing jumps around to make everything right with the constraints you defined<sup><a href="#fn3" class="footnoteRef" id="fnref3">3</a></sup>. I was using Mechanical Desktop for work, but I got a real kick out of just playing with the constraint-based drawing tool. It really seemed like magic. Set up your drawing with some constraints, drag some points around and watch as AutoCAD updates the rest of the drawing to maintain the constraints you specified. Cute and powerful.</p>
<p>The same power can be applied to layout in the diagrams library. You might not want to go the whole hog with the complex geometric constraints available in CAD packages (although why not?), but you can certainly say things like: “These three items lie on a horizontal line; the gaps between them should be equal; I don’t know how wide the items are yet.” This is a very common situation in GUI layout and lots of GUI toolkits provide the capability to specify layout in this fashion. Since the diagrams library is intended to produce images more complex than typical GUI layout, it seems to me that something closer to the AutoCAD experience is what we want. (It will also be more fun!)</p>
<h1 id="goals">Goals</h1>
<p>Given all that spiel, how do I get from nothing to a usable constraints module for the diagrams library?</p>
<ol style="list-style-type: decimal">
<li><p>The first thing to do is probably to implement some existing constraint solver algorithms in Haskell and do some experiments. <a href="http://www.cs.washington.edu/research/constraints/cassowary/">Cassowary</a> seems like a good starting point. Other interesting possibilities are the system used in <a href="http://www.hpl.hp.com/techreports/Compaq-DEC/SRC-RR-131A.html">Juno–2</a> and <a href="http://pages.cs.wisc.edu/~gleicher/">Mike Gleicher’s</a> snap-together mathematics. This shouldn’t be too hard, and would result in a constraint solver working at the level of individual equations and inequalities for sets of real variables.</p></li>
<li><p>The diagrams library already has primitives for drawing various geometric objects, but to start with, I’d like to abstract away from that. Two reasons for this. The first is to reduce the dependence on the details of the representations used in the base diagrams library in order to get an idea of exactly what is required in the constraints system. The second reason is that there are multiple ways of looking at geometrical objects. A point can be identified by its Cartesian coordinates or by its polar coordinates. A line segment can be identified by two points or by a single point, a direction and a length. A rectangle can be identified by giving two corner points and a rotation angle, or by a single corner point, a width and height and a rotation angle. Each of these “views” of these objects is equivalent, and it should be possible to express constraints in any convenient view. For instance, I might want to constrain the centre of a circle <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>C</mi></mrow></math> to lie on the circle <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>r</mi><mo>=</mo><mn>1</mn></mrow></math>. I should be able to give a constraint <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>r</mi><mo stretchy="false">(</mo><mtext mathvariant="normal">centre</mtext><mo stretchy="false">(</mo><mi>C</mi><mo stretchy="false">)</mo><mo stretchy="false">)</mo><mo>=</mo><mn>1</mn></mrow></math> to achieve this. I have an idea of some sort of “constrainable lens” floating around in my head but it’s going to require some experimentation to pin down just how this should work, and keeping this independent from diagrams to start with should help to reduce my confusion to manageable levels. (There are some relevant thoughts about this idea of different views of geometrical objects in Mike Gleicher’s PhD thesis.)</p></li>
<li><p>The most important part of a constraint system from the user’s point of view is the interface for defining and managing constraints. The constraint that two lines are perpendicular, or that a circle is tangent to a particular line segment, can be expressed as sets of equations and/or inequalities that can be handled by a constraint solver, and we’d like a way to work at this higher level: in the most trivial case, I want to be able to say “Point <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>P</mi><mn>1</mn></msub></mrow></math> is coincident with point <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>P</mi><mn>2</mn></msub></mrow></math>”, not “<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>x</mi><mo stretchy="false">(</mo><msub><mi>P</mi><mn>1</mn></msub><mo stretchy="false">)</mo><mo>=</mo><mi>x</mi><mo stretchy="false">(</mo><msub><mi>P</mi><mn>2</mn></msub><mo stretchy="false">)</mo><mo>∧</mo><mi>y</mi><mo stretchy="false">(</mo><msub><mi>P</mi><mn>1</mn></msub><mo stretchy="false">)</mo><mo>=</mo><mi>y</mi><mo stretchy="false">(</mo><msub><mi>P</mi><mn>2</mn></msub><mo stretchy="false">)</mo></mrow></math>”. More complex geometrical constraints can be broken down and expressed as equations in similar ways. Providing an easy-to-use interface between this geometrical view of the world and the equational view required by the constraints solver will be key to making the constraint system useable. Part of that will also involve finding a good way to deal with underconstrained and overconstrained systems.</p></li>
<li><p>The last job to tackle will be taking whatever I come up with and trying to massage it into a state where it’s usable in the diagrams library. I’m going to keep this final goal in mind, but I’m not going to let it constrain what I do too much<sup><a href="#fn4" class="footnoteRef" id="fnref4">4</a></sup>. Chances are, someone else will develop something usable for diagrams before I’m too far out of the starting gate on this, and it’s mostly for my own amusement anyway…</p></li>
</ol>
<h1 id="first-things-first">First things first</h1>
<p>OK, so I’ll start with reading the Cassowary papers and will implement the relevant algorithms in Haskell to act as a baseline for experimentation. Off we go!</p>
<div class="footnotes">
<hr></hr>
<ol>
<li id="fn1"><p>For examples, see Section 1.3 of Goldstein’s <em>Classical Mechanics</em>. <a href="#fnref1" class="footnoteBackLink">↩</a></p></li>
<li id="fn2"><p>Now obsolete. Do I feel old? No way! <a href="#fnref2" class="footnoteBackLink">↩</a></p></li>
<li id="fn3"><p>In Mechanical Desktop, the dimensions were often pulled from a spreadsheet or a database so that you could, for example, draw one metric standard bolt, parameterised by the relevant dimensions, and have an M8 bolt produced from the same base drawing as an M10 bolt. More recent Autodesk and comparable products go a lot further on this front. The other day, I was reading some publicity for Autodesk Inventor, which claims to have a library of some 700,000 standard components to choose from, many of which are presumably parameterised in just this way. (I sure hope so. If not, some poor schmuck had to draw them all by hand…) <a href="#fnref3" class="footnoteBackLink">↩</a></p></li>
<li id="fn4"><p>In Mechanical Desktop, the dimensions were often pulled from a spreadsheet or a database so that you could, for example, draw one metric standard bolt, parameterised by the relevant dimensions, and have an M8 bolt produced from the same base drawing as an M10 bolt. More recent Autodesk and comparable products go a lot further on this front. The other day, I was reading some publicity for Autodesk Inventor, which claims to have a library of some 700,000 standard components to choose from, many of which are presumably parameterised in just this way. (I sure hope so. If not, some poor schmuck had to draw them all by hand…) <a href="#fnref4" class="footnoteBackLink">↩</a></p></li>
</ol>
</div>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/constraints.html">constraints</a></span> <span class="tag"><a href="../../../../tags/haskell.html">haskell</a></span> <span class="tag"><a href="../../../../tags/programming.html">programming</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/11/14/constraints-intro.html</guid>
</item>
<item>
    <title>Oh Canada...</title>
    <link>http://www.skybluetrades.net/posts/2011/11/16/missing-canada.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Oh Canada...</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2011/11/16/missing-canada.html">Oh Canada...</a></div>
    <div class="postdate">November 16, 2011</div>

    <p>I miss Canada.</p>
<p>I miss sea kayaking.</p>
<p>I miss mountain biking.</p>
<p>I miss <a href="http://www.crossfitvic.com/CrossFit_Taranis/Home.html">CrossFit Taranis</a> and all the awesome people there.</p>
<p>We moved to France. Dumbasses. We exchanged a fantastic life in Canada for what? Basically: cheese. Feel free to mock us. We deserve it.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/regrets.html">regrets</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2011/11/16/missing-canada.html</guid>
</item>
<item>
    <title>Thirty Day Challenges</title>
    <link>http://www.skybluetrades.net/posts/2012/01/01/30-day-challenge.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Thirty Day Challenges</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/01/01/30-day-challenge.html">Thirty Day Challenges</a></div>
    <div class="postdate">January  1, 2012</div>

    <p>Looking for a prod to jolt me out of an (involuntary) 45 day blogging hiatus, I’m going to follow a scheme that Rita is using quite successfully: the Thirty Day Challenge. The idea is simple. Just do that thing, whatever it is, every day for thirty days. The timescale is short enough not to be daunting, but long enough to be habit-forming. Or that’s the theory anyway.</p>
<p>I have a few things lined up, including a slew of book reviews of my holiday reading and the creakingly slow commencement of my constraints project, but we’ll see how it goes.</p>
<p>OK, one down, 29 to go. That wasn’t so hard after all!</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/colophonia.html">colophonia</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/01/30-day-challenge.html</guid>
</item>
<item>
    <title>AI Class Wrap-up</title>
    <link>http://www.skybluetrades.net/posts/2012/01/02/ai-class-wrapup.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | AI Class Wrap-up</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/01/02/ai-class-wrapup.html">AI Class Wrap-up</a></div>
    <div class="postdate">January  2, 2012</div>

    <p>One thing that came to an end over the Christmas holidays was the Stanford Artificial Intelligence course. The final exam was on the weekend of 17/18 December and final grades were distributed a couple of days later.</p>
<p>Overall, it was an interesting experience, and I certainly learnt some things. The instructors (Peter Norvig and Sebastian Thrun) were enthusiastic and clearly extremely knowledgeable, and they took on an extremely challenging task in trying to run an online class for tens of thousands of students. For that, I’m very grateful. There are a few things that weren’t 100% ideal about the presentation of the class material, but that’s to be expected the first time out with something like this.</p>
<p>The highlight of the course was definitely Sebastian’s presentation of his work on self-driving cars. I’d heard a bit about the DARPA Grand Challenge before, but I hadn’t known about the progress that the Stanford team had made with self-driving cars in traffic. That’s really impressive work, and Sebastian did a nice job of relating the algorithms used for guiding cars to the simplified versions considered in the class.</p>
<!--MORE-->

<p>This word, <em>algorithms</em>, is kind of key to what I want to talk about here. The content of the course was, to my mind, very focused on algorithms for practical applications. For instance, machine learning, planning, and perception under uncertainty were all covered in a lot of detail (particle filters are a good example). What wasn’t really covered at all was what I tend to think of when I think of “Artificial Intelligence”, which is general reasoning and problem solving.</p>
<p>All of the examples considered in the course were quite constrained, and very far from the early dreams of “intelligent machines”. This is clearly just a reflection of where the field of AI is today: there is much less emphasis on the (very hard) problems of general intelligence, and much more focus on solving practical problems. “Putting AI to work” is the name of the game. I understand why things are this way. It’s much easier to get a research grant for something with an obvious industrial application, rather than a vague programme of research that might have applications in 50 years or 100 years or just… sometime. It’s a little disappointing all the same.</p>
<p>The disappointment stems not so much from the fact that we’re thinking about practical problems (that’s a good thing!), but a feeling that most of the methods being used (probability theory, most of the machine learning algorithms) aren’t really about intelligence as such, but are just mathematical or statistical methods that are useful for some applications. That word “just” is doing a lot of work there: some of these methods are highly nontrivial and very interesting in themselves.</p>
<p>But where are our intelligent machines? You could definitely make a case that an internet search engine capable of finding relevant pages for a vaguely expressed search term is intelligent in some sense, and the same goes for a self-driving car. But you can’t engage them in conversation about what they do. They have no power of introspection. They don’t know that they’re doing what they’re doing. This is all a long way from the idea of “human level AI”.</p>
<p>Some people have expressed this sense of disappointment more strongly than I would. Here’s John McCarthy, a man who knew a thing or two about artificial intelligence, writing in 2007<sup><a href="#fn1" class="footnoteRef" id="fnref1">1</a></sup>:</p>
<blockquote>
<p>The computer science world is still suffering from a 1990s fit of pseudo-practicality that is inimical to the solution of difficult scientific problems. Lip service is given to basic research, and a lot of basic research is done, but the initiation of ambitious research by young people is hampered by the now prevalent doctrine that “basic research” should be done in connection with applied problems that have been identified by the competent committees. I think that Newell and Minsky and I would have had a much harder time initiating AI research if the atmosphere of the 1950s had been like that of the 1990s.</p>
</blockquote>
<p>So, we should still hold out for our intelligent machines! McCarthy’s paper lays out some of the requirements to get there from here. It’s a daunting list, and introspection is one of the features he highlights.</p>
<div class="footnotes">
<hr></hr>
<ol>
<li id="fn1"><p>John McCarthy (2007). From here to human-level AI. <em>Artificial Intelligence</em> <strong>171</strong>, 1174–1182. <a href="#fnref1" class="footnoteBackLink">↩</a></p></li>
</ol>
</div>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/artificial-intelligence.html">artificial-intelligence</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/02/ai-class-wrapup.html</guid>
</item>
<item>
    <title>Holiday Reading #1</title>
    <link>http://www.skybluetrades.net/posts/2012/01/03/holiday-reading-1.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Holiday Reading #1</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/01/03/holiday-reading-1.html">Holiday Reading #1</a></div>
    <div class="postdate">January  3, 2012</div>

    <p>I did a spot of reading over the Christmas and New Year holidays. In fact, reading was more or less all I did. Apart from walking the dog, spending time with Rita and eating myself silly. I read enough to write a lot of book review posts, but I’ll restrain myself to three or so… First off, spy stories.</p>
<!--MORE-->

<p>I’d never read anything by John Le Carré, having once picked up <em>Smiley’s People</em>, read the first page, not liked the tone of the narrative and so put it right down. For some reason though, Amazon insisted on recommending Le Carré’s books to me, and I was tempted to give them a go. I read <em>Tinker Tailor Soldier Spy</em> then <em>The Honourable Schoolboy</em>, which follows right on from Tinker Tailor. I still find the narrative voice uncomfortable. The off-handedness of some of the comments, the descriptions of characters, all make me think of some establishment patrician type pronouncing from his favourite chair in his Mayfair club. On reflection though, the voice makes perfect sense. Much of the action is set in Whitehall, many of the characters really are those old school tie types, and from that point of view, the voice works.</p>
<p>And anyway, maybe it’s supposed to make us feel uncomfortable. The atmosphere of Le Carré’s books is one of claustrophobia and bleakness, where no-one can truly be trusted, where betrayal and treason are the bread-and-butter of the business. Not a recipe for comfort.</p>
<p>I can’t really say that I <em>like</em> Le Carré. I understand why many do, and I see a lot of value in his depiction of the Cold War and the unlikely warriors who fought a large part of it. But still. The way that the death of Jerry Westerby at the end of <em>The Honourable Schoolboy</em> was reported gave the impression that the narrator really didn’t give a toss. Par for the course in the intelligence services? Maybe? Le Carré ought to know, having worked for both MI5 and MI6.</p>
<p>Apparently, Le Carré himself listed Tinker Tailor as being one of his four best novels. Maybe I should read the other three on his list (<em>The Spy Who Came In From The Cold</em>, <em>The Tailor Of Panama</em> and <em>The Constant Gardener</em>).</p>
<p>In a similar, although different, vein is Anthony Price’s <em>Other Paths To Glory</em>, which I read on the recommendation of Charlie Stross, who quoted it as an inspiration for some of the style of <em>The Fuller Memorandum</em>. I didn’t really know what to expect. I was wondering if the title was a reference to Kubrick’s <em>Paths Of Glory</em>, because of the First World War connection, so wasn’t quite in the mindset for a 1970s spy thriller. However, it’s a good read, and grabs hold very quickly, with an entirely unexpected bit of violence and the protagonist’s reaction to it, perhaps borne more of shock than anything else (having just been the victim of a quite professional murder attempt, he’s more worried what his mother will think of him coming in dripping wet from being in the river…). The historical detail of the battlefields of the Somme feels nicely authentic, not that I know anywhere near enough to comment on that, and the connection to the present afforded by the visit of a tour group of veterans works well. The “mystery” at the heart of the plot isn’t all that mysterious, and it’s a little surprising that none of the experts were quite aware of it before the denouement of the action.</p>
<p>My last spy novel of the holiday was a more modern one, <em>The Tourist</em> by Olen Steinhauer. Of the four books described here, this one does the best job of getting across the bleakness and moral ambiguity of the whole spy game. Milo Weaver is a “tourist” for the CIA, travelling the world on the orders of a voice on the phone and performing at best morally ambiguous tasks at the behest of his masters in New York. Burnt out and worn out, he’s back at an office job for the middle of the book, but is never quite able to leave his Tourism behind him. By the end of the novel, it’s no longer very clear who the good guys are. Or if there ever were any. The bad bad guys are picked out fairly clearly (psychopathic paedophile Russian oligarchs, anyone?), but apart from that, no-one has entirely clean hands. Weaver’s (to be honest, rather unlikely) family history eventually gets him out of a little pickle with home office, but he ends up annoying enough people that he’s demoted back to Tourist status.</p>
<p>Not a cheerful book. None of these four are. They’re all bleak and amoral (<em>The Tourist</em> perhaps even more than the others), and it’s never quite clear which side we should cheering for. In <em>The Honourable Schoolboy</em>, one character explicitly, if briefly, mentions this, commenting more or less that “Well, we are better than them, aren’t we? Our system is better, isn’t it?”. “Them” refers to global communism, in the shape of the USSR and China. The question of who are <em>we</em> and who are <em>they</em> is even more obliquely treated in <em>Other Paths To Glory</em> where it’s never clear who the “heroes” end up protecting from the “baddies”.</p>
<p>I’d like to know just how accurate, in particular, is Le Carré’s depiction of the spying life. I guess I’ll need to wait some years before records are declassified (if they ever are) so that someone can write a definitive history of the Cold War…</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/book-reviews.html">book-reviews</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/03/holiday-reading-1.html</guid>
</item>
<item>
    <title>The simplex algorithm: warm-up</title>
    <link>http://www.skybluetrades.net/posts/2012/01/04/simplex-algorithm-warm-up/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | The simplex algorithm: warm-up</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2012/01/04/simplex-algorithm-warm-up/index.html">The simplex algorithm: warm-up</a></div>
    <div class="postdate">January  4, 2012</div>

    <p>Pathetically slow in starting work on my little constraints project as I am, here’s the first of what should be a long series of posts…</p>
<p>One of the constraint solvers I’m looking at starting from, <a href="http://www.cs.washington.edu/research/constraints/cassowary/">Cassowary</a>, uses what is essentially an extended version of one of the most venerable of optimisation algorithms, Dantzig’s <a href="http://en.wikipedia.org/wiki/Simplex_algorithm">simplex algorithm</a>. I’m going to start off thinking a little bit about the general setup of the kind of linear programming problems that the simplex algorithm is designed to solve, just to get a geometrical feeling for how these algorithms work and to understand the issues that might arise from relaxing some of the assumptions used in them.</p>
<!--MORE-->

<h1 id="setup">Setup</h1>
<p>The basic idea of linear programming problems is to find a vector <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mtext mathvariant="bold">x</mtext><mo>∈</mo><msup><mo>ℝ</mo><mi>N</mi></msup></mrow></math> that maximises a linear objective function</p>
<div class="eq">
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>z</mi><mo>=</mo><mtext mathvariant="bold">c</mtext><mo>⋅</mo><mtext mathvariant="bold">x</mtext></mrow></math>
</div>
<br>
<p>subject to <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>M</mi></mrow></math> linear constraints of the form <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mtext mathvariant="bold">a</mtext><mi>i</mi></msub><mo>⋅</mo><mtext mathvariant="bold">x</mtext><mo>≥</mo><msub><mi>b</mi><mi>i</mi></msub></mrow></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mtext mathvariant="bold">a</mtext><mi>i</mi></msub><mo>⋅</mo><mtext mathvariant="bold">x</mtext><mo>=</mo><msub><mi>b</mi><mi>i</mi></msub></mrow></math> or <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mtext mathvariant="bold">a</mtext><mi>i</mi></msub><mo>⋅</mo><mtext mathvariant="bold">x</mtext><mo>≤</mo><msub><mi>b</mi><mi>i</mi></msub></mrow></math>. There is lots of specialised terminology surrounding the field of linear programming, but this is the basic idea.</p>
<p>What’s the connection between this sort of problem and the problem of laying out diagrams? In a diagram, the variables that we are interested in determining, i.e. the components of the vector <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mtext mathvariant="bold">x</mtext></mrow></math>, are the coordinates of certain points in our diagram: perhaps the end points of line segments, the centres of circles, whatever points we’ve included in our constraints. The dimension of the solution space, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>N</mi></mrow></math>, is then just the total number of coordinates we need to find. If we can express our geometrical constraints as linear equations or inequalities between these coordinates, and if we can express a “good” layout for underconstrained situations as a linear function of our coordinate values, then we have a linear programming problem to solve.</p>
<p>Most of the time, we hope that the constraints we impose are sufficient to precisely locate all the elements of the diagram, in which case there is only one possible solution to the constraint equations and our linear programming problem degenerates to the solution of a system of linear equations to determine the unique point satisfying the constraints. On the other hand, if we are building a system of constraints <em>interactively</em>, we will often find ourselves with an underconstrained system — the user has placed a number of shapes, has applied some constraints between them, but those constraints are not sufficient to fix the positions of all the elements of the diagram. We might then choose some optimisation criterion to decide what is a good layout for the underconstrained drawing<sup><a href="#fn1" class="footnoteRef" id="fnref1">1</a></sup>.</p>
<p>What sort of constraints can we treat? Suppose we have three points <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>p</mi><mn>1</mn></msub><mo>=</mo><mo stretchy="false">(</mo><msub><mi>x</mi><mn>1</mn></msub><mo>,</mo><msub><mi>y</mi><mn>1</mn></msub><mo stretchy="false">)</mo></mrow></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>p</mi><mn>2</mn></msub><mo>=</mo><mo stretchy="false">(</mo><msub><mi>x</mi><mn>2</mn></msub><mo>,</mo><msub><mi>y</mi><mn>2</mn></msub><mo stretchy="false">)</mo></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>p</mi><mn>3</mn></msub><mo>=</mo><mo stretchy="false">(</mo><msub><mi>x</mi><mn>3</mn></msub><mo>,</mo><msub><mi>y</mi><mn>3</mn></msub><mo stretchy="false">)</mo></mrow></math>. We can make two points be coincident, for example with the constraint <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>x</mi><mn>1</mn></msub><mo>=</mo><msub><mi>x</mi><mn>2</mn></msub><mo>∧</mo><msub><mi>y</mi><mn>1</mn></msub><mo>=</mo><msub><mi>y</mi><mn>2</mn></msub></mrow></math>. We can make the point <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>p</mi><mn>3</mn></msub></mrow></math> lie on the line segment connecting points <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>p</mi><mn>1</mn></msub></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>p</mi><mn>2</mn></msub></mrow></math> using the constraints</p>
<div class="eq">
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>x</mi><mn>3</mn></msub><mo>=</mo><msub><mi>x</mi><mn>1</mn></msub><mo>+</mo><mi>t</mi><mspace width="0.167em"></mspace><mo stretchy="false">(</mo><msub><mi>x</mi><mn>2</mn></msub><mo>-</mo><msub><mi>x</mi><mn>1</mn></msub><mo stretchy="false">)</mo><mo>∧</mo><msub><mi>y</mi><mn>3</mn></msub><mo>=</mo><msub><mi>y</mi><mn>1</mn></msub><mo>+</mo><mi>t</mi><mspace width="0.167em"></mspace><mo stretchy="false">(</mo><msub><mi>y</mi><mn>2</mn></msub><mo>-</mo><msub><mi>y</mi><mn>1</mn></msub><mo stretchy="false">)</mo><mo>∧</mo><mi>t</mi><mo>≥</mo><mn>0</mn><mo>∧</mo><mi>t</mi><mo>≤</mo><mn>1</mn></mrow></math>,
</div>
<br>
<p>where we introduce an auxiliary variable <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>t</mi></mrow></math>. We can express the condition that the line segment between points <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>p</mi><mn>1</mn></msub></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>p</mi><mn>2</mn></msub></mrow></math> be horizontal by saying <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>y</mi><mn>1</mn></msub><mo>=</mo><msub><mi>y</mi><mn>2</mn></msub></mrow></math>, that it be vertical by saying <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>x</mi><mn>1</mn></msub><mo>=</mo><msub><mi>x</mi><mn>2</mn></msub></mrow></math>, or in general that it lie at any given angle <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mo>θ</mo></mrow></math> by saying</p>
<div class="eq">
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>x</mi><mn>2</mn></msub><mo>=</mo><msub><mi>x</mi><mn>1</mn></msub><mo>+</mo><mi>t</mi><mspace width="0.167em"></mspace><mi>cos</mi><mo>θ</mo><mo>∧</mo><msub><mi>y</mi><mn>2</mn></msub><mo>=</mo><msub><mi>y</mi><mn>1</mn></msub><mo>+</mo><mi>t</mi><mspace width="0.167em"></mspace><mi>sin</mi><mo>θ</mo><mo>∧</mo><mi>t</mi><mo>≥</mo><mn>0</mn></mrow></math>,
</div>
<br>
<p>where again we introduce an auxiliary variable <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>t</mi></mrow></math>.</p>
<p>However, we can’t demand that the distance between points <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>p</mi><mn>1</mn></msub></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>p</mi><mn>2</mn></msub></mrow></math> is at most a particular value, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>d</mi></mrow></math> say, since to express this constraint, we would need to say something like</p>
<div class="eq">
<math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mo stretchy="false">(</mo><msub><mi>x</mi><mn>2</mn></msub><mo>-</mo><msub><mi>x</mi><mn>1</mn></msub><msup><mo stretchy="false">)</mo><mn>2</mn></msup><mo>+</mo><mo stretchy="false">(</mo><msub><mi>y</mi><mn>2</mn></msub><mo>-</mo><msub><mi>y</mi><mn>1</mn></msub><msup><mo stretchy="false">)</mo><mn>2</mn></msup><mo>≤</mo><msup><mi>d</mi><mn>2</mn></msup></mrow></math>,
</div>
<br>
<p>which is <em>not</em> a linear constraint. That seems like a bit of a shame, since distance-based constraints are very natural from a geometrical point of view. I’ll talk below about what it might mean to lift the restriction to linear constraints.</p>
<h1 id="finding-solutions">Finding solutions</h1>
<p>First of all, let’s think about how the constraints that we impose restrict the space of solutions to our optimisation problem. If <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mtext mathvariant="bold">x</mtext><mo>∈</mo><msup><mo>ℝ</mo><mi>n</mi></msup></mrow></math>, then the linear equality <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mtext mathvariant="bold">a</mtext><mi>i</mi></msub><mo>⋅</mo><mtext mathvariant="bold">x</mtext><mo>=</mo><msub><mi>b</mi><mi>i</mi></msub></mrow></math> defines an <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>N</mi><mo>-</mo><mn>1</mn></mrow></math>-dimensional hyperplane in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mo>ℝ</mo><mi>N</mi></msup></mrow></math>. For concreteness, for the moment let’s set <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>N</mi><mo>=</mo><mn>3</mn></mrow></math>. In 3-dimensional Euclidean space, the equation <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mtext mathvariant="bold">r</mtext><mo>⋅</mo><msub><mtext mathvariant="bold">n</mtext><mn>1</mn></msub><mo>=</mo><msub><mi>d</mi><mn>1</mn></msub></mrow></math>, where <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mtext mathvariant="bold">r</mtext></mrow></math> is an unknown vector, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mtext mathvariant="bold">n</mtext><mn>1</mn></msub></mrow></math> is a given unit vector, and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>d</mi><mn>1</mn></msub><mo>≥</mo><mn>0</mn></mrow></math> is a real number, defines a plane with normal vector <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mtext mathvariant="bold">n</mtext><mn>1</mn></msub></mrow></math> and perpendicular distance from the origin <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>d</mi><mn>1</mn></msub></mrow></math>, i.e. solutions <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mtext mathvariant="bold">r</mtext></mrow></math> to this equation lie in the given plane. So the solutions to our optimisation problem have to lie in this plane, not just in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mo>ℝ</mo><mn>3</mn></msup></mrow></math>. If we have a second equality constraint, defined by the equation <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mtext mathvariant="bold">r</mtext><mo>⋅</mo><msub><mtext mathvariant="bold">n</mtext><mn>2</mn></msub><mo>=</mo><msub><mi>d</mi><mn>2</mn></msub></mrow></math>, there are three possibilities: either <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mtext mathvariant="bold">n</mtext><mn>2</mn></msub><mo>=</mo><msub><mtext mathvariant="bold">n</mtext><mn>1</mn></msub></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>d</mi><mn>2</mn></msub><mo>=</mo><msub><mi>d</mi><mn>1</mn></msub></mrow></math> so both equalities refer to the same plane; or <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mtext mathvariant="bold">n</mtext><mn>2</mn></msub><mo>=</mo><msub><mtext mathvariant="bold">n</mtext><mn>1</mn></msub></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>d</mi><mn>2</mn></msub><mo>≠</mo><msub><mi>d</mi><mn>1</mn></msub></mrow></math> or <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mtext mathvariant="bold">n</mtext><mn>2</mn></msub><mo>=</mo><mo>-</mo><msub><mtext mathvariant="bold">n</mtext><mn>1</mn></msub></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>d</mi><mn>1</mn></msub><msub><mi>d</mi><mn>2</mn></msub><mo>≠</mo><mn>0</mn></mrow></math>, a situation where we have two distinct parallel planes and there are thus no consistent solutions for <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mtext mathvariant="bold">r</mtext></mrow></math>; or <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mtext mathvariant="bold">n</mtext><mn>1</mn></msub></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mtext mathvariant="bold">n</mtext><mn>2</mn></msub></mrow></math> are not collinear, the planes are distinct and meet in a line, to which our solutions <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mtext mathvariant="bold">r</mtext></mrow></math> are constrained. In higher dimensional spaces, adding further equality constraints works in the same way: either we have a degenerate case, so there are no admissible solutions, or the additional constraints restrict the admissible solutions to smaller and smaller linear subspaces of the original <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mo>ℝ</mo><mi>N</mi></msup></mrow></math> solution space.</p>
<p>In the end, after considering all of the linear equality constraints, we thus end up with a situation where we need to seek solutions in some linear subspace of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mo>ℝ</mo><mi>N</mi></msup></mrow></math>, subject to our inequality constraints. Further, there always exists a linear transformation <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mo stretchy="false">(</mo><msub><mi>x</mi><mn>1</mn></msub><mo>,</mo><msub><mi>x</mi><mn>2</mn></msub><mo>,</mo><mo>…</mo><mo>,</mo><msub><mi>x</mi><mi>N</mi></msub><mo stretchy="false">)</mo><mo>→</mo><mo stretchy="false">(</mo><msub><mi>u</mi><mn>1</mn></msub><mo>,</mo><msub><mi>u</mi><mn>2</mn></msub><mo>,</mo><mo>…</mo><mo>,</mo><msub><mi>u</mi><mi>N</mi></msub><mo stretchy="false">)</mo></mrow></math> that can simplify our view of this linear subspace so that we end up considering an optimisation problem in a lower-dimensional Euclidean space, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mo>ℝ</mo><mi>M</mi></msup></mrow></math> say, with <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>M</mi><mo>≤</mo><mi>N</mi></mrow></math>, with only inequality constraints of the form <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mover><mtext mathvariant="bold">a</mtext><mo accent="true">~</mo></mover><mi>i</mi></msub><mo>⋅</mo><mtext mathvariant="bold">u</mtext><mo>≤</mo><msub><mover><mi>b</mi><mo accent="true">~</mo></mover><mi>i</mi></msub></mrow></math> or <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mover><mtext mathvariant="bold">a</mtext><mo accent="true">~</mo></mover><mi>i</mi></msub><mo>⋅</mo><mtext mathvariant="bold">u</mtext><mo>≥</mo><msub><mover><mi>b</mi><mo accent="true">~</mo></mover><mi>i</mi></msub></mrow></math>.</p>
<p>Next, let’s think about the role of the inequality constraints in restricting the solution space. Each inequality constraint of the form <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mover><mtext mathvariant="bold">a</mtext><mo accent="true">~</mo></mover><mi>i</mi></msub><mo>⋅</mo><mtext mathvariant="bold">u</mtext><mo>≥</mo><msub><mover><mi>b</mi><mo accent="true">~</mo></mover><mi>i</mi></msub></mrow></math> or <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mover><mtext mathvariant="bold">a</mtext><mo accent="true">~</mo></mover><mi>i</mi></msub><mo>⋅</mo><mtext mathvariant="bold">u</mtext><mo>≤</mo><msub><mover><mi>b</mi><mo accent="true">~</mo></mover><mi>i</mi></msub></mrow></math> divides the space <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mo>ℝ</mo><mi>M</mi></msup></mrow></math> into two half-spaces, one in the permissible solution region and one not. The final permissible region is the intersection of the permissible half-spaces from each of these constraints. A little thought shows that this is a convex polytope<sup><a href="#fn2" class="footnoteRef" id="fnref2">2</a></sup> in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mo>ℝ</mo><mi>M</mi></msup></mrow></math>.</p>
<div class="img-left">
<img src="two-d-example.png" alt="Two-D example"></img>
</div>

<p>Here’s an example in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mo>ℝ</mo><mn>2</mn></msup></mrow></math>. Let’s call our coordinates <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>x</mi></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>y</mi></mrow></math>. Suppose we have the constraints <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>x</mi><mo>≥</mo><mn>0</mn></mrow></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>y</mi><mo>≥</mo><mn>0</mn></mrow></math> (these two are normally included by default in the “traditional” statement of the setup for the simplex algorithm), <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>x</mi><mo>+</mo><mi>y</mi><mo>≤</mo><mn>4</mn></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>x</mi><mo>+</mo><mn>2</mn><mi>y</mi><mo>≤</mo><mn>6</mn></mrow></math>.</p>
<p>The figure to the left shows the constraints as blue boundaries, with the interior of the polygon bounded by the constraint lines being the set of permissible solutions. I’ve also show the contours of a particular gradient function (the red lines) and the resulting best solution (point marked in green). It’s pretty clear that adding more linear inequality constraints can’t make the permissible region anything other than a convex polygon.</p>
<p>It’s also pretty clear from this image that the optimal point, i.e. the maximum of the objective function <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>z</mi></mrow></math>, is going to be found on the boundary of the polygon defined by the constraints. To see this, suppose that we select some point in the interior of the polygon as our putative “best” point. Then we can always go downhill along the contours of the objective function until we reach the boundary of the permissible polygon, thus finding a better solution than our originally proposed one.</p>
<p>In fact, the optimal solution, except in degenerate cases, is found at one of the <em>vertices</em> of this polygon. This is the key point that makes this type of optimisation problem more tractable than it might initially seem: even with large numbers of dimensions, we basically only need to solve a combinatorics problem over the vertices of our permissible polygon. In particular, we don’t need to think about what happens to our objective function in the interior of the polygon. This is a big deal, and we’ll see how lifting the linearity requirement on either the constraints or the objective function renders the problem much more difficult.</p>
<p>In essence, the simplex algorithm is a smart way of doing this combinatorial search along the edges of our permissible polygon, in a way that works for larger problems and with some special cases to deal with degenerate problems and to detect insoluble problems.</p>
<h1 id="lifting-assumptions">Lifting assumptions</h1>
<p>What happens if we lift the requirement that constraints be linear? A general nonlinear equation <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>f</mi><mo stretchy="false">(</mo><mtext mathvariant="bold">x</mtext><mo stretchy="false">)</mo><mo>=</mo><mn>0</mn></mrow></math> in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mo>ℝ</mo><mi>N</mi></msup></mrow></math> defines a manifold<sup><a href="#fn3" class="footnoteRef" id="fnref3">3</a></sup> embedded in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mo>ℝ</mo><mi>N</mi></msup></mrow></math>, so nonlinear equality constraints, instead of reducing our solution space to a nonlinear subspace of <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mo>ℝ</mo><mi>N</mi></msup></mrow></math>, will reduce it to a manifold <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>U</mi><mo>⊂</mo><msup><mo>ℝ</mo><mi>N</mi></msup></mrow></math> on which possible solutions live. Theoretically, this isn’t too much of a problem, but from a practical point of view, it might be tricky to deal with. In principle, we can find some sort of coordinate transform to make nice charts on our manifold <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>U</mi></mrow></math> we can use to think about our inequality constraints, but even in simple cases, care is required to make sure that our charts make a good atlas for the manifold. Suppose <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>N</mi><mo>=</mo><mn>3</mn></mrow></math>, we call our coordinates <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>x</mi></mrow></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>y</mi></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>z</mi></mrow></math> and we have a constraint that <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><msup><mi>y</mi><mn>2</mn></msup><mo>+</mo><msup><mi>z</mi><mn>2</mn></msup><mo>=</mo><mn>1</mn></mrow></math>, i.e. solutions lie on the surface of a sphere of radius one centred on the origin. Geometrically, this is no problem, but if we seek a single coordinate transformation to represent the two-dimensional surface of the sphere, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mo stretchy="false">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo>,</mo><mi>z</mi><mo stretchy="false">)</mo><mo>→</mo><mo stretchy="false">(</mo><mi>u</mi><mo>,</mo><mi>v</mi><mo stretchy="false">)</mo></mrow></math> say, we get into trouble: we need at least two distinct charts to form an atlas for the 2-sphere. It may thus be necessary to continue to work in the original <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mo stretchy="false">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo>,</mo><mi>z</mi><mo stretchy="false">)</mo></mrow></math> coordinate system, even though these are not independent degrees of freedom in the problem.</p>
<p>Nonlinear inequality constraints pose another sort of problem. If we have an inequality like <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mi>x</mi><mn>2</mn></msup><mo>+</mo><msup><mi>y</mi><mn>2</mn></msup><mo>≤</mo><mn>4</mn></mrow></math>, i.e. <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mo stretchy="false">(</mo><mi>x</mi><mo>,</mo><mi>y</mi><mo stretchy="false">)</mo></mrow></math> lies inside a circle of radius 2 centred on the origin, although, given a linear objective function, the optimal point still lies on the boundary of the region defined by the inequality, finding that point is rather more difficult and is no longer a simple combinatorial optimisation over the vertices of a polygon, as in the simplex algorithm.</p>
<p>There is another problem with nonlinear inequalities. Recall that for the linear constraint case, the permissible region was always a <em>convex</em> polytope. In general, nonlinear constraints do not guarantee convex regions (think of the constraints <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mn>0</mn><mo>≤</mo><mi>x</mi><mo>≤</mo><mn>1</mn></mrow></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mn>0</mn><mo>≤</mo><mi>y</mi><mo>≤</mo><mn>1</mn></mrow></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>x</mi><mi>y</mi><mo>≤</mo><mn>1</mn></mrow></math>, for instance) and this can lead to kinds of degenerate problem that do not exist in the linear case (for this set of constraints, optimising the objective <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>z</mi><mo>=</mo><mi>x</mi><mo>+</mo><mi>y</mi></mrow></math> leads to two solutions, one on each of the “corners” of the concave arc defined by the hyperbola equation <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>x</mi><mi>y</mi><mo>=</mo><mn>1</mn></mrow></math>). It seems like it might be possible to restrain ourselves to inequalities defining convex regions, which would mean that the permissible region formed from the intersection of these regions would also be convex<sup><a href="#fn4" class="footnoteRef" id="fnref4">4</a></sup>. Something to think about a bit more, particularly since there are optimisation methods designed for these convex situations.</p>
<p>Lifting the assumption that our objective function is linear means that we can no longer be sure that the optimal value lies on the boundary of our permissible region. An arbitrary nonlinear function can have all sorts of bumps and maxima within the permissible region. There are classes of nonlinear functions (in particular harmonic functions) where we can make definitive statements about extremal values within the permissible region compared to on the boundary, but these don’t seem like practical classes to use to restrict the choice of objective. All other things being equal, a linear objective is probably the best approach for now.</p>
<h1 id="conclusions-and-what-next">Conclusions and what next?</h1>
<ul>
<li>Linear constraints and linear objective function are nice and easy to understand geometrically.</li>
<li>General nonlinear constraints are potentially nasty.</li>
<li>Convex nonlinear constraints might be easier to handle (there’s a whole field called <em>convex optimisation</em> about dealing with this situation) and it seems intuitively likely that most of the nonlinear constraints we’re interested in might be convex — distance constraints essentially define balls in the coordinate space, for example.</li>
<li>Nonlinear objective functions break the whole “optimal solution on the boundary” idea. Best avoided if possible…</li>
</ul>
<p>Next, I’m going to set things up to play with an implementation of the simplex algorithm in Haskell, along the way experimenting with an interface for specifying constraint systems.</p>
<div class="footnotes">
<hr></hr>
<ol>
<li id="fn1"><p>In fact, things are trickier than this. Following the principle of least surprise, adding constraints to a drawing should only cause elements of the drawing to move around if they are in positions inconsistent with the constraints that have been applied so far. The Cassowary solver algorithm is constructed to allow this sort of update. I’ll talk about that another time, since it’s a bit more complicated than the basic simplex algorithm. <a href="#fnref1" class="footnoteBackLink">↩</a></p></li>
<li id="fn2"><p>A <em>polygon</em> lives in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mo>ℝ</mo><mn>2</mn></msup></mrow></math>; a <em>polyhedron</em> lives in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mo>ℝ</mo><mn>3</mn></msup></mrow></math>; a <em>polytope</em> lives in general <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msup><mo>ℝ</mo><mi>n</mi></msup></mrow></math>. <a href="#fnref2" class="footnoteBackLink">↩</a></p></li>
<li id="fn3"><p>Well, really, a variety, but varieties make me itchy, so I’m going to pretend that the solution set of all equations here is a nice smooth manifold. <a href="#fnref3" class="footnoteBackLink">↩</a></p></li>
<li id="fn4"><p>If a region <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>R</mi></mrow></math> is convex, then for any two points <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>x</mi><mi>R</mi></msub></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>y</mi><mi>R</mi></msub></mrow></math> in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>R</mi></mrow></math>, then all points <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>x</mi><mi>R</mi></msub><mo>+</mo><mi>t</mi><mo stretchy="false">(</mo><msub><mi>y</mi><mi>R</mi></msub><mo>-</mo><msub><mi>x</mi><mi>R</mi></msub><mo stretchy="false">)</mo></mrow></math> with <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mn>0</mn><mo>≤</mo><mi>t</mi><mo>≤</mo><mn>1</mn></mrow></math> are also in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>R</mi></mrow></math>. If we denote a second convex region by <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>S</mi></mrow></math>, then for any two points <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>x</mi></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>y</mi></mrow></math> in <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>R</mi><mo>∩</mo><mi>S</mi></mrow></math>, we have that <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>x</mi><mo>∈</mo><mi>R</mi></mrow></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>y</mi><mo>∈</mo><mi>R</mi></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>x</mi><mo>+</mo><mi>t</mi><mo stretchy="false">(</mo><mi>y</mi><mo>-</mo><mi>x</mi><mo stretchy="false">)</mo><mo>∈</mo><mi>R</mi></mrow></math> for <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mn>0</mn><mo>≤</mo><mi>t</mi><mo>≤</mo><mn>1</mn></mrow></math>, and also that <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>x</mi><mo>∈</mo><mi>S</mi></mrow></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>y</mi><mo>∈</mo><mi>S</mi></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>x</mi><mo>+</mo><mi>t</mi><mo stretchy="false">(</mo><mi>y</mi><mo>-</mo><mi>x</mi><mo stretchy="false">)</mo><mo>∈</mo><mi>S</mi></mrow></math> for <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mn>0</mn><mo>≤</mo><mi>t</mi><mo>≤</mo><mn>1</mn></mrow></math>. Thus <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>x</mi><mo>+</mo><mi>t</mi><mo stretchy="false">(</mo><mi>y</mi><mo>-</mo><mi>x</mi><mo stretchy="false">)</mo><mo>∈</mo><mi>R</mi><mo>∩</mo><mi>S</mi></mrow></math> for <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mn>0</mn><mo>≤</mo><mi>t</mi><mo>≤</mo><mn>1</mn></mrow></math> and so <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>R</mi><mo>∩</mo><mi>S</mi></mrow></math> is also convex. <a href="#fnref4" class="footnoteBackLink">↩</a></p></li>
</ol>
</div>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/constraints.html">constraints</a></span> <span class="tag"><a href="../../../../../tags/mathematics.html">mathematics</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/04/simplex-algorithm-warm-up/index.html</guid>
</item>
<item>
    <title>Holiday Reading #2</title>
    <link>http://www.skybluetrades.net/posts/2012/01/05/holiday-reading-2.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Holiday Reading #2</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/01/05/holiday-reading-2.html">Holiday Reading #2</a></div>
    <div class="postdate">January  5, 2012</div>

    <p>After the rather dreary spy novels, time for something a bit more fluffy.</p>
<!--MORE-->

<p>First, a couple by John Scalzi, who is an all-round good guy with a great <a href="http://whatever.scalzi.com">blog</a>, and a fine line in fairly traditional sci-fi. <em>Zoe’s Tale</em> is an alternative view of some of the events in the universe of <em>Old Man’s War</em>, told from the perspective of the teenage daughter of the hero of the original book. It’s an interesting experiment, to rewrite events already told from one perspective from a different viewpoint, one with quite distinct emotional responses and interests. Scalzi says that it was among the hardest things he’s ever written! It’s also interesting in that the protagonist and narrator is a teenage girl. I don’t think I’d have the balls to try to write anything substantial from that point of view, but Scalzi does, as far as I can tell, an excellent job. He says that he ran the book by a lot of female friends to check that he’d got the tone right.</p>
<p><em>The Android’s Dream</em>, also by Scalzi, is a standalone novel introduced by a diplomatic incident precipitated by farting. The book gets sillier from then on. It’s amusing, if you’re prepared to accept the main premise of the book, which is to do with a sheep-human hybrid developed through non-consensual zoophilia (is zoophilia <em>ever</em> consensual) that plays a critical part in the ceremonial involved in the handover of power of the government of an alien power, sort of though not quite allied with humanity. They’re big lizards. Who communicate partially by scent. Hence the farting. Seriously, it’s quite a diverting little book, but very very silly.</p>
<p><em>Snuff</em>: Pratchett, Discworld, Vimes. Does more need to be said? This is another Discworld book that deals with otherness and racism, people who are even more marginalised than dwarves and trolls. For me, the hero of the show? Willikins, Vimes’s manservant, a man with a history so shady you could use it as sunscreen for an albino rhino.</p>
<p>I’ve now read all of the Twenty Palaces novels by Harry Connolly, the latest being <em>Twenty Palaces, A Prequel</em>, which covers some of the backstory of Ray Lilly and the events that occurred before the “first” novel, <em>Child Of Fire</em>. I haven’t yet decided one way or another whether I think they’re any good. But I’m still reading them, so that says something, eh? They have some of the same feeling as spy novels, this sense of another world lying parallel to our own everyday world, where unpleasant people do unpleasant things to each other and everyday folks just suffer the consequences. I’m interested to see where he’s going with it all though, especially if we get to learn some more about where the spell books come from (and what they hell they actually are, since they certainly aren’t <em>books</em>!).</p>
<p>Similarly indecisive critical opinion surrounds Richard Kadrey’s Sandman Slim books. The latest is <em>Aloha From Hell</em>. It has all the usual stuff, with demons and angels (and other weirder things) doing battle, this time in a weirdly skewed Los Angeles in Hell which is an echo of the real L.A. (and you might argue, not all that much different). Kadrey’s books are more “mind candy” than Connolly’s: I get the feeling that Connolly is going somewhere with his stuff, but Kadrey is much more in-your-face with everything at once, with less of the mysterious slow reveal of the Twenty Palaces books. But what do I know? I’m still reading these too, although this may be the last one.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/book-reviews.html">book-reviews</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/05/holiday-reading-2.html</guid>
</item>
<item>
    <title>Friday photo #5</title>
    <link>http://www.skybluetrades.net/posts/2012/01/07/friday-photo-5/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Friday photo #5</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2012/01/07/friday-photo-5/index.html">Friday photo #5</a></div>
    <div class="postdate">January  7, 2012</div>

    <a href="kairouan-door.jpg">
<div class="img-full">
<img src="kairouan-door-small.jpg" alt="Door in Kairouan"></img>
</div>
</a>
<p>Door, Kairouan, Tunisia. April, 2005.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/photos.html">photos</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/07/friday-photo-5/index.html</guid>
</item>
<item>
    <title>We never dropped a bomb.  We never fired a bullet.  We never went to war.</title>
    <link>http://www.skybluetrades.net/posts/2012/01/07/jimmy-carter.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | We never dropped a bomb.  We never fired a bullet.  We never went to war.</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/01/07/jimmy-carter.html">We never dropped a bomb.  We never fired a bullet.  We never went to war.</a></div>
    <div class="postdate">January  7, 2012</div>

    <p>I was born in the UK in 1972. The “world leaders” who defined my youth were Margaret Thatcher, Ronald Reagan and Leonid Brezhnev. This may have something to do with why I am so bitter, cynical and generally misanthropic nowadays, although the star turns we’ve seen in the US, UK and former USSR since then may have helped too.</p>
<p>Before Reagan, there was Jimmy Carter. I remember him from the TV news at the time only very vaguely. Since missing re-election in 1981, Carter has worked on a vast range of issues, mostly to do with disease eradication in developing countries and election supervision in fragile democracies. That his name can send the US right wing into a frothing ball of fury seems to indicate that he’s been doing good things.</p>
<p>A recent <a href="http://www.guardian.co.uk/world/2011/sep/11/president-jimmy-carter-interview">interview</a> in The Guardian brought home just what a great man he is. The description of his house and his manner make me think more of a Greek senator elected by lot than a modern American politician with all the schmaltz and money that goes with it. He’s a humble man who has lived his beliefs. That deserves a lot of respect.</p>
<p>The other thing that comes across in the interview is his intellectual engagement. I loved the story from his chief of staff that he only once was able to tell Carter something that he didn’t already know. If you have any sense, you don’t choose a leader you’d be happy to have a beer with (don’t know if Carter even drinks); you choose a leader who is intelligent, motivated and honest. Carter is all of those things.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/07/jimmy-carter.html</guid>
</item>
<item>
    <title>Holiday Reading #3</title>
    <link>http://www.skybluetrades.net/posts/2012/01/08/holiday-reading-3.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Holiday Reading #3</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/01/08/holiday-reading-3.html">Holiday Reading #3</a></div>
    <div class="postdate">January  8, 2012</div>

    <p>A couple of more substantial (in length) books I read over Christmas were Neal Stephenson’s latest and the first of Tim Powers’ Fisher King series. I liked them both.</p>
<!--MORE-->

<h5 id="reamde-by-neal-stephenson"><em>Reamde</em> by Neal Stephenson</h5>
<p>I can’t help feeling that, after <em>Anathem</em>, Neal Stephenson just wanted to write something with lots of guns and stuff blowing up. He does it very entertainingly, although the gun fetishism is a bit weird for someone unused to it<sup><a href="#fn1" class="footnoteRef" id="fnref1">1</a></sup>. The plot is up to the usual Stephensonian standards of twistedness, and it’s pretty long, although it feels much less long than any of the Baroque Cycle books, probably as a result of rollicking along at a rather frantic pace from page one onwards. The settings, both real and virtual, are nicely done. My only real complaint is that some of the characterisation is a bit two-dimensional. The hero of the piece is a slightly enigmatic man-with-a-past-but-a-heart-of-gold; we have a taciturn former Spetsnaz man working in “security” (there really should be a place in the world for novels featuring former Spetsnaz operatives who now make balloon animals at children’s birthday parties); we have homicidal Russian gangsters; we have an intellectual super-villian (who happens to be a Muslim terrorist, a little disappointed with the hired help his pals in the U.S. are able to round up). James Bond meets World Of Warcraft via the Washington State Tourist Board, perhaps.</p>
<p>Anyway, it’s a lot of fun and it whiled away a few happy hours, but don’t expect another <em>Cryptonomicon</em>.</p>
<h5 id="last-call-by-tim-powers"><em>Last Call</em> by Tim Powers</h5>
<p>The first Tim Powers novel I read was <em>Declare</em>, which is a hard act to follow. <em>Last Call</em> is good, although I enjoyed it less than <em>Declare</em>, mostly I think because the connection to real history (the story of Kim Philby, in <em>Declare</em>) and the slight twisting thereof is where Powers really excels. <em>Last Call</em> isn’t set around any major historical events (that I know of, though I may very well be wrong), but it is connected to some other books by Powers, in particular <em>Expiration Date</em> and <em>Earthquake Weather</em>, which form a sort of loose trilogy with <em>Last Call</em>, and <em>The Drawing Of The Dark</em>, which is also related to the Fisher King myth (and, more importantly, beer and the Turkish siege of Vienna).</p>
<p>One aspect of all of Powers’ novels that I’ve read so far (the other one I’ve finished recently was <em>The Anubis Gates</em>) is “secret history”. Well-known and well-reported historical events are given a new gloss, where the most salient aspects are never known to the general populace, and the characters in the novels live in a parallel world (much like that of spy novels) where minor everyday happenings take on enormous significance. This otherworldliness or extraworldliness is at the forefront of <em>Last Call</em>: in this world, the arcana of the Tarot are real entities, Archetypes that underly all human striving. Since a regular deck of playing cards is basically just a cut-down tarot deck, Las Vegas is a centre of power for the operation of these entities, and for the establishment of the reign of a Fisher King for the West. Powers does a great job of depicting the power of chance and ritual in this world, with some genuinely creepy moments. The climax of the novel is entertaining, although perhaps a little predictable in some ways.</p>
<p>The kind of secret history that Powers writes is very engaging because it offers lots of hooks for a reader to anchor themselves: fantasy written in invented worlds can often leave one adrift, without any points of reference, but once it becomes clear what the rules are, the real history that underlies the secret provides signposts to help keep the reader oriented. The disadvantage, of course, is that it can be difficult not to stretch credibility. Not <em>all</em> of history can be <em>secret</em> history! Some things did happen more or less the way they are reported in the history books, without the intervention of supernatural forces or other strangeness<sup><a href="#fn2" class="footnoteRef" id="fnref2">2</a></sup>.</p>
<p>It’s a very tempting approach to fantasy writing though, and I look forward to reading more from Tim Powers. (I’m slightly stalled on <em>Expiration Date</em> at the moment, as it’s not quite grabbing me, but I read <em>The Anubis Gates</em> in about three sittings.)</p>
<div class="footnotes">
<hr></hr>
<ol>
<li id="fn1"><p>Stephenson comments that he needed the services of a “ballistics copy editor”. There really are a lot of guns. <a href="#fnref1" class="footnoteBackLink">↩</a></p></li>
<li id="fn2"><p>This is something that <em>Declare</em> does breathtakingly well: the <em>secret</em> secret history is hidden behind the everyday secret history of espionage and counterintelligence, and the book draws us slowly into the deeper secrets by way of the more mundane ones. <a href="#fnref2" class="footnoteBackLink">↩</a></p></li>
</ol>
</div>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/book-reviews.html">book-reviews</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/08/holiday-reading-3.html</guid>
</item>
<item>
    <title>Minds and mathematics</title>
    <link>http://www.skybluetrades.net/posts/2012/01/09/galactic-mathematics.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Minds and mathematics</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/01/09/galactic-mathematics.html">Minds and mathematics</a></div>
    <div class="postdate">January  9, 2012</div>

    <p>In 1998, the mathematical physicist David Ruelle wrote an odd little article, entitled <em>Conversations on Mathematics with a Visitor from Outer Space</em>, which appeared as a chapter of the very interesting looking book <em>Mathematics: Frontiers and Perspectives</em>, published by the IMU in 2000. I’ve not read the whole volume, although I think I’ve read at least one of the other chapters as a preprint. Most of the 30 authors seem to have written more or less “straight” articles, but Ruelle’s is different. He wanted to explore the constraints imposed on human mathematics by the structure and capabilities of the human brain. Perhaps <em>constraints</em> is too strong a word — “predispositions” might be better: human mathematics is necessarily tied to human brains, and human brains have evolved to their current state to solve problems that are quite different from the problems encountered in mathematics. One might thus expect human mathematics to have followed the “fault lines” in the Platonic edifice of Mathematics that are most easily appreciated using the mental tools that evolution has given us.</p>
<p>To explore this idea, Ruelle introduces the conceit of a visitor from outer space, a “galatic mathematician” pursuing doctoral studies investigating the nature of human mathematics. She describes some of the characteristics of the human mental apparatus that are relevant: limited short-term memory, and hence inability directly to execute complex algorithms; predisposition to see symmetry and pattern; human brains operate very slowly, even compared to human computers; the importance of geometrical and visual reasoning; and so on. Ruelle comments that despite our limitations, humans have managed to do some fairly complex mathematics, but the question is always: how much further could we go if we could transcend the limitations of our history?</p>
<!--MORE-->

<p>Ruelle’s visitor tells him that it would be impossible for her to explain Galactic Mathematics, since galactic mathematicians have already undergone this transcendence: “an ancient civilization would have fixed such intellectual inadequacies by assisted coevolution, biological engineering, and so on”. Humanity must necessarily do the same if they are to go beyond Human Mathematics.</p>
<p>This reminded me very strongly of an after-dinner talk by Freeman Dyson at a conference at Caltech I attended some years ago. The conference was about the exploration of Mars<sup><a href="#fn1" class="footnoteRef" id="fnref1">1</a></sup>, and Dyson’s chosen topic was, naturally enough, the human exploration of space. The main point of his talk, as I remember it, was that he didn’t think that humans would get all that far into space. At least, not humans as we are now. Too much effort expended on life support, too much danger from radiation or extended periods of weightlessness. Would it not make much more sense, he asked, for us to modify ourselves for life in outer space? Not overnight, of course, since such a process would involve a long period of experimentation and gradual adaptation, but eventually the idea would be to have people able to survive life in a weightless environment, with better resistance to ionising radiation, and perhaps even limited ability to survive in vacuum.</p>
<p>And if we might do that to travel and live in outer space, why not follow a similar process to allow us to explore the further reaches of mathematics? If arithmetic was no longer a question of rote learning but just came naturally, if complex symbolic manipulations were “obvious” instead of a lottery of sign errors, transpositions and copying slip-ups, if complex logical arguments flowed effortlessly at first sight, what might mathematics feel like to us, and how might it feel to be freed from the bondage of our (relatively) plodding squishy brains? What sort of mathematics would be produced by an entity for whom, for instance, the classification of finite groups could be held in the mind’s eye like a gem to be rotated and admired from every angle?</p>
<p>Of course, it’s pretty useless to speculate what it would be like to be such an “extended” mathematician: not so different from the archetypal example of imagining what it might be like to be a bat, although perhaps more like the bat imagining life as a human. Nevertheless, thinking about “extended” or modified human intellects is tied to another topic I’ve been idly thinking about recently, mostly as a follow-on from the Stanford AI course. That’s the question of “common sense”. I’ll write about that another time.</p>
<div class="footnotes">
<hr></hr>
<ol>
<li id="fn1"><p>At the time, I was a PhD student in Oxford, working on the ill-fated Mars Climate Orbiter mission. This was the infamous “metric vs. imperial” screw-up, which put paid to that PhD project quite handily. I had better luck second time out, a long time after this. <a href="#fnref1" class="footnoteBackLink">↩</a></p></li>
</ol>
</div>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/mathematics.html">mathematics</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/09/galactic-mathematics.html</guid>
</item>
<item>
    <title>Past Lives: Part III Maths</title>
    <link>http://www.skybluetrades.net/posts/2012/01/10/part-iii-maths.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Past Lives: Part III Maths</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/01/10/part-iii-maths.html">Past Lives: Part III Maths</a></div>
    <div class="postdate">January 10, 2012</div>

    <p>I’ve been very lucky so far in my life, and have had many opportunities to work and study in interesting places. I’m not sure I’ve made the best use of those opportunities — there’s much that feels unfinished or that didn’t quite work out the way I’d hoped it would — but these “past lives” have given me a lot of experience working in different fields, living in different places, hanging out with different kinds of people.</p>
<p>Blogging is inherently self-indulgent: you have to assume that someone out there is interested in reading your maunderings. (Not really. Honestly, I do this for my own amusement.) The ultimate in self-indulgence has to be autobiographical blogging and reminiscing, where some old fart bends everyone’s ear about the “good old days”. Anyway, since this is for my own amusement and for a bit of writing practice, I don’t really care. I’m going to be brazenly self-indulgent and start writing “Past Lives” articles to see if I can dredge up any interesting memories.</p>
<!--MORE-->

<p>In October 1997, I went to Cambridge to spend 9 months at DAMTP<sup><a href="#fn1" class="footnoteRef" id="fnref1">1</a></sup> to do the course that’s generally called Part III Maths, although it has the official title of the Certificate of Advanced Study in Mathematics. It’s a taught masters’ in mathematics, where you can choose from around 100 different courses on all aspects of maths (pure and applied). It’s examined at the end, and has a reputation as being one of the harder mathematics courses in the world.</p>
<p>It’s also used as a gatekeeper to determine who is offered maths PhD places in Cambridge. I went to Cambridge fresh from a stint in the delightful world of international finance<sup><a href="#fn2" class="footnoteRef" id="fnref2">2</a></sup>, all bright-eyed and bushy-tailed with the idea of doing a PhD in theoretical particle physics. Which meant that I needed to work hard and do well to have any chance of getting a studentship.</p>
<p>Part III is a funny sort of course. Cambridge undergraduates can do it as an optional fourth year of the standard undergraduate maths programme, but people also come in from outside to do it (like me). It’s very much a sink or swim affair. The courses are hard, the exams are harder, and there’s little or no pastoral guidance or help. Go to lectures, sit at home thinking hard and doing maths, go to tutorial classes, rinse and repeat (possibly with a pub visit or two in there somewhere). The lecturing ranges from the abysmally poor (no names…) to the very very good (Peter Goddard lecturing on conformal field theory sticks out as being one of those<sup><a href="#fn3" class="footnoteRef" id="fnref3">3</a></sup>), no prisoners are taken, and you quickly get the impression that you’re surrounded by some very smart people indeed.</p>
<p>I mostly took courses in theoretical physics (quantum field theory, general relativity, elementary particle physics and group theory, more quantum field theory, conformal field theory, plus some other stuff that I don’t remember any more). Mostly it was fun, and I learnt a lot. Some of it was less fun, and I got quite seriously turned off the idea of a particle theory PhD. I think the straw that broke the camel’s back was talking to one of a PhD student who proudly showed me a six-inch stack of paper that was his work for the last couple of months. A single calculation. He described to me what it was about, and I understood perhaps 10% of what he said. “Could it be real?” I asked. “Oh no — no way. Definitely not real. Just a thought experiment. Just something that hadn’t been worked out.” And there was the rub. At that time, and maybe still, the life of a student wasn’t likely to be much more than filling in corners left by the big names. Now, I can look back and recognise that that wasn’t necessarily a bad approach to take for PhD students: they get to learn about the subject on a well-constrained problem, a problem with a definite end-point that’s attainable in three years. At the time though, it seemed pretty uninspiring, so I kicked back and didn’t work terribly hard for the rest of the year, then lit out for Oxford to work on remote sensing of the atmosphere of Mars…</p>
<p>In retrospect, Part III Maths for me served as a good interregnum, a short period between working and starting as a PhD student. It was also a period where I went through big changes in my personal life, splitting up with a long-term girlfriend (fiancée at that time), with all the trauma that that entailed. I wasn’t really in the right frame of mind to truly benefit from the teaching offered in Cambridge at that point, but it was still useful experience. I still don’t know what the <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>L</mi></mrow></math>s are though.</p>
<div class="footnotes">
<hr></hr>
<ol>
<li id="fn1"><p>Department of Applied Mathematics and Theoretical Physics. <a href="#fnref1" class="footnoteBackLink">↩</a></p></li>
<li id="fn2"><p>Some of my worst jobs ever. <a href="#fnref2" class="footnoteBackLink">↩</a></p></li>
<li id="fn3"><p>I sat next to a guy called Dave in this course. In about the third lecture, Goddard introduced a set of operators called the <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>L</mi></mrow></math>s. We didn’t quite understand what they were, which was a bit of a shame, since they appeared in almost every lecture from then on, leading us to ask each other on the way out of every lecture “Do you know what the <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>L</mi></mrow></math>s are yet?”. (They’re the generators of the Virasoro algebra, which is a bit like a Lie algebra for the funny infinite-dimensional symmetry group that crops up in two-dimensional conformal field theory. There. That cleared it up for you, didn’t it?) <a href="#fnref3" class="footnoteBackLink">↩</a></p></li>
</ol>
</div>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/past-lives.html">past-lives</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/10/part-iii-maths.html</guid>
</item>
<item>
    <title>Puppy Purgatory</title>
    <link>http://www.skybluetrades.net/posts/2012/01/12/puppy-purgatory/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Puppy Purgatory</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2012/01/12/puppy-purgatory/index.html">Puppy Purgatory</a></div>
    <div class="postdate">January 12, 2012</div>

    <div class="img-right">
<img src="speedy-dog.jpg" alt="Speedy dog"></img>
<div style="text-align: center;">
<p>
<em>Speedy Dog goes where she likes!</em><br> <em>Well, maybe not any more, little girl…</em>
</p>
</div>
</div>

<p>Yesterday evening, we had a meeting with <a href="http://martine-cruz.franceserv.com/">Martine</a>, the dog behaviourist who’s helping us with Winnie. Winnie has come a long way from the terribly frightened little dog that we picked up from the animal shelter four months ago. She’s no longer terrified of everything in sight, she runs around with her tail up, likes to play with other dogs, likes to sniff in the bushes, likes to run crazily through the fallen leaves in the forest. She’s still jumpy and easily gets scared of people in the street or sudden noises, but she’s come a long way.</p>
<p>Unfortunately, we might have taken the gently-gently treatment we were pursuing to help her stop being so fearful a little bit too far. She doesn’t come when called, unless it suits her, and we had been escalating the treats we offered her to a slightly ridiculous degree. Time for a slightly stricter regime, to let her understand her position in the household. In the long run, it will be better for all of us: no more frustrating walks in the park where she won’t come back, no more worries as she wanders off for 15 or 20 minutes at a time, well out of sight, and safer walks near the road. She has no idea at all that cars and roads and human things in general can be dangerous, and will try to bolt into the road if she sees something really scarey, a bin bag, for instance…</p>
<p>So, we went to a nearby park with a dog area and let her run around with Jedi, Martine’s “regulator” dog-in-training, who is a beautiful Staffie cross. Martine’s diagnosis? Laughing, “She doesn’t give a toss, does she? She just doesn’t care! She’s a confident little dog. She thinks she’s the boss!” We tried walking around the park and hiding behind trees to see if Winnie would notice the absence of her human protectors and come looking for us. Eventually, eventually… Once she had exhausted the sniffing possibilities and was wondering why it was so quiet, she came looking. But not enough.</p>
<p>The prescription is Puppy Purgatory for 10 days or so. No talking to her, no cuddles, no games. Commands, OK. Praise if she comes when called, OK. Day-to-day chat, incessant “Good girl!”, belly rubs, tug games, no. Not for a week and a half. It’s hard. Harder for us than for her, I think. She just doesn’t quite know what’s going on, but we have to ignore her soulful eyes and wagging tail.</p>
<p>But hard as it may be, it seems to be paying off a little already. We’ve only had one day of this regime, and Winnie is already showing more interest in us, at home at least. I did a little bit of clicker training with her in the flat after dinner, and she was doing sit-stay-come pretty nicely: quite a bit better than usual. We’re going to go for a walk in the garrigue near Martine’s house next weekend, and we’ll see how much better Winnie is in terms of recall and staying near us then.</p>
<p>In the meantime though, Puppy Purgatory for all three of us…</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/dogs.html">dogs</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/12/puppy-purgatory/index.html</guid>
</item>
<item>
    <title>Friday photo #6</title>
    <link>http://www.skybluetrades.net/posts/2012/01/13/friday-photo-6/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Friday photo #6</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2012/01/13/friday-photo-6/index.html">Friday photo #6</a></div>
    <div class="postdate">January 13, 2012</div>

    <a href="mt-cain.jpg">
<div class="img-full">
<img src="mt-cain-small.jpg" alt="Mt. Cain"></img>
</div>
</a>
<p>Mt. Cain, Vancouver Island. New Years, 2010/2011.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/photos.html">photos</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/13/friday-photo-6/index.html</guid>
</item>
<item>
    <title>Now That's How You Use A Camera...</title>
    <link>http://www.skybluetrades.net/posts/2012/01/13/nature-photos/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Now That's How You Use A Camera...</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2012/01/13/nature-photos/index.html">Now That's How You Use A Camera...</a></div>
    <div class="postdate">January 13, 2012</div>

    <p>I’m a sucker for nature photos. One of our annual outings when we lived in Bristol was to the Nature Photographer Of The Year exhibition at the city museum. Going by the crowds there, we aren’t the only ones who like this stuff.</p>
<p>So, here’s some eye candy.</p>
<!--MORE-->

<div class="img-full">
<img src="boston-globe-jaguar.jpg" alt="Boston Globe: Jaguar cub"></img>
</div>
</a>
<p>First, The Boston Globe has <a href="http://www.boston.com/bigpicture/2011/12/50_best_photos_of_the_natural.html">The 50 Best Photos From The Natural World</a>. I don’t know about the 50 <em>best</em>, but they’re pretty good!</p>
<div class="img-full">
<img src="llareta.jpg" alt="Oldest Living Things: La Llareta"></img>
</div>
</a>
<p>Like old stuff? <a href="http://iheartphotograph.blogspot.com/2011/10/oldest-living-things-in-world.html">Here’s</a> some old stuff. Some of the oldest there is. Photos of some of the oldest living things in the world. And if you like thought-provoking images of old organisms, check out <a href="http://www.youtube.com/watch?v=OQ-qe19gY34">Mike Iverson’s rendition of “Bristlecone Pine”</a>, an image in sound.</p>
<div class="img-full">
<img src="suren-mavelyan-eye.jpg" alt="Suren Mavelyan: Husky eye"></img>
</div>
</a>
<p>And lastly, let’s look at some eyes. And what eyes. Suren Manvelyan took a simple idea (photograph ideas) and produced <a href="http://www.surenmanvelyan.com/">something truly beautiful</a>. Be sure to check out both the images of animal eyes and those of humans. The variation in patterns is fascinating.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/photos.html">photos</a></span> <span class="tag"><a href="../../../../../tags/science.html">science</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/13/nature-photos/index.html</guid>
</item>
<item>
    <title>Cabins</title>
    <link>http://www.skybluetrades.net/posts/2012/01/16/cabins.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Cabins</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/01/16/cabins.html">Cabins</a></div>
    <div class="postdate">January 16, 2012</div>

    <p>I’ve been thinking for a long time, mostly privately in my idle moments, about the sort of house I’d one day like to build for myself. I have some ideas that I think are pretty cool: multiple small wooden buildings, connected by walkways, with the main building on a slope with a stepped living area; a separate Japanese-style bathhouse; an octagonal library/study with windows all around; a cellar dug into the side of the hill.</p>
<p>Of course, all of this is nothing more than idle daydreaming. Recently though, Rita sent me a link to some pictures of cabins (sheds, huts, that sort of thing) that capture a lot of the spirit of what I’ve been thinking of. You can see them <a href="http://freecabinporn.com/">here</a> (yes, the link is safe!). Some of these places look heavenly.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/photos.html">photos</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/16/cabins.html</guid>
</item>
<item>
    <title>Container Cruising</title>
    <link>http://www.skybluetrades.net/posts/2012/01/16/container-cruising/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Container Cruising</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2012/01/16/container-cruising/index.html">Container Cruising</a></div>
    <div class="postdate">January 16, 2012</div>

    <div class="img-right">
<img src="container-cruising.jpg" alt="Container cruising"></img>
</div>

<p><em>Uh-oh. Getting a bit behind on this 30-day challenge. Time for some shorties…</em></p>
<p>Not really a “past life” as such, but something interesting I did a while ago that was brought back to mind by the Costa Concordia cock-up. I’ve not spent a lot of time on big ships, indeed until 2007, I think the only larger vessels I’d been on were ferries, cross-Channel or around the Greek islands.</p>
<p>In April 2007 though, I went to Canada for a big trip, mostly to visit some potential future places to live and work and to attend a workshop at the <a href="http://www.birs.ca/">Banff International Research Station</a>. I flew out to Vancouver, took a ferry to Vancouver Island where I visited UVic (ended up working there for a couple of years afterwards), then travelled east by train. I made it as far east as Halifax, Nova Scotia, all by train. That was a pretty cool experience in itself, but I’d had a wacky idea for how to get home from Canada to the UK. It’s possible to book passage on container ships under some circumstances, which I decided to do. It’s a tricky process, not super cheap, and the logistics of making the rendezvous with the ship turned out to be a bit more “interesting” than I expected.</p>
<p>At this time, the <a href="http://www.shipspotting.com/gallery/photo.php?lid=937982">M/V Flottbek</a> was sailing a triangular route between Montreal, Liverpool and Antwerp, so my plan was to meet the ship in Montreal and spend a week travelling to Liverpool. Four days before the ship was supposed to sail, I called the port agent from Halifax, letting him know who I was, that I was sailing with the Flottbek in a few days and asking what to do about getting to the ship. “Eh, if you’re sailing on the Flottbek, you won’t be sailing in a few days! You’ll be sailing tomorrow. She’s loading in Montreal right now!” Oh dear. Massive panic. <em>Ran</em> to a travel agent, luckily got a ticket for a flight back to Montreal that evening, taxi to airport, flew back to Montreal, six hours sleep then presented myself at the gates of the container dock in the morning (after a complicated explanation in French to a Québecois taxi driver that yes, I really did want to go to the <em>container</em> port).</p>
<p>I spent seven days on the Flottbek, under the capable care of the German master and chief engineer and they Philippino crew. It was a very interesting experience, though the life of a crewman on a container ship isn’t one that I would want to share any time soon: 9 months on, 3 months off for the men, or a generous 3 months on, 3 months off for the senior officers. Being away from home for that length of time, all the time, sounds more like something out of a Patrick O’Brien novel than real life. Still, for seven days, in spring, with calm seas and beautiful sunsets, it’s something I’d recommend to anyone who has the time.</p>
<p>Everyone on the Flottbek seemed extremely competent and the captain was a serious serious man who’d been a seafarer all his life, having grown up on <a href="http://en.wikipedia.org/wiki/Heligoland">Heligoland</a> and having a little boat of his own as a boy. I can’t, not in a thousand years, imagine him or any of his crew doing what the master of this Italian cruise ship did. The Flottbek had run aground once, on a shoal in the St. Lawrence River, on the way from Montreal to the open sea, but that was the fault of the Lawrence River pilot (thankless job: shifting shoals and big ships don’t make for a stress-free life).</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/past-lives.html">past-lives</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/16/container-cruising/index.html</guid>
</item>
<item>
    <title>Eight legs good, two legs bad!</title>
    <link>http://www.skybluetrades.net/posts/2012/01/17/octopus.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Eight legs good, two legs bad!</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/01/17/octopus.html">Eight legs good, two legs bad!</a></div>
    <div class="postdate">January 17, 2012</div>

    <p>Along with a lot of other people, I’m a big fan of cephalopods. I’ve dived with squid and cuttlefish and have watched octopus while snorkelling. I particularly remember following one cuttlefish across a reef in the Philippines, watching its mesmerising pattern display, until it got bored of the clumsy and noisy thing with too few appendages plodding along behind it and made off for deeper water.</p>
<p>Octopus, in particular, are smart little critters. One of the saddest things I’ve ever read was a section of a book about octopus physiology<sup><a href="#fn1" class="footnoteRef" id="fnref1">1</a></sup> that talked about the effect of certain nervous system lesions on the behaviour of octopus — these were lesions induced by human experimenters, of course. The writer talked about how the cephalopod victims cowered at the back of their tanks and clearly were less than keen on being used as experimental subjects. It stuck in my mind as the only place in the book (otherwise a good and thorough treatment of octopus physiology) where the author seemed tempted in any way to anthopomorphise or to ascribe emotions or feelings to the octopus. That’s why <em>Octopus vulgaris</em> is the only invertebrate protected under the UK’s animal experimentation laws…</p>
<p>Anyway, octopus are very cool and a fascinating model for non-human (and non-vertebrate!) intelligence. A <a href="http://www.orionmagazine.org/index.php/articles/article/6474/">recent article</a> in <em>Orion</em> magazine does a great job of getting across just how amazing these creatures are. Go and read it. If they lived a bit longer and could be trusted not to molest the dog, I would love to have an octopus to live with us. Alas, I don’t like to imagine what would be the result of Winnie versus a Pacific giant octopus. Messy, for sure.</p>
<div class="footnotes">
<hr></hr>
<ol>
<li id="fn1"><p>I <em>really</em> like octopus, OK? I think the book was <em>Octopus: physiology and behaviour of an advanced invertebrate</em> by M. J. Wells, although it was a while ago that I read it. <a href="#fnref1" class="footnoteBackLink">↩</a></p></li>
</ol>
</div>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/17/octopus.html</guid>
</item>
<item>
    <title>Friday photo #7</title>
    <link>http://www.skybluetrades.net/posts/2012/01/23/friday-photo-7/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Friday photo #7</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2012/01/23/friday-photo-7/index.html">Friday photo #7</a></div>
    <div class="postdate">January 23, 2012</div>

    <a href="welsh-mountains.jpg">
<div class="img-full">
<img src="welsh-mountains-small.jpg" alt="Welsh mountains"></img>
</div>
</a>
<p>Carnedd Llywelyn, North Wales. January 2006.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/photos.html">photos</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/23/friday-photo-7/index.html</guid>
</item>
<item>
    <title>Link Round-up</title>
    <link>http://www.skybluetrades.net/posts/2012/01/23/link-roundup.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Link Round-up</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/01/23/link-roundup.html">Link Round-up</a></div>
    <div class="postdate">January 23, 2012</div>

    <p>Some interesting things that passed through my RSS reader recently:</p>
<p><a href="http://www.technologyreview.com/blog/arxiv/27372/">Food pairing and flavour networks</a> <br> This is kind of interesting. Why do cheese and bacon (if you eat that kind of thing) go together so well? Or asparagus and butter? Or caviar and chocolate? (Apparently. If you’re Heston Blumenthal.) The hypothesis was that these “paired” foods had many flavour compounds in common. The data presented in this preprint seems to confirm that idea for Western cookery, but contradict it for Asian cuisine. There’s a lot more in there about the evolution of recipes, clusters of ingredients, and other network analysis goodness.</p>
<p><a href="http://crookedtimber.org/2012/01/14/towards-a-21-hour-working-week/">Economists doing something right?</a> <br> The people at <a href="http://crookedtimber.org">Crooked Timber</a> always have a lot of interesting things to say. This is a summary and some discussion of a meeting at the <a href="http://www.neweconomics.org/">New Economics Foundation</a> talking about the need to cut consumption and spread wealth around by redistributing working hours. From a personal point of view, the idea of earning a reasonable salary from a 21-hour working week and having time to work on personal projects, do some volunteering, spend time with Rita and Winnie, all sounds great. From a social point of view, a gradual redistribution of working hours to reduce unemployment and spread income around more fairly also sounds fine. It seems unlikely to happen, if only because NEF seems to be the only group of economists who can bear to think about the end of economic growth and a transition to a steady-state economy. When I listen to mainstream economists speak, I have this image in my mind of a train racing along a bridge which is being frantically cobbled together bit by bit as the train approaches. Sometimes the train gets closer to the edge, sometimes it backs off a little way. But in the long run, the bridge builders can’t win. They’re just going to run out of stuff to build more bridge.</p>
<p><a href="http://www.nytimes.com/2012/01/17/health/india-full-year-without-a-reported-case-of-polio-is-a-first-in-what-was-a-longtime-hot-spot.html?_r=1&amp;ref=health">Some good news</a> <br> To leaven the economics misery, this is really good. Polio is on the way out in India: not one new case in the last year!</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/23/link-roundup.html</guid>
</item>
<item>
    <title>Ping</title>
    <link>http://www.skybluetrades.net/posts/2012/01/23/naval-sonar.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Ping</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/01/23/naval-sonar.html">Ping</a></div>
    <div class="postdate">January 23, 2012</div>

    <p>For a brief period some years ago, I worked for an engineering firm that did sonar work for the (UK) navy. Many of the people in the company were ex-submariners, who had served both on the Swiftsure/Trafalgar attack boats and on the Vanguard missile boats. These were all pretty solid people, and I remember one in particular who delighted in telling stories about his time working his way up from a “baby sailor” to naval attaché to the British embassy in Washington, D.C. His most amusing tales included a reenactment (with actions) of the joys of carrying soup tureens around crowded submarines, and the entertaining ability of US spy satellites to dip into the atmosphere to take a closer look at interesting sights, like Soviet mini-subs stuck on their motherships in their pens.</p>
<p>A slightly less amusing story revolved around the hubris of submarine commanders. He sent some of us a photograph showing £20 million of towed sonar array snarled up around a mooring buoy, all because the sub commander couldn’t be bothered to wait for the divers to help reeling the thing in. A sad navy man with a big beard stood gazing at the pile of expensive spaghetti, looking like he might burst into tears at any moment. Not the navy’s finest moment.</p>
<p>One of my main jobs was to work on sonar system performance measures, which were used by the Ministry of Defence to try to ensure that they weren’t being diddled by the main contractor for the sonar system in question. Terrifyingly large amounts of money were involved, and some terrifyingly bad engineering decisions. The contractor decided to “buy British” for microprocessors for the beamforming hardware and designed a system using the Inmos Transputer. Oops. Inmos were assimilated into SGS Thomson, the Transputer shortly thereafter became extinct, and a sharp about-turn was needed to redesign the whole processing chain to use off-the-shelf PC components instead of the custom hardware that they had planned for.</p>
<p>It was an interesting little period for me, though I hadn’t wanted to work on the naval side of things. The company also did a lot of aerospace work, and I had nominally been hired to work on that. The structure of the company meant that I got poached for sonar stuff, got grumpy and left.</p>
<p>This company did have one extremely good thing they did though, one that I’ve not yet seen anywhere else (although it may be a standard approach in some kinds of engineering companies). All of the details of all non-classified projects that the company had going, in all of the fields where it worked, were available for perusal via the company’s accounting and time tracking software. Each engineering employee kept track of the time they spent on whatever projects they were assigned to (no surprises so far), but it was also possible to look through any other projects, see what work remained to be done, to see who was assigned to do the work, to see any open slots where people with particular skills were needed, and if you had spare time, to put yourself down to do that work. It was a very efficient system, and it actively encouraged people to talk and cooperate across project boundaries within the company. I think that was probably one of the biggest lessons I took from my time there. That, and, if you have 1500 m of towed array to reel in, wait for the divers…</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/past-lives.html">past-lives</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/23/naval-sonar.html</guid>
</item>
<item>
    <title>Beach Time!</title>
    <link>http://www.skybluetrades.net/posts/2012/01/29/beach-time/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Beach Time!</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2012/01/29/beach-time/index.html">Beach Time!</a></div>
    <div class="postdate">January 29, 2012</div>

    <div class="img-right">
<a href="winnie-on-beach.jpg"><img src="winnie-on-beach-small.jpg" alt="Winnie!"></img></a>
</div>

<p>Today, we had an early morning outing to the <a href="http://g.co/maps/tjmrd">Plage de l’Espiguette</a>, a <em>big</em> beach about 30 km east of Montpellier. We got up at 6:15, picked up the Modulauto car at 7:00, persuaded Winnie into the back (she’s still a bit scared of cars…) and off we went. We arrived at the car park before sunrise and were the only people there! Miles and miles of dunes were ours alone! Much frolicking there was. And climbing up and down the dunes. And digging. And chasing of sticks. And rolling around pretending to be a dog (just Ian, since Winnie is a dog, and Rita isn’t quite as silly as me). It was a lovely morning, and the dunes were very pretty indeed. We’ll be going back there again, some time before the summertime beach dog ban comes in. And hopefully, with more doggie company next time, since I think Winnie could have done with a four-legged buddy to run around with. I do my best, but I don’t quite have what it takes for <em>serious</em> boisterous play, since I can’t run at 40 km/h for hours and hours at a time…</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/dogs.html">dogs</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/29/beach-time/index.html</guid>
</item>
<item>
    <title>Academic publishing</title>
    <link>http://www.skybluetrades.net/posts/2012/01/29/elsevier.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Academic publishing</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/01/29/elsevier.html">Academic publishing</a></div>
    <div class="postdate">January 29, 2012</div>

    <p>After referring to a paper in <a href="http://www.journals.elsevier.com/agricultural-and-forest-meteorology/"><em>Agricultural and Forest Meteorology</em></a> in the last post, I remembered <a href="http://crookedtimber.org/2012/01/26/friends-really-dont-let-friends-publish-in-elsevier-journals/">something I read on Crooked Timber</a> the other day. Many people have a pretty good idea of how toxic the world of academic publishing is — if you don’t, take a look at <a href="http://www.guardian.co.uk/science/2012/jan/16/academic-publishers-enemies-science">this recent Guardian piece</a> by Mike Taylor, who lays out the issues pretty clearly.</p>
<p>But what can individual researchers do to fight the power and toxic influence of the big publishers? Personally, I only submit papers to journals with an open-access policy (the EGU journals like <a href="http://www.biogeosciences.net/">Biogeosciences</a> are good here, especially with their “open peer review” process), and try to encourage co-authors to do the same. But I am among the tiniest of tiny fish in a very big pond, so what I do has an influence barely measurable in pico-Seldons<sup><a href="#fn1" class="footnoteRef" id="fnref1">1</a></sup>. Now some of the big fish are taking an interest, and have started a <a href="http://thecostofknowledge.com/">movement</a>! You should sign up if you’re involved in publishing scientific results and care at all about the free dissemination of knowledge.</p>
<div class="footnotes">
<hr></hr>
<ol>
<li id="fn1"><p>A Seldon being the commonly accepted unit of historical influence. Difficult to quantify precisely, but whatever the scale, I don’t have many of them… <a href="#fnref1" class="footnoteBackLink">↩</a></p></li>
</ol>
</div>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/29/elsevier.html</guid>
</item>
<item>
    <title>Puéchabon webcam</title>
    <link>http://www.skybluetrades.net/posts/2012/01/29/puechabon-webcam/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Puéchabon webcam</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2012/01/29/puechabon-webcam/index.html">Puéchabon webcam</a></div>
    <div class="postdate">January 29, 2012</div>

    <div class="img-right">
<img src="installation.jpg" alt="Webcam installation"></img>
</div>

<p>One of the things I’m responsible for in my day job is a phenology webcam at our <a href="http://maps.google.com/maps?q=43.7414,+3.59583&amp;hl=en&amp;ll=43.740941,3.596987&amp;spn=0.001905,0.004112&amp;sll=43.742143,3.595834&amp;sspn=0.030477,0.065789&amp;vpsrc=6&amp;t=h&amp;z=19">experimental site at Puéchabon</a>. The idea of this is to observe colour changes in the canopy of the forest up there, with a view perhaps eventually to replacing manual phenological observations with information drawn from digital photos. In this sense, <em>phenology</em> means things like when flowers come out, when fruit forms, and so on. The <a href="http://en.wikipedia.org/wiki/Quercus_ilex"><em>Quercus ilex</em></a> (holm oak) forest at Puéchabon is evergreen, so you don’t get the same spectacular seasonal changes in leaf colour that you see in deciduous forests, so we’re not sure whether this is going to work — the changes we’ll be looking at will be a bit more subtle.</p>
<p>We installed the webcam on the 20 metre tower at Puéchabon in July and have been collecting images every half hour since, apart from a few outages. The images aren’t all that exciting (below left), but it’s quite nice to watch the changing angle of the sun on the canopy throughout the day. Very preliminary data analysis indicates that we will at least be able to see <em>something</em> changing through the seasons, even if it’s not abundantly clear to the eye from the images. A recent paper by <a href="http://www.sciencedirect.com/science/article/pii/S0168192311002851">Sonnentag et al.</a> (unfortunately behind the evil Elsevier paywall…) gives some ideas about how to analyse these images. In the plot below right is a time series of the mean <em>chromatic green</em> component of the part of the webcam field of view that covers the forest canopy. This is defined as <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><msub><mi>g</mi><mrow><mi>c</mi><mi>c</mi></mrow></msub><mo>=</mo><mi>G</mi><mo>/</mo><mo stretchy="false">(</mo><mi>R</mi><mo>+</mo><mi>G</mi><mo>+</mo><mi>B</mi><mo stretchy="false">)</mo></mrow></math>, where <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>R</mi></mrow></math>, <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>G</mi></mrow></math> and <math display="inline" xmlns="http://www.w3.org/1998/Math/MathML"><mrow><mi>B</mi></mrow></math> are the red, green and blue components of the digital image. There is definitely some seasonal variation, although with a lot of noise. I want a full year of data, so that we can see the new growth in the spring, before doing some more detailed analysis, since there are definitely still some scene illumination artefacts in what we’re seeing. It’s encouraging that we can at least see something though!</p>
<div>
  <div class="img2-box">
    
<a href="webcam-image.jpg"><img src="webcam-image.jpg" alt="Webcam image"></img></a>
<p style="text-align: center;">
<em>Webcam image</em>
</p>
  </div>
  <div class="img2-box">
    
<a href="gcc.png"><img src="gcc.png" alt="Chromatic green time series"></img></a>
<p style="text-align: center;">
<em>Chromatic green time series</em>
</p>
  </div>
  <div class="img-spacer"></div>
<div>

<p>The potential difficulties in data analysis aren’t helped much by the local criminal low-lives. We’ve had four major thefts at Puéchabon in the last six months, the latest of which involved break-ins at both of the sheds on site and theft of a load of gas analysis and data processing equipment (including the PC collecting the webcam images), as well as power conditioning equipment and batteries used with the generator we use to power the site. Until the <em>third</em> theft of the year, we did have a nice big set of photovoltaic panels for power, but some enterprising lads took a truck up there and carted them all away. Probably 20 square metres of panels, gone in one night. It’s pretty weird. Much of the stuff these idiots have taken is basically worthless to them. It’s hard to imagine them successfully fencing a gas analyser or a fluorometer at one of the local flea markets! They seem to be taking stuff just because it’s there and it’s shiny.</p>
<p>It’s not quite clear what’s going to happen at Puéchabon now going forwards: we can’t afford to have guards at the site 24 hours a day to protect stuff, and it’s getting kind of silly when Alain and Jean-Marc, the technicians who go up there weekly, come back more often than not with long faces and another tale of broken locks and missing stuff. The whole point of a site like this is to have continuous observations, and if those keep getting interrupted by equipment walking away, it reduces the value of the remaining data quite a lot. We’ll have to see what happens.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/day-job.html">day-job</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/29/puechabon-webcam/index.html</guid>
</item>
<item>
    <title>Trident Homeless?</title>
    <link>http://www.skybluetrades.net/posts/2012/01/30/homeless-trident.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Trident Homeless?</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/01/30/homeless-trident.html">Trident Homeless?</a></div>
    <div class="postdate">January 30, 2012</div>

    <p>Trident is the UK’s <em>independent nuclear deterrent</em>. Except that it isn’t independent and it doesn’t deter anyone. It is nuclear though, so we do have that. Apparently, Trident is our ticket to sit down with the big boys, to strut around as part of the Nuclear Club, to be on the right side of the Non-Proliferation Treaty (the side that does all the shouting about non-nuclear states and quietly does nothing about its own disarmament obligations). Narrow-minded political commentators on the right in the UK regularly pull out this argument as a reason for keeping or renewing Trident, despite its obscene cost and highly dubious (at best) morals. And that tells you more or less all you need to know about international politics at the highest levels. It’s just Playground Bullies Redux. He who has the biggest stick wins.</p>
<p>Trident isn’t independent (the missiles are leased from the US, the warheads, although assembled at Aldermaston, are based very firmly on US technology, the re-entry vehicle navigation software is American, and so on), but Scotland might soon be. Which might pose a tiny little problem for the Royal Navy, since the only places in the UK where they can harbour and replenish their missile boats are in Scotland. <a href="http://www.guardian.co.uk/uk/2012/jan/29/trident-nuclear-deterrent-scotland-independence">Oops</a>.</p>
<p>From the Guardian this morning:</p>
<blockquote>
<p>Asked during the referendum debate in the Scottish parliament last week whether the government of an independent Scotland would do a deal to keep Trident, the first minister Alex Salmond replied: “It is inconceivable that an independent nation of 5.25m people would tolerate the continued presence of weapons of mass destruction on its soil.”</p>
</blockquote>
<p>I don’t know if it will really happen. People tend to get all serious about nuclear weapons, and there might be some sort of “deal” done, backed by threats, but I honestly love the idea of Alex Salmond wagging his finger at David Cameron yelling “Oot! Oot, ya wee eejit! An’ tek yon dam’ missals wi’ ye!”.</p>
<p>My Freude is quite quite schaddly tonight…</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/nonsense.html">nonsense</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/30/homeless-trident.html</guid>
</item>
<item>
    <title>Common sense and the well-designed child</title>
    <link>http://www.skybluetrades.net/posts/2012/01/30/well-designed-child.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Common sense and the well-designed child</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/01/30/well-designed-child.html">Common sense and the well-designed child</a></div>
    <div class="postdate">January 30, 2012</div>

    <p>I recently read an interesting article by John McCarthy that set me thinking. The paper is called <em>The Well Designed Child</em><sup><a href="#fn1" class="footnoteRef" id="fnref1">1</a></sup> and talks a bit about about the old nature versus nurture debate: to what extent is a newborn child a blank slate, and to what extent are human intellectual capabilities intrinsic and instinctual?</p>
<p>To me, the whole question of nature versus nurture has always seemed odd. It’s clear that both aspects are important. We are all limited to one extent or another in what we can do purely by the physical parameters of our existence: as much as I would like to teleport myself to Europa to frolic in the sunless sea beneath the ice, I can’t, and never will be able to. Equally though, the potential that exists in all of us at birth can be squandered, and without education and opportunity, none of us can make of ourselves all that we might. So, we need a bit of both.</p>
<p>Perhaps the source of the debate lies in observation of other creatures: beavers don’t go to Beaver Engineering School to learn how to build dams, and spiders don’t attend art college to learn how to make beautiful webs. These abilities are intrinsic, evolved, part of what Richard Dawkins called the “extended phenotype” of these creatures, behavioural manifestations of developmental and neural structures that are passed down from generation to generation. Humans don’t appear much like that. We do have to go to school to learn how to build dams or weave webs or to do any of the thousands of things that we do. The question then is: what intrinsic capabilities are we born with? What is on our slate, since it seems as though it ought not to be completely blank?</p>
<p>Human babies don’t seem all that capable, compared to the young of other species. That’s something of an illusion though, since humans give birth to developmentally very premature infants, mostly as a result of evolutionary compromises to allow us to have large brains combined with an upright posture. I don’t know exactly what human developmental stage would be a good one to use for comparison with other species, to try to decide what intrinsic capabilities we might have. However, there are three fairly obvious capabilities that do spring to mind. These are the capability to learn, the apparently intrinsic facility for language acquisition, and a basic grasp of what, for want of a better term, I’ll call “folk physics”.</p>
<p>The first two are aspects of human development that are quite well known and explored, although none of the questions are yet really settled, as far as I can tell. I’d like to concentrate on the third, this idea of “folk physics”. What do I mean by that? I mean the kind of common sense knowledge of the world of physical objects that we all have — two objects cannot occupy the same space; if one object passes behind another, it does not cease to exist; objects further away appear smaller; gravity gives a definite up-down orientation to the world. You can come up with lots more examples. These things seem almost too obvious to state, but they are still knowledge of a kind that either has to be intrinsic or acquired, and they constitute a large base of shared facts that we all need and use for living in the physical world.</p>
<p>What McCarthy’s paper really set me to thinking about though, was what might minds be like that had different sets of common sense to our own? Uncommon sense, if you like. A couple of examples will give an idea of what I’m talking about. First, think about an entity evolved to live in vacuum, in a micro-gravity environment. Human-default common sense physics seems to be Aristotelian more than Newtonian, but that’s hard to imagine for a creature that never feels air resistance and doesn’t have a large local gravity field to give it a sense of up and down. Just for an example, how would such a creature refer to directions? No up and down may lead to no left and right either, although near and far seem as though they should still be usable. How about referring to directions towards items, rather than abstracting into categories like up and down? That might work, but it would have a fundamental impact on the way that such entities might use language to refer to each other and to objects and places. It’s interesting to speculate what sort of idiomatic usage might arise from this different perspective on the world.</p>
<p>Second, another example, more remote from human experience in many ways. What sort of common sense, and what sort of mind, might an entity inhabiting a computer network (the internet, say) develop? Here, there is no “physics”, since there is no physical. There are no physical directions at all, although the environment has a rich topological and metric structure. The more I think about it, the more I find myself at a loss to imagine what the existence of such an entity might be like. It led me to think that true artificial intelligences, if we ever succeed in creating them, may be even stranger than they are usually portrayed in fiction<sup><a href="#fn2" class="footnoteRef" id="fnref2">2</a></sup>.</p>
<div class="footnotes">
<hr></hr>
<ol>
<li id="fn1"><p>J. McCarthy (2008). The well-designed child. <em>Artificial Intelligence</em> <strong>172</strong>, 2003–2014. Free online version <a href="http://www-formal.stanford.edu/jmc/child/child.html">here</a>. <a href="#fnref1" class="footnoteBackLink">↩</a></p></li>
<li id="fn2"><p>Charlie Stross’s intelligent lobster spam filters might be an exception here on the insufficient strangeness front… <a href="#fnref2" class="footnoteBackLink">↩</a></p></li>
</ol>
</div>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/artificial-intelligence.html">artificial-intelligence</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/01/30/well-designed-child.html</guid>
</item>
<item>
    <title>Thirty Day Challenge: The Stats</title>
    <link>http://www.skybluetrades.net/posts/2012/02/01/30-day-challenge-retrospective.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Thirty Day Challenge: The Stats</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/02/01/30-day-challenge-retrospective.html">Thirty Day Challenge: The Stats</a></div>
    <div class="postdate">February  1, 2012</div>

    <p>Over the course of the month of January, I:</p>
<ul>
<li><p>published 24 blog articles. Less than thirty, but not a crushing failure.</p></li>
<li><p>had 13 days when I didn’t write anything, compensated by two days when I wrote 3 articles and 3 days when I wrote two.</p></li>
<li><p>wrote about 17 articles that I would consider “proper” articles, i.e. involving some actual writing. The others were just links or photos.</p></li>
<li><p>was ill for a few days, which could be a viable excuse for around 5.5 missing articles, which means that I (morally) only missed my target by half an article. Compared to people who liveblog their gall bladder surgery, I feel kind of small. Maybe it’s not so much of a moral victory after all…</p></li>
</ul>
<p>So, was it a useful thing to do? Did I learn anything? I certainly did:</p>
<ol style="list-style-type: decimal">
<li><p>It’s quite hard to come up with substantial and substantive articles every day. I <em>could</em> wiffle on about random subjects without too much difficulty, but things that involve thinking take a bit more time.</p></li>
<li><p>The writing, in terms of putting words down one after another, isn’t something I find too hard. (I think I knew that before, but it’s nice to have it confirmed.)</p></li>
<li><p>Writing reviews of other peoples’ work (books, papers, etc.) is an order of magnitude easier than generating original ideas yourself. There’s an in-between stage that’s quite good for blogging, I think, where you get some interesting ideas from reading or thinking about something, not substantial enough to turn into a longer piece of writing, but perhaps enough to blog about. That provides quite a nice incentive for working through my <em>enormous</em> literature backlog…</p></li>
<li><p>Ultimately, the most satisfying things for me to write are more meaty. I didn’t manage anything I would consider in this category this month, mostly because of the perceived pressure of at least thinking about producing something every day, but I have a few ideas I’m going to work on.</p></li>
</ol>
<p>Given the other things that I want to do with my (limited) time, I think a more reasonable goal is 2–3 articles per week, and that’s what I’m going to try to stick with for the next couple of months. We’ll see how that goes.</p>
<p>What about other 30-day challenges? Well, I have one lined up already. Starting tomorrow, I’m going to try to do 20–30 minutes of German study per day. We’re going to be moving to Austria in a few months, and I’d like to be able to do a bit more than order beer and pretzels once we’re there!</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/colophonia.html">colophonia</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/02/01/30-day-challenge-retrospective.html</guid>
</item>
<item>
    <title>PhD Attempt Number 1</title>
    <link>http://www.skybluetrades.net/posts/2012/02/04/oxford-phd-time.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | PhD Attempt Number 1</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/02/04/oxford-phd-time.html">PhD Attempt Number 1</a></div>
    <div class="postdate">February  4, 2012</div>

    <p>I spent the period from October 1998 until November 2001 as a graduate student in the atmospheric physics department in Oxford. This all started out swimmingly.</p>
<!--MORE-->

<p>The project I was working on was a space mission to remotely sense water vapour in the atmosphere of Mars, using a novel infrared radiometer on the Mars Climate Orbiter (MCO) spacecraft<sup><a href="#fn1" class="footnoteRef" id="fnref1">1</a></sup>. I was going to write software to perform retrievals of temperature and water vapour profiles. MCO was slated to arrive at Mars near the end of my first year, so there would be <em>real data</em> to work on. Exciting stuff.</p>
<p>The first year was great. I learnt a lot of new and interesting things about remote sensing and Mars, and started developing algorithms and software. I visited the Jet Propulsion Laboratory in Pasadena, went to a conference at CalTech, and even won a departmental prize for my first year report. All very sweet.</p>
<p>A week or so before Mars Orbit Insertion, I went on holiday to the Canary Islands with my girlfriend, where we explored the cloud forests of Gomera, drank lots of cheap wine and stayed with some friends of her family. It was lovely and relaxing. We got back to my girlfriend’s place in Brighton afterwards and settled down to read the Sunday newspaper. “Here, isn’t this something to do with your work?” she asked. “‘Mars mission lost’, it says.” Uh-oh. A quick phone call to my supervisor revealed the gory details. This was the famous “metric-imperial mix-up” (it was more complicated than it sounded, but that was no excuse) that resulted in MCO being steered into the planet instead of into an orbit around the planet. Everyone in Oxford was <em>furious</em>, as this was the second time a version of this instrument had been lost.</p>
<p>Back in Oxford, I pondered my future. Friday lunchtime “planetary” beers were somewhat legendary in the department, “lunchtime” often stretching until about seven in the evening. At least one respectable visiting scientist had been discovered sleeping under a bench in the University Parks on Saturday morning, having got “lost” and being unable to find his way home or back to the department (the physics department in Oxford is next to the University Parks). This same respectable scientist afterwards referred to the planetary group as “animals” and refused to visit again. Needless to say, MCO-related sorrows were drowned and drowned again, with an additional toast or two to send them on their way.</p>
<p>Everyone in the department was depressed about the turn of events, and this led me to make a decision, that in the light of hindsight<sup><a href="#fn2" class="footnoteRef" id="fnref2">2</a></sup>, was rather foolish. I <em>could</em> have stuck with the work I was doing, built an instrument simulator to generate synthetic data based on likely Martian atmospheric profiles, finished developing retrieval algorithms which I could have tested on the synthetic data. The result would have been a perfectly respectable PhD thesis. That seemed like a dull and unadventurous approach to take. Oh, the folly of (relative) youth.</p>
<p>Instead, I chose to switch projects (and supervisors). I was going to develop optical delay line hardware and associated control software for a space interferometry mission. When I think back on this decision now, my reactions are something along the lines of “What? What what? What the <em>fuck</em>?”. It’s easy to enumerate the ways in which this was stupid: I had only a physics undergraduate’s grasp of optics and mechanical engineering, knew little about technical drafting and next to nothing about actually making things, I hated electronics as an undergraduate and had avoided it like the plague ever since, there was no money to fund this “project”, I had already spent a year on learning all about Mars and all things Martian, as well as having a lot of software already written for doing atmospheric retrievals from the PMIRR instrument. This was an idea that should have been smothered in the cradle.</p>
<p>As it was, I didn’t get very far. First thing I needed was a platform to test whatever delay line hardware I came up with. That meant an interferometer. Did we have money to buy a nice off-the-shelf metrology instrument? No, we didn’t. My supervisor said, “Well, I suppose you’d better make one then.” Right-oh. High precision machine shop work, optical system design, radio-frequency electronics, data processing electronics. What could possibly go wrong?</p>
<p>I accumulated piles of bits for an interferometer, most of which I made. I designed, built and tried to make work complicated electronics. (They never worked.) At the end of three years, I quit without a PhD and feeling pretty bitter about it all.</p>
<p>Despite that, looking back now, I don’t feel as though those three years were wasted. The outcome was less than ideal, admittedly, but I picked up an amazingly varied set of skills. I spent a lot of time in the workshop alongside people who really knew what they were doing, I learnt a lot about CAD, I learnt more about electronics than I ever really thought I wanted to know<sup><a href="#fn3" class="footnoteRef" id="fnref3">3</a></sup>. None of these were things I would have been exposed to otherwise.</p>
<p>Ten years later, part of me still wishes that I had had the good sense to stick with the remote sensing project so I could get a nice quick PhD and go and work for NASA. But the greater part of me doesn’t regret anything. Apart, perhaps, from some of those Friday “lunch” outings.</p>
<div class="footnotes">
<hr></hr>
<ol>
<li id="fn1"><p>Anyone who has followed the sorry story of “The Curse Of Mars” already knows this isn’t going to be pretty… <a href="#fnref1" class="footnoteBackLink">↩</a></p></li>
<li id="fn2"><p>Life needs a rewind button. <a href="#fnref2" class="footnoteBackLink">↩</a></p></li>
<li id="fn3"><p>I also bought a car from one of the electronics technicians for £150. A car that then burnt to the ground in a service station in France on the way back from a kayaking trip to the Alps. We had to pull all the boats and other gear from the burning car, then after the firemen had been and done their thing, I got a lift into Reims with the driver taking my car to the scrapyard, rented a van, drove my friends and all our gear to Dunkirk where I put them on the ferry, drove the van back to Reims, got a train to Calais, got the ferry to Dover, then the train back to Oxford. John, the technician, hid from me for about a week after I got back, until he had been convinced that I wasn’t going to beat him up… <a href="#fnref3" class="footnoteBackLink">↩</a></p></li>
</ol>
</div>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/past-lives.html">past-lives</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/02/04/oxford-phd-time.html</guid>
</item>
<item>
    <title>Red Plenty</title>
    <link>http://www.skybluetrades.net/posts/2012/02/05/red-plenty-review.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Red Plenty</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/02/05/red-plenty-review.html">Red Plenty</a></div>
    <div class="postdate">February  5, 2012</div>

    <p><em>by Francis Spufford</em></p>
<p>How do you make a book about central economic planning in the Soviet Union into an entertaining page-turner? You do what Francis Spufford did with <a href="http://www.redplenty.com/Front_page.html">Red Plenty</a>, a book that is almost impossible to classify, a mix of fact and fiction and dramatised might-have-beens, plausible if not quite verisimilitudinous<sup><a href="#fn1" class="footnoteRef" id="fnref1">1</a></sup> narratives populated by a melange of real historical personages and imagined characters.</p>
<p>It’s not quite fiction, not quite history. Some reviews that I’ve read weren’t comfortable with the changeling mood of the book, but I thought it was great. It’s hard to bring to life the enormity of the project, and subsequent events and the all too real lies and corruption that surrounded much of what went on in the Soviet era have obscured the visionary nature of the enterprise, but Spufford gets it across through uncovering the motivations of some of the main actors. <a href="http://en.wikipedia.org/wiki/Leonid_Kantorovich">Kantorovich</a> and his colleagues really did want to make the world a better place, to alleviate the suffering that they saw as arising from the unequal distribution of wealth in market economies, and to use science and mathematics to make the lives of ordinary working people more pleasant.</p>
<p>Eventually, the project failed, for many reasons, but there was a period in the 1950s where the expansion of the Soviet planned economy genuinely had western economists and politicians worried. The stagnation of the Brezhnev era that followed had many causes, some related to the failure to diversify the economy of the USSR beyond heavy industry and basic agriculture, but the very real achievements of the Soviet planners shouldn’t be understated. <em>Red Plenty</em> gives a realistic and sometimes cynical portrayal of life in a system supposedly based on equality and scientific planning where a word from Khruschev over the telephone condemned a whole village of striking workers to death.</p>
<p>The cynicism is brought into stark focus by the frequent use of genuine Soviet era jokes throughout the book, all of them taken from the <a href="http://etd.library.pitt.edu/ETD/available/etd-11032003-192424/unrestricted/grahamsethb_etd2003.pdf">PhD thesis</a> of Seth Benedict Graham<sup><a href="#fn2" class="footnoteRef" id="fnref2">2</a></sup>. Here’s a typical example:</p>
<blockquote>
<p>Yuri Gagarin’s daughter answers the phone. “No, mummy and daddy are out,” she says. “Daddy’s orbiting the earth, and he’ll be back tonight at 7 o’clock. But mummy’s gone shopping for groceries, so who knows when she’ll be home.”</p>
</blockquote>
<p>A lot of research went into the book: the representations of daily Soviet life feel very authentic, and the characters of some of the historical personalities who appear are finely detailed. Highly recommended.</p>
<div class="footnotes">
<hr></hr>
<ol>
<li id="fn1"><p>A little like that word I just invented. <a href="#fnref1" class="footnoteBackLink">↩</a></p></li>
<li id="fn2"><p>I actually downloaded and read this. The only Russian literature PhD thesis I have ever read. <a href="#fnref2" class="footnoteBackLink">↩</a></p></li>
</ol>
</div>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/book-reviews.html">book-reviews</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/02/05/red-plenty-review.html</guid>
</item>
<item>
    <title>Mediterranean Climate Blues...</title>
    <link>http://www.skybluetrades.net/posts/2012/02/05/swimming-pool-ice/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Mediterranean Climate Blues...</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2012/02/05/swimming-pool-ice/index.html">Mediterranean Climate Blues...</a></div>
    <div class="postdate">February  5, 2012</div>

    <p>To compensate for the psychopathic driving habits of the French, the Mediterranean climate is often offered up as a benefit of life here. For those of us who are not all that keen on temperatures in the 30s for weeks on end in the summer, that’s not much of a compensation. However, today, I would offer another piece of evidence that this “Mediterranean climate” isn’t all it’s cracked up to be. Here’s the swimming pool in our residence, with a nice layer of ice all across it. And yes, Rita is wearing a down jacket, an article of clothing more common on the ski slopes and high mountains than the Mediterranean coast…</p>
<a href="swimming-pool-ice.jpg">
<div class="img-full">
<img src="swimming-pool-ice-small.jpg" alt="Brrrr..."></img>
</div>
</a>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../../tags/photos.html">photos</a></span> <span class="tag"><a href="../../../../../tags/montpellier.html">montpellier</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/02/05/swimming-pool-ice/index.html</guid>
</item>
<item>
    <title>Link Round-up</title>
    <link>http://www.skybluetrades.net/posts/2012/02/14/link-roundup.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Link Round-up</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/02/14/link-roundup.html">Link Round-up</a></div>
    <div class="postdate">February 14, 2012</div>

    <p>Here’s a rag-bag of entertaining things…</p>
<p><a href="http://whatever.scalzi.com/">Whatever: John Scalzi’s blog</a> <br> John Scalzi writes entertaining science fiction books and is also an all-round good egg. His blog, <a href="http://whatever.scalzi.com/">Whatever</a>, has been around since forever (in internet terms). Scalzi has a magic touch when it comes to moderating comment threads: Whatever must be the politest place on the internet, all without threats or banning or rudeness from John. Scalzi’s books tend towards the light and funny, but his blog posts are sometimes more serious. Here are a couple that really stray dangerously close to thought-provoking: <a href="http://whatever.scalzi.com/2005/09/03/being-poor/">Being Poor</a>, <a href="http://whatever.scalzi.com/2010/10/18/things-i-dont-have-to-think-about-today/">Things I Don’t Have To Think About Today</a>.</p>
<p><a href="http://kasmana.people.cofc.edu/MATHFICT/">Mathematical Fiction</a> <br> Yes, everything is there to be found on the internet. Even a page detailing more or less every work of fiction involving mathematics even tangentially, scored for “Mathematical Content” and “Literary Quality” (although they do need some graphs to show whether there’s any sort of correlation between these scores!). There’s some good stuff on there, and it’s quite interesting just to browse along the “similar story” links to see where you end up.</p>
<p><a href="http://www.structuredprocrastination.com/">Structured Procrastination</a> <br> I’ve never been a fan of the <em>Getting Things Done</em> type of self-help/self-organisation book, but John Perry, a philosophy professor at Stanford, has what sounds like a perfect recipe for making progress on all those tasks that get pushed aside in favour of more interesting things. The key idea seems to be to make a task list with tasks at the top that you’re never really going to do (“Write novel.” “Learn Icelandic.” “Found religion.”) then use your other tasks as excuses to avoid these. That way you can trick yourself into actually doing things. It sounds like a great way to go, and it fits very nicely with the way that a lot of natural procrastinators already work. We don’t do <em>nothing</em>, we just do something more interesting and perhaps less important that what we’re <em>supposed</em> to be doing…</p>
<p><a href="http://www.theatlantic.com/magazine/archive/2012/03/how-your-cat-is-making-you-crazy/8873/?single_page=true">How Your Cat Is Making You Crazy</a> <br> Finally, here is one of the freakiest things I have heard about for a long time. You think you have free will? You think you’re in control of the decisions you take? Maybe you should think again. Rats infected with the parasite <em>Toxoplasma gondii</em>, which they pick up from cat faeces, exhibit a strange mix of behavioural changes, the most striking of which is that they no longer fear cats. Male rats infected with <em>T. gondii</em> find the smell of cat urine sexually exciting. Result: infected rats get eaten by cats and the parasite goes on its way to explore the next part of its charming life cycle. Big deal, you say. Who cares about freaky rats? The big deal is that <em>T. gondii</em> is a zoonose — it infects humans too. There’s not a perfect match between the parasite and human brains, since <em>T. gondii</em> evolved to jump between cats and rats, but the parasite has enough affinity for human grey matter to cause significant changes in behaviour in some carriers. It gets a little scary when you hear just what those changes are. One is increased recklessness (particularly in males), leading to detectable differences in car accident statistics for carriers compared to non-carriers. Another is schizophrenia, which shows strong correlations with <em>T. gondii</em> status. How weird is that? A parasite that lives in cats and rats may be at least partially responsible for one of the most mysterious and terrifying of mental illnesses. There is still a lot of work to be done on this, but there are some serious people involved in the research, and it sounds pretty solid.</p>
<p>For me, I guess there are two separate “whoah!” moments that come out of this. The first is about the power of evolution. The coevolution of parasites and their hosts is already strange, even before you get to mind-altering parasitic cysts that make one of the parasite’s carriers more likely to be eaten by another. I find it quite hard to get my head around this: it’s like the parasites are <em>farming</em> the rats and cats (albeit unintentionally). The second thing is the idea that schizophrenia in humans may just be collateral damage in the <em>T. gondii</em>/<em>Felis catus</em>/<em>Rattus norvegicus</em> arms race. It would be one thing for humans to suffer the by-blows of some cataclysmic war of the gods, but these are cats, rats and protozoa!</p>
<p>If you want to get even more scary, think about the fact that <em>T. gondii</em> is just one environmental parasite, one of the relatively well-studied ones. There might be dozens of other little suckers shaping you to their ineffable monocellular will. Still think you’re the one driving up there?</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/02/14/link-roundup.html</guid>
</item>
<item>
    <title>PhD Attempt Number 2</title>
    <link>http://www.skybluetrades.net/posts/2012/02/15/bristol-phd-time.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | PhD Attempt Number 2</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../posts/2012/02/15/bristol-phd-time.html">PhD Attempt Number 2</a></div>
    <div class="postdate">February 15, 2012</div>

    <p>My second attempt at a PhD went off rather better than my <a href="http://www.skybluetrades.net/posts/2012/02/04/oxford-phd-time.html">first</a>. It was all done, dusted and examined in the allotted three years, without too much psychic suffering. Even more remarkable was that, in a period of four years, both my partner Rita and myself finished, wrote up and graduated. Without any domestic bickering at all (well, more or less).</p>
<p>I put most of this down to the excellent atmosphere in the research group I was in in Bristol, founded by Paul Valdes, one of my two supervisors. We had frequent group meetings, both in the department and in the pub, there was a lot of good cross-fertilisation of ideas, and, best of all, the group was full of people I was happy to spend time with (not at all a common situation for me, as anyone who knows me will testify). It was great. Paul had a super attitude for a group leader, letting people mostly get on with what they wanted to do, never coming the big boss, and it worked really well. The <a href="http://www.bridge.bris.ac.uk/about">BRIDGE</a> group is one of the things I miss most about Bristol.</p>
<p>My other supervisor was Steve Wiggins, in the maths department. He was responsible for enormously broadening my horizons in all kinds of ways. There are mental states I would never have entered without Steve’s prodding, mostly in the form of late night emails with bundles of papers attached, saying “You really ought to know something about this stuff…”. Steve has a work ethic that would kill an ox, and I don’t think he ever missed one of our Friday morning meetings throughout the three years, despite being head of the maths department and running an active research group. I guess someone who has written five or six fat books about dynamical systems probably knows a thing or two about time management. I’m very grateful that he agreed to take me on as a student.</p>
<p>As for the work I did during my PhD time, well, I started off with all sorts of grandiose plans, and ended up producing a workmanlike though not terribly inspiring thesis about nonlinear dimensionality reduction methods. I did learn a lot along the way, and the thesis probably represents only about 20% of the work I did. Since Paul and Steve mostly left me to get on with things, I ended up doing <em>real</em> research, i.e. cocking up repeatedly and having to start over with slightly modified goals and preconceptions. I think that with more guidance, I could probably have written a more impressive end product, but I don’t think I would have learnt as much as I did during my sometimes rather pathetic flailing.</p>
<p>All in all, it was a good time. I met a lot of cool people, did a lot of caving, some kayaking, climbed some mountains, and had a lot of thinking time, something that seems to be sorely lacking as a post-doc!</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF({
        site_id: 290329,
        version: '1.0'
    });
</script>
<!-- END: Livefyre Embed -->

    <div class="tags"><span class="tag"><a href="../../../../tags/past-lives.html">past-lives</a></span></div>

</section>

</div>

      </div>

      <footer class="footer">
        Site content copyright © 2011 Ian Ross      
        Powered by <a href="http://jaspervdj.be/hakyll/">Hakyll</a>
      </footer>
    </div>

    <script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
  </body>
</html>
]]></description>
    <pubDate>No date found.</pubDate>
    <guid>http://www.skybluetrades.net/posts/2012/02/15/bristol-phd-time.html</guid>
</item>
<item>
    <title>Caterpillarpalooza!</title>
    <link>http://www.skybluetrades.net/posts/2012/02/16/caterpillarpalooza/index.html</link>
    <description><![CDATA[<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></meta>
    <title>Sky Blue Trades | Caterpillarpalooza!</title>
    <meta name="description" content>
    <meta name="author" content>
    <link rel="shortcut icon" href="../../../../../favicon.ico">
    <link rel="alternate" type="application/rss+xml" title="Sky Blue Trades" href="../../../../../rss.xml"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/layout.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/default.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/syntax.css"></link>
    <link rel="stylesheet" type="text/css" href="../../../../../css/livefyre.css"></link>
    <script type="text/javascript">
      var _gaq = _gaq || [];
      _gaq.push(['_setAccount', 'UA-22380558-1']);
      _gaq.push(['_setDomainName', 'skybluetrades.net']);
      _gaq.push(['_setAllowLinker', true]);
      _gaq.push(['_trackPageview']);

      (function() {
        var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
      ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
      var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
    })();
    </script>
  </head>
  <body>
    <div class="container">
      <div class="header">
        <a class="sitelink" href="../../../../../">skybluetrades</a>
        <a class="navlink" href="../../../../../static/about.html">about</a>
        <a class="navlink" href="mailto:ian@skybluetrades.net">mail</a>
        <div class="pagetitle">  <a href="../../../../../">sky blue trades</a></div>
      </div>

      <div class="main">
        <div class="full-col">
  <section class="post">
    <div class="posttitle"><a href="../../../../../posts/2012/02/16/caterpillarpalooza/index.html">Caterpillarpalooza!</a></div>
    <div class="postdate">February 16, 2012</div>

    <div class="img-right">
<a href="caterpillar-1.jpg"><img src="caterpillar-1-small.jpg" alt="Caterpillars!"></img></a>
</div>

<p>We saw something cool on the way to work this morning. It turns out that they’re considered pests in this part of the world, but a five metre string of nose-to-tail caterpillars counts as cool in my books even if they <em>are</em> pests. Apparently, these <a href="http://en.wikipedia.org/wiki/Pine_Processionary">little critters</a> make nests high in pine trees (we think we saw the nest — looked like a big ball of spiderweb), then troop down the tree and off into the world to make caterpillary mischief of one sort or another.</p>
<p>We first spotted the caterpillar chain coming out onto the pavement as we were walking up to Rita’s office. Keeping Winnie well out of the way (Rita takes her to work a couple of days a week), since the caterpillars are hairy and would be bad news for a little dog’s nose, we had a good look at what was going on. The caterpillars really were stuck nose-to-tail, wriggling their way along to who knows where.</p>
<p>Most of them were meeting a sad fate on the pavement, as they got stepped on and squashed, so leaving a confusing pile of caterpillar guts that led the caterpillars behind to make strange loops and knots of themselves as they could no longer tell where to go.</p>
<div class="img-left">
<a href="caterpillar-2.jpg"><img src="caterpillar-2-small.jpg" alt="Still caterpillars!"></img></a>
</div>

<p>We followed the trail of caterpillars inside the fence to the tree they were coming from. The trail stretched all the way through the pine needle litter from the tree to the fence, a distance of about three metres. With the metre of caterpillars still coming down the tree and the metre already on the pavement, that gives us five metres of caterpillars, 500 centimetres. Each caterpillar was about 2.5 cm long, so we had about 200 individuals in this troop.</p>
<p>There’s a (not very good) video <a href="http://youtu.be/HTj-Sdd2DO4">here</a> showing the extent of the procession.</p>
<p>Later on, walking home, we saw caterpillar remains in a couple of other places along the road, suggesting that there were quite a few processions that morning. The caterpillars normally come out of their nests together at night, to feed on pine needles, but they leave the nest in the same way when it’s time to pupate, so I guess that was what we were seeing today.</p>

<!-- START: Livefyre Embed -->
<script type="text/javascript" src="http://www.livefyre.com/wjs/v1.0/javascripts/livefyre_init.js"></script>
<script type="text/javascript">
    var fyre = LF
