As per ProjectEuler 75, we would like to generate all integer triples (a, b, c) such that \(a^2 + b^2 = c^2\) with \(a + b + c \leq N\)
These triples are called Pythagorean triples. There is a wide variety of algorithms to generate these as discussed on Wikipedia. We use Euclid’s formula to generate primitive triples, i.e. triples such that the greatest common divisor of a, b, and, c is 1. Primitive triples are uniquely generated by iterating on two integers m and n, such that \(0 < n < m\), \(gcd(m, n) = 1\), and \(m - n\) is odd. Then, \(a = 2mn\), \(b = m^2 - n^2\), and \(c = m^2 + n^2\) define a Pythagorean triple.
Note that c is always the largest element of the triple, but both a and b can be the smallest element depending on the relative values of m and n. This generator can be implemented with the following simple ocaml code:
The fold_prim
function takes as input an initial element init
, a function f
that will be applied to all primitive Pythagorean triple (a, b, c) such that \(a + b + c \leq max_s\). It returns:
And so the type of fold_int
is:
Generating primitive triples in a unique way, i.e. each triple only corresponds to one pair (m, n) and appears once, gives us a way to generate all triples in a unique way too: we only have to iterate over some positive integer k and return (k.a, k.b, k.c) for every positive k and every primitive triple (a, b, c).
We could easily apply this to count the number of Pythagorean triples, including non-primitive ones, below some limit. For example using the code below returns the number of triples below \(10^8\). It runs in ~2s on my modestly powered ChromeBook.
Note that in the implementation of fold_prim
, we generate all the necessary pairs (m, n) and filter the non coprime ones using Euclid’s algorithm for GCD. This is quite inefficient and could be improved using a Stern-Brocot tree for example.