lean4-compile / test.json
rookiemango's picture
Upload folder using huggingface_hub
dddc1ae verified
raw
history blame
9.16 kB
import Mathlib.Algebra.Star.Unitary
import Mathlib.Data.Nat.ModEq
import Mathlib.NumberTheory.Zsqrtd.Basic
import Mathlib.Tactic.Monotonicity
import Mathlib.Algebra.GroupPower.Order
#align_import number_theory.pell_matiyasevic from "leanprover-community/mathlib"@"795b501869b9fa7aa716d5fdadd00c03f983a605"
/-!
# Pell's equation and Matiyasevic's theorem
This file solves Pell's equation, i.e. integer solutions to `x ^ 2 - d * y ^ 2 = 1`
*in the special case that `d = a ^ 2 - 1`*.
This is then applied to prove Matiyasevic's theorem that the power
function is Diophantine, which is the last key ingredient in the solution to Hilbert's tenth
problem. For the definition of Diophantine function, see `NumberTheory.Dioph`.
For results on Pell's equation for arbitrary (positive, non-square) `d`, see
`NumberTheory.Pell`.
## Main definition
* `pell` is a function assigning to a natural number `n` the `n`-th solution to Pell's equation
constructed recursively from the initial solution `(0, 1)`.
## Main statements
* `eq_pell` shows that every solution to Pell's equation is recursively obtained using `pell`
* `matiyasevic` shows that a certain system of Diophantine equations has a solution if and only if
the first variable is the `x`-component in a solution to Pell's equation - the key step towards
Hilbert's tenth problem in Davis' version of Matiyasevic's theorem.
* `eq_pow_of_pell` shows that the power function is Diophantine.
## Implementation notes
The proof of Matiyasevic's theorem doesn't follow Matiyasevic's original account of using Fibonacci
numbers but instead Davis' variant of using solutions to Pell's equation.
## References
* [M. Carneiro, _A Lean formalization of Matiyasevič's theorem_][carneiro2018matiyasevic]
* [M. Davis, _Hilbert's tenth problem is unsolvable_][MR317916]
## Tags
Pell's equation, Matiyasevic's theorem, Hilbert's tenth problem
-/
namespace Pell
open Nat
section
variable {d : β„€}
/-- The property of being a solution to the Pell equation, expressed
as a property of elements of `β„€βˆšd`. -/
def IsPell : β„€βˆšd β†’ Prop
| ⟨x, y⟩ => x * x - d * y * y = 1
#align pell.is_pell Pell.IsPell
theorem isPell_norm : βˆ€ {b : β„€βˆšd}, IsPell b ↔ b * star b = 1
| ⟨x, y⟩ => by simp [Zsqrtd.ext_iff, IsPell, mul_comm]; ring_nf
#align pell.is_pell_norm Pell.isPell_norm
theorem isPell_iff_mem_unitary : βˆ€ {b : β„€βˆšd}, IsPell b ↔ b ∈ unitary (β„€βˆšd)
| ⟨x, y⟩ => by rw [unitary.mem_iff, isPell_norm, mul_comm (star _), and_self_iff]
#align pell.is_pell_iff_mem_unitary Pell.isPell_iff_mem_unitary
theorem isPell_mul {b c : β„€βˆšd} (hb : IsPell b) (hc : IsPell c) : IsPell (b * c) :=
isPell_norm.2 (by simp [mul_comm, mul_left_comm c, mul_assoc,
star_mul, isPell_norm.1 hb, isPell_norm.1 hc])
#align pell.is_pell_mul Pell.isPell_mul
theorem isPell_star : βˆ€ {b : β„€βˆšd}, IsPell b ↔ IsPell (star b)
| ⟨x, y⟩ => by simp [IsPell, Zsqrtd.star_mk]
#align pell.is_pell_star Pell.isPell_star
end
section
-- Porting note: was parameter in Lean3
variable {a : β„•} (a1 : 1 < a)
private def d (_a1 : 1 < a) :=
a * a - 1
@[simp]
theorem d_pos : 0 < d a1 :=
tsub_pos_of_lt (mul_lt_mul a1 (le_of_lt a1) (by decide) (Nat.zero_le _) : 1 * 1 < a * a)
#align pell.d_pos Pell.d_pos
-- TODO(lint): Fix double namespace issue
/-- The Pell sequences, i.e. the sequence of integer solutions to `x ^ 2 - d * y ^ 2 = 1`, where
`d = a ^ 2 - 1`, defined together in mutual recursion. -/
--@[nolint dup_namespace]
def pell : β„• β†’ β„• Γ— β„•
-- Porting note: used pattern matching because `Nat.recOn` is noncomputable
| 0 => (1, 0)
| n+1 => ((pell n).1 * a + d a1 * (pell n).2, (pell n).1 + (pell n).2 * a)
#align pell.pell Pell.pell
/-- The Pell `x` sequence. -/
def xn (n : β„•) : β„• :=
(pell a1 n).1
#align pell.xn Pell.xn
/-- The Pell `y` sequence. -/
def yn (n : β„•) : β„• :=
(pell a1 n).2
#align pell.yn Pell.yn
@[simp]
theorem pell_val (n : β„•) : pell a1 n = (xn a1 n, yn a1 n) :=
show pell a1 n = ((pell a1 n).1, (pell a1 n).2) from
match pell a1 n with
| (_, _) => rfl
#align pell.pell_val Pell.pell_val
@[simp]
theorem xn_zero : xn a1 0 = 1 :=
rfl
#align pell.xn_zero Pell.xn_zero
@[simp]
theorem yn_zero : yn a1 0 = 0 :=
rfl
#align pell.yn_zero Pell.yn_zero
@[simp]
theorem xn_succ (n : β„•) : xn a1 (n + 1) = xn a1 n * a + d a1 * yn a1 n :=
rfl
#align pell.xn_succ Pell.xn_succ
@[simp]
theorem yn_succ (n : β„•) : yn a1 (n + 1) = xn a1 n + yn a1 n * a :=
rfl
#align pell.yn_succ Pell.yn_succ
--@[simp] Porting note (#10618): `simp` can prove it
theorem xn_one : xn a1 1 = a := by simp
#align pell.xn_one Pell.xn_one
--@[simp] Porting note (#10618): `simp` can prove it
theorem yn_one : yn a1 1 = 1 := by simp
#align pell.yn_one Pell.yn_one
/-- The Pell `x` sequence, considered as an integer sequence.-/
def xz (n : β„•) : β„€ :=
xn a1 n
#align pell.xz Pell.xz
/-- The Pell `y` sequence, considered as an integer sequence.-/
def yz (n : β„•) : β„€ :=
yn a1 n
#align pell.yz Pell.yz
section
/-- The element `a` such that `d = a ^ 2 - 1`, considered as an integer.-/
def az (a : β„•) : β„€ :=
a
#align pell.az Pell.az
end
theorem asq_pos : 0 < a * a :=
le_trans (le_of_lt a1)
(by have := @Nat.mul_le_mul_left 1 a a (le_of_lt a1); rwa [mul_one] at this)
#align pell.asq_pos Pell.asq_pos
theorem dz_val : ↑(d a1) = az a * az a - 1 :=
have : 1 ≀ a * a := asq_pos a1
by rw [Pell.d, Int.ofNat_sub this]; rfl
#align pell.dz_val Pell.dz_val
@[simp]
theorem xz_succ (n : β„•) : (xz a1 (n + 1)) = xz a1 n * az a + d a1 * yz a1 n :=
rfl
#align pell.xz_succ Pell.xz_succ
@[simp]
theorem yz_succ (n : β„•) : yz a1 (n + 1) = xz a1 n + yz a1 n * az a :=
rfl
#align pell.yz_succ Pell.yz_succ
/-- The Pell sequence can also be viewed as an element of `β„€βˆšd` -/
def pellZd (n : β„•) : β„€βˆš(d a1) :=
⟨xn a1 n, yn a1 n⟩
#align pell.pell_zd Pell.pellZd
@[simp]
theorem pellZd_re (n : β„•) : (pellZd a1 n).re = xn a1 n :=
rfl
#align pell.pell_zd_re Pell.pellZd_re
@[simp]
theorem pellZd_im (n : β„•) : (pellZd a1 n).im = yn a1 n :=
rfl
#align pell.pell_zd_im Pell.pellZd_im
theorem isPell_nat {x y : β„•} : IsPell (⟨x, y⟩ : β„€βˆš(d a1)) ↔ x * x - d a1 * y * y = 1 :=
⟨fun h =>
Nat.cast_inj.1
(by rw [Int.ofNat_sub (Int.le_of_ofNat_le_ofNat <| Int.le.intro_sub _ h)]; exact h),
fun h =>
show ((x * x : β„•) - (d a1 * y * y : β„•) : β„€) = 1 by
rw [← Int.ofNat_sub <| le_of_lt <| Nat.lt_of_sub_eq_succ h, h]; rfl⟩
#align pell.is_pell_nat Pell.isPell_nat
@[simp]
theorem pellZd_succ (n : β„•) : pellZd a1 (n + 1) = pellZd a1 n * ⟨a, 1⟩ := by ext <;> simp
#align pell.pell_zd_succ Pell.pellZd_succ
theorem isPell_one : IsPell (⟨a, 1⟩ : β„€βˆš(d a1)) :=
show az a * az a - d a1 * 1 * 1 = 1 by simp [dz_val]
#align pell.is_pell_one Pell.isPell_one
theorem isPell_pellZd : βˆ€ n : β„•, IsPell (pellZd a1 n)
| 0 => rfl
| n + 1 => by
let o := isPell_one a1
simp; exact Pell.isPell_mul (isPell_pellZd n) o
#align pell.is_pell_pell_zd Pell.isPell_pellZd
@[simp]
theorem pell_eqz (n : β„•) : xz a1 n * xz a1 n - d a1 * yz a1 n * yz a1 n = 1 :=
isPell_pellZd a1 n
#align pell.pell_eqz Pell.pell_eqz
@[simp]
theorem pell_eq (n : β„•) : xn a1 n * xn a1 n - d a1 * yn a1 n * yn a1 n = 1 :=
let pn := pell_eqz a1 n
have h : (↑(xn a1 n * xn a1 n) : β„€) - ↑(d a1 * yn a1 n * yn a1 n) = 1 := by
repeat' rw [Int.ofNat_mul]; exact pn
have hl : d a1 * yn a1 n * yn a1 n ≀ xn a1 n * xn a1 n :=
Nat.cast_le.1 <| Int.le.intro _ <| add_eq_of_eq_sub' <| Eq.symm h
Nat.cast_inj.1 (by rw [Int.ofNat_sub hl]; exact h)
#align pell.pell_eq Pell.pell_eq
instance dnsq : Zsqrtd.Nonsquare (d a1) :=
⟨fun n h =>
have : n * n + 1 = a * a := by rw [← h]; exact Nat.succ_pred_eq_of_pos (asq_pos a1)
have na : n < a := Nat.mul_self_lt_mul_self_iff.1 (by rw [← this]; exact Nat.lt_succ_self _)
have : (n + 1) * (n + 1) ≀ n * n + 1 := by rw [this]; exact Nat.mul_self_le_mul_self na
have : n + n ≀ 0 :=
@Nat.le_of_add_le_add_right _ (n * n + 1) _ (by ring_nf at this ⊒; assumption)
Nat.ne_of_gt (d_pos a1) <| by
rwa [Nat.eq_zero_of_le_zero ((Nat.le_add_left _ _).trans this)] at h⟩
#align pell.dnsq Pell.dnsq
theorem xn_ge_a_pow : βˆ€ n : β„•, a ^ n ≀ xn a1 n
| 0 => le_refl 1
| n + 1 => by
simp only [_root_.pow_succ, xn_succ]
exact le_trans (Nat.mul_le_mul_right _ (xn_ge_a_pow n)) (Nat.le_add_right _ _)
#align pell.xn_ge_a_pow Pell.xn_ge_a_pow
theorem n_lt_a_pow : βˆ€ n : β„•, n < a ^ n
| 0 => Nat.le_refl 1
| n + 1 => by
have IH := n_lt_a_pow n
have : a ^ n + a ^ n ≀ a ^ n * a := by
rw [← mul_two]
exact Nat.mul_le_mul_left _ a1
simp only [_root_.pow_succ, gt_iff_lt]
refine' lt_of_lt_of_le _ this
exact add_lt_add_of_lt_of_le IH (lt_of_le_of_lt (Nat.zero_le _) IH)
#align pell.n_lt_a_pow Pell.n_lt_a_pow