<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-6594352044318880508</id><updated>2011-07-08T04:29:16.261-07:00</updated><category term='ruby'/><category term='linux'/><category term='ai'/><category term='logic'/><category term='web'/><category term='php'/><category term='ajax'/><category term='apple'/><category term='human  computation'/><category term='latex'/><category term='scifi'/><category term='nagios'/><category term='games'/><category term='language'/><category term='algorithm'/><category term='conference'/><category term='human computation'/><category term='prolog'/><category term='test'/><category term='nlp'/><category term='constraints'/><category term='filesystem'/><category term='oo'/><category term='clp'/><category term='functional'/><category term='jaoo'/><category term='greenpeace'/><category term='sleipner'/><title type='text'>Inferencing</title><subtitle type='html'>Some of my thoughts on programming, artificial intelligence and language</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>28</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-5987582618983217772</id><published>2009-08-24T09:01:00.000-07:00</published><updated>2009-08-24T09:09:42.700-07:00</updated><title type='text'>Nothing to see here, move along</title><content type='html'>I am not using this blog anymore.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-5987582618983217772?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/5987582618983217772/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=5987582618983217772' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/5987582618983217772'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/5987582618983217772'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2009/08/nothing-to-see-here-move-along.html' title='Nothing to see here, move along'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-398806889138467264</id><published>2008-09-30T03:50:00.000-07:00</published><updated>2008-09-30T04:06:37.036-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='functional'/><category scheme='http://www.blogger.com/atom/ns#' term='oo'/><category scheme='http://www.blogger.com/atom/ns#' term='jaoo'/><title type='text'>JAOO, day one</title><content type='html'>I am currently at the JAOO conference :-)&lt;br /&gt;&lt;br /&gt;The conference seems to be buzzing with functional programming today. It started with the keynote by Anders Hejlsberg, where he talked about the future of programming languages, of which he claimed that one of the key components was  functional programming. Concurrency was also mentioned as a key component. The talk also mentioned DSL's and used LINQ as example. It does seem nice - almost makes me want to play with C#. The F# language from Microsoft also seems like a nice alternative to C# if you wish the utilize the dot.net runtime. Very CAML/ML like. &lt;br /&gt;&lt;br /&gt;A few other talks of the day made a great impression on me. I didn't see that many presentation, because I'm was working as crew most of the day.&lt;br /&gt;&lt;br /&gt;I originally planned to go to the Aslaks rspec talk (I missed it a Rubyfools) but it was cancelled and replaced with a talk about meta-programming, and while it's an interesting topic, I've seen my share of those talks. Instead I decided to go the Fortress talk by Guy Steele - and it blew my mind! Fortress seems like a really interesting concurrent programming language. I will have to play around with this. &lt;br /&gt;&lt;br /&gt;After the fortress talk I went to a talk about Scala, by Bill Venners. Scala is a functional language which runs on the JVM an integrates with java libraries. The talk it self was more of an introduction to functional programming for Java programmers and it didn't really mention any of the really interesting features Scala.&lt;br /&gt;&lt;br /&gt;The final talk I went to was "Why Functional Programming (Still) Matters" by Erik Meijer. This was mindblowing. He talked about dealing with the "impurity" of languages introduced by side-effects by using monads. The idea of embracing side-effects - in the right way - rather than than shunning them was eye opening.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-398806889138467264?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/398806889138467264/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=398806889138467264' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/398806889138467264'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/398806889138467264'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2008/09/jaoo-day-one.html' title='JAOO, day one'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-9055940563352441841</id><published>2008-08-31T11:06:00.000-07:00</published><updated>2008-08-31T11:27:47.068-07:00</updated><title type='text'>Extracting facebook friends from public profiles</title><content type='html'>Today I just discovered a small little disclosure issue with facebook and google. Actually, the discovery was due to my girlfriend.&lt;br /&gt;&lt;br /&gt;When you enter a public facebook profile for a person, it will display five friends of that person. Since everybody who is friends with this person also have a public profile, which also lists five friends, there is a reasonable chance that the person turns up in their profile. &lt;br /&gt;&lt;br /&gt;Google indexes these pages, so it is possible to search these public profiles. By searching for the a particular name on facebook using google, it is possible to find a lot more friends of the person. For instance, the query &lt;br /&gt;&lt;a href="http://www.google.com/search?q=%22Christian+Theil+Have%22+site:facebook.com&amp;hl=en&amp;safe=off&amp;filter=0"&gt;&lt;br /&gt;http://www.google.com/search?q=%22Christian+Theil+Have%22+site:facebook.com&amp;hl=en&amp;safe=off&amp;filter=0&lt;/a&gt;&lt;br /&gt;will list a few of my facebook friends.&lt;br /&gt;&lt;br /&gt;I imagine that it is possible to extract quite a big portion of the facebook social network using this method.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-9055940563352441841?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/9055940563352441841/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=9055940563352441841' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/9055940563352441841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/9055940563352441841'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2008/08/extracting-facebook-friends-from-public.html' title='Extracting facebook friends from public profiles'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-3698774310078734118</id><published>2008-04-23T05:34:00.000-07:00</published><updated>2008-04-23T06:53:18.004-07:00</updated><title type='text'>NLP keyword on google</title><content type='html'>Searching on "NLP" on google seems to bring up pages and pages of stuff on neuro-linguistic programming (psychology stuff) rather than on natural language processing. &lt;br /&gt;&lt;br /&gt;In a recent &lt;a href="http://groups.google.com/group/comp.ai.nat-lang/browse_thread/thread/2aa6b9c66288c25f"&gt;post&lt;/a&gt; to comp.ai.nat-lang Amnon urges NLP people "not cede the NLP keyword without a fight". I agree with him, that this is an issue. But I am not sure how to deal with it. Even though, I believe that the abbreviation "NLP" meaning natural language processing is more scientific and probably precedes the neuro-linguistic programming use of the abbreviation (I have no definite source for this), both uses of abbreviation is equally legitimate. However, there is a big overlap in terminology used eg. linguistics, language etc.&lt;br /&gt;&lt;br /&gt;However, it's annoying for me to have a million pages neuro-lingustic programming pages pop when I search for NLP, because I am a million times more interested in natural language processing. But google neglects this fact, although this knowledge should be derivable from my previous searches. Oppositely, it's not transparent what kind of result a given query should give me. Pagerank results in an approximation  which can be compared with the lowest common denominator of query results. With gradual improvement of my query I usually find what I am looking  for though, but this is besides the point. &lt;br /&gt;&lt;br /&gt;I think there is still room for other search engines out there. I could definitely use a search engine which gave me predictable result. And a search engine that took a lot more context into consideration. But google domination (and superiority in terms on amount of indexed pages) is quite a barrier. But I think it's slowly going to happen, as the quality of googles search results deteriorates because of the exceeding amount of information. One algorithm doesn't fit all.&lt;br /&gt;&lt;br /&gt;A scary side-effect is that because of googles domination, I think googles indexing mechanisms might have some serious impacts on the development of language and ultimately &lt;a href="http://en.wikipedia.org/wiki/Sapir-Whorf_hypothesis"&gt;the way we think&lt;/a&gt;. If a search term is drowned by a more popular search term, the less popular might slowly be forgotten or loose it's place in common speak. To add to seriousness of this, it's possible to affect this by means of &lt;a href"http://en.wikipedia.org/wiki/Google_bomb"&gt;google bombing&lt;/a&gt; or similar techniques. That is what SEO is mostly about.&lt;br /&gt;&lt;br /&gt;Until we get better search engines, I guess I might as well throw in a link to the wikipedia definition of &lt;a href="http://en.wikipedia.org/wiki/Natural_language_processing"&gt;NLP&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Natural language processing: one, Neuro-lingustic programming: zero ;-)&lt;br /&gt;&lt;!--&lt;br /&gt;It's rather ironic that many succesful NLP exploits exactly the popularity of words in a similar way to google and that an interpreter of this sentence would probably prefer the neuro-linguistic sense of NLP in this sentence. I admit that the sentence is a bit construed. For instance, I might as well have used the word parser instead of interpreter. But whatever. You get the idea.&lt;br /&gt;--&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-3698774310078734118?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/3698774310078734118/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=3698774310078734118' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/3698774310078734118'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/3698774310078734118'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2008/04/nlp-keyword-on-google.html' title='NLP keyword on google'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-1082011197685233459</id><published>2008-03-05T14:45:00.000-08:00</published><updated>2008-03-05T15:27:33.374-08:00</updated><title type='text'>Better Approximate Ruby Programming</title><content type='html'>Griff just sent me a nicer version of the &lt;a href="http://inferencing.blogspot.com/2008/03/approximate-ruby-programming.html"&gt;approximatize&lt;/a&gt; function, which dynamically defines a module. It's a really cool hack: Now approximatize works for classes, modules and objects alike!&lt;br /&gt;&lt;br /&gt;If the target of the function turns out to be an other module, it will include the new module in it and it's &lt;span style="font-weight: bold;"&gt;included&lt;/span&gt; method will do the aliasing magic. Should the target be a class or an object, it will extend it and is able to re-alias the method_missing method directly. Nice.&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;br /&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;approximatize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;target&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;max_edit_distance&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;m&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Module&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;self.included&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;other&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;other&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;send&lt;/span&gt; &lt;span class="symbol"&gt;:alias_method&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:method_missing_without_approximate&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:method_missing&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;other&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;send&lt;/span&gt; &lt;span class="symbol"&gt;:alias_method&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:method_missing&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="symbol"&gt;:method_missing_with_approximate&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;      &lt;br /&gt;    &lt;span class="ident"&gt;define_method&lt;/span&gt; &lt;span class="symbol"&gt;:method_missing_with_approximate&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;meth&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;shift&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;similar_methods&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;methods&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;       &lt;span class="ident"&gt;dist&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;edit_distance&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;meth&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;dist&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="ident"&gt;max_edit_distance&lt;/span&gt; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;br /&gt;         &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;similar_methods&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;dist&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;nil?&lt;/span&gt; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;br /&gt;            &lt;span class="ident"&gt;similar_methods&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;dist&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt; &lt;span class="punct"&gt;]&lt;/span&gt;&lt;br /&gt;         &lt;span class="keyword"&gt;else&lt;/span&gt;&lt;br /&gt;           &lt;span class="ident"&gt;similar_methods&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;dist&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;&lt;br /&gt;          &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class="comment"&gt;# Eliminate candidates with higher edit distances than the candidates with the lowest&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;similar_methods&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;similar_methods&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;min&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;pop&lt;/span&gt; &lt;span class="keyword"&gt;unless&lt;/span&gt; &lt;span class="ident"&gt;similar_methods&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;min&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;nil?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      &lt;span class="comment"&gt;# Call method only if there is _exactly_ one element with the minimum edit distance&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;similar_methods&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;nil?&lt;/span&gt; &lt;span class="keyword"&gt;or&lt;/span&gt; &lt;span class="ident"&gt;similar_methods&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;size&lt;/span&gt; &lt;span class="punct"&gt;!=&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;br /&gt;        &lt;span class="ident"&gt;method_missing_without_approximate&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;meth&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;else&lt;/span&gt;&lt;br /&gt;        &lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;send&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;similar_methods&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;&lt;span class="punct"&gt;,*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;target&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;kind_of?&lt;/span&gt; &lt;span class="constant"&gt;Module&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;target&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;send&lt;/span&gt; &lt;span class="symbol"&gt;:include&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;else&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;target&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;extend&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;target&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;instance_eval&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;alias&lt;/span&gt; &lt;span class="symbol"&gt;:method_missing_without_approximate&lt;/span&gt; &lt;span class="symbol"&gt;:method_missing&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;alias&lt;/span&gt; &lt;span class="symbol"&gt;:method_missing&lt;/span&gt; &lt;span class="symbol"&gt;:method_missing_with_approximate&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Thanks :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-1082011197685233459?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/1082011197685233459/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=1082011197685233459' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/1082011197685233459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/1082011197685233459'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2008/03/better-approximate-ruby-programming.html' title='Better Approximate Ruby Programming'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-3395176133349343557</id><published>2008-03-04T04:28:00.000-08:00</published><updated>2008-03-05T04:34:33.453-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>Approximate Ruby Programming</title><content type='html'>&lt;span style="font-style: italic; font-weight: bold;"&gt;What if &lt;/span&gt; your programming language interpreter didn't mind small spelling mistakes. Imagine that you type a method name a wee bit wrong, but the the interpreter seems to read your mind and call the correct method instead of throwing an NoMethodFound exception at you.&lt;br /&gt;&lt;br /&gt;I've been playing a bit with this idea and found a simple but naive way this in Ruby. If you try to call a method that doesn't exist, then the &lt;span style="font-weight: bold;"&gt;method_missing&lt;/span&gt; method gets called. If this method_missing in turn figured out what method you really meant to call and called that instead, you where in the clear? Of course, programs  can't read your mind, but a simple  way of approximate this is to find the existing method with the shortest edit distance to the misspelled method and call that instead. This is pretty naive, but it will work in many cases and serve as a simple baseline. And it has a very straight-forward implementation in Ruby. Say hello to ... drumroll, please ... &lt;span style="font-weight: bold;"&gt;approximatize!&lt;/span&gt;.&lt;br /&gt;&lt;pre class="code"&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Example&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;  def &lt;/span&gt;&lt;span class="method"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;str&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;    puts&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;test method called: &lt;span class="expr"&gt;#{str}&lt;/span&gt;&lt;span class="escape"&gt;\n&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;  end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;approximatize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;Example&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;ex&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Example&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;ex&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;test&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;a normal method call&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;ex&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;text&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;Did you mean test?&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;ex&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;tes&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;Did you mean test? (then you forgot a letter)&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;ex&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;ttest&lt;/span&gt; &lt;span class="punct"&gt;"&lt;/span&gt;&lt;span class="string"&gt;Did you mean test? (then wrote a letter to much)&lt;/span&gt;&lt;span class="punct"&gt;"&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;ex&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;and_now_for_something_completely_different&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This example illustrates a simple use of approximatize. In both all cases, but the last, the &lt;span style="font-weight: bold;"&gt;test&lt;/span&gt; method gets called even though the method name was misspelled. However, the are no methods whose spelling resembles the last call, and thus a NoMethodError is thrown. It's possible to adjust how much error to allow, but it's recommended to keep the max_edit_distance low.&lt;br /&gt;&lt;br /&gt;The implementation of approximatize:&lt;br /&gt;&lt;pre class="code"&gt;&lt;br /&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;approximatize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;target&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;max_edit_distance&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;  target&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;target&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;unless&lt;/span&gt; &lt;span class="ident"&gt;target&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;==&lt;/span&gt; &lt;span class="ident"&gt;Class&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;  target&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;class_eval&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;    define_method&lt;/span&gt; &lt;span class="symbol"&gt;:method_missing&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;      meth&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;shift&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;      similar_methods&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="constant"&gt;      self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;methods&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;       &lt;span class="ident"&gt;dist&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;edit_distance&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;meth&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;        if&lt;/span&gt; &lt;span class="ident"&gt;dist&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="ident"&gt;max_edit_distance&lt;/span&gt; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;br /&gt;         &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;similar_methods&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;dist&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;nil?&lt;/span&gt; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;            similar_methods&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;dist&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt; &lt;span class="punct"&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;         else&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;         similar_methods&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;dist&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;          end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;        end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;      end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;      # Eliminate candidates with higher edit distances than the candidates with the lowest&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;      similar_methods&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;similar_methods&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;min&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;pop&lt;/span&gt; &lt;span class="keyword"&gt;unless&lt;/span&gt; &lt;span class="ident"&gt;similar_methods&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;min&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;nil?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;      # Call method only if there is _exactly_ one element with the minimum edit distance&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;      if&lt;/span&gt; &lt;span class="ident"&gt;similar_methods&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;nil?&lt;/span&gt; &lt;span class="keyword"&gt;or&lt;/span&gt; &lt;span class="ident"&gt;similar_methods&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;size&lt;/span&gt; &lt;span class="punct"&gt;!=&lt;/span&gt; &lt;span class="number"&gt;1&lt;/span&gt; &lt;span class="keyword"&gt;then&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;        raise&lt;/span&gt; &lt;span class="constant"&gt;NoMethodError&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;("&lt;/span&gt;&lt;span class="string"&gt;undefined method ‘&lt;span class="expr"&gt;#{meth.to_s}&lt;/span&gt;’ for &lt;span class="expr"&gt;#{self}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;",&lt;/span&gt;&lt;span class="ident"&gt;meth&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;      else&lt;/span&gt;&lt;br /&gt;&lt;span class="constant"&gt;        self&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;__send__&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;similar_methods&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;&lt;span class="punct"&gt;,*&lt;/span&gt;&lt;span class="ident"&gt;args&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;      end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;    end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;  end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Approximatize  defines an method_missing method on the target class. When invoked this method runs through all the methods of the target class and calculates the edit distance of the method. It then selects the method with the lowest edit distance and invokes it (assuming there is only one with such a low edit distance and the this edit distance is lower than the allowed threshold). If no such method can be found, it will throw a NoSuchMethod exception, as would normally have happened when you call a non-existing method.&lt;br /&gt;&lt;br /&gt;The dynamic programming version of the edit distance algorithm is implemented directly on the String class. The running time is O(m*n) so it's feasible (polynomial) even though it is executed for each method in the target class. In practice, this doesn't seem to be a problem, since method names tend to be rather short. However, it would probably be a good idea to cache the result of the calculations, instead doing them each time a non-existing method gets called.&lt;br /&gt;&lt;pre class="code"&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;String&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;  def &lt;/span&gt;&lt;span class="method"&gt;edit_distance&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;other&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;    m&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;    # create base case entries:&lt;/span&gt;&lt;br /&gt;&lt;span class="number"&gt;    0&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;upto&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;size&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[];&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;][&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;i&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span class="number"&gt;    0&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;upto&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;other&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;size&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;j&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;][&lt;/span&gt;&lt;span class="ident"&gt;j&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;j&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;    # Fill out the rest of the matrix&lt;/span&gt;&lt;br /&gt;&lt;span class="number"&gt;    1&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;upto&lt;/span&gt; &lt;span class="ident"&gt;size&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;&lt;span class="number"&gt;      1&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;upto&lt;/span&gt; &lt;span class="ident"&gt;other&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;size&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;j&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;        etj&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;self&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="ident"&gt;other&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;j&lt;/span&gt;&lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;])&lt;/span&gt;&lt;span class="char"&gt;?0&lt;/span&gt;&lt;span class="punct"&gt;:&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;        m&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;][&lt;/span&gt;&lt;span class="ident"&gt;j&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;][&lt;/span&gt;&lt;span class="ident"&gt;j&lt;/span&gt;&lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;etj&lt;/span&gt; &lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;][&lt;/span&gt;&lt;span class="ident"&gt;j&lt;/span&gt;&lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;]+&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;-&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;][&lt;/span&gt;&lt;span class="ident"&gt;j&lt;/span&gt;&lt;span class="punct"&gt;]+&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt; &lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;min&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;      end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;    end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;    m&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;size&lt;/span&gt;&lt;span class="punct"&gt;][&lt;/span&gt;&lt;span class="ident"&gt;other&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;size&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;  end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;If you're the type who likes to live life dangerously and are not afraid to break things, why not &lt;span style="font-weight: bold;"&gt;approximatize&lt;/span&gt; your entire Ruby environment?&lt;br /&gt;&lt;span&gt;&lt;pre class="code"&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;approximatize_world&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;max_edit_distance&lt;/span&gt;&lt;span class="punct"&gt;=&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="constant"&gt;  ObjectSpace&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each_object&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="constant"&gt;Class&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;clazz&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;    approximatize_class&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;clazz&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="ident"&gt;max_edit_distance&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;  end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;/span&gt; &lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;But there are some obvious problems with the concept and the approach:&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span&gt;Expect the unexpected: Sometimes the wrong method gets called. One obviously dangerous case springs to mind: The way Ruby has destructive methods ending with an exclamation mark; an edit distance of one from the original name. As such, edit distance is not very clever, and it's really sensitive when it comes to short  method names. It should be possible to come up with something better, but until then, edit distance serves as reasonable baseline approximation.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span&gt;It's possible to get a list of defined methods of a class, but these doesn't include aliases for methods or methods implemented using method_missing. Actually, using &lt;span&gt;approximatize&lt;/span&gt; on a class might break it's functionality if it depends on method_missing. This can probably be fixed with some clever aliasing though. However, using method_missing like this is asking for trouble.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;&lt;span&gt;Of course, the approach only handles method names. Syntax errors still cause the interpreter to complain like a "strict old aunt", even though it was perfectly clear what I meant ;-) I would be nice with approximate syntax, but that would require a different kind of Ruby parser&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span&gt;Ahh well,  so it isn't very useful in practice, but the idea seems worthwhile, doesn't it? &lt;/span&gt;&lt;span&gt;Even if it isn't very useful it is a working prototype illustrating an interesting concept (imho).&lt;/span&gt;&lt;span&gt;  And more importantly it&lt;/span&gt;&lt;span&gt; provided me with a couple of hours of fun :-)&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-3395176133349343557?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/3395176133349343557/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=3395176133349343557' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/3395176133349343557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/3395176133349343557'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2008/03/approximate-ruby-programming.html' title='Approximate Ruby Programming'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-7942096956998316756</id><published>2007-11-01T01:01:00.000-07:00</published><updated>2007-11-01T03:39:07.343-07:00</updated><title type='text'>php has problems</title><content type='html'>Arrggh! I'm coding stuff in PHP again at work. I've done a lot PHP in past times, and even though the language has improved it's still such a exemplary piece of crap. Language design at it's worst. PHP is supposed to be a recursive acronym of: PHP: Hypertext Processor, however, these acronyms seems to describe the language equally well:&lt;br /&gt;&lt;br /&gt;PHP Has Problems&lt;br /&gt;Pretty Half-baked Programming-language&lt;br /&gt;PHP Hates Programmmers (and also the other way around for many...)&lt;br /&gt;&lt;br /&gt;Feel free to add to list..&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I just needed to get my frustrations out...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-7942096956998316756?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/7942096956998316756/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=7942096956998316756' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/7942096956998316756'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/7942096956998316756'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/11/php-has-problems.html' title='php has problems'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-5698620630576020594</id><published>2007-09-30T11:42:00.000-07:00</published><updated>2007-09-30T12:19:01.649-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><category scheme='http://www.blogger.com/atom/ns#' term='nlp'/><title type='text'>RANLP conference</title><content type='html'>This week I attended the &lt;a href="http://lml.bas.bg/ranlp2007/"&gt;RANLP conference&lt;/a&gt; (Recent Advances in Natural Language Processing) in Bulgaria and it has been an amazing experience. There were many really good and interesting presentations. It seems that NLP is maturing in many respects. A mindblowing conference :-)&lt;br /&gt;&lt;br /&gt;By the way, many of the papers from the workshops are available online on the workshop homepages.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I presented a poster, &lt;br /&gt;&lt;a href="http://farm2.static.flickr.com/1331/1463691373_7a63ffb209_b.jpg"&gt;From Use Cases to UML Class Diagrams using Logic Grammars and Constraints&lt;/a&gt;, with Henning Christiansen and we got some good feedback.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/60429593@N00/1463691373/" title="Photo Sharing"&gt;&lt;img src="http://farm2.static.flickr.com/1331/1463691373_7a63ffb209_m.jpg" width="170" height="240" alt="RANLP poster: From Use Cases to UML Class Diagrams using Logic Grammars and Constraints" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-5698620630576020594?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/5698620630576020594/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=5698620630576020594' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/5698620630576020594'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/5698620630576020594'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/09/ranlp.html' title='RANLP conference'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm2.static.flickr.com/1331/1463691373_7a63ffb209_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-5910102855318713924</id><published>2007-08-22T13:25:00.000-07:00</published><updated>2007-09-30T12:06:20.844-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conference'/><title type='text'>At the Context conference</title><content type='html'>I am currently attending the &lt;a href="http://context-07.ruc.dk/"&gt;Context conference&lt;/a&gt;. The last previous two days there has been workshops and today the conference officially started.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The first day, &lt;/b&gt; I went to the &lt;a href="http://control.ruc.dk/CSLP2007.html"&gt;CSLP workshop&lt;/a&gt;. I presented the paper, &lt;i&gt;Reasoning about Use Cases using Logic Grammars and Constraints&lt;/i&gt; which I have coauthored with Henning Christiansen and Knut Tveitane. It was the first presentation of the day and my first paper presentation at a conference. Quite the experience trying.There were many interesting presentations at the workshop some of which I found particularly inspiring and thought provoking.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The second day&lt;/b&gt; I attended some talks from the MRC&amp;amp;CHUT-07 workshop as well as a few from the CIR workshop. Both contained some fairly interesting talks.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The third day&lt;/b&gt; started with very interesting talk given by &lt;a href="http://cogsci.ucsd.edu/%7Ekirsh/"&gt;David Kirsh&lt;/a&gt; &lt;i&gt;On being situated&lt;/i&gt;. There were several other exciting papers presented during the day as well as a poster&lt;br /&gt;session in the afternoon.&lt;br /&gt;&lt;br /&gt;The invited talk by Peter Gärdenfors on "Concepts, cognition and context" was also a really exciting talk. He talked about some the concepts from his book "The geometry of thought". Really interesting stuff.&lt;br /&gt;&lt;br /&gt;Definitely a nice conference. There were many definitions of context and some splitting hairs over what context really is. There doesn't seem to be a consensus about this. However, there many good talks on various topics related to context such as the semantic web, ontologies, linguistics, cognition and other areas. Many of the talks were really interesting and it's nice to get some different perspectives.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-5910102855318713924?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/5910102855318713924/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=5910102855318713924' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/5910102855318713924'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/5910102855318713924'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/08/at-context-conference.html' title='At the Context conference'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-7081748313138787430</id><published>2007-08-06T23:54:00.000-07:00</published><updated>2007-08-07T00:20:13.801-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='human computation'/><title type='text'>Artificial artificial intelligence</title><content type='html'>To follow up on &lt;a href="http://inferencing.blogspot.com/2007/06/human-computation.html"&gt;my post on human computation&lt;/a&gt;, I should mention Amazons new &lt;a href="http://www.mturk.com/"&gt;Mechanical Turk&lt;/a&gt;. It's a sort of a broker of human computation tasks (HIT's, in their terminology).&lt;br /&gt;&lt;br /&gt;The basic idea is that requesters define a HIT and people get paid to perform these task.&lt;br /&gt;&lt;br /&gt;I wondering what the prices of HIT's will be. The minimum commission charge is $0.005 per HIT, which isn't a lot. However, solving these tasks might appeal to people in countries where the average salary is very low. &lt;br /&gt;&lt;br /&gt;It's an interesting idea. I'm sure we will see some exciting applications of it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-7081748313138787430?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/7081748313138787430/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=7081748313138787430' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/7081748313138787430'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/7081748313138787430'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/08/artificial-artificial-intelligence.html' title='Artificial artificial intelligence'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-76183841512096676</id><published>2007-07-04T03:13:00.000-07:00</published><updated>2007-07-22T15:23:35.147-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ai'/><category scheme='http://www.blogger.com/atom/ns#' term='nlp'/><title type='text'>The Long Road from Text to Meaning</title><content type='html'>I stumbled upon this very interesting lecture with &lt;a href="http://www.kilgarriff.co.uk/"&gt;Adam Kilgarriff&lt;/a&gt; on google videos.&lt;br /&gt;&lt;h4&gt;Key points from the talk:&lt;/h4&gt;&lt;ul&gt;&lt;li&gt;Approaches to language study: Rationalist vs. Empiricist&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Lemmatizers and Part-of-speech tagging&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Word sense, use and meaning&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Word sketching and thesaurus creation from corpora is discussed along with important problems such as representation and ambiguity.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Using google as a NLP tool. Very interesting perspective!&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;embed style="width: 400px; height: 326px;" id="VideoPlayback" type="application/x-shockwave-flash" src="http://video.google.com/googleplayer.swf?docId=-1135583994187927846&amp;amp;hl=en" flashvars=""&gt;&lt;/embed&gt; &lt;i&gt;&lt;b&gt;Abstract: &lt;/b&gt;Computers have given us a new way of thinking about language. Given a large sample of  language, or corpus, and computational tools to process it, we can approach language as physicists approach forces and chemists approach chemicals. This approach is noteworthy for missing out what, from a language-user's point of view, is important about a piece of language: its meaning.&lt;br /&gt;&lt;br /&gt;I shall present this empiricist approach to the study of language and show how, as we develop accurate tools for lemmatisation, part-of-speech tagging and parsing, we move from the raw input -- a character stream -- to an analysis of that stream in increasingly rich terms: words, lemmas, grammatical structures, Fillmore-style frames. Each step on the journey builds on a large corpus accurately analysed at the previous levels. A distributional thesaurus provides generalisations about lexical behaviour which can then feed into an analysis at the ‘frames' level. The talk will be illustrated with work done within the ‘Sketch Engine' tool.&lt;br /&gt;&lt;br /&gt;For much NLP and linguistic theory, meaning is a given. Thus formal semantics assumes meanings for words, in order to address questions of how they combine, and WSD (word sense disambiguation) typically takes a set of meanings (as found in a dictionary) as a starting point and sets itself the challenge of identifying which meaning applies. But, since the birth of philosophy, meaning has been problematic. In our approach meaning is an eventual output of the research programme, not an input.&lt;/i&gt;&lt;br /&gt;&lt;h4&gt;Links&lt;/h4&gt;&lt;a href="www.http://www.kilgarriff.co.uk/.co.uk/"&gt;Adam Kilgarriff&lt;/a&gt; is a research scientist working at the intersection of computational linguistics, corpus linguistics, and dictionary-making. Following a PhD on "Polysemy" from Sussex University, he has worked at Longman Dictionaries, Oxford University Press, and the University of Brighton, and is now Director of two companies, Lexicography MasterClass (&lt;a href="http://www.lexmasterclass.com/"&gt;http://www.lexmasterclass.com&lt;/a&gt;) and Lexical Computing Ltd (&lt;a href="http://www.sketchengine.co.uk/"&gt;http://www.sketchengine.co.uk/&lt;/a&gt;) which provide software, training and consultancy in the research areas.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.sketchengine.co.uk/"&gt;Sketch Engine&lt;/a&gt; (SkE, also known as Word Sketch Engine) is a Corpus Query System incorporating word sketches, grammatical relations, and a distributional thesaurus. A word sketch is a one-page, automatic, corpus-derived summary of a word’s grammatical and collocational behaviour. You can try it using a free trial account.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://labs.google.com/sets"&gt;Google sets&lt;/a&gt; creates a list of similar items given a few items. For instance, the set {apple,banana,strawberry} will result in a larger set with different fruits.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-76183841512096676?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/76183841512096676/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=76183841512096676' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/76183841512096676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/76183841512096676'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/07/long-road-from-text-to-meaning.html' title='The Long Road from Text to Meaning'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-3230976086856965667</id><published>2007-06-10T03:57:00.001-07:00</published><updated>2007-08-07T00:20:35.658-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ai'/><category scheme='http://www.blogger.com/atom/ns#' term='games'/><category scheme='http://www.blogger.com/atom/ns#' term='algorithm'/><category scheme='http://www.blogger.com/atom/ns#' term='human  computation'/><category scheme='http://www.blogger.com/atom/ns#' term='language'/><title type='text'>Human computation</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/Human-based_computation"&gt;Human computation&lt;/a&gt; is the concept of using humans to solve problems that computers suck at. This is the same sort of goal that artificial intelligence has; namely, solving problems that humans are good at but are difficult for computers.&lt;br /&gt;&lt;br /&gt;Human computation might well be the next big paradigm of Artificial Intelligence, even though this sounds like a paradox. Efficient machine learning algorithms usually require supervised training to learn how to solve a given problem, but training can be a daunting task. In unsupervised learning, some sort of fitness or reward function is required. Writing a good fitness function can be really complex. For instance, it would definitely not be trivial writing a fitness function which determines if a picture contains pornographic material. Humans, on the other hand, have little trouble doing this. &lt;a href="http://www.genarts.com/karl/"&gt;Karl Sims&lt;/a&gt; has suggested using humans as fitness functions in genetic algorithms, and applied the technique to evolving beautiful art.&lt;br /&gt;&lt;br /&gt;I think that the potential effect of Human Computation in an AI context can be compared to the effect that web 2.0 has had on content on the web. &lt;br /&gt;&lt;br /&gt;The difficult part is motivating people to collaborate in the training process.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Money for nothing and cycles for free&lt;/h4&gt;Human cycles are usually more expensive than computer cycles. That is, unless you get them for free. &lt;a href="http://www.cs.cmu.edu/%7Ebiglou/"&gt;Luis von Ahn&lt;/a&gt; has found a clever way to get those cycles for free: By designing computer games where the players sort a specific kind of problems. The first batch of games he has designed deals with image classification. For instance the &lt;a href="http://www.espgame.org/"&gt;ESP Game&lt;/a&gt; is two player game where both players have to agree on a word for an image. The result is a set of classifications tags for the image.&lt;br /&gt;&lt;br /&gt;The other games are &lt;a href="http://www.peekaboom.org/"&gt;Peekaboom&lt;/a&gt; and &lt;a href="http://www.peekaboom.org/phetch/"&gt;Phetch&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;embed style="width: 400px; height: 326px;" id="VideoPlayback" type="application/x-shockwave-flash" src="http://video.google.com/googleplayer.swf?docId=-8246463980976635143&amp;hl=en" flashvars="&amp;amp;subtitle=on"&gt;&lt;/embed&gt;&lt;br /&gt;&lt;br /&gt;&lt;font style="font-style: italic;"&gt;In this video Luis von Ahn explains the concept and gives some examples of "human computation" games he has designed.&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I am especially excited about a not-yet-released game, Verbosity, which deals with the problem of creating a large corpus of common-sense knowledge. The MIT project &lt;a href="http://web.media.mit.edu/%7Ehugo/conceptnet/"&gt; ConceptNet&lt;/a&gt; has attempted to do this using web-collaboration. It's currently the best corpus around, but there is certainly room for improvement. Entering common-sense knowledge seems really boring, but this game might actually make the process fun enough to get people to collaborate.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-3230976086856965667?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/3230976086856965667/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=3230976086856965667' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/3230976086856965667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/3230976086856965667'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/06/human-computation.html' title='Human computation'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-7605247151200468842</id><published>2007-06-08T05:20:00.000-07:00</published><updated>2007-06-09T02:25:38.453-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='clp'/><category scheme='http://www.blogger.com/atom/ns#' term='constraints'/><title type='text'>Article about McCarthy's Ambiguous Operator in Ruby</title><content type='html'>I just discovered an &lt;a href="http://www.randomhacks.net/articles/2005/10/11/amb-operator"&gt;article&lt;/a&gt; about an implementation of McCarthy's amb operator in Ruby, written by Erid Kidd. What a gem, it's a beautiful construction. &lt;br /&gt;&lt;br /&gt;It uses continuations to implement backtracking and provides a straight-forward way of representing constraint satisfaction problems in Ruby. &lt;br /&gt;&lt;br /&gt;Find the details, implementation and article here: &lt;a href="http://www.randomhacks.net/articles/2005/10/11/amb-operator"&gt;www.randomhacks.net&lt;/a&gt;.  &lt;br /&gt;It's also the subject of &lt;a href="http://www.rubyquiz.com/quiz70.html"&gt;a Ruby Quiz&lt;/a&gt;. &lt;a href="http://docs.mandragor.org/files/Programming_languages/Scheme/Teach_Yourself_Scheme_in_Fixnum_Days_en/tysch016.htm"&gt;Here &lt;/a&gt; is an other implementation in scheme with a detailed description.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-7605247151200468842?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/7605247151200468842/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=7605247151200468842' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/7605247151200468842'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/7605247151200468842'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/06/i-just-discovered-this-implementation.html' title='Article about McCarthy&apos;s Ambiguous Operator in Ruby'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-1167311893152556374</id><published>2007-05-29T04:37:00.001-07:00</published><updated>2007-07-22T15:24:58.529-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='clp'/><category scheme='http://www.blogger.com/atom/ns#' term='prolog'/><category scheme='http://www.blogger.com/atom/ns#' term='constraints'/><category scheme='http://www.blogger.com/atom/ns#' term='logic'/><title type='text'>A short introduction to CHR</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_B2qRRhuJC7U/RlyXBqT6iVI/AAAAAAAAChA/R103NJz0T24/s1600-h/chr_large.gif"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 196px; height: 196px;" src="http://3.bp.blogspot.com/_B2qRRhuJC7U/RlyXBqT6iVI/AAAAAAAAChA/R103NJz0T24/s320/chr_large.gif" alt="" id="BLOGGER_PHOTO_ID_5070093335305816402" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.cs.kuleuven.ac.be/%7Edtai/projects/CHR/"&gt;Constraint Handling Rules (CHR)&lt;/a&gt; is a declarative language for solving constraint problems. It's mainly used in conjunction with Prolog, but implementations for Java and Haskell are also available. I am currently working on making a Ruby implementation (as a Ruby DSL of course).&lt;br /&gt;&lt;br /&gt;What is interesting about CHR is that it can be used to express constraint problems in a concise manner. It has successfully been applied to a wide range of constraint problems such as planning and &lt;a href="http://akira.ruc.dk/%7Ehenning/chrg/"&gt;language processing&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The language is quite simple. It consists of three kinds of rules that modify a constraint store (a database of constraints). All the rule definitions have a similar syntax:&lt;br /&gt;&lt;code&gt;rule :- head, operator, body.&lt;/code&gt;&lt;br /&gt;The head and the body is basically a list of constraints. A rule is used when the head of the rule is matched by existing constraints in the constraint store. The constraints specified in the body gets added to the constraint store.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Propagation rules&lt;/h4&gt;&lt;code&gt;c1, ..., c ==&gt; Guard | cn+1, ... , cm&lt;/code&gt;&lt;br /&gt;Propagation rules create new rules in the constraint store. Thee rules in the body (cn+1 .. cm) are added to the constraint store given that the guard is true. The rules from the head (c1 ... cn) remains in the constraint store.&lt;br /&gt;&lt;h4&gt;Simplification rules&lt;/h4&gt;&lt;code&gt;c1, ..., cn  &lt;=&gt; Guard | cn+1, ... , cm&lt;/code&gt;&lt;br /&gt;Simplification rules, has purpose of simplifying constraints in a particular way.&lt;br /&gt;Rules in head (c1 .. cn) are removed from constraint store and rules in the body (cn+1 ... cm) is added to the store, provided that the Guard is true.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Simpagation rules&lt;/h4&gt;&lt;code&gt;c1, ..., ci \ ci+1, ..., cn &lt;=&gt; Guard | cn+1, ..., cm &lt;/code&gt;&lt;br /&gt;Simpagation rules is a sort of combination of the two others. The head is separated by a backslash. The rules before the backslash (c1 .. ci) stays in constraint store, while the rules after (ci+1 .. cn) is removed. The rules in the body (cn+1 .. cm) is added, provided the guard is true.&lt;br /&gt;&lt;a href="http://www.cs.kuleuven.ac.be/%7Edtai/projects/CHR/"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-1167311893152556374?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/1167311893152556374/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=1167311893152556374' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/1167311893152556374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/1167311893152556374'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/05/short-introduction-to-chr.html' title='A short introduction to CHR'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_B2qRRhuJC7U/RlyXBqT6iVI/AAAAAAAAChA/R103NJz0T24/s72-c/chr_large.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-8292045334489389289</id><published>2007-05-13T13:20:00.000-07:00</published><updated>2007-05-13T13:45:04.797-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ai'/><category scheme='http://www.blogger.com/atom/ns#' term='scifi'/><title type='text'>Marvin Minsky interview</title><content type='html'>I just stumbled upon &lt;a href="http://discovermagazine.com/2007/jan/interview-minsky/"&gt;an interview&lt;/a&gt; with AI pioneer &lt;a href="http://web.media.mit.edu/~minsky/"&gt;Marvin Minsky&lt;/a&gt;. The interview is mostly about his new book &lt;a href="http://www.amazon.com/Emotion-Machine-Commonsense-Artificial-Intelligence/dp/0743276639"&gt;The emotion machine&lt;/a&gt;, &lt;i&gt;"a machine that can switch between all the different kinds of thinking"&lt;/i&gt;. I definitely want to read this book. &lt;br /&gt;&lt;br /&gt;It's clear that Marvin Minsky has some profoundly different views on what AI should be like. He complains that the field is focused on solving problems with brain models and statistic models, but hardly no-one is working on making systems that can reason by analogy, or in other terms, think like a human.&lt;br /&gt;&lt;br /&gt;He also talks about a bit about scifi, and if you are into that you will love this quote from the interview: &lt;i&gt;"General fiction is pretty much about ways that people get into problems and screw their lives up. Science fiction is about everything else."&lt;/i&gt; I really laughed when I read it (because there is so much truth to it).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-8292045334489389289?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/8292045334489389289/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=8292045334489389289' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/8292045334489389289'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/8292045334489389289'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/05/marvin-minsky-interview.html' title='Marvin Minsky interview'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-655214034240883790</id><published>2007-05-13T09:32:00.000-07:00</published><updated>2007-05-18T05:22:35.841-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='ai'/><category scheme='http://www.blogger.com/atom/ns#' term='nlp'/><title type='text'>Colorless green ideas sleep furiously: Fun with a Ruby ChomskyBot</title><content type='html'>I recently fell over the concept of a &lt;a href="http://en.wikipedia.org/wiki/Chomskybot"&gt;Chomsky bot&lt;/a&gt;. A funny little thing which generates random paragraphs of text from a set sentence building blocks. It combines four kinds of phrases (introduction phrases, subject phrases, verb phrases and object phrases) into a sentence. The sentences this simple construction can create are amazing. They are syntactically correct and &lt;i&gt;"hovers on the edge on understandability"&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;By the way, the title of this post "Colorless green ideas sleep furiously" is a syntactically correct but nonsensical sentence devised by &lt;a href="http://www.chomsky.info/"&gt;Noam Chomsky&lt;/a&gt;. Noam Chomsky pioneered the field of &lt;a href="http://en.wikipedia.org/wiki/Generative_grammar"&gt;generative grammars&lt;/a&gt;. The ChomskyBot implements a simple generative grammar.&lt;br /&gt;&lt;br /&gt;The sentences generated by the bot are similar to the language of Noam Chomsky's works, and I guess the pun is intended.&lt;br /&gt;&lt;br /&gt;Of course, I couldn't resist the temptation to write a Ruby version of the Chomsky bot:&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;ChomskyBot&lt;/span&gt; &lt;br /&gt;  &lt;span class="attribute"&gt;@@phrase_elems&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;intro&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;subject&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;verb&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;object&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;]&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;intro_file&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;subject_file&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;verb_file&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;object_file&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="attribute"&gt;@@phrase_elems&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;e&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;br /&gt;      &lt;span class="ident"&gt;instance_eval&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;@&lt;span class="expr"&gt;#{e}&lt;/span&gt;s = []&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt; &lt;br /&gt;      &lt;span class="ident"&gt;instance_eval&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;File.open(&lt;span class="expr"&gt;#{e}&lt;/span&gt;_file).each_line&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;br /&gt;                    &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;{ |l| @&lt;span class="expr"&gt;#{e}&lt;/span&gt;s.push l.chop }&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;generate_lines&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;n&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;lines&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;n&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;times&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt;      &lt;span class="attribute"&gt;@@phrase_elems&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;e&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;        &lt;span class="ident"&gt;eval&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;lines &amp;lt;&amp;lt; @&lt;span class="expr"&gt;#{e}&lt;/span&gt;s.slice!(rand(@&lt;span class="expr"&gt;#{e}&lt;/span&gt;s.size-1)) &amp;lt;&amp;lt; ' '&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;   &lt;span class="ident"&gt;lines&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;paragraph&lt;/span&gt; &lt;br /&gt;    &lt;span class="ident"&gt;generate_lines&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="number"&gt;5&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;join&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I tried to make it as simple as I could get away with. I shaved quite a few lines using eval, hope it doesn't hurt readability to much.&lt;br /&gt;&lt;br /&gt;You'll need some phrase files to play with it. You can find those here:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www-personal.umich.edu/%7Ejlawler/chomsky.1"&gt;Introduction phrases&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www-personal.umich.edu/%7Ejlawler/chomsky.2"&gt;Subject phrases&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www-personal.umich.edu/%7Ejlawler/chomsky.3"&gt;Verb phrases&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www-personal.umich.edu/%7Ejlawler/chomsky.4"&gt;Object sentences&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;You can try the original version of the  &lt;a href="http://rubberducky.org/cgi-bin/chomsky.pl"&gt;ChomskyBot online&lt;/a&gt;. It's written in Perl &lt;a href="http://www.umich.edu/%7Ejlawler/fogcode.html"&gt;(source)&lt;/a&gt; by &lt;a href="http://www.umich.edu/%7Eclunis/"&gt;Kevin McGovan&lt;/a&gt;. For more information, pay a visit to Chomsky bot inventor John Lawlers &lt;a href="http://www-personal.umich.edu/%7Ejlawler/foggy.faq.html"&gt;website&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-655214034240883790?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/655214034240883790/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=655214034240883790' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/655214034240883790'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/655214034240883790'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/05/fun-with-ruby-chomskybot.html' title='Colorless green ideas sleep furiously: Fun with a Ruby ChomskyBot'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-8325073161078835617</id><published>2007-05-09T01:45:00.000-07:00</published><updated>2007-05-09T02:14:28.780-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='test'/><category scheme='http://www.blogger.com/atom/ns#' term='nagios'/><title type='text'>Nagios as a test suite</title><content type='html'>&lt;a href="http://nagios.org"&gt;Nagios&lt;/a&gt; is designed for network monitoring, and this is reflected in the plugins and the configuration language (e.g. everything is centered around the concepts of hosts and services) However, the flexiblity of Nagios also means that it works nicely as a blackbox test suite. I used this approach to the development of an sms broker solution for a customer recently (a Tomcat based application with a MySQL backend). As an added benefit, the test suite now also works as monitoring of the production system. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Diverse applications&lt;/b&gt;&lt;br /&gt;Many applications consists of different components and bits and parts in different languages. The complicates testing with a standard, language specific tool like jUnit. Nagios is a nice piece of glue that lets you write tests in whatever way you like.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;It's so easy to write a plugin in any language you like.&lt;/b&gt;&lt;br /&gt;Sometimes it's just easier to write that database consistency check in Ruby/Perl/PHP than in Java. You might even be able to find a plugin that suits your needs on &lt;a href="http://nagiosexchange.org"&gt;NagiosExchange&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Continuous testing with different intervals.&lt;/b&gt;&lt;br /&gt;Test suites like jUnit have the drawback that they are usually run manually, so the discovery of an introduced bug may creep up late, if you don't run your testsuite often enough. In Nagios on the other hand, tests can be scheduled on an individual level. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Notify you when a test fails&lt;/b&gt;&lt;br /&gt;Notifications can be done in a variety of ways (email/sms/im), but it's probably most useful in the monitoring phase (e.g. production). However, there are usually cases you want to know upfront when some part of the code mysteriously fails.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-8325073161078835617?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/8325073161078835617/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=8325073161078835617' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/8325073161078835617'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/8325073161078835617'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/05/nagios-as-testsuite.html' title='Nagios as a test suite'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-6813235692998835932</id><published>2007-05-03T01:56:00.000-07:00</published><updated>2007-05-11T01:13:26.827-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='greenpeace'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>Apple responds to critisism from Greenpeace</title><content type='html'>Steve Jobs have written a &lt;a href="http://www.apple.com/hotnews/agreenerapple/"&gt;response&lt;/a&gt; to the &lt;a href="http://www.greenmyapple.org"&gt;criticism&lt;/a&gt; about Apples environmental standards. It seems that they actually do better than Greenpeace thought they did. Well, that's positive :-)&lt;br /&gt;&lt;br /&gt;According to Apple they do better than HP and Dell, and have some sensible plans for chemical reduction and recycling.&lt;br /&gt;&lt;br /&gt;I'm glad that Apple finally put some focus this. We need focus on this. Consumers have a lot to say, but they don't always contextualize. When they do contextualize they have a tendency to do it on a limited information basis. For instance the &lt;a href="http://greenmyapple.org"&gt;Greenpeace campaign&lt;/a&gt; (which I fully &lt;a href="http://inferencing.blogspot.com/2007/04/iwaste-apples-arent-green.html"&gt;support&lt;/a&gt;) apparently didn't have all the relevant information about Apple. &lt;br /&gt;&lt;br /&gt;While the power of the consumer is great to create focus on an issue, in this case, I think what we need is legislation. Set some limits for what chemical levels are allowed  and require computer manufacturers to have a recycling policy. I think we need a objective and trusted investigation entity to determine how the computer manufacturers are doing. &lt;br /&gt;&lt;br /&gt;A solution would be to put a tax on chemicals in computers. That would certainly encourage computer manufacturers to reduce those chemicals.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-6813235692998835932?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/6813235692998835932/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=6813235692998835932' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/6813235692998835932'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/6813235692998835932'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/05/apple-responds-to-critisism-from.html' title='Apple responds to critisism from Greenpeace'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-3525710223238601823</id><published>2007-05-02T12:32:00.000-07:00</published><updated>2007-05-14T02:01:42.128-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='latex'/><category scheme='http://www.blogger.com/atom/ns#' term='logic'/><title type='text'>Transmoglyphing textual logic expression into Latex math</title><content type='html'>Recently I've been doing some exercises which included a lot of logic expressions. Writing those in Latex becomes really tedious after a while, so I got sidetracked and wrote a small ruby program :-) It transforms a textual logic expression to the Latex equivalent.&lt;br /&gt;&lt;br /&gt;For instance, this is a textual of a common logic function (can you see which one?):&lt;br /&gt;&lt;code&gt;(x and not y) or (!x &amp;&amp;amp; y)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;It translates into latex math:&lt;br /&gt;&lt;code&gt;$(x  \wedge   \neg  y)  \vee  ( \neg x  \wedge  y)$&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;When rendered it looks like this:&lt;br /&gt;&lt;img src="http://2.bp.blogspot.com/_B2qRRhuJC7U/RjjubgE12vI/AAAAAAAACF8/tIzcO1kASDo/s320/xor.png" alt="" id="BLOGGER_PHOTO_ID_5060056337584872178" border="0" /&gt;&lt;br /&gt;&lt;br /&gt;Other things like implication, biiimplication and entailment are also supported. The syntax allows a certain degree of freedom in choice of textual logic operators.&lt;br /&gt;&lt;br /&gt;The code:&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;br /&gt;&lt;span class="comment"&gt;#!/usr/bin/env ruby&lt;/span&gt;&lt;br /&gt;&lt;span class="comment"&gt;# Encode text with logic expressions as a latex math expression&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;symbols&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;br /&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;\wedge&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;and&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;],&lt;/span&gt;&lt;br /&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;\vee&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;or&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;||&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;],&lt;/span&gt;&lt;br /&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;\neg&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;^&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;!&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;not&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;],&lt;/span&gt;&lt;br /&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;\Leftrightarrow&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;&amp;lt;=&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;&amp;lt;-&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;],&lt;/span&gt;&lt;br /&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;\Rightarrow&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;],&lt;/span&gt;&lt;br /&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;\models&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;:-&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;:=&lt;/span&gt;&lt;span class="punct"&gt;',&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;entails&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt; &lt;span class="punct"&gt;]&lt;/span&gt;&lt;br /&gt;&lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;match_exp&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{}&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;symbols&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;keys&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;k&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;symbols&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;k&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;re&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;match_exp&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;re&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;k&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;  &lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;# Sort string by their length so that longest regexps are matched first&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;String&lt;/span&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;&amp;lt;=&amp;gt;&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;other&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;                &lt;span class="ident"&gt;other&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;length&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;=&amp;gt;&lt;/span&gt; &lt;span class="ident"&gt;length&lt;/span&gt;&lt;br /&gt;        &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;loop&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt;&lt;br /&gt; &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Enter logic text:&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;span class="ident"&gt;text&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="global"&gt;$stdin&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;gets&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;chomp&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;break&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;text&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;quit&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="ident"&gt;match_exp&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;keys&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;reverse&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;k&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;text&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;gsub!&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;k&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt; &lt;span class="expr"&gt;#{match_exp[k]}&lt;/span&gt; &lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Latex math expr: $&lt;span class="expr"&gt;#{text.chomp}&lt;/span&gt;$&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt; &lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-3525710223238601823?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/3525710223238601823/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=3525710223238601823' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/3525710223238601823'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/3525710223238601823'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/05/transmoglyphing-textual-logic.html' title='Transmoglyphing textual logic expression into Latex math'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_B2qRRhuJC7U/RjjubgE12vI/AAAAAAAACF8/tIzcO1kASDo/s72-c/xor.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-6508322042249141016</id><published>2007-05-01T11:30:00.000-07:00</published><updated>2007-06-11T01:48:06.381-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='clp'/><category scheme='http://www.blogger.com/atom/ns#' term='constraints'/><title type='text'>Generate and Test in Ruby</title><content type='html'>The &lt;a href="http://ktiml.mff.cuni.cz/~bartak/constraints/backtrack.html#GT"&gt;Generate and Test algorithm (GT)&lt;/a&gt; is without comparison the simplest and most inefficient way of solving constraints. Actually, it's not useful for anything but very, very small  problems. But it is serves as a nice little illustrating of the concept of constraint solving. Just for fun I wrote a very small GT constraint solver in Ruby the other day, that I decided sharing.&lt;br /&gt;&lt;br /&gt;Here is a small toy problem for it to solve and a demonstration of how it works:&lt;br /&gt;&lt;br /&gt;&lt;pre class="ruby" style="color: #006; border: 1px solid #d0d0d0; background-color: #f0f0f0;"&gt;&lt;ol&gt;&lt;li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;font: normal normal 130% 'Courier New', Courier, monospace; color: #003030;"&gt;&lt;div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;color: #000020;"&gt;gt = GT.&lt;span style="color:#9900CC;"&gt;new&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;font: normal normal 130% 'Courier New', Courier, monospace; color: #003030;"&gt;&lt;div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;color: #000020;"&gt; &lt;/div&gt;&lt;/li&gt;&lt;li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;font: normal normal 130% 'Courier New', Courier, monospace; color: #003030;"&gt;&lt;div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;color: #000020;"&gt;gt.&lt;span style="color:#9900CC;"&gt;add_var&lt;/span&gt;&lt;span style="color:#006600; font-weight:bold;"&gt;(&lt;/span&gt;&lt;span style="color:#996600;"&gt;"a"&lt;/span&gt;, &lt;span style="color:#006666;"&gt;0&lt;/span&gt;..&lt;span style="color:#006666;"&gt;4&lt;/span&gt;&lt;span style="color:#006600; font-weight:bold;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;font: normal normal 130% 'Courier New', Courier, monospace; color: #003030;"&gt;&lt;div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;color: #000020;"&gt;gt.&lt;span style="color:#9900CC;"&gt;add_var&lt;/span&gt;&lt;span style="color:#006600; font-weight:bold;"&gt;(&lt;/span&gt;&lt;span style="color:#996600;"&gt;"b"&lt;/span&gt;, &lt;span style="color:#006666;"&gt;0&lt;/span&gt;..&lt;span style="color:#006666;"&gt;4&lt;/span&gt;&lt;span style="color:#006600; font-weight:bold;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style="font-weight: bold;font-weight: bold; color: #006060;"&gt;&lt;div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;color: #000020;"&gt;gt.&lt;span style="color:#9900CC;"&gt;add_var&lt;/span&gt;&lt;span style="color:#006600; font-weight:bold;"&gt;(&lt;/span&gt;&lt;span style="color:#996600;"&gt;"c"&lt;/span&gt;, &lt;span style="color:#006666;"&gt;0&lt;/span&gt;..&lt;span style="color:#006666;"&gt;4&lt;/span&gt;&lt;span style="color:#006600; font-weight:bold;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;font: normal normal 130% 'Courier New', Courier, monospace; color: #003030;"&gt;&lt;div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;color: #000020;"&gt; &lt;/div&gt;&lt;/li&gt;&lt;li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;font: normal normal 130% 'Courier New', Courier, monospace; color: #003030;"&gt;&lt;div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;color: #000020;"&gt;gt.&lt;span style="color:#9900CC;"&gt;add_constraint&lt;/span&gt;&lt;span style="color:#006600; font-weight:bold;"&gt;(&lt;/span&gt;&lt;span style="color:#996600;"&gt;"a % 3 == 0"&lt;/span&gt;&lt;span style="color:#006600; font-weight:bold;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;font: normal normal 130% 'Courier New', Courier, monospace; color: #003030;"&gt;&lt;div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;color: #000020;"&gt;gt.&lt;span style="color:#9900CC;"&gt;add_constraint&lt;/span&gt;&lt;span style="color:#006600; font-weight:bold;"&gt;(&lt;/span&gt;&lt;span style="color:#996600;"&gt;"b + a &lt; c"&lt;/span&gt;&lt;span style="color:#006600; font-weight:bold;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style="font-family: 'Courier New', Courier, monospace; color: black; font-weight: normal; font-style: normal;font: normal normal 130% 'Courier New', Courier, monospace; color: #003030;"&gt;&lt;div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;color: #000020;"&gt;gt.&lt;span style="color:#9900CC;"&gt;add_constraint&lt;/span&gt;&lt;span style="color:#006600; font-weight:bold;"&gt;(&lt;/span&gt;&lt;span style="color:#996600;"&gt;"c-a &gt; b"&lt;/span&gt;&lt;span style="color:#006600; font-weight:bold;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li style="font-weight: bold;font-weight: bold; color: #006060;"&gt;&lt;div style="font-family: 'Courier New', Courier, monospace; font-weight: normal;color: #000020;"&gt;gt.&lt;span style="color:#9900CC;"&gt;solve&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Running this code will print:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;Solutions:&lt;br /&gt;{"a"=&gt;0, "b"=&gt;0, "c"=&gt;1}&lt;br /&gt;{"a"=&gt;0, "b"=&gt;0, "c"=&gt;2}&lt;br /&gt;{"a"=&gt;0, "b"=&gt;0, "c"=&gt;3}&lt;br /&gt;{"a"=&gt;0, "b"=&gt;0, "c"=&gt;4}&lt;br /&gt;{"a"=&gt;0, "b"=&gt;1, "c"=&gt;2}&lt;br /&gt;{"a"=&gt;0, "b"=&gt;1, "c"=&gt;3}&lt;br /&gt;{"a"=&gt;0, "b"=&gt;1, "c"=&gt;4}&lt;br /&gt;{"a"=&gt;0, "b"=&gt;2, "c"=&gt;3}&lt;br /&gt;{"a"=&gt;0, "b"=&gt;2, "c"=&gt;4}&lt;br /&gt;{"a"=&gt;0, "b"=&gt;3, "c"=&gt;4}&lt;br /&gt;{"a"=&gt;3, "b"=&gt;0, "c"=&gt;4}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The implementation:&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;GT&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;br /&gt;    &lt;span class="attribute"&gt;@variables&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Hash&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;br /&gt;    &lt;span class="attribute"&gt;@constraints&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Array&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;add_var&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;varname&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;domain&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="attribute"&gt;@variables&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;varname&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;domain&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;add_constraint&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;constraint&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;constraint&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;freeze&lt;/span&gt;&lt;br /&gt;    &lt;span class="attribute"&gt;@constraints&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ident"&gt;constraint&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;generate&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;gen&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="attribute"&gt;@variables&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="constant"&gt;Hash&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="constant"&gt;nil&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;gen&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;variables&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;partial_assignment&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;solutions&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;solutions&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Array&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;solutions&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;nil?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;variables&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;empty?&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;partial_assignment&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;        &lt;span class="ident"&gt;solutions&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ident"&gt;partial_assignment&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;clone&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="constant"&gt;nil&lt;/span&gt; &lt;span class="comment"&gt;# termination&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    &lt;span class="comment"&gt;# pick the first available variable:&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;vars&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;variables&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;clone&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;var_name&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;variables&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;keys&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;domain&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;vars&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;var_name&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;br /&gt;    &lt;span class="ident"&gt;vars&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;delete&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;var_name&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;    &lt;span class="comment"&gt;# Loop over each variable in domain&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;domain&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;value&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;partial_assignment&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;var_name&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;value&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;gen&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;vars&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;partial_assignment&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;solutions&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;solutions&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;test&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;assignment&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="attribute"&gt;@constraints&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;constraint&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;c&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;String&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;constraint&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;assignment&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;key&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="ident"&gt;val&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;        &lt;span class="ident"&gt;c&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;gsub!&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;key&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="ident"&gt;val&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;result&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;instance_eval&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;c&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword"&gt;return&lt;/span&gt; &lt;span class="constant"&gt;false&lt;/span&gt; &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;result&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="constant"&gt;false&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;  &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;solve&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;Solutions:&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;solutions&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;generate&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;solutions&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;s&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;      &lt;span class="ident"&gt;pp&lt;/span&gt; &lt;span class="ident"&gt;s&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It is not useful for solving anything interesting though. I tried to make it solve the the send more money puzzle. But this poor algorithm searches it self to death in vain. It took so long, that it was never allowed to terminate...&lt;br /&gt;&lt;pre class="code"&gt;&lt;br /&gt;&lt;span class="punct"&gt;[&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;s&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;e&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;n&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;d&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;o&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;r&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;n&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;y&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;var&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;gt&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;add_var&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;var&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;..&lt;/span&gt;&lt;span class="number"&gt;9&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;gt&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;add_constraint&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;m != 0&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;gt&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;add_constraint&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;s != 0&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;gt&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;add_constraint&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;m &amp;lt; 3&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;gt&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;add_constraint&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;(1000*s + 100*e + 10*n + d + 1000*m + 100*o + 10*r + e) == (10000*m + 1000*o + 100*n + 10*e + y)&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;  &lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;gt&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;solve&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update:&lt;/b&gt;Also heck out &lt;a href="http://inferencing.blogspot.com/2007/06/i-just-discovered-this-implementation.html"&gt;amb &lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-6508322042249141016?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/6508322042249141016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=6508322042249141016' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/6508322042249141016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/6508322042249141016'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/05/generate-and-test-in-ruby.html' title='Generate and Test in Ruby'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-3915156180644373467</id><published>2007-04-25T07:55:00.000-07:00</published><updated>2007-05-14T07:33:27.113-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='greenpeace'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>iWaste: Apples aren't green :-(</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.greenmyapple.org"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_B2qRRhuJC7U/Ri9zbAE12uI/AAAAAAAACF0/deAMiLd9AoI/s320/home-visual-01.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5057387814274325218" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I am the happy owner of a MacBook Pro, a nice computer with a really nice OS. Or, at least I used to be happy about it. I have had quite ambivalent feelings since I discovered that Apple is one of the biggest pigs when it comes to toxic chemicals in computers :-(&lt;br /&gt;&lt;br /&gt;Then I heard that Apple is going to let the share holders vote about removing those toxics. Actually it seems that the board opposes doing it:&lt;br /&gt;&lt;i&gt;&lt;br /&gt;"Apple's board says it opposes the resolution, arguing that the company already has adequate environmental standards."&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;a href="http://computerworld.com/action/article.do?command=viewArticleBasic&amp;taxonomyName=hardware&amp;articleId=9017622&amp;taxonomyId=12&amp;intsrc=kc_top"&gt;from  computer world article&lt;/A&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Yeah right! Your standards are about the lousiest in the industry! I hope that your sales drops if this doesn't change. Is the only way of being environmental about this to not buy Apple computers any more? If that is the case, I already bought my last mac. Doesn't Apple realize that this is going to drive their stock down? &lt;br /&gt;&lt;br /&gt;Greenpeace is running a campaign where you write Steve and tell him that you are unhappy to. Consider doing it. Go to &lt;a href="http://www.greenmyapple.org/"&gt;www.greenmyapple.org&lt;/a&gt; to check it out.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update&lt;/b&gt;&lt;br /&gt;&lt;a href="http://inferencing.blogspot.com/2007/05/apple-responds-to-critisism-from.html"&gt;Follow up: Apple has responded to criticism from Greenpeace&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-3915156180644373467?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/3915156180644373467/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=3915156180644373467' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/3915156180644373467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/3915156180644373467'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/04/iwaste-apples-arent-green.html' title='iWaste: Apples aren&apos;t green :-('/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_B2qRRhuJC7U/Ri9zbAE12uI/AAAAAAAACF0/deAMiLd9AoI/s72-c/home-visual-01.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-7203196932806828394</id><published>2007-04-22T16:28:00.000-07:00</published><updated>2007-04-23T12:25:34.883-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='sleipner'/><title type='text'>Sleipner is dead</title><content type='html'>With a slight feeling of sadness, I updated the &lt;a href="http://sleipner.sourceforge.net"&gt;Sleipner website&lt;/a&gt; to reflect the fact that the project isn't actively being developed anymore. Neither me nor Jens has the time to do it and other more promising projects in the same category has surfaced since the dawn of Sleipner. But it was a fun project to work on back then :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-7203196932806828394?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/7203196932806828394/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=7203196932806828394' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/7203196932806828394'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/7203196932806828394'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/04/sleipner-is-dead.html' title='Sleipner is dead'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-8500072246146514191</id><published>2007-04-22T06:28:00.000-07:00</published><updated>2007-05-14T02:04:01.628-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>My answer to ruby quiz 121</title><content type='html'>My solution to &lt;a href="http://www.rubyquiz.com/quiz121.html"&gt;Ruby quiz 121&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Given some morse code without breaks between letters (which can have ambiguous interpretations), it will generate the words that the morse code can generate.&lt;br /&gt;&lt;br /&gt;It's implemented as a recursive depth-first search in Ruby. Branches are expanded dynamically in the first_letters function.&lt;br /&gt;&lt;br /&gt;&lt;pre class="code"&gt;&lt;br /&gt;&lt;span class="ident"&gt;require&lt;/span&gt; &lt;span class="punct"&gt;'&lt;/span&gt;&lt;span class="string"&gt;pp&lt;/span&gt;&lt;span class="punct"&gt;'&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;class &lt;/span&gt;&lt;span class="class"&gt;Morse&lt;/span&gt;&lt;br /&gt; &lt;span class="attribute"&gt;@@alpha&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;a&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.-&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;b&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;-...&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;c&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;-.-.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;d&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;-..&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;e&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;f&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;..-.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;g&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;--.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;h&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;....&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;i&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;..&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;j&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.---&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;k&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;-.-&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;l&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.-..&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;--&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;o&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;---&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;p&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.--.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;q&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;--.-&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;r&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.-.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;s&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;...&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;t&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;-&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;u&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;..-&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;v&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;...-&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;w&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.--&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;x&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;-..-&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;y&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;-.--&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt;&lt;br /&gt;  &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;z&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;--..&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;initialize&lt;/span&gt;&lt;br /&gt;  &lt;span class="comment"&gt;# turn around hash index to use morse chars index&lt;/span&gt;&lt;br /&gt;  &lt;span class="attribute"&gt;@rev&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;{}&lt;/span&gt;&lt;br /&gt;  &lt;span class="attribute"&gt;@@alpha&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;k&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt;&lt;span class="ident"&gt;v&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="attribute"&gt;@rev&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;v&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;k&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;to_s&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="comment"&gt;# Returns all letters matching the morse str at this pos&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;first_letters&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;morse&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;pos&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;letters&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;&lt;br /&gt;  &lt;span class="attribute"&gt;@rev&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;keys&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;k&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;  &lt;br /&gt;   &lt;span class="ident"&gt;letters&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="ident"&gt;k&lt;/span&gt; &lt;span class="keyword"&gt;unless&lt;/span&gt; &lt;span class="ident"&gt;morse&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;pos&lt;/span&gt;&lt;span class="punct"&gt;..-&lt;/span&gt;&lt;span class="number"&gt;1&lt;/span&gt;&lt;span class="punct"&gt;].&lt;/span&gt;&lt;span class="ident"&gt;scan&lt;/span&gt;&lt;span class="punct"&gt;(/&lt;/span&gt;&lt;span class="regex"&gt;^&lt;span class="expr"&gt;#{k.gsub(&amp;quot;.&amp;quot;,&amp;quot;\\.&amp;quot;)}&lt;/span&gt;.*&lt;/span&gt;&lt;span class="punct"&gt;/).&lt;/span&gt;&lt;span class="ident"&gt;empty?&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;letters&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="comment"&gt;# Returns an array of words that matches 'morse' string &lt;/span&gt;&lt;br /&gt; &lt;span class="comment"&gt;# It's basically a recursive function implementing depth-first search &lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;morse2words&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;morse&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;pos&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt; &lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;seen&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;solutions&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;[]&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;first_letters&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;morse&lt;/span&gt;&lt;span class="punct"&gt;,&lt;/span&gt; &lt;span class="ident"&gt;pos&lt;/span&gt;&lt;span class="punct"&gt;).&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;l&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;   &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;morse&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;length&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="ident"&gt;pos&lt;/span&gt; &lt;span class="punct"&gt;+&lt;/span&gt; &lt;span class="ident"&gt;l&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;length&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;solutions&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{seen}#{@rev[l]}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;   &lt;span class="keyword"&gt;else&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;result&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;morse2words&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;morse&lt;/span&gt;&lt;span class="punct"&gt;,(&lt;/span&gt;&lt;span class="ident"&gt;pos&lt;/span&gt;&lt;span class="punct"&gt;+&lt;/span&gt;&lt;span class="ident"&gt;l&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;length&lt;/span&gt;&lt;span class="punct"&gt;),&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;span class="expr"&gt;#{seen}#{@rev[l]}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt;&lt;br /&gt;    &lt;span class="ident"&gt;solutions&lt;/span&gt; &lt;span class="punct"&gt;+=&lt;/span&gt; &lt;span class="ident"&gt;result&lt;/span&gt;&lt;br /&gt;   &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  &lt;span class="ident"&gt;solutions&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span class="comment"&gt;# Converts a word to a morse string, used for testing&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;word2morse&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;word&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;morse&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;word&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each_byte&lt;/span&gt; &lt;span class="punct"&gt;{&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;b&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt; &lt;span class="ident"&gt;morse&lt;/span&gt; &lt;span class="punct"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="attribute"&gt;@@alpha&lt;/span&gt;&lt;span class="punct"&gt;[&lt;/span&gt;&lt;span class="ident"&gt;b&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;chr&lt;/span&gt;&lt;span class="punct"&gt;]&lt;/span&gt; &lt;span class="punct"&gt;}&lt;/span&gt;&lt;br /&gt;  &lt;span class="ident"&gt;morse&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="comment"&gt;######################&lt;/span&gt;&lt;br /&gt;&lt;span class="comment"&gt;# Test:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;test_word2morse&lt;/span&gt;&lt;br /&gt; &lt;span class="ident"&gt;m&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Morse&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;raise&lt;/span&gt; &lt;span class="keyword"&gt;unless&lt;/span&gt;  &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;word2morse&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;sofia&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;)&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;...---..-....-&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;  &lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;test_first_letters&lt;/span&gt;&lt;br /&gt; &lt;span class="ident"&gt;m&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Morse&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;raise&lt;/span&gt; &lt;span class="keyword"&gt;unless&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first_letters&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="punct"&gt;[&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;span class="punct"&gt;];&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;raise&lt;/span&gt; &lt;span class="keyword"&gt;unless&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;first_letters&lt;/span&gt;&lt;span class="punct"&gt;(&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;--.--..--.-.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="number"&gt;0&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;==&lt;/span&gt; &lt;span class="punct"&gt;[&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;--&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;-&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;--.&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;,&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;--.-&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;]&lt;/span&gt; &lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="keyword"&gt;def &lt;/span&gt;&lt;span class="method"&gt;test_morse2words&lt;/span&gt;&lt;br /&gt; &lt;span class="ident"&gt;m&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="constant"&gt;Morse&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;new&lt;/span&gt;&lt;br /&gt; &lt;span class="ident"&gt;sofia&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;...---..-....-&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt; &lt;br /&gt; &lt;span class="ident"&gt;solutions&lt;/span&gt; &lt;span class="punct"&gt;=&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;morse2words&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;sofia&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt;&lt;br /&gt; &lt;span class="ident"&gt;pp&lt;/span&gt; &lt;span class="ident"&gt;solutions&lt;/span&gt;&lt;br /&gt; &lt;span class="ident"&gt;solutions&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;each&lt;/span&gt; &lt;span class="keyword"&gt;do&lt;/span&gt; &lt;span class="punct"&gt;|&lt;/span&gt;&lt;span class="ident"&gt;s&lt;/span&gt;&lt;span class="punct"&gt;|&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;if&lt;/span&gt; &lt;span class="ident"&gt;m&lt;/span&gt;&lt;span class="punct"&gt;.&lt;/span&gt;&lt;span class="ident"&gt;word2morse&lt;/span&gt;&lt;span class="punct"&gt;(&lt;/span&gt;&lt;span class="ident"&gt;s&lt;/span&gt;&lt;span class="punct"&gt;)&lt;/span&gt; &lt;span class="punct"&gt;!=&lt;/span&gt; &lt;span class="ident"&gt;sofia&lt;/span&gt; &lt;br /&gt;   &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;bad solution: &lt;span class="expr"&gt;#{s}&lt;/span&gt;&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;   &lt;span class="ident"&gt;puts&lt;/span&gt; &lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;span class="string"&gt;yields &lt;span class="expr"&gt;#{m.word2morse(s)}&lt;/span&gt; in morse&lt;/span&gt;&lt;span class="punct"&gt;&amp;quot;&lt;/span&gt;&lt;br /&gt;   &lt;span class="keyword"&gt;raise&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt; &lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="ident"&gt;test_word2morse&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;test_first_letters&lt;/span&gt;&lt;br /&gt;&lt;span class="ident"&gt;test_morse2words&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-8500072246146514191?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/8500072246146514191/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=8500072246146514191' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/8500072246146514191'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/8500072246146514191'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/04/my-answer-to-ruby-quiz-121.html' title='My answer to ruby quiz 121'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-2205041620938883324</id><published>2007-04-22T04:20:00.001-07:00</published><updated>2007-04-23T12:24:45.994-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><title type='text'>substr in Ruby</title><content type='html'>Some times you want to extract the characters from a certain offset within a string. In Perl and PHP you have the substr function,  e.g.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$str = "Hello world";&lt;br /&gt;substr($str, 6);  # --&gt; "world"&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;In Ruby, this is done using the slice method of the String class. However, slice works a little different; slice is really an alias to [], so:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;str = "Hello world"&lt;br /&gt;str.slice(6) # --&gt; 119&lt;br /&gt;str[6] # --&gt; 119&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;This may come as a surprise if you are used to substr; this returns the value of the character and not the rest of the string. Instead, we can do the same using negative indices, since negative indices count from the end of the string:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;str.slice(6..-1) # --&gt; "world"&lt;br /&gt;str[6..-1] # --&gt; "world"&lt;br /&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-2205041620938883324?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/2205041620938883324/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=2205041620938883324' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/2205041620938883324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/2205041620938883324'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2007/04/slicing-cake-using-ruby.html' title='substr in Ruby'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-168417254374372109</id><published>2006-02-02T12:46:00.000-08:00</published><updated>2008-09-08T12:47:01.836-07:00</updated><title type='text'>Social bookmarking</title><content type='html'>I started bookmarking using http://del.icio.us recently. Awesome site!&lt;br /&gt;&lt;br /&gt;It's displays several trades of an excellent web-application; It's simple, user driven and bloat-free.&lt;br /&gt;&lt;br /&gt;What really made me realize how powerful http://del.icio.us is, was an excellent podcast from http://www.itconversions.com called &lt;a href="http://www.itconversations.com/shows/detail470.html"&gt;"Ontology is overrated"&lt;/a&gt; by &lt;a href="http://www.shirky.com/"&gt;Clay Shirky&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;An &lt;a href="http://www.jfsowa.com/ontology/index.htm"&gt;ontology&lt;/a&gt; is a categorization of things that exists. The categorization tends to take on a dominating perspective influenced by the authors of the ontology. &lt;br /&gt;&lt;br /&gt;For instance, the books in a library is sorted by author rather than by color. So if you're looking to find a specific red book in a library (and you don't know the author), you're out of luck. That's not a supported way of thinking :-(&lt;br /&gt;&lt;br /&gt;Of course, computers and networks and especially the web is excellent for cross-referencing things. So there's no reason at all why you shouldn't be able to do this. It's just that it didn't occur to the people designing the system that you would wan't to do strange stuff like that.&lt;br /&gt;&lt;!--&lt;br /&gt;I hate to be told how to think, and I think most other people feel the same way (Though, this is not obvious from peoples choice of operating system and programming languages). It just shouldn't work that way and del.icio.us doesn't:&lt;br /&gt;--&gt;&lt;br /&gt;&lt;br /&gt;http://del.icio.us is sort of a dynamic ontology realized by having users share bookmarks and apply tags (keywords) to those bookmarks. And yes, this is categorizing, but the users define their own categories. Categories form where different peoples bookmarks intersect. These are also intersections of peoples interests and by copying other peoples bookmarks you're exercising and forming social relations.&lt;br /&gt;&lt;br /&gt;Del.icio.us builds the ontology buttom-up instead of top-down. &lt;br /&gt;&lt;br /&gt;One of the interesting things Clay Shirky talks about is how ontologies tend to degenerate over time. This is bound to happen because the world of existing things on which the ontology reflects, changes. Categories are collapsed and information made up by their difference is inherently lost. Del.icio.us doesn't collapse categories, instead new categories becomes popular. &lt;br /&gt;&lt;br /&gt;Instead of following the traditional model of trying to force users to use and adopt an ontology (like &lt;a href="http://groups.yahoo.com/"&gt;yahoo&lt;/a&gt; groups and the library does), del.icio.us is an adaptive and more useful ontology. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Links&lt;/b&gt;&lt;br /&gt;Found an interesting article on &lt;a href="http://www.dlib.org/dlib/april05/hammond/04hammond.html"&gt;social bookmarking tools&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-168417254374372109?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/168417254374372109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=168417254374372109' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/168417254374372109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/168417254374372109'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2006/02/social-bookmarking.html' title='Social bookmarking'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-7257410229390454420</id><published>2005-10-09T12:43:00.001-07:00</published><updated>2008-09-08T12:54:29.654-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='php'/><category scheme='http://www.blogger.com/atom/ns#' term='oo'/><title type='text'>Simulating polymorphism in PHP</title><content type='html'>Today, I was tearing hairs out of my head to find out how to do &lt;a href="http://en.wikipedia.org/wiki/Polymorphism_%28computer_science%29"&gt;polymorphism&lt;/a&gt;  as described by the &lt;a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle"&gt;Liskov substitution principle&lt;/a&gt; in PHP (version 4).&lt;br /&gt;&lt;br /&gt;The problem I was faced with was the following: I have an object of supertype and I wish to use it as an object of a subtype. Apparently, this is not readily possible in PHP.&lt;br /&gt;&lt;br /&gt;I found my answer in a comment to the &lt;a href="http://www.php.net/manual/en/language.oop.php"&gt;php manual&lt;/a&gt;, credit to Simon Li. It's quite a hack.&lt;br /&gt;&lt;br /&gt;What happens is that the object is &lt;a href="http://dk2.php.net/serialize"&gt;serialized&lt;/a&gt;, it's transformed into a string like this:&lt;br /&gt;&lt;code&gt;string(32) "O:6:&lt;b&gt;"answer"&lt;/b&gt;:1:{s:6:"answer";i:42;}"&lt;/code&gt;&lt;br /&gt;The class name, the third element, is replaced with the class name desired. And finally, the modified string is transformed into a real object again. &lt;br /&gt;&lt;br /&gt;I generalized the code from the comment and ended up with following:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;// hack to simulate polymorphism in php&lt;br /&gt;// you're not gonna like it&lt;br /&gt;class castable {&lt;br /&gt;&amp;nbsp;&amp;nbsp;function cast_to($name) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$tmp = explode(":",serialize($this));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$tmp[1] = strlen($name);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$tmp[2] = "\"$name\"";&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$this = unserialize(implode(":",$tmp));&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class answer extends castable {&lt;br /&gt;&amp;nbsp;&amp;nbsp;var $answer = 42;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class question extends answer {&lt;br /&gt;&amp;nbsp;&amp;nbsp;function tell_me_the_answer () {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;echo "The answer is: ";&lt;br /&gt;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;$deepthought = new answer();&lt;br /&gt;$deepthought-&gt;cast_to("question");&lt;br /&gt;$deepthought-&gt;tell_me_the_answer();&lt;br /&gt;&lt;br /&gt;echo $deepthought-&gt;answer . "\n";&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This outputs:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;The answer is 42&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;!--&lt;br /&gt;Actually, this works regardless of whether question extends answer; as long as answer extends castable. This way you can cast an object to any class, regardless of the inheritance hierarchy. &lt;br /&gt;--&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-7257410229390454420?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/7257410229390454420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=7257410229390454420' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/7257410229390454420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/7257410229390454420'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2005/10/simulating-polymorphism-in-php.html' title='Simulating polymorphism in PHP'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-348102280719983048</id><published>2005-09-30T12:48:00.000-07:00</published><updated>2008-09-08T12:49:38.772-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='filesystem'/><title type='text'>Object filesystems</title><content type='html'>I just stumbled upon RailsFS. Nice.&lt;br /&gt;&lt;a href="http://redhanded.hobix.com/inspect/railsfsAfterACoupleMinutesOfToolingWithFuseWhoa.html"&gt;&lt;br /&gt;RailsFS &lt;/a&gt; is a filesystem that maps the ActiveRecord classes in an Rails app as a Linux filesystem. It's written in my new favourite language &lt;a href="http://wwww.ruby-lang.org"&gt;Ruby&lt;/a&gt; and uses &lt;a href="http://fuse.sf.net"&gt;FUSE&lt;/a&gt; and a &lt;a href="http://rubyforge.org/frs/download.php/6158/fusefs-0.3.tar.gz"&gt;Ruby binding&lt;/a&gt; for FUSE. It's almost no code, impressive.&lt;br /&gt;&lt;br /&gt;Actually, I wrote a very similar filesystem &lt;a href="http://jcfs.sf.net"&gt;JCFS&lt;/a&gt; (Java Class FileSystem) about a year ago also using fuse and some very ugly JNI hacking. JCFS lets you mount Java classes and access class variables and run class methods. &lt;br /&gt;&lt;br /&gt;Never really got around to writing a paper or even making the code remotely readable. But hey, you can &lt;a href=""&gt;download it&lt;/a&gt; and play with yourself if you're curious. &lt;br /&gt;&lt;br /&gt;It release a readable and maybe useable revision of the code soon. Promise.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;I will save a discussion about the deficiencies of FUSE (and the merits of Nimloth) for an other post someday...&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-348102280719983048?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/348102280719983048/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=348102280719983048' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/348102280719983048'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/348102280719983048'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2005/09/i-just-stumbled-upon-railsfs.html' title='Object filesystems'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-6594352044318880508.post-4346314295186654323</id><published>2005-08-20T12:40:00.000-07:00</published><updated>2008-09-08T12:55:31.776-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ajax'/><category scheme='http://www.blogger.com/atom/ns#' term='web'/><title type='text'>ajax stuff</title><content type='html'>I've been reading a bit about AJAX lately. Mostly because its the hot topic that everybody on the web is talking about, but also partly because it's pretty darn useful ;-) &lt;br /&gt;&lt;br /&gt;I've decided to use it in an application I am developing at &lt;a href="http://www.siemens.com/index.jsp?sdc_p=dpo1148058fc43l30s2"&gt;work&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;This application is suppossed to replace an existing windows app which is partly developed using &lt;a href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclib/html/_mfc_class_library_reference_introduction.asp"&gt;MFC&lt;/a&gt;  and partly web-based using IE browser component embedded in the windows application and IE only html. Makes me shiver.&lt;br /&gt;&lt;br /&gt;So I decided to develop it using &lt;a href="http://www.rubyonrails.com"&gt;Ruby on Rails&lt;/a&gt; and it's &lt;a href="http://www.onlamp.com/pub/a/onlamp/2005/06/09/rails_ajax.html"&gt;builtin support for AJAX.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;So what is AJAX&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;AJAX is short for &lt;b&gt;A&lt;/b&gt;synchronous &lt;b&gt;J&lt;/b&gt;avascript &lt;b&gt;A&lt;/b&gt;nd &lt;b&gt;X&lt;/b&gt;ML. AJAX is a way of using JavaScript to develop web applications that are far more responsive than your average form. &lt;br /&gt;&lt;br /&gt;A common limitation with web applications is the request-response model of http. With this model everytime you want some interaction with the server, you pretty much have to reload the entire page. This makes webapplications seem heavy and bothersome compared to native desktop applications.&lt;br /&gt;&lt;br /&gt;Basically, what AJAX does is to let you interact with the server on a much more granular level. It utilizes JavaScript to let you asynchronously call server-side scripts and update content without reloading the page. &lt;br /&gt;&lt;br /&gt;If you want to see AJAX in action take a look at &lt;a href="http://maps.google.com/"&gt;google maps&lt;/a&gt; and &lt;a href="http://script.aculo.us"&gt;script.aculo.us&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I can recommend the links below for learning more about AJAX:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Rasmus' 30 second AJAX Tutorial&lt;/b&gt;&lt;br /&gt;Rasmus Lerdorf of PHP fame &lt;a href= "http://marc.theaimsgroup.com/?l=php-general&amp;m=112198633625636&amp;w=2"&gt; explains AJAX&lt;/a&gt; with a very simple code example, really nice...&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Wikipedia&lt;/b&gt; has &lt;a href="http://en.wikipedia.org/wiki/Ajax_%28programming%29"&gt;good coverage&lt;/a&gt; as usual&lt;br /&gt;&lt;br /&gt;&lt;b&gt;State of AJAX&lt;/b&gt;. &lt;br /&gt;Originally from &lt;a href="http://it.slashdot.org/article.pl?sid=05/08/19/1845204&amp;tid=156&amp;tid=8"&gt; slashdot&lt;/a&gt;. Links AJAX with Service-Oriented Architectures (SOA). &lt;a href="http://hinchcliffe.org/archive/2005/08/18/1675.aspx"&gt;The article&lt;/a&gt; is overrated, but it has a lot of good links.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6594352044318880508-4346314295186654323?l=inferencing.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://inferencing.blogspot.com/feeds/4346314295186654323/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=6594352044318880508&amp;postID=4346314295186654323' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/4346314295186654323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/6594352044318880508/posts/default/4346314295186654323'/><link rel='alternate' type='text/html' href='http://inferencing.blogspot.com/2005/08/ajax-stuff.html' title='ajax stuff'/><author><name>Christian Theil Have</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>
