l3lab/ntp-mathlib huggingface dataset:
theorem impl_length (d : {r : List δ // 0 < r.length}) (w : d.1.length = xs.length + 1) :
    (impl C xs y d).1.length = xs.length + 1 := by
  induction xs generalizing d
  · case nil =>
    rfl
  · case cons x xs ih =>
    

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
x✝ : α
xs✝ : List α
y : β
d✝ : δ
ds : List δ
w✝ : 0 < List.length (d✝ :: ds)
x : α
xs : List α
ih :
  ∀ (d : { r // 0 < List.length r }),
    List.length ↑d = List.length xs + 1 → List.length ↑(impl C xs y d) = List.length xs + 1
d : { r // 0 < List.length r }
w : List.length ↑d = List.length (x :: xs) + 1
⊢ List.length ↑(impl C (x :: xs) y d) = List.length (x :: xs) + 1

Next tactic:
dsimp [impl]
theorem impl_length (d : {r : List δ // 0 < r.length}) (w : d.1.length = xs.length + 1) :
    (impl C xs y d).1.length = xs.length + 1 := by
  induction xs generalizing d
  · case nil =>
    rfl
  · case cons x xs ih =>
    dsimp [impl]
    

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
x✝ : α
xs✝ : List α
y : β
d✝ : δ
ds : List δ
w✝ : 0 < List.length (d✝ :: ds)
x : α
xs : List α
ih :
  ∀ (d : { r // 0 < List.length r }),
    List.length ↑d = List.length xs + 1 → List.length ↑(impl C xs y d) = List.length xs + 1
d : { r // 0 < List.length r }
w : List.length ↑d = List.length (x :: xs) + 1
⊢ List.length
      ↑(List.foldr
          (fun x x_1 =>
            {
              val :=
                min (Cost.delete C x.1 + List.get ↑x_1 { val := 0, isLt := (_ : 0 < List.length ↑x_1) })
                    (min (Cost.insert C y + x.2.1) (Cost.substitute C x.1 y + x.2.2)) ::
                  ↑x_1,
              property := (_ : 0 < Nat.succ (List.length ↑x_1)) })
          { val := [Cost.insert C y + List.getLast ↑d (_ : ↑d ≠ [])], property := impl.proof_3 }
          (List.zip (x :: xs) (List.zip (↑d) (List.tail ↑d)))) =
    Nat.succ (List.length xs) + 1

Next tactic:
match d, w with
    | ⟨d₁ :: d₂ :: ds, _⟩, w =>
      dsimp
      congr 1
      exact ih ⟨d₂ :: ds, (by simp)⟩ (by simpa using w)
theorem impl_length (d : {r : List δ // 0 < r.length}) (w : d.1.length = xs.length + 1) :
    (impl C xs y d).1.length = xs.length + 1 := by
  induction xs generalizing d
  · case nil =>
    rfl
  · case cons x xs ih =>
    dsimp [impl]
    match d, w with
    | ⟨d₁ :: d₂ :: ds, _⟩, w =>
      

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
x✝ : α
xs✝ : List α
y : β
d✝ : δ
ds✝ : List δ
w✝¹ : 0 < List.length (d✝ :: ds✝)
x : α
xs : List α
ih :
  ∀ (d : { r // 0 < List.length r }),
    List.length ↑d = List.length xs + 1 → List.length ↑(impl C xs y d) = List.length xs + 1
d : { r // 0 < List.length r }
w✝ : List.length ↑d = List.length (x :: xs) + 1
d₁ d₂ : δ
ds : List δ
property✝ : 0 < List.length (d₁ :: d₂ :: ds)
w : List.length ↑{ val := d₁ :: d₂ :: ds, property := property✝ } = List.length (x :: xs) + 1
⊢ List.length
      ↑(List.foldr
          (fun x x_1 =>
            {
              val :=
                min (Cost.delete C x.1 + List.get ↑x_1 { val := 0, isLt := (_ : 0 < List.length ↑x_1) })
                    (min (Cost.insert C y + x.2.1) (Cost.substitute C x.1 y + x.2.2)) ::
                  ↑x_1,
              property := (_ : 0 < Nat.succ (List.length ↑x_1)) })
          {
            val :=
              [Cost.insert C y +
                  List.getLast ↑{ val := d₁ :: d₂ :: ds, property := property✝ }
                    (_ : ↑{ val := d₁ :: d₂ :: ds, property := property✝ } ≠ [])],
            property := impl.proof_3 }
          (List.zip (x :: xs)
            (List.zip (↑{ val := d₁ :: d₂ :: ds, property := property✝ })
              (List.tail ↑{ val := d₁ :: d₂ :: ds, property := property✝ })))) =
    Nat.succ (List.length xs) + 1

Next tactic:
dsimp
theorem impl_length (d : {r : List δ // 0 < r.length}) (w : d.1.length = xs.length + 1) :
    (impl C xs y d).1.length = xs.length + 1 := by
  induction xs generalizing d
  · case nil =>
    rfl
  · case cons x xs ih =>
    dsimp [impl]
    match d, w with
    | ⟨d₁ :: d₂ :: ds, _⟩, w =>
      dsimp
      

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
x✝ : α
xs✝ : List α
y : β
d✝ : δ
ds✝ : List δ
w✝¹ : 0 < List.length (d✝ :: ds✝)
x : α
xs : List α
ih :
  ∀ (d : { r // 0 < List.length r }),
    List.length ↑d = List.length xs + 1 → List.length ↑(impl C xs y d) = List.length xs + 1
d : { r // 0 < List.length r }
w✝ : List.length ↑d = List.length (x :: xs) + 1
d₁ d₂ : δ
ds : List δ
property✝ : 0 < List.length (d₁ :: d₂ :: ds)
w : List.length ↑{ val := d₁ :: d₂ :: ds, property := property✝ } = List.length (x :: xs) + 1
⊢ Nat.succ
      (List.length
        ↑(List.foldr
            (fun x x_1 =>
              {
                val :=
                  min (Cost.delete C x.1 + List.get ↑x_1 { val := 0, isLt := (_ : 0 < List.length ↑x_1) })
                      (min (Cost.insert C y + x.2.1) (Cost.substitute C x.1 y + x.2.2)) ::
                    ↑x_1,
                property := (_ : 0 < Nat.succ (List.length ↑x_1)) })
            { val := [Cost.insert C y + List.getLast (d₁ :: d₂ :: ds) (_ : d₁ :: d₂ :: ds ≠ [])],
              property := impl.proof_3 }
            (List.zip xs (List.zip (d₂ :: ds) ds)))) =
    Nat.succ (List.length xs) + 1

Next tactic:
congr 1
theorem impl_length (d : {r : List δ // 0 < r.length}) (w : d.1.length = xs.length + 1) :
    (impl C xs y d).1.length = xs.length + 1 := by
  induction xs generalizing d
  · case nil =>
    rfl
  · case cons x xs ih =>
    dsimp [impl]
    match d, w with
    | ⟨d₁ :: d₂ :: ds, _⟩, w =>
      dsimp
      congr 1
      

Proof state:
case e_n
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
x✝ : α
xs✝ : List α
y : β
d✝ : δ
ds✝ : List δ
w✝¹ : 0 < List.length (d✝ :: ds✝)
x : α
xs : List α
ih :
  ∀ (d : { r // 0 < List.length r }),
    List.length ↑d = List.length xs + 1 → List.length ↑(impl C xs y d) = List.length xs + 1
d : { r // 0 < List.length r }
w✝ : List.length ↑d = List.length (x :: xs) + 1
d₁ d₂ : δ
ds : List δ
property✝ : 0 < List.length (d₁ :: d₂ :: ds)
w : List.length ↑{ val := d₁ :: d₂ :: ds, property := property✝ } = List.length (x :: xs) + 1
⊢ List.length
      ↑(List.foldr
          (fun x x_1 =>
            {
              val :=
                min (Cost.delete C x.1 + List.get ↑x_1 { val := 0, isLt := (_ : 0 < List.length ↑x_1) })
                    (min (Cost.insert C y + x.2.1) (Cost.substitute C x.1 y + x.2.2)) ::
                  ↑x_1,
              property := (_ : 0 < Nat.succ (List.length ↑x_1)) })
          { val := [Cost.insert C y + List.getLast (d₁ :: d₂ :: ds) (_ : d₁ :: d₂ :: ds ≠ [])],
            property := impl.proof_3 }
          (List.zip xs (List.zip (d₂ :: ds) ds))) =
    List.length xs + 1

Next tactic:
exact ih ⟨d₂ :: ds, (by simp)⟩ (by simpa using w)
theorem impl_length (d : {r : List δ // 0 < r.length}) (w : d.1.length = xs.length + 1) :
    (impl C xs y d).1.length = xs.length + 1 := by
  induction xs generalizing d
  · case nil =>
    rfl
  · case cons x xs ih =>
    dsimp [impl]
    match d, w with
    | ⟨d₁ :: d₂ :: ds, _⟩, w =>
      dsimp
      congr 1
      exact ih ⟨d₂ :: ds, (by 

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
x✝ : α
xs✝ : List α
y : β
d✝ : δ
ds✝ : List δ
w✝¹ : 0 < List.length (d✝ :: ds✝)
x : α
xs : List α
ih :
  ∀ (d : { r // 0 < List.length r }),
    List.length ↑d = List.length xs + 1 → List.length ↑(impl C xs y d) = List.length xs + 1
d : { r // 0 < List.length r }
w✝ : List.length ↑d = List.length (x :: xs) + 1
d₁ d₂ : δ
ds : List δ
property✝ : 0 < List.length (d₁ :: d₂ :: ds)
w : List.length ↑{ val := d₁ :: d₂ :: ds, property := property✝ } = List.length (x :: xs) + 1
⊢ 0 < List.length (d₂ :: ds)

Next tactic:
simp
theorem impl_length (d : {r : List δ // 0 < r.length}) (w : d.1.length = xs.length + 1) :
    (impl C xs y d).1.length = xs.length + 1 := by
  induction xs generalizing d
  · case nil =>
    rfl
  · case cons x xs ih =>
    dsimp [impl]
    match d, w with
    | ⟨d₁ :: d₂ :: ds, _⟩, w =>
      dsimp
      congr 1
      exact ih ⟨d₂ :: ds, (by simp)⟩ (by 

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
x✝ : α
xs✝ : List α
y : β
d✝ : δ
ds✝ : List δ
w✝¹ : 0 < List.length (d✝ :: ds✝)
x : α
xs : List α
ih :
  ∀ (d : { r // 0 < List.length r }),
    List.length ↑d = List.length xs + 1 → List.length ↑(impl C xs y d) = List.length xs + 1
d : { r // 0 < List.length r }
w✝ : List.length ↑d = List.length (x :: xs) + 1
d₁ d₂ : δ
ds : List δ
property✝ : 0 < List.length (d₁ :: d₂ :: ds)
w : List.length ↑{ val := d₁ :: d₂ :: ds, property := property✝ } = List.length (x :: xs) + 1
⊢ List.length ↑{ val := d₂ :: ds, property := (_ : 0 < Nat.succ (List.length ds)) } = List.length xs + 1

Next tactic:
simpa using w
/--
`suffixLevenshtein C xs ys` computes the Levenshtein distance
(using the cost functions provided by a `C : Cost α β δ`)
from each suffix of the list `xs` to the list `ys`.

The first element of this list is the Levenshtein distance from `xs` to `ys`.

Note that if the cost functions do not satisfy the inequalities
* `C.delete a + C.insert b ≥ C.substitute a b`
* `C.substitute a b + C.substitute b c ≥ C.substitute a c`
(or if any values are negative)
then the edit distances calculated here may not agree with the general
geodesic distance on the edit graph.
-/
def suffixLevenshtein (xs : List α) (ys : List β) : {r : List δ // 0 < r.length} :=
  ys.foldr
    (impl C xs)
    (xs.foldr (init := ⟨[0], by simp⟩) (fun a ⟨r, w⟩ => ⟨(C.delete a + r[0]) :: r, by 

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
xs : List α
ys : List β
a : α
x✝ : { r // 0 < List.length r }
r : List δ
w : 0 < List.length r
⊢ 0 < List.length ((Cost.delete C a + r[0]) :: r)

Next tactic:
simp
/--
`suffixLevenshtein C xs ys` computes the Levenshtein distance
(using the cost functions provided by a `C : Cost α β δ`)
from each suffix of the list `xs` to the list `ys`.

The first element of this list is the Levenshtein distance from `xs` to `ys`.

Note that if the cost functions do not satisfy the inequalities
* `C.delete a + C.insert b ≥ C.substitute a b`
* `C.substitute a b + C.substitute b c ≥ C.substitute a c`
(or if any values are negative)
then the edit distances calculated here may not agree with the general
geodesic distance on the edit graph.
-/
def suffixLevenshtein (xs : List α) (ys : List β) : {r : List δ // 0 < r.length} :=
  ys.foldr
    (impl C xs)
    (xs.foldr (init := ⟨[0], by 

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
xs : List α
ys : List β
⊢ 0 < List.length [0]

Next tactic:
simp
theorem suffixLevenshtein_length (xs : List α) (ys : List β) :
    (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by
  

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
xs : List α
ys : List β
⊢ List.length ↑(suffixLevenshtein C xs ys) = List.length xs + 1

Next tactic:
induction ys
theorem suffixLevenshtein_length (xs : List α) (ys : List β) :
    (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by
  induction ys
  · 

Proof state:
case nil
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
xs : List α
⊢ List.length ↑(suffixLevenshtein C xs []) = List.length xs + 1

Next tactic:
case nil =>
    dsimp [suffixLevenshtein]
    induction xs
    · case nil => rfl
    · case cons _ xs ih =>
      simp_all
theorem suffixLevenshtein_length (xs : List α) (ys : List β) :
    (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by
  induction ys
  · 

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
xs : List α
⊢ List.length ↑(suffixLevenshtein C xs []) = List.length xs + 1

Next tactic:
case nil =>
    dsimp [suffixLevenshtein]
    induction xs
    · case nil => rfl
    · case cons _ xs ih =>
      simp_all
theorem suffixLevenshtein_length (xs : List α) (ys : List β) :
    (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by
  induction ys
  · case nil =>
    

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
xs : List α
⊢ List.length ↑(suffixLevenshtein C xs []) = List.length xs + 1

Next tactic:
dsimp [suffixLevenshtein]
theorem suffixLevenshtein_length (xs : List α) (ys : List β) :
    (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by
  induction ys
  · case nil =>
    dsimp [suffixLevenshtein]
    

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
xs : List α
⊢ List.length
      ↑(List.foldr
          (fun a x =>
            { val := (Cost.delete C a + List.get ↑x { val := 0, isLt := (_ : 0 < List.length ↑x) }) :: ↑x,
              property := (_ : 0 < Nat.succ (List.length ↑x)) })
          { val := [0], property := suffixLevenshtein.proof_2 } xs) =
    List.length xs + 1

Next tactic:
induction xs
theorem suffixLevenshtein_length (xs : List α) (ys : List β) :
    (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by
  induction ys
  · case nil =>
    dsimp [suffixLevenshtein]
    induction xs
    · 

Proof state:
case nil
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
⊢ List.length
      ↑(List.foldr
          (fun a x =>
            { val := (Cost.delete C a + List.get ↑x { val := 0, isLt := (_ : 0 < List.length ↑x) }) :: ↑x,
              property := (_ : 0 < Nat.succ (List.length ↑x)) })
          { val := [0], property := suffixLevenshtein.proof_2 } []) =
    List.length [] + 1

Next tactic:
case nil => rfl
theorem suffixLevenshtein_length (xs : List α) (ys : List β) :
    (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by
  induction ys
  · case nil =>
    dsimp [suffixLevenshtein]
    induction xs
    · 

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
⊢ List.length
      ↑(List.foldr
          (fun a x =>
            { val := (Cost.delete C a + List.get ↑x { val := 0, isLt := (_ : 0 < List.length ↑x) }) :: ↑x,
              property := (_ : 0 < Nat.succ (List.length ↑x)) })
          { val := [0], property := suffixLevenshtein.proof_2 } []) =
    List.length [] + 1

Next tactic:
case nil => rfl
theorem suffixLevenshtein_length (xs : List α) (ys : List β) :
    (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by
  induction ys
  · case nil =>
    dsimp [suffixLevenshtein]
    induction xs
    · case nil => 

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
⊢ List.length
      ↑(List.foldr
          (fun a x =>
            { val := (Cost.delete C a + List.get ↑x { val := 0, isLt := (_ : 0 < List.length ↑x) }) :: ↑x,
              property := (_ : 0 < Nat.succ (List.length ↑x)) })
          { val := [0], property := suffixLevenshtein.proof_2 } []) =
    List.length [] + 1

Next tactic:
rfl
theorem suffixLevenshtein_length (xs : List α) (ys : List β) :
    (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by
  induction ys
  · case nil =>
    dsimp [suffixLevenshtein]
    induction xs
    · case nil => rfl
    · 

Proof state:
case cons
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
head✝ : α
tail✝ : List α
tail_ih✝ :
  List.length
      ↑(List.foldr
          (fun a x =>
            { val := (Cost.delete C a + List.get ↑x { val := 0, isLt := (_ : 0 < List.length ↑x) }) :: ↑x,
              property := (_ : 0 < Nat.succ (List.length ↑x)) })
          { val := [0], property := suffixLevenshtein.proof_2 } tail✝) =
    List.length tail✝ + 1
⊢ List.length
      ↑(List.foldr
          (fun a x =>
            { val := (Cost.delete C a + List.get ↑x { val := 0, isLt := (_ : 0 < List.length ↑x) }) :: ↑x,
              property := (_ : 0 < Nat.succ (List.length ↑x)) })
          { val := [0], property := suffixLevenshtein.proof_2 } (head✝ :: tail✝)) =
    List.length (head✝ :: tail✝) + 1

Next tactic:
case cons _ xs ih =>
      simp_all
theorem suffixLevenshtein_length (xs : List α) (ys : List β) :
    (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by
  induction ys
  · case nil =>
    dsimp [suffixLevenshtein]
    induction xs
    · case nil => rfl
    · 

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
head✝ : α
xs : List α
ih :
  List.length
      ↑(List.foldr
          (fun a x =>
            { val := (Cost.delete C a + List.get ↑x { val := 0, isLt := (_ : 0 < List.length ↑x) }) :: ↑x,
              property := (_ : 0 < Nat.succ (List.length ↑x)) })
          { val := [0], property := suffixLevenshtein.proof_2 } xs) =
    List.length xs + 1
⊢ List.length
      ↑(List.foldr
          (fun a x =>
            { val := (Cost.delete C a + List.get ↑x { val := 0, isLt := (_ : 0 < List.length ↑x) }) :: ↑x,
              property := (_ : 0 < Nat.succ (List.length ↑x)) })
          { val := [0], property := suffixLevenshtein.proof_2 } (head✝ :: xs)) =
    List.length (head✝ :: xs) + 1

Next tactic:
case cons _ xs ih =>
      simp_all
theorem suffixLevenshtein_length (xs : List α) (ys : List β) :
    (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by
  induction ys
  · case nil =>
    dsimp [suffixLevenshtein]
    induction xs
    · case nil => rfl
    · case cons _ xs ih =>
      

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
head✝ : α
xs : List α
ih :
  List.length
      ↑(List.foldr
          (fun a x =>
            { val := (Cost.delete C a + List.get ↑x { val := 0, isLt := (_ : 0 < List.length ↑x) }) :: ↑x,
              property := (_ : 0 < Nat.succ (List.length ↑x)) })
          { val := [0], property := suffixLevenshtein.proof_2 } xs) =
    List.length xs + 1
⊢ List.length
      ↑(List.foldr
          (fun a x =>
            { val := (Cost.delete C a + List.get ↑x { val := 0, isLt := (_ : 0 < List.length ↑x) }) :: ↑x,
              property := (_ : 0 < Nat.succ (List.length ↑x)) })
          { val := [0], property := suffixLevenshtein.proof_2 } (head✝ :: xs)) =
    List.length (head✝ :: xs) + 1

Next tactic:
simp_all
theorem suffixLevenshtein_length (xs : List α) (ys : List β) :
    (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by
  induction ys
  · case nil =>
    dsimp [suffixLevenshtein]
    induction xs
    · case nil => rfl
    · case cons _ xs ih =>
      simp_all
  · 

Proof state:
case cons
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
xs : List α
head✝ : β
tail✝ : List β
tail_ih✝ : List.length ↑(suffixLevenshtein C xs tail✝) = List.length xs + 1
⊢ List.length ↑(suffixLevenshtein C xs (head✝ :: tail✝)) = List.length xs + 1

Next tactic:
case cons y ys ih =>
    dsimp [suffixLevenshtein]
    rw [impl_length]
    exact ih
theorem suffixLevenshtein_length (xs : List α) (ys : List β) :
    (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by
  induction ys
  · case nil =>
    dsimp [suffixLevenshtein]
    induction xs
    · case nil => rfl
    · case cons _ xs ih =>
      simp_all
  · 

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
xs : List α
y : β
ys : List β
ih : List.length ↑(suffixLevenshtein C xs ys) = List.length xs + 1
⊢ List.length ↑(suffixLevenshtein C xs (y :: ys)) = List.length xs + 1

Next tactic:
case cons y ys ih =>
    dsimp [suffixLevenshtein]
    rw [impl_length]
    exact ih
theorem suffixLevenshtein_length (xs : List α) (ys : List β) :
    (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by
  induction ys
  · case nil =>
    dsimp [suffixLevenshtein]
    induction xs
    · case nil => rfl
    · case cons _ xs ih =>
      simp_all
  · case cons y ys ih =>
    

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
xs : List α
y : β
ys : List β
ih : List.length ↑(suffixLevenshtein C xs ys) = List.length xs + 1
⊢ List.length ↑(suffixLevenshtein C xs (y :: ys)) = List.length xs + 1

Next tactic:
dsimp [suffixLevenshtein]
theorem suffixLevenshtein_length (xs : List α) (ys : List β) :
    (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by
  induction ys
  · case nil =>
    dsimp [suffixLevenshtein]
    induction xs
    · case nil => rfl
    · case cons _ xs ih =>
      simp_all
  · case cons y ys ih =>
    dsimp [suffixLevenshtein]
    

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
xs : List α
y : β
ys : List β
ih : List.length ↑(suffixLevenshtein C xs ys) = List.length xs + 1
⊢ List.length
      ↑(impl C xs y
          (List.foldr (impl C xs)
            (List.foldr
              (fun a x =>
                { val := (Cost.delete C a + List.get ↑x { val := 0, isLt := (_ : 0 < List.length ↑x) }) :: ↑x,
                  property := (_ : 0 < Nat.succ (List.length ↑x)) })
              { val := [0], property := suffixLevenshtein.proof_2 } xs)
            ys)) =
    List.length xs + 1

Next tactic:
rw [impl_length]
theorem suffixLevenshtein_length (xs : List α) (ys : List β) :
    (suffixLevenshtein C xs ys).1.length = xs.length + 1 := by
  induction ys
  · case nil =>
    dsimp [suffixLevenshtein]
    induction xs
    · case nil => rfl
    · case cons _ xs ih =>
      simp_all
  · case cons y ys ih =>
    dsimp [suffixLevenshtein]
    rw [impl_length]
    

Proof state:
case w
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
xs : List α
y : β
ys : List β
ih : List.length ↑(suffixLevenshtein C xs ys) = List.length xs + 1
⊢ List.length
      ↑(List.foldr (impl C xs)
          (List.foldr
            (fun a x =>
              { val := (Cost.delete C a + List.get ↑x { val := 0, isLt := (_ : 0 < List.length ↑x) }) :: ↑x,
                property := (_ : 0 < Nat.succ (List.length ↑x)) })
            { val := [0], property := suffixLevenshtein.proof_2 } xs)
          ys) =
    List.length xs + 1

Next tactic:
exact ih
theorem suffixLevenshtein_eq (xs : List α) (y ys) :
    impl C xs y (suffixLevenshtein C xs ys) = suffixLevenshtein C xs (y :: ys) := by
  

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
xs : List α
y : β
ys : List β
⊢ impl C xs y (suffixLevenshtein C xs ys) = suffixLevenshtein C xs (y :: ys)

Next tactic:
rfl
theorem suffixLevenshtein_nil_nil : (suffixLevenshtein C [] []).1 = [0] := by
  

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
⊢ ↑(suffixLevenshtein C [] []) = [0]

Next tactic:
rfl
theorem List.eq_of_length_one (x : List α) (w : x.length = 1) :
    have : 0 < x.length := (lt_of_lt_of_eq Nat.zero_lt_one w.symm)
    x = [x[0]] := by
  

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
x : List α
w : length x = 1
⊢ let_fun this := (_ : 0 < length x);
  x = [x[0]]

Next tactic:
match x, w with
  | [r], _ => rfl
theorem List.eq_of_length_one (x : List α) (w : x.length = 1) :
    have : 0 < x.length := (lt_of_lt_of_eq Nat.zero_lt_one w.symm)
    x = [x[0]] := by
  match x, w with
  | [r], _ => 

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
x : List α
w : length x = 1
r : α
x✝ : length [r] = 1
⊢ let_fun this := (_ : 0 < length [r]);
  [r] = [[r][0]]

Next tactic:
rfl
theorem suffixLevenshtein_cons₁_aux {x y : {r : List δ // 0 < r.length}}
    (w₀ : x.1[0]'x.2 = y.1[0]'y.2) (w : x.1.tail = y.1.tail) : x = y := by
  

Proof state:
α : Type u_1
β : Type u_2
δ : Type u_3
inst✝¹ : AddZeroClass δ
inst✝ : Min δ
C : Cost α β δ
x y : { r // 0 < List.length r }
w₀ : (↑x)[0] = (↑y)[0]
w : List.tail ↑x = List.tail ↑y
⊢ x = y

Next tactic:
match x, y with
  | ⟨hx :: tx, _⟩, ⟨hy :: ty, _⟩ => simp_all