Theorem: String.firstDiffPos_loop_eq
File: Std/Data/String/Lemmas.lean

tactic: unfold List.takeWhile₂
state_before: l₁ l₂ r₁ r₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
hstop : stop = min (utf8Len l₁ + utf8Len r₁) (utf8Len l₂ + utf8Len r₂)
⊢ firstDiffPos.loop { data := l₁ ++ r₁ } { data := l₂ ++ r₂ } { byteIdx := stop } { byteIdx := p } =
    { byteIdx := p + utf8Len (List.takeWhile₂ (fun x x_1 => decide (x = x_1)) r₁ r₂).fst }

tactic: split <;> unfold firstDiffPos.loop
state_before: l₁ l₂ r₁ r₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
hstop : stop = min (utf8Len l₁ + utf8Len r₁) (utf8Len l₂ + utf8Len r₂)
⊢ firstDiffPos.loop { data := l₁ ++ r₁ } { data := l₂ ++ r₂ } { byteIdx := stop } { byteIdx := p } =
    {
      byteIdx :=
        p +
          utf8Len
            (match r₁, r₂ with
              | a :: as, b :: bs =>
                if decide (a = b) = true then
                  match List.takeWhile₂ (fun x x_1 => decide (x = x_1)) as bs with
                  | (as', bs') => (a :: as', b :: bs')
                else ([], [])
              | x, x_1 => ([], [])).fst }

tactic: next a r₁ b r₂ =>
rw [
  dif_pos <| by
    rw [hstop, ← hl₁, ← hl₂]
    refine Nat.lt_min.2 ⟨?_, ?_⟩ <;> exact Nat.lt_add_of_pos_right add_csize_pos,
  show get ⟨l₁ ++ a :: r₁⟩ ⟨p⟩ = a by simp [hl₁, get_of_valid],
  show get ⟨l₂ ++ b :: r₂⟩ ⟨p⟩ = b by simp [hl₂, get_of_valid]]
simp [bne]; split <;> simp
subst b
rw [show next ⟨l₁ ++ a :: r₁⟩ ⟨p⟩ = ⟨utf8Len l₁ + csize a⟩ by simp [hl₁, next_of_valid]]
simpa [← hl₁, ← Nat.add_assoc, Nat.add_right_comm] using
  firstDiffPos_loop_eq (l₁ ++ [a]) (l₂ ++ [a]) r₁ r₂ stop (p + csize a)
    (by simp [hl₁]) (by simp [hl₂]) (by simp [hstop, ← Nat.add_assoc, Nat.add_right_comm])
state_before: case h_1
l₁ l₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
x✝¹ x✝ : List Char
a✝ : Char
as✝ : List Char
b✝ : Char
bs✝ : List Char
hstop : stop = min (utf8Len l₁ + utf8Len (a✝ :: as✝)) (utf8Len l₂ + utf8Len (b✝ :: bs✝))
⊢ (if h : { byteIdx := p } < { byteIdx := stop } then
      if
          (get { data := l₁ ++ a✝ :: as✝ } { byteIdx := p } != get { data := l₂ ++ b✝ :: bs✝ } { byteIdx := p }) =
            true then
        { byteIdx := p }
      else
        let_fun this :=
          (_ :
            { byteIdx := stop }.byteIdx - (next { data := l₁ ++ a✝ :: as✝ } { byteIdx := p }).byteIdx <
              { byteIdx := stop }.byteIdx - { byteIdx := p }.byteIdx);
        firstDiffPos.loop { data := l₁ ++ a✝ :: as✝ } { data := l₂ ++ b✝ :: bs✝ } { byteIdx := stop }
          (next { data := l₁ ++ a✝ :: as✝ } { byteIdx := p })
    else { byteIdx := p }) =
    {
      byteIdx :=
        p +
          utf8Len
            (if decide (a✝ = b✝) = true then
                match List.takeWhile₂ (fun x x_1 => decide (x = x_1)) as✝ bs✝ with
                | (as', bs') => (a✝ :: as', b✝ :: bs')
              else ([], [])).fst }

tactic: rw [
  dif_pos <| by
    rw [hstop, ← hl₁, ← hl₂]
    refine Nat.lt_min.2 ⟨?_, ?_⟩ <;> exact Nat.lt_add_of_pos_right add_csize_pos,
  show get ⟨l₁ ++ a :: r₁⟩ ⟨p⟩ = a by simp [hl₁, get_of_valid],
  show get ⟨l₂ ++ b :: r₂⟩ ⟨p⟩ = b by simp [hl₂, get_of_valid]]
state_before: l₁ l₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
x✝¹ x✝ : List Char
a : Char
r₁ : List Char
b : Char
r₂ : List Char
hstop : stop = min (utf8Len l₁ + utf8Len (a :: r₁)) (utf8Len l₂ + utf8Len (b :: r₂))
⊢ (if h : { byteIdx := p } < { byteIdx := stop } then
      if (get { data := l₁ ++ a :: r₁ } { byteIdx := p } != get { data := l₂ ++ b :: r₂ } { byteIdx := p }) = true then
        { byteIdx := p }
      else
        let_fun this :=
          (_ :
            { byteIdx := stop }.byteIdx - (next { data := l₁ ++ a :: r₁ } { byteIdx := p }).byteIdx <
              { byteIdx := stop }.byteIdx - { byteIdx := p }.byteIdx);
        firstDiffPos.loop { data := l₁ ++ a :: r₁ } { data := l₂ ++ b :: r₂ } { byteIdx := stop }
          (next { data := l₁ ++ a :: r₁ } { byteIdx := p })
    else { byteIdx := p }) =
    {
      byteIdx :=
        p +
          utf8Len
            (if decide (a = b) = true then
                match List.takeWhile₂ (fun x x_1 => decide (x = x_1)) r₁ r₂ with
                | (as', bs') => (a :: as', b :: bs')
              else ([], [])).fst }

tactic: simp [bne]
state_before: l₁ l₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
x✝¹ x✝ : List Char
a : Char
r₁ : List Char
b : Char
r₂ : List Char
hstop : stop = min (utf8Len l₁ + utf8Len (a :: r₁)) (utf8Len l₂ + utf8Len (b :: r₂))
⊢ (if (a != b) = true then { byteIdx := p }
    else
      let_fun this :=
        (_ :
          { byteIdx := stop }.byteIdx - (next { data := l₁ ++ a :: r₁ } { byteIdx := p }).byteIdx <
            { byteIdx := stop }.byteIdx - { byteIdx := p }.byteIdx);
      firstDiffPos.loop { data := l₁ ++ a :: r₁ } { data := l₂ ++ b :: r₂ } { byteIdx := stop }
        (next { data := l₁ ++ a :: r₁ } { byteIdx := p })) =
    {
      byteIdx :=
        p +
          utf8Len
            (if decide (a = b) = true then
                match List.takeWhile₂ (fun x x_1 => decide (x = x_1)) r₁ r₂ with
                | (as', bs') => (a :: as', b :: bs')
              else ([], [])).fst }

tactic: split <;> simp
state_before: l₁ l₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
x✝¹ x✝ : List Char
a : Char
r₁ : List Char
b : Char
r₂ : List Char
hstop : stop = min (utf8Len l₁ + utf8Len (a :: r₁)) (utf8Len l₂ + utf8Len (b :: r₂))
⊢ (if a = b then
      firstDiffPos.loop { data := l₁ ++ a :: r₁ } { data := l₂ ++ b :: r₂ } { byteIdx := stop }
        (next { data := l₁ ++ a :: r₁ } { byteIdx := p })
    else { byteIdx := p }) =
    {
      byteIdx :=
        p +
          utf8Len
            (if a = b then
                (a :: (List.takeWhile₂ (fun x x_1 => decide (x = x_1)) r₁ r₂).fst,
                  b :: (List.takeWhile₂ (fun x x_1 => decide (x = x_1)) r₁ r₂).snd)
              else ([], [])).fst }

tactic: subst b
state_before: case inl
l₁ l₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
x✝¹ x✝ : List Char
a : Char
r₁ : List Char
b : Char
r₂ : List Char
hstop : stop = min (utf8Len l₁ + utf8Len (a :: r₁)) (utf8Len l₂ + utf8Len (b :: r₂))
h✝ : a = b
⊢ firstDiffPos.loop { data := l₁ ++ a :: r₁ } { data := l₂ ++ b :: r₂ } { byteIdx := stop }
      (next { data := l₁ ++ a :: r₁ } { byteIdx := p }) =
    { byteIdx := p + (utf8Len (List.takeWhile₂ (fun x x_1 => decide (x = x_1)) r₁ r₂).fst + csize a) }

tactic: rw [show next ⟨l₁ ++ a :: r₁⟩ ⟨p⟩ = ⟨utf8Len l₁ + csize a⟩ by simp [hl₁, next_of_valid]]
state_before: case inl
l₁ l₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
x✝¹ x✝ : List Char
a : Char
r₁ r₂ : List Char
hstop : stop = min (utf8Len l₁ + utf8Len (a :: r₁)) (utf8Len l₂ + utf8Len (a :: r₂))
⊢ firstDiffPos.loop { data := l₁ ++ a :: r₁ } { data := l₂ ++ a :: r₂ } { byteIdx := stop }
      (next { data := l₁ ++ a :: r₁ } { byteIdx := p }) =
    { byteIdx := p + (utf8Len (List.takeWhile₂ (fun x x_1 => decide (x = x_1)) r₁ r₂).fst + csize a) }

tactic: simpa [← hl₁, ← Nat.add_assoc, Nat.add_right_comm] using
  firstDiffPos_loop_eq (l₁ ++ [a]) (l₂ ++ [a]) r₁ r₂ stop (p + csize a)
    (by simp [hl₁]) (by simp [hl₂]) (by simp [hstop, ← Nat.add_assoc, Nat.add_right_comm])
state_before: case inl
l₁ l₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
x✝¹ x✝ : List Char
a : Char
r₁ r₂ : List Char
hstop : stop = min (utf8Len l₁ + utf8Len (a :: r₁)) (utf8Len l₂ + utf8Len (a :: r₂))
⊢ firstDiffPos.loop { data := l₁ ++ a :: r₁ } { data := l₂ ++ a :: r₂ } { byteIdx := stop }
      { byteIdx := utf8Len l₁ + csize a } =
    { byteIdx := p + (utf8Len (List.takeWhile₂ (fun x x_1 => decide (x = x_1)) r₁ r₂).fst + csize a) }

tactic: rw [hstop, ← hl₁, ← hl₂]
state_before: l₁ l₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
x✝¹ x✝ : List Char
a : Char
r₁ : List Char
b : Char
r₂ : List Char
hstop : stop = min (utf8Len l₁ + utf8Len (a :: r₁)) (utf8Len l₂ + utf8Len (b :: r₂))
⊢ { byteIdx := p } < { byteIdx := stop }

tactic: refine Nat.lt_min.2 ⟨?_, ?_⟩ <;> exact Nat.lt_add_of_pos_right add_csize_pos
state_before: l₁ l₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
x✝¹ x✝ : List Char
a : Char
r₁ : List Char
b : Char
r₂ : List Char
hstop : stop = min (utf8Len l₁ + utf8Len (a :: r₁)) (utf8Len l₂ + utf8Len (b :: r₂))
⊢ { byteIdx := p } < { byteIdx := min (p + utf8Len (a :: r₁)) (p + utf8Len (b :: r₂)) }

tactic: simp [hl₁, get_of_valid]
state_before: l₁ l₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
x✝¹ x✝ : List Char
a : Char
r₁ : List Char
b : Char
r₂ : List Char
hstop : stop = min (utf8Len l₁ + utf8Len (a :: r₁)) (utf8Len l₂ + utf8Len (b :: r₂))
⊢ get { data := l₁ ++ a :: r₁ } { byteIdx := p } = a

tactic: simp [hl₂, get_of_valid]
state_before: l₁ l₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
x✝¹ x✝ : List Char
a : Char
r₁ : List Char
b : Char
r₂ : List Char
hstop : stop = min (utf8Len l₁ + utf8Len (a :: r₁)) (utf8Len l₂ + utf8Len (b :: r₂))
⊢ get { data := l₂ ++ b :: r₂ } { byteIdx := p } = b

tactic: simp [hl₁, next_of_valid]
state_before: l₁ l₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
x✝¹ x✝ : List Char
a : Char
r₁ r₂ : List Char
hstop : stop = min (utf8Len l₁ + utf8Len (a :: r₁)) (utf8Len l₂ + utf8Len (a :: r₂))
⊢ next { data := l₁ ++ a :: r₁ } { byteIdx := p } = { byteIdx := utf8Len l₁ + csize a }

tactic: simp [hl₁]
state_before: l₁ l₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
x✝¹ x✝ : List Char
a : Char
r₁ r₂ : List Char
hstop : stop = min (utf8Len l₁ + utf8Len (a :: r₁)) (utf8Len l₂ + utf8Len (a :: r₂))
⊢ p + csize a = utf8Len (l₁ ++ [a])

tactic: simp [hl₂]
state_before: l₁ l₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
x✝¹ x✝ : List Char
a : Char
r₁ r₂ : List Char
hstop : stop = min (utf8Len l₁ + utf8Len (a :: r₁)) (utf8Len l₂ + utf8Len (a :: r₂))
⊢ p + csize a = utf8Len (l₂ ++ [a])

tactic: simp [hstop, ← Nat.add_assoc, Nat.add_right_comm]
state_before: l₁ l₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
x✝¹ x✝ : List Char
a : Char
r₁ r₂ : List Char
hstop : stop = min (utf8Len l₁ + utf8Len (a :: r₁)) (utf8Len l₂ + utf8Len (a :: r₂))
⊢ stop = min (utf8Len (l₁ ++ [a]) + utf8Len r₁) (utf8Len (l₂ ++ [a]) + utf8Len r₂)

tactic: next h =>
rw [dif_neg] <;> simp [hstop, ← hl₁, ← hl₂, -Nat.not_lt, Nat.lt_min]
intro h₁ h₂
have : ∀ {cs}, p < p + utf8Len cs → cs ≠ [] := by rintro _ h rfl; simp at h
obtain ⟨a, as, e₁⟩ := List.exists_cons_of_ne_nil (this h₁)
obtain ⟨b, bs, e₂⟩ := List.exists_cons_of_ne_nil (this h₂)
exact h _ _ _ _ e₁ e₂
state_before: case h_2
l₁ l₂ r₁ r₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
hstop : stop = min (utf8Len l₁ + utf8Len r₁) (utf8Len l₂ + utf8Len r₂)
x✝² x✝¹ : List Char
x✝ : ∀ (a : Char) (as : List Char) (b : Char) (bs : List Char), r₁ = a :: as → r₂ = b :: bs → False
⊢ (if h : { byteIdx := p } < { byteIdx := stop } then
      if (get { data := l₁ ++ r₁ } { byteIdx := p } != get { data := l₂ ++ r₂ } { byteIdx := p }) = true then
        { byteIdx := p }
      else
        let_fun this :=
          (_ :
            { byteIdx := stop }.byteIdx - (next { data := l₁ ++ r₁ } { byteIdx := p }).byteIdx <
              { byteIdx := stop }.byteIdx - { byteIdx := p }.byteIdx);
        firstDiffPos.loop { data := l₁ ++ r₁ } { data := l₂ ++ r₂ } { byteIdx := stop }
          (next { data := l₁ ++ r₁ } { byteIdx := p })
    else { byteIdx := p }) =
    { byteIdx := p + utf8Len ([], []).fst }

tactic: rw [dif_neg] <;> simp [hstop, ← hl₁, ← hl₂, -Nat.not_lt, Nat.lt_min]
state_before: l₁ l₂ r₁ r₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
hstop : stop = min (utf8Len l₁ + utf8Len r₁) (utf8Len l₂ + utf8Len r₂)
x✝¹ x✝ : List Char
h : ∀ (a : Char) (as : List Char) (b : Char) (bs : List Char), r₁ = a :: as → r₂ = b :: bs → False
⊢ (if h : { byteIdx := p } < { byteIdx := stop } then
      if (get { data := l₁ ++ r₁ } { byteIdx := p } != get { data := l₂ ++ r₂ } { byteIdx := p }) = true then
        { byteIdx := p }
      else
        let_fun this :=
          (_ :
            { byteIdx := stop }.byteIdx - (next { data := l₁ ++ r₁ } { byteIdx := p }).byteIdx <
              { byteIdx := stop }.byteIdx - { byteIdx := p }.byteIdx);
        firstDiffPos.loop { data := l₁ ++ r₁ } { data := l₂ ++ r₂ } { byteIdx := stop }
          (next { data := l₁ ++ r₁ } { byteIdx := p })
    else { byteIdx := p }) =
    { byteIdx := p + utf8Len ([], []).fst }

tactic: intro h₁ h₂
state_before: case hnc
l₁ l₂ r₁ r₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
hstop : stop = min (utf8Len l₁ + utf8Len r₁) (utf8Len l₂ + utf8Len r₂)
x✝¹ x✝ : List Char
h : ∀ (a : Char) (as : List Char) (b : Char) (bs : List Char), r₁ = a :: as → r₂ = b :: bs → False
⊢ p < p + utf8Len r₁ → ¬p < p + utf8Len r₂

tactic: have : ∀ {cs}, p < p + utf8Len cs → cs ≠ [] := by rintro _ h rfl; simp at h
state_before: case hnc
l₁ l₂ r₁ r₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
hstop : stop = min (utf8Len l₁ + utf8Len r₁) (utf8Len l₂ + utf8Len r₂)
x✝¹ x✝ : List Char
h : ∀ (a : Char) (as : List Char) (b : Char) (bs : List Char), r₁ = a :: as → r₂ = b :: bs → False
h₁ : p < p + utf8Len r₁
h₂ : p < p + utf8Len r₂
⊢ False

tactic: obtain ⟨a, as, e₁⟩ := List.exists_cons_of_ne_nil (this h₁)
state_before: case hnc
l₁ l₂ r₁ r₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
hstop : stop = min (utf8Len l₁ + utf8Len r₁) (utf8Len l₂ + utf8Len r₂)
x✝¹ x✝ : List Char
h : ∀ (a : Char) (as : List Char) (b : Char) (bs : List Char), r₁ = a :: as → r₂ = b :: bs → False
h₁ : p < p + utf8Len r₁
h₂ : p < p + utf8Len r₂
this : ∀ {cs : List Char}, p < p + utf8Len cs → cs ≠ []
⊢ False

tactic: obtain ⟨b, bs, e₂⟩ := List.exists_cons_of_ne_nil (this h₂)
state_before: case hnc.intro.intro
l₁ l₂ r₁ r₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
hstop : stop = min (utf8Len l₁ + utf8Len r₁) (utf8Len l₂ + utf8Len r₂)
x✝¹ x✝ : List Char
h : ∀ (a : Char) (as : List Char) (b : Char) (bs : List Char), r₁ = a :: as → r₂ = b :: bs → False
h₁ : p < p + utf8Len r₁
h₂ : p < p + utf8Len r₂
this : ∀ {cs : List Char}, p < p + utf8Len cs → cs ≠ []
a : Char
as : List Char
e₁ : r₁ = a :: as
⊢ False

tactic: exact h _ _ _ _ e₁ e₂
state_before: case hnc.intro.intro.intro.intro
l₁ l₂ r₁ r₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
hstop : stop = min (utf8Len l₁ + utf8Len r₁) (utf8Len l₂ + utf8Len r₂)
x✝¹ x✝ : List Char
h : ∀ (a : Char) (as : List Char) (b : Char) (bs : List Char), r₁ = a :: as → r₂ = b :: bs → False
h₁ : p < p + utf8Len r₁
h₂ : p < p + utf8Len r₂
this : ∀ {cs : List Char}, p < p + utf8Len cs → cs ≠ []
a : Char
as : List Char
e₁ : r₁ = a :: as
b : Char
bs : List Char
e₂ : r₂ = b :: bs
⊢ False

tactic: rintro _ h rfl
state_before: l₁ l₂ r₁ r₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
hstop : stop = min (utf8Len l₁ + utf8Len r₁) (utf8Len l₂ + utf8Len r₂)
x✝¹ x✝ : List Char
h : ∀ (a : Char) (as : List Char) (b : Char) (bs : List Char), r₁ = a :: as → r₂ = b :: bs → False
h₁ : p < p + utf8Len r₁
h₂ : p < p + utf8Len r₂
⊢ ∀ {cs : List Char}, p < p + utf8Len cs → cs ≠ []

tactic: simp at h
state_before: l₁ l₂ r₁ r₂ : List Char
stop p : Nat
hl₁ : p = utf8Len l₁
hl₂ : p = utf8Len l₂
hstop : stop = min (utf8Len l₁ + utf8Len r₁) (utf8Len l₂ + utf8Len r₂)
x✝¹ x✝ : List Char
h✝ : ∀ (a : Char) (as : List Char) (b : Char) (bs : List Char), r₁ = a :: as → r₂ = b :: bs → False
h₁ : p < p + utf8Len r₁
h₂ : p < p + utf8Len r₂
h : p < p + utf8Len []
⊢ False