l3lab/ntp-mathlib huggingface dataset:
theorem mem_rcons_iff {i j : ι} (p : Pair M i) (m : M j) :
    ⟨_, m⟩ ∈ (rcons p).toList ↔ ⟨_, m⟩ ∈ p.tail.toList ∨
      m ≠ 1 ∧ (∃ h : i = j, m = h ▸ p.head) := by
  simp only [rcons._eq_1, cons._eq_1, ne_eq]
  by_cases hij : i = j
  · subst i
    by_cases hm : m = p.head
    · 

Proof state:
case pos
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
j : ι
m : M j
p : Pair M j
hm : m = p.head
⊢ { fst := j, snd := m } ∈
      (if h : p.head = 1 then p.tail
        else
          { toList := { fst := j, snd := p.head } :: p.tail.toList,
            ne_one := (_ : ∀ l ∈ { fst := j, snd := p.head } :: p.tail.toList, l.snd ≠ 1),
            chain_ne :=
              (_ : List.Chain' (fun l l' => l.fst ≠ l'.fst) ({ fst := j, snd := p.head } :: p.tail.toList)) }).toList ↔
    { fst := j, snd := m } ∈ p.tail.toList ∨ ¬m = 1 ∧ ∃ (h : j = j), m = h ▸ p.head

Next tactic:
subst m
theorem mem_rcons_iff {i j : ι} (p : Pair M i) (m : M j) :
    ⟨_, m⟩ ∈ (rcons p).toList ↔ ⟨_, m⟩ ∈ p.tail.toList ∨
      m ≠ 1 ∧ (∃ h : i = j, m = h ▸ p.head) := by
  simp only [rcons._eq_1, cons._eq_1, ne_eq]
  by_cases hij : i = j
  · subst i
    by_cases hm : m = p.head
    · subst m
      

Proof state:
case pos
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
j : ι
p : Pair M j
⊢ { fst := j, snd := p.head } ∈
      (if h : p.head = 1 then p.tail
        else
          { toList := { fst := j, snd := p.head } :: p.tail.toList,
            ne_one := (_ : ∀ l ∈ { fst := j, snd := p.head } :: p.tail.toList, l.snd ≠ 1),
            chain_ne :=
              (_ : List.Chain' (fun l l' => l.fst ≠ l'.fst) ({ fst := j, snd := p.head } :: p.tail.toList)) }).toList ↔
    { fst := j, snd := p.head } ∈ p.tail.toList ∨ ¬p.head = 1 ∧ ∃ (h : j = j), p.head = h ▸ p.head

Next tactic:
split_ifs
theorem mem_rcons_iff {i j : ι} (p : Pair M i) (m : M j) :
    ⟨_, m⟩ ∈ (rcons p).toList ↔ ⟨_, m⟩ ∈ p.tail.toList ∨
      m ≠ 1 ∧ (∃ h : i = j, m = h ▸ p.head) := by
  simp only [rcons._eq_1, cons._eq_1, ne_eq]
  by_cases hij : i = j
  · subst i
    by_cases hm : m = p.head
    · subst m
      split_ifs <;> 

Proof state:
case pos
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
j : ι
p : Pair M j
h✝ : p.head = 1
⊢ { fst := j, snd := p.head } ∈ p.tail.toList ↔
    { fst := j, snd := p.head } ∈ p.tail.toList ∨ ¬p.head = 1 ∧ ∃ (h : j = j), p.head = h ▸ p.head

Next tactic:
simp_all
theorem mem_rcons_iff {i j : ι} (p : Pair M i) (m : M j) :
    ⟨_, m⟩ ∈ (rcons p).toList ↔ ⟨_, m⟩ ∈ p.tail.toList ∨
      m ≠ 1 ∧ (∃ h : i = j, m = h ▸ p.head) := by
  simp only [rcons._eq_1, cons._eq_1, ne_eq]
  by_cases hij : i = j
  · subst i
    by_cases hm : m = p.head
    · subst m
      split_ifs <;> 

Proof state:
case neg
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
j : ι
p : Pair M j
h✝ : ¬p.head = 1
⊢ { fst := j, snd := p.head } ∈
      { toList := { fst := j, snd := p.head } :: p.tail.toList,
          ne_one := (_ : ∀ l ∈ { fst := j, snd := p.head } :: p.tail.toList, l.snd ≠ 1),
          chain_ne :=
            (_ : List.Chain' (fun l l' => l.fst ≠ l'.fst) ({ fst := j, snd := p.head } :: p.tail.toList)) }.toList ↔
    { fst := j, snd := p.head } ∈ p.tail.toList ∨ ¬p.head = 1 ∧ ∃ (h : j = j), p.head = h ▸ p.head

Next tactic:
simp_all
theorem mem_rcons_iff {i j : ι} (p : Pair M i) (m : M j) :
    ⟨_, m⟩ ∈ (rcons p).toList ↔ ⟨_, m⟩ ∈ p.tail.toList ∨
      m ≠ 1 ∧ (∃ h : i = j, m = h ▸ p.head) := by
  simp only [rcons._eq_1, cons._eq_1, ne_eq]
  by_cases hij : i = j
  · subst i
    by_cases hm : m = p.head
    · subst m
      split_ifs <;> simp_all
    · 

Proof state:
case neg
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
j : ι
m : M j
p : Pair M j
hm : ¬m = p.head
⊢ { fst := j, snd := m } ∈
      (if h : p.head = 1 then p.tail
        else
          { toList := { fst := j, snd := p.head } :: p.tail.toList,
            ne_one := (_ : ∀ l ∈ { fst := j, snd := p.head } :: p.tail.toList, l.snd ≠ 1),
            chain_ne :=
              (_ : List.Chain' (fun l l' => l.fst ≠ l'.fst) ({ fst := j, snd := p.head } :: p.tail.toList)) }).toList ↔
    { fst := j, snd := m } ∈ p.tail.toList ∨ ¬m = 1 ∧ ∃ (h : j = j), m = h ▸ p.head

Next tactic:
split_ifs
theorem mem_rcons_iff {i j : ι} (p : Pair M i) (m : M j) :
    ⟨_, m⟩ ∈ (rcons p).toList ↔ ⟨_, m⟩ ∈ p.tail.toList ∨
      m ≠ 1 ∧ (∃ h : i = j, m = h ▸ p.head) := by
  simp only [rcons._eq_1, cons._eq_1, ne_eq]
  by_cases hij : i = j
  · subst i
    by_cases hm : m = p.head
    · subst m
      split_ifs <;> simp_all
    · split_ifs <;> 

Proof state:
case pos
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
j : ι
m : M j
p : Pair M j
hm : ¬m = p.head
h✝ : p.head = 1
⊢ { fst := j, snd := m } ∈ p.tail.toList ↔
    { fst := j, snd := m } ∈ p.tail.toList ∨ ¬m = 1 ∧ ∃ (h : j = j), m = h ▸ p.head

Next tactic:
simp_all
theorem mem_rcons_iff {i j : ι} (p : Pair M i) (m : M j) :
    ⟨_, m⟩ ∈ (rcons p).toList ↔ ⟨_, m⟩ ∈ p.tail.toList ∨
      m ≠ 1 ∧ (∃ h : i = j, m = h ▸ p.head) := by
  simp only [rcons._eq_1, cons._eq_1, ne_eq]
  by_cases hij : i = j
  · subst i
    by_cases hm : m = p.head
    · subst m
      split_ifs <;> simp_all
    · split_ifs <;> 

Proof state:
case neg
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
j : ι
m : M j
p : Pair M j
hm : ¬m = p.head
h✝ : ¬p.head = 1
⊢ { fst := j, snd := m } ∈
      { toList := { fst := j, snd := p.head } :: p.tail.toList,
          ne_one := (_ : ∀ l ∈ { fst := j, snd := p.head } :: p.tail.toList, l.snd ≠ 1),
          chain_ne :=
            (_ : List.Chain' (fun l l' => l.fst ≠ l'.fst) ({ fst := j, snd := p.head } :: p.tail.toList)) }.toList ↔
    { fst := j, snd := m } ∈ p.tail.toList ∨ ¬m = 1 ∧ ∃ (h : j = j), m = h ▸ p.head

Next tactic:
simp_all
theorem mem_rcons_iff {i j : ι} (p : Pair M i) (m : M j) :
    ⟨_, m⟩ ∈ (rcons p).toList ↔ ⟨_, m⟩ ∈ p.tail.toList ∨
      m ≠ 1 ∧ (∃ h : i = j, m = h ▸ p.head) := by
  simp only [rcons._eq_1, cons._eq_1, ne_eq]
  by_cases hij : i = j
  · subst i
    by_cases hm : m = p.head
    · subst m
      split_ifs <;> simp_all
    · split_ifs <;> simp_all
  · 

Proof state:
case neg
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
i j : ι
p : Pair M i
m : M j
hij : ¬i = j
⊢ { fst := j, snd := m } ∈
      (if h : p.head = 1 then p.tail
        else
          { toList := { fst := i, snd := p.head } :: p.tail.toList,
            ne_one := (_ : ∀ l ∈ { fst := i, snd := p.head } :: p.tail.toList, l.snd ≠ 1),
            chain_ne :=
              (_ : List.Chain' (fun l l' => l.fst ≠ l'.fst) ({ fst := i, snd := p.head } :: p.tail.toList)) }).toList ↔
    { fst := j, snd := m } ∈ p.tail.toList ∨ ¬m = 1 ∧ ∃ (h : i = j), m = h ▸ p.head

Next tactic:
split_ifs
theorem mem_rcons_iff {i j : ι} (p : Pair M i) (m : M j) :
    ⟨_, m⟩ ∈ (rcons p).toList ↔ ⟨_, m⟩ ∈ p.tail.toList ∨
      m ≠ 1 ∧ (∃ h : i = j, m = h ▸ p.head) := by
  simp only [rcons._eq_1, cons._eq_1, ne_eq]
  by_cases hij : i = j
  · subst i
    by_cases hm : m = p.head
    · subst m
      split_ifs <;> simp_all
    · split_ifs <;> simp_all
  · split_ifs <;> 

Proof state:
case pos
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
i j : ι
p : Pair M i
m : M j
hij : ¬i = j
h✝ : p.head = 1
⊢ { fst := j, snd := m } ∈ p.tail.toList ↔
    { fst := j, snd := m } ∈ p.tail.toList ∨ ¬m = 1 ∧ ∃ (h : i = j), m = h ▸ p.head

Next tactic:
simp_all [Ne.symm hij]
theorem mem_rcons_iff {i j : ι} (p : Pair M i) (m : M j) :
    ⟨_, m⟩ ∈ (rcons p).toList ↔ ⟨_, m⟩ ∈ p.tail.toList ∨
      m ≠ 1 ∧ (∃ h : i = j, m = h ▸ p.head) := by
  simp only [rcons._eq_1, cons._eq_1, ne_eq]
  by_cases hij : i = j
  · subst i
    by_cases hm : m = p.head
    · subst m
      split_ifs <;> simp_all
    · split_ifs <;> simp_all
  · split_ifs <;> 

Proof state:
case neg
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
i j : ι
p : Pair M i
m : M j
hij : ¬i = j
h✝ : ¬p.head = 1
⊢ { fst := j, snd := m } ∈
      { toList := { fst := i, snd := p.head } :: p.tail.toList,
          ne_one := (_ : ∀ l ∈ { fst := i, snd := p.head } :: p.tail.toList, l.snd ≠ 1),
          chain_ne :=
            (_ : List.Chain' (fun l l' => l.fst ≠ l'.fst) ({ fst := i, snd := p.head } :: p.tail.toList)) }.toList ↔
    { fst := j, snd := m } ∈ p.tail.toList ∨ ¬m = 1 ∧ ∃ (h : i = j), m = h ▸ p.head

Next tactic:
simp_all [Ne.symm hij]
@[simp]
theorem fstIdx_cons {i} (m : M i) (w : Word M) (hmw : w.fstIdx ≠ some i) (h1 : m ≠ 1) :
    fstIdx (cons m w hmw h1) = some i := by 

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
i : ι
m : M i
w : Word M
hmw : fstIdx w ≠ some i
h1 : m ≠ 1
⊢ fstIdx (cons m w hmw h1) = some i

Next tactic:
simp [cons, fstIdx]
@[simp]
theorem prod_cons (i) (m : M i) (w : Word M) (h1 : m ≠ 1) (h2 : w.fstIdx ≠ some i) :
    prod (cons m w h2 h1) = of m * prod w := by
  

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
i : ι
m : M i
w : Word M
h1 : m ≠ 1
h2 : fstIdx w ≠ some i
⊢ prod (cons m w h2 h1) = of m * prod w

Next tactic:
simp [cons, prod, List.map_cons, List.prod_cons]
/-- Induct on a word by adding letters one at a time without reduction,
effectively inducting on the underlying `List`. -/
@[elab_as_elim]
def consRecOn {motive : Word M → Sort*} (w : Word M) (h_empty : motive empty)
    (h_cons : ∀ (i) (m : M i) (w) h1 h2, motive w → motive (cons m w h1 h2)) :
    motive w := by
  

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
motive : Word M → Sort u_4
w : Word M
h_empty : motive empty
h_cons :
  (i : ι) → (m : M i) → (w : Word M) → (h1 : fstIdx w ≠ some i) → (h2 : m ≠ 1) → motive w → motive (cons m w h1 h2)
⊢ motive w

Next tactic:
rcases w with ⟨w, h1, h2⟩
/-- Induct on a word by adding letters one at a time without reduction,
effectively inducting on the underlying `List`. -/
@[elab_as_elim]
def consRecOn {motive : Word M → Sort*} (w : Word M) (h_empty : motive empty)
    (h_cons : ∀ (i) (m : M i) (w) h1 h2, motive w → motive (cons m w h1 h2)) :
    motive w := by
  rcases w with ⟨w, h1, h2⟩
  

Proof state:
case mk
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
motive : Word M → Sort u_4
h_empty : motive empty
h_cons :
  (i : ι) → (m : M i) → (w : Word M) → (h1 : fstIdx w ≠ some i) → (h2 : m ≠ 1) → motive w → motive (cons m w h1 h2)
w : List ((i : ι) × M i)
h1 : ∀ l ∈ w, l.snd ≠ 1
h2 : List.Chain' (fun l l' => l.fst ≠ l'.fst) w
⊢ motive { toList := w, ne_one := h1, chain_ne := h2 }

Next tactic:
induction w with
  | nil => exact h_empty
  | cons m w ih =>
    refine h_cons m.1 m.2 ⟨w, fun _ hl => h1 _ (List.mem_cons_of_mem _ hl), h2.tail⟩ ?_ ?_ (ih _ _)
    · rw [List.chain'_cons'] at h2
      simp only [fstIdx, ne_eq, Option.map_eq_some',
        Sigma.exists, exists_and_right, exists_eq_right, not_exists]
      intro m' hm'
      exact h2.1 _ hm' rfl
    · exact h1 _ (List.mem_cons_self _ _)
/-- Induct on a word by adding letters one at a time without reduction,
effectively inducting on the underlying `List`. -/
@[elab_as_elim]
def consRecOn {motive : Word M → Sort*} (w : Word M) (h_empty : motive empty)
    (h_cons : ∀ (i) (m : M i) (w) h1 h2, motive w → motive (cons m w h1 h2)) :
    motive w := by
  rcases w with ⟨w, h1, h2⟩
  induction w with
  

Proof state:
case mk.nil
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
motive : Word M → Sort u_4
h_empty : motive empty
h_cons :
  (i : ι) → (m : M i) → (w : Word M) → (h1 : fstIdx w ≠ some i) → (h2 : m ≠ 1) → motive w → motive (cons m w h1 h2)
h1 : ∀ l ∈ [], l.snd ≠ 1
h2 : List.Chain' (fun l l' => l.fst ≠ l'.fst) []
⊢ motive { toList := [], ne_one := h1, chain_ne := h2 }

Next tactic:
| nil => exact h_empty
/-- Induct on a word by adding letters one at a time without reduction,
effectively inducting on the underlying `List`. -/
@[elab_as_elim]
def consRecOn {motive : Word M → Sort*} (w : Word M) (h_empty : motive empty)
    (h_cons : ∀ (i) (m : M i) (w) h1 h2, motive w → motive (cons m w h1 h2)) :
    motive w := by
  rcases w with ⟨w, h1, h2⟩
  induction w with
  | nil => 

Proof state:
case mk.nil
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
motive : Word M → Sort u_4
h_empty : motive empty
h_cons :
  (i : ι) → (m : M i) → (w : Word M) → (h1 : fstIdx w ≠ some i) → (h2 : m ≠ 1) → motive w → motive (cons m w h1 h2)
h1 : ∀ l ∈ [], l.snd ≠ 1
h2 : List.Chain' (fun l l' => l.fst ≠ l'.fst) []
⊢ motive { toList := [], ne_one := h1, chain_ne := h2 }

Next tactic:
exact h_empty
/-- Induct on a word by adding letters one at a time without reduction,
effectively inducting on the underlying `List`. -/
@[elab_as_elim]
def consRecOn {motive : Word M → Sort*} (w : Word M) (h_empty : motive empty)
    (h_cons : ∀ (i) (m : M i) (w) h1 h2, motive w → motive (cons m w h1 h2)) :
    motive w := by
  rcases w with ⟨w, h1, h2⟩
  induction w with
  | nil => exact h_empty
  

Proof state:
case mk.cons
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
motive : Word M → Sort u_4
h_empty : motive empty
h_cons :
  (i : ι) → (m : M i) → (w : Word M) → (h1 : fstIdx w ≠ some i) → (h2 : m ≠ 1) → motive w → motive (cons m w h1 h2)
m : (i : ι) × M i
w : List ((i : ι) × M i)
ih :
  (h1 : ∀ l ∈ w, l.snd ≠ 1) →
    (h2 : List.Chain' (fun l l' => l.fst ≠ l'.fst) w) → motive { toList := w, ne_one := h1, chain_ne := h2 }
h1 : ∀ l ∈ m :: w, l.snd ≠ 1
h2 : List.Chain' (fun l l' => l.fst ≠ l'.fst) (m :: w)
⊢ motive { toList := m :: w, ne_one := h1, chain_ne := h2 }

Next tactic:
| cons m w ih =>
    refine h_cons m.1 m.2 ⟨w, fun _ hl => h1 _ (List.mem_cons_of_mem _ hl), h2.tail⟩ ?_ ?_ (ih _ _)
    · rw [List.chain'_cons'] at h2
      simp only [fstIdx, ne_eq, Option.map_eq_some',
        Sigma.exists, exists_and_right, exists_eq_right, not_exists]
      intro m' hm'
      exact h2.1 _ hm' rfl
    · exact h1 _ (List.mem_cons_self _ _)
/-- Induct on a word by adding letters one at a time without reduction,
effectively inducting on the underlying `List`. -/
@[elab_as_elim]
def consRecOn {motive : Word M → Sort*} (w : Word M) (h_empty : motive empty)
    (h_cons : ∀ (i) (m : M i) (w) h1 h2, motive w → motive (cons m w h1 h2)) :
    motive w := by
  rcases w with ⟨w, h1, h2⟩
  induction w with
  | nil => exact h_empty
  | cons m w ih =>
    

Proof state:
case mk.cons
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
motive : Word M → Sort u_4
h_empty : motive empty
h_cons :
  (i : ι) → (m : M i) → (w : Word M) → (h1 : fstIdx w ≠ some i) → (h2 : m ≠ 1) → motive w → motive (cons m w h1 h2)
m : (i : ι) × M i
w : List ((i : ι) × M i)
ih :
  (h1 : ∀ l ∈ w, l.snd ≠ 1) →
    (h2 : List.Chain' (fun l l' => l.fst ≠ l'.fst) w) → motive { toList := w, ne_one := h1, chain_ne := h2 }
h1 : ∀ l ∈ m :: w, l.snd ≠ 1
h2 : List.Chain' (fun l l' => l.fst ≠ l'.fst) (m :: w)
⊢ motive { toList := m :: w, ne_one := h1, chain_ne := h2 }

Next tactic:
refine h_cons m.1 m.2 ⟨w, fun _ hl => h1 _ (List.mem_cons_of_mem _ hl), h2.tail⟩ ?_ ?_ (ih _ _)
/-- Induct on a word by adding letters one at a time without reduction,
effectively inducting on the underlying `List`. -/
@[elab_as_elim]
def consRecOn {motive : Word M → Sort*} (w : Word M) (h_empty : motive empty)
    (h_cons : ∀ (i) (m : M i) (w) h1 h2, motive w → motive (cons m w h1 h2)) :
    motive w := by
  rcases w with ⟨w, h1, h2⟩
  induction w with
  | nil => exact h_empty
  | cons m w ih =>
    refine h_cons m.1 m.2 ⟨w, fun _ hl => h1 _ (List.mem_cons_of_mem _ hl), h2.tail⟩ ?_ ?_ (ih _ _)
    · 

Proof state:
case mk.cons.refine_1
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
motive : Word M → Sort u_4
h_empty : motive empty
h_cons :
  (i : ι) → (m : M i) → (w : Word M) → (h1 : fstIdx w ≠ some i) → (h2 : m ≠ 1) → motive w → motive (cons m w h1 h2)
m : (i : ι) × M i
w : List ((i : ι) × M i)
ih :
  (h1 : ∀ l ∈ w, l.snd ≠ 1) →
    (h2 : List.Chain' (fun l l' => l.fst ≠ l'.fst) w) → motive { toList := w, ne_one := h1, chain_ne := h2 }
h1 : ∀ l ∈ m :: w, l.snd ≠ 1
h2 : List.Chain' (fun l l' => l.fst ≠ l'.fst) (m :: w)
⊢ fstIdx
      { toList := w, ne_one := (_ : ∀ x ∈ w, x.snd ≠ 1),
        chain_ne := (_ : List.Chain' (fun l l' => l.fst ≠ l'.fst) (List.tail (m :: w))) } ≠
    some m.fst

Next tactic:
rw [List.chain'_cons'] at h2
/-- Induct on a word by adding letters one at a time without reduction,
effectively inducting on the underlying `List`. -/
@[elab_as_elim]
def consRecOn {motive : Word M → Sort*} (w : Word M) (h_empty : motive empty)
    (h_cons : ∀ (i) (m : M i) (w) h1 h2, motive w → motive (cons m w h1 h2)) :
    motive w := by
  rcases w with ⟨w, h1, h2⟩
  induction w with
  | nil => exact h_empty
  | cons m w ih =>
    refine h_cons m.1 m.2 ⟨w, fun _ hl => h1 _ (List.mem_cons_of_mem _ hl), h2.tail⟩ ?_ ?_ (ih _ _)
    · rw [List.chain'_cons'] at h2
      

Proof state:
case mk.cons.refine_1
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
motive : Word M → Sort u_4
h_empty : motive empty
h_cons :
  (i : ι) → (m : M i) → (w : Word M) → (h1 : fstIdx w ≠ some i) → (h2 : m ≠ 1) → motive w → motive (cons m w h1 h2)
m : (i : ι) × M i
w : List ((i : ι) × M i)
ih :
  (h1 : ∀ l ∈ w, l.snd ≠ 1) →
    (h2 : List.Chain' (fun l l' => l.fst ≠ l'.fst) w) → motive { toList := w, ne_one := h1, chain_ne := h2 }
h1 : ∀ l ∈ m :: w, l.snd ≠ 1
h2✝ : List.Chain' (fun l l' => l.fst ≠ l'.fst) (m :: w)
h2 : (∀ y ∈ List.head? w, m.fst ≠ y.fst) ∧ List.Chain' (fun l l' => l.fst ≠ l'.fst) w
⊢ fstIdx
      { toList := w, ne_one := (_ : ∀ x ∈ w, x.snd ≠ 1),
        chain_ne := (_ : List.Chain' (fun l l' => l.fst ≠ l'.fst) (List.tail (m :: w))) } ≠
    some m.fst

Next tactic:
simp only [fstIdx, ne_eq, Option.map_eq_some',
        Sigma.exists, exists_and_right, exists_eq_right, not_exists]
/-- Induct on a word by adding letters one at a time without reduction,
effectively inducting on the underlying `List`. -/
@[elab_as_elim]
def consRecOn {motive : Word M → Sort*} (w : Word M) (h_empty : motive empty)
    (h_cons : ∀ (i) (m : M i) (w) h1 h2, motive w → motive (cons m w h1 h2)) :
    motive w := by
  rcases w with ⟨w, h1, h2⟩
  induction w with
  | nil => exact h_empty
  | cons m w ih =>
    refine h_cons m.1 m.2 ⟨w, fun _ hl => h1 _ (List.mem_cons_of_mem _ hl), h2.tail⟩ ?_ ?_ (ih _ _)
    · rw [List.chain'_cons'] at h2
      simp only [fstIdx, ne_eq, Option.map_eq_some',
        Sigma.exists, exists_and_right, exists_eq_right, not_exists]
      

Proof state:
case mk.cons.refine_1
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
motive : Word M → Sort u_4
h_empty : motive empty
h_cons :
  (i : ι) → (m : M i) → (w : Word M) → (h1 : fstIdx w ≠ some i) → (h2 : m ≠ 1) → motive w → motive (cons m w h1 h2)
m : (i : ι) × M i
w : List ((i : ι) × M i)
ih :
  (h1 : ∀ l ∈ w, l.snd ≠ 1) →
    (h2 : List.Chain' (fun l l' => l.fst ≠ l'.fst) w) → motive { toList := w, ne_one := h1, chain_ne := h2 }
h1 : ∀ l ∈ m :: w, l.snd ≠ 1
h2✝ : List.Chain' (fun l l' => l.fst ≠ l'.fst) (m :: w)
h2 : (∀ y ∈ List.head? w, m.fst ≠ y.fst) ∧ List.Chain' (fun l l' => l.fst ≠ l'.fst) w
⊢ ∀ (x : M m.fst), ¬List.head? w = some { fst := m.fst, snd := x }

Next tactic:
intro m' hm'
/-- Induct on a word by adding letters one at a time without reduction,
effectively inducting on the underlying `List`. -/
@[elab_as_elim]
def consRecOn {motive : Word M → Sort*} (w : Word M) (h_empty : motive empty)
    (h_cons : ∀ (i) (m : M i) (w) h1 h2, motive w → motive (cons m w h1 h2)) :
    motive w := by
  rcases w with ⟨w, h1, h2⟩
  induction w with
  | nil => exact h_empty
  | cons m w ih =>
    refine h_cons m.1 m.2 ⟨w, fun _ hl => h1 _ (List.mem_cons_of_mem _ hl), h2.tail⟩ ?_ ?_ (ih _ _)
    · rw [List.chain'_cons'] at h2
      simp only [fstIdx, ne_eq, Option.map_eq_some',
        Sigma.exists, exists_and_right, exists_eq_right, not_exists]
      intro m' hm'
      

Proof state:
case mk.cons.refine_1
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
motive : Word M → Sort u_4
h_empty : motive empty
h_cons :
  (i : ι) → (m : M i) → (w : Word M) → (h1 : fstIdx w ≠ some i) → (h2 : m ≠ 1) → motive w → motive (cons m w h1 h2)
m : (i : ι) × M i
w : List ((i : ι) × M i)
ih :
  (h1 : ∀ l ∈ w, l.snd ≠ 1) →
    (h2 : List.Chain' (fun l l' => l.fst ≠ l'.fst) w) → motive { toList := w, ne_one := h1, chain_ne := h2 }
h1 : ∀ l ∈ m :: w, l.snd ≠ 1
h2✝ : List.Chain' (fun l l' => l.fst ≠ l'.fst) (m :: w)
h2 : (∀ y ∈ List.head? w, m.fst ≠ y.fst) ∧ List.Chain' (fun l l' => l.fst ≠ l'.fst) w
m' : M m.fst
hm' : List.head? w = some { fst := m.fst, snd := m' }
⊢ False

Next tactic:
exact h2.1 _ hm' rfl
/-- Induct on a word by adding letters one at a time without reduction,
effectively inducting on the underlying `List`. -/
@[elab_as_elim]
def consRecOn {motive : Word M → Sort*} (w : Word M) (h_empty : motive empty)
    (h_cons : ∀ (i) (m : M i) (w) h1 h2, motive w → motive (cons m w h1 h2)) :
    motive w := by
  rcases w with ⟨w, h1, h2⟩
  induction w with
  | nil => exact h_empty
  | cons m w ih =>
    refine h_cons m.1 m.2 ⟨w, fun _ hl => h1 _ (List.mem_cons_of_mem _ hl), h2.tail⟩ ?_ ?_ (ih _ _)
    · rw [List.chain'_cons'] at h2
      simp only [fstIdx, ne_eq, Option.map_eq_some',
        Sigma.exists, exists_and_right, exists_eq_right, not_exists]
      intro m' hm'
      exact h2.1 _ hm' rfl
    · 

Proof state:
case mk.cons.refine_2
ι : Type u_1
M : ι → Type u_2
inst✝² : (i : ι) → Monoid (M i)
N : Type u_3
inst✝¹ : Monoid N
inst✝ : (i : ι) → DecidableEq (M i)
motive : Word M → Sort u_4
h_empty : motive empty
h_cons :
  (i : ι) → (m : M i) → (w : Word M) → (h1 : fstIdx w ≠ some i) → (h2 : m ≠ 1) → motive w → motive (cons m w h1 h2)
m : (i : ι) × M i
w : List ((i : ι) × M i)
ih :
  (h1 : ∀ l ∈ w, l.snd ≠ 1) →
    (h2 : List.Chain' (fun l l' => l.fst ≠ l'.fst) w) → motive { toList := w, ne_one := h1, chain_ne := h2 }
h1 : ∀ l ∈ m :: w, l.snd ≠ 1
h2 : List.Chain' (fun l l' => l.fst ≠ l'.fst) (m :: w)
⊢ m.snd ≠ 1

Next tactic:
exact h1 _ (List.mem_cons_self _ _)
/-- Given `i : ι`, any reduced word can be decomposed into a pair `p` such that `w = rcons p`. -/
private def equivPairAux (i) (w : Word M) : { p : Pair M i // rcons p = w } :=
  consRecOn w ⟨⟨1, .empty, by 

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝³ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝² : Monoid N
inst✝¹ : (i : ι) → DecidableEq (M i)
inst✝ : DecidableEq ι
i : ι
w : Word M
⊢ fstIdx empty ≠ some i

Next tactic:
simp [fstIdx, empty]
/-- Given `i : ι`, any reduced word can be decomposed into a pair `p` such that `w = rcons p`. -/
private def equivPairAux (i) (w : Word M) : { p : Pair M i // rcons p = w } :=
  consRecOn w ⟨⟨1, .empty, by simp [fstIdx, empty]⟩, by 

Proof state:
ι : Type u_1
M : ι → Type u_2
inst✝³ : (i : ι) → Monoid (M i)
N : Type u_3
inst✝² : Monoid N
inst✝¹ : (i : ι) → DecidableEq (M i)
inst✝ : DecidableEq ι
i : ι
w : Word M
⊢ rcons { head := 1, tail := empty, fstIdx_ne := (_ : ¬none = some i) } = empty

Next tactic:
simp [rcons]