l3lab/ntp-mathlib huggingface dataset:
theorem perm_comp_forall₂ {l u v} (hlu : Perm l u) (huv : Forall₂ r u v) :
    (Forall₂ r ∘r Perm) l v := by
  induction hlu generalizing v
  case nil => cases huv; exact ⟨[], Forall₂.nil, Perm.nil⟩
  case cons a l u _hlu ih =>
    cases' huv with _ b _ v hab huv'
    rcases ih huv' with ⟨l₂, h₁₂, h₂₃⟩
    exact ⟨b :: l₂, Forall₂.cons hab h₁₂, h₂₃.cons _⟩
  case swap a₁ a₂ h₂₃ =>
    cases' huv with _ b₁ _ l₂ h₁ hr₂₃
    cases' hr₂₃ with _ b₂ _ l₂ h₂ h₁₂
    exact ⟨b₂ :: b₁ :: l₂, Forall₂.cons h₂ (Forall₂.cons h₁ h₁₂), Perm.swap _ _ _⟩
  case
    trans la₁ la₂ la₃ _ _ ih₁ ih₂ =>
    

Proof state:
α : Type u_1
β : Type u_2
l✝ l₁ l₂ : List α
a : α
γ : Type u_3
δ : Type u_4
r : α → β → Prop
p : γ → δ → Prop
l u la₁ la₂ la₃ : List α
a✝¹ : la₁ ~ la₂
a✝ : la₂ ~ la₃
ih₁ : ∀ {v : List β}, Forall₂ r la₂ v → (Forall₂ r ∘r Perm) la₁ v
ih₂ : ∀ {v : List β}, Forall₂ r la₃ v → (Forall₂ r ∘r Perm) la₂ v
v : List β
huv : Forall₂ r la₃ v
⊢ (Forall₂ r ∘r Perm) la₁ v

Next tactic:
rcases ih₂ huv with ⟨lb₂, hab₂, h₂₃⟩
theorem perm_comp_forall₂ {l u v} (hlu : Perm l u) (huv : Forall₂ r u v) :
    (Forall₂ r ∘r Perm) l v := by
  induction hlu generalizing v
  case nil => cases huv; exact ⟨[], Forall₂.nil, Perm.nil⟩
  case cons a l u _hlu ih =>
    cases' huv with _ b _ v hab huv'
    rcases ih huv' with ⟨l₂, h₁₂, h₂₃⟩
    exact ⟨b :: l₂, Forall₂.cons hab h₁₂, h₂₃.cons _⟩
  case swap a₁ a₂ h₂₃ =>
    cases' huv with _ b₁ _ l₂ h₁ hr₂₃
    cases' hr₂₃ with _ b₂ _ l₂ h₂ h₁₂
    exact ⟨b₂ :: b₁ :: l₂, Forall₂.cons h₂ (Forall₂.cons h₁ h₁₂), Perm.swap _ _ _⟩
  case
    trans la₁ la₂ la₃ _ _ ih₁ ih₂ =>
    rcases ih₂ huv with ⟨lb₂, hab₂, h₂₃⟩
    

Proof state:
case intro.intro
α : Type u_1
β : Type u_2
l✝ l₁ l₂ : List α
a : α
γ : Type u_3
δ : Type u_4
r : α → β → Prop
p : γ → δ → Prop
l u la₁ la₂ la₃ : List α
a✝¹ : la₁ ~ la₂
a✝ : la₂ ~ la₃
ih₁ : ∀ {v : List β}, Forall₂ r la₂ v → (Forall₂ r ∘r Perm) la₁ v
ih₂ : ∀ {v : List β}, Forall₂ r la₃ v → (Forall₂ r ∘r Perm) la₂ v
v : List β
huv : Forall₂ r la₃ v
lb₂ : List β
hab₂ : Forall₂ r la₂ lb₂
h₂₃ : lb₂ ~ v
⊢ (Forall₂ r ∘r Perm) la₁ v

Next tactic:
rcases ih₁ hab₂ with ⟨lb₁, hab₁, h₁₂⟩
theorem perm_comp_forall₂ {l u v} (hlu : Perm l u) (huv : Forall₂ r u v) :
    (Forall₂ r ∘r Perm) l v := by
  induction hlu generalizing v
  case nil => cases huv; exact ⟨[], Forall₂.nil, Perm.nil⟩
  case cons a l u _hlu ih =>
    cases' huv with _ b _ v hab huv'
    rcases ih huv' with ⟨l₂, h₁₂, h₂₃⟩
    exact ⟨b :: l₂, Forall₂.cons hab h₁₂, h₂₃.cons _⟩
  case swap a₁ a₂ h₂₃ =>
    cases' huv with _ b₁ _ l₂ h₁ hr₂₃
    cases' hr₂₃ with _ b₂ _ l₂ h₂ h₁₂
    exact ⟨b₂ :: b₁ :: l₂, Forall₂.cons h₂ (Forall₂.cons h₁ h₁₂), Perm.swap _ _ _⟩
  case
    trans la₁ la₂ la₃ _ _ ih₁ ih₂ =>
    rcases ih₂ huv with ⟨lb₂, hab₂, h₂₃⟩
    rcases ih₁ hab₂ with ⟨lb₁, hab₁, h₁₂⟩
    

Proof state:
case intro.intro.intro.intro
α : Type u_1
β : Type u_2
l✝ l₁ l₂ : List α
a : α
γ : Type u_3
δ : Type u_4
r : α → β → Prop
p : γ → δ → Prop
l u la₁ la₂ la₃ : List α
a✝¹ : la₁ ~ la₂
a✝ : la₂ ~ la₃
ih₁ : ∀ {v : List β}, Forall₂ r la₂ v → (Forall₂ r ∘r Perm) la₁ v
ih₂ : ∀ {v : List β}, Forall₂ r la₃ v → (Forall₂ r ∘r Perm) la₂ v
v : List β
huv : Forall₂ r la₃ v
lb₂ : List β
hab₂ : Forall₂ r la₂ lb₂
h₂₃ : lb₂ ~ v
lb₁ : List β
hab₁ : Forall₂ r la₁ lb₁
h₁₂ : lb₁ ~ lb₂
⊢ (Forall₂ r ∘r Perm) la₁ v

Next tactic:
exact ⟨lb₁, hab₁, Perm.trans h₁₂ h₂₃⟩
theorem forall₂_comp_perm_eq_perm_comp_forall₂ : Forall₂ r ∘r Perm = Perm ∘r Forall₂ r := by
  

Proof state:
α : Type u_1
β : Type u_2
l l₁ l₂ : List α
a : α
γ : Type u_3
δ : Type u_4
r : α → β → Prop
p : γ → δ → Prop
⊢ Forall₂ r ∘r Perm = Perm ∘r Forall₂ r

Next tactic:
funext l₁ l₃
theorem forall₂_comp_perm_eq_perm_comp_forall₂ : Forall₂ r ∘r Perm = Perm ∘r Forall₂ r := by
  funext l₁ l₃; 

Proof state:
case h.h
α : Type u_1
β : Type u_2
l l₁✝ l₂ : List α
a : α
γ : Type u_3
δ : Type u_4
r : α → β → Prop
p : γ → δ → Prop
l₁ : List α
l₃ : List β
⊢ (Forall₂ r ∘r Perm) l₁ l₃ = (Perm ∘r Forall₂ r) l₁ l₃

Next tactic:
apply propext
theorem forall₂_comp_perm_eq_perm_comp_forall₂ : Forall₂ r ∘r Perm = Perm ∘r Forall₂ r := by
  funext l₁ l₃; apply propext
  

Proof state:
case h.h.a
α : Type u_1
β : Type u_2
l l₁✝ l₂ : List α
a : α
γ : Type u_3
δ : Type u_4
r : α → β → Prop
p : γ → δ → Prop
l₁ : List α
l₃ : List β
⊢ (Forall₂ r ∘r Perm) l₁ l₃ ↔ (Perm ∘r Forall₂ r) l₁ l₃

Next tactic:
constructor
theorem forall₂_comp_perm_eq_perm_comp_forall₂ : Forall₂ r ∘r Perm = Perm ∘r Forall₂ r := by
  funext l₁ l₃; apply propext
  constructor
  · 

Proof state:
case h.h.a.mp
α : Type u_1
β : Type u_2
l l₁✝ l₂ : List α
a : α
γ : Type u_3
δ : Type u_4
r : α → β → Prop
p : γ → δ → Prop
l₁ : List α
l₃ : List β
⊢ (Forall₂ r ∘r Perm) l₁ l₃ → (Perm ∘r Forall₂ r) l₁ l₃

Next tactic:
intro h
theorem forall₂_comp_perm_eq_perm_comp_forall₂ : Forall₂ r ∘r Perm = Perm ∘r Forall₂ r := by
  funext l₁ l₃; apply propext
  constructor
  · intro h
    

Proof state:
case h.h.a.mp
α : Type u_1
β : Type u_2
l l₁✝ l₂ : List α
a : α
γ : Type u_3
δ : Type u_4
r : α → β → Prop
p : γ → δ → Prop
l₁ : List α
l₃ : List β
h : (Forall₂ r ∘r Perm) l₁ l₃
⊢ (Perm ∘r Forall₂ r) l₁ l₃

Next tactic:
rcases h with ⟨l₂, h₁₂, h₂₃⟩
theorem forall₂_comp_perm_eq_perm_comp_forall₂ : Forall₂ r ∘r Perm = Perm ∘r Forall₂ r := by
  funext l₁ l₃; apply propext
  constructor
  · intro h
    rcases h with ⟨l₂, h₁₂, h₂₃⟩
    

Proof state:
case h.h.a.mp.intro.intro
α : Type u_1
β : Type u_2
l l₁✝ l₂✝ : List α
a : α
γ : Type u_3
δ : Type u_4
r : α → β → Prop
p : γ → δ → Prop
l₁ : List α
l₃ l₂ : List β
h₁₂ : Forall₂ r l₁ l₂
h₂₃ : l₂ ~ l₃
⊢ (Perm ∘r Forall₂ r) l₁ l₃

Next tactic:
have : Forall₂ (flip r) l₂ l₁ := h₁₂.flip
theorem forall₂_comp_perm_eq_perm_comp_forall₂ : Forall₂ r ∘r Perm = Perm ∘r Forall₂ r := by
  funext l₁ l₃; apply propext
  constructor
  · intro h
    rcases h with ⟨l₂, h₁₂, h₂₃⟩
    have : Forall₂ (flip r) l₂ l₁ := h₁₂.flip
    

Proof state:
case h.h.a.mp.intro.intro
α : Type u_1
β : Type u_2
l l₁✝ l₂✝ : List α
a : α
γ : Type u_3
δ : Type u_4
r : α → β → Prop
p : γ → δ → Prop
l₁ : List α
l₃ l₂ : List β
h₁₂ : Forall₂ r l₁ l₂
h₂₃ : l₂ ~ l₃
this : Forall₂ (flip r) l₂ l₁
⊢ (Perm ∘r Forall₂ r) l₁ l₃

Next tactic:
rcases perm_comp_forall₂ h₂₃.symm this with ⟨l', h₁, h₂⟩
theorem forall₂_comp_perm_eq_perm_comp_forall₂ : Forall₂ r ∘r Perm = Perm ∘r Forall₂ r := by
  funext l₁ l₃; apply propext
  constructor
  · intro h
    rcases h with ⟨l₂, h₁₂, h₂₃⟩
    have : Forall₂ (flip r) l₂ l₁ := h₁₂.flip
    rcases perm_comp_forall₂ h₂₃.symm this with ⟨l', h₁, h₂⟩
    

Proof state:
case h.h.a.mp.intro.intro.intro.intro
α : Type u_1
β : Type u_2
l l₁✝ l₂✝ : List α
a : α
γ : Type u_3
δ : Type u_4
r : α → β → Prop
p : γ → δ → Prop
l₁ : List α
l₃ l₂ : List β
h₁₂ : Forall₂ r l₁ l₂
h₂₃ : l₂ ~ l₃
this : Forall₂ (flip r) l₂ l₁
l' : List α
h₁ : Forall₂ (flip r) l₃ l'
h₂ : l' ~ l₁
⊢ (Perm ∘r Forall₂ r) l₁ l₃

Next tactic:
exact ⟨l', h₂.symm, h₁.flip⟩
theorem forall₂_comp_perm_eq_perm_comp_forall₂ : Forall₂ r ∘r Perm = Perm ∘r Forall₂ r := by
  funext l₁ l₃; apply propext
  constructor
  · intro h
    rcases h with ⟨l₂, h₁₂, h₂₃⟩
    have : Forall₂ (flip r) l₂ l₁ := h₁₂.flip
    rcases perm_comp_forall₂ h₂₃.symm this with ⟨l', h₁, h₂⟩
    exact ⟨l', h₂.symm, h₁.flip⟩
  · 

Proof state:
case h.h.a.mpr
α : Type u_1
β : Type u_2
l l₁✝ l₂ : List α
a : α
γ : Type u_3
δ : Type u_4
r : α → β → Prop
p : γ → δ → Prop
l₁ : List α
l₃ : List β
⊢ (Perm ∘r Forall₂ r) l₁ l₃ → (Forall₂ r ∘r Perm) l₁ l₃

Next tactic:
exact fun ⟨l₂, h₁₂, h₂₃⟩ => perm_comp_forall₂ h₁₂ h₂₃
theorem rel_perm_imp (hr : RightUnique r) : (Forall₂ r ⇒ Forall₂ r ⇒ (· → ·)) Perm Perm :=
  fun a b h₁ c d h₂ h =>
  have : (flip (Forall₂ r) ∘r Perm ∘r Forall₂ r) b d := ⟨a, h₁, c, h, h₂⟩
  have : ((flip (Forall₂ r) ∘r Forall₂ r) ∘r Perm) b d := by
    

Proof state:
α : Type u_1
β : Type u_2
l l₁ l₂ : List α
a✝ : α
γ : Type u_3
δ : Type u_4
r : α → β → Prop
p : γ → δ → Prop
hr : RightUnique r
a : List α
b : List β
h₁ : Forall₂ r a b
c : List α
d : List β
h₂ : Forall₂ r c d
h : a ~ c
this : (flip (Forall₂ r) ∘r Perm ∘r Forall₂ r) b d
⊢ ((flip (Forall₂ r) ∘r Forall₂ r) ∘r Perm) b d

Next tactic:
rwa [← forall₂_comp_perm_eq_perm_comp_forall₂, ← Relation.comp_assoc] at this
lemma subperm_iff : l₁ <+~ l₂ ↔ ∃ l, l ~ l₂ ∧ l₁ <+ l := by
  

Proof state:
α : Type u_1
β : Type u_2
l l₁ l₂ : List α
a : α
⊢ l₁ <+~ l₂ ↔ ∃ l, l ~ l₂ ∧ l₁ <+ l

Next tactic:
refine ⟨?_, fun ⟨l, h₁, h₂⟩ ↦ h₂.subperm.trans h₁.subperm⟩
lemma subperm_iff : l₁ <+~ l₂ ↔ ∃ l, l ~ l₂ ∧ l₁ <+ l := by
  refine ⟨?_, fun ⟨l, h₁, h₂⟩ ↦ h₂.subperm.trans h₁.subperm⟩
  

Proof state:
α : Type u_1
β : Type u_2
l l₁ l₂ : List α
a : α
⊢ l₁ <+~ l₂ → ∃ l, l ~ l₂ ∧ l₁ <+ l

Next tactic:
rintro ⟨l, h₁, h₂⟩
lemma subperm_iff : l₁ <+~ l₂ ↔ ∃ l, l ~ l₂ ∧ l₁ <+ l := by
  refine ⟨?_, fun ⟨l, h₁, h₂⟩ ↦ h₂.subperm.trans h₁.subperm⟩
  rintro ⟨l, h₁, h₂⟩
  

Proof state:
case intro.intro
α : Type u_1
β : Type u_2
l✝ l₁ l₂ : List α
a : α
l : List α
h₁ : l ~ l₁
h₂ : l <+ l₂
⊢ ∃ l, l ~ l₂ ∧ l₁ <+ l

Next tactic:
obtain ⟨l', h₂⟩ := h₂.exists_perm_append
lemma subperm_iff : l₁ <+~ l₂ ↔ ∃ l, l ~ l₂ ∧ l₁ <+ l := by
  refine ⟨?_, fun ⟨l, h₁, h₂⟩ ↦ h₂.subperm.trans h₁.subperm⟩
  rintro ⟨l, h₁, h₂⟩
  obtain ⟨l', h₂⟩ := h₂.exists_perm_append
  

Proof state:
case intro.intro.intro
α : Type u_1
β : Type u_2
l✝ l₁ l₂ : List α
a : α
l : List α
h₁ : l ~ l₁
h₂✝ : l <+ l₂
l' : List α
h₂ : l₂ ~ l ++ l'
⊢ ∃ l, l ~ l₂ ∧ l₁ <+ l

Next tactic:
exact ⟨l₁ ++ l', (h₂.trans (h₁.append_right _)).symm, (prefix_append _ _).sublist⟩
@[simp] lemma subperm_singleton_iff : l <+~ [a] ↔ l = [] ∨ l = [a] := by
  

Proof state:
α : Type u_1
β : Type u_2
l l₁ l₂ : List α
a : α
⊢ l <+~ [a] ↔ l = [] ∨ l = [a]

Next tactic:
constructor
@[simp] lemma subperm_singleton_iff : l <+~ [a] ↔ l = [] ∨ l = [a] := by
  constructor
  · 

Proof state:
case mp
α : Type u_1
β : Type u_2
l l₁ l₂ : List α
a : α
⊢ l <+~ [a] → l = [] ∨ l = [a]

Next tactic:
rw [subperm_iff]
@[simp] lemma subperm_singleton_iff : l <+~ [a] ↔ l = [] ∨ l = [a] := by
  constructor
  · rw [subperm_iff]
    

Proof state:
case mp
α : Type u_1
β : Type u_2
l l₁ l₂ : List α
a : α
⊢ (∃ l_1, l_1 ~ [a] ∧ l <+ l_1) → l = [] ∨ l = [a]

Next tactic:
rintro ⟨s, hla, h⟩
@[simp] lemma subperm_singleton_iff : l <+~ [a] ↔ l = [] ∨ l = [a] := by
  constructor
  · rw [subperm_iff]
    rintro ⟨s, hla, h⟩
    

Proof state:
case mp.intro.intro
α : Type u_1
β : Type u_2
l l₁ l₂ : List α
a : α
s : List α
hla : s ~ [a]
h : l <+ s
⊢ l = [] ∨ l = [a]

Next tactic:
rwa [perm_singleton.mp hla, sublist_singleton] at h
@[simp] lemma subperm_singleton_iff : l <+~ [a] ↔ l = [] ∨ l = [a] := by
  constructor
  · rw [subperm_iff]
    rintro ⟨s, hla, h⟩
    rwa [perm_singleton.mp hla, sublist_singleton] at h
  · 

Proof state:
case mpr
α : Type u_1
β : Type u_2
l l₁ l₂ : List α
a : α
⊢ l = [] ∨ l = [a] → l <+~ [a]

Next tactic:
rintro (rfl | rfl)
@[simp] lemma subperm_singleton_iff : l <+~ [a] ↔ l = [] ∨ l = [a] := by
  constructor
  · rw [subperm_iff]
    rintro ⟨s, hla, h⟩
    rwa [perm_singleton.mp hla, sublist_singleton] at h
  · rintro (rfl | rfl)
    

Proof state:
case mpr.inl
α : Type u_1
β : Type u_2
l₁ l₂ : List α
a : α
⊢ [] <+~ [a]
case mpr.inr α : Type u_1 β : Type u_2 l₁ l₂ : List α a : α ⊢ [a] <+~ [a]

Next tactic:
exacts [nil_subperm, Subperm.refl _]
lemma count_eq_count_filter_add [DecidableEq α] (P : α → Prop) [DecidablePred P]
    (l : List α) (a : α) :
    count a l = count a (l.filter P) + count a (l.filter (¬ P ·)) := by
  

Proof state:
α : Type u_1
β : Type u_2
l✝ l₁ l₂ : List α
a✝ : α
inst✝¹ : DecidableEq α
P : α → Prop
inst✝ : DecidablePred P
l : List α
a : α
⊢ count a l = count a (filter (fun b => decide (P b)) l) + count a (filter (fun x => decide ¬P x) l)

Next tactic:
convert countP_eq_countP_filter_add l _ P
lemma count_eq_count_filter_add [DecidableEq α] (P : α → Prop) [DecidablePred P]
    (l : List α) (a : α) :
    count a l = count a (l.filter P) + count a (l.filter (¬ P ·)) := by
  convert countP_eq_countP_filter_add l _ P
  

Proof state:
case h.e'_3.h.e'_6.h.e'_1.h.e'_2.h
α : Type u_1
β : Type u_2
l✝ l₁ l₂ : List α
a✝ : α
inst✝¹ : DecidableEq α
P : α → Prop
inst✝ : DecidablePred P
l : List α
a x✝ : α
⊢ (decide ¬P x✝) = !decide (P x✝)

Next tactic:
simp only [decide_not]
theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
    ∀ b, foldr f b l₁ = foldr f b l₂ := by
  

Proof state:
α : Type u_1
β : Type u_2
l l₁✝ l₂✝ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
p : l₁ ~ l₂
⊢ ∀ (b : β), foldr f b l₁ = foldr f b l₂

Next tactic:
intro b
theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
    ∀ b, foldr f b l₁ = foldr f b l₂ := by
  intro b
  

Proof state:
α : Type u_1
β : Type u_2
l l₁✝ l₂✝ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
p : l₁ ~ l₂
b : β
⊢ foldr f b l₁ = foldr f b l₂

Next tactic:
induction p using Perm.recOnSwap' generalizing b
theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
    ∀ b, foldr f b l₁ = foldr f b l₂ := by
  intro b
  induction p using Perm.recOnSwap' generalizing b
  

Proof state:
case nil
α : Type u_1
β : Type u_2
l l₁✝ l₂✝ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
b : β
⊢ foldr f b [] = foldr f b []
case cons
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
x✝ : α
l₁✝ l₂✝ : List α
h✝ : l₁✝ ~ l₂✝
a✝ : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
b : β
⊢ foldr f b (x✝ :: l₁✝) = foldr f b (x✝ :: l₂✝)
case swap'
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
x✝ y✝ : α
l₁✝ l₂✝ : List α
h✝ : l₁✝ ~ l₂✝
a✝ : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
b : β
⊢ foldr f b (y✝ :: x✝ :: l₁✝) = foldr f b (x✝ :: y✝ :: l₂✝)
case trans
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
l₁✝ l₂✝ l₃✝ : List α
h₁✝ : l₁✝ ~ l₂✝
h₂✝ : l₂✝ ~ l₃✝
a✝¹ : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
a✝ : ∀ (b : β), foldr f b l₂✝ = foldr f b l₃✝
b : β
⊢ foldr f b l₁✝ = foldr f b l₃✝

Next tactic:
case nil => rfl
theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
    ∀ b, foldr f b l₁ = foldr f b l₂ := by
  intro b
  induction p using Perm.recOnSwap' generalizing b
  

Proof state:
α : Type u_1
β : Type u_2
l l₁✝ l₂✝ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
b : β
⊢ foldr f b [] = foldr f b []

Next tactic:
case nil => rfl
theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
    ∀ b, foldr f b l₁ = foldr f b l₂ := by
  intro b
  induction p using Perm.recOnSwap' generalizing b
  case nil => 

Proof state:
α : Type u_1
β : Type u_2
l l₁✝ l₂✝ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
b : β
⊢ foldr f b [] = foldr f b []

Next tactic:
rfl
theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
    ∀ b, foldr f b l₁ = foldr f b l₂ := by
  intro b
  induction p using Perm.recOnSwap' generalizing b
  case nil => rfl
  

Proof state:
case cons
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
x✝ : α
l₁✝ l₂✝ : List α
h✝ : l₁✝ ~ l₂✝
a✝ : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
b : β
⊢ foldr f b (x✝ :: l₁✝) = foldr f b (x✝ :: l₂✝)
case swap'
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
x✝ y✝ : α
l₁✝ l₂✝ : List α
h✝ : l₁✝ ~ l₂✝
a✝ : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
b : β
⊢ foldr f b (y✝ :: x✝ :: l₁✝) = foldr f b (x✝ :: y✝ :: l₂✝)
case trans
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
l₁✝ l₂✝ l₃✝ : List α
h₁✝ : l₁✝ ~ l₂✝
h₂✝ : l₂✝ ~ l₃✝
a✝¹ : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
a✝ : ∀ (b : β), foldr f b l₂✝ = foldr f b l₃✝
b : β
⊢ foldr f b l₁✝ = foldr f b l₃✝

Next tactic:
case cons r  => simp; rw [r b]
theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
    ∀ b, foldr f b l₁ = foldr f b l₂ := by
  intro b
  induction p using Perm.recOnSwap' generalizing b
  case nil => rfl
  

Proof state:
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
x✝ : α
l₁✝ l₂✝ : List α
h✝ : l₁✝ ~ l₂✝
r : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
b : β
⊢ foldr f b (x✝ :: l₁✝) = foldr f b (x✝ :: l₂✝)

Next tactic:
case cons r  => simp; rw [r b]
theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
    ∀ b, foldr f b l₁ = foldr f b l₂ := by
  intro b
  induction p using Perm.recOnSwap' generalizing b
  case nil => rfl
  case cons r  => 

Proof state:
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
x✝ : α
l₁✝ l₂✝ : List α
h✝ : l₁✝ ~ l₂✝
r : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
b : β
⊢ foldr f b (x✝ :: l₁✝) = foldr f b (x✝ :: l₂✝)

Next tactic:
simp
theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
    ∀ b, foldr f b l₁ = foldr f b l₂ := by
  intro b
  induction p using Perm.recOnSwap' generalizing b
  case nil => rfl
  case cons r  => simp; 

Proof state:
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
x✝ : α
l₁✝ l₂✝ : List α
h✝ : l₁✝ ~ l₂✝
r : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
b : β
⊢ f x✝ (foldr f b l₁✝) = f x✝ (foldr f b l₂✝)

Next tactic:
rw [r b]
theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
    ∀ b, foldr f b l₁ = foldr f b l₂ := by
  intro b
  induction p using Perm.recOnSwap' generalizing b
  case nil => rfl
  case cons r  => simp; rw [r b]
  

Proof state:
case swap'
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
x✝ y✝ : α
l₁✝ l₂✝ : List α
h✝ : l₁✝ ~ l₂✝
a✝ : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
b : β
⊢ foldr f b (y✝ :: x✝ :: l₁✝) = foldr f b (x✝ :: y✝ :: l₂✝)
case trans
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
l₁✝ l₂✝ l₃✝ : List α
h₁✝ : l₁✝ ~ l₂✝
h₂✝ : l₂✝ ~ l₃✝
a✝¹ : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
a✝ : ∀ (b : β), foldr f b l₂✝ = foldr f b l₃✝
b : β
⊢ foldr f b l₁✝ = foldr f b l₃✝

Next tactic:
case swap' r => simp; rw [lcomm, r b]
theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
    ∀ b, foldr f b l₁ = foldr f b l₂ := by
  intro b
  induction p using Perm.recOnSwap' generalizing b
  case nil => rfl
  case cons r  => simp; rw [r b]
  

Proof state:
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
x✝ y✝ : α
l₁✝ l₂✝ : List α
h✝ : l₁✝ ~ l₂✝
r : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
b : β
⊢ foldr f b (y✝ :: x✝ :: l₁✝) = foldr f b (x✝ :: y✝ :: l₂✝)

Next tactic:
case swap' r => simp; rw [lcomm, r b]
theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
    ∀ b, foldr f b l₁ = foldr f b l₂ := by
  intro b
  induction p using Perm.recOnSwap' generalizing b
  case nil => rfl
  case cons r  => simp; rw [r b]
  case swap' r => 

Proof state:
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
x✝ y✝ : α
l₁✝ l₂✝ : List α
h✝ : l₁✝ ~ l₂✝
r : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
b : β
⊢ foldr f b (y✝ :: x✝ :: l₁✝) = foldr f b (x✝ :: y✝ :: l₂✝)

Next tactic:
simp
theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
    ∀ b, foldr f b l₁ = foldr f b l₂ := by
  intro b
  induction p using Perm.recOnSwap' generalizing b
  case nil => rfl
  case cons r  => simp; rw [r b]
  case swap' r => simp; 

Proof state:
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
x✝ y✝ : α
l₁✝ l₂✝ : List α
h✝ : l₁✝ ~ l₂✝
r : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
b : β
⊢ f y✝ (f x✝ (foldr f b l₁✝)) = f x✝ (f y✝ (foldr f b l₂✝))

Next tactic:
rw [lcomm, r b]
theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
    ∀ b, foldr f b l₁ = foldr f b l₂ := by
  intro b
  induction p using Perm.recOnSwap' generalizing b
  case nil => rfl
  case cons r  => simp; rw [r b]
  case swap' r => simp; rw [lcomm, r b]
  

Proof state:
case trans
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
l₁✝ l₂✝ l₃✝ : List α
h₁✝ : l₁✝ ~ l₂✝
h₂✝ : l₂✝ ~ l₃✝
a✝¹ : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
a✝ : ∀ (b : β), foldr f b l₂✝ = foldr f b l₃✝
b : β
⊢ foldr f b l₁✝ = foldr f b l₃✝

Next tactic:
case trans r₁ r₂ => exact Eq.trans (r₁ b) (r₂ b)
theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
    ∀ b, foldr f b l₁ = foldr f b l₂ := by
  intro b
  induction p using Perm.recOnSwap' generalizing b
  case nil => rfl
  case cons r  => simp; rw [r b]
  case swap' r => simp; rw [lcomm, r b]
  

Proof state:
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
l₁✝ l₂✝ l₃✝ : List α
h₁✝ : l₁✝ ~ l₂✝
h₂✝ : l₂✝ ~ l₃✝
r₁ : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
r₂ : ∀ (b : β), foldr f b l₂✝ = foldr f b l₃✝
b : β
⊢ foldr f b l₁✝ = foldr f b l₃✝

Next tactic:
case trans r₁ r₂ => exact Eq.trans (r₁ b) (r₂ b)
theorem Perm.foldr_eq {f : α → β → β} {l₁ l₂ : List α} (lcomm : LeftCommutative f) (p : l₁ ~ l₂) :
    ∀ b, foldr f b l₁ = foldr f b l₂ := by
  intro b
  induction p using Perm.recOnSwap' generalizing b
  case nil => rfl
  case cons r  => simp; rw [r b]
  case swap' r => simp; rw [lcomm, r b]
  case trans r₁ r₂ => 

Proof state:
α : Type u_1
β : Type u_2
l l₁✝¹ l₂✝¹ : List α
a : α
f : α → β → β
l₁ l₂ : List α
lcomm : LeftCommutative f
l₁✝ l₂✝ l₃✝ : List α
h₁✝ : l₁✝ ~ l₂✝
h₂✝ : l₂✝ ~ l₃✝
r₁ : ∀ (b : β), foldr f b l₁✝ = foldr f b l₂✝
r₂ : ∀ (b : β), foldr f b l₂✝ = foldr f b l₃✝
b : β
⊢ foldr f b l₁✝ = foldr f b l₃✝

Next tactic:
exact Eq.trans (r₁ b) (r₂ b)
/-- If elements of a list commute with each other, then their product does not
depend on the order of elements. -/
@[to_additive
      "If elements of a list additively commute with each other, then their sum does not
      depend on the order of elements."]
theorem Perm.prod_eq' [M : Monoid α] {l₁ l₂ : List α} (h : l₁ ~ l₂) (hc : l₁.Pairwise Commute) :
    l₁.prod = l₂.prod := by
  

Proof state:
α : Type u_1
β : Type u_2
l l₁✝ l₂✝ : List α
a : α
M : Monoid α
l₁ l₂ : List α
h : l₁ ~ l₂
hc : Pairwise Commute l₁
⊢ prod l₁ = prod l₂

Next tactic:
refine h.foldl_eq' ?_ _
/-- If elements of a list commute with each other, then their product does not
depend on the order of elements. -/
@[to_additive
      "If elements of a list additively commute with each other, then their sum does not
      depend on the order of elements."]
theorem Perm.prod_eq' [M : Monoid α] {l₁ l₂ : List α} (h : l₁ ~ l₂) (hc : l₁.Pairwise Commute) :
    l₁.prod = l₂.prod := by
  refine h.foldl_eq' ?_ _
  

Proof state:
α : Type u_1
β : Type u_2
l l₁✝ l₂✝ : List α
a : α
M : Monoid α
l₁ l₂ : List α
h : l₁ ~ l₂
hc : Pairwise Commute l₁
⊢ ∀ x ∈ l₁, ∀ y ∈ l₁, ∀ (z : α), z * x * y = z * y * x

Next tactic:
apply Pairwise.forall_of_forall
/-- If elements of a list commute with each other, then their product does not
depend on the order of elements. -/
@[to_additive
      "If elements of a list additively commute with each other, then their sum does not
      depend on the order of elements."]
theorem Perm.prod_eq' [M : Monoid α] {l₁ l₂ : List α} (h : l₁ ~ l₂) (hc : l₁.Pairwise Commute) :
    l₁.prod = l₂.prod := by
  refine h.foldl_eq' ?_ _
  apply Pairwise.forall_of_forall
  · 

Proof state:
case H
α : Type u_1
β : Type u_2
l l₁✝ l₂✝ : List α
a : α
M : Monoid α
l₁ l₂ : List α
h : l₁ ~ l₂
hc : Pairwise Commute l₁
⊢ Symmetric fun x y => ∀ (z : α), z * x * y = z * y * x

Next tactic:
intro x y h z