Wednesday 10 October 2012

When True Was True When It Should Have Been False

(or Why The Devil Is In The Details)

Another 'whoops' moment in class today - another little lesson learned by the teacher: always read the documentation carefully.

In this case, my students had been given the problem of how to 'clean up' a list in Python so that it contained only integers or floats – any strings, tuples, booleans, etc. would need to be removed.

A simple enough task - simply loop over the list and check the type of each item. But here's where the documentation (or more precisely, a cursory read of it) lead us astray.

The Python docs say this about the inbuilt type() function:
type(object)
Return the type of an object. The return value is a type object. The isinstance() built-in function is recommended for testing the type of an object.
So we should use isinstance()? Okay, let's look at that then:
isinstance(object, classinfo)
Return true if the object argument is an instance of the classinfo argument, or of a (direct or indirect) subclass thereof.
So, we can do something like isinstance(i, (int, float)) to check the if the type of i is an integer or float.

And all seemed well right up to the point when this list:
[3, 4.5, "word", True, (3, 5)]
should have been reduced to:
[3, 4.5]
but instead became:
[3, 4.5, True]
Wha...? How did that boolean slip through?

Back to the documentation:
isinstance(object, classinfo)
Return true if the object argument is an instance of the classinfo argument, or of a (direct or indirect) subclass thereof
When we look at the documentation on numeric data types, we find this:
There are four distinct numeric types: plain integers, long integers, floating point numbers, and complex numbers. In addition, Booleans are a subtype of plain integers.
So this:
isinstance(True, int)
returns True rather than False.

I can see some good reasons why booleans have been defined as a subtype of integers (and it's not only Python where this is the case), but it caught us offguard all the same.

So the point of today's lesson - read the documentation carefully, make sure you get your head around the finer details. Not the point I had planned to make, but maybe a better lesson as a result.

Tuesday 20 March 2012

You learn something new every day

Today I attempted to correct a problem in a FileMaker database - and screwed it up badly. (Thank goodness for back-ups.)

The problem concerned some data that had not transferred properly during a change-over between two systems - some dates in the old system had appeared in the new as plain integers instead of dates.

A quick experiment showed me that the GetAsDate() function in FileMaker Pro would convert the number to the correct date - simple. So I duly went ahead and made the change to the data in-place. I know better than to do this, of course, but I was in a hurry and didn't want to take the time to export out the data, convert it and import it back in. So you can imagine my expression when those numbers turned not into the dates I was expecting, but instead into question marks, Filemaker's way of indicating that the data was now invalid.

Grabbed a back-up and retrieved the numbers, but what went wrong?

Doing what I should have done first time, and examining matters more thoroughly, I discovered something that I would not have expected. My initial experiment involved taking a number from a number field and converting it using GetAsDate(). But in the actual database, I was taking numbers from a date field and trying to convert them using GetAsDate(), and this doesn't work. It seems that retrieving a number (invalid data) from a date field does not return the number, and GetAsDate() consequently fails.

It became more interesting when I tried (on a separate file derived from the back-up) to use GetAsNumber() on those numbers in the date field - they all came back as 0. Okay, that doesn't work.

So, one more try - what does GetAsText() return? Aha! I get the number - as a text string. But now I have my answer - GetAsDate(GetAsNumber(GetAsText(theDate))). Problem solved.


You learn something new every day. And sometimes you get to learn an old lesson all over again.

Tuesday 21 February 2012

A Pythagorean Curiosity

Today a colleague asked me to construct a nice question around Pythagoras' Theorem.

Toying with various ideas, I came up with the following figure:


Now it's easy enough to replace a, b, d and e with values, scrub c and one of the right angle symbols and then ask the students to show that the triangle must be right angled. But of course I wanted a nice set of integers for this question, so I wrote a little Python program to generate integer solutions to the set of equations:


Here's the first 30 solutions (given in the form {a, b, c, d, e}):

{9,12,15,20,25}, {16,12,20,15,25}, {18,24,30,40,50}, {25,60,65,156,169}, {27,36,45,60,75}, {32,24,40,30,50}, {36,48,60,80,100}, {45,60,75,100,125}, {48,36,60,45,75}, {49,168,175,600,625}, {50,120,130,312,338}, {54,72,90,120,150}, {63,84,105,140,175}, {64,48,80,60,100}, {64,120,136,255,289}, {72,96,120,160,200}, {75,180,195,468,507}, {80,60,100,75,125}, {81,108,135,180,225}, {90,120,150,200,250}, {96,72,120,90,150}, {99,132,165,220,275}, {100,240,260,624,676}, {108,144,180,240,300}, {112,84,140,105,175}, {117,156,195,260,325}, {125,300,325,780,845}, {126,168,210,280,350}, {128,96,160,120,200}, {128,240,272,510,578}

What stood out was that in most of these, e was a multiple of 5. When I isolated the instances where e was not a multiple of 5, I found that either a or b was!

My first version of my Python program only examined values of a and b up to 1000, so of course I ramped it up a little - to values up to 1000000 for both a and b.

And it still appears to be true. In every solution my program has generated, either e is a multiple of 5 or a or b is.

Looker closer at Pythagorean triplets in general, it is known that at least one number in a Pythagorean triplet has to be a multiple of 5. So if a and b are not multiples of 5, c must be. But if c is a multiple of 5, the Pythagorean triplet of {c, d, e} does not require that e also be a multiple of 5, and yet that appears to be the case for the figure at the top if it is to have integer sides where a and b are not multiples of 5.

Now if I could prove that this it always the case!

Update: when I showed this to another colleague, she pointed out the obvious fact that I had overlooked, namely that the two triangles in the diagram are similar.

Now the matter becomes simple.

Suppose that a is a multiple of 5. Given that the triangles are in the ratio a:c and a and c are the corresponding sides of the two triangles, we find that
and for e to be an integer would mean that c2 must be divisible by a and therefore divisible by 5, and therefore c must be. So both a and c will be multiples of 5. Now it's easy to show that if two of the numbers in a Pythagorean triplet are multiples of 5, the third must be a multiple of 5 as well, so we conclude that if a is a multiple of 5, so are b and c.

What if a is not a multiple of 5? As at least one number in a Pythagorean triplet must be a multiple of 5, if a is not, then either b or c is.

If b is the multiple of 5, c will not be. As stated before, the triangles are in the ratio a:c, so we find
and therefore d is also a multiple of 5. As c is not, we conclude that e is also not a multiple of 5.

The third possibility is that c is the multiple of 5. Again, noting that

but this time, where a and b are not divisible by 5, we conclude that e must be a multiple of 5 as well, and thus d must be as well.

So we find that the possibilities are as follows:
  • if a is a multiple of 5, b and c are multiples of 5 as well (and d and e may be as well)
  • if a is not a multiple of 5 but b is, then d is as well but c and e are not
  • if a and b are not multiples of 5, c must be, and d and e will be as well
Now I can sleep!