1- def largest_divisor : Unit :=
2- ()
1+ /-- Computes the largest divisor in O(sqrt n) via trial divison. -/
2+ def largestDivisor (n : Nat) : Nat :=
3+ go 2
4+ where
5+ go (i : Nat) : Nat :=
6+ if h : n < i * i then
7+ 1
8+ else if n % i = 0 then
9+ n / i
10+ else go (i + 1 )
11+ termination_by n - i
12+ decreasing_by
13+ have : i < n := by
14+ match i with
15+ | 0 => omega
16+ | 1 => omega
17+ | i + 2 => exact Nat.lt_of_lt_of_le (Nat.lt_mul_self_iff.2 (by omega)) (Nat.not_lt.1 h)
18+ omega
19+
20+ example : largestDivisor 3 = 1 := by native_decide
21+ example : largestDivisor 7 = 1 := by native_decide
22+ example : largestDivisor 10 = 5 := by native_decide
23+ example : largestDivisor 100 = 50 := by native_decide
24+ example : largestDivisor 49 = 7 := by native_decide
25+
26+ inductive LargestDivisorSpec (n : Nat) : Nat → Prop
27+ | one : (∀ j, 2 ≤ j → j * j ≤ n → n % j ≠ 0 ) → LargestDivisorSpec n 1
28+ | div {i} : (∀ j, 2 ≤ j → j < i → n % j ≠ 0 ) → 2 ≤ i → n % i = 0 → LargestDivisorSpec n (n / i)
29+
30+ theorem largestDivisorSpec_go {n i : Nat} (hi : 2 ≤ i)
31+ (hi' : ∀ j, 2 ≤ j → j < i → n % j ≠ 0 ) : LargestDivisorSpec n (largestDivisor.go n i) := by
32+ fun_induction largestDivisor.go n i
33+ case case1 i hni =>
34+ rw [largestDivisor.go, dif_pos hni]
35+ apply LargestDivisorSpec.one
36+ intro j hj hj'
37+ apply hi' _ hj
38+ exact Nat.mul_self_lt_mul_self_iff.1 (Nat.lt_of_le_of_lt hj' hni)
39+ case case2 i hni hni' =>
40+ rw [largestDivisor.go, dif_neg hni, if_pos hni']
41+ exact LargestDivisorSpec.div hi' hi hni'
42+ case case3 i hni hni' ih =>
43+ rw [largestDivisor.go, dif_neg hni, if_neg hni']
44+ apply ih (by omega)
45+ intro j hj hij
46+ by_cases hij' : j = i
47+ · exact hij' ▸ hni'
48+ · exact hi' _ hj (by omega)
49+
50+ theorem largestDivisorSpec_largestDivisor {n : Nat} :
51+ LargestDivisorSpec n (largestDivisor n) := by
52+ rw [largestDivisor]
53+ exact largestDivisorSpec_go (Nat.le_refl _) (by omega)
54+
55+ theorem Nat.lt_mul_iff {a b : Nat} : a < a * b ↔ 0 < a ∧ 1 < b := by
56+ obtain (rfl|ha) := Nat.eq_zero_or_pos a
57+ · simp
58+ · simp [ha]
59+
60+ theorem helper {n i : Nat} (hn : 1 < n) (h : ∀ j, 2 ≤ j → j < i → n % j ≠ 0 ) (hi : n % i = 0 )
61+ (k : Nat) (hk : n / i < k) (hk₁ : k < n) : n % k ≠ 0 := by
62+ intro hk₂
63+ obtain ⟨d, rfl⟩ := Nat.dvd_of_mod_eq_zero hk₂
64+ rw [Nat.lt_mul_iff] at hk₁
65+ have hi₀ : 0 < i := by
66+ apply Nat.pos_iff_ne_zero.2
67+ rintro rfl
68+ simp only [Nat.mod_zero] at hi
69+ omega
70+ refine h d ?_ ?_ (by simp)
71+ · omega
72+ · rw [Nat.div_lt_iff_lt_mul hi₀] at hk
73+ exact Nat.lt_of_mul_lt_mul_left hk
74+
75+ theorem similar_helper {n : Nat} (hn : 1 < n) (h : ∀ j, 2 ≤ j → j * j ≤ n → n % j ≠ 0 )
76+ (k : Nat) (hk : n < k * k) (hk₁ : k < n) : n % k ≠ 0 := by
77+ intro hk₂
78+ obtain ⟨d, rfl⟩ := Nat.dvd_of_mod_eq_zero hk₂
79+ rw [Nat.lt_mul_iff] at hk₁
80+ refine h d ?_ ?_ (by simp)
81+ · omega
82+ · refine Nat.mul_le_mul_right _ (Nat.le_of_lt ?_)
83+ exact Nat.lt_of_mul_lt_mul_left hk
84+
85+ theorem largestDivisorSpec_iff {n i : Nat} (hn : 1 < n) :
86+ LargestDivisorSpec n i ↔ i < n ∧ n % i = 0 ∧ ∀ j, j < n → n % j = 0 → j ≤ i := by
87+ constructor
88+ · rintro (h|h)
89+ · refine ⟨hn, Nat.mod_one _, fun j hj hj₁ => Nat.not_lt.1 (fun hj₂ => ?_)⟩
90+ by_cases hj₃ : j * j ≤ n
91+ · exact h j (by omega) hj₃ hj₁
92+ · exact similar_helper hn h j (by omega) hj hj₁
93+ · rename_i i hi hi'
94+ refine ⟨?_, ?_, fun j hj hj₁ => ?_⟩
95+ · apply Nat.div_lt_self <;> omega
96+ · exact Nat.mod_eq_zero_of_dvd (Nat.div_dvd_of_dvd (Nat.dvd_of_mod_eq_zero hi'))
97+ · exact Nat.not_lt.1 (fun hj₂ => helper hn h hi' j hj₂ hj hj₁)
98+ · rintro ⟨hi₁, hi₂, hi₃⟩
99+ obtain (h|rfl|h) := Nat.lt_trichotomy i 1
100+ · obtain rfl : i = 0 := by omega
101+ omega
102+ · refine LargestDivisorSpec.one (fun j hj hj₁ hj₂ => absurd (hi₃ j ?_ hj₂) (by omega))
103+ exact Nat.lt_of_lt_of_le (Nat.lt_mul_self_iff.2 (by omega)) hj₁
104+ · obtain ⟨d, rfl⟩ := Nat.dvd_of_mod_eq_zero hi₂
105+ have hd : 0 < d := Nat.pos_iff_ne_zero.2 (fun hd => by simp [hd] at hn)
106+ rw (occs := [2 ]) [← Nat.mul_div_cancel (m := i) (n := d) hd]
107+ refine LargestDivisorSpec.div ?_ ?_ (by simp)
108+ · intro j hj₁ hj₂ hj₃
109+ have : ¬ i * d / j ≤ i := by
110+ rw [Nat.not_le, Nat.lt_div_iff_mul_lt_of_dvd (by omega) (Nat.dvd_of_mod_eq_zero hj₃)]
111+ exact Nat.mul_lt_mul_of_pos_left hj₂ (by omega)
112+ refine absurd (hi₃ _ ?_ ?_) this
113+ · apply Nat.div_lt_self (by omega) (by omega)
114+ · exact Nat.mod_eq_zero_of_dvd (Nat.div_dvd_of_dvd (Nat.dvd_of_mod_eq_zero hj₃))
115+ · rw [Nat.lt_mul_iff] at hi₁
116+ omega
117+
118+ theorem largestDivisorSpec_unique {n i k : Nat} (hn : 1 < n)
119+ (hi : LargestDivisorSpec n i) (hk : LargestDivisorSpec n k) : i = k := by
120+ simp only [largestDivisorSpec_iff hn] at hi hk
121+ apply Nat.le_antisymm
122+ · apply hk.2 .2 _ hi.1 hi.2 .1
123+ · apply hi.2 .2 _ hk.1 hk.2 .1
124+
125+ theorem largestDivisor_eq_iff {n i : Nat} (hn : 1 < n) :
126+ largestDivisor n = i ↔ i < n ∧ n % i = 0 ∧ ∀ j, j < n → n % j = 0 → j ≤ i := by
127+ rw [← largestDivisorSpec_iff hn]
128+ refine ⟨?_, fun hi => ?_⟩
129+ · rintro rfl
130+ apply largestDivisorSpec_largestDivisor
131+ · apply largestDivisorSpec_unique hn largestDivisorSpec_largestDivisor hi
3132
4133/-!
5134## Prompt
@@ -40,4 +169,4 @@ def check(candidate):
40169 assert candidate(100) == 50
41170 assert candidate(49) == 7
42171```
43- -/
172+ -/
0 commit comments