<?xml version="1.0" encoding="UTF-8"?>
<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/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Dave&#039;s Programming Blog &#187; Random experiments</title>
	<atom:link href="http://dev.mcleish.id.au/category/random-experiments/feed/" rel="self" type="application/rss+xml" />
	<link>http://dev.mcleish.id.au</link>
	<description>The Church of Alan Turing of Latter-Day Sorcerers</description>
	<lastBuildDate>Wed, 09 Feb 2011 12:09:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Sudoku Goggles</title>
		<link>http://dev.mcleish.id.au/2011/01/sudoku-goggles/</link>
		<comments>http://dev.mcleish.id.au/2011/01/sudoku-goggles/#comments</comments>
		<pubDate>Wed, 12 Jan 2011 00:22:07 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Random experiments]]></category>

		<guid isPermaLink="false">http://dev.mcleish.id.au/?p=276</guid>
		<description><![CDATA[A couple of my interests overlapped this morning when I found out that Google Goggles solves Sudoku. (As an almost-related aside, I&#8217;m still tweaking my Go Sudoku solver. More on that later.) So, after a bit of discussion, we decided to try to mess with it by feeding it invalid puzzles. Here&#8217;s one of the [...]]]></description>
			<content:encoded><![CDATA[<p>A couple of my interests overlapped this morning when I found out that <a href="http://www.i-programmer.info/news/105-artificial-intelligence/1818-google-goggles-solves-sudoku.html">Google Goggles solves Sudoku</a>.</p>
<p>(As an almost-related aside, I&#8217;m still tweaking my <a href="http://hg.mcleish.id.au/sudoku-go/">Go Sudoku solver</a>. More on that later.)</p>
<p>So, after a bit of discussion, we decided to try to mess with it by feeding it invalid puzzles. Here&#8217;s one of the tests I tried &#8211; note the 4 in the upper-left block, which should be a 3.</p>
<p><a href="http://dev.mcleish.id.au/wp-content/uploads/2011/01/badsudoku.png"><img class="alignnone size-full wp-image-277" title="Bad sudoku" src="http://dev.mcleish.id.au/wp-content/uploads/2011/01/badsudoku.png" alt="Bad sudoku" width="354" height="384" /></a></p>
<p>What Goggles detected is below. Note that the 4 in question is there, but it&#8217;s missed a few numbers elsewhere in the puzzle.</p>
<p><a href="http://dev.mcleish.id.au/wp-content/uploads/2011/01/detectedsudoku.png"><img class="alignnone size-full wp-image-278" title="Detected sudoku" src="http://dev.mcleish.id.au/wp-content/uploads/2011/01/detectedsudoku.png" alt="Detected sudoku" width="354" height="384" /></a></p>
<p>It solves this version quite happily. At first I thought it was cheating by overwriting some of the original cells, until I noticed the gaps. I tried it again a few times, keeping the camera as steady as possible and cropping out other distractions; it detected a different subset of the numbers each time, so I started to think that the OCR was a bit flaky. But it always seemed to detect a valid puzzle&#8230; and when I tried it with the <em>original</em> valid puzzle, it detected everything.</p>
<p>It seems like Goggles doesn&#8217;t just recognise any old 9&#215;9 grid of numbers as a Sudoku puzzle; it will only recognise a <em>valid Sudoku puzzle</em> as a Sudoku puzzle. My theory is that when it looks at the invalid Sudoku, its best match for it is a valid Sudoku with fewer numbers, plus some noise where its OCR thought there was <em>probably</em> a number but wasn&#8217;t quite as confident &#8211; as though, for example, there was some dust on the lens in front of those squares. (Most of the time it seemed to drop 1s, which have fewer obvious features than other numbers and are hard to distinguish from 2s.)</p>
<p>The interesting thing about this is that a naïve implementation (i.e. what I&#8217;d probably do) would OCR the grid <em>first</em>, set that in stone, then feed it into a Sudoku solver/validity-checker. Google&#8217;s implementation seems to tie more organically into however its recognition engine works (from this very limited set of tests anyway) &#8211; i.e. the space of objects it recognises includes all valid Sudoku puzzles. Somehow.</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.mcleish.id.au/2011/01/sudoku-goggles/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Kris Kringle</title>
		<link>http://dev.mcleish.id.au/2010/11/kris-kringle/</link>
		<comments>http://dev.mcleish.id.au/2010/11/kris-kringle/#comments</comments>
		<pubDate>Sat, 20 Nov 2010 07:55:26 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Random experiments]]></category>

		<guid isPermaLink="false">http://dev.mcleish.id.au/?p=220</guid>
		<description><![CDATA[Our family is breaking with our old everyone-buys-a-gift-for-everyone tradition this year and doing Kris Kringle instead. There&#8217;s a bit of kerfuffle about how to select names and get word out to everyone; I mentioned to wifey that the cleanest way would be to write a short program to shuffle the names and send each person [...]]]></description>
			<content:encoded><![CDATA[<p>Our family is breaking with our old everyone-buys-a-gift-for-everyone tradition this year and doing <a href="http://en.wikipedia.org/wiki/Secret_Santa">Kris Kringle</a> instead. There&#8217;s a bit of kerfuffle about how to select names and get word out to everyone; I mentioned to wifey that the cleanest way would be to write a short program to shuffle the names and send each person a private email. This probably isn&#8217;t going to happen at this stage, but I might suggest it for next year. (Should go down well.)</p>
<p>In the meantime, it got me thinking about how to deal with people drawing their own name, which anecdotally seems to happen at least once without fail. I brute-forced some statistics, and the probability of someone <em>not</em> drawing their own name in any given run seems to approach e<sup>-1</sup>:</p>
<blockquote>
<pre> 1:        0 of        1 = zero
 2:        1 of        2 = 1 in 2.000000000000
 3:        2 of        6 = 1 in 3.000000000000
 4:        9 of       24 = 1 in 2.666666666667
 5:       44 of      120 = 1 in 2.727272727273
 6:      265 of      720 = 1 in 2.716981132075
 7:     1854 of     5040 = 1 in 2.718446601942
 8:    14833 of    40320 = 1 in 2.718263331760
 9:   133496 of   362880 = 1 in 2.718283693893
10:  1334961 of  3628800 = 1 in 2.718281657666
</pre>
</blockquote>
<p>In other words, there&#8217;s about a 63% chance that at least one person will pick their own name and have to redraw. (There&#8217;s a 1/n chance that it&#8217;ll be the last person, which really screws things up.)</p>
<p>One way to avoid this if we end up doing it programmatically &#8211; other than re-shuffling until it works &#8211; is to shuffle the list of names, then assign everyone to buy a gift for the person <em>after</em> them in the (cyclic) list. This guarantees nobody getting their own name (for n &gt; 1), and also has the property that there are no disjoint sets of people &#8211; everyone is in one cycle, rather than, say, two people buying for each other, or some number of larger cycles.</p>
<p>That seems more festive somehow. Also, it&#8217;s an actual advantage of doing it the geek way, since I can&#8217;t think of a way of doing it manually; which means I might actually be able to convince everyone that it&#8217;s a good idea.</p>
<p>&#8230;</p>
<p>Okay, here&#8217;s how you&#8217;d do to do it manually. Shuffle some playing cards, one for each person. Everyone takes a card, remembers it (without showing anyone), and writes their name on the back. Take the cards back, shuffle them again, and lay them out in a circle, face up. Everyone goes out of the room. One at a time, each person comes into the room (with nobody else watching), finds their own card, picks up the card clockwise from it and reads the name on the back.</p>
<p>Of course, my way prevents cheating.</p>
]]></content:encoded>
			<wfw:commentRss>http://dev.mcleish.id.au/2010/11/kris-kringle/feed/</wfw:commentRss>
		<slash:comments>29</slash:comments>
		</item>
		<item>
		<title>n-queens Mexican Standoff</title>
		<link>http://dev.mcleish.id.au/2010/01/n-queens-mexican-standoff/</link>
		<comments>http://dev.mcleish.id.au/2010/01/n-queens-mexican-standoff/#comments</comments>
		<pubDate>Mon, 11 Jan 2010 06:03:39 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Random experiments]]></category>

		<guid isPermaLink="false">http://dev.mcleish.id.au/?p=41</guid>
		<description><![CDATA[The first day back at work has proved fruitful in the form of someone coming up with the opposite of the traditional n-queens problem: the n-queens Mexican standoff. Instead of minimising the number of mutually attacking queens (to zero), the objective of the standoff version is to maximise the number of attacks. We haven&#8217;t done [...]]]></description>
			<content:encoded><![CDATA[<p>The first day back at work has proved fruitful in the form of someone coming up with the opposite of the traditional <a href="http://en.wikipedia.org/wiki/N_queens"><em>n</em>-queens</a> problem: the <em>n</em>-queens Mexican standoff. Instead of minimising the number of mutually attacking queens (to zero), the objective of the standoff version is to <em>maximise</em> the number of attacks.</p>
<p>We haven&#8217;t done an exhaustive search yet, but I&#8217;ve been running a simulated-annealing-ish script for a while, and it looks like the most attacks is 34 (17 pairs of mutual attacks), in two configurations:</p>
<blockquote>
<pre>QQ.    .QQ.
QQQ or QQQQ
QQQ    .QQ.
</pre>
</blockquote>
<p>&#8230;either of which can be expanded by adding gaps between the queens, or rotating by multiples of 45 degrees.</p>
<blockquote>
<pre>Q.Q..   .Q.Q.   Q...Q..
.....   Q.Q.Q   .......
Q.Q.Q   .Q.Q.   ..Q...Q
.....   ..Q..   .......
Q.Q.Q           Q...Q..
                .......
                ..Q...Q</pre>
</blockquote>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 201px; width: 1px; height: 1px;">
<pre>Q...Q...</pre>
</div>
<p><strong>Update:</strong> Python code below the fold.</p>
<p><span id="more-41"></span></p>
<blockquote>
<pre>import random
from numpy import array, exp

def print_board((n, queens, board)):
    for row in board:
        for val in row:
            print ('.','#')[val],
        print

def new_board(n=8):
    board = array([[False] * n for i in range(n)])
    queens = []
    while len(queens) < n:
        x = random.randint(0, n-1)
        y = random.randint(0, n-1)
        if not (x,y) in queens:
            queens.append((x, y))
            board[x,y] = True
    return (n, queens, board)

def eval_attack((n, queens, board)):
    attacks = 0
    for (x,y) in queens:
        for (dx,dy) in ((-1,-1),(-1,0),(-1,1),
                        (0,-1),(0,1),
                        (1,-1),(1,0),(1,1)):
            (cx, cy) = (x, y)
            while True:
                cx += dx
                cy += dy
                if cx < 0 or cx >= n or cy < 0 or cy >= n:
                    break
                if board[cx,cy]:
                    attacks += 1
                    break
    return attacks

def move_queen((n, queens, board), q=None, dest=None):
    if q is None:
        q = random.randint(0, n-1)
    if dest is None:
        while True:
            x = random.randint(0, n-1)
            y = random.randint(0, n-1)
            if not board[x,y]:
                dest = (x,y)
                break
    prev = queens[q]
    queens[q] = dest
    board[prev] = False
    board[dest] = True
    return (q, prev)

def find_most_attack(board=None, n=8, temp=2.0, threshold=10000):
    if board is None:
        board = new_board(n)

    best = 0
    meta_best = best
    since_improve = 0
    while True:
        (prev_q, prev_pos) = move_queen(board)
        score = eval_attack(board)
        if score > best:
            best = score
            since_improve = 0
            if best >= meta_best:
                meta_best = best
                print_board(board)
                print score
        else:
            since_improve += 1
            if since_improve > threshold:
                since_improve = 0
                board = new_board(n)
                best = 0
            elif random.random() >= exp((score - best)/temp):
                move_queen(board, prev_q, prev_pos)
</pre>
</blockquote>
]]></content:encoded>
			<wfw:commentRss>http://dev.mcleish.id.au/2010/01/n-queens-mexican-standoff/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fibonacci music</title>
		<link>http://dev.mcleish.id.au/2010/01/fibonacci-music/</link>
		<comments>http://dev.mcleish.id.au/2010/01/fibonacci-music/#comments</comments>
		<pubDate>Wed, 06 Jan 2010 05:13:09 +0000</pubDate>
		<dc:creator>David</dc:creator>
				<category><![CDATA[Random experiments]]></category>

		<guid isPermaLink="false">http://dev.mcleish.id.au/?p=19</guid>
		<description><![CDATA[I spent most of today messing around with music based on the Fibonacci sequence. The result I&#8217;m happiest with has four voices, each using the Fibonacci sequence mod 12 to determine the pitch (in semitones), and using the sequence with other moduli (4, 5, 3 and 2 respectively) to determine the timing. Fibonacci MIDI (9.8KB) [...]]]></description>
			<content:encoded><![CDATA[<p>I spent most of today messing around with music based on the Fibonacci sequence. The result I&#8217;m happiest with has four voices, each using the Fibonacci sequence mod 12 to determine the pitch (in semitones), and using the sequence with other moduli (4, 5, 3 and 2 respectively) to determine the timing.</p>
<p><a href="http://dev.mcleish.id.au/wp-content/uploads/2010/01/fibonacci.midi">Fibonacci MIDI (9.8KB)</a></p>
<p><a href="http://dev.mcleish.id.au/wp-content/uploads/2010/01/fibonacci.mp3">Fibonacci MP3 (3.0MB)</a></p>
<p>It could generously be described as &#8220;atonal crap&#8221;, but it sort of has moments of not-completely-awful-ness. Sort of.</p>
<p>Python code below the fold.</p>
<p><span id="more-19"></span></p>
<p>This produces output that can be included in a <a href="http://lilypond.org/">Lilypond</a> file. For the record: I&#8217;m not actually expecting anyone to actually <em>do</em> this (other than me), I&#8217;m just sort of documenting it for posterity.</p>
<pre>SCALE = ['c','cis','d','dis','e','f','fis',
         'g','gis','a','ais','b']

class Fibonacci:
    def __init__(self, mod, offset=0, coeff=1, a=0, b=1):
        self.mod = mod
        self.offset = offset
        self.coeff = coeff
        self.a = a
        self.b = b

    def next(self):
        val = self.coeff * self.a + self.offset
        (self.a, self.b) = (self.b, (self.a + self.b) % self.mod)
        return val

def note(n):
    suffix = ''
    while n &lt; 0:
        suffix += ','
        n += len(SCALE)
    while n &gt;= len(SCALE):
        suffix += '\''
        n -= len(SCALE)
    return SCALE[n] + suffix

def make_music(n, voices):
    for (rests, note_seq, time_seq) in voices:
        print '{',

        count = rests * 16

        while rests &gt; 0:
            if rests &gt;= 4:
                print 'r1',
                rests -= 4
            elif rests &gt;= 2:
                print 'r2',
                rests -= 2
            elif rests &gt;= 1:
                print 'r4',
                rests -= 1

        while count &lt; n:
            time = 2**time_seq.next()
            print '%s%d' % (note(note_seq.next()), time),
            count += 64 // time
        print '}'

if __name__ == '__main__':
    make_music(9312, [
            (0, Fibonacci(12, 12), Fibonacci(4, 0)),
            (23, Fibonacci(12, 5), Fibonacci(5, 0)),
            (46, Fibonacci(12, 0), Fibonacci(3, 0)),
            (69, Fibonacci(12, -7), Fibonacci(2, 0))
            ])</pre>
]]></content:encoded>
			<wfw:commentRss>http://dev.mcleish.id.au/2010/01/fibonacci-music/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://dev.mcleish.id.au/wp-content/uploads/2010/01/fibonacci.midi" length="5079" type="audio/midi" />
<enclosure url="http://dev.mcleish.id.au/wp-content/uploads/2010/01/fibonacci.mp3" length="3153149" type="audio/mpeg" />
		</item>
	</channel>
</rss>
