<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>popcyclical - fsharp</title>
    <link>http://popcyclical.com/</link>
    <description>The software development blog of James "poprhythm" Kolpack</description>
    <language>en-us</language>
    <copyright>James Kolpack</copyright>
    <lastBuildDate>Thu, 26 Apr 2012 00:44:10 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.3.12105.0</generator>
    <managingEditor>dasblog@example.com</managingEditor>
    <webMaster>dasblog@example.com</webMaster>
    <item>
      <trackback:ping>http://popcyclical.com/Trackback.aspx?guid=ff41614e-56ce-4e46-bc03-41dee971eed7</trackback:ping>
      <pingback:server>http://popcyclical.com/pingback.aspx</pingback:server>
      <pingback:target>http://popcyclical.com/PermaLink,guid,ff41614e-56ce-4e46-bc03-41dee971eed7.aspx</pingback:target>
      <dc:creator>James Kolpack</dc:creator>
      <wfw:comment>http://popcyclical.com/CommentView,guid,ff41614e-56ce-4e46-bc03-41dee971eed7.aspx</wfw:comment>
      <wfw:commentRss>http://popcyclical.com/SyndicationService.asmx/GetEntryCommentsRss?guid=ff41614e-56ce-4e46-bc03-41dee971eed7</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
I’ve been slowly making my way through the first 100 <a href="http://projecteuler.net/">Project
Euler</a> problems while learning F# in an attempt to be <a href="http://www.amazon.com/gp/product/020161622X?ie=UTF8&amp;tag=popcyclical-20&amp;linkCode=shr&amp;camp=213733&amp;creative=393185&amp;creativeASIN=020161622X">more
pragmatic</a> - and to try and prevent my grey matter from getting too stale. 
After many hours of keyboard-head-banging, I’m now getting to the point where I don’t
flail uselessly when beginning to type in some F# code – the <a href="http://msdn.microsoft.com/en-us/library/dd547125.aspx">pattern
matching</a>, <a href="http://msdn.microsoft.com/en-us/library/dd233183.aspx">automatic
generalization</a> and <a href="http://en.wikibooks.org/wiki/F_Sharp_Programming/Higher_Order_Functions">higher-order
functions</a> now feel like useful tools rather than strange curiosities.  Since
I’ve primarily coded in C# for many years, I’ve been using the book “<a href="http://www.amazon.com/gp/product/1933988924?ie=UTF8&amp;tag=popcyclical-20&amp;linkCode=shr&amp;camp=213733&amp;creative=393185&amp;creativeASIN=1933988924">Real
World Functional Programming</a>” by <a href="http://tomasp.net/">Tomas Petricek</a> as
a starting point – it’s been a pretty good read. So, for this post the code will be
in F#, but it’ll be secondary to the more general topic of problem solving for puzzle-type
scenarios commonly found on Project Euler.
</p>
        <p>
I found this <a href="http://projecteuler.net/problem=98">particular problem, #98</a>,
a bit more challenging than usual - and kind of fun to work through.  It involves
matching anagrams with square numbers using character replacement – here’s the full
description:
</p>
        <blockquote>
          <p>
By replacing each of the letters in the word CARE with 1, 2, 9, and 6 respectively,
we form a square number: 1296 = 36<sup>2</sup>. What is remarkable is that, by using
the same digital substitutions, the anagram, RACE, also forms a square number: 9216
= 96<sup>2</sup>. We shall call CARE (and RACE) a square anagram word pair and specify
further that leading zeroes are not permitted, neither may a different letter have
the same digital value as another letter. 
</p>
          <p>
Using words.txt, a 16K text file containing nearly two-thousand common English words,
find all the square anagram word pairs (a palindromic word is NOT considered to be
an anagram of itself). 
</p>
          <p>
What is the largest square number formed by any member of such a pair?
</p>
        </blockquote>
        <p>
This is what I’d consider a pretty good puzzle – the elements (a word list and square
numbers) are easy enough to grasp, the way they’re related together is unique for
this scenario, and an effective solution does not immediately pop into mind. 
Well, it didn’t pop into <em>my </em>mind, at least.  So – where to begin?
</p>
        <p>
Many of the problems (at least the ones I’ve solved so far) on Project Euler involve
a few common steps to reach a solution:
</p>
        <ul>
          <li>
            <strong>Generate a set of input values for the problem</strong> – usually this will
be a large set of potential values, such as all the prime numbers below 10,000,000,
or in this case, 16K of words and a bunch of square numbers. 
</li>
          <li>
Given these inputs, <strong>build an algorithm that can test for the solution</strong>. 
</li>
          <li>
            <strong>Add constraints to reduce the size of the input set</strong> so that the solution
can quickly be found.  On modern hardware, this is usually under 1 second – but
anything under a minute is <a href="http://projecteuler.net/about">considered kosher</a>.</li>
        </ul>
        <h3>Input Values
</h3>
        <p>
The input values are easy here – they’ve provided the word list, and a sequence of
square numbers should be trivial.  First, reading the word list.  Instead
of placing the words each on a new line, the file instead contains a single line formatted
like:
</p>
        <blockquote>
          <pre>"A","ABILITY","ABLE","ABOUT","ABOVE","ABSENCE"...</pre>
        </blockquote>
        <p>
Ok – so it’ll take a little parsing.  No problem.
</p>
        <pre>
          <code>let words = System.IO.File.ReadAllLines(@"words.txt") |&gt; Array.collect
(fun line -&gt; line.Split(',')) |&gt; Array.map (fun w -&gt; w.Replace("\"", "").ToLower())</code>
        </pre>
        <p>
This loads the line from the file, splits the words by commas, and removes the quotations…
and I threw in making the words lowercase – since I hate having my puzzles constantly
shouting at me.  A little aside for the language particulars: the <code>|&gt;</code> is
the magical-looking-but-actually-quite-simple <a href="http://msdn.microsoft.com/en-us/magazine/cc164244.aspx#S6">pipeline
operator</a> – it passes the output from the function on the left to be input for
the function on the right. And the <code>fun –&gt;</code> is <a href="http://msdn.microsoft.com/en-us/library/dd233201.aspx">F#
syntax for lambda expressions</a>.  At the end of the pipeline comes a simple
array containing the parsed words. 
</p>
        <p>
  
</p>
        <p>
So for the rest of the input - the square numbers.  F# has the means to generate
an infinite sequence which can then be sliced and diced to get at the bits that are
needed.  The perfect squares can be generated with:
</p>
        <pre>
          <code>let allSquares = 
<br />
Seq.unfold(fun (square,odd) -&gt; Some(square, (square+odd, odd+2))) (0,1)</code>
        </pre>
        <p>
The square numbers are “<a href="http://msdn.microsoft.com/en-us/library/ee340363.aspx">unfolded</a>”
– that is, each element is calculated based on the result from the previous element,
like you’d do with.  Square numbers have a <a href="http://en.wikipedia.org/wiki/Square_number#Properties">property
where they can be generated by as the sum of a list of successive odd numbers</a>.
The <a href="http://msdn.microsoft.com/en-us/library/dd233200.aspx">tuple</a> of <code>(0,1)</code> on
the far right is fed in as an initial value, with <code>0</code> being the first “square”
number and <code>1</code> being the first odd number.  At each step of the unfold,
the odd number is increased by 2, and the square number is calculated by the adding
the previous odd number. So, the (square,odd) tuples being computed will look like:<code>(0,1),(1,3),(4,5),(9,7),(16,9)</code><font face="Lucida Sans Unicode">,
with only the squares being captured as output.  Works for me!</font></p>
        <p>
As with most simple-yet-effective bits of code, this one went through a couple of
refinements before nailing it.  The first pass looked like this:
</p>
        <pre>
          <code>Seq.unfold(fun i -&gt; Some(i, i + 1)) 0 |&gt; Seq.map (fun i -&gt;
i*i)</code>
        </pre>
        <p>
…where the squares are generated in two steps instead of one. The first bit unfolds
all the natural numbers from 0 to infinity (or more likely, maxint), and the second
part maps these each by squaring them.  It produces the same result, but is less
elegant because it uses more moving pieces.
</p>
        <p>
That’s all the input this problem should require – next, to design the…
</p>
        <h3>Success Algorithm
</h3>
        <p>
A useful bit of the Project Euler problem descriptions is that they usually include
an example which can be used as a test case for a solution algorithm. Here they’ve
provided:
</p>
        <pre>care, race // &lt;- anagrams map to<br />
1296, 9216 // &lt;- squares</pre>
        <p>
…with a replacement dictionary of <code>(c,1),(a,2),(r,9),(e,6)</code>.  It’s
important to note that the anagrams and squares might be symmetric, where the numbers
can be swapped (i.e. <code>(c,9),(a,2),(r,1),(e,6)</code> works as well), but there
are cases (such as the final answer) where this doesn’t hold.
</p>
        <p>
To devise an algorithm to test for an answer, the first step is to think it over before
doing any typing.  It’s better to have some notion of a strategy than to rush
in with the codes.  I struggle with adhering to this – it’s just too easy to
think “I’m so good, I’ll just figure it out as I program.”  I’ve found it’s more
productive to get away - get a pen and some paper and start sketching ideas, take
a walk, etc.  There’ll be plenty of time to work through all the details in code,
but it’s best to go in with a plan – a vague or even an incorrect strategy is better
than none at all.
</p>
        <p>
For this problem, I started with the idea of comparing each letter of the first word
with the first square number, building a replacement dictionary while iterating through
them.  If a valid replacement dictionary for the first set is found, it would
then be tested against the second word-square-number pair. Writing in algorithm in
F# meant I could treat the words as lists and iterate them using a common combination
of recursive function calls and pattern matching.
</p>
        <pre>
          <code>let rec getReplacementDictionary (sToT, tToS) (source, target) = match
source, target with // have already seen this exact mapping -&gt; skip it | s::ss,
t::tt when Map.containsKey s sToT &amp;&amp; (Map.find s sToT) = t -&gt; getReplacementDictionary
(sToT, tToS) (ss, tt) // have a mapping for the source, but it's not the target -&gt;
failure | s::_, _ when Map.containsKey s sToT -&gt; None // have a mapping for the
target, but it's not the source -&gt; failure | _::_, t::_ when Map.containsKey t
tToS -&gt; None // never before seen mapping -&gt; add it | s::ss, t::tt -&gt; getReplacementDictionary
(Map.add s t sToT, Map.add t s tToS) (ss, tt) // end of the line - a successful translation!
| [], [] -&gt; Some(sToT, tToS) | _ -&gt; raise(System.ArgumentException("words not
equal length")) </code>
        </pre>
        <p>
I’ve named the variables “source” and “target” – they’ll get passed the word and the
number, respectively.  They are “matched” against conditions using the patterns
seen on each line following the pipe “<code>|</code>” character.  The easiest
of these to grasp is near the end – “<code>| [], [] –&gt; Some(sToT, tToS)</code>“
which matches two empty lists, indicating that the words have been completely checked
and that there is a valid dictionary.  For the dictionary itself, I found that
it was necessary to keep tabs on both the source-to-target values (sToT) as well as
the target-to-source (tToS) values.  A bi-directional mapping structure would
be ideal, but it would have been more effort to construct that than to fudge it with
an extra variable.  If there is a better way to handle this, I’d be interested
to hear it…  
</p>
        <p>
At any rate, the result of this function will either be a failure - with the None
value - or with the completed dictionary(s) – the Some(sToT, tToS).  Testing
it against “care” and “1296” produces the expect result:
</p>
        <pre>
          <code>&gt; getReplacementDictionary (Map.empty, Map.empty) ("care" |&gt;
List.ofSeq, "1296" |&gt; List.ofSeq);; val it : (Map&lt;char,char&gt; * Map&lt;char,char&gt;)
option = Some (map [('a', '2'); ('c', '1'); ('e', '6'); ('r', '9')], map [('1', 'c');
('2', 'a'); ('6', 'e'); ('9', 'r')])</code>
        </pre>
        <p>
…and changing a digit in the number to one of the already mapped digits results (I’m
using 1292 which repeats the 2) in a failure:
</p>
        <pre>
          <code>&gt; getReplacementDictionary (Map.empty, Map.empty) ("care" |&gt;
List.ofSeq, "1292" |&gt; List.ofSeq);; val it : (Map&lt;char,char&gt; * Map&lt;char,char&gt;)
option = None</code>
        </pre>
        <p>
To test this dictionary against the second group, “race” and “9216”, the original
function may be reused because all of the character mappings will have been seen in
the first group and they will simply be verified via the first pattern.  
</p>
        <pre>
          <code>let dict = getReplacementDictionary (Map.empty, Map.empty) ("care"
|&gt; List.ofSeq, "1296" |&gt; List.ofSeq) getReplacementDictionary dict.Value ("race"
|&gt; List.ofSeq, "9216" |&gt; List.ofSeq);; val dict : (Map&lt;char,char&gt; * Map&lt;char,char&gt;)
option = Some (map [('a', '2'); ('c', '1'); ('e', '6'); ('r', '9')], map [('1', 'c');
('2', 'a'); ('6', 'e'); ('9', 'r')])</code>
        </pre>
        <p>
This is making an assumption that the input words are anagrams of each other – this
is an OK assumption to make for now.  Indeed, it can be even assumed that the
input data may be filtered for anagrams – I’ll cover that in the next section.
</p>
        <p>
I noticed that this could be further streamlined by simply appending the words and
the numbers together, since that is more-or-less what is occurring when calling it
twice.  And in that case, the function no longer needs to return the mapping
dictionary – just a simple boolean indicating if a valid dictionary can be applied
to the input.   So, the function can be modified as follows, making sure
to rename it:
</p>
        <pre>
          <code>let rec hasReplacementDictionary (sToT, tToS) (source, target) = match
source, target with | s::ss, t::tt when Map.containsKey s sToT &amp;&amp; (Map.find
s sToT) = t -&gt; hasReplacementDictionary (sToT, tToS) (ss, tt) | s::_, _ when Map.containsKey
s sToT -&gt; false | _::_, t::_ when Map.containsKey t tToS -&gt; false | s::ss, t::tt
-&gt; hasReplacementDictionary (Map.add s t sToT, Map.add t s tToS) (ss, tt) | [],
[] -&gt; true | _ -&gt; raise(System.ArgumentException("words not equal length"))</code>
        </pre>
        <p>
and run a test:
</p>
        <pre>
          <code>&gt; let los = List.ofSeq let s = List.append (List.ofSeq "care") (List.ofSeq
"race") let t = List.append (List.ofSeq "1296") (List.ofSeq "9216");; &gt; hasReplacementDictionary
(Map.empty, Map.empty) (s, t);; val it : bool = true</code>
        </pre>
        <p>
Success!  Now, having all the necessary input and a valid algorithm, it would
be possible to test every possibly combination of inputs to find the correct answer.  
</p>
        <h3>Input Constraints 
</h3>
        <p>
Project Euler problems are usually infeasible to answer without a computer. 
(There’s sometimes really smart math folks in the forums who will find clever ways
around this, but for the rest of us…)  
</p>
        <p>
How many combinations of the input data could there be, anyway?  There’s a total
of 1,786 words ranging in length from 1 to 14 characters, which leads to ~3.2 million
combinations of just the words.  My script to calculate the count of all square
numbers under 14 digits ran out of memory, but it turns out only up to 9 digit squares
are needed.  There are 31,623 of those.  The number of combinations would
be 1,786<sup>2</sup> × 31,623<sup>2</sup> ≈ 3.2E15.  That’s several thousand
billion – got to keep filtering or it’ll take a year!
</p>
        <p>
The next obvious step is to pair up the anagrams and discard the rest of the words. 
A simple way to do this is to alphabetically sort each character in each word and
group together the ones that are exactly the same.  For example “care” and “race”
will both map to “acer” – neat trick!  Here’s the code
</p>
        <pre>
          <code>let groupAnagrams ws = ws // sort by characters in each string and then
glue them back together |&gt; Seq.groupBy (Array.ofSeq &gt;&gt; Array.sort &gt;&gt;
(fun cs -&gt; new string(cs))) // take only the anagrams - where the number of words
is greater than one |&gt; Seq.map snd |&gt; Seq.filter (Seq.length &gt;&gt; ((&lt;)
1))</code>
        </pre>
        <p>
This is a great first step – but it’s not quite enough.  I want all the pairs
of anagrams and there are cases where there are more than 2 words that all have the
same letters.  For example, “post”, “spot” and “stop” will all group together. 
What I need is combinations of all the pairs – so I’ll end up with (“post”, “spot”),
(“spot”, stop”), and (“post”, “stop”).  Fortunately, I had already borrowed/stolen
a generic combination function that <a href="http://stackoverflow.com/a/4495708/99492">Tomas
had posted on Stack Overflow</a>.
</p>
        <pre>
          <code>let combinations size set = let rec combinations acc size set = seq { match
size, set with | n, x::xs -&gt; if n &gt; 0 then yield! combinations (x::acc) (n -
1) xs if n &gt;= 0 then yield! combinations acc n xs | 0, [] -&gt; yield acc | _,
[] -&gt; () } combinations [] size (set |&gt; List.ofSeq)</code>
        </pre>
        <p>
Now I can run all the whole list of anagram groups through the combinations algorithm
and produce a single list of anagram pairs:
</p>
        <pre>
          <code>let pairwiseTuples = Seq.collect ( combinations 2 &gt;&gt; Seq.map (fun
l -&gt; l.[0], l.[1]) ) </code>
        </pre>
        <p>
And indeed – it does its job:
</p>
        <pre>[|("cat", "act"); ... ("race", "care");
  ...
  ("spot", "post"); ("stop", "post"); ("stop", "spot"); 
  ...|]</pre>
        <p>
Running the words through this results in 44 pairs of anagrams with the lengthiest
pair being 9 letters long ("reduction", "introduce"). This is starting to sound reasonable
to process – and it’s where I got stuck for a bit.  Looping through all of the
squares for each pair still seems computationally prohibitive.  
</p>
        <p>
I walked away from it for the day and in the shower the next morning – “duh, the square
numbers can be bundled up as anagrams as well!"  These are the ah-ha moments
that make it all worthwhile.  A few examples – (“1024”, “2401”), (“14400”, “10404”). 
There turned out to still be quite a few for the larger digit counts (for example,
there are 70052 anagram pairs for square numbers with 9 digits), but since there are
so few words in the list that are above 5 characters long, it turned out to be OK.
</p>
        <p>
All was left was to write a few more lines to run all the equal-length anagram pairs
through the success function and find the result.  It ran in about a second on
my hardware, so that is an acceptable solution in my mind.  There are undoubtedly
numerous additional optimizations that could be applied – and perhaps even a way to
word it out on paper (I doubt it for this one) – so I’d be eager to hear any comments.
</p>
        <img width="0" height="0" src="http://popcyclical.com/aggbug.ashx?id=ff41614e-56ce-4e46-bc03-41dee971eed7" />
        <br />
        <hr />
        <a href="http://www.codeproject.com/script/Articles/BlogFeedList.aspx?amid=1252729" rel="tag" style="display:none">CodeProject</a>
      </body>
      <title>How Do You Solve a Problem Like a Euler? Using F#</title>
      <guid isPermaLink="false">http://popcyclical.com/PermaLink,guid,ff41614e-56ce-4e46-bc03-41dee971eed7.aspx</guid>
      <link>http://popcyclical.com/2012/04/26/HowDoYouSolveAProblemLikeAEulerUsingF.aspx</link>
      <pubDate>Thu, 26 Apr 2012 00:44:10 GMT</pubDate>
      <description>&lt;p&gt;
I’ve been slowly making my way through the first 100 &lt;a href="http://projecteuler.net/"&gt;Project
Euler&lt;/a&gt; problems while learning F# in an attempt to be &lt;a href="http://www.amazon.com/gp/product/020161622X?ie=UTF8&amp;amp;tag=popcyclical-20&amp;amp;linkCode=shr&amp;amp;camp=213733&amp;amp;creative=393185&amp;amp;creativeASIN=020161622X"&gt;more
pragmatic&lt;/a&gt; - and to try and prevent my grey matter from getting too stale.&amp;nbsp;
After many hours of keyboard-head-banging, I’m now getting to the point where I don’t
flail uselessly when beginning to type in some F# code – the &lt;a href="http://msdn.microsoft.com/en-us/library/dd547125.aspx"&gt;pattern
matching&lt;/a&gt;, &lt;a href="http://msdn.microsoft.com/en-us/library/dd233183.aspx"&gt;automatic
generalization&lt;/a&gt; and &lt;a href="http://en.wikibooks.org/wiki/F_Sharp_Programming/Higher_Order_Functions"&gt;higher-order
functions&lt;/a&gt; now feel like useful tools rather than strange curiosities.&amp;nbsp; Since
I’ve primarily coded in C# for many years, I’ve been using the book “&lt;a href="http://www.amazon.com/gp/product/1933988924?ie=UTF8&amp;amp;tag=popcyclical-20&amp;amp;linkCode=shr&amp;amp;camp=213733&amp;amp;creative=393185&amp;amp;creativeASIN=1933988924"&gt;Real
World Functional Programming&lt;/a&gt;” by &lt;a href="http://tomasp.net/"&gt;Tomas Petricek&lt;/a&gt; as
a starting point – it’s been a pretty good read. So, for this post the code will be
in F#, but it’ll be secondary to the more general topic of problem solving for puzzle-type
scenarios commonly found on Project Euler.
&lt;/p&gt;
&lt;p&gt;
I found this &lt;a href="http://projecteuler.net/problem=98"&gt;particular problem, #98&lt;/a&gt;,
a bit more challenging than usual - and kind of fun to work through.&amp;nbsp; It involves
matching anagrams with square numbers using character replacement – here’s the full
description:
&lt;/p&gt;
&lt;blockquote&gt; 
&lt;p&gt;
By replacing each of the letters in the word CARE with 1, 2, 9, and 6 respectively,
we form a square number: 1296 = 36&lt;sup&gt;2&lt;/sup&gt;. What is remarkable is that, by using
the same digital substitutions, the anagram, RACE, also forms a square number: 9216
= 96&lt;sup&gt;2&lt;/sup&gt;. We shall call CARE (and RACE) a square anagram word pair and specify
further that leading zeroes are not permitted, neither may a different letter have
the same digital value as another letter. 
&lt;p&gt;
Using words.txt, a 16K text file containing nearly two-thousand common English words,
find all the square anagram word pairs (a palindromic word is NOT considered to be
an anagram of itself). 
&lt;p&gt;
What is the largest square number formed by any member of such a pair?
&lt;/p&gt;
&lt;/blockquote&gt; 
&lt;p&gt;
This is what I’d consider a pretty good puzzle – the elements (a word list and square
numbers) are easy enough to grasp, the way they’re related together is unique for
this scenario, and an effective solution does not immediately pop into mind.&amp;nbsp;
Well, it didn’t pop into &lt;em&gt;my &lt;/em&gt;mind, at least.&amp;nbsp; So – where to begin?
&lt;/p&gt;
&lt;p&gt;
Many of the problems (at least the ones I’ve solved so far) on Project Euler involve
a few common steps to reach a solution:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Generate a set of input values for the problem&lt;/strong&gt; – usually this will
be a large set of potential values, such as all the prime numbers below 10,000,000,
or in this case, 16K of words and a bunch of square numbers. 
&lt;li&gt;
Given these inputs, &lt;strong&gt;build an algorithm that can test for the solution&lt;/strong&gt;. 
&lt;li&gt;
&lt;strong&gt;Add constraints to reduce the size of the input set&lt;/strong&gt; so that the solution
can quickly be found.&amp;nbsp; On modern hardware, this is usually under 1 second – but
anything under a minute is &lt;a href="http://projecteuler.net/about"&gt;considered kosher&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Input Values
&lt;/h3&gt;
&lt;p&gt;
The input values are easy here – they’ve provided the word list, and a sequence of
square numbers should be trivial.&amp;nbsp; First, reading the word list.&amp;nbsp; Instead
of placing the words each on a new line, the file instead contains a single line formatted
like:
&lt;/p&gt;
&lt;blockquote&gt;&lt;pre&gt;"A","ABILITY","ABLE","ABOUT","ABOVE","ABSENCE"...&lt;/pre&gt;&lt;/blockquote&gt; 
&lt;p&gt;
Ok – so it’ll take a little parsing.&amp;nbsp; No problem.
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let words = System.IO.File.ReadAllLines(@"words.txt") |&amp;gt; Array.collect
(fun line -&amp;gt; line.Split(',')) |&amp;gt; Array.map (fun w -&amp;gt; w.Replace("\"", "").ToLower())&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
This loads the line from the file, splits the words by commas, and removes the quotations…
and I threw in making the words lowercase – since I hate having my puzzles constantly
shouting at me.&amp;nbsp; A little aside for the language particulars: the &lt;code&gt;|&amp;gt;&lt;/code&gt; is
the magical-looking-but-actually-quite-simple &lt;a href="http://msdn.microsoft.com/en-us/magazine/cc164244.aspx#S6"&gt;pipeline
operator&lt;/a&gt; – it passes the output from the function on the left to be input for
the function on the right. And the &lt;code&gt;fun –&amp;gt;&lt;/code&gt; is &lt;a href="http://msdn.microsoft.com/en-us/library/dd233201.aspx"&gt;F#
syntax for lambda expressions&lt;/a&gt;.&amp;nbsp; At the end of the pipeline comes a simple
array containing the parsed words. 
&lt;p&gt;
&amp;nbsp; 
&lt;p&gt;
So for the rest of the input - the square numbers.&amp;nbsp; F# has the means to generate
an infinite sequence which can then be sliced and diced to get at the bits that are
needed.&amp;nbsp; The perfect squares can be generated with:&lt;pre&gt;&lt;code&gt;let allSquares
= 
&lt;br&gt;
Seq.unfold(fun (square,odd) -&amp;gt; Some(square, (square+odd, odd+2))) (0,1)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
The square numbers are “&lt;a href="http://msdn.microsoft.com/en-us/library/ee340363.aspx"&gt;unfolded&lt;/a&gt;”
– that is, each element is calculated based on the result from the previous element,
like you’d do with.&amp;nbsp; Square numbers have a &lt;a href="http://en.wikipedia.org/wiki/Square_number#Properties"&gt;property
where they can be generated by as the sum of a list of successive odd numbers&lt;/a&gt;.
The &lt;a href="http://msdn.microsoft.com/en-us/library/dd233200.aspx"&gt;tuple&lt;/a&gt; of &lt;code&gt;(0,1)&lt;/code&gt; on
the far right is fed in as an initial value, with &lt;code&gt;0&lt;/code&gt; being the first “square”
number and &lt;code&gt;1&lt;/code&gt; being the first odd number.&amp;nbsp; At each step of the unfold,
the odd number is increased by 2, and the square number is calculated by the adding
the previous odd number. So, the (square,odd) tuples being computed will look like:&lt;code&gt;(0,1),(1,3),(4,5),(9,7),(16,9)&lt;/code&gt;&lt;font face="Lucida Sans Unicode"&gt;,
with only the squares being captured as output.&amp;nbsp; Works for me!&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
As with most simple-yet-effective bits of code, this one went through a couple of
refinements before nailing it.&amp;nbsp; The first pass looked like this:&lt;pre&gt;&lt;code&gt;Seq.unfold(fun
i -&amp;gt; Some(i, i + 1)) 0 |&amp;gt; Seq.map (fun i -&amp;gt; i*i)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
…where the squares are generated in two steps instead of one. The first bit unfolds
all the natural numbers from 0 to infinity (or more likely, maxint), and the second
part maps these each by squaring them.&amp;nbsp; It produces the same result, but is less
elegant because it uses more moving pieces.
&lt;/p&gt;
&lt;p&gt;
That’s all the input this problem should require – next, to design the…
&lt;/p&gt;
&lt;h3&gt;Success Algorithm
&lt;/h3&gt;
&lt;p&gt;
A useful bit of the Project Euler problem descriptions is that they usually include
an example which can be used as a test case for a solution algorithm. Here they’ve
provided:
&lt;/p&gt;
&lt;pre&gt;care, race // &amp;lt;- anagrams map to&lt;br&gt;
1296, 9216 // &amp;lt;- squares&lt;/pre&gt;
&lt;p&gt;
…with a replacement dictionary of &lt;code&gt;(c,1),(a,2),(r,9),(e,6)&lt;/code&gt;.&amp;nbsp; It’s
important to note that the anagrams and squares might be symmetric, where the numbers
can be swapped (i.e. &lt;code&gt;(c,9),(a,2),(r,1),(e,6)&lt;/code&gt; works as well), but there
are cases (such as the final answer) where this doesn’t hold.
&lt;/p&gt;
&lt;p&gt;
To devise an algorithm to test for an answer, the first step is to think it over before
doing any typing.&amp;nbsp; It’s better to have some notion of a strategy than to rush
in with the codes.&amp;nbsp; I struggle with adhering to this – it’s just too easy to
think “I’m so good, I’ll just figure it out as I program.”&amp;nbsp; I’ve found it’s more
productive to get away - get a pen and some paper and start sketching ideas, take
a walk, etc.&amp;nbsp; There’ll be plenty of time to work through all the details in code,
but it’s best to go in with a plan – a vague or even an incorrect strategy is better
than none at all.
&lt;/p&gt;
&lt;p&gt;
For this problem, I started with the idea of comparing each letter of the first word
with the first square number, building a replacement dictionary while iterating through
them.&amp;nbsp; If a valid replacement dictionary for the first set is found, it would
then be tested against the second word-square-number pair. Writing in algorithm in
F# meant I could treat the words as lists and iterate them using a common combination
of recursive function calls and pattern matching.
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let rec getReplacementDictionary (sToT, tToS) (source, target) = match
source, target with // have already seen this exact mapping -&amp;gt; skip it | s::ss,
t::tt when Map.containsKey s sToT &amp;amp;&amp;amp; (Map.find s sToT) = t -&amp;gt; getReplacementDictionary
(sToT, tToS) (ss, tt) // have a mapping for the source, but it's not the target -&amp;gt;
failure | s::_, _ when Map.containsKey s sToT -&amp;gt; None // have a mapping for the
target, but it's not the source -&amp;gt; failure | _::_, t::_ when Map.containsKey t
tToS -&amp;gt; None // never before seen mapping -&amp;gt; add it | s::ss, t::tt -&amp;gt; getReplacementDictionary
(Map.add s t sToT, Map.add t s tToS) (ss, tt) // end of the line - a successful translation!
| [], [] -&amp;gt; Some(sToT, tToS) | _ -&amp;gt; raise(System.ArgumentException("words not
equal length")) &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
I’ve named the variables “source” and “target” – they’ll get passed the word and the
number, respectively.&amp;nbsp; They are “matched” against conditions using the patterns
seen on each line following the pipe “&lt;code&gt;|&lt;/code&gt;” character.&amp;nbsp; The easiest
of these to grasp is near the end – “&lt;code&gt;| [], [] –&amp;gt; Some(sToT, tToS)&lt;/code&gt;“
which matches two empty lists, indicating that the words have been completely checked
and that there is a valid dictionary.&amp;nbsp; For the dictionary itself, I found that
it was necessary to keep tabs on both the source-to-target values (sToT) as well as
the target-to-source (tToS) values.&amp;nbsp; A bi-directional mapping structure would
be ideal, but it would have been more effort to construct that than to fudge it with
an extra variable.&amp;nbsp; If there is a better way to handle this, I’d be interested
to hear it…&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
At any rate, the result of this function will either be a failure - with the None
value - or with the completed dictionary(s) – the Some(sToT, tToS).&amp;nbsp; Testing
it against “care” and “1296” produces the expect result:&lt;pre&gt;&lt;code&gt;&amp;gt; getReplacementDictionary
(Map.empty, Map.empty) ("care" |&amp;gt; List.ofSeq, "1296" |&amp;gt; List.ofSeq);; val it
: (Map&amp;lt;char,char&amp;gt; * Map&amp;lt;char,char&amp;gt;) option = Some (map [('a', '2'); ('c',
'1'); ('e', '6'); ('r', '9')], map [('1', 'c'); ('2', 'a'); ('6', 'e'); ('9', 'r')])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
…and changing a digit in the number to one of the already mapped digits results (I’m
using 1292 which repeats the 2) in a failure:&lt;pre&gt;&lt;code&gt;&amp;gt; getReplacementDictionary
(Map.empty, Map.empty) ("care" |&amp;gt; List.ofSeq, "1292" |&amp;gt; List.ofSeq);; val it
: (Map&amp;lt;char,char&amp;gt; * Map&amp;lt;char,char&amp;gt;) option = None&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
To test this dictionary against the second group, “race” and “9216”, the original
function may be reused because all of the character mappings will have been seen in
the first group and they will simply be verified via the first pattern.&amp;nbsp; &lt;pre&gt;&lt;code&gt;let
dict = getReplacementDictionary (Map.empty, Map.empty) ("care" |&amp;gt; List.ofSeq, "1296"
|&amp;gt; List.ofSeq) getReplacementDictionary dict.Value ("race" |&amp;gt; List.ofSeq, "9216"
|&amp;gt; List.ofSeq);; val dict : (Map&amp;lt;char,char&amp;gt; * Map&amp;lt;char,char&amp;gt;) option
= Some (map [('a', '2'); ('c', '1'); ('e', '6'); ('r', '9')], map [('1', 'c'); ('2',
'a'); ('6', 'e'); ('9', 'r')])&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
This is making an assumption that the input words are anagrams of each other – this
is an OK assumption to make for now.&amp;nbsp; Indeed, it can be even assumed that the
input data may be filtered for anagrams – I’ll cover that in the next section.
&lt;/p&gt;
&lt;p&gt;
I noticed that this could be further streamlined by simply appending the words and
the numbers together, since that is more-or-less what is occurring when calling it
twice.&amp;nbsp; And in that case, the function no longer needs to return the mapping
dictionary – just a simple boolean indicating if a valid dictionary can be applied
to the input.&amp;nbsp;&amp;nbsp; So, the function can be modified as follows, making sure
to rename it:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let rec hasReplacementDictionary (sToT, tToS) (source, target) = match
source, target with | s::ss, t::tt when Map.containsKey s sToT &amp;amp;&amp;amp; (Map.find
s sToT) = t -&amp;gt; hasReplacementDictionary (sToT, tToS) (ss, tt) | s::_, _ when Map.containsKey
s sToT -&amp;gt; false | _::_, t::_ when Map.containsKey t tToS -&amp;gt; false | s::ss, t::tt
-&amp;gt; hasReplacementDictionary (Map.add s t sToT, Map.add t s tToS) (ss, tt) | [],
[] -&amp;gt; true | _ -&amp;gt; raise(System.ArgumentException("words not equal length"))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
and run a test:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; let los = List.ofSeq let s = List.append (List.ofSeq "care") (List.ofSeq
"race") let t = List.append (List.ofSeq "1296") (List.ofSeq "9216");; &amp;gt; hasReplacementDictionary
(Map.empty, Map.empty) (s, t);; val it : bool = true&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Success!&amp;nbsp; Now, having all the necessary input and a valid algorithm, it would
be possible to test every possibly combination of inputs to find the correct answer.&amp;nbsp; 
&lt;/p&gt;
&lt;h3&gt;Input Constraints 
&lt;/h3&gt;
&lt;p&gt;
Project Euler problems are usually infeasible to answer without a computer.&amp;nbsp;
(There’s sometimes really smart math folks in the forums who will find clever ways
around this, but for the rest of us…)&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
How many combinations of the input data could there be, anyway?&amp;nbsp; There’s a total
of 1,786 words ranging in length from 1 to 14 characters, which leads to ~3.2 million
combinations of just the words.&amp;nbsp; My script to calculate the count of all square
numbers under 14 digits ran out of memory, but it turns out only up to 9 digit squares
are needed.&amp;nbsp; There are 31,623 of those.&amp;nbsp; The number of combinations would
be 1,786&lt;sup&gt;2&lt;/sup&gt; × 31,623&lt;sup&gt;2&lt;/sup&gt; ≈ 3.2E15.&amp;nbsp; That’s several thousand
billion – got to keep filtering or it’ll take a year!
&lt;/p&gt;
&lt;p&gt;
The next obvious step is to pair up the anagrams and discard the rest of the words.&amp;nbsp;
A simple way to do this is to alphabetically sort each character in each word and
group together the ones that are exactly the same.&amp;nbsp; For example “care” and “race”
will both map to “acer” – neat trick!&amp;nbsp; Here’s the code
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let groupAnagrams ws = ws // sort by characters in each string and then
glue them back together |&amp;gt; Seq.groupBy (Array.ofSeq &amp;gt;&amp;gt; Array.sort &amp;gt;&amp;gt;
(fun cs -&amp;gt; new string(cs))) // take only the anagrams - where the number of words
is greater than one |&amp;gt; Seq.map snd |&amp;gt; Seq.filter (Seq.length &amp;gt;&amp;gt; ((&amp;lt;)
1))&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
This is a great first step – but it’s not quite enough.&amp;nbsp; I want all the pairs
of anagrams and there are cases where there are more than 2 words that all have the
same letters.&amp;nbsp; For example, “post”, “spot” and “stop” will all group together.&amp;nbsp;
What I need is combinations of all the pairs – so I’ll end up with (“post”, “spot”),
(“spot”, stop”), and (“post”, “stop”).&amp;nbsp; Fortunately, I had already borrowed/stolen
a generic combination function that &lt;a href="http://stackoverflow.com/a/4495708/99492"&gt;Tomas
had posted on Stack Overflow&lt;/a&gt;.
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let combinations size set = let rec combinations acc size set = seq { match
size, set with | n, x::xs -&amp;gt; if n &amp;gt; 0 then yield! combinations (x::acc) (n -
1) xs if n &amp;gt;= 0 then yield! combinations acc n xs | 0, [] -&amp;gt; yield acc | _,
[] -&amp;gt; () } combinations [] size (set |&amp;gt; List.ofSeq)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
Now I can run all the whole list of anagram groups through the combinations algorithm
and produce a single list of anagram pairs:
&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;let pairwiseTuples = Seq.collect ( combinations 2 &amp;gt;&amp;gt; Seq.map (fun
l -&amp;gt; l.[0], l.[1]) ) &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;
And indeed – it does its job:
&lt;/p&gt;
&lt;pre&gt;[|("cat", "act"); ... ("race", "care");
  ...
  ("spot", "post"); ("stop", "post"); ("stop", "spot"); 
  ...|]&lt;/pre&gt;
&lt;p&gt;
Running the words through this results in 44 pairs of anagrams with the lengthiest
pair being 9 letters long ("reduction", "introduce"). This is starting to sound reasonable
to process – and it’s where I got stuck for a bit.&amp;nbsp; Looping through all of the
squares for each pair still seems computationally prohibitive.&amp;nbsp; 
&lt;/p&gt;
&lt;p&gt;
I walked away from it for the day and in the shower the next morning – “duh, the square
numbers can be bundled up as anagrams as well!"&amp;nbsp; These are the ah-ha moments
that make it all worthwhile.&amp;nbsp; A few examples – (“1024”, “2401”), (“14400”, “10404”).&amp;nbsp;
There turned out to still be quite a few for the larger digit counts (for example,
there are 70052 anagram pairs for square numbers with 9 digits), but since there are
so few words in the list that are above 5 characters long, it turned out to be OK.
&lt;/p&gt;
&lt;p&gt;
All was left was to write a few more lines to run all the equal-length anagram pairs
through the success function and find the result.&amp;nbsp; It ran in about a second on
my hardware, so that is an acceptable solution in my mind.&amp;nbsp; There are undoubtedly
numerous additional optimizations that could be applied – and perhaps even a way to
word it out on paper (I doubt it for this one) – so I’d be eager to hear any comments.
&lt;/p&gt;
&lt;img width="0" height="0" src="http://popcyclical.com/aggbug.ashx?id=ff41614e-56ce-4e46-bc03-41dee971eed7" /&gt;
&lt;br /&gt;
&lt;hr /&gt;
&lt;a href="http://www.codeproject.com/script/Articles/BlogFeedList.aspx?amid=1252729" rel="tag" style="display:none"&gt;CodeProject&lt;/a&gt;</description>
      <comments>http://popcyclical.com/CommentView,guid,ff41614e-56ce-4e46-bc03-41dee971eed7.aspx</comments>
      <category>fsharp</category>
      <category>projecteuler</category>
    </item>
  </channel>
</rss>