{"id":555,"date":"2008-10-31T17:12:49","date_gmt":"2008-10-31T16:12:49","guid":{"rendered":"http:\/\/www.navision-blog.de\/2008\/10\/31\/damerau-levenshtein-distance-in-f\/"},"modified":"2008-11-01T14:41:35","modified_gmt":"2008-11-01T13:41:35","slug":"damerau-levenshtein-distance-in-fsharp-part-i","status":"publish","type":"post","link":"http:\/\/www.navision-blog.de\/blog\/2008\/10\/31\/damerau-levenshtein-distance-in-fsharp-part-i\/","title":{"rendered":"Damerau-Levenshtein-Distance in F# &#8211; part I"},"content":{"rendered":"<p>Today I am publishing an algorithm for calculating the <a href=\"http:\/\/en.wikipedia.org\/wiki\/Damerau-Levenshtein_distance\">Damerau-Levenshtein distance<\/a> in F#. The <a href=\"http:\/\/en.wikipedia.org\/wiki\/Levenshtein_distance\">Levenshtein distance<\/a> is a metric that allows to measure the amount of difference between two sequences and shows how many edit operations (insert, delete, substitution) are needed to transform one sequence into the other. The <a href=\"http:\/\/en.wikipedia.org\/wiki\/Damerau-Levenshtein_distance\">Damerau-Levenshtein distance<\/a> allows the <a href=\"http:\/\/en.wikipedia.org\/wiki\/Transposition\">transposition<\/a> of two characters as an operation. It is often used for spelling corrections or to measure the variation (&#8220;edit distance&#8221;) between DNA sequences.<\/p>\n<div style=\"font-size: 10pt; background: white; color: black; font-family: courier new\">\n<pre style=\"margin: 0px\"><span style=\"color: blue\">let<\/span> damerauLevenshtein(a:'a array) (b:'a array) =&#160;&#160;&#160;&#160;&#160;&#160; <\/pre>\n<pre style=\"margin: 0px\">&#160; <span style=\"color: blue\">let<\/span> init i j =<\/pre>\n<pre style=\"margin: 0px\">&#160;&#160;&#160; <span style=\"color: blue\">if<\/span> j = 0 <span style=\"color: blue\">then<\/span> i<\/pre>\n<pre style=\"margin: 0px\">&#160;&#160;&#160; <span style=\"color: blue\">elif<\/span> i = 0 <span style=\"color: blue\">then<\/span> j <span style=\"color: blue\">else<\/span> 0<\/pre>\n<pre style=\"margin: 0px\">&#160; <span style=\"color: blue\">let<\/span> n = a.Length + 1<\/pre>\n<pre style=\"margin: 0px\">&#160; <span style=\"color: blue\">let<\/span> m = b.Length + 1<\/pre>\n<pre style=\"margin: 0px\">&#160;<\/pre>\n<pre style=\"margin: 0px\">&#160; <span style=\"color: blue\">let<\/span> d = Array2.init n m init<\/pre>\n<pre style=\"margin: 0px\">&#160;<\/pre>\n<pre style=\"margin: 0px\">&#160; <span style=\"color: blue\">for<\/span> i <span style=\"color: blue\">in<\/span> [1..a.Length] <span style=\"color: blue\">do<\/span><\/pre>\n<pre style=\"margin: 0px\">&#160;&#160;&#160; <span style=\"color: blue\">for<\/span> j <span style=\"color: blue\">in<\/span> [1..b.Length] <span style=\"color: blue\">do<\/span>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; <\/pre>\n<pre style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">let<\/span> cost = <\/pre>\n<pre style=\"margin: 0px\">        <span style=\"color: blue\">if<\/span> a.[i-1] = b.[j-1] <span style=\"color: blue\">then<\/span> 0 <span style=\"color: blue\">else<\/span> 1<\/pre>\n<pre style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">let<\/span> deletion = d.[i-1, j] + 1<\/pre>\n<pre style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">let<\/span> insertion = d.[i,j-1] + 1<\/pre>\n<pre style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">let<\/span> substitution = d.[i-1,j-1] + cost<\/pre>\n<pre style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; d.[i, j] &lt;- <\/pre>\n<pre style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; deletion <\/pre>\n<pre style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; |&gt; min insertion <\/pre>\n<pre style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; |&gt; min substitution<\/pre>\n<pre style=\"margin: 0px\">&#160;<\/pre>\n<pre style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">if<\/span> i &gt; 1 &amp;&amp; j &gt; 1 &amp;&amp; a.[i-1] = b.[j-2] &amp;&amp; <\/pre>\n<pre style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; a.[i-2] = b.[j-1] <span style=\"color: blue\">then<\/span><\/pre>\n<pre style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; <span style=\"color: blue\">let<\/span> transposition = d.[i-2,j-2] + cost&#160; <\/pre>\n<pre style=\"margin: 0px\">&#160;&#160;&#160;&#160;&#160;&#160;&#160; d.[i, j] &lt;- min d.[i,j] transposition&#160; <\/pre>\n<pre style=\"margin: 0px\">&#160;<\/pre>\n<pre style=\"margin: 0px\">&#160; d.[a.Length, b.Length]&#160; <\/pre>\n<\/div>\n<p>This na&#239;ve implementation needs quadratic space (<em>O(m*n)<\/em>). Since the algorithm is used to calculate the edit distance of large DNA sequences this is extremly bad. <a href=\"http:\/\/www.navision-blog.de\/2008\/11\/01\/damerau-levenshtein-distance-in-fsharp-part-ii\/\">Next time<\/a> I will show how we can get linear space (<em>O(m+n)<\/em>) for the algorithm.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Today I am publishing an algorithm for calculating the Damerau-Levenshtein distance in F#. The Levenshtein distance is a metric that allows to measure the amount of difference between two sequences and shows how many edit operations (insert, delete, substitution) are needed to transform one sequence into the other. The Damerau-Levenshtein distance allows the transposition of [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[9,448,8],"tags":[53,465,86,469,468,664,467,466],"_links":{"self":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts\/555"}],"collection":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/comments?post=555"}],"version-history":[{"count":17,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts\/555\/revisions"}],"predecessor-version":[{"id":573,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/posts\/555\/revisions\/573"}],"wp:attachment":[{"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/media?parent=555"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/categories?post=555"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.navision-blog.de\/blog\/wp-json\/wp\/v2\/tags?post=555"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}