Monday, April 18, 2016

Los Alamos 10742: The Making of

Modern rendering of the original 1947 Memo 10742

Before reading


If you've not read the first part (The return of the Los Alamos Memo 10742) of this blog, go there now. There will be a link to come back here at the end, so you don't forget ...


Your assignment


If you remember, in the previous article, I had asked the students (and, you, the reader) to try this exercise:

"Replicate either:
a) the whole memo
or
b) the list of numbers 
Whichever assignment you choose, the numbers must be generated programmatically."

One possible way

We'll use Python 3 and do b):

In [1]:
def num_to_words(n):
    """Returns a number in words, covering 0 to 100 inclusive."""
    n2w = {
        0: 'zero', 1: 'one', 2: 'two', 3: 'three', 4: 'four', 5: 'five', 6: 'six',
        7: 'seven', 8: 'eight', 9: 'nine', 10: 'ten', 11: 'eleven', 12: 'a dozen',
        13: 'thirteen', 14: 'fourteen', 15: 'fifteen', 16: 'sixteen', 17: 'seventeen',
        18: 'eighteen', 19: 'nineteen', 
        20: 'twenty', 30: 'thirty', 40: 'fourty', 50: 'fifty', 60: 'sixty', 70: 'seventy',
        80: 'eighty', 90: 'ninety', 100: 'one hundred'
    }
    try:
        return n2w[n]
    except KeyError:
        return n2w[n-n%10] + ' ' + n2w[n%10]
The famous twelve as 'a dozen'
In [2]:
num_to_words(12)
Out[2]:
'a dozen'
In [3]:
num_to_words(7)
Out[3]:
'seven'
In [4]:
num_to_words(67)
Out[4]:
'sixty seven'
In [5]:
num_to_words(100)
Out[5]:
'one hundred'
Generating the alphabetical word list, not including number 10
In [6]:
word_tuples = sorted([(num_to_words(num),num) for num in range(101) if num != 10])
Now that the list is sorted alphabetically, just want the second item of each tuple [1]
In [7]:
result = list(zip(*word_tuples))[1]
Let's print this.
In [8]:
print(str(result)[1:-1])
12, 8, 18, 80, 88, 85, 84, 89, 81, 87, 86, 83, 82, 11, 15, 50, 58, 55, 54, 59, 51, 57, 56, 53, 52, 5, 4, 14, 40, 48, 45, 44, 49, 41, 47, 46, 43, 42, 9, 19, 90, 98, 95, 94, 99, 91, 97, 96, 93, 92, 1, 100, 7, 17, 70, 78, 75, 74, 79, 71, 77, 76, 73, 72, 6, 16, 60, 68, 65, 64, 69, 61, 67, 66, 63, 62, 13, 30, 38, 35, 34, 39, 31, 37, 36, 33, 32, 3, 20, 28, 25, 24, 29, 21, 27, 26, 23, 22, 2, 0
In [ ]:

If you read the commentaries for the previous article on the subject, you surely ran into Edward Carney's almost working proposed solution. I am adding it here as another way of attacking the problem. Edward used a module named num2words. As you'll discover over years of writing python code, most anything you can think of has already been done. And in some cases, multiple times.

Why did I say almost working? Let's see if somebody finds the issue. If not I'll post the correction in a future post (the very next one will diverge from this subject to talk about fractals). I'll also introduce the inflect module and since we're introducing some NLP concepts, I'll bring in NLTK too.

In [1]:
import num2words as n2w
In [2]:
key_set = []
[key_set.append(n2w.num2words(i)) for i in list(range(101))]
key_set[12] = 'dozen'
key_set[100] = 'one hundred'
numset_dict = dict(zip(key_set,list(range(101))))
line_breaks = [14, 30, 46, 62, 78, 94]
for i, k in enumerate(yvals):
    print('{} '.format(k[1]),end='')
    if i in line_breaks:
        print('\n')
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-2-6c7998a49267> in <module>()
      5 numset_dict = dict(zip(key_set,list(range(101))))
      6 line_breaks = [14, 30, 46, 62, 78, 94]
----> 7 for i, k in enumerate(yvals):
      8     print('{} '.format(k[1]),end='')
      9     if i in line_breaks:

NameError: name 'yvals' is not defined



You know the solution? Post it in the comments section.

Francois Dion
@f_dion