l3lab/ntp-mathlib huggingface dataset:
/-- The set `𝒫 S := {x | x ⊆ S}` is equivalent to the type `Set S`. -/
protected def powerset {α} (S : Set α) :
    𝒫 S ≃ Set S where
  toFun := fun x : 𝒫 S => Subtype.val ⁻¹' (x : Set α)
  invFun := fun x : Set S => ⟨Subtype.val '' x, by rintro _ ⟨a : S, _, rfl⟩; exact a.2⟩
  left_inv x := by ext y;exact ⟨fun ⟨⟨_, _⟩, h, rfl⟩ => h, fun h => ⟨⟨_, x.2 h⟩, h, rfl⟩⟩
  right_inv x := by 

Proof state:
α✝ : Sort u
β : Sort v
γ : Sort w
α : Type ?u.49510
S : Set α
x : Set ↑S
⊢ (fun x => Subtype.val ⁻¹' ↑x)
      ((fun x => { val := Subtype.val '' x, property := (_ : ∀ ⦃a : α⦄, a ∈ Subtype.val '' x → a ∈ S) }) x) =
    x

Next tactic:
ext
/-- The set `𝒫 S := {x | x ⊆ S}` is equivalent to the type `Set S`. -/
protected def powerset {α} (S : Set α) :
    𝒫 S ≃ Set S where
  toFun := fun x : 𝒫 S => Subtype.val ⁻¹' (x : Set α)
  invFun := fun x : Set S => ⟨Subtype.val '' x, by rintro _ ⟨a : S, _, rfl⟩; exact a.2⟩
  left_inv x := by ext y;exact ⟨fun ⟨⟨_, _⟩, h, rfl⟩ => h, fun h => ⟨⟨_, x.2 h⟩, h, rfl⟩⟩
  right_inv x := by ext; 

Proof state:
case h
α✝ : Sort u
β : Sort v
γ : Sort w
α : Type ?u.49510
S : Set α
x : Set ↑S
x✝ : ↑S
⊢ x✝ ∈
      (fun x => Subtype.val ⁻¹' ↑x)
        ((fun x => { val := Subtype.val '' x, property := (_ : ∀ ⦃a : α⦄, a ∈ Subtype.val '' x → a ∈ S) }) x) ↔
    x✝ ∈ x

Next tactic:
simp
/-- If `s` is a set in `range f`,
then its image under `rangeSplitting f` is in bijection (via `f`) with `s`.
-/
@[simps]
noncomputable def rangeSplittingImageEquiv {α β : Type*} (f : α → β) (s : Set (range f)) :
    rangeSplitting f '' s ≃ s where
  toFun x :=
    ⟨⟨f x, by 

Proof state:
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
f : α → β
s : Set ↑(range f)
x : ↑(rangeSplitting f '' s)
⊢ f ↑x ∈ range f

Next tactic:
simp
/-- If `s` is a set in `range f`,
then its image under `rangeSplitting f` is in bijection (via `f`) with `s`.
-/
@[simps]
noncomputable def rangeSplittingImageEquiv {α β : Type*} (f : α → β) (s : Set (range f)) :
    rangeSplitting f '' s ≃ s where
  toFun x :=
    ⟨⟨f x, by simp⟩, by
      

Proof state:
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
f : α → β
s : Set ↑(range f)
x : ↑(rangeSplitting f '' s)
⊢ { val := f ↑x, property := (_ : f ↑x ∈ range f) } ∈ s

Next tactic:
rcases x with ⟨x, ⟨y, ⟨m, rfl⟩⟩⟩
/-- If `s` is a set in `range f`,
then its image under `rangeSplitting f` is in bijection (via `f`) with `s`.
-/
@[simps]
noncomputable def rangeSplittingImageEquiv {α β : Type*} (f : α → β) (s : Set (range f)) :
    rangeSplitting f '' s ≃ s where
  toFun x :=
    ⟨⟨f x, by simp⟩, by
      rcases x with ⟨x, ⟨y, ⟨m, rfl⟩⟩⟩
      

Proof state:
case mk.intro.intro
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
f : α → β
s : Set ↑(range f)
y : ↑(range f)
m : y ∈ s
⊢ { val := f ↑{ val := rangeSplitting f y, property := (_ : ∃ a ∈ s, rangeSplitting f a = rangeSplitting f y) },
      property :=
        (_ :
          f ↑{ val := rangeSplitting f y, property := (_ : ∃ a ∈ s, rangeSplitting f a = rangeSplitting f y) } ∈
            range f) } ∈
    s

Next tactic:
simpa [apply_rangeSplitting f] using m
/-- If `s` is a set in `range f`,
then its image under `rangeSplitting f` is in bijection (via `f`) with `s`.
-/
@[simps]
noncomputable def rangeSplittingImageEquiv {α β : Type*} (f : α → β) (s : Set (range f)) :
    rangeSplitting f '' s ≃ s where
  toFun x :=
    ⟨⟨f x, by simp⟩, by
      rcases x with ⟨x, ⟨y, ⟨m, rfl⟩⟩⟩
      simpa [apply_rangeSplitting f] using m⟩
  invFun x := ⟨rangeSplitting f x, ⟨x, ⟨x.2, rfl⟩⟩⟩
  left_inv x := by
    

Proof state:
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
f : α → β
s : Set ↑(range f)
x : ↑(rangeSplitting f '' s)
⊢ (fun x => { val := rangeSplitting f ↑x, property := (_ : ∃ a ∈ s, rangeSplitting f a = rangeSplitting f ↑x) })
      ((fun x =>
          { val := { val := f ↑x, property := (_ : f ↑x ∈ range f) },
            property := (_ : { val := f ↑x, property := (_ : f ↑x ∈ range f) } ∈ s) })
        x) =
    x

Next tactic:
rcases x with ⟨x, ⟨y, ⟨m, rfl⟩⟩⟩
/-- If `s` is a set in `range f`,
then its image under `rangeSplitting f` is in bijection (via `f`) with `s`.
-/
@[simps]
noncomputable def rangeSplittingImageEquiv {α β : Type*} (f : α → β) (s : Set (range f)) :
    rangeSplitting f '' s ≃ s where
  toFun x :=
    ⟨⟨f x, by simp⟩, by
      rcases x with ⟨x, ⟨y, ⟨m, rfl⟩⟩⟩
      simpa [apply_rangeSplitting f] using m⟩
  invFun x := ⟨rangeSplitting f x, ⟨x, ⟨x.2, rfl⟩⟩⟩
  left_inv x := by
    rcases x with ⟨x, ⟨y, ⟨m, rfl⟩⟩⟩
    

Proof state:
case mk.intro.intro
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
f : α → β
s : Set ↑(range f)
y : ↑(range f)
m : y ∈ s
⊢ (fun x => { val := rangeSplitting f ↑x, property := (_ : ∃ a ∈ s, rangeSplitting f a = rangeSplitting f ↑x) })
      ((fun x =>
          { val := { val := f ↑x, property := (_ : f ↑x ∈ range f) },
            property := (_ : { val := f ↑x, property := (_ : f ↑x ∈ range f) } ∈ s) })
        { val := rangeSplitting f y, property := (_ : ∃ a ∈ s, rangeSplitting f a = rangeSplitting f y) }) =
    { val := rangeSplitting f y, property := (_ : ∃ a ∈ s, rangeSplitting f a = rangeSplitting f y) }

Next tactic:
simp [apply_rangeSplitting f]
/-- If `s` is a set in `range f`,
then its image under `rangeSplitting f` is in bijection (via `f`) with `s`.
-/
@[simps]
noncomputable def rangeSplittingImageEquiv {α β : Type*} (f : α → β) (s : Set (range f)) :
    rangeSplitting f '' s ≃ s where
  toFun x :=
    ⟨⟨f x, by simp⟩, by
      rcases x with ⟨x, ⟨y, ⟨m, rfl⟩⟩⟩
      simpa [apply_rangeSplitting f] using m⟩
  invFun x := ⟨rangeSplitting f x, ⟨x, ⟨x.2, rfl⟩⟩⟩
  left_inv x := by
    rcases x with ⟨x, ⟨y, ⟨m, rfl⟩⟩⟩
    simp [apply_rangeSplitting f]
  right_inv x := by 

Proof state:
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
f : α → β
s : Set ↑(range f)
x : ↑s
⊢ (fun x =>
        { val := { val := f ↑x, property := (_ : f ↑x ∈ range f) },
          property := (_ : { val := f ↑x, property := (_ : f ↑x ∈ range f) } ∈ s) })
      ((fun x => { val := rangeSplitting f ↑x, property := (_ : ∃ a ∈ s, rangeSplitting f a = rangeSplitting f ↑x) })
        x) =
    x

Next tactic:
simp [apply_rangeSplitting f]
/-- Equivalence between the range of `Sum.inl : α → α ⊕ β` and `α`. -/
@[simps symm_apply_coe]
def rangeInl (α β : Type*) : Set.range (Sum.inl : α → α ⊕ β) ≃ α where
  toFun
  | ⟨.inl x, _⟩ => x
  | ⟨.inr _, h⟩ => False.elim <| by 

Proof state:
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
val✝ : β
h : Sum.inr val✝ ∈ range Sum.inl
⊢ False

Next tactic:
rcases h with ⟨x, h'⟩
/-- Equivalence between the range of `Sum.inl : α → α ⊕ β` and `α`. -/
@[simps symm_apply_coe]
def rangeInl (α β : Type*) : Set.range (Sum.inl : α → α ⊕ β) ≃ α where
  toFun
  | ⟨.inl x, _⟩ => x
  | ⟨.inr _, h⟩ => False.elim <| by rcases h with ⟨x, h'⟩; 

Proof state:
case intro
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
val✝ : β
x : α
h' : Sum.inl x = Sum.inr val✝
⊢ False

Next tactic:
cases h'
/-- Equivalence between the range of `Sum.inr : β → α ⊕ β` and `β`. -/
@[simps symm_apply_coe]
def rangeInr (α β : Type*) : Set.range (Sum.inr : β → α ⊕ β) ≃ β where
  toFun
  | ⟨.inl _, h⟩ => False.elim <| by 

Proof state:
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
val✝ : α
h : Sum.inl val✝ ∈ range Sum.inr
⊢ False

Next tactic:
rcases h with ⟨x, h'⟩
/-- Equivalence between the range of `Sum.inr : β → α ⊕ β` and `β`. -/
@[simps symm_apply_coe]
def rangeInr (α β : Type*) : Set.range (Sum.inr : β → α ⊕ β) ≃ β where
  toFun
  | ⟨.inl _, h⟩ => False.elim <| by rcases h with ⟨x, h'⟩; 

Proof state:
case intro
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
val✝ : α
x : β
h' : Sum.inr x = Sum.inl val✝
⊢ False

Next tactic:
cases h'
@[simp]
theorem ofInjective_symm_apply {α β} {f : α → β} (hf : Injective f) (a : α) :
    (ofInjective f hf).symm ⟨f a, ⟨a, rfl⟩⟩ = a := by
  

Proof state:
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Sort u_1
β : Type u_2
f : α → β
hf : Injective f
a : α
⊢ (ofInjective f hf).symm { val := f a, property := (_ : ∃ y, f y = f a) } = a

Next tactic:
apply (ofInjective f hf).injective
@[simp]
theorem ofInjective_symm_apply {α β} {f : α → β} (hf : Injective f) (a : α) :
    (ofInjective f hf).symm ⟨f a, ⟨a, rfl⟩⟩ = a := by
  apply (ofInjective f hf).injective
  

Proof state:
case a
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Sort u_1
β : Type u_2
f : α → β
hf : Injective f
a : α
⊢ (ofInjective f hf) ((ofInjective f hf).symm { val := f a, property := (_ : ∃ y, f y = f a) }) = (ofInjective f hf) a

Next tactic:
simp [apply_ofInjective_symm hf]
theorem coe_ofInjective_symm {α β} {f : α → β} (hf : Injective f) :
    ((ofInjective f hf).symm : range f → α) = rangeSplitting f := by
  

Proof state:
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
f : α → β
hf : Injective f
⊢ ⇑(ofInjective f hf).symm = rangeSplitting f

Next tactic:
ext ⟨y, x, rfl⟩
theorem coe_ofInjective_symm {α β} {f : α → β} (hf : Injective f) :
    ((ofInjective f hf).symm : range f → α) = rangeSplitting f := by
  ext ⟨y, x, rfl⟩
  

Proof state:
case h.mk.intro
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
f : α → β
hf : Injective f
x : α
⊢ (ofInjective f hf).symm { val := f x, property := (_ : ∃ y, f y = f x) } =
    rangeSplitting f { val := f x, property := (_ : ∃ y, f y = f x) }

Next tactic:
apply hf
theorem coe_ofInjective_symm {α β} {f : α → β} (hf : Injective f) :
    ((ofInjective f hf).symm : range f → α) = rangeSplitting f := by
  ext ⟨y, x, rfl⟩
  apply hf
  

Proof state:
case h.mk.intro.a
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
f : α → β
hf : Injective f
x : α
⊢ f ((ofInjective f hf).symm { val := f x, property := (_ : ∃ y, f y = f x) }) =
    f (rangeSplitting f { val := f x, property := (_ : ∃ y, f y = f x) })

Next tactic:
simp [apply_rangeSplitting f]
theorem ofLeftInverse_eq_ofInjective {α β : Type*} (f : α → β) (f_inv : Nonempty α → β → α)
    (hf : ∀ h : Nonempty α, LeftInverse (f_inv h) f) :
    ofLeftInverse f f_inv hf =
      ofInjective f ((isEmpty_or_nonempty α).elim (fun h _ _ _ => Subsingleton.elim _ _)
        (fun h => (hf h).injective)) := by
  

Proof state:
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
f : α → β
f_inv : Nonempty α → β → α
hf : ∀ (h : Nonempty α), LeftInverse (f_inv h) f
⊢ ofLeftInverse f f_inv hf = ofInjective f (_ : Injective f)

Next tactic:
ext
theorem ofLeftInverse_eq_ofInjective {α β : Type*} (f : α → β) (f_inv : Nonempty α → β → α)
    (hf : ∀ h : Nonempty α, LeftInverse (f_inv h) f) :
    ofLeftInverse f f_inv hf =
      ofInjective f ((isEmpty_or_nonempty α).elim (fun h _ _ _ => Subsingleton.elim _ _)
        (fun h => (hf h).injective)) := by
  ext
  

Proof state:
case H.a
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
f : α → β
f_inv : Nonempty α → β → α
hf : ∀ (h : Nonempty α), LeftInverse (f_inv h) f
x✝ : α
⊢ ↑((ofLeftInverse f f_inv hf) x✝) = ↑((ofInjective f (_ : Injective f)) x✝)

Next tactic:
simp
theorem ofLeftInverse'_eq_ofInjective {α β : Type*} (f : α → β) (f_inv : β → α)
    (hf : LeftInverse f_inv f) : ofLeftInverse' f f_inv hf = ofInjective f hf.injective := by
  

Proof state:
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
f : α → β
f_inv : β → α
hf : LeftInverse f_inv f
⊢ ofLeftInverse' f f_inv hf = ofInjective f (_ : Injective f)

Next tactic:
ext
theorem ofLeftInverse'_eq_ofInjective {α β : Type*} (f : α → β) (f_inv : β → α)
    (hf : LeftInverse f_inv f) : ofLeftInverse' f f_inv hf = ofInjective f hf.injective := by
  ext
  

Proof state:
case H.a
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : Type u_2
f : α → β
f_inv : β → α
hf : LeftInverse f_inv f
x✝ : α
⊢ ↑((ofLeftInverse' f f_inv hf) x✝) = ↑((ofInjective f (_ : Injective f)) x✝)

Next tactic:
simp
theorem preimage_piEquivPiSubtypeProd_symm_pi {α : Type*} {β : α → Type*} (p : α → Prop)
    [DecidablePred p] (s : ∀ i, Set (β i)) :
    (piEquivPiSubtypeProd p β).symm ⁻¹' pi univ s =
      (pi univ fun i : { i // p i } => s i) ×ˢ pi univ fun i : { i // ¬p i } => s i := by
  

Proof state:
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : α → Type u_2
p : α → Prop
inst✝ : DecidablePred p
s : (i : α) → Set (β i)
⊢ ⇑(piEquivPiSubtypeProd p β).symm ⁻¹' pi univ s = (pi univ fun i => s ↑i) ×ˢ pi univ fun i => s ↑i

Next tactic:
ext ⟨f, g⟩
theorem preimage_piEquivPiSubtypeProd_symm_pi {α : Type*} {β : α → Type*} (p : α → Prop)
    [DecidablePred p] (s : ∀ i, Set (β i)) :
    (piEquivPiSubtypeProd p β).symm ⁻¹' pi univ s =
      (pi univ fun i : { i // p i } => s i) ×ˢ pi univ fun i : { i // ¬p i } => s i := by
  ext ⟨f, g⟩
  

Proof state:
case h.mk
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : α → Type u_2
p : α → Prop
inst✝ : DecidablePred p
s : (i : α) → Set (β i)
f : (i : { x // p x }) → β ↑i
g : (i : { x // ¬p x }) → β ↑i
⊢ (f, g) ∈ ⇑(piEquivPiSubtypeProd p β).symm ⁻¹' pi univ s ↔ (f, g) ∈ (pi univ fun i => s ↑i) ×ˢ pi univ fun i => s ↑i

Next tactic:
simp only [mem_preimage, mem_univ_pi, prod_mk_mem_set_prod_eq, Subtype.forall, ← forall_and]
theorem preimage_piEquivPiSubtypeProd_symm_pi {α : Type*} {β : α → Type*} (p : α → Prop)
    [DecidablePred p] (s : ∀ i, Set (β i)) :
    (piEquivPiSubtypeProd p β).symm ⁻¹' pi univ s =
      (pi univ fun i : { i // p i } => s i) ×ˢ pi univ fun i : { i // ¬p i } => s i := by
  ext ⟨f, g⟩
  simp only [mem_preimage, mem_univ_pi, prod_mk_mem_set_prod_eq, Subtype.forall, ← forall_and]
  

Proof state:
case h.mk
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : α → Type u_2
p : α → Prop
inst✝ : DecidablePred p
s : (i : α) → Set (β i)
f : (i : { x // p x }) → β ↑i
g : (i : { x // ¬p x }) → β ↑i
⊢ (∀ (i : α), (piEquivPiSubtypeProd p β).symm (f, g) i ∈ s i) ↔
    ∀ (x : α), (∀ (b : p x), f { val := x, property := b } ∈ s x) ∧ ∀ (b : ¬p x), g { val := x, property := b } ∈ s x

Next tactic:
refine' forall_congr' fun i => _
theorem preimage_piEquivPiSubtypeProd_symm_pi {α : Type*} {β : α → Type*} (p : α → Prop)
    [DecidablePred p] (s : ∀ i, Set (β i)) :
    (piEquivPiSubtypeProd p β).symm ⁻¹' pi univ s =
      (pi univ fun i : { i // p i } => s i) ×ˢ pi univ fun i : { i // ¬p i } => s i := by
  ext ⟨f, g⟩
  simp only [mem_preimage, mem_univ_pi, prod_mk_mem_set_prod_eq, Subtype.forall, ← forall_and]
  refine' forall_congr' fun i => _
  

Proof state:
case h.mk
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : α → Type u_2
p : α → Prop
inst✝ : DecidablePred p
s : (i : α) → Set (β i)
f : (i : { x // p x }) → β ↑i
g : (i : { x // ¬p x }) → β ↑i
i : α
⊢ (piEquivPiSubtypeProd p β).symm (f, g) i ∈ s i ↔
    (∀ (b : p i), f { val := i, property := b } ∈ s i) ∧ ∀ (b : ¬p i), g { val := i, property := b } ∈ s i

Next tactic:
dsimp only [Subtype.coe_mk]
theorem preimage_piEquivPiSubtypeProd_symm_pi {α : Type*} {β : α → Type*} (p : α → Prop)
    [DecidablePred p] (s : ∀ i, Set (β i)) :
    (piEquivPiSubtypeProd p β).symm ⁻¹' pi univ s =
      (pi univ fun i : { i // p i } => s i) ×ˢ pi univ fun i : { i // ¬p i } => s i := by
  ext ⟨f, g⟩
  simp only [mem_preimage, mem_univ_pi, prod_mk_mem_set_prod_eq, Subtype.forall, ← forall_and]
  refine' forall_congr' fun i => _
  dsimp only [Subtype.coe_mk]
  

Proof state:
case h.mk
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : α → Type u_2
p : α → Prop
inst✝ : DecidablePred p
s : (i : α) → Set (β i)
f : (i : { x // p x }) → β ↑i
g : (i : { x // ¬p x }) → β ↑i
i : α
⊢ (piEquivPiSubtypeProd p β).symm (f, g) i ∈ s i ↔
    (∀ (b : p i), f { val := i, property := b } ∈ s i) ∧ ∀ (b : ¬p i), g { val := i, property := b } ∈ s i

Next tactic:
by_cases hi : p i
theorem preimage_piEquivPiSubtypeProd_symm_pi {α : Type*} {β : α → Type*} (p : α → Prop)
    [DecidablePred p] (s : ∀ i, Set (β i)) :
    (piEquivPiSubtypeProd p β).symm ⁻¹' pi univ s =
      (pi univ fun i : { i // p i } => s i) ×ˢ pi univ fun i : { i // ¬p i } => s i := by
  ext ⟨f, g⟩
  simp only [mem_preimage, mem_univ_pi, prod_mk_mem_set_prod_eq, Subtype.forall, ← forall_and]
  refine' forall_congr' fun i => _
  dsimp only [Subtype.coe_mk]
  by_cases hi : p i <;> 

Proof state:
case pos
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : α → Type u_2
p : α → Prop
inst✝ : DecidablePred p
s : (i : α) → Set (β i)
f : (i : { x // p x }) → β ↑i
g : (i : { x // ¬p x }) → β ↑i
i : α
hi : p i
⊢ (piEquivPiSubtypeProd p β).symm (f, g) i ∈ s i ↔
    (∀ (b : p i), f { val := i, property := b } ∈ s i) ∧ ∀ (b : ¬p i), g { val := i, property := b } ∈ s i

Next tactic:
simp [hi]
theorem preimage_piEquivPiSubtypeProd_symm_pi {α : Type*} {β : α → Type*} (p : α → Prop)
    [DecidablePred p] (s : ∀ i, Set (β i)) :
    (piEquivPiSubtypeProd p β).symm ⁻¹' pi univ s =
      (pi univ fun i : { i // p i } => s i) ×ˢ pi univ fun i : { i // ¬p i } => s i := by
  ext ⟨f, g⟩
  simp only [mem_preimage, mem_univ_pi, prod_mk_mem_set_prod_eq, Subtype.forall, ← forall_and]
  refine' forall_congr' fun i => _
  dsimp only [Subtype.coe_mk]
  by_cases hi : p i <;> 

Proof state:
case neg
α✝ : Sort u
β✝ : Sort v
γ : Sort w
α : Type u_1
β : α → Type u_2
p : α → Prop
inst✝ : DecidablePred p
s : (i : α) → Set (β i)
f : (i : { x // p x }) → β ↑i
g : (i : { x // ¬p x }) → β ↑i
i : α
hi : ¬p i
⊢ (piEquivPiSubtypeProd p β).symm (f, g) i ∈ s i ↔
    (∀ (b : p i), f { val := i, property := b } ∈ s i) ∧ ∀ (b : ¬p i), g { val := i, property := b } ∈ s i

Next tactic:
simp [hi]
/-- The composition of an updated function with an equiv on a subtype can be expressed as an
updated function. -/
-- porting note: replace `s : Set α` and `: s` with `p : α → Prop` and `: Subtype p`, since the
-- former now unfolds syntactically to a less general case of the latter.
theorem dite_comp_equiv_update {α : Type*} {β : Sort*} {γ : Sort*} {p : α → Prop}
    (e : β ≃ Subtype p)
    (v : β → γ) (w : α → γ) (j : β) (x : γ) [DecidableEq β] [DecidableEq α]
    [∀ j, Decidable (p j)] :
    (fun i : α => if h : p i then (Function.update v j x) (e.symm ⟨i, h⟩) else w i) =
      Function.update (fun i : α => if h : p i then v (e.symm ⟨i, h⟩) else w i) (e j) x := by
  

Proof state:
α✝ : Sort u
β✝ : Sort v
γ✝ : Sort w
α : Type u_1
β : Sort u_2
γ : Sort u_3
p : α → Prop
e : β ≃ Subtype p
v : β → γ
w : α → γ
j : β
x : γ
inst✝² : DecidableEq β
inst✝¹ : DecidableEq α
inst✝ : (j : α) → Decidable (p j)
⊢ (fun i => if h : p i then update v j x (e.symm { val := i, property := h }) else w i) =
    update (fun i => if h : p i then v (e.symm { val := i, property := h }) else w i) (↑(e j)) x

Next tactic:
ext i
/-- The composition of an updated function with an equiv on a subtype can be expressed as an
updated function. -/
-- porting note: replace `s : Set α` and `: s` with `p : α → Prop` and `: Subtype p`, since the
-- former now unfolds syntactically to a less general case of the latter.
theorem dite_comp_equiv_update {α : Type*} {β : Sort*} {γ : Sort*} {p : α → Prop}
    (e : β ≃ Subtype p)
    (v : β → γ) (w : α → γ) (j : β) (x : γ) [DecidableEq β] [DecidableEq α]
    [∀ j, Decidable (p j)] :
    (fun i : α => if h : p i then (Function.update v j x) (e.symm ⟨i, h⟩) else w i) =
      Function.update (fun i : α => if h : p i then v (e.symm ⟨i, h⟩) else w i) (e j) x := by
  ext i
  

Proof state:
case h
α✝ : Sort u
β✝ : Sort v
γ✝ : Sort w
α : Type u_1
β : Sort u_2
γ : Sort u_3
p : α → Prop
e : β ≃ Subtype p
v : β → γ
w : α → γ
j : β
x : γ
inst✝² : DecidableEq β
inst✝¹ : DecidableEq α
inst✝ : (j : α) → Decidable (p j)
i : α
⊢ (if h : p i then update v j x (e.symm { val := i, property := h }) else w i) =
    update (fun i => if h : p i then v (e.symm { val := i, property := h }) else w i) (↑(e j)) x i

Next tactic:
by_cases h : p i
/-- The composition of an updated function with an equiv on a subtype can be expressed as an
updated function. -/
-- porting note: replace `s : Set α` and `: s` with `p : α → Prop` and `: Subtype p`, since the
-- former now unfolds syntactically to a less general case of the latter.
theorem dite_comp_equiv_update {α : Type*} {β : Sort*} {γ : Sort*} {p : α → Prop}
    (e : β ≃ Subtype p)
    (v : β → γ) (w : α → γ) (j : β) (x : γ) [DecidableEq β] [DecidableEq α]
    [∀ j, Decidable (p j)] :
    (fun i : α => if h : p i then (Function.update v j x) (e.symm ⟨i, h⟩) else w i) =
      Function.update (fun i : α => if h : p i then v (e.symm ⟨i, h⟩) else w i) (e j) x := by
  ext i
  by_cases h : p i
  · 

Proof state:
case pos
α✝ : Sort u
β✝ : Sort v
γ✝ : Sort w
α : Type u_1
β : Sort u_2
γ : Sort u_3
p : α → Prop
e : β ≃ Subtype p
v : β → γ
w : α → γ
j : β
x : γ
inst✝² : DecidableEq β
inst✝¹ : DecidableEq α
inst✝ : (j : α) → Decidable (p j)
i : α
h : p i
⊢ (if h : p i then update v j x (e.symm { val := i, property := h }) else w i) =
    update (fun i => if h : p i then v (e.symm { val := i, property := h }) else w i) (↑(e j)) x i

Next tactic:
rw [dif_pos h, Function.update_apply_equiv_apply, Equiv.symm_symm,
      Function.update_apply, Function.update_apply, dif_pos h]
/-- The composition of an updated function with an equiv on a subtype can be expressed as an
updated function. -/
-- porting note: replace `s : Set α` and `: s` with `p : α → Prop` and `: Subtype p`, since the
-- former now unfolds syntactically to a less general case of the latter.
theorem dite_comp_equiv_update {α : Type*} {β : Sort*} {γ : Sort*} {p : α → Prop}
    (e : β ≃ Subtype p)
    (v : β → γ) (w : α → γ) (j : β) (x : γ) [DecidableEq β] [DecidableEq α]
    [∀ j, Decidable (p j)] :
    (fun i : α => if h : p i then (Function.update v j x) (e.symm ⟨i, h⟩) else w i) =
      Function.update (fun i : α => if h : p i then v (e.symm ⟨i, h⟩) else w i) (e j) x := by
  ext i
  by_cases h : p i
  · rw [dif_pos h, Function.update_apply_equiv_apply, Equiv.symm_symm,
      Function.update_apply, Function.update_apply, dif_pos h]
    

Proof state:
case pos
α✝ : Sort u
β✝ : Sort v
γ✝ : Sort w
α : Type u_1
β : Sort u_2
γ : Sort u_3
p : α → Prop
e : β ≃ Subtype p
v : β → γ
w : α → γ
j : β
x : γ
inst✝² : DecidableEq β
inst✝¹ : DecidableEq α
inst✝ : (j : α) → Decidable (p j)
i : α
h : p i
⊢ (if { val := i, property := h } = e j then x else (v ∘ ⇑e.symm) { val := i, property := h }) =
    if i = ↑(e j) then x else v (e.symm { val := i, property := h })

Next tactic:
have h_coe : (⟨i, h⟩ : Subtype p) = e j ↔ i = e j :=
      Subtype.ext_iff.trans (by rw [Subtype.coe_mk])
/-- The composition of an updated function with an equiv on a subtype can be expressed as an
updated function. -/
-- porting note: replace `s : Set α` and `: s` with `p : α → Prop` and `: Subtype p`, since the
-- former now unfolds syntactically to a less general case of the latter.
theorem dite_comp_equiv_update {α : Type*} {β : Sort*} {γ : Sort*} {p : α → Prop}
    (e : β ≃ Subtype p)
    (v : β → γ) (w : α → γ) (j : β) (x : γ) [DecidableEq β] [DecidableEq α]
    [∀ j, Decidable (p j)] :
    (fun i : α => if h : p i then (Function.update v j x) (e.symm ⟨i, h⟩) else w i) =
      Function.update (fun i : α => if h : p i then v (e.symm ⟨i, h⟩) else w i) (e j) x := by
  ext i
  by_cases h : p i
  · rw [dif_pos h, Function.update_apply_equiv_apply, Equiv.symm_symm,
      Function.update_apply, Function.update_apply, dif_pos h]
    have h_coe : (⟨i, h⟩ : Subtype p) = e j ↔ i = e j :=
      Subtype.ext_iff.trans (by 

Proof state:
α✝ : Sort u
β✝ : Sort v
γ✝ : Sort w
α : Type u_1
β : Sort u_2
γ : Sort u_3
p : α → Prop
e : β ≃ Subtype p
v : β → γ
w : α → γ
j : β
x : γ
inst✝² : DecidableEq β
inst✝¹ : DecidableEq α
inst✝ : (j : α) → Decidable (p j)
i : α
h : p i
⊢ ↑{ val := i, property := h } = ↑(e j) ↔ i = ↑(e j)

Next tactic:
rw [Subtype.coe_mk]