Questions about whole numbers
On Christmas Day 1640, Pierre de Fermat wrote to Marin Mersenne that every prime of the form is a sum of two squares — , , — while no prime of the form is. He gave no proof, and Leonhard Euler supplied one a century later. Why should the remainder on division by decide such a thing?
Some questions look even more innocent. Is a perfect square modulo , that is, does divide for some ? One can try all residues. Euler, Adrien-Marie Legendre and finally Carl Friedrich Gauss found something much better, a hidden symmetry between primes: whether is a square modulo is tied to whether is a square modulo . Gauss called this theorema aureum, the golden theorem, and gave eight proofs.
The oldest question here is Pell's equation . Brahmagupta studied it in 628, and Bhāskara II solved in the twelfth century with his chakravāla method. The smallest solution is
In 1657 Fermat set the same equation as a challenge to European mathematicians, apparently unaware it had been solved in India five hundred years earlier.
This lesson proves the central results of classical number theory beyond congruences. The tools are the group theory of groups (the unit group modulo is cyclic), a clever count of lattice points (for reciprocity), the Gaussian integers of rings (for sums of two squares), and approximation of irrationals by fractions (for Pell).
Powers going round the clock
Take the powers of modulo : . They visit every non-zero residue before returning to . So every non-zero residue is a power of , and is a primitive root modulo . The powers of only reach . Modulo nothing works: , , , so every unit has order at most .
When a primitive root exists, the multiplicative structure becomes additive. Every unit is , multiplying units adds exponents, and is a perfect square exactly when is even. So modulo an odd prime exactly half of the non-zero residues are squares. Modulo they are , the even powers of . A whole theory of quadratic residues grows from this observation, and its crowning result relates the squares modulo to those modulo .
Primes in columns of four
With four columns, the odd primes fall into two columns: remainder 1 and remainder 3 on division by 4. The primes in the first column are exactly the odd primes that are sums of two squares.
- prime
- crossed out
Step 1 of 7
Here are the numbers from 1 to 100. Press “Next step” to start sieving.
Primitive roots, residues and arithmetic functions
Throughout, and denote primes, is Euler's totient, and is the group of units modulo , of order . For , is the order of in this group, the least with .
Definition— primitive root
A primitive root modulo is an integer with , that is, a generator of . A primitive root exists iff is cyclic.
Definition— quadratic residue and Legendre symbol
For an odd prime and , is a quadratic residue modulo if has a solution, and a non-residue otherwise. The Legendre symbol is
Definition— arithmetic functions
An arithmetic function is a function . It is multiplicative if and whenever . The Dirichlet convolution is . Important examples are , , , the divisor functions and , Euler's , and the Möbius function : if is a product of distinct primes, and if has a square factor.
Definition— Pell's equation
For a positive integer that is not a square, Pell's equation is in integers. Its solutions with are non-trivial. Identify with the real number . The norm is multiplicative.
Worked examples
Example— Primitive roots and indices
Modulo , , since and . So is a primitive root, and its powers give every unit an index (discrete logarithm). For instance . To solve , write : then , so and . Check: .
Example— Squares modulo 13
The squares of modulo are . These are the six quadratic residues, and and have the same square, so the list is complete. The non-residues are . Note that is a residue (), as it must be for .
Example— Arithmetic functions
, , , and , , . Since these functions are multiplicative, it suffices to know them on prime powers: , , . For example .
Example— A Pell equation solved by hand
For : , so is a solution. Its powers , , … are solutions too, because the norm is multiplicative. The fractions approximate extremely well. Pell's equation is about the best rational approximations to .
Primitive roots
Theorem— Theorem 1 (the units modulo a prime form a cyclic group)
For every prime , is cyclic of order . More precisely, for each there are exactly elements of order ; in particular there are primitive roots.
Proof
Let be the number of elements of order . By Lagrange's theorem every order divides , so . Suppose , and let have order . Then are distinct roots of . Over the field a polynomial of degree has at most roots (factor theorem plus no zero divisors), so these are all the roots. Every element of order is therefore a power , and has order iff . Hence whenever , so for all . But (groups lesson, Proposition 4), so the inequalities are equalities. In particular .
∎
The same proof shows that every finite subgroup of the multiplicative group of any field is cyclic. The proof does not construct a primitive root, and no efficient deterministic method is known for finding one. In practice one tests using the criterion: is a primitive root modulo iff for every prime .
Theorem— Theorem 2 (no primitive roots modulo 2ᵏ for k ≥ 3)
If and is odd, then . Since , there is no primitive root modulo .
Proof
For : gives , as is even. If , squaring gives . Induct on .
∎
Theorem— Theorem 3 (which moduli have primitive roots)
A primitive root modulo exists if and only if or , where is an odd prime and .
Proof
None otherwise. If with , use Theorem 2. Otherwise with and , so and are both even. By the Chinese remainder theorem (quotients), . Every element then has order dividing .
Odd prime powers. Let be a primitive root modulo . If , replace by : by the binomial theorem . So we may assume with . By induction, using the binomial theorem and odd, with . The order of modulo divides and is a multiple of (reduce modulo ), so it is for some . It is not for , since . So is a primitive root modulo every .
, and . (the factor is trivial), and an odd primitive root modulo is a primitive root modulo . Modulo and , and are primitive roots.
∎
Quadratic residues and reciprocity
Fix an odd prime .
Theorem— Theorem 4 (Euler's criterion)
For every integer , . Consequently there are exactly quadratic residues and non-residues, and the Legendre symbol is completely multiplicative: .
Proof
If both sides are . Otherwise let be a primitive root (Theorem 1) and . Then is a square iff is even: means , and is even. On the other hand , because it is a root of other than (as has order ). So . This is for even and for odd . Exactly half of are even. Multiplicativity follows since , and the values are distinct modulo .
∎
Theorem— Corollary 5 (first supplementary law)
: is a square modulo iff .
Theorem— Lemma 6 (Gauss's lemma)
Let , and let be the number of for which the least positive residue of exceeds . Then .
Proof
Let . Write the residues of as (those below ) and (those above). The numbers all lie in , and they are distinct. The 's are distinct, and so are the 's. If , then for some , so , impossible as . So they are exactly in some order. Multiplying, . Cancel and use Euler's criterion.
∎
Theorem— Corollary 7 (second supplementary law)
: is a square modulo iff .
Proof
For , the residues with are just . Those exceeding are the with , so . Checking gives . So is even exactly for , and in each case.
∎
Theorem— Theorem 8 (law of quadratic reciprocity)
For distinct odd primes and ,
So unless , in which case .
Proof
(Eisenstein, 1844.) Step 1: for odd with , . With the notation of Lemma 6, . Summing over gives
From the proof of Lemma 6, . Subtracting, . Reduce modulo : is even and is odd, so .
Step 2: count lattice points. Consider the points with and ; there are of them. None lies on the line , since that would need . Below the line, the column at contains points, so there are points below. Symmetrically, there are points above. By Gauss's lemma,
∎
Example— Computing a Legendre symbol
Is a square modulo ? Both numbers are small enough to check by hand, but reciprocity makes it quick. , so . Since , . Since , , as . So , and is a square modulo ; indeed .
Arithmetic functions and Möbius inversion
Theorem— Proposition 9 (the Dirichlet ring)
Dirichlet convolution is commutative and associative, with identity . If and are multiplicative, so is . And , that is, .
Proof
is symmetric in , and is symmetric in the bracketing. Also . If , the divisors of are exactly the products with , , each uniquely, and then and . So . Finally is multiplicative, and on a prime power with it is .
∎
Theorem— Theorem 10 (Möbius inversion)
For arithmetic functions : for all for all .
Proof
The first statement says , the second . If then . If then .
∎
Example— Euler's function and necklaces
Gauss's identity says . By inversion , that is, , since only square-free contribute. In the same way, the number of monic irreducible polynomials of degree over is (see fields and Galois theory). That is also the number of aperiodic necklaces of beads in colours.
Sums of two squares
Theorem— Theorem 11 (Fermat; proved by Euler)
An odd prime is a sum of two squares if and only if .
Proof
Only if. Squares are or modulo , so .
If. Let . By Corollary 5 there is an with in the Gaussian integers . But divides neither factor, since . So is not a prime element of . Now is a Euclidean domain, hence a UFD in which irreducible elements are prime (rings lesson, Theorems 6–9). So is not irreducible: with non-units. Taking norms, with , so . Writing gives .
∎
The representation is unique up to order and signs (by unique factorisation in ). Combined with the Brahmagupta–Fibonacci identity
which is the multiplicativity of on , this gives the full answer. A positive integer is a sum of two squares iff every prime divides it to an even power. (If divides , then and , because is not a square modulo .) Don Zagier (1990) found a famous "one-sentence" proof of Theorem 11, by an involution on a finite set with exactly one fixed point. Roger Heath-Brown's earlier argument underlies it.
Pell's equation
Let be a non-square, so is irrational. Write and . The set is a group under multiplication. It is closed under products by the multiplicativity of the norm, and . This is Brahmagupta's bhāvanā: .
Theorem— Lemma 12 (Dirichlet's approximation theorem)
For every irrational there are infinitely many pairs of integers with and .
Proof
Fix . The numbers (fractional parts) lie in . By the pigeonhole principle two of them, say for , lie in the same interval . Then and satisfy . As is irrational, . Taking larger than produces a new pair each time, so there are infinitely many.
∎
Theorem— Theorem 13 (Pell's equation; Lagrange 1768)
(a) Pell's equation has a non-trivial solution. (b) There is a least solution , the fundamental solution, and every solution is with . So , and there are infinitely many solutions.
Proof
(a) For each pair from Lemma 12 (with ),
So infinitely many pairs give values in a finite set. None is , since is irrational. By the pigeonhole principle infinitely many pairs share the same value and the same residues of and modulo . Take two distinct such pairs , with positive coordinates, and set
Modulo , and , so . Taking norms, . If then , and the two positive numbers would be equal, so the pairs would be equal. Hence .
(b) If and , then , so and . Such exist by (a): replace by . Among them, the one with the least (and so the least ) is the least element of . Now let with , and choose with . Then , so it equals by minimality, and . If , apply this to .
∎
Finding . The continued fraction of is periodic, with (Lagrange). If are its convergents, the fundamental solution is if is even, and if is odd. For , has odd period , and the method gives . For the period has length , and the answer is the enormous solution of the introduction. For proofs see Niven, Zuckerman and Montgomery (1991), chapter 7. The third experiment runs the algorithm.
Number theory in Lean and Mathlib
Mathlib has a substantial library of elementary number theory. ZMod n is , legendreSym p a is , ArithmeticFunction with ArithmeticFunction.moebius handles Dirichlet convolution, and Pell.Solution₁ d is the group of solutions of Pell's equation.
Primitive roots (Theorems 1 and 2). Cyclicity is cited, and the computations modulo and are checked by decide. The impossibility of a primitive root modulo is the lesson's argument:
/-- For a prime `p`, the group `(ℤ/pℤ)ˣ` is cyclic: a primitive root exists. Mathlib proves
that every finite subgroup of the units of an integral domain is cyclic
(`isCyclic_of_subgroup_isDomain`), by the counting argument of the lesson. -/
theorem units_cyclic (p : ℕ) [Fact p.Prime] : IsCyclic (ZMod p)ˣ :=
inferInstance/-- Gauss's identity `∑_{d ∣ n} φ(d) = n`, the key to the cyclicity proof. Mathlib's
`Nat.sum_totient`. -/
theorem sum_totient (n : ℕ) : ∑ d ∈ n.divisors, Nat.totient d = n :=
Nat.sum_totient n/-- `3` is a primitive root modulo `7`: its powers `3, 2, 6, 4, 5, 1` run through all six
non-zero residues, i.e. its order is `6`. `decide` checks `3⁶ = 1` and `3ᵐ ≠ 1` for `0 < m < 6`. -/
theorem three_primitive_root_mod_seven : orderOf (3 : ZMod 7) = 6 :=
(orderOf_eq_iff (by norm_num)).mpr ⟨by decide, by decide⟩/-- Every unit modulo `8` squares to `1`: `1² = 1`, `3² = 9`, `5² = 25`, `7² = 49` are all `≡ 1`.
Checked by `decide` over the four units. -/
theorem units_mod_eight_sq : ∀ u : (ZMod 8)ˣ, u ^ 2 = 1 := by
decide/-- **There is no primitive root modulo `8`.** `(ℤ/8ℤ)ˣ` has `φ(8) = 4` elements; a generator
would have order `4`, but every unit has order dividing `2` (`units_mod_eight_sq`). -/
theorem no_primitive_root_mod_eight : ¬ IsCyclic (ZMod 8)ˣ := by
intro h
obtain ⟨g, hg⟩ := h.exists_generator
have hcard : Nat.card (ZMod 8)ˣ = 4 := by
rw [Nat.card_eq_fintype_card, ZMod.card_units_eq_totient]
decide
have hord : orderOf g = 4 := by
rw [← hcard]
exact orderOf_eq_card_of_forall_mem_zpowers hg
have hdvd : orderOf g ∣ 2 := orderOf_dvd_of_pow_eq_one (units_mod_eight_sq g)
rw [hord] at hdvd
omegaQuadratic residues. A non-residue checked by computation, then Euler's criterion, the supplementary laws and reciprocity, all from Mathlib. Mathlib's proof of reciprocity uses Gauss's lemma and Eisenstein's lattice-point count, as Theorem 8 does:
/-- `2` is a quadratic non-residue modulo `5`: the squares modulo `5` are `0, 1, 4`. -/
theorem two_not_square_mod_five : ¬ IsSquare (2 : ZMod 5) := by
rintro ⟨r, hr⟩
revert hr
revert r
decide/-- **Euler's criterion**: for `a ≢ 0 (mod p)`, `a` is a square modulo `p` iff
`a^((p − 1)/2) ≡ 1`. Mathlib's `ZMod.euler_criterion` (here `p / 2 = (p − 1)/2` for odd `p`). -/
theorem euler_criterion (p : ℕ) [Fact p.Prime] {a : ZMod p} (ha : a ≠ 0) :
IsSquare a ↔ a ^ (p / 2) = 1 :=
ZMod.euler_criterion p ha/-- **First supplementary law**: `−1` is a square modulo a prime `p` iff `p ≢ 3 (mod 4)`.
Mathlib's `ZMod.exists_sq_eq_neg_one_iff`. -/
theorem neg_one_square_iff (p : ℕ) [Fact p.Prime] : IsSquare (-1 : ZMod p) ↔ p % 4 ≠ 3 :=
ZMod.exists_sq_eq_neg_one_iff/-- **Second supplementary law**: for an odd prime `p`, `2` is a square modulo `p` iff
`p ≡ ±1 (mod 8)`. Mathlib's `ZMod.exists_sq_eq_two_iff`. -/
theorem two_square_iff (p : ℕ) [Fact p.Prime] (hp : p ≠ 2) :
IsSquare (2 : ZMod p) ↔ p % 8 = 1 ∨ p % 8 = 7 :=
ZMod.exists_sq_eq_two_iff hp/-- **The law of quadratic reciprocity**: for distinct odd primes `p` and `q`,
`(q/p)(p/q) = (−1)^(((p−1)/2)((q−1)/2))`. Mathlib's `legendreSym.quadratic_reciprocity`,
proved (like the lesson) via Gauss's lemma and a lattice-point count. -/
theorem quadratic_reciprocity (p q : ℕ) [Fact p.Prime] [Fact q.Prime] (hp : p ≠ 2) (hq : q ≠ 2)
(hpq : p ≠ q) :
legendreSym q p * legendreSym p q = (-1) ^ (p / 2 * (q / 2)) :=
legendreSym.quadratic_reciprocity hp hq hpqMöbius inversion (Theorem 10):
/-- **Möbius inversion**: `g(n) = ∑_{d ∣ n} f(d)` for all `n > 0` iff
`f(n) = ∑_{de = n} μ(d) g(e)` for all `n > 0`. Mathlib's
`ArithmeticFunction.sum_eq_iff_sum_mul_moebius_eq`. -/
theorem moebius_inversion {f g : ℕ → ℤ} :
(∀ n > 0, ∑ i ∈ n.divisors, f i = g n) ↔
∀ n > 0, ∑ x ∈ n.divisorsAntidiagonal,
(ArithmeticFunction.moebius x.fst : ℤ) * g x.snd = f n :=
ArithmeticFunction.sum_eq_iff_sum_mul_moebius_eqSums of two squares. The "only if" direction of Theorem 11 is proved here, in the stronger form that no integer is a sum of two squares, together with the Brahmagupta–Fibonacci identity. Fermat's theorem itself is cited; Mathlib proves it through the Gaussian integers, as the lesson does:
/-- Squares modulo `4` are `0` or `1`. -/
theorem sq_mod_four : ∀ x : ZMod 4, x ^ 2 = 0 ∨ x ^ 2 = 1 := by
decide/-- No integer `≡ 3 (mod 4)` is a sum of two squares: modulo `4`, `a² + b²` is `0 + 0`, `0 + 1`,
`1 + 0` or `1 + 1`, never `3`. In particular no prime `p ≡ 3 (mod 4)` is a sum of two squares. -/
theorem not_sum_two_squares (a b : ℤ) : (a ^ 2 + b ^ 2) % 4 ≠ 3 := by
intro h
have hcast : ((a ^ 2 + b ^ 2 : ℤ) : ZMod 4) = ((3 : ℤ) : ZMod 4) := by
rw [ZMod.intCast_eq_intCast_iff']
simpa using h
push_cast at hcast
rcases sq_mod_four (a : ZMod 4) with ha | ha <;> rcases sq_mod_four (b : ZMod 4) with hb | hb <;>
rw [ha, hb] at hcast <;> revert hcast <;> decide/-- **Brahmagupta–Fibonacci identity**: a product of sums of two squares is a sum of two squares,
`(a² + b²)(c² + d²) = (ac − bd)² + (ad + bc)²` — the multiplicativity of the norm on `ℤ[i]`. -/
theorem brahmagupta_fibonacci (a b c d : ℤ) :
(a ^ 2 + b ^ 2) * (c ^ 2 + d ^ 2) = (a * c - b * d) ^ 2 + (a * d + b * c) ^ 2 := by
ring/-- **Fermat's two-squares theorem**: a prime `p` with `p ≢ 3 (mod 4)` is a sum of two squares.
Mathlib's `Nat.Prime.sq_add_sq`, proved via the Gaussian integers as in the lesson. -/
theorem fermat_two_squares (p : ℕ) [Fact p.Prime] (hp : p % 4 ≠ 3) :
∃ a b : ℕ, a ^ 2 + b ^ 2 = p :=
Nat.Prime.sq_add_sq hpPell's equation. The composition law and a numerical example are proved here. Existence (Theorem 13(a), proved in Mathlib by Dirichlet approximation) and the structure of all solutions (Theorem 13(b)) are cited:
/-- **Composition of Pell solutions** (Brahmagupta's *bhāvanā*): if `x₁² − d y₁² = 1` and
`x₂² − d y₂² = 1`, then `(x₁x₂ + d y₁y₂)² − d (x₁y₂ + x₂y₁)² = 1`. It is the multiplicativity of
the norm `N(x + y√d) = x² − dy²`. -/
theorem pell_composition (d x₁ y₁ x₂ y₂ : ℤ) (h₁ : x₁ ^ 2 - d * y₁ ^ 2 = 1)
(h₂ : x₂ ^ 2 - d * y₂ ^ 2 = 1) :
(x₁ * x₂ + d * y₁ * y₂) ^ 2 - d * (x₁ * y₂ + x₂ * y₁) ^ 2 = 1 := by
linear_combination (x₂ ^ 2 - d * y₂ ^ 2) * h₁ + h₂/-- The fundamental solution of `x² − 13y² = 1` is surprisingly large: `649² − 13 · 180² = 1`. -/
theorem pell_thirteen : (649 : ℤ) ^ 2 - 13 * 180 ^ 2 = 1 := by
norm_num/-- **Pell's equation has a non-trivial solution** for every positive non-square `d`.
Mathlib's `Pell.exists_of_not_isSquare`, proved by Dirichlet's approximation argument as in the
lesson. -/
theorem pell_exists {d : ℤ} (h₀ : 0 < d) (hd : ¬ IsSquare d) :
∃ x y : ℤ, x ^ 2 - d * y ^ 2 = 1 ∧ y ≠ 0 :=
Pell.exists_of_not_isSquare h₀ hd/-- Every solution with `x > 0` and `y ≥ 0` is a power of the fundamental solution `ε`:
`x + y√d = εⁿ`. Mathlib's `Pell.IsFundamental.eq_pow_of_nonneg`, stated for its structure
`Pell.Solution₁ d` of solutions. -/
theorem pell_powers {d : ℤ} {ε : Pell.Solution₁ d} (hε : Pell.IsFundamental ε)
{a : Pell.Solution₁ d} (hx : 0 < a.x) (hy : 0 ≤ a.y) : ∃ n : ℕ, a = ε ^ n :=
hε.eq_pow_of_nonneg hx hyWhat is and is not formalised. Proved independently here: there is no primitive root modulo (Theorem 2 for ); is a primitive root modulo ; is a non-residue modulo ; no integer is a sum of two squares; the Brahmagupta–Fibonacci identity; the composition of Pell solutions; and . Cited from Mathlib: Theorem 1, Gauss's identity, Euler's criterion, both supplementary laws, quadratic reciprocity, Möbius inversion, Fermat's two-squares theorem, and Theorem 13. Not formalised here: Theorem 2 for general , the full classification of Theorem 3, and the continued-fraction algorithm for Pell's equation.
Experiments with primes
The first program decides for every whether a primitive root exists, checks Theorem 3, lists least primitive roots, and asks how often is a primitive root.
"""Primitive roots: which moduli have them, and how often 2 is one.
A primitive root modulo n is a generator of the unit group (Z/nZ)^x. The
program finds, for every n up to 60, whether a primitive root exists, and
compares with the theorem: exactly when n is 1, 2, 4, p^k or 2p^k for an odd
prime p. It lists the least primitive root of the first primes, then counts the
primes below 50000 for which 2 is a primitive root and compares the proportion
with Artin's constant 0.3739558..., which Artin conjectured in 1927 to be the
limiting density (proved by Hooley in 1967 assuming the generalised Riemann
hypothesis; still open unconditionally).
"""
from math import gcd
ARTIN_CONSTANT = 0.3739558136
def prime_factors(n):
"""The distinct prime factors of n, by trial division."""
factors, q = [], 2
while q * q <= n:
if n % q == 0:
factors.append(q)
while n % q == 0:
n //= q
q += 1
if n > 1:
factors.append(n)
return factors
def totient(n):
"""Euler's phi function from the prime factorisation."""
result = n
for q in prime_factors(n):
result -= result // q
return result
def multiplicative_order(a, n):
"""Least k >= 1 with a^k = 1 mod n (requires gcd(a, n) = 1)."""
phi = totient(n)
order = phi
for q in prime_factors(phi):
while order % q == 0 and pow(a, order // q, n) == 1:
order //= q
return order
def primitive_root(n):
"""The least primitive root modulo n, or None if there is none."""
if n == 1:
return 0
phi = totient(n)
for a in range(1, n):
if gcd(a, n) == 1 and multiplicative_order(a, n) == phi:
return a
return None
def predicted(n):
"""The classification: n = 1, 2, 4, p^k or 2 p^k with p an odd prime."""
if n in (1, 2, 4):
return True
m = n // 2 if n % 2 == 0 else n
if m % 2 == 0:
return False
return len(prime_factors(m)) == 1
def primes_below(n):
"""Sieve of Eratosthenes."""
sieve = bytearray([1]) * n
sieve[0:2] = b"\x00\x00"
for i in range(2, int(n ** 0.5) + 1):
if sieve[i]:
sieve[i * i::i] = bytearray(len(sieve[i * i::i]))
return [i for i in range(n) if sieve[i]]
def two_is_primitive_share(bound):
"""(number of odd primes p < bound with 2 a primitive root, number of odd primes)."""
ps = primes_below(bound)[1:]
hits = sum(multiplicative_order(2, p) == p - 1 for p in ps)
return hits, len(ps)
def main():
have = [n for n in range(1, 61) if primitive_root(n) is not None]
print("n <= 60 with a primitive root:")
print(" " + " ".join(map(str, have[:24])))
print(" " + " ".join(map(str, have[24:])))
agree = all((primitive_root(n) is not None) == predicted(n) for n in range(1, 61))
print(f"matches 1, 2, 4, p^k, 2p^k for every n <= 60: {agree}")
print("no primitive root: 8, 12, 15, ... e.g. orders mod 8:",
[multiplicative_order(a, 8) for a in (1, 3, 5, 7)])
first = primes_below(60)
print("least primitive root of p:")
print(" " + " ".join(f"{p}:{primitive_root(p)}" for p in first[:9]))
print(" " + " ".join(f"{p}:{primitive_root(p)}" for p in first[9:]))
for bound in (1000, 10000, 50000):
hits, total = two_is_primitive_share(bound)
print(f"2 is a primitive root for {hits:>4} of {total:>4} odd primes "
f"below {bound:>5}: {hits / total:.4f}")
print(f"Artin's constant (conjectured density): {ARTIN_CONSTANT:.4f}")
print()
print("Epistemic status: the table for n <= 60 is exact and exhaustive, and")
print("agrees with the classification proved in the lesson. The proportions")
print("for 2 are statistical evidence for Artin's conjecture, which remains")
print("unproved without the generalised Riemann hypothesis.")
if __name__ == "__main__":
main()The table is exact. The last lines are statistical evidence for a famous open problem. Emil Artin conjectured in 1927 that (indeed any integer other than that is not a perfect square) is a primitive root modulo infinitely many primes, with a density close to (Artin's constant, , for ). Christopher Hooley proved this in 1967 assuming the generalised Riemann hypothesis. Unconditionally, Roger Heath-Brown (1986) showed that at most two prime numbers fail to be primitive roots for infinitely many primes — but no specific integer, not even , has been proved to work.
The second program checks quadratic reciprocity, Gauss's lemma and Eisenstein's count for all pairs of odd primes below , and finds which small primes are sums of two squares.
"""Quadratic reciprocity, checked three ways, and sums of two squares.
For every pair of distinct odd primes p, q below 200 the program computes the
Legendre symbols (p/q) and (q/p) by Euler's criterion and checks the law of
quadratic reciprocity. It also checks the two ingredients of the lesson's proof:
Gauss's lemma, (q/p) = (-1)^mu with mu the number of "negative" least residues
of q, 2q, ..., ((p-1)/2) q, and Eisenstein's lattice-point identity, that the
points under the diagonal of the (p/2) x (q/2) rectangle number
((p-1)/2)((q-1)/2). Finally it lists which primes are sums of two squares.
"""
def odd_primes_below(n):
"""Odd primes below n by trial division."""
return [p for p in range(3, n, 2) if all(p % d for d in range(3, int(p ** 0.5) + 1, 2))]
def legendre(a, p):
"""Legendre symbol (a/p) for an odd prime p, by Euler's criterion."""
r = pow(a % p, (p - 1) // 2, p)
return -1 if r == p - 1 else r
def gauss_lemma(q, p):
"""(-1)^mu, mu = number of k*q (1 <= k <= (p-1)/2) with residue above p/2."""
mu = sum((k * q) % p > p // 2 for k in range(1, (p - 1) // 2 + 1))
return (-1) ** mu
def lattice_points(p, q):
"""Points (x, y), 1 <= x <= (p-1)/2, 1 <= y <= (q-1)/2, counted in two
triangles: below the diagonal qx = py, and above it."""
below = sum((k * q) // p for k in range(1, (p - 1) // 2 + 1))
above = sum((k * p) // q for k in range(1, (q - 1) // 2 + 1))
return below, above
def two_squares(n):
"""A representation n = a^2 + b^2 with 0 <= a <= b, or None."""
a = 0
while 2 * a * a <= n:
b2 = n - a * a
b = int(round(b2 ** 0.5))
for c in (b - 1, b, b + 1):
if c >= 0 and c * c == b2:
return a, c
a += 1
return None
def main():
primes = odd_primes_below(200)
pairs = [(p, q) for p in primes for q in primes if p < q]
reciprocity = all(legendre(p, q) * legendre(q, p)
== (-1) ** (((p - 1) // 2) * ((q - 1) // 2)) for p, q in pairs)
gauss = all(gauss_lemma(q, p) == legendre(q, p) for p, q in pairs) and all(
gauss_lemma(p, q) == legendre(p, q) for p, q in pairs)
eisenstein = all(sum(lattice_points(p, q)) == ((p - 1) // 2) * ((q - 1) // 2)
for p, q in pairs)
print(f"{len(pairs)} pairs of distinct odd primes below 200:")
print(f" (p/q)(q/p) = (-1)^((p-1)/2 * (q-1)/2) in every case: {reciprocity}")
print(f" Gauss's lemma agrees with Euler's criterion: {gauss}")
print(f" lattice points below + above diagonal = product: {eisenstein}")
below, above = lattice_points(7, 11)
print(f" e.g. p = 7, q = 11: {below} + {above} = {below + above} = 3 * 5;"
f" (7/11)(11/7) = {legendre(7, 11) * legendre(11, 7)}")
minus_one = all((legendre(-1, p) == 1) == (p % 4 == 1) for p in primes)
two = all((legendre(2, p) == 1) == (p % 8 in (1, 7)) for p in primes)
print(f" (-1/p) = 1 exactly when p = 1 mod 4: {minus_one}")
print(f" (2/p) = 1 exactly when p = +-1 mod 8: {two}")
print("Primes below 100 as sums of two squares:")
reps = [(p, two_squares(p)) for p in [2] + odd_primes_below(100)]
line = ""
for p, rep in reps:
if rep:
item = f"{p}={rep[0]}^2+{rep[1]}^2"
if len(line) + len(item) > 74:
print(" " + line.rstrip())
line = ""
line += item + " "
print(" " + line.rstrip())
missing = [p for p, rep in reps if rep is None]
print(f" not sums of two squares: {missing}")
print(f" all of these are 3 mod 4: {all(p % 4 == 3 for p in missing)}")
print()
print("Epistemic status: exact, exhaustive checks for primes below 200 (and")
print("100). They confirm the theorems for these primes only; the lesson's")
print("proofs (Gauss's lemma and Eisenstein's count, and the Gaussian")
print("integers for two squares) cover all primes.")
if __name__ == "__main__":
main()These are exhaustive checks of proved theorems: confirmation, and a test of the proofs' ingredients one by one, but not proofs for all primes. The third program runs the continued-fraction algorithm for Pell's equation and verifies every answer exactly.
"""Pell's equation x^2 - d y^2 = 1 solved by continued fractions.
The continued fraction of sqrt(d), for d not a square, is periodic:
sqrt(d) = [a0; a1, ..., a_r] with the block a1..a_r repeating. The convergents
h/k satisfy h^2 - d k^2 = (-1)^(i+1) q_(i+1), and the fundamental solution of
Pell's equation is the convergent just before the end of the first period (or
of the second, when the period length r is odd). The program runs the exact
integer algorithm, checks each answer, and composes the fundamental solution
with itself (Brahmagupta's composition) to produce the next solutions.
"""
from math import isqrt
def sqrt_continued_fraction(d):
"""(a0, period) for sqrt(d), d > 0 not a square, by the exact (m, q, a) recursion."""
a0 = isqrt(d)
if a0 * a0 == d:
raise ValueError("d must not be a perfect square")
m, q, a = 0, 1, a0
period = []
while a != 2 * a0:
m = a * q - m
q = (d - m * m) // q
a = (a0 + m) // q
period.append(a)
return a0, period
def fundamental_solution(d):
"""Least x > 1, y > 0 with x^2 - d y^2 = 1, from the convergents of sqrt(d)."""
a0, period = sqrt_continued_fraction(d)
r = len(period)
terms = [a0] + (period * 2)[: (r if r % 2 == 0 else 2 * r) - 1]
h_prev, h = 1, terms[0]
k_prev, k = 0, 1
for a in terms[1:]:
h_prev, h = h, a * h + h_prev
k_prev, k = k, a * k + k_prev
return h, k
def compose(s, t, d):
"""Brahmagupta's composition of two solutions (x1 + y1 sqrt d)(x2 + y2 sqrt d)."""
(x1, y1), (x2, y2) = s, t
return x1 * x2 + d * y1 * y2, x1 * y2 + x2 * y1
def brute_force(d, limit):
"""Least y in 1..limit with d y^2 + 1 a square, as (x, y), or None."""
for y in range(1, limit + 1):
x2 = d * y * y + 1
x = isqrt(x2)
if x * x == x2:
return x, y
return None
def main():
print(" d period of sqrt(d) fundamental solution (x, y)")
ok = True
for d in range(2, 31):
if isqrt(d) ** 2 == d:
continue
a0, period = sqrt_continued_fraction(d)
x, y = fundamental_solution(d)
ok &= x * x - d * y * y == 1
if d <= 14 or d in (19, 22, 29):
shown = "[" + str(a0) + "; " + ",".join(map(str, period)) + "]"
print(f"{d:>2} {shown:<21} ({x}, {y})")
print(f"every non-square d <= 30 solved and checked exactly: {ok}")
agree = all(brute_force(d, 2000) == fundamental_solution(d)
for d in range(2, 31) if isqrt(d) ** 2 != d)
print(f"brute force agrees for d <= 30 (y <= 2000): {agree}")
for d in (61, 109):
x, y = fundamental_solution(d)
print(f"d = {d}: x = {x}, y = {y}")
print(f" x^2 - {d} y^2 = {x * x - d * y * y}")
s = fundamental_solution(2)
powers = [s]
for _ in range(4):
powers.append(compose(powers[-1], s, 2))
print("x^2 - 2y^2 = 1: the powers of (3, 2) under composition are")
print(" " + ", ".join(map(str, powers)))
print()
print("Epistemic status: exact integer computations, each solution verified")
print("by substitution. That the continued-fraction method always finds the")
print("fundamental solution, and that every solution is a power of it, are")
print("theorems (see the lesson); the runs here are illustrations.")
if __name__ == "__main__":
main()The jump from (solution ) to (a ten-digit ) shows why the equation is hard to solve by search, and why Fermat chose for his challenge. The size of the fundamental solution is governed by the class number and the regulator of , an analytic subject in its own right.
Explore: multiplicative partners and primitive roots
In the multiplication tab of the clock, choose a prime number of hours . Every non-zero residue has a partner, so the units form a group of order . Try and step through the multiples of in your head: . The powers of visit every unit. Then try , where the units are each their own partner. That is the reason, in Theorem 2, that no primitive root exists.
The clock laboratory
On a clock with k hours, counting wraps around. Explore adding and multiplying.
9 + 5 = 14 ≡ 2 (mod 12)
14 hours forward on a 12-hour clock lands on 2: the remainder when 14 is divided by 12.
Exercises
1. Number theory
Warm-upHumanHow many primitive roots are there modulo ?
2. Number theory
CoreHumanUse quadratic reciprocity to compute the Legendre symbol . (Enter or .)
3. Number theory
CoreHumanFor which moduli does a primitive root exist? (Select all that apply.)
4. Number theory
Warm-upHumanWhich of these numbers are sums of two squares of integers? (Select all that apply.)
5. Number theory
CoreHumanIn the proof of Euler's criterion, let be a primitive root modulo an odd prime and . Why is exactly when is even?
6. Number theory
CoreHumanCompute , where is the Möbius function.
7. Number theory
StretchHumanThe fundamental solution of is . Using composition, , find the next solution. What is its ?
8. Number theory
CoreFormalIn Lean, legendreSym p a is the Legendre symbol . Which statement is the law of quadratic reciprocity for primes p, q (with [Fact p.Prime] [Fact q.Prime])?
9. Number theory
StretchComputationalWrite order(a, n) returning the multiplicative order of modulo (assume , ), and primitive_roots(p) returning the sorted list of primitive roots modulo a prime . Check that there are of them.
Common misconceptions
Misconception
"Every modulus has a primitive root." Modulo every unit squares to , and modulo every unit has order dividing . Primitive roots exist exactly for with an odd prime (Theorem 3).
Misconception
"Quadratic reciprocity is an isolated trick." It has more than two hundred published proofs, through Gauss sums, lattice points, cyclotomic fields, counting arguments and more, and far-reaching generalisations. These include cubic and biquadratic reciprocity (Gauss, Eisenstein, Jacobi), Hilbert's reciprocity law, the Artin reciprocity law of class field theory, and the Langlands programme, which can be read as a vast non-abelian reciprocity law.
Misconception
"A Jacobi symbol means that is a square modulo ." The Legendre symbol does detect squares modulo a prime. Its extension to odd composite moduli, the Jacobi symbol , does not. For example , yet is not a square modulo (it is not even a square modulo ).
Misconception
"Every is a sum of two squares." The congruence condition is necessary only. is not a sum of two squares, because and divide it to odd powers. The full criterion is about the prime factorisation.
Misconception
"Pell's equation is Pell's." Euler attributed it to John Pell by mistake (Pell did not solve it). The equation was studied by Brahmagupta (628), solved in general by the chakravāla method of Jayadeva and Bhāskara II (11th–12th centuries), and its solvability was first proved by Lagrange (1768).
Many ways of seeing
Algebra— Reciprocity from cyclotomic fields
Let and form the Gauss sum . A short computation gives , so . Now work modulo in the ring . On one side , by the Frobenius property . On the other, , by Euler's criterion. Comparing the two gives reciprocity. In the language of Galois theory, records whether the Frobenius element at fixes , and records whether the corresponding element of is a square. Reciprocity says these agree, and Artin reciprocity generalises it to all abelian extensions.
Geometry— Lattices and hyperbolas
The proof of Theorem 8 is a lattice-point count, and lattice geometry gives other proofs too. By Minkowski's theorem, a convex region symmetric about with area greater than contains a non-zero point of the lattice . Take , where , with , and the disc . It contains a point with and , so . Pell's equation is geometric too. Its solutions are the lattice points on the hyperbola , and acts on the hyperbola as a hyperbolic "rotation" (a Lorentz boost) preserving the lattice . The group is the group of such symmetries. This is the first case of Dirichlet's unit theorem in algebraic number theory.
Analysis— Primes in progressions and L-functions
Are there infinitely many primes ? Yes. If were all of them, any prime factor of would be by Corollary 5, and new. Dirichlet's theorem (1837) gives infinitely many primes whenever , and each class receives the same share . The proof is analytic. It uses the -functions attached to characters of , and the key point is that . For , the character modulo , Leibniz's series is . Its non-vanishing is the first case. See analytic number theory.
Probability— Heuristics, biases and densities
Many statements in this subject are densities: half the odd primes are ; is a quadratic residue for half the primes, namely those ; is a primitive root for a proportion of primes (conjecturally). Artin's constant comes from a probabilistic heuristic. For each prime , the chance that and is an -th power modulo is "", and treating these events as independent gives . Heuristics like this are guides, not proofs. They can even mislead: Chebyshev's bias is the observation that primes are ahead of primes in most initial segments. Rubinstein and Sarnak (1994) quantified it, under the generalised Riemann hypothesis and a linear independence hypothesis: the logarithmic density of for which leads is about .
Computation— Cryptography and fast algorithms
Primitive roots are the setting of Diffie–Hellman key exchange (1976). With a public prime and primitive root , two parties exchange and and share the secret . Computing is fast by repeated squaring. Recovering — the discrete logarithm — is believed to be hard for well-chosen large , a belief supported by decades of cryptanalysis, not by proof (cryptography). Legendre and Jacobi symbols can be computed in polynomial time with reciprocity, without factoring. Square roots modulo a prime are found efficiently by the Tonelli–Shanks algorithm. Distinguishing squares from non-squares modulo a composite without knowing and seems hard, and the Goldwasser–Micali cryptosystem (1982) is built on that assumption.
History and global context
- India. Brahmagupta's Brāhmasphuṭasiddhānta (628) introduced the composition law (bhāvanā) for and used it to generate solutions of Pell's equation. Jayadeva (11th century) and Bhāskara II (Bījagaṇita, 1150) gave the cyclic chakravāla method, which always succeeds, and solved .
- Fermat and Euler. Fermat stated the two-squares theorem (letter to Mersenne, 1640) and challenged mathematicians with (1657); William Brouncker and John Wallis found methods. Euler proved the two-squares theorem (1747–1749), introduced the totient and the term "primitive root", and conjectured quadratic reciprocity. Lagrange proved that Pell's equation always has a non-trivial solution (1768).
- Legendre and Gauss. Legendre introduced his symbol (1798) and published an incomplete proof of reciprocity. Gauss gave the first complete proof in the Disquisitiones Arithmeticae (1801), together with the first proof that primitive roots exist modulo every prime, and eventually published eight proofs. Gotthold Eisenstein's lattice-point proof (1844) is the one given here.
- The nineteenth and twentieth centuries. August Möbius introduced his function (1832). Peter Gustav Lejeune Dirichlet proved his theorem on primes in progressions (1837), founding analytic number theory. Emil Artin made his conjecture on primitive roots in 1927, and Christopher Hooley proved it conditionally in 1967. Reciprocity grew into class field theory (Hilbert, Takagi, Artin) and then into the Langlands programme.
Further reading
- Kenneth Ireland and Michael Rosen, A Classical Introduction to Modern Number Theory (2nd edition, 1990), chapters 2–6 — primitive roots, quadratic reciprocity with Gauss sums, and more.
- G. H. Hardy and E. M. Wright, An Introduction to the Theory of Numbers (1938; 6th edition 2008) — arithmetic functions, sums of squares, continued fractions and Pell's equation.
- Ivan Niven, Herbert S. Zuckerman and Hugh L. Montgomery, An Introduction to the Theory of Numbers (5th edition, 1991).
- Franz Lemmermeyer, Reciprocity Laws: From Euler to Eisenstein (2000) — the history and many proofs of reciprocity.
- André Weil, Number Theory: An Approach through History from Hammurapi to Legendre (1984).