l3lab/ntp-mathlib huggingface dataset:
theorem pmap_eq_some_iff {hf} {y : β} :
    pmap f x hf = some y ↔ ∃ (a : α) (H : x = some a), f a (hf a H) = y := by
  rcases x with (_|x)
  · 

Proof state:
case none
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : α → Prop
f : (a : α) → p a → β
y : β
hf : ∀ (a : α), a ∈ none → p a
⊢ pmap f none hf = some y ↔ ∃ a H, f a (_ : p a) = y

Next tactic:
simp only [not_mem_none, exists_false, pmap, not_false_iff, exists_prop_of_false]
theorem pmap_eq_some_iff {hf} {y : β} :
    pmap f x hf = some y ↔ ∃ (a : α) (H : x = some a), f a (hf a H) = y := by
  rcases x with (_|x)
  · simp only [not_mem_none, exists_false, pmap, not_false_iff, exists_prop_of_false]
  · 

Proof state:
case some
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : α → Prop
f : (a : α) → p a → β
y : β
x : α
hf : ∀ (a : α), a ∈ some x → p a
⊢ pmap f (some x) hf = some y ↔ ∃ a H, f a (_ : p a) = y

Next tactic:
constructor
theorem pmap_eq_some_iff {hf} {y : β} :
    pmap f x hf = some y ↔ ∃ (a : α) (H : x = some a), f a (hf a H) = y := by
  rcases x with (_|x)
  · simp only [not_mem_none, exists_false, pmap, not_false_iff, exists_prop_of_false]
  · constructor
    · 

Proof state:
case some.mp
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : α → Prop
f : (a : α) → p a → β
y : β
x : α
hf : ∀ (a : α), a ∈ some x → p a
⊢ pmap f (some x) hf = some y → ∃ a H, f a (_ : p a) = y

Next tactic:
intro h
theorem pmap_eq_some_iff {hf} {y : β} :
    pmap f x hf = some y ↔ ∃ (a : α) (H : x = some a), f a (hf a H) = y := by
  rcases x with (_|x)
  · simp only [not_mem_none, exists_false, pmap, not_false_iff, exists_prop_of_false]
  · constructor
    · intro h
      

Proof state:
case some.mp
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : α → Prop
f : (a : α) → p a → β
y : β
x : α
hf : ∀ (a : α), a ∈ some x → p a
h : pmap f (some x) hf = some y
⊢ ∃ a H, f a (_ : p a) = y

Next tactic:
simp only [pmap, Option.some_inj] at h
theorem pmap_eq_some_iff {hf} {y : β} :
    pmap f x hf = some y ↔ ∃ (a : α) (H : x = some a), f a (hf a H) = y := by
  rcases x with (_|x)
  · simp only [not_mem_none, exists_false, pmap, not_false_iff, exists_prop_of_false]
  · constructor
    · intro h
      simp only [pmap, Option.some_inj] at h
      

Proof state:
case some.mp
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : α → Prop
f : (a : α) → p a → β
y : β
x : α
hf : ∀ (a : α), a ∈ some x → p a
h : f x (_ : p x) = y
⊢ ∃ a H, f a (_ : p a) = y

Next tactic:
refine ⟨x, rfl, h⟩
theorem pmap_eq_some_iff {hf} {y : β} :
    pmap f x hf = some y ↔ ∃ (a : α) (H : x = some a), f a (hf a H) = y := by
  rcases x with (_|x)
  · simp only [not_mem_none, exists_false, pmap, not_false_iff, exists_prop_of_false]
  · constructor
    · intro h
      simp only [pmap, Option.some_inj] at h
      refine ⟨x, rfl, h⟩
    · 

Proof state:
case some.mpr
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : α → Prop
f : (a : α) → p a → β
y : β
x : α
hf : ∀ (a : α), a ∈ some x → p a
⊢ (∃ a H, f a (_ : p a) = y) → pmap f (some x) hf = some y

Next tactic:
rintro ⟨a, H, rfl⟩
theorem pmap_eq_some_iff {hf} {y : β} :
    pmap f x hf = some y ↔ ∃ (a : α) (H : x = some a), f a (hf a H) = y := by
  rcases x with (_|x)
  · simp only [not_mem_none, exists_false, pmap, not_false_iff, exists_prop_of_false]
  · constructor
    · intro h
      simp only [pmap, Option.some_inj] at h
      refine ⟨x, rfl, h⟩
    · rintro ⟨a, H, rfl⟩
      

Proof state:
case some.mpr.intro.intro
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : α → Prop
f : (a : α) → p a → β
x : α
hf : ∀ (a : α), a ∈ some x → p a
a : α
H : some x = some a
⊢ pmap f (some x) hf = some (f a (_ : p a))

Next tactic:
simp only [mem_def, Option.some_inj] at H
theorem pmap_eq_some_iff {hf} {y : β} :
    pmap f x hf = some y ↔ ∃ (a : α) (H : x = some a), f a (hf a H) = y := by
  rcases x with (_|x)
  · simp only [not_mem_none, exists_false, pmap, not_false_iff, exists_prop_of_false]
  · constructor
    · intro h
      simp only [pmap, Option.some_inj] at h
      refine ⟨x, rfl, h⟩
    · rintro ⟨a, H, rfl⟩
      simp only [mem_def, Option.some_inj] at H
      

Proof state:
case some.mpr.intro.intro
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : α → Prop
f : (a : α) → p a → β
x : α
hf : ∀ (a : α), a ∈ some x → p a
a : α
H✝ : some x = some a
H : x = a
⊢ pmap f (some x) hf = some (f a (_ : p a))

Next tactic:
simp only [H, pmap]
theorem join_pmap_eq_pmap_join {f : ∀ a, p a → β} {x : Option (Option α)} (H) :
    (pmap (pmap f) x H).join = pmap f x.join fun a h ↦ H (some a) (mem_of_mem_join h) _ rfl := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : α → Prop
f✝ : (a : α) → p a → β
x✝ : Option α
f : (a : α) → p a → β
x : Option (Option α)
H : ∀ (a : Option α), a ∈ x → ∀ (a_2 : α), a_2 ∈ a → p a_2
⊢ join (pmap (pmap f) x H) = pmap f (join x) (_ : ∀ (a : α), a ∈ join x → p a)

Next tactic:
rcases x with (_ | _ | x)
theorem join_pmap_eq_pmap_join {f : ∀ a, p a → β} {x : Option (Option α)} (H) :
    (pmap (pmap f) x H).join = pmap f x.join fun a h ↦ H (some a) (mem_of_mem_join h) _ rfl := by
  rcases x with (_ | _ | x) <;> 

Proof state:
case none
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : α → Prop
f✝ : (a : α) → p a → β
x : Option α
f : (a : α) → p a → β
H : ∀ (a : Option α), a ∈ none → ∀ (a_2 : α), a_2 ∈ a → p a_2
⊢ join (pmap (pmap f) none H) = pmap f (join none) (_ : ∀ (a : α), a ∈ join none → p a)

Next tactic:
simp
theorem join_pmap_eq_pmap_join {f : ∀ a, p a → β} {x : Option (Option α)} (H) :
    (pmap (pmap f) x H).join = pmap f x.join fun a h ↦ H (some a) (mem_of_mem_join h) _ rfl := by
  rcases x with (_ | _ | x) <;> 

Proof state:
case some.none
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : α → Prop
f✝ : (a : α) → p a → β
x : Option α
f : (a : α) → p a → β
H : ∀ (a : Option α), a ∈ some none → ∀ (a_2 : α), a_2 ∈ a → p a_2
⊢ join (pmap (pmap f) (some none) H) = pmap f (join (some none)) (_ : ∀ (a : α), a ∈ join (some none) → p a)

Next tactic:
simp
theorem join_pmap_eq_pmap_join {f : ∀ a, p a → β} {x : Option (Option α)} (H) :
    (pmap (pmap f) x H).join = pmap f x.join fun a h ↦ H (some a) (mem_of_mem_join h) _ rfl := by
  rcases x with (_ | _ | x) <;> 

Proof state:
case some.some
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : α → Prop
f✝ : (a : α) → p a → β
x✝ : Option α
f : (a : α) → p a → β
x : α
H : ∀ (a : Option α), a ∈ some (some x) → ∀ (a_2 : α), a_2 ∈ a → p a_2
⊢ join (pmap (pmap f) (some (some x)) H) = pmap f (join (some (some x))) (_ : ∀ (a : α), a ∈ join (some (some x)) → p a)

Next tactic:
simp
@[simp]
theorem none_orElse' (x : Option α) : none.orElse (fun _ ↦ x) = x := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
x : Option α
⊢ (Option.orElse none fun x_1 => x) = x

Next tactic:
cases x
@[simp]
theorem none_orElse' (x : Option α) : none.orElse (fun _ ↦ x) = x := by cases x <;> 

Proof state:
case none
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
⊢ (Option.orElse none fun x => none) = none

Next tactic:
rfl
@[simp]
theorem none_orElse' (x : Option α) : none.orElse (fun _ ↦ x) = x := by cases x <;> 

Proof state:
case some
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
val✝ : α
⊢ (Option.orElse none fun x => some val✝) = some val✝

Next tactic:
rfl
@[simp]
theorem orElse_none' (x : Option α) : x.orElse (fun _ ↦ none) = x := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
x : Option α
⊢ (Option.orElse x fun x => none) = x

Next tactic:
cases x
@[simp]
theorem orElse_none' (x : Option α) : x.orElse (fun _ ↦ none) = x := by cases x <;> 

Proof state:
case none
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
⊢ (Option.orElse none fun x => none) = none

Next tactic:
rfl
@[simp]
theorem orElse_none' (x : Option α) : x.orElse (fun _ ↦ none) = x := by cases x <;> 

Proof state:
case some
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
val✝ : α
⊢ (Option.orElse (some val✝) fun x => none) = some val✝

Next tactic:
rfl
theorem getD_default_eq_iget [Inhabited α] (o : Option α) :
    o.getD default = o.iget := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
inst✝ : Inhabited α
o : Option α
⊢ getD o default = iget o

Next tactic:
cases o
theorem getD_default_eq_iget [Inhabited α] (o : Option α) :
    o.getD default = o.iget := by cases o <;> 

Proof state:
case none
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
inst✝ : Inhabited α
⊢ getD none default = iget none

Next tactic:
rfl
theorem getD_default_eq_iget [Inhabited α] (o : Option α) :
    o.getD default = o.iget := by cases o <;> 

Proof state:
case some
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
inst✝ : Inhabited α
val✝ : α
⊢ getD (some val✝) default = iget (some val✝)

Next tactic:
rfl
@[simp]
theorem guard_eq_some' {p : Prop} [Decidable p] (u) : _root_.guard p = some u ↔ p := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : Prop
inst✝ : Decidable p
u : Unit
⊢ _root_.guard p = some u ↔ p

Next tactic:
cases u
@[simp]
theorem guard_eq_some' {p : Prop} [Decidable p] (u) : _root_.guard p = some u ↔ p := by
  cases u
  

Proof state:
case unit
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : Prop
inst✝ : Decidable p
⊢ _root_.guard p = some PUnit.unit ↔ p

Next tactic:
by_cases h : p
@[simp]
theorem guard_eq_some' {p : Prop} [Decidable p] (u) : _root_.guard p = some u ↔ p := by
  cases u
  by_cases h : p <;> 

Proof state:
case pos
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : Prop
inst✝ : Decidable p
h : p
⊢ _root_.guard p = some PUnit.unit ↔ p

Next tactic:
simp [_root_.guard, h]
@[simp]
theorem guard_eq_some' {p : Prop} [Decidable p] (u) : _root_.guard p = some u ↔ p := by
  cases u
  by_cases h : p <;> 

Proof state:
case neg
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : Prop
inst✝ : Decidable p
h : ¬p
⊢ _root_.guard p = some PUnit.unit ↔ p

Next tactic:
simp [_root_.guard, h]
@[simp]
theorem guard_eq_some' {p : Prop} [Decidable p] (u) : _root_.guard p = some u ↔ p := by
  cases u
  by_cases h : p <;> simp [_root_.guard, h]; 

Proof state:
case pos
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
p : Prop
inst✝ : Decidable p
h : p
⊢ pure () = some PUnit.unit

Next tactic:
rfl
theorem liftOrGet_choice {f : α → α → α} (h : ∀ a b, f a b = a ∨ f a b = b) :
    ∀ o₁ o₂, liftOrGet f o₁ o₂ = o₁ ∨ liftOrGet f o₁ o₂ = o₂
  | none, none => Or.inl rfl
  | some a, none => Or.inl rfl
  | none, some b => Or.inr rfl
  | some a, some b => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
f : α → α → α
h : ∀ (a b : α), f a b = a ∨ f a b = b
a b : α
⊢ liftOrGet f (some a) (some b) = some a ∨ liftOrGet f (some a) (some b) = some b

Next tactic:
simpa [liftOrGet] using h a b
theorem casesOn'_none_coe (f : Option α → β) (o : Option α) :
    casesOn' o (f none) (f ∘ (fun a ↦ ↑a)) = f o := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
f : Option α → β
o : Option α
⊢ casesOn' o (f none) (f ∘ fun a => some a) = f o

Next tactic:
cases o
theorem casesOn'_none_coe (f : Option α → β) (o : Option α) :
    casesOn' o (f none) (f ∘ (fun a ↦ ↑a)) = f o := by cases o <;> 

Proof state:
case none
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
f : Option α → β
⊢ casesOn' none (f none) (f ∘ fun a => some a) = f none

Next tactic:
rfl
theorem casesOn'_none_coe (f : Option α → β) (o : Option α) :
    casesOn' o (f none) (f ∘ (fun a ↦ ↑a)) = f o := by cases o <;> 

Proof state:
case some
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
f : Option α → β
val✝ : α
⊢ casesOn' (some val✝) (f none) (f ∘ fun a => some a) = f (some val✝)

Next tactic:
rfl
theorem orElse_eq_some (o o' : Option α) (x : α) :
    (o <|> o') = some x ↔ o = some x ∨ o = none ∧ o' = some x := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
o o' : Option α
x : α
⊢ (HOrElse.hOrElse o fun x => o') = some x ↔ o = some x ∨ o = none ∧ o' = some x

Next tactic:
cases o
theorem orElse_eq_some (o o' : Option α) (x : α) :
    (o <|> o') = some x ↔ o = some x ∨ o = none ∧ o' = some x := by
  cases o
  · 

Proof state:
case none
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
o' : Option α
x : α
⊢ (HOrElse.hOrElse none fun x => o') = some x ↔ none = some x ∨ none = none ∧ o' = some x

Next tactic:
simp only [true_and, false_or, eq_self_iff_true, none_orElse]
theorem orElse_eq_some (o o' : Option α) (x : α) :
    (o <|> o') = some x ↔ o = some x ∨ o = none ∧ o' = some x := by
  cases o
  · simp only [true_and, false_or, eq_self_iff_true, none_orElse]
  · 

Proof state:
case some
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
o' : Option α
x val✝ : α
⊢ (HOrElse.hOrElse (some val✝) fun x => o') = some x ↔ some val✝ = some x ∨ some val✝ = none ∧ o' = some x

Next tactic:
simp only [some_orElse, or_false, false_and]
@[simp]
theorem orElse_eq_none (o o' : Option α) : (o <|> o') = none ↔ o = none ∧ o' = none := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
o o' : Option α
⊢ (HOrElse.hOrElse o fun x => o') = none ↔ o = none ∧ o' = none

Next tactic:
cases o
@[simp]
theorem orElse_eq_none (o o' : Option α) : (o <|> o') = none ↔ o = none ∧ o' = none := by
  cases o
  · 

Proof state:
case none
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
o' : Option α
⊢ (HOrElse.hOrElse none fun x => o') = none ↔ none = none ∧ o' = none

Next tactic:
simp only [true_and, none_orElse, eq_self_iff_true]
@[simp]
theorem orElse_eq_none (o o' : Option α) : (o <|> o') = none ↔ o = none ∧ o' = none := by
  cases o
  · simp only [true_and, none_orElse, eq_self_iff_true]
  · 

Proof state:
case some
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
o' : Option α
val✝ : α
⊢ (HOrElse.hOrElse (some val✝) fun x => o') = none ↔ some val✝ = none ∧ o' = none

Next tactic:
simp only [some_orElse, false_and]
theorem elim_none_some (f : Option α → β) : (fun x ↦ Option.elim x (f none) (f ∘ some)) = f :=
  funext fun o ↦ by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
f : Option α → β
o : Option α
⊢ Option.elim o (f none) (f ∘ some) = f o

Next tactic:
cases o
theorem elim_none_some (f : Option α → β) : (fun x ↦ Option.elim x (f none) (f ∘ some)) = f :=
  funext fun o ↦ by cases o <;> 

Proof state:
case none
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
f : Option α → β
⊢ Option.elim none (f none) (f ∘ some) = f none

Next tactic:
rfl
theorem elim_none_some (f : Option α → β) : (fun x ↦ Option.elim x (f none) (f ∘ some)) = f :=
  funext fun o ↦ by cases o <;> 

Proof state:
case some
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
f : Option α → β
val✝ : α
⊢ Option.elim (some val✝) (f none) (f ∘ some) = f (some val✝)

Next tactic:
rfl
theorem elim_comp (h : α → β) {f : γ → α} {x : α} {i : Option γ} :
    (i.elim (h x) fun j => h (f j)) = h (i.elim x f) := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
h : α → β
f : γ → α
x : α
i : Option γ
⊢ (Option.elim i (h x) fun j => h (f j)) = h (Option.elim i x f)

Next tactic:
cases i
theorem elim_comp (h : α → β) {f : γ → α} {x : α} {i : Option γ} :
    (i.elim (h x) fun j => h (f j)) = h (i.elim x f) := by cases i <;> 

Proof state:
case none
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
h : α → β
f : γ → α
x : α
⊢ (Option.elim none (h x) fun j => h (f j)) = h (Option.elim none x f)

Next tactic:
rfl
theorem elim_comp (h : α → β) {f : γ → α} {x : α} {i : Option γ} :
    (i.elim (h x) fun j => h (f j)) = h (i.elim x f) := by cases i <;> 

Proof state:
case some
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
h : α → β
f : γ → α
x : α
val✝ : γ
⊢ (Option.elim (some val✝) (h x) fun j => h (f j)) = h (Option.elim (some val✝) x f)

Next tactic:
rfl
theorem elim_comp₂ (h : α → β → γ) {f : γ → α} {x : α} {g : γ → β} {y : β}
    {i : Option γ} : (i.elim (h x y) fun j => h (f j) (g j)) = h (i.elim x f) (i.elim y g) := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
h : α → β → γ
f : γ → α
x : α
g : γ → β
y : β
i : Option γ
⊢ (Option.elim i (h x y) fun j => h (f j) (g j)) = h (Option.elim i x f) (Option.elim i y g)

Next tactic:
cases i
theorem elim_comp₂ (h : α → β → γ) {f : γ → α} {x : α} {g : γ → β} {y : β}
    {i : Option γ} : (i.elim (h x y) fun j => h (f j) (g j)) = h (i.elim x f) (i.elim y g) := by
  cases i <;> 

Proof state:
case none
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
h : α → β → γ
f : γ → α
x : α
g : γ → β
y : β
⊢ (Option.elim none (h x y) fun j => h (f j) (g j)) = h (Option.elim none x f) (Option.elim none y g)

Next tactic:
rfl
theorem elim_comp₂ (h : α → β → γ) {f : γ → α} {x : α} {g : γ → β} {y : β}
    {i : Option γ} : (i.elim (h x y) fun j => h (f j) (g j)) = h (i.elim x f) (i.elim y g) := by
  cases i <;> 

Proof state:
case some
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
h : α → β → γ
f : γ → α
x : α
g : γ → β
y : β
val✝ : γ
⊢ (Option.elim (some val✝) (h x y) fun j => h (f j) (g j)) =
    h (Option.elim (some val✝) x f) (Option.elim (some val✝) y g)

Next tactic:
rfl
theorem elim_apply {f : γ → α → β} {x : α → β} {i : Option γ} {y : α} :
    i.elim x f y = i.elim (x y) fun j => f j y := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
δ : Type u_4
f : γ → α → β
x : α → β
i : Option γ
y : α
⊢ Option.elim i x f y = Option.elim i (x y) fun j => f j y

Next tactic:
rw [elim_comp fun f : α → β => f y]
/-- Over `Fin (n + 1)`, the multisets of size `k + 1` containing `0` are equivalent to those of size
`k`, as demonstrated by respectively erasing or appending `0`. -/
protected def e1 {n k : ℕ} : { s : Sym (Fin (n + 1)) (k + 1) // ↑0 ∈ s } ≃ Sym (Fin n.succ) k where
  toFun s := s.1.erase 0 s.2
  invFun s := ⟨cons 0 s, mem_cons_self 0 s⟩
  left_inv s := by 

Proof state:
α : Type u_1
β : Type u_2
n✝ n k : ℕ
s : { s // 0 ∈ s }
⊢ (fun s => { val := 0 ::ₛ s, property := (_ : 0 ∈ 0 ::ₛ s) }) ((fun s => erase (↑s) 0 (_ : 0 ∈ ↑s)) s) = s

Next tactic:
simp
/-- Over `Fin (n + 1)`, the multisets of size `k + 1` containing `0` are equivalent to those of size
`k`, as demonstrated by respectively erasing or appending `0`. -/
protected def e1 {n k : ℕ} : { s : Sym (Fin (n + 1)) (k + 1) // ↑0 ∈ s } ≃ Sym (Fin n.succ) k where
  toFun s := s.1.erase 0 s.2
  invFun s := ⟨cons 0 s, mem_cons_self 0 s⟩
  left_inv s := by simp
  right_inv s := by 

Proof state:
α : Type u_1
β : Type u_2
n✝ n k : ℕ
s : Sym (Fin (succ n)) k
⊢ (fun s => erase (↑s) 0 (_ : 0 ∈ ↑s)) ((fun s => { val := 0 ::ₛ s, property := (_ : 0 ∈ 0 ::ₛ s) }) s) = s

Next tactic:
simp
/-- The multisets of size `k` over `Fin n+2` not containing `0`
are equivalent to those of size `k` over `Fin n+1`,
as demonstrated by respectively decrementing or incrementing every element of the multiset.
-/
protected def e2 {n k : ℕ} : { s : Sym (Fin n.succ.succ) k // ↑0 ∉ s } ≃ Sym (Fin n.succ) k where
  toFun s := map (Fin.predAbove 0) s.1
  invFun s :=
    ⟨map (Fin.succAbove 0) s,
      (mt mem_map.1) (not_exists.2 fun t => not_and.2 fun _ => Fin.succAbove_ne _ t)⟩
  left_inv s := by
    

Proof state:
α : Type u_1
β : Type u_2
n✝ n k : ℕ
s : { s // 0 ∉ s }
⊢ (fun s => { val := map (Fin.succAbove 0) s, property := (_ : 0 ∉ map (Fin.succAbove 0) s) })
      ((fun s => map (Fin.predAbove 0) ↑s) s) =
    s

Next tactic:
ext1
/-- The multisets of size `k` over `Fin n+2` not containing `0`
are equivalent to those of size `k` over `Fin n+1`,
as demonstrated by respectively decrementing or incrementing every element of the multiset.
-/
protected def e2 {n k : ℕ} : { s : Sym (Fin n.succ.succ) k // ↑0 ∉ s } ≃ Sym (Fin n.succ) k where
  toFun s := map (Fin.predAbove 0) s.1
  invFun s :=
    ⟨map (Fin.succAbove 0) s,
      (mt mem_map.1) (not_exists.2 fun t => not_and.2 fun _ => Fin.succAbove_ne _ t)⟩
  left_inv s := by
    ext1
    

Proof state:
case a
α : Type u_1
β : Type u_2
n✝ n k : ℕ
s : { s // 0 ∉ s }
⊢ ↑((fun s => { val := map (Fin.succAbove 0) s, property := (_ : 0 ∉ map (Fin.succAbove 0) s) })
        ((fun s => map (Fin.predAbove 0) ↑s) s)) =
    ↑s

Next tactic:
simp only [map_map]
/-- The multisets of size `k` over `Fin n+2` not containing `0`
are equivalent to those of size `k` over `Fin n+1`,
as demonstrated by respectively decrementing or incrementing every element of the multiset.
-/
protected def e2 {n k : ℕ} : { s : Sym (Fin n.succ.succ) k // ↑0 ∉ s } ≃ Sym (Fin n.succ) k where
  toFun s := map (Fin.predAbove 0) s.1
  invFun s :=
    ⟨map (Fin.succAbove 0) s,
      (mt mem_map.1) (not_exists.2 fun t => not_and.2 fun _ => Fin.succAbove_ne _ t)⟩
  left_inv s := by
    ext1
    simp only [map_map]
    

Proof state:
case a
α : Type u_1
β : Type u_2
n✝ n k : ℕ
s : { s // 0 ∉ s }
⊢ map (Fin.succAbove 0 ∘ Fin.predAbove 0) ↑s = ↑s

Next tactic:
refine (Sym.map_congr fun v hv ↦ ?_).trans (map_id' _)
/-- The multisets of size `k` over `Fin n+2` not containing `0`
are equivalent to those of size `k` over `Fin n+1`,
as demonstrated by respectively decrementing or incrementing every element of the multiset.
-/
protected def e2 {n k : ℕ} : { s : Sym (Fin n.succ.succ) k // ↑0 ∉ s } ≃ Sym (Fin n.succ) k where
  toFun s := map (Fin.predAbove 0) s.1
  invFun s :=
    ⟨map (Fin.succAbove 0) s,
      (mt mem_map.1) (not_exists.2 fun t => not_and.2 fun _ => Fin.succAbove_ne _ t)⟩
  left_inv s := by
    ext1
    simp only [map_map]
    refine (Sym.map_congr fun v hv ↦ ?_).trans (map_id' _)
    

Proof state:
case a
α : Type u_1
β : Type u_2
n✝ n k : ℕ
s : { s // 0 ∉ s }
v : Fin (succ n + 1)
hv : v ∈ ↑s
⊢ (Fin.succAbove 0 ∘ Fin.predAbove 0) v = v

Next tactic:
exact Fin.succAbove_predAbove (ne_of_mem_of_not_mem hv s.2)
/-- The multisets of size `k` over `Fin n+2` not containing `0`
are equivalent to those of size `k` over `Fin n+1`,
as demonstrated by respectively decrementing or incrementing every element of the multiset.
-/
protected def e2 {n k : ℕ} : { s : Sym (Fin n.succ.succ) k // ↑0 ∉ s } ≃ Sym (Fin n.succ) k where
  toFun s := map (Fin.predAbove 0) s.1
  invFun s :=
    ⟨map (Fin.succAbove 0) s,
      (mt mem_map.1) (not_exists.2 fun t => not_and.2 fun _ => Fin.succAbove_ne _ t)⟩
  left_inv s := by
    ext1
    simp only [map_map]
    refine (Sym.map_congr fun v hv ↦ ?_).trans (map_id' _)
    exact Fin.succAbove_predAbove (ne_of_mem_of_not_mem hv s.2)
  right_inv s := by
    

Proof state:
α : Type u_1
β : Type u_2
n✝ n k : ℕ
s : Sym (Fin (succ n)) k
⊢ (fun s => map (Fin.predAbove 0) ↑s)
      ((fun s => { val := map (Fin.succAbove 0) s, property := (_ : 0 ∉ map (Fin.succAbove 0) s) }) s) =
    s

Next tactic:
simp only [map_map, comp_apply, ← Fin.castSucc_zero, Fin.predAbove_succAbove, map_id']
theorem card_sym_fin_eq_multichoose : ∀ n k : ℕ, card (Sym (Fin n) k) = multichoose n k
  | n, 0 => by 

Proof state:
α : Type u_1
β : Type u_2
n✝ n : ℕ
⊢ Fintype.card (Sym (Fin n) 0) = multichoose n 0

Next tactic:
simp
theorem card_sym_fin_eq_multichoose : ∀ n k : ℕ, card (Sym (Fin n) k) = multichoose n k
  | n, 0 => by simp
  | 0, k + 1 => by 

Proof state:
α : Type u_1
β : Type u_2
n k : ℕ
⊢ Fintype.card (Sym (Fin 0) (k + 1)) = multichoose 0 (k + 1)

Next tactic:
rw [multichoose_zero_succ]
theorem card_sym_fin_eq_multichoose : ∀ n k : ℕ, card (Sym (Fin n) k) = multichoose n k
  | n, 0 => by simp
  | 0, k + 1 => by rw [multichoose_zero_succ]; 

Proof state:
α : Type u_1
β : Type u_2
n k : ℕ
⊢ Fintype.card (Sym (Fin 0) (k + 1)) = 0

Next tactic:
exact card_eq_zero
theorem card_sym_fin_eq_multichoose : ∀ n k : ℕ, card (Sym (Fin n) k) = multichoose n k
  | n, 0 => by simp
  | 0, k + 1 => by rw [multichoose_zero_succ]; exact card_eq_zero
  | 1, k + 1 => by 

Proof state:
α : Type u_1
β : Type u_2
n k : ℕ
⊢ Fintype.card (Sym (Fin 1) (k + 1)) = multichoose 1 (k + 1)

Next tactic:
simp
theorem card_sym_fin_eq_multichoose : ∀ n k : ℕ, card (Sym (Fin n) k) = multichoose n k
  | n, 0 => by simp
  | 0, k + 1 => by rw [multichoose_zero_succ]; exact card_eq_zero
  | 1, k + 1 => by simp
  | n + 2, k + 1 => by
    

Proof state:
α : Type u_1
β : Type u_2
n✝ n k : ℕ
⊢ Fintype.card (Sym (Fin (n + 2)) (k + 1)) = multichoose (n + 2) (k + 1)

Next tactic:
rw [multichoose_succ_succ, ← card_sym_fin_eq_multichoose (n + 1) (k + 1),
      ← card_sym_fin_eq_multichoose (n + 2) k, add_comm (Fintype.card _), ← card_sum]