l3lab/ntp-mathlib huggingface dataset:
theorem ltb_cons_addChar (c : Char) (cs₁ cs₂ : List Char) (i₁ i₂ : Pos) :
    ltb ⟨⟨c :: cs₁⟩, i₁ + c⟩ ⟨⟨c :: cs₂⟩, i₂ + c⟩ = ltb ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ := by
  apply ltb.inductionOn ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ (motive := fun ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ ↦
    ltb ⟨⟨c :: cs₁⟩, i₁ + c⟩ ⟨⟨c :: cs₂⟩, i₂ + c⟩ =
    ltb ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩) <;> simp <;>
  intro ⟨cs₁⟩ ⟨cs₂⟩ i₁ i₂ <;>
  intros <;>
  (conv => lhs; rw [ltb]) <;> (conv => rhs; rw [ltb]) <;>
  simp only [Iterator.hasNext_cons_addChar, ite_false, ite_true, *]
  · rename_i h₂ h₁ heq ih
    

Proof state:
case ind
c : Char
cs₁✝ cs₂✝ : List Char
i₁✝ i₂✝ : Pos
cs₁ cs₂ : List Char
i₁ i₂ : Pos
h₂ : Iterator.hasNext { s := { data := cs₂ }, i := i₂ } = true
h₁ : Iterator.hasNext { s := { data := cs₁ }, i := i₁ } = true
heq : get { data := cs₁ } i₁ = get { data := cs₂ } i₂
ih :
  ltb
      { s := { data := c :: (Iterator.next { s := { data := cs₁ }, i := i₁ }).1.data },
        i := (Iterator.next { s := { data := cs₁ }, i := i₁ }).i + c }
      { s := { data := c :: (Iterator.next { s := { data := cs₂ }, i := i₂ }).1.data },
        i := (Iterator.next { s := { data := cs₂ }, i := i₂ }).i + c } =
    ltb
      { s := { data := (Iterator.next { s := { data := cs₁ }, i := i₁ }).1.data },
        i := (Iterator.next { s := { data := cs₁ }, i := i₁ }).i }
      { s := { data := (Iterator.next { s := { data := cs₂ }, i := i₂ }).1.data },
        i := (Iterator.next { s := { data := cs₂ }, i := i₂ }).i }
⊢ (if
        Iterator.curr { s := { data := c :: cs₁ }, i := i₁ + c } =
          Iterator.curr { s := { data := c :: cs₂ }, i := i₂ + c } then
      ltb (Iterator.next { s := { data := c :: cs₁ }, i := i₁ + c })
        (Iterator.next { s := { data := c :: cs₂ }, i := i₂ + c })
    else
      decide
        (Iterator.curr { s := { data := c :: cs₁ }, i := i₁ + c } <
          Iterator.curr { s := { data := c :: cs₂ }, i := i₂ + c })) =
    if Iterator.curr { s := { data := cs₁ }, i := i₁ } = Iterator.curr { s := { data := cs₂ }, i := i₂ } then
      ltb (Iterator.next { s := { data := cs₁ }, i := i₁ }) (Iterator.next { s := { data := cs₂ }, i := i₂ })
    else decide (Iterator.curr { s := { data := cs₁ }, i := i₁ } < Iterator.curr { s := { data := cs₂ }, i := i₂ })

Next tactic:
simp [Iterator.curr, get_cons_addChar, Iterator.next, next, *] at *
theorem ltb_cons_addChar (c : Char) (cs₁ cs₂ : List Char) (i₁ i₂ : Pos) :
    ltb ⟨⟨c :: cs₁⟩, i₁ + c⟩ ⟨⟨c :: cs₂⟩, i₂ + c⟩ = ltb ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ := by
  apply ltb.inductionOn ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ (motive := fun ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ ↦
    ltb ⟨⟨c :: cs₁⟩, i₁ + c⟩ ⟨⟨c :: cs₂⟩, i₂ + c⟩ =
    ltb ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩) <;> simp <;>
  intro ⟨cs₁⟩ ⟨cs₂⟩ i₁ i₂ <;>
  intros <;>
  (conv => lhs; rw [ltb]) <;> (conv => rhs; rw [ltb]) <;>
  simp only [Iterator.hasNext_cons_addChar, ite_false, ite_true, *]
  · rename_i h₂ h₁ heq ih
    simp [Iterator.curr, get_cons_addChar, Iterator.next, next, *] at *
    

Proof state:
case ind
c : Char
cs₁✝ cs₂✝ : List Char
i₁✝ i₂✝ : Pos
cs₁ cs₂ : List Char
i₁ i₂ : Pos
h₂ : Iterator.hasNext { s := { data := cs₂ }, i := i₂ } = true
h₁ : Iterator.hasNext { s := { data := cs₁ }, i := i₁ } = true
heq : get { data := cs₁ } i₁ = get { data := cs₂ } i₂
ih :
  ltb { s := { data := c :: cs₁ }, i := i₁ + get { data := cs₂ } i₂ + c }
      { s := { data := c :: cs₂ }, i := i₂ + get { data := cs₂ } i₂ + c } =
    ltb { s := { data := cs₁ }, i := i₁ + get { data := cs₂ } i₂ }
      { s := { data := cs₂ }, i := i₂ + get { data := cs₂ } i₂ }
⊢ ltb { s := { data := c :: cs₁ }, i := i₁ + c + get { data := cs₂ } i₂ }
      { s := { data := c :: cs₂ }, i := i₂ + c + get { data := cs₂ } i₂ } =
    ltb { s := { data := cs₁ }, i := i₁ + get { data := cs₂ } i₂ }
      { s := { data := cs₂ }, i := i₂ + get { data := cs₂ } i₂ }

Next tactic:
repeat rw [Pos.addChar_right_comm _ c]
theorem ltb_cons_addChar (c : Char) (cs₁ cs₂ : List Char) (i₁ i₂ : Pos) :
    ltb ⟨⟨c :: cs₁⟩, i₁ + c⟩ ⟨⟨c :: cs₂⟩, i₂ + c⟩ = ltb ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ := by
  apply ltb.inductionOn ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ (motive := fun ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ ↦
    ltb ⟨⟨c :: cs₁⟩, i₁ + c⟩ ⟨⟨c :: cs₂⟩, i₂ + c⟩ =
    ltb ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩) <;> simp <;>
  intro ⟨cs₁⟩ ⟨cs₂⟩ i₁ i₂ <;>
  intros <;>
  (conv => lhs; rw [ltb]) <;> (conv => rhs; rw [ltb]) <;>
  simp only [Iterator.hasNext_cons_addChar, ite_false, ite_true, *]
  · rename_i h₂ h₁ heq ih
    simp [Iterator.curr, get_cons_addChar, Iterator.next, next, *] at *
    repeat 

Proof state:
case ind
c : Char
cs₁✝ cs₂✝ : List Char
i₁✝ i₂✝ : Pos
cs₁ cs₂ : List Char
i₁ i₂ : Pos
h₂ : Iterator.hasNext { s := { data := cs₂ }, i := i₂ } = true
h₁ : Iterator.hasNext { s := { data := cs₁ }, i := i₁ } = true
heq : get { data := cs₁ } i₁ = get { data := cs₂ } i₂
ih :
  ltb { s := { data := c :: cs₁ }, i := i₁ + get { data := cs₂ } i₂ + c }
      { s := { data := c :: cs₂ }, i := i₂ + get { data := cs₂ } i₂ + c } =
    ltb { s := { data := cs₁ }, i := i₁ + get { data := cs₂ } i₂ }
      { s := { data := cs₂ }, i := i₂ + get { data := cs₂ } i₂ }
⊢ ltb { s := { data := c :: cs₁ }, i := i₁ + c + get { data := cs₂ } i₂ }
      { s := { data := c :: cs₂ }, i := i₂ + c + get { data := cs₂ } i₂ } =
    ltb { s := { data := cs₁ }, i := i₁ + get { data := cs₂ } i₂ }
      { s := { data := cs₂ }, i := i₂ + get { data := cs₂ } i₂ }

Next tactic:
rw [Pos.addChar_right_comm _ c]
theorem ltb_cons_addChar (c : Char) (cs₁ cs₂ : List Char) (i₁ i₂ : Pos) :
    ltb ⟨⟨c :: cs₁⟩, i₁ + c⟩ ⟨⟨c :: cs₂⟩, i₂ + c⟩ = ltb ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ := by
  apply ltb.inductionOn ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ (motive := fun ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ ↦
    ltb ⟨⟨c :: cs₁⟩, i₁ + c⟩ ⟨⟨c :: cs₂⟩, i₂ + c⟩ =
    ltb ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩) <;> simp <;>
  intro ⟨cs₁⟩ ⟨cs₂⟩ i₁ i₂ <;>
  intros <;>
  (conv => lhs; rw [ltb]) <;> (conv => rhs; rw [ltb]) <;>
  simp only [Iterator.hasNext_cons_addChar, ite_false, ite_true, *]
  · rename_i h₂ h₁ heq ih
    simp [Iterator.curr, get_cons_addChar, Iterator.next, next, *] at *
    repeat 

Proof state:
case ind
c : Char
cs₁✝ cs₂✝ : List Char
i₁✝ i₂✝ : Pos
cs₁ cs₂ : List Char
i₁ i₂ : Pos
h₂ : Iterator.hasNext { s := { data := cs₂ }, i := i₂ } = true
h₁ : Iterator.hasNext { s := { data := cs₁ }, i := i₁ } = true
heq : get { data := cs₁ } i₁ = get { data := cs₂ } i₂
ih :
  ltb { s := { data := c :: cs₁ }, i := i₁ + get { data := cs₂ } i₂ + c }
      { s := { data := c :: cs₂ }, i := i₂ + get { data := cs₂ } i₂ + c } =
    ltb { s := { data := cs₁ }, i := i₁ + get { data := cs₂ } i₂ }
      { s := { data := cs₂ }, i := i₂ + get { data := cs₂ } i₂ }
⊢ ltb { s := { data := c :: cs₁ }, i := i₁ + get { data := cs₂ } i₂ + c }
      { s := { data := c :: cs₂ }, i := i₂ + c + get { data := cs₂ } i₂ } =
    ltb { s := { data := cs₁ }, i := i₁ + get { data := cs₂ } i₂ }
      { s := { data := cs₂ }, i := i₂ + get { data := cs₂ } i₂ }

Next tactic:
rw [Pos.addChar_right_comm _ c]
theorem ltb_cons_addChar (c : Char) (cs₁ cs₂ : List Char) (i₁ i₂ : Pos) :
    ltb ⟨⟨c :: cs₁⟩, i₁ + c⟩ ⟨⟨c :: cs₂⟩, i₂ + c⟩ = ltb ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ := by
  apply ltb.inductionOn ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ (motive := fun ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ ↦
    ltb ⟨⟨c :: cs₁⟩, i₁ + c⟩ ⟨⟨c :: cs₂⟩, i₂ + c⟩ =
    ltb ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩) <;> simp <;>
  intro ⟨cs₁⟩ ⟨cs₂⟩ i₁ i₂ <;>
  intros <;>
  (conv => lhs; rw [ltb]) <;> (conv => rhs; rw [ltb]) <;>
  simp only [Iterator.hasNext_cons_addChar, ite_false, ite_true, *]
  · rename_i h₂ h₁ heq ih
    simp [Iterator.curr, get_cons_addChar, Iterator.next, next, *] at *
    repeat 

Proof state:
case ind
c : Char
cs₁✝ cs₂✝ : List Char
i₁✝ i₂✝ : Pos
cs₁ cs₂ : List Char
i₁ i₂ : Pos
h₂ : Iterator.hasNext { s := { data := cs₂ }, i := i₂ } = true
h₁ : Iterator.hasNext { s := { data := cs₁ }, i := i₁ } = true
heq : get { data := cs₁ } i₁ = get { data := cs₂ } i₂
ih :
  ltb { s := { data := c :: cs₁ }, i := i₁ + get { data := cs₂ } i₂ + c }
      { s := { data := c :: cs₂ }, i := i₂ + get { data := cs₂ } i₂ + c } =
    ltb { s := { data := cs₁ }, i := i₁ + get { data := cs₂ } i₂ }
      { s := { data := cs₂ }, i := i₂ + get { data := cs₂ } i₂ }
⊢ ltb { s := { data := c :: cs₁ }, i := i₁ + get { data := cs₂ } i₂ + c }
      { s := { data := c :: cs₂ }, i := i₂ + get { data := cs₂ } i₂ + c } =
    ltb { s := { data := cs₁ }, i := i₁ + get { data := cs₂ } i₂ }
      { s := { data := cs₂ }, i := i₂ + get { data := cs₂ } i₂ }

Next tactic:
rw [Pos.addChar_right_comm _ c]
theorem ltb_cons_addChar (c : Char) (cs₁ cs₂ : List Char) (i₁ i₂ : Pos) :
    ltb ⟨⟨c :: cs₁⟩, i₁ + c⟩ ⟨⟨c :: cs₂⟩, i₂ + c⟩ = ltb ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ := by
  apply ltb.inductionOn ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ (motive := fun ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ ↦
    ltb ⟨⟨c :: cs₁⟩, i₁ + c⟩ ⟨⟨c :: cs₂⟩, i₂ + c⟩ =
    ltb ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩) <;> simp <;>
  intro ⟨cs₁⟩ ⟨cs₂⟩ i₁ i₂ <;>
  intros <;>
  (conv => lhs; rw [ltb]) <;> (conv => rhs; rw [ltb]) <;>
  simp only [Iterator.hasNext_cons_addChar, ite_false, ite_true, *]
  · rename_i h₂ h₁ heq ih
    simp [Iterator.curr, get_cons_addChar, Iterator.next, next, *] at *
    repeat rw [Pos.addChar_right_comm _ c]
    

Proof state:
case ind
c : Char
cs₁✝ cs₂✝ : List Char
i₁✝ i₂✝ : Pos
cs₁ cs₂ : List Char
i₁ i₂ : Pos
h₂ : Iterator.hasNext { s := { data := cs₂ }, i := i₂ } = true
h₁ : Iterator.hasNext { s := { data := cs₁ }, i := i₁ } = true
heq : get { data := cs₁ } i₁ = get { data := cs₂ } i₂
ih :
  ltb { s := { data := c :: cs₁ }, i := i₁ + get { data := cs₂ } i₂ + c }
      { s := { data := c :: cs₂ }, i := i₂ + get { data := cs₂ } i₂ + c } =
    ltb { s := { data := cs₁ }, i := i₁ + get { data := cs₂ } i₂ }
      { s := { data := cs₂ }, i := i₂ + get { data := cs₂ } i₂ }
⊢ ltb { s := { data := c :: cs₁ }, i := i₁ + get { data := cs₂ } i₂ + c }
      { s := { data := c :: cs₂ }, i := i₂ + get { data := cs₂ } i₂ + c } =
    ltb { s := { data := cs₁ }, i := i₁ + get { data := cs₂ } i₂ }
      { s := { data := cs₂ }, i := i₂ + get { data := cs₂ } i₂ }

Next tactic:
exact ih
theorem ltb_cons_addChar (c : Char) (cs₁ cs₂ : List Char) (i₁ i₂ : Pos) :
    ltb ⟨⟨c :: cs₁⟩, i₁ + c⟩ ⟨⟨c :: cs₂⟩, i₂ + c⟩ = ltb ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ := by
  apply ltb.inductionOn ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ (motive := fun ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ ↦
    ltb ⟨⟨c :: cs₁⟩, i₁ + c⟩ ⟨⟨c :: cs₂⟩, i₂ + c⟩ =
    ltb ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩) <;> simp <;>
  intro ⟨cs₁⟩ ⟨cs₂⟩ i₁ i₂ <;>
  intros <;>
  (conv => lhs; rw [ltb]) <;> (conv => rhs; rw [ltb]) <;>
  simp only [Iterator.hasNext_cons_addChar, ite_false, ite_true, *]
  · rename_i h₂ h₁ heq ih
    simp [Iterator.curr, get_cons_addChar, Iterator.next, next, *] at *
    repeat rw [Pos.addChar_right_comm _ c]
    exact ih
  · 

Proof state:
case eq
c : Char
cs₁✝ cs₂✝ : List Char
i₁✝ i₂✝ : Pos
cs₁ cs₂ : List Char
i₁ i₂ : Pos
a✝² : Iterator.hasNext { s := { data := cs₂ }, i := i₂ } = true
a✝¹ : Iterator.hasNext { s := { data := cs₁ }, i := i₁ } = true
a✝ : ¬get { data := cs₁ } i₁ = get { data := cs₂ } i₂
⊢ (if
        Iterator.curr { s := { data := c :: cs₁ }, i := i₁ + c } =
          Iterator.curr { s := { data := c :: cs₂ }, i := i₂ + c } then
      ltb (Iterator.next { s := { data := c :: cs₁ }, i := i₁ + c })
        (Iterator.next { s := { data := c :: cs₂ }, i := i₂ + c })
    else
      decide
        (Iterator.curr { s := { data := c :: cs₁ }, i := i₁ + c } <
          Iterator.curr { s := { data := c :: cs₂ }, i := i₂ + c })) =
    if Iterator.curr { s := { data := cs₁ }, i := i₁ } = Iterator.curr { s := { data := cs₂ }, i := i₂ } then
      ltb (Iterator.next { s := { data := cs₁ }, i := i₁ }) (Iterator.next { s := { data := cs₂ }, i := i₂ })
    else decide (Iterator.curr { s := { data := cs₁ }, i := i₁ } < Iterator.curr { s := { data := cs₂ }, i := i₂ })

Next tactic:
rename_i h₂ h₁ hne
theorem ltb_cons_addChar (c : Char) (cs₁ cs₂ : List Char) (i₁ i₂ : Pos) :
    ltb ⟨⟨c :: cs₁⟩, i₁ + c⟩ ⟨⟨c :: cs₂⟩, i₂ + c⟩ = ltb ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ := by
  apply ltb.inductionOn ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ (motive := fun ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩ ↦
    ltb ⟨⟨c :: cs₁⟩, i₁ + c⟩ ⟨⟨c :: cs₂⟩, i₂ + c⟩ =
    ltb ⟨⟨cs₁⟩, i₁⟩ ⟨⟨cs₂⟩, i₂⟩) <;> simp <;>
  intro ⟨cs₁⟩ ⟨cs₂⟩ i₁ i₂ <;>
  intros <;>
  (conv => lhs; rw [ltb]) <;> (conv => rhs; rw [ltb]) <;>
  simp only [Iterator.hasNext_cons_addChar, ite_false, ite_true, *]
  · rename_i h₂ h₁ heq ih
    simp [Iterator.curr, get_cons_addChar, Iterator.next, next, *] at *
    repeat rw [Pos.addChar_right_comm _ c]
    exact ih
  · rename_i h₂ h₁ hne
    

Proof state:
case eq
c : Char
cs₁✝ cs₂✝ : List Char
i₁✝ i₂✝ : Pos
cs₁ cs₂ : List Char
i₁ i₂ : Pos
h₂ : Iterator.hasNext { s := { data := cs₂ }, i := i₂ } = true
h₁ : Iterator.hasNext { s := { data := cs₁ }, i := i₁ } = true
hne : ¬get { data := cs₁ } i₁ = get { data := cs₂ } i₂
⊢ (if
        Iterator.curr { s := { data := c :: cs₁ }, i := i₁ + c } =
          Iterator.curr { s := { data := c :: cs₂ }, i := i₂ + c } then
      ltb (Iterator.next { s := { data := c :: cs₁ }, i := i₁ + c })
        (Iterator.next { s := { data := c :: cs₂ }, i := i₂ + c })
    else
      decide
        (Iterator.curr { s := { data := c :: cs₁ }, i := i₁ + c } <
          Iterator.curr { s := { data := c :: cs₂ }, i := i₂ + c })) =
    if Iterator.curr { s := { data := cs₁ }, i := i₁ } = Iterator.curr { s := { data := cs₂ }, i := i₂ } then
      ltb (Iterator.next { s := { data := cs₁ }, i := i₁ }) (Iterator.next { s := { data := cs₂ }, i := i₂ })
    else decide (Iterator.curr { s := { data := cs₁ }, i := i₁ } < Iterator.curr { s := { data := cs₂ }, i := i₂ })

Next tactic:
simp [Iterator.curr, get_cons_addChar, *]
@[simp]
theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList < s₂.toList
  | ⟨s₁⟩, ⟨s₂⟩ => show ltb ⟨⟨s₁⟩, 0⟩ ⟨⟨s₂⟩, 0⟩ ↔ s₁ < s₂ by
    

Proof state:
s₁ s₂ : List Char
⊢ ltb { s := { data := s₁ }, i := 0 } { s := { data := s₂ }, i := 0 } = true ↔ s₁ < s₂

Next tactic:
induction s₁ generalizing s₂
@[simp]
theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList < s₂.toList
  | ⟨s₁⟩, ⟨s₂⟩ => show ltb ⟨⟨s₁⟩, 0⟩ ⟨⟨s₂⟩, 0⟩ ↔ s₁ < s₂ by
    induction s₁ generalizing s₂ <;> 

Proof state:
case nil
s₂ : List Char
⊢ ltb { s := { data := [] }, i := 0 } { s := { data := s₂ }, i := 0 } = true ↔ [] < s₂

Next tactic:
cases s₂
@[simp]
theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList < s₂.toList
  | ⟨s₁⟩, ⟨s₂⟩ => show ltb ⟨⟨s₁⟩, 0⟩ ⟨⟨s₂⟩, 0⟩ ↔ s₁ < s₂ by
    induction s₁ generalizing s₂ <;> 

Proof state:
case cons
head✝ : Char
tail✝ : List Char
tail_ih✝ :
  ∀ (s₂ : List Char), ltb { s := { data := tail✝ }, i := 0 } { s := { data := s₂ }, i := 0 } = true ↔ tail✝ < s₂
s₂ : List Char
⊢ ltb { s := { data := head✝ :: tail✝ }, i := 0 } { s := { data := s₂ }, i := 0 } = true ↔ head✝ :: tail✝ < s₂

Next tactic:
cases s₂
@[simp]
theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList < s₂.toList
  | ⟨s₁⟩, ⟨s₂⟩ => show ltb ⟨⟨s₁⟩, 0⟩ ⟨⟨s₂⟩, 0⟩ ↔ s₁ < s₂ by
    induction s₁ generalizing s₂ <;> cases s₂
    · 

Proof state:
case nil.nil
⊢ ltb { s := { data := [] }, i := 0 } { s := { data := [] }, i := 0 } = true ↔ [] < []

Next tactic:
decide
@[simp]
theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList < s₂.toList
  | ⟨s₁⟩, ⟨s₂⟩ => show ltb ⟨⟨s₁⟩, 0⟩ ⟨⟨s₂⟩, 0⟩ ↔ s₁ < s₂ by
    induction s₁ generalizing s₂ <;> cases s₂
    · decide
    · 

Proof state:
case nil.cons
head✝ : Char
tail✝ : List Char
⊢ ltb { s := { data := [] }, i := 0 } { s := { data := head✝ :: tail✝ }, i := 0 } = true ↔ [] < head✝ :: tail✝

Next tactic:
rename_i c₂ cs₂
@[simp]
theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList < s₂.toList
  | ⟨s₁⟩, ⟨s₂⟩ => show ltb ⟨⟨s₁⟩, 0⟩ ⟨⟨s₂⟩, 0⟩ ↔ s₁ < s₂ by
    induction s₁ generalizing s₂ <;> cases s₂
    · decide
    · rename_i c₂ cs₂; 

Proof state:
case nil.cons
c₂ : Char
cs₂ : List Char
⊢ ltb { s := { data := [] }, i := 0 } { s := { data := c₂ :: cs₂ }, i := 0 } = true ↔ [] < c₂ :: cs₂

Next tactic:
apply iff_of_true
@[simp]
theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList < s₂.toList
  | ⟨s₁⟩, ⟨s₂⟩ => show ltb ⟨⟨s₁⟩, 0⟩ ⟨⟨s₂⟩, 0⟩ ↔ s₁ < s₂ by
    induction s₁ generalizing s₂ <;> cases s₂
    · decide
    · rename_i c₂ cs₂; apply iff_of_true
      · 

Proof state:
case nil.cons.ha
c₂ : Char
cs₂ : List Char
⊢ ltb { s := { data := [] }, i := 0 } { s := { data := c₂ :: cs₂ }, i := 0 } = true

Next tactic:
rw [ltb]
@[simp]
theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList < s₂.toList
  | ⟨s₁⟩, ⟨s₂⟩ => show ltb ⟨⟨s₁⟩, 0⟩ ⟨⟨s₂⟩, 0⟩ ↔ s₁ < s₂ by
    induction s₁ generalizing s₂ <;> cases s₂
    · decide
    · rename_i c₂ cs₂; apply iff_of_true
      · rw [ltb]; 

Proof state:
case nil.cons.ha
c₂ : Char
cs₂ : List Char
⊢ (if Iterator.hasNext { s := { data := c₂ :: cs₂ }, i := 0 } = true then
      if Iterator.hasNext { s := { data := [] }, i := 0 } = true then
        if Iterator.curr { s := { data := [] }, i := 0 } = Iterator.curr { s := { data := c₂ :: cs₂ }, i := 0 } then
          ltb (Iterator.next { s := { data := [] }, i := 0 }) (Iterator.next { s := { data := c₂ :: cs₂ }, i := 0 })
        else
          decide (Iterator.curr { s := { data := [] }, i := 0 } < Iterator.curr { s := { data := c₂ :: cs₂ }, i := 0 })
      else true
    else false) =
    true

Next tactic:
simp only [Iterator.hasNext, Iterator.curr]
@[simp]
theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList < s₂.toList
  | ⟨s₁⟩, ⟨s₂⟩ => show ltb ⟨⟨s₁⟩, 0⟩ ⟨⟨s₂⟩, 0⟩ ↔ s₁ < s₂ by
    induction s₁ generalizing s₂ <;> cases s₂
    · decide
    · rename_i c₂ cs₂; apply iff_of_true
      · rw [ltb]; simp only [Iterator.hasNext, Iterator.curr]
        

Proof state:
case nil.cons.ha
c₂ : Char
cs₂ : List Char
⊢ (if decide (0.byteIdx < (endPos { data := c₂ :: cs₂ }).byteIdx) = true then
      if decide (0.byteIdx < (endPos { data := [] }).byteIdx) = true then
        if get { data := [] } 0 = get { data := c₂ :: cs₂ } 0 then
          ltb (Iterator.next { s := { data := [] }, i := 0 }) (Iterator.next { s := { data := c₂ :: cs₂ }, i := 0 })
        else decide (get { data := [] } 0 < get { data := c₂ :: cs₂ } 0)
      else true
    else false) =
    true

Next tactic:
simp [endPos, utf8ByteSize, utf8ByteSize.go, csize_pos]
@[simp]
theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList < s₂.toList
  | ⟨s₁⟩, ⟨s₂⟩ => show ltb ⟨⟨s₁⟩, 0⟩ ⟨⟨s₂⟩, 0⟩ ↔ s₁ < s₂ by
    induction s₁ generalizing s₂ <;> cases s₂
    · decide
    · rename_i c₂ cs₂; apply iff_of_true
      · rw [ltb]; simp only [Iterator.hasNext, Iterator.curr]
        simp [endPos, utf8ByteSize, utf8ByteSize.go, csize_pos]
      · 

Proof state:
case nil.cons.hb
c₂ : Char
cs₂ : List Char
⊢ [] < c₂ :: cs₂

Next tactic:
apply List.nil_lt_cons
@[simp]
theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList < s₂.toList
  | ⟨s₁⟩, ⟨s₂⟩ => show ltb ⟨⟨s₁⟩, 0⟩ ⟨⟨s₂⟩, 0⟩ ↔ s₁ < s₂ by
    induction s₁ generalizing s₂ <;> cases s₂
    · decide
    · rename_i c₂ cs₂; apply iff_of_true
      · rw [ltb]; simp only [Iterator.hasNext, Iterator.curr]
        simp [endPos, utf8ByteSize, utf8ByteSize.go, csize_pos]
      · apply List.nil_lt_cons
    · 

Proof state:
case cons.nil
head✝ : Char
tail✝ : List Char
tail_ih✝ :
  ∀ (s₂ : List Char), ltb { s := { data := tail✝ }, i := 0 } { s := { data := s₂ }, i := 0 } = true ↔ tail✝ < s₂
⊢ ltb { s := { data := head✝ :: tail✝ }, i := 0 } { s := { data := [] }, i := 0 } = true ↔ head✝ :: tail✝ < []

Next tactic:
rename_i c₁ cs₁ ih
@[simp]
theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList < s₂.toList
  | ⟨s₁⟩, ⟨s₂⟩ => show ltb ⟨⟨s₁⟩, 0⟩ ⟨⟨s₂⟩, 0⟩ ↔ s₁ < s₂ by
    induction s₁ generalizing s₂ <;> cases s₂
    · decide
    · rename_i c₂ cs₂; apply iff_of_true
      · rw [ltb]; simp only [Iterator.hasNext, Iterator.curr]
        simp [endPos, utf8ByteSize, utf8ByteSize.go, csize_pos]
      · apply List.nil_lt_cons
    · rename_i c₁ cs₁ ih; 

Proof state:
case cons.nil
c₁ : Char
cs₁ : List Char
ih : ∀ (s₂ : List Char), ltb { s := { data := cs₁ }, i := 0 } { s := { data := s₂ }, i := 0 } = true ↔ cs₁ < s₂
⊢ ltb { s := { data := c₁ :: cs₁ }, i := 0 } { s := { data := [] }, i := 0 } = true ↔ c₁ :: cs₁ < []

Next tactic:
apply iff_of_false
@[simp]
theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList < s₂.toList
  | ⟨s₁⟩, ⟨s₂⟩ => show ltb ⟨⟨s₁⟩, 0⟩ ⟨⟨s₂⟩, 0⟩ ↔ s₁ < s₂ by
    induction s₁ generalizing s₂ <;> cases s₂
    · decide
    · rename_i c₂ cs₂; apply iff_of_true
      · rw [ltb]; simp only [Iterator.hasNext, Iterator.curr]
        simp [endPos, utf8ByteSize, utf8ByteSize.go, csize_pos]
      · apply List.nil_lt_cons
    · rename_i c₁ cs₁ ih; apply iff_of_false
      · 

Proof state:
case cons.nil.ha
c₁ : Char
cs₁ : List Char
ih : ∀ (s₂ : List Char), ltb { s := { data := cs₁ }, i := 0 } { s := { data := s₂ }, i := 0 } = true ↔ cs₁ < s₂
⊢ ¬ltb { s := { data := c₁ :: cs₁ }, i := 0 } { s := { data := [] }, i := 0 } = true

Next tactic:
rw [ltb]
@[simp]
theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList < s₂.toList
  | ⟨s₁⟩, ⟨s₂⟩ => show ltb ⟨⟨s₁⟩, 0⟩ ⟨⟨s₂⟩, 0⟩ ↔ s₁ < s₂ by
    induction s₁ generalizing s₂ <;> cases s₂
    · decide
    · rename_i c₂ cs₂; apply iff_of_true
      · rw [ltb]; simp only [Iterator.hasNext, Iterator.curr]
        simp [endPos, utf8ByteSize, utf8ByteSize.go, csize_pos]
      · apply List.nil_lt_cons
    · rename_i c₁ cs₁ ih; apply iff_of_false
      · rw [ltb]; 

Proof state:
case cons.nil.ha
c₁ : Char
cs₁ : List Char
ih : ∀ (s₂ : List Char), ltb { s := { data := cs₁ }, i := 0 } { s := { data := s₂ }, i := 0 } = true ↔ cs₁ < s₂
⊢ ¬(if Iterator.hasNext { s := { data := [] }, i := 0 } = true then
        if Iterator.hasNext { s := { data := c₁ :: cs₁ }, i := 0 } = true then
          if Iterator.curr { s := { data := c₁ :: cs₁ }, i := 0 } = Iterator.curr { s := { data := [] }, i := 0 } then
            ltb (Iterator.next { s := { data := c₁ :: cs₁ }, i := 0 }) (Iterator.next { s := { data := [] }, i := 0 })
          else
            decide
              (Iterator.curr { s := { data := c₁ :: cs₁ }, i := 0 } < Iterator.curr { s := { data := [] }, i := 0 })
        else true
      else false) =
      true

Next tactic:
simp [Iterator.hasNext, Iterator.curr]
@[simp]
theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList < s₂.toList
  | ⟨s₁⟩, ⟨s₂⟩ => show ltb ⟨⟨s₁⟩, 0⟩ ⟨⟨s₂⟩, 0⟩ ↔ s₁ < s₂ by
    induction s₁ generalizing s₂ <;> cases s₂
    · decide
    · rename_i c₂ cs₂; apply iff_of_true
      · rw [ltb]; simp only [Iterator.hasNext, Iterator.curr]
        simp [endPos, utf8ByteSize, utf8ByteSize.go, csize_pos]
      · apply List.nil_lt_cons
    · rename_i c₁ cs₁ ih; apply iff_of_false
      · rw [ltb]; simp [Iterator.hasNext, Iterator.curr]
      · 

Proof state:
case cons.nil.hb
c₁ : Char
cs₁ : List Char
ih : ∀ (s₂ : List Char), ltb { s := { data := cs₁ }, i := 0 } { s := { data := s₂ }, i := 0 } = true ↔ cs₁ < s₂
⊢ ¬c₁ :: cs₁ < []

Next tactic:
apply not_lt_of_lt
@[simp]
theorem lt_iff_toList_lt : ∀ {s₁ s₂ : String}, s₁ < s₂ ↔ s₁.toList < s₂.toList
  | ⟨s₁⟩, ⟨s₂⟩ => show ltb ⟨⟨s₁⟩, 0⟩ ⟨⟨s₂⟩, 0⟩ ↔ s₁ < s₂ by
    induction s₁ generalizing s₂ <;> cases s₂
    · decide
    · rename_i c₂ cs₂; apply iff_of_true
      · rw [ltb]; simp only [Iterator.hasNext, Iterator.curr]
        simp [endPos, utf8ByteSize, utf8ByteSize.go, csize_pos]
      · apply List.nil_lt_cons
    · rename_i c₁ cs₁ ih; apply iff_of_false
      · rw [ltb]; simp [Iterator.hasNext, Iterator.curr]
      · apply not_lt_of_lt; 

Proof state:
case cons.nil.hb.a
c₁ : Char
cs₁ : List Char
ih : ∀ (s₂ : List Char), ltb { s := { data := cs₁ }, i := 0 } { s := { data := s₂ }, i := 0 } = true ↔ cs₁ < s₂
⊢ [] < c₁ :: cs₁

Next tactic:
apply List.nil_lt_cons