<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.3.2" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>

<channel>
	<title>akalin.cx</title>
	<link>http://www.akalin.cx</link>
	<description>Musings on math, music, and computer science</description>
	<pubDate>Wed, 23 Jul 2008 08:20:33 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.3.2</generator>
	<language>en</language>
			<item>
		<title>July 2008 Japan Trip, Day 1</title>
		<link>http://www.akalin.cx/2008/07/23/july-2008-japan-trip-day-1/</link>
		<comments>http://www.akalin.cx/2008/07/23/july-2008-japan-trip-day-1/#comments</comments>
		<pubDate>Wed, 23 Jul 2008 08:10:23 +0000</pubDate>
		<dc:creator>akalin</dc:creator>
		
		<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://www.akalin.cx/2008/07/23/july-2008-japan-trip-day-1/</guid>
		<description><![CDATA[



My favorite place in Tokyo is the Hachiko exit around Shibuya and its
surroundings, and it was the first place my friends and I visited once
we arrived in Japan and dropped off our things at the hotel.  It was
a hot muggy afternoon but it was still as crowded as ever, especially
the famous scramble crossing:


  [...]]]></description>
			<content:encoded><![CDATA[<style>
<!--
.photo {
  border: solid 1px black;
}

.photodiv {
  text-align: center;
}
-->
</style></p>

<p>My favorite place in Tokyo is the Hachiko exit around Shibuya and its
surroundings, and it was the first place my friends and I visited once
we arrived in Japan and dropped off our things at the hotel.  It was
a hot muggy afternoon but it was still as crowded as ever, especially
the famous scramble crossing:</p>

<div class="photodiv">
  <img alt="Shibuya scramble crossing" height="600" width="800"
  class="photo" src="/july-2008-japan-trip/shibuya-scramble.jpg" />
</div>

<p>I spent some time walking around the shopping area and seeing what
changed, which wasn't much:</p>

<div class="photodiv">

  <img alt="Shibuya streets" height="600" width="800"
  class="photo" src="/july-2008-japan-trip/shibuya-streets.jpg" />
</div>

<p>And hey, the Condomania store was still there:</p>

<div class="photodiv">
  <img alt="Condomania" height="600" width="800"
  class="photo" src="/july-2008-japan-trip/shibuya-condomania.jpg" />
</div>

<p>After meeting up in Shibuya with all the SJEC people we all went to
eat at 録 ～Roku～:</p>

<div class="photodiv">
  <img alt="Dinner at 録 ～Roku～" height="600" width="800"
  class="photo" src="/july-2008-japan-trip/roku-dinner.jpg" />

</div>

<p>and then after that we had a blast at karaoke:</p>

<div class="photodiv">
  <img alt="Karaoke" height="600" width="800"
  class="photo" src="/july-2008-japan-trip/karaoke.jpg" />
</div>

<p>And no blog post about Japan would be complete without some Engrish.
Keen-eyed readers would notice a mistake in the mural on the wall
above.  Here's a close-up:</p>

<div class="photodiv">
  <img alt="Mermaid Princess, Peal legend" height="134" width="386"
  class="photo" src="/july-2008-japan-trip/peal-legend.jpg" />
</div>

<p>and here's some of the text on the other walls:</p>

<div class="photodiv">
  <img alt="At the bottom of the quiet sea, Beautiful mermaids' fighting starts now"
  height="121" width="724"
  class="photo" src="/july-2008-japan-trip/mermaids-fighting.jpg" />
  <br />
  <br />
  <img alt="The precious treasure which sleeps to deep sea"
  height="154" width="707"
  class="photo" src="/july-2008-japan-trip/sleeps-to-deep-sea.jpg" />  
</div>]]></content:encoded>
			<wfw:commentRss>http://www.akalin.cx/2008/07/23/july-2008-japan-trip-day-1/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Parallelizing FLAC encoding</title>
		<link>http://www.akalin.cx/2008/05/05/parallelizing-flac-encoding/</link>
		<comments>http://www.akalin.cx/2008/05/05/parallelizing-flac-encoding/#comments</comments>
		<pubDate>Tue, 06 May 2008 00:46:17 +0000</pubDate>
		<dc:creator>akalin</dc:creator>
		
		<category><![CDATA[Computers]]></category>

		<category><![CDATA[Technical]]></category>

		<guid isPermaLink="false">http://www.akalin.cx/2008/05/05/parallelizing-flac-encoding/</guid>
		<description><![CDATA[One thing I noticed ever since getting a multi-core system
was that the reference FLAC encoder is not multi-threaded.  This isn't
a huge problem for most people as you can simply encode multiple files
at the same time but I usually rip my audio CDs into a single audio
file with a cue sheet instead of separate track [...]]]></description>
			<content:encoded><![CDATA[<p>One thing I noticed ever since getting a <a href="http://www.akalin.cx/2008/01/27/mac-pro-first-impressions/">multi-core system</a>
was that the reference FLAC encoder is not multi-threaded.  This isn't
a huge problem for most people as you can simply encode multiple files
at the same time but I usually rip my audio CDs into a single audio
file with a cue sheet instead of separate track files and so I am
usually encoding a single large audio file instead of multiple smaller
ones.  Even so, encoding a CD-length audio file takes under a minute
but I thought it would be a fun and useful weekend project to see if I
could parallelize the simpler <a href="http://flac.cvs.sourceforge.net/flac/flac/examples/c/encode/file/main.c?revision=1.2&amp;view=markup">example encoder</a>.  The

<a href="http://flac.sourceforge.net/format.html">format specification</a> indicates that input blocks are
encoded independently which makes the problem <a href="http://en.wikipedia.org/wiki/Embarrassingly_parallel">embarassingly
parallel</a> and trawling through the <a href="http://www.mail-archive.com/flac-dev@xiph.org/msg00724.html">FLAC
mailing lists</a> reveals that no one has had the time
nor the inclination to look into it.</p>

<p>However, I was able to write a multithreaded FLAC encoder that
achieves near-linear speedup with only minor hacks to the libFLAC API.
Here are some encode times on an 8-core 2.8 GHz Xeon 5400 for a 636 MB
wave file (some caveats are discussed below):</p>

<table>
<tr>
<th>baseline</th><td>34.906s</td>

</tr>
<tr>
<th>1 threads</th><td>31.424s</td>
</tr>
<tr>
<th>2 threads</th><td>16.936s</td>
</tr>
<tr>
<th>4 threads</th><td>10.173s</td>
</tr>
<tr>

<th>8 threads</th><td>6.808s</td>
</tr>
</table>

<p>I took the simple approach of sharding the input file into

<var>n</var> roughly equal pieces and passing them to <var>n</var>
encoder threads, assembling the output file from the <var>n</var>
output buffers.  In general this is not a good way of partitioning the
workload as time is wasted if one shard takes significantly more time
to process but for my use case this isn't a significant problem.</p>

<p>The best way to share the input file among the encoding threads is to
map it into memory.  In fact, memory-mapped file I/O has so many
advantages in general that I'm surprised at how little I see it used,
although it does have the disadvantage of requiring a bit more
bookkeeping.  Here is how I use it in my multithreaded encoder
(slightly paraphrased):</p>

<pre>
#include &lt;fcntl.h&gt; /* open() */
#include &lt;sys/mman.h&gt; /* mmap()/munmap() */
#include &lt;sys/stat.h&gt; /* stat() */
#include &lt;unistd.h&gt; /* close() */

int main(int argc, char *argv[]) {
  int fdin;
  struct stat buf;
  char *bufin;

  fdin = open(argv[1], O_RDONLY);
  fstat(fdin, &#038;buf);
  bufin = mmap(NULL, buf.st_size, PROT_READ, MAP_SHARED, fdin, 0);

  /* The input file (passed in via argv[1]) is now mapped read-only to
     the memory region in bufin up to bufin + buf.st_size. */

  /* Note that you can work directly with the mapped input file
     instead of fread()ing the header into a buffer. */
  if((buf.st_size < WAV_HEADER_SIZE) ||
     memcmp(bufin, "RIFF", 4) ||
     memcmp(bufin+8, "WAVEfmt \020\000\000\000\001\000\002\000", 16) ||
     memcmp(bufin+32, "\004\000\020\000data", 8)) {
    /* Invalid input file: print error and exit. */
  }

  for (i = 0; i < num_threads; ++i) {
    shard_infos[i].bufin = bufin + WAV_HEADER_SIZE + i * bytes_per_thread;
    /* bufsize for the last thread may be slightly larger. */
    shard_infos[i].bufsize = bytes_per_thread;
  }

  /* Spawn encode threads (which calls encode_shard() below) passing
     an element of shard_infos to each. */

  ...

  munmap(bufin, buf.st_size);
  close(fdin);
}

FLAC__bool encode_shard(struct shard_info *shard_info) {
  FLAC__StreamEncoder *encoder = FLAC__stream_encoder_new();

  ...

  /* The input file is paged in lazily as this function accesses
     bufin from shard_info->bufin. */
  FLAC__stream_encoder_process_interleaved(encoder,
                                           shard_info->bufin,
                                           shard_info->bufsize);

  ...

  FLAC__stream_encoder_delete(encoder);
}
</pre>

<p>However, handling the output file is a bit trickier.  Since the
encoded FLAC data output by the threads vary in size we have to wait
until all encoding threads are done before we know the right offsets
to write the output data.  A convenient and fast way to handle this is
to use asynchronous I/O; we know where to write the output data for a
shard as soon as the encoding thread for all previous shards finish so
we simply wait for the encoding threads in shard order and queue up a
write request after each thread finishes.  Here I use the POSIX
asynchronous I/O API in my multithreaded encoder (again, slightly
paraphrased):</p>

<pre>
#include &lt;aio.h&gt; /* aio_*() */
#include &lt;pthread.h&gt; /* pthread_*() */
#include &lt;string.h&gt; /* memset() */

int main(int argc, char *argv[]) {
  int fdout;
  pthread_t threads[MAX_THREADS];
  struct aiocb aiocbs[MAX_THREADS];
  unsigned long byte_offset = 0;

  /* mmap input file in. */

  ...

  fdout = open(argv[2], O_WRONLY | O_CREAT | O_TRUNC);

  /* Spawn encode threads passing an element of shard_infos to
     each. */

  ...

  /* Wait for each thread in sequence and queue up output writes. */

  /* We need to zero out any aiocb struct that we use before we fill
     in any members. */
  memset(aiocbs, 0, num_threads * sizeof(*aiocbs));
  for (i = 0; i < num_threads; ++i) {
    pthread_join(threads[i], NULL);
    aiocbs[i].aio_buf = shard_infos[i].bufout;
    aiocbs[i].aio_nbytes = shards_infos[i].bytes_written;
    aiocbs[i].aio_offset = byte_offset;
    aiocbs[i].aio_fildes = fdout;
    aio_write(&#038;aiocbs[i]);
    byte_offset += shard_infos[i].bytes_written;
  }

  /* Wait for all output writes to finish. */

  for (i = 0; i < num_threads; ++i) {
    const struct aiocb *aiocbp = &#038;aiocbs[i];
    aio_suspend(&#038;aiocbp, 1, NULL);
    aio_return(&#038;aiocbs[i]);
  }

  close(fdout);
}
</pre>
<p>The POSIX API is a bit unwieldy for this use case; ideally, there
would be a version of <tt>aio_suspend()</tt> that would suspend the
calling process until <em>all</em> of the specified requests have completed.
As it is now the simplest way is to loop through the requests as
above, especially since the maximum number of simultaneous
asynchronous I/O requests is usually quite small (16 on my system).</p>

<p>Also, I found that the OS X implementation of <tt>aio_write()</tt>
did not obey this part of the specified behavior:</p>

<blockquote>
  <p>If O_APPEND is set for aiocbp->aio_fildes, aio_write() operations append
  to the file in the same order as the calls were made.  If O_APPEND is not
  set for the file descriptor, the write operation will occur at the abso-
  lute position from the beginning of the file plus aiocbp->aio_offset.</p>

</blockquote>

<p>but it was just as easy (and clearer) to explicitly set the correct
offset.</p>

<p>I had to hack up libFLAC a bit to implement my multithreaded encoder.
I exposed the <tt>update_metadata_()</tt> to make it easy to write the
correct number of total samples in the metadata field and also to zero
out the min/max framesize fields.  I also exposed the
<tt>FLAC__stream_encoder_set_do_md5()</tt> function (which it should
have been in the first place) so that I can turn off the writing of
md5 field in the metadata.  Finally, I added the function
<tt>FLAC__stream_encoder_set_current_frame_number()</tt> so that the
correct frame numbers are written at encode time.</p>

<p>For comparison purposes I turn off md5 calculation in my multithreaded
encoder as well as the baseline one.  Since calling
<tt>FLAC__stream_encoder_set_current_frame_number()</tt> causes
crashes with vericiation turned on I also turn that off.  The numbers
above reflect that so they're underestimates of how a production
multithreaded encoder would perform.  However, the essential behavior
of the program shouldn't change much.</p>

<p><a href="http://www.akalin.cx/patch-libFLAC.in">Here</a> is a patch file for the <a href="http://downloads.sourceforge.net/flac/flac-1.2.1.tar.gz?modtime=1189961849&amp;big_mirror=0">flac 1.2.1
source</a> that implements the hacks I described
above.  <a href="http://www.akalin.cx/mt_encode.c">Here</a> is the source for my multithreaded FLAC
encoder.  I've tested it with <tt>i686-apple-darwin9-gcc-4.0.1</tt>

and <tt>i686-apple-darwin9-gcc-4.2.1</tt> on Mac OS X.  I got the
above numbers compiling
<tt>mt_encode.c</tt> with gcc 4.2.1 and the switches <tt>-Wall
-Werror -g -O2 -ansi</tt>.</p>]]></content:encoded>
			<wfw:commentRss>http://www.akalin.cx/2008/05/05/parallelizing-flac-encoding/feed/</wfw:commentRss>
		</item>
		<item>
		<title>bfpp - embed brainfuck in C++</title>
		<link>http://www.akalin.cx/2008/04/23/bfpp-embed-brainfuck-in-cpp/</link>
		<comments>http://www.akalin.cx/2008/04/23/bfpp-embed-brainfuck-in-cpp/#comments</comments>
		<pubDate>Wed, 23 Apr 2008 08:38:30 +0000</pubDate>
		<dc:creator>akalin</dc:creator>
		
		<category><![CDATA[Computers]]></category>

		<category><![CDATA[Technical]]></category>

		<guid isPermaLink="false">http://www.akalin.cx/2008/04/23/bfpp-embeded-brainfuck-in-cpp/</guid>
		<description><![CDATA[Okay, I lied; you can't really embed brainfuck in C++
but you can get pretty close.  Here is an example:


#include "bfpp.h"

int main() {
  // Prints out factorial numbers in sequence.  Adapted from
  // http://www.hevanet.com/cristofd/brainfuck/factorial.b .
  bfpp
    * + + + + + + + + + + * [...]]]></description>
			<content:encoded><![CDATA[<p>Okay, I lied; you can't <em>really</em> embed <a href="http://www.muppetlabs.com/~breadbox/bf/">brainfuck</a> in C++
but you can get pretty close.  Here is an example:</p>

<pre>
#include "bfpp.h"

int main() {
  // Prints out factorial numbers in sequence.  Adapted from
  // http://www.hevanet.com/cristofd/brainfuck/factorial.b .
  bfpp
    * + + + + + + + + + + * * * + * + -- * * * + -- - -- &#038; &#038; &#038; &#038; &#038; -- +
    &#038; &#038; &#038; &#038; &#038; ++ * * -- -- - ++ * -- &#038; &#038; + * + * - ++ &#038; -- * + &#038; - ++ &#038;
    -- * + &#038; - -- * + &#038; - -- * + &#038; - -- * + &#038; - -- * + &#038; - -- * + &#038; - --
    * + &#038; - -- * + &#038; - -- * + &#038; - -- * -- - ++ * * * * + * + &#038; &#038; &#038; &#038; &#038; &#038;
    - -- * + &#038; - ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ * -- &#038; + * - ++ + * *
    * * * ++ &#038; &#038; &#038; &#038; &#038; -- &#038; &#038; &#038; &#038; &#038; ++ * * * * * * * -- * * * * * ++ + +
    -- - &#038; &#038; &#038; &#038; &#038; ++ * * * * * * - ++ + * * * * * ++ &#038; -- * + + &#038; - ++
    &#038; &#038; &#038; &#038; -- &#038; -- * + &#038; - ++ &#038; &#038; &#038; &#038; ++ * * -- - * -- - ++ + + + + + +
    -- &#038; + + + + + + + + * - ++ * * * * ++ &#038; &#038; &#038; &#038; &#038; -- &#038; -- * + * + &#038; &#038;
    - ++ * ! &#038; &#038; &#038; &#038; &#038; ++ * ! * * * * ++ 
  end_bfpp
}
</pre>

<p>I call this variant "bfpp" as it has some pretty significant
differences from brainfuck.  First of all, some commands had to be
adapted; although <tt>+</tt> and <tt>-</tt> remain the same,</p>

<ul>
<li><tt>&lt;</tt> and <tt>&gt;</tt> were changed to <tt>&amp;</tt> and
<tt>*</tt>,</li>
<li><tt>.</tt> and <tt>,</tt> were changed to <tt>!</tt> and <tt>~</tt>

(mnemonic: <tt>!</tt> contains <tt>.</tt> within it and <tt>~</tt>
is kind of like a sideways <tt>,</tt>),</li>
<li>and <tt>[</tt> and <tt>]</tt> were changed to <tt>--</tt> and

<tt>++</tt> (mnemonic: <tt>[</tt> and <tt>]</tt> are the most
complex brainfuck commands [to implement, at least] and so deserve to be mapped to the wider
and more prominent operators).</li>
</ul>

<p>This magic is made possible by the fact that brainfuck has exactly
eight commands and C++ has exactly eight overloadable symbolic unary
operators.  Add some macros to hide the C++ scaffolding behind some
delimiters and you have a convincing illusion of an embedded language.</p>

<p><a href="http://www.akalin.cx/bfpp.h">bfpp.h</a> implements a simple (&lt;100 lines) bfpp interpreter and
the magic described above, and <a href="http://www.akalin.cx/bf2bfpp.c">bf2bfpp.c</a> is a
straightforward translator from brainfuck to bfpp.  Gotta love C++!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.akalin.cx/2008/04/23/bfpp-embed-brainfuck-in-cpp/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A musical week</title>
		<link>http://www.akalin.cx/2008/04/03/a-musical-week/</link>
		<comments>http://www.akalin.cx/2008/04/03/a-musical-week/#comments</comments>
		<pubDate>Thu, 03 Apr 2008 10:35:22 +0000</pubDate>
		<dc:creator>akalin</dc:creator>
		
		<category><![CDATA[Classical Music]]></category>

		<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://www.akalin.cx/2008/04/03/a-musical-week/</guid>
		<description><![CDATA[Just today I got the chance to see the violinist Anne-Sophie
Mutter play the three Brahms violin sonatas.  Her
playing (as well as her accompanist Lamber Orkis') was impeccable,
although I found only the third sonata to be really interesting.  She
also came out to play four (!) encore pieces, also by Brahms.  After
dazzling performances of [...]]]></description>
			<content:encoded><![CDATA[<p>Just today I got the chance to see the violinist <a href="http://en.wikipedia.org/wiki/Anne-Sophie_Mutter">Anne-Sophie
Mutter</a> play the three Brahms violin sonatas.  Her
playing (as well as her accompanist Lamber Orkis') was impeccable,
although I found only the third sonata to be really interesting.  She
also came out to play four (!) encore pieces, also by Brahms.  After
dazzling performances of three of the Hungarian Dances (the first two
were Nos. 7 and 1 but I did not catch the third one) she played the
<a href="http://en.wikipedia.org/wiki/Brahms%27_Lullaby"><em>Weigenlied</em></a> before bidding good night.</p>

<p>Also this past weekend I and a group of fellow pianists played at a
party hosted by their former piano teacher.  I had the rare chance to
hear the formidable solo version of Gershwin's <em>Rhapsody in Blue</em>
performed (<a href="http://www.youtube.com/watch?v=EeS9eT88hFY">first part here</a> and <a href="http://www.youtube.com/watch?v=ZRY_PEWhnzo">second part
here</a>) as well as one of Ginastera's more
accessible works, the second of the <em>Tres Danzas Argentinas</em> (1:40 in
<a href="http://youtube.com/watch?v=WZQE53BDM-I">this clip</a>).  I with my duet partner played
the <a href="http://youtube.com/watch?v=Txt6b6JJixg">Waltz</a> and <a href="http://youtube.com/watch?v=myqHI10zyDs">Romance</a> from Rachmaninoff's second
two-piano suite and his <em>Rhapsody on a Theme of Paganini</em>, arranged by
Rachmaninoff himself for two pianos (<a href="http://www.youtube.com/watch?v=ORP4dlwNsKM">first part
here</a>, <a href="http://youtube.com/watch?v=_Fjoj_fTeOk">second part here</a>,
and <a href="http://youtube.com/watch?v=_Fjoj_fTeOk">third part here</a>, with the famous 18th
variation being 5:24 in the second part).</p>

<p>I also finally started looking at new pieces again.  I ordered some of
<a href="http://www.fazilsay.net/">Fazil Say</a>'s published sheet music
(<a href="http://youtube.com/watch?v=gOo_IZypu6U">these</a> <a href="http://youtube.com/watch?v=MFSm5_4afro">pieces</a>, among others) and
I am also looking at <a href="http://en.wikipedia.org/wiki/Sonata_No._3_(Scriabin)">Scriabin's third sonata</a>
(<a href="http://youtube.com/watch?v=z3Al8sDdNpc">first movement here</a>, <a href="http://youtube.com/watch?v=E4Jt59leFbk">second movement
here</a>, <a href="http://youtube.com/watch?v=4zzsXkgYyps">third movement
here</a>, and <a href="http://youtube.com/watch?v=l5z53PQeavY">fourth movement
here</a>) which has always been a favorite of mine.
It is shaping up to be a fine challenge; one particularly obnoxious
section has an ossia (a simplified version of a passage) with the
footnote:</p>

<blockquote>
  <p>This passage, difficult to perform at a rapid tempo, was played
    differently by Scriabin himself[.]</p>
</blockquote>

<p>Hopefully this marks an end to the musical slump I've been in; it's
been too long since I've prepared new pieces.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.akalin.cx/2008/04/03/a-musical-week/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Mac Pro woes</title>
		<link>http://www.akalin.cx/2008/01/27/mac-pro-woes/</link>
		<comments>http://www.akalin.cx/2008/01/27/mac-pro-woes/#comments</comments>
		<pubDate>Sun, 27 Jan 2008 22:44:26 +0000</pubDate>
		<dc:creator>akalin</dc:creator>
		
		<category><![CDATA[Computers]]></category>

		<category><![CDATA[Technical]]></category>

		<guid isPermaLink="false">http://www.akalin.cx/2008/01/27/mac-pro-woes/</guid>
		<description><![CDATA[I woke today to find my computer restarted instead of waking from sleep.  Then 10 minutes later it froze with some graphics corruption.  Looks like I&#8217;ve been hit with the problems described in this thread and on this page.  I will try an SMC reset and PRAM reset but if it doesn&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p>I woke today to find my computer restarted instead of waking from sleep.  Then 10 minutes later it froze with some graphics corruption.  Looks like I&#8217;ve been hit with the problems described in <a href="http://discussions.apple.com/thread.jspa?messageID=6434024">this thread</a> and on <a href="http://xlr8yourmac.com/systems/2008_mac_pro_reports.html">this page</a>.  I will try an SMC reset and PRAM reset but if it doesn&#8217;t work I might have to exchange this for another one.</p>
<p>On a brighter note <a href="http://macapper.com/2007/11/27/parallels-tip-relocate-your-windows-taskbar/">this tip</a> solved my gripe with Parallels&#8217; coherence mode.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.akalin.cx/2008/01/27/mac-pro-woes/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Mac Pro first impressions</title>
		<link>http://www.akalin.cx/2008/01/27/mac-pro-first-impressions/</link>
		<comments>http://www.akalin.cx/2008/01/27/mac-pro-first-impressions/#comments</comments>
		<pubDate>Sun, 27 Jan 2008 11:57:09 +0000</pubDate>
		<dc:creator>akalin</dc:creator>
		
		<category><![CDATA[Computers]]></category>

		<category><![CDATA[Technical]]></category>

		<guid isPermaLink="false">http://www.akalin.cx/2008/01/27/mac-pro-first-impressions/</guid>
		<description><![CDATA[I was long overdue for a computer upgrade so I decided to take the plunge and get the newly-upgraded Mac Pro.  Here are my thoughts in no particular order.
First, this thing is seriously heavy, weighing 43.4 lbs when removed from the box.  It is much quieter than my old Athlon, though.
I was waiting [...]]]></description>
			<content:encoded><![CDATA[<p>I was long overdue for a computer upgrade so I decided to take the plunge and get the <a href="http://www.apple.com/macpro/">newly-upgraded Mac Pro</a>.  Here are my thoughts in no particular order.</p>
<p>First, this thing is seriously heavy, weighing 43.4 lbs when removed from the box.  It is much quieter than my old Athlon, though.</p>
<p>I was waiting to buy this because I was expecting the 8-core (or &#8220;arachnocore&#8221; if you prefer) models to go from stupidly expensive ($4000) to moderately expensive ($2800).  I bought the stock configuration; not buying RAM or extra hard drives from Apple was a no-brainer, and although I wanted to get the 8800 GT instead of the default 2600 XT it would have pushed the shipment date out over a month.  I can always upgrade later which might cost a little more, depending on how much I can sell the 2600 XT for.</p>
<pre>
Babbage:~ akalin$ for i in `seq 1 8`; do (yes $i >/dev/null &#038;); done
Babbage:~ akalin$ top -o cpu
  PID COMMAND      %CPU   TIME   #TH #PRTS #MREGS RPRVT  RSHRD  RSIZE  VSIZE
53600 yes         99.1%  0:25.62   1    13     18  208K   188K   416K    18M
53612 yes         99.0%  0:25.58   1    13     18  208K   188K   416K    18M
53604 yes         98.6%  0:25.27   1    13     18  208K   188K   416K    18M
53598 yes         98.0%  0:25.74   1    13     18  208K   188K   416K    18M
53608 yes         95.6%  0:25.30   1    13     18  208K   188K   416K    18M
53602 yes         94.6%  0:25.84   1    13     18  208K   188K   416K    18M
53606 yes         94.5%  0:25.49   1    13     18  208K   188K   416K    18M
53610 yes         93.1%  0:25.77   1    13     18  208K   188K   416K    18M
</pre>
<p>Yeap, it&#8217;s 8 cores all right.  I&#8217;m a bit disappointed that the overall CPU usage in &#8220;top&#8221; is properly normalized to [0%, 100%] instead of the more impressive [0%, 800%], though.</p>
<p>It is nice to be running a *nix as a primary OS again.  However, one thing Windows does well is support weird display configurations, like my two rotatable widescreen monitors.  I&#8217;m still using one of the monitors for my old computer but hopefully OS X will be able to switch monitor orientations (preferably with a hotkey) like my old setup.  I&#8217;ll find out soon.</p>
<p>Setting up Boot Camp was a breeze but I had a ton of problems with Parallels.  First I tried using it with my Boot Camp partition but it never detected my keyboard and mouse no matter how long I waited.  Worse yet, it messed up the driver configuration enough so that even with booting back into Windows from Boot Camp I was unable to use my keyboard and mouse.  After I started having weird freezes when switching back and forth between OS X and Windows I decided to scrap the Windows partition and start over.  After installing Windows a second time I used Disk Utility to image the partition before I tried Parallels on it again.  After confirming that it still didn&#8217;t work, I just restore the Boot Camp partition from the backup and had Parallels work on its own separate image.  It&#8217;s slightly more inconvenient but it&#8217;s probably a more stable setup.</p>
<p>Another problem with Parallels is that it refuses to start up after a reboot, complaining about not being able to communicate with services.  Reinstalling Parallels solves the problem but that&#8217;s annoying to do on every reboot.  I&#8217;ll have to investigate further.</p>
<p>Parallels performs really well even with only 512 MB of RAM allocated to it on business apps and non-3d games.  However, its 3d support is still lacking; <a href="http://www.mythos.com/">Mythos</a> suffers from show-stopping graphics corruption and crashes, and even when it runs I get only about 10 fps. However, Mythos performs beautifully with Boot Camp, getting ~40 fps with everything but shadows turned all the way up.  This makes me curious as to how well WoW performs, but that&#8217;s tempting fate.</p>
<p>Booting into Boot Camp to play games is a bit of a pain but it&#8217;s mitigated by being able to hibernate in Windows.  Curiously, OS X is lacking in this department; you can use a widget called &#8220;Deep Sleep&#8221; to put it into the equivalent &#8220;Safe Sleep&#8221;, but starting the computer again does not let you switch partitions as far as I can tell, so it&#8217;s useless for switching quickly between operating systems.  I&#8217;ll have to investigate further into this, too.</p>
<p>Some miscellaneous gripes:</p>
<ul>
<li>Disk Utility has this really weird bug where it would only rarely let me drag the disk to restore from an image to the &#8220;Destination&#8221; field.  I just ended up using the equivalent command-line utility &#8220;asr&#8221;.</li>
<li>Not having an eject button on optical drives is annoying, especially when in Windows.</li>
<li>Safari does not close tabs on middle-click.</li>
<li>Safari is fickle when deciding when to let you use cmd-shift-left/right to move between tabs.</li>
<li>Coherence mode in Parallels leaves the entire taskbar visible.  Perhaps this has something to do with me using the classic theme/Start menu.</li>
<li>I wish there was a way to turn off the &#8220;<a href="http://docs.info.apple.com/article.html?artnum=306811">Caps Lock protection</a>&#8221; in the new thin Apple keyboards as I bind it to Ctrl.  I&#8217;m not impressed with its feel anyway, so I&#8217;ll probably end up buying another keyboard.  I&#8217;m seriously considering getting the <a href="http://www.geekstuff4u.com/product_info.php?manufacturers_id=&#038;products_id=346">Happy Hacking Keyboard Professional 2</a>, but it&#8217;s stupidly expensive.</li>
<li>I find the Mighty Mouse quite uncomfortable to use due to its shape.  It is also quite finicky and sometimes the pointer goes off wildly to a corner of the screen.  I&#8217;ll probably stick with an <a href="http://www.microsoft.com/hardware/gaming/productdetails.aspx?pid=087">IntelliMouse Explorer</a>.</li>
</ul>
<p>Overall I&#8217;m quite satisfied with this computer.  I look forward to learning the ins and outs of OS X which I was unable to really do when interacting with it only on laptops.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.akalin.cx/2008/01/27/mac-pro-first-impressions/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Backwards day at akalin.cx</title>
		<link>http://www.akalin.cx/2008/01/27/backwards-day-at-akalincx/</link>
		<comments>http://www.akalin.cx/2008/01/27/backwards-day-at-akalincx/#comments</comments>
		<pubDate>Sun, 27 Jan 2008 10:59:00 +0000</pubDate>
		<dc:creator>akalin</dc:creator>
		
		<category><![CDATA[Computers]]></category>

		<category><![CDATA[Site]]></category>

		<category><![CDATA[Technical]]></category>

		<guid isPermaLink="false">http://www.akalin.cx/2008/01/27/backwards-day-at-akalincx/</guid>
		<description><![CDATA[If any of you have glanced at my blog lately or (more likely) I&#8217;ve complained about it to you, you&#8217;d know that blog entries have been appearing in reverse order for a while.  From other people with the same problem it looks like this MySQL bug was the culprit, and indeed this post from [...]]]></description>
			<content:encoded><![CDATA[<p>If any of you have glanced at my blog lately or (more likely) I&#8217;ve complained about it to you, you&#8217;d know that blog entries have been appearing in reverse order for a while.  From <a href="http://comox.textdrive.com/pipermail/wp-hackers/2008-January/017200.html">other people with the same problem</a> it looks like <a href="http://bugs.mysql.com/bug.php?id=30596">this MySQL bug</a> was the culprit, and indeed <a href="http://blog.apisnetworks.com/2008/01/09/minor-maintenance-window-tonight-mysql-upgrade-ssl-certificate-refresh/">this post from my host</a> confirms that MySQL was upgraded recently.  5.0.52 is out only for enterprise customers now but this only affects older versions of WordPress so I just gritted my teeth and went through the pain of upgrading to the latest version of WordPress.</p>
<p>We now return to your regularly scheduled programming.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.akalin.cx/2008/01/27/backwards-day-at-akalincx/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Finding the longest palindromic substring in linear time</title>
		<link>http://www.akalin.cx/2007/11/28/finding-the-longest-palindromic-substring-in-linear-time/</link>
		<comments>http://www.akalin.cx/2007/11/28/finding-the-longest-palindromic-substring-in-linear-time/#comments</comments>
		<pubDate>Wed, 28 Nov 2007 09:58:41 +0000</pubDate>
		<dc:creator>akalin</dc:creator>
		
		<category><![CDATA[Computers]]></category>

		<category><![CDATA[Technical]]></category>

		<guid isPermaLink="false">https://secure.akalin.cx/2007/11/28/finding-the-longest-palindromic-substring-in-linear-time/</guid>
		<description><![CDATA[
/*

Another interesting
problem I stumbled across on reddit is finding the longest
substring of a given string that is a palindrome.  I found the
explanation on Johan Jeuring's blog somewhat confusing and I had
to spend some time poring over the Haskell code (eventually rewriting
it in Python) and walking through examples before it "clicked."  I
haven't found any [...]]]></description>
			<content:encoded><![CDATA[<style type="text/css" media="all">
/*<![CDATA[*/
span.palind {
  color: red;
}
/*]]&gt;*/
</style>

<p>Another <a
href="http://programming.reddit.com/info/2dykz/comments/c2e7r0">interesting
problem</a> I stumbled across on reddit is finding the longest
substring of a given string that is a palindrome.  I found <a
href="http://johanjeuring.blogspot.com/2007/08/finding-palindromes.html">the
explanation on Johan Jeuring's blog</a> somewhat confusing and I had
to spend some time poring over the Haskell code (eventually rewriting
it in Python) and walking through examples before it "clicked."  I
haven't found any other explanations of the same approach so hopefully
my explanation below will help the next person who is curious about
this problem.</p>

<p>Of course, the most naive solution would be to exhaustively examine
all <var>n</var> (<var>n</var> + 1) / 2 substrings of the given
<var>n</var>-length string, test each one if it's a palindrome, and
keep track of the longest one seen so far.  This has worst-case
complexity <var>O</var>(<var>n</var><sup>3</sup>), but we can easily
do better by realizing that a palindrome is centered on either a
letter (for odd-length palindromes) or a space between letters (for
even-length palindromes).  Therefore we can examine all 2<var>n</var>
+ 1 possible centers and find the longest palindrome for that center,
keeping track of the overall longest palindrome.  This has worst-case
complexity <var>O</var>(<var>n</var><sup>2</sup>).</p>

<p>It is not immediately clear that we can do better but if we're told
that an <var>O</var>(<var>n</var>) algorithm exists we can infer that
the algorithm is most likely structured as an iteration through all
possible centers.  As an off-the-cuff first attempt, we can adapt the
above algorithm by keeping track of the current center and expanding
until we find the longest palindrome around that center, in which case
we then consider the last letter (or space) of that palindrome as the
new center.  The algorithm (which isn't correct) looks like this
informally:</p>

<pre>
1. set the current center to the first letter
2. loop while the current center is valid
  a. expand to the left and right simultaneously until we find the largest
     palindrome around this center
  b. if the current palindrome is bigger than the stored maximum one, store
     the current one as the maximum one
  c. set the space following the current palindrome as the current center
     unless the two letters immediately surrounding it are different, in
     which case set the last letter of the current palindrome as the current
     center
3. return the stored maximum palindrome
</pre>

<p>This seems to work but it doesn't handle all cases: consider the
string "abababa".  The first non-trivial palindrome we see is "<span
class="palind">a</span>|bababa", followed by "<span
class="palind">aba</span>|baba".  Considering the current space as the
center doesn't get us anywhere but considering the preceding letter
(the second 'a') as the center, we can expand to get "<span
class="palind">ababa</span>|ba".  From this state, considering the
current space again doesn't get us anywhere but considering the preceding
letter as the center, we can expand to get "ab<span
class="palind">ababa</span>|".  However, this is incorrect as the
longest palindrome is actually the entire string!  We can remedy this
case by changing the algorithm to try and set the new center to be one
before the end of the last palindrome, but it is clear that having a
fixed "lookbehind" doesn't solve the general case and anything more
than that will probably bump us back up to quadratic time.</p>

<p>The key question is this: given the state from the example above,
"<span class="palind">ababa</span>|ba", what makes the second 'b' so
special that it should be the new center?  To use another example, in
"<span class="palind">abcbabcba</span>|bcba", what makes the second
'c' so special that it should be the new center?  Hopefully, the
answer to this question will lead to the answer to the more important
question: once we stop expanding the palindrome around the current
center, how do we pick the next center?  To answer the first question,
first notice that the current palindromes in the above examples
themselves contain smaller non-trivial palindromes: "ababa" contains
"aba" and "abcbabcba" contains "abcba" which also contains "bcb".
Then, notice that if we expand around the "special" letters, we get a
palindrome which shares a right edge with the current palindrome; that
is, <em>the longest palindrome around the special letters are proper
suffixes of the current palindrome</em>.  With a little thought, we
can then answer the second question: <em>to pick the next center, take
the center of the longest palindromic proper suffix of the current
palindrome</em>.  Our algorithm then looks like this:</p>

<pre>
1. set the current center to the first letter
2. loop while the current center is valid
  a. expand to the left and right simultaneously until we find the largest
     palindrome around this center
  b. if the current palindrome is bigger than the stored maximum one, store
     the current one as the maximum one
  c. find the maximal palindromic proper suffix of the current palindrome
  d. set the center of the suffix from c as the current center and start
     expanding from the suffix as it is palindromic
3. return the stored maximum palindrome
</pre>

<p>However, unless step 2c can be done efficiently, it will cause the
algorithm to be superlinear.  Doing step 2c efficiently seems
impossible since we have to examine the entire current palindrome to
find the longest palindromic suffix unless we somehow keep track of
extra state as we progress through the input string.  Notice that the
longest palindromic suffix would by definition also be a palindrome of
the input string so it might suffice to keep track of every
palindrome that we see as we move through the string and hopefully,
by the time we finish expanding around a given center, we would know
where all the palindromes with centers lying to the left of the
current one are.  However, if the longest palindromic suffix has a
center to the right of the current center, we would not know about it.
But we also have at our disposal the very useful fact that <em>a
palindromic proper suffix of a palindrome has a corresponding dual
palindromic proper prefix</em>.  For example, in one of our examples
above, "abcbabcba", notice that "abcba" appears twice: once as a
prefix and once as a suffix.  Therefore, while we wouldn't know about
all the palindromic suffixes of our current palindrome, we would know
about either it or its dual.</p>

<p>Another crucial realization is the fact that we don't have to keep
track of all the palindromes we've seen.  To use the example
"abcbabcba" again, we don't really care about "bcb" that much, since
it's already contained in the palindrome "abcba".  In fact, we only
really care about keeping track of the longest palindromes for a given
center or equivalently, the length of the longest palindrome for a
given center.  But this is simply a more general version of our
original problem, which is to find the longest palindrome around
<em>any</em> center!  Thus, if we can keep track of this state
efficiently, maybe by taking advantage of the properties of
palindromes, we don't have to keep track of the maximal palindrome and
can instead figure it out at the very end.</p>

<p>Unfortunately, we seem to be back where we started; the second
naive algorithm that we have is simply to loop through all possible
centers and for each one find the longest palindrome around that
center.  But our discussion has led us to a different incremental
formulation: given a current center, the longest palindrome around
that center, and a list of the lengths of the longest palindromes
around the centers to the left of the current center, can we figure
out the new center to consider and extend the list of longest
palindrome lengths up to that center efficiently?  For example, if we
have the state:</p>

<p>&lt;"ab<span class="palind">a</span>ba|??", [0, 1, 0, 3, 0, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?]&gt;</p>

<p>where the highlighted letter is the current center, the vertical line
is our current position, the question marks represent unread
characters or unknown quantities, and the array represents the list
of longest palindrome lengths by center, can we get to the state:</p>

<p>&lt;"aba<span class="palind">b</span>a|??", [0, 1, 0, 3, 0, 5, 0, ?, ?, ?, ?, ?, ?, ?, ?]&gt;</p>

<p>and then to:</p>

<p>&lt;"aba<span class="palind">b</span>aba|", [0, 1, 0, 3, 0, 5, 0, 7, 0, 5, 0, 3, 0, 1, 0]&gt;</p>

<p>efficiently?  The crucial thing to notice is that the longest
palindrome lengths array (we'll call it simply the lengths array) in
the final state is palindromic since the original string is
palindromic.  In fact, the lengths array obeys a more general
property: <em>the longest palindrome <var>d</var> places to the right
of the current center (the <var>d</var>-right palindrome) is at least
as long as the longest palindrome d places to the left of the current
center (the <var>d</var>-left palindrome) if the <var>d</var>-left
palindrome is completely contained in the longest palindrome around
the current center (the center palindrome), and it is of equal length
if the <var>d</var>-left palindrome is not a prefix of the center
palindrome or if the center palindrome is a suffix of the entire
string</em>.  This then implies that we can more or less fill in the
values to the right of the current center from the values to the left
of the current center.  For example, from [0, 1, 0, 3, 0, 5, ?, ?, ?,
?, ?, ?, ?, ?, ?] we can get to [0, 1, 0, 3, 0, 5, 0, &ge;3?, 0,
&ge;1?, 0, ?, ?, ?, ?].  This also implies that the first unknown
entry (in this case, &ge;3?) should be the new center because it
means that the center palindrome is not a suffix of the input string
(i.e., we're not done) and that the <var>d</var>-left palindrome is a
prefix of the center palindrome.</p>

<p>From these observations we can construct our final algorithm which
returns the lengths array, and from which it is easy to find the
longest palindromic substring:</p>

<pre>
1. initialize the lengths array to the number of possible centers
2. set the current center to the first center
3. loop while the current center is valid
  a. expand to the left and right simultaneously until we find the largest
     palindrome around this center
  b. fill in the appropriate entry in the longest palindrome lengths array
  c. iterate through the longest palindrome lengths array backwards and fill
     in the corresponding values to the right of the entry for the current
     center until an unknown value (as described above) is encountered
  d. set the new center to the index of this unknown value
4. return the lengths array
</pre>

<p>Note that at each step of the algorithm we're either incrementing
our current position in the input string or filling in an entry in the
lengths array.  Since the lengths array has size linear in the size of
the input array, the algorithm has worst-case linear running time.
Since given the lengths array we can find and return the longest
palindromic substring in linear time, a linear-time algorithm to find
the longest palindromic substring is the composition of these two
operations.</p>

<p>Here is Python code that implements the above algorithm (although
it is closer to Johan Jeuring's Haskell implementation than to the
above description):</p>

<pre class="python" style="background: #eeeeee;"><span style="color: #ff7700;font-weight:bold;">def</span> fastLongestPalindromes<span style="color: black;">&#40;</span>seq<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;</span><span style="color: #483d8b;">&quot;
    Behaves identically to naiveLongestPalindrome (see below), but runs in linear time.
    &quot;</span><span style="color: #483d8b;">&quot;&quot;</span>
    seqLen = <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>seq<span style="color: black;">&#41;</span>
    l = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
    i = <span style="color: #ff4500;">0</span>
    palLen = <span style="color: #ff4500;">0</span>
    <span style="color: #808080; font-style: italic;"># Loop invariant: seq[(i - palLen):i] is a palindrome.</span>
    <span style="color: #808080; font-style: italic;"># Loop invariant: len(l) &gt;= 2 * i - palLen. The code path that </span>
    <span style="color: #808080; font-style: italic;"># increments palLen skips the l-filling inner-loop.</span>
    <span style="color: #808080; font-style: italic;"># Loop invariant: len(l) &lt; 2 * i + 1. Any code path that increments</span>
    <span style="color: #808080; font-style: italic;"># i past seqLen - 1 exits the loop early and so skips the</span>
    <span style="color: #808080; font-style: italic;"># l-filling inner loop.</span>
    <span style="color: #ff7700;font-weight:bold;">while</span> i &lt; seqLen:
        <span style="color: #808080; font-style: italic;"># First, see if we can extend the current palindrome.  Note that</span>
        <span style="color: #808080; font-style: italic;"># the center of the palindrome remains fixed.</span>
        <span style="color: #ff7700;font-weight:bold;">if</span> i &gt; palLen <span style="color: #ff7700;font-weight:bold;">and</span> seq<span style="color: black;">&#91;</span>i - palLen - <span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> == seq<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span>:
            palLen += <span style="color: #ff4500;">2</span>
            i += <span style="color: #ff4500;">1</span>
            <span style="color: #ff7700;font-weight:bold;">continue</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># The current palindrome is as large as it gets, so we append it.</span>
        l.<span style="color: black;">append</span><span style="color: black;">&#40;</span>palLen<span style="color: black;">&#41;</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Now to make further progress, we look for a smaller palindrome</span>
        <span style="color: #808080; font-style: italic;"># sharing the right edge with the current palindrome.  If we find</span>
        <span style="color: #808080; font-style: italic;"># one, we can try to expand it and see where that takes us.</span>
        <span style="color: #808080; font-style: italic;"># At the same time, we can fill the values for l that we neglected</span>
        <span style="color: #808080; font-style: italic;"># during the loop above. We make use of our knowledge of the length</span>
        <span style="color: #808080; font-style: italic;"># of the previous palindrome (palLen) and the fact that the values</span>
        <span style="color: #808080; font-style: italic;"># of l for positions on the right half of the palindrome are</span>
        <span style="color: #808080; font-style: italic;"># closely related to the values of the corresponding positions on</span>
        <span style="color: #808080; font-style: italic;"># the left half of the palindrome.</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Traverse backwards starting from the second-to-last index up</span>
        <span style="color: #808080; font-style: italic;"># to the edge of the last palindrome.</span>
        s = <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>l<span style="color: black;">&#41;</span> - <span style="color: #ff4500;">2</span>
        e = s - palLen
        <span style="color: #ff7700;font-weight:bold;">for</span> j <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>s, e, <span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>:
            <span style="color: #808080; font-style: italic;"># d is the value l[j] must have in order for the palindrome</span>
            <span style="color: #808080; font-style: italic;"># centered there to share the left edge with the last palindrome.</span>
            <span style="color: #808080; font-style: italic;"># (Drawing it out is helpful to understanding why the - 1</span>
            <span style="color: #808080; font-style: italic;"># is there.)</span>
            d = j - e - <span style="color: #ff4500;">1</span>
&nbsp;
            <span style="color: #808080; font-style: italic;"># We check to see if the palindrome at l[j] shares a left edge</span>
            <span style="color: #808080; font-style: italic;"># with the last palindrome.  If so, the corresponding palindrome</span>
            <span style="color: #808080; font-style: italic;"># on the right half must share the right edge with the last</span>
            <span style="color: #808080; font-style: italic;"># palindrome, and so we have a new value for palLen.</span>
            <span style="color: #ff7700;font-weight:bold;">if</span> l<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span> == d: <span style="color: #808080; font-style: italic;"># *</span>
                palLen = d
                <span style="color: #808080; font-style: italic;"># We actually want to go to the beginning of the outer</span>
                <span style="color: #808080; font-style: italic;"># loop, but Python doesn't have loop labels.  Instead,</span>
                <span style="color: #808080; font-style: italic;"># we use an else block corresponding to the inner loop,</span>
                <span style="color: #808080; font-style: italic;"># which gets executed only when the for loop exits normally</span>
                <span style="color: #808080; font-style: italic;"># (i.e., not via break).</span>
                <span style="color: #ff7700;font-weight:bold;">break</span>
&nbsp;
            <span style="color: #808080; font-style: italic;"># Otherwise, we just copy the value over to the right side.</span>
            <span style="color: #808080; font-style: italic;"># We have to bound l[i] because palindromes on the left side</span>
            <span style="color: #808080; font-style: italic;"># could extend past the left edge of the last palindrome,</span>
            <span style="color: #808080; font-style: italic;"># whereas their counterparts won't extend past the right edge.</span>
            l.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: #008000;">min</span><span style="color: black;">&#40;</span>d, l<span style="color: black;">&#91;</span>j<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
        <span style="color: #ff7700;font-weight:bold;">else</span>:
            <span style="color: #808080; font-style: italic;"># This code is executed in two cases: when the for loop</span>
            <span style="color: #808080; font-style: italic;"># isn't taken at all (palLen == 0) or the inner loop was</span>
            <span style="color: #808080; font-style: italic;"># unable to find a palindrome sharing the left edge with the</span>
            <span style="color: #808080; font-style: italic;"># last palindrome.  In either case, we're free to consider</span>
            <span style="color: #808080; font-style: italic;"># the palindrome centered at seq[i].</span>
            palLen = <span style="color: #ff4500;">1</span>
            i += <span style="color: #ff4500;">1</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># We know from the loop invariant that len(l) &lt; 2 * seqLen + 1, so we</span>
    <span style="color: #808080; font-style: italic;"># must fill in the remaining values of l.</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Obviously, the last palindrome we're looking at can't grow any more.</span>
    l.<span style="color: black;">append</span><span style="color: black;">&#40;</span>palLen<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #808080; font-style: italic;"># Traverse backwards starting from the second-to-last index up until</span>
    <span style="color: #808080; font-style: italic;"># we get l to size 2 * seqLen + 1. We can deduce from the loop invariants</span>
    <span style="color: #808080; font-style: italic;"># we have enough elements.</span>
    lLen = <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>l<span style="color: black;">&#41;</span>
    s = lLen - <span style="color: #ff4500;">2</span>
    e = s - <span style="color: black;">&#40;</span><span style="color: #ff4500;">2</span> * seqLen + <span style="color: #ff4500;">1</span> - lLen<span style="color: black;">&#41;</span>
    <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>s, e, <span style="color: #ff4500;">-1</span><span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># The d here uses the same formula as the d in the inner loop above.</span>
        <span style="color: #808080; font-style: italic;"># (Computes distance to left edge of the last palindrome.)</span>
        d = i - e - <span style="color: #ff4500;">1</span>
        <span style="color: #808080; font-style: italic;"># We bound l[i] with min for the same reason as in the inner loop</span>
        <span style="color: #808080; font-style: italic;"># above.</span>
        l.<span style="color: black;">append</span><span style="color: black;">&#40;</span><span style="color: #008000;">min</span><span style="color: black;">&#40;</span>d, l<span style="color: black;">&#91;</span>i<span style="color: black;">&#93;</span><span style="color: black;">&#41;</span><span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> l</pre>

<p>(* An exercise for the reader: in this place in the code you might
think that you can replace the == with >= to improve performance.
This does not change the correctness of the algorithm but it does hurt
performance, contrary to expectations.  Why?)</p>

<p>And here is a naive quadratic version for comparison:</p>

<pre class="python" style="background: #eeeeee;"><span style="color: #ff7700;font-weight:bold;">def</span> naiveLongestPalindromes<span style="color: black;">&#40;</span>seq<span style="color: black;">&#41;</span>:
    <span style="color: #483d8b;">&quot;&quot;</span><span style="color: #483d8b;">&quot;
    Given a sequence seq, returns a list l such that l[2 * i + 1] holds the
    length of the longest palindrome centered at seq[i] (which must be odd),
    l[2 * i] holds the length of the longest palindrome centered between
    seq[i - 1] and seq[i] (which must be even), and l[2 * len(seq)] holds
    the length of the longest palindrome centered past the last element of
    seq (which must be 0, as is l[0]).
&nbsp;
    The actual palindrome for l[i] is seq[s:(s + l[i])] where s is
    i // 2 - l[i] // 2. (// is integer division.)
&nbsp;
    Example:
    naiveLongestPalindrome('ababa') -&gt; [0, 1, 0, 3, 0, 5, 0, 3, 0, 1]
&nbsp;
    Runs in quadratic time.
    &quot;</span><span style="color: #483d8b;">&quot;&quot;</span>
    seqLen = <span style="color: #008000;">len</span><span style="color: black;">&#40;</span>seq<span style="color: black;">&#41;</span>
    lLen = <span style="color: #ff4500;">2</span> * seqLen + <span style="color: #ff4500;">1</span>
    l = <span style="color: black;">&#91;</span><span style="color: black;">&#93;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">for</span> i <span style="color: #ff7700;font-weight:bold;">in</span> <span style="color: #008000;">xrange</span><span style="color: black;">&#40;</span>lLen<span style="color: black;">&#41;</span>:
        <span style="color: #808080; font-style: italic;"># If i is even (i.e., we're on a space), this will produce</span>
        <span style="color: #808080; font-style: italic;"># e == s.  Otherwise, we're on an element and e == s + 1, as</span>
        <span style="color: #808080; font-style: italic;"># a single letter is trivially a palindrome.</span>
        s = i / <span style="color: #ff4500;">2</span>
        e = s + i % <span style="color: #ff4500;">2</span>
&nbsp;
        <span style="color: #808080; font-style: italic;"># Loop invariant: seq[s:e] is a palindrome.</span>
        <span style="color: #ff7700;font-weight:bold;">while</span> s &gt; <span style="color: #ff4500;">0</span> <span style="color: #ff7700;font-weight:bold;">and</span> e &lt; seqLen <span style="color: #ff7700;font-weight:bold;">and</span> seq<span style="color: black;">&#91;</span>s - <span style="color: #ff4500;">1</span><span style="color: black;">&#93;</span> == seq<span style="color: black;">&#91;</span>e<span style="color: black;">&#93;</span>:
            s -= <span style="color: #ff4500;">1</span>
            e += <span style="color: #ff4500;">1</span>
&nbsp;
        l.<span style="color: black;">append</span><span style="color: black;">&#40;</span>e - s<span style="color: black;">&#41;</span>
&nbsp;
    <span style="color: #ff7700;font-weight:bold;">return</span> l</pre>

<p>Note that this is not the only efficient solution to this problem;
building a suffix tree is linear in the length of the input string and
you can use one to solve this problem but as Johan also mentions,
that is a much less direct and efficient solution compared to this
one.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.akalin.cx/2007/11/28/finding-the-longest-palindromic-substring-in-linear-time/feed/</wfw:commentRss>
		</item>
		<item>
		<title>At long last&#8230;</title>
		<link>http://www.akalin.cx/2007/11/21/at-long-last-the-kindle/</link>
		<comments>http://www.akalin.cx/2007/11/21/at-long-last-the-kindle/#comments</comments>
		<pubDate>Wed, 21 Nov 2007 09:35:13 +0000</pubDate>
		<dc:creator>akalin</dc:creator>
		
		<category><![CDATA[Books]]></category>

		<category><![CDATA[Computers]]></category>

		<category><![CDATA[Technical]]></category>

		<guid isPermaLink="false">https://secure.akalin.cx/2007/11/21/at-long-last/</guid>
		<description><![CDATA[The project I was working on at Amazon finally  launched!
It&#8217;s drawn a lot of criticism since it was first leaked more than a year ago; I wonder if Amazon&#8217;s take on the e-book reader is bold enough to overcome the current limitations of e-ink and its high price tag. Hopefully this will kick-start an [...]]]></description>
			<content:encoded><![CDATA[<p>The project I was working on at Amazon finally <a href="http://www.newsweek.com/id/70983"> launched</a>!</p>
<p>It&#8217;s drawn a lot of criticism since it was first <a href="http://www.engadget.com/2006/09/11/amazon-kindle-meet-amazons-e-book-reader/">leaked</a> more than a year ago; I wonder if Amazon&#8217;s take on the e-book reader is bold enough to overcome the current limitations of e-ink and its high price tag. Hopefully this will kick-start an industry that has so far languished in obscurity.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.akalin.cx/2007/11/21/at-long-last-the-kindle/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A foray into number theory with Haskell</title>
		<link>http://www.akalin.cx/2007/07/06/a-foray-into-number-theory-with-haskell/</link>
		<comments>http://www.akalin.cx/2007/07/06/a-foray-into-number-theory-with-haskell/#comments</comments>
		<pubDate>Sat, 07 Jul 2007 02:39:38 +0000</pubDate>
		<dc:creator>akalin</dc:creator>
		
		<category><![CDATA[Computers]]></category>

		<category><![CDATA[Math]]></category>

		<category><![CDATA[Technical]]></category>

		<guid isPermaLink="false">https://secure.akalin.cx/2007/07/06/a-foray-into-number-theory-with-haskell/</guid>
		<description><![CDATA[I encountered
an
interesting problem on reddit a few days ago which can be
paraphrased as follows:

Find a perfect square s such that
1597 s + 1 is also perfect square.

After reading the discussion about implementing a brute-force
algorithm to solve the problem and spending a futile half-hour or so
trying my hand at find a better way, someone noticed that [...]]]></description>
			<content:encoded><![CDATA[<p>I encountered
<a href="http://programming.reddit.com/info/216p9/comments">an
interesting problem</a> on reddit a few days ago which can be
paraphrased as follows:</p>

<blockquote><p>Find a perfect square <var>s</var> such that
1597 <var>s</var> + 1 is also perfect square.</p></blockquote>

<p>After reading the discussion about implementing a brute-force
algorithm to solve the problem and spending a futile half-hour or so
trying my hand at find a better way, someone noticed that the problem
was an instance
of <a href="http://en.wikipedia.org/wiki/Pell%27s_equation">Pell's
equation</a> which is known to have an elegant and fast solution;
indeed, he posted
a <a href="http://programming.reddit.com/info/216p9/comments/c21dpn">one-liner
in Mathematica</a> solving the given problem. However, I wanted to try
coding up the solution myself as the Mathematica solution, while
succinct, isn't very enlightening since the heavy lifting is already
done by a built-in function and an arbitrary constant was used for this
particular instance of Pell's equation.</p>

<p>Pell's equation is simply the
<a href="http://en.wikipedia.org/wiki/Diophantine_equation">Diophantine
equation</a>
<var>x</var><sup>2</sup> &minus; <var>d</var> <var>y</var><sup>2</sup>
= 1 for a given <var>d</var>; being Diophantine means that all
variables involved take on only integer values. (In our original
problem, <var>d</var> is 1597 and we are asked
for <var>y</var><sup>2</sup>.) The solution involves finding
the <em>continued fraction expansion</em> of &radic;<var>d</var>, finding the
first <em>convergent</em> of the expansion that satisfies Pell's
equation, and then generating all other solutions from that
<em>fundamental solution</em>. We rule out the trivial
solution <var>x</var> = 1, <var>y</var> = 0 which also implies that
if <var>d</var> is a perfect square then there is no solution. As a
rule we'll avoid considering trivial cases and re-stating obvious
assumptions (like <var>d</var> having to be a positive integer).</p>

<p>A continued fraction is an expression of the form:</p>

<p style="text-align: center;"><img align="bottom" alt="x = a_0 + \cfrac{1}{a_i +
\cfrac{1}{a_2 + \cfrac{1}{a_3 + \cfrac{1}{\ddots\,}}}}" src="http://www.akalin.cx/wp-content/figurerender/f39d462ad69de19518f8efdca62d000e.png" /></p>

<p>where all <var>a</var><sub><var>i</var></sub> are integers and all but
 the first one are positive.  The standard math notation for continued
 fractions is quite unwieldy so from now on we'll use
 &lt;<var>a</var><sub>0</sub>; <var>a</var><sub>1</sub>,
 <var>a</var><sub>2</sub>, ...&gt; instead of the above.</p>

<p>The theory of continued fractions is a rich and beautiful one but
 for now we'll just state a few facts:</p>

<ul>
<li>The continued fraction expansion of a number is (mostly) unique.</li>
<li>The continued fraction expansion of a rational number is
  finite.</li>
<li>The continued fraction expansion of a irrational number is
infinite.</li>
<li>A <a href="http://en.wikipedia.org/wiki/Quadratic_surd">quadratic
surd</a> is a number of the form <img align="bottom" alt="\frac{a + \sqrt{b}}{c}" src="http://www.akalin.cx/wp-content/figurerender/46641493dad17dfefd46c7e4580f78a2.png" />
where
<var>a</var>, <var>b</var>, and <var>c</var> are integers.  Except
maybe for the first term, the continued fraction expansion of a
quadratic surd is periodic; that is, it repeats forever after a
certain number of terms. This applies in particular to the square root
of an integer.</li>
<li>Truncating an infinite continued fraction to get a finite
continued fraction gives (in some sense) an optimal rational
approximation to the irrational number represented by the infinite
continued fraction.</li>
</ul>

<p>Given a quadratic surd it is fairly easy to manipulate it into the
form <img align="bottom" alt="a + \frac{1}{q}" src="http://www.akalin.cx/wp-content/figurerender/221a1e3fb4ffc2aeb655b635ce3d1660.png" /> where <var>q</var> is another
quadratic surd. This fact can be used to come up with an algorithm to
find the continued fraction expansion of a square
root. Wikipedia <a href="http://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Continued_fraction_expansion">explains
it pretty well</a> so I won't go over it, but here is my Haskell
implementation:</p>

<pre class="haskell" style="background: #eeeeee;">sqrt_continued_fraction n = <span style="color: green;">&#91;</span> a_i | <span style="color: green;">&#40;</span>_, _, a_i<span style="color: green;">&#41;</span> &lt;- mdas <span style="color: green;">&#93;</span>
    <span style="color: #06c; font-weight: bold;">where</span>
      mdas = <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:iterate"><span style="font-weight: bold;background: #eeeeee;">iterate</span></a> get_next_triplet <span style="color: green;">&#40;</span>m_0, d_0, a_0<span style="color: green;">&#41;</span>
&nbsp;
      m_0 = <span style="color: red;">0</span>
      d_0 = <span style="color: red;">1</span>
      a_0 = <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:truncate"><span style="font-weight: bold;background: #eeeeee;">truncate</span></a> $ <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:sqrt"><span style="font-weight: bold;background: #eeeeee;">sqrt</span></a> $ <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:fromIntegral"><span style="font-weight: bold;background: #eeeeee;">fromIntegral</span></a> n
&nbsp;
      get_next_triplet <span style="color: green;">&#40;</span>m_i, d_i, a_i<span style="color: green;">&#41;</span> = <span style="color: green;">&#40;</span>m_j, d_j, a_j<span style="color: green;">&#41;</span>
          <span style="color: #06c; font-weight: bold;">where</span>
            m_j = d_i * a_i - m_i
            d_j = <span style="color: green;">&#40;</span>n - m_j * m_j<span style="color: green;">&#41;</span> `<a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:div"><span style="font-weight: bold;background: #eeeeee;">div</span></a>` d_i
            a_j = <span style="color: green;">&#40;</span>a_0 + m_j<span style="color: green;">&#41;</span> `<a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:div"><span style="font-weight: bold;background: #eeeeee;">div</span></a>` d_j</pre>

<p>and here are some examples:</p>

<pre style="background-color: #eeeeee;">
Prelude Main> take 20 $ sqrt_continued_fraction 2
[1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2]

Prelude Main> take 20 $ sqrt_continued_fraction 103
[10,6,1,2,1,1,9,1,1,2,1,6,20,6,1,2,1,1,9,1]

Prelude Main> take 20 $ sqrt_continued_fraction 36
[6,*** Exception: divide by zero
</pre>

<p>(Note that we're assuming that we won't be called with a perfect
square. Also, do you notice anything interesting about the periodic
portion of the continued fractions, particularly of &radic;103?)</p>

<p>For those who are unfamiliar with Haskell, here's a quick list of key facts:

<ul>
<li>The first line takes a list of triplets and forms a list of all
  third elements, which is what we're interested in. (The other two
  elements of the triplet are auxiliary variables used by the
  algorithm.)</li>
<li><var>iterate</var> is a function which takes in another
  function <var>f</var>, an initial variable <var>x</var>, and returns
  the infinite list [ <var>x</var>, <var>f</var>(<var>x</var>),
  <var>f</var>(<var>f</var>(<var>x</var>)),
  <var>f</var>(<var>f</var>(<var>f</var>(<var>x</var>))), ... ].</li>
<li>Note that Haskell
  uses <a href="http://en.wikipedia.org/wiki/Lazy_evaluation">lazy
  evaluation</a> and so this function does not take an infinite amount
  of time to run; all its elements are evaluated (and memoized) only
  when needed.</li>
<li>The rest of the function is a straightforward representation of
  the meat of the algorithm described in the above Wikipedia entry.</li>
</ul>

<p>It may not be clear what &radic;<var>d</var> and its continued fraction
expansion has to do with solving Pell's equation. However, notice that
if <var>x</var> and <var>y</var> solve Pell's equation then
manipulating Pell's equation to get &radic;<var>d</var> on one side reveals
that <var>x</var>&frasl;<var>y</var> is a good approximation of
&radic;n. In fact, it is so good that you can prove that
<var>x</var>&frasl;<var>y</var> <em>must</em> come from truncating the
continued fraction expansion of &radic;<var>d</var>.</p>

<p>This leads us to the following: if you have an infinite continued
fraction &lt;<var>a</var><sub>0</sub>; <var>a</var><sub>1</sub>,
<var>a</var><sub>2</sub>, ...&gt; you can truncate it into a finite
continued fraction &lt;<var>a</var><sub>0</sub>;
<var>a</var><sub>1</sub>, <var>a</var><sub>2</sub>, ...,
<var>a</var><sub><var>i</var></sub>&gt; and simplify it into the
rational number
<var>p</var><sub><var>i</var></sub>&frasl;<var>q</var><sub><var>i</var></sub>.
The sequence <var>p</var><sub>0</sub>&frasl;<var>q</var><sub>0</sub>,
<var>p</var><sub>1</sub>&frasl;<var>q</var><sub>1</sub>,
<var>p</var><sub>2</sub>&frasl;<var>q</var><sub>2</sub>, ... forms the
<a
href="http://en.wikipedia.org/wiki/Convergent_%28continued_fraction%29"><em>convergents</em></a>
of &lt;<var>a</var><sub>0</sub>; <var>a</var><sub>1</sub>,
<var>a</var><sub>2</sub>, ...&gt; and converges to its represented
irrational number.</p>

<p>It turns out you can calculate <var>p</var><sub><var>i</var> +
1</sub> and <var>q</var><sub><var>i</var> + 1</sub> efficiently from
<var>p</var><sub><var>i</var></sub>,
<var>q</var><sub><var>i</var></sub>, <var>p</var><sub><var>i</var> -
1</sub>, <var>q</var><sub><var>i</var> - 1</sub>, and
<var>a</var><sub><var>i</var> + 1</sub> using
the <a href="http://en.wikipedia.org/wiki/Fundamental_recurrence_formulas"><em>fundamental
recurrence formulas</em></a> (which can be proved by induction). Here
is my Haskell implementation:</p>

<pre class="haskell" style="background: #eeeeee;">get_convergents <span style="color: green;">&#40;</span>a_0 : a_1 : <span style="color: #06c; font-weight: bold;">as</span><span style="color: green;">&#41;</span> = pqs
    <span style="color: #06c; font-weight: bold;">where</span>
      pqs = <span style="color: green;">&#40;</span>p_0, q_0<span style="color: green;">&#41;</span> : <span style="color: green;">&#40;</span>p_1, q_1<span style="color: green;">&#41;</span> :
            <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:zipWith3"><span style="font-weight: bold;background: #eeeeee;">zipWith3</span></a> get_next_convergent pqs <span style="color: green;">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:tail"><span style="font-weight: bold;background: #eeeeee;">tail</span></a> pqs<span style="color: green;">&#41;</span> <span style="color: #06c; font-weight: bold;">as</span>
&nbsp;
      p_0 = a_0
      q_0 = <span style="color: red;">1</span>
&nbsp;
      p_1 = a_1 * a_0 + <span style="color: red;">1</span>
      q_1 = a_1
&nbsp;
      get_next_convergent <span style="color: green;">&#40;</span>p_i, q_i<span style="color: green;">&#41;</span> <span style="color: green;">&#40;</span>p_j, q_j<span style="color: green;">&#41;</span> a_k = <span style="color: green;">&#40;</span>p_k, q_k<span style="color: green;">&#41;</span>
          <span style="color: #06c; font-weight: bold;">where</span>
            p_k = a_k * p_j + p_i
            q_k = a_k * q_j + q_i</pre>

<p>and some more examples:</p>

<pre style="background-color: #eeeeee;">
Prelude Main> take 8 $ get_convergents $ sqrt_continued_fraction 2
[(1,1),(3,2),(7,5),(17,12),(41,29),(99,70),(239,169),(577,408)]

Prelude Main> take 8 $ get_convergents $ sqrt_continued_fraction 103
[(10,1),(61,6),(71,7),(203,20),(274,27),(477,47),(4567,450),(5044,497)]

Prelude Main> take 8 $ get_convergents $ sqrt_continued_fraction 1597
[(39,1),(40,1),(1039,26),(1079,27),(2118,53),(3197,80),(27694,693),(113973,2852)]

Prelude Main> let divFrac (x, y) = (fromInteger x) / (fromInteger y)

Prelude Main> take 8 $ map divFrac $ get_convergents $ sqrt_continued_fraction 2
[1.0,1.5,1.4,1.4166666666666667,1.4137931034482758,1.4142857142857144,1.4142011834319526,1.4142156862745099]

Prelude Main> take 8 $ map divFrac $ get_convergents $ sqrt_continued_fraction 103
[10.0,10.166666666666666,10.142857142857142,10.15,10.148148148148149,10.148936170212766,10.148888888888889,10.148893360160965]

Prelude Main> take 8 $ map divFrac $ get_convergents $ sqrt_continued_fraction 1597
[39.0,40.0,39.96153846153846,39.96296296296296,39.9622641509434,39.9625,39.96248196248196,39.9624824684432]
</pre>

<p>Here are a few more quick facts to help those unfamiliar with
  Haskell:</p>

<ul>
<li>The expression <var>a</var> : <var>as</var> forms a new list from the
  element <var>a</var> and the existing list <var>as</var>
  (equivalent to <var>cons</var> in Lisp).</li>
<li><var>zipWith3</var> is a function that takes in a
  function <var>f</var>, three lists <var>a</var>, <var>b</var>,
  and <var>c</var> of the same (possibly infinite)
  length <var>n</var>, and forms the new list
  [ <var>f</var>(<var>a</var><sub>0</sub>, <var>b</var><sub>0</sub>,
  <var>c</var><sub>0</sub>),
  <var>f</var>(<var>a</var><sub>1</sub>, <var>b</var><sub>1</sub>,
  <var>c</var><sub>1</sub>),
  ...,
  <var>f</var>(<var>a</var><sub>n</sub>, <var>b</var><sub>n</sub>,
  <var>c</var><sub>n</sub>) ].</li>
<li>Note that the result of zipWith3 is part of the
  variable <var>pqs</var> which itself appears (twice!) in the
  arguments to zipWith3. This is a Haskell idiom and reflects the fact
  that the recurrence formulas define a convergent in terms of its two
  previous convergents. A simpler example (using the Fibonacci
  sequence) can be found in the
  <a href="http://en.wikipedia.org/wiki/Lazy_evaluation">Wikipedia
  entry for lazy evaluation</a>.</li>
<li>Haskell has built-in data types for integers of arbitrary size
  which is necessary as the numerators and denominators of the
  convergents get large quickly. In fact, Haskell has built-in
  data types for rational numbers (represented as fractions) but it
  doesn't help us much here.</li>
</ul>

<p>Since we are guaranteed that some convergent eventually satisfies
  Pell's equation, we can write a simple function to generate all
  convergents, test each one to see if it satisfies Pell's equation,
  and return the first one we see. Here is the Haskell implementation:</p>

<pre class="haskell" style="background: #eeeeee;">get_pell_fundamental_solution n = <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:head"><span style="font-weight: bold;background: #eeeeee;">head</span></a> $ solutions
    <span style="color: #06c; font-weight: bold;">where</span>
      solutions = <span style="color: green;">&#91;</span> <span style="color: green;">&#40;</span>p, q<span style="color: green;">&#41;</span> | <span style="color: green;">&#40;</span>p, q<span style="color: green;">&#41;</span> &lt;- convergents, p * p - n * q * q == <span style="color: red;">1</span> <span style="color: green;">&#93;</span>
&nbsp;
      convergents = get_convergents $ sqrt_continued_fraction n</pre>

<p>Note the use of the
  Haskell's <a href="http://en.wikipedia.org/wiki/List_comprehension">list
  comprehension</a> syntax, similar to Python, which expresses what I
  just described in a matter reminiscent of set notation.

Here is the full Haskell program designed so its output may be
  conveniently piped
  to <a href="http://en.wikipedia.org/wiki/Bc_programming_language">bc</a>
  for verification:

<pre class="haskell" style="background: #eeeeee;"><span style="color: #06c; font-weight: bold;">module</span> Main <span style="color: #06c; font-weight: bold;">where</span>
&nbsp;
<span style="color: #06c; font-weight: bold;">import</span> System <span style="color: green;">&#40;</span>getArgs<span style="color: green;">&#41;</span>
&nbsp;
sqrt_continued_fraction :: <span style="color: green;">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Integral"><span style="color: #cccc00; font-weight: bold;background: #eeeeee;">Integral</span></a> a<span style="color: green;">&#41;</span> =&gt; a -&gt; <span style="color: green;">&#91;</span>a<span style="color: green;">&#93;</span>
<span style="color: #5d478b; font-style: italic;">{- ... the sqrt_continued_fraction function explained above ... -}</span>
&nbsp;
get_convergents :: <span style="color: green;">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Integral"><span style="color: #cccc00; font-weight: bold;background: #eeeeee;">Integral</span></a> a<span style="color: green;">&#41;</span> =&gt; <span style="color: green;">&#91;</span>a<span style="color: green;">&#93;</span> -&gt; <span style="color: green;">&#91;</span><span style="color: green;">&#40;</span>a, a<span style="color: green;">&#41;</span><span style="color: green;">&#93;</span>
<span style="color: #5d478b; font-style: italic;">{- ... the get_convergents function explained above ... -}</span>
&nbsp;
get_pell_fundamental_solution :: <span style="color: green;">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Integral"><span style="color: #cccc00; font-weight: bold;background: #eeeeee;">Integral</span></a> a<span style="color: green;">&#41;</span> =&gt; a -&gt; <span style="color: green;">&#40;</span>a, a<span style="color: green;">&#41;</span>
<span style="color: #5d478b; font-style: italic;">{- ... the get_pell_fundamental_solution function explained above ... -}</span>
&nbsp;
main :: <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:IO"><span style="color: #cccc00; font-weight: bold;background: #eeeeee;">IO</span></a> <span style="color: green;">&#40;</span><span style="color: green;">&#41;</span>
main = <span style="color: #06c; font-weight: bold;">do</span>
  args &lt;- System.getArgs
  <span style="color: #06c; font-weight: bold;">let</span> d      = <span style="color: green;">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:read"><span style="font-weight: bold;background: #eeeeee;">read</span></a> $ <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:head"><span style="font-weight: bold;background: #eeeeee;">head</span></a> $ args :: <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Integer"><span style="color: #cccc00; font-weight: bold;background: #eeeeee;">Integer</span></a><span style="color: green;">&#41;</span>
      <span style="color: green;">&#40;</span>p, q<span style="color: green;">&#41;</span> = get_pell_fundamental_solution d <span style="color: #06c; font-weight: bold;">in</span>
    <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:putStr"><span style="font-weight: bold;background: #eeeeee;">putStr</span></a> $ <span style="background-color: #3cb371;">&quot;d = &quot;</span> ++ <span style="color: green;">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:show"><span style="font-weight: bold;background: #eeeeee;">show</span></a> d<span style="color: green;">&#41;</span> ++ <span style="background-color: #3cb371;">&quot;<span style="">\n</span>&quot;</span> ++
             <span style="background-color: #3cb371;">&quot;p = &quot;</span> ++ <span style="color: green;">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:show"><span style="font-weight: bold;background: #eeeeee;">show</span></a> p<span style="color: green;">&#41;</span> ++ <span style="background-color: #3cb371;">&quot;<span style="">\n</span>&quot;</span> ++
             <span style="background-color: #3cb371;">&quot;q = &quot;</span> ++ <span style="color: green;">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:show"><span style="font-weight: bold;background: #eeeeee;">show</span></a> q<span style="color: green;">&#41;</span> ++ <span style="background-color: #3cb371;">&quot;<span style="">\n</span>&quot;</span> ++
             <span style="background-color: #3cb371;">&quot;p^2 - d * q^2 == 1<span style="">\n</span>&quot;</span></pre>

and here is it in action:

<pre style="background-color: #eeeeee;">
$ ./solve_pell 1597
d = 1597
p = 519711527755463096224266385375638449943026746249
q = 13004986088790772250309504643908671520836229100
p^2 - d * q^2 == 1
</pre>

<p>The solution to the original problem is therefore:
5054112910466227478111803017176109047976100000000.</p>

<p>Now that we've found a method to get <em>a</em> solution, the
question remains as to whether it's the only one. In fact it is not,
but it is the minimal one, and all other solutions (of which there are
an infinite number) can be generated from this fundamental one with a
simple recurrence relation as described on
the <a href="http://en.wikipedia.org/wiki/Pell%27s_equation#Solution_technique">Wikipedia
article</a>. My program above can be easily extended to generate all
solutions instead of just the fundamental one (I'll leave it to the
reader as an exercise).</p>

<p>One remaining question is the efficiency of this algorithm. For
simplicity, let's neglect the cost of the arbitrary-precision
arithmetic involved and assume that the incremental cost of generating
each term of the continued fraction expansion and the convergents is
constant. Then the main cost is just how many convergents we have to
generate before we find one that satisfies Pell's equation. In fact,
it turns out that this depends on the length of the period of the
continue fraction expansion of &radic;<var>d</var>, which has a rough
upper bound of O(ln <var>d</var> &radic;<var>d</var>). Therefore, the
cost of solving Pell's equation (in terms of how many convergents to
generate) for a given <var>n</var>-digit number is O(<var>n</var>
2<sup><Var>n</var> &frasl; 2</sup>). This is pretty expensive already,
although it's still much better than brute-force search (which is on
the order of exponentiating the above expression). Can we do better?
Well, sort of; it turns out the length of the answer is of the same
order as the expression above, so any algorithm that explicitly
outputs a solution necessarily takes that long. However, if you can
somehow factor <var>d</var> into <var>s</var> <var>d</var>&prime;,
where <var>s</var> is a perfect square and <var>d</var>&prime;
is <a href="http://en.wikipedia.org/wiki/Squarefree">squarefree</a>
(i.e., not divisible by any perfect square), then you can solve Pell's
equation for the smaller number <var>d</var>&prime; and output the
solution for <var>d</var>&prime; as the smaller fundamental solution
and an expression raised to a certain power involving it. Note that in
general this involves factoring <var>d</var>, another hard problem,
but for which there exists tons of prior work. An interested reader
can peruse the papers
by <a href="http://www.ams.org/notices/200202/fea-lenstra.pdf">Lenstra</a>
and <a href="https://www.math.nyu.edu/~crorres/Archimedes/Cattle/cattle_vardi.pdf">Vardi</a>
for more details.</p>

<p>As a final note, one of the things I really like about number
theory is that investigating such a simple program can lead you down
surprising avenues of mathematics and computational theory. In fact,
I've had to omit a lot of things I had planned to say to avoid growing
this entry to be longer than it already is. Hopefully, this entry
helps someone else learn more about this interesting corner of number
theory.</p>]]></content:encoded>
			<wfw:commentRss>http://www.akalin.cx/2007/07/06/a-foray-into-number-theory-with-haskell/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
