<div>wow I just woke up to see this :). Im impressed at the speed of the response, thanks Daniel<br></div><div><br></div><br>
<div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">Bad news first.<br>
a) According to codechef, you must also consider digits.<br>
</blockquote><div><br></div><div>you&#39;re right, I totally missed this. Thanks :)</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">b) Your distance function is wrong.<br>
</blockquote><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
With idx i j = (i+1)*(j+1) - 1, you write to the same position several times, resulting in<br>
garbage. You should use idx i j = i*(n+1) + j.<br> Unfortunately, that slows things down.<br></blockquote><div><br></div><div>wow that&#39;s just such an incredibly &quot;doh&quot; moment for me. I had initially written the array as being indexed by a tuple (i,j) and later to speed things up I moved to a single dimensional array without realising I had done something so dumb. </div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">Now some good news.<br>
a) Since the substitution cost for a pair of letters doesn&#39;t depend on the strings, you<br>
can make a universal substitution-cost matrix (UArray (Char,Char) Int) and read the cost<br>
off that. Doesn&#39;t work wonders, but speeds things up a little.<br></blockquote><div><br></div><div>yes this makes a lot of sense. I had initially kept the letterHash outside. I moved it inside thinking to encapsulate it into substition cost because it didnt change the time much. But making the entire substitution cost matrix fixed makes a lot of sense</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
b) If the lengths of the two strings differs by more than 2, the Levenshtein distance is<br>
at least 3, so you needn&#39;t calculate. This was probably your intention, but laziness<br>
doesn&#39;t quite work the way you thought (if I interpreted your intentions correctly).<br>
With<br>
<br>
distance orig new = memf m n<br>
where<br>
m = snd $ bounds orig<br>
n = snd $ bounds new ...<br>
<br>
, if |m - n| &gt; 2, the thunks for the array entries must still be written - although most<br>
needn&#39;t be evaluated in this case, that still takes a lot of time.<br>
Make it<br>
<br>
distance orig new = f m n<br>
<br>
and no thunks need be written at all in this case.<br>
Cuts down running time by nearly half :)<br></blockquote><div><br></div><div>wow yes. I was too obsessed with how I had seen the fibonacci example of memoisation that I didnt think of this. Also I think I still dont pay enough attention to thunks and the time they take. So the problem here is when I calculate memf an entire array of thunks is written down and then the last one is being evaluated. So I could avoid the array creation. Makes sense to me :)</div>
<div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br> I think you could speed it up significantly by calculating the distance more lazily.</blockquote><div><br></div><div>I&#39;d love to hear your thoughts on how that might happen? I thought the whole thing was inherently lazy? </div>
<div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
The profiling output is pretty straightforward. You have two functions that take up more<br>
or less all the time, one is substitutionCost, the other distance.<br>
<br>
The former is comparatively benign, the letterHash should be calculated only once and kept<br>
alive through the entire run, but you use a Map.lookup and `elem` (plus a branch); with 26<br>
letters, a lookup takes on average about 4 comparisons, then in general two comparisons<br>
for `elem`. An array-lookup will be much faster.<br></blockquote><div><br></div><div>aha right. </div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br>
The latter uses really a lot of time. As said before, a large part of it is because you&#39;re<br>
not lazy enough. Still, it is a complicated calculation, so it remains a time-consuming<br>
task.<br>
For more detailed information which parts of it take the most time, add further cost<br>
centres ({-# SCC &quot;thing&quot; #-} annotations). Be aware however, that profiling often rules<br>
out optimisations and thus changes the run-time behaviour of your code.<br>
<br>
&gt;<br>
&gt; thanks<br>
<br>
</blockquote></div>thanks a bunch. Im gonna make those changes here now :). Might take me a while though cause my haskell code writing speed is still a bit slow =p.<br>