Binomial coefficients on natural numbers, defined by the Pascal recursion.
Equations
- Hex.Nat.choose x✝ 0 = 1
- Hex.Nat.choose 0 n.succ = 0
- Hex.Nat.choose n.succ k.succ = Hex.Nat.choose n k + Hex.Nat.choose n (k + 1)
Instances For
Primality as a bounded search: for p ≥ 2, having only trivial divisors is
the same as having no divisor strictly between 1 and p. The point of the
restatement is that the right-hand side quantifies over a finite range, which is
what makes the decidability instance below possible.
Primality by trial division up to the square root.
A composite has a nontrivial divisor d with d * d ≤ p: of any factor pair
p = d * e, the smaller one qualifies. Bounding the search that way is what
makes decide practical. The linear form above needs p steps, which is fine
for a two-digit modulus and is not fine beyond that — decide on
Prime 3221 takes about fourteen seconds through it, and the primes that turn
up in p ^ n - 1 for the committed Conway table run to five digits. This form
needs about √p steps instead.
Primality from trial division up to a caller-supplied bound.
prime_iff_forall_le_sqrt cannot drive a decide: core's Nat.sqrt is
defined by well-founded recursion, so the kernel will not evaluate it. Taking
the bound as data instead keeps everything the kernel sees structural. The
caller supplies b with p < (b + 1) ^ 2, which decide checks in one
multiplication, and then only b + 1 divisors have to be ruled out rather
than p of them.
The Decidable instance now routes through isPrimeTrial (defined below), so
decide is O (√p) remainder tests; this lemma remains for callers that
already hold an explicit bound and want the divisor obligations alone.
Linear-time binomial coefficient.
Hex.Nat.binom walks a single Pascal row from
choose n 0 = 1 using the multiplicative recurrence
Hex.Nat.succ_mul_choose_succ, folding over the shorter half
min k (n - k) of the row using Hex.Nat.choose_symm. It therefore
costs O(min k (n - k)) natural-number operations. The proof-facing
Hex.Nat.choose is the exponential Pascal recursion; the forward
correctness theorem binom_eq_choose, registered with @[csimp], makes
compiled callers use this linear fold.
Equations
- Hex.Nat.binom n k = if n < k then 0 else List.foldl (fun (acc i : Nat) => acc * (n - i) / (i + 1)) 1 (List.range (min k (n - k)))
Instances For
Choosing 0 elements always gives 1.
Every nontrivial binomial coefficient in the pth row of Pascal's triangle is
divisible by p when p is prime. This is the binomial-divisibility fact used
to erase the middle terms in add_pow_prime_mod.
Balanced trial division over the 2 ^ fuel candidates starting at k.
The square guard is checked before descending into an interval, so no
candidate with n < k * k is tested. Splitting the interval in half keeps
kernel reduction depth logarithmic in the number of candidate divisors.
This helper is a primality test only with a range large enough to cover every
small divisor; isPrimeTrial is the supported entry point.
Equations
Instances For
Executable bounded trial-division primality test. Returns true exactly when
n is prime. Candidate divisors start at 2, and the loop stops before
testing the first k whose square exceeds n; thus it performs at most
⌊√n⌋ - 1 remainder tests. It remains pure Lean so emitted primality
certificates can be replayed by the kernel without Mathlib, native_decide,
or a fixed prime table.
Equations
- Hex.Nat.isPrimeTrial n = (decide (2 ≤ n) && Hex.Nat.isPrimeTrialAux n (n.log2 + 1) 2)
Instances For
Soundness of the trial-division primality test against the Mathlib-free
Hex.Nat.Prime predicate. It turns a successful runtime test into
explicit primality evidence without relying on a hardcoded prime table.
Completeness of the executable trial-division test: every project-local prime
witness makes the Boolean checker return true.
Primality is decidable through isPrimeTrial, so decide costs
O (√p) remainder tests with kernel reduction depth logarithmic in the
candidate count.