# Amazon, Python, and Ellison

Let’s start with an apology. If you follow me on Twitter, you’ll find me tweeting links to Kindle books more frequently than I did in the past. This is not because I’m desperate for the 8¢ commission on each \$2 sale book you buy, but because Amazon turns off my ability to use its product advertising API if I go more than 30 days without a sale. Apparently, this policy has been in place for years,

Note that your account will lose access to Product Advertising API if it has not generated referring sales for a consecutive 30-day period.

but I don’t think Amazon was enforcing it.

Anyway, I ran into this a week or so ago when my shortcut for tweeting affiliate links failed because it had been a couple of months since I last used it. I had to create the tweet by hand (yes, like an animal) and promised myself I’d never let that happen again.

It also reminded me that I’d never written about the changes I had to make to my Kindle tweeting shortcut after iOS 13 was released. So here goes.

In early October, I wanted to tweet a link to a book that was on sale, but my shortcut, which used a combination of Shortcuts and Pythonista, kept failing. I traced the problem to a bug in passing parameters (in this case, the Amazon product ID code of the book) to Pythonista. Whether this was a bug in the new version of Shortcuts or a change in Shortcuts that exposed a bug in Pythonista, I didn’t know and didn’t care to dig into. I just wanted a Shortcut that worked.

The Pythonista part of this workflow handled the communication with the Amazon API and included HMAC encoding of the request with my API account keys. I thought about rewriting this in JavaScript using Scriptable, but I didn’t want to rewrite a bunch of code in a language I don’t much like. And besides, it wasn’t Python that was failing me, it was Pythonista and its connection to Shortcuts. The easier and more reliable solution was to run the Python script somewhere other than iOS.1

I set up a CGI script on a web server to take the place of Pythonista. Scoff if you like at my invocation of 90s web tech, but it was the perfect solution, requiring only a few edits to the Pythonista script and fitting my out-of-date web development skillset. Here’s the script:

 1:  #!/usr/bin/python3
2:
3:  import cgi
4:  import requests
5:  from datetime import datetime
6:  import base64, hashlib, hmac
7:  import urllib.parse
8:  from bs4 import BeautifulSoup
9:  import sys
10:  import re
11:  import json
12:
13:  # Get the Amazon ASIN
14:  form = cgi.FieldStorage()
15:  itemASIN = form['asin'].value
16:
17:  # Date and time
18:  t = datetime.utcnow()
19:  timeStamp = urllib.parse.quote(t.strftime('%Y-%m-%dT%H:%M:%SZ'))
20:
21:  # Parameters
22:  associateTag = 'my-associate-tag'
23:  accessKey = 'my-access-key'
24:  secretKey = b'my-secret-key'
25:  parameters = ['Service=AWSECommerceService',
26:    'Operation=ItemLookup',
27:    'ResponseGroup=Large',
28:    'ItemId={}'.format(itemASIN),
29:    'AWSAccessKeyId={}'.format(accessKey),
30:    'AssociateTag={}'.format(associateTag),
31:    'Timestamp={}'.format(timeStamp)]
32:  parameters.sort()
33:  paramString = '&'.join(parameters)
34:
35:  # Generate signature from parameters and secret key
36:  unsignedString = '''GET
37:  webservices.amazon.com
38:  /onca/xml
39:  {}'''.format(paramString)
40:  signedString = hmac.new(secretKey, msg=unsignedString.encode(), digestmod=hashlib.sha256).digest()
41:  sig = urllib.parse.quote(base64.b64encode(signedString))
42:
43:  # Generate URL from parameters and signature
44:  url = 'http://webservices.amazon.com/onca/xml?{}&Signature={}'.format(paramString, sig)
45:
46:  # Get image information
47:  resp = requests.get(url)
48:  xml = resp.text
49:  # print(xml)
50:
51:  # Extract the information from from the XML
52:  # response and build a dictionary
53:  soup = BeautifulSoup(xml, 'html5lib')
54:  info = {}
55:  info['imgURL'] = soup.item.largeimage.url.text
56:  info['author'] = soup.item.itemattributes.author.text
57:  info['title'] = soup.item.itemattributes.title.text
59:
60:  print('Content-Type: application/json')
61:  print()
62:  print(json.dumps(info))


I won’t describe the fundamental logic—you can get that in this post from last year. The only changes I had to make were at the beginning and end of the script to get the input and output to conform with the requirements of web use.

1. The ID code for the book (what Amazon calls an ASIN) is passed to the script through a GET request, like this,

https://server.com/cgi-bin/amazon-script.cgi?asin=0691181624


and Lines 14–15 use Python’s cgi module to extract the ASIN string.

2. The JSON output is preceded by a Content-Type header in Lines 60–62.

As before, the JSON output includes the title, author, a link to the book’s cover image, and an affiliate link to the book itself.

The script is called by this shortcut:

The shortcut differs from the original in more ways than just the call to a CGI script. Instead of trying to build and send the tweet directly, this new version puts the tweet text in Drafts, which makes it easier for me to edit the tweet before sending it. Also, I can write the tweet when I first see that an interesting book is on sale—typically early in the morning—and send it out later in the day. The downside is that the book’s cover image is saved in Photos and I have to add it to the tweet manually before sending. Overall, though, I think this is a better solution.

The logic of the Shortcut is fairly simple. It’s meant to be called from the Share Sheet in Safari when the book of interest is the current page. The first two steps extract the ASIN from the URL of the page. I know of three places the ASIN can be within the URL, and the regular expression in the first step accounts for all three of those ways. The shortcut then calls the CGI script using the ASIN, collects its output, and converts the JSON into a dictionary for later reference.

One of the items in the dictionary is the URL of the book’s cover image. The next two steps get that image and save it to the Recents folder in Photos.

The shortcut then goes interactive, asking me for the price of the book (getting this from the Amazon API is a lot more difficult than getting the other information, and I decided it wasn’t worth the effort). It then constructs the tweet text using my answer combined with the other information from the dictionary. Finally, it saves the tweet text in Drafts.

After running the script, I can edit the tweet in Drafts to add any extra comments I want and then use the the Tweet with Tweetbot action to send the text to Tweetbot. That’s where I add the the image and send it off. It is, I think, a reasonable combination of automation and manual work.

Moving slightly off-topic…

After a few sales last week unlocked my access to the Amazon API, I used the shortcut yesterday for this tweet:

Of the five retweets you see at the bottom of the screenshot, two came from friends Jason Snell and David J. Loehr, whose appreciation of Ellison (and “Jeffty is Five”) you can hear on this episode of The Incomparable. There’s also a lovely Jeffty/Ellison-based pun David wrote in the very first Incomparable Radio Theater episode.

But with all due respect to Jason and David, the retweet I appreciated the most was the one that came from The Magazine of Fantasy and Science Fiction, a magazine I devoured in my prime sf-reading days. As I said in the tweet, I read the story “Jeffty is Five” when it was initially published in F&SF back in 1977. This issue with a fun cover by Kelly Freas:

Image from the Interactive Speculative Fiction Database.

Set me back a whole dollar, but it was worth it.

“Jeffty is Five” struck a chord with me because of my father. He was about Ellison’s age and was a big fan of the golden age of radio, a bit of which he passed on to me. So even though I was just 16 when I read “Jeffty,” I knew all the references because of Dad and saw him in the narrator.

I say Dad was a fan of the golden age of radio, but he was a fan of radio, period, even when it wasn’t what it had been. He always preferred it to TV and movies and spent a lot of time and money in his later years trying to find decent shows to listen to. He would have loved the age of podcasts.

1. This is a common theme in my use of iOS as a “real computer.” I like my iPad Pro and don’t have a laptop anymore, but if I couldn’t use Prompt and the terminal emulator in Textastic to run commands on Macs and Linux servers, it would be impossible for me to get my work done on it.

# Python Countdown

One of my wastes of time is watching celebrity-based British game shows on YouTube. This started with Never Mind the Buzzzcocks, expanded to QI, and now covers a handful of shows, including 8 Out of 10 Cats Does Countdown.1 One of the puzzles in this show is to form the longest possible word from a string of nine letters. I don’t have a head for anagrams, but I do like recreational programming, so I’ve always thought it would be fun to write a program that generates solutions to the show’s “letters round.”

The obvious way to do this—generate all permutations of the nine letters, then eight of the letters, then seven of the letters, etc., and filter them through a list of real words—didn’t appeal to me. There are 362,880 ways to arrange nine letters, the same number of ways to arrange eight of the nine letters, 181,440 ways to arrange seven of the nine letters, and so on. I’m not above brute force programming when I need to get a job done, but I prefer more elegant solutions when programming for fun. So my Countdown script didn’t get written.

Then last month John C. Cook wrote this post about anagram frequency and the light went on. The trick is to start with a list of words and build a data structure that allows you to look up all the anagrams of a given string of letters. A convenient data structure for this is an associative array, called a dictionary in Python. The clever bit is that the dictionary keys are the letters of the anagrams in alphabetical order and the values are lists of anagrams corresponding to those letters.

For example, one entry for six-letter words would have the key aeprss and the value

'aspers', 'parses', 'passer', 'prases', 'repass', 'spares', 'sparse', 'spears'


So if we were searching for anagrams in the string psasre, we’d first alphabetize it to aeprss and then look it up directly in our dictionary of six-letter anagrams.

The starting point, then, is to build a dictionary of anagrams. Because I wanted a bit more structure, I built four dictionaries, one each for nine-letter, eight-letter, seven-letter, and six-letter words.2 I then assembled those into a higher-level dictionary in which the word lengths were the keys.

I got the lists of words from which to build the dictionaries from this Scrabble help site. It provides long lists of legal Scrabble words of whatever length you like. By copying the pages for words of six through nine letters and doing a little editing, I created files of words of each length, with every word on its own line. I named these files word6.txt through word9.txt. Then I ran this script:

python:
1:  from collections import defaultdict
2:  import pickle
3:
4:  def sig(word):
5:    return ''.join(sorted(word)).strip()
6:
7:  words = {}
8:  for count in range(6, 10):
9:    lines = [ x.strip() for x in open(f'word{count}.txt') ]
10:    words[count] = defaultdict(set)
11:    for word in lines:
13:
14:  wordsfile = open('scrabble-words', 'wb')
15:  pickle.dump(words, wordsfile)


The sig function returns the alphabetized letters of the argument string and is used to generate the key, or “signature,” of each word in the file. It’s a simplified version of the sig function John C. Cook wrote.

The script goes through each of the wordn.txt files, adding the words in that file to the subdictionary associated with its word length. The defaultdict type from the collections module is used to avoid the initialization problem that arises when using regular Python dictionaries. The anagrams are stored as sets of strings (see Line 10 for how the defaultdicts are generated), which we’ll find useful later to avoid repetition when blending sets together.

When the looping in Lines 8—12 is done, we have a dictionary of dictionaries of sets assembled in words. The anagrams we looked at earlier can be found in words[6]['aeprss'].

This complex data structure is then stored in a file called scrabble-words using Python’s pickle method of data serialization. The idea is that we create this data structure once and then use it later without having to rebuild it every time we play Countdown.3

Which brings us to the script that gives us all the anagrams in a string:

python:
1:  import pickle
2:  from itertools import combinations
3:
4:  wordfile = open('scrabble-words', 'rb')
6:
7:  def sig(word):
8:    return ''.join(sorted(word)).strip()
9:
10:  w = input("Letters: ").strip()
11:  print()
12:  for count in range(9, 5, -1):
13:    found = set()
14:    for s in combinations(w, count):
15:      t = ''.join(s)
16:      anagrams = sorted(words[count][sig(t)])
17:      if len(anagrams) > 0:
18:        found |= set(anagrams)
19:    if len(found) > 0:
20:      print(f'{len(found)} {count}-letter word{"s" if len(found)>1 else ""}:')
21:      print(' '.join(sorted(found)))
22:    else:
23:      print(f'No {count}-letter words')
24:    print()


Line 3–4 read in the scrabble-words file and convert it back into the data structure we want. Line 10 asks for the string of letters, and the rest of the script generates the anagrams.

The loop that begins on Line 12 sets the length of anagrams to search for. It starts at nine letters and works its way down to six, which means we’ll see the highest-scoring answers first. Line 13 creates an empty set of found words and Line 14 starts a loop that goes through all the count-letter combinations of the nine given letters. These combinations are generated by the aptly named combinations function in the itertools library.

Because the combinations function returns a tuple of letters, we use Line 15 to turn the tuple into a string. Line 16 then gets all the anagrams of that string. If there are any (Line 17), they’re added to the found set through the union operation to avoid repeats (Line 18).

The rest of the script is just output. Here’s an example of a run in Pythonista on my phone:

Is this cheating? Sure, but I’m not a contestant. I think of it more as an expansion of what Susie Dent does.

1. This is, oddly, an amalgam of two shows I find unwatchable: the Family Feud-like celebrity show, 8 Out of 10 Cats and the long-running traditional game show, Countdown

2. Words of five or fewer letters are fair game in Countdown and could have been included in my program, but I wasn’t interested in words that short.

3. This could be a false efficiency. While it’s true that reading the scrabble-words file is faster than building the data structure from scratch each time—about twice as fast according to my timings—both are so fast that the difference in speed is practically unnoticeable. And the speed difference comes at a price in storage space. The four wordn.txt files take up less than one megabyte of space in aggregate, while the scrabble-words file is just over five megabytes. I may test other storage schemes to see how they balance space and speed.

# A little more on Galileo’s column

After last week’s post, I thought some more about Galileo’s column problem. The mechanic in Galileo’s story tried to reduce the bending stress when the column is being stored on its side by inserting a third support. A simpler way would be to keep two supports but change the spacing between them. Let’s see how to do that in a way that minimizes the bending stress.

Here’s a uniform beam with supports set in a distance $a$ from its ends. Below it is the corresponding bending moment diagram.

The moment at the supports is

and the moment at the center is

As we discussed last time, the difference between positive and negative moments is whether the tension—and therefore where the cracking starts—is on the bottom or top of the beam. In assessing the overall strength of the beam, top and bottom cracking are equivalent, so we don’t have to worry about the sign of moment, only its magnitude.1 We want to find the value of $a$ that minimizes the maximum moment in absolute terms.

Seeing the word “minimize” might make you think it’s time to do some calculus, but let’s try a different approach. Note that for small values of $a$, $|M_s|$ increases and $M_c$ decreases with increasing $a$. As we increase $a$, there will be a point at which the two are equal. This will minimize the maximum absolute moment in the beam.

So we set

and solve for $a$. To nondimensionalize the equation, let’s use the substitution $x = a/L$ to get

Expanding, canceling, and rearranging gives us

which we can solve by completing the square or through the quadratic formula. Either way, we get two solutions:

and

The first solution is negative and can be ignored as a mathematical artifact. The second is the solution we want. It’s approximately $x = 0.207$ and gives a maximum absolute moment in the beam of $M_{max} = 0.0214 wL^2$. Compare this with the maximum moment with the supports at the ends ($0.125 wL^2$) and you can see how much value there is in moving the supports in.

If we plot $M_{max}$ against $a$, we can see why calculus wouldn’t have helped us find the miminum. The smallest value of $M_{max}$ is at a cusp, the intersection of the lines for $M_c$ and $M_s$. Setting a derivative equal to zero won’t locate that point.

Note that the graph also shows us something we looked at in the previous post: the maximum moment when the beam is balanced over a support at the center is the same as when it’s supported at its ends.

Apart from being a fun little problem to think about, Galileo’s column illustrates an important concern in structural engineering. Structural elements that would survive perfectly well in the completed structure sometimes fail during construction because they see loading during assembly (or storage or transportation) that they’ll never see afterward. Although engineers’ main concern is how the elements behave when the building is complete, they also have to account for the stresses that arise before then.

1. This is not true in general, but it is true for beams in which the upper and lower halves of the cross-section are symmetric. Recall that this beam is intended to be tilted up and used as a column, which means its cross-section is either circular or circular with flutes and has the required symmetry.

# Galileo and failure

Last week’s episode of the 99% Invisible podcast was about failure and the problems that arise when we try to design safety systems to prevent failure. I found myself disagreeing with a lot of what was said, but a particular example struck me as flatly wrong. As I looked into it in more detail, I learned that it was wrong for more reasons than I originally thought.

The episode was not produced by the usual 99% Invisible team. It was one of Tim Harford’s Cautionary Tales shows with a 99PI frame around it. My main problem with the show was that its thesis—Safety systems add complexity, and that complexity may lead to failure—was overemphasized to such an extent that it transformed into the more fatalistic Safety systems add complexity which leads to failure. The examples given in the show of failures caused by the introduction of complexity were, I thought, too glibly1 presented.

To be fair, I’ve been investigating failure professionally for three decades, and it may be that no simplified journalistic approach to the topic of failure would have satisfied me. But there is a line between justified simplification and misleading oversimplification, and one of the show’s examples went over that line.

Here’s how it was introduced (from 99PI’s transcript):

Tim Harford:
Galileo Galilei is known for his astronomy and because his work was consigned to the church’s ‘Index Librorum Prohibitorum’, the list of forbidden books, but the great man’s final work opens with a less provocative topic, the correct method of storing a stone column on a building site. Bear with me, this book from 1638 is going to explain the Oscar fiasco and much more.

Galileo Galilei:
“I must relate a circumstance which is worthy of your attention as indeed are all events, which happen contrary to expectation, especially when a precautionary measure turns out to be a cause of disaster.”

Tim Harford:
A precautionary measure turns out to be a cause of disaster. That’s very interesting, Galileo, please go on.

Galileo Galilei:
“A large marble column was laid out so that its two ends rested each upon the piece of beam.”

Tim Harford:
I can picture that in my mind, support the column while it’s being stored horizontally ready for use. If you lay it on the ground it may get stained and you’ll probably break it when you try to get ropes underneath it to pull it upright. So yes, store it flat but propped up by a support at one end and a support at the other. But what if the column can’t support its own weight like that and simply snaps in half? Galileo has thought of that.

Galileo Galilei:
“A little later it occurred to a mechanic that in order to be doubly sure its not breaking in the middle, it would be wise to lay a third support midway. This seemed too all an excellent idea.”

Tim Harford:
Yes. If two supports are good, surely three supports are better.

Galileo Galilei:
“It was quite the opposite, for not many months passed before the column was found cracked and broken exactly above the new middle support.”

Tim Harford:
How did that happen?

Galileo Galilei:
“One of the end supports had after a long while become decayed and sunken, but the middle one remained hard and strong, thus causing one half of the column to project in the air without any support.”

Tim Harford:
The central support didn’t make the column safer. It pressed into it like the central pivot of a seesaw snapping it in half. Galileo’s tale isn’t really about storing columns and neither is mine. It’s about what I’m going to call Galileo’s principle, the steps we take to make ourselves safe sometimes lead us into danger.

I first heard this while driving my car to work and thought “That doesn’t sound right.” I paused the podcast and thought about it some more: “No, it isn’t right.” But it’s easy to lose terms when you’re doing algebra in your head, so when I got to work I sketched out the two ways of supporting the column and redid the work. Harford (and Galileo?) were still wrong: the stress in the column with a central support is no larger than the stress in the column with end supports. There’s no reason to believe that putting in a central support made things worse.

It’s easy to see why, but we need a few preliminaries:

1. When a column is resting horizontally, it’s being bent by its own weight and the reaction forces at the supports. Therefore, it’s acting more like a beam than a column, and I will refer to it as a beam.
2. The stresses in a beam are related to the bending moments in that beam. The stresses will be highest where the bending moments are highest (in absolute value).
3. Structural engineers use a sign convention for bending moments: those that put the bottom of a beam in tension and top of the beam in compression are taken as positive; those that put the bottom of the beam in compression and the top of the beam in tension are taken as negative.
4. Stone is strong in compression but weak in tension. All other things being equal, it will fail where the tension is the highest.

For the purposes of this post, all of these will be taken as given. I’ve discussed bending moments and stresses in beams briefly here and here, but you can find better treatments in any strength of materials book.

Here’s Galileo’s beam with supports at its ends and the associated moment diagram:

The moment diagram is parabolic and positive along the entire length of the beam. If we call the beam’s weight per unit length $w$, then the peak moment at the center of the beam is

and if the beam were to fail, we would expect it to fail starting at the bottom center where the tension is the highest.

The goal of Galileo’s mechanic was to support the beam in the center as well as at the ends, reducing the maximum (absolute) moment. Here’s what that would look like:

The maximum moment in absolute terms is still at the center, but now it’s a negative moment with this magnitude:

This is one-fourth of the moment when the beam has just end supports, so the mechanic’s action makes sense.

Unfortunately, one of the end supports gave way, leading to this condition:

I’ve drawn the middle support as being a bit off-center; we’ll see why in a bit.

The maximum moment in absolute terms is at the middle support and is negative:

The largest value of the overhang length, $x$, is $L/2$. Any longer than that and the beam will tip clockwise, with the left end lifting off its support and the right end coming to rest on its lowered support. For the purposes of calculating the maximum moment, this would be structurally equivalent to (albeit a mirror image of) what we’ve shown above.

Setting $x$ to its maximum value of $L/2$, we get

This is exactly the same as the maximum moment with supports at the ends of the beam. The only difference is that this beam will start fracturing on the top surface (as Galileo said) instead of at the bottom surface.

So why didn’t the beam crack before the mechanic put in the middle support? I can think of a few reasons:

1. Because stone isn’t uniform in strength, it may be that the top of the beam is a bit weaker than the bottom. If so, a beam that’s just barely able to survive a high positive moment will fail when it sees a high negative moment of the same magnitude. This means that the beam’s survival when it was briefly on two end supports only was pure luck. If it had been set down with the weak side on the bottom, it would have failed then.
2. There is some time dependence to the cracking of the stone. If so, the beam would have cracked eventually on its two end supports.
3. The story is slightly off, and the mechanic had the middle support in place right from the start.
4. The whole story is just made up, either by Galileo or whoever told it to him.

None of these scenarios support the idea that what the mechanic did was add complexity that caused the failure.

I got curious about why Galileo even told this story. It’s in his Dialogues Concerning Two New Sciences (that’s an affiliate link), and is part of an introduction to the square-cube law. It’s preceded by

Thus, for example, a small obelisk or column or other solid figure can certainly be laid down or set up without danger of breaking, while the very large ones will go to pieces under the slightest provocation, and that purely on account of their own weight.

and succeeded by

This is an accident which could not possibly have happened to a small column, even though made of the same stone and having a length corresponding to its thickness, i.e., preserving the ratio between thickness and length found in the large pillar.

But the story of the inserted middle support has nothing to do with the square-cube law. It’s not a story about small structures being better able to support their own weight than large structures. Even weirder, Galileo knew perfectly well that the beam with half its length overhanging a support had the same strength as one supported at its ends. Later on in the book, near the end of the second day,2 Galileo explicitly explains this:

Hitherto we have considered the moments and resistances of prisms and solid cylinders fixed at one end with a weight applied at the other end; three cases were discussed, namely, that in which the applied force was the only one acting, that in which the weight of the prism itself is also taken into consideration, and that in which the weight of the prism alone is taken into consideration.

He’s referring to an earlier discussion on the behaviour of cantilever beams. Here’s the charming drawing that goes along with that portion of the book:

Let us now consider the same prisms and cylinders when supported at both ends or at a single point placed somewhere between the ends.

Here’s the drawing that goes with the new discussion:

I should point out that for the situation in which the right support has sunk out of the way and the middle support is at exactly $x = L/2$, the reaction at the left support will be zero, so it’s as if the beam were balanced on the central support, as Galileo shows in the upper drawing.

Here’s the nut:

In the first place, I remark that a cylinder carrying only its own weight and having the maximum length, beyond which it will break, will, when supported either in the middle or at both ends, have twice the length of one which is mortised into a wall and supported only at one end.

There you have it. The maximum length of a beam that’s balanced on a support at its center is equal to the maximum length of a beam that’s on supports at both ends. Both of them are twice the maximum length of a cantilever beam.

For completeness, here’s his explanation. It’s tough sledding.

This is very evident because, if we denote the cylinder by ABC and if we assume that one-half of it, AB, is the greatest possible length capable of supporting his own weight with one end fixed at B, then, for the same reason, if the cylinder is carried on the point G, the first half will be counterbalanced by the other half BC. So also in the case of the cylinder DEF, if its length be such that it will support only one-half this length when the end D is held fixed, or the other half when the end F is fixed, then it is evident that when supports, such as H and I, are placed under the ends D and F respectively the moment of any additional force or weight placed at E will produce fracture at this point.

In the introduction to Two New Sciences, the translators, Henry Crew and Alfonso de Salvio, say that they have “made this translation as literal as is consistent with clearness and modernity.” We may take it, then, that Galileo wrote like a patent attorney.

Having gone through all of the second day and a good chunk of the first day of Two New Sciences, I still have no idea why Galileo included the story of the column and the mechanic. It has nothing to do with the topic being covered where he included it, and it doesn’t match his own (generally correct) understanding of the strength of beams. I wonder if it was written before he’d done the work on the maximum length of beams, and he just never went back to check it.

I think we can forgive Galileo this lapse. He was creating new knowledge and, given his trouble with the Vatican, was desperate to get it published. Editing was of secondary concern at best.

I’m less forgiving of Tim Harford. Anyone who’s taken a statics class could have told him that the story on which he was basing “Galileo’s Principle” didn’t demonstrate that principle.

1. Yes, I thought the show oversimplified complexity.

2. The book’s conceit is that it is a series of discussions between a teacher and two pupils. The discussions take place over four days.