-- Mathlib.Logic.Equiv.PartialEquiv.Simps (L161-L165)
def Simps.symm_apply (e : PartialEquiv α β) : β → α :=
e.symm

initialize_simps_projections PartialEquiv (toFun → apply, invFun → symm_apply)

-- Mathlib.Logic.Equiv.PartialEquiv.coe_mk (L166-L168)
theorem coe_mk (f : α → β) (g s t ml mr il ir) :
    (PartialEquiv.mk f g s t ml mr il ir : α → β) = f := rfl

-- Mathlib.Logic.Equiv.PartialEquiv.coe_symm_mk (L170-L173)
theorem coe_symm_mk (f : α → β) (g s t ml mr il ir) :
    ((PartialEquiv.mk f g s t ml mr il ir).symm : β → α) = g :=
rfl

-- Mathlib.Logic.Equiv.PartialEquiv.invFun_as_coe (L175-L177)
theorem invFun_as_coe : e.invFun = e.symm :=
rfl

-- Mathlib.Logic.Equiv.PartialEquiv.map_source'' (L183-L185)
lemma map_source'' : e '' e.source ⊆ e.target :=
fun _ ⟨_, hx, hex⟩ ↦ mem_of_eq_of_mem (id hex.symm) (e.map_source' hx)

-- Mathlib.Logic.Equiv.PartialEquiv.map_target (L187-L189)
theorem map_target {x : β} (h : x ∈ e.target) : e.symm x ∈ e.source :=
e.map_target' h

-- Mathlib.Logic.Equiv.PartialEquiv.left_inv (L191-L193)
theorem left_inv {x : α} (h : x ∈ e.source) : e.symm (e x) = x :=
e.left_inv' h

-- Mathlib.Logic.Equiv.PartialEquiv.right_inv (L195-L197)
theorem right_inv {x : β} (h : x ∈ e.target) : e (e.symm x) = x :=
e.right_inv' h

-- Mathlib.Logic.Equiv.PartialEquiv.target_subset_range (L198-L200)
theorem target_subset_range : e.target ⊆ range e :=
fun x hx ↦ ⟨e.symm x, right_inv e hx⟩

-- Mathlib.Logic.Equiv.PartialEquiv.symm_source (L280-L282)
theorem symm_source : e.symm.source = e.target :=
rfl

-- Mathlib.Logic.Equiv.PartialEquiv.symm_target (L284-L286)
theorem symm_target : e.symm.target = e.source :=
rfl

-- Mathlib.Logic.Equiv.PartialEquiv.symm_symm (L288-L289)
theorem symm_symm : e.symm.symm = e := rfl

-- Mathlib.Logic.Equiv.PartialEquiv.image_source_eq_target (L294-L296)
theorem image_source_eq_target : e '' e.source = e.target :=
e.bijOn.image_eq

-- Mathlib.Logic.Equiv.PartialEquiv.forall_mem_target (L297-L299)
theorem forall_mem_target {p : β → Prop} : (∀ y ∈ e.target, p y) ↔ ∀ x ∈ e.source, p (e x) := by
rw [← image_source_eq_target, forall_mem_image]

-- Mathlib.Logic.Equiv.PartialEquiv.IsImage (L310-L316)
def IsImage (s : Set α) (t : Set β) : Prop :=
∀ ⦃x⦄, x ∈ e.source → (e x ∈ t ↔ x ∈ s)

namespace IsImage

variable {e} {s : Set α} {t : Set β} {x : α}

-- Mathlib.Logic.Equiv.PartialEquiv.apply_mem_iff (L317-L319)
theorem apply_mem_iff (h : e.IsImage s t) (hx : x ∈ e.source) : e x ∈ t ↔ x ∈ s :=
h hx

-- Mathlib.Logic.Equiv.Basic.swap_comm (L642-L644)
theorem swap_comm (a b : α) : swap a b = swap b a :=
ext fun r => swapCore_comm r _ _

-- Mathlib.Logic.Equiv.Basic.swap_comp_apply (L676-L680)
theorem swap_comp_apply {a b x : α} (π : Perm α) :
    π.trans (swap a b) x = if π x = a then b else if π x = b then a else π x := by
cases π
  rfl

-- Mathlib.Logic.Equiv.Basic.eq_or_eq_of_swap_apply_ne_self (L660-L663)
theorem eq_or_eq_of_swap_apply_ne_self {a b x : α} (h : swap a b x ≠ x) : x = a ∨ x = b := by
contrapose! h
  exact swap_apply_of_ne_of_ne h.1 h.2

-- Mathlib.Logic.Equiv.Basic.swap_self (L639-L641)
theorem swap_self (a : α) : swap a a = Equiv.refl _ :=
ext fun r => swapCore_self r a

-- Mathlib.Logic.Equiv.Basic.swap_eq_refl_iff (L673-L675)
theorem swap_eq_refl_iff {x y : α} : swap x y = Equiv.refl _ ↔ x = y :=
⟨fun h => (Equiv.refl _).injective (by grind), by grind⟩

-- Mathlib.Logic.Equiv.Basic.swap_apply_right (L654-L656)
theorem swap_apply_right (a b : α) : swap a b b = a := by
grind

-- Mathlib.Logic.Equiv.Basic.symm_trans_swap_trans (L689-L692)
theorem symm_trans_swap_trans [DecidableEq β] (a b : α) (e : α ≃ β) :
    (e.symm.trans (swap a b)).trans e = swap (e a) (e b) := by
grind

-- Mathlib.Logic.Equiv.Basic.piComm (L154-L156)
def piComm (φ : α → β → Sort*) : (∀ a b, φ a b) ≃ ∀ b a, φ a b :=
⟨swap, swap, fun _ => rfl, fun _ => rfl⟩

-- Mathlib.Logic.Equiv.Basic.subtypeEquivRight (L295-L297)
def subtypeEquivRight {p q : α → Prop} (e : ∀ x, p x ↔ q x) : { x // p x } ≃ { x // q x } :=
subtypeEquiv (Equiv.refl _) e

-- Mathlib.Logic.Equiv.Basic.natSumPUnitEquivNat (L228-L231)
def natSumPUnitEquivNat : ℕ ⊕ PUnit ≃ ℕ :=
natEquivNatSumPUnit.symm

/-- The type of integer numbers is equivalent to `ℕ ⊕ ℕ`. -/

-- Mathlib.Logic.Equiv.Basic.subtypeEquivRight_apply (L298-L300)
lemma subtypeEquivRight_apply {p q : α → Prop} (e : ∀ x, p x ↔ q x)
    (z : { x // p x }) : subtypeEquivRight e z = ⟨z, (e z.1).mp z.2⟩ := rfl

-- Mathlib.Logic.Equiv.Basic.comp_swap_eq_update (L684-L687)
theorem comp_swap_eq_update (i j : α) (f : α → β) :
    f ∘ Equiv.swap i j = update (update f j (f i)) i (f j) := by
grind

-- Mathlib.Logic.Equiv.Basic.swap_eq_update (L681-L683)
theorem swap_eq_update (i j : α) : (Equiv.swap i j : α → α) = update (update id j i) i j := by
grind

-- Mathlib.Logic.Equiv.Basic.swapCore_self (L622-L625)
theorem swapCore_self (r a : α) : swapCore a a r = r := by
unfold swapCore
  split_ifs <;> simp [*]

-- Mathlib.Logic.Equiv.Basic.swap_apply_def (L646-L648)
theorem swap_apply_def (a b x : α) : swap a b x = if x = a then b else if x = b then a else x :=
rfl

-- Mathlib.Logic.Equiv.Basic.swap_apply_left (L650-L652)
theorem swap_apply_left (a b : α) : swap a b a = b :=
if_pos rfl

-- Mathlib.Logic.Equiv.Basic.subtypeEquivCodomain_apply (L513-L516)
theorem subtypeEquivCodomain_apply (f : { x' // x' ≠ x } → Y) (g) :
    subtypeEquivCodomain f g = (g : X → Y) x :=
rfl

-- Mathlib.Logic.Equiv.Basic.swapCore_swapCore (L626-L628)
theorem swapCore_swapCore (r a b : α) : swapCore a b (swapCore a b r) = r := by
unfold swapCore; split_ifs <;> grind

-- Mathlib.Logic.Equiv.Basic.swap (L634-L637)
def swap (a b : α) : Perm α :=
⟨swapCore a b, swapCore a b, fun r => swapCore_swapCore r a b,
    fun r => swapCore_swapCore r a b⟩

-- Mathlib.Logic.Equiv.Basic.swapCore (L619-L621)
def swapCore (a b r : α) : α :=
if r = a then b else if r = b then a else r

-- Mathlib.Logic.Equiv.Basic.Perm (L63-L65)
def Perm.subtypeCongr : Equiv.Perm ε :=
permCongr (sumCompl p) (sumCongr ep en)

-- Mathlib.Logic.Equiv.Basic.swap_swap (L665-L667)
theorem swap_swap (a b : α) : (swap a b).trans (swap a b) = Equiv.refl _ :=
ext fun _ => swapCore_swapCore _ _ _

-- Mathlib.Logic.Equiv.Basic.swap_apply_of_ne_of_ne (L657-L659)
theorem swap_apply_of_ne_of_ne {a b x : α} : x ≠ a → x ≠ b → swap a b x = x := by
grind

-- Mathlib.Logic.Equiv.Basic.coe_subtypeEquivCodomain (L507-L511)
theorem coe_subtypeEquivCodomain (f : { x' // x' ≠ x } → Y) :
    (subtypeEquivCodomain f : _ → Y) =
      fun g : { g : X → Y // g ∘ (↑) = f } => (g : X → Y) x :=
rfl

-- Mathlib.Logic.Equiv.Array.Array (L50-L53)
instance Array.encodable {α} [Encodable α] : Encodable (Array α) :=
Encodable.ofEquiv _ (Equiv.arrayEquivList _)

/-- If `α` is countable, then so is `Array α`. -/

-- Mathlib.Logic.Equiv.Basic.symm_swap (L669-L671)
theorem symm_swap (a b : α) : (swap a b).symm = swap a b :=
rfl

theorem refl_coe : (PartialEquiv.refl α : α → α) = id

[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Logic.Equiv.PartialEquiv).

[User]
Prove the following theorem. The retrieved context below may help.

```lean
theorem refl_coe : (PartialEquiv.refl α : α → α) = id
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.Simps (L161-L165)
def Simps.symm_apply (e : PartialEquiv α β) : β → α :=
e.symm

initialize_simps_projections PartialEquiv (toFun → apply, invFun → symm_apply)
```

-- snippet 2
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.coe_mk (L166-L168)
theorem coe_mk (f : α → β) (g s t ml mr il ir) :
    (PartialEquiv.mk f g s t ml mr il ir : α → β) = f := rfl
```

-- snippet 3
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.coe_symm_mk (L170-L173)
theorem coe_symm_mk (f : α → β) (g s t ml mr il ir) :
    ((PartialEquiv.mk f g s t ml mr il ir).symm : β → α) = g :=
rfl
```

-- snippet 4
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.invFun_as_coe (L175-L177)
theorem invFun_as_coe : e.invFun = e.symm :=
rfl
```

-- snippet 5
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.map_source (L179-L182)
theorem map_source {x : α} (h : x ∈ e.source) : e x ∈ e.target :=
e.map_source' h

/-- Variant of `e.map_source` and `map_source'`, stated for images of subsets of `source`. -/
```

-- snippet 6
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.map_source'' (L183-L185)
lemma map_source'' : e '' e.source ⊆ e.target :=
fun _ ⟨_, hx, hex⟩ ↦ mem_of_eq_of_mem (id hex.symm) (e.map_source' hx)
```

-- snippet 7
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.map_target (L187-L189)
theorem map_target {x : β} (h : x ∈ e.target) : e.symm x ∈ e.source :=
e.map_target' h
```

-- snippet 8
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.left_inv (L191-L193)
theorem left_inv {x : α} (h : x ∈ e.source) : e.symm (e x) = x :=
e.left_inv' h
```

-- snippet 9
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.right_inv (L195-L197)
theorem right_inv {x : β} (h : x ∈ e.target) : e (e.symm x) = x :=
e.right_inv' h
```

-- snippet 10
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.target_subset_range (L198-L200)
theorem target_subset_range : e.target ⊆ range e :=
fun x hx ↦ ⟨e.symm x, right_inv e hx⟩
```

-- snippet 11
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.eq_symm_apply (L201-L206)
theorem eq_symm_apply {x : α} {y : β} (hx : x ∈ e.source) (hy : y ∈ e.target) :
    x = e.symm y ↔ e x = y :=
⟨fun h => by rw [← e.right_inv hy, h], fun h => by rw [← e.left_inv hx, h]⟩

protected theorem mapsTo : MapsTo e e.source e.target := fun _ => e.map_source
```

-- snippet 12
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.symm_mapsTo (L207-L227)
theorem symm_mapsTo : MapsTo e.symm e.target e.source :=
e.symm.mapsTo

protected theorem leftInvOn : LeftInvOn e.symm e e.source := fun _ => e.left_inv

protected theorem rightInvOn : RightInvOn e.symm e e.target := fun _ => e.right_inv

protected theorem invOn : InvOn e.symm e e.source e.target :=
  ⟨e.leftInvOn, e.rightInvOn⟩

protected theorem injOn : InjOn e e.source :=
  e.leftInvOn.injOn

protected theorem bijOn : BijOn e e.source e.target :=
  e.invOn.bijOn e.mapsTo e.symm_mapsTo

protected theorem surjOn : SurjOn e e.source e.target :=
  e.bijOn.surjOn

/-- Interpret an `Equiv` as a `PartialEquiv` by restricting it to `s` in the domain
and to `t` in the codomain. -/
```

-- snippet 13
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.inhabitedOfEmpty (L248-L251)
instance inhabitedOfEmpty [IsEmpty α] [IsEmpty β] : Inhabited (PartialEquiv α β) :=
⟨((Equiv.equivEmpty α).trans (Equiv.equivEmpty β).symm).toPartialEquiv⟩

/-- Create a copy of a `PartialEquiv` providing better definitional equalities. -/
```

-- snippet 14
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.copy (L253-L264)
def copy (e : PartialEquiv α β) (f : α → β) (hf : ⇑e = f) (g : β → α) (hg : ⇑e.symm = g) (s : Set α)
    (hs : e.source = s) (t : Set β) (ht : e.target = t) :
    PartialEquiv α β where
  toFun := f
invFun := g
  source := s
  target := t
  map_source' _ := ht ▸ hs ▸ hf ▸ e.map_source
  map_target' _ := hs ▸ ht ▸ hg ▸ e.map_target
  left_inv' _ := hs ▸ hf ▸ hg ▸ e.left_inv
  right_inv' _ := ht ▸ hf ▸ hg ▸ e.right_inv
```

-- snippet 15
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.copy_eq (L265-L278)
theorem copy_eq (e : PartialEquiv α β) (f : α → β) (hf : ⇑e = f) (g : β → α) (hg : ⇑e.symm = g)
    (s : Set α) (hs : e.source = s) (t : Set β) (ht : e.target = t) :
    e.copy f hf g hg s hs t ht = e := by
substs f g s t
  cases e
  rfl

/-- Associate to a `PartialEquiv` an `Equiv` between the source and the target. -/
protected def toEquiv : e.source ≃ e.target where
  toFun x := ⟨e x, e.map_source x.mem⟩
  invFun y := ⟨e.symm y, e.map_target y.mem⟩
  left_inv := fun ⟨_, hx⟩ => Subtype.ext <| e.left_inv hx
  right_inv := fun ⟨_, hy⟩ => Subtype.ext <| e.right_inv hy
```

-- snippet 16
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.symm_source (L280-L282)
theorem symm_source : e.symm.source = e.target :=
rfl
```

-- snippet 17
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.symm_target (L284-L286)
theorem symm_target : e.symm.target = e.source :=
rfl
```

-- snippet 18
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.symm_symm (L288-L289)
theorem symm_symm : e.symm.symm = e := rfl
```

-- snippet 19
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.symm_bijective (L290-L293)
theorem symm_bijective :
    Function.Bijective (PartialEquiv.symm : PartialEquiv α β → PartialEquiv β α) :=
Function.bijective_iff_has_inverse.mpr ⟨_, symm_symm, symm_symm⟩
```

-- snippet 20
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.image_source_eq_target (L294-L296)
theorem image_source_eq_target : e '' e.source = e.target :=
e.bijOn.image_eq
```

-- snippet 21
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.forall_mem_target (L297-L299)
theorem forall_mem_target {p : β → Prop} : (∀ y ∈ e.target, p y) ↔ ∀ x ∈ e.source, p (e x) := by
rw [← image_source_eq_target, forall_mem_image]
```

-- snippet 22
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.exists_mem_target (L300-L309)
theorem exists_mem_target {p : β → Prop} : (∃ y ∈ e.target, p y) ↔ ∃ x ∈ e.source, p (e x) := by
rw [← image_source_eq_target, exists_mem_image]

/-- We say that `t : Set β` is an image of `s : Set α` under a partial equivalence if
any of the following equivalent conditions hold:

* `e '' (e.source ∩ s) = e.target ∩ t`;
* `e.source ∩ e ⁻¹ t = e.source ∩ s`;
* `∀ x ∈ e.source, e x ∈ t ↔ x ∈ s` (this one is used in the definition).
-/
```

-- snippet 23
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.IsImage (L310-L316)
def IsImage (s : Set α) (t : Set β) : Prop :=
∀ ⦃x⦄, x ∈ e.source → (e x ∈ t ↔ x ∈ s)

namespace IsImage

variable {e} {s : Set α} {t : Set β} {x : α}
```

-- snippet 24
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.apply_mem_iff (L317-L319)
theorem apply_mem_iff (h : e.IsImage s t) (hx : x ∈ e.source) : e x ∈ t ↔ x ∈ s :=
h hx
```

-- snippet 25
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.symm_apply_mem_iff (L320-L325)
theorem symm_apply_mem_iff (h : e.IsImage s t) : ∀ ⦃y⦄, y ∈ e.target → (e.symm y ∈ s ↔ y ∈ t) :=
e.forall_mem_target.mpr fun x hx => by rw [e.left_inv hx, h hx]

protected theorem symm (h : e.IsImage s t) : e.symm.IsImage t s :=
  h.symm_apply_mem_iff
```

-- snippet 26
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSigmaSubtype (L448-L457)
def sigmaSigmaSubtype {α : Type*} {β : α → Type*} {γ : (a : α) → β a → Type*}
    (p : (a : α) × β a → Prop) [uniq : Unique {ab // p ab}] {a : α} {b : β a} (h : p ⟨a, b⟩) :
    {s : (a : α) × (b : β a) × γ a b // p ⟨s.1, s.2.1⟩} ≃ γ a b :=
calc {s : (a : α) × (b : β a) × γ a b // p ⟨s.1, s.2.1⟩}
  _ ≃ _ := subtypeEquiv (p := fun ⟨a, b, c⟩ ↦ p ⟨a, b⟩) (q := (p ·.1))
    (sigmaAssoc γ).symm fun s ↦ by simp [sigmaAssoc]
  _ ≃ _ := subtypeSigmaEquiv _ _
  _ ≃ _ := uniqueSigma (fun ab ↦ γ (Sigma.fst <| Subtype.val ab) (Sigma.snd <| Subtype.val ab))
  _ ≃ γ a b := Equiv.cast <| by rw [← show ⟨⟨a, b⟩, h⟩ = uniq.default from uniq.uniq _]
```

-- snippet 27
```lean
-- Mathlib.Logic.Equiv.Basic.swap_comm (L642-L644)
theorem swap_comm (a b : α) : swap a b = swap b a :=
ext fun r => swapCore_comm r _ _
```

-- snippet 28
```lean
-- Mathlib.Logic.Equiv.Basic.swap_comp_apply (L676-L680)
theorem swap_comp_apply {a b x : α} (π : Perm α) :
    π.trans (swap a b) x = if π x = a then b else if π x = b then a else π x := by
cases π
  rfl
```

-- snippet 29
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeSubtypeEquivSubtype (L340-L345)
def subtypeSubtypeEquivSubtype {α} {p q : α → Prop} (h : ∀ {x}, q x → p x) :
    { x : Subtype p // q x.1 } ≃ Subtype q :=
(subtypeSubtypeEquivSubtypeInter p _).trans <| subtypeEquivRight fun _ => and_iff_right_of_imp h

/-- If a proposition holds for all elements, then the subtype is
equivalent to the original type. -/
```

-- snippet 30
```lean
-- Mathlib.Logic.Equiv.Basic.subtypePreimage_symm_apply_coe_pos (L128-L131)
theorem subtypePreimage_symm_apply_coe_pos (x : { a // ¬p a } → β) (a : α) (h : p a) :
    ((subtypePreimage p x₀).symm x : α → β) a = x₀ ⟨a, h⟩ :=
dif_pos h
```

-- snippet 31
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivProp (L316-L320)
def subtypeEquivProp {p q : α → Prop} (h : p = q) : Subtype p ≃ Subtype q :=
subtypeEquiv (Equiv.refl α) fun _ => h ▸ Iff.rfl

/-- A subtype of a subtype is equivalent to the subtype of elements satisfying both predicates. This
version allows the “inner” predicate to depend on `h : p a`. -/
```

-- snippet 32
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquiv_symm (L281-L284)
theorem subtypeEquiv_symm {p : α → Prop} {q : β → Prop} (e : α ≃ β) (h : ∀ a : α, p a ↔ q (e a)) :
    (e.subtypeEquiv h).symm = e.symm.subtypeEquiv (by as_aux_lemma => grind) :=
rfl
```

-- snippet 33
```lean
-- Mathlib.Logic.Equiv.Basic.piCongrRight_refl (L148-L152)
lemma piCongrRight_refl {β : α → Sort*} : piCongrRight (fun a ↦ .refl (β a)) = .refl (∀ a, β a) :=
rfl

/-- Given `φ : α → β → Sort*`, we have an equivalence between `∀ a b, φ a b` and `∀ b a, φ a b`.
This is `Function.swap` as an `Equiv`. -/
```

-- snippet 34
```lean
-- Mathlib.Logic.Equiv.Basic.eq_or_eq_of_swap_apply_ne_self (L660-L663)
theorem eq_or_eq_of_swap_apply_ne_self {a b x : α} (h : swap a b x ≠ x) : x = a ∨ x = b := by
contrapose! h
  exact swap_apply_of_ne_of_ne h.1 h.2
```

-- snippet 35
```lean
-- Mathlib.Logic.Equiv.Basic.ofFiberEquiv_map (L195-L200)
theorem ofFiberEquiv_map {α β γ} {f : α → γ} {g : β → γ}
    (e : ∀ c, { a // f a = c } ≃ { b // g b = c }) (a : α) : g (ofFiberEquiv e a) = f a :=
(_ : { b // g b = _ }).property

end prodCongr
```

-- snippet 36
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeSigmaEquiv (L351-L357)
def subtypeSigmaEquiv {α} (p : α → Type v) (q : α → Prop) : { y : Sigma p // q y.1 } ≃ Σ x :
    Subtype q, p x.1 :=
⟨fun x => ⟨⟨x.1.1, x.2⟩, x.1.2⟩, fun x => ⟨⟨x.1.1, x.2⟩, x.1.2⟩, fun _ => rfl,
    fun _ => rfl⟩

/-- A sigma type over a subtype is equivalent to the sigma set over the original type,
if the fiber is empty outside of the subset -/
```

-- snippet 37
```lean
-- Mathlib.Logic.Equiv.Basic.swap_self (L639-L641)
theorem swap_self (a : α) : swap a a = Equiv.refl _ :=
ext fun r => swapCore_self r a
```

-- snippet 38
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSigmaSubtypeEq_symm_apply (L482-L485)
lemma sigmaSigmaSubtypeEq_symm_apply {α β : Type*} {γ : α → β → Type*} {a : α} {b : β} (c : γ a b) :
    (sigmaSigmaSubtypeEq a b).symm c = ⟨⟨a, ⟨b, c⟩⟩, ⟨rfl, rfl⟩⟩ := by
simp [sigmaSigmaSubtypeEq]
```

-- snippet 39
```lean
-- Mathlib.Logic.Equiv.Basic.swap_eq_refl_iff (L673-L675)
theorem swap_eq_refl_iff {x y : α} : swap x y = Equiv.refl _ ↔ x = y :=
⟨fun h => (Equiv.refl _).injective (by grind), by grind⟩
```

-- snippet 40
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquiv (L262-L268)
def subtypeEquiv {p : α → Prop} {q : β → Prop} (e : α ≃ β) (h : ∀ a, p a ↔ q (e a)) :
    { a : α // p a } ≃ { b : β // q b } where
  toFun a := ⟨e a, (h _).mp a.property⟩
invFun b := ⟨e.symm b, (h _).mpr ((e.apply_symm_apply b).symm ▸ b.property)⟩
  left_inv a := Subtype.ext <| by simp
  right_inv b := Subtype.ext <| by simp
```

-- snippet 41
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeCongr (L54-L62)
def subtypeCongr {α} {p q : α → Prop} [DecidablePred p] [DecidablePred q]
    (e : { x // p x } ≃ { x // q x }) (f : { x // ¬p x } ≃ { x // ¬q x }) : Perm α :=
(sumCompl p).symm.trans ((sumCongr e f).trans (sumCompl q))

variable {ε : Type*} {p : ε → Prop} [DecidablePred p]
variable (ep ep' : Perm { a // p a }) (en en' : Perm { a // ¬p a })

/-- Combining permutations on `ε` that permute only inside or outside the subtype
split induced by `p : ε → Prop` constructs a permutation on `ε`. -/
```

-- snippet 42
```lean
-- Mathlib.Logic.Equiv.Basic.swap_apply_right (L654-L656)
theorem swap_apply_right (a b : α) : swap a b b = a := by
grind
```

-- snippet 43
```lean
-- Mathlib.Logic.Equiv.Basic.symm_trans_swap_trans (L689-L692)
theorem symm_trans_swap_trans [DecidableEq β] (a b : α) (e : α ≃ β) :
    (e.symm.trans (swap a b)).trans e = swap (e a) (e b) := by
grind
```

-- snippet 44
```lean
-- Mathlib.Logic.Equiv.Basic.subtypePreimage (L112-L127)
def subtypePreimage : { x : α → β // x ∘ Subtype.val = x₀ } ≃ ({ a // ¬p a } → β) where
  toFun (x : { x : α → β // x ∘ Subtype.val = x₀ }) a := (x : α → β) a
invFun x := ⟨fun a => if h : p a then x₀ ⟨a, h⟩ else x ⟨a, h⟩, funext fun ⟨_, h⟩ => dif_pos h⟩
  left_inv := fun ⟨x, hx⟩ =>
    Subtype.val_injective <|
      funext fun a => by
        dsimp only
        split_ifs
        · rw [← hx]; rfl
        · rfl
  right_inv x :=
    funext fun ⟨a, h⟩ =>
      show dite (p a) _ _ = _ by
        dsimp only
        rw [dif_neg h]
```

-- snippet 45
```lean
-- Mathlib.Logic.Equiv.Basic.subtypePreimage_symm_apply_coe_neg (L132-L137)
theorem subtypePreimage_symm_apply_coe_neg (x : { a // ¬p a } → β) (a : α) (h : ¬p a) :
    ((subtypePreimage p x₀).symm x : α → β) a = x ⟨a, h⟩ :=
dif_neg h

end subtypePreimage
```

-- snippet 46
```lean
-- Mathlib.Logic.Equiv.Basic.piComm (L154-L156)
def piComm (φ : α → β → Sort*) : (∀ a b, φ a b) ≃ ∀ b a, φ a b :=
⟨swap, swap, fun _ => rfl, fun _ => rfl⟩
```

-- snippet 47
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivRight (L295-L297)
def subtypeEquivRight {p q : α → Prop} (e : ∀ x, p x ↔ q x) : { x // p x } ≃ { x // q x } :=
subtypeEquiv (Equiv.refl _) e
```

-- snippet 48
```lean
-- Mathlib.Logic.Equiv.Basic.natSumPUnitEquivNat (L228-L231)
def natSumPUnitEquivNat : ℕ ⊕ PUnit ≃ ℕ :=
natEquivNatSumPUnit.symm

/-- The type of integer numbers is equivalent to `ℕ ⊕ ℕ`. -/
```

-- snippet 49
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivRight_apply (L298-L300)
lemma subtypeEquivRight_apply {p q : α → Prop} (e : ∀ x, p x ↔ q x)
    (z : { x // p x }) : subtypeEquivRight e z = ⟨z, (e z.1).mp z.2⟩ := rfl
```

-- snippet 50
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSubtypeEquivOfSubset (L358-L363)
def sigmaSubtypeEquivOfSubset {α} (p : α → Type v) (q : α → Prop) (h : ∀ x, p x → q x) :
    (Σ x : Subtype q, p x) ≃ Σ x : α, p x :=
(subtypeSigmaEquiv p q).symm.trans <| subtypeUnivEquiv fun x => h x.1 x.2

/-- If a predicate `p : β → Prop` is true on the range of a map `f : α → β`, then
`Σ y : {y // p y}, {x // f x = y}` is equivalent to `α`. -/
```

-- snippet 51
```lean
-- Mathlib.Logic.Equiv.Basic.coe_subtypeEquiv_eq_map (L269-L272)
lemma coe_subtypeEquiv_eq_map {X Y} {p : X → Prop} {q : Y → Prop} (e : X ≃ Y)
    (h : ∀ x, p x ↔ q (e x)) : ⇑(e.subtypeEquiv h) = Subtype.map e (h · |>.mp) :=
rfl
```

-- snippet 52
```lean
-- Mathlib.Logic.Equiv.Basic.comp_swap_eq_update (L684-L687)
theorem comp_swap_eq_update (i j : α) (f : α → β) :
    f ∘ Equiv.swap i j = update (update f j (f i)) i (f j) := by
grind
```

-- snippet 53
```lean
-- Mathlib.Logic.Equiv.Basic.swap_eq_update (L681-L683)
theorem swap_eq_update (i j : α) : (Equiv.swap i j : α → α) = update (update id j i) i j := by
grind
```

-- snippet 54
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeQuotientEquivQuotientSubtype_mk (L601-L606)
theorem subtypeQuotientEquivQuotientSubtype_mk (p₁ : α → Prop)
    [s₁ : Setoid α] [s₂ : Setoid (Subtype p₁)] (p₂ : Quotient s₁ → Prop) (hp₂ : ∀ a, p₁ a ↔ p₂ ⟦a⟧)
    (h : ∀ x y : Subtype p₁, s₂ x y ↔ (x : α) ≈ y)
    (x hx) : subtypeQuotientEquivQuotientSubtype p₁ p₂ hp₂ h ⟨⟦x⟧, hx⟩ = ⟦⟨x, (hp₂ _).2 hx⟩⟧ :=
rfl
```

-- snippet 55
```lean
-- Mathlib.Logic.Equiv.Basic.piCongrRight (L143-L146)
def piCongrRight {β₁ β₂ : α → Sort*} (F : ∀ a, β₁ a ≃ β₂ a) : (∀ a, β₁ a) ≃ (∀ a, β₂ a) :=
⟨Pi.map fun a ↦ F a, Pi.map fun a ↦ (F a).symm, fun H => funext <| by simp,
    fun H => funext <| by simp⟩
```

-- snippet 56
```lean
-- Mathlib.Logic.Equiv.Basic.piEquivSubtypeSigma (L402-L411)
def piEquivSubtypeSigma (ι) (π : ι → Type*) :
    (∀ i, π i) ≃ { f : ι → Σ i, π i // ∀ i, (f i).1 = i } where
  toFun := fun f => ⟨fun i => ⟨i, f i⟩, fun _ => rfl⟩
invFun := fun f i => by rw [← f.2 i]; exact (f.1 i).2
  right_inv := fun ⟨f, hf⟩ =>
    Subtype.ext <| funext fun i =>
      Sigma.eq (hf i).symm <| eq_of_heq <| rec_heq_of_heq _ <| by simp

/-- The type of functions `f : ∀ a, β a` such that for all `a` we have `p a (f a)` is equivalent
to the type of functions `∀ a, {b : β a // p a b}`. -/
```

-- snippet 57
```lean
-- Mathlib.Logic.Equiv.Basic.swapCore_self (L622-L625)
theorem swapCore_self (r a : α) : swapCore a a r = r := by
unfold swapCore
  split_ifs <;> simp [*]
```

-- snippet 58
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSubtypeFiberEquivSubtype (L372-L387)
def sigmaSubtypeFiberEquivSubtype {α β : Type*} (f : α → β) {p : α → Prop} {q : β → Prop}
    (h : ∀ x, p x ↔ q (f x)) : (Σ y : Subtype q, { x : α // f x = y }) ≃ Subtype p :=
calc
    (Σ y : Subtype q, { x : α // f x = y }) ≃ Σ y :
        Subtype q, { x : Subtype p // Subtype.mk (f x) ((h x).1 x.2) = y } := by {
          apply sigmaCongrRight
          intro y
          apply Equiv.symm
          refine (subtypeSubtypeEquivSubtypeExists _ _).trans (subtypeEquivRight ?_)
          intro x
          exact ⟨fun ⟨hp, h'⟩ => congr_arg Subtype.val h', fun h' => ⟨(h x).2 (h'.symm ▸ y.2),
            Subtype.ext h'⟩⟩ }
    _ ≃ Subtype p := sigmaFiberEquiv fun x : Subtype p => (⟨f x, (h x).1 x.property⟩ : Subtype q)

/-- A sigma type over an `Option` is equivalent to the sigma set over the original type,
if the fiber is empty at none. -/
```

-- snippet 59
```lean
-- Mathlib.Logic.Equiv.Basic.swap_apply_def (L646-L648)
theorem swap_apply_def (a b x : α) : swap a b x = if x = a then b else if x = b then a else x :=
rfl
```

-- snippet 60
```lean
-- Mathlib.Logic.Equiv.Basic.piCurry (L165-L172)
def piCurry {α} {β : α → Type*} (γ : ∀ a, β a → Type*) :
    (∀ x : Σ i, β i, γ x.1 x.2) ≃ ∀ a b, γ a b where
  toFun := Sigma.curry
invFun := Sigma.uncurry
  left_inv := Sigma.uncurry_curry
  right_inv := Sigma.curry_uncurry

-- `simps` overapplies these but `simps -fullyApplied` under-applies them
```

-- snippet 61
```lean
-- Mathlib.Logic.Equiv.Basic.swap_apply_left (L650-L652)
theorem swap_apply_left (a b : α) : swap a b a = b :=
if_pos rfl
```

-- snippet 62
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeQuotientEquivQuotientSubtype_symm_mk (L608-L618)
theorem subtypeQuotientEquivQuotientSubtype_symm_mk (p₁ : α → Prop)
    [s₁ : Setoid α] [s₂ : Setoid (Subtype p₁)] (p₂ : Quotient s₁ → Prop) (hp₂ : ∀ a, p₁ a ↔ p₂ ⟦a⟧)
    (h : ∀ x y : Subtype p₁, s₂ x y ↔ (x : α) ≈ y) (x) :
    (subtypeQuotientEquivQuotientSubtype p₁ p₂ hp₂ h).symm ⟦x⟧ = ⟨⟦x⟧, (hp₂ _).1 x.property⟩ :=
rfl

section Swap

variable [DecidableEq α]

/-- A helper function for `Equiv.swap`. -/
```

-- snippet 63
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivCodomain_apply (L513-L516)
theorem subtypeEquivCodomain_apply (f : { x' // x' ≠ x } → Y) (g) :
    subtypeEquivCodomain f g = (g : X → Y) x :=
rfl
```

-- snippet 64
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeUnivEquiv (L347-L350)
def subtypeUnivEquiv {α} {p : α → Prop} (h : ∀ x, p x) : Subtype p ≃ α :=
⟨fun x => x, fun x => ⟨x, h x⟩, fun _ => Subtype.ext rfl, fun _ => rfl⟩

/-- A subtype of a sigma-type is a sigma-type over a subtype. -/
```

-- snippet 65
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivCodomain (L496-L505)
def subtypeEquivCodomain (f : { x' // x' ≠ x } → Y) :
    { g : X → Y // g ∘ (↑) = f } ≃ Y :=
(subtypePreimage _ f).trans <|
    @funUnique { x' // ¬x' ≠ x } _ <|
      show Unique { x' // ¬x' ≠ x } from
        @Equiv.unique _ _
          (show Unique { x' // x' = x } from {
            default := ⟨x, rfl⟩, uniq := fun ⟨_, h⟩ => Subtype.val_injective h })
          (subtypeEquivRight fun _ => not_not)
```

-- snippet 66
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeQuotientEquivQuotientSubtype (L583-L599)
def subtypeQuotientEquivQuotientSubtype (p₁ : α → Prop) {s₁ : Setoid α} {s₂ : Setoid (Subtype p₁)}
    (p₂ : Quotient s₁ → Prop) (hp₂ : ∀ a, p₁ a ↔ p₂ ⟦a⟧)
    (h : ∀ x y : Subtype p₁, s₂.r x y ↔ s₁.r x y) : {x // p₂ x} ≃ Quotient s₂ where
  toFun a :=
Quotient.hrecOn a.1 (fun a h => ⟦⟨a, (hp₂ _).2 h⟩⟧)
      (fun a b hab => hfunext (by rw [Quotient.sound hab]) fun _ _ _ =>
        heq_of_eq (Quotient.sound ((h _ _).2 hab)))
      a.2
  invFun a :=
    Quotient.liftOn a (fun a => (⟨⟦a.1⟧, (hp₂ _).1 a.2⟩ : { x // p₂ x })) fun _ _ hab =>
      Subtype.ext (Quotient.sound ((h _ _).1 hab))
  left_inv a := by
    obtain ⟨a, ha⟩ := a
    induction a using Quotient.inductionOn
    rfl
  right_inv a := by induction a using Quotient.inductionOn; rfl
```

-- snippet 67
```lean
-- Mathlib.Logic.Equiv.Basic.coe_subtypeEquivCodomain_symm (L517-L521)
theorem coe_subtypeEquivCodomain_symm (f : { x' // x' ≠ x } → Y) :
    ((subtypeEquivCodomain f).symm : Y → _) = fun y =>
      ⟨fun x' => if h : x' ≠ x then f ⟨x', h⟩ else y, by grind⟩ :=
rfl
```

-- snippet 68
```lean
-- Mathlib.Logic.Equiv.Basic.swapCore_swapCore (L626-L628)
theorem swapCore_swapCore (r a b : α) : swapCore a b (swapCore a b r) = r := by
unfold swapCore; split_ifs <;> grind
```

-- snippet 69
```lean
-- Mathlib.Logic.Equiv.Array.for (L31-L49)
instance for `array` was)

2. belong in `Mathlib/Control/Traversable/Instances.lean` instead of this file. -/

-- namespace Array'

-- open Function

-- variable {n : ℕ}
-- instance : Traversable (Array' n) :=
--   @Equiv.traversable (flip Vector n) _ (fun α => Equiv.vectorEquivArray α n) _

-- instance : LawfulTraversable (Array' n) :=
--   @Equiv.isLawfulTraversable (flip Vector n) _ (fun α => Equiv.vectorEquivArray α n) _ _

-- end Array'

/-- If `α` is encodable, then so is `Array α`. -/
```

-- snippet 70
```lean
-- Mathlib.Logic.Equiv.Basic.swap (L634-L637)
def swap (a b : α) : Perm α :=
⟨swapCore a b, swapCore a b, fun r => swapCore_swapCore r a b,
    fun r => swapCore_swapCore r a b⟩
```

-- snippet 71
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquiv_trans (L286-L293)
theorem subtypeEquiv_trans {p : α → Prop} {q : β → Prop} {r : γ → Prop} (e : α ≃ β) (f : β ≃ γ)
    (h : ∀ a : α, p a ↔ q (e a)) (h' : ∀ b : β, q b ↔ r (f b)) :
    (e.subtypeEquiv h).trans (f.subtypeEquiv h')
    = (e.trans f).subtypeEquiv (by as_aux_lemma => exact fun a => (h a).trans (h' <| e a)) :=
rfl

/-- If two predicates `p` and `q` are pointwise equivalent, then `{x // p x}` is equivalent to
`{x // q x}`. -/
```

-- snippet 72
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeSubtypeEquivSubtypeExists (L322-L330)
def subtypeSubtypeEquivSubtypeExists (p : α → Prop) (q : Subtype p → Prop) :
    Subtype q ≃ { a : α // ∃ h : p a, q ⟨a, h⟩ } :=
⟨fun a =>
    ⟨a.1, a.1.2, by
      rcases a with ⟨⟨a, hap⟩, haq⟩
      exact haq⟩,
    fun a => ⟨⟨a, a.2.fst⟩, a.2.snd⟩, fun ⟨⟨_, _⟩, _⟩ => rfl, fun ⟨_, _, _⟩ => rfl⟩

/-- A subtype of a subtype is equivalent to the subtype of elements satisfying both predicates. -/
```

-- snippet 73
```lean
-- Mathlib.Logic.Equiv.Basic.subtypePiEquivPi (L412-L425)
def subtypePiEquivPi {β : α → Sort v} {p : ∀ a, β a → Prop} :
    { f : ∀ a, β a // ∀ a, p a (f a) } ≃ ∀ a, { b : β a // p a b } where
  toFun := fun f a => ⟨f.1 a, f.2 a⟩
invFun := fun f => ⟨fun a => (f a).1, fun a => (f a).2⟩
  left_inv := by
    rintro ⟨f, h⟩
    rfl
  right_inv := by
    rintro f
    funext a
    exact Subtype.ext rfl

/-- A sigma of a sigma whose second base does not depend on the first is equivalent
to a sigma whose base is a product. -/
```

-- snippet 74
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSubtype (L434-L441)
def sigmaSubtype {α : Type*} {β : α → Type*} (a : α) :
    {s : Sigma β // s.1 = a} ≃ β a where
  toFun := fun ⟨⟨_, b⟩, h⟩ => h ▸ b
invFun b := ⟨⟨a, b⟩, rfl⟩
  left_inv := fun ⟨a, h⟩ ↦ by cases h; simp
  right_inv b := by simp
```

-- snippet 75
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivRight_symm_apply (L301-L305)
lemma subtypeEquivRight_symm_apply {p q : α → Prop} (e : ∀ x, p x ↔ q x)
    (z : { x // q x }) : (subtypeEquivRight e).symm z = ⟨z, (e z.1).mpr z.2⟩ := rfl
/-- If `α ≃ β`, then for any predicate `p : β → Prop` the subtype `{a // p (e a)}` is equivalent
to the subtype `{b // p b}`. -/
```

-- snippet 76
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivCodomain_symm_apply (L523-L526)
theorem subtypeEquivCodomain_symm_apply (f : { x' // x' ≠ x } → Y) (y : Y) (x' : X) :
    ((subtypeEquivCodomain f).symm y : X → Y) x' = if h : x' ≠ x then f ⟨x', h⟩ else y :=
rfl
```

-- snippet 77
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivCodomain_symm_apply_ne (L531-L537)
theorem subtypeEquivCodomain_symm_apply_ne
    (f : { x' // x' ≠ x } → Y) (y : Y) (x' : X) (h : x' ≠ x) :
    ((subtypeEquivCodomain f).symm y : X → Y) x' = f ⟨x', h⟩ :=
dif_pos h

end subtypeEquivCodomain
```

-- snippet 78
```lean
-- Mathlib.Logic.Equiv.Basic.uniqueCongr (L241-L247)
def uniqueCongr (e : α ≃ β) : Unique α ≃ Unique β where
  toFun h := @Equiv.unique _ _ h e.symm
invFun h := @Equiv.unique _ _ h e
  left_inv _ := Subsingleton.elim _ _
  right_inv _ := Subsingleton.elim _ _

/-- If `α` is equivalent to `β`, then `IsEmpty α` is equivalent to `IsEmpty β`. -/
```

-- snippet 79
```lean
-- Mathlib.Logic.Equiv.Basic.swapCore (L619-L621)
def swapCore (a b r : α) : α :=
if r = a then b else if r = b then a else r
```

-- snippet 80
```lean
-- Mathlib.Logic.Equiv.Basic.piComm_symm (L158-L164)
theorem piComm_symm {φ : α → β → Sort*} : (piComm φ).symm = (piComm <| swap φ) :=
rfl

/-- Dependent `curry` equivalence: the type of dependent functions on `Σ i, β i` is equivalent
to the type of dependent functions of two arguments (i.e., functions to the space of functions).

This is `Sigma.curry` and `Sigma.uncurry` together as an equiv. -/
```

-- snippet 81
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeSubtypeEquivSubtypeInter (L332-L338)
def subtypeSubtypeEquivSubtypeInter {α : Type u} (p q : α → Prop) :
    { x : Subtype p // q x.1 } ≃ Subtype fun x => p x ∧ q x :=
(subtypeSubtypeEquivSubtypeExists p _).trans <|
    subtypeEquivRight fun x => @exists_prop (q x) (p x)

/-- If the outer subtype has more restrictive predicate than the inner one,
then we can drop the latter. -/
```

-- snippet 82
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSubtypeFiberEquiv (L364-L371)
def sigmaSubtypeFiberEquiv {α β : Type*} (f : α → β) (p : β → Prop) (h : ∀ x, p (f x)) :
    (Σ y : Subtype p, { x : α // f x = y }) ≃ α :=
calc
    _ ≃ Σ y : β, { x : α // f x = y } := sigmaSubtypeEquivOfSubset _ p fun _ ⟨x, h'⟩ => h' ▸ h x
    _ ≃ α := sigmaFiberEquiv f

/-- If for each `x` we have `p x ↔ q (f x)`, then `Σ y : {y // q y}, f ⁻¹' {y}` is equivalent
to `{x // p x}`. -/
```

-- snippet 83
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquiv_refl (L274-L279)
theorem subtypeEquiv_refl {p : α → Prop} (h : ∀ a, p a ↔ p (Equiv.refl _ a) := fun _ => Iff.rfl) :
(Equiv.refl α).subtypeEquiv h = Equiv.refl { a : α // p a } := by
  ext
  rfl

-- We use `as_aux_lemma` here to avoid creating large proof terms when using `simp`
```

-- snippet 84
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSigmaSubtype_symm_apply (L459-L467)
lemma sigmaSigmaSubtype_symm_apply {α : Type*} {β : α → Type*} {γ : (a : α) → β a → Type*}
    (p : (a : α) × β a → Prop) [uniq : Unique {ab // p ab}]
    {a : α} {b : β a} (c : γ a b) (h : p ⟨a, b⟩) :
    (sigmaSigmaSubtype p h).symm c = ⟨⟨a, ⟨b, c⟩⟩, h⟩ := by
rw [Equiv.symm_apply_eq]; simp

/-- A specialization of `sigmaSigmaSubtype` to the case where the second base
does not depend on the first, and the property being checked for is simple
equality. Useful e.g. when `γ` is `Hom` inside a category. -/
```

-- snippet 85
```lean
-- Mathlib.Logic.Equiv.Basic.Perm (L63-L65)
def Perm.subtypeCongr : Equiv.Perm ε :=
permCongr (sumCompl p) (sumCongr ep en)
```

-- snippet 86
```lean
-- Mathlib.Logic.Equiv.Basic.intEquivNatSumNat (L232-L237)
def intEquivNatSumNat : ℤ ≃ ℕ ⊕ ℕ where
  toFun z := Int.casesOn z inl inr
invFun := Sum.elim Int.ofNat Int.negSucc
  left_inv := by rintro (m | n) <;> rfl
  right_inv := by rintro (m | n) <;> rfl
```

-- snippet 87
```lean
-- Mathlib.Logic.Equiv.Basic.swap_swap (L665-L667)
theorem swap_swap (a b : α) : (swap a b).trans (swap a b) = Equiv.refl _ :=
ext fun _ => swapCore_swapCore _ _ _
```

-- snippet 88
```lean
-- Mathlib.Logic.Equiv.Basic.swap_apply_of_ne_of_ne (L657-L659)
theorem swap_apply_of_ne_of_ne {a b x : α} : x ≠ a → x ≠ b → swap a b x = x := by
grind
```

-- snippet 89
```lean
-- Mathlib.Logic.Equiv.Basic.ofFiberEquiv (L191-L194)
def ofFiberEquiv {α β γ} {f : α → γ} {g : β → γ}
    (e : ∀ c, { a // f a = c } ≃ { b // g b = c }) : α ≃ β :=
(sigmaFiberEquiv f).symm.trans <| (Equiv.sigmaCongrRight e).trans (sigmaFiberEquiv g)
```

-- snippet 90
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivOfSubtype' (L311-L315)
def subtypeEquivOfSubtype' {p : α → Prop} (e : α ≃ β) :
    { a : α // p a } ≃ { b : β // p (e.symm b) } :=
e.symm.subtypeEquivOfSubtype.symm

/-- If two predicates are equal, then the corresponding subtypes are equivalent. -/
```

-- snippet 91
```lean
-- Mathlib.Logic.Equiv.Basic.swapCore_comm (L629-L633)
theorem swapCore_comm (r a b : α) : swapCore a b r = swapCore b a r := by
unfold swapCore; split_ifs <;> grind

/-- `swap a b` is the permutation that swaps `a` and `b` and
  leaves other values as is. -/
```

-- snippet 92
```lean
-- Mathlib.Logic.Equiv.Basic.isEmpty_congr (L248-L253)
theorem isEmpty_congr (e : α ≃ β) : IsEmpty α ↔ IsEmpty β :=
⟨fun h => @Function.isEmpty _ _ h e.symm, fun h => @Function.isEmpty _ _ h e⟩

protected theorem isEmpty (e : α ≃ β) [IsEmpty β] : IsEmpty α :=
  e.isEmpty_congr.mpr ‹_›
```

-- snippet 93
```lean
-- Mathlib.Logic.Equiv.Basic.piOptionEquivProd (L44-L53)
def piOptionEquivProd {α} {β : Option α → Type*} :
    (∀ a : Option α, β a) ≃ β none × ∀ a : α, β (some a) where
  toFun f := (f none, fun a => f (some a))
invFun x a := Option.casesOn a x.fst x.snd
  left_inv f := funext fun a => by cases a <;> rfl

section subtypeCongr

/-- Combines an `Equiv` between two subtypes with an `Equiv` between their complements to form a
  permutation. -/
```

-- snippet 94
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivOfSubtype (L306-L310)
def subtypeEquivOfSubtype {p : β → Prop} (e : α ≃ β) : { a : α // p (e a) } ≃ { b : β // p b } :=
subtypeEquiv e <| by simp

/-- If `α ≃ β`, then for any predicate `p : α → Prop` the subtype `{a // p a}` is equivalent
to the subtype `{b // p (e.symm b)}`. This version is used by `equiv_rw`. -/
```

-- snippet 95
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaOptionEquivOfSome (L388-L401)
def sigmaOptionEquivOfSome {α} (p : Option α → Type v) (h : p none → False) :
    (Σ x : Option α, p x) ≃ Σ x : α, p (some x) :=
haveI h' : ∀ x, p x → x.isSome := by
    intro x
    cases x
    · intro n
      exfalso
      exact h n
    · intro _
      exact rfl
  (sigmaSubtypeEquivOfSubset _ _ h').symm.trans (sigmaCongrLeft' (optionIsSomeEquiv α))

/-- The `Pi`-type `∀ i, π i` is equivalent to the type of sections `f : ι → Σ i, π i` of the
`Sigma` type such that for all `i` we have `(f i).fst = i`. -/
```

-- snippet 96
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSigmaSubtypeEq (L468-L474)
def sigmaSigmaSubtypeEq {α β : Type*} {γ : α → β → Type*} (a : α) (b : β) :
    {s : (a : α) × (b : β) × γ a b // s.1 = a ∧ s.2.1 = b} ≃ γ a b :=
have : Unique (@Subtype ((_ : α) × β) (fun ⟨a', b'⟩ ↦ a' = a ∧ b' = b)) := {
    default := ⟨⟨a, b⟩, ⟨rfl, rfl⟩⟩
    uniq := by rintro ⟨⟨a', b'⟩, ⟨rfl, rfl⟩⟩; rfl }
  sigmaSigmaSubtype (fun ⟨a', b'⟩ ↦ a' = a ∧ b' = b) ⟨rfl, rfl⟩
```

-- snippet 97
```lean
-- Mathlib.Logic.Equiv.Basic.coe_subtypeEquivCodomain (L507-L511)
theorem coe_subtypeEquivCodomain (f : { x' // x' ≠ x } → Y) :
    (subtypeEquivCodomain f : _ → Y) =
      fun g : { g : X → Y // g ∘ (↑) = f } => (g : X → Y) x :=
rfl
```

-- snippet 98
```lean
-- Mathlib.Logic.Equiv.Array.Array (L50-L53)
instance Array.encodable {α} [Encodable α] : Encodable (Array α) :=
Encodable.ofEquiv _ (Equiv.arrayEquivList _)

/-- If `α` is countable, then so is `Array α`. -/
```

-- snippet 99
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivCodomain_symm_apply_eq (L527-L530)
theorem subtypeEquivCodomain_symm_apply_eq (f : { x' // x' ≠ x } → Y) (y : Y) :
    ((subtypeEquivCodomain f).symm y : X → Y) x = y :=
dif_neg (not_not.mpr rfl)
```

-- snippet 100
```lean
-- Mathlib.Logic.Equiv.Array.arrayEquivList (L20-L30)
def arrayEquivList (α : Type*) : Array α ≃ List α where
  toFun := Array.toList
invFun := Array.mk

end Equiv

/- Porting note: removed instances for what would be ported as `Traversable (Array α)` and
`LawfulTraversable (Array α)`. These would

1. be implemented directly in terms of `Array` functionality for efficiency, rather than being the
traversal of some other type transported along an equivalence to `Array α` (as the traversable
```

-- snippet 101
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaNatSucc (L206-L213)
def sigmaNatSucc (f : ℕ → Type u) : (Σ n, f n) ≃ f 0 ⊕ Σ n, f (n + 1) :=
⟨fun x =>
    @Sigma.casesOn ℕ f (fun _ => f 0 ⊕ Σ n, f (n + 1)) x fun n =>
      @Nat.casesOn (fun i => f i → f 0 ⊕ Σ n : ℕ, f (n + 1)) n (fun x : f 0 => Sum.inl x)
        fun (n : ℕ) (x : f n.succ) => Sum.inr ⟨n, x⟩,
    Sum.elim (Sigma.mk 0) (Sigma.map Nat.succ fun _ => id), by rintro ⟨n | n, x⟩ <;> rfl, by
    rintro (x | ⟨n, x⟩) <;> rfl⟩
```

-- snippet 102
```lean
-- Mathlib.Logic.Equiv.Basic.symm_swap (L669-L671)
theorem symm_swap (a b : α) : (swap a b).symm = swap a b :=
rfl
```

-- snippet 103
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaAssocProd (L427-L432)
def sigmaAssocProd {α β : Type*} {γ : α → β → Type*} :
    (ab : α × β) × γ ab.1 ab.2 ≃ (a : α) × (b : β) × γ a b :=
sigmaCongrLeft' (sigmaEquivProd _ _).symm |>.trans <| sigmaAssoc γ

/-- A subtype of a sigma which pins down the base of the sigma is equivalent to
the respective fiber. -/
```

-- snippet 104
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSigmaSubtypeEq_apply (L476-L480)
lemma sigmaSigmaSubtypeEq_apply {α β : Type*} {γ : α → β → Type*} {a : α} {b : β}
    (s : {s : (a : α) × (b : β) × γ a b // s.1 = a ∧ s.2.1 = b}) :
    sigmaSigmaSubtypeEq a b s = cast (congrArg₂ γ s.2.1 s.2.2) s.1.2.2 := by
simp [sigmaSigmaSubtypeEq]
```

-- snippet 105
```lean
-- Mathlib.Logic.Equiv.Basic.natEquivNatSumPUnit (L221-L227)
def natEquivNatSumPUnit : ℕ ≃ ℕ ⊕ PUnit where
  toFun n := Nat.casesOn n (inr PUnit.unit) inl
invFun := Sum.elim Nat.succ fun _ => 0
  left_inv n := by cases n <;> rfl
  right_inv := by rintro (_ | _) <;> rfl

/-- `ℕ ⊕ PUnit` is equivalent to `ℕ`. -/
```

<s>[SYSTEM_PROMPT]You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Logic.Equiv.PartialEquiv).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]Prove the following theorem. The retrieved context below may help.

```lean
theorem refl_coe : (PartialEquiv.refl α : α → α) = id
```

## Retrieved context
-- snippet 1
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.Simps (L161-L165)
def Simps.symm_apply (e : PartialEquiv α β) : β → α :=
e.symm

initialize_simps_projections PartialEquiv (toFun → apply, invFun → symm_apply)
```

-- snippet 2
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.coe_mk (L166-L168)
theorem coe_mk (f : α → β) (g s t ml mr il ir) :
    (PartialEquiv.mk f g s t ml mr il ir : α → β) = f := rfl
```

-- snippet 3
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.coe_symm_mk (L170-L173)
theorem coe_symm_mk (f : α → β) (g s t ml mr il ir) :
    ((PartialEquiv.mk f g s t ml mr il ir).symm : β → α) = g :=
rfl
```

-- snippet 4
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.invFun_as_coe (L175-L177)
theorem invFun_as_coe : e.invFun = e.symm :=
rfl
```

-- snippet 5
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.map_source (L179-L182)
theorem map_source {x : α} (h : x ∈ e.source) : e x ∈ e.target :=
e.map_source' h

/-- Variant of `e.map_source` and `map_source'`, stated for images of subsets of `source`. -/
```

-- snippet 6
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.map_source'' (L183-L185)
lemma map_source'' : e '' e.source ⊆ e.target :=
fun _ ⟨_, hx, hex⟩ ↦ mem_of_eq_of_mem (id hex.symm) (e.map_source' hx)
```

-- snippet 7
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.map_target (L187-L189)
theorem map_target {x : β} (h : x ∈ e.target) : e.symm x ∈ e.source :=
e.map_target' h
```

-- snippet 8
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.left_inv (L191-L193)
theorem left_inv {x : α} (h : x ∈ e.source) : e.symm (e x) = x :=
e.left_inv' h
```

-- snippet 9
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.right_inv (L195-L197)
theorem right_inv {x : β} (h : x ∈ e.target) : e (e.symm x) = x :=
e.right_inv' h
```

-- snippet 10
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.target_subset_range (L198-L200)
theorem target_subset_range : e.target ⊆ range e :=
fun x hx ↦ ⟨e.symm x, right_inv e hx⟩
```

-- snippet 11
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.eq_symm_apply (L201-L206)
theorem eq_symm_apply {x : α} {y : β} (hx : x ∈ e.source) (hy : y ∈ e.target) :
    x = e.symm y ↔ e x = y :=
⟨fun h => by rw [← e.right_inv hy, h], fun h => by rw [← e.left_inv hx, h]⟩

protected theorem mapsTo : MapsTo e e.source e.target := fun _ => e.map_source
```

-- snippet 12
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.symm_mapsTo (L207-L227)
theorem symm_mapsTo : MapsTo e.symm e.target e.source :=
e.symm.mapsTo

protected theorem leftInvOn : LeftInvOn e.symm e e.source := fun _ => e.left_inv

protected theorem rightInvOn : RightInvOn e.symm e e.target := fun _ => e.right_inv

protected theorem invOn : InvOn e.symm e e.source e.target :=
  ⟨e.leftInvOn, e.rightInvOn⟩

protected theorem injOn : InjOn e e.source :=
  e.leftInvOn.injOn

protected theorem bijOn : BijOn e e.source e.target :=
  e.invOn.bijOn e.mapsTo e.symm_mapsTo

protected theorem surjOn : SurjOn e e.source e.target :=
  e.bijOn.surjOn

/-- Interpret an `Equiv` as a `PartialEquiv` by restricting it to `s` in the domain
and to `t` in the codomain. -/
```

-- snippet 13
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.inhabitedOfEmpty (L248-L251)
instance inhabitedOfEmpty [IsEmpty α] [IsEmpty β] : Inhabited (PartialEquiv α β) :=
⟨((Equiv.equivEmpty α).trans (Equiv.equivEmpty β).symm).toPartialEquiv⟩

/-- Create a copy of a `PartialEquiv` providing better definitional equalities. -/
```

-- snippet 14
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.copy (L253-L264)
def copy (e : PartialEquiv α β) (f : α → β) (hf : ⇑e = f) (g : β → α) (hg : ⇑e.symm = g) (s : Set α)
    (hs : e.source = s) (t : Set β) (ht : e.target = t) :
    PartialEquiv α β where
  toFun := f
invFun := g
  source := s
  target := t
  map_source' _ := ht ▸ hs ▸ hf ▸ e.map_source
  map_target' _ := hs ▸ ht ▸ hg ▸ e.map_target
  left_inv' _ := hs ▸ hf ▸ hg ▸ e.left_inv
  right_inv' _ := ht ▸ hf ▸ hg ▸ e.right_inv
```

-- snippet 15
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.copy_eq (L265-L278)
theorem copy_eq (e : PartialEquiv α β) (f : α → β) (hf : ⇑e = f) (g : β → α) (hg : ⇑e.symm = g)
    (s : Set α) (hs : e.source = s) (t : Set β) (ht : e.target = t) :
    e.copy f hf g hg s hs t ht = e := by
substs f g s t
  cases e
  rfl

/-- Associate to a `PartialEquiv` an `Equiv` between the source and the target. -/
protected def toEquiv : e.source ≃ e.target where
  toFun x := ⟨e x, e.map_source x.mem⟩
  invFun y := ⟨e.symm y, e.map_target y.mem⟩
  left_inv := fun ⟨_, hx⟩ => Subtype.ext <| e.left_inv hx
  right_inv := fun ⟨_, hy⟩ => Subtype.ext <| e.right_inv hy
```

-- snippet 16
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.symm_source (L280-L282)
theorem symm_source : e.symm.source = e.target :=
rfl
```

-- snippet 17
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.symm_target (L284-L286)
theorem symm_target : e.symm.target = e.source :=
rfl
```

-- snippet 18
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.symm_symm (L288-L289)
theorem symm_symm : e.symm.symm = e := rfl
```

-- snippet 19
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.symm_bijective (L290-L293)
theorem symm_bijective :
    Function.Bijective (PartialEquiv.symm : PartialEquiv α β → PartialEquiv β α) :=
Function.bijective_iff_has_inverse.mpr ⟨_, symm_symm, symm_symm⟩
```

-- snippet 20
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.image_source_eq_target (L294-L296)
theorem image_source_eq_target : e '' e.source = e.target :=
e.bijOn.image_eq
```

-- snippet 21
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.forall_mem_target (L297-L299)
theorem forall_mem_target {p : β → Prop} : (∀ y ∈ e.target, p y) ↔ ∀ x ∈ e.source, p (e x) := by
rw [← image_source_eq_target, forall_mem_image]
```

-- snippet 22
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.exists_mem_target (L300-L309)
theorem exists_mem_target {p : β → Prop} : (∃ y ∈ e.target, p y) ↔ ∃ x ∈ e.source, p (e x) := by
rw [← image_source_eq_target, exists_mem_image]

/-- We say that `t : Set β` is an image of `s : Set α` under a partial equivalence if
any of the following equivalent conditions hold:

* `e '' (e.source ∩ s) = e.target ∩ t`;
* `e.source ∩ e ⁻¹ t = e.source ∩ s`;
* `∀ x ∈ e.source, e x ∈ t ↔ x ∈ s` (this one is used in the definition).
-/
```

-- snippet 23
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.IsImage (L310-L316)
def IsImage (s : Set α) (t : Set β) : Prop :=
∀ ⦃x⦄, x ∈ e.source → (e x ∈ t ↔ x ∈ s)

namespace IsImage

variable {e} {s : Set α} {t : Set β} {x : α}
```

-- snippet 24
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.apply_mem_iff (L317-L319)
theorem apply_mem_iff (h : e.IsImage s t) (hx : x ∈ e.source) : e x ∈ t ↔ x ∈ s :=
h hx
```

-- snippet 25
```lean
-- Mathlib.Logic.Equiv.PartialEquiv.symm_apply_mem_iff (L320-L325)
theorem symm_apply_mem_iff (h : e.IsImage s t) : ∀ ⦃y⦄, y ∈ e.target → (e.symm y ∈ s ↔ y ∈ t) :=
e.forall_mem_target.mpr fun x hx => by rw [e.left_inv hx, h hx]

protected theorem symm (h : e.IsImage s t) : e.symm.IsImage t s :=
  h.symm_apply_mem_iff
```

-- snippet 26
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSigmaSubtype (L448-L457)
def sigmaSigmaSubtype {α : Type*} {β : α → Type*} {γ : (a : α) → β a → Type*}
    (p : (a : α) × β a → Prop) [uniq : Unique {ab // p ab}] {a : α} {b : β a} (h : p ⟨a, b⟩) :
    {s : (a : α) × (b : β a) × γ a b // p ⟨s.1, s.2.1⟩} ≃ γ a b :=
calc {s : (a : α) × (b : β a) × γ a b // p ⟨s.1, s.2.1⟩}
  _ ≃ _ := subtypeEquiv (p := fun ⟨a, b, c⟩ ↦ p ⟨a, b⟩) (q := (p ·.1))
    (sigmaAssoc γ).symm fun s ↦ by simp [sigmaAssoc]
  _ ≃ _ := subtypeSigmaEquiv _ _
  _ ≃ _ := uniqueSigma (fun ab ↦ γ (Sigma.fst <| Subtype.val ab) (Sigma.snd <| Subtype.val ab))
  _ ≃ γ a b := Equiv.cast <| by rw [← show ⟨⟨a, b⟩, h⟩ = uniq.default from uniq.uniq _]
```

-- snippet 27
```lean
-- Mathlib.Logic.Equiv.Basic.swap_comm (L642-L644)
theorem swap_comm (a b : α) : swap a b = swap b a :=
ext fun r => swapCore_comm r _ _
```

-- snippet 28
```lean
-- Mathlib.Logic.Equiv.Basic.swap_comp_apply (L676-L680)
theorem swap_comp_apply {a b x : α} (π : Perm α) :
    π.trans (swap a b) x = if π x = a then b else if π x = b then a else π x := by
cases π
  rfl
```

-- snippet 29
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeSubtypeEquivSubtype (L340-L345)
def subtypeSubtypeEquivSubtype {α} {p q : α → Prop} (h : ∀ {x}, q x → p x) :
    { x : Subtype p // q x.1 } ≃ Subtype q :=
(subtypeSubtypeEquivSubtypeInter p _).trans <| subtypeEquivRight fun _ => and_iff_right_of_imp h

/-- If a proposition holds for all elements, then the subtype is
equivalent to the original type. -/
```

-- snippet 30
```lean
-- Mathlib.Logic.Equiv.Basic.subtypePreimage_symm_apply_coe_pos (L128-L131)
theorem subtypePreimage_symm_apply_coe_pos (x : { a // ¬p a } → β) (a : α) (h : p a) :
    ((subtypePreimage p x₀).symm x : α → β) a = x₀ ⟨a, h⟩ :=
dif_pos h
```

-- snippet 31
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivProp (L316-L320)
def subtypeEquivProp {p q : α → Prop} (h : p = q) : Subtype p ≃ Subtype q :=
subtypeEquiv (Equiv.refl α) fun _ => h ▸ Iff.rfl

/-- A subtype of a subtype is equivalent to the subtype of elements satisfying both predicates. This
version allows the “inner” predicate to depend on `h : p a`. -/
```

-- snippet 32
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquiv_symm (L281-L284)
theorem subtypeEquiv_symm {p : α → Prop} {q : β → Prop} (e : α ≃ β) (h : ∀ a : α, p a ↔ q (e a)) :
    (e.subtypeEquiv h).symm = e.symm.subtypeEquiv (by as_aux_lemma => grind) :=
rfl
```

-- snippet 33
```lean
-- Mathlib.Logic.Equiv.Basic.piCongrRight_refl (L148-L152)
lemma piCongrRight_refl {β : α → Sort*} : piCongrRight (fun a ↦ .refl (β a)) = .refl (∀ a, β a) :=
rfl

/-- Given `φ : α → β → Sort*`, we have an equivalence between `∀ a b, φ a b` and `∀ b a, φ a b`.
This is `Function.swap` as an `Equiv`. -/
```

-- snippet 34
```lean
-- Mathlib.Logic.Equiv.Basic.eq_or_eq_of_swap_apply_ne_self (L660-L663)
theorem eq_or_eq_of_swap_apply_ne_self {a b x : α} (h : swap a b x ≠ x) : x = a ∨ x = b := by
contrapose! h
  exact swap_apply_of_ne_of_ne h.1 h.2
```

-- snippet 35
```lean
-- Mathlib.Logic.Equiv.Basic.ofFiberEquiv_map (L195-L200)
theorem ofFiberEquiv_map {α β γ} {f : α → γ} {g : β → γ}
    (e : ∀ c, { a // f a = c } ≃ { b // g b = c }) (a : α) : g (ofFiberEquiv e a) = f a :=
(_ : { b // g b = _ }).property

end prodCongr
```

-- snippet 36
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeSigmaEquiv (L351-L357)
def subtypeSigmaEquiv {α} (p : α → Type v) (q : α → Prop) : { y : Sigma p // q y.1 } ≃ Σ x :
    Subtype q, p x.1 :=
⟨fun x => ⟨⟨x.1.1, x.2⟩, x.1.2⟩, fun x => ⟨⟨x.1.1, x.2⟩, x.1.2⟩, fun _ => rfl,
    fun _ => rfl⟩

/-- A sigma type over a subtype is equivalent to the sigma set over the original type,
if the fiber is empty outside of the subset -/
```

-- snippet 37
```lean
-- Mathlib.Logic.Equiv.Basic.swap_self (L639-L641)
theorem swap_self (a : α) : swap a a = Equiv.refl _ :=
ext fun r => swapCore_self r a
```

-- snippet 38
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSigmaSubtypeEq_symm_apply (L482-L485)
lemma sigmaSigmaSubtypeEq_symm_apply {α β : Type*} {γ : α → β → Type*} {a : α} {b : β} (c : γ a b) :
    (sigmaSigmaSubtypeEq a b).symm c = ⟨⟨a, ⟨b, c⟩⟩, ⟨rfl, rfl⟩⟩ := by
simp [sigmaSigmaSubtypeEq]
```

-- snippet 39
```lean
-- Mathlib.Logic.Equiv.Basic.swap_eq_refl_iff (L673-L675)
theorem swap_eq_refl_iff {x y : α} : swap x y = Equiv.refl _ ↔ x = y :=
⟨fun h => (Equiv.refl _).injective (by grind), by grind⟩
```

-- snippet 40
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquiv (L262-L268)
def subtypeEquiv {p : α → Prop} {q : β → Prop} (e : α ≃ β) (h : ∀ a, p a ↔ q (e a)) :
    { a : α // p a } ≃ { b : β // q b } where
  toFun a := ⟨e a, (h _).mp a.property⟩
invFun b := ⟨e.symm b, (h _).mpr ((e.apply_symm_apply b).symm ▸ b.property)⟩
  left_inv a := Subtype.ext <| by simp
  right_inv b := Subtype.ext <| by simp
```

-- snippet 41
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeCongr (L54-L62)
def subtypeCongr {α} {p q : α → Prop} [DecidablePred p] [DecidablePred q]
    (e : { x // p x } ≃ { x // q x }) (f : { x // ¬p x } ≃ { x // ¬q x }) : Perm α :=
(sumCompl p).symm.trans ((sumCongr e f).trans (sumCompl q))

variable {ε : Type*} {p : ε → Prop} [DecidablePred p]
variable (ep ep' : Perm { a // p a }) (en en' : Perm { a // ¬p a })

/-- Combining permutations on `ε` that permute only inside or outside the subtype
split induced by `p : ε → Prop` constructs a permutation on `ε`. -/
```

-- snippet 42
```lean
-- Mathlib.Logic.Equiv.Basic.swap_apply_right (L654-L656)
theorem swap_apply_right (a b : α) : swap a b b = a := by
grind
```

-- snippet 43
```lean
-- Mathlib.Logic.Equiv.Basic.symm_trans_swap_trans (L689-L692)
theorem symm_trans_swap_trans [DecidableEq β] (a b : α) (e : α ≃ β) :
    (e.symm.trans (swap a b)).trans e = swap (e a) (e b) := by
grind
```

-- snippet 44
```lean
-- Mathlib.Logic.Equiv.Basic.subtypePreimage (L112-L127)
def subtypePreimage : { x : α → β // x ∘ Subtype.val = x₀ } ≃ ({ a // ¬p a } → β) where
  toFun (x : { x : α → β // x ∘ Subtype.val = x₀ }) a := (x : α → β) a
invFun x := ⟨fun a => if h : p a then x₀ ⟨a, h⟩ else x ⟨a, h⟩, funext fun ⟨_, h⟩ => dif_pos h⟩
  left_inv := fun ⟨x, hx⟩ =>
    Subtype.val_injective <|
      funext fun a => by
        dsimp only
        split_ifs
        · rw [← hx]; rfl
        · rfl
  right_inv x :=
    funext fun ⟨a, h⟩ =>
      show dite (p a) _ _ = _ by
        dsimp only
        rw [dif_neg h]
```

-- snippet 45
```lean
-- Mathlib.Logic.Equiv.Basic.subtypePreimage_symm_apply_coe_neg (L132-L137)
theorem subtypePreimage_symm_apply_coe_neg (x : { a // ¬p a } → β) (a : α) (h : ¬p a) :
    ((subtypePreimage p x₀).symm x : α → β) a = x ⟨a, h⟩ :=
dif_neg h

end subtypePreimage
```

-- snippet 46
```lean
-- Mathlib.Logic.Equiv.Basic.piComm (L154-L156)
def piComm (φ : α → β → Sort*) : (∀ a b, φ a b) ≃ ∀ b a, φ a b :=
⟨swap, swap, fun _ => rfl, fun _ => rfl⟩
```

-- snippet 47
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivRight (L295-L297)
def subtypeEquivRight {p q : α → Prop} (e : ∀ x, p x ↔ q x) : { x // p x } ≃ { x // q x } :=
subtypeEquiv (Equiv.refl _) e
```

-- snippet 48
```lean
-- Mathlib.Logic.Equiv.Basic.natSumPUnitEquivNat (L228-L231)
def natSumPUnitEquivNat : ℕ ⊕ PUnit ≃ ℕ :=
natEquivNatSumPUnit.symm

/-- The type of integer numbers is equivalent to `ℕ ⊕ ℕ`. -/
```

-- snippet 49
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivRight_apply (L298-L300)
lemma subtypeEquivRight_apply {p q : α → Prop} (e : ∀ x, p x ↔ q x)
    (z : { x // p x }) : subtypeEquivRight e z = ⟨z, (e z.1).mp z.2⟩ := rfl
```

-- snippet 50
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSubtypeEquivOfSubset (L358-L363)
def sigmaSubtypeEquivOfSubset {α} (p : α → Type v) (q : α → Prop) (h : ∀ x, p x → q x) :
    (Σ x : Subtype q, p x) ≃ Σ x : α, p x :=
(subtypeSigmaEquiv p q).symm.trans <| subtypeUnivEquiv fun x => h x.1 x.2

/-- If a predicate `p : β → Prop` is true on the range of a map `f : α → β`, then
`Σ y : {y // p y}, {x // f x = y}` is equivalent to `α`. -/
```

-- snippet 51
```lean
-- Mathlib.Logic.Equiv.Basic.coe_subtypeEquiv_eq_map (L269-L272)
lemma coe_subtypeEquiv_eq_map {X Y} {p : X → Prop} {q : Y → Prop} (e : X ≃ Y)
    (h : ∀ x, p x ↔ q (e x)) : ⇑(e.subtypeEquiv h) = Subtype.map e (h · |>.mp) :=
rfl
```

-- snippet 52
```lean
-- Mathlib.Logic.Equiv.Basic.comp_swap_eq_update (L684-L687)
theorem comp_swap_eq_update (i j : α) (f : α → β) :
    f ∘ Equiv.swap i j = update (update f j (f i)) i (f j) := by
grind
```

-- snippet 53
```lean
-- Mathlib.Logic.Equiv.Basic.swap_eq_update (L681-L683)
theorem swap_eq_update (i j : α) : (Equiv.swap i j : α → α) = update (update id j i) i j := by
grind
```

-- snippet 54
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeQuotientEquivQuotientSubtype_mk (L601-L606)
theorem subtypeQuotientEquivQuotientSubtype_mk (p₁ : α → Prop)
    [s₁ : Setoid α] [s₂ : Setoid (Subtype p₁)] (p₂ : Quotient s₁ → Prop) (hp₂ : ∀ a, p₁ a ↔ p₂ ⟦a⟧)
    (h : ∀ x y : Subtype p₁, s₂ x y ↔ (x : α) ≈ y)
    (x hx) : subtypeQuotientEquivQuotientSubtype p₁ p₂ hp₂ h ⟨⟦x⟧, hx⟩ = ⟦⟨x, (hp₂ _).2 hx⟩⟧ :=
rfl
```

-- snippet 55
```lean
-- Mathlib.Logic.Equiv.Basic.piCongrRight (L143-L146)
def piCongrRight {β₁ β₂ : α → Sort*} (F : ∀ a, β₁ a ≃ β₂ a) : (∀ a, β₁ a) ≃ (∀ a, β₂ a) :=
⟨Pi.map fun a ↦ F a, Pi.map fun a ↦ (F a).symm, fun H => funext <| by simp,
    fun H => funext <| by simp⟩
```

-- snippet 56
```lean
-- Mathlib.Logic.Equiv.Basic.piEquivSubtypeSigma (L402-L411)
def piEquivSubtypeSigma (ι) (π : ι → Type*) :
    (∀ i, π i) ≃ { f : ι → Σ i, π i // ∀ i, (f i).1 = i } where
  toFun := fun f => ⟨fun i => ⟨i, f i⟩, fun _ => rfl⟩
invFun := fun f i => by rw [← f.2 i]; exact (f.1 i).2
  right_inv := fun ⟨f, hf⟩ =>
    Subtype.ext <| funext fun i =>
      Sigma.eq (hf i).symm <| eq_of_heq <| rec_heq_of_heq _ <| by simp

/-- The type of functions `f : ∀ a, β a` such that for all `a` we have `p a (f a)` is equivalent
to the type of functions `∀ a, {b : β a // p a b}`. -/
```

-- snippet 57
```lean
-- Mathlib.Logic.Equiv.Basic.swapCore_self (L622-L625)
theorem swapCore_self (r a : α) : swapCore a a r = r := by
unfold swapCore
  split_ifs <;> simp [*]
```

-- snippet 58
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSubtypeFiberEquivSubtype (L372-L387)
def sigmaSubtypeFiberEquivSubtype {α β : Type*} (f : α → β) {p : α → Prop} {q : β → Prop}
    (h : ∀ x, p x ↔ q (f x)) : (Σ y : Subtype q, { x : α // f x = y }) ≃ Subtype p :=
calc
    (Σ y : Subtype q, { x : α // f x = y }) ≃ Σ y :
        Subtype q, { x : Subtype p // Subtype.mk (f x) ((h x).1 x.2) = y } := by {
          apply sigmaCongrRight
          intro y
          apply Equiv.symm
          refine (subtypeSubtypeEquivSubtypeExists _ _).trans (subtypeEquivRight ?_)
          intro x
          exact ⟨fun ⟨hp, h'⟩ => congr_arg Subtype.val h', fun h' => ⟨(h x).2 (h'.symm ▸ y.2),
            Subtype.ext h'⟩⟩ }
    _ ≃ Subtype p := sigmaFiberEquiv fun x : Subtype p => (⟨f x, (h x).1 x.property⟩ : Subtype q)

/-- A sigma type over an `Option` is equivalent to the sigma set over the original type,
if the fiber is empty at none. -/
```

-- snippet 59
```lean
-- Mathlib.Logic.Equiv.Basic.swap_apply_def (L646-L648)
theorem swap_apply_def (a b x : α) : swap a b x = if x = a then b else if x = b then a else x :=
rfl
```

-- snippet 60
```lean
-- Mathlib.Logic.Equiv.Basic.piCurry (L165-L172)
def piCurry {α} {β : α → Type*} (γ : ∀ a, β a → Type*) :
    (∀ x : Σ i, β i, γ x.1 x.2) ≃ ∀ a b, γ a b where
  toFun := Sigma.curry
invFun := Sigma.uncurry
  left_inv := Sigma.uncurry_curry
  right_inv := Sigma.curry_uncurry

-- `simps` overapplies these but `simps -fullyApplied` under-applies them
```

-- snippet 61
```lean
-- Mathlib.Logic.Equiv.Basic.swap_apply_left (L650-L652)
theorem swap_apply_left (a b : α) : swap a b a = b :=
if_pos rfl
```

-- snippet 62
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeQuotientEquivQuotientSubtype_symm_mk (L608-L618)
theorem subtypeQuotientEquivQuotientSubtype_symm_mk (p₁ : α → Prop)
    [s₁ : Setoid α] [s₂ : Setoid (Subtype p₁)] (p₂ : Quotient s₁ → Prop) (hp₂ : ∀ a, p₁ a ↔ p₂ ⟦a⟧)
    (h : ∀ x y : Subtype p₁, s₂ x y ↔ (x : α) ≈ y) (x) :
    (subtypeQuotientEquivQuotientSubtype p₁ p₂ hp₂ h).symm ⟦x⟧ = ⟨⟦x⟧, (hp₂ _).1 x.property⟩ :=
rfl

section Swap

variable [DecidableEq α]

/-- A helper function for `Equiv.swap`. -/
```

-- snippet 63
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivCodomain_apply (L513-L516)
theorem subtypeEquivCodomain_apply (f : { x' // x' ≠ x } → Y) (g) :
    subtypeEquivCodomain f g = (g : X → Y) x :=
rfl
```

-- snippet 64
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeUnivEquiv (L347-L350)
def subtypeUnivEquiv {α} {p : α → Prop} (h : ∀ x, p x) : Subtype p ≃ α :=
⟨fun x => x, fun x => ⟨x, h x⟩, fun _ => Subtype.ext rfl, fun _ => rfl⟩

/-- A subtype of a sigma-type is a sigma-type over a subtype. -/
```

-- snippet 65
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivCodomain (L496-L505)
def subtypeEquivCodomain (f : { x' // x' ≠ x } → Y) :
    { g : X → Y // g ∘ (↑) = f } ≃ Y :=
(subtypePreimage _ f).trans <|
    @funUnique { x' // ¬x' ≠ x } _ <|
      show Unique { x' // ¬x' ≠ x } from
        @Equiv.unique _ _
          (show Unique { x' // x' = x } from {
            default := ⟨x, rfl⟩, uniq := fun ⟨_, h⟩ => Subtype.val_injective h })
          (subtypeEquivRight fun _ => not_not)
```

-- snippet 66
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeQuotientEquivQuotientSubtype (L583-L599)
def subtypeQuotientEquivQuotientSubtype (p₁ : α → Prop) {s₁ : Setoid α} {s₂ : Setoid (Subtype p₁)}
    (p₂ : Quotient s₁ → Prop) (hp₂ : ∀ a, p₁ a ↔ p₂ ⟦a⟧)
    (h : ∀ x y : Subtype p₁, s₂.r x y ↔ s₁.r x y) : {x // p₂ x} ≃ Quotient s₂ where
  toFun a :=
Quotient.hrecOn a.1 (fun a h => ⟦⟨a, (hp₂ _).2 h⟩⟧)
      (fun a b hab => hfunext (by rw [Quotient.sound hab]) fun _ _ _ =>
        heq_of_eq (Quotient.sound ((h _ _).2 hab)))
      a.2
  invFun a :=
    Quotient.liftOn a (fun a => (⟨⟦a.1⟧, (hp₂ _).1 a.2⟩ : { x // p₂ x })) fun _ _ hab =>
      Subtype.ext (Quotient.sound ((h _ _).1 hab))
  left_inv a := by
    obtain ⟨a, ha⟩ := a
    induction a using Quotient.inductionOn
    rfl
  right_inv a := by induction a using Quotient.inductionOn; rfl
```

-- snippet 67
```lean
-- Mathlib.Logic.Equiv.Basic.coe_subtypeEquivCodomain_symm (L517-L521)
theorem coe_subtypeEquivCodomain_symm (f : { x' // x' ≠ x } → Y) :
    ((subtypeEquivCodomain f).symm : Y → _) = fun y =>
      ⟨fun x' => if h : x' ≠ x then f ⟨x', h⟩ else y, by grind⟩ :=
rfl
```

-- snippet 68
```lean
-- Mathlib.Logic.Equiv.Basic.swapCore_swapCore (L626-L628)
theorem swapCore_swapCore (r a b : α) : swapCore a b (swapCore a b r) = r := by
unfold swapCore; split_ifs <;> grind
```

-- snippet 69
```lean
-- Mathlib.Logic.Equiv.Array.for (L31-L49)
instance for `array` was)

2. belong in `Mathlib/Control/Traversable/Instances.lean` instead of this file. -/

-- namespace Array'

-- open Function

-- variable {n : ℕ}
-- instance : Traversable (Array' n) :=
--   @Equiv.traversable (flip Vector n) _ (fun α => Equiv.vectorEquivArray α n) _

-- instance : LawfulTraversable (Array' n) :=
--   @Equiv.isLawfulTraversable (flip Vector n) _ (fun α => Equiv.vectorEquivArray α n) _ _

-- end Array'

/-- If `α` is encodable, then so is `Array α`. -/
```

-- snippet 70
```lean
-- Mathlib.Logic.Equiv.Basic.swap (L634-L637)
def swap (a b : α) : Perm α :=
⟨swapCore a b, swapCore a b, fun r => swapCore_swapCore r a b,
    fun r => swapCore_swapCore r a b⟩
```

-- snippet 71
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquiv_trans (L286-L293)
theorem subtypeEquiv_trans {p : α → Prop} {q : β → Prop} {r : γ → Prop} (e : α ≃ β) (f : β ≃ γ)
    (h : ∀ a : α, p a ↔ q (e a)) (h' : ∀ b : β, q b ↔ r (f b)) :
    (e.subtypeEquiv h).trans (f.subtypeEquiv h')
    = (e.trans f).subtypeEquiv (by as_aux_lemma => exact fun a => (h a).trans (h' <| e a)) :=
rfl

/-- If two predicates `p` and `q` are pointwise equivalent, then `{x // p x}` is equivalent to
`{x // q x}`. -/
```

-- snippet 72
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeSubtypeEquivSubtypeExists (L322-L330)
def subtypeSubtypeEquivSubtypeExists (p : α → Prop) (q : Subtype p → Prop) :
    Subtype q ≃ { a : α // ∃ h : p a, q ⟨a, h⟩ } :=
⟨fun a =>
    ⟨a.1, a.1.2, by
      rcases a with ⟨⟨a, hap⟩, haq⟩
      exact haq⟩,
    fun a => ⟨⟨a, a.2.fst⟩, a.2.snd⟩, fun ⟨⟨_, _⟩, _⟩ => rfl, fun ⟨_, _, _⟩ => rfl⟩

/-- A subtype of a subtype is equivalent to the subtype of elements satisfying both predicates. -/
```

-- snippet 73
```lean
-- Mathlib.Logic.Equiv.Basic.subtypePiEquivPi (L412-L425)
def subtypePiEquivPi {β : α → Sort v} {p : ∀ a, β a → Prop} :
    { f : ∀ a, β a // ∀ a, p a (f a) } ≃ ∀ a, { b : β a // p a b } where
  toFun := fun f a => ⟨f.1 a, f.2 a⟩
invFun := fun f => ⟨fun a => (f a).1, fun a => (f a).2⟩
  left_inv := by
    rintro ⟨f, h⟩
    rfl
  right_inv := by
    rintro f
    funext a
    exact Subtype.ext rfl

/-- A sigma of a sigma whose second base does not depend on the first is equivalent
to a sigma whose base is a product. -/
```

-- snippet 74
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSubtype (L434-L441)
def sigmaSubtype {α : Type*} {β : α → Type*} (a : α) :
    {s : Sigma β // s.1 = a} ≃ β a where
  toFun := fun ⟨⟨_, b⟩, h⟩ => h ▸ b
invFun b := ⟨⟨a, b⟩, rfl⟩
  left_inv := fun ⟨a, h⟩ ↦ by cases h; simp
  right_inv b := by simp
```

-- snippet 75
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivRight_symm_apply (L301-L305)
lemma subtypeEquivRight_symm_apply {p q : α → Prop} (e : ∀ x, p x ↔ q x)
    (z : { x // q x }) : (subtypeEquivRight e).symm z = ⟨z, (e z.1).mpr z.2⟩ := rfl
/-- If `α ≃ β`, then for any predicate `p : β → Prop` the subtype `{a // p (e a)}` is equivalent
to the subtype `{b // p b}`. -/
```

-- snippet 76
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivCodomain_symm_apply (L523-L526)
theorem subtypeEquivCodomain_symm_apply (f : { x' // x' ≠ x } → Y) (y : Y) (x' : X) :
    ((subtypeEquivCodomain f).symm y : X → Y) x' = if h : x' ≠ x then f ⟨x', h⟩ else y :=
rfl
```

-- snippet 77
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivCodomain_symm_apply_ne (L531-L537)
theorem subtypeEquivCodomain_symm_apply_ne
    (f : { x' // x' ≠ x } → Y) (y : Y) (x' : X) (h : x' ≠ x) :
    ((subtypeEquivCodomain f).symm y : X → Y) x' = f ⟨x', h⟩ :=
dif_pos h

end subtypeEquivCodomain
```

-- snippet 78
```lean
-- Mathlib.Logic.Equiv.Basic.uniqueCongr (L241-L247)
def uniqueCongr (e : α ≃ β) : Unique α ≃ Unique β where
  toFun h := @Equiv.unique _ _ h e.symm
invFun h := @Equiv.unique _ _ h e
  left_inv _ := Subsingleton.elim _ _
  right_inv _ := Subsingleton.elim _ _

/-- If `α` is equivalent to `β`, then `IsEmpty α` is equivalent to `IsEmpty β`. -/
```

-- snippet 79
```lean
-- Mathlib.Logic.Equiv.Basic.swapCore (L619-L621)
def swapCore (a b r : α) : α :=
if r = a then b else if r = b then a else r
```

-- snippet 80
```lean
-- Mathlib.Logic.Equiv.Basic.piComm_symm (L158-L164)
theorem piComm_symm {φ : α → β → Sort*} : (piComm φ).symm = (piComm <| swap φ) :=
rfl

/-- Dependent `curry` equivalence: the type of dependent functions on `Σ i, β i` is equivalent
to the type of dependent functions of two arguments (i.e., functions to the space of functions).

This is `Sigma.curry` and `Sigma.uncurry` together as an equiv. -/
```

-- snippet 81
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeSubtypeEquivSubtypeInter (L332-L338)
def subtypeSubtypeEquivSubtypeInter {α : Type u} (p q : α → Prop) :
    { x : Subtype p // q x.1 } ≃ Subtype fun x => p x ∧ q x :=
(subtypeSubtypeEquivSubtypeExists p _).trans <|
    subtypeEquivRight fun x => @exists_prop (q x) (p x)

/-- If the outer subtype has more restrictive predicate than the inner one,
then we can drop the latter. -/
```

-- snippet 82
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSubtypeFiberEquiv (L364-L371)
def sigmaSubtypeFiberEquiv {α β : Type*} (f : α → β) (p : β → Prop) (h : ∀ x, p (f x)) :
    (Σ y : Subtype p, { x : α // f x = y }) ≃ α :=
calc
    _ ≃ Σ y : β, { x : α // f x = y } := sigmaSubtypeEquivOfSubset _ p fun _ ⟨x, h'⟩ => h' ▸ h x
    _ ≃ α := sigmaFiberEquiv f

/-- If for each `x` we have `p x ↔ q (f x)`, then `Σ y : {y // q y}, f ⁻¹' {y}` is equivalent
to `{x // p x}`. -/
```

-- snippet 83
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquiv_refl (L274-L279)
theorem subtypeEquiv_refl {p : α → Prop} (h : ∀ a, p a ↔ p (Equiv.refl _ a) := fun _ => Iff.rfl) :
(Equiv.refl α).subtypeEquiv h = Equiv.refl { a : α // p a } := by
  ext
  rfl

-- We use `as_aux_lemma` here to avoid creating large proof terms when using `simp`
```

-- snippet 84
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSigmaSubtype_symm_apply (L459-L467)
lemma sigmaSigmaSubtype_symm_apply {α : Type*} {β : α → Type*} {γ : (a : α) → β a → Type*}
    (p : (a : α) × β a → Prop) [uniq : Unique {ab // p ab}]
    {a : α} {b : β a} (c : γ a b) (h : p ⟨a, b⟩) :
    (sigmaSigmaSubtype p h).symm c = ⟨⟨a, ⟨b, c⟩⟩, h⟩ := by
rw [Equiv.symm_apply_eq]; simp

/-- A specialization of `sigmaSigmaSubtype` to the case where the second base
does not depend on the first, and the property being checked for is simple
equality. Useful e.g. when `γ` is `Hom` inside a category. -/
```

-- snippet 85
```lean
-- Mathlib.Logic.Equiv.Basic.Perm (L63-L65)
def Perm.subtypeCongr : Equiv.Perm ε :=
permCongr (sumCompl p) (sumCongr ep en)
```

-- snippet 86
```lean
-- Mathlib.Logic.Equiv.Basic.intEquivNatSumNat (L232-L237)
def intEquivNatSumNat : ℤ ≃ ℕ ⊕ ℕ where
  toFun z := Int.casesOn z inl inr
invFun := Sum.elim Int.ofNat Int.negSucc
  left_inv := by rintro (m | n) <;> rfl
  right_inv := by rintro (m | n) <;> rfl
```

-- snippet 87
```lean
-- Mathlib.Logic.Equiv.Basic.swap_swap (L665-L667)
theorem swap_swap (a b : α) : (swap a b).trans (swap a b) = Equiv.refl _ :=
ext fun _ => swapCore_swapCore _ _ _
```

-- snippet 88
```lean
-- Mathlib.Logic.Equiv.Basic.swap_apply_of_ne_of_ne (L657-L659)
theorem swap_apply_of_ne_of_ne {a b x : α} : x ≠ a → x ≠ b → swap a b x = x := by
grind
```

-- snippet 89
```lean
-- Mathlib.Logic.Equiv.Basic.ofFiberEquiv (L191-L194)
def ofFiberEquiv {α β γ} {f : α → γ} {g : β → γ}
    (e : ∀ c, { a // f a = c } ≃ { b // g b = c }) : α ≃ β :=
(sigmaFiberEquiv f).symm.trans <| (Equiv.sigmaCongrRight e).trans (sigmaFiberEquiv g)
```

-- snippet 90
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivOfSubtype' (L311-L315)
def subtypeEquivOfSubtype' {p : α → Prop} (e : α ≃ β) :
    { a : α // p a } ≃ { b : β // p (e.symm b) } :=
e.symm.subtypeEquivOfSubtype.symm

/-- If two predicates are equal, then the corresponding subtypes are equivalent. -/
```

-- snippet 91
```lean
-- Mathlib.Logic.Equiv.Basic.swapCore_comm (L629-L633)
theorem swapCore_comm (r a b : α) : swapCore a b r = swapCore b a r := by
unfold swapCore; split_ifs <;> grind

/-- `swap a b` is the permutation that swaps `a` and `b` and
  leaves other values as is. -/
```

-- snippet 92
```lean
-- Mathlib.Logic.Equiv.Basic.isEmpty_congr (L248-L253)
theorem isEmpty_congr (e : α ≃ β) : IsEmpty α ↔ IsEmpty β :=
⟨fun h => @Function.isEmpty _ _ h e.symm, fun h => @Function.isEmpty _ _ h e⟩

protected theorem isEmpty (e : α ≃ β) [IsEmpty β] : IsEmpty α :=
  e.isEmpty_congr.mpr ‹_›
```

-- snippet 93
```lean
-- Mathlib.Logic.Equiv.Basic.piOptionEquivProd (L44-L53)
def piOptionEquivProd {α} {β : Option α → Type*} :
    (∀ a : Option α, β a) ≃ β none × ∀ a : α, β (some a) where
  toFun f := (f none, fun a => f (some a))
invFun x a := Option.casesOn a x.fst x.snd
  left_inv f := funext fun a => by cases a <;> rfl

section subtypeCongr

/-- Combines an `Equiv` between two subtypes with an `Equiv` between their complements to form a
  permutation. -/
```

-- snippet 94
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivOfSubtype (L306-L310)
def subtypeEquivOfSubtype {p : β → Prop} (e : α ≃ β) : { a : α // p (e a) } ≃ { b : β // p b } :=
subtypeEquiv e <| by simp

/-- If `α ≃ β`, then for any predicate `p : α → Prop` the subtype `{a // p a}` is equivalent
to the subtype `{b // p (e.symm b)}`. This version is used by `equiv_rw`. -/
```

-- snippet 95
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaOptionEquivOfSome (L388-L401)
def sigmaOptionEquivOfSome {α} (p : Option α → Type v) (h : p none → False) :
    (Σ x : Option α, p x) ≃ Σ x : α, p (some x) :=
haveI h' : ∀ x, p x → x.isSome := by
    intro x
    cases x
    · intro n
      exfalso
      exact h n
    · intro _
      exact rfl
  (sigmaSubtypeEquivOfSubset _ _ h').symm.trans (sigmaCongrLeft' (optionIsSomeEquiv α))

/-- The `Pi`-type `∀ i, π i` is equivalent to the type of sections `f : ι → Σ i, π i` of the
`Sigma` type such that for all `i` we have `(f i).fst = i`. -/
```

-- snippet 96
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSigmaSubtypeEq (L468-L474)
def sigmaSigmaSubtypeEq {α β : Type*} {γ : α → β → Type*} (a : α) (b : β) :
    {s : (a : α) × (b : β) × γ a b // s.1 = a ∧ s.2.1 = b} ≃ γ a b :=
have : Unique (@Subtype ((_ : α) × β) (fun ⟨a', b'⟩ ↦ a' = a ∧ b' = b)) := {
    default := ⟨⟨a, b⟩, ⟨rfl, rfl⟩⟩
    uniq := by rintro ⟨⟨a', b'⟩, ⟨rfl, rfl⟩⟩; rfl }
  sigmaSigmaSubtype (fun ⟨a', b'⟩ ↦ a' = a ∧ b' = b) ⟨rfl, rfl⟩
```

-- snippet 97
```lean
-- Mathlib.Logic.Equiv.Basic.coe_subtypeEquivCodomain (L507-L511)
theorem coe_subtypeEquivCodomain (f : { x' // x' ≠ x } → Y) :
    (subtypeEquivCodomain f : _ → Y) =
      fun g : { g : X → Y // g ∘ (↑) = f } => (g : X → Y) x :=
rfl
```

-- snippet 98
```lean
-- Mathlib.Logic.Equiv.Array.Array (L50-L53)
instance Array.encodable {α} [Encodable α] : Encodable (Array α) :=
Encodable.ofEquiv _ (Equiv.arrayEquivList _)

/-- If `α` is countable, then so is `Array α`. -/
```

-- snippet 99
```lean
-- Mathlib.Logic.Equiv.Basic.subtypeEquivCodomain_symm_apply_eq (L527-L530)
theorem subtypeEquivCodomain_symm_apply_eq (f : { x' // x' ≠ x } → Y) (y : Y) :
    ((subtypeEquivCodomain f).symm y : X → Y) x = y :=
dif_neg (not_not.mpr rfl)
```

-- snippet 100
```lean
-- Mathlib.Logic.Equiv.Array.arrayEquivList (L20-L30)
def arrayEquivList (α : Type*) : Array α ≃ List α where
  toFun := Array.toList
invFun := Array.mk

end Equiv

/- Porting note: removed instances for what would be ported as `Traversable (Array α)` and
`LawfulTraversable (Array α)`. These would

1. be implemented directly in terms of `Array` functionality for efficiency, rather than being the
traversal of some other type transported along an equivalence to `Array α` (as the traversable
```

-- snippet 101
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaNatSucc (L206-L213)
def sigmaNatSucc (f : ℕ → Type u) : (Σ n, f n) ≃ f 0 ⊕ Σ n, f (n + 1) :=
⟨fun x =>
    @Sigma.casesOn ℕ f (fun _ => f 0 ⊕ Σ n, f (n + 1)) x fun n =>
      @Nat.casesOn (fun i => f i → f 0 ⊕ Σ n : ℕ, f (n + 1)) n (fun x : f 0 => Sum.inl x)
        fun (n : ℕ) (x : f n.succ) => Sum.inr ⟨n, x⟩,
    Sum.elim (Sigma.mk 0) (Sigma.map Nat.succ fun _ => id), by rintro ⟨n | n, x⟩ <;> rfl, by
    rintro (x | ⟨n, x⟩) <;> rfl⟩
```

-- snippet 102
```lean
-- Mathlib.Logic.Equiv.Basic.symm_swap (L669-L671)
theorem symm_swap (a b : α) : (swap a b).symm = swap a b :=
rfl
```

-- snippet 103
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaAssocProd (L427-L432)
def sigmaAssocProd {α β : Type*} {γ : α → β → Type*} :
    (ab : α × β) × γ ab.1 ab.2 ≃ (a : α) × (b : β) × γ a b :=
sigmaCongrLeft' (sigmaEquivProd _ _).symm |>.trans <| sigmaAssoc γ

/-- A subtype of a sigma which pins down the base of the sigma is equivalent to
the respective fiber. -/
```

-- snippet 104
```lean
-- Mathlib.Logic.Equiv.Basic.sigmaSigmaSubtypeEq_apply (L476-L480)
lemma sigmaSigmaSubtypeEq_apply {α β : Type*} {γ : α → β → Type*} {a : α} {b : β}
    (s : {s : (a : α) × (b : β) × γ a b // s.1 = a ∧ s.2.1 = b}) :
    sigmaSigmaSubtypeEq a b s = cast (congrArg₂ γ s.2.1 s.2.2) s.1.2.2 := by
simp [sigmaSigmaSubtypeEq]
```

-- snippet 105
```lean
-- Mathlib.Logic.Equiv.Basic.natEquivNatSumPUnit (L221-L227)
def natEquivNatSumPUnit : ℕ ≃ ℕ ⊕ PUnit where
  toFun n := Nat.casesOn n (inr PUnit.unit) inl
invFun := Sum.elim Nat.succ fun _ => 0
  left_inv n := by cases n <;> rfl
  right_inv := by rintro (_ | _) <;> rfl

/-- `ℕ ⊕ PUnit` is equivalent to `ℕ`. -/
```
[/INST]


[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Condensed.Discrete.Colimit).

[User]
The following Lean code fails to compile. Fix it.

```lean
lemma isoLocallyConstantOfIsColimit_inv (X : LightProfinite.{u}ᵒᵖ ⥤ Type u)
    [PreservesFiniteProducts X] (hX : ∀ S : LightProfinite.{u}, (IsColimit <|
      X.mapCocone (coconeRightOpOfCone S.asLimitCone))) :
    (isoLocallyConstantOfIsColimit X hX).inv =
      (CompHausLike.LocallyConstant.counitApp.{u, u} X)
:= by .someMissingNamespaceXYZ
dsimp [isoLocallyConstantOfIsColimit]
  simp only [Category.assoc]
  rw [Iso.inv_comp_eq]
  ext S : 2
  apply colimit.hom_ext
  intro ⟨Y, _, g⟩
  suffices _ ≫ (isoFinYonedaComponents _ _).inv ≫ X.map g =
    (locallyConstantPresheaf _).map g ≫ counitAppApp (Opposite.unop S) X by
      simpa [locallyConstantIsoFinYoneda, isoFinYoneda, counitApp]
  erw [(counitApp.{u, u} X).naturality]
  simp only [← Category.assoc, op_obj, functorToPresheaves_obj_obj]
  congr
  ext f
  simp only [types_comp_apply, counitApp_app]
  apply presheaf_ext.{u, u} (X := X) (Y := X) (f := f)
  intro x
  rw [incl_of_counitAppApp]
  simp only [counitAppAppImage]
  have : Finite (fiber.{u, u} f x) :=
    Finite.of_injective (sigmaIncl.{u, u} f x).1 Subtype.val_injective
  apply injective_of_mono (isoFinYonedaComponents X (fiber.{u, u} f x)).hom
  ext y
  simp only [isoFinYonedaComponents_hom_apply, ← FunctorToTypes.map_comp_apply, ← op_comp]
  rw [show (LightProfinite.of PUnit.{u + 1}).const y ≫ IsTerminal.from _ (fiber f x) = 𝟙 _ from rfl]
  simp only [op_comp, FunctorToTypes.map_comp_apply, op_id, FunctorToTypes.map_id_apply]
  rw [← isoFinYonedaComponents_inv_comp X _ (sigmaIncl.{u, u} f x)]
  simpa [← isoFinYonedaComponents_hom_apply] using x.map_eq_image f y

end LightCondensed
```

## Compiler diagnostic
```
[CompilationUnit(i_begin=0, i_end=70, messages=[Message(data='expected token', pos=Position(line=1, column=66), pos_end=None, severity=<Severity.ERROR: 3>, kind=None)], invocations=None, goal_state=None, goal_src_boundaries=None, new_constants=None), CompilationUnit(i_begin=70, i_end=1652, messages=[Message(data='Invalid `end`: There is no current scope to end\n\nNote: Scopes are introduced using `namespace` and `section`', pos=Position(line=35, column=0), pos_end=Position(line=35, column=18), severity=<Severity.ERROR: 3>, kind=None)], invocations=None, goal_state=None, goal_src_boundaries=None, new_constants=None)]
```

Return a corrected, compiling version of the code.

<s>[SYSTEM_PROMPT]You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Condensed.Discrete.Colimit).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]The following Lean code fails to compile. Fix it.

```lean
lemma isoLocallyConstantOfIsColimit_inv (X : LightProfinite.{u}ᵒᵖ ⥤ Type u)
    [PreservesFiniteProducts X] (hX : ∀ S : LightProfinite.{u}, (IsColimit <|
      X.mapCocone (coconeRightOpOfCone S.asLimitCone))) :
    (isoLocallyConstantOfIsColimit X hX).inv =
      (CompHausLike.LocallyConstant.counitApp.{u, u} X)
:= by .someMissingNamespaceXYZ
dsimp [isoLocallyConstantOfIsColimit]
  simp only [Category.assoc]
  rw [Iso.inv_comp_eq]
  ext S : 2
  apply colimit.hom_ext
  intro ⟨Y, _, g⟩
  suffices _ ≫ (isoFinYonedaComponents _ _).inv ≫ X.map g =
    (locallyConstantPresheaf _).map g ≫ counitAppApp (Opposite.unop S) X by
      simpa [locallyConstantIsoFinYoneda, isoFinYoneda, counitApp]
  erw [(counitApp.{u, u} X).naturality]
  simp only [← Category.assoc, op_obj, functorToPresheaves_obj_obj]
  congr
  ext f
  simp only [types_comp_apply, counitApp_app]
  apply presheaf_ext.{u, u} (X := X) (Y := X) (f := f)
  intro x
  rw [incl_of_counitAppApp]
  simp only [counitAppAppImage]
  have : Finite (fiber.{u, u} f x) :=
    Finite.of_injective (sigmaIncl.{u, u} f x).1 Subtype.val_injective
  apply injective_of_mono (isoFinYonedaComponents X (fiber.{u, u} f x)).hom
  ext y
  simp only [isoFinYonedaComponents_hom_apply, ← FunctorToTypes.map_comp_apply, ← op_comp]
  rw [show (LightProfinite.of PUnit.{u + 1}).const y ≫ IsTerminal.from _ (fiber f x) = 𝟙 _ from rfl]
  simp only [op_comp, FunctorToTypes.map_comp_apply, op_id, FunctorToTypes.map_id_apply]
  rw [← isoFinYonedaComponents_inv_comp X _ (sigmaIncl.{u, u} f x)]
  simpa [← isoFinYonedaComponents_hom_apply] using x.map_eq_image f y

end LightCondensed
```

## Compiler diagnostic
```
[CompilationUnit(i_begin=0, i_end=70, messages=[Message(data='expected token', pos=Position(line=1, column=66), pos_end=None, severity=<Severity.ERROR: 3>, kind=None)], invocations=None, goal_state=None, goal_src_boundaries=None, new_constants=None), CompilationUnit(i_begin=70, i_end=1652, messages=[Message(data='Invalid `end`: There is no current scope to end\n\nNote: Scopes are introduced using `namespace` and `section`', pos=Position(line=35, column=0), pos_end=Position(line=35, column=18), severity=<Severity.ERROR: 3>, kind=None)], invocations=None, goal_state=None, goal_src_boundaries=None, new_constants=None)]
```

Return a corrected, compiling version of the code.[/INST]


Instruction: Explain the Lean statement below in plain mathematical language, then formalize a short related example in Lean 4.

[System] You are Leanstral, a Lean 4 proof assistant. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.AlgebraicTopology.SimplicialSet.Monoidal).

[User]
Explain the Lean statement below in plain mathematical language, then formalize a short related example in Lean 4.

Open namespaces: Simplicial, CategoryTheory, MonoidalCategory, CartesianMonoidalCategory

## Surrounding context in Mathlib/AlgebraicTopology/SimplicialSet/Monoidal.lean
```lean
-- Mathlib.AlgebraicTopology.SimplicialSet.Monoidal.leftUnitor_hom_app_apply (L36-L38)
lemma leftUnitor_hom_app_apply (K : SSet.{u}) {Δ : SimplexCategoryᵒᵖ} (x : (𝟙_ _ ⊗ K).obj Δ) :
    (λ_ K).hom.app Δ x = x.2

-- Mathlib.AlgebraicTopology.SimplicialSet.Monoidal.leftUnitor_inv_app_apply (L40-L42)
lemma leftUnitor_inv_app_apply (K : SSet.{u}) {Δ : SimplexCategoryᵒᵖ} (x : K.obj Δ) :
    (λ_ K).inv.app Δ x = ⟨PUnit.unit, x⟩

-- Mathlib.AlgebraicTopology.SimplicialSet.Monoidal.rightUnitor_hom_app_apply (L44-L46)
lemma rightUnitor_hom_app_apply (K : SSet.{u}) {Δ : SimplexCategoryᵒᵖ} (x : (K ⊗ 𝟙_ _).obj Δ) :
    (ρ_ K).hom.app Δ x = x.1
```

```lean
lemma prod_le_prod_top {X Y : SSet.{u}} (A : X.Subcomplex) (B : Y.Subcomplex) :
    A.prod B ≤ A.prod ⊤
```

Declaration: `Mathlib.AlgebraicTopology.SimplicialSet.Monoidal.prod_le_prod_top` (module Mathlib.AlgebraicTopology.SimplicialSet.Monoidal).

You are Leanstral, a Lean 4 proof assistant. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.AlgebraicTopology.SimplicialSet.Monoidal).

Explain the Lean statement below in plain mathematical language, then formalize a short related example in Lean 4.

Open namespaces: Simplicial, CategoryTheory, MonoidalCategory, CartesianMonoidalCategory

## Surrounding context in Mathlib/AlgebraicTopology/SimplicialSet/Monoidal.lean
```lean
-- Mathlib.AlgebraicTopology.SimplicialSet.Monoidal.leftUnitor_hom_app_apply (L36-L38)
lemma leftUnitor_hom_app_apply (K : SSet.{u}) {Δ : SimplexCategoryᵒᵖ} (x : (𝟙_ _ ⊗ K).obj Δ) :
    (λ_ K).hom.app Δ x = x.2

-- Mathlib.AlgebraicTopology.SimplicialSet.Monoidal.leftUnitor_inv_app_apply (L40-L42)
lemma leftUnitor_inv_app_apply (K : SSet.{u}) {Δ : SimplexCategoryᵒᵖ} (x : K.obj Δ) :
    (λ_ K).inv.app Δ x = ⟨PUnit.unit, x⟩

-- Mathlib.AlgebraicTopology.SimplicialSet.Monoidal.rightUnitor_hom_app_apply (L44-L46)
lemma rightUnitor_hom_app_apply (K : SSet.{u}) {Δ : SimplexCategoryᵒᵖ} (x : (K ⊗ 𝟙_ _).obj Δ) :
    (ρ_ K).hom.app Δ x = x.1
```

```lean
lemma prod_le_prod_top {X Y : SSet.{u}} (A : X.Subcomplex) (B : Y.Subcomplex) :
    A.prod B ≤ A.prod ⊤
```

Declaration: `Mathlib.AlgebraicTopology.SimplicialSet.Monoidal.prod_le_prod_top` (module Mathlib.AlgebraicTopology.SimplicialSet.Monoidal).


[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.AlgebraicTopology.SimplicialSet.Skeleton).

[User]
The following proof-state transcript was extracted from a real mathlib proof. Use it to answer the question below.

```text
Proof-state transcript for `Mathlib.AlgebraicTopology.SimplicialSet.Skeleton.mem_skeleton`:
State 0: ⊢ lemma mem_skeleton {i : ℕ} (x : X _⦋i⦌) {n : ℕ} (hi : i < n
Tactic: obtain ⟨j, f, _, y, rfl⟩ := X.exists_nonDegenerate x  suffices Subcomplex.ofSimplex y.1 ≤ X.skeleton n from  (X.skeleton n).map _ (this _ (Subcomplex.mem_ofSimplex_obj _))
State 1: ⊢ <goal after obtain ⟨j, f, _, y, rfl⟩ := X.exists_nonDegenerate x>
Tactic: exact le_trans (by exact le_trans (by rfl) (le_iSup _ y))  (le_iSup _ ⟨j, lt_of_le_of_lt  (SimplexCategory.len_le_of_epi f) hi⟩)
```

Question: what is the next tactic after the last recorded state, and why?

<s>[SYSTEM_PROMPT]You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.AlgebraicTopology.SimplicialSet.Skeleton).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]The following proof-state transcript was extracted from a real mathlib proof. Use it to answer the question below.

```text
Proof-state transcript for `Mathlib.AlgebraicTopology.SimplicialSet.Skeleton.mem_skeleton`:
State 0: ⊢ lemma mem_skeleton {i : ℕ} (x : X _⦋i⦌) {n : ℕ} (hi : i < n
Tactic: obtain ⟨j, f, _, y, rfl⟩ := X.exists_nonDegenerate x  suffices Subcomplex.ofSimplex y.1 ≤ X.skeleton n from  (X.skeleton n).map _ (this _ (Subcomplex.mem_ofSimplex_obj _))
State 1: ⊢ <goal after obtain ⟨j, f, _, y, rfl⟩ := X.exists_nonDegenerate x>
Tactic: exact le_trans (by exact le_trans (by rfl) (le_iSup _ y))  (le_iSup _ ⟨j, lt_of_le_of_lt  (SimplexCategory.len_le_of_epi f) hi⟩)
```

Question: what is the next tactic after the last recorded state, and why?[/INST]


Instruction: Edit `tr` so it still compiles and the proof is simplified where possible. Return the full updated `tr` block.

[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Computability.TuringMachine.PostTuringMachine).

[User]
You are editing a file in `Mathlib/Computability/TuringMachine/PostTuringMachine.lean` (mathlib commit 5e932f97dd25535344f80f9dd8da3aab83df0fe6).

## Current excerpt (around `Mathlib.Computability.TuringMachine.PostTuringMachine.tr`, L986-L995)
Open namespaces: List, (Vector), Relation, Nat, (iterate), Function, (update, iterate_succ

## Surrounding context in Mathlib/Computability/TuringMachine/PostTuringMachine.lean
```lean
-- Mathlib.Computability.TuringMachine.PostTuringMachine.Stmt (L122-L133)
instance Stmt.inhabited [Inhabited Γ] : Inhabited (Stmt Γ)

-- Mathlib.Computability.TuringMachine.PostTuringMachine.Machine (L135-L152)
def Machine [Inhabited Λ]

-- Mathlib.Computability.TuringMachine.PostTuringMachine.Cfg (L156-L158)
instance Cfg.inhabited : Inhabited (Cfg Γ Λ)
```

```lean
def tr : Λ' Γ Λ → TM1.Stmt Γ (Λ' Γ Λ) Unit
  | Λ'.normal q =>
    branch (fun a _ ↦ (M q a).isNone) halt <|
      goto fun a _ ↦ match M q a with
      | none => default -- unreachable
      | some (q', s) => Λ'.act s q'
  | Λ'.act (TM0.Stmt.move d) q => move d <| goto fun _ _ ↦ Λ'.normal q
  | Λ'.act (TM0.Stmt.write a) q => (write fun _ _ ↦ a) <| goto fun _ _ ↦ Λ'.normal q

/-- The configuration translation. -/
```

## Edit instruction
Edit `tr` so it still compiles and the proof is simplified where possible. Return the full updated `tr` block.

You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Computability.TuringMachine.PostTuringMachine).

You are editing a file in `Mathlib/Computability/TuringMachine/PostTuringMachine.lean` (mathlib commit 5e932f97dd25535344f80f9dd8da3aab83df0fe6).

## Current excerpt (around `Mathlib.Computability.TuringMachine.PostTuringMachine.tr`, L986-L995)
Open namespaces: List, (Vector), Relation, Nat, (iterate), Function, (update, iterate_succ

## Surrounding context in Mathlib/Computability/TuringMachine/PostTuringMachine.lean
```lean
-- Mathlib.Computability.TuringMachine.PostTuringMachine.Stmt (L122-L133)
instance Stmt.inhabited [Inhabited Γ] : Inhabited (Stmt Γ)

-- Mathlib.Computability.TuringMachine.PostTuringMachine.Machine (L135-L152)
def Machine [Inhabited Λ]

-- Mathlib.Computability.TuringMachine.PostTuringMachine.Cfg (L156-L158)
instance Cfg.inhabited : Inhabited (Cfg Γ Λ)
```

```lean
def tr : Λ' Γ Λ → TM1.Stmt Γ (Λ' Γ Λ) Unit
  | Λ'.normal q =>
    branch (fun a _ ↦ (M q a).isNone) halt <|
      goto fun a _ ↦ match M q a with
      | none => default -- unreachable
      | some (q', s) => Λ'.act s q'
  | Λ'.act (TM0.Stmt.move d) q => move d <| goto fun _ _ ↦ Λ'.normal q
  | Λ'.act (TM0.Stmt.write a) q => (write fun _ _ ↦ a) <| goto fun _ _ ↦ Λ'.normal q

/-- The configuration translation. -/
```

## Edit instruction
Edit `tr` so it still compiles and the proof is simplified where possible. Return the full updated `tr` block.


[System] You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.AlgebraicTopology.SimplicialSet.StdSimplex).

[User]
The following proof-state transcript was extracted from a real mathlib proof. Use it to answer the question below.

```text
Proof-state transcript for `Mathlib.AlgebraicTopology.SimplicialSet.StdSimplex.face_eq_ofSimplex`:
State 0: ⊢ lemma face_eq_ofSimplex {n : ℕ} (S : Finset (Fin (n + 1))) (m : ℕ) (e : Fin (m + 1) ≃o S) :
    face.{u} S =
      Subcomplex.ofSimplex (X
Tactic: apply le_antisymm  · rintro ⟨k⟩ x hx
State 1: ⊢ <goal after apply le_antisymm>
Tactic: induction k using SimplexCategory.rec with | _ k
State 2: ⊢ <goal after induction k using SimplexCategory.rec with | _ k>
Tactic: rw [mem_face_iff] at hx  let φ : Fin (k + 1) →o S :=  { toFun i := ⟨x i, hx i⟩  monotone' := (objEquiv x).toOrderHom.monotone }
State 3: ⊢ <goal after rw [mem_face_iff] at hx>
Tactic: refine ⟨Quiver.Hom.op  (SimplexCategory.Hom.mk ((e.symm.toOrderEmbedding.toOrderHom.comp φ))), ?_⟩
State 4: ⊢ <goal after refine ⟨Quiver.Hom.op>
Tactic: ext j : 1
State 5: ⊢ <goal after ext j : 1>
Tactic: simpa only [Subtype.ext_iff] using e.apply_symm_apply ⟨_, hx j⟩  · simp  set_option backward.isDefEq.respectTransparency false in  /-- If `S : Finset (Fin (n + 1))` is order isomorphic to `Fin (m + 1)`,  then the face `face S` of `Δ[n]` is representable by `m`,  i.e. `face S` is isomorphic to `Δ[m]`, see `stdSimplex.isoOfRepresentableBy`. -/
```

Question: what is the next tactic after the last recorded state, and why?

<s>[SYSTEM_PROMPT]You are Leanstral, a Lean 4 proof assistant. Complete the task below using the provided Lean source context. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.AlgebraicTopology.SimplicialSet.StdSimplex).[/SYSTEM_PROMPT][MODEL_SETTINGS]{"reasoning_effort": "none"}[/MODEL_SETTINGS][INST]The following proof-state transcript was extracted from a real mathlib proof. Use it to answer the question below.

```text
Proof-state transcript for `Mathlib.AlgebraicTopology.SimplicialSet.StdSimplex.face_eq_ofSimplex`:
State 0: ⊢ lemma face_eq_ofSimplex {n : ℕ} (S : Finset (Fin (n + 1))) (m : ℕ) (e : Fin (m + 1) ≃o S) :
    face.{u} S =
      Subcomplex.ofSimplex (X
Tactic: apply le_antisymm  · rintro ⟨k⟩ x hx
State 1: ⊢ <goal after apply le_antisymm>
Tactic: induction k using SimplexCategory.rec with | _ k
State 2: ⊢ <goal after induction k using SimplexCategory.rec with | _ k>
Tactic: rw [mem_face_iff] at hx  let φ : Fin (k + 1) →o S :=  { toFun i := ⟨x i, hx i⟩  monotone' := (objEquiv x).toOrderHom.monotone }
State 3: ⊢ <goal after rw [mem_face_iff] at hx>
Tactic: refine ⟨Quiver.Hom.op  (SimplexCategory.Hom.mk ((e.symm.toOrderEmbedding.toOrderHom.comp φ))), ?_⟩
State 4: ⊢ <goal after refine ⟨Quiver.Hom.op>
Tactic: ext j : 1
State 5: ⊢ <goal after ext j : 1>
Tactic: simpa only [Subtype.ext_iff] using e.apply_symm_apply ⟨_, hx j⟩  · simp  set_option backward.isDefEq.respectTransparency false in  /-- If `S : Finset (Fin (n + 1))` is order isomorphic to `Fin (m + 1)`,  then the face `face S` of `Δ[n]` is representable by `m`,  i.e. `face S` is isomorphic to `Δ[m]`, see `stdSimplex.isoOfRepresentableBy`. -/
```

Question: what is the next tactic after the last recorded state, and why?[/INST]


Instruction: Explain the Lean statement below in plain mathematical language, then formalize a short related example in Lean 4.

[System] You are Leanstral, a Lean 4 proof assistant. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Computability.Primrec.List).

[User]
Explain the Lean statement below in plain mathematical language, then formalize a short related example in Lean 4.

Open namespaces: List, (Vector), Denumerable, Encodable, Function, Primrec, PrimrecPred

## Surrounding context in Mathlib/Computability/Primrec/List.lean
```lean
-- Mathlib.Computability.Primrec.List.list (L109-L141)
instance list : Primcodable (List α)

-- Mathlib.Computability.Primrec.List.list_cons (L142-L144)
theorem list_cons : Primrec₂ (@List.cons α)

-- Mathlib.Computability.Primrec.List.list_casesOn (L145-L150)
theorem list_casesOn {f : α → List β} {g : α → σ} {h : α → β × List β → σ} :
    Primrec f →
      Primrec g →
        Primrec₂ h → @Primrec _ σ _ _ fun a => List.casesOn (f a) (g a) fun b l => h a (b, l)
```

```lean
theorem vector_tail {n} : Primrec (@List.Vector.tail α n)
```

Declaration: `Mathlib.Computability.Primrec.List.vector_tail` (module Mathlib.Computability.Primrec.List).

You are Leanstral, a Lean 4 proof assistant. The target mathlib commit is 5e932f97dd25535344f80f9dd8da3aab83df0fe6 (module Mathlib.Computability.Primrec.List).

Explain the Lean statement below in plain mathematical language, then formalize a short related example in Lean 4.

Open namespaces: List, (Vector), Denumerable, Encodable, Function, Primrec, PrimrecPred

## Surrounding context in Mathlib/Computability/Primrec/List.lean
```lean
-- Mathlib.Computability.Primrec.List.list (L109-L141)
instance list : Primcodable (List α)

-- Mathlib.Computability.Primrec.List.list_cons (L142-L144)
theorem list_cons : Primrec₂ (@List.cons α)

-- Mathlib.Computability.Primrec.List.list_casesOn (L145-L150)
theorem list_casesOn {f : α → List β} {g : α → σ} {h : α → β × List β → σ} :
    Primrec f →
      Primrec g →
        Primrec₂ h → @Primrec _ σ _ _ fun a => List.casesOn (f a) (g a) fun b l => h a (b, l)
```

```lean
theorem vector_tail {n} : Primrec (@List.Vector.tail α n)
```

Declaration: `Mathlib.Computability.Primrec.List.vector_tail` (module Mathlib.Computability.Primrec.List).