<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
  <channel>
    <title>Random Hacks: McCarthy's Ambiguous Operator</title>
    <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Technology and Other Fun Stuff</description>
    <item>
      <title>"McCarthy's Ambiguous Operator" by Doug Auclair</title>
      <description>&lt;p&gt;The Haskell version of &lt;span class="caps"&gt;SEND&lt;/span&gt;+MORE=MONEY in the amb-style:&lt;/p&gt;


&lt;pre&gt;
&amp;gt; sendmory = [(s,e,n,d,m,o,r,y) | s &amp;lt;- pos, e &amp;lt;- all, n &amp;lt;- all, d &amp;lt;- all,
&amp;gt;                                 m &amp;lt;- [1], o &amp;lt;- all, r &amp;lt;- all, y &amp;lt;- all,
&amp;gt;                                 y == d + e || y == d + e - 10,
&amp;gt;                                 s + m + 1 &amp;gt;= 10, 
&amp;gt;                                 num [s,e,n,d] + num [m,o,r,e]
&amp;gt;                                       == num [m,o,n,e,y],
&amp;gt;                                 allDiff [s,e,n,d,m,o,r,y]]
&amp;gt;   where
&amp;gt;     pos = [2..9]
&amp;gt;     all = 0:pos

&amp;gt; num :: [Int] -&amp;gt; Int
&amp;gt; num = foldl ((+).(*10)) 0

&amp;gt; allDiff :: [Int] -&amp;gt; Bool
&amp;gt; allDiff [] = True
&amp;gt; allDiff (x:xs) = notElem x xs &amp;#38;&amp;#38; allDiff xs
&lt;/pre&gt;

	&lt;p&gt;... note that a definition for amb is unnecessary, as list compression (as a MonadPlus) already makes choice.&lt;/p&gt;


	&lt;p&gt;The above, as already pointed out, is not very efficient, so using a state monad to narrow the selection in-place:&lt;/p&gt;


&lt;pre&gt;
&amp;gt; sendmory' :: StateT [Int] [] [Int]
&amp;gt; sendmory' = -- do [m] &amp;lt;- item
&amp;gt;             --    verify (m == 1)
&amp;gt;             -- the first two lines can be written 'do let m = 1'
&amp;gt;             -- iff the passed in list does not contain the number 1
&amp;gt;             do let m = 1
&amp;gt;                [s] &amp;lt;- item
&amp;gt;                verify (s + m + 1 &amp;gt;= 10)
&amp;gt;                [e] &amp;lt;- item
&amp;gt;                [d] &amp;lt;- item
&amp;gt;                [y] &amp;lt;- item
&amp;gt;                verify (y == d + e || y == d + e - 10)
&amp;gt;                [n] &amp;lt;- item
&amp;gt;                [o] &amp;lt;- item
&amp;gt;                [r] &amp;lt;- item
&amp;gt;                verify (num [s,e,n,d] + num [m,o,r,e]
&amp;gt;                                    == num [m,o,n,e,y])
&amp;gt;                -- item obviates allDiff
&amp;gt;                return [s,e,n,d,m,o,r,y]
&amp;gt;

&amp;gt; -- split list into all combinations of one element and rest
&amp;gt; splits :: [a] -&amp;gt; [([a],[a])]
&amp;gt; splits l = splitAccum [] l where
&amp;gt;   splitAccum ys []     = []
&amp;gt;   splitAccum ys (x:xs) = ([x],xs++ys) : splitAccum (x:ys) xs

&amp;gt; choose :: StateT [a] [] [a]
&amp;gt; choose = StateT $ \s -&amp;gt; splits s 

&amp;gt; item :: StateT [Int] [] [Int]
&amp;gt; item = choose

&amp;gt; verify :: Bool -&amp;gt; StateT [Int] [] ()
&amp;gt; verify p = StateT $ \s -&amp;gt; if p then [((), s)] else []
&lt;/pre&gt;

	&lt;p&gt;splits, choose, and verify are thanks to Dirk Thierbach on comp.lang.haskell.  This version is 200x faster than the amb-style one&amp;#8212;10x speed up for redundant digit elimination and on top of that a 20x speed up from placing the guards as far up in the computation as possible.  Although it requires some helper functions to implement nondeterminism with elimination, sendmory&amp;#8217; retains the declarative feel of it&amp;#8217;s amb-styled counterpart.&lt;/p&gt;</description>
      <pubDate>Thu, 29 Nov 2007 18:49:38 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:52018815-1dfb-47c8-a358-175fcca0bc43</guid>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator#comment-541</link>
    </item>
    <item>
      <title>"McCarthy's Ambiguous Operator" by Doug Auclair</title>
      <description>&lt;p&gt;@Christian, you are quite right!  For this particular problem (SEND+MORE=MONEY), eliminated selected digits narrows the search-space considerably, speeding up the calculation by a factor of ~50:&lt;/p&gt;


	&lt;p&gt;http://www.cotilliongroup.com/arts/DCG.html&lt;/p&gt;


	&lt;p&gt;(done with Prolog&amp;#8217;s definite clause grammars, which have a similar feel to Haskell&amp;#8217;s monads)&lt;/p&gt;


	&lt;p&gt;And, I suppose, one can use, e.g., Gwydion Dylan&amp;#8217;s matrix library (http://www.opendylan.org/gdref/gdlibs/libs-matrix-operations.html), along the lines of a gausse-jordan elimination, to solve the system of equations linearly? Perhaps not apropos to this problem, but handles several kinds of constraint problems.&lt;/p&gt;</description>
      <pubDate>Wed, 28 Nov 2007 15:54:11 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:a4d92ae3-9bd1-4330-a605-a24f08d1fb84</guid>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator#comment-537</link>
    </item>
    <item>
      <title>"McCarthy's Ambiguous Operator" by Christian Theil Have</title>
      <description>&lt;p&gt;&amp;#8220;Since a backtracking search takes O(2^N) time (yikes!), it’s worth doing a lot of work before actually branching.&amp;#8221;&lt;/p&gt;


	&lt;p&gt;This really depends on the nature of the problem. If you are only going to backtrack a little, it might not be worth spend cycles on forward-checking or ensuring arc consistency. Propagation can also be quite costly.&lt;/p&gt;


	&lt;p&gt;But sure, in most cases, amb is not a very efficient way solving constraint problems..&lt;/p&gt;</description>
      <pubDate>Fri, 08 Jun 2007 08:17:17 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:77886418-508f-4b7f-aba2-9cfcdc439d53</guid>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator#comment-465</link>
    </item>
    <item>
      <title>"McCarthy's Ambiguous Operator" by Eric Kidd</title>
      <description>&lt;p&gt;Wow! That&amp;#8217;s very cool.&lt;/p&gt;


	&lt;p&gt;If you&amp;#8217;re into constraint languages, you might also enjoy &lt;a href="http://www.mozart-oz.org/" rel="nofollow"&gt;Oz&lt;/a&gt;, which can do heavily-optimized searches of constraint problems.&lt;/p&gt;


	&lt;p&gt;The big advantage of Oz: Before choosing which path to investigate, it tries to infer as much information as possible (aka &amp;#8220;propagation&amp;#8221;). And then it makes very intelligent guesses about exactly which &amp;#8220;guess&amp;#8221; to make next (aka &amp;#8220;distribution&amp;#8221;).&lt;/p&gt;


	&lt;p&gt;Since a backtracking search takes O(2^N) time (yikes!), it&amp;#8217;s worth doing a &lt;em&gt;lot&lt;/em&gt; of work before actually branching.&lt;/p&gt;


	&lt;p&gt;And the most popular implementation of Oz can actually spread the search over an entire cluster of computers!&lt;/p&gt;</description>
      <pubDate>Sun, 21 Jan 2007 11:51:06 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:3398b76a-e2cf-462c-84e5-3a98d3ed5cba</guid>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator#comment-235</link>
    </item>
    <item>
      <title>"McCarthy's Ambiguous Operator" by Ben</title>
      <description>&lt;p&gt;Wow, I just implemented the send+more=money solver with amb:&lt;/p&gt;


&lt;pre&gt;

# define variables
m = 1
n = amb(0, 2, 3, 4, 5, 6, 7, 8, 9)
o = amb(0, 2, 3, 4, 5, 6, 7, 8, 9)
r = amb(0, 2, 3, 4, 5, 6, 7, 8, 9)
s = amb(2, 3, 4, 5, 6, 7, 8, 9)
y = amb(0, 2, 3, 4, 5, 6, 7, 8, 9)
e = amb(0, 2, 3, 4, 5, 6, 7, 8, 9)
d = amb(0, 2, 3, 4, 5, 6, 7, 8, 9)

# reduce the problem space
amb unless(d+e == y || d+e == y+10)
amb unless(s+m+1 &amp;gt;= 10)

# The actual problem
send = s*1000 + e*100 + n*10 + d
more = m*1000 + o*100 + n*10 + e
money = m*10000 + o*1000 + n*100 + e*10 + y
amb unless(send+more == money)

# p "m=#{m}, n=#{n},  o=#{o}, r=#{r}, s=#{s}, y=#{y}, e=#{e}, d=#{d}," 

# Make sure all variables are different
a = [m, n, o, r, s, y, e, d]
t = Array.new(10, 0)
a.each { |v| amb unless (t[v]+=1)&amp;lt;2 }

# stop
cut

p "Final solution: m=#{m}, n=#{n},  o=#{o}, r=#{r}, s=#{s}, y=#{y}, e=#{e}, d=#{d}," 
&lt;/pre&gt;

	&lt;p&gt;Amb is pretty cool!
Ben&lt;/p&gt;</description>
      <pubDate>Wed, 17 Jan 2007 12:05:24 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:4150c877-da90-49a5-a235-031034a4c7d9</guid>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator#comment-231</link>
    </item>
    <item>
      <title>"McCarthy's Ambiguous Operator" by Ben</title>
      <description>&lt;p&gt;Thats really interesting.
It means that you could write a constraint &lt;span class="caps"&gt;DSL&lt;/span&gt; in Ruby or any other language which implements continuations. I thought constraint engines were hard&amp;#8230;&lt;/p&gt;


	&lt;p&gt;Cheers
Ben&lt;/p&gt;</description>
      <pubDate>Wed, 17 Jan 2007 06:58:29 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:1d2c6985-5144-43e7-9d14-2c01dac14d3c</guid>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator#comment-230</link>
    </item>
    <item>
      <title>"McCarthy's Ambiguous Operator" by Dan Piponi</title>
      <description>&lt;p&gt;I have an implementation of &amp;#8220;amb&amp;#8221; that can be used in C &lt;a href="http://homepage.mac.com/sigfpe/Computing/continuations.html" rel="nofollow"&gt;here&lt;/a&gt;. Thanks for giving a name to this operator for me &amp;#8211; I never knew what to call it.&lt;/p&gt;</description>
      <pubDate>Wed, 22 Feb 2006 19:32:06 -0500</pubDate>
      <guid isPermaLink="false">urn:uuid:52440908-5880-4154-aed6-2629d690ebcb</guid>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator#comment-174</link>
    </item>
    <item>
      <title>McCarthy's Ambiguous Operator</title>
      <description>    &lt;p&gt;Back in 1961, John McCarthy (the inventor of LISP) &lt;a href='http://citeseer.ist.psu.edu/mccarthy63basis.html'&gt;described&lt;/a&gt;
    an interesting mathematical operator called &lt;code&gt;amb&lt;/code&gt;.  Essentially,
    &lt;code&gt;amb&lt;/code&gt; &lt;i&gt;hates&lt;/i&gt; to be called with no arguments, and can look
    into the future to keep that from happening.  Here's how it might look
    in Ruby.&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.randomhacks.net/articles/2005/10/11/amb-operator"&gt;Read More&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Tue, 11 Oct 2005 00:00:00 -0400</pubDate>
      <guid isPermaLink="false">urn:uuid:8d29ae6d-81d0-4f48-a6cb-80187e1821a7</guid>
      <author>Eric</author>
      <link>http://www.randomhacks.net/articles/2005/10/11/amb-operator</link>
      <category>Ruby</category>
      <category>Continuations</category>
      <category>Hacks</category>
      <category>Recommended</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/70</trackback:ping>
    </item>
  </channel>
</rss>
