Zulip Chat Archive
Stream: Program verification
Topic: Proving termination/correctness of KMP helper
Clarence Chew (Jan 27 2024 at 12:53):
I'm trying out Lean4 so I'm proving some stuff as practice. I'm trying to implementing KMP, but for now it's just the function that calculates how much to jump forward while string searching. Below is what I tried.
/-
Implementation details:
(boundary W i) gives the length of the longest prefix which is also a proper suffix of W[0:i].
(boundary W 0) is defined to be -1
Note that (boundary W i) >= (boundary W (i-1)) + 1
(boundary helper W i j) gives the length of the longest prefix which is also a proper suffix of W[0:i],
given that
- j is the length of some prefix which is also a suffix of W[0:i-1]
- we tried extending all prefixes which are also suffixes of W[0:i-1], longer than j, and it didn't work
(boundary W 0) is defined to be -1
(boundary W 1) is calculatable as 0
-/
mutual
def boundary (W : String) (i : Nat) (h : i ≤ W.length) : Int :=
have boundary_zero_eq_neg_one (W : String) : (boundary W Nat.zero (Nat.zero_le W.length)) + 1 = 0 := by
-- boundary.casesOn
sorry
have boundary_loop_inv (W : String) (i : Nat) (h : i ≤ W.length) : (boundary W i h) + 1 ≤ i := by
/- induction' i with zero succ
rw [boundary_zero_eq_neg_one W]
linarith-/
sorry
/-have hyp : boundary W (Nat.succ a) h + 1 ≤ (Nat.succ a) := by
exact (ha h)-/
match i with
| Nat.zero => -1
| Nat.succ k => Id.run do {
have boundary_hyp : k ≤ W.length := by
linarith
have boundary_helper_hyp : (boundary W k boundary_hyp) + 2 ≤ Int.ofNat (Nat.succ k) := by
have hyp : (boundary W k boundary_hyp) + 2 ≤ k + 1 := by
have hyp : (boundary W k boundary_hyp) + 1 ≤ k := by
exact (boundary_loop_inv W k boundary_hyp)
linarith
have hyp2 : Int.ofNat k + 1 ≤ Int.ofNat (Nat.succ k) := by
sorry
exact (le_trans hyp hyp2)
boundary_helper W (Nat.succ k) h (boundary W k boundary_hyp) boundary_helper_hyp
}
def boundary_helper (W : String) (i : Nat) (h : i ≤ W.length) (j : Int) (hj : j + 2 ≤ i) : Int :=
match j, (W.take (i-1) == W.take (Int.toNat j)) with
| Int.negSucc _, _ => 0
| _, true => j+1
| Int.ofNat k, false => Id.run do {
have hyp : k ≤ W.length := by
sorry
have boundary_helper_hyp : (boundary W k hyp) + 2 ≤ i := by
sorry
boundary_helper W i h (boundary W k hyp) boundary_helper_hyp
}
end
termination_by
boundary W i h => (i, i)
boundary_helper W i h j hj => (i, Int.toNat (j + 1))
decreasing_by
simp_wf
have hyp : 0 ≤ i := by
exact (Nat.zero_le i)
/-have termination_hyp1 (k : Nat) : (k, k) < (Nat.succ k, Nat.succ k) := by
sorry
have termination_hyp2 : (Nat.succ k, Int.toNat (boundary W k boundary_hyp)) < (Nat.succ k, Nat.succ k) := by
sorry
have termination_hyp3 : (boundary W k hyp) + 1 ≤ k := by
sorry-/
sorry
I tried running the definition with
lemma h : (4 ≤ "123123123".length) := by sorry
#eval boundary "123123123" 4 h
expected value: 1, actual value: 0
Also, in the decreasing_by block I'm getting a goal of the following (Prod.Lex):
image.png
I'm confused because I'm not sure why Lean is getting me to prove (0, 0) < (i, i). It's false because i could be 0.
Clarence Chew (Jan 29 2024 at 09:42):
Update: I rewrote it in this form, it seems more promising to prove the required results to demonstrate termination.
def boundary (W : String) (i : Nat) (h : i ≤ W.length) : Int :=
...
where boundary_helper (W : String) (i : Nat) (h : i ≤ W.length) (j : Int) (hj : j + 2 ≤ i) : Int :=
...
termination_by
...
decreasing_by
...
Last updated: May 02 2025 at 03:31 UTC