Skip to content

Commit 15a34ce

Browse files
committed
cleanups
1 parent 84c57af commit 15a34ce

File tree

1 file changed

+45
-25
lines changed

1 file changed

+45
-25
lines changed

HumanEvalLean/HumanEval59.lean

Lines changed: 45 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ decreasing_by
2626

2727
/--
2828
Returns the largest prime factor of a given number by iteratively dividing away the smallest factor.
29+
30+
Other than the Python reference implementation, this one runs in `O(sqrt(n) + log(n))`.
2931
-/
3032
def largestPrimeFactor (n : Nat) : Nat := Id.run do
3133
if hn : 0 < n then
@@ -93,6 +95,21 @@ theorem largestPrimeFactor_dvd :
9395
· .withEarlyReturn (fun cur ⟨m, factor⟩ => ⌜factor ∣ n ∧ m.val ∣ n⌝) (fun ret ⟨m, factor⟩ => ⌜ret ∣ n⌝)
9496
with grind [dividePower_dvd, Nat.dvd_trans, Nat.dvd_refl]
9597

98+
theorem Nat.div_div_eq_div_mul' {a b c : Nat} (h : b ∣ a) (h' : c ∣ b) : a / (b / c) = a / b * c := by
99+
by_cases a = 0
100+
· simp [*]
101+
· have : 0 < b := Nat.pos_of_dvd_of_pos h (by grind)
102+
have : 0 < c := Nat.pos_of_dvd_of_pos h' (by grind)
103+
rw [Nat.div_eq_iff_eq_mul_left]
104+
· rw [Nat.mul_assoc, ← Nat.mul_div_assoc, Nat.mul_div_cancel_left, Nat.div_mul_cancel]
105+
all_goals assumption
106+
· have : c ≤ b := Nat.le_of_dvd ‹_› ‹_›
107+
simp only [Nat.div_pos_iff]
108+
grind
109+
· refine Nat.dvd_trans ?_ h
110+
apply Nat.div_dvd_of_dvd
111+
assumption
112+
96113
theorem dvd_or_dvd_of_dvd_self_div_dividePower {e : Nat} (h : m.val ∣ n)
97114
(h : e ∣ n / (dividePower m d hd)) (hp : IsPrime e) :
98115
e ∣ n / m ∨ e ∣ d := by
@@ -102,37 +119,38 @@ theorem dvd_or_dvd_of_dvd_self_div_dividePower {e : Nat} (h : m.val ∣ n)
102119
specialize ih (by grind [Nat.dvd_trans, Nat.div_dvd_of_dvd]) h
103120
cases ih
104121
· rename_i h'
105-
have (a b c : Nat) (h : b ∣ a) (h' : c ∣ b) : a / (b / c) = a / b * c := by
106-
by_cases a = 0
107-
· simp [*]
108-
· have : 0 < b := Nat.pos_of_dvd_of_pos h (by grind)
109-
have : 0 < c := Nat.pos_of_dvd_of_pos h' (by grind)
110-
rw [Nat.div_eq_iff_eq_mul_left]
111-
· rw [Nat.mul_assoc, ← Nat.mul_div_assoc, Nat.mul_div_cancel_left, Nat.div_mul_cancel]
112-
all_goals assumption
113-
· have : c ≤ b := Nat.le_of_dvd ‹_› ‹_›
114-
simp only [Nat.div_pos_iff]
115-
grind
116-
· refine Nat.dvd_trans ?_ h
117-
apply Nat.div_dvd_of_dvd
118-
assumption
119-
grind [hp.dvd_mul_iff]
122+
grind [hp.dvd_mul_iff, Nat.div_div_eq_div_mul']
120123
· grind
121124
· grind
122125

126+
/--
127+
Main theorem: `largestPrimeFactor n` is prime and maximal.
128+
Even though the problem description does not require it, we also prove this statement for
129+
`n` prime.
130+
131+
The loop invariant tracks that `factor` divides `n`, all prime divisors of `m` are ≥ the current
132+
trial divisor, and `factor` is the largest prime factor found so far among those already divided
133+
out. -/
123134
theorem isPrime_largestPrimeFactor (h : 1 < n) :
124135
IsPrime (largestPrimeFactor n) ∧ ∀ d : Nat, d ∣ n → IsPrime d → d ≤ (largestPrimeFactor n) := by
125136
generalize hwp : largestPrimeFactor n = wp
126137
apply Id.of_wp_run_eq hwp
127138
mvcgen
128139
invariants
129140
· .withEarlyReturn
130-
(fun cur ⟨m, factor⟩ =>
131-
let i := cur.pos + 2;
132-
factor < i ∧
133-
m.val ∣ n ∧
134-
(if m.val = n then factor = 1 else IsPrime factor ∧ ∀ e : Nat, e ∣ n / m → IsPrime e → e ≤ factor) ∧
135-
∀ e : Nat, e ∣ m → e = 1 ∨ i ≤ e⌝)
141+
(fun cur ⟨m, mostRecentFactor⟩ =>
142+
let i := cur.pos + 2; -- loop variable
143+
-- At the beginning of the loop, the `mostRecentFactor` variable is less than the loop variable.
144+
mostRecentFactor < i ∧
145+
-- The `m` variable is a divisor of `n`.
146+
m.val ∣ n ∧
147+
-- Except if `m = n`, `mostRecentFactor` is the largest prime factor of `n / m`.
148+
(if m.val = n then
149+
mostRecentFactor = 1
150+
else
151+
IsPrime mostRecentFactor ∧ ∀ e : Nat, e ∣ n / m → IsPrime e → e ≤ mostRecentFactor) ∧
152+
-- Every nontrivial divisor of `m` is at least as large as the loop variable.
153+
∀ e : Nat, e ∣ m → e = 1 ∨ i ≤ e⌝)
136154
(fun ret ⟨m, factor⟩ => ⌜IsPrime ret ∧ ∀ d : Nat, d ∣ n → IsPrime d → d ≤ ret⌝)
137155
case vc1 pref cur suf _ _ _ m _ _ _ ih =>
138156
simp only [reduceCtorEq, false_and, exists_false, or_false]
@@ -166,7 +184,7 @@ theorem isPrime_largestPrimeFactor (h : 1 < n) :
166184
cases he
167185
· grind
168186
· exact Nat.le_of_dvd (by grind) ‹_›
169-
· simp at *
187+
· simp only [List.Cursor.pos_mk, reduceCtorEq, false_and, and_false, exists_const, or_false] at *
170188
intro e he
171189
have : e ≠ cur := by grind [not_dvd_dividePower]
172190
replace ih := ih.2.2.2.2 e
@@ -193,8 +211,9 @@ theorem isPrime_largestPrimeFactor (h : 1 < n) :
193211
have : 0 < e := Nat.pos_of_dvd_of_pos he ‹0 < n›
194212
grind
195213
case vc5 r _ ih =>
196-
simp at *
197-
simp_all
214+
simp only [List.Cursor.pos_mk, Rcc.length_toList, Nat.size_rcc, Nat.reduceSubDiff,
215+
true_and] at *
216+
simp_all only [true_and, reduceCtorEq, false_and, exists_const, or_false]
198217
have := ih.2.2.2 _ (Nat.dvd_refl _)
199218
have : r.2.1.val ≤ n := Nat.le_of_dvd ‹0 < n› ih.2.1
200219
have : r.2.1.val = 1 := by grind
@@ -204,7 +223,8 @@ theorem isPrime_largestPrimeFactor (h : 1 < n) :
204223
case vc7 => grind
205224
-- Early return verification conditions:
206225
case vc3 pref cur suff _ _ _ m _ hlt ih =>
207-
simp_all
226+
simp_all only [Nat.not_le, List.Cursor.pos_mk, reduceCtorEq, false_and, and_false, exists_const,
227+
or_false, Option.some.injEq, true_and, exists_eq_left', false_or]
208228
rw [max_eq_if]
209229
split
210230
· constructor

0 commit comments

Comments
 (0)