-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
-
13
-
14
-
15
-
16
-
17
-
18
-
19
-
20
-
21
-
22
-
23
-
24
-
25
-
26
-
27
-
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
-
37
-
38
-
39
-
40
-
41
-
42
-
43
-
44
-
45
-
46
-
47
-
48
-
49
-
50
-
51
-
52
-
53
-
54
-
55
-
56
-
57
-
58
-
59
-
60
-
61
-
62
-
63
-
64
-
65
-
66
-
67
-
68
-
69
-
70
-
71
-
72
-
73
-
74
-
75
-
76
-
77
-
78
-
79
-
80
-
81
-
82
-
83
-
84
-
85
-
86
-
87
-
88
import Std.Tactic.Do
import Batteries.Data.Array.Pairwise
import Mathlib.Data.Nat.Basic
-- Specify universe for α to avoid
-- https://github.com/leanprover/lean4/pull/10865
variable {α : Type} [LinearOrder α] (A : Array α)
def BubbleSort := Id.run do
let N := A.size
let mut A := A.toVector
for i in List.range (N - 1) do
for hj : j in List.range (N - i - 1) do
have := List.mem_range.mp hj
if A[j + 1] < A[j] then
A := A.swap j (j + 1)
return A.toArray
def ICan'tBelieveItCanSort := Id.run do
let N := A.size
let mut A := A.toVector
for hi : i in [:N] do
for hj : j in [:N] do
if A[i] < A[j] then
A := A.swap i j
return A.toArray
#guard let A := #[69, 420, 1, 1, 13, 1, 65536]
ICan'tBelieveItCanSort A = A.qsort
open Std.Do
-- https://leanprover.zulipchat.com/#narrow/channel/113489-new-members/topic/mvcgen.20doesn't.20produce.20any.20invariant.20goals/near/557949517
theorem perm : ICan'tBelieveItCanSort A |>.Perm A := by
generalize h : ICan'tBelieveItCanSort A = x
apply Id.of_wp_run_eq h
mvcgen invariants
· ⇓⟨_, A'⟩ => ⌜Array.Perm A A'.toArray⌝
· ⇓⟨_, A'⟩ => ⌜Array.Perm A A'.toArray⌝
with grind [Array.Perm.trans, Array.Perm.symm, Array.swap_perm]
theorem sorted : ICan'tBelieveItCanSort A |>.Pairwise (· ≤ ·) := by
generalize h : ICan'tBelieveItCanSort A = x
apply Id.of_wp_run_eq h
mvcgen <;> expose_names
case inv1 => exact ⇓⟨xs, A'⟩ => ⌜A'.take xs.pos |>.toArray.Pairwise (· ≤ ·)⌝
case inv2 =>
exact ⇓⟨xs, A'⟩ => ⌜(A'.take cur).toArray.Pairwise (· ≤ ·) ∧ ∀ i (_ : i < xs.pos), A'[i]'(by
have : xs.prefix.length + xs.suffix.length = N := by simp [← List.length_append, xs.property]
grind
) ≤ A'[cur]'(by grind)⌝
case vc1.step.isTrue =>
simp_all
constructor
· rw [Array.pairwise_iff_getElem] at h_5 ⊢
grind
· grind
case vc2.step.isFalse => grind
case vc3.step.pre => grind
case vc4.step.post.success =>
simp_all
rw [Array.pairwise_iff_getElem] at h_3 ⊢
grind
case vc5.a.pre => grind
case vc6.a.post.success =>
simp_all
exact (show r.toArray = r.toArray.extract 0 N by grind) ▸ h_1
theorem ICan'tBelieveICanProveItCanSort : (ICan'tBelieveItCanSort A).Perm A
∧ (ICan'tBelieveItCanSort A).Pairwise (· ≤ ·) :=
⟨perm A, sorted A⟩
-- Not sure why this needs so much boilerplate
abbrev le (a b : (ℕ × String)) := a.1 > b.1 ∨ (a.1 = b.1 ∧ a.2 ≤ b.2)
instance : LE (ℕ × String) where le := le
@[grind]
lemma le_def {a b : (ℕ × String)} : a ≤ b ↔ le a b := .rfl
instance : LinearOrder (ℕ × String) where
le_refl := by grind
le_trans := by grind
le_antisymm := by grind
le_total := by grind
toDecidableLE a b := inferInstanceAs <| Decidable <| le a b
#eval ICan'tBelieveItCanSort #[(69, "hi"), (1729, "blah"), (13, "a"), (420, "a"), (420, "meow")]