l3lab/ntp-mathlib huggingface dataset:
instance : PartialOrder (Multiset α) where
  le := Multiset.Le
  le_refl := by rintro ⟨l⟩; exact Subperm.refl _
  le_trans := by rintro ⟨l₁⟩ ⟨l₂⟩ ⟨l₃⟩; 

Proof state:
case mk.mk.mk
α : Type u_1
β : Type v
γ : Type u_2
a✝ : Multiset α
l₁ : List α
b✝ : Multiset α
l₂ : List α
c✝ : Multiset α
l₃ : List α
⊢ Quot.mk Setoid.r l₁ ≤ Quot.mk Setoid.r l₂ →
    Quot.mk Setoid.r l₂ ≤ Quot.mk Setoid.r l₃ → Quot.mk Setoid.r l₁ ≤ Quot.mk Setoid.r l₃

Next tactic:
exact @Subperm.trans _ _ _ _
instance : PartialOrder (Multiset α) where
  le := Multiset.Le
  le_refl := by rintro ⟨l⟩; exact Subperm.refl _
  le_trans := by rintro ⟨l₁⟩ ⟨l₂⟩ ⟨l₃⟩; exact @Subperm.trans _ _ _ _
  le_antisymm := by 

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
⊢ ∀ (a b : Multiset α), a ≤ b → b ≤ a → a = b

Next tactic:
rintro ⟨l₁⟩ ⟨l₂⟩ h₁ h₂
instance : PartialOrder (Multiset α) where
  le := Multiset.Le
  le_refl := by rintro ⟨l⟩; exact Subperm.refl _
  le_trans := by rintro ⟨l₁⟩ ⟨l₂⟩ ⟨l₃⟩; exact @Subperm.trans _ _ _ _
  le_antisymm := by rintro ⟨l₁⟩ ⟨l₂⟩ h₁ h₂; 

Proof state:
case mk.mk
α : Type u_1
β : Type v
γ : Type u_2
a✝ : Multiset α
l₁ : List α
b✝ : Multiset α
l₂ : List α
h₁ : Quot.mk Setoid.r l₁ ≤ Quot.mk Setoid.r l₂
h₂ : Quot.mk Setoid.r l₂ ≤ Quot.mk Setoid.r l₁
⊢ Quot.mk Setoid.r l₁ = Quot.mk Setoid.r l₂

Next tactic:
exact Quot.sound (Subperm.antisymm h₁ h₂)
theorem lt_cons_self (s : Multiset α) (a : α) : s < a ::ₘ s :=
  Quot.inductionOn s fun l =>
    suffices l <+~ a :: l ∧ ¬l ~ a :: l by 

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s✝ t : Multiset α
a✝ : α
s : Multiset α
a : α
l : List α
this : l <+~ a :: l ∧ ¬l ~ a :: l
⊢ Quot.mk Setoid.r l < a ::ₘ Quot.mk Setoid.r l

Next tactic:
simpa [lt_iff_le_and_ne]
theorem le_cons_of_not_mem (m : a ∉ s) : s ≤ a ::ₘ t ↔ s ≤ t := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s t : Multiset α
a : α
m : a ∉ s
⊢ s ≤ a ::ₘ t ↔ s ≤ t

Next tactic:
refine' ⟨_, fun h => le_trans h <| le_cons_self _ _⟩
theorem le_cons_of_not_mem (m : a ∉ s) : s ≤ a ::ₘ t ↔ s ≤ t := by
  refine' ⟨_, fun h => le_trans h <| le_cons_self _ _⟩
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s t : Multiset α
a : α
m : a ∉ s
⊢ s ≤ a ::ₘ t → s ≤ t

Next tactic:
suffices ∀ {t'}, s ≤ t' → a ∈ t' → a ::ₘ s ≤ t' by
    exact fun h => (cons_le_cons_iff a).1 (this h (mem_cons_self _ _))
theorem le_cons_of_not_mem (m : a ∉ s) : s ≤ a ::ₘ t ↔ s ≤ t := by
  refine' ⟨_, fun h => le_trans h <| le_cons_self _ _⟩
  suffices ∀ {t'}, s ≤ t' → a ∈ t' → a ::ₘ s ≤ t' by
    

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s t : Multiset α
a : α
m : a ∉ s
this : ∀ {t' : Multiset α}, s ≤ t' → a ∈ t' → a ::ₘ s ≤ t'
⊢ s ≤ a ::ₘ t → s ≤ t

Next tactic:
exact fun h => (cons_le_cons_iff a).1 (this h (mem_cons_self _ _))
theorem le_cons_of_not_mem (m : a ∉ s) : s ≤ a ::ₘ t ↔ s ≤ t := by
  refine' ⟨_, fun h => le_trans h <| le_cons_self _ _⟩
  suffices ∀ {t'}, s ≤ t' → a ∈ t' → a ::ₘ s ≤ t' by
    exact fun h => (cons_le_cons_iff a).1 (this h (mem_cons_self _ _))
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s t : Multiset α
a : α
m : a ∉ s
⊢ ∀ {t' : Multiset α}, s ≤ t' → a ∈ t' → a ::ₘ s ≤ t'

Next tactic:
introv h
theorem le_cons_of_not_mem (m : a ∉ s) : s ≤ a ::ₘ t ↔ s ≤ t := by
  refine' ⟨_, fun h => le_trans h <| le_cons_self _ _⟩
  suffices ∀ {t'}, s ≤ t' → a ∈ t' → a ::ₘ s ≤ t' by
    exact fun h => (cons_le_cons_iff a).1 (this h (mem_cons_self _ _))
  introv h
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s t : Multiset α
a : α
m : a ∉ s
t' : Multiset α
h : s ≤ t'
⊢ a ∈ t' → a ::ₘ s ≤ t'

Next tactic:
revert m
theorem le_cons_of_not_mem (m : a ∉ s) : s ≤ a ::ₘ t ↔ s ≤ t := by
  refine' ⟨_, fun h => le_trans h <| le_cons_self _ _⟩
  suffices ∀ {t'}, s ≤ t' → a ∈ t' → a ::ₘ s ≤ t' by
    exact fun h => (cons_le_cons_iff a).1 (this h (mem_cons_self _ _))
  introv h
  revert m
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s t : Multiset α
a : α
t' : Multiset α
h : s ≤ t'
⊢ a ∉ s → a ∈ t' → a ::ₘ s ≤ t'

Next tactic:
refine' leInductionOn h _
theorem le_cons_of_not_mem (m : a ∉ s) : s ≤ a ::ₘ t ↔ s ≤ t := by
  refine' ⟨_, fun h => le_trans h <| le_cons_self _ _⟩
  suffices ∀ {t'}, s ≤ t' → a ∈ t' → a ::ₘ s ≤ t' by
    exact fun h => (cons_le_cons_iff a).1 (this h (mem_cons_self _ _))
  introv h
  revert m
  refine' leInductionOn h _
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s t : Multiset α
a : α
t' : Multiset α
h : s ≤ t'
⊢ ∀ {l₁ l₂ : List α}, l₁ <+ l₂ → a ∉ ↑l₁ → a ∈ ↑l₂ → a ::ₘ ↑l₁ ≤ ↑l₂

Next tactic:
introv s m₁ m₂
theorem le_cons_of_not_mem (m : a ∉ s) : s ≤ a ::ₘ t ↔ s ≤ t := by
  refine' ⟨_, fun h => le_trans h <| le_cons_self _ _⟩
  suffices ∀ {t'}, s ≤ t' → a ∈ t' → a ::ₘ s ≤ t' by
    exact fun h => (cons_le_cons_iff a).1 (this h (mem_cons_self _ _))
  introv h
  revert m
  refine' leInductionOn h _
  introv s m₁ m₂
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s✝ t : Multiset α
a : α
t' : Multiset α
h : s✝ ≤ t'
l₁ l₂ : List α
s : l₁ <+ l₂
m₁ : a ∉ ↑l₁
m₂ : a ∈ ↑l₂
⊢ a ::ₘ ↑l₁ ≤ ↑l₂

Next tactic:
rcases mem_split m₂ with ⟨r₁, r₂, rfl⟩
theorem le_cons_of_not_mem (m : a ∉ s) : s ≤ a ::ₘ t ↔ s ≤ t := by
  refine' ⟨_, fun h => le_trans h <| le_cons_self _ _⟩
  suffices ∀ {t'}, s ≤ t' → a ∈ t' → a ::ₘ s ≤ t' by
    exact fun h => (cons_le_cons_iff a).1 (this h (mem_cons_self _ _))
  introv h
  revert m
  refine' leInductionOn h _
  introv s m₁ m₂
  rcases mem_split m₂ with ⟨r₁, r₂, rfl⟩
  

Proof state:
case intro.intro
α : Type u_1
β : Type v
γ : Type u_2
s✝ t : Multiset α
a : α
t' : Multiset α
h : s✝ ≤ t'
l₁ : List α
m₁ : a ∉ ↑l₁
r₁ r₂ : List α
s : l₁ <+ r₁ ++ a :: r₂
m₂ : a ∈ ↑(r₁ ++ a :: r₂)
⊢ a ::ₘ ↑l₁ ≤ ↑(r₁ ++ a :: r₂)

Next tactic:
exact
    perm_middle.subperm_left.2
      ((subperm_cons _).2 <| ((sublist_or_mem_of_sublist s).resolve_right m₁).subperm)
@[simp] lemma le_singleton : s ≤ {a} ↔ s = 0 ∨ s = {a} :=
  Quot.induction_on s fun l ↦ by 

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s t : Multiset α
a : α
l : List α
⊢ Quot.mk Setoid.r l ≤ {a} ↔ Quot.mk Setoid.r l = 0 ∨ Quot.mk Setoid.r l = {a}

Next tactic:
simp only [cons_zero, ← coe_singleton, quot_mk_to_coe'', coe_le,
    coe_eq_zero, coe_eq_coe, perm_singleton, subperm_singleton_iff]
@[simp] lemma lt_singleton : s < {a} ↔ s = 0 := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s t : Multiset α
a : α
⊢ s < {a} ↔ s = 0

Next tactic:
simp only [lt_iff_le_and_ne, le_singleton, or_and_right, Ne.def, and_not_self, or_false,
    and_iff_left_iff_imp]
@[simp] lemma lt_singleton : s < {a} ↔ s = 0 := by
  simp only [lt_iff_le_and_ne, le_singleton, or_and_right, Ne.def, and_not_self, or_false,
    and_iff_left_iff_imp]
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s t : Multiset α
a : α
⊢ s = 0 → ¬s = {a}

Next tactic:
rintro rfl
@[simp] lemma lt_singleton : s < {a} ↔ s = 0 := by
  simp only [lt_iff_le_and_ne, le_singleton, or_and_right, Ne.def, and_not_self, or_false,
    and_iff_left_iff_imp]
  rintro rfl
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
t : Multiset α
a : α
⊢ ¬0 = {a}

Next tactic:
exact (singleton_ne_zero _).symm
@[simp] lemma ssubset_singleton_iff : s ⊂ {a} ↔ s = 0 := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s t : Multiset α
a : α
⊢ s ⊂ {a} ↔ s = 0

Next tactic:
refine ⟨fun hs ↦ eq_zero_of_subset_zero fun b hb ↦ (hs.2 ?_).elim, ?_⟩
@[simp] lemma ssubset_singleton_iff : s ⊂ {a} ↔ s = 0 := by
  refine ⟨fun hs ↦ eq_zero_of_subset_zero fun b hb ↦ (hs.2 ?_).elim, ?_⟩
  · 

Proof state:
case refine_1
α : Type u_1
β : Type v
γ : Type u_2
s t : Multiset α
a : α
hs : s ⊂ {a}
b : α
hb : b ∈ s
⊢ {a} ⊆ s

Next tactic:
obtain rfl := mem_singleton.1 (hs.1 hb)
@[simp] lemma ssubset_singleton_iff : s ⊂ {a} ↔ s = 0 := by
  refine ⟨fun hs ↦ eq_zero_of_subset_zero fun b hb ↦ (hs.2 ?_).elim, ?_⟩
  · obtain rfl := mem_singleton.1 (hs.1 hb)
    

Proof state:
case refine_1
α : Type u_1
β : Type v
γ : Type u_2
s t : Multiset α
b : α
hb : b ∈ s
hs : s ⊂ {b}
⊢ {b} ⊆ s

Next tactic:
rwa [singleton_subset]
@[simp] lemma ssubset_singleton_iff : s ⊂ {a} ↔ s = 0 := by
  refine ⟨fun hs ↦ eq_zero_of_subset_zero fun b hb ↦ (hs.2 ?_).elim, ?_⟩
  · obtain rfl := mem_singleton.1 (hs.1 hb)
    rwa [singleton_subset]
  · 

Proof state:
case refine_2
α : Type u_1
β : Type v
γ : Type u_2
s t : Multiset α
a : α
⊢ s = 0 → s ⊂ {a}

Next tactic:
rintro rfl
@[simp] lemma ssubset_singleton_iff : s ⊂ {a} ↔ s = 0 := by
  refine ⟨fun hs ↦ eq_zero_of_subset_zero fun b hb ↦ (hs.2 ?_).elim, ?_⟩
  · obtain rfl := mem_singleton.1 (hs.1 hb)
    rwa [singleton_subset]
  · rintro rfl
    

Proof state:
case refine_2
α : Type u_1
β : Type v
γ : Type u_2
t : Multiset α
a : α
⊢ 0 ⊂ {a}

Next tactic:
simp
theorem le_add_right (s t : Multiset α) : s ≤ s + t := by 

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s t : Multiset α
⊢ s ≤ s + t

Next tactic:
simpa using add_le_add_left (zero_le t) s
theorem le_add_left (s t : Multiset α) : s ≤ t + s := by 

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s t : Multiset α
⊢ s ≤ t + s

Next tactic:
simpa using add_le_add_right (zero_le t) s
@[simp]
theorem cons_add (a : α) (s t : Multiset α) : a ::ₘ s + t = a ::ₘ (s + t) := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
a : α
s t : Multiset α
⊢ a ::ₘ s + t = a ::ₘ (s + t)

Next tactic:
rw [← singleton_add, ← singleton_add, add_assoc]
@[simp]
theorem add_cons (a : α) (s t : Multiset α) : s + a ::ₘ t = a ::ₘ (s + t) := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
a : α
s t : Multiset α
⊢ s + a ::ₘ t = a ::ₘ (s + t)

Next tactic:
rw [add_comm, cons_add, add_comm]
theorem mem_of_mem_nsmul {a : α} {s : Multiset α} {n : ℕ} (h : a ∈ n • s) : a ∈ s := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
a : α
s : Multiset α
n : ℕ
h : a ∈ n • s
⊢ a ∈ s

Next tactic:
induction' n with n ih
theorem mem_of_mem_nsmul {a : α} {s : Multiset α} {n : ℕ} (h : a ∈ n • s) : a ∈ s := by
  induction' n with n ih
  · 

Proof state:
case zero
α : Type u_1
β : Type v
γ : Type u_2
a : α
s : Multiset α
h : a ∈ zero • s
⊢ a ∈ s

Next tactic:
rw [zero_nsmul] at h
theorem mem_of_mem_nsmul {a : α} {s : Multiset α} {n : ℕ} (h : a ∈ n • s) : a ∈ s := by
  induction' n with n ih
  · rw [zero_nsmul] at h
    

Proof state:
case zero
α : Type u_1
β : Type v
γ : Type u_2
a : α
s : Multiset α
h : a ∈ 0
⊢ a ∈ s

Next tactic:
exact absurd h (not_mem_zero _)
theorem mem_of_mem_nsmul {a : α} {s : Multiset α} {n : ℕ} (h : a ∈ n • s) : a ∈ s := by
  induction' n with n ih
  · rw [zero_nsmul] at h
    exact absurd h (not_mem_zero _)
  · 

Proof state:
case succ
α : Type u_1
β : Type v
γ : Type u_2
a : α
s : Multiset α
n : ℕ
ih : a ∈ n • s → a ∈ s
h : a ∈ succ n • s
⊢ a ∈ s

Next tactic:
rw [succ_nsmul, mem_add] at h
theorem mem_of_mem_nsmul {a : α} {s : Multiset α} {n : ℕ} (h : a ∈ n • s) : a ∈ s := by
  induction' n with n ih
  · rw [zero_nsmul] at h
    exact absurd h (not_mem_zero _)
  · rw [succ_nsmul, mem_add] at h
    

Proof state:
case succ
α : Type u_1
β : Type v
γ : Type u_2
a : α
s : Multiset α
n : ℕ
ih : a ∈ n • s → a ∈ s
h : a ∈ s ∨ a ∈ n • s
⊢ a ∈ s

Next tactic:
exact h.elim id ih
@[simp]
theorem mem_nsmul {a : α} {s : Multiset α} {n : ℕ} (h0 : n ≠ 0) : a ∈ n • s ↔ a ∈ s := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
a : α
s : Multiset α
n : ℕ
h0 : n ≠ 0
⊢ a ∈ n • s ↔ a ∈ s

Next tactic:
refine' ⟨mem_of_mem_nsmul, fun h => _⟩
@[simp]
theorem mem_nsmul {a : α} {s : Multiset α} {n : ℕ} (h0 : n ≠ 0) : a ∈ n • s ↔ a ∈ s := by
  refine' ⟨mem_of_mem_nsmul, fun h => _⟩
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
a : α
s : Multiset α
n : ℕ
h0 : n ≠ 0
h : a ∈ s
⊢ a ∈ n • s

Next tactic:
obtain ⟨n, rfl⟩ := exists_eq_succ_of_ne_zero h0
@[simp]
theorem mem_nsmul {a : α} {s : Multiset α} {n : ℕ} (h0 : n ≠ 0) : a ∈ n • s ↔ a ∈ s := by
  refine' ⟨mem_of_mem_nsmul, fun h => _⟩
  obtain ⟨n, rfl⟩ := exists_eq_succ_of_ne_zero h0
  

Proof state:
case intro
α : Type u_1
β : Type v
γ : Type u_2
a : α
s : Multiset α
h : a ∈ s
n : ℕ
h0 : succ n ≠ 0
⊢ a ∈ succ n • s

Next tactic:
rw [succ_nsmul, mem_add]
@[simp]
theorem mem_nsmul {a : α} {s : Multiset α} {n : ℕ} (h0 : n ≠ 0) : a ∈ n • s ↔ a ∈ s := by
  refine' ⟨mem_of_mem_nsmul, fun h => _⟩
  obtain ⟨n, rfl⟩ := exists_eq_succ_of_ne_zero h0
  rw [succ_nsmul, mem_add]
  

Proof state:
case intro
α : Type u_1
β : Type v
γ : Type u_2
a : α
s : Multiset α
h : a ∈ s
n : ℕ
h0 : succ n ≠ 0
⊢ a ∈ s ∨ a ∈ n • s

Next tactic:
exact Or.inl h
theorem nsmul_cons {s : Multiset α} (n : ℕ) (a : α) :
    n • (a ::ₘ s) = n • ({a} : Multiset α) + n • s := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s : Multiset α
n : ℕ
a : α
⊢ n • (a ::ₘ s) = n • {a} + n • s

Next tactic:
rw [← singleton_add, nsmul_add]
@[simp]
theorem length_toList (s : Multiset α) : s.toList.length = card s := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s : Multiset α
⊢ length (toList s) = card s

Next tactic:
rw [← coe_card, coe_toList]
theorem card_nsmul (s : Multiset α) (n : ℕ) : card (n • s) = n * card s := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s : Multiset α
n : ℕ
⊢ card (n • s) = n * card s

Next tactic:
rw [card.map_nsmul s n, Nat.nsmul_eq_mul]
@[simp]
theorem card_singleton (a : α) : card ({a} : Multiset α) = 1 := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
a : α
⊢ card {a} = 1

Next tactic:
simp only [← cons_zero, card_zero, eq_self_iff_true, zero_add, card_cons]
theorem card_pair (a b : α) : card {a, b} = 2 := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
a b : α
⊢ card {a, b} = 2

Next tactic:
rw [insert_eq_cons, card_cons, card_singleton]
@[simp]
theorem card_eq_zero {s : Multiset α} : card s = 0 ↔ s = 0 :=
  ⟨fun h => (eq_of_le_of_card_le (zero_le _) (le_of_eq h)).symm, fun e => by 

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
s : Multiset α
e : s = 0
⊢ card s = 0

Next tactic:
simp [e]
/-- The strong induction principle for multisets. -/
@[elab_as_elim]
def strongInductionOn {p : Multiset α → Sort*} (s : Multiset α) (ih : ∀ s, (∀ t < s, p t) → p s) :
    p s :=
    (ih s) fun t _h =>
      strongInductionOn t ih
termination_by _ => card s
decreasing_by 

Proof state:
α : Type u_1
p : Multiset α → Sort u_3
s : Multiset α
ih : (s : Multiset α) → ((t : Multiset α) → t < s → p t) → p s
t : Multiset α
_h : t < s
⊢ (invImage (fun a => PSigma.casesOn a fun s snd => card s) instWellFoundedRelation).1 { fst := t, snd := ih }
    { fst := s, snd := ih }

Next tactic:
exact card_lt_of_lt _h
theorem strongInductionOn_eq {p : Multiset α → Sort*} (s : Multiset α) (H) :
    @strongInductionOn _ p s H = H s fun t _h => @strongInductionOn _ p t H := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
p : Multiset α → Sort u_3
s : Multiset α
H : (s : Multiset α) → ((t : Multiset α) → t < s → p t) → p s
⊢ strongInductionOn s H = H s fun t _h => strongInductionOn t H

Next tactic:
rw [strongInductionOn]
/-- Suppose that, given that `p t` can be defined on all supersets of `s` of cardinality less than
`n`, one knows how to define `p s`. Then one can inductively define `p s` for all multisets `s` of
cardinality less than `n`, starting from multisets of card `n` and iterating. This
can be used either to define data, or to prove properties. -/
def strongDownwardInduction {p : Multiset α → Sort*} {n : ℕ}
    (H : ∀ t₁, (∀ {t₂ : Multiset α}, card t₂ ≤ n → t₁ < t₂ → p t₂) → card t₁ ≤ n → p t₁)
    (s : Multiset α) :
    card s ≤ n → p s :=
  H s fun {t} ht _h =>
    strongDownwardInduction H t ht
termination_by _ => n - card s
decreasing_by 

Proof state:
α : Type u_1
n : ℕ
s t : Multiset α
ht : card t ≤ n
_h : s < t
⊢ (invImage (fun a => n - card a) instWellFoundedRelation).1 t s

Next tactic:
exact (tsub_lt_tsub_iff_left_of_le ht).2 (card_lt_of_lt _h)
theorem strongDownwardInduction_eq {p : Multiset α → Sort*} {n : ℕ}
    (H : ∀ t₁, (∀ {t₂ : Multiset α}, card t₂ ≤ n → t₁ < t₂ → p t₂) → card t₁ ≤ n → p t₁)
    (s : Multiset α) :
    strongDownwardInduction H s = H s fun ht _hst => strongDownwardInduction H _ ht := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
p : Multiset α → Sort u_3
n : ℕ
H : (t₁ : Multiset α) → ({t₂ : Multiset α} → card t₂ ≤ n → t₁ < t₂ → p t₂) → card t₁ ≤ n → p t₁
s : Multiset α
⊢ strongDownwardInduction H s = H s fun {t₂} ht _hst => strongDownwardInduction H t₂ ht

Next tactic:
rw [strongDownwardInduction]
theorem strongDownwardInductionOn_eq {p : Multiset α → Sort*} (s : Multiset α) {n : ℕ}
    (H : ∀ t₁, (∀ {t₂ : Multiset α}, card t₂ ≤ n → t₁ < t₂ → p t₂) → card t₁ ≤ n → p t₁) :
    s.strongDownwardInductionOn H = H s fun {t} ht _h => t.strongDownwardInductionOn H ht := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
p : Multiset α → Sort u_3
s : Multiset α
n : ℕ
H : (t₁ : Multiset α) → ({t₂ : Multiset α} → card t₂ ≤ n → t₁ < t₂ → p t₂) → card t₁ ≤ n → p t₁
⊢ (fun a => strongDownwardInductionOn s H a) = H s fun {t} ht _h => strongDownwardInductionOn t H ht

Next tactic:
dsimp only [strongDownwardInductionOn]
theorem strongDownwardInductionOn_eq {p : Multiset α → Sort*} (s : Multiset α) {n : ℕ}
    (H : ∀ t₁, (∀ {t₂ : Multiset α}, card t₂ ≤ n → t₁ < t₂ → p t₂) → card t₁ ≤ n → p t₁) :
    s.strongDownwardInductionOn H = H s fun {t} ht _h => t.strongDownwardInductionOn H ht := by
  dsimp only [strongDownwardInductionOn]
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
p : Multiset α → Sort u_3
s : Multiset α
n : ℕ
H : (t₁ : Multiset α) → ({t₂ : Multiset α} → card t₂ ≤ n → t₁ < t₂ → p t₂) → card t₁ ≤ n → p t₁
⊢ (fun a => strongDownwardInduction H s a) = H s fun {t} ht _h => strongDownwardInduction H t ht

Next tactic:
rw [strongDownwardInduction]
theorem nsmul_singleton (a : α) (n) : n • ({a} : Multiset α) = replicate n a := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
a : α
n : ℕ
⊢ n • {a} = replicate n a

Next tactic:
rw [← replicate_one, nsmul_replicate, mul_one]
theorem replicate_le_replicate (a : α) {k n : ℕ} : replicate k a ≤ replicate n a ↔ k ≤ n :=
  _root_.trans (by 

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
a : α
k n : ℕ
⊢ replicate k a ≤ replicate n a ↔ List.replicate k a <+ List.replicate n a

Next tactic:
rw [← replicate_le_coe, coe_replicate]
theorem lt_replicate_succ {m : Multiset α} {x : α} {n : ℕ} :
    m < replicate (n + 1) x ↔ m ≤ replicate n x := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
m : Multiset α
x : α
n : ℕ
⊢ m < replicate (n + 1) x ↔ m ≤ replicate n x

Next tactic:
rw [lt_iff_cons_le]
theorem lt_replicate_succ {m : Multiset α} {x : α} {n : ℕ} :
    m < replicate (n + 1) x ↔ m ≤ replicate n x := by
  rw [lt_iff_cons_le]
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
m : Multiset α
x : α
n : ℕ
⊢ (∃ a, a ::ₘ m ≤ replicate (n + 1) x) ↔ m ≤ replicate n x

Next tactic:
constructor
theorem lt_replicate_succ {m : Multiset α} {x : α} {n : ℕ} :
    m < replicate (n + 1) x ↔ m ≤ replicate n x := by
  rw [lt_iff_cons_le]
  constructor
  · 

Proof state:
case mp
α : Type u_1
β : Type v
γ : Type u_2
m : Multiset α
x : α
n : ℕ
⊢ (∃ a, a ::ₘ m ≤ replicate (n + 1) x) → m ≤ replicate n x

Next tactic:
rintro ⟨x', hx'⟩
theorem lt_replicate_succ {m : Multiset α} {x : α} {n : ℕ} :
    m < replicate (n + 1) x ↔ m ≤ replicate n x := by
  rw [lt_iff_cons_le]
  constructor
  · rintro ⟨x', hx'⟩
    

Proof state:
case mp.intro
α : Type u_1
β : Type v
γ : Type u_2
m : Multiset α
x : α
n : ℕ
x' : α
hx' : x' ::ₘ m ≤ replicate (n + 1) x
⊢ m ≤ replicate n x

Next tactic:
have := eq_of_mem_replicate (mem_of_le hx' (mem_cons_self _ _))
theorem lt_replicate_succ {m : Multiset α} {x : α} {n : ℕ} :
    m < replicate (n + 1) x ↔ m ≤ replicate n x := by
  rw [lt_iff_cons_le]
  constructor
  · rintro ⟨x', hx'⟩
    have := eq_of_mem_replicate (mem_of_le hx' (mem_cons_self _ _))
    

Proof state:
case mp.intro
α : Type u_1
β : Type v
γ : Type u_2
m : Multiset α
x : α
n : ℕ
x' : α
hx' : x' ::ₘ m ≤ replicate (n + 1) x
this : x' = x
⊢ m ≤ replicate n x

Next tactic:
rwa [this, replicate_succ, cons_le_cons_iff] at hx'
theorem lt_replicate_succ {m : Multiset α} {x : α} {n : ℕ} :
    m < replicate (n + 1) x ↔ m ≤ replicate n x := by
  rw [lt_iff_cons_le]
  constructor
  · rintro ⟨x', hx'⟩
    have := eq_of_mem_replicate (mem_of_le hx' (mem_cons_self _ _))
    rwa [this, replicate_succ, cons_le_cons_iff] at hx'
  · 

Proof state:
case mpr
α : Type u_1
β : Type v
γ : Type u_2
m : Multiset α
x : α
n : ℕ
⊢ m ≤ replicate n x → ∃ a, a ::ₘ m ≤ replicate (n + 1) x

Next tactic:
intro h
theorem lt_replicate_succ {m : Multiset α} {x : α} {n : ℕ} :
    m < replicate (n + 1) x ↔ m ≤ replicate n x := by
  rw [lt_iff_cons_le]
  constructor
  · rintro ⟨x', hx'⟩
    have := eq_of_mem_replicate (mem_of_le hx' (mem_cons_self _ _))
    rwa [this, replicate_succ, cons_le_cons_iff] at hx'
  · intro h
    

Proof state:
case mpr
α : Type u_1
β : Type v
γ : Type u_2
m : Multiset α
x : α
n : ℕ
h : m ≤ replicate n x
⊢ ∃ a, a ::ₘ m ≤ replicate (n + 1) x

Next tactic:
rw [replicate_succ]
theorem lt_replicate_succ {m : Multiset α} {x : α} {n : ℕ} :
    m < replicate (n + 1) x ↔ m ≤ replicate n x := by
  rw [lt_iff_cons_le]
  constructor
  · rintro ⟨x', hx'⟩
    have := eq_of_mem_replicate (mem_of_le hx' (mem_cons_self _ _))
    rwa [this, replicate_succ, cons_le_cons_iff] at hx'
  · intro h
    rw [replicate_succ]
    

Proof state:
case mpr
α : Type u_1
β : Type v
γ : Type u_2
m : Multiset α
x : α
n : ℕ
h : m ≤ replicate n x
⊢ ∃ a, a ::ₘ m ≤ x ::ₘ replicate n x

Next tactic:
exact ⟨x, cons_le_cons _ h⟩
theorem erase_cons_tail_of_mem (h : a ∈ s) :
    (b ::ₘ s).erase a = b ::ₘ s.erase a := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
inst✝ : DecidableEq α
s t : Multiset α
a b : α
h : a ∈ s
⊢ erase (b ::ₘ s) a = b ::ₘ erase s a

Next tactic:
rcases eq_or_ne a b with rfl | hab
theorem erase_cons_tail_of_mem (h : a ∈ s) :
    (b ::ₘ s).erase a = b ::ₘ s.erase a := by
  rcases eq_or_ne a b with rfl | hab
  · 

Proof state:
case inl
α : Type u_1
β : Type v
γ : Type u_2
inst✝ : DecidableEq α
s t : Multiset α
a : α
h : a ∈ s
⊢ erase (a ::ₘ s) a = a ::ₘ erase s a

Next tactic:
simp [cons_erase h]
theorem erase_cons_tail_of_mem (h : a ∈ s) :
    (b ::ₘ s).erase a = b ::ₘ s.erase a := by
  rcases eq_or_ne a b with rfl | hab
  · simp [cons_erase h]
  · 

Proof state:
case inr
α : Type u_1
β : Type v
γ : Type u_2
inst✝ : DecidableEq α
s t : Multiset α
a b : α
h : a ∈ s
hab : a ≠ b
⊢ erase (b ::ₘ s) a = b ::ₘ erase s a

Next tactic:
exact s.erase_cons_tail hab.symm
theorem le_cons_erase (s : Multiset α) (a : α) : s ≤ a ::ₘ s.erase a :=
  if h : a ∈ s then le_of_eq (cons_erase h).symm
  else by 

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
inst✝ : DecidableEq α
s✝ t : Multiset α
a✝ b : α
s : Multiset α
a : α
h : a ∉ s
⊢ s ≤ a ::ₘ erase s a

Next tactic:
rw [erase_of_not_mem h]
theorem le_cons_erase (s : Multiset α) (a : α) : s ≤ a ::ₘ s.erase a :=
  if h : a ∈ s then le_of_eq (cons_erase h).symm
  else by rw [erase_of_not_mem h]; 

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
inst✝ : DecidableEq α
s✝ t : Multiset α
a✝ b : α
s : Multiset α
a : α
h : a ∉ s
⊢ s ≤ a ::ₘ s

Next tactic:
apply le_cons_self
theorem add_singleton_eq_iff {s t : Multiset α} {a : α} : s + {a} = t ↔ a ∈ t ∧ s = t.erase a := by
  

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
inst✝ : DecidableEq α
s✝ t✝ : Multiset α
a✝ b : α
s t : Multiset α
a : α
⊢ s + {a} = t ↔ a ∈ t ∧ s = erase t a

Next tactic:
rw [add_comm, singleton_add]
theorem add_singleton_eq_iff {s t : Multiset α} {a : α} : s + {a} = t ↔ a ∈ t ∧ s = t.erase a := by
  rw [add_comm, singleton_add]; 

Proof state:
α : Type u_1
β : Type v
γ : Type u_2
inst✝ : DecidableEq α
s✝ t✝ : Multiset α
a✝ b : α
s t : Multiset α
a : α
⊢ a ::ₘ s = t ↔ a ∈ t ∧ s = erase t a

Next tactic:
constructor
theorem add_singleton_eq_iff {s t : Multiset α} {a : α} : s + {a} = t ↔ a ∈ t ∧ s = t.erase a := by
  rw [add_comm, singleton_add]; constructor
  · 

Proof state:
case mp
α : Type u_1
β : Type v
γ : Type u_2
inst✝ : DecidableEq α
s✝ t✝ : Multiset α
a✝ b : α
s t : Multiset α
a : α
⊢ a ::ₘ s = t → a ∈ t ∧ s = erase t a

Next tactic:
rintro rfl
theorem add_singleton_eq_iff {s t : Multiset α} {a : α} : s + {a} = t ↔ a ∈ t ∧ s = t.erase a := by
  rw [add_comm, singleton_add]; constructor
  · rintro rfl
    

Proof state:
case mp
α : Type u_1
β : Type v
γ : Type u_2
inst✝ : DecidableEq α
s✝ t : Multiset α
a✝ b : α
s : Multiset α
a : α
⊢ a ∈ a ::ₘ s ∧ s = erase (a ::ₘ s) a

Next tactic:
exact ⟨s.mem_cons_self a, (s.erase_cons_head a).symm⟩