Problem Statement

From the FiveThirtyEight website: “From Steve Abney comes a particularly prismatic puzzle:

Suppose I have a rectangle whose side lengths are each a whole number, and whose area (in square units) is the same as its perimeter (in units of length). What are the possible dimensions for this rectangle?

Alas, that’s not the riddle — that’s just the appetizer. The rectangle could be 4 by 4 or 3 by 6. You can check both of these: 4 · 4 = 16 and 4 + 4 + 4 + 4 = 16, while 3 · 6 = 18 and 3 + 6 + 3 + 6 = 18. These are the only two whole number dimensions the rectangle could have. (One way to see this is to call the rectangle’s length \(a\) and its width \(b\). You’re looking for whole number solutions to the equation \(ab = 2a + 2b\).)

On to the main course! Instead of rectangles, let’s give rectangular prisms a try. What whole number dimensions can rectangular prisms have so that their volume (in cubic units) is the same as their surface area (in square units)?

To get you started, Steve notes that 6 by 6 by 6 is one such solution. How many others can you find?"

Solution

As hinted at in the problem statement, this can be expressed as a Diophantine equation: \(abc = 2ab + 2bc +2ac\). An equivalent form that will be useful in solving is \(1 = \frac{2}{a} +\frac{2}{b} +\frac{2}{c}\).

Let’s assume \(a \leq b \leq c\). We can limit the possible values for \(a\) by noting that \(a \leq 6\), or else all the terms on the right would be less than \(\frac{1}{3}\). It is useful to have a finite number of possible vaules for \(a\) because if we specify a value for \(a\) we can write the equation as \(\frac{a-2}{a} = \frac{2}{b} +\frac{2}{c}\). This reduces the problem to a 2-variable equation that has the same form as the example problem, the only difference being the rational number on the left-hand side. So what we need is a general method to solve Diophantine equations of the form \(\frac{n}{d} = \sum_{i=1}^{k}\frac{2}{x_i}\). The following Python code does so by defining a recursive function of \(n\), \(d\), and \(k\). It takes advantage of the earlier observation that there is an upper bound on the smallest value in the solution. Once the function is defined we just need to apply it for \(n=1\), \(d=1\), and \(k=3\).

This is an example of the Inventor’s Paradox: Solving a more general problem can be simpler than the particular problem that interests you.

def rational_subtract(x,y):
    return (x[0]*y[1]-y[0]*x[1],x[1]*y[1])
       
def solve_diophantine(n,d,terms):
    if terms == 1:
        x = 2
        while(n*x < 2*d):
            x += 1
        if n*x == 2*d:
            solutions = [[x]]
        else:
            solutions = []
    else:
        solutions = []
        possible_min = 2
        while terms*2.0/possible_min >= n/float(d):
            if 2.0/possible_min < n/float(d):
                temp = rational_subtract((n,d),(2,possible_min))
                temp_sol = solve_diophantine(temp[0],temp[1],terms-1)
                if len(temp_sol) > 0:
                    for s in temp_sol:
                        if all([s[i] >= possible_min for i in range(len(s))]):
                            new_sol = [possible_min]
                            for i in range(len(s)):
                                new_sol.append(s[i])
                            solutions.append(new_sol)
            possible_min += 1
        
    return solutions
            
answer = solve_diophantine(1,1,3)
print len(answer)
for a in answer:
    print tuple(a)
## 10
## (3, 7, 42)
## (3, 8, 24)
## (3, 9, 18)
## (3, 10, 15)
## (3, 12, 12)
## (4, 5, 20)
## (4, 6, 12)
## (4, 8, 8)
## (5, 5, 10)
## (6, 6, 6)