I’m currently reading
Elliptic Tales, some light relief from lockdown. On reading the preface alone, I discovered something I hadn’t known before. This might be quite well-know to people with a “traditonal” maths background, but I did “modern maths” at school: lots of cool set and group theory, very little classical geometry.
The discussion in the book is just about circles, but a little googling helped me discover this is a result that applies more broadly.
Consider the general quadratic equation of two variables:
\(a x^2 + b x y + c y^2 + d x + e y + f = 0\)
where not all of the coefficients of the quadratic terms, \(a,b,c\), are zero. Depending on the coefficent values, this gives a circle, ellipse, parabola, or hyperbola, that is, a
conic section.
Let’s now consider the restricted case where all the coefficients are
rational numbers. A rational solution to this equation is a solution \((x,y)\) where both \(x\) and \(y\) are rational numbers.
Now comes the interesting bit. Take a straight line with rational slope, \(y = q x + r\), where \(q\) is rational, that cuts the quadratic curve at two points. Then
either both points are rational solutions, or neither is.
The book proves this for the case of a circle, and then shows how to use the result to find all the rational points on the unit circle, \(x^2+y^2=1\). You need one point that you know is rational, so let’s chose \((-1,0)\). Then draw a straight line with rational slope that crosses the \(y\) axis at \(q\); that is, \(q\) is rational. This line has equation \(y=q(x+1)\). Then solve for the other point where the line crosses the circle to get a rational solution:
It is clear from the form of the solution that if \(q\) is rational, so is the point \((x_q,y_q)\). Additionally, there are no rational solutions that correspond to an irrational value of \(q\), so we can use \(q\) to parameterise
all the rational solutions.
Notice also that if we scale up the yellow right-angled triangle, multiplying it by a suitable integer \(n\), so that both \(n x_q\) and \(n y_q\) are integers, the three sides form a
Pythagorean triple.
These points and triples can be generated very easily, just by scanning through values of \(q\) and printing out the unique triples. And Python’s fraction module makes this particularly straightforward (with a bit of fiddling to print in a fixed width format to make things line up neatly; yes, I’m a bit picky about things like this):
from fractions import Fraction as frac
found = set()
for denom in range(1,15):
for num in range(1,denom):
q = frac(num,denom)
xq = (1-q*q)/(1+q*q)
yq = 2*q/(1+q*q)
n = xq.denominator
triple = sorted([int(xq*n), int(yq*n), n])
if triple[0] not in found:
print( '{0:<7} ({1:^7}, {2:^7}) {3}'.format(str(q),str(xq),str(yq),triple) )
found.add(triple[0])
This gives the output:
1/2 ( 3/5 , 4/5 ) [3, 4, 5]
2/3 ( 5/13 , 12/13 ) [5, 12, 13]
1/4 ( 15/17 , 8/17 ) [8, 15, 17]
3/4 ( 7/25 , 24/25 ) [7, 24, 25]
2/5 ( 21/29 , 20/29 ) [20, 21, 29]
4/5 ( 9/41 , 40/41 ) [9, 40, 41]
1/6 ( 35/37 , 12/37 ) [12, 35, 37]
5/6 ( 11/61 , 60/61 ) [11, 60, 61]
2/7 ( 45/53 , 28/53 ) [28, 45, 53]
4/7 ( 33/65 , 56/65 ) [33, 56, 65]
6/7 ( 13/85 , 84/85 ) [13, 84, 85]
1/8 ( 63/65 , 16/65 ) [16, 63, 65]
3/8 ( 55/73 , 48/73 ) [48, 55, 73]
5/8 ( 39/89 , 80/89 ) [39, 80, 89]
7/8 (15/113 , 112/113) [15, 112, 113]
2/9 ( 77/85 , 36/85 ) [36, 77, 85]
4/9 ( 65/97 , 72/97 ) [65, 72, 97]
8/9 (17/145 , 144/145) [17, 144, 145]
3/10 (91/109 , 60/109 ) [60, 91, 109]
7/10 (51/149 , 140/149) [51, 140, 149]
9/10 (19/181 , 180/181) [19, 180, 181]
2/11 (117/125, 44/125 ) [44, 117, 125]
4/11 (105/137, 88/137 ) [88, 105, 137]
6/11 (85/157 , 132/157) [85, 132, 157]
8/11 (57/185 , 176/185) [57, 176, 185]
10/11 (21/221 , 220/221) [21, 220, 221]
1/12 (143/145, 24/145 ) [24, 143, 145]
5/12 (119/169, 120/169) [119, 120, 169]
7/12 (95/193 , 168/193) [95, 168, 193]
11/12 (23/265 , 264/265) [23, 264, 265]
2/13 (165/173, 52/173 ) [52, 165, 173]
4/13 (153/185, 104/185) [104, 153, 185]
6/13 (133/205, 156/205) [133, 156, 205]
8/13 (105/233, 208/233) [105, 208, 233]
10/13 (69/269 , 260/269) [69, 260, 269]
12/13 (25/313 , 312/313) [25, 312, 313]
3/14 (187/205, 84/205 ) [84, 187, 205]
5/14 (171/221, 140/221) [140, 171, 221]
9/14 (115/277, 252/277) [115, 252, 277]
11/14 (75/317 , 308/317) [75, 308, 317]
13/14 (27/365 , 364/365) [27, 364, 365]
and larger values are readily calculated, such as:
500/1001 (752001/1252001, 1001000/1252001) [752001, 1001000, 1252001]
So I’ve only read the Preface so far, and yet I’ve already learned some interesting stuff, and had an excuse to play with Python. Let’s hope the rest is as good (but I suspect it will rapidly get harder…)