<?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-11149365</id><updated>2012-01-25T17:48:40.918Z</updated><category term='awk'/><category term='wide finder'/><category term='python example training'/><category term='europython EDA python'/><category term='meritocracy'/><category term='python'/><category term='crunchy python tutorials'/><category term='script'/><category term='rosettacode'/><category term='python truth-table boolean'/><category term='algorithms'/><category term='duck typing type python'/><category term='nice community'/><category term='J-language programming-language.'/><category term='python example'/><category term='advocacy'/><category term='duck typing'/><category term='maths Kaprekar'/><title type='text'>Go deh!</title><subtitle type='html'>Mainly Tech projects on Python and Electronic Design Automation.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default?start-index=101&amp;max-results=100'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>120</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-11149365.post-437811903177661701</id><published>2011-11-22T06:52:00.001Z</published><updated>2011-11-22T07:19:07.167Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='meritocracy'/><title type='text'>A better candidate selection process</title><content type='html'>I just read an article that had a good go at explaining why Silicon Valley firms are filled with white middle class males that managed to actually do what it set out to do when it explained why it wanted to take a more reasoned approach. They boil it down to everyone having an in-built bias - not necessarily a good or bad thing, it is just how humans operate. The article then comes up with a very useful experiment:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;When selecting from resumes for interview, have the names, age, sex, and origin of the candidates blanked out.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;The author found that his resulting selections for interview were a lot different to what he had before.&lt;br /&gt;&lt;br /&gt;He goes on to discuss how orchestras changed from being all male affairs to the current mix of genders by them adopting a selection process where candidates played unseen, behind a screen, and where selected based on how well they played.&lt;br /&gt;&lt;br /&gt;This got me wondering about the current controversy about Oxbridge admissions. Maybe the universities should adopt similar schemes, candidates should be lead to a separate room, unseen, where voice changers would mask ethnicity and accent, The interview would be audio only and taped, with the selection panel in a separate room. After the interview, the candidate should be given a copy of the tape, and another copy kept for independent review. The idea would be to make the process a better meritocracy rather than the obvious selection of "people like me" that goes on at the moment.&lt;br /&gt;&lt;br /&gt;Oh, here's the&lt;a href="http://techcrunch.com/2011/11/19/racism-and-meritocracy/"&gt; link to the original article&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-437811903177661701?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/437811903177661701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2011/11/better-candidate-selection-process.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/437811903177661701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/437811903177661701'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2011/11/better-candidate-selection-process.html' title='A better candidate selection process'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>4</thr:total><georss:featurename>Bristol, City of Bristol BS1 2, UK</georss:featurename><georss:point>51.4553129 -2.5919023</georss:point><georss:box>51.3761589 -2.7498308000000002 51.534466900000005 -2.4339738</georss:box></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-5374919945829318581</id><published>2011-11-08T05:04:00.000Z</published><updated>2011-11-08T05:04:23.363Z</updated><title type='text'>Should you worry about a 2x speedup?</title><content type='html'>Let's take as context an implementation of a task for &lt;a href="http://rosettacode.org/wiki/Rosetta_Code"&gt;Rosetta Code&lt;/a&gt; - a site set up to compare how different programming languages are used to implement the same task for over &lt;a href="http://rosettacode.org/wiki/Category:Programming_Tasks"&gt;five hundred tasks&lt;/a&gt; and over&lt;a href="http://rosettacode.org/wiki/Category:Programming_Languages"&gt; four hundred languages&lt;/a&gt;.&lt;br /&gt; &lt;br /&gt;My short answer would be &lt;i&gt;&lt;b&gt;it depends&lt;/b&gt;&lt;/i&gt;! You need to:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Read all of the task description,&lt;/li&gt;&lt;li&gt;Read some of the solutions in other languages,&amp;nbsp;&lt;/li&gt;&lt;li&gt;And maybe skim the tasks talk page&lt;/li&gt;&lt;/ul&gt;I.e.&amp;nbsp; ensure you know what the task is asking for and then verify that both solutions&lt;b&gt; solve the task as stated&lt;/b&gt;. It can be very easy to misinterpret what the task is asking for, for example, if a task asks for a particular algorithm, do both the examples you are comparing use that algorithm?&lt;br /&gt;&lt;br /&gt;As well as comparing two implementations for speed, you should also compare for&lt;b&gt; readability&lt;/b&gt;. How well the code reads can have a large impact on how easy the code is to &lt;b&gt;maintain&lt;/b&gt;. It has been known for task descriptions to be modified; someone tracking that modification may need to work out if and how code needs to be updated. If an example is overly complex&amp;nbsp; and/or unidiomatic then it could cause problems.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Time complexity&lt;/b&gt;. If one version of code works better when given 'bigger' data then&amp;nbsp; you need to know more about when that happens - it could be that the cross-over point in terms of speed of execution is never &lt;b&gt;likely &lt;/b&gt;to be met. Maybe the size of data needed to reach cross over is &lt;b&gt;unreasonable &lt;/b&gt;to expect, or that other mechanisms come into play that mask predicted gains (in other words you might need to verify using that actual bigger data set to account for things like swapping or caching at the OS and hardware level.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How fast does it need to be&lt;/b&gt;? Rosetta code doesn't usually mention absolute speed of execution, but if one example takes ten hours and the other takes five then you might want to take that into account. If one example took 0.2 seconds and the other only 0.1 seconds then I guess there is an unwritten expectation that examples "don't take long to run" where long is related to the expectation and patience of the user.&lt;br /&gt;&lt;br /&gt;You need to look at the &lt;b&gt;context&lt;/b&gt;. In the case of Rosetta code, it may be best to give a solution using a similar algorithm to other examples, or a solution that shows accepted use of the language.&lt;br /&gt;&lt;br /&gt;When you make your considered choice, you might want to squirrel away the losing code with notes on why it wasn't used,&amp;nbsp; - On Rosetta Code we sometimes add more than one solution to a task with comments contrasting the two if they both have merit.&lt;br /&gt;&lt;br /&gt;It seems to me that talk about optimising for speed, and speed comparisons tends to dominate on the web over other optimisations, (usually with no extra info on the accuracy of the result. Actually there might be more cases of a revised result that showed not even the first digit of the original answer was right, but more than two digits of precision were shown in the answers)!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-5374919945829318581?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/5374919945829318581/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2011/11/should-you-worry-about-2x-speedup.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/5374919945829318581'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/5374919945829318581'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2011/11/should-you-worry-about-2x-speedup.html' title='Should you worry about a 2x speedup?'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-4232624708395587128</id><published>2011-06-08T01:12:00.000+01:00</published><updated>2011-06-08T01:12:09.142+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='maths Kaprekar'/><title type='text'>Woa - a glitch on Wolfram Mathworld?</title><content type='html'>I had come across Kaprekar numbers and decided to write a&lt;a href="http://rosettacode.org/wiki/Kaprekar_numbers"&gt; Rosetta Code task&lt;/a&gt; around the series. There were issues about the need for extra explanation of why 1 is a member of the series.&lt;br /&gt;I had originally read the &lt;a href="http://en.wikipedia.org/wiki/Kaprekar_number"&gt;wp description&lt;/a&gt; and noted that there is a main part to testing if a number is in the series:&lt;br /&gt;&lt;blockquote&gt;&amp;nbsp;In mathematics, a &lt;b&gt;Kaprekar number&lt;/b&gt; for a given base is a non-negative integer, the representation of whose square in that base can be split into two parts that add up to the original number again. For instance, 45 is a Kaprekar number, because 45² = 2025 and 20+25 = 45.&lt;/blockquote&gt;&amp;nbsp;That is, splitting the ordered digits of the square of the number into two parts that sum to the original number.&lt;br /&gt;&lt;br /&gt;Wikipedia then goes on to state that runs of all zeros are &lt;i&gt;not &lt;/i&gt;considered positive integers and so 100*100 = 10,000 and 100 + 000 = 100 is &lt;i&gt;disallowed&lt;/i&gt;. &lt;br /&gt;&lt;br /&gt;What got me was tha&lt;u&gt;t 1 is considered a member of the series&lt;/u&gt;. The only way I could shoe-horn it into the general rule is to allow "splitting" the digits of the square before the first or after the last digit and so producing a number with no digits in it as a partial sum that &lt;b&gt;is &lt;/b&gt;allowed and has value zero?!&lt;br /&gt;&lt;br /&gt;I widened my references and took a look at the &lt;a href="http://mathworld.wolfram.com/KaprekarNumber.html"&gt;Wolfram Mathworld entry&lt;/a&gt;.&amp;nbsp; Its explanation for the series does not allow for 1 being a member, but shows it as such anyway. It is confused as it describes a series that would exclude numbers &lt;tt&gt;4879 and 5292&lt;/tt&gt;, i.e. Sloanes &lt;tt&gt;&lt;a href="http://oeis.org/A053816" title="Another version of the Kaprekar numbers: n such that n=q+r and n^2=q*10^m+r, for some m &amp;gt;= 1, q&amp;gt;=0 and 0&amp;lt;=r&amp;lt;10^m, with n != ..."&gt;A053816&lt;/a&gt;&lt;/tt&gt;; but points to&amp;nbsp; Sloanes&amp;nbsp; &lt;a class="Hyperlink" href="http://oeis.org/A006886"&gt;A006886&lt;/a&gt;!&lt;br /&gt;&lt;br /&gt;Sloanes&lt;tt&gt; &lt;a href="http://oeis.org/A006886" title="Kaprekar numbers: n such that n=q+r and n^2=q*10^m+r, for some m &amp;gt;= 1, q&amp;gt;=0 and 0&amp;lt;=r&amp;lt;10^m, with n != 10^a, a&amp;gt;=1."&gt;A006886&lt;/a&gt;&lt;/tt&gt; gives another definition for the series:&lt;br /&gt;&lt;blockquote&gt;&amp;nbsp;Kaprekar numbers: n such that n=q+r and n^2=q*10^m+r, for some m &amp;gt;= 1, q&amp;gt;=0 and 0&amp;lt;=r&amp;lt;10^m, with n != 10^a, a&amp;gt;=1.            &lt;/blockquote&gt;&amp;nbsp;If we try n = 1 then n*n = 1 and there is no m, q, and r that satisfies all the conditions.&lt;br /&gt;&lt;br /&gt;I will submit a comment to Mathworld and see what they have to say.&lt;br /&gt; &lt;br /&gt;P.S. I could have started this blog entry: "I'm not a mathematician but ..."&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &lt;br /&gt; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-4232624708395587128?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/4232624708395587128/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2011/06/woa-glitch-on-wolfram-mathworld.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/4232624708395587128'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/4232624708395587128'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2011/06/woa-glitch-on-wolfram-mathworld.html' title='Woa - a glitch on Wolfram Mathworld?'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-3664356587167821581</id><published>2011-06-01T09:04:00.000+01:00</published><updated>2011-06-01T09:04:08.849+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nice community'/><title type='text'>What http://perl6.org/ gets right</title><content type='html'>One thing I really like about the perl6 &lt;a href="http://perl6.org/"&gt;homepage &lt;/a&gt;is that they politely ask for people to be nice to each other up-front. The psychology goes a bit further: they use a female "voice", and associate the niceness with a butterfly image that is repeated on other pages.&lt;br /&gt;&lt;br /&gt;Now that is brilliant! Finding a problem and directly addressing it in such an appropriate manner is something I really like.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-3664356587167821581?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/3664356587167821581/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2011/06/what-httpperl6org-gets-right.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/3664356587167821581'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/3664356587167821581'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2011/06/what-httpperl6org-gets-right.html' title='What http://perl6.org/ gets right'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-3520533573056832672</id><published>2011-05-29T21:12:00.001+01:00</published><updated>2011-05-30T05:30:58.106+01:00</updated><title type='text'>Good enough solutions can be great!</title><content type='html'>I've had to imlement the solutions to two problems on Rosetta code lately and they both involve heuristics that get around the prolems of exhaustive search.&lt;br /&gt;&lt;br /&gt;The first problem was in finding a way to shuffle the letters of a string so that a minimum of letters end up in the same place. My first solution was to go through all letter permutations and return the best. That takes for ever on longer strings such as the word 'antidisestablishmentarianism'. &lt;br /&gt;The algorithm I then turned to just swaps letters if they swap into positions that put different characters into corresponding locations.&lt;a href="http://rosettacode.org/wiki/Best_shuffle#Swap_if_it_is_locally_better_algorithm"&gt; That algorithm&lt;/a&gt; is very fast and seems to give good answers.&lt;br /&gt;&lt;br /&gt;The second problem was in creating&lt;a href="http://en.wikipedia.org/wiki/Knight%27s_tour"&gt; knights tours&lt;/a&gt; of chess boards of varying sizes. The given &lt;a href="http://en.wikipedia.org/wiki/Knight%27s_tour#Warnsdorff.27s_algorithm"&gt;Wansdorff's algorithm&lt;/a&gt; is much quicker than a full depth first search, and was &lt;a href="http://rosettacode.org/wiki/Knight%27s_tour#Python"&gt;straight-forward to code&lt;/a&gt; . I later found &lt;a href="http://www.cs.cmu.edu/%7Esganzfri/REUPaper.pdf"&gt;evidence &lt;/a&gt;that for larger board sizes the algorithm fails . (Although the paper does suggest simple improvements that work for boards sizes with thousands of squares).&lt;br /&gt;&lt;br /&gt;Coding those two, makes me remember that results are what count&amp;nbsp; normally. You won't achieve much by searching for the theory of relativity if the queen wants Newtons laws of motion so that sailing ships can trade and plunder!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-3520533573056832672?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/3520533573056832672/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2011/05/good-enough-solutions-can-be-great.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/3520533573056832672'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/3520533573056832672'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2011/05/good-enough-solutions-can-be-great.html' title='Good enough solutions can be great!'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-5654781086598206169</id><published>2011-03-12T07:29:00.000Z</published><updated>2011-03-12T07:29:51.184Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='rosettacode'/><title type='text'>"That Goes Without Saying (or Does It)".  It didn't!</title><content type='html'>I spent the time to watch a &lt;a href="http://www.youtube.com/results?search_query=%E2%80%9CThat+Goes+Without+Saying+%28or+Does+It%29%E2%80%9D&amp;amp;aq=f"&gt;talk &lt;/a&gt;from Larry Wall the Perl, and now Perl 6 author; where he is using the&lt;a href="http://rosettacode.org/"&gt; Rosetta Code&lt;/a&gt; site for what it was built for - comparing programming language design, by examples.&lt;br /&gt;&lt;br /&gt;Unfortunately he was preaching to his acolytes so there is no meat to the talk. Larry says 'X' about a language compared to Perl or Perl 6 and the audience accepts without even asking for clarifications. Argument never enters their minds.&lt;br /&gt;&lt;br /&gt;What he did do well is to show examples first from the &lt;a href="http://rosettacode.org/wiki/Averages/Root_mean_square"&gt;Root mean square&lt;/a&gt; page and indicate how anyone can compare and contrast languages using it. Larry then categorized &lt;a href="http://rosettacode.org/wiki/Spiral_matrix"&gt;Spiral matrix&lt;/a&gt; and &lt;a href="http://rosettacode.org/wiki/Zig-zag_matrix"&gt;Zigzag matrix&lt;/a&gt; as tasks whose examples in Perl where &lt;u&gt;&lt;i&gt;"fun to write"&lt;/i&gt;&lt;/u&gt; which I liked as I remember getting a lot out of Zigzag when I first found RC, so much so that I think starting the new task "Spiral matrix" was probably the first task I wrote for RC. (I thought it would be good to learn by doing a variant of an existing task).&lt;br /&gt;&lt;br /&gt;Larry showed extended versions of the zigzag and spiral matrix solutions that used text based turtle graphics to animate the solutions.&lt;br /&gt;&lt;br /&gt;In summary, his language comparisons were droopy; his use of RC - spot on!&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://2.gvt0.com/vi/KJUVP2Z13Yo/0.jpg"&gt;&lt;param name="movie" value="http://www.youtube.com/v/KJUVP2Z13Yo&amp;fs=1&amp;source=uds" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;embed width="320" height="266" src="http://www.youtube.com/v/KJUVP2Z13Yo&amp;fs=1&amp;source=uds" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://2.gvt0.com/vi/lzil9AzXtiI/0.jpg"&gt;&lt;param name="movie" value="http://www.youtube.com/v/lzil9AzXtiI&amp;fs=1&amp;source=uds" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;embed width="320" height="266" src="http://www.youtube.com/v/lzil9AzXtiI&amp;fs=1&amp;source=uds" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;object width="320" height="266" class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://3.gvt0.com/vi/uzUTIffsc-M/0.jpg"&gt;&lt;param name="movie" value="http://www.youtube.com/v/uzUTIffsc-M&amp;fs=1&amp;source=uds" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;embed width="320" height="266" src="http://www.youtube.com/v/uzUTIffsc-M&amp;fs=1&amp;source=uds" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-5654781086598206169?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/5654781086598206169/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2011/03/that-goes-without-saying-or-does-it-it.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/5654781086598206169'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/5654781086598206169'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2011/03/that-goes-without-saying-or-does-it-it.html' title='&quot;That Goes Without Saying (or Does It)&quot;.  It didn&apos;t!'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-7632868270420498725</id><published>2011-01-11T19:00:00.000Z</published><updated>2011-01-11T19:00:28.119Z</updated><title type='text'>New laptop with an i7-640M processor; and a 32 inch "monitor".</title><content type='html'>After a lot of hard work, and the car scrappage schemes of last year, I got rewarded with bonus!?&lt;br /&gt;Nothing like a b&lt;span style="font-size: x-small;"&gt;&lt;strike&gt;w&lt;/strike&gt;&lt;/span&gt;ankers bonus, but enough to buy some fripperies after the essentials, and I decided to replace my aging 17" desktop-replacement laptop and get me a large 28" &lt;a href="http://www.trustedreviews.com/monitors/review/2008/09/01/Hanns-G-HG281DJ-28in-LCD-Monitor/p1"&gt;monitor&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;After much searching in the post-xmas sales, I came across a curious machine at a very good price. The &lt;a href="http://reviews.cnet.co.uk/laptops/advent-sienna-710-review-50000655/"&gt;Advent Sienna 710&lt;/a&gt; is a PCWorld/Dixons/Currys own-branded 15" laptop that has what, at the time, is the highest speed core for a laptop processor - an Intel 17-640M for under £500.&lt;br /&gt;&lt;br /&gt;I guess the laptop has such a low price as it will not appeal to a gamer as it relies on Intels graphics accelerator and is so basic it doesn't have the usual scroll area at the side of the pad., which isn't too hot but that makes it ideal for me as I wanted something fast and multi-core, but don't indulge in much 3D work and can live with the pad deficiencies.&lt;br /&gt;&lt;br /&gt;Our second TV had packed up mid-2010 and we were making-do with a very old 19" LCD. Instead of getting the 28" monitor I decided to buy a 32" Sony 1080P TV and use that as my monitor.&lt;br /&gt;&lt;br /&gt;Well, the Advent laptop and Sony TV work beautifully together. I have a huge 32" screen at a decent resolution and with the sound coming through the HDMI connection, I don't need extra laptop speakers as the Sony sound is very good&amp;nbsp; (better than on our more expensive main TV).&lt;br /&gt;&lt;br /&gt;I ran my improved &lt;a href="http://rosettacode.org/wiki/Parallel_calculations#Python"&gt;Python multi-processing example&lt;/a&gt; on the laptop and was very impressed with the speed, and with all the python instances appearing in the task manager.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;style type="text/css"&gt;&lt;!--pre { font-family: monospace; color: #000000; background-color: #ffffff; }body { font-family: monospace; color: #000000; background-color: #ffffff; }.Special { color: #6a5acd; }.Identifier { color: #008080; }.Statement { color: #804040; font-weight: bold; }.Comment { color: #0000ff; }.Constant { color: #ff00ff; }.PreProc { color: #a020f0; }--&gt;&lt;/style&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="PreProc"&gt;from&lt;/span&gt; concurrent &lt;span class="PreProc"&gt;import&lt;/span&gt; futures&lt;br /&gt;&lt;span class="PreProc"&gt;from&lt;/span&gt; math &lt;span class="PreProc"&gt;import&lt;/span&gt; floor, sqrt&lt;br /&gt;&lt;br /&gt;NUMBERS = [&lt;span class="Constant"&gt;2&lt;/span&gt;**n - &lt;span class="Constant"&gt;1&lt;/span&gt; &lt;span class="Statement"&gt;for&lt;/span&gt; n &lt;span class="Statement"&gt;in&lt;/span&gt; &lt;span class="Identifier"&gt;range&lt;/span&gt;(&lt;span class="Constant"&gt;55&lt;/span&gt;, &lt;span class="Constant"&gt;65&lt;/span&gt;)]&lt;br /&gt;&lt;br /&gt;&lt;span class="Statement"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;lowest_factor&lt;/span&gt;(n, _start=&lt;span class="Constant"&gt;3&lt;/span&gt;):&lt;br /&gt;    &lt;span class="Statement"&gt;if&lt;/span&gt; n % &lt;span class="Constant"&gt;2&lt;/span&gt; == &lt;span class="Constant"&gt;0&lt;/span&gt;:&lt;br /&gt;        &lt;span class="Statement"&gt;return&lt;/span&gt; &lt;span class="Constant"&gt;2&lt;/span&gt;&lt;br /&gt;    search_max = &lt;span class="Identifier"&gt;int&lt;/span&gt;(floor(sqrt(n))) + &lt;span class="Constant"&gt;1&lt;/span&gt;&lt;br /&gt;    &lt;span class="Statement"&gt;for&lt;/span&gt; i &lt;span class="Statement"&gt;in&lt;/span&gt; &lt;span class="Identifier"&gt;range&lt;/span&gt;(_start, search_max, &lt;span class="Constant"&gt;2&lt;/span&gt;):&lt;br /&gt;        &lt;span class="Statement"&gt;if&lt;/span&gt; n % i == &lt;span class="Constant"&gt;0&lt;/span&gt;:&lt;br /&gt;            &lt;span class="Statement"&gt;return&lt;/span&gt; i&lt;br /&gt;    &lt;span class="Statement"&gt;return&lt;/span&gt; n&lt;br /&gt;&lt;br /&gt;&lt;span class="Statement"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;prime_factors&lt;/span&gt;(n, lowest):&lt;br /&gt;    pf = []&lt;br /&gt;    &lt;span class="Statement"&gt;while&lt;/span&gt; n &amp;gt; &lt;span class="Constant"&gt;1&lt;/span&gt;:&lt;br /&gt;        pf.append(lowest)&lt;br /&gt;        n //= lowest&lt;br /&gt;        lowest = lowest_factor(n, &lt;span class="Identifier"&gt;max&lt;/span&gt;(lowest, &lt;span class="Constant"&gt;3&lt;/span&gt;))&lt;br /&gt;    &lt;span class="Statement"&gt;return&lt;/span&gt; pf&lt;br /&gt;&lt;br /&gt;&lt;span class="Statement"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;prime_factors_of_number_with_lowest_prime_factor&lt;/span&gt;(NUMBERS):&lt;br /&gt;    &lt;span class="Statement"&gt;with&lt;/span&gt; futures.ProcessPoolExecutor() &lt;span class="Statement"&gt;as&lt;/span&gt; executor:&lt;br /&gt;        low_factor, number = &lt;span class="Identifier"&gt;max&lt;/span&gt;( (l, f) &lt;span class="Statement"&gt;for&lt;/span&gt; l, f &lt;span class="Statement"&gt;in&lt;/span&gt; &lt;span class="Identifier"&gt;zip&lt;/span&gt;(executor.&lt;span class="Identifier"&gt;map&lt;/span&gt;(lowest_factor, NUMBERS), NUMBERS) )&lt;br /&gt;        all_factors = prime_factors(number, low_factor)&lt;br /&gt;        &lt;span class="Statement"&gt;return&lt;/span&gt; number, all_factors&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Statement"&gt;def&lt;/span&gt; &lt;span class="Identifier"&gt;main&lt;/span&gt;():&lt;br /&gt;    &lt;span class="Identifier"&gt;print&lt;/span&gt;( &lt;span class="Constant"&gt;'For these numbers:&lt;/span&gt;&lt;span class="Special"&gt;\n&lt;/span&gt;&lt;span class="Constant"&gt;  '&lt;/span&gt; + &lt;span class="Constant"&gt;'&lt;/span&gt;&lt;span class="Special"&gt;\n&lt;/span&gt;&lt;span class="Constant"&gt;  '&lt;/span&gt;.join(&lt;span class="Identifier"&gt;str&lt;/span&gt;(p) &lt;span class="Statement"&gt;for&lt;/span&gt; p &lt;span class="Statement"&gt;in&lt;/span&gt; NUMBERS) )&lt;br /&gt;    number, all_factors = prime_factors_of_number_with_lowest_prime_factor(NUMBERS)&lt;br /&gt;    &lt;span class="Identifier"&gt;print&lt;/span&gt;(&lt;span class="Constant"&gt;'    The one with the largest minimum prime factor is %i:'&lt;/span&gt; % number)&lt;br /&gt;    &lt;span class="Identifier"&gt;print&lt;/span&gt;(&lt;span class="Constant"&gt;'      All its prime factors in order are: %s'&lt;/span&gt; % all_factors)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Statement"&gt;if&lt;/span&gt; __name__ == &lt;span class="Constant"&gt;'__main__'&lt;/span&gt;:&lt;br /&gt;    main()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;END.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-7632868270420498725?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/7632868270420498725/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2011/01/new-laptop-with-i7-640m-processor-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/7632868270420498725'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/7632868270420498725'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2011/01/new-laptop-with-i7-640m-processor-and.html' title='New laptop with an i7-640M processor; and a 32 inch &quot;monitor&quot;.'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-1166938932685970557</id><published>2010-12-07T05:29:00.000Z</published><updated>2010-12-07T05:29:59.244Z</updated><title type='text'>Stupid macro languages</title><content type='html'>In the Python web world, the debate on whether templating languages should offer programming language type abilities has reared its head again. from &lt;a href="http://pydanny.blogspot.com/2010/12/stupid-template-languages.html"&gt;"Stupid templating languages"&lt;/a&gt;, to &lt;a href="http://lucumr.pocoo.org/2010/12/5/not-so-stupid-template-languages/"&gt;"Not So Stupid Template Languages"&lt;/a&gt;, &lt;a href="http://techspot.zzzeek.org/2010/12/04/in-response-to-stupid-template-languages/"&gt;"In Response to "Stupid Template Languages""&lt;/a&gt;, and discussed more on reddit &lt;a href="http://www.reddit.com/r/Python/comments/eh3up/in_response_to_stupid_template_languages_by_mike/"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In the world of Electronic Design Automation and integrating complex EDA software tools, the EDA companies,, on the whole, have embraced TCL as their scripting tool, but sometimes I have inherited a complex design flow, where, to add control, and later flexibility within that control, proprietary initialization file formats and their parsers have grown by adding their own macro language type features and grown to need the power of something like the bash shell.&amp;nbsp; Rather than ditching their proprietary lashed-together, one-off languages for something that is tried and tested and used/debugged by many - such as bash/python/Tcl/Lua they persevere by adding more capability to an in-house, one project language.&lt;br /&gt;&lt;br /&gt;In the case of web templating the main argument is that given an intelligent web templating language, people are apt to migrate what should be business logic into the templates thereby muddying the separation of the business logic from the presentation layer. In the EDA field the problem is often the maintenance of the proprietary macro language and the proliferation of languages with which one needs to be familiar with in order to master a design environment.&lt;br /&gt;&lt;br /&gt;I won't comment more on the web templating debate, but when it comes to initialization file formats and or initialization scripts then you should stick to pre-existing standards such as .ini files or .csv files in the simpler cases, or use pre-existing scripting languages when you need more power such as bash scripts, Python, or Tcl.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-1166938932685970557?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/1166938932685970557/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2010/12/stupid-macro-languages.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1166938932685970557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1166938932685970557'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2010/12/stupid-macro-languages.html' title='Stupid macro languages'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-6819366939544844648</id><published>2010-10-04T16:06:00.000+01:00</published><updated>2010-10-04T16:06:30.844+01:00</updated><title type='text'>Ipod Tablet Opportunity?</title><content type='html'>The ipad is close to £600 in the UK. The ipod touch is less than £200. Given that there are &lt;a href="http://wirelesstechnews.com/2010/10/04/next-launch-cut-price-tablet/427"&gt;tablet&lt;/a&gt; computers on &lt;a href="http://www.storage.itproportal.com/portal/news/article/2010/10/4/85-7-inch-android-tablet-goes-sale-morgan-computers/"&gt;sale&lt;/a&gt; for less than £200, and inspired by news of a future ipod touch add-on that gives it &lt;a href="http://techcrunch.com/2010/09/28/ipod-touch-calls-pinger/"&gt;phone capabilities&lt;/a&gt;; how about designing a ten-inch screen,&amp;nbsp; extra battery, and phone dongle that would take a (partially disassembled), ipod touch &lt;i&gt;inside it&lt;/i&gt; and turn it into a ten inch ipad-alike?&lt;br /&gt;&lt;br /&gt;One problem I see is that you would probably have to provide a service to take the users ipod touch and disassemble/assemble it inside the ten-inch&amp;nbsp; "dock"; but Apple seems to provide a lot of monetary difference to try and make a profit.&lt;br /&gt;&lt;br /&gt;Just a thought! &lt;br /&gt; &lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-6819366939544844648?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/6819366939544844648/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2010/10/ipod-tablet-opportunity.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/6819366939544844648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/6819366939544844648'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2010/10/ipod-tablet-opportunity.html' title='Ipod Tablet Opportunity?'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-7262837625661472039</id><published>2010-09-18T08:34:00.004+01:00</published><updated>2010-09-19T08:24:23.470+01:00</updated><title type='text'>Regression runners: Whot! No Job Arrays?</title><content type='html'>I went from running regressions consisting of greater than 50K simulations nightly using Mentors QuestaSim, where I had written the regression framework and results preparation myself - to my first real Cadece &lt;a href="http://www.cadence.com/products/fv/enterprise_manager/pages/default.aspx"&gt;vManager &lt;/a&gt;controlled regression project.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;I should explain to my readers who usually see Python focused blog entries, that  this is about the running of large regressions on compute farms for verifying ASICs (although my regression runner used Python extensively). &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I did like the more minimal, HTML-based GUI on the tool - I've spent too much time creating work-arounds for flashy GUI's that don't work outside a narrow area, and so know they can be a double-edged sword. The tool needs a lot of configuration behind the scenes, and they have chosen to do this using their own vsif file format which seems to me to be a design fault. If they had gone for XML (gosh is that me advocating the use of XML), or YAML, then the format would  be as readable and more easily used in other tools - no tool is an island in a design flow.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The main problem with vManager, is with its use of &lt;a href="http://www.platform.com/workload-management/high-performance-computing"&gt;LSF&lt;/a&gt;. &lt;/span&gt;LSF is a separate tool used to harness a network of computers into a compute cluster. LSF runs jobs on the cluster, managing the cluster to give maximum job throughput. vManager can turn each test that needs to run on the design into a possible series of jobs for LSF, but &lt;span style="font-weight: bold;"&gt;it fails to use &lt;a href="http://www-cecpv.u-strasbg.fr/Documentations/lsf/html/lsf6.1_admin/G_jobarrays.html"&gt;job arrays&lt;/a&gt;!&lt;/span&gt;  Job arrays allow for many similar jobs to be submitted and controlled as one array of jobs where the indexing of the individual job in the array is used to introduce a variation in the test.&lt;br /&gt;&lt;br /&gt;In my regression framework I created arrays of over 100K jobs, that took several weeks to run, and all the time that the job array at the heart of my regression was running, IT could change the parameters of my job array to control its use of resources according to changing priorities; scale back the maximum number of concurrent simulations during the 9-till-5; ramp up during weekends, (or stop then resume for a 'planned' license outage). IT had all the information they need to show the&lt;span style="font-style: italic;"&gt; full extent&lt;/span&gt; of the regression and LSF will give the throughput of the array from which I can estimate completion times. Another engineer wishing to start a regression has immediate feedback of what else is running rather than a huge list of hundreds of jobs that it is difficult to make sense of.  In short, &lt;span style="font-weight: bold;"&gt;ASIC verification regressions map naturally to Job Arrays&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;The other problem I have with vManager is a missing feature: &lt;span style="font-weight: bold;"&gt;Randomization of the order that tests are run&lt;/span&gt;. If you have 100 tests to run on five areas of the design then it is natural to compose the vsif file that describes each test in some sort of orderly progression through the tests to run. When the regression is running and you are monitoring partial results then it is easier to get a sense of the overall result if the individual tests are run in a random order. In my regression framework I generated tests in an order, then randomized the set of tests based on &lt;a href="http://docs.python.org/library/random.html"&gt;Pythons &lt;/a&gt;excellent&lt;a href="http://en.wikipedia.org/wiki/Mersenne_twister"&gt; Mersenne Twister&lt;/a&gt; implementation. By monitoring results during previous runs I could judge how much of a regression had to run if we needed results in a specified time.&lt;br /&gt;&lt;br /&gt;A bit of background (re?)search showed that Mentor have their own regression running framework, that also doesn't use job arrays; and that the &lt;a href="http://wikis.sun.com/display/gridengine62u2/Submitting+Array+Jobs"&gt;Grid Engine&lt;/a&gt; cluster management tool supports job arrays.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-7262837625661472039?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/7262837625661472039/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2010/09/regression-runners-whot-no-job-arrays.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/7262837625661472039'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/7262837625661472039'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2010/09/regression-runners-whot-no-job-arrays.html' title='Regression runners: Whot! No Job Arrays?'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-1622176709999237253</id><published>2010-08-23T18:00:00.007+01:00</published><updated>2010-08-23T22:43:55.945+01:00</updated><title type='text'>McCarthy's amb operator in Python</title><content type='html'>From what I can gather after some reading [&lt;a href="http://www.randomhacks.net/articles/2005/10/11/amb-operator"&gt;1&lt;/a&gt;], [&lt;a href="http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-28.html#%_sec_4.3"&gt;2&lt;/a&gt;], [&lt;a href="http://rosettacode.org/wiki/Amb"&gt;3&lt;/a&gt;]; McCarthy's amb operator, would allow you to give the possible values for variables; then give functions that constrain the values; and finally extract values for those variables that satisfy the constraints just by calling amb without any arguments.&lt;br /&gt;&lt;br /&gt;I decided to work backwards from how I thought it should be used to an implementation.&lt;br /&gt;&lt;br /&gt;Given the problem of finding Pythagorean triples for integers &lt;=10, i.e &lt;span style="font-weight: bold;"&gt;define three variables x, y, and z that can have values 1..10  subject to the constraint that x*x +y*y == z*z. What are the possible values of x, y and z that satisfy the constraint?&lt;/span&gt;  For an amb-type solution adapted a little to python, being amb-like is all in the way that the problem is expressed. I would like to write something like:  &lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;("&lt;span style="color: rgb(106, 90, 205);"&gt;\n&lt;/span&gt;&lt;span style="color: rgb(255, 0, 255);"&gt;Small Pythagorean triples problem&lt;/span&gt;")&lt;br /&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;# Set rage of global variables&lt;/span&gt;&lt;br /&gt;x = amb(range(1,11))&lt;br /&gt;y = amb(range(1,11))&lt;br /&gt;z = amb(range(1,11))&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;# Extract solutions to global variables and print&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; _dummy &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; amb( &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;lambda&lt;/b&gt;&lt;/span&gt; x, y, z: x*x + y*y == z*z ):&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt; x, y, z&lt;br /&gt;&lt;/pre&gt;I took a little liberty in the way I had seen other implementations work, as I had seen examples where the call of amb with an argument of a function just set things up and 'registered' the function, then subsequent calls of amb() without any arguments, would set the global variables used in the lambda function to successive values that satisfy the constraint. I reasoned that calls to amb after registering the constraint function should follow the Python iterator protocol ( with an __iter__ and a next method), so all the values, if any, could be accessed in a loop. I liked the idea of automatically setting global variables so decided to give that a go (but I was prepared to jettison this setting global variables if it proved long-winded).&lt;br /&gt;&lt;br /&gt;The solution follows. To modify global names, I noted that functions have f.func_globals which is the globals environment in which the function was created. I get this from the lambda expression. I also cheat a little in requiring the parameter names of the constraint function to be the global names that were previously assigned value ranges.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(160, 32, 240);"&gt;import&lt;/span&gt; itertools &lt;span style="color: rgb(160, 32, 240);"&gt;as&lt;/span&gt; _itertools&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;Amb&lt;/span&gt;(object):&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;__init__&lt;/span&gt;(self):&lt;br /&gt;     self._names2values   = {}       &lt;span style="color: rgb(0, 0, 255);"&gt;# set of values for each global name&lt;/span&gt;&lt;br /&gt;     self._func           = None     &lt;span style="color: rgb(0, 0, 255);"&gt;# Boolean constraint function&lt;/span&gt;&lt;br /&gt;     self._valueiterator  = None     &lt;span style="color: rgb(0, 0, 255);"&gt;# itertools.product of names values&lt;/span&gt;&lt;br /&gt;     self._funcargnames   = None     &lt;span style="color: rgb(0, 0, 255);"&gt;# Constraint parameter names&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;__call__&lt;/span&gt;(self, arg=None):&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; hasattr(arg, '&lt;span style="color: rgb(255, 0, 255);"&gt;func_globals&lt;/span&gt;'):&lt;br /&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;##&lt;/span&gt;&lt;br /&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;## Called with a constraint function. &lt;/span&gt;&lt;br /&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;##&lt;/span&gt;&lt;br /&gt;         globls = arg.func_globals&lt;br /&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;# Names used in constraint&lt;/span&gt;&lt;br /&gt;         argv = arg.__code__.co_varnames[:arg.__code__.co_argcount]&lt;br /&gt;         &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; name &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; argv:&lt;br /&gt;             &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; name &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;not&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; self._names2values:&lt;br /&gt;                 &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt; name &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; globls, &lt;span style="color: rgb(106, 90, 205);"&gt;\&lt;/span&gt;&lt;br /&gt;                        "&lt;span style="color: rgb(255, 0, 255);"&gt;Global name %s not found in function globals&lt;/span&gt;" % name&lt;br /&gt;                 self._names2values[name] = globls[name]&lt;br /&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;# Gather the range of values of all names used in the constraint&lt;/span&gt;&lt;br /&gt;         valuesets = [self._names2values[name] &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; name &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; argv]&lt;br /&gt;         self._valueiterator = _itertools.product(*valuesets)&lt;br /&gt;         self._func = arg&lt;br /&gt;         self._funcargnames = argv&lt;br /&gt;         &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; self&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;elif&lt;/b&gt;&lt;/span&gt; arg &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;not&lt;/b&gt;&lt;/span&gt; None:&lt;br /&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;##&lt;/span&gt;&lt;br /&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;## Assume called with an iterable set of values&lt;/span&gt;&lt;br /&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;##&lt;/span&gt;&lt;br /&gt;         arg = frozenset(arg)&lt;br /&gt;         &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; arg&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/span&gt;:&lt;br /&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;##&lt;/span&gt;&lt;br /&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;## blank call tries to return next solution&lt;/span&gt;&lt;br /&gt;         &lt;span style="color: rgb(0, 0, 255);"&gt;##&lt;/span&gt;&lt;br /&gt;         &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; self._nextinsearch()&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;_nextinsearch&lt;/span&gt;(self):&lt;br /&gt;     arg = self._func&lt;br /&gt;     globls = arg.func_globals&lt;br /&gt;     argv = self._funcargnames&lt;br /&gt;     found = False&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; values &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; self._valueiterator:&lt;br /&gt;         &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; arg(*values):&lt;br /&gt;             &lt;span style="color: rgb(0, 0, 255);"&gt;# Set globals.&lt;/span&gt;&lt;br /&gt;             found = True&lt;br /&gt;             &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; n, v &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; zip(argv, values):&lt;br /&gt;                 globls[n] = v&lt;br /&gt;             &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;break&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;not&lt;/b&gt;&lt;/span&gt; found: &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;raise&lt;/b&gt;&lt;/span&gt; StopIteration&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; values&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;__iter__&lt;/span&gt;(self):&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; self&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;next&lt;/span&gt;(self):&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; self()&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; __name__ == '&lt;span style="color: rgb(255, 0, 255);"&gt;__main__&lt;/span&gt;':&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; True:&lt;br /&gt;     amb = Amb()&lt;br /&gt;&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;("&lt;span style="color: rgb(106, 90, 205);"&gt;\n&lt;/span&gt;&lt;span style="color: rgb(255, 0, 255);"&gt;Small Pythagorean triples problem:&lt;/span&gt;")&lt;br /&gt;     x = amb(range(1,11))&lt;br /&gt;     y = amb(range(1,11))&lt;br /&gt;     z = amb(range(1,11))&lt;br /&gt;&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; _dummy &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; amb( &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;lambda&lt;/b&gt;&lt;/span&gt; x, y, z: x*x + y*y == z*z ):&lt;br /&gt;         &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt; x, y, z&lt;br /&gt;&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; True:&lt;br /&gt;     amb = Amb()&lt;br /&gt;&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;("&lt;span style="color: rgb(106, 90, 205);"&gt;\n&lt;/span&gt;&lt;span style="color: rgb(255, 0, 255);"&gt;Rosetta Code Amb problem:&lt;/span&gt;")&lt;br /&gt;     w1 = amb(["&lt;span style="color: rgb(255, 0, 255);"&gt;the&lt;/span&gt;", "&lt;span style="color: rgb(255, 0, 255);"&gt;that&lt;/span&gt;", "&lt;span style="color: rgb(255, 0, 255);"&gt;a&lt;/span&gt;"])&lt;br /&gt;     w2 = amb(["&lt;span style="color: rgb(255, 0, 255);"&gt;frog&lt;/span&gt;", "&lt;span style="color: rgb(255, 0, 255);"&gt;elephant&lt;/span&gt;", "&lt;span style="color: rgb(255, 0, 255);"&gt;thing&lt;/span&gt;"])&lt;br /&gt;     w3 = amb(["&lt;span style="color: rgb(255, 0, 255);"&gt;walked&lt;/span&gt;", "&lt;span style="color: rgb(255, 0, 255);"&gt;treaded&lt;/span&gt;", "&lt;span style="color: rgb(255, 0, 255);"&gt;grows&lt;/span&gt;"])&lt;br /&gt;     w4 = amb(["&lt;span style="color: rgb(255, 0, 255);"&gt;slowly&lt;/span&gt;", "&lt;span style="color: rgb(255, 0, 255);"&gt;quickly&lt;/span&gt;"])&lt;br /&gt;&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; _dummy &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; amb( &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;lambda&lt;/b&gt;&lt;/span&gt; w1, w2, w3, w4: &lt;span style="color: rgb(106, 90, 205);"&gt;\&lt;/span&gt;&lt;br /&gt;                          w1[-1] == w2[0] &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(106, 90, 205);"&gt;\&lt;/span&gt;&lt;br /&gt;                          w2[-1] == w3[0] &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(106, 90, 205);"&gt;\&lt;/span&gt;&lt;br /&gt;                          w3[-1] == w4[0] ):&lt;br /&gt;         &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt; w1, w2, w3, w4&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; True:&lt;br /&gt;     amb = Amb()&lt;br /&gt;&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;("&lt;span style="color: rgb(106, 90, 205);"&gt;\n&lt;/span&gt;&lt;span style="color: rgb(255, 0, 255);"&gt;Amb problem from &lt;/span&gt;"&lt;br /&gt;         "&lt;span style="color: rgb(255, 0, 255);"&gt;&lt;a href="http://www.randomhacks.net/articles/2005/10/11/amb-operator:"&gt;http://www.randomhacks.net/articles/2005/10/11/amb-operator:&lt;/a&gt;&lt;/span&gt;")&lt;br /&gt;     x = amb([1, 2, 3])&lt;br /&gt;     y = amb([4, 5, 6])&lt;br /&gt;&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; _dummy &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; amb( &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;lambda&lt;/b&gt;&lt;/span&gt; x, y: x * y != 8 ):&lt;br /&gt;         &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt; x, y&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Program output looks like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Small Pythagorean triples problem:&lt;br /&gt;3 4 5&lt;br /&gt;4 3 5&lt;br /&gt;6 8 10&lt;br /&gt;8 6 10&lt;br /&gt;&lt;br /&gt;Rosetta Code Amb problem:&lt;br /&gt;that thing grows slowly&lt;br /&gt;&lt;br /&gt;Amb problem from http://www.randomhacks.net/articles/2005/10/11/amb-operator:&lt;br /&gt;1 4&lt;br /&gt;1 5&lt;br /&gt;1 6&lt;br /&gt;2 5&lt;br /&gt;2 6&lt;br /&gt;3 4&lt;br /&gt;3 5&lt;br /&gt;3 6&lt;/pre&gt;&lt;br /&gt;So, what you end up with is a declarative style of programming that is good as an exercise, but the solving algorithm is just a brute-force search over all permutations of possible inputs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-1622176709999237253?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/1622176709999237253/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2010/08/mccarthys-amb-operator-in-python.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1622176709999237253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1622176709999237253'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2010/08/mccarthys-amb-operator-in-python.html' title='McCarthy&apos;s amb operator in Python'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-685204547915407156</id><published>2010-07-24T08:38:00.003+01:00</published><updated>2010-07-24T09:18:20.633+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='europython EDA python'/><title type='text'>Python and EDA" at EuroPython</title><content type='html'>I &lt;a href="http://www.europython.eu/talks/talk_abstracts/index.html#talk13"&gt;presented &lt;/a&gt;on Thursday at EuroPython.  from the feedback at the end it seemed to go well.&lt;br /&gt;&lt;br /&gt;I've been told that the video will go up on the EuroPython web site by the end of next week which should be "interesting", as it would be the first time that I've watched myself present,  (and I don't do many conference presentations).&lt;br /&gt;&lt;br /&gt;What I found different was that I am used to presenting to others within the industry who know about RTL, VHDL, digital simulation, coverage, ... To address this Python-savvy audience I re-wrote a presentation on coverage ranking of Verilog/VHDL and cast it in terms of getting coverage of a Python program and ranking the coverage of three Python tests of the Python program. I then walked them through the ranking algorithm for this much simplified case, then tried to show some of the extra work that needs to be done for the real app.&lt;br /&gt;&lt;br /&gt;I decided to &lt;span style="font-weight: bold; font-style: italic;"&gt;not &lt;/span&gt;show a more polished version of the script. I showed a version where the main functionality could easily be split into more functions for readability; a psyco import does effectively nothing ... The reason was that what I showed was what I did to convince myself that the algorithm was correct and the speed was fast enough. I would have chucked it at this stage if it was slow. (The need was speed of execution as well as an acceptable algorithm for ranking).&lt;br /&gt;&lt;br /&gt;The finish was a "winding down" example of just what you can do when you decide to add documentation for a file format in with the program.&lt;br /&gt;&lt;br /&gt;I would like to thank my audience for making someone from an industry they may not have known, feel welcome; and the EuroPython organisers, especially John Pinner, for making it happen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-685204547915407156?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/685204547915407156/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2010/07/python-and-eda-at-europython.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/685204547915407156'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/685204547915407156'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2010/07/python-and-eda-at-europython.html' title='Python and EDA&quot; at EuroPython'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-5165107768867301274</id><published>2010-04-25T11:29:00.004+01:00</published><updated>2010-04-25T12:31:02.599+01:00</updated><title type='text'>More on binary search</title><content type='html'>I wrote this post: &lt;a href="http://paddy3118.blogspot.com/2010/04/am-i-one-of-10-of-programmers-who-can.html"&gt;Am  I one of the 10% of programmers who can write a binary search?&lt;/a&gt; as a reply to: &lt;a href="http://reprog.wordpress.com/2010/04/19/are-you-one-of-the-10-percent/"&gt;Are you one of the 10% of programmers who can write a binary search?&lt;/a&gt; by Mike Taylor.&lt;br /&gt;&lt;br /&gt;Since then, Mike has followed up with this: &lt;a href="http://reprog.wordpress.com/2010/04/23/testing-is-not-a-substitute-for-thinking-binary-search-part-3/"&gt;Testing is not a substitute for thinking&lt;/a&gt; which starts as a summary of the responses to the earlier post then moves on to his own views on testing.&lt;br /&gt;&lt;br /&gt;There is mention of some great work by &lt;a href="http://reprog.wordpress.com/2010/04/19/are-you-one-of-the-10-percent/#comment-2274"&gt;Darius Bacon&lt;/a&gt; who tests around twenty solutions gathered, painstakingly, from the comments. Darius' program is great work, but I thought that my testing &lt;span style="font-style: italic;"&gt;strategy &lt;/span&gt;might be better so modified his code to:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Add my attempt as function: paddy3118&lt;/li&gt;&lt;li&gt;Graft on a version of my test routine to his list of function variants&lt;/li&gt;&lt;/ol&gt;The delta code was added to the end and looks like the following:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color:#804040;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color:#008080;"&gt;paddy3118&lt;/span&gt;(data, item):&lt;br /&gt;   &lt;span style="color:#804040;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; &lt;span style="color:#804040;"&gt;&lt;b&gt;not&lt;/b&gt;&lt;/span&gt; data:&lt;br /&gt;       &lt;span style="color:#804040;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; -1&lt;br /&gt;   lo, hi = 0, len(data)-1&lt;br /&gt;   mid = (hi + lo) // 2&lt;br /&gt;   &lt;span style="color:#0000ff;"&gt;#print(lo,mid,hi)&lt;/span&gt;&lt;br /&gt;   &lt;span style="color:#804040;"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/span&gt; item != data[mid] &lt;span style="color:#804040;"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/span&gt; lo &amp;lt; hi:&lt;br /&gt;       lo, mid, hi = ( (lo, (lo + mid) // 2, mid)&lt;br /&gt;                       &lt;span style="color:#804040;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; item &amp;lt; data[mid] &lt;span style="color:#804040;"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;                       (mid+1, (hi + mid + 1) // 2, hi) )&lt;br /&gt;       &lt;span style="color:#0000ff;"&gt;#print(lo,mid,hi)&lt;/span&gt;&lt;br /&gt;   &lt;span style="color:#0000ff;"&gt;#0/0&lt;/span&gt;&lt;br /&gt;   &lt;span style="color:#804040;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; mid &lt;span style="color:#804040;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; item == data[mid] &lt;span style="color:#804040;"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/span&gt; -1&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;# PASSES test()&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;#test(paddy3118)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#0000ff;"&gt;#print sorted(k for k,v in globals().items() if type(v)==type(dan) and 'test' not in k)&lt;/span&gt;&lt;br /&gt;tests = (Max, aaron_maxwell, ashish_yadav, ben_gutierrez, clark,&lt;br /&gt;        dan, dave_r, ed_marshall, guilherme_melo, jasper, martin,&lt;br /&gt;        michael_fogleman, paddy3118, patrick_shields, paul,&lt;br /&gt;        rodrigo_b, scott, si, tomas_henriquez,&lt;br /&gt;        travis_wrapped, yc)&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#804040;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; __name__ == '&lt;span style="color:#ff00ff;"&gt;__main__&lt;/span&gt;':&lt;br /&gt;   totpass = 0&lt;br /&gt;   &lt;span style="color:#804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; t &lt;span style="color:#804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; tests:&lt;br /&gt;       fails =0&lt;br /&gt;       &lt;span style="color:#804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; dlimit &lt;span style="color:#804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; range(5):&lt;br /&gt;           data = list(range(dlimit))&lt;br /&gt;           &lt;span style="color:#804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; item &lt;span style="color:#804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; data:&lt;br /&gt;               &lt;span style="color:#804040;"&gt;&lt;b&gt;try&lt;/b&gt;&lt;/span&gt;:&lt;br /&gt;                   &lt;span style="color:#804040;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt; t(data, item) != -1&lt;br /&gt;               &lt;span style="color:#804040;"&gt;&lt;b&gt;except&lt;/b&gt;&lt;/span&gt;:&lt;br /&gt;                   fails += 1&lt;br /&gt;                   &lt;span style="color:#804040;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;("&lt;span style="color:#ff00ff;"&gt;  ERROR: %s FAIL when looking for %i in %r&lt;/span&gt;" %&lt;br /&gt;                         (t.func_name, item, data))&lt;br /&gt;                   &lt;span style="color:#804040;"&gt;&lt;b&gt;break&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;           &lt;span style="color:#804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; item &lt;span style="color:#804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; list(range(dlimit+1)):&lt;br /&gt;               &lt;span style="color:#804040;"&gt;&lt;b&gt;try&lt;/b&gt;&lt;/span&gt;:&lt;br /&gt;                   &lt;span style="color:#804040;"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt; t(data, item - 0.5) == -1&lt;br /&gt;               &lt;span style="color:#804040;"&gt;&lt;b&gt;except&lt;/b&gt;&lt;/span&gt;:&lt;br /&gt;                   fails += 1&lt;br /&gt;                   &lt;span style="color:#804040;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;("&lt;span style="color:#ff00ff;"&gt;  ERROR: %s FAIL as %3.1f is found in %r&lt;/span&gt;" %&lt;br /&gt;                         (t.func_name, item - 0.5, data))&lt;br /&gt;                   &lt;span style="color:#804040;"&gt;&lt;b&gt;break&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;           &lt;span style="color:#804040;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; fails:&lt;br /&gt;               &lt;span style="color:#804040;"&gt;&lt;b&gt;break&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;       &lt;span style="color:#804040;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; &lt;span style="color:#804040;"&gt;&lt;b&gt;not&lt;/b&gt;&lt;/span&gt; fails:&lt;br /&gt;           totpass += 1&lt;br /&gt;           &lt;span style="color:#804040;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;('&lt;span style="color:#ff00ff;"&gt;PASS: %s&lt;/span&gt;' % t.func_name)&lt;br /&gt;   &lt;span style="color:#804040;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;("&lt;span style="color:#6a5acd;"&gt;\n&lt;/span&gt;&lt;span style="color:#ff00ff;"&gt;%i/%i = %3.1f%% of functions pass&lt;/span&gt;" %&lt;br /&gt;         (totpass, len(tests), 100 * totpass / float(len(tests))))&lt;br /&gt;   '''&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;    PASS: Max&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;      ERROR: aaron_maxwell FAIL as -0.5 is found in []&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;    PASS: ashish_yadav&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;    PASS: ben_gutierrez&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;      ERROR: clark FAIL when looking for 0 in [0]&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;      ERROR: dan FAIL as -0.5 is found in []&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;      ERROR: dave_r FAIL as -0.5 is found in []&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;      ERROR: ed_marshall FAIL as -0.5 is found in []&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;      ERROR: guilherme_melo FAIL as -0.5 is found in []&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;      ERROR: jasper FAIL as -0.5 is found in []&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;      ERROR: martin FAIL as -0.5 is found in []&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;    PASS: michael_fogleman&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;    PASS: paddy3118&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;      ERROR: patrick_shields FAIL as -0.5 is found in []&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;    PASS: paul&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;      ERROR: rodrigo_b FAIL as -0.5 is found in []&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;      ERROR: scott FAIL as 1.5 is found in [0, 1, 2]&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;    PASS: si&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;      ERROR: tomas_henriquez FAIL when looking for 0 in [0, 1]&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;      ERROR: tomas_henriquez FAIL as 1.5 is found in [0, 1]&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;      ERROR: travis_wrapped FAIL when looking for 0 in [0]&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;    PASS: yc&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;    8/21 = 38.1% of functions pass&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;    &lt;/span&gt;'''&lt;br /&gt;&lt;/pre&gt;I find that i cannot agree with a lot of Mikes writing on test driven development as he seems to take an extreme position by separating test from development too much.&lt;br /&gt;When I was creating my function, i new that there were likely to be issues with off-by-ones when modifying range indices, and with handling of an empty data list. I chose to leave a 'mental place-holder' on the off-by-one issues as I thought i could easily write tests to exercise those corners and fill them in. The alternative would be to mentally interpret those corner cases to write them down in 'development', then still have to thoroughly test for them anyway.&lt;br /&gt;&lt;br /&gt;When writing my tests:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;I thought about the division of the range of the indices- and thought that I should use data of both odd and even lengths, and of sufficient length so that a range might be divided more than one.&lt;/li&gt;&lt;li&gt;I thought about all the comparisons - and decided to test for every item that is in the data.&lt;/li&gt;&lt;li&gt;I thought about the significant ways that an item might not be in the data - and decided to test for items between each and every data item, an items below the smallest and above the largest data items.&lt;/li&gt;&lt;/ul&gt;My paddy3118 function passed the Darius tests. My test routine &lt;span style="font-style: italic;"&gt;failed the  guilherme_melo test&lt;/span&gt; that was passed by Darius.&lt;br /&gt;&lt;br /&gt;The only conclusion I can bring, is that you need to do some white box testing, i.e. tests based on knowledge of the code too. Mike Taylor needs to recognise that imposing rigid categories might well  lead to extremes. I guess, their is no substitute for experience, but the unexperienced need to be given rules until they can learn enough to break them - Do we teach testing up front? Or not? (Remembering that given half a chance, testing by the novice will be inadequate).&lt;br /&gt;&lt;br /&gt;- Paddy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-5165107768867301274?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/5165107768867301274/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2010/04/more-on-binary-search.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/5165107768867301274'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/5165107768867301274'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2010/04/more-on-binary-search.html' title='More on binary search'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-2490940628165046148</id><published>2010-04-20T00:58:00.002+01:00</published><updated>2010-04-20T01:42:21.871+01:00</updated><title type='text'>Am I one of the 10% of programmers who can write a binary search?</title><content type='html'>I just read &lt;a href="http://reprog.wordpress.com/2010/04/19/are-you-one-of-the-10-percent/"&gt;this post&lt;/a&gt; where the blogger read a passage in a book that stated that only 10% of programmers could write a binary search from the description. I read up to the description of the binary search algorithm given in the book then thought I would try and implement it without finishing the reading of the rest of his blog entry.&lt;br /&gt;&lt;br /&gt;I took around half an hour to come up with the following:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;'''&lt;br /&gt;&lt;span style="color: rgb(255, 0, 255);"&gt; from: &lt;a href="http://reprog.wordpress.com/2010/04/19/are-you-one-of-the-10-percent/"&gt;http://reprog.wordpress.com/2010/04/19/are-you-one-of-the-10-percent/&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 255);"&gt; "Only 10% of programmers can write a binary search"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 255);"&gt;    Binary search solves the problem [of searching within a pre-sorted&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 255);"&gt;    array] by keeping track of a range within the array in which T&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 255);"&gt;    [i.e. the sought value] must be if it is anywhere in the array.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 255);"&gt;    Initially, the range is the entire array.  The range is shrunk by&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 255);"&gt;    comparing its middle element to T and discarding half the range.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 255);"&gt;    The process continues until T is discovered in the array, or until&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 255);"&gt;    the range in which it must lie is known to be empty.  In an&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(255, 0, 255);"&gt;    N-element table, the search uses roughly log(2) N comparisons.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;'''&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;binsearch&lt;/span&gt;(data, item):&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;not&lt;/b&gt;&lt;/span&gt; data:&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; False&lt;br /&gt; lo, hi = 0, len(data)-1&lt;br /&gt; mid = (hi + lo) // 2&lt;br /&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;#print(lo,mid,hi)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/span&gt; item != data[mid] &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/span&gt; lo &amp;lt; hi:&lt;br /&gt;     lo, mid, hi = ( (lo, (lo + mid) // 2, mid)&lt;br /&gt;                     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; item &amp;lt; data[mid] &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;                     (mid+1, (hi + mid + 1) // 2, hi) )&lt;br /&gt;     &lt;span style="color: rgb(0, 0, 255);"&gt;#print(lo,mid,hi)&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(0, 0, 255);"&gt;#0/0&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; item == data[mid]&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; __name__ == '&lt;span style="color: rgb(255, 0, 255);"&gt;__main__&lt;/span&gt;':&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; dlimit &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; range(5):&lt;br /&gt;     data = list(range(dlimit))&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;(data)&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; item &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; data:&lt;br /&gt;         &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt; binsearch(data, item)&lt;br /&gt;     &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; item &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; list(range(dlimit+1)):&lt;br /&gt;         &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;(item)&lt;br /&gt;         &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;not&lt;/b&gt;&lt;/span&gt; binsearch(data, item - 0.5)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;What happens with an empty list, and the little plus ones were added after I put in the assert statements, and I was satisfied enough to go on and complete the reading of the blog.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;Extra Restrictions&lt;/h2&gt;&lt;br /&gt;The blog goes on to state that the rules of test are that &lt;span style="font-weight: bold; font-style: italic;"&gt;no testing is to be done. A compiler can be used to ensure that their are no mechanical errors however.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Whoa! I was shocked and then secretly pleased. I use Python, and automatically added the tests as part of my development process. In no way did I think that I could do the task without passing some tests. I am still not saying that my implementation is correct, but I have tested for a lot of corner-cases such as:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Lists of length zero, one and more than one.&lt;/li&gt;&lt;li&gt;Items in every position of the list.&lt;/li&gt;&lt;li&gt;Items outside the list: less than, greater than and between all members of the list.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;I of course assume that items are comparable, and that data is sorted and subscript-able.&lt;br /&gt;&lt;br /&gt;All I can conclude is that if given the test and access to a compiler/interpreter of your choice then one should argue convincingly for testing any submission as you would never deign to submit any code as complete unless tested. If the testers remain unconvinced then it may be time to stick to your guns as you don't gain by lowering your standards, especially in an interview situation when you know that testing is right!&lt;br /&gt;&lt;br /&gt;P.S. I have since had a look at the code of the Python &lt;a href="http://www.koders.com/python/fid5F7B13874FCA7D732FE7DED77C059FBC09753BCE.aspx"&gt;bisect module&lt;/a&gt; and the algorithm given on &lt;a href="http://en.wikipedia.org/wiki/Binary_search#Implementations"&gt;Wikipedia&lt;/a&gt;, and they both seem more elegant than mine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-2490940628165046148?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/2490940628165046148/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2010/04/am-i-one-of-10-of-programmers-who-can.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/2490940628165046148'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/2490940628165046148'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2010/04/am-i-one-of-10-of-programmers-who-can.html' title='Am I one of the 10% of programmers who can write a binary search?'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-999207468062129712</id><published>2010-04-16T21:14:00.001+01:00</published><updated>2010-04-16T21:16:31.077+01:00</updated><title type='text'>The  Securities and Exchange Commission is to mandate the use of Python?</title><content type='html'>&lt;a href="http://jrvarma.wordpress.com/2010/04/16/the-sec-and-the-python/"&gt;Read on&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-999207468062129712?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/999207468062129712/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2010/04/securities-and-exchange-commission-is.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/999207468062129712'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/999207468062129712'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2010/04/securities-and-exchange-commission-is.html' title='The  Securities and Exchange Commission is to mandate the use of Python?'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-8644818096783790005</id><published>2010-04-10T14:14:00.002+01:00</published><updated>2010-04-10T14:23:03.110+01:00</updated><title type='text'>Smartphone Programming, Compare and Contrast</title><content type='html'>&lt;ul&gt;&lt;li&gt;Apple: &lt;a href="http://whydoeseverythingsuck.com/2010/04/steve-jobs-has-just-gone-mad.html"&gt;Steve Jobs Has Just Gone Mad&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Android: &lt;a href="http://code.google.com/p/android-scripting/"&gt;Android Scripting  Environment brings scripting languages to Android.&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Nokia: &lt;a href="http://opensource.nokia.com/projects/pythonfors60/"&gt;Python for S60&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;Do you still want that Ipad?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-8644818096783790005?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/8644818096783790005/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2010/04/smartphone-programming-compare-and.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/8644818096783790005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/8644818096783790005'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2010/04/smartphone-programming-compare-and.html' title='Smartphone Programming, Compare and Contrast'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-14504062175043901</id><published>2010-03-30T20:22:00.002+01:00</published><updated>2010-03-30T20:31:23.722+01:00</updated><title type='text'>Why Python?</title><content type='html'>Choose for yourself. Have a look at the examples on the &lt;a href="http://rosettacode.org/wiki/Main_Page"&gt;Rosetta Code&lt;/a&gt; site. You might like to follow the links to a few pages that I did the task descriptions for as they tend to be &lt;a href="http://rosettacode.org/wiki/User_talk:Paddy3118#Sample_output_on_10_March_2010"&gt;meatier tasks&lt;/a&gt;, but the examples in different languages should allow you to compare how different languages are used to solve the same problems.&lt;br /&gt;&lt;br /&gt;Unfortunately it cannot eliminate the issue of the competence of the individual programmers, but it might provide some useful info.&lt;br /&gt;&lt;br /&gt;Have fun :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-14504062175043901?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/14504062175043901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2010/03/why-python.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/14504062175043901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/14504062175043901'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2010/03/why-python.html' title='Why Python?'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-8373211093143051086</id><published>2010-03-16T20:43:00.006Z</published><updated>2010-03-16T21:13:13.432Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='python truth-table boolean'/><title type='text'>Expressions to Truth-Tables</title><content type='html'>I had a need for the data in the truth tables for a standard cell library, rather like that shown &lt;a href="http://docs.google.com/viewer?url=http://www.ece.virginia.edu/%7Emrs8n/cadence/SynthesisTutorials/tsmc18.pdf"&gt;here&lt;/a&gt; if you look at say page 35 you will see that for for every Cell it gives the cell name; the cell function as a boolean expression, and the truth-table for the cell.&lt;br /&gt;&lt;br /&gt;My cell library was an &lt;a href="http://www.infineon.com/"&gt;Infineon&lt;/a&gt; one and I had the pdf version of the databook. A quick squirt through pdftotext scrambled the truth table, but did preserve the boolean expression of each cells' function, and the cell name.&lt;br /&gt;&lt;br /&gt;I wrote a Python script that used a multi-line regexp to extract each cells info including the boolean equation.&lt;br /&gt;&lt;br /&gt;The equation from the Infineon databook uses +,*, and ! for boolean or, and and not operators, but also used lots of parentheses so that operator precedence did not affect the value of the infix expression. I realised that I could substitute for the Python bitwise operators, and form a python expression that could then be evaluated with appropriate values for any input names to create a truth table.&lt;br /&gt;&lt;br /&gt;I have left out the parsing and present a function to create a truth-table from a boolean expression:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(160, 32, 240);"&gt;from&lt;/span&gt; itertools &lt;span style="color: rgb(160, 32, 240);"&gt;import&lt;/span&gt; product&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;truthtable&lt;/span&gt;(expressionstring):&lt;br /&gt;  comp = compile(expressionstring.strip(), '&lt;span style="color: rgb(255, 0, 255);"&gt;-&lt;/span&gt;', '&lt;span style="color: rgb(255, 0, 255);"&gt;eval&lt;/span&gt;')&lt;br /&gt;  inputs = sorted(comp.co_names)&lt;br /&gt;  table = {}&lt;br /&gt;  &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; values &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; product( *([(0,1)] * len(inputs)) ):&lt;br /&gt;      valuedict = dict(zip(inputs, values))&lt;br /&gt;      answer = eval(comp, valuedict)&lt;br /&gt;      table[values] = answer&lt;br /&gt;  &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; expressionstring.strip(), inputs, table&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;pptable&lt;/span&gt;(ex, inputs, table):&lt;br /&gt;  &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;("&lt;span style="color: rgb(106, 90, 205);"&gt;\n&lt;/span&gt;&lt;span style="color: rgb(255, 0, 255);"&gt;TRUTH-TABLE FOR EXPRESSION: %r&lt;/span&gt;&lt;span style="color: rgb(106, 90, 205);"&gt;\n&lt;/span&gt;" % ex)&lt;br /&gt;  &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;('&lt;span style="color: rgb(255, 0, 255);"&gt; &lt;/span&gt;' + '&lt;span style="color: rgb(255, 0, 255);"&gt; &lt;/span&gt;'.join('&lt;span style="color: rgb(255, 0, 255);"&gt;%2s&lt;/span&gt;' % inp &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; inp &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; inputs) + '&lt;span style="color: rgb(255, 0, 255);"&gt;: OUTPUT&lt;/span&gt;')&lt;br /&gt;  fmt = '&lt;span style="color: rgb(255, 0, 255);"&gt;  %i&lt;/span&gt;' * len(inputs) + '&lt;span style="color: rgb(255, 0, 255);"&gt;:  %i&lt;/span&gt;'&lt;br /&gt;  &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; inp, ans &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; sorted(table.items()):&lt;br /&gt;      &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;(fmt % tuple(list(inp) + [ans]))&lt;br /&gt;&lt;br /&gt;ex, inputs, table = truthtable('&lt;span style="color: rgb(255, 0, 255);"&gt;(A &amp;amp; (~C)) | D&lt;/span&gt;')&lt;br /&gt;pptable(ex, inputs, table)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Going through function truthtable:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;compile() gives access to all the names in the compiled expression via attribute .co_names - this is all the names used in the expression.&lt;/li&gt;&lt;li&gt;product() allows you to quickly generate the 1/0 value combinations for the input names.&lt;/li&gt;&lt;li&gt;valuedict assigns a value to each name used in the expression.&lt;/li&gt;&lt;li&gt;eval evaluates the expression with the given values on each name&lt;/li&gt;&lt;/ul&gt;The output of the program is:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;TRUTH-TABLE FOR EXPRESSION: '(A &amp; (~C)) | D'&lt;br /&gt;&lt;br /&gt;  A  C  D: OUTPUT&lt;br /&gt;  0  0  0:  0&lt;br /&gt;  0  0  1:  1&lt;br /&gt;  0  1  0:  0&lt;br /&gt;  0  1  1:  1&lt;br /&gt;  1  0  0:  1&lt;br /&gt;  1  0  1:  1&lt;br /&gt;  1  1  0:  0&lt;br /&gt;  1  1  1:  1&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;- No separate parser required!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-8373211093143051086?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/8373211093143051086/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2010/03/expressions-to-truth-tables.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/8373211093143051086'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/8373211093143051086'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2010/03/expressions-to-truth-tables.html' title='Expressions to Truth-Tables'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-4340702225284504886</id><published>2010-03-04T22:59:00.006Z</published><updated>2010-03-04T23:17:17.418Z</updated><title type='text'>NPR 2002 Puzzle</title><content type='html'>A puzzle I copied from &lt;a href="http://www2.stetson.edu/%7Eefriedma/npr/"&gt;here &lt;/a&gt;via reddit:&lt;br /&gt;    &lt;span style="font-family:courier new;"&gt;1 2 3 4 5 6 7 8 9 = 2002&lt;/span&gt;&lt;br /&gt;Put any combination of plus, times, and spaces between the digits on the left to make the identify true.&lt;br /&gt;The answer was easy and was quick to compute.&lt;br /&gt;&lt;br /&gt;I realised that you could evaluate all expressions where the numbers 1 through nine are separated by the permutations of either a null string, '', '+' or '*'&lt;br /&gt;&lt;br /&gt;The answer came from the following:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&gt;&gt;&gt; from itertools import product&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&gt;&gt;&gt; eqn = '%s'.join(list('123456789')) + '==2002'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&gt;&gt;&gt; eqn&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;'1%s2%s3%s4%s5%s6%s7%s8%s9==2002'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&gt;&gt;&gt; for ops in product(*[['', '+', '*']]*8):&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    if eval(eqn % ops):&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        print(eqn % ops)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;1*23+45*6*7+89==2002&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;1*2+34*56+7+89==2002&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&gt;&gt;&gt; &lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So, there are two solutions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-4340702225284504886?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/4340702225284504886/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2010/03/npr-2002-puzzle.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/4340702225284504886'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/4340702225284504886'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2010/03/npr-2002-puzzle.html' title='NPR 2002 Puzzle'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-4835475413270175357</id><published>2009-12-03T04:44:00.002Z</published><updated>2009-12-03T04:58:50.261Z</updated><title type='text'>What is a first-class function?</title><content type='html'>There is a &lt;a href="http://en.wikipedia.org/wiki/Talk:First-class_function"&gt;debate &lt;/a&gt;about it on Wikipedia, and I am curious:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Does a language have first-class functions if it can use its functions to solve particular problems in a certain manner, or&lt;/li&gt;&lt;li&gt;Does a language have first-class functions if functions are just as flexible as other types in the language itself?&lt;/li&gt;&lt;/ol&gt;It probably means 1. above, as the second definition would omit most static languages, as they might be able, for example, to take textual input and change it into an internal representation of an integer, but not do the same for a function with similar effort. Someone who exclusively thinks in terms of static languages may not have realized a difference.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-4835475413270175357?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/4835475413270175357/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/12/what-is-first-class-function.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/4835475413270175357'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/4835475413270175357'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/12/what-is-first-class-function.html' title='What is a first-class function?'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-1890576172149041445</id><published>2009-11-28T08:38:00.001Z</published><updated>2009-11-28T08:40:28.826Z</updated><title type='text'>Hamming Numbers (and Perl: Why I just ignored it)</title><content type='html'>I had read the following post: &lt;a href="http://blog.newint.org/tech/2009/11/26/perl-dont-ingore-it/" target="_blank"&gt;"Perl: Love it, or hate it, but don’t ignore&lt;br /&gt;it."&lt;/a&gt;, by Phillip Smith, in which the author wishes Perl&lt;br /&gt;solutions were credited as much as solutions in other languages such as&lt;br /&gt;Python and Ruby.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I agreed that Perl wasn't mentioned as much as it was, and a day or so&lt;br /&gt;later I came across an example of why....&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I monitor whats happening in Python, and came across a new recipe added&lt;br /&gt;to Activestate code called: &lt;a href="http://code.activestate.com/recipes/576961/" target="_blank"&gt;"Recipe 576961: Technique for cyclical&lt;br /&gt;iteration"&lt;/a&gt;, by Raymond Hettinger. On first, second, and third&lt;br /&gt;readings, i just couldn't understand the need for the deferred_output&lt;br /&gt;function; the whole recipe remained opaque:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; text-decoration: underline;"&gt;Raymond's&lt;br /&gt;code:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="color:#a020f0;"&gt;from&lt;/span&gt; itertools &lt;span style="color:#a020f0;"&gt;import&lt;/span&gt; tee, chain, islice&lt;br /&gt;&lt;span style="color:#a020f0;"&gt;from&lt;/span&gt; heapq &lt;span style="color:#a020f0;"&gt;import&lt;/span&gt; merge&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#804040;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color:#008080;"&gt;hamming_numbers&lt;/span&gt;():&lt;br /&gt;   &lt;span style="color:#0000ff;"&gt;# Generate "5-smooth" numbers, also called "Hamming numbers"&lt;/span&gt;&lt;br /&gt;   &lt;span style="color:#0000ff;"&gt;# or "Regular numbers". See: &lt;a href="http://en.wikipedia.org/wiki/Regular_number"&gt;http://en.wikipedia.org/wiki/Regular_number&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;   &lt;span style="color:#0000ff;"&gt;# Finds solutions to 2**i * 3**j * 5**k for some integers i, j, and k.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="color:#804040;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color:#008080;"&gt;no_repeats&lt;/span&gt;(it):&lt;br /&gt;       last = None&lt;br /&gt;       &lt;span style="color:#804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; i &lt;span style="color:#804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; it:&lt;br /&gt;           &lt;span style="color:#804040;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; i &lt;span style="color:#804040;"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/span&gt; &lt;span style="color:#804040;"&gt;&lt;b&gt;not&lt;/b&gt;&lt;/span&gt; last:&lt;br /&gt;                &lt;span style="color:#804040;"&gt;&lt;b&gt;yield&lt;/b&gt;&lt;/span&gt; i&lt;br /&gt;                last = i&lt;br /&gt;&lt;br /&gt;&lt;span style="background-color: rgb(255, 255, 153);"&gt;  &lt;/span&gt;  &lt;span style="color:#804040;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color:#008080;"&gt;deferred_output&lt;/span&gt;():&lt;br /&gt;       &lt;span style="color:#804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; i &lt;span style="color:#804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; output:&lt;br /&gt;           &lt;span style="color:#804040;"&gt;&lt;b&gt;yield&lt;/b&gt;&lt;/span&gt; i&lt;br /&gt;&lt;br /&gt;   result, p2, p3, p5 = tee(deferred_output(), 4)&lt;br /&gt;   m2 = (2*x &lt;span style="color:#804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; x &lt;span style="color:#804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; p2) &lt;span style="color:#0000ff;"&gt;# multiples of 2&lt;/span&gt;&lt;br /&gt;   m3 = (3*x &lt;span style="color:#804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; x &lt;span style="color:#804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; p3) &lt;span style="color:#0000ff;"&gt;# multiples of 3&lt;/span&gt;&lt;br /&gt;   m5 = (5*x &lt;span style="color:#804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; x &lt;span style="color:#804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; p5) &lt;span style="color:#0000ff;"&gt;# multiples of 5&lt;/span&gt;&lt;br /&gt;   merged = merge(m2, m3, m5)&lt;br /&gt;   combined = chain([1], merged) &lt;span style="color:#0000ff;"&gt;# prepend a starting point&lt;/span&gt;&lt;br /&gt;   output = no_repeats(combined) &lt;span style="color:#0000ff;"&gt;# eliminate duplicates&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;   &lt;span style="color:#804040;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; result&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#804040;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; __name__ == '&lt;span style="color:#ff00ff;"&gt;__main__&lt;/span&gt;':&lt;br /&gt;   &lt;span style="color:#804040;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;(list(islice(hamming_numbers(), 1000))) &lt;span style="color:#0000ff;"&gt;# Show first 1000 hamming numbers&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I was hooked by the series however and so went looking for more&lt;br /&gt;information.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Perl&lt;/h3&gt;&lt;br /&gt;I came across a mention to the following page: &lt;a href="http://perl.plover.com/Stream/stream.html" target="_blank"&gt;"Infinite&lt;br /&gt;lists in Perl"&lt;/a&gt; by Mark Dominus which is copyright 1997 by the&lt;br /&gt;Perl Journal. Normally I wouldn't mention the article, as it spends&lt;br /&gt;more time creating an implementation of generators in Perl as it does&lt;br /&gt;on addressing the computation of Hamming numbers. It also uses the term&lt;br /&gt;"stream" instead of generators. but maybe this is down to the age of&lt;br /&gt;the article, i.e. 1997?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Haskell&lt;/h3&gt;&lt;br /&gt;Looking a bit further, I found this &lt;a href="http://dobbscodetalk.com/index.php?option=com_content&amp;amp;task=view&amp;amp;id=913&amp;amp;Itemid=85" target="_blank"&gt;Dr Dobbs Article&lt;/a&gt;, and this&lt;br /&gt;commented &lt;a href="http://www.answers.com/topic/haskell-programming-language-1#More_complex_examples" target="_blank"&gt;Haskell&lt;br /&gt;solution&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre class="de1"&gt;hamming &lt;span class="sy0"&gt;=&lt;/span&gt; 1 : &lt;span class="kw3"&gt;map&lt;/span&gt; &lt;span class="br0"&gt;(&lt;/span&gt;2&lt;span class="sy0"&gt;*&lt;/span&gt;&lt;span class="br0"&gt;)&lt;/span&gt; hamming `merge` &lt;span class="kw3"&gt;map&lt;/span&gt; &lt;span class="br0"&gt;(&lt;/span&gt;3&lt;span class="sy0"&gt;*&lt;/span&gt;&lt;span class="br0"&gt;)&lt;/span&gt; hamming `merge` &lt;span class="kw3"&gt;map&lt;/span&gt; &lt;span class="br0"&gt;(&lt;/span&gt;5&lt;span class="sy0"&gt;*&lt;/span&gt;&lt;span class="br0"&gt;)&lt;/span&gt; hamming&lt;br /&gt;    &lt;span class="kw1"&gt;where&lt;/span&gt; merge &lt;span class="br0"&gt;(&lt;/span&gt;x:xs&lt;span class="br0"&gt;)&lt;/span&gt; &lt;span class="br0"&gt;(&lt;/span&gt;y:ys&lt;span class="br0"&gt;)&lt;/span&gt;&lt;br /&gt;           &lt;span class="sy0"&gt;|&lt;/span&gt; x &lt;span class="sy0"&gt;&amp;lt;&lt;/span&gt; y &lt;span class="sy0"&gt;=&lt;/span&gt; x : xs `merge` &lt;span class="br0"&gt;(&lt;/span&gt;y:ys&lt;span class="br0"&gt;)&lt;/span&gt;&lt;br /&gt;           &lt;span class="sy0"&gt;|&lt;/span&gt; x &lt;span class="sy0"&gt;&amp;gt;&lt;/span&gt; y &lt;span class="sy0"&gt;=&lt;/span&gt; y : &lt;span class="br0"&gt;(&lt;/span&gt;x:xs&lt;span class="br0"&gt;)&lt;/span&gt; `merge` ys&lt;br /&gt;           &lt;span class="sy0"&gt;|&lt;/span&gt; &lt;span class="kw3"&gt;otherwise&lt;/span&gt; &lt;span class="sy0"&gt;=&lt;/span&gt; x : xs `merge` ys&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The Haskell solution lead me to think that maybe Python has an issue&lt;br /&gt;with defining recursive generators, and some experimentation lead me to&lt;br /&gt;believe that yep, maybe that was why Raymond has the deferred_output&lt;br /&gt;function.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;My Python&lt;/h3&gt;&lt;br /&gt;Since I have trouble understanding Raymond s I went away and wrote my&lt;br /&gt;own solution. It works. It can generate very large values of the&lt;br /&gt;sequence quite quickly. But it does need memory to store&lt;br /&gt; multiples:&lt;br /&gt;&lt;br /&gt;&lt;pre style="margin-left: 40px;"&gt;&lt;span style="color:#a020f0;"&gt;from&lt;/span&gt; itertools &lt;span style="color:#a020f0;"&gt;import&lt;/span&gt; islice&lt;br /&gt;&lt;span style="color:#a020f0;"&gt;from&lt;/span&gt; pprint &lt;span style="color:#a020f0;"&gt;import&lt;/span&gt; pprint &lt;span style="color:#a020f0;"&gt;as&lt;/span&gt; pp&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#804040;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color:#008080;"&gt;regularnumbergen&lt;/span&gt;(start = 1, multipliers=(2, 3, 5)):&lt;br /&gt;   '''&lt;span style="color:#6a5acd;"&gt;\&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;    Generates the Regular Number sequence defined here:&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;        &lt;a href="http://en.wikipedia.org/wiki/Regular_number"&gt;http://en.wikipedia.org/wiki/Regular_number&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;    The sequence starts with 1 and consists of all multiples by 2, 3, or 5&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;    of any number in the sequence in non-repeating, increasing  order.&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#ff00ff;"&gt;    &lt;/span&gt;'''&lt;br /&gt;   multiples = [[] &lt;span style="color:#804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; i &lt;span style="color:#804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; multipliers]&lt;br /&gt;   this = start&lt;br /&gt;   &lt;span style="color:#804040;"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/span&gt; True:&lt;br /&gt;       &lt;span style="color:#804040;"&gt;&lt;b&gt;yield&lt;/b&gt;&lt;/span&gt; this&lt;br /&gt;       &lt;span style="color:#0000ff;"&gt;# get multiples&lt;/span&gt;&lt;br /&gt;       &lt;span style="color:#804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; multiple, multiplier &lt;span style="color:#804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; zip(multiples, multipliers):&lt;br /&gt;           multiple.append(this * multiplier)&lt;br /&gt;       &lt;span style="color:#0000ff;"&gt;# get next&lt;/span&gt;&lt;br /&gt;       this = min(m[0] &lt;span style="color:#804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; m &lt;span style="color:#804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; multiples)&lt;br /&gt;       &lt;span style="color:#0000ff;"&gt;# remove this from multiples&lt;/span&gt;&lt;br /&gt;       &lt;span style="color:#804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; multiple &lt;span style="color:#804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; multiples:&lt;br /&gt;           &lt;span style="color:#804040;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; multiple[0] == this:&lt;br /&gt;               &lt;span style="color:#804040;"&gt;&lt;b&gt;del&lt;/b&gt;&lt;/span&gt; multiple[0]&lt;br /&gt;&lt;br /&gt;&lt;span style="color:#804040;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; __name__ == '&lt;span style="color:#ff00ff;"&gt;__main__&lt;/span&gt;':&lt;br /&gt;   &lt;span style="color:#804040;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;(list(islice(regularnumbergen(), 10)))&lt;/pre&gt;&lt;br /&gt;Generating the following large values of the sequence took only seconds:&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; print(list(islice(regularnumbergen(), 99999, 100001)))&lt;br /&gt;[290142196707511001929482240000000000000, 290237644800000000000000000000000000000]&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; &lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Wrapup&lt;/h3&gt;&lt;br /&gt;Well, I've learnt a bit more about generators, the limitatins in their&lt;br /&gt;Python implementation w.r.t. Haskel, and I've put more meat on why I&lt;br /&gt;tend to not quote much Perl In this case, i couldn't see the wood for&lt;br /&gt;the trees! (But &lt;a href="http://paddy3118.blogspot.com/2009/08/story-of-regexp-and-primes.html" target="_blank"&gt;I do quote Perl)&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-1890576172149041445?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/1890576172149041445/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/11/hamming-numbers-and-perl-why-i-just.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1890576172149041445'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1890576172149041445'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/11/hamming-numbers-and-perl-why-i-just.html' title='Hamming Numbers (and Perl: Why I just ignored it)'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-6512965331528773761</id><published>2009-11-12T08:20:00.003Z</published><updated>2009-11-12T08:28:01.179Z</updated><title type='text'>Curious about Go.</title><content type='html'>Verilog is to SytemVerilog as C is to C++ .&lt;br /&gt;Verilog is to __________ as C is to &lt;a href="http://golang.org"&gt;Go &lt;/a&gt;?&lt;br /&gt;&lt;br /&gt;My main criticism of SytemVerilog was the size of the language compared to Verilog. Maybe we'll get SystemGo in five years time. (Or maybe Go itself will warp into some monstrosity; my crystal ball needs a new backlight).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-6512965331528773761?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/6512965331528773761/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/11/curious-about-go.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/6512965331528773761'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/6512965331528773761'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/11/curious-about-go.html' title='Curious about Go.'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-4739255624560760253</id><published>2009-11-04T18:55:00.004Z</published><updated>2009-11-05T03:44:46.464Z</updated><title type='text'>More Words From Hex Letters (with extra zero's)</title><content type='html'>&lt;span style="font-weight: bold; font-style: italic;"&gt;STOP PRESS! Someone commented that zeros could be used as ones so an update is at the bottom.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It was pointed out to me that I needn't restrict myself to four character words, and could use the number '1' as letter 'l', and the number '5' as the letter 'S'.&lt;br /&gt;&lt;br /&gt;So here is the program and output of words of four or more characters that can be made from hexadecimal characters.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(160, 32, 240);"&gt;import&lt;/span&gt; urllib&lt;br /&gt;&lt;br /&gt;words = urllib.urlopen('&lt;span style="color: rgb(255, 0, 255);"&gt;&lt;a href="http://www.puzzlers.org/pub/wordlists/unixdict.txt"&gt;http://www.puzzlers.org/pub/wordlists/unixdict.txt&lt;/a&gt;&lt;/span&gt;'&lt;br /&gt;                  ).read().split()&lt;br /&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;#len(words) == 25104&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;findwords&lt;/span&gt;(hexchars):&lt;br /&gt;hexchars = set(hexchars)&lt;br /&gt;hexwords = [w &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; w &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; words &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; 4 &amp;lt;= len(w) &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/span&gt; all(ch &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; hexchars &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; ch &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; w)]&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; hexwords&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;printwords&lt;/span&gt;(hexwords):&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; i &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; range(0, len(hexwords), 5):&lt;br /&gt;   &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt; ('&lt;span style="color: rgb(255, 0, 255);"&gt;  &lt;/span&gt;' + '&lt;span style="color: rgb(255, 0, 255);"&gt; &lt;/span&gt;'.join("&lt;span style="color: rgb(255, 0, 255);"&gt;%-8s&lt;/span&gt;" % w &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; w &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; hexwords[i:i+5]))&lt;br /&gt;&lt;br /&gt;hexchars = '&lt;span style="color: rgb(255, 0, 255);"&gt;abcdef&lt;/span&gt;'&lt;br /&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;#hexwords = findwords(hexchars)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;#print "\nHEXWORDS"&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;#printwords(hexwords)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 255);"&gt;# Now to use one: 1 as ell: l; and five: 5 as ess: s&lt;/span&gt;&lt;br /&gt;hexwords = findwords(hexchars + '&lt;span style="color: rgb(255, 0, 255);"&gt;ls&lt;/span&gt;')&lt;br /&gt;hexwords = [word.replace('&lt;span style="color: rgb(255, 0, 255);"&gt;s&lt;/span&gt;','&lt;span style="color: rgb(255, 0, 255);"&gt;5&lt;/span&gt;').replace('&lt;span style="color: rgb(255, 0, 255);"&gt;l&lt;/span&gt;','&lt;span style="color: rgb(255, 0, 255);"&gt;1&lt;/span&gt;') &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; word &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; hexwords]&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt; "&lt;span style="color: rgb(106, 90, 205);"&gt;\n&lt;/span&gt;&lt;span style="color: rgb(255, 0, 255);"&gt;HEXWORDS USING one: 1 AS ell: l; AND five: 5 AS ess: s&lt;/span&gt;"&lt;br /&gt;printwords(hexwords)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The list of words found have some gems, such as babble, for when you know your generating data that no one will read; baffle, baseball, blab, bleed, bless, (and blessed if it were in the dictionary), cabal, cascade, cease, debacle, decade, decease, (and should have deceased), false, flee, label, ...&lt;br /&gt;&lt;br /&gt;(Someone at work suggested we use 1abe1 or label to prefix a section of writes to a peripheral in an assembler prog which got me going).&lt;br /&gt;&lt;br /&gt;The words:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;HEXWORDS USING one: 1 AS ell: l; AND five: 5 AS ess: s&lt;br /&gt;aaa5     ababa    aba5e    abba5    abbe&lt;br /&gt;abed     abe1     ab1e     ab5ce55  accede&lt;br /&gt;acce55   added    add1e    ade1e    affab1e&lt;br /&gt;a1ba     a1ec     a1fa1fa  a11e1e   a55e55&lt;br /&gt;babb1e   babe     babe1    bade     baff1e&lt;br /&gt;ba1d     ba1e     ba11     ba11ad   ba11ed&lt;br /&gt;ba15a    ba5a1    ba5e     ba5eba11 ba5e1&lt;br /&gt;ba55     bead     bead1e   beebe    beef&lt;br /&gt;befa11   befe11   be1a     be11     be11a&lt;br /&gt;be11e    be55     be55e1   b1ab     b1ade&lt;br /&gt;b1ed     b1eed    b1e55    caba1    cab1e&lt;br /&gt;cafe     ca1eb    ca1f     ca11     ca11a&lt;br /&gt;ca5cade  ca5e     cea5e    cede     ce1ebe5&lt;br /&gt;ce11     c1ad     c1a55    dabb1e   dacca&lt;br /&gt;dada     dade     da1e     da11a5   dead&lt;br /&gt;deaf     dea1     debac1e  deba5e   decade&lt;br /&gt;deca1    decca    decea5e  deed     deface&lt;br /&gt;de11     de11a    ea5e     ea5e1    ecc1e5&lt;br /&gt;efface   effaceab1e e1ba     e11a     e15e&lt;br /&gt;fab1e    facade   face     fade     fa11&lt;br /&gt;fa15e    feeb1e   feed     fee1     fe11&lt;br /&gt;f1ea     f1ed     f1ee     f1eece   1abe1&lt;br /&gt;1ace     1ad1e    1a5e     1a55     1ead&lt;br /&gt;1eaf     1ea5e    1eed5    1e55     1e55ee&lt;br /&gt;5ab1e    5accade  5add1e   5afe     5a1ad&lt;br /&gt;5a1e     5a11e    5cab     5ca1a    5ca1d&lt;br /&gt;5ca1e    5ea1     5ecede   5eeab1e  5eed&lt;br /&gt;5eedbed  5e1f     5e11     51ab     51ed&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Additional Words with an 'o'&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Without Michaels comment I would have skipped all words that use zero for an o, so I made the following two changes:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;hexwords = findwords(hexchars + '&lt;span style="color: rgb(255, 0, 255);"&gt;lso&lt;/span&gt;')&lt;br /&gt;hexwords = [word.replace('&lt;span style="color: rgb(255, 0, 255);"&gt;s&lt;/span&gt;','&lt;span style="color: rgb(255, 0, 255);"&gt;5&lt;/span&gt;').replace('&lt;span style="color: rgb(255, 0, 255);"&gt;l&lt;/span&gt;','&lt;span style="color: rgb(255, 0, 255);"&gt;1&lt;/span&gt;').replace('&lt;span style="color: rgb(255, 0, 255);"&gt;o&lt;/span&gt;', '&lt;span style="color: rgb(255, 0, 255);"&gt;0&lt;/span&gt;') &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; word &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; hexwords]&lt;/pre&gt;&lt;br /&gt;And created the following extra words:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;  ab0de    acc01ade ad0be    a1c0a    a110cab1e&lt;br /&gt;a10e     a100f    a150     ba1b0a   ba550 &lt;br /&gt;b10b     b10c     b100d    b0bb1e   b0ca  &lt;br /&gt;b0de     b01d     b01dface b01e     b010  &lt;br /&gt;b05e     b055     caca0    c10d     c105e &lt;br /&gt;c0a1     c0a1e5ce c0bb     c0bb1e   c0b01 &lt;br /&gt;c0ca     c0c0     c0c0a    c0da     c0dd1e&lt;br /&gt;c0de     c0ed     c0ffee   c01a     c01d  &lt;br /&gt;c01e     c01055a1 c001     c05ec    dec0de&lt;br /&gt;d0bb5    d0dd     d0d0     d0ff     d01ce &lt;br /&gt;d01e     d011     d00d1e   d05e     ec01e &lt;br /&gt;ee0c     fa110ff  f10c     f10e     f100d &lt;br /&gt;f0a1     f0ca1    f01d     f00d     f001  &lt;br /&gt;f055     1a05     1a550    10ad     10af  &lt;br /&gt;10be     10b0     10ca1    10ca1e   10eb  &lt;br /&gt;10e55    101a     1011     1005e    1005e1eaf&lt;br /&gt;105ab1e  105e     1055     0a5e5    0be5e &lt;br /&gt;0b0e     0b5e55   0de55a   0ffa1    0ff10ad&lt;br /&gt;0ff5add1e 01af     00d1e5   0510     5caff01d&lt;br /&gt;5c0ff    5c01d    5eaf00d  510b     510e  &lt;br /&gt;50da     50fa     501ace   501d     501e  &lt;br /&gt;5010 &lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-4739255624560760253?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/4739255624560760253/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/11/more-words-from-hex-letters.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/4739255624560760253'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/4739255624560760253'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/11/more-words-from-hex-letters.html' title='More Words From Hex Letters (with extra zero&apos;s)'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-1315649810519635524</id><published>2009-11-01T07:53:00.003Z</published><updated>2009-11-01T08:35:06.105Z</updated><title type='text'>The 24 game</title><content type='html'>I've just created a new task over on Rosetta Code for the &lt;a href="http://rosettacode.org/wiki/24_game"&gt;24 game&lt;/a&gt;, and a separate task to create a &lt;a href="http://rosettacode.org/wiki/24_game_Player"&gt;solver &lt;/a&gt;for the game.&lt;br /&gt;&lt;br /&gt;It's a brute -force solver, but I find the game to be playable, so will get my sprogs to test their arithmetic skills with it later.&lt;br /&gt;&lt;br /&gt;I've just realised that the solver could be easily modified to solve "The numbers game" from the UK Channel 4 program &lt;a href="http://www.askoxford.com/wordgames/countdown/rules/?view=uk"&gt;Countdown&lt;/a&gt;. (Although their could be an issue with division as, when given the digits&lt;span style="font-family: courier new;"&gt; 3 3 7 7&lt;/span&gt;, the solver finds the solution:&lt;span style="font-family: courier new;"&gt; ( 3 + 3 / 7 ) * 7&lt;/span&gt; which may not be allowed by the countdown rules which state that &lt;span style="font-style: italic;"&gt;"only whole numbers may be used"&lt;/span&gt;).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-1315649810519635524?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/1315649810519635524/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/11/24-game.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1315649810519635524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1315649810519635524'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/11/24-game.html' title='The 24 game'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-7911102711214613277</id><published>2009-10-18T20:48:00.001+01:00</published><updated>2009-10-18T20:51:29.310+01:00</updated><title type='text'>Template for forking a Python program</title><content type='html'>I am doing a large regression run of some 30,000 simulations producing aroung 30 Gigs of logs to extract test parameter and simulation result from each.&lt;br /&gt;&lt;br /&gt;I have a  program that goes through each log in turn extracting results and this may take tens of minutes to complete.&lt;br /&gt;&lt;br /&gt;A future optimisation will be to extract pass/fail data for each regression run in the same job that ran the simulation, but at present, there may be changes to the pass/fail criteria, so it is run as a separate task after the regression simulations are all done.&lt;br /&gt;&lt;br /&gt;I normally run the log extraction process on an 8core, 16 thread machine with a fast connection to the file server, so was thinking of ways to parallelise the task.&lt;br /&gt;&lt;br /&gt;Enter &lt;a href="http://blog.doughellmann.com/2007/06/pymotw-os-part-4.html"&gt;this article&lt;/a&gt;, part of Doug Hellmann's PyMOTW series, about forking a process.&lt;br /&gt;&lt;br /&gt;After running it, I decided to expand on it to be more like my situation where you have a list of similar tasks to perform and want to split it between multiple processes via the Posix fork()  call. The following is just a framework - I hope to get time to acctually use it and see what the problems with it are.&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt; &lt;pre&gt;&lt;span style="color:#a52a2a;"&gt; 1 &lt;/span&gt;&lt;span style="color:#a020f0;"&gt;import&lt;/span&gt; os&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt; 2 &lt;/span&gt;&lt;span style="color:#a020f0;"&gt;import&lt;/span&gt; sys&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt; 3 &lt;/span&gt;&lt;span style="color:#a020f0;"&gt;import&lt;/span&gt; time&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt; 4 &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt; 5 &lt;/span&gt;maxprocs = 4 &lt;span style="color:#0000ff;"&gt;# procs - 1 children and the parent to do the work&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt; 6 &lt;/span&gt;jobarray = range(25) &lt;span style="color:#0000ff;"&gt;# Work to be split between proccesses&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt; 7 &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt; 8 &lt;/span&gt;&lt;span style="color:#a52a2a;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color:#008b8b;"&gt;do1job&lt;/span&gt;(job):&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt; 9 &lt;/span&gt; '&lt;span style="color:#ff00ff;"&gt;Process one item from the jobarray&lt;/span&gt;'&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;10 &lt;/span&gt; &lt;span style="color:#a52a2a;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; job&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;11 &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;12 &lt;/span&gt;&lt;span style="color:#a52a2a;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color:#008b8b;"&gt;picklesave&lt;/span&gt;(results):&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;13 &lt;/span&gt; '&lt;span style="color:#ff00ff;"&gt;save partialresults to file&lt;/span&gt;'&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;14 &lt;/span&gt; time.sleep(3)&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;15 &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;16 &lt;/span&gt;&lt;span style="color:#a52a2a;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color:#008b8b;"&gt;unpickleread&lt;/span&gt;(proc):&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;17 &lt;/span&gt; '&lt;span style="color:#ff00ff;"&gt;read partial results previousely saved by process number procc&lt;/span&gt;'&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;18 &lt;/span&gt; &lt;span style="color:#a52a2a;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; [] &lt;span style="color:#0000ff;"&gt;# dummy&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;19 &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;20 &lt;/span&gt;&lt;span style="color:#a52a2a;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color:#008b8b;"&gt;dowork&lt;/span&gt;(proc, maxprocs=maxprocs, jobarray=jobarray):&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;21 &lt;/span&gt; '&lt;span style="color:#ff00ff;"&gt; Split jobarray tasks between maxprocs by proci number&lt;/span&gt;'&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;22 &lt;/span&gt; time.sleep(proc) &lt;span style="color:#0000ff;"&gt;# convenience processing time &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;23 &lt;/span&gt; results = []&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;24 &lt;/span&gt; &lt;span style="color:#a52a2a;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; count, job &lt;span style="color:#a52a2a;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; enumerate(jobarray):&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;25 &lt;/span&gt; &lt;span style="color:#a52a2a;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; count % maxprocs == proc:&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;26 &lt;/span&gt; results.append(do1job(job))&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;27 &lt;/span&gt; picklesave(results)&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;28 &lt;/span&gt; &lt;span style="color:#a52a2a;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt; ("&lt;span style="color:#ff00ff;"&gt;Process: %i completed jobs: %s&lt;/span&gt;" % (proc, results))&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;29 &lt;/span&gt; &lt;span style="color:#a52a2a;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; results&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;30 &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;31 &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;32 &lt;/span&gt;&lt;span style="color:#a52a2a;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color:#008b8b;"&gt;createworkerchildren&lt;/span&gt;(maxprocs=maxprocs):&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;33 &lt;/span&gt; &lt;span style="color:#a52a2a;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; proc &lt;span style="color:#a52a2a;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; range(1, maxprocs):&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;34 &lt;/span&gt; &lt;span style="color:#a52a2a;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt; '&lt;span style="color:#ff00ff;"&gt;PARENT: Forking %s&lt;/span&gt;' % proc&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;35 &lt;/span&gt; worker_pid = os.fork()&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;36 &lt;/span&gt; &lt;span style="color:#a52a2a;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; &lt;span style="color:#a52a2a;"&gt;&lt;b&gt;not&lt;/b&gt;&lt;/span&gt; worker_pid:&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;37 &lt;/span&gt; '&lt;span style="color:#ff00ff;"&gt;This is a child process&lt;/span&gt;'&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;38 &lt;/span&gt; dowork(proc)&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;39 &lt;/span&gt; &lt;span style="color:#0000ff;"&gt;# Children exit here!&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;40 &lt;/span&gt; sys.exit(proc)&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;41 &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;42 &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;# Start and don't wait for child proccesses to do their work&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;43 &lt;/span&gt;createworkerchildren()&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;44 &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;45 &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;# Do parent processes share of the work&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;46 &lt;/span&gt;results = []&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;47 &lt;/span&gt;results += dowork(0) &lt;span style="color:#0000ff;"&gt;# don't have to pickle/unpickle Parent processes share&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;48 &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;49 &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;# wait for children&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;50 &lt;/span&gt;&lt;span style="color:#a52a2a;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; proc &lt;span style="color:#a52a2a;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; range(1, maxprocs):&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;51 &lt;/span&gt; &lt;span style="color:#a52a2a;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt; '&lt;span style="color:#ff00ff;"&gt;PARENT: Waiting for any child&lt;/span&gt;'&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;52 &lt;/span&gt; done = os.wait()&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;53 &lt;/span&gt; &lt;span style="color:#a52a2a;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt; '&lt;span style="color:#ff00ff;"&gt;PARENT: got child&lt;/span&gt;', done&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;54 &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;55 &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;# read and integrate child results&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;56 &lt;/span&gt;&lt;span style="color:#a52a2a;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; proc &lt;span style="color:#a52a2a;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; range(1, maxprocs):&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;57 &lt;/span&gt; results += unpickleread(proc)&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;58 &lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;59 &lt;/span&gt;&lt;span style="color:#0000ff;"&gt;# Calculate and print data summary&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;60 &lt;/span&gt;&lt;span style="color:#a52a2a;"&gt;&lt;b&gt;pass&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color:#a52a2a;"&gt;61 &lt;/span&gt;&lt;/pre&gt; &lt;/div&gt;&lt;br /&gt;Running the above on cygwin produced:&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span style="font-family: monospace;"&gt;bash$ &lt;span style="font-weight: bold;"&gt;python testfork.py&lt;/span&gt; &lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: monospace;"&gt;PARENT: Forking 1&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: monospace;"&gt;PARENT: Forking 2&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: monospace;"&gt;PARENT: Forking 3&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: monospace;"&gt;Process: 0 completed jobs: [0, 4, 8, 12, 16, 20, 24]&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: monospace;"&gt;PARENT: Waiting for any child&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: monospace;"&gt;Process: 1 completed jobs: [1, 5, 9, 13, 17, 21]&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: monospace;"&gt;PARENT: got child (5536, 256)&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: monospace;"&gt;PARENT: Waiting for any child&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: monospace;"&gt;Process: 2 completed jobs: [2, 6, 10, 14, 18, 22]&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: monospace;"&gt;PARENT: got child (3724, 512)&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: monospace;"&gt;PARENT: Waiting for any child&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: monospace;"&gt;Process: 3 completed jobs: [3, 7, 11, 15, 19, 23]&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: monospace;"&gt;PARENT: got child (4236, 768)&lt;/span&gt;&lt;br /&gt; &lt;span style="font-family: monospace;"&gt;bash$ &lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Notice how each child gets to do a fair poition of the jobs, (assuming all jobs need the same resources).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-7911102711214613277?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/7911102711214613277/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/10/template-for-forking-python-program.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/7911102711214613277'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/7911102711214613277'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/10/template-for-forking-python-program.html' title='Template for forking a Python program'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-5607446098450042460</id><published>2009-10-11T10:18:00.004+01:00</published><updated>2009-10-11T11:21:41.984+01:00</updated><title type='text'>Extend functools.partial to nested function calls?</title><content type='html'>I am reading the 1977 ACM Turing Award Lecture&lt;a href="http://www.stanford.edu/class/cs242/readings/backus.pdf"&gt; "Can Programming Be Liberated from the von Neumann Style? A Functional Style and Its Algebra of Programs"&lt;/a&gt; by John Backus.&lt;br /&gt;&lt;br /&gt;In section 5.1 he is contrasting a von Neumann program for inner product, which he gives as:&lt;pre&gt;c := 0&lt;br /&gt;for i := 1 step 1 until n do&lt;br /&gt;   c := c + c[i] x b[i]&lt;/pre&gt;The above converts quit nicely to the python equivalent:&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; v1, v2 = [1,2,3], [6,5,4]&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;ip_von_neumann&lt;/span&gt;(a, b):&lt;br /&gt;    c = 0&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;    for&lt;/b&gt;&lt;/span&gt; i &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; range(3):&lt;br /&gt;       c = c  + a[i] * b[i]&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;    return&lt;/b&gt;&lt;/span&gt; c&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; ip_von_neumann(v1, v2)&lt;br /&gt;28&lt;/pre&gt;Backus then goes on to contrast the von Neumann style with his functional program:&lt;pre&gt;Def Innerproduct ≡ (Insert +)o(ApplyToAll x)oTranspose&lt;/pre&gt; Which I converted to the following functional style Python:&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style="color: rgb(160, 32, 240);"&gt;from&lt;/span&gt; operator &lt;span style="color: rgb(160, 32, 240);"&gt;import&lt;/span&gt; add, mul&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style="color: rgb(160, 32, 240);"&gt;from&lt;/span&gt; functools &lt;span style="color: rgb(160, 32, 240);"&gt;import&lt;/span&gt; reduce &lt;span style="color: rgb(160, 32, 240);"&gt;as&lt;/span&gt; insert&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;ip_functional&lt;/span&gt;(*x):&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;    return&lt;/b&gt;&lt;/span&gt; insert(add, map(mul, *x))&lt;br /&gt;&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; ip_functional(v1, v2)&lt;br /&gt;28&lt;/pre&gt;&lt;br /&gt;Well, the Python  works, but it still has this name &lt;span style="font-weight: bold;"&gt;x &lt;/span&gt;that I would like to eliminate.&lt;br /&gt;&lt;br /&gt;I think I can go part of the way by using functools.partial. For example, for the single function call of map(mul, *x) I can do:&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style="color: rgb(160, 32, 240);"&gt;from&lt;/span&gt; functools &lt;span style="color: rgb(160, 32, 240);"&gt;import&lt;/span&gt; partial&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; p1 = partial(map, mul)&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/span&gt; p1(v1, v2) == map(mul, *(v1, v2))&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; map(mul, *(v1, v2))&lt;br /&gt;[6, 10, 12]&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/pre&gt; But I don't know how to go that extra step and remove x from the definition fully, ie end up with just some assignment like:&lt;pre&gt;ip_purefunctional = {A pure function of functions without any argument placeholders}&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;All help would be appreciated, Thanks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-5607446098450042460?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/5607446098450042460/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/10/extend-functoolspartial-to-nested.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/5607446098450042460'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/5607446098450042460'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/10/extend-functoolspartial-to-nested.html' title='Extend functools.partial to nested function calls?'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-1107998403290968238</id><published>2009-10-02T23:02:00.000+01:00</published><updated>2009-10-02T23:02:46.303+01:00</updated><title type='text'>The Otter Algorithm</title><content type='html'>I was reading about a Richard Dawkins program that through random mutation and selection of best fit, would gradually converge a random string into a target string. It is called the &lt;a href="http://en.wikipedia.org/wiki/Weasel_program#Weasel_algorithm"&gt;Weasel Program&lt;/a&gt;,and a rough outline of it is:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Start with a random string of 28 characters&lt;/li&gt;&lt;li&gt;Copy this string 100 times, with a 5% chance per character of that character being replaced with a random character&lt;/li&gt;&lt;li&gt;Compare each new string with the target "METHINKS IT IS LIKE A WEASEL", and give each a score&lt;/li&gt;&lt;li&gt;If any of the new strings has a perfect score, halt&lt;/li&gt;&lt;li&gt;Otherwise, take the highest scoring string, and go to step 2&lt;/li&gt;&lt;/ol&gt;After coding it up, I found it just would not converge to a final match for me. I suspected I had a mistake somewhere , but just did not like how long it was taking to converge. &lt;br /&gt;&lt;br /&gt;I decided to change things.&lt;br /&gt;&lt;br /&gt;It seemed to me that if you are further away from the ideal, then you should change more letters; and, after seeing the score for how good the current best string&amp;nbsp; is sometimes decrease, I made a modification to choose the best of the copies and the best string that they are mutations of.&lt;br /&gt;&lt;br /&gt;With that modification, convergence was swift.&lt;br /&gt;&lt;br /&gt;Oh, I call it the Otter program, as it is more than the Weasel.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The prog&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span style="color: #804040;"&gt; 1 &lt;/span&gt;&lt;br /&gt;&lt;span style="color: #804040;"&gt; 2 &lt;/span&gt;'''&lt;br /&gt;&lt;span style="color: #804040;"&gt; 3 &lt;/span&gt;&lt;span style="color: magenta;"&gt;From: &lt;a href="http://en.wikipedia.org/wiki/Weasel_program"&gt;http://en.wikipedia.org/wiki/Weasel_program&lt;/a&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #804040;"&gt; 4 &lt;/span&gt;&lt;span style="color: magenta;"&gt;      With modifications&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #804040;"&gt; 5 &lt;/span&gt;'''&lt;br /&gt;&lt;span style="color: #804040;"&gt; 6 &lt;/span&gt;&lt;br /&gt;&lt;span style="color: #804040;"&gt; 7 &lt;/span&gt;&lt;span style="color: #a020f0;"&gt;from&lt;/span&gt; string &lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; ascii_uppercase&lt;br /&gt;&lt;span style="color: #804040;"&gt; 8 &lt;/span&gt;&lt;span style="color: #a020f0;"&gt;from&lt;/span&gt; random &lt;span style="color: #a020f0;"&gt;import&lt;/span&gt; choice, random&lt;br /&gt;&lt;span style="color: #804040;"&gt; 9 &lt;/span&gt;&lt;br /&gt;&lt;span style="color: #804040;"&gt;10 &lt;/span&gt;target = list("&lt;span style="color: magenta;"&gt;METHINKS IT IS LIKE A WEASEL&lt;/span&gt;")&lt;br /&gt;&lt;span style="color: #804040;"&gt;11 &lt;/span&gt;chance = .05&lt;br /&gt;&lt;span style="color: #804040;"&gt;12 &lt;/span&gt;times  = 100&lt;br /&gt;&lt;span style="color: #804040;"&gt;13 &lt;/span&gt;&lt;br /&gt;&lt;span style="color: #804040;"&gt;14 &lt;/span&gt;charset      = ascii_uppercase + '&lt;span style="color: magenta;"&gt; &lt;/span&gt;'&lt;br /&gt;&lt;span style="color: #804040;"&gt;15 &lt;/span&gt;iterations   = 0&lt;br /&gt;&lt;span style="color: #804040;"&gt;16 &lt;/span&gt;highscore    = [choice(charset) &lt;span style="color: #804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; _ &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; range(len(target))]&lt;br /&gt;&lt;span style="color: #804040;"&gt;17 &lt;/span&gt;perfectscore = len(target)&lt;br /&gt;&lt;span style="color: #804040;"&gt;18 &lt;/span&gt;&lt;br /&gt;&lt;span style="color: #804040;"&gt;19 &lt;/span&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt; &lt;span style="color: teal;"&gt;score&lt;/span&gt;(trial):&lt;br /&gt;&lt;span style="color: #804040;"&gt;20 &lt;/span&gt;    &lt;span style="color: #804040;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt; sum(t==h &lt;span style="color: #804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; t,h &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; zip(trial, target))&lt;br /&gt;&lt;span style="color: #804040;"&gt;21 &lt;/span&gt;&lt;br /&gt;&lt;span style="color: #804040;"&gt;22 &lt;/span&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/span&gt; highscore != target:&lt;br /&gt;&lt;span style="color: #804040;"&gt;23 &lt;/span&gt;    thischance =  1-((perfectscore - score(highscore)) / perfectscore * (1 - chance))&lt;br /&gt;&lt;span style="color: #804040;"&gt;24 &lt;/span&gt;    &lt;span style="color: blue;"&gt;#thischance = chance&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #804040;"&gt;25 &lt;/span&gt;    iterations += 1&lt;br /&gt;&lt;span style="color: #804040;"&gt;26 &lt;/span&gt;    &lt;span style="color: #804040;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; iterations % 50 == 0:&lt;br /&gt;&lt;span style="color: #804040;"&gt;27 &lt;/span&gt;        &lt;span style="color: #804040;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt; (iterations, score(highscore), ''.join(highscore))&lt;br /&gt;&lt;span style="color: #804040;"&gt;28 &lt;/span&gt;    copies = [ [(ch &lt;span style="color: #804040;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; random() &amp;lt;= thischance &lt;span style="color: #804040;"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/span&gt; choice(charset)) &lt;span style="color: #804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; ch &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; highscore]&lt;br /&gt;&lt;span style="color: #804040;"&gt;29 &lt;/span&gt;               &lt;span style="color: #804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; _ &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; range(times) ]  + [highscore]&lt;br /&gt;&lt;span style="color: #804040;"&gt;30 &lt;/span&gt;    highscore = max(copies, key=score)&lt;br /&gt;&lt;span style="color: #804040;"&gt;31 &lt;/span&gt;&lt;span style="color: #804040;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt; (iterations, ''.join(highscore))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Function score at line 19 uses the fact that booleans True and False are also numbers and calculates how many characters are in the right position as its result.&lt;br /&gt;&lt;br /&gt;Line 23 modifies the amount of randomness injected, based on how bad the last &lt;i&gt;highscore &lt;/i&gt;was: Change more if you are further away from the target - less as you approach.&lt;br /&gt;Name &lt;i&gt;thischance &lt;/i&gt;is used in&amp;nbsp; line 28. random returns a float between 0.0 and 1.0. if it is less than &lt;i&gt;thischance &lt;/i&gt;then a particular character is not changed.&lt;br /&gt;&lt;br /&gt;The function for &lt;i&gt;thischance &lt;/i&gt;in line 23 is &lt;i&gt;equal to chance &lt;/i&gt;when no characters match, and 1.0 if all characters were to match. This forces less change as you approach the target string.&lt;br /&gt;&lt;br /&gt;Here is a little snippet to show how &lt;i&gt;thischance &lt;/i&gt;varies with the score (&lt;i&gt;sc&lt;/i&gt;):&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span style="color: #804040;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt; sc &lt;span style="color: #804040;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt; range(0,29,7):&lt;br /&gt;        &lt;span style="color: #804040;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;( "&lt;span style="color: magenta;"&gt;score=%2i, thischance=%5.2f&lt;/span&gt;" % (sc,&lt;br /&gt;                1-((perfectscore - sc) / perfectscore * (1 - chance))) )&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;score= 0, thischance= 0.05&lt;br /&gt;score= 7, thischance= 0.29&lt;br /&gt;score=14, thischance= 0.53&lt;br /&gt;score=21, thischance= 0.76&lt;br /&gt;score=28, thischance= 1.00&amp;nbsp;&lt;/pre&gt;&lt;pre&gt;&amp;nbsp;&lt;/pre&gt;In line 29 the addition of &lt;i&gt;highscore &lt;/i&gt;into &lt;i&gt;copies &lt;/i&gt;means that the max taken in line 30 can never decrease.&lt;br /&gt;&lt;br /&gt;P.S. The post is only tangentially linked to Darwinism. I am secure in the knowledge that my children's school teaches it, and I am not really interested in it being mentioned in any comments. Treat it just as a way to go from a random choice of letters and home in on a target string by&amp;nbsp; repeated random alterations, and selection of the "best".&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-1107998403290968238?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/1107998403290968238/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/10/otter-algorithm.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1107998403290968238'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1107998403290968238'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/10/otter-algorithm.html' title='The Otter Algorithm'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-3034800156678555513</id><published>2009-09-24T06:40:00.000+01:00</published><updated>2009-09-24T06:41:21.234+01:00</updated><title type='text'>Natural Sorting</title><content type='html'>Natural sorting orders items in some way that is more than just the&lt;br /&gt;order dictated by computer character codes. It is called natural&lt;br /&gt;because the new ordering is supposed to mean more to a human consumer&lt;br /&gt;than an ordering on base character codes .&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I guess, what is becoming the canonical example is the ordering of&lt;br /&gt;numbered files in a directory listing. A normal sorted directory&lt;br /&gt;listing might show:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;bash$ for (( i=0;&lt;br /&gt;i&amp;lt;111;i+=5)); do touch f$i.txt; done&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;bash$ ls -1&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f0.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f10.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f100.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f105.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f110.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f15.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f20.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f25.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f30.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f35.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f40.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f45.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f5.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f50.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f55.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f60.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f65.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f70.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f75.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f80.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f85.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f90.txt&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f95.txt&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;It might be more friendly if the files were ordered so that the numeric&lt;br /&gt;section increased steadily.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;In other situations, such as in Movie listings, you sometimes see&lt;br /&gt;common words such as "the" ignored for sorting purposes (or even&lt;br /&gt;transferred to the end of the item so "The Silence of the Lambs" would&lt;br /&gt;be listed as "Silence of the Lambs, The")&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Ignoring case, and treating white-space characters as the same - and&lt;br /&gt;multiple strings of whitespace characters as a single whitespace, might&lt;br /&gt;also be useful.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Since my initial tentative steps into working with non-ASCII characters&lt;br /&gt;I tried to consider sorting accented characters as if the accent was&lt;br /&gt;not present; ligatures as separate characters, and made a stab at&lt;br /&gt;tackling&amp;nbsp; what I call 'replacements' - where certain&lt;br /&gt;characters, such as the German &lt;a&lt;br /&gt; href="http://en.wikipedia.org/wiki/Scharfes_S"&gt;scharfes S&lt;/a&gt;&lt;br /&gt;might be sorted as SS,.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I had a quick stab at creating a natural sort routine &amp;nbsp;and&lt;br /&gt;added several natural sorting abilities. They might not all be useful&lt;br /&gt;at once, but it should be straight forward to pick and choose what you&lt;br /&gt;want n your natural sort..&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;As always, when working with non-ASCII character sets, I find it&lt;br /&gt;difficult to translate my working multi-byte Python program to HTML,&lt;br /&gt;but there should be enough surrounding information to ensure that any&lt;br /&gt;multi-byte character can be worked-out.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#804040"&gt;  1 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;  2 &lt;/font&gt;&lt;font color="#0000ff"&gt;# -*- coding: utf-8 -*-&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;  3 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Not Python 3.x (Can't compare str and int)&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;  4 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;  5 &lt;/font&gt;'''&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;  6 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    Natural sorting: Sorting of text that does more than rely on the&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;  7 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    order of individual characters codes to make the finding of&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;  8 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    individual strings easier for a human reader.&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;  9 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 10 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    Some 'natural' orderings might include:&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 11 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        1) Ignore leading, trailing and multiple adjacent spaces&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 12 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        2) All space types equivalent.&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 13 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        3) Sorting without regard to case.&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 14 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        4) Sorting numeric portions of strings in numeric order:&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 15 &lt;/font&gt;&lt;font color="#ff00ff"&gt;            foo9.txt before foo10.txt&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 16 &lt;/font&gt;&lt;font color="#ff00ff"&gt;            As well as ... x9y99 before x9y100, before x10y0&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 17 &lt;/font&gt;&lt;font color="#ff00ff"&gt;            ... (for any number of groups of integers in a string).&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 18 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        5) Title sorts: without regard to a leading, very common, word such&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 19 &lt;/font&gt;&lt;font color="#ff00ff"&gt;           as 'The' in "The thirty-nine steps".&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 20 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        6) Sort letters without regard to accents.&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 21 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        7) Sort ligatures as separate letters.&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 22 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        8) Replacements:&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 23 &lt;/font&gt;&lt;font color="#ff00ff"&gt;            Sort german scharfes S (ÃŸ) as ss&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 24 &lt;/font&gt;&lt;font color="#ff00ff"&gt;            Sort Å¿,  LATIN SMALL LETTER LONG S as s&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 25 &lt;/font&gt;&lt;font color="#ff00ff"&gt;            Sort Ê’,  LATIN SMALL LETTER EZH as s&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 26 &lt;/font&gt;&lt;font color="#ff00ff"&gt;            ...&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 27 &lt;/font&gt;'''&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 28 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 29 &lt;/font&gt;&lt;font color="#a020f0"&gt;from&lt;/font&gt; itertools &lt;font&lt;br /&gt; color="#a020f0"&gt;import&lt;/font&gt; groupby&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 30 &lt;/font&gt;&lt;font color="#a020f0"&gt;from&lt;/font&gt; unicodedata &lt;font&lt;br /&gt; color="#a020f0"&gt;import&lt;/font&gt; decomposition, name&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 31 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 32 &lt;/font&gt;commonleaders = ['&lt;font&lt;br /&gt; color="#ff00ff"&gt;the&lt;/font&gt;'] &lt;font color="#0000ff"&gt;# lowercase leading words to ignore&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 33 &lt;/font&gt;replacements = {'&lt;font&lt;br /&gt; color="#ff00ff"&gt;ÃŸ&lt;/font&gt;': '&lt;font color="#ff00ff"&gt;ss&lt;/font&gt;',  &lt;font&lt;br /&gt; color="#0000ff"&gt;# Map single char to replacement string&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 34 &lt;/font&gt;                '&lt;font&lt;br /&gt; color="#ff00ff"&gt;Å¿&lt;/font&gt;': '&lt;font color="#ff00ff"&gt;s&lt;/font&gt;',&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 35 &lt;/font&gt;                '&lt;font&lt;br /&gt; color="#ff00ff"&gt;Ê’&lt;/font&gt;': '&lt;font color="#ff00ff"&gt;s&lt;/font&gt;',&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 36 &lt;/font&gt;                }&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 37 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 38 &lt;/font&gt;hexdigits = set('&lt;font&lt;br /&gt; color="#ff00ff"&gt;0123456789abcdef&lt;/font&gt;')&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 39 &lt;/font&gt;decdigits = set('&lt;font&lt;br /&gt; color="#ff00ff"&gt;0123456789&lt;/font&gt;')   &lt;font&lt;br /&gt; color="#0000ff"&gt;# Don't use str.isnumeric&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 40 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 41 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;splitchar&lt;/font&gt;(c):&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 42 &lt;/font&gt;    '&lt;font&lt;br /&gt; color="#ff00ff"&gt; De-ligature. De-accent a char&lt;/font&gt;'&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 43 &lt;/font&gt;    de = decomposition(c)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 44 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; de:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 45 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#0000ff"&gt;# Just the words that are also hex numbers&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 46 &lt;/font&gt;        de = [d &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; d &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; de.split()&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 47 &lt;/font&gt;                  &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; all(c.lower()&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 48 &lt;/font&gt;                         &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; hexdigits &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; c &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; d)]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 49 &lt;/font&gt;        n = name(c, c).upper()&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 50 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#0000ff"&gt;# (Gosh it's onerous)&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 51 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; len(de)&amp;gt; 1 &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; '&lt;font&lt;br /&gt; color="#ff00ff"&gt;PRECEDE&lt;/font&gt;' &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; n:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 52 &lt;/font&gt;            &lt;font&lt;br /&gt; color="#0000ff"&gt;# E.g. Å‰  LATIN SMALL LETTER N PRECEDED BY APOSTROPHE&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 53 &lt;/font&gt;            de[1], de[0] = de[0], de[1]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 54 &lt;/font&gt;        tmp = [ unichr(int(k, 16)) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; k &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; de]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 55 &lt;/font&gt;        base, others = tmp[0], tmp[1:]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 56 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; '&lt;font&lt;br /&gt; color="#ff00ff"&gt;LIGATURE&lt;/font&gt;' &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; n:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 57 &lt;/font&gt;            &lt;font&lt;br /&gt; color="#0000ff"&gt;# Assume two character ligature&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 58 &lt;/font&gt;            base += others.pop(0)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 59 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt;:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 60 &lt;/font&gt;        base = c&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 61 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; base&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 62 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 63 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 64 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;sortkeygen&lt;/font&gt;(s):&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 65 &lt;/font&gt;    '''&lt;font&lt;br /&gt; color="#ff00ff"&gt;Generate 'natural' sort key for s&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 66 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 67 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    Doctests:&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 68 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        &amp;gt;&amp;gt;&amp;gt; sortkeygen('  some extra    spaces  ')&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 69 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        [u'some extra spaces']&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 70 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        &amp;gt;&amp;gt;&amp;gt; sortkeygen('CasE InseNsItIve')&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 71 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        [u'case insensitive']&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 72 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        &amp;gt;&amp;gt;&amp;gt; sortkeygen('The Wind in the Willows')&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 73 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        [u'wind in the willows']&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 74 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        &amp;gt;&amp;gt;&amp;gt; sortkeygen(u'&lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;\462&lt;/font&gt;&lt;font color="#ff00ff"&gt; ligature')&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 75 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        [u'ij ligature']&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 76 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        &amp;gt;&amp;gt;&amp;gt; sortkeygen(u'&lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;\335\375&lt;/font&gt;&lt;font color="#ff00ff"&gt; upper/lower case Y with acute accent')&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 77 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        [u'yy upper/lower case y with acute accent']&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 78 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        &amp;gt;&amp;gt;&amp;gt; sortkeygen('foo9.txt')&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 79 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        [u'foo', 9, u'.txt']&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 80 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        &amp;gt;&amp;gt;&amp;gt; sortkeygen('x9y99')&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 81 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        [u'x', 9, u'y', 99]&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 82 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    &lt;/font&gt;'''&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 83 &lt;/font&gt;    &lt;font color="#0000ff"&gt;# Ignore leading and trailing spaces&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 84 &lt;/font&gt;    s = unicode(s).strip()&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 85 &lt;/font&gt;    &lt;font color="#0000ff"&gt;# All space types are equivalent&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 86 &lt;/font&gt;    s = '&lt;font&lt;br /&gt; color="#ff00ff"&gt; &lt;/font&gt;'.join(s.split())&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 87 &lt;/font&gt;    &lt;font color="#0000ff"&gt;# case insentsitive&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 88 &lt;/font&gt;    s = s.lower()&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 89 &lt;/font&gt;    &lt;font color="#0000ff"&gt;# Title&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 90 &lt;/font&gt;    words = s.split()&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 91 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; len(words) &amp;gt; 1 &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; words[0] &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; commonleaders:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 92 &lt;/font&gt;        s = '&lt;font&lt;br /&gt; color="#ff00ff"&gt; &lt;/font&gt;'.join( words[1:])&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 93 &lt;/font&gt;    &lt;font color="#0000ff"&gt;# accent and ligatures&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 94 &lt;/font&gt;    s = ''.join(splitchar(c) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; c &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; s)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 95 &lt;/font&gt;    &lt;font color="#0000ff"&gt;# Replacements (single char replaced by one or more)&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 96 &lt;/font&gt;    s = ''.join( replacements.get(ch, ch) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; ch &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; s )&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 97 &lt;/font&gt;    &lt;font color="#0000ff"&gt;# Numeric sections as numerics&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 98 &lt;/font&gt;    s = [ int("".join(g)) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; isinteger &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt; "".join(g)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 99 &lt;/font&gt;          &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; isinteger,g &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; groupby(s, &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;lambda&lt;/b&gt;&lt;/font&gt; x: x &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; decdigits)]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;100 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;101 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; s&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;102 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;103 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;naturalsort&lt;/font&gt;(items):&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;104 &lt;/font&gt;    '''&lt;font&lt;br /&gt; color="#ff00ff"&gt; Naturally sort a series of strings&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;105 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;106 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    Doctests:&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;107 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        &amp;gt;&amp;gt;&amp;gt; naturalsort(['The Wind in the Willows','The 40th step more',&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;108 &lt;/font&gt;&lt;font color="#ff00ff"&gt;                         'The 39 steps', 'Wanda'])&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;109 &lt;/font&gt;&lt;font color="#ff00ff"&gt;        ['The 39 steps', 'The 40th step more', 'Wanda', 'The Wind in the Willows']&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;110 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;111 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    &lt;/font&gt;'''&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;112 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; sorted(items, key=sortkeygen)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;113 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;114 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;115 &lt;/font&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;116 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Extras...&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;117 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;118 &lt;/font&gt;'''&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;119 &lt;/font&gt;&lt;font color="#ff00ff"&gt;Help on built-in function decomposition in module unicodedata:&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;120 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;121 &lt;/font&gt;&lt;font color="#ff00ff"&gt;decomposition(...)&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;122 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    decomposition(unichr)&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;123 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;124 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    Returns the character decomposition mapping assigned to the Unicode&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;125 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    character unichr as string. An empty string is returned in case no&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;126 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    such mapping is defined.&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;127 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;128 &lt;/font&gt;&lt;font color="#ff00ff"&gt;Help on built-in function name in module unicodedata:&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;129 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;130 &lt;/font&gt;&lt;font color="#ff00ff"&gt;name(...)&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;131 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    name(unichr[, default])&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;132 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    Returns the name assigned to the Unicode character unichr as a&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;133 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    string. If no name is defined, default is returned, or, if not&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;134 &lt;/font&gt;&lt;font color="#ff00ff"&gt;    given, ValueError is raised.&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;135 &lt;/font&gt;'''&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;136 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;137 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;138 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;_temp&lt;/font&gt;():&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;139 &lt;/font&gt;    &lt;font color="#0000ff"&gt;# for c in u'\370\157\117\463\462\511\733\337\337':&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;140 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; c &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; u'&lt;span&lt;br /&gt; class="Constant"&gt;Ã¸oOÄ³Ä²Å‰Ç&lt;t_ ã=""&gt;ÃŸÃÃ½&lt;/t_&gt;&lt;/span&gt;':&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;141 &lt;/font&gt;        de = decomposition(c)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;142 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; de:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;143 &lt;/font&gt;            de = [d &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; d &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; de.split()&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;144 &lt;/font&gt;                      &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; all(c.upper()&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;145 &lt;/font&gt;                         &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; '&lt;font&lt;br /&gt; color="#ff00ff"&gt;0123456789ABCDEF&lt;/font&gt;' &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; c &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; d)]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;146 &lt;/font&gt;            n = name(c, c).upper()&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;147 &lt;/font&gt;            &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; len(de)&amp;gt; 1 &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; '&lt;font&lt;br /&gt; color="#ff00ff"&gt;PRECEDE&lt;/font&gt;' &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; n:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;148 &lt;/font&gt;                &lt;font&lt;br /&gt; color="#0000ff"&gt;# E.g. Å‰  LATIN SMALL LETTER N PRECEDED BY APOSTROPHE&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;149 &lt;/font&gt;                de[1], de[0] = de[0], de[1]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;150 &lt;/font&gt;            tmp = [ unichr(int(k, 16)) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; k &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; de]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;151 &lt;/font&gt;            base, others = tmp[0], tmp[1:]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;152 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt;:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;153 &lt;/font&gt;            base, others = c, []&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;154 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt;("&lt;font&lt;br /&gt; color="#ff00ff"&gt;%s %o %s&lt;/font&gt;&lt;font color="#6a5acd"&gt;\n&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;  %s  %s&lt;/font&gt;" %&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;155 &lt;/font&gt;                  (c,ord(c), name(c,'&lt;font&lt;br /&gt; color="#ff00ff"&gt;-&lt;/font&gt;'),&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;156 &lt;/font&gt;                   name(base, base),&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;157 &lt;/font&gt;                   '&lt;font&lt;br /&gt; color="#ff00ff"&gt; &lt;/font&gt;'.join(name(o,o) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; o &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; others)))&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;158 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;159 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;160 &lt;/font&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-3034800156678555513?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/3034800156678555513/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/09/natural-sorting.html#comment-form' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/3034800156678555513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/3034800156678555513'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/09/natural-sorting.html' title='Natural Sorting'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-5941293135324746230</id><published>2009-09-14T00:11:00.001+01:00</published><updated>2009-09-14T00:18:52.752+01:00</updated><title type='text'>Easy Command-line Parallelism</title><content type='html'>I am trying out a dual chip Xeon server with 8 cores that shows up as&lt;br /&gt;16 CPU's to Redhat Linux. I have my &lt;a target="_blank"&lt;br /&gt; href="http://paddy3118.blogspot.com/search?q=process"&gt;process&lt;br /&gt;runner&lt;/a&gt; script, that I use with a list of 100000 simulations&lt;br /&gt;to do overnight and have experimented with running different numbers of&lt;br /&gt;simulations in parallel to get good throughput.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;The process runner is good, I still use it, but I also wanted something&lt;br /&gt;for more general command-line use. for example, I have around 750&lt;br /&gt;directories, each containing files relating to one test. I organize the&lt;br /&gt;directories to have regular names, and am used to using shell for loops&lt;br /&gt;to process the dataset.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;For example, to gzip all the */transcript files I would do:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;foreach f (*/transcript)&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; gzip $f&lt;br&gt;end&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;(Yep, I know it's cshell, but that is the 'standard' at work.) &lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;This isn't making much use of the processing power at hand, so I went&lt;br /&gt;googling for a lightweight way to run such tasks in parallel.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I found two methods. One, to use make and its -P option to run several&lt;br /&gt;jobs in parallel would need the creation of a make file in each case,&lt;br /&gt;which is onerous. The other, which was new to me, rather than a&lt;br /&gt;forgotten feature, is that xargs has a -P option that does a similar&lt;br /&gt;thing - in combination with other options it will run &amp;nbsp;up to a&lt;br /&gt;given number of jobs in parallel:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;/bin/ls */transcript \&lt;br&gt;  | xargs -n1 -iX -P16 gzip X&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;The above lists all the files, pipes them to xargs which takes them one&lt;br /&gt;at a time (-n1) to form a job by substituting all occurrences of&lt;br /&gt;character X (-iX) in its arguments after its options. a maximum of 16&lt;br /&gt;(-P16) jobs are then run at any one time.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;When I want to simulate all 750 tests and create a coverage listing of&lt;br /&gt;each test I use xargs to call the bash shell and write something like:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;/bin/ls -d * \&lt;br&gt; | xargs -n1 -iX -P16 bash \&lt;br&gt; -c 'cd X &amp;amp;&amp;amp; vsim tb -c -coverage -do "coverage save -onexit -code t coverX.ucdb;do ../run.do" 2&amp;gt;&amp;amp;1 &amp;gt;/dev/null &amp;amp;&amp;amp; vcover report -file coverX.rpt coverX.ucdb 2&amp;gt;&amp;amp;1 &amp;gt;/dev/null'&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Yep, I do create such long monstrosities at times. It's because I am&lt;br /&gt;exploring new avenues at the moment, and things are likely to change,&lt;br /&gt;plus I need to know, and change, the details quite frequently. Although&lt;br /&gt;i do make a note of these long one-liners, (and keep a lot of history&lt;br /&gt;in my shells), I tend to only wrap things in a (bash), script when it&lt;br /&gt;becomes stable.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Note:&lt;/span&gt;&lt;br&gt;&lt;br /&gt;Following the links from the Wikipedia page, it seems that the -P&lt;br /&gt;option to xargs is not mandated by &lt;a&lt;br /&gt; href="http://www.opengroup.org/onlinepubs/9699919799/utilities/xargs.html"&gt;The&lt;br /&gt;Open Group&lt;/a&gt;, and does not appear in &lt;a&lt;br /&gt; href="http://docs.sun.com/app/docs/doc/816-5165/xargs-1?a=view"&gt;Suns&lt;br /&gt;version&lt;/a&gt; of xargs. I work in a mixed Solaris/Linux environment&lt;br /&gt;and have been using Unix for many years which makes it hard to keep up&lt;br /&gt;with the GNU extensions to what were familiar commands. But such is&lt;br /&gt;progress. Bring it on!&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-5941293135324746230?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/5941293135324746230/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/09/easy-command-line-parallelism.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/5941293135324746230'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/5941293135324746230'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/09/easy-command-line-parallelism.html' title='Easy Command-line Parallelism'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-8207576736313305708</id><published>2009-09-02T01:19:00.004+01:00</published><updated>2009-09-02T01:43:42.818+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='J-language programming-language.'/><title type='text'>J for a Py Guy</title><content type='html'>I just started reading a little bit more about the &lt;a href="http://www.jsoftware.com/"&gt;J programming language&lt;/a&gt;, after a lot of J activity on &lt;a href="http://rosettacode.org/"&gt;RC&lt;/a&gt;. I read the &lt;a href="http://www.jsoftware.com/help/jforc/foreword.htm"&gt;forward &lt;/a&gt;to "J for C Programmers" where I picked out an acknowledgement to Ken Iverson whose name &lt;a href="http://en.wikipedia.org/wiki/Kenneth_E._Iverson"&gt;rang a bell&lt;/a&gt;.&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;It seems that the J-language is from the APL family tree, but uses the ASCII character set and with later ideas from  &lt;a href="http://en.wikipedia.org/wiki/Function-level_programming" title="Function-level programming"&gt;function-level programming&lt;/a&gt; added. It is good for MIMD machines it says, so I wonder how well it works for todays cheaper four to sixteen cores in a box machines, or whether it needs massively MIMD machines to really shine?&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;br /&gt;It has tickled my fancy. I'll read some more of J for C.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-8207576736313305708?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/8207576736313305708/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/09/j-for-py-guy.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/8207576736313305708'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/8207576736313305708'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/09/j-for-py-guy.html' title='J for a Py Guy'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-4808004887186006000</id><published>2009-08-27T08:01:00.005+01:00</published><updated>2009-08-27T08:07:20.630+01:00</updated><title type='text'>Saw this, and thought of you...</title><content type='html'>Here in the UK, it is back-to-school time with many parents buying new school computers for their children. Windows 7 is not released yet, but here is an alternative opinion on the operating system from a competitor:&lt;br /&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;a href="http://windows7sins.org/#7"&gt;http://windows7sins.org/#7&lt;/a&gt;&lt;br&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-4808004887186006000?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/4808004887186006000/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/08/saw-this-and-thought-of-you.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/4808004887186006000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/4808004887186006000'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/08/saw-this-and-thought-of-you.html' title='Saw this, and thought of you...'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-4631255470606573330</id><published>2009-08-26T07:47:00.000+01:00</published><updated>2009-08-26T07:54:16.839+01:00</updated><title type='text'>The Story of the Regexp and the Primes</title><content type='html'>If you are all sitting comfortably, then I shall begin...&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Once upon a time, in a land an internet away, A python programmer was&lt;br /&gt;browsing the web when he StumbledUpon a post with a curious regular&lt;br /&gt;expression purporting to test numbers for primality. On further&lt;br /&gt;investigation, the regexp was attributed in more than one place to&lt;br /&gt;"Abigail" and took the form:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-weight: bold; font-family: monospace;"&gt;^1?$|^(11+?)\1+$&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Wanting to find out how it worked, the programmer was stumped, as all&lt;br /&gt;the posts mentioning the regexp asked you to visit a page with a&lt;br /&gt;supposedly excellent explanation of its inner workings, but the domain&lt;br /&gt;name was no longer present.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;The programmer decided to work it out for himself and came up with the&lt;br /&gt;following...&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;A prime number is a&lt;br /&gt;positive integer that is only divisible by itself and one. Zero and one&lt;br /&gt;are not prime.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Let's say a number N, greater than one,&amp;nbsp; is not prime. Then&lt;br /&gt;there exists two numbers, S and T, that when multiplied together equal&lt;br /&gt;N. We have:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;S x T = N&lt;br&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;Lets us further assume&lt;br /&gt;that T is greater than, or equal to S. (They can be swapped if&lt;br /&gt;necessary to make this so). Then a small bit of manipulation gives:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;(S x (T-1)) + S = N&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt; (You take one less S in&lt;br /&gt;the multiplication, then you need to add the S back).&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Lets swap the terms and write this as equation (a):&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-weight: bold;"&gt;S + (S x (T-1)) = N&lt;/span&gt;&amp;nbsp;&lt;span&lt;br /&gt; style="font-weight: bold;"&gt; when S,T,N are integers greater&lt;br /&gt;than one, and N is &lt;/span&gt;&lt;span&lt;br /&gt; style="font-style: italic; font-weight: bold;"&gt;not&lt;/span&gt;&lt;span&lt;br /&gt; style="font-weight: bold;"&gt; prime&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Abigail's regexp relies on representing integers as strings of that&lt;br /&gt;number of ones:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;Zero would be&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; ''&lt;br&gt;&lt;br /&gt;One would be &amp;nbsp;&amp;nbsp;&amp;nbsp; '1'&lt;br&gt;&lt;br /&gt;two becomes &amp;nbsp;&amp;nbsp;&amp;nbsp; '11'&lt;br&gt;&lt;br /&gt;and so on...&lt;br&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br&gt;&lt;br /&gt;The regexp gives a match if the string of ones does not represent a&lt;br /&gt;prime.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;To match zero or one occurrences of a 1 we use the first half of the&lt;br /&gt;regexp:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;^1?$&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;Where ^anchors the following to a match from the beginning of the&lt;br /&gt;string, ? will match zero or one occurrences of the preceding 1, and&lt;br /&gt;the&amp;nbsp; trailing $ matches the end of the string, i.e. it matches&lt;br /&gt;a string that contains only zero or one 1 characters.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Going back to equation (a), greater than one, is the same as two or&lt;br /&gt;more.&lt;br&gt;&lt;br /&gt;So S will be represented by two or more 1's - we don't know how many,&lt;br /&gt;but we do know that it is two or more. S, in a regexp, becomes&lt;br /&gt;something like:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;11+&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;1&amp;nbsp;followed by one or more 1's. S is less than or equal to T,&lt;br /&gt;which translates to using a less greedy form of the zero-or-one&lt;br /&gt;matcher, which is +? giving a representation of S as:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;11+?&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;We want to find S followed by T-1 identical copies of S, so lets form a&lt;br /&gt;group out of what matches S:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;(11+?)&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;Then by referring to this group, it is the first group in the regexp so&lt;br /&gt;can be referred to as \1, we can search for extra copies of the group&lt;br /&gt;by:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 80px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;\1+&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;S and its copies must cover the whole of the number so must start at ^&lt;br /&gt;and finish at $:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-weight: bold; font-family: monospace;"&gt;^(11+?)\1+$&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Together with the earlier regexp fraction that covers the numbers zero&lt;br /&gt;and one, they can be&amp;nbsp;or'd together to cover all non primes as&lt;br /&gt;the following:&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px; font-weight: bold;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;^1?$|^(11+?)\1+$&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;...Not knowing when to quit, the programmer opted to display some of&lt;br /&gt;his Python code that defines a primality tester using the regexp:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; import re&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; def isprime(n):&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return not re.match(r'&lt;span&lt;br /&gt; style="font-weight: bold;"&gt;^1?$|^(11+?)\1+$&lt;/span&gt;', '1' * n)&lt;br&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; [i for i in range(40) if isprime(i)]&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;And another function that shows S and T &amp;nbsp;from the regexp match:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; def is&lt;span&lt;br /&gt; style="font-weight: bold;"&gt;not&lt;/span&gt;prime(n):&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; notprime = re.match(r'^(1?)$|^(11+?)(\2+)$', '1' * n)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; if notprime:&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; if n &amp;lt;=1:&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; return (len( notprime.groups()[0]), )&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; else:&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; S, SxT1 = notprime.groups()[1:]&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; s = len(S)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; t = 1 + len(SxT1)//s&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; return (s,t)&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; else:&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&amp;nbsp;&amp;nbsp; return ()&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; [(i, isnotprime(i)) for i in range(15)]&lt;/pre&gt;&lt;br /&gt;&lt;pre&gt;[(0, (0,)), (1, (1,)), (2, ()), (3, ()), (4, (2, 2)), (5, ()), (6, (2, 3)), (7, ()), (8, (2, 4)), (9, (3, 3)), (10, (2, 5)), (11, ()), (12, (2, 6)), (13, ()), (14, (2, 7))]&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;... And so to bed.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;THE END.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-4631255470606573330?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/4631255470606573330/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/08/story-of-regexp-and-primes.html#comment-form' title='13 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/4631255470606573330'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/4631255470606573330'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/08/story-of-regexp-and-primes.html' title='The Story of the Regexp and the Primes'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>13</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-4381651796685983091</id><published>2009-08-08T09:54:00.000+01:00</published><updated>2009-08-08T09:55:58.113+01:00</updated><title type='text'>Words From Hex Letters</title><content type='html'>Enter the six hexadecimal letters into an &lt;a&lt;br /&gt; href="http://rosettacode.org/wiki/Anagrams#Python"&gt;anagram&lt;br /&gt;solver&lt;/a&gt; with a large scrabble-like &lt;a&lt;br /&gt; href="http://www.puzzlers.org/pub/wordlists/unixdict.txt"&gt;dictionary&lt;/a&gt;&lt;br /&gt;and you can generate a list of sixteen 'English' words that are also&lt;br /&gt;hex numbers. Good for sprinkling around your assembler listings to&lt;br /&gt;spice up the usual DEADBEEF. CAFÉABBÉ anyone? (confess over a coffee).&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;table&lt;br /&gt; style="text-align: left; width: 189px; height: 648px; margin-left: 40px;"&lt;br /&gt; border="1" cellpadding="2" cellspacing="2"&gt;&lt;br /&gt;  &lt;tbody&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td style="font-weight: bold;"&gt;WORD&lt;/td&gt;&lt;br /&gt;      &lt;td style="font-weight: bold;"&gt;MEANING&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;ABBE&lt;/td&gt;&lt;br /&gt;      &lt;td&gt;priest/clergyman&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;ABED&lt;/td&gt;&lt;br /&gt;      &lt;td&gt;in bed/ asleep&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;BABE&lt;/td&gt;&lt;br /&gt;      &lt;td&gt;infant&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;BADE&lt;/td&gt;&lt;br /&gt;      &lt;td&gt;bid, appeal&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;BEAD&lt;/td&gt;&lt;br /&gt;      &lt;td&gt;droplet&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;BEEF&lt;/td&gt;&lt;br /&gt;      &lt;td&gt;meat from cow. complaint.&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;CAFE&lt;/td&gt;&lt;br /&gt;      &lt;td&gt;small restaurant&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;CEDE&lt;/td&gt;&lt;br /&gt;      &lt;td&gt;surrender, abdicate&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;DADA&lt;/td&gt;&lt;br /&gt;      &lt;td&gt;father, dad&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;DADE&lt;/td&gt;&lt;br /&gt;      &lt;td&gt;&amp;lt;None found&amp;gt;&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;DEAD&lt;/td&gt;&lt;br /&gt;      &lt;td&gt;"pining for the &lt;a&lt;br /&gt; href="http://en.wikipedia.org/wiki/Fjords" title="Fjords"&lt;br /&gt; class="mw-redirect"&gt;fjords&lt;/a&gt;", stunned,&lt;br /&gt;&amp;nbsp;snuffed-it.&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;DEAF&lt;/td&gt;&lt;br /&gt;      &lt;td&gt;"hard of hearing"&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;DEED&lt;/td&gt;&lt;br /&gt;      &lt;td&gt;contract. accomplishment&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;FACE&lt;/td&gt;&lt;br /&gt;      &lt;td&gt;boldness. front&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;FADE&lt;/td&gt;&lt;br /&gt;      &lt;td&gt;disappear gradually.&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;FEED&lt;/td&gt;&lt;br /&gt;      &lt;td&gt;food. give food&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;  &lt;/tbody&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;P.S. Anyone have a meaning for DADE?&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-4381651796685983091?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/4381651796685983091/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/08/words-from-hex-letters.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/4381651796685983091'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/4381651796685983091'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/08/words-from-hex-letters.html' title='Words From Hex Letters'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-8395030729737165179</id><published>2009-08-02T18:32:00.000+01:00</published><updated>2009-08-02T18:33:15.545+01:00</updated><title type='text'>Facebook User-Clustering Puzzle</title><content type='html'>I came across the following &lt;a&lt;br /&gt; href="http://www.facebook.com/careers/puzzles.php?puzzle_id=8"&gt;puzzle&lt;/a&gt;&lt;br /&gt;at facebook. The task is to generate clusters of users based on who&lt;br /&gt;they send emails to, as extracted from their large log file.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;They give a strict format for the log file entries of:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;&amp;lt;date&amp;gt; '\t'&lt;br /&gt;&amp;lt;send email address&amp;gt; '\t' &amp;lt;to email address&amp;gt;&lt;/span&gt;&lt;br&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Some lines from the log might look like:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;Thu Dec 11 18:17:01 PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp; Finley.Cox@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; James.Harrison@xx.com&lt;br&gt;Thu Dec 11 18:21:01 PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp; Alfie.Khan@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Tyler.Blanchet@xx.com&lt;br&gt;Thu Dec 11 18:23:01 PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp; Harry.White@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp;Finley.Ali@xx.com&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;They then state that a cluster exists if everyone in the group has sent&lt;br /&gt;at least one email to everyone else in the group, so a cluster of users&lt;br /&gt;A B and C, would have had to have sent the following emails at some&lt;br /&gt;time:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;from: A to B&lt;br&gt;&lt;br /&gt;from: A to C&lt;br&gt;&lt;br /&gt;from: B to A&lt;br&gt;&lt;br /&gt;from: B to C&lt;br&gt;&lt;br /&gt;from: C to A&lt;br&gt;&lt;br /&gt;from: C to B&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;You should extract the clusters from the log and report only maximal&lt;br /&gt;clusters, i.e. in the example above, don't report A,C as a cluster if&lt;br /&gt;you are also reporting A,B,C.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Their is also a format for how clusters are to be reported:&lt;br&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;Only clusters of three or more people are to be reported&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Reports are to be printed to stdout.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;A cluster to a line.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Emails in the cluster to appear in sorted order; &lt;span&lt;br /&gt; style="font-style: italic;"&gt;separated&lt;/span&gt; by the&lt;br /&gt;two characters of a single comma followed by a single space.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;The lines of clusters to also be sorted on the characters&lt;br /&gt;appearing in the each cluster line.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;An output for some log file might look like:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;Aaron.Lewis@xx.com, Callum.Bennett@xx.com, Jayden.Mills@xx.com, Lucas.Lewis@xx.com, Matthew.Kennedy@xx.com&lt;br&gt;Alfie.Clarke@xx.com, Amy.Russell@xx.com, Connor.King@xx.com, Ethan.Thomas@xx.com, Joshua.Mcdonald@xx.com&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;The log files are said to be large.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;The above is the original problem, re-phrased.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h2&gt;The Reverse Problem&lt;/h2&gt;&lt;br /&gt;Early on in thinking about how to solve the problem I thought I would&lt;br /&gt;need &amp;nbsp;much more than the ten lines or so of sample log lines&lt;br /&gt;that they gave. I then thought that &lt;span&lt;br /&gt; style="font-style: italic;"&gt;generating&lt;/span&gt; a log&lt;br /&gt;file would be a good &amp;nbsp;task too and set out to solve that&lt;br /&gt;instead!&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I need to:&lt;br&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;Generate pseudo-random email addresses&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Generate clusters of users&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Generate a log from the clusters&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&amp;nbsp;And in that order too. When I have emails, I can create&lt;br /&gt;clusters of emails of different sizes, then expand the clusters into a&lt;br /&gt;log file structure, then print the log in the correct format.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;The code follows, this description.&lt;br&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;Line 9 is a debug remnant.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Although have only run the code in Python 3, I think it&lt;br /&gt;should work in Python 2.6 as well.&lt;br&gt;&lt;br /&gt;Lines 10-13 are because intern is moved to the sys module in Python 3.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Lines 15-40: I needed thousands of names so trawled WP for &lt;a&lt;br /&gt; href="http://en.wikipedia.org/wiki/List_of_most_popular_given_names"&gt;first&lt;br /&gt;names&lt;/a&gt; and &lt;a&lt;br /&gt; href="http://en.wikipedia.org/wiki/List_of_most_common_surnames"&gt;family&lt;br /&gt;names&lt;/a&gt; to create their product.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Lines 27 and 41: I intern'd the strings because I could -&lt;br /&gt;It's a possible premature &lt;span&lt;br /&gt; style="text-decoration: line-through;"&gt;ejacu&lt;/span&gt;&lt;br /&gt;optimization, but hey.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Lines 43-45: I will be building the log without times but&lt;br /&gt;in order, then adding times to the ordered log entries. to do that i&lt;br /&gt;need the time to start, and some possible time increments between log&lt;br /&gt;entries that I will randomly choose between.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Line 48; The size of cluster I generate is a random choice&lt;br /&gt;between the sizes mentioned here.. For example, a cluster size of 2, (&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;[2]*20&lt;/span&gt;), will&lt;br /&gt;predominate.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Line 51 controls how many &lt;span&lt;br /&gt; style="font-style: italic;"&gt;extra&lt;/span&gt; times an&lt;br /&gt;email might be sent between two people.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Line 53: &lt;span style="font-weight: bold;"&gt;namegen&lt;/span&gt;&lt;br /&gt;just pairs every first name with every family name. If you want more,&lt;br /&gt;you could use two first names for example, as well as extending the&lt;br /&gt;name lists. (or hyphenated family names). Anyone for Imogen Ethan&lt;br /&gt;Islam-Singh :-)&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Line 60: &lt;span style="font-weight: bold;"&gt;name2email&lt;/span&gt;&lt;br /&gt;changes the name from namegen into an email address string&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Lines 64-69: &lt;span style="font-weight: bold;"&gt;clustergen&lt;/span&gt;&lt;br /&gt;generates clustercount clusters of names. It randomly chooses how many&lt;br /&gt;names to put in each cluster using clustersizefreq;, then generates&lt;br /&gt;that many names per cluster. nextname feeds new names are required, and&lt;br /&gt;the sorts ensure the clusters are generated in the correct order for&lt;br /&gt;printing to satisfy the original puzzles output criteria.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Lines 71-74: clusterprint will correctly format and print&lt;br /&gt;the clustergen data structure.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;Lines 76-95: &lt;span style="font-weight: bold;"&gt;logggen&lt;/span&gt;.&lt;br /&gt;The largest function&amp;nbsp;&lt;/li&gt;&lt;br /&gt;  &lt;ul&gt;&lt;br /&gt;    &lt;li&gt;Line 81 creates a number of clusters&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Line 83 takes the cluster of users and turns each cluster&lt;br /&gt;in turn into the expanded set of correspondances between every member&lt;br /&gt;of the cluster, in order.&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Line 86 randomly duplicates some entries of the log using&lt;br /&gt;      &lt;span style="font-weight: bold;"&gt;repeatmsgfraction&lt;/span&gt;.&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Line 89 adds some authenticity by randomising the order&lt;br /&gt;of the emails&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Lines 91-94 add the time information to the log.&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;Line 95 returns the cluster info as well as the log.&lt;/li&gt;&lt;br /&gt;  &lt;/ul&gt;&lt;br /&gt;  &lt;li&gt;Lines 97-101 function logprint can correctly format and&lt;br /&gt;print the log data. Note the handling of the PST timezone in line 100.&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#804040"&gt; 1 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 2 &lt;/font&gt;'''&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 3 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Random Data generator for:&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 4 &lt;/font&gt;&lt;font color="#ff00ff"&gt; &lt;a&lt;br /&gt; href="http://www.facebook.com/careers/puzzles.php?puzzle_id=8"&gt;http://www.facebook.com/careers/puzzles.php?puzzle_id=8&lt;/a&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 5 &lt;/font&gt;'''&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 6 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 7 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 8 &lt;/font&gt;&lt;font color="#a020f0"&gt;import&lt;/font&gt; itertools, random, datetime&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 9 &lt;/font&gt;&lt;font color="#a020f0"&gt;from&lt;/font&gt; pprint &lt;font&lt;br /&gt; color="#a020f0"&gt;import&lt;/font&gt; pprint &lt;font&lt;br /&gt; color="#a020f0"&gt;as&lt;/font&gt; pp&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 10 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;try&lt;/b&gt;&lt;/font&gt;: &lt;font&lt;br /&gt; color="#0000ff"&gt;# Python 3/2 compatibility&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 11 &lt;/font&gt; &lt;font color="#a020f0"&gt;from&lt;/font&gt; sys &lt;font&lt;br /&gt; color="#a020f0"&gt;import&lt;/font&gt; intern&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 12 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;except&lt;/b&gt;&lt;/font&gt;:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 13 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;pass&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 14 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 15 &lt;/font&gt;firstname = '''&lt;font&lt;br /&gt; color="#ff00ff"&gt; &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 16 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Lola Imogen Jasmine Leah Daniel Isla Millie Lilly Benjamin Evie&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 17 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Finlay Ella Jacob Grace Jayden Freya Summer James Adam Henry&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 18 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Poppy Joshua Charlotte Thomas Noah Maisie Tyler Liam George Mason&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 19 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Matthew Joseph Nathan Stan Scarlett Jessica Samuel Leo William Olivia&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 20 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Ruby Isabella Emma Isabelle Charlie Phoebe Alfie Owen Erin Oscar&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 21 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Cameron Katie Harvey Aaron Ethan Lily Finley Riley Jamie Megan&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 22 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Caitlin Amy Connor Alexander Ben Eva Bethany Brooke Layla Harry&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 23 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Chloe Harrison Lauren Ava Oliver Mia Abigail Ellie Holly Jake&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 24 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Hannah Luke Molly Jack Amelia Dylan Alex Lucas Lucy Ryan&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 25 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Daisy Sophie Sophia Archie Callum Lewis Isabel Logan Max Emily&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 26 &lt;/font&gt;&lt;font color="#ff00ff"&gt; &lt;/font&gt;'''.split()&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 27 &lt;/font&gt;firstname = [intern(n) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; n &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; firstname]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 28 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 29 &lt;/font&gt;familyname = list(set( '''&lt;font&lt;br /&gt; color="#ff00ff"&gt; &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 30 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Wilson Russell Smith Phillips Dixon White Gill Brown Statham Oneill&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 31 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Harris Doyle James Ahmad Roberts Mann Moore Thomas Saunders Barker&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 32 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Bright Allen George Hill Jackson Rose Malley Mills Sheppard Mason&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 33 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Wright Holt Pearce Bull Richards Ward Lopez Mathey King Stone&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 34 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Johnson Baker Dupont Green Davis Blanchet Taylor Dean Donnelly Evans&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 35 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Woods Patel Meacher Simon Clarke Young Ellis Palmer Lynch Alexander&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 36 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Sutton Ahmed Adams Kennedy Davies Walker Austin Fernandez Mustafa Rodriguez&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 37 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Bennett Murray Powell Harrison Campbell Cole Khan Mcdonald Edwards Wood&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 38 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Thompson Singh Williams Power Price Watson Hall Jones Cox Chapman&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 39 &lt;/font&gt;&lt;font color="#ff00ff"&gt; Arnold Reid Garcia Morgan Mitchell Ali Lewis Stubbs Scott Islam&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 40 &lt;/font&gt;&lt;font color="#ff00ff"&gt; &lt;/font&gt;'''.split() ))&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 41 &lt;/font&gt;familyname = [intern(n) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; n &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; familyname]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 42 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 43 &lt;/font&gt;starttime = datetime.datetime(2008, 12, 11, 17, 53, 1, 0)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 44 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Choice of delta times between log entries&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 45 &lt;/font&gt;timedeltafreq = [ datetime.timedelta(0, secs) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; secs &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; [60]*3 + [120]*10 + [240]*10 ]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 46 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 47 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Choice of cluster sizes&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 48 &lt;/font&gt;clustersizefreq = [2]*20 + [3]*8 + [4]*3 + [5]*2 + [6]*1 +[7]*1 + [8]*1&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 49 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 50 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Many messages between the same two people?&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 51 &lt;/font&gt;repeatmsgfraction = 2.0 &lt;font&lt;br /&gt; color="#0000ff"&gt;# Extra 200%&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 52 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 53 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;namegen&lt;/font&gt;():&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 54 &lt;/font&gt; '&lt;font color="#ff00ff"&gt;Generates (first, family) name tuples&lt;/font&gt;'&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 55 &lt;/font&gt; names = list(itertools.product(firstname, familyname))&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 56 &lt;/font&gt; random.shuffle(names)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 57 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; name &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; names:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 58 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;yield&lt;/b&gt;&lt;/font&gt; name&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 59 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 60 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;name2email&lt;/font&gt;(name):&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 61 &lt;/font&gt; '&lt;font color="#ff00ff"&gt;format (first, family) name as email address&lt;/font&gt;'&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 62 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; '&lt;font&lt;br /&gt; color="#ff00ff"&gt;%s.%s@xx.com&lt;/font&gt;' % name&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 63 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 64 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;clustergen&lt;/font&gt;(clustercount, clustersizefreq=clustersizefreq,&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 65 &lt;/font&gt; firstname=firstname, familyname=familyname):&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 66 &lt;/font&gt; '&lt;font color="#ff00ff"&gt;Generate clustercount clusters of unique users&lt;/font&gt;'&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 67 &lt;/font&gt; nextname = namegen().__next__&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 68 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; sorted( sorted(nextname() &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; range(random.choice(clustersizefreq)))&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 69 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; j &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; range(clustercount) )&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 70 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 71 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;clusterprint&lt;/font&gt;(clusters):&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 72 &lt;/font&gt; '&lt;font color="#ff00ff"&gt;Print already sorted clusters in output format&lt;/font&gt;'&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 73 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; cluster &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; clusters:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 74 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; ( '&lt;font&lt;br /&gt; color="#ff00ff"&gt;, &lt;/font&gt;'.join(name2email(n) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; n &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; cluster) )&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 75 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 76 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;loggen&lt;/font&gt;(clustercount, clustersizefreq=clustersizefreq,&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 77 &lt;/font&gt; firstname=firstname, familyname=familyname,&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 78 &lt;/font&gt; starttime=starttime, timedeltafreq=timedeltafreq,&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 79 &lt;/font&gt; repeatmsgfraction=repeatmsgfraction):&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 80 &lt;/font&gt; '&lt;font color="#ff00ff"&gt;Generate a log of clustercount clusters of unique users&lt;/font&gt;'&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 81 &lt;/font&gt; clusters = clustergen(clustercount)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 82 &lt;/font&gt; &lt;font color="#0000ff"&gt;# clustered emails&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 83 &lt;/font&gt; log = sum([ list(itertools.permutations(cluster, 2)) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; cluster &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; clusters ],&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 84 &lt;/font&gt; [])&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 85 &lt;/font&gt; &lt;font color="#0000ff"&gt;# repeats&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 86 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; range(int(repeatmsgfraction*len(log))):&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 87 &lt;/font&gt; log.append(random.choice(log))&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 88 &lt;/font&gt; &lt;font color="#0000ff"&gt;# dispersed emails&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 89 &lt;/font&gt; random.shuffle(log)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 90 &lt;/font&gt; &lt;font color="#0000ff"&gt;# log times for emails&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 91 &lt;/font&gt; logtime = starttime&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 92 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; n, (send, to) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; enumerate(log):&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 93 &lt;/font&gt; log[n] = (logtime, send, to)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 94 &lt;/font&gt; logtime += random.choice(timedeltafreq)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 95 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; clusters, log&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 96 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 97 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;logprint&lt;/font&gt;(log):&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 98 &lt;/font&gt; '&lt;font color="#ff00ff"&gt;Print log in input format&lt;/font&gt;'&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 99 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; logtime, send, to &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; log:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;100 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; ('&lt;font&lt;br /&gt; color="#ff00ff"&gt;%s&lt;/font&gt;&lt;font color="#6a5acd"&gt;\t&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;%s&lt;/font&gt;&lt;font color="#6a5acd"&gt;\t&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;%s&lt;/font&gt;' % (logtime.strftime("&lt;font&lt;br /&gt; color="#ff00ff"&gt;%a %b %d %H:%M:%S PST %Y&lt;/font&gt;")&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;101 &lt;/font&gt; , name2email(send), name2email(to)))&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;102 &lt;/font&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3 style="margin-left: 40px;"&gt;The Program in use&lt;/h3&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;Switching to the command&lt;br /&gt;line shell, I generate a log and its clustering and print the results.&lt;br /&gt;Because of the way the log is generated from the clustering, the&lt;br /&gt;clustering of the log should be as stated.&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;&amp;gt;&amp;gt;&amp;gt; &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;clusters, log = loggen(3);&lt;br /&gt;clusterprint(clusters); print(); logprint(log); print(); len(log)&lt;/span&gt;&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Alfie.Khan@xx.com,&lt;br /&gt;Lily.Rose@xx.com, Tyler.Blanchet@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Finley.Ali@xx.com,&lt;br /&gt;Harry.White@xx.com&lt;/span&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Finley.Cox@xx.com,&lt;br /&gt;James.Harrison@xx.com&lt;/span&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 17:53:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Finley.Cox@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; James.Harrison@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 17:55:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Lily.Rose@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Alfie.Khan@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 17:59:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Finley.Cox@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; James.Harrison@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:03:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Finley.Ali@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Harry.White@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:07:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Tyler.Blanchet@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Alfie.Khan@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:09:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Tyler.Blanchet@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Alfie.Khan@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:13:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Alfie.Khan@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Lily.Rose@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:17:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Finley.Cox@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; James.Harrison@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:21:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Alfie.Khan@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Tyler.Blanchet@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:23:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Harry.White@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Finley.Ali@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:27:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Harry.White@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Finley.Ali@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:29:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;James.Harrison@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Finley.Cox@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:33:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Alfie.Khan@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Tyler.Blanchet@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:37:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Alfie.Khan@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Lily.Rose@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:39:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;James.Harrison@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Finley.Cox@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:43:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Tyler.Blanchet@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Alfie.Khan@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:45:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Alfie.Khan@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Tyler.Blanchet@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:47:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Harry.White@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Finley.Ali@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:49:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Harry.White@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Finley.Ali@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:53:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;James.Harrison@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Finley.Cox@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:57:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Finley.Cox@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; James.Harrison@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 18:59:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Harry.White@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Finley.Ali@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 19:03:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Lily.Rose@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Alfie.Khan@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 19:04:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Tyler.Blanchet@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Lily.Rose@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 19:06:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;James.Harrison@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Finley.Cox@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 19:10:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Tyler.Blanchet@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Alfie.Khan@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 19:12:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Lily.Rose@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Tyler.Blanchet@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 19:16:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Finley.Cox@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; James.Harrison@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 19:20:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Tyler.Blanchet@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Lily.Rose@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Thu Dec 11 19:22:01&lt;br /&gt;PST 2008&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;Alfie.Khan@xx.com&amp;nbsp;&amp;nbsp;&amp;nbsp; Tyler.Blanchet@xx.com&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;30&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h2&gt;To Do&lt;/h2&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;The cluster info for the puzzle should, of course, have the&lt;br /&gt;clusters of size two filtered out &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;I haave a solution to the original puzzle, but: "&lt;font&lt;br /&gt; style="font-style: italic;" title="Insert schoolboy excuse here"&gt;Blue&lt;br /&gt;Martians forcibly wiped it from my brain&lt;/font&gt;" :-)&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;- Paddy.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-8395030729737165179?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/8395030729737165179/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/08/facebook-user-clustering-puzzle.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/8395030729737165179'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/8395030729737165179'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/08/facebook-user-clustering-puzzle.html' title='Facebook User-Clustering Puzzle'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-940372100118598663</id><published>2009-07-28T09:16:00.000+01:00</published><updated>2009-07-28T09:17:45.426+01:00</updated><title type='text'>The case of the disappearing over-bar</title><content type='html'>Rosetta-code has &lt;a href="http://rosettacode.org/wiki/Reversing_a_string"&gt;a task&lt;/a&gt;&lt;br /&gt;which asks you to reverse a Unicode string&lt;br /&gt;correctly. I had glanced at the &lt;a href="http://rosettacode.org/wiki/Reversing_a_string#Python"&gt;Python&lt;br /&gt;solution&lt;/a&gt; and thought nothing of&lt;br /&gt;it until someone did something similar in the R language and stated&lt;br /&gt;that it may be incorrect for the given pattern which includes an&lt;br /&gt;over-bar (my description) over the f in "as⃝df̅" (See the&lt;a href="http://rosettacode.org/wiki/Reversing_a_string"&gt;&lt;br /&gt;orginal article&lt;/a&gt; for the true Unicode string). &lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I cut-n-pasted the Python solution and the test string into Python 3.1&lt;br /&gt;idle and decided to test it:&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;Python 3.1 (r31:73574, Jun 26 2009, 20:21:35) [MSC v.1500 32 bit (Intel)] on win32&lt;br&gt;Type "&lt;font color="#ff00ff"&gt;copyright&lt;/font&gt;", "&lt;font color="#ff00ff"&gt;credits&lt;/font&gt;" &lt;font color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; "&lt;font color="#ff00ff"&gt;license()&lt;/font&gt;" &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; more information.&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font color="#0000ff"&gt;# I cut and paste the following string with an over-bar on the f&lt;/font&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; x = input()&lt;br&gt;as⃝df̅&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font color="#0000ff"&gt;# Just showing x gives the over-bar on the f&lt;/font&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; x&lt;br&gt;'&lt;font color="#ff00ff"&gt;asâƒdfÌ…&lt;/font&gt;'&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font color="#0000ff"&gt;# Print it and it is fine.&lt;/font&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt;(x)&lt;br&gt;asâƒdfÌ…&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font color="#0000ff"&gt;# Reverse x though, and the over-bar movesover the quote!&lt;/font&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; x[::-1]&lt;br&gt;'&lt;font color="#ff00ff"&gt;Ì…fdâƒsa&lt;/font&gt;'&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font color="#0000ff"&gt;# print the reversed x and it disappears altogether!&lt;/font&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt;(x[::-1])&lt;br&gt;Ì…fdâƒsa&lt;br&gt;&amp;gt;&amp;gt;&amp;gt;&lt;br&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;|NowCut and paste the unicode characters from firefox for the input&lt;br /&gt;statement, and make sure that:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; ['%x' % ord(char) for char in x]&lt;br&gt;['61', '73', '20dd', '64', '66', '305']&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;As the unicode might otherwise be lost in my editing to try and present&lt;br /&gt;it to you above.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;A bit of &lt;a href="http://en.wikipedia.org/wiki/Category:Unicode" target="_blank"&gt;scary reading&lt;/a&gt; introduced me to&lt;br /&gt;Unicode character classes. It seems that Unicode characters are&lt;br /&gt;sometimes composed, and that if I know what character gets composed&lt;br /&gt;with another, (always the last non-composed character to the left),&lt;br /&gt;then you should be able to form composed groups of characters and then&lt;br /&gt;reverse them.&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;The WP article gave me the vocabulary, so a quick search in Pythons&lt;br /&gt;library gave me the &lt;a href="http://docs.python.org/3.1/library/unicodedata.html"&gt;unicodedata&lt;/a&gt;&lt;br /&gt;module which has the &lt;a href="http://docs.python.org/3.1/library/unicodedata.html?highlight=unicodedata.name#unicodedata.name"&gt;name&lt;/a&gt;&lt;br /&gt;function. I am not sure if this will work in every case, but from the&lt;br /&gt;WP article and this experimentation:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; [(c,'%s' % unicodedata.name(c,0xfffff)) for c in x]&lt;br&gt;[('a', 'LATIN SMALL LETTER A'), ('s', 'LATIN SMALL LETTER S'), ('⃝', 'COMBINING ENCLOSING CIRCLE'), ('d', 'LATIN SMALL LETTER D'), ('f', 'LATIN SMALL LETTER F'), ('̅', 'COMBINING OVERLINE')]&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I think I can group by the presence of the word &lt;span style="font-family: monospace;"&gt;COMBINING&lt;/span&gt; in the name&lt;br /&gt;of a character and so produced the following reversal function:&lt;br&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;pre&gt;'''&lt;br&gt;&lt;font color="#ff00ff"&gt;  Reverse a Unicode string with proper handling of combining characters&lt;/font&gt;&lt;br&gt;'''&lt;br&gt;&lt;br&gt;&lt;font color="#a020f0"&gt;import&lt;/font&gt; unicodedata&lt;br&gt;&lt;br&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font color="#008080"&gt;ureverse&lt;/font&gt;(ustring):&lt;br&gt;    '''&lt;br&gt;&lt;font color="#ff00ff"&gt;    Reverse a string including unicode combining characters&lt;/font&gt;&lt;br&gt;&lt;br&gt;&lt;font color="#ff00ff"&gt;    Example:&lt;/font&gt;&lt;br&gt;&lt;font color="#ff00ff"&gt;        &amp;gt;&amp;gt;&amp;gt; ucode = ''.join( chr(int(n, 16))&lt;/font&gt;&lt;br&gt;&lt;font color="#ff00ff"&gt;                             for n in ['61', '73', '20dd', '64', '66', '305'] )&lt;/font&gt;&lt;br&gt;&lt;font color="#ff00ff"&gt;        &amp;gt;&amp;gt;&amp;gt; ucoderev = ureverse(ucode)&lt;/font&gt;&lt;br&gt;&lt;font color="#ff00ff"&gt;        &amp;gt;&amp;gt;&amp;gt; ['%x' % ord(char) for char in ucoderev]&lt;/font&gt;&lt;br&gt;&lt;font color="#ff00ff"&gt;        ['66', '305', '64', '73', '20dd', '61']&lt;/font&gt;&lt;br&gt;&lt;font color="#ff00ff"&gt;        &amp;gt;&amp;gt;&amp;gt; &lt;/font&gt;&lt;br&gt;&lt;font color="#ff00ff"&gt;    &lt;/font&gt;'''&lt;br&gt;    groupedchars = []&lt;br&gt;    uchar = list(ustring)&lt;br&gt;    &lt;font color="#804040"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt; uchar:&lt;br&gt;        &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; '&lt;font color="#ff00ff"&gt;COMBINING&lt;/font&gt;' &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; unicodedata.name(uchar[0], ''):&lt;br&gt;            groupedchars[-1] += uchar.pop(0)&lt;br&gt;        &lt;font color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt;:&lt;br&gt;            groupedchars.append(uchar.pop(0))&lt;br&gt;    &lt;font color="#0000ff"&gt;# Grouped reversal&lt;/font&gt;&lt;br&gt;    groupedchars = groupedchars[::-1]&lt;br&gt;&lt;br&gt;    &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; ''.join(groupedchars)&lt;br&gt;&lt;br&gt;&lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; __name__ == '&lt;font color="#ff00ff"&gt;__main__&lt;/font&gt;':&lt;br&gt;    ucode = ''.join( chr(int(n, 16))&lt;br&gt;                     &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; n &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; ['&lt;font color="#ff00ff"&gt;61&lt;/font&gt;', '&lt;font color="#ff00ff"&gt;73&lt;/font&gt;', '&lt;font color="#ff00ff"&gt;20dd&lt;/font&gt;', '&lt;font color="#ff00ff"&gt;64&lt;/font&gt;', '&lt;font color="#ff00ff"&gt;66&lt;/font&gt;', '&lt;font color="#ff00ff"&gt;305&lt;/font&gt;'] )&lt;br&gt;    ucoderev = ureverse(ucode)&lt;br&gt;    &lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; (ucode)&lt;br&gt;    &lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; (ucoderev)&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&amp;nbsp; &lt;br&gt;&lt;br /&gt;It works for the given example text (Try running it to see the output -&lt;br /&gt;I've given up trying to work out what characters you might see).&lt;br&gt;&lt;br&gt;Gosh, an attractive Unicode issue! Whatever next.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-940372100118598663?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/940372100118598663/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/07/case-of-disappearing-over-bar.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/940372100118598663'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/940372100118598663'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/07/case-of-disappearing-over-bar.html' title='The case of the disappearing over-bar'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-658990826994126937</id><published>2009-06-24T22:18:00.004+01:00</published><updated>2009-06-25T04:22:37.495+01:00</updated><title type='text'>Type based API's and Duck Typing Shocker!!</title><content type='html'>The Voidspace tech blog has &lt;a&lt;br /&gt; href="http://www.voidspace.org.uk/python/articles/duck_typing.shtml"&gt;an&lt;br /&gt;article&lt;/a&gt; in which the author, Michael Ford, blames duck-typing&lt;br /&gt;for a problem in trying to find the&amp;nbsp;type of an argument.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;After a very good explanation of how duck typing in Python&lt;br /&gt;&amp;nbsp;comes about Michael starts his section on the problem by&lt;br /&gt;stating the principal of duck typing as:&lt;br&gt;&lt;br /&gt;&lt;div style="font-style: italic; margin-left: 40px;"&gt;"The&lt;br /&gt;principle of duck typing says that you shouldn't care what type of&lt;br /&gt;object you have - just whether or not you can do the required action&lt;br /&gt;with your object."&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;All well and good but then later on Michael states:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px; font-style: italic;"&gt;"If we&lt;br /&gt;want our code to treat different types of object differently then&lt;br /&gt;the approach in example two fails. This isn't contrived - this is&lt;br /&gt;exactly the situation we found ourselves in with ConfigObj."&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;So, type is important in his case. Fine. &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;But why lay the blame at duck&lt;br /&gt;typings door ?&lt;/span&gt;&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;His example interface relies on knowing what constitutes a "listy"&lt;br /&gt;object, or a "stringy" object, etc, in Python 2.x, which he notes is a&lt;br /&gt;pain, but I think the cause of the problem w.r.t. duck typing is&lt;br /&gt;choosing an API that relies on an ill-defined idea of what constitutes&lt;br /&gt;close enough to a dict/list/string or whatever, then not having the&lt;br /&gt;language provide an easy solution.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;a href="http://docs.python.org/library/abc.html"&gt;Abstract&lt;br /&gt;base classes&lt;/a&gt; are an attempt to help out in such cases that is&lt;br /&gt;new in Python 2.6 and 3.0, but if you want to link functionality with&lt;br /&gt;type then you can't expect to get duck typing too.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h3&gt;Where Duck Typing Does Not fit.&lt;/h3&gt;&lt;br /&gt;If a function has an expensive or non-reversible operation that depends&lt;br /&gt;on an &amp;nbsp;attribute of an argument, then it may be wise to check&lt;br /&gt;all arguments for compatibility up-front; but even then, whats wrong&lt;br /&gt;with reading the code? &amp;nbsp;Defensive programming can creep up on&lt;br /&gt;you...&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-658990826994126937?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/658990826994126937/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/06/type-based-apis-and-duck-typing-shocker.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/658990826994126937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/658990826994126937'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/06/type-based-apis-and-duck-typing-shocker.html' title='Type based API&apos;s and Duck Typing Shocker!!'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-3021544453226366367</id><published>2009-06-22T19:55:00.000+01:00</published><updated>2009-06-22T19:56:01.885+01:00</updated><title type='text'>Killer Script</title><content type='html'>&lt;br&gt;&lt;br /&gt;Following on from my &lt;a&lt;br /&gt; href="http://paddy3118.blogspot.com/2009/03/batch-process-runner-in-bash-shell.html"&lt;br /&gt; target="_blank"&gt;Batch process runner script&lt;/a&gt;, I got&lt;br /&gt;thinking that a nice capability would be to have a maximum runtime&lt;br /&gt;limit for the jobs. &lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;My first thought was to create an &lt;a&lt;br /&gt; href="http://unixhelp.ed.ac.uk/CGI/man-cgi?at" target="_blank"&gt;at&lt;/a&gt;&lt;br /&gt;command set to execute the reuired time after the start of each job,&lt;br /&gt;one for each job, that would kill the job. &lt;br&gt;&lt;br /&gt;Nah. &lt;br&gt;&lt;br /&gt;Discussions with a friend lead to consideration of using &lt;a&lt;br /&gt; href="http://docs.sun.com/app/docs/doc/816-5165/ulimit-1?l=en&amp;amp;a=view&amp;amp;q=ulimit"&lt;br /&gt; target="_blank"&gt;ulimit&lt;/a&gt; in the script to limit the&lt;br /&gt;run time, but unfortunately on the Unix box I was testing on, ulimit&lt;br /&gt;could only limit the maximum CPU time, not run time. If the job was&lt;br /&gt;stuck in a non-busy wait then it would not be auto-killed.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I decided to try creating a script to run a time eating processing task&lt;br /&gt;that created a background kill task so the script would be self&lt;br /&gt;killing. &lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h3&gt;The script&lt;/h3&gt;&lt;br /&gt;Line 1:&amp;nbsp;&amp;nbsp;&amp;nbsp; The KILLAFTER environment&lt;br /&gt;variable will kill the script after 3 seconds&lt;br&gt;&lt;br /&gt;Line 5:&amp;nbsp;&amp;nbsp;&amp;nbsp; Store the process ID for the&lt;br /&gt;'bash -c' &amp;nbsp;script for killing later&lt;br&gt;&lt;br /&gt;Line 8:&amp;nbsp;&amp;nbsp;&amp;nbsp; This is the slleping background&lt;br /&gt;sub-process that wakes after KILLAFTER seconds and kills the script.&lt;br&gt;&lt;br /&gt;Line 9:&amp;nbsp;&amp;nbsp;&amp;nbsp; But if the normal script commands&lt;br /&gt;finish, store the sub-process PID so it can be cleanly killed itself.&lt;br&gt;&lt;br /&gt;Line 12:&amp;nbsp; Some dummy command that counts up every second.&lt;br&gt;&lt;br /&gt;Line 13:&amp;nbsp;&amp;nbsp; And save its exit status so it can be&lt;br /&gt;restored after removing the background kill process.&lt;br&gt;&lt;br /&gt;Line 16:&amp;nbsp;&amp;nbsp; Terminate the background kill process so&lt;br /&gt;we are not left waiting.&lt;br&gt;&lt;br /&gt;Line 18:&amp;nbsp;&amp;nbsp; Exit with the saved exit status.&lt;br&gt;&lt;br /&gt;Line 19:&amp;nbsp;&amp;nbsp; Prints the exit status of the whole 'bash&lt;br /&gt;-c' script&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Lines 20-24 show the output of the first run. Notice how although the&lt;br /&gt;for loop in line 12 is set to count to 5, the count gets killed after&lt;br /&gt;printing 3, i.e. the three seconds of $KILLAFTER.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Lines 27 onwards show a second run where KILLAFTER is set to more time&lt;br /&gt;than is used by the for loop. Notice how the script prints the full&lt;br /&gt;count up to 5, and has a return status of zero.&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#804040"&gt; 1 &lt;/font&gt;bash-paddy: &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;env &lt;/span&gt;&lt;font&lt;br /&gt; style="font-weight: bold;" color="#008080"&gt;KILLAFTER&lt;/font&gt;&lt;span&lt;br /&gt; style="font-weight: bold;"&gt;=&lt;/span&gt;&lt;font&lt;br /&gt; style="font-weight: bold;" color="#ff00ff"&gt;3&lt;/font&gt;&lt;span&lt;br /&gt; style="font-weight: bold;"&gt; bash &lt;/span&gt;&lt;font&lt;br /&gt; style="font-weight: bold;" color="#6a5acd"&gt;-c&lt;/font&gt;&lt;span&lt;br /&gt; style="font-weight: bold;"&gt; '&lt;/span&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 2 &lt;/font&gt;&lt;font color="#0000ff"&gt;# New bash script shell environment&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 3 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 4 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Its PID&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 5 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;export&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;thisshellpid&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$$&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 6 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 7 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Sleeping killer will blast this script after given time&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 8 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;(&lt;/b&gt;&lt;/font&gt;sleep &lt;font&lt;br /&gt; color="#a020f0"&gt;$KILLAFTER&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;kill&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#ff00ff"&gt;-9&lt;/font&gt; &lt;font color="#a020f0"&gt;$thisshellpid&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;)&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;&amp;amp;&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 9 &lt;/font&gt;&lt;font color="#008080"&gt;killerpid&lt;/font&gt;=&lt;font&lt;br /&gt; color="#a020f0"&gt;$!&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;10 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;11 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Any time consuming command&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;12 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; y &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt; &lt;font color="#ff00ff"&gt;2&lt;/font&gt; &lt;font&lt;br /&gt; color="#ff00ff"&gt;3&lt;/font&gt; &lt;font color="#ff00ff"&gt;4&lt;/font&gt; &lt;font&lt;br /&gt; color="#ff00ff"&gt;5&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;do&lt;/b&gt;&lt;/font&gt; sleep &lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;echo&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt; &lt;/font&gt;&lt;font color="#a020f0"&gt;$y&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;done&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;13 &lt;/font&gt;&lt;font color="#008080"&gt;trueexitstatus&lt;/font&gt;=&lt;font&lt;br /&gt; color="#a020f0"&gt;$?&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;14 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;15 &lt;/font&gt;&lt;font color="#0000ff"&gt;# If time consuming command worked OK then...&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;16 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;kill&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#ff00ff"&gt;-9&lt;/font&gt; &lt;font color="#a020f0"&gt;$killerpid&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;17 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;18 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;exit&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#a020f0"&gt;$trueexitstatus&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;19 &lt;/font&gt;&lt;span&lt;br /&gt; style="font-weight: bold;"&gt;' &lt;/span&gt;&lt;font&lt;br /&gt; style="font-weight: bold;" color="#804040"&gt;;&lt;/font&gt;&lt;span&lt;br /&gt; style="font-weight: bold;"&gt; &lt;/span&gt;&lt;font&lt;br /&gt; style="font-weight: bold;" color="#804040"&gt;echo&lt;/font&gt;&lt;font&lt;br /&gt; style="font-weight: bold;" color="#ff00ff"&gt; Returned status: &lt;/font&gt;&lt;font&lt;br /&gt; style="font-weight: bold;" color="#a020f0"&gt;$?&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;20 &lt;/font&gt;&lt;font color="#ff00ff"&gt;1&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;21 &lt;/font&gt;&lt;font color="#ff00ff"&gt;2&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;22 &lt;/font&gt;&lt;font color="#ff00ff"&gt;3&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;23 &lt;/font&gt;Killed&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;24 &lt;/font&gt;Returned status: &lt;font&lt;br /&gt; color="#ff00ff"&gt;137&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;25 &lt;/font&gt;bash-paddy:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;26 &lt;/font&gt;bash-paddy:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;27 &lt;/font&gt;bash-paddy: &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;env &lt;/span&gt;&lt;font&lt;br /&gt; style="font-weight: bold;" color="#008080"&gt;KILLAFTER&lt;/font&gt;&lt;span&lt;br /&gt; style="font-weight: bold;"&gt;=&lt;/span&gt;&lt;font&lt;br /&gt; style="font-weight: bold;" color="#ff00ff"&gt;10&lt;/font&gt;&lt;span&lt;br /&gt; style="font-weight: bold;"&gt; bash &lt;/span&gt;&lt;font&lt;br /&gt; style="font-weight: bold;" color="#6a5acd"&gt;-c&lt;/font&gt;&lt;span&lt;br /&gt; style="font-weight: bold;"&gt; '&lt;/span&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;28 &lt;/font&gt;&lt;font color="#0000ff"&gt;# New bash script shell environment&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;29 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;30 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Its PID&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;31 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;export&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;thisshellpid&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$$&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;32 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;33 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Sleeping killer will blast this script after given time&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;34 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;(&lt;/b&gt;&lt;/font&gt;sleep &lt;font&lt;br /&gt; color="#a020f0"&gt;$KILLAFTER&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;kill&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#ff00ff"&gt;-9&lt;/font&gt; &lt;font color="#a020f0"&gt;$thisshellpid&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;)&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;&amp;amp;&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;35 &lt;/font&gt;&lt;font color="#008080"&gt;killerpid&lt;/font&gt;=&lt;font&lt;br /&gt; color="#a020f0"&gt;$!&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;36 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;37 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Any time consuming command&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;38 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; y &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt; &lt;font color="#ff00ff"&gt;2&lt;/font&gt; &lt;font&lt;br /&gt; color="#ff00ff"&gt;3&lt;/font&gt; &lt;font color="#ff00ff"&gt;4&lt;/font&gt; &lt;font&lt;br /&gt; color="#ff00ff"&gt;5&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;do&lt;/b&gt;&lt;/font&gt; sleep &lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;echo&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt; &lt;/font&gt;&lt;font color="#a020f0"&gt;$y&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;done&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;39 &lt;/font&gt;&lt;font color="#008080"&gt;trueexitstatus&lt;/font&gt;=&lt;font&lt;br /&gt; color="#a020f0"&gt;$?&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;40 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;41 &lt;/font&gt;&lt;font color="#0000ff"&gt;# If time consuming command worked OK then...&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;42 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;kill&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#ff00ff"&gt;-9&lt;/font&gt; &lt;font color="#a020f0"&gt;$killerpid&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;43 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;44 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;exit&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#a020f0"&gt;$trueexitstatus&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;45 &lt;/font&gt;&lt;span&lt;br /&gt; style="font-weight: bold;"&gt;' &lt;/span&gt;&lt;font&lt;br /&gt; style="font-weight: bold;" color="#804040"&gt;;&lt;/font&gt;&lt;span&lt;br /&gt; style="font-weight: bold;"&gt; &lt;/span&gt;&lt;font&lt;br /&gt; style="font-weight: bold;" color="#804040"&gt;echo&lt;/font&gt;&lt;font&lt;br /&gt; style="font-weight: bold;" color="#ff00ff"&gt; Returned status: &lt;/font&gt;&lt;font&lt;br /&gt; style="font-weight: bold;" color="#a020f0"&gt;$?&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;46 &lt;/font&gt;&lt;font color="#ff00ff"&gt;1&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;47 &lt;/font&gt;&lt;font color="#ff00ff"&gt;2&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;48 &lt;/font&gt;&lt;font color="#ff00ff"&gt;3&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;49 &lt;/font&gt;&lt;font color="#ff00ff"&gt;4&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;50 &lt;/font&gt;&lt;font color="#ff00ff"&gt;5&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;51 &lt;/font&gt;Returned status: &lt;font&lt;br /&gt; color="#ff00ff"&gt;0&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;52 &lt;/font&gt;bash-paddy:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;53 &lt;/font&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-3021544453226366367?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/3021544453226366367/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/06/killer-script.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/3021544453226366367'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/3021544453226366367'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/06/killer-script.html' title='Killer Script'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-1005346900427667474</id><published>2009-06-15T01:01:00.000+01:00</published><updated>2009-06-15T01:02:25.389+01:00</updated><title type='text'>XKCD Simpler Knapsack Solution</title><content type='html'>&amp;nbsp;After reading the feedback on my &lt;a&lt;br /&gt; href="http://paddy3118.blogspot.com/2009/06/xkcd-knapsack-solution.html"&lt;br /&gt; target="_blank"&gt;earlier solution to the XKCD knapsack problem&lt;/a&gt;,&lt;br /&gt;I decided to re-write it without itertools.product and with integer&lt;br /&gt;maths.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I came up with a solution that used explicit while loops that worked,&lt;br /&gt;and used much less traversals through nested loops, but I then boiled&lt;br /&gt;that down to a recursive solution which retains the ability to easily&lt;br /&gt;modify the number of dishes , whilst restricting the number of times&lt;br /&gt;through the loops to the bare minimum. &lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;In the previous solution I worked out the maximum number of each dish&lt;br /&gt;that cost less than or equal to the amount and looped from zero to that&lt;br /&gt;many times. In the solution below the while loops cut off looping on&lt;br /&gt;any particular dish when adding another would put the cost over the&lt;br /&gt;maximum.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;And now the code:&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;big&gt;items = ( ('&lt;font color="#ff00ff"&gt;MIXED FRUIT&lt;/font&gt;',   2.15),&lt;br&gt;          ('&lt;font&lt;br /&gt; color="#ff00ff"&gt;FRENCH FRIES&lt;/font&gt;',  2.75),&lt;br&gt;          ('&lt;font&lt;br /&gt; color="#ff00ff"&gt;SIDE SALAD&lt;/font&gt;',    3.35),&lt;br&gt;          ('&lt;font&lt;br /&gt; color="#ff00ff"&gt;HOT WINGS&lt;/font&gt;',     3.55),&lt;br&gt;          ('&lt;font&lt;br /&gt; color="#ff00ff"&gt;MOZZ STICKS&lt;/font&gt;',   4.20),&lt;br&gt;          ('&lt;font&lt;br /&gt; color="#ff00ff"&gt;SAMPLER PLATE&lt;/font&gt;', 5.80),&lt;br&gt;          ('&lt;font&lt;br /&gt; color="#ff00ff"&gt;BARBEQUE&lt;/font&gt;',      6.55) )&lt;br&gt;&lt;br&gt;exactcost = 15.05&lt;br&gt;&lt;br&gt;dishes, prices = zip(*items)&lt;br&gt;&lt;font&lt;br /&gt; color="#0000ff"&gt;# All calcs in integer cents.&lt;/font&gt;&lt;br&gt;prices = [int(price*100) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; price &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; prices]&lt;br&gt;ecost = int(exactcost*100)&lt;br&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#0000ff"&gt;# counts of each dish&lt;/font&gt;&lt;br&gt;dishcounts = [0]*len(prices)&lt;br&gt;&lt;font&lt;br /&gt; color="#0000ff"&gt;&lt;/font&gt;possibleorders = []&lt;br&gt;cost = 0&lt;br&gt;maxnesting = len(dishcounts)&lt;br&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;enumeratedish&lt;/font&gt;(nest, cost, possibleorders):&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;global&lt;/b&gt;&lt;/font&gt; dishcounts, prices, ecost, maxnesting&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt; cost &amp;lt;= ecost:&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; nest+1 &amp;lt; maxnesting:&lt;br&gt;            enumeratedish(nest+1, cost, possibleorders)&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;elif&lt;/b&gt;&lt;/font&gt; cost == ecost:&lt;br&gt;            possibleorders.append(dishcounts[:])&lt;br&gt;            &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;break&lt;/b&gt;&lt;/font&gt;&lt;br&gt;        dishcounts[nest] += 1&lt;br&gt;        cost += prices[nest]&lt;br&gt;        &lt;font&lt;br /&gt; color="#0000ff"&gt;#print (dishcounts)&lt;/font&gt;&lt;br&gt;    cost -= prices[nest] * dishcounts[nest]&lt;br&gt;    dishcounts[nest] = 0&lt;br&gt;&lt;br&gt;enumeratedish(0, 0, possibleorders)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt;('&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n&lt;/font&gt;&lt;font color="#ff00ff"&gt;ALL POSSIBLE CHOICES OF MENU ITEMS THAT COST %.2f, ONE PER LINE&lt;/font&gt;' % exactcost)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; order &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; possibleorders:&lt;br&gt;    order = zip(dishes, order)&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt;( '&lt;font&lt;br /&gt; color="#ff00ff"&gt;  &lt;/font&gt;',&lt;br&gt;           '&lt;font&lt;br /&gt; color="#ff00ff"&gt;, &lt;/font&gt;'.join('&lt;font&lt;br /&gt; color="#ff00ff"&gt;%s: %i&lt;/font&gt;' % dishcount &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; dishcount &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; order &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; dishcount[1]))&lt;/big&gt;&lt;br&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;feel free to compare the two solutions.&amp;nbsp;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-1005346900427667474?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/1005346900427667474/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/06/xkcd-simpler-knapsack-solution.html#comment-form' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1005346900427667474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1005346900427667474'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/06/xkcd-simpler-knapsack-solution.html' title='XKCD Simpler Knapsack Solution'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-5437317569960489333</id><published>2009-06-13T21:34:00.001+01:00</published><updated>2009-06-13T22:35:38.464+01:00</updated><title type='text'>XKCD Knapsack Solution</title><content type='html'>A brute force solution to the following comic from &lt;a&lt;br /&gt; href="http://xkcd.com/287/"&gt;XKCD&lt;/a&gt;:&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;img style="width: 640px; height: 414px;" alt=""&lt;br /&gt; title="General solutions get you a 50% tip."&lt;br /&gt; src="http://imgs.xkcd.com/comics/np_complete.png"&gt;&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Assuming the one sandwich represents the end of the menu, I used an&lt;br /&gt;exhaustive search algorithm. Things to note are the use of zip(*table)&lt;br /&gt;to transpose the items and itertools.product instead of nested for&lt;br /&gt;loops. &lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;big&gt;'''&lt;br&gt;&lt;font color="#ff00ff"&gt;from: &lt;a&lt;br /&gt; href="http://xkcd.com/287/"&gt;http://xkcd.com/287/&lt;/a&gt;&lt;/font&gt;&lt;br&gt;'''&lt;br&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;from&lt;/font&gt; itertools &lt;font&lt;br /&gt; color="#a020f0"&gt;import&lt;/font&gt; product&lt;br&gt;&lt;br&gt;items = ( ('&lt;font&lt;br /&gt; color="#ff00ff"&gt;MIXED FRUIT&lt;/font&gt;',   2.15),&lt;br&gt;          ('&lt;font&lt;br /&gt; color="#ff00ff"&gt;FRENCH FRIES&lt;/font&gt;',  2.75),&lt;br&gt;          ('&lt;font&lt;br /&gt; color="#ff00ff"&gt;SIDE SALAD&lt;/font&gt;',    3.35),&lt;br&gt;          ('&lt;font&lt;br /&gt; color="#ff00ff"&gt;HOT WINGS&lt;/font&gt;',     3.55),&lt;br&gt;          ('&lt;font&lt;br /&gt; color="#ff00ff"&gt;MOZZ STICKS&lt;/font&gt;',   4.20),&lt;br&gt;          ('&lt;font&lt;br /&gt; color="#ff00ff"&gt;SAMPLER PLATE&lt;/font&gt;', 5.80),&lt;br&gt;          ('&lt;font&lt;br /&gt; color="#ff00ff"&gt;BARBEQUE&lt;/font&gt;',      6.55) )&lt;br&gt;&lt;br&gt;exactcost = 15.05&lt;br&gt;&lt;br&gt;dishes, prices = zip(*items)&lt;br&gt;rangeofdishes = [tuple(range(1+int( (exactcost+0.005)/price ))) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; price &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; prices]&lt;br&gt;&lt;br&gt;possibleorders = [tuple(zip(dishes, numbers))&lt;br&gt;                  &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; numbers &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; product(*rangeofdishes)&lt;br&gt;                  &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; int(exactcost*100)&lt;br&gt;                       == int(100* sum(num*price&lt;br&gt;                                       &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; num,price &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; zip(numbers, prices)))&lt;br&gt;                  ]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt;('&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n&lt;/font&gt;&lt;font color="#ff00ff"&gt;ALL POSSIBLE CHOICES OF MENU ITEMS THAT COST %.2f, ONE PER LINE&lt;/font&gt;' % exactcost)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; order &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; possibleorders:&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt;( '&lt;font&lt;br /&gt; color="#ff00ff"&gt;  &lt;/font&gt;',&lt;br&gt;           '&lt;font&lt;br /&gt; color="#ff00ff"&gt;, &lt;/font&gt;'.join('&lt;font&lt;br /&gt; color="#ff00ff"&gt;%s: %i&lt;/font&gt;' % dishcount &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; dishcount &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; order &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; dishcount[1]))&lt;br&gt;&lt;/big&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;The&amp;nbsp;answers I get are:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;ALL POSSIBLE CHOICES OF MENU&lt;br /&gt;ITEMS THAT COST 15.05, ONE PER LINE&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;MIXED FRUIT: 1, HOT WINGS: 2, SAMPLER PLATE: 1&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;MIXED FRUIT: 2, MOZZ STICKS: 1, BARBEQUE: 1&lt;/span&gt;&lt;br&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;MIXED FRUIT: 7&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;(I'd go with the hot wings).&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-5437317569960489333?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/5437317569960489333/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/06/xkcd-knapsack-solution.html#comment-form' title='31 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/5437317569960489333'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/5437317569960489333'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/06/xkcd-knapsack-solution.html' title='XKCD Knapsack Solution'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>31</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-6756447778684672429</id><published>2009-05-31T09:48:00.001+01:00</published><updated>2009-05-31T09:48:54.719+01:00</updated><title type='text'>Zed and community</title><content type='html'>Who is Zed?&lt;br&gt;&lt;br /&gt;Zed it seems knows about his blogging style: asking &lt;a&lt;br /&gt; href="http://www.zedshaw.com/blog/2009-02-27.html"&gt;questions&lt;/a&gt;&lt;br /&gt;as statements;and &lt;a&lt;br /&gt; href="http://www.zedshaw.com/rants/rails_is_a_ghetto.html"&gt;ranting&lt;/a&gt;.but&lt;br /&gt;it seems that he has written good code for the Rails community in the&lt;br /&gt;past and has earned some peoples respect. Now he is a new member of the&lt;br /&gt;Python community I would hope that current members realize his style&lt;br /&gt;and try not to emulate it. &lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Zed may be here for a long stay, or gone tomorrow, but I wouldn't want&lt;br /&gt;the lasting effect to be a rise in the abrasiveness of the Python&lt;br /&gt;community, or an &lt;span style="font-style: italic;"&gt;unthinking&lt;/span&gt;&lt;br /&gt;abandonment of community &amp;nbsp;practices. Even if Zed does produce&lt;br /&gt;Pythons Holy Grail, we have to remember that that is software.&lt;br /&gt;Community&amp;nbsp; matters,&amp;nbsp; and we have to work with the&lt;br /&gt;Zeds, the Alex's, the Xah's, the Tim's without being seen to sink to&lt;br /&gt;the lowest common denominator.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-6756447778684672429?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/6756447778684672429/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/05/zed-and-community.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/6756447778684672429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/6756447778684672429'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/05/zed-and-community.html' title='Zed and community'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-5063812569422220722</id><published>2009-05-23T04:50:00.001+01:00</published><updated>2009-05-23T04:50:53.079+01:00</updated><title type='text'>Pipe Fitting with Python Generators</title><content type='html'>I was investigating the Hofstadter-Conway &lt;a&lt;br /&gt; href="http://mathworld.wolfram.com/Hofstadter-Conway10000-DollarSequence.html"&lt;br /&gt; target="_blank"&gt;$10,000 sequence&lt;/a&gt; which, for&lt;br /&gt;mathematics, has a very&lt;a&lt;br /&gt; href="http://www.nytimes.com/1988/08/30/science/intellectual-duel-brash-challenge-swift-response.html"&lt;br /&gt; target="_blank"&gt; interesting story&lt;/a&gt;. &amp;nbsp;To&lt;br /&gt;'follow the money', you have to generate the sequence of values and&lt;br /&gt;calculate maxima and minima of the sequence values so I decided to&lt;br /&gt;create a generator of the sequence values and pass it through filters&lt;br /&gt;that would emit local maxima/minima. I ended up with something like:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;high_generator =&lt;br /&gt;maxima(sequence_generator())&lt;br&gt;&lt;br /&gt;highs = [high_generator.next() for i in range(1000)]&lt;br&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Now I just hated the nested call of generators. If it were a Unix&lt;br /&gt;shell, I would have hoped to have written:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;sequence_generator |&lt;br /&gt;maxima |head 1000 &amp;gt; highs&lt;br&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Notice how the data flows from source at the left to sink at the right.&lt;br /&gt;I like that.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I spent some time trying to use classes and redefine bitwise or for&lt;br /&gt;class instances, but it was looking messy and my heart wasn't really in&lt;br /&gt;a class based solution.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I left it for a week. And in that week I remembered seeing a function&lt;br /&gt;called pipe being used to pipe things so decided to write my own pipe&lt;br /&gt;function for combining generators in a more natural way.&lt;br&gt;&lt;br /&gt;&lt;h3&gt;Pipe&lt;/h3&gt;&lt;br /&gt;What I wanted was a function called pipe, that when called with several&lt;br /&gt;generators, returned a nested call of all its arguments, with the&lt;br /&gt;leftmost argument being in the center of the nest. For example, a call&lt;br /&gt;of:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px; font-family: monospace;"&gt;pipe(a,b,c,d)&lt;/div&gt;&lt;br /&gt;Would return the equivalent of:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px; font-family: monospace;"&gt;d(c(b(a)))&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;The eventual definition turned out to be quite straight-forward:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#804040"&gt;&lt;b&gt;&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;pipe&lt;/font&gt;(*cmds):&lt;br&gt;    '''&lt;font&lt;br /&gt; color="#ff00ff"&gt; pipe(a,b,c,d, ...) -&amp;gt; yield from ...d(c(b(a())))&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;    &lt;/font&gt;'''&lt;br&gt;    gen = cmds[0]&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; cmd &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; cmds[1:]:&lt;br&gt;        gen = cmd(gen)&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; x &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; gen:&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;yield&lt;/b&gt;&lt;/font&gt; x&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;&lt;br&gt;&lt;br /&gt;&lt;/h3&gt;&lt;br /&gt;&lt;h3&gt;Pipe in use&lt;/h3&gt;&lt;br /&gt;Lets create some simple generators; &lt;span&lt;br /&gt; style="font-family: monospace;"&gt;count&lt;/span&gt; is just&lt;br /&gt;itertools.count; &lt;span style="font-family: monospace;"&gt;sqr&lt;br /&gt;&lt;/span&gt;yields the square of items on its input iterator&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#a020f0"&gt;from&lt;/font&gt; itertools &lt;font&lt;br /&gt; color="#a020f0"&gt;import&lt;/font&gt; count&lt;br&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;sqr&lt;/font&gt;(x):&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;    for&lt;/b&gt;&lt;/font&gt; val &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; x:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;        yield&lt;/b&gt;&lt;/font&gt; val*val&lt;br&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I can now generate the squares of integers:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; p = pipe(count(), sqr)&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; [p.next() &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; range(5)]&lt;br&gt;[0, 1, 4, 9, 16]&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;But I need a more complex definition for head as it needs to have a&lt;br /&gt;parameter of the maximum number of items to pass through.&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;head&lt;/font&gt;(n):&lt;br&gt;    '''&lt;font&lt;br /&gt; color="#ff00ff"&gt; return a generator that passes through at most n items&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;    &lt;/font&gt;'''&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;head&lt;/font&gt;(x):&lt;br&gt;        i = n&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; val &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; x:&lt;br&gt;            &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; i&amp;gt;0:&lt;br&gt;                i -= 1&lt;br&gt;                &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;yield&lt;/b&gt;&lt;/font&gt; val&lt;br&gt;            &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt;:&lt;br&gt;                &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;raise&lt;/b&gt;&lt;/font&gt; StopIteration&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; head&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;And now with head I can more naturally express nested generator&lt;br /&gt;functions as I can stop an infinite generator stream easily for example:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; list(pipe(count(), sqr, head(4)))&lt;br&gt;[0, 1, 4, 9]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; pipe(count(), sqr, head(10)):&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; i,&lt;br&gt;&lt;br&gt;0 1 4 9 16 25 36 49 64 81&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h3&gt;Generalized function generator and filter&lt;/h3&gt;&lt;br /&gt;I thought it might be handy to have a function that skipped an input if&lt;br /&gt;the prefilter(input) was false; applied a given function, fn(input) to&lt;br /&gt;the input stream and passed on fn(input) to the output if&lt;br /&gt;postfilter(fn(input)) was true. Think of a stream of data. You can&lt;br /&gt;filter it, apply a function to it, or filter after applying the&lt;br /&gt;function - all via this pipe filter. I called it fnf for function&lt;br /&gt;filter:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;fnf&lt;/font&gt;(fn, prefilter=None, postfilter=None):&lt;br&gt;    '''&lt;font&lt;br /&gt; color="#ff00ff"&gt; functionfilter:&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;            for s in x:&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;                yield fn(s) subject to prefilter(s), postfilter(fn(s)) returning True if present,&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;                or skip this s&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;    &lt;/font&gt;'''&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;_fnf&lt;/font&gt;(x):&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; s &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; x:&lt;br&gt;            &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; prefilter &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt; None &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; prefilter(s):&lt;br&gt;                fns = fn(s)&lt;br&gt;                &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; postfilter &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt; None &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;or&lt;/b&gt;&lt;/font&gt; postfilter(fns):&lt;br&gt;                    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;yield&lt;/b&gt;&lt;/font&gt; fns&lt;br&gt;    _fnf.__doc__ = '&lt;font&lt;br /&gt; color="#ff00ff"&gt;_fnf = fnf(%s, %s, %s)&lt;/font&gt;' %(fn, prefilter, postfilter)&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; _fnf&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I'll show fnf in action. &lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font color="#0000ff"&gt;# turns the input stream of numbers, x into a stream of tuples x,x/2.0&lt;/font&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;n_nby2&lt;/font&gt;(x): &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; x, x/2.0&lt;br&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; list(pipe( count(), sqr, head(5), &lt;span&lt;br /&gt; style="font-weight: bold; text-decoration: underline;"&gt;fnf&lt;/span&gt;(n_nby2) ))&lt;br&gt;[(0, 0.0), (1, 0.5), (4, 2.0), (9, 4.5), (16, 8.0)]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#0000ff"&gt;# Lets create a prefilter&lt;/font&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;even&lt;/font&gt;(x): &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; x%2 == 0&lt;br&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; list(pipe( count(), sqr, head(5), fnf(n_nby2,&lt;span&lt;br /&gt; style="font-weight: bold; text-decoration: underline;"&gt;even&lt;/span&gt;) ))&lt;br&gt;[(0, 0.0), (4, 2.0), (16, 8.0)]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#0000ff"&gt;# And now a postfilter which must work on the result of applying fn&lt;/font&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;frac&lt;/font&gt;(x): &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; int(x[1]) != x[1]&lt;br&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; list(pipe( count(), sqr, head(5), fnf(n_nby2,&lt;span&lt;br /&gt; style="font-style: italic; font-weight: bold;"&gt;None&lt;/span&gt;,&lt;span&lt;br /&gt; style="font-weight: bold; text-decoration: underline;"&gt;frac&lt;/span&gt;) ))&lt;br&gt;[(1, 0.5), (9, 4.5)]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#0000ff"&gt;# Note the presence of &lt;span&lt;br /&gt; style="font-weight: bold; font-style: italic;"&gt;None&lt;/span&gt; in the above call as we don't use a prefilter&lt;/font&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Thats it for now with the pipe fitting. I do have a tee function for&lt;br /&gt;printing intermediate results, &amp;nbsp;but it's &lt;span&lt;br /&gt; style="text-decoration: line-through;"&gt;late&lt;/span&gt;&lt;br /&gt;early and I'm tired....&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;- Paddy.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-5063812569422220722?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/5063812569422220722/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/05/pipe-fitting-with-python-generators.html#comment-form' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/5063812569422220722'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/5063812569422220722'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/05/pipe-fitting-with-python-generators.html' title='Pipe Fitting with Python Generators'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-8055366745362928445</id><published>2009-05-13T22:15:00.000+01:00</published><updated>2009-05-13T22:17:15.234+01:00</updated><title type='text'>Extended unpacking in Python 3.0</title><content type='html'>After reading about &lt;a&lt;br /&gt; href="http://www.rosettacode.org/wiki/Pattern_Matching"&lt;br /&gt; target="_blank"&gt;pattern matching&lt;/a&gt; on Rosetta Code,&lt;br /&gt;I wondered, (and still am wondering), if it has anything to do with&lt;br /&gt;list unpacking in Python, which lead me to do some simple explorations&lt;br /&gt;of the &lt;a href="http://www.python.org/dev/peps/pep-3132/"&lt;br /&gt; target="_blank"&gt;extended iterable unpacking&lt;/a&gt; that&lt;br /&gt;is new in Python 3.0.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h3&gt;Introducing a star&lt;/h3&gt;&lt;br /&gt;The feature builds on the pre-existing capability of being able to&lt;br /&gt;unpack a list or tuple into multiple names in Python 2.x, so in Python&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2.x&lt;/span&gt; you&lt;br /&gt;could do:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;" border="2"&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font color="#a020f0"&gt;import&lt;/font&gt; platform&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; platform.python_version()&lt;br&gt;'&lt;font&lt;br /&gt; color="#ff00ff"&gt;2.6.1&lt;/font&gt;'&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; lst = [1,2,3]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; a,b,c = lst&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; print a,b,c&lt;br&gt;1 2 3&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; tpl = (1,2,3)&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; a,b,c = tpl&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; print a,b,c&lt;br&gt;1 2 3&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; iter = (x for x in range(4))&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; iter&lt;br&gt;&amp;lt;generator object &amp;lt;genexpr&amp;gt; at 0x01300468&amp;gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; a,b,c,d = iter&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; print a,b,c,d&lt;br&gt;0 1 2 3&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#0000ff"&gt;# You could also do the (fancy), but non-* stuff too&lt;/font&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; a,b,(c,d) = (1,2,(3,4))&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; a,b,c,d&lt;br&gt;1 2 3 4&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#0000ff"&gt;# But not&lt;br&gt;&lt;/font&gt;&amp;gt;&amp;gt;&amp;gt; a,*b = (1,2,3,4)&lt;br&gt;SyntaxError: invalid syntax&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;br&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;In Python 3.0 you get all of the above plus the ability to 'soak up'&lt;br /&gt;the&amp;nbsp;rest of the values using &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;*&lt;/span&gt; (which I pronounce&lt;br /&gt;as 'star' in this&lt;br /&gt;context).&lt;br&gt;&lt;br /&gt;It is similar to how you can use *args in a function definition to&lt;br /&gt;assign extra positional arguments to a name. In an assignment however&lt;br /&gt;it means &lt;span style="font-style: italic;"&gt;'take&lt;br /&gt;whatever's left of the what is being assigned and assign it to me as a&lt;br /&gt;list&lt;/span&gt;'.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Here are some examples:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font color="#a020f0"&gt;import&lt;/font&gt; platform&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; platform.python_version()&lt;br&gt;'&lt;font&lt;br /&gt; color="#ff00ff"&gt;3.0.1&lt;/font&gt;'&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; a,*b = [1,2,3,4]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt;(a,b, sep='&lt;font&lt;br /&gt; color="#ff00ff"&gt;    &lt;/font&gt;')&lt;br&gt;1    [2, 3, 4]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; a = [1,2,3,4]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#0000ff"&gt;# Note the comma after the *b to make it a tuple&lt;/font&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; *b, = [1,2,3,4]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; a == b&lt;br&gt;True&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#0000ff"&gt;# Only one * per iterable (or sub-iterable) being assigned&lt;/font&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; *a,*b = [1,2,3,4]&lt;br&gt;&lt;span&lt;br /&gt; style="color: red;"&gt;SyntaxError: two starred expressions &lt;/span&gt;&lt;font&lt;br /&gt; style="color: red;" color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt;&lt;span&lt;br /&gt; style="color: red;"&gt; assignment (&amp;lt;pyshell&lt;/span&gt;&lt;font&lt;br /&gt; style="color: red;" color="#0000ff"&gt;#87&amp;gt;, line 1)&lt;/font&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#0000ff"&gt;# but note:&lt;/font&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; a,*b,(c,*d) = [1,2,3,[4,5,6]]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt;(a,b,c,d, sep='&lt;font&lt;br /&gt; color="#ff00ff"&gt;    &lt;/font&gt;')&lt;br&gt;1    [2, 3]    4    [5, 6]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#0000ff"&gt;# Notice that &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;*&lt;/span&gt; &lt;span&lt;br /&gt; style="text-decoration: underline;"&gt;always&lt;/span&gt; creates a list&lt;/font&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; *a, = (1,2,3)&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; a&lt;br&gt;&lt;span&lt;br /&gt; style="font-weight: bold; color: rgb(0, 153, 0);"&gt;[&lt;/span&gt;1, 2, 3&lt;span&lt;br /&gt; style="font-weight: bold; color: rgb(0, 153, 0);"&gt;]&lt;/span&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; a,b,(*c,) = (x &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; x&amp;lt;2 &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt; range(5) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; x &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; range(3))&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt;(a,b,c, sep='&lt;font&lt;br /&gt; color="#ff00ff"&gt;    &lt;/font&gt;')&lt;br&gt;0    1    [0, 1, 2, 3, 4]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#0000ff"&gt;# Although you can have only one &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;*&lt;/span&gt; per (sub)iterable, its position is flexible&lt;/font&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; a,*b,c = [1,2,3,4]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; b&lt;br&gt;[2, 3]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; *b,a,c = [1,2,3,4]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; b&lt;br&gt;[1, 2]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; a,c,*b = [1,2,3,4]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#0000ff"&gt;# And look!&lt;/font&gt;&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; a,c,*b,d,e = [1,2,3,4]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; b&lt;br&gt;[]&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; a,b,c,d,e&lt;br&gt;(1, [], 2, 3, 4)&lt;br&gt;&amp;gt;&amp;gt;&amp;gt; &lt;font&lt;br /&gt; color="#0000ff"&gt;# So &lt;span style="font-weight: bold;"&gt;*&lt;/span&gt; can accumulate &lt;span&lt;br /&gt; style="text-decoration: underline;"&gt;no&lt;/span&gt; values in some cases&lt;/font&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;I'm looking forward to using this feature in 3.1.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-8055366745362928445?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/8055366745362928445/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/05/extended-unpacking-in-python-30.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/8055366745362928445'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/8055366745362928445'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/05/extended-unpacking-in-python-30.html' title='Extended unpacking in Python 3.0'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-1800055503990534867</id><published>2009-05-12T06:30:00.000+01:00</published><updated>2009-05-12T06:34:13.203+01:00</updated><title type='text'>Critique of pseudocode explanations of the Closest Pair Algorithm</title><content type='html'>I watched &lt;a href="http://www.rosettacode.org/wiki/Closest_pair_problem"&gt;this&lt;br /&gt;task&lt;/a&gt; on Rosetta Code from its inception on the 6&lt;sup&gt;th&lt;/sup&gt; of&lt;br /&gt;May, but had problems understanding the pseudo-code given, and some&lt;br /&gt;of the stuff I googled too. after a couple of days though I was more&lt;br /&gt;familiar with attempts at &lt;i&gt;O(nlog(n))&lt;/i&gt; divide-n-conquer&lt;br /&gt;algorithms having seen a few and happened to find &lt;a href="http://www.cs.iupui.edu/%7Exkzou/teaching/CS580/Divide-and-conquer-closestPair.ppt"&gt;this&lt;/a&gt;&lt;br /&gt;explanation (.ppt file) where it seemed to click for me.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;After problems with the other references I thought I might go&lt;br /&gt;through and identify what I found problematic with them.&lt;/p&gt;&lt;br /&gt;&lt;h3 class="western"&gt;The Rosetta Code Pseudo-code:&lt;/h3&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre style="margin-left: 1.25cm;"&gt;&lt;b&gt;closestPair&lt;/b&gt; of P(1), P(2), ... P(N)&lt;br /&gt;&lt;b&gt;if&lt;/b&gt; N ≤ 3 &lt;b&gt;then&lt;/b&gt;&lt;br /&gt;  &lt;b&gt;return&lt;/b&gt; closest points of P using brute-force algorithm&lt;br /&gt;&lt;b&gt;else&lt;/b&gt;&lt;br /&gt;  xP ← P ordered by the x coordinate, in ascending order&lt;br /&gt;  P&lt;sub&gt;L&lt;/sub&gt; ← points of xP from 1 to ⌈N/2⌉&lt;br /&gt;  P&lt;sub&gt;R&lt;/sub&gt; ← points of xP from ⌈N/2⌉+1 to N&lt;br /&gt;  (d&lt;sub&gt;L&lt;/sub&gt;, pair&lt;sub&gt;L&lt;/sub&gt;) ← &lt;i&gt;closestPair&lt;/i&gt; of P&lt;sub&gt;L&lt;/sub&gt;&lt;br /&gt;&lt;br /&gt;  (d&lt;sub&gt;R&lt;/sub&gt;, pair&lt;sub&gt;R&lt;/sub&gt;) ← &lt;i&gt;closestPair&lt;/i&gt; of P&lt;sub&gt;R&lt;/sub&gt;&lt;br /&gt;  (d&lt;sub&gt;min&lt;/sub&gt;, pair&lt;sub&gt;min&lt;/sub&gt;) ← (d&lt;sub&gt;R&lt;/sub&gt;, pair&lt;sub&gt;R&lt;/sub&gt;)&lt;br /&gt;  &lt;b&gt;if&lt;/b&gt; d&lt;sub&gt;L&lt;/sub&gt; &amp;lt; d&lt;sub&gt;R&lt;/sub&gt; &lt;b&gt;then&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;    (d&lt;sub&gt;min&lt;/sub&gt;, pair&lt;sub&gt;min&lt;/sub&gt;) ← (d&lt;sub&gt;L&lt;/sub&gt;, pair&lt;sub&gt;L&lt;/sub&gt;)&lt;br /&gt;  &lt;b&gt;endif&lt;/b&gt;&lt;br /&gt;  x&lt;sub&gt;M&lt;/sub&gt; ← xP(⌈N/2⌉)&lt;sub&gt;x&lt;/sub&gt;&lt;br /&gt;&lt;br /&gt;  S ← { p ∈ xP&amp;nbsp;: |x&lt;sub&gt;M&lt;/sub&gt; - p&lt;sub&gt;x&lt;/sub&gt;| &amp;lt; d&lt;sub&gt;min&lt;/sub&gt; }&lt;br /&gt;  yP ← S ordered by the y coordinate, in ascending order&lt;br /&gt;  nP ← number of points in yP&lt;br /&gt;  (closest, closestPair) ← (d&lt;sub&gt;min&lt;/sub&gt;, pair&lt;sub&gt;min&lt;/sub&gt;)&lt;br /&gt;  &lt;b&gt;for&lt;/b&gt; i &lt;b&gt;from&lt;/b&gt; 1 &lt;b&gt;to&lt;/b&gt; nP - 1&lt;br /&gt;    k ← i + 1&lt;br /&gt;    &lt;b&gt;while&lt;/b&gt; k ≤ nP &lt;b&gt;and&lt;/b&gt; yP(k)&lt;sub&gt;y&lt;/sub&gt; - yP(k)&lt;sub&gt;y&lt;/sub&gt; &amp;lt; d&lt;sub&gt;min&lt;/sub&gt;&lt;br /&gt;&lt;br /&gt;      &lt;b&gt;if&lt;/b&gt; |yP(k) - yP(i)| &amp;lt; closest &lt;b&gt;then&lt;/b&gt;&lt;br /&gt;        (closest, closestPair) ← (|yP(k) - yP(i)|, {yP(k), yP(i)})&lt;br /&gt;      &lt;b&gt;endif&lt;/b&gt;&lt;br /&gt;      k ← k + 1&lt;br /&gt;    &lt;b&gt;endwhile&lt;/b&gt;&lt;br /&gt;  &lt;b&gt;return&lt;/b&gt; closest, closestPair&lt;br /&gt;&lt;br /&gt;&lt;b&gt;endif&lt;/b&gt;&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;The author had noted that the above could have problems so I was&lt;br /&gt;warned, but still started by trying to follow the above. I was&lt;br /&gt;blindly following the pseudo-code until I got the the statement: x&lt;sub&gt;M&lt;/sub&gt;&lt;br /&gt;← xP(⌈N/2⌉)&lt;sub&gt;x&lt;/sub&gt; which I couldn't understand.&lt;br /&gt; &lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This prompted my wider search for a better explanation. After&lt;br /&gt;finding it (linked in the first paragraph), I modified my Python&lt;br /&gt;program to follow the new explanation.&lt;/p&gt;&lt;br /&gt;&lt;h3 class="western"&gt;The RC references&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;There were several references quoted. &lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;br /&gt; &lt;li&gt;&lt;p&gt;&lt;b&gt;The Wikipedia article&lt;/b&gt; &lt;br&gt;Did not give pseudo-code &lt;br /&gt; &lt;/p&gt;&lt;br /&gt; &lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href="http://www.cs.mcgill.ca/%7Ecs251/ClosestPair/ClosestPairDQ.html"&gt;Closest&lt;br /&gt; Pair (McGill)&lt;/a&gt; &lt;br&gt;Section 3.4 on improving their previous&lt;br /&gt; O(&lt;i&gt;n&lt;/i&gt;log&lt;sup&gt;2&lt;/sup&gt;&lt;i&gt;n&lt;/i&gt;)  into an O(&lt;i&gt;n&lt;/i&gt;log&lt;i&gt;n&lt;/i&gt;) &lt;br /&gt; algorithm I found to be very vague. Just how do you “returning&lt;br /&gt; the points in each set in sorted order by &lt;i&gt;y&lt;/i&gt;-coordinate “&lt;br /&gt; without doing an nlogn sort leading again to an  O(&lt;i&gt;n&lt;/i&gt;log&lt;sup&gt;2&lt;/sup&gt;&lt;i&gt;n&lt;/i&gt;)&lt;br /&gt; solution?&lt;/p&gt;&lt;br /&gt;&lt;br /&gt; &lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href="http://www.cs.ucsb.edu/%7Esuri/cs235/ClosestPair.pdf"&gt;Closest&lt;br /&gt; Pair (UCBS)&lt;/a&gt; &lt;br&gt;This seems to concur with my preferred reference&lt;br /&gt; but is given at a higher level than pseudo-code, and so would be&lt;br /&gt; harder to implement from the description given.&lt;/p&gt;&lt;br /&gt; &lt;/li&gt;&lt;li&gt;&lt;p&gt;&lt;a href="http://classes.cec.wustl.edu/%7Ecse241/handouts/closestpair.pdf"&gt;Closest&lt;br /&gt; pair (WUStL)&lt;/a&gt;  by Dr. Jeremy Buhler&lt;br&gt;Their seems to be a&lt;br /&gt; problem with having N, the number of points as an argument of the&lt;br /&gt; function. What if N is odd? The pseudo-code seems to rely on other&lt;br /&gt; material probably presented in a class and is at a higher level than&lt;br /&gt; my preferred solution as it seems to be set as an exercise for&lt;br /&gt; students.&lt;/p&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h3 class="western"&gt;My Python Solution&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;The only tests done is to generate random points and compare the&lt;br /&gt;brute force algorithms solution with that of the divide and conquer.&lt;/p&gt;&lt;br /&gt;&lt;pre style="margin-left: 1.25cm;"&gt;'''&lt;br /&gt;&lt;br /&gt;&lt;font color="#ff00ff"&gt;  Compute nearest pair of points using two algorithms&lt;/font&gt;&lt;br /&gt;&lt;font color="#ff00ff"&gt;  &lt;/font&gt;&lt;br /&gt;&lt;font color="#ff00ff"&gt;  First algorithm is 'brute force' comparison of every possible pair.&lt;/font&gt;&lt;br /&gt;&lt;font color="#ff00ff"&gt;  Second, 'divide and conquer', is based on:&lt;/font&gt;&lt;br /&gt;&lt;font color="#ff00ff"&gt;    www.cs.iupui.edu/~xkzou/teaching/CS580/Divide-and-conquer-closestPair.ppt &lt;/font&gt;&lt;br /&gt;'''&lt;br /&gt;&lt;br /&gt;&lt;font color="#a020f0"&gt;from&lt;/font&gt; random &lt;font color="#a020f0"&gt;import&lt;/font&gt; randint&lt;br /&gt;&lt;br /&gt;infinity = float('&lt;font color="#ff00ff"&gt;inf&lt;/font&gt;')&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;font color="#0000ff"&gt;# Note the use of complex numbers to represent 2D points making distance == abs(P1-P2)&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font color="#008080"&gt;bruteForceClosestPair&lt;/font&gt;(point):&lt;br /&gt;    numPoints = len(point)&lt;br /&gt;    &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; numPoints &amp;lt; 2:&lt;br /&gt;        &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; infinity, (None, None)&lt;br /&gt;    &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; min( ((abs(point[i] - point[j]), (point[i], point[j]))&lt;br /&gt;                 &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; range(numPoints-1)&lt;br /&gt;                 &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; j &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; range(i+1,numPoints)),&lt;br /&gt;                key=&lt;font color="#804040"&gt;&lt;b&gt;lambda&lt;/b&gt;&lt;/font&gt; x: x[0])&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font color="#008080"&gt;closestPair&lt;/font&gt;(point):&lt;br /&gt;    xP = sorted(point, key= &lt;font color="#804040"&gt;&lt;b&gt;lambda&lt;/b&gt;&lt;/font&gt; p: p.real)&lt;br /&gt;    yP = sorted(point, key= &lt;font color="#804040"&gt;&lt;b&gt;lambda&lt;/b&gt;&lt;/font&gt; p: p.imag)&lt;br /&gt;    &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; _closestPair(xP, yP)&lt;br /&gt;&lt;br /&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font color="#008080"&gt;_closestPair&lt;/font&gt;(xP, yP):&lt;br /&gt;    numPoints = len(xP)&lt;br /&gt;    &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; numPoints &amp;lt;= 3:&lt;br /&gt;        &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; bruteForceClosestPair(xP)&lt;br /&gt;    Pl = xP[:numPoints/2]&lt;br /&gt;    Pr = xP[numPoints/2:]&lt;br /&gt;    Yl, Yr = [], []&lt;br /&gt;    xDivider = Pl[-1].real&lt;br /&gt;    &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; p &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; yP:&lt;br /&gt;        &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; p.real &amp;lt;= xDivider:&lt;br /&gt;            Yl.append(p)&lt;br /&gt;        &lt;font color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt;:&lt;br /&gt;            Yr.append(p)&lt;br /&gt;    dl, pairl = _closestPair(Pl, Yl)&lt;br /&gt;    dr, pairr = _closestPair(Pr, Yr)&lt;br /&gt;    dm, pairm = (dl, pairl) &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; dl &amp;lt; dr &lt;font color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt; (dr, pairr)&lt;br /&gt;    &lt;font color="#0000ff"&gt;# Points within dm of xDivider sorted by Y coord&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;    closeY = [p &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; p &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; yP  &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; abs(p.real - xDivider) &amp;lt; dm]&lt;br /&gt;    numCloseY = len(closeY)&lt;br /&gt;    &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; numCloseY &amp;gt; 1:&lt;br /&gt;        &lt;font color="#0000ff"&gt;# There is a proof that you only need compare a max of 7 other points&lt;/font&gt;&lt;br /&gt;&lt;br /&gt;        closestY = min( ((abs(closeY[i] - closeY[j]), (closeY[i], closeY[j]))&lt;br /&gt;                         &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; range(numCloseY-1)&lt;br /&gt;                         &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; j &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; range(i+1,min(i+8, numCloseY))),&lt;br /&gt;                        key=&lt;font color="#804040"&gt;&lt;b&gt;lambda&lt;/b&gt;&lt;/font&gt; x: x[0])&lt;br /&gt;        &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; (dm, pairm) &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; dm &amp;lt;= closestY[0] &lt;font color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt; closestY&lt;br /&gt;    &lt;font color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt;:&lt;br /&gt;        &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; dm, pairm&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font color="#008080"&gt;times&lt;/font&gt;():&lt;br /&gt;    '''&lt;font color="#ff00ff"&gt; Time the different functions&lt;/font&gt;&lt;br /&gt;&lt;font color="#ff00ff"&gt;    &lt;/font&gt;'''&lt;br /&gt;    &lt;font color="#a020f0"&gt;import&lt;/font&gt; timeit&lt;br /&gt;&lt;br /&gt;    functions = [bruteForceClosestPair, closestPair]&lt;br /&gt;    &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; f &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; functions:&lt;br /&gt;        &lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; '&lt;font color="#ff00ff"&gt;Time for&lt;/font&gt;', f.__name__, timeit.Timer(&lt;br /&gt;            '&lt;font color="#ff00ff"&gt;%s(pointList)&lt;/font&gt;' % f.__name__,&lt;br /&gt;            '&lt;font color="#ff00ff"&gt;from closestpair import %s, pointList&lt;/font&gt;' % f.__name__).timeit(number=1)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;pointList = [randint(0,1000)+1j*randint(0,1000) &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; range(2000)]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; __name__ == '&lt;font color="#ff00ff"&gt;__main__&lt;/font&gt;':&lt;br /&gt;    pointList = [(5+9j), (9+3j), (2+0j), (8+4j), (7+4j), (9+10j), (1+9j), (8+2j), 10j, (9+6j)]&lt;br /&gt;    &lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; pointList&lt;br /&gt;    &lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; '&lt;font color="#ff00ff"&gt;  bruteForceClosestPair:&lt;/font&gt;', bruteForceClosestPair(pointList)&lt;br /&gt;    &lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; '&lt;font color="#ff00ff"&gt;            closestPair:&lt;/font&gt;', closestPair(pointList)&lt;br /&gt;    &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; range(10):&lt;br /&gt;        pointList = [randint(0,10)+1j*randint(0,10) &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; range(10)]&lt;br /&gt;        &lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; '&lt;font color="#6a5acd"&gt;\n&lt;/font&gt;', pointList&lt;br /&gt;        &lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; '&lt;font color="#ff00ff"&gt; bruteForceClosestPair:&lt;/font&gt;', bruteForceClosestPair(pointList)&lt;br /&gt;        &lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; '&lt;font color="#ff00ff"&gt;           closestPair:&lt;/font&gt;', closestPair(pointList)&lt;br /&gt;    &lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; '&lt;font color="#6a5acd"&gt;\n&lt;/font&gt;'&lt;br /&gt;    times()&lt;br /&gt;    times()&lt;br /&gt;    times()&lt;/pre&gt;&lt;h4 class="western"&gt;&lt;br /&gt;&lt;br /&gt;Sample output:&lt;/h4&gt;&lt;br /&gt;&lt;p style="margin-bottom: 0cm;"&gt;&lt;br&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;pre style="margin-left: 1.25cm;"&gt;[(5+9j), (9+3j), (2+0j), (8+4j), (7+4j), (9+10j), (1+9j), (8+2j), 10j, (9+6j)]&lt;br /&gt;  bruteForceClosestPair: (1.0, ((8+4j), (7+4j)))&lt;br /&gt;            closestPair: (1.0, ((8+4j), (7+4j)))&lt;br /&gt;&lt;br /&gt;[(6+8j), (4+1j), 7j, (4+10j), (10+6j), (1+9j), (10+10j), (5+0j), (3+1j), (6+4j)]&lt;br /&gt; bruteForceClosestPair: (1.0, ((4+1j), (3+1j)))&lt;br /&gt;           closestPair: (1.0, ((3+1j), (4+1j)))&lt;br /&gt;&lt;br /&gt;[(5+5j), (10+9j), 3j, (6+1j), (9+5j), 1j, (8+0j), 8j, (3+2j), (10+4j)]&lt;br /&gt; bruteForceClosestPair: (1.4142135623730951, ((9+5j), (10+4j)))&lt;br /&gt;           closestPair: (1.4142135623730951, ((9+5j), (10+4j)))&lt;br /&gt;&lt;br /&gt;[(9+2j), (1+2j), 5j, (10+0j), (6+6j), (6+4j), (5+1j), (2+5j), (8+6j), (3+2j)]&lt;br /&gt; bruteForceClosestPair: (2.0, ((1+2j), (3+2j)))&lt;br /&gt;           closestPair: (2.0, ((6+6j), (6+4j)))&lt;br /&gt;&lt;br /&gt;[(2+3j), (9+0j), (9+7j), 8j, (4+5j), (6+7j), (6+2j), (3+3j), (3+10j), (7+5j)]&lt;br /&gt; bruteForceClosestPair: (1.0, ((2+3j), (3+3j)))&lt;br /&gt;           closestPair: (1.0, ((2+3j), (3+3j)))&lt;br /&gt;&lt;br /&gt;[(7+2j), (2+10j), (3+7j), (8+6j), (2+1j), 3j, (8+5j), (6+9j), (1+0j), 0j]&lt;br /&gt; bruteForceClosestPair: (1.0, ((8+6j), (8+5j)))&lt;br /&gt;           closestPair: (1.0, ((8+6j), (8+5j)))&lt;br /&gt;&lt;br /&gt;[(10+7j), (6+3j), (2+7j), (3+6j), (9+3j), (8+5j), (5+7j), (3+10j), 5j, (3+7j)]&lt;br /&gt; bruteForceClosestPair: (1.0, ((2+7j), (3+7j)))&lt;br /&gt;           closestPair: (1.0, ((3+6j), (3+7j)))&lt;br /&gt;&lt;br /&gt;[(4+6j), (5+4j), 2j, (7+0j), 4j, (6+5j), (7+5j), (8+9j), (10+5j), (8+2j)]&lt;br /&gt; bruteForceClosestPair: (1.0, ((6+5j), (7+5j)))&lt;br /&gt;           closestPair: (1.0, ((6+5j), (7+5j)))&lt;br /&gt;&lt;br /&gt;[(4+0j), (7+9j), 7j, 8j, (7+1j), (2+5j), (7+3j), (1+3j), (3+9j), (10+7j)]&lt;br /&gt; bruteForceClosestPair: (1.0, (7j, 8j))&lt;br /&gt;           closestPair: (1.0, (7j, 8j))&lt;br /&gt;&lt;br /&gt;[(9+1j), (5+0j), (8+3j), (6+9j), (3+7j), (4+6j), (7+6j), (8+6j), (10+8j), (2+5j)]&lt;br /&gt; bruteForceClosestPair: (1.0, ((7+6j), (8+6j)))&lt;br /&gt;           closestPair: (1.0, ((7+6j), (8+6j)))&lt;br /&gt;&lt;br /&gt;[(2+2j), (10+8j), (3+0j), (8+0j), (1+1j), (6+5j), 10j, (6+8j), (10+4j), (4+10j)]&lt;br /&gt; bruteForceClosestPair: (1.4142135623730951, ((2+2j), (1+1j)))&lt;br /&gt;           closestPair: (1.4142135623730951, ((1+1j), (2+2j)))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Time for bruteForceClosestPair 4.59288093878&lt;br /&gt;Time for closestPair 0.120782948671&lt;br /&gt;Time for bruteForceClosestPair 5.00096353028&lt;br /&gt;Time for closestPair 0.120047939054&lt;br /&gt;Time for bruteForceClosestPair 4.86709875138&lt;br /&gt;Time for closestPair 0.123363723602&lt;/pre&gt;&lt;p&gt;&lt;br /&gt;Note how much slower the brute force algorithm is for only 2000&lt;br /&gt;points.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;br&gt;&lt;br&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;(Oh, I guess I should add that the above is all my own work –&lt;br /&gt;students might want to say the same).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-1800055503990534867?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/1800055503990534867/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/05/critique-of-pseudocode-explanations-of_12.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1800055503990534867'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1800055503990534867'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/05/critique-of-pseudocode-explanations-of_12.html' title='Critique of pseudocode explanations of the Closest Pair Algorithm'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-3851898976146372943</id><published>2009-05-10T01:54:00.001+01:00</published><updated>2009-05-10T01:54:32.327+01:00</updated><title type='text'>On "RailsConf: What killed Smalltalk could kill Ruby, too"</title><content type='html'>&lt;div xmlns=''&gt;&lt;p style='margin-bottom: 0cm'&gt;Browsing Reddit introduced me to  &lt;a href='http://railsconf.blip.tv/file/2089545/'&gt;RailsConf: What killed Smalltalk could kill Ruby, too&lt;/a&gt; The keynote speech by Robert Martin. I found it to be quite interesting as I had been monitoring odd posts on the Rails community and its general attitude.&lt;/p&gt;&lt;p&gt;Some of the points made by Robert on why Smalltalk contracted in popularity included:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;p&gt;It was too easy to make a mess. &lt;br/&gt;And the mess was found late in the project timeline, leading to failed projects.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;Smalltakers didn't want to deal with the boring 'corporate' tasks. &lt;br/&gt;Leading to the rise of programmers using other languages to earn a corporate living.&lt;/p&gt;&lt;/li&gt;&lt;li&gt;&lt;p&gt;When Smalltalk was 'riding high', a tendency to look down on other languages. &lt;br/&gt;This would alienate the general population of programmers.&lt;/p&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Robert put in a big, recurring, plug for both TDD and refactoring IDEs as ways to keep Ruby alive.&lt;/p&gt;&lt;p&gt;One comment he made was that he thought that in the dynamic vs static typing, language wars: Dynamic won and cited as evidence that most mainstream 'static' languages such as Java, C++ and C# have ways to do dynamic type checking – although badly. I wouldn't go that far, as I suspect that little of the mindset of programming in a dynamic language such as Python would be adopted by a C# or Java programmer. I suspect that they will use the dynamism available to them as a last resort as part of a design pattern to solve a particular sub-problem.&lt;/p&gt;&lt;p&gt; &lt;br/&gt; &lt;br/&gt; &lt;/p&gt;&lt;br clear='left'/&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-3851898976146372943?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/3851898976146372943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/05/on-what-killed-smalltalk-could-kill.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/3851898976146372943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/3851898976146372943'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/05/on-what-killed-smalltalk-could-kill.html' title='On &amp;quot;RailsConf: What killed Smalltalk could kill Ruby, too&amp;quot;'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-1944255663798302652</id><published>2009-05-03T06:17:00.000+01:00</published><updated>2009-05-03T06:18:40.361+01:00</updated><title type='text'>Tech Issues For The Euro Elections</title><content type='html'>Elections for members of the European Parliament are &lt;a&lt;br /&gt; href="http://news.bbc.co.uk/1/hi/world/europe/7819889.stm"&lt;br /&gt; target="_blank"&gt;coming&lt;/a&gt; up soon. At the moment, it&lt;br /&gt;seems certain companies are lobbying to have &lt;a target="_blank"&lt;br /&gt; href="http://www.theregister.co.uk/2009/05/02/microsoft_open_source_eu_patents/"&gt;software&lt;br /&gt;patents&lt;/a&gt; &amp;nbsp;extended into Europe which is something I&lt;br /&gt;don't agree with, as on algorithms - how can you distinguish between&lt;br /&gt;the maths and the code? On something like look-and-feel of a GUI - how&lt;br /&gt;can you distinguish between the idea and its implementation? If you see&lt;br /&gt;that person A used a&amp;nbsp;pinching motion of the fingers to&lt;br /&gt;zoom-out centered on the pinch then I don't think that should stop&lt;br /&gt;person B from coding his own implementation using different code. I do&lt;br /&gt;think that the screen technology that allows a particular&lt;br /&gt;implementation of multi-touch should be patentable however.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;There is another tech issue that I need to talk to prospective&lt;br /&gt;candidates about: their stance on&lt;a&lt;br /&gt; href="http://www.theregister.co.uk/2008/04/04/ooxml_ec_investigation_iso/"&lt;br /&gt; target="_blank"&gt; ODF vs OOX ML&lt;/a&gt;, and more widely:&lt;br /&gt;their stance on the promotion of the use of open &lt;span&lt;br /&gt; style="text-decoration: underline;"&gt;standards&lt;/span&gt;&lt;br /&gt;within government.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Can't think of any more tech issues at the moment but if you can think&lt;br /&gt;of any...&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;P.S. Happy birthday to me. Happy birthday to me,...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-1944255663798302652?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/1944255663798302652/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/05/tech-issues-for-euro-elections.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1944255663798302652'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1944255663798302652'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/05/tech-issues-for-euro-elections.html' title='Tech Issues For The Euro Elections'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-6137917326288151518</id><published>2009-04-29T08:20:00.002+01:00</published><updated>2009-04-29T08:27:43.269+01:00</updated><title type='text'>Fight for the community you want</title><content type='html'>Someone &lt;a href="http://dyepot-teapot.com/2009/04/25/dear-fellow-rubyists/"&gt;took offence&lt;/a&gt; at a puerile and sexist presentation given at what is supposed to be a technical event in the Rails community. Good on them. The community is what &lt;u&gt;you&lt;/u&gt; make of it. &lt;br /&gt;&lt;br /&gt;"Using sex to sell spanners" doesn't make me think they are good spanners. &lt;br /&gt;&lt;br /&gt;- Paddy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-6137917326288151518?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/6137917326288151518/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/04/fight-for-community-you-want.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/6137917326288151518'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/6137917326288151518'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/04/fight-for-community-you-want.html' title='Fight for the community &lt;u&gt;you&lt;/u&gt; want'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-1956614544050315022</id><published>2009-04-21T22:40:00.001+01:00</published><updated>2009-04-21T22:40:42.027+01:00</updated><title type='text'>Monitoring a linux process as it reads files</title><content type='html'>I am processing 20 thousand files with some proprietary software and&lt;br /&gt;needed to monitor how far it got in reading the files. In my own Python&lt;br /&gt;version of the utility the reading of data was ten times faster than&lt;br /&gt;the subsequent processing and i wanted to find out if this proprietary&lt;br /&gt;solution, which was havinfg performance problems , was equally spending&lt;br /&gt;most of its time reading data.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;The proprietary program took a list of 20000 files to process as its&lt;br /&gt;first argument and I remembered that&amp;nbsp; on Linux, the /proc&lt;br /&gt;directory had info on running processes &amp;nbsp;and sure enough , the&lt;br /&gt;/proc/&amp;lt;process id&amp;gt;/fd directory had info on all the file&lt;br /&gt;descriptors currently open by the process as links. So by opening the&lt;br /&gt;list of files to in my editor and searching within it for the file name&lt;br /&gt;shown on &amp;nbsp;one of the file descriptors, I could gauge how many&lt;br /&gt;files been read so far.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I decided to automate the checking and wrote a shell script using&lt;br /&gt;cat/fgrep/gawk/... that then told me what line in the list of files to&lt;br /&gt;process the program was currently at.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Now I've had time to refine things to use mainly python but to&lt;br /&gt;demonstrate its use I also have to generate a test environment&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h3&gt;First create some test files to process&lt;/h3&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;bash$ &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;mkdir -p /tmp/test&lt;/span&gt;&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;bash$&amp;nbsp;&lt;span&lt;br /&gt; style="font-weight: bold;"&gt;for ((i=0; i &amp;lt; 100; i++))&lt;br /&gt;do touch /tmp/test/file$i ;done&lt;/span&gt;&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;bash$ &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;/bin/ls /tmp/test/file* &amp;gt;&lt;br /&gt;/tmp/test/all_files.lst&lt;/span&gt;&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;bash$ &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;head /tmp/test/all_files.lst&lt;/span&gt;&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;/tmp/test/file0&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;/tmp/test/file1&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;/tmp/test/file10&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;/tmp/test/file11&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;/tmp/test/file12&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;/tmp/test/file13&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;/tmp/test/file14&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;/tmp/test/file15&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;/tmp/test/file16&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;/tmp/test/file17&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;bash$&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h3&gt;Now lets create a test executable to monitor&lt;/h3&gt;&lt;br /&gt;This script just holds each file open for reading for twenty seconds&lt;br /&gt;before closing the file.&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;bash$ &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;python -c&lt;/span&gt; '&lt;span&lt;br /&gt; style="color: rgb(0, 0, 153);"&gt;import sys,time&lt;/span&gt;&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace; color: rgb(0, 0, 153);"&gt;&lt;br /&gt;&lt;span style="font-family: monospace; color: rgb(0, 0, 153);"&gt;for&lt;br /&gt;name in file(sys.argv[1]):&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace; color: rgb(0, 0, 153);"&gt;&lt;br /&gt;&lt;span style="font-family: monospace; color: rgb(0, 0, 153);"&gt;&amp;nbsp;&lt;br /&gt;f = file(name.strip())&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace; color: rgb(0, 0, 153);"&gt;&lt;br /&gt;&lt;span style="font-family: monospace; color: rgb(0, 0, 153);"&gt;&amp;nbsp;&lt;br /&gt;time.sleep(45)&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace; color: rgb(0, 0, 153);"&gt;&lt;br /&gt;&lt;span style="font-family: monospace; color: rgb(0, 0, 153);"&gt;&amp;nbsp;&lt;br /&gt;f.close()&lt;/span&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;' &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;/tmp/test/all_files.lst&amp;nbsp;&lt;br /&gt;&amp;amp;&lt;/span&gt;&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;[2]&amp;nbsp;&lt;span&lt;br /&gt; style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&lt;br /&gt; style="font-family: monospace; color: rgb(0, 0, 153);"&gt;&lt;span&lt;br /&gt; style="font-weight: bold; color: red;"&gt;7984&lt;/span&gt;&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;bash$&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h3&gt;here is what the fd directory looks like&lt;/h3&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;bash$ ls -l /proc/&lt;/span&gt;&lt;span&lt;br /&gt; style="font-family: monospace; color: rgb(0, 0, 153);"&gt;&lt;span&lt;br /&gt; style="font-weight: bold; color: red;"&gt;7984&lt;/span&gt;&lt;/span&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;/fd&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;total 0&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;lrwxrwxrwx 1 HP&lt;br /&gt;DV8025EA None 0 Apr 21 22:17 0 -&amp;gt; /dev/tty1&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;lrwxrwxrwx 1 HP&lt;br /&gt;DV8025EA None 0 Apr 21 22:17 1 -&amp;gt; /dev/tty1&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;lrwxrwxrwx 1 HP&lt;br /&gt;DV8025EA None 0 Apr 21 22:17 2 -&amp;gt; /dev/tty1&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;lrwxrwxrwx 1 HP&lt;br /&gt;DV8025EA None 0 Apr 21 22:17 3 -&amp;gt; /tmp/test/all_files.lst&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;lrwxrwxrwx 1 HP&lt;br /&gt;DV8025EA None 0 Apr 21 22:17 4 -&amp;gt; /tmp/test/file0&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;bash$&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h3&gt;And here is a python script to monitor that fd directories&lt;br /&gt;link number 4 periodically&lt;/h3&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;bash$ &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;python -c '&lt;/span&gt;&lt;span&lt;br /&gt; style="color: rgb(0, 0, 153);"&gt;import sys,time,os,datetime&lt;/span&gt;&lt;br&lt;br /&gt; style="color: rgb(0, 0, 153);"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;name2index =&lt;br /&gt;dict((name.strip(), index) for index,name in&lt;br /&gt;enumerate(file(sys.argv[1])))&lt;/span&gt;&lt;br&lt;br /&gt; style="color: rgb(0, 0, 153);"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;all = len(name2index)&lt;/span&gt;&lt;br&lt;br /&gt; style="color: rgb(0, 0, 153);"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;while True:&lt;/span&gt;&lt;br&lt;br /&gt; style="color: rgb(0, 0, 153);"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;&amp;nbsp; path =&lt;br /&gt;os.path.realpath("/proc/&lt;span style="color: red; font-weight: bold;"&gt;7984&lt;/span&gt;/fd/&lt;span&lt;br /&gt; style="font-weight: bold; color: red;"&gt;4&lt;/span&gt;").strip()&lt;/span&gt;&lt;br&lt;br /&gt; style="color: rgb(0, 0, 153);"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;&amp;nbsp; print&lt;br /&gt;name2index[path],"/",all, path, datetime.datetime.now().isoformat()&lt;/span&gt;&lt;br&lt;br /&gt; style="color: rgb(0, 0, 153);"&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 153);"&gt;&amp;nbsp;&lt;br /&gt;time.sleep(30)&lt;/span&gt;&lt;br&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;' /tmp/test/all_files.lst&lt;/span&gt;&lt;br&gt;&lt;br /&gt;22 / 100 /tmp/test/file29 2009-04-21T22:34:07.817750&lt;br&gt;&lt;br /&gt;23 / 100 /tmp/test/file3 2009-04-21T22:34:37.820750&lt;br&gt;&lt;br /&gt;24 / 100 /tmp/test/file30 2009-04-21T22:35:07.825750&lt;br&gt;&lt;br /&gt;24 / 100 /tmp/test/file30 2009-04-21T22:35:37.834750&lt;br&gt;&lt;br /&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I watched the monitor output over the next couple of hours and found&lt;br /&gt;out when file reading ended and processing of read data started.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;END.&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-1956614544050315022?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/1956614544050315022/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/04/monitoring-linux-process-as-it-reads.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1956614544050315022'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/1956614544050315022'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/04/monitoring-linux-process-as-it-reads.html' title='Monitoring a linux process as it reads files'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-2355418732941002841</id><published>2009-04-16T19:08:00.001+01:00</published><updated>2009-04-16T19:20:07.794+01:00</updated><title type='text'>Bimap. Bi-directional mapping/dictionary for Python?</title><content type='html'>I had a chance encounter with the boost C++ library documentation and&lt;br /&gt;came across a description of their &lt;a&lt;br /&gt; href="http://cablemodem.fibertel.com.ar/mcape/boost/libs/bimap/index.html"&gt;bimap&lt;/a&gt;&lt;br /&gt;&lt;small&gt;(that is bimap without a 't') &lt;/small&gt;.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;It seems to be a bi-directional mapping. &lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;In a Python dict, keys map to values. In a bimap, values would also map&lt;br /&gt;to keys. It seems they put keys/values on an equal footing by renaming&lt;br /&gt;them as left and right members, and having methods that work on either&lt;br /&gt;the right to left or the left to right mapping.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I had just re-visited a program of mine that dealt with what I would&lt;br /&gt;consider large sets of values. I was mapping test names to test&lt;br /&gt;coverage where their were tens of trhousands of test names, each of&lt;br /&gt;~100 characters long and for each file, I had many thousands of code&lt;br /&gt;coverage points, which themselves were strings of ~150 characters each.&lt;br /&gt;I new I had to work with a dict mapping test_names to sets of covered&lt;br /&gt;points for each test and do a lot of set arithmatic to rank the tests&lt;br /&gt;in order of contribution to the overall coverage figure, so I decided&lt;br /&gt;to use indices; replacing files by negative numbers and coverage points&lt;br /&gt;by positive numbers. My program works, and is very fast but I note that&lt;br /&gt;I create both a testname2index mapping dict and the inverse&lt;br /&gt;index2testname mapping, (and coverpoint2index and index2coverpoint&lt;br /&gt;mapping dicts).&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;What I had been constructing, unawares, was a bimap by using two dicts.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I then spent time googling for Python bimaps to no avail, (although I&lt;br /&gt;think there are haskel and Java implementations out there - and Google&lt;br /&gt;'helps' by sugesting you meant bitmap with a 't').&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;So my questions are:&lt;br&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;&amp;nbsp;Is their a Python bimap implementation out there?&lt;br /&gt;  &lt;/li&gt;&lt;br /&gt;  &lt;li&gt;&amp;nbsp;Would anyone want one? (I already code around its&lt;br /&gt;absense).&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;&amp;nbsp;What would its methods be?&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Methods&lt;/span&gt;&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;On my third question, I guess you could have all the normal methods of&lt;br /&gt;a dict but preceeded by either&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;left_ &lt;/span&gt;or &lt;span style="font-family: monospace;"&gt;right_&lt;/span&gt;&lt;br /&gt;with calling of a method without those prefixes raising an exception,&lt;br /&gt;as it seems important to not favour one mapping direction over another.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;This would give:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace; font-weight: bold; text-decoration: underline;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;DICT&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; BIMOD&lt;br /&gt;(LEFT)&amp;nbsp; BIMOD (RIGHT)&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace; font-weight: bold;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace; font-weight: bold;"&gt;&lt;/span&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;clear&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;left_clear&amp;nbsp; right_clear&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;copy&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;left_copy&amp;nbsp; right_copy&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;fromkeys&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;left_fromkeys&amp;nbsp; right_fromkeys &amp;nbsp;&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;get&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;left_get&amp;nbsp;&lt;br /&gt;right_get&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;has_key&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;left_has_key&amp;nbsp; right_has_key&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;items&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;left_items&amp;nbsp; right_items&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;iteritems&amp;nbsp;&amp;nbsp;&amp;nbsp; left_iteritems&amp;nbsp;&lt;br /&gt;right_iteritems &lt;/span&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;iterkeys&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;left_iterkeys&amp;nbsp; right_iterkeys &amp;nbsp;&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;itervalues&amp;nbsp;&amp;nbsp;&lt;br /&gt;left_itervalues&amp;nbsp; right_itervalues&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;keys&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;left_keys&amp;nbsp; right_keys&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&lt;/span&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;left_pop&amp;nbsp;&lt;br /&gt;right_pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;popitem&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;left_popitem&amp;nbsp; right_popitem&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;setdefault&amp;nbsp;&amp;nbsp;&lt;br /&gt;left_setdefault&amp;nbsp; right_setdefault&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;update&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;left_update&amp;nbsp; right_update&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;values&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;left_values&amp;nbsp; right_values&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;br&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;The above couldn't be extended for indexing however, unless you did&lt;br /&gt;something like:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&amp;nbsp; &lt;span&lt;br /&gt; style="font-family: monospace;"&gt;bimod_instance.left[leftindex]&lt;br /&gt;and bimod_instance..right[rightindex]&lt;/span&gt;&lt;br&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;but then wouldn't it be better to use the dotted form for all the&lt;br /&gt;methods and have:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;bimod_instance.left.haskey&amp;nbsp; # (with a dot after left), ...&lt;/span&gt;&lt;br&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I note that their are redundancies above, for example, left_clear ==&lt;br /&gt;right_clear ...&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Strewth, I've only scratched the surface :-)&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;- Paddy.&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-2355418732941002841?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/2355418732941002841/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/04/bimap-bi-directional-mappingdictionary.html#comment-form' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/2355418732941002841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/2355418732941002841'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/04/bimap-bi-directional-mappingdictionary.html' title='Bimap. Bi-directional mapping/dictionary for Python?'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-7634822566933463769</id><published>2009-04-10T22:56:00.001+01:00</published><updated>2009-04-10T22:56:51.946+01:00</updated><title type='text'>Knapsack solution by OO Calc</title><content type='html'>I had previously solved the &lt;a&lt;br /&gt; href="http://www.rosettacode.org/wiki/Knapsack_Problem"&lt;br /&gt; target="_blank"&gt;knapsack problem in Python&lt;/a&gt;. I came&lt;br /&gt;across the Solver function of OpenOffice Calc and so tried to use it to&lt;br /&gt;solve knapsack.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h3&gt;A quick recap of the problem&lt;/h3&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;p&gt;A traveller gets diverted and has to make an unscheduled stop&lt;br /&gt;in&lt;br /&gt;what turns out to be Shangri La. Opting to leave, he is allowed to take&lt;br /&gt;as much as he likes of the following items, so long as it will fit in&lt;br /&gt;his knapsack, and he can carry it.&lt;br /&gt;He knows that he can carry no more than 25 'weights' in total; and that&lt;br /&gt;the capacity of his knapsack is 0.25 'cubic lengths'.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Looking just above the bar codes on the items he finds their&lt;br /&gt;weights and volumes. He digs out his recent copy of a financial paper&lt;br /&gt;and gets the value of each item.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;table style="text-align: left; width: 80%;" border="4"&lt;br /&gt; cellpadding="2" cellspacing="2"&gt;&lt;br /&gt;  &lt;tbody&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td style="font-weight: bold;" align="left"&lt;br /&gt; nowrap="nowrap" valign="middle"&gt;Item&lt;/td&gt;&lt;br /&gt;      &lt;td style="font-weight: bold;" align="left"&lt;br /&gt; nowrap="nowrap" valign="middle"&gt;Explanation&lt;/td&gt;&lt;br /&gt;      &lt;td style="font-weight: bold;" align="left"&lt;br /&gt; nowrap="nowrap" valign="middle"&gt;Value (each)&lt;/td&gt;&lt;br /&gt;      &lt;td style="font-weight: bold;" align="left"&lt;br /&gt; nowrap="nowrap" valign="middle"&gt;weight&lt;/td&gt;&lt;br /&gt;      &lt;td style="font-weight: bold;" align="left"&lt;br /&gt; nowrap="nowrap" valign="middle"&gt;Volume (each)&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td align="left" nowrap="nowrap" valign="middle"&gt;panacea&lt;br /&gt;(vials of)&lt;/td&gt;&lt;br /&gt;      &lt;td align="left" nowrap="nowrap" valign="middle"&gt;Incredible&lt;br /&gt;healing properties&lt;/td&gt;&lt;br /&gt;      &lt;td align="left" nowrap="nowrap" valign="middle"&gt;3000&lt;/td&gt;&lt;br /&gt;      &lt;td align="left" nowrap="nowrap" valign="middle"&gt;0.3&lt;/td&gt;&lt;br /&gt;      &lt;td align="left" nowrap="nowrap" valign="middle"&gt;0.025&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td align="left" nowrap="nowrap" valign="middle"&gt;ichor&lt;br /&gt;(ampules of)&lt;/td&gt;&lt;br /&gt;      &lt;td align="left" nowrap="nowrap" valign="middle"&gt;Vampires&lt;br /&gt;blood&lt;/td&gt;&lt;br /&gt;      &lt;td align="left" nowrap="nowrap" valign="middle"&gt;1800&lt;/td&gt;&lt;br /&gt;      &lt;td align="left" nowrap="nowrap" valign="middle"&gt;0.2&lt;/td&gt;&lt;br /&gt;      &lt;td align="left" nowrap="nowrap" valign="middle"&gt;0.015&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td align="left" nowrap="nowrap" valign="middle"&gt;gold&lt;br /&gt;(bars)&lt;/td&gt;&lt;br /&gt;      &lt;td align="left" nowrap="nowrap" valign="middle"&gt;Shiney&lt;br /&gt;shiney&lt;/td&gt;&lt;br /&gt;      &lt;td align="left" nowrap="nowrap" valign="middle"&gt;2500&lt;/td&gt;&lt;br /&gt;      &lt;td align="left" nowrap="nowrap" valign="middle"&gt;2.0&lt;/td&gt;&lt;br /&gt;      &lt;td align="left" nowrap="nowrap" valign="middle"&gt;0.002&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td style="background-color: rgb(255, 204, 255);"&lt;br /&gt; align="left" nowrap="nowrap" valign="middle"&gt;Knapsack&lt;/td&gt;&lt;br /&gt;      &lt;td style="background-color: rgb(255, 204, 255);"&lt;br /&gt; align="left" nowrap="nowrap" valign="middle"&gt;For&lt;br /&gt;the carrying of&lt;/td&gt;&lt;br /&gt;      &lt;td style="background-color: rgb(255, 204, 255);"&lt;br /&gt; align="left" nowrap="nowrap" valign="middle"&gt;-&lt;/td&gt;&lt;br /&gt;      &lt;td style="background-color: rgb(255, 204, 255);"&lt;br /&gt; align="left" nowrap="nowrap" valign="middle"&gt;&amp;lt;=25&lt;/td&gt;&lt;br /&gt;      &lt;td style="background-color: rgb(255, 204, 255);"&lt;br /&gt; align="left" nowrap="nowrap" valign="middle"&gt;&amp;lt;=0.25&amp;nbsp;&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;  &lt;/tbody&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;p&gt;He can only take whole units of any item,, but there is much&lt;br /&gt;more of any item than he could ever carry&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;b&gt;How many of each item does he take to maximise the&lt;br /&gt;value of items he is carrying away with him?&lt;/b&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Note: &lt;/p&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt; There are four solutions that maximise the value taken.&lt;br /&gt;Only one &lt;i&gt;need&lt;/i&gt; be given.&lt;br /&gt;  &lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;OO Calc setup&lt;/h3&gt;&lt;br /&gt;I am using version 3.0.1. I opened a new spreadsheat and literally&lt;br /&gt;cut-n-pasted the above table into the sheet. The solver needs to be&lt;br /&gt;able to change some cells (the variables) that affect one cell&lt;br /&gt;containing the value to optimise.. I added the table in blue, at the&lt;br /&gt;right of the &amp;nbsp;figure below to calculate the value, weight and&lt;br /&gt;volume of what is in the knapsack based on the amount of each item&lt;br /&gt;chosen, so you can change what is in the &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;Number&lt;/span&gt; column and&lt;br /&gt;get new totals calculated in the &lt;span style="font-weight: bold;"&gt;Totals&lt;/span&gt;&lt;br /&gt;row &lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;img&lt;br /&gt; style="width: 914px; height: 444px;"&lt;br /&gt; alt="Knapsack problem formulae" title="(Showing cell formulae)"&lt;br /&gt; src="http://lh3.ggpht.com/_ueV7OWnroeY/Sd-9LlNhkmI/AAAAAAAAAD8/4oXkLjx0xzU/Knapsack_problem_fomulae.PNG"&gt;&lt;/div&gt;&lt;br /&gt;I show the formulae in the cells in the image above.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h3&gt;The Solver &lt;/h3&gt;&lt;br /&gt;Menu Tools-&amp;gt; Solver shows a form for filling in. from top to&lt;br /&gt;bottom:&lt;br&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;  &lt;li&gt;The target cell is the cell I want to maximise, which is&lt;br /&gt;the total value of all items in cell H8&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;I want to Maximise.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;I want to change the &lt;span style="font-weight: bold;"&gt;Number&lt;/span&gt;&lt;br /&gt;of each item i.e. vary cells G4:G6&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;My limiting conditions are:&lt;/li&gt;&lt;br /&gt;  &lt;ul&gt;&lt;br /&gt;    &lt;li&gt;The weight is &amp;lt;= 25&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;The volume is &amp;lt;= 0.25&lt;/li&gt;&lt;br /&gt;    &lt;li&gt;The Number of each item cannot be negative.&lt;/li&gt;&lt;br /&gt;  &lt;/ul&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;img&lt;br /&gt; style="width: 455px; height: 373px;" alt="Solver Menu"&lt;br /&gt; title="Solver menu"&lt;br /&gt; src="http://lh6.ggpht.com/_ueV7OWnroeY/Sd-9L2VfwsI/AAAAAAAAAEU/8mlo9NrxqIg/Knapsack_problem_solver.PNG"&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;You also need to click the Solvers &lt;span style="font-weight: bold;"&gt;Options&lt;/span&gt;&lt;br /&gt;button and ensure the options are set like this:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;img&lt;br /&gt; style="width: 431px; height: 286px;" alt="Solver Options"&lt;br /&gt; title="Solver Options"&lt;br /&gt; src="http://lh6.ggpht.com/_ueV7OWnroeY/Sd-9L2P_QgI/AAAAAAAAAEM/Af-j8UvPRMg/Knapsack_problem_solve_optionsr.PNG"&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Ok the Options, then hit Solve on the Solver window and eventually you&lt;br /&gt;will get the following result:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;img&lt;br /&gt; style="width: 914px; height: 444px;"&lt;br /&gt; alt="Result of Knapsack constraints problem"&lt;br /&gt; title="Result of Knapsack constraints problem"&lt;br /&gt; src="http://lh5.ggpht.com/_ueV7OWnroeY/Sd-9Lx1yvmI/AAAAAAAAAEE/j9ZFL0JLe_k/Knapsack_problem_result.PNG"&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;The solver has correctly determined that carrying no panacea, fifteen&lt;br /&gt;ampules of ichor, and eleven gold bars will maximise the value, subject&lt;br /&gt;to the given constraints..&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h3&gt;Comment&lt;/h3&gt;&lt;br /&gt;Their are actually other values that give the same total value under&lt;br /&gt;the same constraints but I can't find an easy way for the solver to&lt;br /&gt;give them all.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;END.&lt;/span&gt;&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-7634822566933463769?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/7634822566933463769/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/04/knapsack-solution-by-oo-calc.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/7634822566933463769'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/7634822566933463769'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/04/knapsack-solution-by-oo-calc.html' title='Knapsack solution by OO Calc'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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://lh3.ggpht.com/_ueV7OWnroeY/Sd-9LlNhkmI/AAAAAAAAAD8/4oXkLjx0xzU/s72-c/Knapsack_problem_fomulae.PNG' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-8731776049083092235</id><published>2009-04-10T09:11:00.000+01:00</published><updated>2009-04-10T09:12:04.397+01:00</updated><title type='text'>Memoization and stack use.</title><content type='html'>I was caught out today when investigating how to apply memoization to&lt;br /&gt;allow computation of larger values of a recursive function.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h2&gt;Mutual Recursion&lt;/h2&gt;&lt;br /&gt;I had thought up a new task for Rosetta Code called &lt;a&lt;br /&gt; href="http://www.rosettacode.org/wiki/Mutual_Recursion"&gt;Mutual&lt;br /&gt;Recursion&lt;/a&gt;, as I had remembered that some languages needed&lt;br /&gt;&amp;nbsp;at least the signature of a function to be defined before it&lt;br /&gt;could be called, and so creating mutually recursive functions would&lt;br /&gt;allow you to compare the languages in an interesting way - which is&lt;br /&gt;what R.C. is all about. &lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;For the example for implementation I used &lt;a&lt;br /&gt; href="http://en.wikipedia.org/wiki/Hofstadter_sequence#Hofstadter_Female_and_Male_sequences"&lt;br /&gt; target="_blank"&gt;Hoffstadters Female and Male&lt;/a&gt;&lt;br /&gt;sequences, and produced the following &lt;a&lt;br /&gt; href="http://www.rosettacode.org/wiki/Mutual_Recursion#Python"&gt;Python&lt;br /&gt;definitions&lt;/a&gt;:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;F&lt;/font&gt;(n): &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; 1 &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; n == 0 &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt; n - M(F(n-1))&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;M&lt;/font&gt;(n): &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; 0 &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; n == 0 &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt; n - F(M(n-1))&lt;br&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;It seems that other members of R.C. liked the task and soon added many&lt;br /&gt;examples in other languages.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Apart from the computation of the series for 0&amp;lt;=n&amp;lt;20, I&lt;br /&gt;did try to compute F(200) but it blew the stack so I went to bed and&lt;br /&gt;decided to memoize the functions another day.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h2&gt;&lt;a href="http://en.wikipedia.org/wiki/Chad_%28graffiti%29"&lt;br /&gt; target="_blank"&gt;Wot&lt;/a&gt;, no memoize?&lt;/h2&gt;&lt;br /&gt;Memoization came very easily to mind, so I thought that Python would&lt;br /&gt;have such available as a decorator waiting to be applied. No such luck,&lt;br /&gt;I would have to craft my own . I did remember correctly however that&lt;br /&gt;there was some &amp;nbsp;helper function that made wrapped functions&lt;br /&gt;look a lot more like what had been wrapped, and so used functools.wrap:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#a020f0"&gt;from&lt;/font&gt; functools &lt;font&lt;br /&gt; color="#a020f0"&gt;import&lt;/font&gt; wraps&lt;br&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;memoize0&lt;/font&gt;(func):&lt;br&gt;    '&lt;font&lt;br /&gt; color="#ff00ff"&gt; Adds cache as attribute to wrapped function for ease of access&lt;/font&gt;'&lt;br&gt;    &lt;font&lt;br /&gt; color="#a020f0"&gt;@&lt;/font&gt;&lt;font color="#008080"&gt;wraps&lt;/font&gt;(func)&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;wrapper&lt;/font&gt;(*args):&lt;br&gt;        argsl = tuple(args)&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; argsl &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; wrapper._cache:&lt;br&gt;            &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; wrapper._cache[argsl]&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt;:&lt;br&gt;            &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; wrapper._cache.setdefault(argsl, func(*args))&lt;br&gt;    wrapper._cache = dict()&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; wrapper&lt;br&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;memoize&lt;/font&gt;(func):&lt;br&gt;    '&lt;font&lt;br /&gt; color="#ff00ff"&gt; Creates closure around locally created cache&lt;/font&gt;'&lt;br&gt;    cache = dict()&lt;br&gt;    &lt;font&lt;br /&gt; color="#a020f0"&gt;@&lt;/font&gt;&lt;font color="#008080"&gt;wraps&lt;/font&gt;(func)&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;wrapper&lt;/font&gt;(*args):&lt;br&gt;        argsl = tuple(args)&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; argsl &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; cache:&lt;br&gt;            &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; cache[argsl]&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt;:&lt;br&gt;            &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; cache.setdefault(argsl, func(*args))&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; wrapper&lt;br&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I haven't got over my (probably infantile) lust for attaching&lt;br /&gt;attributes to functions so justified memoize0 as it allows you to look&lt;br /&gt;at the contents of the cache. Combined with the fact that you cannot do&lt;br /&gt;a memoization decorator without applying it to a &lt;a&lt;br /&gt; href="http://en.wikipedia.org/wiki/Fibonacci_function"&gt;Fibonacci&lt;br /&gt;number&lt;/a&gt; function: &lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; __name__ == '&lt;font&lt;br /&gt; color="#ff00ff"&gt;__main__&lt;/font&gt;':&lt;br&gt;    &lt;font&lt;br /&gt; color="#a020f0"&gt;@&lt;/font&gt;&lt;font color="#008080"&gt;memoize0&lt;/font&gt;&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;fib&lt;/font&gt;(n): &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; n &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; n &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; (0,1) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt; fib(n - 1) + fib(n - 2)&lt;br&gt;    &lt;font&lt;br /&gt; color="#a020f0"&gt;@&lt;/font&gt;&lt;font color="#008080"&gt;memoize0&lt;/font&gt;&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;fib2&lt;/font&gt;(n): &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; n &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; n &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; (0,1) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt; fib2(n - 1) + fib2(n - 2)&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/font&gt; fib._cache &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;not&lt;/b&gt;&lt;/font&gt; fib2._cache&lt;br&gt;    fib(50); fib2(50)&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/font&gt; fib._cache == fib2._cache &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;and&lt;/b&gt;&lt;/font&gt; (fib._cache &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;is&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;not&lt;/b&gt;&lt;/font&gt; fib2._cache)&lt;br&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;It is important that caches are not shared for mutually recursive&lt;br /&gt;functions.&lt;br&gt;&lt;br /&gt;&lt;h2&gt;A blown stack&lt;/h2&gt;&lt;br /&gt;I had initial success with the Male and Female sequence and was easily&lt;br /&gt;able to compute F(200) with:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br&gt;    &lt;font color="#a020f0"&gt;@&lt;/font&gt;&lt;font&lt;br /&gt; color="#008080"&gt;memoize&lt;/font&gt;&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;F&lt;/font&gt;(n):&lt;br&gt;        '&lt;font&lt;br /&gt; color="#ff00ff"&gt; Hofstadters Female Male sequences&lt;/font&gt;'&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; 1 &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; n == 0 &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt; n - M(F(n-1))&lt;br&gt;&lt;br&gt;    &lt;font&lt;br /&gt; color="#a020f0"&gt;@&lt;/font&gt;&lt;font color="#008080"&gt;memoize&lt;/font&gt;&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;M&lt;/font&gt;(n):&lt;br&gt;        '&lt;font&lt;br /&gt; color="#ff00ff"&gt; Hofstadters Female Male sequences&lt;/font&gt;'&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; 0 &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; n == 0 &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt; n - F(M(n-1))&lt;br&gt;&lt;br&gt;    &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/font&gt; F(200) == 124&lt;br&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;But I got cocky, as F(2000) ran out of stack.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;A little thought made me realise that I only had a cached results for F&lt;br /&gt;and M up to around 200 and so a call of F(2000) was going to eat up&lt;br /&gt;huge amounts of stack before recursing down to cached values.&lt;br&gt;&lt;br /&gt;With that knowledge in mind I thought I might gradually jump to higher&lt;br /&gt;values of&amp;nbsp; n and, indeed, the following worked:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#804040"&gt;&lt;b&gt;    print&lt;/b&gt;&lt;/font&gt; ([F(n) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; n &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; range(0,20000+1,100)])&lt;br&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;In real-world applicatrions, you might have to have some scheme to&lt;br /&gt;reduce or limit cache size if memory rather than the stack becomes an&lt;br /&gt;issue, and I have a great solution that I have just completed in the&lt;br /&gt;margin :-)&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;- Paddy.&lt;br&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-8731776049083092235?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/8731776049083092235/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/04/memoization-and-stack-use.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/8731776049083092235'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/8731776049083092235'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/04/memoization-and-stack-use.html' title='Memoization and stack use.'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-2981552897112217126</id><published>2009-04-02T22:07:00.005+01:00</published><updated>2009-04-03T07:00:00.188+01:00</updated><title type='text'>(Ab)use of Pythons in-built data structures</title><content type='html'>I like to use Pythons in-built data structures quit a lot, and tend to&lt;br /&gt;force myself to ask whether I &amp;nbsp;should create my own classes,&lt;br /&gt;which allows you to use meaningful names for fields and add&lt;br /&gt;comments/docstrings to the datastructure but usually at the cost of&lt;br /&gt;adding more lines of text.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;After writing about Huffman codes and posting solutions to &lt;a&lt;br /&gt; href="http://www.rosettacode.org/w/index.php?title=Huffman_codes&amp;amp;oldid=27804#Python"&gt;Rosetta&lt;br /&gt;code&lt;/a&gt; and &lt;a&lt;br /&gt; href="http://paddy3118.blogspot.com/2009/03/huffman-encoding-in-python.html"&gt;my&lt;br /&gt;blog&lt;/a&gt;:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#804040"&gt; 29 &lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;codecreate&lt;/font&gt;(symbol2weights, tutor= False):&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 30 &lt;/font&gt;    '''&lt;font&lt;br /&gt; color="#ff00ff"&gt; Huffman encode the given dict mapping symbols to weights &lt;/font&gt;'''&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 31 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;global&lt;/b&gt;&lt;/font&gt; decode&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 32 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 33 &lt;/font&gt;    heap = [ [float(wt), [[sym, []]], repr(sym)] &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; sym, wt &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; symbol2weights.iteritems() ]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 34 &lt;/font&gt;    heapify(heap)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 35 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; tutor: &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#ff00ff"&gt;ENCODING:&lt;/font&gt;", sorted(symbol2weights.iteritems())&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 36 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt; len(heap) &amp;gt;1:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 37 &lt;/font&gt;        lo = heappop(heap)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 38 &lt;/font&gt;        hi = heappop(heap)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 39 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; tutor: &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#ff00ff"&gt;  COMBINING:&lt;/font&gt;", lo, '&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n&lt;/font&gt;&lt;font color="#ff00ff"&gt;        AND:&lt;/font&gt;', hi&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 40 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; lo[1]: i[1].insert(0, '&lt;font&lt;br /&gt; color="#ff00ff"&gt;0&lt;/font&gt;')&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 41 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; hi[1]: i[1].insert(0, '&lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt;')&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 42 &lt;/font&gt;        lohi = [ lo[0] + hi[0] ] + [lo[1] + hi[1]]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 43 &lt;/font&gt;        lohi.append('&lt;font&lt;br /&gt; color="#ff00ff"&gt;(%s if nextbit() else %s)&lt;/font&gt;' % (hi[2], lo[2]))&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 44 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; tutor: &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#ff00ff"&gt;  PRODUCING:&lt;/font&gt;", lohi, '&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n&lt;/font&gt;'&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 45 &lt;/font&gt;        heappush(heap, lohi)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 46 &lt;/font&gt;    wt, codes, decoder = heappop(heap)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 47 &lt;/font&gt;    decode = eval('&lt;font&lt;br /&gt; color="#ff00ff"&gt;lambda :&lt;/font&gt;' + decoder, globals())&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 48 &lt;/font&gt;    decode.__doc__ = decoder&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 49 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; codes: i[1] = ''.join(i[1])&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 50 &lt;/font&gt;    &lt;font color="#0000ff"&gt;#for i in codes: i[::] = i[:2]&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 51 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; sorted(codes, key=&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;lambda&lt;/b&gt;&lt;/font&gt; x: (len(x[-1]), x))&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 52 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;/font&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;Someone posted a&lt;a&lt;br /&gt; href="http://www.rosettacode.org/w/index.php?title=Huffman_codes&amp;amp;oldid=27804#Java"&gt;&lt;br /&gt;Java solution,&lt;/a&gt; that was over three times as long. Instead of&lt;br /&gt;just counting and comparing line counts,&amp;nbsp; I took a closer&lt;br /&gt;look to see what the extra code was for.&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#a020f0"&gt;import&lt;/font&gt; java.util.*;&lt;br&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;abstract&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/font&gt; HuffmanTree &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;implements&lt;/b&gt;&lt;/font&gt; Comparable&amp;lt;HuffmanTree&amp;gt; {&lt;br&gt;    &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;int&lt;/b&gt;&lt;/font&gt; frequency; &lt;font&lt;br /&gt; color="#0000ff"&gt;// the frequency of this tree&lt;/font&gt;&lt;br&gt;    &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; HuffmanTree(&lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;int&lt;/b&gt;&lt;/font&gt; freq) { frequency = freq; }&lt;br&gt;&lt;br&gt;    &lt;font&lt;br /&gt; color="#0000ff"&gt;// compares on the frequency&lt;/font&gt;&lt;br&gt;    &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;int&lt;/b&gt;&lt;/font&gt; compareTo(HuffmanTree tree) {&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; frequency - tree.frequency;&lt;br&gt;    }&lt;br&gt;}&lt;br&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/font&gt; HuffmanLeaf &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;extends&lt;/b&gt;&lt;/font&gt; HuffmanTree {&lt;br&gt;    &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;char&lt;/b&gt;&lt;/font&gt; value; &lt;font&lt;br /&gt; color="#0000ff"&gt;// the character this leaf represents&lt;/font&gt;&lt;br&gt;&lt;br&gt;    &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; HuffmanLeaf(&lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;int&lt;/b&gt;&lt;/font&gt; freq, &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;char&lt;/b&gt;&lt;/font&gt; val) {&lt;br&gt;        &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;super&lt;/b&gt;&lt;/font&gt;(freq);&lt;br&gt;        value = val;&lt;br&gt;    }&lt;br&gt;}&lt;br&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/font&gt; HuffmanNode &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;extends&lt;/b&gt;&lt;/font&gt; HuffmanTree {&lt;br&gt;    &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; HuffmanTree left, right; &lt;font&lt;br /&gt; color="#0000ff"&gt;// subtrees&lt;/font&gt;&lt;br&gt;&lt;br&gt;    &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; HuffmanNode(HuffmanTree l, HuffmanTree r) {&lt;br&gt;        &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;super&lt;/b&gt;&lt;/font&gt;(l.frequency + r.frequency);&lt;br&gt;        left = l;&lt;br&gt;        right = r;&lt;br&gt;    }&lt;br&gt;}&lt;br&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/font&gt; HuffmanCode {&lt;br&gt;    &lt;font&lt;br /&gt; color="#0000ff"&gt;// input is an array of frequencies, indexed by character code&lt;/font&gt;&lt;br&gt;    &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;static&lt;/b&gt;&lt;/font&gt; HuffmanTree buildTree(&lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;int&lt;/b&gt;&lt;/font&gt;[] charFreqs) {&lt;br&gt;        PriorityQueue&amp;lt;HuffmanTree&amp;gt; trees = &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/font&gt; PriorityQueue&amp;lt;HuffmanTree&amp;gt;();&lt;br&gt;        &lt;font&lt;br /&gt; color="#0000ff"&gt;// initially, we have a forest of leaves&lt;/font&gt;&lt;br&gt;        &lt;font&lt;br /&gt; color="#0000ff"&gt;// one for each non-empty character&lt;/font&gt;&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; (&lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;int&lt;/b&gt;&lt;/font&gt; i = &lt;font&lt;br /&gt; color="#ff00ff"&gt;0&lt;/font&gt;; i &amp;lt; charFreqs.length; i++)&lt;br&gt;            &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; (charFreqs[i] &amp;gt; &lt;font&lt;br /&gt; color="#ff00ff"&gt;0&lt;/font&gt;)&lt;br&gt;                trees.offer(&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/font&gt; HuffmanLeaf(charFreqs[i], (&lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;char&lt;/b&gt;&lt;/font&gt;)i));&lt;br&gt;&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/font&gt; trees.size() &amp;gt; &lt;font&lt;br /&gt; color="#ff00ff"&gt;0&lt;/font&gt;;&lt;br&gt;        &lt;font&lt;br /&gt; color="#0000ff"&gt;// loop until there is only one tree left&lt;/font&gt;&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt; (trees.size() &amp;gt; &lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt;) {&lt;br&gt;            &lt;font&lt;br /&gt; color="#0000ff"&gt;// two trees with least frequency&lt;/font&gt;&lt;br&gt;            HuffmanTree a = trees.poll();&lt;br&gt;            HuffmanTree b = trees.poll();&lt;br&gt;&lt;br&gt;            &lt;font&lt;br /&gt; color="#0000ff"&gt;// put into new node and re-insert into queue&lt;/font&gt;&lt;br&gt;            trees.offer(&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/font&gt; HuffmanNode(a, b));&lt;br&gt;        }&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; trees.poll();&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;static&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;void&lt;/b&gt;&lt;/font&gt; printCodes(HuffmanTree tree, Stack&amp;lt;Character&amp;gt; prefix) {&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;assert&lt;/b&gt;&lt;/font&gt; tree != &lt;font&lt;br /&gt; color="#ff00ff"&gt;null&lt;/font&gt;;&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; (tree &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;instanceof&lt;/b&gt;&lt;/font&gt; HuffmanLeaf) {&lt;br&gt;            HuffmanLeaf leaf = (HuffmanLeaf)tree;&lt;br&gt;&lt;br&gt;            &lt;font&lt;br /&gt; color="#0000ff"&gt;// print out character and frequency&lt;/font&gt;&lt;br&gt;            System.out.print(leaf.value + &lt;font&lt;br /&gt; color="#ff00ff"&gt;"&lt;/font&gt;&lt;font color="#6a5acd"&gt;\t&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;"&lt;/font&gt; + leaf.frequency + &lt;font&lt;br /&gt; color="#ff00ff"&gt;"&lt;/font&gt;&lt;font color="#6a5acd"&gt;\t&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;"&lt;/font&gt;);&lt;br&gt;&lt;br&gt;            &lt;font&lt;br /&gt; color="#0000ff"&gt;// print out code for this leaf, which is just the prefix&lt;/font&gt;&lt;br&gt;            &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; (&lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;char&lt;/b&gt;&lt;/font&gt; bit : prefix)&lt;br&gt;                System.out.print(bit);&lt;br&gt;            System.out.println();&lt;br&gt;&lt;br&gt;        } &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; (tree &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;instanceof&lt;/b&gt;&lt;/font&gt; HuffmanNode) {&lt;br&gt;            HuffmanNode node = (HuffmanNode)tree;&lt;br&gt;&lt;br&gt;            &lt;font&lt;br /&gt; color="#0000ff"&gt;// traverse left&lt;/font&gt;&lt;br&gt;            prefix.push(&lt;font&lt;br /&gt; color="#ff00ff"&gt;'0'&lt;/font&gt;);&lt;br&gt;            printCodes(node.left, prefix);&lt;br&gt;            prefix.pop();&lt;br&gt;&lt;br&gt;            &lt;font&lt;br /&gt; color="#0000ff"&gt;// traverse right&lt;/font&gt;&lt;br&gt;            prefix.push(&lt;font&lt;br /&gt; color="#ff00ff"&gt;'1'&lt;/font&gt;);&lt;br&gt;            printCodes(node.right, prefix);&lt;br&gt;            prefix.pop();&lt;br&gt;        }&lt;br&gt;    }&lt;br&gt;&lt;br&gt;    &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;static&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;void&lt;/b&gt;&lt;/font&gt; main(String[] args) {&lt;br&gt;        String test = &lt;font&lt;br /&gt; color="#ff00ff"&gt;"this is an example for huffman encoding"&lt;/font&gt;;&lt;br&gt;&lt;br&gt;        &lt;font&lt;br /&gt; color="#0000ff"&gt;// we will assume that all our characters will have&lt;/font&gt;&lt;br&gt;        &lt;font&lt;br /&gt; color="#0000ff"&gt;// code less than 256, for simplicity&lt;/font&gt;&lt;br&gt;        &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;int&lt;/b&gt;&lt;/font&gt;[] charFreqs = &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;int&lt;/b&gt;&lt;/font&gt;[&lt;font&lt;br /&gt; color="#ff00ff"&gt;256&lt;/font&gt;];&lt;br&gt;        &lt;font&lt;br /&gt; color="#0000ff"&gt;// read each character and record the frequencies&lt;/font&gt;&lt;br&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; (&lt;font&lt;br /&gt; color="#2e8b57"&gt;&lt;b&gt;char&lt;/b&gt;&lt;/font&gt; c : test.toCharArray())&lt;br&gt;            charFreqs[c]++;&lt;br&gt;&lt;br&gt;        &lt;font&lt;br /&gt; color="#0000ff"&gt;// build tree&lt;/font&gt;&lt;br&gt;        HuffmanTree tree = buildTree(charFreqs);&lt;br&gt;&lt;br&gt;        &lt;font&lt;br /&gt; color="#0000ff"&gt;// print out results&lt;/font&gt;&lt;br&gt;        System.out.println(&lt;font&lt;br /&gt; color="#ff00ff"&gt;"SYMBOL&lt;/font&gt;&lt;font color="#6a5acd"&gt;\t&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;WEIGHT&lt;/font&gt;&lt;font color="#6a5acd"&gt;\t&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;HUFFMAN CODE"&lt;/font&gt;);&lt;br&gt;        printCodes(tree, &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/font&gt; Stack&amp;lt;Character&amp;gt;());&lt;br&gt;    }&lt;br&gt;}&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I&lt;br /&gt;noticed that the Java was tidy, and that they had defined their own&lt;br /&gt;classes for a HuffmanLeaf structure used when constructing a&lt;br /&gt;HuffmanTree. &lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;In my original Python, I used a nested list as&lt;br /&gt;the equivalent to the HuffmanLeaf of the Java example. It worked, but I&lt;br /&gt;had to introduce 'magic constants' to access the fields of the Python&lt;br /&gt;leaf , which is also un-named as a structure in the program (lline 33&lt;br /&gt;of&lt;br /&gt;the Python code creates a list of Leaf structures):&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#804040"&gt;33 &lt;/font&gt; heap = [ [float(wt), [sym, []]] &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; sym, wt &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; symbol2weights.iteritems() ]&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Now&amp;nbsp;I didn't want to go to the trouble of creating my own&lt;br /&gt;classes, but that's were the new &lt;a&lt;br /&gt; href="http://docs.python.org/dev/py3k/library/collections.html#collections.namedtuple"&gt;namedtuple&lt;/a&gt;&lt;br /&gt;class factory of Python 2.6 came to the rescue.&lt;br&gt;&lt;br /&gt;&lt;h2&gt;namedtuple&lt;/h2&gt;&lt;br /&gt;namedtuple&lt;br /&gt;will generate a subtype of the tuple class that allows the fields of&lt;br /&gt;the tuple to be named and accessed via subscription, [], or as if the&lt;br /&gt;fields are instance variable names.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I modified my Python program to use two named tuples:&lt;br&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;For the Leaf structure as a whole in line 3.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;For a component of the Leaf structure that holds the symbol&lt;br /&gt;and the&amp;nbsp;Huffman code (accumulated so far), in line 4.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#804040"&gt; 1 &lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;from&lt;/font&gt; collections &lt;font&lt;br /&gt; color="#a020f0"&gt;import&lt;/font&gt; namedtuple&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 2 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 3 &lt;/font&gt;Leaf = namedtuple('&lt;font&lt;br /&gt; color="#ff00ff"&gt;Leaf&lt;/font&gt;', '&lt;font color="#ff00ff"&gt;weight, symbols&lt;/font&gt;')&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 4 &lt;/font&gt;SH = namedtuple('&lt;font&lt;br /&gt; color="#ff00ff"&gt;SH&lt;/font&gt;', '&lt;font color="#ff00ff"&gt;sym, huff&lt;/font&gt;')&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 5 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 6 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;codecreate2&lt;/font&gt;(symbol2weights, tutor= False):&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 7 &lt;/font&gt;    '''&lt;font&lt;br /&gt; color="#ff00ff"&gt; Huffman codecreate2 the given dict mapping symbols to weights &lt;/font&gt;'''&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 8 &lt;/font&gt;    heap = [ Leaf(weight=float(wt), symbols=[ SH(sym, []) ])&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 9 &lt;/font&gt;             &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; sym, wt &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; symbol2weights.iteritems() ]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;10 &lt;/font&gt;    heapify(heap)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;11 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; tutor: &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#ff00ff"&gt;ENCODING:&lt;/font&gt;", sorted(symbol2weights.iteritems())&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;12 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt; len(heap) &amp;gt;1:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;13 &lt;/font&gt;        lo = heappop(heap)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;14 &lt;/font&gt;        hi = heappop(heap)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;15 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; tutor: &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#ff00ff"&gt;  COMBINING:&lt;/font&gt;", lo, '&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n&lt;/font&gt;&lt;font color="#ff00ff"&gt;        AND:&lt;/font&gt;', hi&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;16 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; sh &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; lo.symbols: sh.huff.insert(0, '&lt;font&lt;br /&gt; color="#ff00ff"&gt;0&lt;/font&gt;')&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;17 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; sh &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; hi.symbols: sh.huff.insert(0, '&lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt;')&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;18 &lt;/font&gt;        lohi = Leaf(weight  = lo.weight + hi.weight,&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;19 &lt;/font&gt;                    symbols = lo.symbols + hi.symbols)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;20 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; tutor: &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#ff00ff"&gt;  PRODUCING:&lt;/font&gt;", lohi, '&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n&lt;/font&gt;'&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;21 &lt;/font&gt;        heappush(heap, lohi)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;22 &lt;/font&gt;    symbols = heappop(heap).symbols&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;23 &lt;/font&gt;    symbols = [SH(sym, ''.join(huff)) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; sym, huff &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; symbols]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;24 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; sorted(symbols, key=&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;lambda&lt;/b&gt;&lt;/font&gt; sh: (len(sh.huff), sh))&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;25 &lt;/font&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;The&lt;br /&gt;class generation is succinct in lines 3 and 4, and I use the field&lt;br /&gt;names for clarity for example when creating the original list of Leaves&lt;br /&gt;that will form the heap in line 8&lt;br&gt;&lt;br /&gt;&lt;h3&gt;Printing namedtuples&lt;/h3&gt;&lt;br /&gt;The print statements stay the same, but before you got output like this:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;&lt;/span&gt;&lt;small&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;...&lt;br&gt;&lt;br /&gt;&amp;nbsp; COMBINING: [2.5, ['C', []]] &lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;AND: [5.0, ['A', []]]&lt;/span&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;PRODUCING: [7.5, ['C', ['0']], ['A', ['1']]] &lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;...&lt;/span&gt;&lt;/small&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Now you get the clearer:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;&lt;small&gt;&amp;nbsp;ENCODING:&lt;br /&gt;[('A', '5'), ('B', '25'), ('C', '2.5'), ('D', '12.5')]&lt;br&gt;&lt;br /&gt;&amp;nbsp; COMBINING: Leaf(weight=2.5, symbols=[SH(sym='C', huff=[])]) &lt;br&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;AND: Leaf(weight=5.0, symbols=[SH(sym='A', huff=[])])&lt;br&gt;&lt;br /&gt;&amp;nbsp; PRODUCING: Leaf(weight=7.5, symbols=[SH(sym='C',&lt;br /&gt;huff=['0']), SH(sym='A', huff=['1'])]) &lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&amp;nbsp; COMBINING: Leaf(weight=7.5, symbols=[SH(sym='C',&lt;br /&gt;huff=['0']), SH(sym='A', huff=['1'])]) &lt;br&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;AND: Leaf(weight=12.5, symbols=[SH(sym='D', huff=[])])&lt;br&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;PRODUCING: Leaf(weight=20.0, symbols=[SH(sym='C', huff=['0', '0']),&lt;br /&gt;SH(sym='A', huff=['0', '1']), SH(sym='D', huff=['1'])]) &lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;COMBINING: Leaf(weight=20.0, symbols=[SH(sym='C', huff=['0', '0']),&lt;br /&gt;SH(sym='A', huff=['0', '1']), SH(sym='D', huff=['1'])]) &lt;br&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;AND: Leaf(weight=25.0, symbols=[SH(sym='B', huff=[])])&lt;br&gt;&lt;br /&gt;&amp;nbsp;&lt;br /&gt;PRODUCING: Leaf(weight=45.0, symbols=[SH(sym='C', huff=['0', '0',&lt;br /&gt;'0']), SH(sym='A', huff=['0', '0', '1']), SH(sym='D', huff=['0', '1']),&lt;br /&gt;SH(sym='B', huff=['1'])]) &lt;/small&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h2&gt;Conclusion&lt;/h2&gt;&lt;br /&gt;&amp;nbsp;Although&lt;br /&gt;you can do so much with Python lists, if each position in the list has&lt;br /&gt;a fixed meaning then you might be best to use tuples, and if you should&lt;br /&gt;be using tuples, then namedtuples can make your code more readable&lt;br /&gt;without bloating it with long class definitions.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;- Paddy.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-2981552897112217126?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/2981552897112217126/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/04/abuse-of-pythons-in-built-data.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/2981552897112217126'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/2981552897112217126'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/04/abuse-of-pythons-in-built-data.html' title='(Ab)use of Pythons in-built data structures'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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-11149365.post-3739700295514179469</id><published>2009-03-28T00:11:00.000Z</published><updated>2009-03-28T00:13:07.349Z</updated><title type='text'>Huffman Encoding in Python</title><content type='html'>&lt;br&gt;&lt;br /&gt;Huffman encoding came up on &lt;a&lt;br /&gt; href="http://www.rosettacode.org/wiki/Huffman_codes"&gt;Rosetta&lt;br /&gt;Code&lt;/a&gt;.&lt;br&gt;&lt;br /&gt;&lt;p&gt;Huffman encoding is a way to assign binary codes to symbols&lt;br /&gt;that&lt;br /&gt;reduces the overall number of bits used to encode a typical string of&lt;br /&gt;of those symbols.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;For example, if you use letters as symbols and have details of&lt;br /&gt;the frequency of occurence of those letters in typical strings, then&lt;br /&gt;you could just encode each letter with a fixed number of bits, such as&lt;br /&gt;in ASCII codes. You can do better than this by encoding more frequently&lt;br /&gt;occurring letters such as e and a, with smaller bit strings; and less&lt;br /&gt;frequently occurring letters such as q and x with longer bit strings.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Any string of letters will be encoded as a string of bits that&lt;br /&gt;are no-longer of the same length per letter. To successfully decode&lt;br /&gt;such as string, the smaller codes assigned to letters such as 'e'&lt;br /&gt;cannot occur as a prefix in the larger codes such as that for 'x'.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;dl&gt;&lt;br /&gt;  &lt;dd&gt;If you were to assign a code 01 for 'e' and code 011 for&lt;br /&gt;'x',&lt;br /&gt;then if the bits to decode started as 011... then you would not know&lt;br /&gt;iif you should decode an 'e' or an 'x'.&lt;br /&gt;  &lt;/dd&gt;&lt;br /&gt;&lt;/dl&gt;&lt;br /&gt;&lt;p&gt;The Huffman coding scheme takes each symbol and its weight (or&lt;br /&gt;frequency of occurrence), and generates proper encodings for each&lt;br /&gt;symbol taking account of the weights of each symbol, so that higher&lt;br /&gt;weighted symbols have less bits in their encoding. (See the &lt;a&lt;br /&gt; href="http://en.wikipedia.org/wiki/Huffman_coding" class="extiw"&lt;br /&gt; title="wp:Huffman_coding"&gt;WP article&lt;/a&gt; for more&lt;br /&gt;information).&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;A Huffman encoding can be computed by first creating a tree of&lt;br /&gt;nodes:&lt;/p&gt;&lt;br /&gt;&lt;table style="text-align: left; width: 90%;" border="0"&lt;br /&gt; cellpadding="1" cellspacing="1"&gt;&lt;br /&gt;  &lt;tbody&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td&gt;&lt;br /&gt;      &lt;div class="floatright"&gt;&lt;br /&gt;      &lt;ol&gt;&lt;br /&gt;        &lt;li&gt; Create a leaf node for each symbol and add it to the&lt;br /&gt;priority queue.&lt;br /&gt;        &lt;/li&gt;&lt;br /&gt;        &lt;li&gt; While there is more than one node in the queue:&lt;br /&gt;          &lt;ol&gt;&lt;br /&gt;            &lt;li&gt; Remove the node of highest priority (lowest&lt;br /&gt;probability) twice to get two nodes.&lt;br /&gt;            &lt;/li&gt;&lt;br /&gt;            &lt;li&gt; Create a new internal node with these two nodes&lt;br /&gt;as children&lt;br /&gt;and with probability equal to the sum of the two nodes' probabilities.&lt;br /&gt;            &lt;/li&gt;&lt;br /&gt;            &lt;li&gt; Add the new node to the queue.&lt;br /&gt;            &lt;/li&gt;&lt;br /&gt;          &lt;/ol&gt;&lt;br /&gt;        &lt;/li&gt;&lt;br /&gt;        &lt;li&gt; The remaining node is the root node and the tree is&lt;br /&gt;complete.&lt;br /&gt;        &lt;/li&gt;&lt;br /&gt;      &lt;/ol&gt;&lt;br /&gt;Traverse the constructed binary tree from root to leaves&lt;br /&gt;assigning&lt;br /&gt;and accumulating a '0' for one branch and a '1' for the other at each&lt;br /&gt;node. The accumulated zeroes and ones at each leaf constitute a Huffman&lt;br /&gt;encoding for those symbols and weights.&lt;br /&gt;      &lt;/div&gt;&lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;      &lt;td&gt;&lt;br /&gt;      &lt;div class="floatright"&gt;&lt;span&gt;&lt;a&lt;br /&gt; href="http://www.rosettacode.org/wiki/Image:Huffman_coding_example.jpg"&lt;br /&gt; class="image" title="Huffman coding example.jpg"&gt;&lt;img&lt;br /&gt; alt=""&lt;br /&gt; src="http://www.rosettacode.org/w/images/thumb/8/8b/Huffman_coding_example.jpg/250px-Huffman_coding_example.jpg"&lt;br /&gt; border="0" height="120" width="250"&gt;&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;  &lt;/tbody&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;h2&gt;In Python&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;I orginally gave an an example that matched a definition that&lt;br /&gt;was later found to be insufficient, so substituted my own definition&lt;br /&gt;above.. My &lt;a&lt;br /&gt; href="http://www.rosettacode.org/w/index.php?title=Huffman_codes&amp;amp;oldid=26720#Python"&gt;first&lt;br /&gt;Python solution &amp;nbsp;on RC&lt;/a&gt; to the wrong definition, did&lt;br /&gt;have the advantage, (as I saw it), of not having to traverse a tree.&lt;/p&gt;&lt;br /&gt;My 'true' Huffman&amp;nbsp;code creator assembles each symbol and its&lt;br /&gt;weight into the following structure initially (the &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;leaf structure)&lt;/span&gt;:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;[ weight, [ symbol, []]]&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;big&gt;The weight applies to every (in this case only one), of the&lt;span&lt;br /&gt; style="font-family: monospace;"&gt; [symbol, []]&lt;/span&gt;&lt;br /&gt;pairs after it in the same list.&lt;br&gt;&lt;br /&gt;The empty list is used to accumulate the Huffman code for the symbol as&lt;br /&gt;we manipulate the heap, without having to walk a constructed tree&lt;br /&gt;structure.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;There are two types of input to the program that I am running examples&lt;br /&gt;with:&lt;br&gt;&lt;br /&gt;&lt;/big&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;  &lt;li&gt;A string of space separated symbol, weight pairs, as used&lt;br /&gt;in small examples.&lt;/li&gt;&lt;br /&gt;  &lt;li&gt;A sample of text for which letters and letter frequencies&lt;br /&gt;are extracted.&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;The if statement at line &lt;span style="font-weight: bold;"&gt;23&lt;/span&gt;&lt;br /&gt;&amp;nbsp;allows me to switch between the two types of input whilst&lt;br /&gt;exploring the algorithm.&lt;br&gt;&lt;br /&gt;The tutor argument to the encode function shows what is happening in&lt;br /&gt;the loop around the heap pops&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#804040"&gt; 1 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 2 &lt;/font&gt;&lt;font color="#a020f0"&gt;from&lt;/font&gt; heapq &lt;font&lt;br /&gt; color="#a020f0"&gt;import&lt;/font&gt; heappush, heappop, heapify&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 3 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 4 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;codecreate&lt;/font&gt;(symbol2weights, tutor= False):&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 5 &lt;/font&gt;    '''&lt;font&lt;br /&gt; color="#ff00ff"&gt; Huffman encode the given dict mapping symbols to weights &lt;/font&gt;'''&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 6 &lt;/font&gt;    heap = [ [float(wt), [sym, []]] &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; sym, wt &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; symbol2weights.iteritems() ]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 7 &lt;/font&gt;    heapify(heap)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 8 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; tutor: &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#ff00ff"&gt;ENCODING:&lt;/font&gt;", sorted(symbol2weights.iteritems())&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 9 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt; len(heap) &amp;gt;1:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;10 &lt;/font&gt;        lo = heappop(heap)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;11 &lt;/font&gt;        hi = heappop(heap)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;12 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; tutor: &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#ff00ff"&gt;  COMBINING:&lt;/font&gt;", lo, '&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n&lt;/font&gt;&lt;font color="#ff00ff"&gt;        AND:&lt;/font&gt;', hi&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;13 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; lo[1:]: i[1].insert(0, '&lt;font&lt;br /&gt; color="#ff00ff"&gt;0&lt;/font&gt;')&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;14 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; hi[1:]: i[1].insert(0, '&lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt;')&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;15 &lt;/font&gt;        lohi = [ lo[0] + hi[0] ] + lo[1:] + hi[1:]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;16 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; tutor: &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#ff00ff"&gt;  PRODUCING:&lt;/font&gt;", lohi, '&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n&lt;/font&gt;'&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;17 &lt;/font&gt;        heappush(heap, lohi)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;18 &lt;/font&gt;    codes = heappop(heap)[1:]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;19 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; codes: i[1] = ''.join(i[1])&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;20 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; sorted(codes, key=&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;lambda&lt;/b&gt;&lt;/font&gt; x: (len(x[-1]), x))&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;21 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;22 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Input types&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;span&lt;br /&gt; style="font-weight: bold; background-color: rgb(255, 255, 102);"&gt;23&lt;/span&gt; &lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; 1:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;24 &lt;/font&gt;    readin = "&lt;font&lt;br /&gt; color="#ff00ff"&gt;B 25   C 2.5 D  12.5 A 5 &lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n&lt;/font&gt;"&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;25 &lt;/font&gt;    &lt;font color="#0000ff"&gt;#readin = "a .1 b .15 c .3 d .16 e .29" # Wikipedia sample&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;26 &lt;/font&gt;    &lt;font color="#0000ff"&gt;#readin = "a1 .4 a2 .35 a3 .2 a4 .05" # Wikipedia sample&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;27 &lt;/font&gt;    &lt;font color="#0000ff"&gt;#readin = "A 50 B 25 C 12.5 D 12.5" # RC example&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;28 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;29 &lt;/font&gt;    cleaned = readin.strip().split()&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;30 &lt;/font&gt;    symbol2weights = dict((symbol, wt)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;31 &lt;/font&gt;                         &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; symbol, wt &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; zip(cleaned[0::2], cleaned[1::2]) )&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;32 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt;:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;33 &lt;/font&gt;    astring = "&lt;font&lt;br /&gt; color="#ff00ff"&gt;this is an example for huffman encoding&lt;/font&gt;"&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;34 &lt;/font&gt;    symbol2weights = dict((ch, astring.count(ch)) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; ch &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; set(astring)) &lt;font&lt;br /&gt; color="#0000ff"&gt;# for astring&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;35 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;36 &lt;/font&gt;huff = codecreate(symbol2weights, True)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;37 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n&lt;/font&gt;&lt;font color="#ff00ff"&gt;SYMBOL&lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;\t&lt;/font&gt;&lt;font color="#ff00ff"&gt;WEIGHT&lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;\t&lt;/font&gt;&lt;font color="#ff00ff"&gt;HUFFMAN CODE&lt;/font&gt;"&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;38 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; h &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; huff:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;39 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#ff00ff"&gt;%s&lt;/font&gt;&lt;font color="#6a5acd"&gt;\t&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;%s&lt;/font&gt;&lt;font color="#6a5acd"&gt;\t&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;%s&lt;/font&gt;" % (h[0], symbol2weights[h[0]], h[1])&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;A run, with the tutor enabled gives the following output:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;ENCODING: [('A', '5'), ('B',&lt;br /&gt;'25'), ('C', '2.5'), ('D', '12.5')]&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;COMBINING: [2.5, ['C', []]] &lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;AND: [5.0, ['A', []]]&lt;/span&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;PRODUCING: [7.5, ['C', ['0']], ['A', ['1']]] &lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;COMBINING: [7.5, ['C', ['0']], ['A', ['1']]] &lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;AND: [12.5, ['D', []]]&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;PRODUCING: [20.0, ['C', ['0', '0']], ['A', ['0', '1']], ['D', ['1']]] &lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;COMBINING: [20.0, ['C', ['0', '0']], ['A', ['0', '1']], ['D', ['1']]] &lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;AND: [25.0, ['B', []]]&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;PRODUCING: [45.0, ['C', ['0', '0', '0']], ['A', ['0', '0', '1']], ['D',&lt;br /&gt;['0', '1']], ['B', ['1']]] &lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;SYMBOL&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;WEIGHT&amp;nbsp;&amp;nbsp;&amp;nbsp; HUFFMAN CODE&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;B&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;25&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; 1&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;D&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;12.5 &amp;nbsp; &amp;nbsp;&amp;nbsp; 01&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;A&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;5&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;001&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;C&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;2.5&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp;000&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;h2&gt;Encode/Decode Round-tripping&lt;/h2&gt;&lt;br /&gt;I realised that I could use a method similar to how I accumulate the&lt;br /&gt;codes in the heap loop, to generate a single function that can&lt;br /&gt;recognise a single symbol from the beginning of the encoded symbols. By&lt;br /&gt;using the function in a loop, I could regenerate the symbol list.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;In the codecreate function, the &lt;span style="font-weight: bold;"&gt;leaf&lt;br /&gt;structure&lt;/span&gt; is modified:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;[weight, [ [symbol, []] ],&lt;br /&gt;repr(sym)]&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;Their is an extra level of list around the [symbol, code accumulation&lt;br /&gt;list pair] &amp;nbsp;as well as a new item: 'repr(sym)' it is the third&lt;br /&gt;item in the outer list and will always be the &amp;nbsp;function to&lt;br /&gt;generate the item as accumulated so far.. This function starts off by&lt;br /&gt;returning just the symbol and an outer if/then/else expression is added&lt;br /&gt;as we go around the heap loop (see line &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;43&lt;/span&gt;)&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;After the outer expression is accumulated, it is turned into a lambda&lt;br /&gt;expression, the string eval'd, and assigned to a global variable (see&lt;br /&gt;line &lt;span style="font-weight: bold;"&gt;47&lt;/span&gt;)&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I use function probchoice (from earlier RC work), to create an&lt;br /&gt;arbitrary sequence of symbols to in the given weighting then encode and&lt;br /&gt;decode it as well as giving some stats on space saving.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#804040"&gt;  1 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;  2 &lt;/font&gt;&lt;font color="#a020f0"&gt;from&lt;/font&gt; heapq &lt;font&lt;br /&gt; color="#a020f0"&gt;import&lt;/font&gt; heappush, heappop, heapify&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;  3 &lt;/font&gt;&lt;font color="#a020f0"&gt;import&lt;/font&gt; random, bisect&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;  4 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;  5 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;  6 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Helper routine for generating test sequences&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;span&lt;br /&gt; style="background-color: rgb(255, 255, 102);"&gt;  7&lt;/span&gt; &lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;probchoice&lt;/font&gt;(items, probs):&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;  8 &lt;/font&gt;  '''&lt;font&lt;br /&gt; color="#6a5acd"&gt;\&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;  9 &lt;/font&gt;&lt;font color="#ff00ff"&gt;  Splits the interval 0.0-1.0 in proportion to probs&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 10 &lt;/font&gt;&lt;font color="#ff00ff"&gt;  then finds where each random.random() choice lies&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 11 &lt;/font&gt;&lt;font color="#ff00ff"&gt;  (This routine, probchoice, was released under the&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 12 &lt;/font&gt;&lt;font color="#ff00ff"&gt;  GNU Free Documentation License 1.2)&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 13 &lt;/font&gt;&lt;font color="#ff00ff"&gt;  &lt;/font&gt;'''&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 14 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 15 &lt;/font&gt;  prob_accumulator = 0&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 16 &lt;/font&gt;  accumulator = []&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 17 &lt;/font&gt;  &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; p &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; probs:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 18 &lt;/font&gt;    prob_accumulator += p&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 19 &lt;/font&gt;    accumulator.append(prob_accumulator)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 20 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 21 &lt;/font&gt;  &lt;font color="#804040"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt; True:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 22 &lt;/font&gt;    r = random.random()&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 23 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;yield&lt;/b&gt;&lt;/font&gt; items[bisect.bisect(accumulator, r)]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 24 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 25 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 26 &lt;/font&gt;&lt;font color="#0000ff"&gt;# placeholder&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 27 &lt;/font&gt;decode = &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;lambda&lt;/b&gt;&lt;/font&gt; : None&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 28 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 29 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;codecreate&lt;/font&gt;(symbol2weights, tutor= False):&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 30 &lt;/font&gt;    '''&lt;font&lt;br /&gt; color="#ff00ff"&gt; Huffman encode the given dict mapping symbols to weights &lt;/font&gt;'''&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 31 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;global&lt;/b&gt;&lt;/font&gt; decode&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 32 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 33 &lt;/font&gt;    heap = [ [float(wt), [[sym, []]], repr(sym)] &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; sym, wt &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; symbol2weights.iteritems() ]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 34 &lt;/font&gt;    heapify(heap)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 35 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; tutor: &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#ff00ff"&gt;ENCODING:&lt;/font&gt;", sorted(symbol2weights.iteritems())&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 36 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt; len(heap) &amp;gt;1:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 37 &lt;/font&gt;        lo = heappop(heap)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 38 &lt;/font&gt;        hi = heappop(heap)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 39 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; tutor: &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#ff00ff"&gt;  COMBINING:&lt;/font&gt;", lo, '&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n&lt;/font&gt;&lt;font color="#ff00ff"&gt;        AND:&lt;/font&gt;', hi&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 40 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; lo[1]: i[1].insert(0, '&lt;font&lt;br /&gt; color="#ff00ff"&gt;0&lt;/font&gt;')&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 41 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; hi[1]: i[1].insert(0, '&lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt;')&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 42 &lt;/font&gt;        lohi = [ lo[0] + hi[0] ] + [lo[1] + hi[1]]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;span&lt;br /&gt; style="background-color: rgb(255, 255, 102);"&gt; 43&lt;/span&gt; &lt;/font&gt;        lohi.append('&lt;font&lt;br /&gt; color="#ff00ff"&gt;(%s if nextbit() else %s)&lt;/font&gt;' % (hi[2], lo[2]))&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 44 &lt;/font&gt;        &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; tutor: &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#ff00ff"&gt;  PRODUCING:&lt;/font&gt;", lohi, '&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n&lt;/font&gt;'&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 45 &lt;/font&gt;        heappush(heap, lohi)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 46 &lt;/font&gt;    wt, codes, decoder = heappop(heap)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;span&lt;br /&gt; style="background-color: rgb(255, 255, 102);"&gt; 47&lt;/span&gt; &lt;/font&gt;    decode = eval('&lt;font&lt;br /&gt; color="#ff00ff"&gt;lambda :&lt;/font&gt;' + decoder, globals())&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 48 &lt;/font&gt;    decode.__doc__ = decoder&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 49 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; codes: i[1] = ''.join(i[1])&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 50 &lt;/font&gt;    &lt;font color="#0000ff"&gt;#for i in codes: i[::] = i[:2]&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 51 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt; sorted(codes, key=&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;lambda&lt;/b&gt;&lt;/font&gt; x: (len(x[-1]), x))&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 52 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 53 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Input types&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;span&lt;br /&gt; style="background-color: rgb(255, 255, 102);"&gt; 54&lt;/span&gt; &lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; 1:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 55 &lt;/font&gt;    tutor = True&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 56 &lt;/font&gt;    sequencecount = 50&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 57 &lt;/font&gt;    readin = "&lt;font&lt;br /&gt; color="#ff00ff"&gt;B 25   C 2.5 D  12.5 A 5 &lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n&lt;/font&gt;"&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 58 &lt;/font&gt;    &lt;font color="#0000ff"&gt;#readin = "a .1 b .15 c .3 d .16 e .29" # Wikipedia sample&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 59 &lt;/font&gt;    &lt;font color="#0000ff"&gt;#readin = "a1 .4 a2 .35 a3 .2 a4 .05" # Wikipedia sample&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 60 &lt;/font&gt;    &lt;font color="#0000ff"&gt;#readin = "A 50 B 25 C 12.5 D 12.5" # RC example&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 61 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 62 &lt;/font&gt;    cleaned = readin.strip().split()&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 63 &lt;/font&gt;    symbol2weights = dict((symbol, wt)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 64 &lt;/font&gt;                         &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; symbol, wt &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; zip(cleaned[0::2], cleaned[1::2]) )&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 65 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt;:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 66 &lt;/font&gt;    tutor = False&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 67 &lt;/font&gt;    sequencecount = 500&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 68 &lt;/font&gt;    astring = "&lt;font&lt;br /&gt; color="#ff00ff"&gt;this is an example for huffman encoding&lt;/font&gt;"&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 69 &lt;/font&gt;    symbol2weights = dict((ch, astring.count(ch)) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; ch &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; set(astring)) &lt;font&lt;br /&gt; color="#0000ff"&gt;# for astring&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 70 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 71 &lt;/font&gt;huff = codecreate(symbol2weights, tutor= tutor)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 72 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n&lt;/font&gt;&lt;font color="#ff00ff"&gt;SYMBOL&lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;\t&lt;/font&gt;&lt;font color="#ff00ff"&gt;WEIGHT&lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;\t&lt;/font&gt;&lt;font color="#ff00ff"&gt;HUFFMAN CODE&lt;/font&gt;"&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 73 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; h &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; huff:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 74 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#ff00ff"&gt;%s&lt;/font&gt;&lt;font color="#6a5acd"&gt;\t&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;%s&lt;/font&gt;&lt;font color="#6a5acd"&gt;\t&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;%s&lt;/font&gt;" % (h[0], symbol2weights[h[0]], h[1])&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 75 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 76 &lt;/font&gt;&lt;font color="#0000ff"&gt;##&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 77 &lt;/font&gt;&lt;font color="#0000ff"&gt;## encode-decode check&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 78 &lt;/font&gt;&lt;font color="#0000ff"&gt;##&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 79 &lt;/font&gt;symbol2code = dict(huff)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 80 &lt;/font&gt;symbols, weights = zip(*symbol2weights.iteritems())&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 81 &lt;/font&gt;&lt;font color="#0000ff"&gt;# normalize weights&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 82 &lt;/font&gt;weights = [float(wt) &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; wt &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; weights]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 83 &lt;/font&gt;tot = sum(weights)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 84 &lt;/font&gt;weights = [wt/tot &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; wt &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; weights]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 85 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Generate a sequence&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 86 &lt;/font&gt;nxt = probchoice(symbols, weights).next&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 87 &lt;/font&gt;symbolsequence = [nxt() &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; i &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; range(sequencecount)]&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 88 &lt;/font&gt;&lt;font color="#0000ff"&gt;# encode it&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 89 &lt;/font&gt;bitsequence = ''.join(symbol2code[sym] &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; sym &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; symbolsequence)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 90 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 91 &lt;/font&gt;sslen, slen, blen = len(symbolsequence), len(symbols), len(bitsequence)&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 92 &lt;/font&gt;countlen = len(bin(slen-1)[2:])&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 93 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; '''&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 94 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 95 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 96 &lt;/font&gt;&lt;font color="#ff00ff"&gt;ROUND-TRIPPING&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 97 &lt;/font&gt;&lt;font color="#ff00ff"&gt;==============&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 98 &lt;/font&gt;&lt;font color="#ff00ff"&gt;I have generated a random sequence of %i symbols to the given weights.&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 99 &lt;/font&gt;&lt;font color="#ff00ff"&gt;If I use a binary count to encode each of the %i symbols I would need&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;100 &lt;/font&gt;&lt;font color="#ff00ff"&gt;%i * %i = %i bits to encode the sequence.&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;101 &lt;/font&gt;&lt;font color="#ff00ff"&gt;Using the Huffman code, I need only %i bits.&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;102 &lt;/font&gt;''' % (sslen, slen, sslen, countlen, sslen * countlen, blen )&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;103 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;104 &lt;/font&gt;&lt;font color="#0000ff"&gt;## decoding&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;105 &lt;/font&gt;nextbit = (bit=='&lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt;' &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; bit &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/font&gt; bitsequence).next&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;106 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;107 &lt;/font&gt;decoded = []&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;108 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;try&lt;/b&gt;&lt;/font&gt;:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;109 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt; 1:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;110 &lt;/font&gt;        decoded.append(decode())&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;111 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;except&lt;/b&gt;&lt;/font&gt; StopIteration:&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;112 &lt;/font&gt;    &lt;font color="#804040"&gt;&lt;b&gt;pass&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;113 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;114 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/font&gt; "&lt;font&lt;br /&gt; color="#ff00ff"&gt;Comparing the decoded sequence with the original I get:&lt;/font&gt;", decoded == symbolsequence&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;This short run is in tutor mode, so you can track the accumulation of&lt;br /&gt;the decode function:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;ENCODING: [('A', '5'), ('B',&lt;br /&gt;'25'), ('C', '2.5'), ('D', '12.5')]&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;COMBINING: [2.5, [['C', []]], &lt;span style="font-weight: bold;"&gt;"'C'"&lt;/span&gt;]&lt;br /&gt;&lt;/span&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;AND: [5.0, [['A', []]], &lt;span style="font-weight: bold;"&gt;"'A'"&lt;/span&gt;]&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;PRODUCING: [7.5, [['C', ['0']], ['A', ['1']]], &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;"('A' if nextbit() else 'C')"&lt;/span&gt;]&lt;br /&gt;&lt;/span&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;COMBINING: [7.5, [['C', ['0']], ['A', ['1']]], "('A' if nextbit() else&lt;br /&gt;'C')"] &lt;/span&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;AND: [12.5, [['D', []]], "'D'"]&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;PRODUCING: [20.0, [['C', ['0', '0']], ['A', ['0', '1']], ['D', ['1']]],&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;"('D' if nextbit() else&lt;br /&gt;('A' if nextbit() else 'C'))"&lt;/span&gt;] &lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;COMBINING: [20.0, [['C', ['0', '0']], ['A', ['0', '1']], ['D', ['1']]],&lt;br /&gt;"('D' if nextbit() else ('A' if nextbit() else 'C'))"] &lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;AND: [25.0, [['B', []]], "'B'"]&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;PRODUCING: [45.0, [['C', ['0', '0', '0']], ['A', ['0', '0', '1']],&lt;br /&gt;['D', ['0', '1']], ['B', ['1']]], &lt;span style="font-weight: bold;"&gt;"('B'&lt;br /&gt;if nextbit() else ('D' if nextbit() else ('A' if nextbit() else 'C')))"&lt;/span&gt;]&lt;br /&gt;&lt;/span&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;SYMBOL&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;WEIGHT&amp;nbsp;&amp;nbsp;&amp;nbsp; HUFFMAN CODE&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;B&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;25&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;1&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;D&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;12.5&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp;&amp;nbsp; 01&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;A&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;5&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;001&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;C&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;2.5&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp; &amp;nbsp;000&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;ROUND-TRIPPING&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;==============&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;I have generated a&lt;br /&gt;random sequence of 50 symbols to the given weights.&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;If I use a binary&lt;br /&gt;count to encode each of the 4 symbols I would need&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;50 * 2 = &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;100&lt;/span&gt; bits to encode&lt;br /&gt;the sequence.&lt;/span&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Using the Huffman&lt;br /&gt;code, I need only &lt;span style="font-weight: bold;"&gt;90&lt;/span&gt;&lt;br /&gt;bits.&lt;/span&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Comparing the&lt;br /&gt;decoded sequence with the original I get: &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;True&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;And if I change line &lt;span style="font-weight: bold;"&gt;54&lt;/span&gt;&lt;br /&gt;to be False, I get the following:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;span&lt;br /&gt; style="font-family: monospace;"&gt;SYMBOL&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;WEIGHT&amp;nbsp;&amp;nbsp;&amp;nbsp; HUFFMAN CODE&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;6&amp;nbsp;&amp;nbsp;&amp;nbsp; 101&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;n&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;4&amp;nbsp;&amp;nbsp;&amp;nbsp; 010&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;a&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp; 1001&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;e&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp; 1100&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;f&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp; 1101&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;h&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp; 0001&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;i&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;3&amp;nbsp;&amp;nbsp;&amp;nbsp; 1110&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;m&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp; 0010&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;o&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp; 0011&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;s&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp; 0111&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;g&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp; 00000&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;l&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp; 00001&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;p&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp; 01100&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;r&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp; 01101&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;t&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp; 10000&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;u&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp; 10001&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;x&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp; 11110&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;c&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp; 111110&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;d&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;1&amp;nbsp;&amp;nbsp;&amp;nbsp; 111111&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;ROUND-TRIPPING&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;==============&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;I have generated a&lt;br /&gt;random sequence of 500 symbols to the given weights.&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;If I use a binary&lt;br /&gt;count to encode each of the 19 symbols I would need&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;500 * 5 = 2500 bits&lt;br /&gt;to encode the sequence.&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Using the Huffman&lt;br /&gt;code, I need only 2012 bits.&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;br style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="font-family: monospace;"&gt;Comparing the&lt;br /&gt;decoded sequence with the original I get: True&lt;/span&gt;&lt;br&lt;br /&gt; style="font-family: monospace;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Note: The purpose of the program is to teach me more about Huffman&lt;br /&gt;coding and is not an&amp;nbsp;exercise in speed!&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;I am the author of all the Python on this page. The diagram is from&lt;br /&gt;Wikipedia. Please refrain from passing-off my code as your own (that&lt;br /&gt;one is mainly for students).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/11149365-3739700295514179469?l=paddy3118.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://paddy3118.blogspot.com/feeds/3739700295514179469/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://paddy3118.blogspot.com/2009/03/huffman-encoding-in-python.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/3739700295514179469'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/11149365/posts/default/3739700295514179469'/><link rel='alternate' type='text/html' href='http://paddy3118.blogspot.com/2009/03/huffman-encoding-in-python.html' title='Huffman Encoding in Python'/><author><name>Paddy3118</name><uri>http://www.blogger.com/profile/06899509753521482267</uri><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>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-11149365.post-5802195128901405000</id><published>2009-03-21T06:35:00.000Z</published><updated>2009-03-21T06:37:21.652Z</updated><title type='text'>Batch Process Runner in bash shell - Forgotten Enhancements</title><content type='html'>A comment on an &lt;a&lt;br /&gt; href="http://paddy3118.blogspot.com/2007/12/batch-process-runner-in-bash-shell.html"&gt;earlier&lt;br /&gt;post&lt;/a&gt; caused me to dig out this enhancement to my original&lt;br /&gt;batch process runner. &lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;What you do is create a file of one-liner commands that you would enter&lt;br /&gt;at a command prompt, for example, this is file &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;process_list.txt&lt;/span&gt; :&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#804040"&gt;1 &lt;/font&gt;&lt;font&lt;br /&gt; color="#0000ff"&gt;# (Comments have '#' at the left margin)&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;2 &lt;/font&gt;sleep 4; echo slept for 4 at line 2; csdf_sdf_sd; exit 19&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;3 &lt;/font&gt;sleep 1; cause-an-error; echo slept for 1 at line 3&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;4 &lt;/font&gt;sleep 3; echo &lt;font&lt;br /&gt; color="#ff00ff"&gt;'slept for 3 at line 4'&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;5 &lt;/font&gt;sleep 7; echo &lt;font&lt;br /&gt; color="#ff00ff"&gt;"slept for 7 at line 5"&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;6 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Whee!&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;7 &lt;/font&gt;sleep 9; another-erro; echo slept for 9 at line 7&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt;8 &lt;/font&gt;sleep 5; echo &lt;font&lt;br /&gt; color="#ff00ff"&gt;'slept "for 5" at line 8'&lt;/font&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;A bit of warning, bash returns the exit code of this laast command it&lt;br /&gt;executes, earlier exit codes won't be seen.&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;Give my script the number of processes to run in parallel, N, followed&lt;br /&gt;by the above file, and it will create N '.job'&amp;nbsp; files out of&lt;br /&gt;the non-comment lines of process_list.txt and execute them as&lt;br /&gt;background jobs, with their output sent to '.n' files.:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;bash$ &lt;span style="font-weight: bold;"&gt;./process_list_runner.sh 2 process_list.txt&lt;/span&gt;&lt;br&gt;&lt;br&gt;## STARTING 6 Processes from file: process_list.txt, 2 at a time with id plr_HPDV8025EA_2009-03-21-05_36_19_PADDYS-HPLAPTOP&lt;br&gt;&lt;br&gt;# 2 Jobs in background. 6/6 started. 2009-03-21-05:36:36&lt;br&gt;&lt;br&gt;## FINISHED, (stats in plr_HPDV8025EA_2009-03-21-05_36_19_PADDYS-HPLAPTOP.csv)&lt;br&gt;&lt;br&gt;bash$ &lt;span&lt;br /&gt; style="font-weight: bold;"&gt;ls -1 plr_HPDV8025EA_2009-03-21-05_36_19_PADDYS-HPLAPTOP.*&lt;/span&gt;&lt;br&gt;plr_HPDV8025EA_2009-03-21-05_36_19_PADDYS-HPLAPTOP.1&lt;br&gt;plr_HPDV8025EA_2009-03-21-05_36_19_PADDYS-HPLAPTOP.2&lt;br&gt;plr_HPDV8025EA_2009-03-21-05_36_19_PADDYS-HPLAPTOP.3&lt;br&gt;plr_HPDV8025EA_2009-03-21-05_36_19_PADDYS-HPLAPTOP.4&lt;br&gt;plr_HPDV8025EA_2009-03-21-05_36_19_PADDYS-HPLAPTOP.5&lt;br&gt;plr_HPDV8025EA_2009-03-21-05_36_19_PADDYS-HPLAPTOP.6&lt;br&gt;plr_HPDV8025EA_2009-03-21-05_36_19_PADDYS-HPLAPTOP.csv&lt;br&gt;plr_HPDV8025EA_2009-03-21-05_36_19_PADDYS-HPLAPTOP.job_0&lt;br&gt;plr_HPDV8025EA_2009-03-21-05_36_19_PADDYS-HPLAPTOP.job_1&lt;br&gt;bash$ &lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;The script does what it can to create a csv file of run stats, which,&lt;br /&gt;with a bit of tidying up in calc produces the following:&lt;br&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;table border="0" cellspacing="0" cols="12"&lt;br /&gt; frame="void" rules="none"&gt;&lt;br /&gt;  &lt;colgroup&gt;&lt;col width="44"&gt;&lt;col width="46"&gt;&lt;col&lt;br /&gt; width="340"&gt;&lt;col width="106"&gt;&lt;col width="115"&gt;&lt;col&lt;br /&gt; width="110"&gt;&lt;col width="141"&gt;&lt;col width="118"&gt;&lt;col&lt;br /&gt; width="115"&gt;&lt;col width="100"&gt;&lt;col width="101"&gt;&lt;col&lt;br /&gt; width="73"&gt;&lt;/colgroup&gt; &lt;tbody&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td colspan="12" align="center" height="24"&lt;br /&gt; width="1409"&gt;&lt;b&gt;&lt;u&gt;&lt;font size="4"&gt;##&lt;br /&gt;STARTING 6 Processes from file: process_list.txt&lt;/font&gt;&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td colspan="12" align="center" height="24"&gt;&lt;b&gt;&lt;u&gt;&lt;font&lt;br /&gt; size="4"&gt;2 at a time with id&lt;br /&gt;plr_HPDV8025EA_2009-03-21-05_36_19_PADDYS-HPLAPTOP&lt;/font&gt;&lt;/u&gt;&lt;/b&gt;&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td align="left" height="17"&gt;&lt;br&gt;&lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;      &lt;td align="left"&gt;&lt;br&gt;&lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;      &lt;td align="left"&gt;&lt;br&gt;&lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;      &lt;td align="left"&gt;&lt;br&gt;&lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;      &lt;td align="left"&gt;&lt;br&gt;&lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;      &lt;td align="left"&gt;&lt;br&gt;&lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;      &lt;td align="left"&gt;&lt;br&gt;&lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;      &lt;td align="left"&gt;&lt;br&gt;&lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;      &lt;td align="left"&gt;&lt;br&gt;&lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;      &lt;td align="left"&gt;&lt;br&gt;&lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;      &lt;td align="left"&gt;&lt;br&gt;&lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;      &lt;td align="left"&gt;&lt;br&gt;&lt;br /&gt;      &lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; align="center" bgcolor="#ccffff" height="123"&lt;br /&gt; valign="middle"&gt;&lt;b&gt;JOB&lt;/b&gt;&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; align="right" bgcolor="#ccffff" valign="middle"&gt;&lt;b&gt;LINE&lt;/b&gt;&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; align="center" bgcolor="#ccffff" valign="middle"&gt;&lt;b&gt;Command&lt;br /&gt;being timed&lt;/b&gt;&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; align="center" bgcolor="#ccffff" valign="middle"&gt;&lt;b&gt;User&lt;br /&gt;time (seconds)&lt;/b&gt;&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; align="center" bgcolor="#ccffff" valign="middle"&gt;&lt;b&gt;System&lt;br /&gt;time (seconds)&lt;/b&gt;&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; align="center" bgcolor="#ccffff" valign="middle"&gt;&lt;b&gt;Percent&lt;br /&gt;of CPU this job got&lt;/b&gt;&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; align="center" bgcolor="#ccffff" valign="middle"&gt;&lt;b&gt;Elapsed&lt;br /&gt;(wall clock) time (h:mm:ss or m:ss)&lt;/b&gt;&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; align="center" bgcolor="#ccffff" valign="middle"&gt;&lt;b&gt;Maximum&lt;br /&gt;resident set size (kbytes)&lt;/b&gt;&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; align="center" bgcolor="#ccffff" valign="middle"&gt;&lt;b&gt;Major&lt;br /&gt;(requiring I/O) page faults&lt;/b&gt;&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; align="center" bgcolor="#ccffff" valign="middle"&gt;&lt;b&gt;Signals&lt;br /&gt;delivered&lt;/b&gt;&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; align="center" bgcolor="#ccffff" valign="middle"&gt;&lt;b&gt;Page&lt;br /&gt;size (bytes)&lt;/b&gt;&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; align="center" bgcolor="#ccffff" valign="middle"&gt;&lt;b&gt;Exit&lt;br /&gt;status&lt;/b&gt;&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="1"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&lt;br /&gt; height="18"&gt;1&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="2"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;2&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" align="left"&lt;br /&gt; bgcolor="#ffffcc"&gt;sleep 4; echo slept for 4 at line 2;&lt;br /&gt;csdf_sdf_sd; exit 19&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.13"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;0.13&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.15"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;0.15&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.06"&lt;br /&gt; sdnum="2057;0;0.00%" align="center" bgcolor="#ffffcc"&gt;6.00%&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="0.0000503472222222222" sdnum="2057;0;MM:SS.00"&lt;br /&gt; align="center" bgcolor="#ffffcc"&gt;00:04.35&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="760832" sdnum="2057;" align="center"&lt;br /&gt; bgcolor="#ffffcc"&gt;760832&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="3277"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;3277&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="6"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;6&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="65536" sdnum="2057;" align="center"&lt;br /&gt; bgcolor="#ffffcc"&gt;65536&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="19"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;19&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="2"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&lt;br /&gt; height="17"&gt;2&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="3"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;3&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" align="left"&lt;br /&gt; bgcolor="#ccccff"&gt;sleep 1; cause-an-error; echo slept for 1&lt;br /&gt;at line 3&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.12"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;0.12&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.09"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;0.09&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.16"&lt;br /&gt; sdnum="2057;0;0.00%" align="center" bgcolor="#ccccff"&gt;16.00%&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="0.0000152777777777778" sdnum="2057;0;MM:SS.00"&lt;br /&gt; align="center" bgcolor="#ccccff"&gt;00:01.32&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="761088" sdnum="2057;" align="center"&lt;br /&gt; bgcolor="#ccccff"&gt;761088&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="3273"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;3273&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="6"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;6&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="65536" sdnum="2057;" align="center"&lt;br /&gt; bgcolor="#ccccff"&gt;65536&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;0&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="3"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&lt;br /&gt; height="17"&gt;3&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="4"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;4&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" align="left"&lt;br /&gt; bgcolor="#ffffcc"&gt;sleep 3; echo 'slept for 3 at line 4'&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.07"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;0.07&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.06"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;0.06&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.04"&lt;br /&gt; sdnum="2057;0;0.00%" align="center" bgcolor="#ffffcc"&gt;4.00%&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="0.0000377314814814815" sdnum="2057;0;MM:SS.00"&lt;br /&gt; align="center" bgcolor="#ffffcc"&gt;00:03.26&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="617216" sdnum="2057;" align="center"&lt;br /&gt; bgcolor="#ffffcc"&gt;617216&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="2639"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;2639&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="3"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;3&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="65536" sdnum="2057;" align="center"&lt;br /&gt; bgcolor="#ffffcc"&gt;65536&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;0&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="4"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&lt;br /&gt; height="17"&gt;4&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="5"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;5&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" align="left"&lt;br /&gt; bgcolor="#ccccff"&gt;sleep 7; echo "slept for 7 at line 5"&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.07"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;0.07&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.07"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;0.07&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.02"&lt;br /&gt; sdnum="2057;0;0.00%" align="center" bgcolor="#ccccff"&gt;2.00%&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="0.000084837962962963" sdnum="2057;0;MM:SS.00"&lt;br /&gt; align="center" bgcolor="#ccccff"&gt;00:07.33&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="617216" sdnum="2057;" align="center"&lt;br /&gt; bgcolor="#ccccff"&gt;617216&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="2644"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;2644&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="3"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;3&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="65536" sdnum="2057;" align="center"&lt;br /&gt; bgcolor="#ccccff"&gt;65536&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;0&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="5"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&lt;br /&gt; height="18"&gt;5&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="7"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;7&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" align="left"&lt;br /&gt; bgcolor="#ffffcc"&gt;sleep 9; another-erro; echo slept for 9 at&lt;br /&gt;line 7&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.09"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;0.09&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.13"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;0.13&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.02"&lt;br /&gt; sdnum="2057;0;0.00%" align="center" bgcolor="#ffffcc"&gt;2.00%&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="0.000106597222222222" sdnum="2057;0;MM:SS.00"&lt;br /&gt; align="center" bgcolor="#ffffcc"&gt;00:09.21&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="760064" sdnum="2057;" align="center"&lt;br /&gt; bgcolor="#ffffcc"&gt;760064&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="3274"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;3274&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="6"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;6&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="65536" sdnum="2057;" align="center"&lt;br /&gt; bgcolor="#ffffcc"&gt;65536&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ffffcc"&gt;0&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;    &lt;tr&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="6"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&lt;br /&gt; height="17"&gt;6&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="8"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;8&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" align="left"&lt;br /&gt; bgcolor="#ccccff"&gt;sleep 5; echo 'slept "for 5" at line 8'&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.1"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;0.1&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.06"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;0.06&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0.03"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;0.03&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="0.0000622685185185185" sdnum="2057;0;MM:SS.00"&lt;br /&gt; align="center" bgcolor="#ccccff"&gt;00:05.38&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="617216" sdnum="2057;" align="center"&lt;br /&gt; bgcolor="#ccccff"&gt;617216&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="2639"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;2639&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="3"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;3&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);"&lt;br /&gt; sdval="65536" sdnum="2057;" align="center"&lt;br /&gt; bgcolor="#ccccff"&gt;65536&lt;/td&gt;&lt;br /&gt;      &lt;td style="border: 1px solid rgb(0, 0, 0);" sdval="0"&lt;br /&gt; sdnum="2057;" align="center" bgcolor="#ccccff"&gt;0&lt;/td&gt;&lt;br /&gt;    &lt;/tr&gt;&lt;br /&gt;  &lt;/tbody&gt;&lt;br /&gt;&lt;/table&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br&gt;&lt;br /&gt;The script itself is:&lt;br&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;br /&gt;&lt;pre&gt;&lt;font color="#804040"&gt; 1 &lt;/font&gt;&lt;font&lt;br /&gt; color="#0000ff"&gt;#!/bin/bash &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 2 &lt;/font&gt;&lt;font color="#0000ff"&gt;#!/opt/TWWfsw/bin/bash -&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 3 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 4 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;set &lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#008080"&gt;-u&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 5 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 6 &lt;/font&gt;&lt;font color="#0000ff"&gt;##&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 7 &lt;/font&gt;&lt;font color="#0000ff"&gt;## process_runner.sh &amp;lt;concurrent&amp;gt; &amp;lt;total procs&amp;gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 8 &lt;/font&gt;&lt;font color="#0000ff"&gt;##&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 9 &lt;/font&gt;&lt;font color="#0000ff"&gt;## Example script given the maximum number of processes to&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 10 &lt;/font&gt;&lt;font color="#0000ff"&gt;## run concurrently, c, and the total number of processes, n&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 11 &lt;/font&gt;&lt;font color="#0000ff"&gt;## runs at most c, processes in the background until all n&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 12 &lt;/font&gt;&lt;font color="#0000ff"&gt;## Have been run.&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 13 &lt;/font&gt;&lt;font color="#0000ff"&gt;##&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 14 &lt;/font&gt;&lt;font color="#0000ff"&gt;## Author Donald 'Paddy' McCarthy Dec. 17 2007&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 15 &lt;/font&gt;&lt;font color="#0000ff"&gt;##&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 16 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 17 &lt;/font&gt;&lt;font color="#0000ff"&gt;# how many processes to run in parallel&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 18 &lt;/font&gt;&lt;font color="#008080"&gt;concurrent&lt;/font&gt;=&lt;font&lt;br /&gt; color="#a020f0"&gt;$1&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 19 &lt;/font&gt;&lt;font color="#0000ff"&gt;# File of commands&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 20 &lt;/font&gt;&lt;font color="#008080"&gt;proclist&lt;/font&gt;=&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$2&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 21 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 22 &lt;/font&gt;&lt;font color="#0000ff"&gt;##&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 23 &lt;/font&gt;&lt;font color="#0000ff"&gt;##&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 24 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 25 &lt;/font&gt;&lt;font color="#0000ff"&gt;# main loop wait time between checking background procs.&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 26 &lt;/font&gt;&lt;font color="#008080"&gt;tick&lt;/font&gt;=&lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 27 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Unique_id for process files of this run&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 28 &lt;/font&gt;&lt;font color="#008080"&gt;unique_id&lt;/font&gt;=plr_&lt;font&lt;br /&gt; color="#6a5acd"&gt;`date +&lt;/font&gt;&lt;font color="#a020f0"&gt;${&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;USER&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;//&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;}&lt;/font&gt;&lt;font color="#6a5acd"&gt;_%F-%T_&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;${&lt;/font&gt;&lt;font color="#a020f0"&gt;HOSTNAME&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;//&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;}&lt;/font&gt;&lt;font color="#6a5acd"&gt;`&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 29 &lt;/font&gt;&lt;font color="#008080"&gt;unique_id&lt;/font&gt;=&lt;font&lt;br /&gt; color="#a020f0"&gt;${&lt;/font&gt;&lt;font color="#a020f0"&gt;unique_id&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;//&lt;/b&gt;&lt;/font&gt;:&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;/&lt;/b&gt;&lt;/font&gt;_&lt;font&lt;br /&gt; color="#a020f0"&gt;}&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 30 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 31 &lt;/font&gt;&lt;font color="#008080"&gt;function&lt;/font&gt; read_proclistfile &lt;font&lt;br /&gt; color="#6a5acd"&gt;{&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 32 &lt;/font&gt; &lt;font color="#0000ff"&gt;# read processes from file ignoring comment lines&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 33 &lt;/font&gt; &lt;font color="#008080"&gt;maxprocs&lt;/font&gt;=&lt;font&lt;br /&gt; color="#ff00ff"&gt;0&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 34 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;local&lt;/b&gt;&lt;/font&gt; -i &lt;font&lt;br /&gt; color="#008080"&gt;linenumber&lt;/font&gt;=&lt;font&lt;br /&gt; color="#ff00ff"&gt;0&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 35 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;while&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt; &lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;read&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt; &lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;do&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 36 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;((&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#008080"&gt;linenumber+&lt;/font&gt;=&lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;))&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 37 &lt;/font&gt; &lt;font color="#0000ff"&gt;# echo [ "${REPLY:0:1}" == "#" ] $maxprocs $REPLY&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 38 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;[&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;${&lt;/font&gt;&lt;font color="#a020f0"&gt;REPLY&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;:&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;0&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;:&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt;&lt;font color="#a020f0"&gt;}&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;!=&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;#&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;]&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;then&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 39 &lt;/font&gt; &lt;font color="#6a5acd"&gt;((&lt;/font&gt;maxprocs+&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt;&lt;font color="#6a5acd"&gt;))&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 40 &lt;/font&gt; allprocs&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;[&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$maxprocs&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;]&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$REPLY&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 41 &lt;/font&gt; allprocline&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;[&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$maxprocs&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;]&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$linenumber&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 42 &lt;/font&gt; &lt;font color="#0000ff"&gt;# echo $linenumber $maxprocs $REPLY&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 43 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;fi&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 44 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;done&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;&amp;lt;&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#a020f0"&gt;$proclist&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 45 &lt;/font&gt;&lt;font color="#6a5acd"&gt;}&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 46 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 47 &lt;/font&gt;read_proclistfile&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 48 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 49 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;printf&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n&lt;/font&gt;&lt;font color="#ff00ff"&gt;## STARTING %i Processes from file: %s, %i at a time with id %s&lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n\n&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt; \&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 50 &lt;/font&gt; &lt;font color="#a020f0"&gt;$maxprocs&lt;/font&gt; &lt;font&lt;br /&gt; color="#a020f0"&gt;$proclist&lt;/font&gt; &lt;font&lt;br /&gt; color="#a020f0"&gt;$concurrent&lt;/font&gt; &lt;font&lt;br /&gt; color="#a020f0"&gt;$unique_id&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 51 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 52 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 53 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 54 &lt;/font&gt;&lt;font color="#008080"&gt;function&lt;/font&gt; assemble_job &lt;font&lt;br /&gt; color="#6a5acd"&gt;{&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 55 &lt;/font&gt; &lt;font color="#0000ff"&gt;#&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 56 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;local&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;plr_unique_id&lt;/font&gt;=&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$1&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;";&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;local&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;plr_ran&lt;/font&gt;=&lt;font color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$2&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;";&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;local&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;plr_proc&lt;/font&gt;=&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$3&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;";&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;local&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;plr_procline&lt;/font&gt;=&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$4&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;";&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;local&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#008080"&gt;plr_proclist&lt;/font&gt;=&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$5&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 57 &lt;/font&gt; cat &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;&amp;lt;&amp;lt;!&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 58 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 59 &lt;/font&gt;&lt;font color="#ff00ff"&gt;# &lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$plr_unique_id&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt; &lt;/font&gt;&lt;font color="#a020f0"&gt;$plr_ran&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt; &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 60 &lt;/font&gt;&lt;font color="#6a5acd"&gt;`&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;local&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;`&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 61 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 62 &lt;/font&gt;&lt;font color="#ff00ff"&gt;trap 'error=&lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;\$&lt;/font&gt;&lt;font color="#ff00ff"&gt;?;printf "&lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n\n&lt;/font&gt;&lt;font color="#ff00ff"&gt;##STATISTICS For Job %i&lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n&lt;/font&gt;&lt;font color="#ff00ff"&gt;" &lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$plr_ran&lt;/font&gt;&lt;font color="#ff00ff"&gt;; printf "# Line %i of file %s&lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;\n\n&lt;/font&gt;&lt;font color="#ff00ff"&gt;" &lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$plr_procline&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt; &lt;/font&gt;&lt;font color="#a020f0"&gt;$plr_proclist&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;; exit &lt;/font&gt;&lt;font color="#6a5acd"&gt;\$&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;error' EXIT&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 63 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 64 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 65 &lt;/font&gt;&lt;font color="#a020f0"&gt;$plr_proc&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 66 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 67 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;!&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 68 &lt;/font&gt;&lt;font color="#6a5acd"&gt;}&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 69 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 70 &lt;/font&gt;&lt;font color="#008080"&gt;function&lt;/font&gt; print_runstats &lt;font&lt;br /&gt; color="#6a5acd"&gt;{&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 71 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;printf&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;'&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;# %i Jobs in background. %i/%i started. %s\r&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;'&lt;/b&gt;&lt;/font&gt; \&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 72 &lt;/font&gt; &lt;font color="#6a5acd"&gt;`&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;jobs&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt; -&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;r&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;|&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;wc -l`&lt;/font&gt; &lt;font color="#a020f0"&gt;$ran&lt;/font&gt; &lt;font&lt;br /&gt; color="#a020f0"&gt;$maxprocs&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#6a5acd"&gt;`date +%F-%T`&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 73 &lt;/font&gt;&lt;font color="#6a5acd"&gt;}&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 74 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 75 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Bash array running keeps track of the background process numbers&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 76 &lt;/font&gt;&lt;font color="#0000ff"&gt;# Start with nothing running (sentinel value will not be a process number&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 77 &lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#6a5acd"&gt;((&lt;/font&gt;i&lt;font color="#804040"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;0&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; i&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;&amp;lt;&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$concurrent&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; i+&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt; &lt;font color="#6a5acd"&gt;))&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;do&lt;/b&gt;&lt;/font&gt; running&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;[&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$i&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;]&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;123456789&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;done&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 78 &lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 79 &lt;/font&gt;&lt;font color="#008080"&gt;ran&lt;/font&gt;=&lt;font&lt;br /&gt; color="#ff00ff"&gt;0&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 80 &lt;/font&gt;until&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 81 &lt;/font&gt; while &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;[&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#a020f0"&gt;$ran&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;-lt&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#a020f0"&gt;$maxprocs&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;]&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;do&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 82 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#6a5acd"&gt;((&lt;/font&gt;p&lt;font color="#804040"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;0&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; p&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;&amp;lt;&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$concurrent&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; p+&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt; &lt;font color="#6a5acd"&gt;))&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;do&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 83 &lt;/font&gt; &lt;font color="#008080"&gt;proc&lt;/font&gt;=&lt;font&lt;br /&gt; color="#a020f0"&gt;${&lt;/font&gt;&lt;font color="#a020f0"&gt;running&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;[&lt;/font&gt;&lt;font color="#a020f0"&gt;$p&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;]&lt;/font&gt;&lt;font color="#a020f0"&gt;}&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 84 &lt;/font&gt; &lt;font color="#0000ff"&gt;# Over all running processes...&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 85 &lt;/font&gt; &lt;font color="#0000ff"&gt;# $proc still running?&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 86 &lt;/font&gt; ps &lt;font color="#804040"&gt;&lt;b&gt;-p&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#a020f0"&gt;$proc&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;|&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;fgrep&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#a020f0"&gt;$proc&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;&amp;gt;&lt;/b&gt;&lt;/font&gt;/dev/null&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 87 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;[&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#a020f0"&gt;$?&lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;-ne&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;'&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;0&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;'&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;]&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;;&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;then&lt;/b&gt;&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 88 &lt;/font&gt; &lt;font color="#0000ff"&gt;# Not found i.e. its finished&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 89 &lt;/font&gt; &lt;font color="#0000ff"&gt;# So start the next&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 90 &lt;/font&gt; &lt;font color="#6a5acd"&gt;((&lt;/font&gt;ran+&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#ff00ff"&gt;1&lt;/font&gt;&lt;font color="#6a5acd"&gt;))&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 91 &lt;/font&gt; &lt;font color="#0000ff"&gt;#(assemble_job ) &amp;gt;$unique_id.job_$p&lt;/font&gt;&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 92 &lt;/font&gt; &lt;font color="#804040"&gt;&lt;b&gt;(&lt;/b&gt;&lt;/font&gt; assemble_job &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$unique_id&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;$ran&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt; &lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;${&lt;/font&gt;&lt;font color="#a020f0"&gt;allprocs&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;[&lt;/font&gt;&lt;font color="#a020f0"&gt;$ran&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;]&lt;/font&gt;&lt;font color="#a020f0"&gt;}&lt;/font&gt;&lt;font&lt;br /&gt; color="#804040"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/font&gt; \&lt;br&gt;&lt;font&lt;br /&gt; color="#804040"&gt; 93 &lt;/font&gt; &lt;font color="#a020f0"&gt;${&lt;/font&gt;&lt;font&lt;br /&gt; color="#a020f0"&gt;allprocline&lt;/font&gt;&lt;font
