Skip to content

Commit 688143d

Browse files
authored
126 using mvcgen (#214)
This PR solves problem 126.
1 parent 0c03fd8 commit 688143d

File tree

1 file changed

+181
-7
lines changed

1 file changed

+181
-7
lines changed

HumanEvalLean/HumanEval126.lean

Lines changed: 181 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,179 @@
1-
def is_sorted : Unit :=
2-
()
1+
module
2+
3+
import Std
4+
open Std Std.Do
5+
6+
set_option mvcgen.warning false
7+
8+
/-!
9+
## Implementation
10+
-/
11+
12+
def isSorted (xs : Array Nat) : Bool := Id.run do
13+
if h : xs.size > 0 then
14+
let mut last := xs[0]
15+
let mut repeated := false
16+
for x in xs[1...*] do
17+
match compare last x with
18+
| .lt =>
19+
last := x
20+
repeated := false
21+
| .eq =>
22+
if repeated then
23+
return false
24+
else
25+
repeated := true
26+
| .gt =>
27+
return false
28+
return true
29+
30+
/-!
31+
## Tests
32+
-/
33+
34+
example : isSorted #[5] = true := by native_decide
35+
example : isSorted #[1, 2, 3, 4, 5] = true := by native_decide
36+
example : isSorted #[1, 3, 2, 4, 5] = false := by native_decide
37+
example : isSorted #[1, 2, 3, 4, 5, 6] = true := by native_decide
38+
example : isSorted #[1, 2, 3, 4, 5, 6, 7] = true := by native_decide
39+
example : isSorted #[1, 3, 2, 4, 5, 6, 7] = false := by native_decide
40+
example : isSorted #[] = true := by native_decide
41+
example : isSorted #[1] = true := by native_decide
42+
example : isSorted #[3, 2, 1] = false := by native_decide
43+
example : isSorted #[1, 2, 2, 2, 3, 4] = false := by native_decide
44+
example : isSorted #[1, 2, 3, 3, 3, 4] = false := by native_decide
45+
example : isSorted #[1, 2, 2, 3, 3, 4] = true := by native_decide
46+
example : isSorted #[1, 2, 3, 4] = true := by native_decide
47+
48+
/-!
49+
## Missing API
50+
-/
51+
52+
instance : LawfulOrderOrd Nat where
53+
isLE_compare := by grind [Nat.isLE_compare]
54+
isGE_compare := by grind [Nat.isGE_compare]
55+
56+
attribute [- grind] Array.mkSlice_rci_eq_mkSlice_rco
57+
attribute [grind =] Array.toList_mkSlice_rci
58+
attribute [grind .] List.Pairwise.nil
59+
60+
grind_pattern compare_eq_lt => compare a b, Ordering.lt where
61+
guard compare a b = .lt
62+
63+
grind_pattern compare_eq_eq => compare a b, Ordering.eq where
64+
guard compare a b = .eq
65+
66+
grind_pattern compare_eq_gt => compare a b, Ordering.gt where
67+
guard compare a b = .gt
68+
69+
/-!
70+
## Verification
71+
-/
72+
73+
theorem pairwise_append_of_trans {xs ys : List α} {R : α → α → Prop} [Trans R R R] :
74+
(xs ++ ys).Pairwise R ↔ xs.Pairwise R ∧ ys.Pairwise R ∧ (∀ (hxs : xs ≠ []) (hys : ys ≠ []), R (xs.getLast hxs) (ys.head hys)) := by
75+
rw [List.pairwise_append]
76+
apply Iff.intro
77+
· grind
78+
· rintro ⟨hpxs, hpys, h⟩
79+
refine ⟨hpxs, hpys, fun x hx y hy => ?_⟩
80+
rw [List.pairwise_iff_getElem] at hpxs hpys
81+
specialize h (by grind) (by grind)
82+
simp only [List.getLast_eq_getElem, List.head_eq_getElem] at h
83+
rw [List.mem_iff_getElem] at hx hy
84+
obtain ⟨i, hi, rfl⟩ := hx
85+
obtain ⟨j, hj, rfl⟩ := hy
86+
have h₁ : i < xs.length - 1 → R xs[i] xs[xs.length - 1] := by grind
87+
have h₂ : 0 < j → R ys[0] ys[j] := by grind
88+
by_cases hi' : i = xs.length - 1 <;> by_cases hj' : j = 0
89+
· grind
90+
· exact Trans.trans (r := R) (by grind) (h₂ (by grind))
91+
· exact Trans.trans (s := R) (h₁ (by grind)) (by grind)
92+
· exact Trans.trans (h₁ (by grind)) (Trans.trans h (h₂ (by grind)))
93+
94+
theorem pairwise_cons_of_trans {x : α} {xs : List α} {R : α → α → Prop} [Trans R R R] :
95+
(x :: xs).Pairwise R ↔ (∀ (hxs : xs ≠ []), R x (xs.head hxs)) ∧ xs.Pairwise R := by
96+
have := pairwise_append_of_trans (R := R) (xs := [x]) (ys := xs)
97+
grind
98+
99+
theorem sorted_of_isSorted {xs : Array Nat} (h : isSorted xs) : xs.toList.Pairwise (· ≤ ·) := by
100+
revert h -- Without reverting, we will not be able to use that the return value is `true` to show
101+
--that early returns cannot happen.
102+
generalize hwp : isSorted xs = wp
103+
rw [← Array.toArray_toList (xs := xs)] at *
104+
generalize xs.toList = xs at *
105+
apply Id.of_wp_run_eq hwp
106+
mvcgen
107+
invariants
108+
| inv1 => .withEarlyReturn
109+
(fun cur ⟨last, _⟩ =>
110+
⌜(xs[0] :: cur.prefix).getLast? = some last ∧ (xs[0] :: cur.prefix).Pairwise (· ≤ ·)⌝)
111+
(fun ret _ => ⌜ret = false⌝)
112+
case vc1 =>
113+
simp only [pairwise_cons_of_trans, pairwise_append_of_trans] at *
114+
grind
115+
case vc3 =>
116+
simp only [pairwise_cons_of_trans, pairwise_append_of_trans] at *
117+
grind
118+
all_goals grind [List.getElem_zero, List.drop_one]
119+
120+
theorem count_le_two_of_isSorted {xs : Array Nat} {x : Nat} (h : isSorted xs) : xs.count x ≤ 2 := by
121+
have hp : xs.toList.Pairwise (· ≤ ·) := sorted_of_isSorted h
122+
rw [List.pairwise_iff_getElem] at hp
123+
revert h
124+
generalize hwp : isSorted xs = wp
125+
rw [← Array.toArray_toList (xs := xs)] at *
126+
generalize xs.toList = xs at *
127+
apply Id.of_wp_run_eq hwp
128+
mvcgen
129+
invariants
130+
| inv1 => .withEarlyReturn
131+
(fun cur ⟨last, repeated⟩ => ⌜(xs[0] :: cur.prefix).getLast? = some last ∧ (xs[0] :: cur.prefix).count x ≤ (if (last = x ∧ repeated) ∨ x < last then 2 else 1)⌝)
132+
(fun ret _ => ⌜ret = false⌝)
133+
case vc1 pref cur suff _ _ _ _ _ _ _ =>
134+
simp only [← List.cons_append]
135+
-- We generalize to simplify the problem.
136+
generalize hpref' : xs[0] :: pref = pref' at *
137+
have : xs = pref' ++ cur :: suff := by grind [List.getElem_zero, List.drop_one]
138+
clear hpref'
139+
simp only [List.count_append, List.count_singleton]
140+
have : ¬ cur ∈ pref' := by grind [List.mem_iff_getElem]
141+
split <;> grind [List.count_eq_zero]
142+
case vc6 a b c d e f =>
143+
grind [List.getElem_zero, List.drop_one]
144+
all_goals (clear hp; grind)
145+
146+
theorem not_pairwise_or_exists_count_of_isSorted_eq_false {xs : Array Nat} (h : isSorted xs = false) :
147+
¬ xs.toList.Pairwise (· ≤ ·) ∨ (∃ x, xs.count x ≥ 3) := by
148+
revert h
149+
generalize hwf : isSorted xs = wf
150+
rw [← Array.toArray_toList (xs := xs)] at *
151+
generalize xs.toList = xs at *
152+
apply Id.of_wp_run_eq hwf
153+
mvcgen
154+
invariants
155+
| inv1 => .withEarlyReturn
156+
(fun cur ⟨last, repeated⟩ => ⌜(xs[0] :: cur.prefix).getLast? = some last ∧ (repeated → (xs[0] :: cur.prefix).count last ≥ 2)⌝)
157+
(fun ret ⟨last, repeated⟩ => ⌜¬ xs.Pairwise (· ≤ ·) ∨ xs.count last ≥ 3⌝)
158+
case vc2 pref cur suff _ _ _ _ _ _ _ _ =>
159+
have : xs = xs[0] :: pref ++ cur :: suff := by grind [List.getElem_zero, List.drop_one]
160+
grind
161+
case vc4 pref cur suff _ _ _ last _ _ _ =>
162+
have : xs = xs[0] :: pref ++ cur :: suff := by grind [List.getElem_zero, List.drop_one]
163+
have : ∃ (i j : Nat), i < j ∧ ∃ hi, ∃ hj, (xs[j]'hj) < (xs[i]'hi) := ⟨pref.length, pref.length + 1, by grind⟩
164+
simp [List.pairwise_iff_getElem, this]
165+
case vc7 =>
166+
-- Because the `xs.toArray.count` call is under an `∃` binder in the goal, `grind`'s
167+
-- congruence closure is not able to use `List.count_toArray`.
168+
simp only [List.count_toArray] at *
169+
grind
170+
171+
all_goals grind
172+
173+
theorem isSorted_iff {xs : Array Nat} :
174+
isSorted xs ↔ xs.toList.Pairwise (· ≤ ·) ∧ ∀ x, xs.count x ≤ 2 := by
175+
grind [sorted_of_isSorted, count_le_two_of_isSorted,
176+
not_pairwise_or_exists_count_of_isSorted_eq_false]
3177

4178
/-!
5179
## Prompt
@@ -29,15 +203,15 @@ def is_sorted(lst):
29203
```python3
30204
count_digit = dict([(i, 0) for i in lst])
31205
for i in lst:
32-
count_digit[i]+=1
206+
count_digit[i]+=1
33207
if any(count_digit[i] > 2 for i in lst):
34208
return False
35209
if all(lst[i-1] <= lst[i] for i in range(1, len(lst))):
36210
return True
37211
else:
38212
return False
39-
40-
213+
214+
41215
```
42216
43217
## Tests
@@ -55,12 +229,12 @@ def check(candidate):
55229
assert candidate([]) == True, "This prints if this assert fails 2 (good for debugging!)"
56230
assert candidate([1]) == True, "This prints if this assert fails 3 (good for debugging!)"
57231
assert candidate([3, 2, 1]) == False, "This prints if this assert fails 4 (good for debugging!)"
58-
232+
59233
# Check some edge cases that are easy to work out by hand.
60234
assert candidate([1, 2, 2, 2, 3, 4]) == False, "This prints if this assert fails 5 (good for debugging!)"
61235
assert candidate([1, 2, 3, 3, 3, 4]) == False, "This prints if this assert fails 6 (good for debugging!)"
62236
assert candidate([1, 2, 2, 3, 3, 4]) == True, "This prints if this assert fails 7 (good for debugging!)"
63237
assert candidate([1, 2, 3, 4]) == True, "This prints if this assert fails 8 (good for debugging!)"
64238
65239
```
66-
-/
240+
-/

0 commit comments

Comments
 (0)