Skip to content
Browse chapters

Chapter 32 — String Matching

CLRS, fourth edition · Lean 4 formalization

The proofs below use the models and assumptions described in the scope and implementation notes.

Imports
import Mathlib

32.1. The Naive String-Matching Algorithm

This section defines the string/text model used throughout Chapter 32: string matching. A string is a list of elements drawn from an alphabet. We define the basic operations — length, prefix, suffix, and the corresponding predicates — that the finite-automaton and KMP constructions rely on.

The definitions are parameterized over the element type α; for concrete executability, instantiate α := Char or α := UInt8.

Key definitions

  • Text α: a string (alias for List α).

  • length: number of characters.

  • textPrefix t k: the first k characters of t.

  • suffix t k: the last k characters of t.

  • isPrefix p t: p is a prefix of t.

  • isSuffix p t: p is a suffix of t.

All operations are zero-indexed: the first character is at position 0, and taking a prefix of length 0 yields the empty list.

Implementation details

namespace CLRSnamespace Chapter32

A text (string) is a list of elements from an alphabet. Use α := Char for concrete text, or a generic α for abstract reasoning.

abbrev Text (α : Type) := List α
variable {α : Type}

The length of a text.

abbrev length (t : Text α) : ℕ := t.length

The prefix of t of length k. If k exceeds the text length, the result is the full text.

def textPrefix (t : Text α) (k : ℕ) : Text α := t.take k

The suffix of t of length k. If k exceeds the text length, the result is the full text.

def suffix (t : Text α) (k : ℕ) : Text α := t.drop (t.length - k)

p is a prefix of t.

def isPrefix (p t : Text α) : Prop := ∃ s, p ++ s = t

p is a suffix of t.

def isSuffix (p t : Text α) : Prop := ∃ s, s ++ p = t

p is a proper prefix of t: a prefix that is strictly shorter than t.

def isProperPrefix (p t : Text α) : Prop := isPrefix p t ∧ p.length < t.length

p is a proper suffix of t: a suffix that is strictly shorter than t.

def isProperSuffix (p t : Text α) : Prop := isSuffix p t ∧ p.length < t.length

The empty text is a prefix of every text.

theorem isPrefix_empty (t : Text α) : isPrefix [] t := ⟨t, by simp [This simp argument is unused: isPrefix Hint: Omit it from the simp argument list. simp ̵[̵i̵s̵P̵r̵e̵f̵i̵x̵]̵ Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`isPrefix]⟩

The empty text is a suffix of every text.

theorem isSuffix_empty (t : Text α) : isSuffix [] t := ⟨t, by simp [This simp argument is unused: isSuffix Hint: Omit it from the simp argument list. simp ̵[̵i̵s̵S̵u̵f̵f̵i̵x̵]̵ Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`isSuffix]⟩

Every text is a prefix of itself.

theorem isPrefix_self (t : Text α) : isPrefix t t := ⟨[], by simp [This simp argument is unused: isPrefix Hint: Omit it from the simp argument list. simp ̵[̵i̵s̵P̵r̵e̵f̵i̵x̵]̵ Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`isPrefix]⟩

Every text is a suffix of itself.

theorem isSuffix_self (t : Text α) : isSuffix t t := ⟨[], by simp [This simp argument is unused: isSuffix Hint: Omit it from the simp argument list. simp ̵[̵i̵s̵S̵u̵f̵f̵i̵x̵]̵ Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`isSuffix]⟩

If p is a prefix of t, then p.length ≤ t.length.

theorem isPrefix_length_le (hp : isPrefix p t) : p.length ≤ t.length := by rcases hp with ⟨s, h⟩ have := calc t.length = (p ++ s).length := by rw [h] _ = p.length + s.length := by simp omega

If p is a suffix of t, then p.length ≤ t.length.

theorem isSuffix_length_le (hp : isSuffix p t) : p.length ≤ t.length := by rcases hp with ⟨s, h⟩ have := calc t.length = (s ++ p).length := by rw [h] _ = s.length + p.length := by simp omega

The prefix of length 0 is the empty list.

@[simp] theorem textPrefix_zero (t : Text α) : textPrefix t 0 = [] := by simp [textPrefix]

Taking the prefix of length equal to the text length returns the whole text.

@[simp] theorem textPrefix_length (t : Text α) : textPrefix t t.length = t := by simp [textPrefix]

The suffix of length 0 is the empty list.

@[simp] theorem suffix_zero (t : Text α) : suffix t 0 = [] := by simp [suffix]

Taking the suffix of length equal to the text length returns the whole text.

@[simp] theorem suffix_length (t : Text α) : suffix t t.length = t := by simp [suffix]

The empty text has no non-empty prefix.

theorem textPrefix_nil_of_length_eq_zero (t : Text α) (h : length t = 0) (k : ℕ) : textPrefix t k = [] := by have : t = [] := by simpa [length] using h subst this; simp [textPrefix]

The empty text has no non-empty suffix.

theorem suffix_nil_of_length_eq_zero (t : Text α) (h : length t = 0) (k : ℕ) : suffix t k = [] := by have : t = [] := by simpa [length] using h subst this; simp [suffix]

textPrefix is a prefix of the original text.

theorem isPrefix_textPrefix (t : Text α) (k : ℕ) : isPrefix (textPrefix t k) t := by refine ⟨t.drop k, ?_⟩ simp [This simp argument is unused: isPrefix Hint: Omit it from the simp argument list. simp [i̵s̵P̵r̵e̵f̵i̵x̵,̵ ̵textPrefix, List.take_append_drop] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`isPrefix, textPrefix, List.take_append_drop]

suffix is a suffix of the original text.

theorem isSuffix_suffix (t : Text α) (k : ℕ) : isSuffix (suffix t k) t := by refine ⟨t.take (t.length - k), ?_⟩ simp [This simp argument is unused: isSuffix Hint: Omit it from the simp argument list. simp [̵i̵s̵S̵u̵f̵f̵i̵x̵,̵ ̵s̵u̵f̵f̵i̵x̵,̵[̲s̲u̲f̲f̲i̲x̲,̲ List.take_append_drop, add_comm] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`isSuffix, suffix, List.take_append_drop, This simp argument is unused: add_comm Hint: Omit it from the simp argument list. simp [isSuffix, suffix, List.take_append_drop,̵ ̵a̵d̵d̵_̵c̵o̵m̵m̵] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`add_comm]
end Chapter32end CLRS

Definitions and proofs

CLRSLean.FourthEdition.Chapter_32.Section_32_1_String_Model.Naive_Matcher

Section 32.1 — Naive String-Matching Algorithm

The naive string-matching algorithm (CLRS §32.1) finds all occurrences of a pattern P of length m in a text T of length n by trying every possible shift s = 0, 1, …, n-m and checking whether P matches T at that position. The worst-case running time is Θ((n-m+1)·m) = O(m·n).

Key definitions
  • matchesAt T P s — pattern P occurs in text T starting at shift s.

  • naiveMatcher T P — returns the list of all shifts where P occurs in T.

  • noMatch — convenience abbreviation for the empty match list.

Notation

This file uses Text α = List α from Section_32_1_String_Model and standard Nat-based lengths.

namespace CLRSnamespace Chapter32variable {α : Type} [BEq α] [DecidableEq α]

Pattern P matches text T at shift s: the substring of T from position s of length |P| equals P. Formally, (T.drop s).take |P| = P.

def matchesAt (T P : Text α) (s : ℕ) : Bool := if s + P.length ≤ T.length then (T.drop s).take P.length == P else false

The naive string matcher: enumerate all shifts s ∈ [0, n-m] and return those where the pattern matches.

def naiveMatcher (T P : Text α) : List ℕ := if P.length = 0 then List.range (T.length + 1) else let n := T.length let m := P.length let maxShift := n - m (List.range (maxShift + 1)).filter fun s => matchesAt T P s

Convenience abbreviation for "no match".

abbrev noMatch : List ℕ := []

If a shift s is in naiveMatcher T P, then matchesAt T P s is true.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_sound`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem naiveMatcher_sound (T P : Text α) (s : ℕ) (h : s ∈ naiveMatcher T P) : matchesAt T P s := by unfold naiveMatcher at h split at h · -- case: P.length = 0 rename_i hzero have hempty : P = [] := by cases P · rfl · simp at hzero subst hempty unfold matchesAt have hs : s ≤ T.length := by have := List.mem_range.mp h omega simp [hs] · -- case: P.length ≠ 0 have hmem := List.mem_filter.mp h exact hmem.2

If matchesAt T P s is true, then s is in naiveMatcher T P.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_complete`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem naiveMatcher_complete (T P : Text α) (s : ℕ) (hmatch : matchesAt T P s) : s ∈ naiveMatcher T P := by unfold naiveMatcher by_cases hzero : P.length = 0 · -- empty pattern: all shifts are included, need s ≤ T.length from hmatch have hempty : P = [] := by cases P · rfl · simp at hzero subst hempty unfold matchesAt at hmatch -- hmatch: (if s + 0 ≤ T.length then [] == [] else false) = true simp at hmatch -- hmatch now gives s ≤ T.length have hs : s < T.length + 1 := by omega simp [hs] · -- non-empty pattern have hbound : s + P.length ≤ T.length := by unfold matchesAt at hmatch split at hmatch · assumption · simp at hmatch have hshift : s ≤ T.length - P.length := by omega have hle : s < (T.length - P.length) + 1 := by omega have hmatch' : matchesAt T P s = true := hmatch simpa [hzero] using List.mem_filter.mpr ⟨List.mem_range.mpr hle, hmatch'⟩

The empty pattern matches at every position.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_empty`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_empty`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_empty`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` @[simp] automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_empty`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem naiveMatcher_empty (T : Text α) : naiveMatcher T [] = List.range (T.length + 1) := by unfold naiveMatcher; simp

If the pattern is longer than the text, there are no matches.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`Try `simp at h` instead of `simpa using h` Note: This linter can be disabled with `set_option linter.unnecessarySimpa false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.naiveMatcher_pattern_too_long`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem naiveMatcher_pattern_too_long (T P : Text α) (h : T.length < P.length) : naiveMatcher T P = noMatch := by unfold naiveMatcher noMatch by_cases hzero : P.length = 0 · -- P is empty, impossible because T.length < 0 would be contradiction have : T.length < 0 := by Try `simp at h` instead of `simpa using h` Note: This linter can be disabled with `set_option linter.unnecessarySimpa false`simpa [hzero] using h omega · have hsub : T.length - P.length = 0 := by omega simp [hzero, hsub] -- Need to show: filter (matchesAt T P) (range 1) = [] -- range 1 = [0], and matchesAt T P 0 = false because 0+P.length > T.length have hfalse : matchesAt T P 0 = false := by unfold matchesAt simp omega simp [hfalse]

Shifts returned by naiveMatcher are within bounds.

theorem naiveMatcher_shifts_valid (T P : Text α) (s : ℕ) (h : s ∈ naiveMatcher T P) : s + P.length ≤ T.length := by have hmatch := naiveMatcher_sound T P s h unfold matchesAt at hmatch split at hmatch · assumption · simp at hmatch
end Chapter32end CLRS
Imports

32.2. The Rabin–Karp Algorithm

The Rabin–Karp algorithm (CLRS §32.2) finds all occurrences of a pattern P in a text T by hashing the pattern and every |P|-length window of T, and comparing the hashes modulo q. A shift whose hash matches but whose string does not is a spurious hit: the algorithm rules it out with an explicit character-by-character comparison (matchesAt), so it remains correct for every choice of modulus.

Key definitions

  • hash d q val w — the base-d modular hash of w over the numeric values val c, computed by Horner's rule modulo q.

  • rabinKarpMatcher T P d q val — returns the list of all shifts where P occurs in T (hash match plus explicit comparison), mirroring naiveMatcher.

Main results

  • Theorem hash_snoc — the O(1) incremental update hash (w ++ [c]) = (hash w · d + val c) mod q.

  • Theorem hash_eq_of_text_eq — equal strings have equal hashes; hence a real match is never discarded as a spurious hit.

  • Theorem rabinKarp_sound — every shift returned by rabinKarpMatcher is a valid match.

  • Theorem rabinKarp_complete — every valid match is returned by rabinKarpMatcher.

  • Theorem rabinKarp_correct — rabinKarpMatcher agrees with naiveMatcher on every shift.

The CLRS window-slide recurrence (eq. (32.3)) is proved as hash_slide. rabinKarpRollingMatches_correct connects the rolling execution to the all-occurrences specification, while rabinKarpRollingCost_eq and rabinKarpRollingCost_le attach the deterministic work bound to that execution.

Notation conventions used in this section:

  • T : the text being searched

  • P : the pattern being searched for

  • d : the radix of the numeric alphabet

  • q : the modulus (CLRS assumes 0 < q)

  • val : assigns each alphabet symbol a numeric value in ℕ

namespace CLRSnamespace Chapter32variable {α : Type} [BEq α] [DecidableEq α] [LawfulBEq α]

The base-d modular hash of w over the numeric values val c, computed by Horner's rule modulo q (CLRS §32.2). For w = [a₀, …, a_{k-1}] this is ((⋯((val a₀ · d + val a₁) · d + …) · d + val a_{k-1}) mod q. The function is total (x % 0 = x); CLRS assumes a modulus 0 < q.

def hash (d q : ℕ) (val : α → ℕ) (w : Text α) : ℕ := w.foldl (fun acc c => (acc * d + val c) % q) 0

The O(1) incremental update: appending a character to a string costs one multiplication, one addition and one modulus, rather than a full re-hash. This is the step used to seed the Rabin–Karp hashes (CLRS §32.2).

automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem hash_snoc (d q : ℕ) (val : α → ℕ) (w : Text α) (c : α) : hash d q val (w ++ [c]) = (hash d q val w * d + val c) % q := by unfold hash rw [List.foldl_append] simp

Equal strings have equal hashes, for any radix, modulus and value map.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_eq_of_text_eq`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_eq_of_text_eq`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_eq_of_text_eq`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_eq_of_text_eq`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem hash_eq_of_text_eq (d q : ℕ) (val : α → ℕ) {w₁ w₂ : Text α} (h : w₁ = w₂) : hash d q val w₁ = hash d q val w₂ := by subst h rfl

If the pattern matches at shift s, then the window's hash equals the pattern's hash: a real match is never discarded as a spurious hit. This is the completeness half of the hash test.

lemma hash_beq_of_matchesAt (T P : Text α) (d q : ℕ) (val : α → ℕ) (s : ℕ) (hm : matchesAt T P s = true) : (hash d q val ((T.drop s).take P.length) == hash d q val P) = true := by have hwind : ((T.drop s).take P.length == P) = true := by unfold matchesAt at hm split at hm · simpa using hm · contradiction have hwindEq : (T.drop s).take P.length = P := by exact beq_iff_eq.mp hwind rw [hash_eq_of_text_eq d q val hwindEq] simp

The Rabin–Karp acceptance test for shift s: the hash of the window (T.drop s).take |P| equals the hash of P, and the window literally equals P. The second conjunct filters out spurious hits, keeping the test sound for every modulus.

def rabinKarpShift (T P : Text α) (d q : ℕ) (val : α → ℕ) (s : ℕ) : Bool := (hash d q val ((T.drop s).take P.length) == hash d q val P) && matchesAt T P s

The Rabin–Karp string matcher: enumerate all shifts and return those that pass rabinKarpShift. For an empty pattern it returns every shift, exactly like naiveMatcher.

def rabinKarpMatcher (T P : Text α) (d q : ℕ) (val : α → ℕ) : List ℕ := if P.length = 0 then List.range (T.length + 1) else let n := T.length let m := P.length (List.range (n - m + 1)).filter (rabinKarpShift T P d q val)

The Rabin–Karp acceptance test agrees with the plain match test on every shift: when the pattern matches, the hash equality is automatic, and when it does not, the explicit comparison rejects the shift regardless of the hash.

lemma rabinKarpShift_eq_matchesAt (T P : Text α) (d q : ℕ) (val : α → ℕ) (s : ℕ) : rabinKarpShift T P d q val s = matchesAt T P s := by unfold rabinKarpShift by_cases h : matchesAt T P s = true · have hb := hash_beq_of_matchesAt T P d q val s h simp [h, hb] · have hf : matchesAt T P s = false := by cases hb : matchesAt T P s · rfl · exact False.elim (h hb) simp [hf]

If a shift s is in rabinKarpMatcher, then matchesAt T P s is true.

theorem rabinKarp_sound (T P : Text α) (d q : ℕ) (val : α → ℕ) (s : ℕ) (h : s ∈ rabinKarpMatcher T P d q val) : matchesAt T P s := by unfold rabinKarpMatcher at h split at h · rename_i hzero have hempty : P = [] := by cases P · rfl · simp at hzero subst hempty unfold matchesAt have hs : s ≤ T.length := by have := List.mem_range.mp h omega simp [hs] · have hmem := List.mem_filter.mp h simpa [rabinKarpShift_eq_matchesAt T P d q val s] using hmem.2

If matchesAt T P s is true, then s is in rabinKarpMatcher.

theorem rabinKarp_complete (T P : Text α) (d q : ℕ) (val : α → ℕ) (s : ℕ) (hmatch : matchesAt T P s) : s ∈ rabinKarpMatcher T P d q val := by unfold rabinKarpMatcher by_cases hzero : P.length = 0 · have hempty : P = [] := by cases P · rfl · simp at hzero subst hempty unfold matchesAt at hmatch simp at hmatch have hs : s < T.length + 1 := by omega simp [hs] · have hbound : s + P.length ≤ T.length := by unfold matchesAt at hmatch split at hmatch · assumption · simp at hmatch have hle : s < (T.length - P.length) + 1 := by omega have hmatch' : matchesAt T P s = true := hmatch have hshift : rabinKarpShift T P d q val s = true := by rw [rabinKarpShift_eq_matchesAt T P d q val s, hmatch'] simpa [hzero] using List.mem_filter.mpr ⟨List.mem_range.mpr hle, hshift⟩

Correctness of Rabin–Karp. rabinKarpMatcher returns exactly the shifts that naiveMatcher returns, for every text, pattern, radix, modulus and numeric value map. Soundness is by construction (the explicit comparison); completeness uses the fact that equal strings have equal hashes, so a valid match can never be filtered out as a spurious hit.

theorem rabinKarp_correct (T P : Text α) (d q : ℕ) (val : α → ℕ) : rabinKarpMatcher T P d q val = naiveMatcher T P := by by_cases hzero : P.length = 0 · simp [hzero, rabinKarpMatcher, naiveMatcher] · simp [hzero, rabinKarpMatcher, naiveMatcher] apply List.filter_congr intro s hs exact rabinKarpShift_eq_matchesAt T P d q val s
/- The rolling-window recurrence and its proof. This section adds the executable rolling recurrence (CLRS eq. (32.3)) on top of the hash-and-confirm matcher above, plus the rolling matcher that uses it and the deterministic work bound. -/ section Rollingvariable {α : Type} [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α]

Horner evaluation of w over val without the intermediate modular reductions. hash d q val w is exactly hashNoMod d val w % q.

def hashNoMod (d : ℕ) (val : α → ℕ) (w : Text α) : ℕ := w.foldl (fun acc c => acc * d + val c) 0

A Horner fold is congruent modulo q when its initial accumulator is.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_mod_congr`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_mod_congr`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_mod_congr`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_mod_congr`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_mod_congr`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_mod_congr`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_mod_congr`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma foldl_horner_mod_congr (d q : ℕ) (val : α → ℕ) (as : Text α) {x y : ℕ} (h : Nat.ModEq q x y) : Nat.ModEq q (as.foldl (fun a c => a * d + val c) x) (as.foldl (fun a c => a * d + val c) y) := by induction as generalizing x y with | nil => simpa using h | cons a as ih => have hstep : Nat.ModEq q (x * d + val a) (y * d + val a) := (Nat.ModEq.mul h (Nat.ModEq.refl d)).add (Nat.ModEq.refl (val a)) exact ih hstep

Reducing after each Horner step is congruent to reducing once at the end.

lemma foldl_mod_congr (d q : ℕ) (val : α → ℕ) (w : Text α) (acc : ℕ) : Nat.ModEq q (w.foldl (fun a c => (a * d + val c) % q) acc) (w.foldl (fun a c => a * d + val c) acc) := by induction w generalizing acc with | nil => exact Nat.ModEq.refl acc | cons a as ih => rw [List.foldl_cons, List.foldl_cons] have h1 := ih ((acc * d + val a) % q) have h2 : Nat.ModEq q (as.foldl (fun a c => a * d + val c) ((acc * d + val a) % q)) (as.foldl (fun a c => a * d + val c) (acc * d + val a)) := foldl_horner_mod_congr d q val as (Nat.mod_modEq (acc * d + val a) q) exact h1.trans h2

hash is always below the modulus for a positive modulus.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_lt`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_lt`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_lt`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_lt`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_lt`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_lt`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_lt`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_lt`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_lt`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_lt`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_lt`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_lt`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_lt`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_lt`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem hash_lt (d q : ℕ) (val : α → ℕ) (w : Text α) (hq : 0 < q) : hash d q val w < q := by unfold hash have hmain : ∀ acc, acc < q → (w.foldl (fun a c => (a * d + val c) % q) acc) < q := by induction w with | nil => intro acc hacc; exact hacc | cons a as ih => intro acc hacc rw [List.foldl_cons] exact ih ((acc * d + val a) % q) (Nat.mod_lt _ hq) exact hmain 0 hq

hash is the Horner evaluation reduced modulo q.

theorem hash_eq_hashNoMod_mod (d q : ℕ) (val : α → ℕ) (w : Text α) : hash d q val w = hashNoMod d val w % q := by unfold hash hashNoMod by_cases hq : q = 0 · subst q; simp · have hqpos : 0 < q := Nat.pos_of_ne_zero hq have hcong := foldl_mod_congr d q val w 0 have hl : (w.foldl (fun a c => (a * d + val c) % q) 0) < q := by simpa [hash] using hash_lt d q val w hqpos simpa [Nat.ModEq, Nat.mod_eq_of_lt hl] using hcong

A Horner fold with initial accumulator acc equals acc · d^|as| plus the fold starting from 0.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_acc`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_acc`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_acc`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_acc`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_acc`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_acc`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_acc`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_acc`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_acc`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_acc`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_acc`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_acc`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_acc`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_acc`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.foldl_horner_acc`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma foldl_horner_acc (d : ℕ) (val : α → ℕ) (as : Text α) (acc : ℕ) : as.foldl (fun a c => a * d + val c) acc = acc * d ^ as.length + as.foldl (fun a c => a * d + val c) 0 := by induction as generalizing acc with | nil => simp | cons b bs ih => rw [List.foldl_cons, ih (acc * d + val b)] rw [List.foldl_cons, ih (0 * d + val b)] rw [List.length_cons, pow_succ] ring

The leading character contributes val a · d^|as| to the Horner hash.

lemma hashNoMod_cons (d : ℕ) (val : α → ℕ) (a : α) (as : Text α) : hashNoMod d val (a :: as) = val a * (d ^ as.length) + hashNoMod d val as := by unfold hashNoMod rw [List.foldl_cons] simpa using foldl_horner_acc d val as (val a)

(x + y) % q is unchanged when y is reduced modulo q.

lemma add_mod_add_mod (q x y : ℕ) : (x + y) % q = (x + y % q) % q := (Nat.ModEq.add (Nat.ModEq.refl x) (Nat.mod_modEq y q)).symm

The leading character's contribution to the Horner hash (CLRS §32.2).

theorem hash_cons (d q : ℕ) (val : α → ℕ) (a : α) (as : Text α) : hash d q val (a :: as) = (val a * (d ^ as.length) + hash d q val as) % q := by rw [hash_eq_hashNoMod_mod d q val (a :: as)] rw [hashNoMod_cons] rw [add_mod_add_mod q (val a * d ^ as.length) (hashNoMod d val as)] rw [← hash_eq_hashNoMod_mod d q val as]

Casting x % q into ZMod q is the same as casting x.

lemma zmod_natCast_mod (q x : ℕ) : ((x % q : ℕ) : ZMod q) = (x : ZMod q) := (ZMod.natCast_eq_natCast_iff (x % q) x q).2 (Nat.mod_mod x q)

The rolling recurrence (CLRS eq. (32.3)): given the hash h of a nonempty window w and the incoming character c, the hash of w.drop 1 ++ [c] is (d·h + val c − val w[0]·d^|w|) mod q, with the subtraction normalized into ℕ by the + q term (valid for 0 < q).

def slideHash (d q : ℕ) (val : α → ℕ) (h : ℕ) (w : Text α) (c : α) : ℕ := (d * h + val c + q - (val (w.headD default) * d ^ w.length) % q) % q

The ZMod q value of a slide: the + q − x normalization collapses to the true modular subtraction.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.slideHash_zmod`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.slideHash_zmod`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.slideHash_zmod`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.slideHash_zmod`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.slideHash_zmod`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.slideHash_zmod`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.slideHash_zmod`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.slideHash_zmod`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.slideHash_zmod`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.slideHash_zmod`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.slideHash_zmod`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.slideHash_zmod`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.slideHash_zmod`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.slideHash_zmod`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.slideHash_zmod`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.slideHash_zmod`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma slideHash_zmod (d q : ℕ) (hq : 0 < q) (val : α → ℕ) (w : Text α) (h : ℕ) (c : α) : ((slideHash d q val h w c : ℕ) : ZMod q) = (d : ZMod q) * (h : ZMod q) + (val c : ZMod q) - (val (w.headD default) : ZMod q) * (d : ZMod q) ^ w.length := by unfold slideHash rw [zmod_natCast_mod q (d * h + val c + q - (val (w.headD default) * d ^ w.length) % q)] have hge : (val (w.headD default) * d ^ w.length) % q ≤ d * h + val c + q := by exact Nat.le_trans (Nat.le_of_lt (Nat.mod_lt _ hq)) (Nat.le_add_left _ _) rw [Nat.cast_sub hge] rw [zmod_natCast_mod q (val (w.headD default) * d ^ w.length)] push_cast rw [ZMod.natCast_self] ring

The Horner hash of a cons in ZMod q.

lemma hash_cons_zmod (d q : ℕ) (val : α → ℕ) (a : α) (as : Text α) : (hash d q val (a :: as) : ZMod q) = (val a : ZMod q) * (d : ZMod q) ^ as.length + (hash d q val as : ZMod q) := by rw [hash_cons, zmod_natCast_mod] push_cast rfl

The Horner hash of a snoc in ZMod q.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_snoc_zmod`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_snoc_zmod`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_snoc_zmod`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_snoc_zmod`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_snoc_zmod`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_snoc_zmod`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.hash_snoc_zmod`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma hash_snoc_zmod (d q : ℕ) (val : α → ℕ) (w : Text α) (c : α) : (hash d q val (w ++ [c]) : ZMod q) = (hash d q val w : ZMod q) * d + (val c : ZMod q) := by rw [hash_snoc, zmod_natCast_mod] push_cast rfl

Rabin–Karp rolling recurrence (CLRS eq. (32.3)). Sliding a nonempty window by one position — dropping the leading character and appending a new one — satisfies the hash recurrence below. The legacy slideHash recomputes d ^ w.length, so this definition does not itself give a constant-cost slide. The CachedPower companion prepares the power once and uses seven fixed scalar arithmetic operations per update.

theorem hash_slide (d q : ℕ) (val : α → ℕ) (w : Text α) (c : α) (hq : 0 < q) (hw : w ≠ []) : hash d q val (w.drop 1 ++ [c]) = slideHash d q val (hash d q val w) w c := by rcases w with _ | ⟨a, as⟩ · contradiction change hash d q val (as ++ [c]) = slideHash d q val (hash d q val (a :: as)) (a :: as) c have hl : hash d q val (as ++ [c]) < q := hash_lt d q val (as ++ [c]) hq have hr : slideHash d q val (hash d q val (a :: as)) (a :: as) c < q := by unfold slideHash; exact Nat.mod_lt _ hq have hcong : ((hash d q val (as ++ [c]) : ZMod q) = (slideHash d q val (hash d q val (a :: as)) (a :: as) c : ZMod q)) := by rw [hash_snoc_zmod] rw [slideHash_zmod d q hq val (a :: as) (hash d q val (a :: as)) c] rw [hash_cons_zmod] rw [List.length_cons, pow_succ] simp only [List.headD] ring have hmod : hash d q val (as ++ [c]) % q = slideHash d q val (hash d q val (a :: as)) (a :: as) c % q := (ZMod.natCast_eq_natCast_iff _ _ q).1 hcong rw [Nat.mod_eq_of_lt hl, Nat.mod_eq_of_lt hr] at hmod exact hmod

range (n+1) mapped by f is f 0 followed by the shifted tail.

'change (List.range (n + 1 + 1)).map f = f 0 :: (List.range (n + 1)).map (fun i => f (i + 1))' tactic does nothing Note: This linter can be disabled with `set_option linter.unusedTactic false` lemma range_succ_map (n : ℕ) (f : ℕ → β) : (List.range (n + 1)).map f = f 0 :: (List.range n).map (fun i => f (i + 1)) := by induction n with | zero => rfl | succ n ih => 'change (List.range (n + 1 + 1)).map f = f 0 :: (List.range (n + 1)).map (fun i => f (i + 1))' tactic does nothing Note: This linter can be disabled with `set_option linter.unusedTactic false`change (List.range (n + 1 + 1)).map f = f 0 :: (List.range (n + 1)).map (fun i => f (i + 1)) rw [List.range_succ, List.map_append, List.map_cons, ih] rw [List.range_succ, List.map_append, List.map_cons] simp

The acceptance test of the rolling scan agrees with the plain match test.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingTest_eq_matchesAt`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingTest_eq_matchesAt`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingTest_eq_matchesAt`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingTest_eq_matchesAt`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingTest_eq_matchesAt`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingTest_eq_matchesAt`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingTest_eq_matchesAt`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingTest_eq_matchesAt`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingTest_eq_matchesAt`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingTest_eq_matchesAt`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingTest_eq_matchesAt`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingTest_eq_matchesAt`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingTest_eq_matchesAt`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingTest_eq_matchesAt`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma rollingTest_eq_matchesAt (T P : Text α) (d q : ℕ) (val : α → ℕ) (p m s : ℕ) (w : Text α) (h : ℕ) (hp : p = hash d q val P) (hm : m = P.length) (hw : w = (T.drop s).take m) (hh : h = hash d q val w) : (h == p && matchesAt T P s) = matchesAt T P s := by by_cases hmt : matchesAt T P s = true · have hbeq : (h == p) = true := by have hb := hash_beq_of_matchesAt T P d q val s hmt simpa [hh, hp, hm, hw] using hb simp [hmt, hbeq] · have hf : matchesAt T P s = false := by cases hb : matchesAt T P s <;> simp [hb] at hmt ⊢ simp [hf]

The hash-hit test of the rolling scan is exactly the window hash equality.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingHashHit_eq`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingHashHit_eq`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingHashHit_eq`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma rollingHashHit_eq (T P : Text α) (d q : ℕ) (val : α → ℕ) (p m s : ℕ) (w : Text α) (h : ℕ) (hp : p = hash d q val P) (hm : m = P.length) (hw : w = (T.drop s).take m) (hh : h = hash d q val w) : (h == p) = (hash d q val ((T.drop s).take P.length) == hash d q val P) := by simp [hh, hp, hm, hw]

The number of hash hits among the k+1 consecutive windows starting at shift s, defined recursively so the head-split is definitional.

def hashHitsIn (T P : Text α) (d q : ℕ) (val : α → ℕ) (s k : ℕ) : ℕ := match k with | 0 => if hash d q val ((T.drop s).take P.length) == hash d q val P then 1 else 0 | k + 1 => (if hash d q val ((T.drop s).take P.length) == hash d q val P then 1 else 0) + hashHitsIn T P d q val (s + 1) k

hashHitsIn over a single window.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.hashHitsIn_zero`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma hashHitsIn_zero (T P : Text α) (d q : ℕ) (val : α → ℕ) (s : ℕ) : hashHitsIn T P d q val s 0 = (if hash d q val ((T.drop s).take P.length) == hash d q val P then 1 else 0) := rfl

hashHitsIn splits across the first window.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.hashHitsIn_succ`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.hashHitsIn_succ`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.hashHitsIn_succ`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma hashHitsIn_succ (T P : Text α) (d q : ℕ) (val : α → ℕ) (s k : ℕ) : hashHitsIn T P d q val s (k + 1) = hashHitsIn T P d q val s 0 + hashHitsIn T P d q val (s + 1) k := by rfl

Sliding the window: dropping one leading character and appending c yields the next length-m window of T.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.window_slide`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma window_slide {T : Text α} {s m : ℕ} {w : Text α} {c : α} {rest' : Text α} (hw : w = (T.drop s).take m) (hwlen : w.length = m) (hm0 : 0 < m) (hr : c :: rest' = T.drop (s + m)) : w.tail ++ [c] = (T.drop (s + 1)).take m := by have hwrest : w ++ (c :: rest') = T.drop s := by calc w ++ (c :: rest') = (T.drop s).take m ++ T.drop (s + m) := by rw [hw, ← hr] _ = (T.drop s).take m ++ (T.drop s).drop m := by rw [List.drop_drop] _ = T.drop s := List.take_append_drop m (T.drop s) have hlen_tail : w.tail.length = m - 1 := by rw [List.length_tail, hwlen] calc w.tail ++ [c] = (w.tail ++ (c :: rest')).take m := by rw [List.take_append] have hle : w.tail.length ≤ m := by omega have hone : m - w.tail.length = 1 := by omega rw [List.take_of_length_le hle, hone] simp _ = ((w ++ (c :: rest')).drop 1).take m := by rw [List.drop_append_of_le_length (show 1 ≤ w.length by omega)] rw [List.drop_one] _ = ((T.drop s).drop 1).take m := by rw [hwrest] _ = (T.drop (s + 1)).take m := by rw [List.drop_drop]

One rolling scan step, returning the matches found and the accumulated work.

def rollingGo (T P : Text α) (d q : ℕ) (val : α → ℕ) (p m s : ℕ) (w : Text α) (h : ℕ) (rest : Text α) : List ℕ × ℕ := match rest with | [] => (if h == p && matchesAt T P s then [s] else [], 1 + (if h == p then m else 0)) | c :: rest' => let (tail, costTail) := rollingGo T P d q val p m (s + 1) (w.tail ++ [c]) (slideHash d q val h w c) rest' let conf := if h == p then m else 0 if h == p && matchesAt T P s then (s :: tail, conf + 1 + costTail) else (tail, conf + 1 + costTail)

The rolling scan's specification: rollingGo returns exactly the shifts in [s, s + rest.length] where P matches, and a cost of one rolling update per shift plus an m-step character confirmation at every hash hit.

lemma rollingGo_spec (T P : Text α) (d q : ℕ) (val : α → ℕ) (p m s : ℕ) (w : Text α) (h : ℕ) (rest : Text α) (hq : 0 < q) (hm0 : 0 < m) (hp : p = hash d q val P) (hm : m = P.length) (hw : w = (T.drop s).take m) (hwlen : w.length = m) (hh : h = hash d q val w) (hr : rest = T.drop (s + m)) : rollingGo T P d q val p m s w h rest = ( ((List.range (rest.length + 1)).map (fun i => s + i)).filter (fun s' => matchesAt T P s'), rest.length + 1 + hashHitsIn T P d q val s rest.length * m ) := by induction rest generalizing s w h with | nil => rw [rollingGo] rw [rollingTest_eq_matchesAt T P d q val p m s w h hp hm hw hh] rw [rollingHashHit_eq T P d q val p m s w h hp hm hw hh] simp only [List.length_nil] rw [hashHitsIn_zero T P d q val s] congr · by_cases h : matchesAt T P s <;> simp [h] · by_cases h : hash d q val ((T.drop s).take P.length) == hash d q val P <;> simp [h] | cons c rest' ih => simp only [rollingGo] -- set up the recursive invariants have hw' : w.tail ++ [c] = (T.drop (s + 1)).take m := window_slide hw hwlen hm0 hr have hwlen' : (w.tail ++ [c]).length = m := by rw [List.length_append, List.length_cons, List.length_nil] rw [List.length_tail, hwlen] omega have hh' : slideHash d q val h w c = hash d q val (w.tail ++ [c]) := by have hwne : w ≠ [] := by intro he; subst he; simp at hwlen; omega rw [hh] simpa [List.drop_one] using (hash_slide d q val w c hq hwne).symm have hr' : rest' = T.drop ((s + 1) + m) := by calc rest' = (c :: rest').drop 1 := by rfl _ = (T.drop (s + m)).drop 1 := by rw [hr] _ = T.drop ((s + 1) + m) := by rw [List.drop_drop]; congr 1; omega simp only [ih (s + 1) (w.tail ++ [c]) (slideHash d q val h w c) hw' hwlen' hh' hr'] rw [rollingTest_eq_matchesAt T P d q val p m s w h hp hm hw hh] rw [rollingHashHit_eq T P d q val p m s w h hp hm hw hh] -- split the range and the hash-hit count simp only [List.length_cons] rw [range_succ_map (rest'.length + 1) (fun i => s + i)] rw [hashHitsIn_succ T P d q val s rest'.length] have hmap : ((List.range (rest'.length + 1)).map (fun i => s + 1 + i)) = ((List.range (rest'.length + 1)).map (fun i => s + (i + 1))) := by congr; funext i; omega have hcost : (if hash d q val ((T.drop s).take P.length) == hash d q val P then m else 0) = hashHitsIn T P d q val s 0 * m := by simp only [hashHitsIn] cases hb : hash d q val ((T.drop s).take P.length) == hash d q val P <;> simp rw [hmap, hcost] apply Prod.ext · simp only [List.filter_cons, This simp argument is unused: List.map_cons Hint: Omit it from the simp argument list. simp only [List.filter_cons, L̵i̵s̵t̵.̵m̵a̵p̵_̵c̵o̵n̵s̵,̵ ̵List.map_append] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`List.map_cons, This simp argument is unused: List.map_append Hint: Omit it from the simp argument list. simp only [List.filter_cons, List.map_cons,̵ ̵L̵i̵s̵t̵.̵m̵a̵p̵_̵a̵p̵p̵e̵n̵d̵] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`List.map_append] by_cases h : matchesAt T P s <;> simp [h] · by_cases h : matchesAt T P s <;> simp [h] <;> ring

The rolling Rabin-Karp matcher (CLRS §32.2), returning the list of matches and the deterministic work performed.

def rabinKarpRolling (T P : Text α) (d q : ℕ) (val : α → ℕ) : List ℕ × ℕ := let m := P.length let p := hash d q val P if m = 0 then (List.range (T.length + 1), T.length + 1) else let r := rollingGo T P d q val p m 0 (T.take m) (hash d q val (T.take m)) (T.drop m) (r.1, m + r.2)

The matches returned by the rolling matcher.

def rabinKarpRollingMatches (T P : Text α) (d q : ℕ) (val : α → ℕ) : List ℕ := (rabinKarpRolling T P d q val).1

Selected shift/confirmation budget: a legacy m seed charge, one charge per shift and m per hash hit. It does not count power preparation, all seed arithmetic or list-window movement; the cached-power companion adds actual power and both seed-hash counters.

def rabinKarpRollingCost (T P : Text α) (d q : ℕ) (val : α → ℕ) : ℕ := (rabinKarpRolling T P d q val).2

The top-level rolling scan applied to the whole text.

lemma rollingGo_top (T P : Text α) (d q : ℕ) (val : α → ℕ) (hq : 0 < q) (hm0 : 0 < P.length) (hmle : P.length ≤ T.length) : rollingGo T P d q val (hash d q val P) P.length 0 (T.take P.length) (hash d q val (T.take P.length)) (T.drop P.length) = (((List.range (T.length - P.length + 1)).filter (fun s' => matchesAt T P s')), T.length - P.length + 1 + hashHitsIn T P d q val 0 (T.length - P.length) * P.length) := by have hwlen : (T.take P.length).length = P.length := by rw [List.length_take]; omega have hspec := rollingGo_spec T P d q val (hash d q val P) P.length 0 (T.take P.length) (hash d q val (T.take P.length)) (T.drop P.length) hq hm0 rfl rfl rfl hwlen rfl (by simp) rw [hspec] simp [List.length_drop]

Correctness of the rolling Rabin-Karp matcher. The rolling matcher returns exactly the shifts returned by naiveMatcher (and hence by the hash-and-confirm rabinKarpMatcher): rolling hashes preserve exactly the set of matches. The separate cached-power implementation supplies a fixed-operation slide.

theorem rabinKarpRollingMatches_correct (T P : Text α) (d q : ℕ) (val : α → ℕ) (hq : 0 < q) : rabinKarpRollingMatches T P d q val = naiveMatcher T P := by by_cases hzero : P.length = 0 · simp [rabinKarpRollingMatches, rabinKarpRolling, hzero, naiveMatcher] · have hm0 : 0 < P.length := Nat.pos_of_ne_zero hzero by_cases hlong : T.length < P.length · have hdrop : T.drop P.length = [] := by apply List.eq_nil_of_length_eq_zero; rw [List.length_drop]; omega have hmt : matchesAt T P 0 = false := by unfold matchesAt; simp [hlong] rw [show rabinKarpRollingMatches T P d q val = [] by simp [rabinKarpRollingMatches, rabinKarpRolling, hzero, This simp argument is unused: hlong Hint: Omit it from the simp argument list. simp [rabinKarpRollingMatches, rabinKarpRolling, hzero, h̵l̵o̵n̵g̵,̵ ̵rollingGo, hdrop, hmt] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`hlong, rollingGo, hdrop, hmt]] simpa [noMatch] using (naiveMatcher_pattern_too_long T P hlong).symm · have hmle : P.length ≤ T.length := Nat.le_of_not_gt hlong have htop := rollingGo_top T P d q val hq hm0 hmle simp [rabinKarpRollingMatches, rabinKarpRolling, hzero, This simp argument is unused: hlong Hint: Omit it from the simp argument list. simp [rabinKarpRollingMatches, rabinKarpRolling, hzero, hl̵o̵n̵g̵,̵ ̵h̵top, naiveMatcher] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`hlong, htop, naiveMatcher]

The refined work bound: the rolling matcher performs exactly m operations to seed the first hash, one rolling update per shift, and an m-step character confirmation at every hash hit — the term that is O(n + m·(#hits)). A spurious hit is a hash hit that is not a real match; both cost the same m confirmations.

Used `tac1 <;> tac2` where `(tac1; tac2)` would suffice Note: This linter can be disabled with `set_option linter.unnecessarySeqFocus false` theorem rabinKarpRollingCost_eq (T P : Text α) (d q : ℕ) (val : α → ℕ) (hq : 0 < q) : rabinKarpRollingCost T P d q val = P.length + (T.length - P.length + 1) + hashHitsIn T P d q val 0 (T.length - P.length) * P.length := by by_cases hzero : P.length = 0 · simp [rabinKarpRollingCost, rabinKarpRolling, hzero] · have hm0 : 0 < P.length := Nat.pos_of_ne_zero hzero by_cases hlong : T.length < P.length · have hdrop : T.drop P.length = [] := by apply List.eq_nil_of_length_eq_zero; rw [List.length_drop]; omega have hsub : T.length - P.length = 0 := by omega simp [rabinKarpRollingCost, rabinKarpRolling, hzero, This simp argument is unused: hlong Hint: Omit it from the simp argument list. simp [rabinKarpRollingCost, rabinKarpRolling, hzero, h̵l̵o̵n̵g̵,̵ ̵rollingGo, hdrop, hashHitsIn, hsub] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`hlong, rollingGo, hdrop, hashHitsIn, hsub] by_cases hhit : hash d q val (T.take P.length) = hash d q val P <;> simp [hhit] Used `tac1 <;> tac2` where `(tac1; tac2)` would suffice Note: This linter can be disabled with `set_option linter.unnecessarySeqFocus false`<;> omega · have hmle : P.length ≤ T.length := Nat.le_of_not_gt hlong have htop := rollingGo_top T P d q val hq hm0 hmle simp [rabinKarpRollingCost, rabinKarpRolling, hzero, This simp argument is unused: hlong Hint: Omit it from the simp argument list. simp [rabinKarpRollingCost, rabinKarpRolling, hzero, hl̵o̵n̵g̵,̵ ̵h̵top] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`hlong, htop] omega

The cost-only trace of the rolling scan, mirroring rollingGo's second component without the match-list bookkeeping.

def rollingCost (T P : Text α) (d q : ℕ) (val : α → ℕ) (p m s : ℕ) (w : Text α) (h : ℕ) (rest : Text α) : ℕ := match rest with | [] => 1 + (if h == p then m else 0) | c :: rest' => (if h == p then m else 0) + 1 + rollingCost T P d q val p m (s + 1) (w.tail ++ [c]) (slideHash d q val h w c) rest'

rollingGo's cost component is exactly rollingCost.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingGo_snd_eq_rollingCost`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingGo_snd_eq_rollingCost`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingGo_snd_eq_rollingCost`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingGo_snd_eq_rollingCost`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingGo_snd_eq_rollingCost`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingGo_snd_eq_rollingCost`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingGo_snd_eq_rollingCost`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingGo_snd_eq_rollingCost`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingGo_snd_eq_rollingCost`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingGo_snd_eq_rollingCost`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma rollingGo_snd_eq_rollingCost (T P : Text α) (d q : ℕ) (val : α → ℕ) (p m s : ℕ) (w : Text α) (h : ℕ) (rest : Text α) : (rollingGo T P d q val p m s w h rest).2 = rollingCost T P d q val p m s w h rest := by induction rest generalizing s w h with | nil => rfl | cons c rest' ih => simp only [rollingGo, rollingCost] cases hb : (h == p && matchesAt T P s) <;> simp [This simp argument is unused: hb Hint: Omit it from the simp argument list. simp [h̵b̵,̵ ̵ih] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`hb, ih]

Each step of the rolling scan costs at most m + 1 operations: one rolling update plus at most m confirmation comparisons.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.rollingCost_le`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma rollingCost_le (T P : Text α) (d q : ℕ) (val : α → ℕ) (p m s : ℕ) (w : Text α) (h : ℕ) (rest : Text α) : rollingCost T P d q val p m s w h rest ≤ (rest.length + 1) * (m + 1) := by induction rest generalizing s w h with | nil => simp [rollingCost] have hif : (if h = p then m else 0) ≤ m := by by_cases hh : h = p <;> simp [hh] <;> this tactic is never executed Note: This linter can be disabled with `set_option linter.unreachableTactic false`'omega' tactic does nothing Note: This linter can be disabled with `set_option linter.unusedTactic false`omega omega | cons c rest' ih => simp [rollingCost] have hih := ih (s + 1) (w.tail ++ [c]) (slideHash d q val h w c) have hif : (if h = p then m else 0) ≤ m := by by_cases hh : h = p <;> simp [hh] <;> 'omega' tactic does nothing Note: This linter can be disabled with `set_option linter.unusedTactic false`this tactic is never executed Note: This linter can be disabled with `set_option linter.unreachableTactic false`omega nlinarith [hif, hih]

rollingGo's cost component is bounded by (rest.length + 1) * (m + 1).

lemma rollingGo_cost_le (T P : Text α) (d q : ℕ) (val : α → ℕ) (p m s : ℕ) (w : Text α) (h : ℕ) (rest : Text α) : (rollingGo T P d q val p m s w h rest).2 ≤ (rest.length + 1) * (m + 1) := by rw [rollingGo_snd_eq_rollingCost T P d q val p m s w h rest] exact rollingCost_le T P d q val p m s w h rest

The worst-case deterministic work bound: the rolling matcher never performs more than m + (n − m + 1)·(m + 1) operations — O(n·m) in the worst case, matching the textbook statement (CLRS §32.2). When hits are sparse, the refined rabinKarpRollingCost_eq gives the expected O(n + m·(#hits)) form.

Used `tac1 <;> tac2` where `(tac1; tac2)` would suffice Note: This linter can be disabled with `set_option linter.unnecessarySeqFocus false` theorem rabinKarpRollingCost_le (T P : Text α) (d q : ℕ) (val : α → ℕ) : rabinKarpRollingCost T P d q val ≤ P.length + (T.length - P.length + 1) * (P.length + 1) := by by_cases hzero : P.length = 0 · simp [rabinKarpRollingCost, rabinKarpRolling, hzero] · have hm0 : 0 < P.length := Nat.pos_of_ne_zero hzero by_cases hlong : T.length < P.length · have hdrop : T.drop P.length = [] := by apply List.eq_nil_of_length_eq_zero; rw [List.length_drop]; omega have hsub : T.length - P.length = 0 := by omega simp [rabinKarpRollingCost, rabinKarpRolling, hzero, This simp argument is unused: hlong Hint: Omit it from the simp argument list. simp [rabinKarpRollingCost, rabinKarpRolling, hzero, h̵l̵o̵n̵g̵,̵ ̵rollingGo, hdrop, hsub] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`hlong, rollingGo, hdrop, hsub] by_cases hhit : hash d q val (T.take P.length) = hash d q val P <;> simp [hhit] Used `tac1 <;> tac2` where `(tac1; tac2)` would suffice Note: This linter can be disabled with `set_option linter.unnecessarySeqFocus false`<;> omega · have hmle : P.length ≤ T.length := Nat.le_of_not_gt hlong have hbound : (rollingGo T P d q val (hash d q val P) P.length 0 (T.take P.length) (hash d q val (T.take P.length)) (T.drop P.length)).2 ≤ (T.length - P.length + 1) * (P.length + 1) := by simpa [List.length_drop] using (rollingGo_cost_le T P d q val (hash d q val P) P.length 0 (T.take P.length) (hash d q val (T.take P.length)) (T.drop P.length)) simp [rabinKarpRollingCost, rabinKarpRolling, hzero, This simp argument is unused: hlong Hint: Omit it from the simp argument list. simp [rabinKarpRollingCost, rabinKarpRolling, hzero,̵ ̵h̵l̵o̵n̵g̵] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`hlong] omega
end Rollingend Chapter32end CLRS

Definitions and proofs

CLRSLean.FourthEdition.Chapter_32.Section_32_2_Rabin_Karp.CachedPower

Rabin–Karp with a prepared high-position power

Prepare the power once and pass it through every slide. The fixed slide formula contains no exponentiation or window-length traversal. Power and seed hashing are counted from their actual recursions. The scan retains the existing shift/confirmation budget; list window movement, symbol-map evaluation and bit-operation costs are outside this scalar charge model.

namespace CLRS.Chapter32.RKExecutionvariable {α : Type} [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α]def power (d : Nat) : Nat → Nat × Nat | 0 => (1,0) | m+1 => let prev := power d m; (prev.1*d,prev.2+1)@[simp] theorem power_value (d m : Nat) : (power d m).1 = d^m := by induction m with | zero => rfl | succ m ih => simp [power, ih, pow_succ]@[simp] theorem power_multiplications (d m : Nat) : (power d m).2 = m := by induction m with | zero => rfl | succ m ih => simp [power, ih]def hashLoop (d q : Nat) (val : α → Nat) : Nat → Text α → Nat × Nat | acc, [] => (acc,0) | acc, c::xs => let rest := hashLoop d q val ((acc*d+val c)%q) xs (rest.1,rest.2+1)automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.hashLoop_value`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.hashLoop_value`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.hashLoop_value`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.hashLoop_value`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.hashLoop_value`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` @[simp] automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.hashLoop_value`: [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem hashLoop_value (d q : Nat) (val : α → Nat) (acc : Nat) (xs : Text α) : (hashLoop d q val acc xs).1 = xs.foldl (fun a c => (a*d+val c)%q) acc := by induction xs generalizing acc with | nil => rfl | cons c xs ih => simp [hashLoop, ih]@[simp] theorem hashLoop_characters (d q : Nat) (val : α → Nat) (acc : Nat) (xs : Text α) : (hashLoop d q val acc xs).2 = xs.length := by induction xs generalizing acc with | nil => rfl | cons c xs ih => simp [hashLoop, ih]

Two multiplications, two additions, one subtraction and two remainders.

def slide (d q high leading incoming h : Nat) : Nat := (d*h + incoming + q - (leading*high)%q)%q

With the prepared power, the fixed-operation slide equals the old recurrence.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.slide_eq`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem slide_eq (d q : Nat) (val : α → Nat) (h : Nat) (w : Text α) (c : α) : slide d q (d^w.length) (val (w.headD default)) (val c) h = slideHash d q val h w c := rfl
structure Scan where positions : List Nat charges : Nat slides : Natdef run (T P : Text α) (d q : Nat) (val : α → Nat) (high p m : Nat) : Nat → Text α → Nat → Text α → Scan | s,Variable name `w` is not explicitly referenced. The binding can be removed (if unused) or named `_` (if used implicitly). Note: This linter can be disabled with `set_option linter.unusedVariables false`w,h,[] => ⟨if h == p && matchesAt T P s then [s] else [],1+(if h==p then m else 0),0⟩ | s,w,h,c::rest => let next := slide d q high (val (w.headD default)) (val c) h let tail := run T P d q val high p m (s+1) (w.tail++[c]) next rest ⟨if h==p && matchesAt T P s then s::tail.positions else tail.positions, (if h==p then m else 0)+1+tail.charges,tail.slides+1⟩automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_slides`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_slides`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_slides`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_slides`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_slides`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` @[simp] automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_slides`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem run_slides (T P : Text α) (d q : Nat) (val : α → Nat) (high p m s : Nat) (w : Text α) (h : Nat) (rest : Text α) : (run T P d q val high p m s w h rest).slides = rest.length := by induction rest generalizing s w h with | nil => rfl | cons c rest ih => simp [run, ih]automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.RKExecution.run_refines`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem run_refines (T P : Text α) (d q : Nat) (val : α → Nat) (p m s : Nat) (w : Text α) (h : Nat) (rest : Text α) (hm : 0 < m) (hw : w.length = m) : let r := run T P d q val (d^m) p m s w h rest (r.positions,r.charges) = rollingGo T P d q val p m s w h rest := by induction rest generalizing s w h with | nil => rfl | cons c rest ih => have hw' : (w.tail++[c]).length = m := by simp [List.length_tail,hw]; omega have hs : slide d q (d^m) (val (w.headD default)) (val c) h = slideHash d q val h w c := by rw [← hw]; rfl have hr := ih (s+1) (w.tail++[c]) (slideHash d q val h w c) hw' simp only [run, hs, rollingGo] rw [← hr] split <;> rflstructure Result where positions : List Nat powerMultiplications : Nat hashCharacters : Nat slides : Nat scanCharges : Natdef execute (T P : Text α) (d q : Nat) (val : α → Nat) : Result := if P.length = 0 then ⟨List.range (T.length+1),0,0,0,T.length+1⟩ else if T.length < P.length then ⟨[],0,0,0,0⟩ else let high := power d P.length let pattern := hashLoop d q val 0 P let window := T.take P.length let seed := hashLoop d q val 0 window let output := run T P d q val high.1 pattern.1 P.length 0 window seed.1 (T.drop P.length) ⟨output.positions,high.2,pattern.2+seed.2,output.slides,output.charges⟩

Scalar preparation plus seven arithmetic primitives per slide and the shift/confirmation budget. This is not the runtime of list copies or comparisons.

def chargedWork (r : Result) : Nat := r.powerMultiplications + 3*r.hashCharacters + 7*r.slides + r.scanCharges

Both seed hashes and the prepared power are charged once.

theorem execute_preparation (T P : Text α) (d q : Nat) (val : α → Nat) (hP : 0 < P.length) (hT : P.length ≤ T.length) : (execute T P d q val).powerMultiplications = P.length ∧ (execute T P d q val).hashCharacters = 2 * P.length ∧ (execute T P d q val).slides = T.length - P.length := by simp [execute, Nat.ne_of_gt hP, Nat.not_lt.mpr hT, List.length_take, Nat.min_eq_left hT, Nat.two_mul]
theorem execute_refines (T P : Text α) (d q : Nat) (val : α → Nat) (hP : 0 < P.length) (hT : P.length ≤ T.length) : (execute T P d q val).positions = (rabinKarpRolling T P d q val).1 ∧ P.length + (execute T P d q val).scanCharges = (rabinKarpRolling T P d q val).2 := by have hw : (T.take P.length).length = P.length := by simp [Nat.min_eq_left hT] have hr := run_refines T P d q val (hash d q val P) P.length 0 (T.take P.length) (hash d q val (T.take P.length)) (T.drop P.length) hP hw have hpos := congrArg Prod.fst hr have hcost := congrArg Prod.snd hr simp only at hpos hcost simp only [execute, Nat.ne_of_gt hP, Nat.not_lt.mpr hT, ↓reduceIte, power_value, hashLoop_value, rabinKarpRolling] change _ = _ ∧ _ = _ simp only [hash] at hpos hcost exact ⟨hpos, congrArg (P.length + ·) hcost⟩

Actual cached-power execution returns every and only matching shift.

theorem execute_correct (T P : Text α) (d q : Nat) (val : α → Nat) (hq : 0 < q) : (execute T P d q val).positions = naiveMatcher T P := by by_cases hempty : P.length = 0 · have hp : P = [] := by cases P <;> simp_all subst P simp [execute, naiveMatcher] · by_cases hlong : T.length < P.length · simp [execute, hempty, hlong, naiveMatcher_pattern_too_long T P hlong] · have he := (execute_refines T P d q val (by omega) (by omega)).1 exact he.trans (rabinKarpRollingMatches_correct T P d q val hq)

Exact connection to the established shift/confirmation charge, with newly counted preparation and constant arithmetic per slide.

theorem execute_chargedWork (T P : Text α) (d q : Nat) (val : α → Nat) (hP : 0 < P.length) (hT : P.length ≤ T.length) : chargedWork (execute T P d q val) = 6 * P.length + 7 * (T.length-P.length) + (rabinKarpRolling T P d q val).2 := by obtain ⟨hpow,hhash,hslides⟩ := execute_preparation T P d q val hP hT have hcost := (execute_refines T P d q val hP hT).2 simp only [chargedWork, hpow, hhash, hslides] omega
end CLRS.Chapter32.RKExecution
Imports
set_option maxHeartbeats 1000000

32.3. String Matching with Finite Automata

The finite-automaton string matcher (CLRS §32.3) builds a deterministic finite automaton whose states are 0 … |P|, with transition δ(q, a) = σ(P_q a), the length of the longest prefix of P that is a suffix of P_q a (here σ is the suffix function of CLRS §32.3). After preprocessing, scanning the text with δ accepts a prefix exactly when the pattern is a suffix of that prefix, so a shift is recorded whenever the state reaches |P|.

Key definitions

  • suffixTest p t — decidable "is p a suffix of t".

  • suffixLen P x — the suffix function σ(x).

  • delta P q a — the transition δ(q, a).

  • deltaStar P q t — δ extended to a string.

Main results

  • Lemma 32.3 — σ(xa) ≤ σ(x) + 1 (suffixLen_snoc_le).

  • Lemma 32.4 — σ(xa) = σ(P_{σ(x)} a) (suffixLen_snoc_eq).

  • Theorem deltaStar_eq_suffixLen — δ*(q, T) = σ(P_q T).

  • Theorem deltaStar_accepts_iff_suffix — δ*(0, T) = |P| ↔ P is a suffix of T.

  • dfaMatcher — the all-occurrences automaton matcher, with dfaMatcher_sound, dfaMatcher_complete, and dfaMatcher_correct (equivalence to naiveMatcher).

  • transitionTable/transitionLookup — the finite-alphabet transition table, with transitionLookup_eq_delta (lookup is exactly δ).

  • dfaMatcherTable — the table-driven matcher, refining dfaMatcher (dfaMatcherTable_correct).

  • transitionTableBuildCost_eq / dfaMatcherCost_eq count table cells and transition requests. They do not count suffix-search construction or list/alphabet lookup runtime. CachedScan passes one constructed table explicitly and counts the actual transition requests.

Notation conventions used in this section:

  • P : the pattern

  • T : the text

  • σ : the suffix function (written suffixLen P)

  • alphabet : a finite list of the alphabet symbols used to build the table

namespace CLRSnamespace Chapter32variable {α : Type} [BEq α] [DecidableEq α] [LawfulBEq α]

Decidable "is p a suffix of t", computed by checking the trailing substring.

def suffixTest (p t : Text α) : Bool := if p.length ≤ t.length then (t.drop (t.length - p.length) == p) else false

suffixTest decides isSuffix.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_eq_isSuffix`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem suffixTest_eq_isSuffix (p t : Text α) : suffixTest p t = true ↔ isSuffix p t := by constructor · intro h unfold suffixTest at h split at h · next hlen => have hdrop : t.drop (t.length - p.length) = p := beq_iff_eq.mp h refine ⟨t.take (t.length - p.length), ?_⟩ simpa [hdrop] using (List.take_append_drop (t.length - p.length) t) · simp at h · intro h unfold suffixTest have hlen : p.length ≤ t.length := isSuffix_length_le h rw [if_pos hlen] have hdrop : p = t.drop (t.length - p.length) := by rcases h with ⟨s, hs⟩ have hlen' : s.length + p.length = t.length := by simpa [List.length_append] using congrArg List.length hs calc p = (s ++ p).drop s.length := by simp _ = t.drop s.length := by rw [hs] _ = t.drop (t.length - p.length) := by congr 1 omega rw [← hdrop] simp

If p is a suffix of t, then p = t.drop (t.length - p.length).

automatically included section variable(s) unused in theorem `CLRS.Chapter32.isSuffix_eq_drop`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.isSuffix_eq_drop`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.isSuffix_eq_drop`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.isSuffix_eq_drop`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.isSuffix_eq_drop`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.isSuffix_eq_drop`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.isSuffix_eq_drop`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.isSuffix_eq_drop`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.isSuffix_eq_drop`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.isSuffix_eq_drop`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.isSuffix_eq_drop`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.isSuffix_eq_drop`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.isSuffix_eq_drop`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma isSuffix_eq_drop {p t : Text α} (h : isSuffix p t) : p = t.drop (t.length - p.length) := by rcases h with ⟨s, hs⟩ have hlen : s.length + p.length = t.length := by simpa [List.length_append] using congrArg List.length hs calc p = (s ++ p).drop s.length := by simp _ = t.drop s.length := by rw [hs] _ = t.drop (t.length - p.length) := by congr 1 omega

p is a suffix of t → p ++ u is a suffix of t ++ u.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_append_right`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_append_right`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_append_right`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_append_right`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_append_right`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_append_right`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_append_right`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma suffix_append_right {p t u : Text α} (h : isSuffix p t) : isSuffix (p ++ u) (t ++ u) := by rcases h with ⟨s, hs⟩ refine ⟨s, ?_⟩ rw [← List.append_assoc, hs]

Suffix is transitive.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_trans`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_trans`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_trans`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_trans`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_trans`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_trans`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_trans`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_trans`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_trans`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma suffix_trans {r s t : Text α} (hrs : isSuffix r s) (hst : isSuffix s t) : isSuffix r t := by rcases hrs with ⟨p, hp⟩ rcases hst with ⟨q, hq⟩ refine ⟨q ++ p, ?_⟩ rw [List.append_assoc, hp, hq]

If y and z are both suffixes of x and z.length ≤ y.length, then z is a suffix of y.

lemma isSuffix_of_suffix_of_suffix {x y z : Text α} (hy : isSuffix y x) (hz : isSuffix z x) (hlen : z.length ≤ y.length) : isSuffix z y := by have hylen : y.length ≤ x.length := isSuffix_length_le hy have hzlen : z.length ≤ x.length := isSuffix_length_le hz rw [isSuffix_eq_drop hy, isSuffix_eq_drop hz] refine ⟨(x.drop (x.length - y.length)).take (y.length - z.length), ?_⟩ rw [show List.drop (x.length - z.length) x = List.drop (y.length - z.length) (List.drop (x.length - y.length) x) by rw [List.drop_drop] congr 1 omega] exact List.take_append_drop (y.length - z.length) (List.drop (x.length - y.length) x)

The suffix function search: largest k ≤ n with P.take k a suffix of x.

def suffixLenAux (P x : Text α) : ℕ → ℕ | 0 => 0 | n + 1 => if suffixTest (P.take (n + 1)) x then n + 1 else suffixLenAux P x n

The suffix function σ(x): the largest k ≤ |P| with P.take k a suffix of x (CLRS §32.3).

def suffixLen (P x : Text α) : ℕ := suffixLenAux P x P.length

suffixLenAux never exceeds its bound.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixLenAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixLenAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixLenAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixLenAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixLenAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixLenAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixLenAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixLenAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixLenAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixLenAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixLenAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma suffixLenAux_le (P x : Text α) (n : ℕ) : suffixLenAux P x n ≤ n := by induction n with | zero => simp [suffixLenAux] | succ n ih => by_cases ht : suffixTest (P.take (n + 1)) x · simp [suffixLenAux, ht] · simp [suffixLenAux, ht]; omega

σ(x) ≤ |P|.

theorem suffixLen_le (P x : Text α) : suffixLen P x ≤ P.length := by unfold suffixLen exact suffixLenAux_le P x P.length

P.take (σ x) is a suffix of x.

try 'simp' instead of 'simpa' Note: This linter can be disabled with `set_option linter.unnecessarySimpa false` theorem suffixLen_satisfies (P x : Text α) : isSuffix (P.take (suffixLen P x)) x := by unfold suffixLen have hgo : ∀ n, suffixLenAux P x n = 0 ∨ suffixTest (P.take (suffixLenAux P x n)) x = true := by intro n induction n with | zero => left; simp [suffixLenAux] | succ n ih => by_cases ht : suffixTest (P.take (n + 1)) x · right; try 'simp' instead of 'simpa' Note: This linter can be disabled with `set_option linter.unnecessarySimpa false`simpa [suffixLenAux, ht] using ht · simpa [suffixLenAux, ht] using ih rcases hgo P.length with hzero | hsuf · rw [hzero]; exact isSuffix_empty x · exact (suffixTest_eq_isSuffix _ _).mp hsuf

σ(x) is maximal: any k ≤ |P| whose P.take k is a suffix of x satisfies k ≤ σ(x).

Try `simp at ht` instead of `simpa using ht` Note: This linter can be disabled with `set_option linter.unnecessarySimpa false` theorem suffixLen_maximal (P x : Text α) (k : ℕ) (hk : k ≤ P.length) (hsuf : isSuffix (P.take k) x) : k ≤ suffixLen P x := by unfold suffixLen have ht : suffixTest (P.take k) x = true := (suffixTest_eq_isSuffix _ _).mpr hsuf have hgo : ∀ n, k ≤ n → k ≤ suffixLenAux P x n := by intro n hkn induction n with | zero => omega | succ n ih => by_cases hts : suffixTest (P.take (n + 1)) x · simp [suffixLenAux, hts] omega · have hklt : k < n + 1 := by by_cases hk_eq : k = n + 1 · subst k; Try `simp at ht` instead of `simpa using ht` Note: This linter can be disabled with `set_option linter.unnecessarySimpa false`simpa [hts] using ht · omega have := ih (by omega) simpa [suffixLenAux, hts] using this exact hgo P.length hk

σ(x) ≤ |x|.

theorem suffixLen_le_length (P x : Text α) : suffixLen P x ≤ x.length := by have hle := isSuffix_length_le (suffixLen_satisfies P x) have hlen : (P.take (suffixLen P x)).length = suffixLen P x := by rw [List.length_take] have : suffixLen P x ≤ P.length := suffixLen_le P x omega rwa [hlen] at hle

The suffix function at a prefix of P returns that prefix's length.

theorem suffixLen_of_take (P : Text α) (q : ℕ) (hq : q ≤ P.length) : suffixLen P (P.take q) = q := by have hle : q ≤ suffixLen P (P.take q) := suffixLen_maximal P (P.take q) q hq (isSuffix_self (P.take q)) have hge : suffixLen P (P.take q) ≤ q := by have hle' := suffixLen_le_length P (P.take q) rw [List.length_take] at hle' omega omega

If P.take r is a suffix of x ++ [a] with 0 < r, then P.take (r-1) is a suffix of x.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_dropLast_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma suffix_dropLast_of_snoc (P x : Text α) (r : ℕ) (a : α) (hr : 0 < r) (hk : r ≤ P.length) (hsuf : isSuffix (P.take r) (x ++ [a])) : isSuffix (P.take (r - 1)) x := by rcases hsuf with ⟨s, hs⟩ have hdropLast : (P.take r).dropLast = P.take (r - 1) := by rw [List.dropLast_eq_take] have hlen : (P.take r).length = r := by rw [List.length_take]; exact Nat.min_eq_left hk rw [hlen, List.take_take, Nat.min_eq_left (by omega)] refine ⟨s, ?_⟩ have hne : (P.take r) ≠ [] := by have hlenr : (P.take r).length = r := by rw [List.length_take]; exact Nat.min_eq_left hk intro he have h0 : (P.take r).length = 0 := by simp [he] omega have hd : s ++ P.take (r - 1) = x := by have h1 : (s ++ P.take r).dropLast = (x ++ [a]).dropLast := by rw [hs] rw [List.dropLast_concat] at h1 have h2 : (s ++ P.take r).dropLast = s ++ P.take (r - 1) := by rw [List.dropLast_append] by_cases h : (P.take r).isEmpty = true · have : P.take r = [] := (List.isEmpty_iff.mp h) exact (hne this).elim · simp [h, hdropLast] rw [h2] at h1 exact h1 exact hd

If P.take r is a suffix of x ++ [a] and 0 < r ≤ |P|, then the last character of P.take r is a.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffix_last_char_of_snoc`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma suffix_last_char_of_snoc (P x : Text α) (r : ℕ) (a : α) (hsuf : isSuffix (P.take r) (x ++ [a])) (hrpos : 0 < r) (hk : r ≤ P.length) : (P.take r).getLast? = some a := by rcases hsuf with ⟨s, hs⟩ have hne : P.take r ≠ [] := by have hlenr : (P.take r).length = r := by rw [List.length_take]; exact Nat.min_eq_left hk intro he have h0 : (P.take r).length = 0 := by simp [he] omega have hlast : (s ++ P.take r).getLast? = some a := by rw [hs, List.getLast?_concat] have hrel : (s ++ P.take r).getLast? = (P.take r).getLast? := by rw [List.getLast?_append] rw [show (P.take r).getLast? = some ((P.take r).getLast hne) from `List.getLast?_eq_getLast` has been deprecated: Use `List.getLast?_eq_some_getLast` insteadList.getLast?_eq_getLast hne] simp rw [hrel] at hlast exact hlast

P.take r = P.take (r-1) ++ [a] when (P.take r) ends in a.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_eq_take_pred_append`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma take_eq_take_pred_append (P : Text α) (r : ℕ) (a : α) (hrpos : 0 < r) (hk : r ≤ P.length) (hchar : (P.take r).getLast? = some a) : P.take r = P.take (r - 1) ++ [a] := by have hne : P.take r ≠ [] := by have hlenr : (P.take r).length = r := by rw [List.length_take]; exact Nat.min_eq_left hk intro he have h0 : (P.take r).length = 0 := by simp [he] omega have hgetLast : (P.take r).getLast hne = a := by have := hchar rw [`List.getLast?_eq_getLast` has been deprecated: Use `List.getLast?_eq_some_getLast` insteadList.getLast?_eq_getLast hne] at this exact Option.some.inj this rw [← List.dropLast_append_getLast hne] rw [hgetLast] congr 1 rw [List.dropLast_eq_take] have hlenr : (P.take r).length = r := by rw [List.length_take]; exact Nat.min_eq_left hk rw [hlenr, List.take_take] rw [Nat.min_eq_left (by omega)]

CLRS Lemma 32.3: σ(xa) ≤ σ(x) + 1.

theorem suffixLen_snoc_le (P x : Text α) (a : α) : suffixLen P (x ++ [a]) ≤ suffixLen P x + 1 := by let k := suffixLen P (x ++ [a]) by_cases h0 : k = 0 · omega · have hsuf : isSuffix (P.take k) (x ++ [a]) := suffixLen_satisfies P (x ++ [a]) have hk : k ≤ P.length := suffixLen_le P (x ++ [a]) have hpre : isSuffix (P.take (k - 1)) x := suffix_dropLast_of_snoc P x k a (Nat.pos_of_ne_zero h0) hk hsuf have hle : k - 1 ≤ suffixLen P x := suffixLen_maximal P x (k - 1) (by omega) hpre omega

CLRS Lemma 32.4: σ(xa) = σ(P_{σ(x)} a).

theorem suffixLen_snoc_eq (P x : Text α) (a : α) : suffixLen P (x ++ [a]) = suffixLen P (P.take (suffixLen P x) ++ [a]) := by let q := suffixLen P x -- direction 1: σ(P_q a) ≤ σ(x a) have hle₁ : suffixLen P (P.take q ++ [a]) ≤ suffixLen P (x ++ [a]) := by have hsufq : isSuffix (P.take q) x := suffixLen_satisfies P x have hsuf' : isSuffix (P.take q ++ [a]) (x ++ [a]) := suffix_append_right hsufq have hsuf₂ : isSuffix (P.take (suffixLen P (P.take q ++ [a]))) (P.take q ++ [a]) := suffixLen_satisfies P (P.take q ++ [a]) have hsuf₃ : isSuffix (P.take (suffixLen P (P.take q ++ [a]))) (x ++ [a]) := suffix_trans hsuf₂ hsuf' have hk : suffixLen P (P.take q ++ [a]) ≤ P.length := suffixLen_le P (P.take q ++ [a]) exact suffixLen_maximal P (x ++ [a]) (suffixLen P (P.take q ++ [a])) hk hsuf₃ -- direction 2: σ(x a) ≤ σ(P_q a) have hle₂ : suffixLen P (x ++ [a]) ≤ suffixLen P (P.take q ++ [a]) := by let r := suffixLen P (x ++ [a]) have hr : r ≤ q + 1 := suffixLen_snoc_le P x a have hsuf : isSuffix (P.take r) (x ++ [a]) := suffixLen_satisfies P (x ++ [a]) have hk : r ≤ P.length := suffixLen_le P (x ++ [a]) have hsufP : isSuffix (P.take r) (P.take q ++ [a]) := by by_cases hrq : r ≤ q · -- r ≤ q: P.take (r-1) suffix of x, hence suffix of P.take q; P[r-1] = a by_cases h0 : r = 0 · rw [h0]; exact isSuffix_empty _ · have hpre : isSuffix (P.take (r - 1)) x := suffix_dropLast_of_snoc P x r a (Nat.pos_of_ne_zero h0) hk hsuf have hq : isSuffix (P.take q) x := suffixLen_satisfies P x have hlen : (P.take (r - 1)).length ≤ (P.take q).length := by have h1 : (P.take (r - 1)).length = r - 1 := by rw [List.length_take]; exact Nat.min_eq_left (by omega) have h2 : (P.take q).length = q := by rw [List.length_take]; exact Nat.min_eq_left (suffixLen_le P x) rw [h1, h2]; omega have hpreq : isSuffix (P.take (r - 1)) (P.take q) := isSuffix_of_suffix_of_suffix hq hpre hlen have hchar : (P.take r).getLast? = some a := suffix_last_char_of_snoc P x r a hsuf (Nat.pos_of_ne_zero h0) hk have htake : P.take r = P.take (r - 1) ++ [a] := take_eq_take_pred_append P r a (Nat.pos_of_ne_zero h0) hk hchar rw [htake] exact suffix_append_right hpreq · -- r = q + 1: P.take r = P.take q ++ [a] have hreq : r = q + 1 := by omega have hchar : (P.take (q + 1)).getLast? = some a := by have hsuf' : isSuffix (P.take (q + 1)) (x ++ [a]) := by simpa [hreq] using hsuf have hk' : q + 1 ≤ P.length := by omega exact suffix_last_char_of_snoc P x (q + 1) a hsuf' (by omega) hk' have htake : P.take r = P.take q ++ [a] := by rw [hreq] simpa using take_eq_take_pred_append P (q + 1) a (by omega) (by omega) hchar rw [htake] exact isSuffix_self _ exact suffixLen_maximal P (P.take q ++ [a]) r hk hsufP exact le_antisymm hle₂ hle₁

σ(y T) = σ(P_{σ(y)} T): the suffix function of an extended string only depends on the longest prefix-suffix of the base.

theorem suffixLen_append_eq (P : Text α) (y T : Text α) : suffixLen P (y ++ T) = suffixLen P (P.take (suffixLen P y) ++ T) := by induction T generalizing y with | nil => rw [List.append_nil, List.append_nil] exact (suffixLen_of_take P (suffixLen P y) (suffixLen_le P y)).symm | cons a T ih => rw [show y ++ (a :: T) = (y ++ [a]) ++ T by simp] rw [ih (y ++ [a]), suffixLen_snoc_eq P y a] rw [show P.take (suffixLen P y) ++ (a :: T) = (P.take (suffixLen P y) ++ [a]) ++ T by simp] exact (ih (P.take (suffixLen P y) ++ [a])).symm

The transition function δ(q, a) = σ(P_q a) (CLRS §32.3).

def delta (P : Text α) (q : ℕ) (a : α) : ℕ := suffixLen P (P.take q ++ [a])

δ extended to a string: δ*(q, T) = foldl δ q T.

def deltaStar (P : Text α) (q : ℕ) : Text α → ℕ := List.foldl (delta P) q
@[simp] automatically included section variable(s) unused in theorem `CLRS.Chapter32.deltaStar_nil`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem deltaStar_nil (P : Text α) (q : ℕ) : deltaStar P q [] = q := rfl@[simp] automatically included section variable(s) unused in theorem `CLRS.Chapter32.deltaStar_cons`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem deltaStar_cons (P : Text α) (q : ℕ) (a : α) (T : Text α) : deltaStar P q (a :: T) = deltaStar P (delta P q a) T := rfl

δ*(q, T) = σ(P_q T).

theorem deltaStar_eq_suffixLen (P : Text α) (q : ℕ) (T : Text α) (hq : q ≤ P.length) : deltaStar P q T = suffixLen P (P.take q ++ T) := by induction T generalizing q with | nil => rw [deltaStar_nil, List.append_nil]; exact (suffixLen_of_take P q hq).symm | cons a T ih => rw [deltaStar_cons] have hq' : delta P q a ≤ P.length := by unfold delta; exact suffixLen_le P (P.take q ++ [a]) rw [ih (delta P q a) hq'] unfold delta rw [show P.take q ++ (a :: T) = (P.take q ++ [a]) ++ T by simp] exact (suffixLen_append_eq P (P.take q ++ [a]) T).symm

The automaton (from state 0) reaches state |P| exactly when P is a suffix of the input.

theorem deltaStar_accepts_iff_suffix (P T : Text α) : deltaStar P 0 T = P.length ↔ isSuffix P T := by have h := deltaStar_eq_suffixLen P 0 T (by omega) rw [h] change suffixLen P T = P.length ↔ isSuffix P T constructor · intro hlen have hsuf := suffixLen_satisfies P T rw [hlen, List.take_length] at hsuf simpa using hsuf · intro hsuf have hmax := suffixLen_maximal P T P.length (by rfl) (by simpa using hsuf) have hle := suffixLen_le P T omega

δ*(0, x) = σ(x) never exceeds the length of its input.

lemma deltaStar_le_length (P x : Text α) : deltaStar P 0 x ≤ x.length := by rw [deltaStar_eq_suffixLen P 0 x (by omega)] simpa using (suffixLen_le_length P x)

The empty pattern is never a proper suffix: δ* from 0 stays at 0.

lemma deltaStar_empty (x : Text α) : deltaStar ([] : Text α) 0 x = 0 := by rw [deltaStar_eq_suffixLen ([] : Text α) 0 x (by omega)] simp [suffixLen, suffixLenAux]

Appending one character to the scanned text advances δ* by one transition.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.deltaStar_append_one`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.deltaStar_append_one`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.deltaStar_append_one`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.deltaStar_append_one`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.deltaStar_append_one`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.deltaStar_append_one`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma deltaStar_append_one (P : Text α) (scanned : Text α) (c : α) : deltaStar P 0 (scanned ++ [c]) = delta P (deltaStar P 0 scanned) c := by change List.foldl (delta P) 0 (scanned ++ [c]) = delta P (List.foldl (delta P) 0 scanned) c rw [List.foldl_append] rfl

range (n + 2) is 0 followed by range (n + 1) shifted by one.

lemma range_succ_cons (n : ℕ) : List.range (n + 2) = 0 :: (List.range (n + 1)).map (fun k => 1 + k) := by conv_lhs => rw [show n + 2 = 1 + (n + 1) by omega] rw [List.range_add] simp only [List.range_one, List.singleton_append]
@[simp] automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_cons_zero`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma take_cons_zero (c : α) (T : Text α) : (c :: T).take 0 = [] := rflautomatically included section variable(s) unused in theorem `CLRS.Chapter32.take_cons_succ_one`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_cons_succ_one`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_cons_succ_one`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_cons_succ_one`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_cons_succ_one`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_cons_succ_one`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_cons_succ_one`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.take_cons_succ_one`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma take_cons_succ_one (c : α) (T : Text α) (k : ℕ) : (c :: T).take (1 + k) = c :: T.take k := by rw [List.take_cons (by omega : 0 < 1 + k)] rw [show (1 + k) - 1 = k by omega]

The finite-automaton scan (CLRS FINITE-AUTOMATON-MATCHER). scanned is the text already scanned, q = δ*(0, scanned) the current state, and m = |P|. It returns, in increasing order, every shift scanned.length - m at which the state has reached m, i.e. every shift where P matches the text.

def dfaScan (P : Text α) (m : ℕ) (scanned : Text α) (q : ℕ) : Text α → List ℕ | [] => if q == m then [scanned.length - m] else [] | c :: rest => let q' := delta P q c let tail := dfaScan P m (scanned ++ [c]) q' rest if q == m then (scanned.length - m) :: tail else tail
@[simp] automatically included section variable(s) unused in theorem `CLRS.Chapter32.dfaScan_nil`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma dfaScan_nil (P : Text α) (m : ℕ) (scanned : Text α) (q : ℕ) : dfaScan P m scanned q [] = (if q == m then [scanned.length - m] else []) := rflautomatically included section variable(s) unused in theorem `CLRS.Chapter32.dfaScan_cons`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.dfaScan_cons`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.dfaScan_cons`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.dfaScan_cons`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.dfaScan_cons`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma dfaScan_cons (P : Text α) (m : ℕ) (scanned : Text α) (q : ℕ) (c : α) (T : Text α) : dfaScan P m scanned q (c :: T) = (if q == m then [scanned.length - m] else []) ++ dfaScan P m (scanned ++ [c]) (delta P q c) T := by by_cases h : q == m <;> simp [dfaScan, h]

The tail of the scan specification: the composed shift/state functions rewrite to the RHS functions.

lemma dfaScan_spec_tail (P : Text α) (m : ℕ) (scanned : Text α) (c : α) (T : Text α) : List.map ((fun j => scanned.length + j - m) ∘ (fun k => 1 + k)) (List.filter ((fun j => deltaStar P 0 (scanned ++ (c :: T).take j) == m) ∘ (fun k => 1 + k)) (List.range (T.length + 1))) = List.map (fun j => (scanned ++ [c]).length + j - m) (List.filter (fun j => deltaStar P 0 ((scanned ++ [c]) ++ T.take j) == m) (List.range (T.length + 1))) := by have hp : ((fun j => deltaStar P 0 (scanned ++ (c :: T).take j) == m) ∘ (fun k => 1 + k)) = (fun j => deltaStar P 0 ((scanned ++ [c]) ++ T.take j) == m) := by funext j simp [take_cons_succ_one, List.append_assoc] have hf : ((fun j => scanned.length + j - m) ∘ (fun k => 1 + k)) = (fun j => (scanned ++ [c]).length + j - m) := by funext j simp [List.length_append] omega rw [hp, hf]

The RHS of the scan specification, decomposed across one consumed character.

lemma dfaScan_spec_cons (P : Text α) (m : ℕ) (scanned : Text α) (c : α) (T : Text α) : ((List.range ((c :: T).length + 1)).filter (fun j => deltaStar P 0 (scanned ++ (c :: T).take j) == m)).map (fun j => scanned.length + j - m) = (if deltaStar P 0 scanned == m then [scanned.length - m] else []) ++ ((List.range (T.length + 1)).filter (fun j => deltaStar P 0 ((scanned ++ [c]) ++ T.take j) == m)).map (fun j => (scanned ++ [c]).length + j - m) := by change ((List.range (T.length + 2)).filter (fun j => deltaStar P 0 (scanned ++ (c :: T).take j) == m)).map (fun j => scanned.length + j - m) = (if deltaStar P 0 scanned == m then [scanned.length - m] else []) ++ ((List.range (T.length + 1)).filter (fun j => deltaStar P 0 ((scanned ++ [c]) ++ T.take j) == m)).map (fun j => (scanned ++ [c]).length + j - m) rw [range_succ_cons T.length] simp only [List.filter_cons, This simp argument is unused: List.map_cons Hint: Omit it from the simp argument list. simp only [List.filter_cons, List.m̵a̵p̵_̵c̵o̵n̵s̵,̵ ̵L̵i̵s̵t̵.̵filter_nil, List.map_nil, List.map_append] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`List.map_cons, This simp argument is unused: List.filter_nil Hint: Omit it from the simp argument list. simp only [List.filter_cons, List.map_cons, List.f̵i̵l̵t̵e̵r̵_̵n̵i̵l̵,̵ ̵L̵i̵s̵t̵.̵map_nil, List.map_append] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`List.filter_nil, This simp argument is unused: List.map_nil Hint: Omit it from the simp argument list. simp only [List.filter_cons, List.map_cons, List.filter_nil, List.map_n̵i̵l̵,̵ ̵L̵i̵s̵t̵.̵m̵ap_̵a̵pp̵end] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`List.map_nil, This simp argument is unused: List.map_append Hint: Omit it from the simp argument list. simp only [List.filter_cons, List.map_cons, List.filter_nil, List.map_nil,̵ ̵L̵i̵s̵t̵.̵m̵a̵p̵_̵a̵p̵p̵e̵n̵d̵] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`List.map_append] simp only [List.filter_map] by_cases h : deltaStar P 0 scanned = m <;> simp [h, List.map_map, List.append_nil] <;> rw [dfaScan_spec_tail P m scanned c T] <;> simp

The automaton scan from a scanned whose state is δ*(0, scanned) returns exactly the shifts scanned.length + j - m for end positions scanned.length + j whose scanned text scanned ++ T.take j reaches state m.

lemma dfaScan_spec (P : Text α) (m : ℕ) (scanned T : Text α) : dfaScan P m scanned (deltaStar P 0 scanned) T = ((List.range (T.length + 1)).filter (fun j => deltaStar P 0 (scanned ++ T.take j) == m)).map (fun j => scanned.length + j - m) := by induction T generalizing scanned with | nil => simp [dfaScan, List.append_nil, This simp argument is unused: List.take_zero Hint: Omit it from the simp argument list. simp [dfaScan, List.append_nil, List.t̵a̵k̵e̵_̵z̵e̵ro̵,̵ ̵L̵i̵s̵t̵.̵r̵ange_one, List.filter_cons, List.map_cons] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`List.take_zero, List.range_one, List.filter_cons, This simp argument is unused: List.map_cons Hint: Omit it from the simp argument list. simp [dfaScan, List.append_nil, List.take_zero, List.range_one, List.filter_cons,̵ ̵L̵i̵s̵t̵.̵m̵a̵p̵_̵c̵o̵n̵s̵] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`List.map_cons] by_cases h : deltaStar P 0 scanned = m <;> simp [h] | cons c T ih => rw [dfaScan_cons, ← deltaStar_append_one P scanned c] rw [ih (scanned ++ [c])] exact (dfaScan_spec_cons P m scanned c T).symm

The finite-automaton matcher: scan T left-to-right maintaining the automaton state, recording every shift where the state reaches |P|. This is the all-occurrences DFA matcher of CLRS §32.3.

def dfaMatcher (P T : Text α) : List ℕ := dfaScan P P.length [] 0 T

The automaton matcher, expressed as an end-position filter-map.

theorem dfaMatcher_spec (P T : Text α) : dfaMatcher P T = ((List.range (T.length + 1)).filter (fun j => deltaStar P 0 (T.take j) == P.length)).map (fun j => j - P.length) := by unfold dfaMatcher simpa using (dfaScan_spec P P.length [] T)

A real match at shift s is exactly a suffix of the (s + |P|)-scanned.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.matchesAt_iff_isSuffix_take`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma matchesAt_iff_isSuffix_take (P T : Text α) (s : ℕ) (hs : s + P.length ≤ T.length) : matchesAt T P s = true ↔ isSuffix P (T.take (s + P.length)) := by unfold matchesAt rw [if_pos hs, beq_iff_eq] constructor · intro h refine ⟨T.take s, ?_⟩ rw [List.take_add (i := s) (j := P.length) (l := T), h] · intro h rcases h with ⟨u, hu⟩ have hulen : u.length = s := by have hlen := congrArg List.length hu rw [List.length_append, List.length_take] at hlen have hmin : min (s + P.length) T.length = s + P.length := Nat.min_eq_left hs rw [hmin] at hlen omega calc (T.drop s).take P.length = (T.take (s + P.length)).drop s := by rw [List.drop_take]; simp _ = (u ++ P).drop s := by rw [← hu] _ = (u ++ P).drop u.length := by rw [hulen] _ = P := List.drop_left

δ*(0, T.take (s + |P|)) accepting agrees with matchesAt T P s.

lemma deltaStar_take_eq_matchesAt (P T : Text α) (s : ℕ) (hs : s + P.length ≤ T.length) : (deltaStar P 0 (T.take (s + P.length)) == P.length) = matchesAt T P s := by have hacc : (deltaStar P 0 (T.take (s + P.length)) = P.length) ↔ (matchesAt T P s = true) := by constructor · intro hd have hsuf := (deltaStar_accepts_iff_suffix P (T.take (s + P.length))).mp hd exact (matchesAt_iff_isSuffix_take P T s hs).mpr hsuf · intro hm have hsuf := (matchesAt_iff_isSuffix_take P T s hs).mp hm exact (deltaStar_accepts_iff_suffix P (T.take (s + P.length))).mpr hsuf cases h : matchesAt T P s with | true => have hd : deltaStar P 0 (T.take (s + P.length)) = P.length := hacc.mpr h simp [hd, This simp argument is unused: beq_iff_eq Hint: Omit it from the simp argument list. simp [hd,̵ ̵b̵e̵q̵_̵i̵f̵f̵_̵e̵q̵] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`beq_iff_eq] | false => have hd : deltaStar P 0 (T.take (s + P.length)) ≠ P.length := by intro hd' have htrue : matchesAt T P s = true := hacc.mp hd' rw [h] at htrue cases htrue cases hb : deltaStar P 0 (T.take (s + P.length)) == P.length with | true => have heq : deltaStar P 0 (T.take (s + P.length)) = P.length := beq_iff_eq.mp hb exact (hd heq).elim | false => rfl

The end-position filter-map of the automaton matcher equals the shift-domain naiveMatcher result.

lemma filter_map_delta_eq_naive (P T : Text α) : ((List.range (T.length + 1)).filter (fun j => deltaStar P 0 (T.take j) == P.length)).map (fun j => j - P.length) = naiveMatcher T P := by by_cases hzero : P.length = 0 · have hnil : P = [] := List.eq_nil_of_length_eq_zero hzero subst P simp [naiveMatcher_empty, deltaStar_empty] · have hm0 : 0 < P.length := Nat.pos_of_ne_zero hzero by_cases hle : P.length ≤ T.length · have hrange : List.range (T.length + 1) = List.range P.length ++ List.map (fun x => P.length + x) (List.range (T.length - P.length + 1)) := by have h := List.range_add (n := P.length) (m := T.length - P.length + 1) rw [show P.length + (T.length - P.length + 1) = T.length + 1 by omega] at h exact h rw [hrange, List.filter_append, List.map_append] have hfilt1 : (List.range P.length).filter (fun j => deltaStar P 0 (T.take j) == P.length) = [] := by rw [List.eq_nil_iff_forall_not_mem] intro j hj rw [List.mem_filter] at hj rcases hj with ⟨hjr, hjp⟩ have hjm : j < P.length := List.mem_range.mp hjr have hd : deltaStar P 0 (T.take j) ≤ j := by exact le_trans (deltaStar_le_length P (T.take j)) (by rw [List.length_take]; exact Nat.min_le_left _ _) have hbad : deltaStar P 0 (T.take j) = P.length := beq_iff_eq.mp hjp have hle' : P.length ≤ j := by simpa [hbad] using hd omega rw [hfilt1, List.map_nil, List.nil_append] rw [List.filter_map, List.map_map] have hsub : (fun x => (P.length + x) - P.length) = (fun x => x) := by funext x; rw [Nat.add_sub_cancel_left] change List.map (fun x => (P.length + x) - P.length) ((List.range (T.length - P.length + 1)).filter (fun x => deltaStar P 0 (T.take (P.length + x)) == P.length)) = naiveMatcher T P simp [This simp argument is unused: hsub Hint: Omit it from the simp argument list. simp ̵[̵h̵s̵u̵b̵]̵ Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`hsub] rw [naiveMatcher, if_neg hzero] apply List.filter_congr intro s hs have hsle : s + P.length ≤ T.length := by have := List.mem_range.mp hs omega rw [show P.length + s = s + P.length by omega] exact deltaStar_take_eq_matchesAt P T s hsle · have hlong : T.length < P.length := Nat.lt_of_not_ge hle have hfilt : (List.range (T.length + 1)).filter (fun j => deltaStar P 0 (T.take j) == P.length) = [] := by rw [List.eq_nil_iff_forall_not_mem] intro j hj rw [List.mem_filter] at hj rcases hj with ⟨hjr, hjp⟩ have hjn : j < T.length + 1 := List.mem_range.mp hjr have hd : deltaStar P 0 (T.take j) ≤ j := by exact le_trans (deltaStar_le_length P (T.take j)) (by rw [List.length_take]; exact Nat.min_le_left _ _) have hbad : deltaStar P 0 (T.take j) = P.length := beq_iff_eq.mp hjp have hle' : P.length ≤ j := by simpa [hbad] using hd omega rw [hfilt, List.map_nil] simpa [noMatch] using (naiveMatcher_pattern_too_long T P hlong).symm

Correctness of the finite-automaton matcher. dfaMatcher P T returns exactly the shifts that naiveMatcher T P returns, for every pattern and text.

theorem dfaMatcher_correct (P T : Text α) : dfaMatcher P T = naiveMatcher T P := by rw [dfaMatcher_spec, filter_map_delta_eq_naive]

Every shift returned by the automaton matcher is a valid match.

theorem dfaMatcher_sound (P T : Text α) (s : ℕ) (h : s ∈ dfaMatcher P T) : matchesAt T P s := by rw [dfaMatcher_correct] at h exact naiveMatcher_sound T P s h

Every valid match is returned by the automaton matcher.

theorem dfaMatcher_complete (P T : Text α) (s : ℕ) (h : matchesAt T P s) : s ∈ dfaMatcher P T := by rw [dfaMatcher_correct] exact naiveMatcher_complete T P s h

Transition-request budget: one per text character. This does not count transition computation, alphabet indexing or list-table access.

def dfaMatcherCost (Variable name `P` is not explicitly referenced. The binding can be removed (if unused) or named `_` (if used implicitly). Note: This linter can be disabled with `set_option linter.unusedVariables false`P T : Text α) : ℕ := T.length

The automaton matcher scans each character once.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.dfaMatcherCost_eq`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem dfaMatcherCost_eq (P T : Text α) : dfaMatcherCost P T = T.length := rfl
section TransitionTable

The transition table for pattern P over a finite alphabet alphabet (CLRS §32.3 COMPUTE-TRANSITION-FUNCTION): one row per state q ∈ [0, |P|], each row listing the precomputed next-state δ(q, a) for every a ∈ alphabet, in row-major order.

def transitionTable (alphabet : List α) (P : Text α) : List (List ℕ) := (List.range (P.length + 1)).map (fun q => alphabet.map (fun a => delta P q a))

Look up the next state for state q and symbol a in a transition table indexed by alphabet, returning 0 for an out-of-range state or symbol.

def transitionLookup (alphabet : List α) (table : List (List ℕ)) (q : ℕ) (a : α) : ℕ := (table.getD q []).getD (alphabet.idxOf a) 0

The transition table has one row per state.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionTable_length`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionTable_length`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionTable_length`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionTable_length`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem transitionTable_length (alphabet : List α) (P : Text α) : (transitionTable alphabet P).length = P.length + 1 := by unfold transitionTable simp

The table lookup agrees with the semantic transition δ: for every state q ≤ |P| and every symbol a in the alphabet, the entry stored in transitionTable alphabet P at (q, a) is exactly δ(q, a).

automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionLookup_eq_delta`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem transitionLookup_eq_delta (alphabet : List α) (P : Text α) (q : ℕ) (hq : q ≤ P.length) (a : α) (ha : a ∈ alphabet) : transitionLookup alphabet (transitionTable alphabet P) q a = delta P q a := by unfold transitionLookup transitionTable have hrow : ((List.range (P.length + 1)).map (fun q => alphabet.map (fun a => delta P q a))).getD q [] = alphabet.map (fun a => delta P q a) := by rw [List.getD_eq_getElem] · rw [List.getElem_map, List.getElem_range] · rw [List.length_map, List.length_range] omega rw [hrow] have hlt : alphabet.idxOf a < alphabet.length := (List.idxOf_lt_length_iff).mpr ha have hlen : alphabet.idxOf a < (alphabet.map (fun a => delta P q a)).length := by simpa using hlt rw [List.getD_eq_getElem (l := alphabet.map (fun a => delta P q a)) (d := 0) (n := alphabet.idxOf a) hlen] rw [List.getElem_map] rw [List.getElem_idxOf hlt]

The table-driven scan: the same left-to-right scan as dfaScan, but each transition uses a table expression. This legacy definition contains table construction inside each recursive call; CachedScan instead accepts a previously constructed table as an explicit parameter.

def dfaScanTable (alphabet : List α) (P : Text α) (m : ℕ) (scanned : Text α) (q : ℕ) : Text α → List ℕ | [] => if q == m then [scanned.length - m] else [] | c :: rest => let q' := transitionLookup alphabet (transitionTable alphabet P) q c let tail := dfaScanTable alphabet P m (scanned ++ [c]) q' rest if q == m then (scanned.length - m) :: tail else tail
automatically included section variable(s) unused in theorem `CLRS.Chapter32.dfaScanTable_cons`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.dfaScanTable_cons`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.dfaScanTable_cons`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.dfaScanTable_cons`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.dfaScanTable_cons`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma dfaScanTable_cons (alphabet : List α) (P : Text α) (m : ℕ) (scanned : Text α) (q : ℕ) (c : α) (T : Text α) : dfaScanTable alphabet P m scanned q (c :: T) = (if q == m then [scanned.length - m] else []) ++ dfaScanTable alphabet P m (scanned ++ [c]) (transitionLookup alphabet (transitionTable alphabet P) q c) T := by by_cases h : q == m <;> simp [dfaScanTable, h]

The table-driven matcher (CLRS FINITE-AUTOMATON-MATCHER with precomputed δ): the reference scan over a table expression. List lookup and alphabet indexing do not provide constant-time transitions.

def dfaMatcherTable (alphabet : List α) (P T : Text α) : List ℕ := dfaScanTable alphabet P P.length [] 0 T

The table-driven scan agrees with the semantic scan when every state is in range and every scanned character is in the alphabet.

lemma dfaScanTable_eq_dfaScan (alphabet : List α) (P : Text α) (scanned T : Text α) (q : ℕ) (hq : q ≤ P.length) (hT : ∀ c ∈ T, c ∈ alphabet) : dfaScanTable alphabet P P.length scanned q T = dfaScan P P.length scanned q T := by induction T generalizing scanned q with | nil => rfl | cons c T ih => rw [dfaScanTable_cons, dfaScan_cons] have hlookup : transitionLookup alphabet (transitionTable alphabet P) q c = delta P q c := transitionLookup_eq_delta alphabet P q hq c (hT c (by simp)) have hq' : delta P q c ≤ P.length := by unfold delta; exact suffixLen_le P (P.take q ++ [c]) have hT' : ∀ c ∈ T, c ∈ alphabet := by intro c hc; exact hT c (by simp [hc]) rw [hlookup, ih (scanned ++ [c]) (delta P q c) hq' hT']

The table-driven matcher refines the semantic automaton matcher over a finite alphabet: when every character of T lies in alphabet, the two return exactly the same shifts.

theorem dfaMatcherTable_correct (alphabet : List α) (P T : Text α) (hT : ∀ c ∈ T, c ∈ alphabet) : dfaMatcherTable alphabet P T = dfaMatcher P T := by unfold dfaMatcherTable dfaMatcher exact dfaScanTable_eq_dfaScan alphabet P [] T 0 (by omega) hT

The table-driven matcher returns exactly the shifts of naiveMatcher when the text stays within the alphabet.

theorem dfaMatcherTable_eq_naive (alphabet : List α) (P T : Text α) (hT : ∀ c ∈ T, c ∈ alphabet) : dfaMatcherTable alphabet P T = naiveMatcher T P := by rw [dfaMatcherTable_correct alphabet P T hT, dfaMatcher_correct]

Table-cell count, excluding the suffix-search work used to compute each transition and excluding allocation costs.

def transitionTableBuildCost (alphabet : List α) (P : Text α) : ℕ := ((transitionTable alphabet P).map List.length).sum

The table has (|P| + 1) * |alphabet| cells, one per state/symbol pair. This does not prove that the suffix-search builder runs in that many operations.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionTableBuildCost_eq`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionTableBuildCost_eq`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionTableBuildCost_eq`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionTableBuildCost_eq`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionTableBuildCost_eq`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionTableBuildCost_eq`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.transitionTableBuildCost_eq`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem transitionTableBuildCost_eq (alphabet : List α) (P : Text α) : transitionTableBuildCost alphabet P = (P.length + 1) * alphabet.length := by unfold transitionTableBuildCost transitionTable rw [List.map_map] change ((List.range (P.length + 1)).map (fun q => List.length (alphabet.map (fun a => delta P q a)))).sum = (P.length + 1) * alphabet.length simp [List.length_map, List.length_range, List.sum_replicate]

Sum of the table-cell and transition-request budgets, not total runtime.

theorem dfaTotalCost_eq (alphabet : List α) (P T : Text α) : transitionTableBuildCost alphabet P + dfaMatcherCost P T = (P.length + 1) * alphabet.length + T.length := by rw [transitionTableBuildCost_eq, dfaMatcherCost_eq]
end TransitionTableend Chapter32end CLRS

Definitions and proofs

CLRSLean.FourthEdition.Chapter_32.Section_32_3_Finite_Automata.CachedScan

One constructed transition table and a counted scan

The table is an explicit scan parameter and is built once by the matcher. Counters count table cells and transition requests only. Suffix search inside delta, alphabet indexing and list-table lookup are not constant-time operations in this representation, so these counts are not construction or machine-runtime bounds.

namespace CLRS.Chapter32.DFAExecutionvariable {α : Type} [BEq α] [DecidableEq α] [LawfulBEq α]structure Scan where positions : List Nat transitions : Natdef scan (alphabet : List α) (table : List (List Nat)) (m : Nat) : Nat → Nat → Text α → Scan | processed, q, [] => ⟨if q == m then [processed-m] else [],0⟩ | processed, q, c :: rest => let next := transitionLookup alphabet table q c let tail := scan alphabet table m (processed+1) next rest ⟨if q == m then (processed-m)::tail.positions else tail.positions, tail.transitions+1⟩omit [DecidableEq α] [LawfulBEq α] in @[simp] theorem scan_transitions (alphabet : List α) (table : List (List Nat)) (m processed q : Nat) (xs : Text α) : (scan alphabet table m processed q xs).transitions = xs.length := by induction xs generalizing processed q with | nil => rfl | cons c xs ih => simp [scan, ih]omit [DecidableEq α] [LawfulBEq α] in theorem scan_refines (alphabet : List α) (P : Text α) (m : Nat) (scanned : Text α) (q : Nat) (xs : Text α) : (scan alphabet (transitionTable alphabet P) m scanned.length q xs).positions = dfaScanTable alphabet P m scanned q xs := by induction xs generalizing scanned q with | nil => rfl | cons c xs ih => simp only [scan, dfaScanTable] have h := ih (scanned ++ [c]) (transitionLookup alphabet (transitionTable alphabet P) q c) simpa using congrArg (fun tail => if q == m then (scanned.length-m)::tail else tail) hstructure Result where table : List (List Nat) positions : List Nat cells : Nat transitions : Natdef execute (alphabet : List α) (P T : Text α) : Result := let table := transitionTable alphabet P let output := scan alphabet table P.length 0 0 T ⟨table, output.positions, (table.map List.length).sum, output.transitions⟩@[simp] automatically included section variable(s) unused in theorem `CLRS.Chapter32.DFAExecution.execute_transitions`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem execute_transitions (alphabet : List α) (P T : Text α) : (execute alphabet P T).transitions = T.length := scan_transitions _ _ _ _ _ _@[simp] theorem execute_cells (alphabet : List α) (P T : Text α) : (execute alphabet P T).cells = (P.length + 1) * alphabet.length := transitionTableBuildCost_eq _ _theorem execute_correct (alphabet : List α) (P T : Text α) (hT : ∀ c ∈ T, c ∈ alphabet) : (execute alphabet P T).positions = naiveMatcher T P := by have h := scan_refines alphabet P P.length [] 0 T change (scan alphabet (transitionTable alphabet P) P.length 0 0 T).positions = _ exact h.trans (dfaMatcherTable_eq_naive alphabet P T hT)end CLRS.Chapter32.DFAExecution
Imports
set_option maxHeartbeats 1000000

32.4. The Knuth–Morris–Pratt Algorithm

The Knuth–Morris–Pratt algorithm (CLRS §32.4) finds all occurrences of a pattern P in a text T in time O(|P| + |T|) by precomputing a prefix function π on the pattern, then scanning the text once, falling back along π whenever a match attempt fails.

Key definitions

  • prefixLen P q — the prefix function π[q]: the longest proper prefix of P that is a suffix of P.take q.

  • computePrefixFunction P — the executable COMPUTE-PREFIX-FUNCTION (failure-link recurrence), returning the prefix array.

  • kmpMatcher P T — the executable all-occurrences KMP-MATCHER scan.

Main results

  • prefixLen_satisfies / prefixLen_maximal — P.take (π q) is the longest proper prefix of P that is a suffix of P.take q.

  • prefixLen_chain_step — the CLRS Lemma 32.5 induction step: a shorter prefix-suffix of P.take q is a prefix-suffix of P.take (π q).

  • prefixLen_snoc_eq — the CLRS Lemma 32.6 recurrence: π(q + 1) extends the longest prefix-suffix of P.take q whose next character matches P[q].

  • failureFollow_eq_prefixMatchAux — following failure links from π(q) agrees with the from-scratch search.

  • computePrefixFunction_correct — each entry of the executable array equals prefixLen (CLRS Lemma 32.6).

  • kmpStep_eq_delta — one executable scan step computes the automaton transition δ(q, a).

  • kmpMatcher_correct — kmpMatcher P T agrees with naiveMatcher T P (all and only matches), with kmpMatcher_sound/kmpMatcher_complete.

  • kmpTotalCost_le — the costed prefix construction plus costed scan runs in linear time O(|P| + |T|).

Notation conventions used in this section:

  • P : the pattern

  • T : the text

  • π : the prefix function (written prefixLen P)

namespace CLRSnamespace Chapter32variable {α : Type} [BEq α] [DecidableEq α] [LawfulBEq α] [Inhabited α]

Search for the largest k ≤ n such that P.take k is a suffix of x.

def prefixLenAux (P x : Text α) : ℕ → ℕ | 0 => 0 | n + 1 => if suffixTest (P.take (n + 1)) x then n + 1 else prefixLenAux P x n

The prefix function π(q): the longest proper prefix of P that is a suffix of P.take q (CLRS §32.4). Bounded by q - 1 so it is always proper.

def prefixLen (P : Text α) (q : ℕ) : ℕ := prefixLenAux P (P.take q) (q - 1)

prefixLenAux never exceeds its bound.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLenAux_le`: [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLenAux_le`: [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLenAux_le`: [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLenAux_le`: [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLenAux_le`: [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLenAux_le`: [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLenAux_le`: [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLenAux_le`: [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLenAux_le`: [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLenAux_le`: [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLenAux_le`: [DecidableEq α] [LawfulBEq α] [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma prefixLenAux_le (P x : Text α) (n : ℕ) : prefixLenAux P x n ≤ n := by induction n with | zero => simp [prefixLenAux] | succ n ih => by_cases h : suffixTest (P.take (n + 1)) x · simp [prefixLenAux, h] · simp [prefixLenAux, h]; omega

The prefix function never exceeds its index.

theorem prefixLen_le (P : Text α) (q : ℕ) : prefixLen P q ≤ q := by unfold prefixLen exact le_trans (prefixLenAux_le P (P.take q) (q - 1)) (by omega)

The prefix function is proper when its index is positive.

theorem prefixLen_lt_of_pos (P : Text α) (q : ℕ) (hq : 0 < q) : prefixLen P q < q := by unfold prefixLen have hle := prefixLenAux_le P (P.take q) (q - 1) omega

P.take (π q) is a suffix of P.take q.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`try 'simp' instead of 'simpa' Note: This linter can be disabled with `set_option linter.unnecessarySimpa false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_satisfies`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem prefixLen_satisfies (P : Text α) (q : ℕ) : isSuffix (P.take (prefixLen P q)) (P.take q) := by unfold prefixLen have hgo : ∀ n, prefixLenAux P (P.take q) n = 0 ∨ suffixTest (P.take (prefixLenAux P (P.take q) n)) (P.take q) = true := by intro n induction n with | zero => left; simp [prefixLenAux] | succ n ih => by_cases h : suffixTest (P.take (n + 1)) (P.take q) · right; try 'simp' instead of 'simpa' Note: This linter can be disabled with `set_option linter.unnecessarySimpa false`simpa [prefixLenAux, h] using h · simpa [prefixLenAux, h] using ih rcases hgo (q - 1) with hzero | hsuf · rw [hzero]; exact isSuffix_empty _ · exact (suffixTest_eq_isSuffix _ _).mp hsuf

π(q) is maximal among proper prefixes of P that are suffixes of P.take q.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`Try `simp at ht` instead of `simpa using ht` Note: This linter can be disabled with `set_option linter.unnecessarySimpa false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixLen_maximal`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`theorem prefixLen_maximal (P : Text α) (q k : ℕ) (hk : k < q) (hsuf : isSuffix (P.take k) (P.take q)) : k ≤ prefixLen P q := by unfold prefixLen have ht : suffixTest (P.take k) (P.take q) = true := (suffixTest_eq_isSuffix _ _).mpr hsuf have hgo : ∀ n, k ≤ n → k ≤ prefixLenAux P (P.take q) n := by intro n hkn induction n with | zero => omega | succ n ih => by_cases hts : suffixTest (P.take (n + 1)) (P.take q) · simp [prefixLenAux, hts]; omega · have hklt : k < n + 1 := by by_cases hk_eq : k = n + 1 · subst k; Try `simp at ht` instead of `simpa using ht` Note: This linter can be disabled with `set_option linter.unnecessarySimpa false`simpa [hts] using ht · omega have := ih (by omega) simpa [prefixLenAux, hts] using this have hle : k ≤ q - 1 := by omega exact hgo (q - 1) hle

Follow failure links from k: repeatedly replace k by π[k-1] while k > 0 and P[k] ≠ c, returning the first k (along the chain) with P[k] = c, or 0. hinv guarantees every π[i] < i + 1, so the chain strictly decreases.

def failureFollow (P : Text α) (π : List ℕ) (c : α) (k : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) : ℕ := if hk : k = 0 then 0 else if (P.getD k default) = c then k else failureFollow P π c (π.getD (k - 1) 0) hinv termination_by k decreasing_by simp_wf have hpos : 0 < k := Nat.pos_of_ne_zero hk have hk' : (k - 1) + 1 = k := by omega simpa [hk'] using hinv (k - 1)

failureFollow never increases its argument.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma failureFollow_le (P : Text α) (π : List ℕ) (c : α) (k : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) : failureFollow P π c k hinv ≤ k := by rw [failureFollow.eq_1] by_cases hk : k = 0 · simp [hk] · simp [hk] by_cases hc : P[k]?.getD default = c · simp [hc] · simp [hc] have ih := failureFollow_le P π c (π.getD (k - 1) 0) hinv have hlt : π.getD (k - 1) 0 < k := by have hpos : 0 < k := Nat.pos_of_ne_zero hk have h := hinv (k - 1) omega exact le_of_lt (lt_of_le_of_lt ih hlt) termination_by k decreasing_by simp_wf have hpos : 0 < k := Nat.pos_of_ne_zero hk have hk' : (k - 1) + 1 = k := by omega simpa [hk'] using hinv (k - 1)

The executable COMPUTE-PREFIX-FUNCTION (CLRS §32.4). π is the prefix array computed so far (length q), k = π[q-1], and hinv records that every π[i] < i + 1; hk_lt records k < π.length.

def computePrefixGo (P : Text α) (π : List ℕ) (k : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) (hk_lt : k < π.length) : Text α → List ℕ | [] => π | c :: rest => let k' := failureFollow P π c k hinv let k'' := if (P.getD k' default) = c then k' + 1 else 0 have hk'le : k' ≤ k := failureFollow_le P π c k hinv have hk'lt : k' < π.length := lt_of_le_of_lt hk'le hk_lt have hk''le : k'' ≤ π.length := by unfold k'' split <;> omega have hinv' : ∀ i, (π ++ [k'']).getD i 0 < i + 1 := by intro i by_cases hi : i < π.length · rw [List.getD_append π [k''] 0 i hi] exact hinv i · have hge : π.length ≤ i := by omega rw [List.getD_append_right π [k''] 0 i hge] have hle : [k''].getD (i - π.length) 0 ≤ k'' := by by_cases h : i - π.length = 0 <;> simp [List.getD, h] omega have hk''lt : k'' < (π ++ [k'']).length := by simp [hk''le] computePrefixGo P (π ++ [k'']) k'' hinv' hk''lt rest

The executable prefix-function array: (computePrefixFunction P)[q] is the prefix function π(q) (CLRS §32.4).

def computePrefixFunction (P : Text α) : List ℕ := match P with | [] => [] | a :: as => computePrefixGo P [0] 0 (by intro i; simp) (by simp) as

If k < π(q) and P.take k is a suffix of P.take q, then P.take k is also a suffix of P.take (π q) (CLRS Lemma 32.5, induction step).

lemma prefixLen_chain_step (P : Text α) (q k : ℕ) (hk : isSuffix (P.take k) (P.take q)) (hklt : k < prefixLen P q) : isSuffix (P.take k) (P.take (prefixLen P q)) := by have hpfx : isSuffix (P.take (prefixLen P q)) (P.take q) := prefixLen_satisfies P q have hlen : (P.take k).length ≤ (P.take (prefixLen P q)).length := by simp [List.length_take] omega exact isSuffix_of_suffix_of_suffix hpfx hk hlen

Search for the largest k ≤ n such that P.take k is a suffix of P.take q and P[k] = c.

def prefixMatchAux (P : Text α) (q : ℕ) (c : α) : ℕ → ℕ | 0 => 0 | n + 1 => if suffixTest (P.take (n + 1)) (P.take q) && (P.getD (n + 1) default == c) then n + 1 else prefixMatchAux P q c n

One plus the largest k < q such that P.take k is a suffix of P.take q and P[k] = c, or 0 when no such k exists.

def prefixMatch (P : Text α) (q : ℕ) (c : α) : ℕ := let k := prefixMatchAux P q c (q - 1) if suffixTest (P.take k) (P.take q) && (P.getD k default == c) then k + 1 else 0

prefixMatchAux never exceeds its bound.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_le`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma prefixMatchAux_le (P : Text α) (q : ℕ) (c : α) (n : ℕ) : prefixMatchAux P q c n ≤ n := by induction n with | zero => simp [prefixMatchAux] | succ n ih => unfold prefixMatchAux split <;> omega

If prefixMatchAux returns a nonzero value, that value's character matches c.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_char`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_char`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_char`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_char`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_char`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_char`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_char`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_char`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_char`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_char`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_char`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_char`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_char`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_char`: [DecidableEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma prefixMatchAux_char (P : Text α) (q : ℕ) (c : α) (n : ℕ) : prefixMatchAux P q c n = 0 ∨ (P.getD (prefixMatchAux P q c n) default == c) = true := by induction n with | zero => simp [prefixMatchAux] | succ n ih => unfold prefixMatchAux split · next h => right; exact (Bool.and_eq_true_iff.mp h).2 · next _ => exact ih

prefixMatchAux is maximal: any candidate below the bound is at most its result.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_maximal`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma prefixMatchAux_maximal (P : Text α) (q : ℕ) (c : α) (n k : ℕ) (hk : k ≤ n) (hsuf : suffixTest (P.take k) (P.take q) = true) (hchar : (P.getD k default == c) = true) : k ≤ prefixMatchAux P q c n := by induction n with | zero => omega | succ n ih => unfold prefixMatchAux split · next _ => omega · next hnot => have hkne : k ≠ n + 1 := by intro hkk apply hnot subst k rw [hsuf, hchar] rfl have hklt : k ≤ n := by omega exact ih hklt

If a candidate exists below the bound, the result of prefixMatchAux is itself a candidate (its character matches c).

automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_found`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma prefixMatchAux_found (P : Text α) (q : ℕ) (c : α) (n : ℕ) (hex : ∃ j, j ≤ n ∧ (suffixTest (P.take j) (P.take q) && (P.getD j default == c)) = true) : (P.getD (prefixMatchAux P q c n) default == c) = true := by induction n with | zero => rcases hex with ⟨j, hj, hjprop⟩ have hj0 : j = 0 := by omega change (P.getD 0 default == c) = true rw [hj0] at hjprop exact (Bool.and_eq_true_iff.mp hjprop).2 | succ n ih => unfold prefixMatchAux by_cases ht : (suffixTest (P.take (n+1)) (P.take q) && (P.getD (n+1) default == c)) = true · rw [ht] exact (Bool.and_eq_true_iff.mp ht).2 · have htf : (suffixTest (P.take (n+1)) (P.take q) && (P.getD (n+1) default == c)) = false := by cases hh : (suffixTest (P.take (n+1)) (P.take q) && (P.getD (n+1) default == c)) · rfl · exact (ht hh).elim rw [htf] rcases hex with ⟨j, hj, hjprop⟩ have hjne : j ≠ n + 1 := by intro hjj rw [hjj] at hjprop exact (ht hjprop).elim have hjle : j ≤ n := by omega exact ih ⟨j, hjle, hjprop⟩

The empty prefix P.take 0 = [] is always a suffix of P.take q.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_take_zero`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_take_zero`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.suffixTest_take_zero`: [Inhabited α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [Inhabited α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma suffixTest_take_zero (P : Text α) (q : ℕ) : suffixTest (P.take 0) (P.take q) = true := by exact (suffixTest_eq_isSuffix (P.take 0) (P.take q)).mpr (isSuffix_empty _)

prefixMatchAux always returns a value whose prefix is a suffix of P.take q.

lemma prefixMatchAux_satisfies (P : Text α) (q : ℕ) (c : α) (n : ℕ) : suffixTest (P.take (prefixMatchAux P q c n)) (P.take q) = true := by induction n with | zero => simp [prefixMatchAux]; exact suffixTest_take_zero P q | succ n ih => unfold prefixMatchAux split · next h => exact (Bool.and_eq_true_iff.mp h).1 · next _ => exact ih

If P.take r is a suffix of P.take q ++ [a] with 0 < r ≤ P.length, then the character P[r-1] equals a.

lemma suffix_snoc_char_eq (P : Text α) (q r : ℕ) (a : α) (hrpos : 0 < r) (hrle : r ≤ P.length) (hsuf : isSuffix (P.take r) (P.take q ++ [a])) : P.getD (r - 1) default = a := by have hchar : (P.take r).getLast? = some a := suffix_last_char_of_snoc P (P.take q) r a hsuf hrpos hrle have htake : P.take r = P.take (r - 1) ++ [a] := take_eq_take_pred_append P r a hrpos hrle hchar have hlenr : (P.take r).length = r := by rw [List.length_take]; exact Nat.min_eq_left hrle have hlt : r - 1 < (P.take r).length := by rw [hlenr]; omega have hltP : r - 1 < P.length := by omega have h1 : (P.take r).getD (r - 1) default = P.getD (r - 1) default := by rw [List.getD_eq_getElem (P.take r) default hlt] rw [List.getElem_take] rw [← List.getD_eq_getElem P default hltP] have h2 : (P.take (r - 1) ++ [a]).getD (r - 1) default = a := by have hlen : (P.take (r - 1)).length = r - 1 := by rw [List.length_take] exact Nat.min_eq_left (by omega) rw [List.getD_append_right (P.take (r - 1)) [a] default (r - 1) (by omega)] simp [hlen] calc P.getD (r - 1) default = (P.take r).getD (r - 1) default := h1.symm _ = (P.take (r - 1) ++ [a]).getD (r - 1) default := by rw [htake] _ = a := h2

prefixMatch P q c equals k + 1 when the search result's character matches c, and 0 otherwise.

lemma prefixMatch_eq (P : Text α) (q : ℕ) (c : α) : prefixMatch P q c = if (P.getD (prefixMatchAux P q c (q - 1)) default == c) then prefixMatchAux P q c (q - 1) + 1 else 0 := by unfold prefixMatch dsimp rw [prefixMatchAux_satisfies P q c (q - 1)] rfl

The recurrence (CLRS Lemma 32.6): π(q + 1) extends the longest proper prefix-suffix of P.take q whose next character matches P[q].

`List.take_succ` has been deprecated: Use `List.take_add_one` instead`List.take_succ` has been deprecated: Use `List.take_add_one` instead theorem prefixLen_snoc_eq (P : Text α) (q : ℕ) (hqpos : 0 < q) (hq : q < P.length) : prefixLen P (q + 1) = prefixMatch P q (P.getD q default) := by have hqlen : q + 1 ≤ P.length := Nat.succ_le_of_lt hq have htake : P.take (q + 1) = P.take q ++ [P.getD q default] := by rw [`List.take_succ` has been deprecated: Use `List.take_add_one` insteadList.take_succ] congr 1 rw [List.getD_eq_getElem P default (by omega : q < P.length)] simp let c := P.getD q default let k := prefixMatchAux P q c (q - 1) have hksuf : suffixTest (P.take k) (P.take q) = true := by dsimp [k] exact prefixMatchAux_satisfies P q c (q - 1) have hkle : k ≤ q - 1 := by dsimp [k] exact prefixMatchAux_le P q c (q - 1) have hklt : k < q := by omega have hkltP : k < P.length := by omega -- direction ≤ : π(q+1) ≤ prefixMatch P q c have hle : prefixLen P (q + 1) ≤ prefixMatch P q c := by by_cases h0 : prefixLen P (q + 1) = 0 · rw [h0] exact Nat.zero_le _ · let r := prefixLen P (q + 1) have hrpos : 0 < r := Nat.pos_of_ne_zero h0 have hrle : r ≤ P.length := le_trans (prefixLen_le P (q + 1)) hqlen have hrle' : r ≤ q := by have hlt := prefixLen_lt_of_pos P (q + 1) (by omega) dsimp [r] omega have hsat := prefixLen_satisfies P (q + 1) rw [htake] at hsat have hpre : isSuffix (P.take (r - 1)) (P.take q) := suffix_dropLast_of_snoc P (P.take q) r c hrpos hrle hsat have hlastchar : P.getD (r - 1) default = c := suffix_snoc_char_eq P q r c hrpos hrle hsat have hsuf' : suffixTest (P.take (r - 1)) (P.take q) = true := (suffixTest_eq_isSuffix _ _).mpr hpre have hchar' : (P.getD (r - 1) default == c) = true := beq_iff_eq.mpr hlastchar have hcand : (suffixTest (P.take (r - 1)) (P.take q) && (P.getD (r - 1) default == c)) = true := by rw [hsuf', hchar'] rfl have hmax : r - 1 ≤ k := prefixMatchAux_maximal P q c (q - 1) (r - 1) (by omega) hsuf' hchar' have hchar_k : (P.getD k default == c) = true := prefixMatchAux_found P q c (q - 1) ⟨r - 1, by omega, hcand⟩ have hpm : prefixMatch P q c = k + 1 := by rw [prefixMatch_eq] dsimp [k] at hchar_k rw [hchar_k] rfl rw [hpm] omega -- direction ≥ : prefixMatch P q c ≤ π(q+1) have hge : prefixMatch P q c ≤ prefixLen P (q + 1) := by by_cases hck : (P.getD k default == c) = true · have hchar : P.getD k default = c := beq_iff_eq.mp hck have hksuf' : isSuffix (P.take k) (P.take q) := (suffixTest_eq_isSuffix _ _).mp hksuf have htakek : P.take (k + 1) = P.take k ++ [P.getD k default] := by rw [`List.take_succ` has been deprecated: Use `List.take_add_one` insteadList.take_succ] congr 1 rw [List.getD_eq_getElem P default (by omega : k < P.length)] simp have hsufk1 : isSuffix (P.take (k + 1)) (P.take (q + 1)) := by rw [htakek, htake] have hchar' : P.getD k default = P.getD q default := by dsimp [c] at hchar exact hchar have hsuf0 : isSuffix (P.take k ++ [P.getD k default]) (P.take q ++ [P.getD k default]) := suffix_append_right hksuf' rw [← hchar'] exact hsuf0 have hklt1 : k + 1 < q + 1 := by omega have hk1 : k + 1 ≤ prefixLen P (q + 1) := prefixLen_maximal P (q + 1) (k + 1) hklt1 hsufk1 have hpm : prefixMatch P q c = k + 1 := by rw [prefixMatch_eq] dsimp [k] at hck rw [hck] rfl rw [hpm] exact hk1 · have hpm : prefixMatch P q c = 0 := by rw [prefixMatch_eq] have hf : (P.getD (prefixMatchAux P q c (q - 1)) default == c) = false := by dsimp [k] at hck cases hh : (P.getD (prefixMatchAux P q c (q - 1)) default == c) · rfl · exact (hck hh).elim rw [hf] rfl rw [hpm] exact Nat.zero_le _ exact le_antisymm hle hge

When P.take (n+1) is not a suffix of P.take q, prefixMatchAux at n+1 falls through to n.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_succ_of_not_suffix`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_succ_of_not_suffix`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_succ_of_not_suffix`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma prefixMatchAux_succ_of_not_suffix (P : Text α) (q : ℕ) (c : α) (n : ℕ) (h : suffixTest (P.take (n + 1)) (P.take q) = false) : prefixMatchAux P q c (n + 1) = prefixMatchAux P q c n := by simp [prefixMatchAux, h]

If no value in (n', n] is a suffix of P.take q, the search from n agrees with the search from n'.

lemma prefixMatchAux_drop (P : Text α) (q : ℕ) (c : α) (n n' : ℕ) (hle : n' ≤ n) (h : ∀ j, n' < j → j ≤ n → suffixTest (P.take j) (P.take q) = false) : prefixMatchAux P q c n = prefixMatchAux P q c n' := by induction n generalizing n' with | zero => have hn' : n' = 0 := by omega subst n' rfl | succ n ih => by_cases hn' : n' = n + 1 · subst n'; rfl · have hn'le : n' ≤ n := by omega have hsuf : suffixTest (P.take (n + 1)) (P.take q) = false := h (n + 1) (by omega) (by omega) rw [prefixMatchAux_succ_of_not_suffix P q c n hsuf] exact ih n' hn'le (fun j hj1 hj2 => h j hj1 (by omega))

prefixMatchAux is insensitive to the suffix target q, provided the suffix tests agree on every position up to the bound.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.prefixMatchAux_congr`: [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma prefixMatchAux_congr (P : Text α) (q q' : ℕ) (c : α) (n : ℕ) (h : ∀ j, j ≤ n → (suffixTest (P.take j) (P.take q) = true ↔ suffixTest (P.take j) (P.take q') = true)) : prefixMatchAux P q c n = prefixMatchAux P q' c n := by induction n with | zero => rfl | succ n ih => have hsuf : suffixTest (P.take (n + 1)) (P.take q) = suffixTest (P.take (n + 1)) (P.take q') := by have hiff := h (n + 1) (by omega) revert hiff generalize hq : suffixTest (P.take (n + 1)) (P.take q) = b1 generalize hq' : suffixTest (P.take (n + 1)) (P.take q') = b2 intro hiff cases b1 <;> cases b2 <;> simp_all have ih' : prefixMatchAux P q c n = prefixMatchAux P q' c n := ih (fun j hj => h j (by omega)) rw [prefixMatchAux, prefixMatchAux] rw [hsuf] rw [ih']

The from-scratch search from k - 1 over P.take q agrees with the search from prefixLen P k over P.take k, when k = prefixLen P q (the failure-link jump).

lemma prefixMatchAux_chain_jump (P : Text α) (q k : ℕ) (c : α) (hk : k = prefixLen P q) (hkpos : 0 < k) : prefixMatchAux P q c (k - 1) = prefixMatchAux P k c (prefixLen P k) := by have hplt : prefixLen P k < k := prefixLen_lt_of_pos P k hkpos have hdrop : prefixMatchAux P q c (k - 1) = prefixMatchAux P q c (prefixLen P k) := by refine prefixMatchAux_drop P q c (k - 1) (prefixLen P k) (by omega) ?_ intro j hj1 hj2 by_contra hsj have hsjt : suffixTest (P.take j) (P.take q) = true := by cases h : suffixTest (P.take j) (P.take q) with | false => exact (hsj h).elim | true => rfl have hjsuf : isSuffix (P.take j) (P.take q) := (suffixTest_eq_isSuffix _ _).mp hsjt have hjltpl : j < prefixLen P q := by rw [← hk]; omega have hchain : isSuffix (P.take j) (P.take k) := by simpa [hk] using (prefixLen_chain_step P q j hjsuf hjltpl) have hjltk : j < k := by omega have hmax : j ≤ prefixLen P k := prefixLen_maximal P k j hjltk hchain omega have hcongr : prefixMatchAux P q c (prefixLen P k) = prefixMatchAux P k c (prefixLen P k) := by refine prefixMatchAux_congr P q k c (prefixLen P k) ?_ intro j hj constructor · intro hsjt have hjsuf : isSuffix (P.take j) (P.take q) := (suffixTest_eq_isSuffix _ _).mp hsjt have hjltpl : j < prefixLen P q := by rw [← hk] omega have hchain : isSuffix (P.take j) (P.take k) := by simpa [hk] using (prefixLen_chain_step P q j hjsuf hjltpl) exact (suffixTest_eq_isSuffix _ _).mpr hchain · intro hsjt have hjsuf : isSuffix (P.take j) (P.take k) := (suffixTest_eq_isSuffix _ _).mp hsjt have hksuf : isSuffix (P.take k) (P.take q) := by simpa [hk] using prefixLen_satisfies P q have hjsuf' : isSuffix (P.take j) (P.take q) := suffix_trans hjsuf hksuf exact (suffixTest_eq_isSuffix _ _).mpr hjsuf' exact hdrop.trans hcongr

Following failure links from k = π(q) agrees with the from-scratch search prefixMatchAux P q c k, when π is the correct prefix-function array.

lemma failureFollow_eq_prefixMatchAux (P : Text α) (π : List ℕ) (c : α) (q k : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) (hπ : ∀ i, i < q → π.getD i 0 = prefixLen P (i + 1)) (hk : k = prefixLen P q) : failureFollow P π c k hinv = prefixMatchAux P q c k := by revert q refine Nat.strong_induction_on k ?_ intro k ih q hπ hk by_cases hk0 : k = 0 · subst hk0 rw [failureFollow.eq_1, prefixMatchAux] rfl · have hkpos : 0 < k := Nat.pos_of_ne_zero hk0 have hsuf : suffixTest (P.take k) (P.take q) = true := by simpa [hk] using (suffixTest_eq_isSuffix _ _).mpr (prefixLen_satisfies P q) obtain ⟨n, rfl⟩ := Nat.exists_eq_succ_of_ne_zero hk0 have hqpos : 0 < q := by have hle := prefixLen_le P q rw [← hk] at hle omega have hnltq : n < q := by have hlt := prefixLen_lt_of_pos P q hqpos rw [← hk] at hlt omega rw [failureFollow.eq_1] simp only [Nat.succ_ne_zero, This simp argument is unused: if_false Hint: Omit it from the simp argument list. simp only [Nat.succ_ne_zero,̵ ̵i̵f̵_̵f̵a̵l̵s̵e̵] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`if_false] rw [prefixMatchAux] rw [hsuf] change (if P.getD (n + 1) default = c then n + 1 else failureFollow P π c (π.getD n 0) hinv) = (if (P.getD (n + 1) default == c) = true then n + 1 else prefixMatchAux P q c n) by_cases hc : P.getD (n + 1) default = c · rw [if_pos hc, if_pos (beq_iff_eq.mpr hc)] · have hcneg : ¬ (P.getD (n + 1) default == c) = true := by intro hh exact hc (beq_iff_eq.mp hh) rw [if_neg hc, if_neg hcneg] have hπn : π.getD n 0 = prefixLen P (n + 1) := hπ n hnltq rw [hπn] have hih := ih (prefixLen P (n + 1)) (prefixLen_lt_of_pos P (n + 1) (by omega)) (n + 1) (fun i hi => hπ i (by omega)) rfl rw [hih] exact (prefixMatchAux_chain_jump P q (n + 1) c (by simpa [hk]) (by omega)).symm

prefixMatchAux from prefixLen P q agrees with the full search from q - 1.

lemma prefixMatchAux_top_drop (P : Text α) (q : ℕ) (c : α) (hqpos : 0 < q) : prefixMatchAux P q c (prefixLen P q) = prefixMatchAux P q c (q - 1) := by have hle : prefixLen P q ≤ q - 1 := by have hlt := prefixLen_lt_of_pos P q hqpos omega refine (prefixMatchAux_drop P q c (q - 1) (prefixLen P q) hle ?_).symm intro j hj1 hj2 by_contra hsj have hsjt : suffixTest (P.take j) (P.take q) = true := by cases h : suffixTest (P.take j) (P.take q) with | false => exact (hsj h).elim | true => rfl have hjsuf : isSuffix (P.take j) (P.take q) := (suffixTest_eq_isSuffix _ _).mp hsjt have hjltq : j < q := by omega have hmax : j ≤ prefixLen P q := prefixLen_maximal P q j hjltq hjsuf omega

One step of computePrefixGo computes prefixLen P (π.length + 1) (the failure-link recurrence, CLRS Lemma 32.6).

lemma computePrefixGo_step (P : Text α) (π : List ℕ) (k : ℕ) (c : α) (hinv : ∀ i, π.getD i 0 < i + 1) (hπ : ∀ i, i < π.length → π.getD i 0 = prefixLen P (i + 1)) (hk : k = prefixLen P π.length) (hc : c = P.getD π.length default) (hqpos : 0 < π.length) (hqlt : π.length < P.length) : (if (P.getD (failureFollow P π c k hinv) default) = c then failureFollow P π c k hinv + 1 else 0) = prefixLen P (π.length + 1) := by have hk' : failureFollow P π c k hinv = prefixMatchAux P π.length c (π.length - 1) := by rw [failureFollow_eq_prefixMatchAux P π c π.length k hinv hπ hk] rw [hk] exact prefixMatchAux_top_drop P π.length c hqpos have hsnoc : prefixLen P (π.length + 1) = prefixMatch P π.length c := by simpa [hc] using (prefixLen_snoc_eq P π.length hqpos hqlt) have hpm : prefixMatch P π.length c = (if (P.getD (prefixMatchAux P π.length c (π.length - 1)) default == c) then prefixMatchAux P π.length c (π.length - 1) + 1 else 0) := prefixMatch_eq P π.length c rw [hsnoc] rw [hpm, hk'] by_cases hc' : P.getD (prefixMatchAux P π.length c (π.length - 1)) default = c · rw [if_pos hc', if_pos (beq_iff_eq.mpr hc')] · have hneg : ¬ (P.getD (prefixMatchAux P π.length c (π.length - 1)) default == c) = true := by intro hh exact hc' (beq_iff_eq.mp hh) rw [if_neg hc', if_neg hneg]

failureFollow's result is independent of its hinv proof argument.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_irrelevant`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_irrelevant`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_irrelevant`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_irrelevant`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_irrelevant`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_irrelevant`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma failureFollow_irrelevant (P : Text α) (π : List ℕ) (c : α) (k : ℕ) (hinv hinv' : ∀ i, π.getD i 0 < i + 1) : failureFollow P π c k hinv = failureFollow P π c k hinv' := by unfold failureFollow by_cases hk : k = 0 <;> simp [hk]

computePrefixGo's result is independent of its hinv/hk_lt proof arguments.

lemma computePrefixGo_irrelevant (P : Text α) (π : List ℕ) (k : ℕ) (rest : Text α) (hinv hinv' : ∀ i, π.getD i 0 < i + 1) (hk_lt hk_lt' : k < π.length) : computePrefixGo P π k hinv hk_lt rest = computePrefixGo P π k hinv' hk_lt' rest := by induction rest generalizing π k hinv hinv' hk_lt hk_lt' with | nil => rfl | cons c rest' ih => unfold computePrefixGo simp [This simp argument is unused: failureFollow_irrelevant Hint: Omit it from the simp argument list. s̵i̵m̵p̵ ̵[̵f̵a̵i̵l̵u̵r̵e̵F̵o̵l̵l̵o̵w̵_̵i̵r̵r̵e̵l̵e̵v̵a̵n̵t̵,̵ ̵i̵h̵]̵s̲i̲m̲p̲ ̲[̲i̲h̲]̲ Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`failureFollow_irrelevant, This simp argument is unused: ih Hint: Omit it from the simp argument list. simp [failureFollow_irrelevant,̵ ̵i̵h̵] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`ih]

Extract the head/tail of P.drop n = c :: rest.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.drop_cons`: [BEq α] [DecidableEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [DecidableEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma drop_cons (P : Text α) (n : ℕ) (c : α) (rest : Text α) (h : P.drop n = c :: rest) : n < P.length ∧ c = P.getD n default ∧ rest = P.drop (n + 1) := by have hlen : n < P.length := by by_contra hge have hnil : P.drop n = [] := List.drop_eq_nil_of_le (by omega) rw [h] at hnil cases hnil refine ⟨hlen, ?_, ?_⟩ · have hhead : (P.drop n).head? = (c :: rest).head? := by rw [h] simp at hhead have : P.getD n default = c := by change P[n]?.getD default = c rw [hhead] rfl exact this.symm · have htail : (P.drop n).drop 1 = (c :: rest).drop 1 := by rw [h] simp at htail exact htail.symm

The invariant of computePrefixGo: it extends a correct prefix array.

lemma computePrefixGo_correct (P : Text α) (π : List ℕ) (k : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) (hk_lt : k < π.length) (hπ : ∀ i, i < π.length → π.getD i 0 = prefixLen P (i + 1)) (hk : k = prefixLen P π.length) : ∀ rest, rest = P.drop π.length → ∀ i, i < (computePrefixGo P π k hinv hk_lt rest).length → (computePrefixGo P π k hinv hk_lt rest).getD i 0 = prefixLen P (i + 1) := by intro rest hrest induction rest generalizing π k hinv hk_lt hπ hk with | nil => intro i hi simpa [computePrefixGo] using hπ i (by simpa [computePrefixGo] using hi) | cons c rest' ih => intro i hi have hd := drop_cons P π.length c rest' hrest.symm have hqlt : π.length < P.length := hd.1 have hc : c = P.getD π.length default := hd.2.1 have hrest' : rest' = P.drop (π.length + 1) := hd.2.2 have hqpos : 0 < π.length := by omega let k' := failureFollow P π c k hinv let k'' := if (P.getD k' default) = c then k' + 1 else 0 have hk'le : k' ≤ k := failureFollow_le P π c k hinv have hk''le : k'' ≤ π.length := by dsimp [k''] have hk'lt : k' < π.length := lt_of_le_of_lt hk'le hk_lt split <;> omega have hstep : k'' = prefixLen P (π.length + 1) := by dsimp [k'', k'] exact computePrefixGo_step P π k c hinv hπ hk hc hqpos hqlt have hπ' : ∀ j, j < (π ++ [k'']).length → (π ++ [k'']).getD j 0 = prefixLen P (j + 1) := by intro j hj by_cases hjπ : j < π.length · rw [List.getD_append π [k''] 0 j hjπ] exact hπ j hjπ · have hge : π.length ≤ j := by omega rw [List.getD_append_right π [k''] 0 j hge] have hj_eq : j = π.length := by have hj' : j < π.length + 1 := by simpa [List.length_append] using hj omega subst j simpa using hstep have hk' : k'' = prefixLen P (π ++ [k'']).length := by simpa [List.length_append] using hstep have hinv'' : ∀ j, (π ++ [k'']).getD j 0 < j + 1 := by intro j by_cases hjπ : j < π.length · rw [List.getD_append π [k''] 0 j hjπ] exact hinv j · have hge : π.length ≤ j := by omega rw [List.getD_append_right π [k''] 0 j hge] have hle : [k''].getD (j - π.length) 0 ≤ k'' := by by_cases h : j - π.length = 0 <;> simp [List.getD, h] omega have hk''lt : k'' < (π ++ [k'']).length := by simp [hk''le] have heq : computePrefixGo P π k hinv hk_lt (c :: rest') = computePrefixGo P (π ++ [k'']) k'' hinv'' hk''lt rest' := by rw [computePrefixGo] rw [heq] at hi ⊢ exact (ih (π ++ [k'']) k'' hinv'' hk''lt hπ' hk' (by simpa [List.length_append] using hrest')) i hi

computePrefixGo's result has length π.length + rest.length.

lemma computePrefixGo_length (P : Text α) (π : List ℕ) (k : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) (hk_lt : k < π.length) (rest : Text α) : (computePrefixGo P π k hinv hk_lt rest).length = π.length + rest.length := by induction rest generalizing π k hinv hk_lt with | nil => rfl | cons c rest' ih => rw [computePrefixGo] rw [ih] simp omega

The executable COMPUTE-PREFIX-FUNCTION array equals the prefix function prefixLen (CLRS Lemma 32.6).

theorem computePrefixFunction_correct (P : Text α) (i : ℕ) (hi : i < P.length) : (computePrefixFunction P).getD i 0 = prefixLen P (i + 1) := by cases P with | nil => simp at hi | cons a as => have hπ : ∀ j, j < 1 → [0].getD j 0 = prefixLen (a :: as) (j + 1) := by intro j hj have hj0 : j = 0 := by omega subst j simp [prefixLen, prefixLenAux] have hk : 0 = prefixLen (a :: as) 1 := by simp [prefixLen, prefixLenAux] have hres := computePrefixGo_correct (a :: as) [0] 0 (by intro j; simp) (by simp) hπ hk as (by simp) have hlen : (computePrefixGo (a :: as) [0] 0 (by intro j; simp) (by simp) as).length = (a :: as).length := by rw [computePrefixGo_length] simp omega simpa [computePrefixFunction] using (hres i (by simpa [hlen] using hi))

The executable prefix array has exactly |P| entries.

lemma computePrefixFunction_length (P : Text α) : (computePrefixFunction P).length = P.length := by cases P with | nil => simp [computePrefixFunction] | cons a as => simp [computePrefixFunction] rw [computePrefixGo_length] simp [Nat.add_comm]

Every entry of the executable prefix array is strictly below its successor index, so it can serve as the hinv termination argument of failureFollow.

lemma computePrefixFunction_inv (P : Text α) : ∀ i, (computePrefixFunction P).getD i 0 < i + 1 := by intro i by_cases hi : i < P.length · rw [computePrefixFunction_correct P i hi] exact prefixLen_lt_of_pos P (i + 1) (by omega) · rw [List.getD_eq_default (hn := by rw [computePrefixFunction_length P]; omega)] omega

The KMP scan

The advance step of the KMP scan: if the current fallback position's character matches a, extend the match by one; otherwise restart at 0. failureFollow guarantees its result is 0 whenever its character does not match a, so the else 0 branch is exactly the textbook q ← q state.

def kmpAdvance (P : Text α) (q' : ℕ) (a : α) : ℕ := if P.getD q' default = a then q' + 1 else 0

One KMP scan step (CLRS KMP-MATCHER lines 6-9): given the current state q (the number of matched characters, q ≤ |P|) and the next text character a, follow failure links until the next character matches, then advance. When q = |P| the step first falls back to π[|P|-1], which is the textbook reset q ← π[q] performed before the next character is read.

def kmpStep (P : Text α) (π : List ℕ) (q : ℕ) (a : α) (hinv : ∀ i, π.getD i 0 < i + 1) : ℕ := if q = P.length then kmpAdvance P (failureFollow P π a (π.getD (P.length - 1) 0) hinv) a else kmpAdvance P (failureFollow P π a q hinv) a

The Knuth–Morris–Pratt scan: scan T left-to-right maintaining the automaton state q = δ*(0, scanned), recording every shift where the state reaches |P|. scanned is the text already scanned and m = |P|.

def kmpScan (P : Text α) (π : List ℕ) (m : ℕ) (scanned : Text α) (q : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) : Text α → List ℕ | [] => if q == m then [scanned.length - m] else [] | c :: rest => let q' := kmpStep P π q c hinv let tail := kmpScan P π m (scanned ++ [c]) q' hinv rest if q == m then (scanned.length - m) :: tail else tail

The Knuth–Morris–Pratt matcher: the list of all shifts where P occurs in T, computed by the prefix function plus a single left-to-right scan (CLRS §32.4).

def kmpMatcher (P T : Text α) : List ℕ := if P.length = 0 then List.range (T.length + 1) else kmpScan P (computePrefixFunction P) P.length [] 0 (computePrefixFunction_inv P) T

The specification transition: δ(q, a) written as "extend by one if the character matches P[q], otherwise the longest proper prefix-suffix extension prefixMatch". This is the semantic content of one KMP scan step.

def kmpNextSpec (P : Text α) (q : ℕ) (a : α) : ℕ := if q < P.length ∧ P.getD q default = a then q + 1 else prefixMatch P q a

kmpAdvance over the from-scratch search result is exactly prefixMatch.

'change (if P.getD (prefixMatchAux P q a (q - 1)) default = a then prefixMatchAux P q a (q - 1) + 1 else 0) = (if (P.getD (prefixMatchAux P q a (q - 1)) default == a) = true then prefixMatchAux P q a (q - 1) + 1 else 0)' tactic does nothing Note: This linter can be disabled with `set_option linter.unusedTactic false` lemma kmpAdvance_eq_prefixMatch (P : Text α) (q : ℕ) (a : α) : kmpAdvance P (prefixMatchAux P q a (q - 1)) a = prefixMatch P q a := by unfold kmpAdvance rw [prefixMatch_eq P q a] 'change (if P.getD (prefixMatchAux P q a (q - 1)) default = a then prefixMatchAux P q a (q - 1) + 1 else 0) = (if (P.getD (prefixMatchAux P q a (q - 1)) default == a) = true then prefixMatchAux P q a (q - 1) + 1 else 0)' tactic does nothing Note: This linter can be disabled with `set_option linter.unusedTactic false`change (if P.getD (prefixMatchAux P q a (q - 1)) default = a then prefixMatchAux P q a (q - 1) + 1 else 0) = (if (P.getD (prefixMatchAux P q a (q - 1)) default == a) = true then prefixMatchAux P q a (q - 1) + 1 else 0) by_cases h : P.getD (prefixMatchAux P q a (q - 1)) default = a · rw [if_pos h, if_pos (beq_iff_eq.mpr h)] · rw [if_neg h] have hneg : ¬ (P.getD (prefixMatchAux P q a (q - 1)) default == a) = true := by intro hh exact h (beq_iff_eq.mp hh) rw [if_neg hneg]

If P[q] = a, the failure-link search starting at q stays at q.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_eq_self_of_char`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma failureFollow_eq_self_of_char (P : Text α) (π : List ℕ) (a : α) (q : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) (hchar : P.getD q default = a) : failureFollow P π a q hinv = q := by rw [failureFollow.eq_1] by_cases hq0 : q = 0 · simp [hq0] · simp only [hq0, This simp argument is unused: if_false Hint: Omit it from the simp argument list. simp only [hq0,̵ ̵i̵f̵_̵f̵a̵l̵s̵e̵] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`if_false] by_cases hc : P[q]?.getD default = a · simp [hc] · have hc' : P[q]?.getD default = a := by simpa using hchar exact (hc hc').elim

One fallback step: when P[q] ≠ a and q > 0, the search moves to π[q-1].

automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollow_step_eq`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma failureFollow_step_eq (P : Text α) (π : List ℕ) (a : α) (q : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) (hqpos : 0 < q) (hne : P.getD q default ≠ a) : failureFollow P π a q hinv = failureFollow P π a (π.getD (q - 1) 0) hinv := by rw [failureFollow.eq_1] by_cases hq0 : q = 0 · omega · simp only [hq0, This simp argument is unused: if_false Hint: Omit it from the simp argument list. simp only [hq0,̵ ̵i̵f̵_̵f̵a̵l̵s̵e̵] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`if_false] by_cases hc : P[q]?.getD default = a · have hc' : P[q]?.getD default = a := by simpa using hc have hne' : P[q]?.getD default ≠ a := by simpa using hne exact (hne' hc').elim · simp [hc]

The failure-link search from prefixLen P q agrees with the from-scratch search prefixMatchAux P q a (q - 1).

lemma failureFollow_from_prefixLen_eq (P : Text α) (π : List ℕ) (a : α) (q : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) (hπ : ∀ i, i < q → π.getD i 0 = prefixLen P (i + 1)) (hqpos : 0 < q) : failureFollow P π a (prefixLen P q) hinv = prefixMatchAux P q a (q - 1) := by rw [failureFollow_eq_prefixMatchAux P π a q (prefixLen P q) hinv hπ rfl] exact prefixMatchAux_top_drop P q a hqpos

When P[q] ≠ a, the failure-link search from q agrees with the from-scratch search prefixMatchAux P q a (q - 1) (for q = 0 both are 0).

lemma failureFollow_eq_prefixMatchAux_top_of_ne (P : Text α) (π : List ℕ) (a : α) (q : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) (hπ : ∀ i, i < q → π.getD i 0 = prefixLen P (i + 1)) (hne : P.getD q default ≠ a) : failureFollow P π a q hinv = prefixMatchAux P q a (q - 1) := by by_cases hq0 : q = 0 · subst q simp [failureFollow, prefixMatchAux] · have hqpos : 0 < q := by omega rw [failureFollow_step_eq P π a q hinv hqpos hne] have hπq1 : π.getD (q - 1) 0 = prefixLen P q := by have h := hπ (q - 1) (by omega) rwa [Nat.sub_add_cancel hqpos] at h rw [hπq1] exact failureFollow_from_prefixLen_eq P π a q hinv hπ hqpos

suffixLen P (P.take q ++ [a]) ≤ kmpNextSpec P q a: the suffix function of a one-step extension never exceeds the specification transition.

`List.take_succ` has been deprecated: Use `List.take_add_one` instead lemma suffixLen_snoc_le_spec (P : Text α) (q : ℕ) (a : α) (Variable name `hq` is not explicitly referenced. The binding can be removed (if unused) or named `_` (if used implicitly). Note: This linter can be disabled with `set_option linter.unusedVariables false`hq : q ≤ P.length) : suffixLen P (P.take q ++ [a]) ≤ kmpNextSpec P q a := by unfold kmpNextSpec by_cases hcond : q < P.length ∧ P.getD q default = a · rw [if_pos hcond] have hle := suffixLen_le_length P (P.take q ++ [a]) have hlen : (P.take q ++ [a]).length ≤ q + 1 := by rw [List.length_append, List.length_singleton, List.length_take] exact Nat.add_le_add_right (Nat.min_le_left q P.length) 1 omega · rw [if_neg hcond] have hr : suffixLen P (P.take q ++ [a]) ≤ P.length := suffixLen_le P (P.take q ++ [a]) have hrle : suffixLen P (P.take q ++ [a]) ≤ q + 1 := by have hle := suffixLen_le_length P (P.take q ++ [a]) have hlen : (P.take q ++ [a]).length ≤ q + 1 := by rw [List.length_append, List.length_singleton, List.length_take] exact Nat.add_le_add_right (Nat.min_le_left q P.length) 1 omega have hsuf : isSuffix (P.take (suffixLen P (P.take q ++ [a]))) (P.take q ++ [a]) := suffixLen_satisfies P (P.take q ++ [a]) set r := suffixLen P (P.take q ++ [a]) with hr_def have hr' : r ≤ P.length := by simpa [hr_def] using hr have hrle' : r ≤ q + 1 := by simpa [hr_def] using hrle have hsuf' : isSuffix (P.take r) (P.take q ++ [a]) := by simpa [hr_def] using hsuf by_cases hrq : r = q + 1 · exfalso have hqlt : q < P.length := by have : q + 1 ≤ P.length := by simpa [hrq] using hr' omega have hchar : P.getD q default = a := by have hsuf'' : isSuffix (P.take (q + 1)) (P.take q ++ [a]) := by simpa [hrq] using hsuf' have hk' : q + 1 ≤ P.length := by omega have hlast : (P.take (q + 1)).getLast? = some a := suffix_last_char_of_snoc P (P.take q) (q + 1) a hsuf'' (by omega) hk' have htake1 : P.take (q + 1) = P.take q ++ [a] := take_eq_take_pred_append P (q + 1) a (by omega) hk' hlast have htake2 : P.take (q + 1) = P.take q ++ [P.getD q default] := by rw [`List.take_succ` has been deprecated: Use `List.take_add_one` insteadList.take_succ] congr 1 rw [List.getD_eq_getElem P default (by omega : q < P.length)] simp have hconcat : P.take q ++ [a] = P.take q ++ [P.getD q default] := by rw [← htake1, ← htake2] have hsing : [a] = [P.getD q default] := by simpa [List.drop_left] using (congrArg (fun t => t.drop (P.take q).length) hconcat) exact (List.cons.inj hsing).1.symm exact hcond ⟨hqlt, hchar⟩ · have hrq' : r ≤ q := by omega by_cases hr0 : r = 0 · rw [hr0] exact Nat.zero_le _ · have hrpos : 0 < r := Nat.pos_of_ne_zero hr0 have hpre : isSuffix (P.take (r - 1)) (P.take q) := suffix_dropLast_of_snoc P (P.take q) r a hrpos hr' hsuf' have hchar : P.getD (r - 1) default = a := suffix_snoc_char_eq P q r a hrpos hr' hsuf' have hsuf_t : suffixTest (P.take (r - 1)) (P.take q) = true := (suffixTest_eq_isSuffix _ _).mpr hpre have hchar_t : (P.getD (r - 1) default == a) = true := beq_iff_eq.mpr hchar have hcand : (suffixTest (P.take (r - 1)) (P.take q) && (P.getD (r - 1) default == a)) = true := by rw [hsuf_t, hchar_t] rfl have hmax : r - 1 ≤ prefixMatchAux P q a (q - 1) := prefixMatchAux_maximal P q a (q - 1) (r - 1) (by omega) hsuf_t hchar_t have hchar_k : (P.getD (prefixMatchAux P q a (q - 1)) default == a) = true := prefixMatchAux_found P q a (q - 1) ⟨r - 1, by omega, hcand⟩ have hpm : prefixMatch P q a = prefixMatchAux P q a (q - 1) + 1 := by rw [prefixMatch_eq] rw [hchar_k] rfl rw [hpm] omega

kmpNextSpec P q a ≤ suffixLen P (P.take q ++ [a]): the specification transition never exceeds the suffix function.

`List.take_succ` has been deprecated: Use `List.take_add_one` instead`List.take_succ` has been deprecated: Use `List.take_add_one` instead lemma spec_le_suffixLen_snoc (P : Text α) (q : ℕ) (a : α) (hP : 0 < P.length) (hq : q ≤ P.length) : kmpNextSpec P q a ≤ suffixLen P (P.take q ++ [a]) := by unfold kmpNextSpec by_cases hcond : q < P.length ∧ P.getD q default = a · rw [if_pos hcond] rcases hcond with ⟨hqlt, hchar⟩ have htake0 : P.take (q + 1) = P.take q ++ [P.getD q default] := by rw [`List.take_succ` has been deprecated: Use `List.take_add_one` insteadList.take_succ] congr 1 rw [List.getD_eq_getElem P default (by omega : q < P.length)] simp have htake : P.take (q + 1) = P.take q ++ [a] := by rw [htake0, hchar] have hsuf : isSuffix (P.take (q + 1)) (P.take q ++ [a]) := by rw [htake] exact isSuffix_self _ have hk : q + 1 ≤ P.length := by omega exact suffixLen_maximal P (P.take q ++ [a]) (q + 1) hk hsuf · rw [if_neg hcond] by_cases h0 : prefixMatch P q a = 0 · rw [h0] exact Nat.zero_le _ · have hkchar : (P.getD (prefixMatchAux P q a (q - 1)) default == a) = true := by by_contra hneg have hf : (P.getD (prefixMatchAux P q a (q - 1)) default == a) = false := by cases hh : (P.getD (prefixMatchAux P q a (q - 1)) default == a) · rfl · exact (hneg hh).elim have : prefixMatch P q a = 0 := by rw [prefixMatch_eq] rw [hf] rfl exact h0 this have hkchar' : P.getD (prefixMatchAux P q a (q - 1)) default = a := beq_iff_eq.mp hkchar have hksuf : isSuffix (P.take (prefixMatchAux P q a (q - 1))) (P.take q) := (suffixTest_eq_isSuffix _ _).mp (prefixMatchAux_satisfies P q a (q - 1)) have hkle : prefixMatchAux P q a (q - 1) ≤ q - 1 := prefixMatchAux_le P q a (q - 1) have hkltP : prefixMatchAux P q a (q - 1) < P.length := by omega have htake0 : P.take (prefixMatchAux P q a (q - 1) + 1) = P.take (prefixMatchAux P q a (q - 1)) ++ [P.getD (prefixMatchAux P q a (q - 1)) default] := by rw [`List.take_succ` has been deprecated: Use `List.take_add_one` insteadList.take_succ] congr 1 rw [List.getD_eq_getElem P default (by omega : prefixMatchAux P q a (q - 1) < P.length)] simp have htake : P.take (prefixMatchAux P q a (q - 1) + 1) = P.take (prefixMatchAux P q a (q - 1)) ++ [a] := by rw [htake0, hkchar'] have hsuf1 : isSuffix (P.take (prefixMatchAux P q a (q - 1) + 1)) (P.take q ++ [a]) := by rw [htake] exact suffix_append_right hksuf have hk1 : prefixMatchAux P q a (q - 1) + 1 ≤ P.length := by omega have hle : prefixMatchAux P q a (q - 1) + 1 ≤ suffixLen P (P.take q ++ [a]) := suffixLen_maximal P (P.take q ++ [a]) (prefixMatchAux P q a (q - 1) + 1) hk1 hsuf1 have hpm : prefixMatch P q a = prefixMatchAux P q a (q - 1) + 1 := by rw [prefixMatch_eq] rw [hkchar] rfl rw [hpm] exact hle

The transition δ(q, a) equals the specification transition: q + 1 when q < |P| and P[q] = a, and prefixMatch P q a otherwise.

lemma delta_spec (P : Text α) (q : ℕ) (a : α) (hP : 0 < P.length) (hq : q ≤ P.length) : delta P q a = kmpNextSpec P q a := by unfold delta exact le_antisymm (suffixLen_snoc_le_spec P q a hq) (spec_le_suffixLen_snoc P q a hP hq)

The executable KMP step computes exactly the automaton transition δ.

lemma kmpStep_eq_delta (P : Text α) (π : List ℕ) (q : ℕ) (a : α) (hP : 0 < P.length) (hinv : ∀ i, π.getD i 0 < i + 1) (hπ : ∀ i, i < P.length → π.getD i 0 = prefixLen P (i + 1)) (hq : q ≤ P.length) : kmpStep P π q a hinv = delta P q a := by rw [delta_spec P q a hP hq] by_cases hqlt : q < P.length · have hqne : q ≠ P.length := by omega unfold kmpStep kmpNextSpec rw [if_neg hqne] by_cases hchar : P.getD q default = a · rw [if_pos ⟨hqlt, hchar⟩] have hff : failureFollow P π a q hinv = q := failureFollow_eq_self_of_char P π a q hinv hchar rw [hff] unfold kmpAdvance rw [if_pos hchar] · rw [if_neg (by intro h; exact hchar h.2)] have hπq : ∀ i, i < q → π.getD i 0 = prefixLen P (i + 1) := by intro i hi exact hπ i (by omega) have hff : failureFollow P π a q hinv = prefixMatchAux P q a (q - 1) := failureFollow_eq_prefixMatchAux_top_of_ne P π a q hinv hπq hchar rw [hff] exact kmpAdvance_eq_prefixMatch P q a · have hqe : q = P.length := by omega subst q unfold kmpStep kmpNextSpec rw [if_pos rfl] rw [if_neg (by intro h; omega)] have hπm : π.getD (P.length - 1) 0 = prefixLen P P.length := by have h := hπ (P.length - 1) (by omega) rwa [Nat.sub_add_cancel hP] at h have hff : failureFollow P π a (prefixLen P P.length) hinv = prefixMatchAux P P.length a (P.length - 1) := failureFollow_from_prefixLen_eq P π a P.length hinv hπ hP rw [hπm, hff] exact kmpAdvance_eq_prefixMatch P P.length a

The KMP scan equation across one consumed character.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.kmpScan_cons`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.kmpScan_cons`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.kmpScan_cons`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.kmpScan_cons`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.kmpScan_cons`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma kmpScan_cons (P : Text α) (π : List ℕ) (m : ℕ) (scanned : Text α) (q : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) (c : α) (T : Text α) : kmpScan P π m scanned q hinv (c :: T) = (if q == m then [scanned.length - m] else []) ++ kmpScan P π m (scanned ++ [c]) (kmpStep P π q c hinv) hinv T := by by_cases h : q == m <;> simp [kmpScan, h]

The KMP scan agrees with the finite-automaton scan when π is the correct prefix-function array.

lemma kmpScan_eq_dfaScan (P : Text α) (π : List ℕ) (hP : 0 < P.length) (hπ : ∀ i, i < P.length → π.getD i 0 = prefixLen P (i + 1)) (hinv : ∀ i, π.getD i 0 < i + 1) : ∀ (T scanned : Text α) (q : ℕ), q ≤ P.length → kmpScan P π P.length scanned q hinv T = dfaScan P P.length scanned q T := by intro T scanned q hq induction T generalizing scanned q with | nil => rfl | cons c T ih => have hstep : kmpStep P π q c hinv = delta P q c := kmpStep_eq_delta P π q c hP hinv hπ hq have hq' : kmpStep P π q c hinv ≤ P.length := by rw [hstep] unfold delta exact suffixLen_le P (P.take q ++ [c]) rw [kmpScan_cons P π P.length scanned q hinv c T] rw [dfaScan_cons P P.length scanned q c T] rw [ih (scanned ++ [c]) (kmpStep P π q c hinv) hq'] rw [hstep]

Correctness of the Knuth–Morris–Pratt matcher. kmpMatcher P T returns exactly the shifts that naiveMatcher T P returns, for every pattern and text (CLRS §32.4).

theorem kmpMatcher_correct (P T : Text α) : kmpMatcher P T = naiveMatcher T P := by unfold kmpMatcher by_cases hP0 : P.length = 0 · have hnil : P = [] := List.eq_nil_of_length_eq_zero hP0 subst P simp [naiveMatcher_empty] · have hP : 0 < P.length := Nat.pos_of_ne_zero hP0 have hscan := kmpScan_eq_dfaScan P (computePrefixFunction P) hP (by intro i hi; exact computePrefixFunction_correct P i hi) (computePrefixFunction_inv P) have hsc : kmpScan P (computePrefixFunction P) P.length [] 0 (computePrefixFunction_inv P) T = dfaScan P P.length [] 0 T := hscan T [] 0 (by omega) rw [hsc] simp [hP0] simpa [dfaMatcher] using dfaMatcher_correct P T

Every shift returned by the KMP matcher is a valid match.

theorem kmpMatcher_sound (P T : Text α) (s : ℕ) (h : s ∈ kmpMatcher P T) : matchesAt T P s := by rw [kmpMatcher_correct] at h exact naiveMatcher_sound T P s h

Every valid match is returned by the KMP matcher.

theorem kmpMatcher_complete (P T : Text α) (s : ℕ) (h : matchesAt T P s) : s ∈ kmpMatcher P T := by rw [kmpMatcher_correct] exact naiveMatcher_complete T P s h

Costed KMP

The functions below instrument the executable KMP operations with an abstract unit control-step count: one unit per failure-link traversal plus one unit per character processed. The metric charges the potentially super-constant part of the algorithm — the while q > 0 ∧ P[q] ≠ c fallback loop — so that a linear bound on this metric is a real statement about the executable scan. Erasure theorems (*_result) show the costed functions project to the plain executables above.

failureFollow paired with the number of failure-link traversals.

def failureFollowWithCost (P : Text α) (π : List ℕ) (c : α) (k : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) : ℕ × ℕ := if hk : k = 0 then (0, 0) else if (P.getD k default) = c then (k, 0) else let r := failureFollowWithCost P π c (π.getD (k - 1) 0) hinv (r.1, r.2 + 1) termination_by k decreasing_by simp_wf have hpos : 0 < k := Nat.pos_of_ne_zero hk have hk' : (k - 1) + 1 = k := by omega simpa [hk'] using hinv (k - 1)

Erasing the cost recovers failureFollow.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_result`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma failureFollowWithCost_result (P : Text α) (π : List ℕ) (c : α) (k : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) : (failureFollowWithCost P π c k hinv).1 = failureFollow P π c k hinv := by refine Nat.strong_induction_on k ?_ intro k ih rw [failureFollowWithCost, failureFollow.eq_1] by_cases hk : k = 0 · simp [hk] · simp only [hk, This simp argument is unused: if_false Hint: Omit it from the simp argument list. simp only [hk,̵ ̵i̵f̵_̵f̵a̵l̵s̵e̵] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`if_false] by_cases hc : P[k]?.getD default = c · simp [hc] · simp [hc] exact ih (π[k - 1]?.getD 0) (by have hpos : 0 < k := Nat.pos_of_ne_zero hk have h := hinv (k - 1) have hk' : (k - 1) + 1 = k := by omega simpa [hk'] using h)

The fallback cost plus the final state never exceeds the initial state.

automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false` automatically included section variable(s) unused in theorem `CLRS.Chapter32.failureFollowWithCost_cost_add_le`: [BEq α] [LawfulBEq α] consider restructuring your `variable` declarations so that the variables are not in scope or explicitly omit them: omit [BEq α] [LawfulBEq α] in theorem ... Note: This linter can be disabled with `set_option linter.unusedSectionVars false`lemma failureFollowWithCost_cost_add_le (P : Text α) (π : List ℕ) (c : α) (k : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) : (failureFollowWithCost P π c k hinv).2 + (failureFollowWithCost P π c k hinv).1 ≤ k := by refine Nat.strong_induction_on k ?_ intro k ih rw [failureFollowWithCost] by_cases hk : k = 0 · simp [hk] · simp only [hk, This simp argument is unused: if_false Hint: Omit it from the simp argument list. simp only [hk,̵ ̵i̵f̵_̵f̵a̵l̵s̵e̵] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`if_false] by_cases hc : P[k]?.getD default = c · simp [hc] · simp [hc] have hlt : π[k - 1]?.getD 0 < k := by have hpos : 0 < k := Nat.pos_of_ne_zero hk have h := hinv (k - 1) have hk' : (k - 1) + 1 = k := by omega simpa [hk'] using h have hih := ih (π[k - 1]?.getD 0) hlt omega

computePrefixGo paired with its unit cost and the final failure state.

def computePrefixGoWithCost (P : Text α) (π : List ℕ) (k : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) (hk_lt : k < π.length) : Text α → List ℕ × ℕ × ℕ | [] => (π, 0, k) | c :: rest => let k' := (failureFollowWithCost P π c k hinv).1 let cf := (failureFollowWithCost P π c k hinv).2 let k'' := if (P.getD k' default) = c then k' + 1 else 0 have hk'le : k' ≤ k := by have hcost := failureFollowWithCost_cost_add_le P π c k hinv omega have hk'lt : k' < π.length := lt_of_le_of_lt hk'le hk_lt have hk''le : k'' ≤ π.length := by unfold k'' split <;> omega have hinv' : ∀ i, (π ++ [k'']).getD i 0 < i + 1 := by intro i by_cases hi : i < π.length · rw [List.getD_append π [k''] 0 i hi] exact hinv i · have hge : π.length ≤ i := by omega rw [List.getD_append_right π [k''] 0 i hge] have hle : [k''].getD (i - π.length) 0 ≤ k'' := by by_cases h : i - π.length = 0 <;> simp [List.getD, h] omega have hk''lt : k'' < (π ++ [k'']).length := by simp [hk''le] let r := computePrefixGoWithCost P (π ++ [k'']) k'' hinv' hk''lt rest (r.1, cf + 1 + r.2.1, r.2.2)

Erasing the cost recovers computePrefixGo.

lemma computePrefixGoWithCost_result (P : Text α) (π : List ℕ) (k : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) (hk_lt : k < π.length) (rest : Text α) : (computePrefixGoWithCost P π k hinv hk_lt rest).1 = computePrefixGo P π k hinv hk_lt rest := by induction rest generalizing π k hinv hk_lt with | nil => simp [computePrefixGoWithCost, computePrefixGo] | cons c rest ih => simp [computePrefixGoWithCost, computePrefixGo, failureFollowWithCost_result, ih]

The amortized potential invariant: cost + final_k ≤ 2 · rest.length + k.

lemma computePrefixGoWithCost_potential (P : Text α) (π : List ℕ) (k : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) (hk_lt : k < π.length) (rest : Text α) : (computePrefixGoWithCost P π k hinv hk_lt rest).2.1 + (computePrefixGoWithCost P π k hinv hk_lt rest).2.2 ≤ 2 * rest.length + k := by induction rest generalizing π k hinv hk_lt with | nil => simp [computePrefixGoWithCost] | cons c rest ih => rw [computePrefixGoWithCost] let k' := (failureFollowWithCost P π c k hinv).1 let cf := (failureFollowWithCost P π c k hinv).2 let k'' := if (P.getD k' default) = c then k' + 1 else 0 have hk'le : k' ≤ k := by have hcost := failureFollowWithCost_cost_add_le P π c k hinv omega have hk'lt : k' < π.length := lt_of_le_of_lt hk'le hk_lt have hk''le : k'' ≤ π.length := by unfold k'' split <;> omega have hinv' : ∀ i, (π ++ [k'']).getD i 0 < i + 1 := by intro i by_cases hi : i < π.length · rw [List.getD_append π [k''] 0 i hi] exact hinv i · have hge : π.length ≤ i := by omega rw [List.getD_append_right π [k''] 0 i hge] have hle : [k''].getD (i - π.length) 0 ≤ k'' := by by_cases h : i - π.length = 0 <;> simp [List.getD, h] omega have hk''lt : k'' < (π ++ [k'']).length := by simp [hk''le] have hcost := failureFollowWithCost_cost_add_le P π c k hinv have hih := ih (π ++ [k'']) k'' hinv' hk''lt have hk''le' : k'' ≤ k' + 1 := by unfold k'' split <;> omega change cf + 1 + (computePrefixGoWithCost P (π ++ [k'']) k'' hinv' hk''lt rest).2.1 + (computePrefixGoWithCost P (π ++ [k'']) k'' hinv' hk''lt rest).2.2 ≤ 2 * (rest.length + 1) + k omega

computePrefixFunction paired with its preprocessing cost.

def computePrefixFunctionWithCost (P : Text α) : List ℕ × ℕ := match P with | [] => ([], 0) | a :: as => let r := computePrefixGoWithCost P [0] 0 (by intro i; simp) (by simp) as (r.1, r.2.1)

Erasing the cost recovers computePrefixFunction.

lemma computePrefixFunctionWithCost_result (P : Text α) : (computePrefixFunctionWithCost P).1 = computePrefixFunction P := by cases P with | nil => simp [computePrefixFunctionWithCost, computePrefixFunction] | cons a as => simp [computePrefixFunctionWithCost, computePrefixFunction] exact computePrefixGoWithCost_result (a :: as) [0] 0 (by intro i; simp) (by simp) as

The prefix-function construction costs at most 2 · |P| steps.

theorem computePrefixFunctionWithCost_cost_le (P : Text α) : (computePrefixFunctionWithCost P).2 ≤ 2 * P.length := by cases P with | nil => simp [computePrefixFunctionWithCost] | cons a as => simp [computePrefixFunctionWithCost] have h := computePrefixGoWithCost_potential (a :: as) [0] 0 (by intro i; simp) (by simp) as omega

One KMP scan step paired with its unit cost (one fallback traversal plus one character).

def kmpStepWithCost (P : Text α) (π : List ℕ) (q : ℕ) (a : α) (hinv : ∀ i, π.getD i 0 < i + 1) : ℕ × ℕ := if q = P.length then let r := failureFollowWithCost P π a (π.getD (P.length - 1) 0) hinv (if P.getD r.1 default = a then r.1 + 1 else 0, r.2 + 1) else let r := failureFollowWithCost P π a q hinv (if P.getD r.1 default = a then r.1 + 1 else 0, r.2 + 1)

Erasing the cost recovers kmpStep.

lemma kmpStepWithCost_result (P : Text α) (π : List ℕ) (q : ℕ) (a : α) (hinv : ∀ i, π.getD i 0 < i + 1) : (kmpStepWithCost P π q a hinv).1 = kmpStep P π q a hinv := by unfold kmpStepWithCost kmpStep kmpAdvance by_cases hq : q = P.length <;> simp [hq, failureFollowWithCost_result]

The scan-step cost plus the next state never exceeds q + 2.

lemma kmpStepWithCost_cost_add_le (P : Text α) (π : List ℕ) (q : ℕ) (a : α) (hinv : ∀ i, π.getD i 0 < i + 1) : (kmpStepWithCost P π q a hinv).2 + (kmpStepWithCost P π q a hinv).1 ≤ q + 2 := by unfold kmpStepWithCost by_cases hq : q = P.length · simp only [hq, if_true] have hcost := failureFollowWithCost_cost_add_le P π a (π.getD (P.length - 1) 0) hinv have hle : π.getD (P.length - 1) 0 ≤ q := by subst q have h := hinv (P.length - 1) omega split <;> omega · simp only [hq, if_false] have hcost := failureFollowWithCost_cost_add_le P π a q hinv split <;> omega

The KMP scan paired with its unit cost and the final failure state.

def kmpScanWithCost (P : Text α) (π : List ℕ) (m : ℕ) (scanned : Text α) (q : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) : Text α → List ℕ × ℕ × ℕ | [] => (if q == m then [scanned.length - m] else [], 0, q) | c :: rest => let q' := (kmpStepWithCost P π q c hinv).1 let cstep := (kmpStepWithCost P π q c hinv).2 let r := kmpScanWithCost P π m (scanned ++ [c]) q' hinv rest (if q == m then (scanned.length - m) :: r.1 else r.1, cstep + r.2.1, r.2.2)

Erasing the cost recovers kmpScan.

lemma kmpScanWithCost_result (P : Text α) (π : List ℕ) (m : ℕ) (scanned : Text α) (q : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) (T : Text α) : (kmpScanWithCost P π m scanned q hinv T).1 = kmpScan P π m scanned q hinv T := by induction T generalizing scanned q with | nil => simp [kmpScanWithCost, kmpScan] | cons c T ih => simp only [kmpScanWithCost, kmpScan] rw [kmpStepWithCost_result] simp [ih]

The amortized potential invariant of the scan: cost + final_q ≤ 2 · |T| + q.

lemma kmpScanWithCost_potential (P : Text α) (π : List ℕ) (m : ℕ) (scanned : Text α) (q : ℕ) (hinv : ∀ i, π.getD i 0 < i + 1) (T : Text α) : (kmpScanWithCost P π m scanned q hinv T).2.1 + (kmpScanWithCost P π m scanned q hinv T).2.2 ≤ 2 * T.length + q := by induction T generalizing scanned q with | nil => simp [kmpScanWithCost] | cons c T ih => rw [kmpScanWithCost] let q' := (kmpStepWithCost P π q c hinv).1 let cstep := (kmpStepWithCost P π q c hinv).2 have hstep := kmpStepWithCost_cost_add_le P π q c hinv have hih := ih (scanned ++ [c]) q' change cstep + (kmpScanWithCost P π m (scanned ++ [c]) q' hinv T).2.1 + (kmpScanWithCost P π m (scanned ++ [c]) q' hinv T).2.2 ≤ 2 * (T.length + 1) + q omega

kmpMatcher paired with its matching-phase cost (the prefix construction cost is tracked separately by computePrefixFunctionWithCost).

def kmpMatcherWithCost (P T : Text α) : List ℕ × ℕ := if P.length = 0 then (List.range (T.length + 1), T.length + 1) else let r := kmpScanWithCost P (computePrefixFunction P) P.length [] 0 (computePrefixFunction_inv P) T (r.1, r.2.1)

Erasing the cost recovers kmpMatcher.

lemma kmpMatcherWithCost_result (P T : Text α) : (kmpMatcherWithCost P T).1 = kmpMatcher P T := by unfold kmpMatcherWithCost kmpMatcher by_cases hP0 : P.length = 0 · simp [hP0] · simp [hP0] exact kmpScanWithCost_result P (computePrefixFunction P) P.length [] 0 (computePrefixFunction_inv P) T

The matching phase costs at most 2 · |T| + 1 steps.

theorem kmpMatcherWithCost_cost_le (P T : Text α) : (kmpMatcherWithCost P T).2 ≤ 2 * T.length + 1 := by unfold kmpMatcherWithCost by_cases hP0 : P.length = 0 · simp [hP0] omega · simp [hP0] have h := kmpScanWithCost_potential P (computePrefixFunction P) P.length [] 0 (computePrefixFunction_inv P) T omega

The total deterministic KMP work: prefix construction plus scan.

def kmpTotalCost (P T : Text α) : ℕ := (computePrefixFunctionWithCost P).2 + (kmpMatcherWithCost P T).2

KMP total cost. The instrumented prefix construction plus the instrumented all-occurrences scan costs at most 2·|P| + 2·|T| + 1 control steps, i.e. the KMP algorithm runs in linear time O(|P| + |T|) (CLRS §32.4).

theorem kmpTotalCost_le (P T : Text α) : kmpTotalCost P T ≤ 2 * P.length + 2 * T.length + 1 := by unfold kmpTotalCost have hpre := computePrefixFunctionWithCost_cost_le P have hscan := kmpMatcherWithCost_cost_le P T omega
end Chapter32end CLRS
Imports

32.5. Suffix Arrays

This section formalizes the suffix-array data structure of CLRS §32.5: the array of starting positions of a text's suffixes sorted into lexicographic order, together with suffix-array-based pattern search.

A suffix array is a permutation of the positions 0 .. n-1 such that reading the positions in order lists the suffixes in non-decreasing lexicographic order. Once the suffixes are sorted, every position at which a pattern p occurs corresponds to a suffix that begins with p, so a single linear pass recovers exactly the occurrence set.

Main results:

  • Definition suffixAt: the suffix of a text starting at a given position.

  • Definition suffixLe: the lexicographic order on suffixes, with ties broken by starting position (a total order, so the construction is well-defined even when a text has repeated suffixes).

  • Definition SuffixArrayValid: the validity predicate — a permutation of the positions that is sorted by suffixLe.

  • Definition suffixArray: an executable construction (insertion sort of the positions by suffixLe).

  • Theorem suffixArray_valid: the construction returns a valid suffix array.

  • Definition suffixArraySearch: suffix-array-based pattern search.

  • Theorem suffixArraySearch_mem_iff: the search result is sound and complete — an index i is returned exactly when p is a prefix of suffixAt t i (i.e. p occurs at position i).

Complexity

The stored suffix positions are 0,...,n-1. For an empty pattern the range query returns those positions and omits the terminal boundary n that the naive matcher includes. The fast construction counts whole-suffix comparisons; one such comparison may inspect linearly many characters. Query bounds exclude construction, list-index lookup and range materialization.

The baseline construction sorts n positions by insertion sort (O(n³) worst-case work) and the scan search costs O(n · |p|). This section also adds the textbook-complexity layers:

  • suffixArrayFast (merge sort under a comparison model) with an explicit O(n log n) work theorem (suffixArrayFast_work_isBigO_nlogn), proved valid by suffixArrayFast_valid against the same SuffixArrayValid specification.

  • suffixArrayRange, the binary-search range query: two binary searches over the sorted suffix array find the lower/upper bounds of the pattern's interval. suffixArrayRange_mem_iff proves the returned range is sound and complete, and suffixArrayQueryWork_le bounds the query work by 2 · (|p| + 1) · (⌊log₂ n⌋ + 2) character comparisons under the stated string-comparison model (jointly O(|p| log n), via suffixArrayQueryWork_isBigO_logn).

Notation conventions used in this section:

  • t : the text (a Text α, i.e. List α)

  • p : a pattern (also a List α)

  • n : t.length

  • i, j : positions (natural numbers, 0-indexed)

namespace CLRSnamespace Chapter32open Chapter03variable {α : Type} [LinearOrder α]

The suffix of t starting at position i (the substring t[i:]).

def suffixAt (t : Text α) (i : ℕ) : Text α := t.drop i

Lexicographic order on suffixes, with ties broken by the starting index: suffix t i < suffix t j, or equal suffixes with i ≤ j.

def suffixLe (t : Text α) (i j : ℕ) : Prop := suffixAt t i < suffixAt t j ∨ (suffixAt t i = suffixAt t j ∧ i ≤ j)

suffixLe is decidable.

instance suffixLe_decidable (t : Text α) : DecidableRel (suffixLe t) := fun i j => by unfold suffixLe suffixAt; infer_instance

suffixLe is total: any two indices are comparable by suffix order.

instance suffixLe_total (t : Text α) : Std.Total (suffixLe t) := ⟨fun i j => by rcases trichotomous_of (· < ·) (suffixAt t i) (suffixAt t j) with h | h | h · exact Or.inl (Or.inl h) · rcases le_total i j with hij | hji · exact Or.inl (Or.inr ⟨h, hij⟩) · exact Or.inr (Or.inr ⟨h.symm, hji⟩) · exact Or.inr (Or.inl h)⟩

suffixLe is transitive.

instance suffixLe_trans (t : Text α) : IsTrans ℕ (suffixLe t) := ⟨fun i j k hij hjk => by rcases hij with h1 | h1 · rcases hjk with h2 | h2 · exact Or.inl (List.lt_trans h1 h2) · rcases h2 with ⟨hjk_eq, _⟩ exact Or.inl (by simpa [hjk_eq] using h1) · rcases h1 with ⟨hij_eq, hij_le⟩ rcases hjk with h2 | h2 · exact Or.inl (by simpa [hij_eq] using h2) · rcases h2 with ⟨hjk_eq, hjk_le⟩ exact Or.inr ⟨hij_eq.trans hjk_eq, le_trans hij_le hjk_le⟩⟩

The suffix array of t: the indices 0..t.length-1 sorted by their suffix's lexicographic order.

def suffixArray (t : Text α) : List ℕ := List.insertionSort (suffixLe t) (List.range t.length)

A list is a valid suffix array for t when it is a permutation of the indices and is sorted by the suffix order.

def SuffixArrayValid (t : Text α) (sa : List ℕ) : Prop := sa.Perm (List.range t.length) ∧ List.Pairwise (suffixLe t) sa

The suffix-array construction is valid: it is a sorted permutation of the indices.

theorem suffixArray_valid (t : Text α) : SuffixArrayValid t (suffixArray t) := by constructor · exact List.perm_insertionSort (suffixLe t) (List.range t.length) · exact List.pairwise_insertionSort (suffixLe t) (List.range t.length)

A pattern is a prefix of a text iff the text's prefix of the pattern's length equals the pattern.

omit [LinearOrder α] in theorem isPrefix_iff_take_eq (p s : Text α) : isPrefix p s ↔ s.take p.length = p := by constructor · rintro ⟨t, ht⟩ rw [← ht] simp · intro h refine ⟨s.drop p.length, ?_⟩ exact (congrArg (fun x => x ++ s.drop p.length) h.symm).trans (List.take_append_drop p.length s)

Suffix-array pattern search: all indices whose suffix begins with p, in suffix-array order.

def suffixArraySearch (t : Text α) (p : Text α) : List ℕ := (suffixArray t).filter (fun i => decide ((suffixAt t i).take p.length = p))

Soundness and completeness of suffix-array search. An index i is returned iff i is a valid position and p is a prefix of suffixAt t i (equivalently, p occurs at position i).

theorem suffixArraySearch_mem_iff (t : Text α) (p : Text α) (i : ℕ) : i ∈ suffixArraySearch t p ↔ i < t.length ∧ isPrefix p (suffixAt t i) := by unfold suffixArraySearch rw [List.mem_filter] rw [(suffixArray_valid t).1.mem_iff] rw [List.mem_range] constructor · rintro ⟨hi, hpref⟩ exact ⟨hi, (isPrefix_iff_take_eq p (suffixAt t i)).mpr (of_decide_eq_true hpref)⟩ · rintro ⟨hi, hpref⟩ exact ⟨hi, decide_eq_true ((isPrefix_iff_take_eq p (suffixAt t i)).mp hpref)⟩

Textbook-complexity construction

The baseline above proves correctness but uses insertion sort. This section adds a comparison-model construction: the suffix array is produced by merge sort, and a unit of work is charged for each lexicographic suffix comparison. The construction cost is proved to be O(n log n) comparisons, and the result is proved to satisfy the same SuffixArrayValid specification.

One lexicographic suffix comparison, charged as a single unit of work in the comparison model.

def suffixCompare (t : Text α) (i j : ℕ) : Bool := decide (suffixLe t i j)

suffixCompare is equivalent to suffixLe.

theorem suffixCompare_eq_true_iff (t : Text α) (i j : ℕ) : suffixCompare t i j = true ↔ suffixLe t i j := by simp [suffixCompare]

suffixCompare is transitive (so merge sort returns a sorted list).

theorem suffixCompare_trans (t : Text α) (i j k : ℕ) (hij : suffixCompare t i j = true) (hjk : suffixCompare t j k = true) : suffixCompare t i k = true := by have hij' : suffixLe t i j := (suffixCompare_eq_true_iff t i j).mp hij have hjk' : suffixLe t j k := (suffixCompare_eq_true_iff t j k).mp hjk exact decide_eq_true ((inferInstance : IsTrans ℕ (suffixLe t)).trans i j k hij' hjk')

suffixCompare is total (so merge sort compares any two suffixes).

theorem suffixCompare_total (t : Text α) (i j : ℕ) : (suffixCompare t i j || suffixCompare t j i) = true := by rcases (suffixLe_total (t := t)).total i j with h | h · simp [suffixCompare, decide_eq_true h] · simp [suffixCompare, decide_eq_true h]

Costed merge: merges two sorted lists and charges one comparison per step.

def mergeWithCost (t : Text α) : List ℕ → List ℕ → List ℕ × Nat | [], ys => (ys, 0) | xs, [] => (xs, 0) | x :: xs, y :: ys => if suffixCompare t x y then let r := mergeWithCost t xs (y :: ys) (x :: r.1, r.2 + 1) else let r := mergeWithCost t (x :: xs) ys (y :: r.1, r.2 + 1)

Costed merge sort, splitting at (n+1)/2 exactly like List.mergeSort.

def mergeSortWithCost (t : Text α) : List ℕ → List ℕ × Nat | [] => ([], 0) | [x] => ([x], 0) | a :: b :: xs => let lr := (a :: b :: xs).splitAt (((a :: b :: xs).length + 1) / 2) let sl := mergeSortWithCost t lr.1 let sr := mergeSortWithCost t lr.2 let sm := mergeWithCost t sl.1 sr.1 (sm.1, sl.2 + sr.2 + sm.2) termination_by xs => xs.length

Erasing the merge cost recovers List.merge.

theorem mergeWithCost_result (t : Text α) (xs ys : List ℕ) : (mergeWithCost t xs ys).1 = List.merge xs ys (suffixCompare t) := by induction h : xs.length + ys.length using Nat.strong_induction_on generalizing xs ys with | h n ih => cases xs with | nil => simp [mergeWithCost] | cons x xs => cases ys with | nil => simp [mergeWithCost] | cons y ys => by_cases hc : suffixCompare t x y · simp [mergeWithCost, hc] apply ih (xs.length + (y :: ys).length) ?_ xs (y :: ys) rfl simp [List.length_cons] at * omega · simp [mergeWithCost, hc] apply ih ((x :: xs).length + ys.length) ?_ (x :: xs) ys rfl simp [List.length_cons] at * omega

A merge preserves the multiset of the two input lists.

theorem mergeWithCost_perm (t : Text α) (xs ys : List ℕ) : (mergeWithCost t xs ys).1.Perm (xs ++ ys) := by rw [mergeWithCost_result] exact List.merge_perm_append (suffixCompare t)

A merge of two sorted lists is sorted.

theorem mergeWithCost_sorted (t : Text α) {xs ys : List ℕ} (hxs : List.Pairwise (suffixLe t) xs) (hys : List.Pairwise (suffixLe t) ys) : List.Pairwise (suffixLe t) (mergeWithCost t xs ys).1 := by rw [mergeWithCost_result] have hxs' : List.Pairwise (fun a b => suffixCompare t a b = true) xs := hxs.imp (fun {a b} (hab : suffixLe t a b) => (suffixCompare_eq_true_iff t a b).mpr hab) have hys' : List.Pairwise (fun a b => suffixCompare t a b = true) ys := hys.imp (fun {a b} (hab : suffixLe t a b) => (suffixCompare_eq_true_iff t a b).mpr hab) have h := List.pairwise_merge (suffixCompare_trans t) (suffixCompare_total t) xs ys hxs' hys' exact h.imp (fun {a b} (hab : suffixCompare t a b = true) => (suffixCompare_eq_true_iff t a b).mp hab)

(n + 1) / 2 < n for 2 ≤ n.

theorem half_succ_lt_self (n : ℕ) (hn : 2 ≤ n) : (n + 1) / 2 < n := by omega

n - (n + 1) / 2 = n / 2.

theorem sub_half_succ_eq_half (n : ℕ) : n - (n + 1) / 2 = n / 2 := by omega

n / 2 < n for 1 ≤ n.

theorem div_two_lt_self (n : ℕ) (hn : 1 ≤ n) : n / 2 < n := by omega

Merge sort is a permutation.

theorem mergeSortWithCost_perm (t : Text α) (xs : List ℕ) : (mergeSortWithCost t xs).1.Perm xs := by induction h : xs.length using Nat.strong_induction_on generalizing xs with | h n ih => cases xs with | nil => simp [mergeSortWithCost] | cons a rest => cases rest with | nil => simp [mergeSortWithCost] | cons b rest => simp only [mergeSortWithCost] rw [List.splitAt_eq] let l1 := (a :: b :: rest).take (((a :: b :: rest).length + 1) / 2) let l2 := (a :: b :: rest).drop (((a :: b :: rest).length + 1) / 2) change (mergeWithCost t (mergeSortWithCost t l1).1 (mergeSortWithCost t l2).1).1.Perm (a :: b :: rest) have hlt1 : l1.length < n := by have hL : 2 ≤ (a :: b :: rest).length := by simp [List.length_cons] calc l1.length ≤ ((a :: b :: rest).length + 1) / 2 := by simp [l1, List.length_take] _ < (a :: b :: rest).length := half_succ_lt_self _ hL _ = n := h have hlt2 : l2.length < n := by have hL : 1 ≤ (a :: b :: rest).length := by simp [List.length_cons] calc l2.length = (a :: b :: rest).length - ((a :: b :: rest).length + 1) / 2 := by simp [l2, List.length_drop] _ = (a :: b :: rest).length / 2 := sub_half_succ_eq_half _ _ < (a :: b :: rest).length := div_two_lt_self _ hL _ = n := h have h1 : (mergeSortWithCost t l1).1.Perm l1 := ih l1.length hlt1 l1 rfl have h2 : (mergeSortWithCost t l2).1.Perm l2 := ih l2.length hlt2 l2 rfl have hmerge := mergeWithCost_perm t (mergeSortWithCost t l1).1 (mergeSortWithCost t l2).1 exact hmerge.trans ((h1.append h2).trans (by rw [List.take_append_drop]))

Merge sort returns a sorted list.

theorem mergeSortWithCost_sorted (t : Text α) (xs : List ℕ) : List.Pairwise (suffixLe t) (mergeSortWithCost t xs).1 := by induction h : xs.length using Nat.strong_induction_on generalizing xs with | h n ih => cases xs with | nil => simp [mergeSortWithCost] | cons a rest => cases rest with | nil => simp [mergeSortWithCost] | cons b rest => simp only [mergeSortWithCost] rw [List.splitAt_eq] let l1 := (a :: b :: rest).take (((a :: b :: rest).length + 1) / 2) let l2 := (a :: b :: rest).drop (((a :: b :: rest).length + 1) / 2) change List.Pairwise (suffixLe t) (mergeWithCost t (mergeSortWithCost t l1).1 (mergeSortWithCost t l2).1).1 have hlt1 : l1.length < n := by have hL : 2 ≤ (a :: b :: rest).length := by simp [List.length_cons] calc l1.length ≤ ((a :: b :: rest).length + 1) / 2 := by simp [l1, List.length_take] _ < (a :: b :: rest).length := half_succ_lt_self _ hL _ = n := h have hlt2 : l2.length < n := by have hL : 1 ≤ (a :: b :: rest).length := by simp [List.length_cons] calc l2.length = (a :: b :: rest).length - ((a :: b :: rest).length + 1) / 2 := by simp [l2, List.length_drop] _ = (a :: b :: rest).length / 2 := sub_half_succ_eq_half _ _ < (a :: b :: rest).length := div_two_lt_self _ hL _ = n := h have h1 : List.Pairwise (suffixLe t) (mergeSortWithCost t l1).1 := ih l1.length hlt1 l1 rfl have h2 : List.Pairwise (suffixLe t) (mergeSortWithCost t l2).1 := ih l2.length hlt2 l2 rfl exact mergeWithCost_sorted t h1 h2

A merge charges at most one comparison per merged element.

theorem mergeWithCost_cost_le (t : Text α) (xs ys : List ℕ) : (mergeWithCost t xs ys).2 ≤ xs.length + ys.length := by induction h : xs.length + ys.length using Nat.strong_induction_on generalizing xs ys with | h n ih => cases xs with | nil => simp [mergeWithCost] | cons x xs => cases ys with | nil => simp [mergeWithCost] | cons y ys => by_cases hc : suffixCompare t x y · simp [mergeWithCost, hc] have hrec := ih (xs.length + (y :: ys).length) (by simp [List.length_cons] at *; omega) xs (y :: ys) rfl simp [List.length_cons] at * omega · simp [mergeWithCost, hc] have hrec := ih ((x :: xs).length + ys.length) (by simp [List.length_cons] at *; omega) (x :: xs) ys rfl simp [List.length_cons] at * omega

Nat.clog 2 n ≤ Nat.log 2 n + 1.

theorem clog_two_le_log_two_add_one (n : ℕ) : Nat.clog 2 n ≤ Nat.log 2 n + 1 := by rw [Nat.clog_le_iff_le_pow (by norm_num : 1 < 2)] exact Nat.le_of_lt (Nat.lt_pow_succ_log_self (by norm_num : 1 < 2) n)

Halving drops the ceiling-log by one (for n ≥ 2).

theorem clog_two_ceil_half_le_pred (n : ℕ) (hn : 2 ≤ n) : Nat.clog 2 ((n + 1) / 2) ≤ Nat.clog 2 n - 1 := by have h := Nat.clog_of_two_le (by norm_num : 1 < 2) hn have h' : n + 2 - 1 = n + 1 := by omega rw [h'] at h rw [h] omega

The floor half also drops the ceiling-log by one (for n ≥ 2).

theorem clog_two_floor_half_le_pred (n : ℕ) (hn : 2 ≤ n) : Nat.clog 2 (n / 2) ≤ Nat.clog 2 n - 1 := by have hdiv : n / 2 ≤ (n + 1) / 2 := Nat.div_le_div_right (by omega : n ≤ n + 1) exact (Nat.clog_mono_right 2 hdiv).trans (clog_two_ceil_half_le_pred n hn)

Merge sort performs at most length · ⌈log₂ length⌉ comparisons.

theorem mergeSortWithCost_cost_le_clog (t : Text α) (xs : List ℕ) : (mergeSortWithCost t xs).2 ≤ xs.length * Nat.clog 2 xs.length := by induction h : xs.length using Nat.strong_induction_on generalizing xs with | h n ih => cases xs with | nil => simp [mergeSortWithCost] | cons a rest => cases rest with | nil => simp [mergeSortWithCost] | cons b rest => simp only [mergeSortWithCost] rw [List.splitAt_eq] let l1 := List.take (((a :: b :: rest).length + 1) / 2) (a :: b :: rest) let l2 := List.drop (((a :: b :: rest).length + 1) / 2) (a :: b :: rest) change (mergeSortWithCost t l1).2 + (mergeSortWithCost t l2).2 + (mergeWithCost t (mergeSortWithCost t l1).1 (mergeSortWithCost t l2).1).2 ≤ n * Nat.clog 2 n have hlen1 : l1.length = ((a :: b :: rest).length + 1) / 2 := by simp [l1, List.length_take]; omega have hlen2 : l2.length = (a :: b :: rest).length / 2 := by simp [l2, List.length_drop]; omega have hlt1 : l1.length < n := by have hL : 2 ≤ (a :: b :: rest).length := by simp [List.length_cons] calc l1.length ≤ ((a :: b :: rest).length + 1) / 2 := by simp [l1, List.length_take] _ < (a :: b :: rest).length := half_succ_lt_self _ hL _ = n := h have hlt2 : l2.length < n := by have hL : 1 ≤ (a :: b :: rest).length := by simp [List.length_cons] calc l2.length = (a :: b :: rest).length - ((a :: b :: rest).length + 1) / 2 := by simp [l2, List.length_drop] _ = (a :: b :: rest).length / 2 := sub_half_succ_eq_half _ _ < (a :: b :: rest).length := div_two_lt_self _ hL _ = n := h have h1 := ih l1.length hlt1 l1 rfl have h2 := ih l2.length hlt2 l2 rfl have hmerge := mergeWithCost_cost_le t (mergeSortWithCost t l1).1 (mergeSortWithCost t l2).1 have hlen1' : (mergeSortWithCost t l1).1.length = l1.length := (mergeSortWithCost_perm t l1).length_eq have hlen2' : (mergeSortWithCost t l2).1.length = l2.length := (mergeSortWithCost_perm t l2).length_eq have hclog1 : Nat.clog 2 l1.length + 1 ≤ Nat.clog 2 (a :: b :: rest).length := by have hpos : 1 ≤ Nat.clog 2 (a :: b :: rest).length := Nat.clog_pos (by norm_num) (by simp [List.length_cons]) have hc := clog_two_ceil_half_le_pred (a :: b :: rest).length (by simp) rw [hlen1] omega have hclog2 : Nat.clog 2 l2.length + 1 ≤ Nat.clog 2 (a :: b :: rest).length := by have hpos : 1 ≤ Nat.clog 2 (a :: b :: rest).length := Nat.clog_pos (by norm_num) (by simp [List.length_cons]) have hc := clog_two_floor_half_le_pred (a :: b :: rest).length (by simp) rw [hlen2] omega have hlen_sum : l1.length + l2.length = (a :: b :: rest).length := by rw [hlen1, hlen2]; simp; omega have h1c : (mergeSortWithCost t l1).2 + l1.length ≤ l1.length * Nat.clog 2 (a :: b :: rest).length := by have hdist : l1.length * Nat.clog 2 l1.length + l1.length = l1.length * (Nat.clog 2 l1.length + 1) := by ring nlinarith [h1, hclog1] have h2c : (mergeSortWithCost t l2).2 + l2.length ≤ l2.length * Nat.clog 2 (a :: b :: rest).length := by nlinarith [h2, hclog2] have hmerge' : (mergeWithCost t (mergeSortWithCost t l1).1 (mergeSortWithCost t l2).1).2 ≤ l1.length + l2.length := by simpa [hlen1', hlen2'] using hmerge calc (mergeSortWithCost t l1).2 + (mergeSortWithCost t l2).2 + (mergeWithCost t (mergeSortWithCost t l1).1 (mergeSortWithCost t l2).1).2 ≤ (mergeSortWithCost t l1).2 + (mergeSortWithCost t l2).2 + (l1.length + l2.length) := Nat.add_le_add_left hmerge' _ _ ≤ l1.length * Nat.clog 2 (a :: b :: rest).length + l2.length * Nat.clog 2 (a :: b :: rest).length := by nlinarith [h1c, h2c] _ = n * Nat.clog 2 n := by rw [← Nat.add_mul, hlen_sum, h]

Merge sort performs at most length · (⌊log₂ length⌋ + 1) comparisons.

theorem mergeSortWithCost_cost_le_log (t : Text α) (xs : List ℕ) : (mergeSortWithCost t xs).2 ≤ xs.length * Nat.log 2 xs.length + xs.length := by have h := Nat.mul_le_mul_left xs.length (clog_two_le_log_two_add_one xs.length) nlinarith [mergeSortWithCost_cost_le_clog t xs, h]

The fast suffix-array construction (comparison model, merge sort).

def suffixArrayFast (t : Text α) : List ℕ := (mergeSortWithCost t (List.range t.length)).1

The comparison work of the fast suffix-array construction.

def suffixArrayBuildWork (t : Text α) : Nat := (mergeSortWithCost t (List.range t.length)).2

The fast construction is a valid suffix array.

theorem suffixArrayFast_valid (t : Text α) : SuffixArrayValid t (suffixArrayFast t) := by constructor · exact (mergeSortWithCost_perm t (List.range t.length)) · exact mergeSortWithCost_sorted t (List.range t.length)

The fast construction performs at most n · (⌊log₂ n⌋ + 1) comparisons.

theorem suffixArrayFast_work_le (t : Text α) : suffixArrayBuildWork t ≤ t.length * (Nat.log 2 t.length + 1) := by unfold suffixArrayBuildWork have h := mergeSortWithCost_cost_le_log t (List.range t.length) rw [List.length_range] at h nlinarith

The fast construction is O(n log n) under the comparison model.

theorem suffixArrayFast_work_isBigO_nlogn : isBigO (fun n : ℕ => (n * Nat.log 2 n + n : ℝ)) (fun n : ℕ => (n : ℝ) * (Nat.log 2 n : ℝ)) := by rw [isBigO_iff] refine ⟨2, by norm_num, 2, fun n hn => ?_⟩ have hlog : (1 : ℝ) ≤ (Nat.log 2 n : ℝ) := by exact_mod_cast (Nat.log_pos (by norm_num : 1 < 2) hn) rw [abs_of_nonneg (by positivity), abs_of_nonneg (by positivity)] have hn' : (0 : ℝ) ≤ n := by positivity have hmul : (n : ℝ) ≤ (n : ℝ) * (Nat.log 2 n : ℝ) := by calc (n : ℝ) = 1 * (n : ℝ) := by ring _ ≤ (Nat.log 2 n : ℝ) * (n : ℝ) := mul_le_mul_of_nonneg_right hlog hn' _ = (n : ℝ) * (Nat.log 2 n : ℝ) := by ring calc (n : ℝ) * (Nat.log 2 n : ℝ) + (n : ℝ) ≤ (n : ℝ) * (Nat.log 2 n : ℝ) + (n : ℝ) * (Nat.log 2 n : ℝ) := add_le_add_right hmul ((n : ℝ) * (Nat.log 2 n : ℝ)) _ = 2 * ((n : ℝ) * (Nat.log 2 n : ℝ)) := by ring

Textbook-complexity range query

The O(n log n) construction above gives a sorted suffix array. This section adds the other half of CLRS §32.5: a pattern search that finds every occurrence of p by two binary searches over that array. Each probe compares p against one suffix; in the stated string-comparison model a probe costs at most |p| + 1 character comparisons, so the whole query runs in O(|p| log n).

A suffix begins with p exactly when it lies between the two bounds

  • patternLE p s: p ≤ s lexicographically (the lower-bound predicate), and

  • patternGT p s: p < s and p is not a prefix of s (the upper-bound predicate).

Because the suffix array is sorted by suffixLe, both predicates are monotone along it, so each bound is found by binary search.

p is at-or-before suffix s in lexicographic order: the lower-bound predicate of the range query.

def patternLE (p s : Text α) : Prop := p ≤ s

s is strictly after every suffix that begins with p: the upper-bound predicate of the range query.

def patternGT (p s : Text α) : Prop := p < s ∧ s.take p.length ≠ p

patternLE is decidable.

instance patternLE_decidable (p s : Text α) : Decidable (patternLE p s) := by unfold patternLE; infer_instance

patternGT is decidable.

instance patternGT_decidable (p s : Text α) : Decidable (patternGT p s) := by unfold patternGT; infer_instance

The empty list is at-or-before every list in lexicographic order.

theorem nil_le (l : Text α) : [] ≤ l := by rcases l with _ | ⟨b, l⟩ · exact le_rfl · exact le_of_lt ((List.lt_iff_lex_lt [] (b :: l)).mp List.Lex.nil)

Taking a prefix is monotone with respect to lexicographic order.

theorem take_lex_le {s₁ s₂ : Text α} (hlex : List.Lex (· < ·) s₁ s₂) : ∀ k, s₁.take k ≤ s₂.take k := by induction hlex with | nil => rename_i b l intro k simpa using (nil_le ((b :: l).take k)) | rel hlt => intro k; cases k with | zero => simp | succ k => exact le_of_lt ((List.lt_iff_lex_lt _ _).mp (List.Lex.rel hlt)) | cons h ih => intro k; cases k with | zero => simp | succ k => exact List.cons_le_cons _ (ih k)

Taking a prefix is monotone with respect to lexicographic order.

theorem take_le_take {s₁ s₂ : Text α} (h : s₁ ≤ s₂) : ∀ k, s₁.take k ≤ s₂.take k := by rcases lt_or_eq_of_le h with hlt | rfl · exact take_lex_le ((List.lt_iff_lex_lt s₁ s₂).mp hlt) · intro k; rfl

A prefix is at-or-before its extension in lexicographic order.

theorem le_of_isPrefix {p s : Text α} (h : isPrefix p s) : p ≤ s := by rcases h with ⟨r, rfl⟩ exact le_iff_lt_or_eq.mpr <| match r with | [] => Or.inr (by simp) | b :: r' => Or.inl ((List.lt_iff_lex_lt p (p ++ b :: r')).mp (by simpa using (List.Lex.append_left (· < ·) (List.Lex.nil : List.Lex (· < ·) [] (b :: r')) p)))

If p ≤ s₁ ≤ s₂ and p is a prefix of s₂, then p is a prefix of s₁.

theorem isPrefix_of_le_of_isPrefix {p s₁ s₂ : Text α} (hps : p ≤ s₁) (hss : s₁ ≤ s₂) (hp₂ : isPrefix p s₂) : isPrefix p s₁ := by have ht : s₂.take p.length = p := (isPrefix_iff_take_eq p s₂).mp hp₂ have h₁ : s₁.take p.length ≤ s₂.take p.length := take_le_take hss p.length have h₂ : p ≤ s₁.take p.length := by simpa using (take_le_take hps p.length) have : s₁.take p.length = p := le_antisymm (by simpa [ht] using h₁) h₂ exact (isPrefix_iff_take_eq p s₁).mpr this

patternLE is monotone in the suffix argument.

theorem patternLE_mono {p s₁ s₂ : Text α} (h₁ : patternLE p s₁) (hss : s₁ ≤ s₂) : patternLE p s₂ := le_trans h₁ hss

patternGT is monotone in the suffix argument.

theorem patternGT_mono {p s₁ s₂ : Text α} (h₁ : patternGT p s₁) (hss : s₁ ≤ s₂) : patternGT p s₂ := by rcases h₁ with ⟨hlt, hne⟩ constructor · exact lt_of_lt_of_le hlt hss · intro htake have hpfx : isPrefix p s₂ := (isPrefix_iff_take_eq p s₂).mpr htake have hpfx₁ : isPrefix p s₁ := isPrefix_of_le_of_isPrefix (le_of_lt hlt) hss hpfx exact hne ((isPrefix_iff_take_eq p s₁).mp hpfx₁)

A pattern is a prefix of s exactly when it lies between the lower and upper bounds.

theorem isPrefix_iff_patternLE_and_not_patternGT (p s : Text α) : isPrefix p s ↔ patternLE p s ∧ ¬ patternGT p s := by constructor · intro hpfx constructor · exact le_of_isPrefix hpfx · intro hgt exact hgt.2 ((isPrefix_iff_take_eq p s).mp hpfx) · intro h rcases h with ⟨hle, hngt⟩ rcases lt_or_eq_of_le hle with hlt | heq · by_cases hpfx : s.take p.length = p · exact (isPrefix_iff_take_eq p s).mpr hpfx · exact False.elim (hngt ⟨hlt, hpfx⟩) · subst s; exact ⟨[], by simp⟩

suffixLe orders suffixes by their lexicographic order.

theorem suffixAt_le_of_suffixLe {t : Text α} {i j : ℕ} (h : suffixLe t i j) : suffixAt t i ≤ suffixAt t j := by rcases h with hlt | ⟨heq, _⟩ · exact le_of_lt hlt · exact le_of_eq heq

In a suffix-array-sorted list, suffixes at smaller positions are at-or-before suffixes at larger positions.

theorem sorted_suffixAt_le {t : Text α} {sa : List ℕ} (hsorted : List.Pairwise (suffixLe t) sa) {i j : ℕ} (hi : i < sa.length) (hj : j < sa.length) (hij : i < j) : suffixAt t sa[i] ≤ suffixAt t sa[j] := by exact suffixAt_le_of_suffixLe (List.Pairwise.rel_get_of_lt hsorted (a := ⟨i, hi⟩) (b := ⟨j, hj⟩) hij)

A single reusable costed binary search finds the first index in a list where a monotone boolean predicate turns true.

Costed binary search for the first index k in [lo, hi) with P (sa.getD k 0) true, charging one probe per comparison.

def binarySearchFirstCostAux (P : ℕ → Bool) (sa : List ℕ) (lo hi : ℕ) : ℕ × Nat := if lo < hi then let mid := (lo + hi) / 2 if P (sa.getD mid 0) then let r := binarySearchFirstCostAux P sa lo mid (r.1, r.2 + 1) else let r := binarySearchFirstCostAux P sa (mid + 1) hi (r.1, r.2 + 1) else (lo, 0) termination_by hi - lo

The pure binary search, erasing the probe count.

def binarySearchFirstAux (P : ℕ → Bool) (sa : List ℕ) (lo hi : ℕ) : ℕ := if lo < hi then let mid := (lo + hi) / 2 if P (sa.getD mid 0) then binarySearchFirstAux P sa lo mid else binarySearchFirstAux P sa (mid + 1) hi else lo termination_by hi - lo

Erasing the cost recovers the pure binary search.

theorem binarySearchFirstCostAux_fst (P : ℕ → Bool) (sa : List ℕ) (lo hi : ℕ) : (binarySearchFirstCostAux P sa lo hi).1 = binarySearchFirstAux P sa lo hi := by induction h : hi - lo using Nat.strong_induction_on generalizing lo hi with | h d ih => unfold binarySearchFirstCostAux binarySearchFirstAux by_cases hlt : lo < hi · simp only [hlt, ↓reduceIte] by_cases hP : P (sa.getD ((lo + hi) / 2) 0) · simp only [hP, ↓reduceIte] exact ih (((lo + hi) / 2) - lo) (by omega) lo ((lo + hi) / 2) rfl · simp only [hP, This simp argument is unused: ↓reduceIte Hint: Omit it from the simp argument list. simp only [hP,̵ ̵↓̵r̵e̵d̵u̵c̵e̵I̵t̵e̵] Note: This linter can be disabled with `set_option linter.unusedSimpArgs false`↓reduceIte] exact ih (hi - ((lo + hi) / 2 + 1)) (by omega) ((lo + hi) / 2 + 1) hi rfl · simp only [hlt, ↓reduceIte]

r is the first index in [lo, hi] where P holds along sa.

def BinarySearchSpec (P : ℕ → Bool) (sa : List ℕ) (lo hi r : ℕ) : Prop := lo ≤ r ∧ r ≤ hi ∧ (∀ k, lo ≤ k → k < r → P (sa.getD k 0) = false) ∧ (r < hi → P (sa.getD r 0) = true)

The binary search returns the first index with P true (or hi if none).

theorem binarySearchFirstAux_spec (P : ℕ → Bool) (sa : List ℕ) (hmono : ∀ ⦃i j⦄, i < j → j < sa.length → P (sa.getD i 0) = true → P (sa.getD j 0) = true) : ∀ lo hi, lo ≤ hi → hi ≤ sa.length → (∀ k, k < lo → P (sa.getD k 0) = false) → (∀ k, hi ≤ k → k < sa.length → P (sa.getD k 0) = true) → BinarySearchSpec P sa lo hi (binarySearchFirstAux P sa lo hi) := by intro lo hi induction h : hi - lo using Nat.strong_induction_on generalizing lo hi with | h d ih => intro hle hhi hL hR unfold binarySearchFirstAux by_cases hlt : lo < hi · have hmid_lo : lo ≤ (lo + hi) / 2 := by exact (Nat.le_div_iff_mul_le (by decide : 0 < 2)).mpr (by omega) have hmid_hi : (lo + hi) / 2 < hi := by exact (Nat.div_lt_iff_lt_mul (by decide : 0 < 2)).mpr (by omega) have hmid_len : (lo + hi) / 2 < sa.length := lt_of_lt_of_le hmid_hi hhi simp only [hlt, ↓reduceIte] by_cases hP : P (sa.getD ((lo + hi) / 2) 0) = true · rw [if_pos hP] have hR' : ∀ k, (lo + hi) / 2 ≤ k → k < sa.length → P (sa.getD k 0) = true := by intro k hkmid hkl by_cases hk : k = (lo + hi) / 2 · subst k; exact hP · have hmid_lt_k : (lo + hi) / 2 < k := lt_of_le_of_ne hkmid (Ne.symm hk) exact hmono hmid_lt_k hkl hP have hspec := ih ((lo + hi) / 2 - lo) (by omega) lo ((lo + hi) / 2) rfl hmid_lo (le_of_lt hmid_len) hL hR' rcases hspec with ⟨hrlo, hrhi, hfalse, htrue⟩ constructor · exact hrlo constructor · exact le_trans hrhi (le_of_lt hmid_hi) constructor · exact hfalse · intro hrhi' by_cases hrm : binarySearchFirstAux P sa lo ((lo + hi) / 2) < (lo + hi) / 2 · exact htrue hrm · have hreq : binarySearchFirstAux P sa lo ((lo + hi) / 2) = (lo + hi) / 2 := le_antisymm hrhi (le_of_not_gt hrm) simpa [hreq] using hP · rw [if_neg hP] have hPfalse : P (sa.getD ((lo + hi) / 2) 0) = false := by simpa [Bool.not_eq_true] using hP have hmid1_hi : (lo + hi) / 2 + 1 ≤ hi := by omega have hL' : ∀ k, k < (lo + hi) / 2 + 1 → P (sa.getD k 0) = false := by intro k hklt by_cases hklo : k < lo · exact hL k hklo · have hk_le_mid : k ≤ (lo + hi) / 2 := by omega by_cases hkm : k = (lo + hi) / 2 · subst k; exact hPfalse · have hk_lt_mid : k < (lo + hi) / 2 := lt_of_le_of_ne hk_le_mid hkm have hkmid_true : P (sa.getD k 0) = true → False := by intro hkP exact hP (hmono hk_lt_mid hmid_len hkP) by_cases hc : P (sa.getD k 0) = true · exact (hkmid_true hc).elim · exact (Bool.not_eq_true _).mp hc have hspec := ih (hi - ((lo + hi) / 2 + 1)) (by omega) ((lo + hi) / 2 + 1) hi rfl hmid1_hi hhi hL' hR rcases hspec with ⟨hrlo, hrhi, hfalse, htrue⟩ constructor · exact le_trans hmid_lo (le_trans (by omega) hrlo) constructor · exact hrhi constructor · intro k hklo hkr by_cases hk_mid : k ≤ (lo + hi) / 2 · exact hL' k (by omega) · have hmid1_k : (lo + hi) / 2 + 1 ≤ k := by omega exact hfalse k hmid1_k hkr · exact htrue · simp only [hlt, ↓reduceIte] constructor · omega constructor · omega constructor · intro k hklo hkr; omega · intro hrhi; omega

Halving a ceiling-log: clog 2 (n/2 + 1) ≤ clog 2 (n+1) - 1 for n ≥ 1.

theorem clog_two_half_add_one_le_pred (n : ℕ) (hn : 1 ≤ n) : Nat.clog 2 (n / 2 + 1) ≤ Nat.clog 2 (n + 1) - 1 := by have hh := clog_two_ceil_half_le_pred (n + 1) (by omega : 2 ≤ n + 1) have hhalf : (n + 1 + 1) / 2 = n / 2 + 1 := by omega simpa [hhalf] using hh

The costed binary search performs at most ⌈log₂ (hi - lo + 1)⌉ probes.

theorem binarySearchFirstCostAux_cost_le (P : ℕ → Bool) (sa : List ℕ) (lo hi : ℕ) : (binarySearchFirstCostAux P sa lo hi).2 ≤ Nat.clog 2 (hi - lo + 1) := by induction h : hi - lo using Nat.strong_induction_on generalizing lo hi with | h d ih => unfold binarySearchFirstCostAux by_cases hlt : lo < hi · have hmid_lo : lo ≤ (lo + hi) / 2 := by exact (Nat.le_div_iff_mul_le (by decide : 0 < 2)).mpr (by omega) have hmid_hi : (lo + hi) / 2 < hi := by exact (Nat.div_lt_iff_lt_mul (by decide : 0 < 2)).mpr (by omega) simp only [hlt, ↓reduceIte] by_cases hP : P (sa.getD ((lo + hi) / 2) 0) = true · rw [if_pos hP, ← h] have hrec := ih (((lo + hi) / 2) - lo) (by omega) lo ((lo + hi) / 2) rfl have hmid_eq : (lo + hi) / 2 - lo = (hi - lo) / 2 := by omega rw [hmid_eq] at hrec have hclogpos : 1 ≤ Nat.clog 2 (hi - lo + 1) := by exact Nat.succ_le_of_lt (Nat.clog_pos (by decide : 1 < 2) (by omega : 2 ≤ hi - lo + 1)) have hclog : Nat.clog 2 ((hi - lo) / 2 + 1) ≤ Nat.clog 2 (hi - lo + 1) - 1 := by exact clog_two_half_add_one_le_pred (hi - lo) (by omega) have hstep : Nat.clog 2 ((hi - lo) / 2 + 1) + 1 ≤ Nat.clog 2 (hi - lo + 1) := Nat.add_le_of_le_sub hclogpos hclog calc (binarySearchFirstCostAux P sa lo ((lo + hi) / 2)).2 + 1 ≤ Nat.clog 2 ((hi - lo) / 2 + 1) + 1 := Nat.add_le_add_right hrec 1 _ ≤ Nat.clog 2 (hi - lo + 1) := hstep · rw [if_neg hP, ← h] have hrec := ih (hi - ((lo + hi) / 2 + 1)) (by omega) ((lo + hi) / 2 + 1) hi rfl have hsub_le : hi - ((lo + hi) / 2 + 1) ≤ (hi - lo) / 2 := by omega have hclogpos : 1 ≤ Nat.clog 2 (hi - lo + 1) := by exact Nat.succ_le_of_lt (Nat.clog_pos (by decide : 1 < 2) (by omega : 2 ≤ hi - lo + 1)) have hclog' : Nat.clog 2 (hi - ((lo + hi) / 2 + 1) + 1) ≤ Nat.clog 2 ((hi - lo) / 2 + 1) := by exact Nat.clog_mono_right 2 (by omega) have hclog : Nat.clog 2 ((hi - lo) / 2 + 1) ≤ Nat.clog 2 (hi - lo + 1) - 1 := by exact clog_two_half_add_one_le_pred (hi - lo) (by omega) have hstep : Nat.clog 2 ((hi - lo) / 2 + 1) + 1 ≤ Nat.clog 2 (hi - lo + 1) := Nat.add_le_of_le_sub hclogpos hclog calc (binarySearchFirstCostAux P sa ((lo + hi) / 2 + 1) hi).2 + 1 ≤ Nat.clog 2 (hi - ((lo + hi) / 2 + 1) + 1) + 1 := Nat.add_le_add_right hrec 1 _ ≤ Nat.clog 2 ((hi - lo) / 2 + 1) + 1 := Nat.add_le_add_right hclog' 1 _ ≤ Nat.clog 2 (hi - lo + 1) := hstep · simp only [hlt, ↓reduceIte] exact Nat.zero_le _

Binary search for the first index in a whole list with P true.

def binarySearchFirst (P : ℕ → Bool) (sa : List ℕ) : ℕ := binarySearchFirstAux P sa 0 sa.length

The costed binary search over a whole list.

def binarySearchFirstCost (P : ℕ → Bool) (sa : List ℕ) : ℕ × Nat := binarySearchFirstCostAux P sa 0 sa.length

The whole-list binary search returns the first index with P true.

theorem binarySearchFirst_spec (P : ℕ → Bool) (sa : List ℕ) (hmono : ∀ ⦃i j⦄, i < j → j < sa.length → P (sa.getD i 0) = true → P (sa.getD j 0) = true) : (binarySearchFirst P sa) ≤ sa.length ∧ (∀ k, k < binarySearchFirst P sa → P (sa.getD k 0) = false) ∧ (binarySearchFirst P sa < sa.length → P (sa.getD (binarySearchFirst P sa) 0) = true) := by have hspec := binarySearchFirstAux_spec P sa hmono 0 sa.length (Nat.zero_le _) le_rfl (by intro k hk; omega) (by intro k hk hkl; omega) rcases hspec with ⟨hrlo, hrhi, hfalse, htrue⟩ constructor · exact hrhi constructor · intro k hkr exact hfalse k (Nat.zero_le _) hkr · exact htrue

The whole-list costed binary search performs at most ⌈log₂ (n+1)⌉ probes.

theorem binarySearchFirstCost_cost_le (P : ℕ → Bool) (sa : List ℕ) : (binarySearchFirstCost P sa).2 ≤ Nat.clog 2 (sa.length + 1) := by unfold binarySearchFirstCost exact binarySearchFirstCostAux_cost_le P sa 0 sa.length

The range query

The decidable lower-bound probe: does the suffix at position x reach the pattern?

def lowerDecide (t : Text α) (p : Text α) (x : ℕ) : Bool := decide (patternLE p (suffixAt t x))

The decidable upper-bound probe: is the suffix at position x strictly past every suffix beginning with p?

def upperDecide (t : Text α) (p : Text α) (x : ℕ) : Bool := decide (patternGT p (suffixAt t x))

lowerDecide is monotone along a sorted suffix array.

theorem lowerDecide_mono {t : Text α} {p : Text α} {sa : List ℕ} (hsorted : List.Pairwise (suffixLe t) sa) (i j : ℕ) (hij : i < j) (hj : j < sa.length) : lowerDecide t p (sa.getD i 0) = true → lowerDecide t p (sa.getD j 0) = true := by intro hi have hi_lt : i < sa.length := lt_trans hij hj have hle : suffixAt t (sa.getD i 0) ≤ suffixAt t (sa.getD j 0) := by have hg : suffixAt t sa[i] ≤ suffixAt t sa[j] := sorted_suffixAt_le hsorted hi_lt hj hij have hiD : sa.getD i 0 = sa[i] := List.getD_eq_getElem sa 0 hi_lt have hjD : sa.getD j 0 = sa[j] := List.getD_eq_getElem sa 0 hj simpa only [hiD, hjD] using hg have hle' : patternLE p (suffixAt t (sa.getD i 0)) := of_decide_eq_true hi have hle'' : patternLE p (suffixAt t (sa.getD j 0)) := patternLE_mono hle' hle exact decide_eq_true hle''

upperDecide is monotone along a sorted suffix array.

theorem upperDecide_mono {t : Text α} {p : Text α} {sa : List ℕ} (hsorted : List.Pairwise (suffixLe t) sa) (i j : ℕ) (hij : i < j) (hj : j < sa.length) : upperDecide t p (sa.getD i 0) = true → upperDecide t p (sa.getD j 0) = true := by intro hi have hi_lt : i < sa.length := lt_trans hij hj have hle : suffixAt t (sa.getD i 0) ≤ suffixAt t (sa.getD j 0) := by have hg : suffixAt t sa[i] ≤ suffixAt t sa[j] := sorted_suffixAt_le hsorted hi_lt hj hij have hiD : sa.getD i 0 = sa[i] := List.getD_eq_getElem sa 0 hi_lt have hjD : sa.getD j 0 = sa[j] := List.getD_eq_getElem sa 0 hj simpa only [hiD, hjD] using hg have hle' : patternGT p (suffixAt t (sa.getD i 0)) := of_decide_eq_true hi have hle'' : patternGT p (suffixAt t (sa.getD j 0)) := patternGT_mono hle' hle exact decide_eq_true hle''

The lower bound of the pattern's interval in the fast suffix array.

def suffixArrayLower (t : Text α) (p : Text α) : ℕ := binarySearchFirst (lowerDecide t p) (suffixArrayFast t)

The upper bound of the pattern's interval in the fast suffix array.

def suffixArrayUpper (t : Text α) (p : Text α) : ℕ := binarySearchFirst (upperDecide t p) (suffixArrayFast t)

The lower bound is at most the upper bound.

theorem suffixArrayLower_le_upper (t : Text α) (p : Text α) : suffixArrayLower t p ≤ suffixArrayUpper t p := by let sa := suffixArrayFast t have hsorted : List.Pairwise (suffixLe t) sa := (suffixArrayFast_valid t).2 have hlower := binarySearchFirst_spec (lowerDecide t p) sa (lowerDecide_mono (t := t) (p := p) hsorted) have hupper := binarySearchFirst_spec (upperDecide t p) sa (upperDecide_mono (t := t) (p := p) hsorted) have hlo_len : suffixArrayLower t p ≤ sa.length := hlower.1 by_contra hgt have hupper_lt_lo : suffixArrayUpper t p < suffixArrayLower t p := lt_of_not_ge hgt have hupper_len : suffixArrayUpper t p < sa.length := lt_of_lt_of_le hupper_lt_lo hlo_len have hupper_true : upperDecide t p (sa.getD (suffixArrayUpper t p) 0) = true := hupper.2.2 hupper_len have hlower_false : lowerDecide t p (sa.getD (suffixArrayUpper t p) 0) = false := hlower.2.1 (suffixArrayUpper t p) hupper_lt_lo have hgt_p : patternGT p (suffixAt t (sa.getD (suffixArrayUpper t p) 0)) := of_decide_eq_true hupper_true have hle_p : patternLE p (suffixAt t (sa.getD (suffixArrayUpper t p) 0)) := le_of_lt hgt_p.1 have hlower_true : lowerDecide t p (sa.getD (suffixArrayUpper t p) 0) = true := decide_eq_true hle_p exact Bool.noConfusion (hlower_false.symm.trans hlower_true)

The fast range query: the slice of the fast suffix array whose suffixes begin with p.

def suffixArrayRange (t : Text α) (p : Text α) : List ℕ := let sa := suffixArrayFast t (sa.drop (suffixArrayLower t p)).take (suffixArrayUpper t p - suffixArrayLower t p)

The character-comparison work of the fast range query: two binary searches, each probe charged |p| + 1 character comparisons.

def suffixArrayQueryWork (t : Text α) (p : Text α) : Nat := let sa := suffixArrayFast t let lo := binarySearchFirstCost (lowerDecide t p) sa let hi := binarySearchFirstCost (upperDecide t p) sa (lo.2 + hi.2) * (p.length + 1)

The lower bound of the interval is where suffixes first reach p.

theorem suffixArrayLower_spec (t : Text α) (p : Text α) : (suffixArrayLower t p ≤ (suffixArrayFast t).length ∧ (∀ k, k < suffixArrayLower t p → lowerDecide t p ((suffixArrayFast t).getD k 0) = false) ∧ (suffixArrayLower t p < (suffixArrayFast t).length → lowerDecide t p ((suffixArrayFast t).getD (suffixArrayLower t p) 0) = true)) := by exact binarySearchFirst_spec (lowerDecide t p) (suffixArrayFast t) (lowerDecide_mono (t := t) (p := p) ((suffixArrayFast_valid t).2))

The upper bound of the interval is where suffixes first move past p.

theorem suffixArrayUpper_spec (t : Text α) (p : Text α) : (suffixArrayUpper t p ≤ (suffixArrayFast t).length ∧ (∀ k, k < suffixArrayUpper t p → upperDecide t p ((suffixArrayFast t).getD k 0) = false) ∧ (suffixArrayUpper t p < (suffixArrayFast t).length → upperDecide t p ((suffixArrayFast t).getD (suffixArrayUpper t p) 0) = true)) := by exact binarySearchFirst_spec (upperDecide t p) (suffixArrayFast t) (upperDecide_mono (t := t) (p := p) ((suffixArrayFast_valid t).2))

Membership in the slice (l.drop lo).take (hi - lo).

theorem mem_drop_take_iff (l : List ℕ) (lo hi x : ℕ) (hlo : lo ≤ hi) : x ∈ (l.drop lo).take (hi - lo) ↔ ∃ j, lo ≤ j ∧ j < hi ∧ l[j]? = some x := by rw [List.mem_iff_getElem?] constructor · rintro ⟨k, hk⟩ rw [List.getElem?_take, List.getElem?_drop] at hk have hklt : k < hi - lo := by by_cases h : k < hi - lo · exact h · simp [h] at hk have hsome : l[lo + k]? = some x := by simpa [hklt] using hk refine ⟨lo + k, by omega, by omega, hsome⟩ · rintro ⟨j, hjlo, hjhi, hsome⟩ refine ⟨j - lo, ?_⟩ have hjlt : j - lo < hi - lo := by omega rw [List.getElem?_take, List.getElem?_drop] simp [hjlt] have : lo + (j - lo) = j := by omega simpa [this] using hsome

Soundness and completeness of the fast range query. An index i is returned by suffixArrayRange exactly when p is a prefix of the suffix at i (equivalently, p occurs at position i).

theorem suffixArrayRange_mem_iff (t : Text α) (p : Text α) (i : ℕ) : i ∈ suffixArrayRange t p ↔ i < t.length ∧ isPrefix p (suffixAt t i) := by let sa := suffixArrayFast t have hperm : sa.Perm (List.range t.length) := (suffixArrayFast_valid t).1 have hlo_hi : suffixArrayLower t p ≤ suffixArrayUpper t p := suffixArrayLower_le_upper t p have hlower := suffixArrayLower_spec t p have hupper := suffixArrayUpper_spec t p unfold suffixArrayRange rw [mem_drop_take_iff sa (suffixArrayLower t p) (suffixArrayUpper t p) i hlo_hi] constructor · rintro ⟨j, hjlo, hjhi, hsome⟩ have hj : j < sa.length := lt_of_lt_of_le hjhi hupper.1 have hsai : sa[j] = i := by rw [List.getElem?_eq_some_iff] at hsome exact hsome.2 have hlower_true_j : lowerDecide t p (sa.getD j 0) = true := by by_cases hlo_eq : suffixArrayLower t p = j · have hgoal : lowerDecide t p (sa.getD (suffixArrayLower t p) 0) = true := hlower.2.2 (by simpa [hlo_eq] using hj) simpa only [hlo_eq] using hgoal · have hlo_lt : suffixArrayLower t p < sa.length := lt_of_le_of_lt hjlo hj have hlo_true : lowerDecide t p (sa.getD (suffixArrayLower t p) 0) = true := hlower.2.2 hlo_lt have hlo_lt_j : suffixArrayLower t p < j := lt_of_le_of_ne hjlo hlo_eq have hmono := lowerDecide_mono (t := t) (p := p) ((suffixArrayFast_valid t).2) exact hmono (suffixArrayLower t p) j hlo_lt_j hj hlo_true have hupper_false_j : upperDecide t p (sa.getD j 0) = false := hupper.2.1 j hjhi have hle : patternLE p (suffixAt t (sa.getD j 0)) := of_decide_eq_true hlower_true_j have hngt : ¬ patternGT p (suffixAt t (sa.getD j 0)) := of_decide_eq_false hupper_false_j have hpfx : isPrefix p (suffixAt t (sa.getD j 0)) := (isPrefix_iff_patternLE_and_not_patternGT p (suffixAt t (sa.getD j 0))).mpr ⟨hle, hngt⟩ have hget : sa.getD j 0 = i := by rw [List.getD_eq_getElem sa 0 hj] exact hsai constructor · have hmem : i ∈ List.range t.length := by rw [← hperm.mem_iff] exact List.mem_iff_getElem?.mpr ⟨j, by simpa only [hget] using hsome⟩ simpa using hmem · simpa only [hget] using hpfx · rintro ⟨hi_len, hpfx⟩ have himem : i ∈ sa := by rw [hperm.mem_iff] simpa using (List.mem_range.mpr hi_len) rcases List.mem_iff_getElem?.mp himem with ⟨j, hsome⟩ rw [List.getElem?_eq_some_iff] at hsome have hj : j < sa.length := hsome.1 have hji : sa[j] = i := hsome.2 have hgetD : sa.getD j 0 = i := by rw [List.getD_eq_getElem sa 0 hj] exact hji have hpfx_j : isPrefix p (suffixAt t (sa.getD j 0)) := by simpa only [hgetD] using hpfx have hboth := (isPrefix_iff_patternLE_and_not_patternGT p (suffixAt t (sa.getD j 0))).mp hpfx_j have hlower_true : lowerDecide t p (sa.getD j 0) = true := decide_eq_true hboth.1 have hupper_false : upperDecide t p (sa.getD j 0) = false := decide_eq_false hboth.2 have hlo_le_j : suffixArrayLower t p ≤ j := by by_contra hneg have hj_lt_lo : j < suffixArrayLower t p := lt_of_not_ge hneg have hlo_false : lowerDecide t p (sa.getD j 0) = false := hlower.2.1 j hj_lt_lo exact Bool.noConfusion (hlo_false.symm.trans hlower_true) have hj_lt_hi : j < suffixArrayUpper t p := by by_contra hneg have hhi_le_j : suffixArrayUpper t p ≤ j := le_of_not_gt hneg have hmono := upperDecide_mono (t := t) (p := p) ((suffixArrayFast_valid t).2) have hhi_true : upperDecide t p (sa.getD j 0) = true := by by_cases hhj : suffixArrayUpper t p = j · subst hhj exact hupper.2.2 hj · have hhi_lt_j : suffixArrayUpper t p < j := lt_of_le_of_ne hhi_le_j hhj have hhi_len : suffixArrayUpper t p < sa.length := lt_of_lt_of_le hhi_lt_j (Nat.le_of_lt hj) exact hmono (suffixArrayUpper t p) j hhi_lt_j hj (hupper.2.2 hhi_len) exact Bool.noConfusion (hupper_false.symm.trans hhi_true) refine ⟨j, hlo_le_j, hj_lt_hi, ?_⟩ rw [List.getElem?_eq_some_iff] exact ⟨hj, hji⟩

Nat.log 2 (n+1) ≤ Nat.log 2 n + 1.

theorem log_succ_le_log_add_one (n : ℕ) : Nat.log 2 (n + 1) ≤ Nat.log 2 n + 1 := by by_cases h : n = 0 · subst n; norm_num [Nat.log] · have h1 : 1 ≤ n := Nat.succ_le_of_lt (Nat.pos_of_ne_zero h) have hle : n + 1 ≤ n * 2 := by omega have hlog : Nat.log 2 (n + 1) ≤ Nat.log 2 (n * 2) := Nat.log_monotone (b := 2) hle have hlog2 : Nat.log 2 (n * 2) = Nat.log 2 n + 1 := Nat.log_mul_base (by norm_num : 1 < 2) h rw [hlog2] at hlog exact hlog

Nat.clog 2 (n+1) ≤ Nat.log 2 n + 2.

theorem clog_succ_le_log_add_two (n : ℕ) : Nat.clog 2 (n + 1) ≤ Nat.log 2 n + 2 := by have h := clog_two_le_log_two_add_one (n + 1) have h' := Nat.add_le_add_right (log_succ_le_log_add_one n) 1 omega

The fast range query performs at most 2 · (|p| + 1) · (⌊log₂ n⌋ + 2) character comparisons.

theorem suffixArrayQueryWork_le (t : Text α) (p : Text α) : suffixArrayQueryWork t p ≤ 2 * (p.length + 1) * (Nat.log 2 t.length + 2) := by let sa := suffixArrayFast t have hlen : sa.length = t.length := by exact ((suffixArrayFast_valid t).1).length_eq.trans (List.length_range (n := t.length)) unfold suffixArrayQueryWork have hlo := binarySearchFirstCost_cost_le (lowerDecide t p) sa have hhi := binarySearchFirstCost_cost_le (upperDecide t p) sa have hclog : Nat.clog 2 (sa.length + 1) ≤ Nat.log 2 t.length + 2 := by rw [hlen] exact clog_succ_le_log_add_two t.length calc ((binarySearchFirstCost (lowerDecide t p) sa).2 + (binarySearchFirstCost (upperDecide t p) sa).2) * (p.length + 1) ≤ (Nat.clog 2 (sa.length + 1) + Nat.clog 2 (sa.length + 1)) * (p.length + 1) := Nat.mul_le_mul_right (p.length + 1) (Nat.add_le_add hlo hhi) _ = 2 * (p.length + 1) * Nat.clog 2 (sa.length + 1) := by ring _ ≤ 2 * (p.length + 1) * (Nat.log 2 t.length + 2) := Nat.mul_le_mul_left (2 * (p.length + 1)) hclog

For a fixed pattern length m, the query work is O(log n) in the text length under the comparison model, with the |p| factor carried in the constant — jointly O(|p| log n).

theorem suffixArrayQueryWork_isBigO_logn (m : ℕ) : isBigO (fun n : ℕ => (2 * ((m : ℝ) + 1) * (((Nat.log 2 n : ℕ) : ℝ) + 2))) (fun n : ℕ => ((m : ℝ) + 1) * ((Nat.log 2 n : ℕ) : ℝ)) := by rw [isBigO_iff] refine ⟨8, by norm_num, 2, fun n hn => ?_⟩ have hlog : (1 : ℝ) ≤ (Nat.log 2 n : ℝ) := by exact_mod_cast (Nat.log_pos (by norm_num : 1 < 2) (by omega : 2 ≤ n)) rw [abs_of_nonneg (by positivity), abs_of_nonneg (by positivity)] have hm : (0 : ℝ) ≤ (m : ℝ) + 1 := by positivity nlinarith
end Chapter32end CLRS

Scope and implementation notes

Imports

Current source

Section 32.1 is a native fourth-edition section (the string model with the naive matcher), imported directly from Section 32.1. Section 32.2 (the Rabin-Karp algorithm) is a native fourth-edition section in Section 32.2. Section 32.3 (string matching with finite automata) is a native fourth-edition section in Section 32.3. Section 32.4 (the Knuth-Morris-Pratt algorithm) is a native fourth-edition section in Section 32.4. Section 32.5 (suffix arrays) is a native fourth-edition section in Section 32.5. Declarations keep their current namespaces; the third-edition-numbered imports CLRSLean.Chapter_32 and CLRSLean.Chapter_32.Section_32_* forward to these sources.

Implementation details

The supporting implementation pages remain available outside the main sidebar:

Coverage boundary

The native sections supply the represented fourth-edition string-matching sections (§32.1, §32.2, §32.3, §32.4, and §32.5). RKExecution.execute prepares the high-position power and both seed hashes once, then uses seven fixed scalar arithmetic operations per slide. The returned shifts refine the naive matcher, including empty and oversized patterns. Power/seed counters are actual recursions; confirmation remains the stated per-hit budget, excluding list movement, symbol-map and bit costs.

DFAExecution.execute builds one table and passes it explicitly into a scan that counts one transition request per character. The table-cell count excludes suffix search inside delta; list and alphabet lookup are not constant-time. No efficient table-construction runtime is claimed.

Suffix-array sorting counts whole-suffix comparisons, not character work. Binary queries exclude construction, list indexing and result materialization. Their empty-pattern results range over stored positions 0,...,n-1, omitting the terminal boundary n. KMP retains its proved execution control-step metric and its existing storage-cost boundary.

See docs/clrs-fourth-edition-map.csv for the section-level mapping and docs/migrations/clrs4.md for compatibility and deprecation policy.

CLRS, fourth edition · Chapter 32 of 35