Skip to content

Commit c0c4b5e

Browse files
authored
127 (#215)
This solves problem 127.
1 parent 721e684 commit c0c4b5e

File tree

3 files changed

+229
-69
lines changed

3 files changed

+229
-69
lines changed

HumanEvalLean/Common/IsPrime.lean

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
module
2+
3+
import Std.Data.Iterators
4+
import Std.Tactic.Do
5+
6+
open Std
7+
8+
public def isPrime (n : Nat) : Bool :=
9+
let divisors := (2...<n).iter.takeWhile (fun i => i * i ≤ n) |>.filter (· ∣ n)
10+
2 ≤ n ∧ divisors.fold (init := 0) (fun count _ => count + 1) = 0
11+
12+
public def IsPrime (n : Nat) : Prop :=
13+
2 ≤ n ∧ ∀ d : Nat, d ∣ n → d = 1 ∨ d = n
14+
15+
public theorem isPrime_iff {n : Nat} :
16+
IsPrime n ↔ (2 ≤ n ∧ ∀ d : Nat, d ∣ n → d = 1 ∨ d = n) :=
17+
Iff.rfl
18+
19+
public theorem two_le_of_isPrime {n : Nat} (h : IsPrime n) :
20+
2 ≤ n := by
21+
grind [isPrime_iff]
22+
23+
public theorem isPrime_eq_true_iff {n : Nat} :
24+
isPrime n = true2 ≤ n ∧
25+
(List.filter (· ∣ n) (List.takeWhile (fun i => i * i ≤ n) (2...n).toList)).length = 0 := by
26+
simp [isPrime, ← Iter.foldl_toList]
27+
28+
public theorem isPrime_iff_mul_self {n : Nat} :
29+
IsPrime n ↔ (2 ≤ n ∧ ∀ (a : Nat), 2 ≤ a ∧ a < n → a ∣ n → n < a * a) := by
30+
rw [IsPrime]
31+
by_cases hn : 2 ≤ n; rotate_left; grind
32+
apply Iff.intro
33+
· grind
34+
· rintro ⟨hn, h⟩
35+
refine ⟨hn, fun d hd => ?_⟩
36+
have : 0 < d := Nat.pos_of_dvd_of_pos hd (by grind)
37+
have : d ≤ n := Nat.le_of_dvd (by grind) hd
38+
false_or_by_contra
39+
by_cases hsq : d * d ≤ n
40+
· specialize h d
41+
grind
42+
· replace h := h (n / d) ?_ ?_; rotate_left
43+
· have : d ≥ 2 := by grind
44+
refine ⟨?_, Nat.div_lt_self (n := n) (k := d) (by grind) (by grind)⟩
45+
false_or_by_contra; rename_i hc
46+
have : n / d * d ≤ 1 * d := Nat.mul_le_mul_right d (Nat.le_of_lt_succ (Nat.lt_of_not_ge hc))
47+
grind [Nat.dvd_iff_div_mul_eq]
48+
· exact Nat.div_dvd_of_dvd hd
49+
simp only [Nat.not_le] at hsq
50+
have := Nat.mul_lt_mul_of_lt_of_lt h hsq
51+
replace : n * n < ((n / d) * d) * ((n / d) * d) := by grind
52+
rw [Nat.dvd_iff_div_mul_eq] at hd
53+
rw [hd] at this
54+
grind
55+
56+
theorem List.takeWhile_eq_filter {P : α → Bool} {xs : List α}
57+
(h : xs.Pairwise (fun x y => P y → P x)) :
58+
xs.takeWhile P = xs.filter P := by
59+
induction xs with
60+
| nil => simp
61+
| cons x xs ih =>
62+
simp only [takeWhile_cons, filter_cons]
63+
simp only [pairwise_cons] at h
64+
split
65+
· simp [*]
66+
· simpa [*] using h
67+
68+
public theorem isPrime_eq_true_iff_isPrime {n : Nat} :
69+
isPrime n ↔ IsPrime n := by
70+
simp only [isPrime_eq_true_iff]
71+
by_cases hn : 2 ≤ n; rotate_left
72+
· grind [IsPrime]
73+
rw [List.takeWhile_eq_filter]; rotate_left
74+
· apply Std.Rco.pairwise_toList_le.imp
75+
intro a b hab hb
76+
have := Nat.mul_self_le_mul_self hab
77+
grind
78+
-- `mem_toList_iff_mem` and `mem_iff` should be simp lemmas
79+
simp [hn, isPrime_iff_mul_self, Std.Rco.mem_toList_iff_mem, Std.Rco.mem_iff]

HumanEvalLean/HumanEval127.lean

Lines changed: 145 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,146 @@
1-
def intersection : Unit :=
2-
()
1+
module
2+
3+
import HumanEvalLean.Common.IsPrime
4+
meta import HumanEvalLean.Common.IsPrime -- for `native_decide`
5+
6+
/-!
7+
## Implementation
8+
-/
9+
10+
def intersection (p : Int × Int) (q : Int × Int) : String :=
11+
let l := max p.1 q.1
12+
let r := min p.2 q.2
13+
let length := r - l
14+
if length > 0 ∧ isPrime length.toNat then "YES" else "NO"
15+
16+
/-!
17+
## Tests
18+
-/
19+
20+
example : intersection (1, 2) (2, 3) = "NO" := by native_decide
21+
example : intersection (-1, 1) (0, 4) = "NO" := by native_decide
22+
example : intersection (-3, -1) (-5, 5) = "YES" := by native_decide
23+
example : intersection (-2, 2) (-4, 0) = "YES" := by native_decide
24+
example : intersection (-11, 2) (-1, -1) = "NO" := by native_decide
25+
example : intersection (1, 2) (3, 5) = "NO" := by native_decide
26+
example : intersection (1, 2) (1, 2) = "NO" := by native_decide
27+
example : intersection (-2, -2) (-3, -2) = "NO" := by native_decide
28+
29+
/-!
30+
## Missing API
31+
-/
32+
33+
-- stolen from Init.Data.Range.Polymorphic.Lemmas, which is private
34+
private theorem eq_of_pairwise_lt_of_mem_iff_mem {lt : α → α → Prop} [asymm : Std.Asymm lt]
35+
{l l' : List α} (hl : l.Pairwise lt) (hl' : l'.Pairwise lt)
36+
(h : ∀ a, a ∈ l ↔ a ∈ l') : l = l' := by
37+
induction l generalizing l'
38+
· cases l'
39+
· rfl
40+
· rename_i x xs
41+
specialize h x
42+
simp at h
43+
· rename_i x xs ih
44+
cases l'
45+
· specialize h x
46+
simp at h
47+
· have hx := (h x).mp (List.mem_cons_self)
48+
cases List.mem_cons.mp hx
49+
· rename_i y ys heq
50+
cases heq
51+
simp only [List.cons.injEq, true_and]
52+
apply ih hl.tail hl'.tail
53+
intro a
54+
specialize h a
55+
constructor
56+
· intro haxs
57+
replace h := h.mp (List.mem_cons_of_mem _ haxs)
58+
cases List.mem_cons.mp h
59+
· rename_i heq
60+
cases heq
61+
simp only [List.pairwise_cons] at hl
62+
have := hl.1 x haxs
63+
cases Std.Asymm.asymm _ _ this this
64+
· simp [*]
65+
· intro hays
66+
replace h := h.mpr (List.mem_cons_of_mem _ hays)
67+
cases List.mem_cons.mp h
68+
· rename_i heq
69+
cases heq
70+
simp only [List.pairwise_cons] at hl'
71+
have := hl'.1 x hays
72+
cases Std.Asymm.asymm _ _ this this
73+
· simp [*]
74+
· rename_i y ys hx
75+
simp only [List.pairwise_cons] at hl'
76+
have hlt := hl'.1 _ hx
77+
have hmem : y ∈ x :: xs := (h y).mpr List.mem_cons_self
78+
cases List.mem_cons.mp hmem
79+
· rename_i heq
80+
cases heq
81+
cases Std.Asymm.asymm _ _ hlt hlt
82+
· simp only [List.pairwise_cons] at hl
83+
have hgt := hl.1 y ‹_›
84+
cases Std.Asymm.asymm _ _ hlt hgt
85+
86+
deriving instance DecidableEq for Std.Rcc
87+
88+
/-!
89+
## Verification
90+
-/
91+
92+
theorem intersection_swap {p q} :
93+
intersection p q = intersection q p := by
94+
grind [intersection]
95+
96+
theorem intersection_mem {p q} :
97+
intersection p q ∈ ["YES", "NO"] := by
98+
grind [intersection]
99+
100+
/--
101+
According to the problem description, the length of a range is the difference of its bounds.
102+
Caution: This is different from the size of the range, a.k.a. `r.size` and `r.toList.length`.
103+
-/
104+
def intervalLength (r : Std.Rcc Int) : Nat :=
105+
(r.upper - r.lower).toNat
106+
107+
example : intervalLength (2...=3) = 1 := by decide -- example from the problem description
108+
example : intervalLength (2...=2) = 0 := by decide
109+
example : intervalLength (5...=0) = 0 := by decide
110+
111+
section IntervalIntersection
112+
113+
def intervalIntersection (r s : Std.Rcc Int) : Std.Rcc Int :=
114+
(max r.lower s.lower)...=(min r.upper s.upper)
115+
116+
example : intervalIntersection (1...=3) (2...=4) = (2...=3) := by native_decide
117+
118+
/-! The following three lemmas justify the name `intervalIntersection`. -/
119+
120+
theorem mem_intervalIntersection_iff {l₁ r₁ l₂ r₂ x} :
121+
x ∈ intervalIntersection (l₁...=r₁) (l₂...=r₂) ↔ x ∈ (l₁...=r₁) ∧ x ∈ (l₂...=r₂) := by
122+
grind [intervalIntersection, Std.Rcc.mem_iff]
123+
124+
theorem intervalIntersection_swap {r s} :
125+
intervalIntersection r s = intervalIntersection s r := by
126+
grind [intervalIntersection]
127+
128+
theorem toList_intervalIntersection_eq_filter_mem_rcc_toList_rcc {l₁ r₁ l₂ r₂} :
129+
(intervalIntersection (l₁...=r₁) (l₂...=r₂)).toList = (l₁...=r₁).toList.filter (· ∈ l₂...=r₂) := by
130+
apply eq_of_pairwise_lt_of_mem_iff_mem (lt := LT.lt)
131+
· apply Std.Rcc.pairwise_toList_lt
132+
· apply List.Pairwise.filter
133+
apply Std.Rcc.pairwise_toList_lt
134+
· grind [mem_intervalIntersection_iff, Std.Rcc.mem_toList_iff_mem]
135+
136+
end IntervalIntersection
137+
138+
theorem intersection_spec {p q} :
139+
intersection p q = "YES" ↔ IsPrime (intervalLength (intervalIntersection (p.1...=p.2) (q.1...=q.2))) := by
140+
simp only [intersection, isPrime_eq_true_iff_isPrime, ite_eq_left_iff]
141+
suffices h : (min p.2 q.2 - max p.1 q.1).toNat = intervalLength (intervalIntersection (p.1...=p.2) (q.1...=q.2)) by
142+
grind [isPrime_iff]
143+
grind [intervalLength, intervalIntersection]
3144

4145
/-!
5146
## Prompt
@@ -12,7 +153,7 @@ def intersection(interval1, interval2):
12153
The given intervals are closed which means that the interval (start, end)
13154
includes both start and end.
14155
For each given interval, it is assumed that its start is less or equal its end.
15-
Your task is to determine whether the length of intersection of these two
156+
Your task is to determine whether the length of intersection of these two
16157
intervals is a prime number.
17158
Example, the intersection of the intervals (1, 3), (2, 4) is (2, 3)
18159
which its length is 1, which not a prime number.
@@ -67,4 +208,4 @@ def check(candidate):
67208
assert candidate((-2, -2), (-3, -2)) == "NO"
68209
69210
```
70-
-/
211+
-/

HumanEvalLean/HumanEval150.lean

Lines changed: 5 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1+
module
2+
13
import Std.Data.Iterators
24
import Init.Notation
35
import Std.Tactic.Do
46

7+
import HumanEvalLean.Common.IsPrime
8+
meta import HumanEvalLean.Common.IsPrime -- for `native_decide`
9+
510
open Std
611

712
set_option mvcgen.warning false
@@ -10,10 +15,6 @@ set_option mvcgen.warning false
1015
## Implementation
1116
-/
1217

13-
def isPrime (n : Nat) : Bool :=
14-
let divisors := (2...<n).iter.takeWhile (fun i => i * i ≤ n) |>.filter (· ∣ n)
15-
2 ≤ n ∧ divisors.fold (init := 0) (fun count _ => count + 1) = 0
16-
1718
def x_or_y (n : Int) (x y : α) : α := Id.run do
1819
let some n := n.toNat? | return y
1920
if isPrime n then
@@ -43,71 +44,10 @@ example : x_or_y 2 2 0 = 2 := by native_decide
4344
## Verification
4445
-/
4546

46-
def IsPrime (n : Nat) : Prop :=
47-
2 ≤ n ∧ ∀ d : Nat, d ∣ n → d = 1 ∨ d = n
48-
49-
theorem isPrime_eq_true_iff {n : Nat} :
50-
isPrime n = true2 ≤ n ∧
51-
(List.filter (· ∣ n) (List.takeWhile (fun i => i * i ≤ n) (2...n).toList)).length = 0 := by
52-
simp [isPrime, ← Iter.foldl_toList]
53-
5447
example {n d : Nat} (h : n / d * d = n) (h' : n * n < n / d * d * (n / d * d)) : False := by
5548
rw [h] at h' -- Why do we need this?
5649
grind
5750

58-
theorem isPrime_iff_mul_self {n : Nat} :
59-
IsPrime n ↔ (2 ≤ n ∧ ∀ (a : Nat), 2 ≤ a ∧ a < n → a ∣ n → n < a * a) := by
60-
rw [IsPrime]
61-
by_cases hn : 2 ≤ n; rotate_left; grind
62-
apply Iff.intro
63-
· grind
64-
· rintro ⟨hn, h⟩
65-
refine ⟨hn, fun d hd => ?_⟩
66-
have : 0 < d := Nat.pos_of_dvd_of_pos hd (by grind)
67-
have : d ≤ n := Nat.le_of_dvd (by grind) hd
68-
false_or_by_contra
69-
by_cases hsq : d * d ≤ n
70-
· specialize h d
71-
grind
72-
· replace h := h (n / d) ?_ ?_; rotate_left
73-
· have : d ≥ 2 := by grind
74-
refine ⟨?_, Nat.div_lt_self (n := n) (k := d) (by grind) (by grind)⟩
75-
false_or_by_contra; rename_i hc
76-
have : n / d * d ≤ 1 * d := Nat.mul_le_mul_right d (Nat.le_of_lt_succ (Nat.lt_of_not_ge hc))
77-
grind [Nat.dvd_iff_div_mul_eq]
78-
· exact Nat.div_dvd_of_dvd hd
79-
simp only [Nat.not_le] at hsq
80-
have := Nat.mul_lt_mul_of_lt_of_lt h hsq
81-
replace : n * n < ((n / d) * d) * ((n / d) * d) := by grind
82-
rw [Nat.dvd_iff_div_mul_eq] at hd
83-
rw [hd] at this
84-
grind
85-
86-
theorem List.takeWhile_eq_filter {P : α → Bool} {xs : List α}
87-
(h : xs.Pairwise (fun x y => P y → P x)) :
88-
xs.takeWhile P = xs.filter P := by
89-
induction xs with
90-
| nil => simp
91-
| cons x xs ih =>
92-
simp only [takeWhile_cons, filter_cons]
93-
simp only [pairwise_cons] at h
94-
split
95-
· simp [*]
96-
· simpa [*] using h
97-
98-
theorem isPrime_eq_true_iff_isPrime {n : Nat} :
99-
isPrime n ↔ IsPrime n := by
100-
simp only [isPrime_eq_true_iff]
101-
by_cases hn : 2 ≤ n; rotate_left
102-
· grind [IsPrime]
103-
rw [List.takeWhile_eq_filter]; rotate_left
104-
· apply Std.Rco.pairwise_toList_le.imp
105-
intro a b hab hb
106-
have := Nat.mul_self_le_mul_self hab
107-
grind
108-
-- `mem_toList_iff_mem` and `mem_iff` should be simp lemmas
109-
simp [hn, isPrime_iff_mul_self, Std.Rco.mem_toList_iff_mem, Std.Rco.mem_iff]
110-
11151
open Classical in
11252
theorem x_or_y_of_isPrime {n : Int} {x y : α} :
11353
x_or_y n x y = if n ≥ 0 ∧ IsPrime n.toNat then x else y := by

0 commit comments

Comments
 (0)