l3lab/ntp-mathlib huggingface dataset:
/-- A sigma type over an `Option` is equivalent to the sigma set over the original type,
if the fiber is empty at none. -/
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
    

Proof state:
α : Type ?u.77889
p : Option α → Type v
h : p none → False
x : Option α
⊢ p x → Option.isSome x = true

Next tactic:
cases x
/-- A sigma type over an `Option` is equivalent to the sigma set over the original type,
if the fiber is empty at none. -/
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
    · 

Proof state:
case none
α : Type ?u.77889
p : Option α → Type v
h : p none → False
⊢ p none → Option.isSome none = true

Next tactic:
intro n
/-- A sigma type over an `Option` is equivalent to the sigma set over the original type,
if the fiber is empty at none. -/
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
      

Proof state:
case none
α : Type ?u.77889
p : Option α → Type v
h : p none → False
n : p none
⊢ Option.isSome none = true

Next tactic:
exfalso
/-- A sigma type over an `Option` is equivalent to the sigma set over the original type,
if the fiber is empty at none. -/
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
      

Proof state:
case none.h
α : Type ?u.77889
p : Option α → Type v
h : p none → False
n : p none
⊢ False

Next tactic:
exact h n
/-- A sigma type over an `Option` is equivalent to the sigma set over the original type,
if the fiber is empty at none. -/
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
    · 

Proof state:
case some
α : Type ?u.77889
p : Option α → Type v
h : p none → False
val✝ : α
⊢ p (some val✝) → Option.isSome (some val✝) = true

Next tactic:
intro _
/-- A sigma type over an `Option` is equivalent to the sigma set over the original type,
if the fiber is empty at none. -/
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 _
      

Proof state:
case some
α : Type ?u.77889
p : Option α → Type v
h : p none → False
val✝ : α
a✝ : p (some val✝)
⊢ Option.isSome (some val✝) = true

Next tactic:
exact rfl
/-- 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`. -/
def piEquivSubtypeSigma (ι) (π : ι → Type*) :
    (∀ i, π i) ≃ { f : ι → Σ i, π i // ∀ i, (f i).1 = i } where
  toFun := fun f => ⟨fun i => ⟨i, f i⟩, fun i => rfl⟩
  invFun := fun f i => by 

Proof state:
ι : Type ?u.78296
π : ι → Type u_1
f : { f // ∀ (i : ι), (f i).fst = i }
i : ι
⊢ π i

Next tactic:
rw [← f.2 i]
/-- 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`. -/
def piEquivSubtypeSigma (ι) (π : ι → Type*) :
    (∀ i, π i) ≃ { f : ι → Σ i, π i // ∀ i, (f i).1 = i } where
  toFun := fun f => ⟨fun i => ⟨i, f i⟩, fun i => rfl⟩
  invFun := fun f i => by rw [← f.2 i]; 

Proof state:
ι : Type ?u.78296
π : ι → Type u_1
f : { f // ∀ (i : ι), (f i).fst = i }
i : ι
⊢ π (↑f i).fst

Next tactic:
exact (f.1 i).2
/-- 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`. -/
def piEquivSubtypeSigma (ι) (π : ι → Type*) :
    (∀ i, π i) ≃ { f : ι → Σ i, π i // ∀ i, (f i).1 = i } where
  toFun := fun f => ⟨fun i => ⟨i, f i⟩, fun i => rfl⟩
  invFun := fun f i => by rw [← f.2 i]; exact (f.1 i).2
  left_inv := fun f => funext fun i => rfl
  right_inv := fun ⟨f, hf⟩ =>
    Subtype.eq <| funext fun i =>
      Sigma.eq (hf i).symm <| eq_of_heq <| rec_heq_of_heq _ <| by 

Proof state:
ι : Type ?u.78296
π : ι → Type u_1
x✝ : { f // ∀ (i : ι), (f i).fst = i }
f : ι → (i : ι) × π i
hf : ∀ (i : ι), (f i).fst = i
i : ι
⊢ HEq
    (↑((fun f =>
              { val := fun i => { fst := i, snd := f i },
                property :=
                  (_ :
                    ∀ (i : ι),
                      ((fun i => { fst := i, snd := f i }) i).fst = ((fun i => { fst := i, snd := f i }) i).fst) })
            ((fun f i => Eq.mpr (_ : π i = π (↑f i).fst) (↑f i).snd) { val := f, property := hf }))
        i).snd
    (↑{ val := f, property := hf } i).snd

Next tactic:
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}`. -/
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
    

Proof state:
α : Sort ?u.79333
β : α → Sort v
p : (a : α) → β a → Prop
⊢ LeftInverse (fun f => { val := fun a => ↑(f a), property := (_ : ∀ (a : α), p a ↑(f a)) }) fun f a =>
    { val := ↑f a, property := (_ : p a (↑f a)) }

Next tactic:
rintro ⟨f, h⟩
/-- 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}`. -/
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⟩
    

Proof state:
case mk
α : Sort ?u.79333
β : α → Sort v
p : (a : α) → β a → Prop
f : (a : α) → β a
h : ∀ (a : α), p a (f a)
⊢ (fun f => { val := fun a => ↑(f a), property := (_ : ∀ (a : α), p a ↑(f a)) })
      ((fun f a => { val := ↑f a, property := (_ : p a (↑f a)) }) { val := f, property := h }) =
    { val := f, property := h }

Next tactic:
rfl
/-- 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}`. -/
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
    

Proof state:
α : Sort ?u.79333
β : α → Sort v
p : (a : α) → β a → Prop
⊢ Function.RightInverse (fun f => { val := fun a => ↑(f a), property := (_ : ∀ (a : α), p a ↑(f a)) }) fun f a =>
    { val := ↑f a, property := (_ : p a (↑f a)) }

Next tactic:
rintro f
/-- 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}`. -/
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
    

Proof state:
α : Sort ?u.79333
β : α → Sort v
p : (a : α) → β a → Prop
f : (a : α) → { b // p a b }
⊢ (fun f a => { val := ↑f a, property := (_ : p a (↑f a)) })
      ((fun f => { val := fun a => ↑(f a), property := (_ : ∀ (a : α), p a ↑(f a)) }) f) =
    f

Next tactic:
funext a
/-- 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}`. -/
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
    

Proof state:
case h
α : Sort ?u.79333
β : α → Sort v
p : (a : α) → β a → Prop
f : (a : α) → { b // p a b }
a : α
⊢ (fun f a => { val := ↑f a, property := (_ : p a (↑f a)) })
      ((fun f => { val := fun a => ↑(f a), property := (_ : ∀ (a : α), p a ↑(f a)) }) f) a =
    f a

Next tactic:
exact Subtype.ext_val rfl
/-- A subtype of a `Prod` is equivalent to a sigma type whose fibers are subtypes. -/
def subtypeProdEquivSigmaSubtype (p : α → β → Prop) :
    { x : α × β // p x.1 x.2 } ≃ Σa, { b : β // p a b } where
  toFun x := ⟨x.1.1, x.1.2, x.property⟩
  invFun x := ⟨⟨x.1, x.2⟩, x.2.property⟩
  left_inv x := by 

Proof state:
α : Type ?u.80864
β : Type ?u.80863
p : α → β → Prop
x : { x // p x.1 x.2 }
⊢ (fun x => { val := (x.fst, ↑x.snd), property := (_ : p x.fst ↑x.snd) })
      ((fun x => { fst := (↑x).1, snd := { val := (↑x).2, property := (_ : p (↑x).1 (↑x).2) } }) x) =
    x

Next tactic:
ext
/-- A subtype of a `Prod` is equivalent to a sigma type whose fibers are subtypes. -/
def subtypeProdEquivSigmaSubtype (p : α → β → Prop) :
    { x : α × β // p x.1 x.2 } ≃ Σa, { b : β // p a b } where
  toFun x := ⟨x.1.1, x.1.2, x.property⟩
  invFun x := ⟨⟨x.1, x.2⟩, x.2.property⟩
  left_inv x := by ext <;> 

Proof state:
case a.a
α : Type ?u.80864
β : Type ?u.80863
p : α → β → Prop
x : { x // p x.1 x.2 }
⊢ (↑((fun x => { val := (x.fst, ↑x.snd), property := (_ : p x.fst ↑x.snd) })
          ((fun x => { fst := (↑x).1, snd := { val := (↑x).2, property := (_ : p (↑x).1 (↑x).2) } }) x))).1 =
    (↑x).1

Next tactic:
rfl
/-- A subtype of a `Prod` is equivalent to a sigma type whose fibers are subtypes. -/
def subtypeProdEquivSigmaSubtype (p : α → β → Prop) :
    { x : α × β // p x.1 x.2 } ≃ Σa, { b : β // p a b } where
  toFun x := ⟨x.1.1, x.1.2, x.property⟩
  invFun x := ⟨⟨x.1, x.2⟩, x.2.property⟩
  left_inv x := by ext <;> 

Proof state:
case a.a
α : Type ?u.80864
β : Type ?u.80863
p : α → β → Prop
x : { x // p x.1 x.2 }
⊢ (↑((fun x => { val := (x.fst, ↑x.snd), property := (_ : p x.fst ↑x.snd) })
          ((fun x => { fst := (↑x).1, snd := { val := (↑x).2, property := (_ : p (↑x).1 (↑x).2) } }) x))).2 =
    (↑x).2

Next tactic:
rfl
/-- The type `∀ (i : α), β i` can be split as a product by separating the indices in `α`
depending on whether they satisfy a predicate `p` or not. -/
@[simps]
def piEquivPiSubtypeProd {α : Type*} (p : α → Prop) (β : α → Type*) [DecidablePred p] :
    (∀ i : α, β i) ≃ (∀ i : { x // p x }, β i) × ∀ i : { x // ¬p x }, β i where
  toFun f := (fun x => f x, fun x => f x)
  invFun f x := if h : p x then f.1 ⟨x, h⟩ else f.2 ⟨x, h⟩
  right_inv := by
    rintro ⟨f, g⟩
    ext1 <;>
      · ext y
        rcases y with ⟨val, property⟩
        simp only [property, dif_pos, dif_neg, not_false_iff, Subtype.coe_mk]
  left_inv f := by
    

Proof state:
α : Type u_1
p : α → Prop
β : α → Type u_2
inst✝ : DecidablePred p
f : (i : α) → β i
⊢ (fun f x => if h : p x then f.1 { val := x, property := h } else f.2 { val := x, property := h })
      ((fun f => (fun x => f ↑x, fun x => f ↑x)) f) =
    f

Next tactic:
ext x
/-- The type `∀ (i : α), β i` can be split as a product by separating the indices in `α`
depending on whether they satisfy a predicate `p` or not. -/
@[simps]
def piEquivPiSubtypeProd {α : Type*} (p : α → Prop) (β : α → Type*) [DecidablePred p] :
    (∀ i : α, β i) ≃ (∀ i : { x // p x }, β i) × ∀ i : { x // ¬p x }, β i where
  toFun f := (fun x => f x, fun x => f x)
  invFun f x := if h : p x then f.1 ⟨x, h⟩ else f.2 ⟨x, h⟩
  right_inv := by
    rintro ⟨f, g⟩
    ext1 <;>
      · ext y
        rcases y with ⟨val, property⟩
        simp only [property, dif_pos, dif_neg, not_false_iff, Subtype.coe_mk]
  left_inv f := by
    ext x
    

Proof state:
case h
α : Type u_1
p : α → Prop
β : α → Type u_2
inst✝ : DecidablePred p
f : (i : α) → β i
x : α
⊢ (fun f x => if h : p x then f.1 { val := x, property := h } else f.2 { val := x, property := h })
      ((fun f => (fun x => f ↑x, fun x => f ↑x)) f) x =
    f x

Next tactic:
by_cases h:p x
/-- The type `∀ (i : α), β i` can be split as a product by separating the indices in `α`
depending on whether they satisfy a predicate `p` or not. -/
@[simps]
def piEquivPiSubtypeProd {α : Type*} (p : α → Prop) (β : α → Type*) [DecidablePred p] :
    (∀ i : α, β i) ≃ (∀ i : { x // p x }, β i) × ∀ i : { x // ¬p x }, β i where
  toFun f := (fun x => f x, fun x => f x)
  invFun f x := if h : p x then f.1 ⟨x, h⟩ else f.2 ⟨x, h⟩
  right_inv := by
    rintro ⟨f, g⟩
    ext1 <;>
      · ext y
        rcases y with ⟨val, property⟩
        simp only [property, dif_pos, dif_neg, not_false_iff, Subtype.coe_mk]
  left_inv f := by
    ext x
    by_cases h:p x <;>
      · 

Proof state:
case pos
α : Type u_1
p : α → Prop
β : α → Type u_2
inst✝ : DecidablePred p
f : (i : α) → β i
x : α
h : p x
⊢ (fun f x => if h : p x then f.1 { val := x, property := h } else f.2 { val := x, property := h })
      ((fun f => (fun x => f ↑x, fun x => f ↑x)) f) x =
    f x

Next tactic:
simp only [h, dif_neg, dif_pos, not_false_iff]
/-- The type `∀ (i : α), β i` can be split as a product by separating the indices in `α`
depending on whether they satisfy a predicate `p` or not. -/
@[simps]
def piEquivPiSubtypeProd {α : Type*} (p : α → Prop) (β : α → Type*) [DecidablePred p] :
    (∀ i : α, β i) ≃ (∀ i : { x // p x }, β i) × ∀ i : { x // ¬p x }, β i where
  toFun f := (fun x => f x, fun x => f x)
  invFun f x := if h : p x then f.1 ⟨x, h⟩ else f.2 ⟨x, h⟩
  right_inv := by
    rintro ⟨f, g⟩
    ext1 <;>
      · ext y
        rcases y with ⟨val, property⟩
        simp only [property, dif_pos, dif_neg, not_false_iff, Subtype.coe_mk]
  left_inv f := by
    ext x
    by_cases h:p x <;>
      · 

Proof state:
case neg
α : Type u_1
p : α → Prop
β : α → Type u_2
inst✝ : DecidablePred p
f : (i : α) → β i
x : α
h : ¬p x
⊢ (fun f x => if h : p x then f.1 { val := x, property := h } else f.2 { val := x, property := h })
      ((fun f => (fun x => f ↑x, fun x => f ↑x)) f) x =
    f x

Next tactic:
simp only [h, dif_neg, dif_pos, not_false_iff]
/-- The type `∀ (i : α), β i` can be split as a product by separating the indices in `α`
depending on whether they satisfy a predicate `p` or not. -/
@[simps]
def piEquivPiSubtypeProd {α : Type*} (p : α → Prop) (β : α → Type*) [DecidablePred p] :
    (∀ i : α, β i) ≃ (∀ i : { x // p x }, β i) × ∀ i : { x // ¬p x }, β i where
  toFun f := (fun x => f x, fun x => f x)
  invFun f x := if h : p x then f.1 ⟨x, h⟩ else f.2 ⟨x, h⟩
  right_inv := by
    

Proof state:
α : Type u_1
p : α → Prop
β : α → Type u_2
inst✝ : DecidablePred p
⊢ Function.RightInverse
    (fun f x => if h : p x then f.1 { val := x, property := h } else f.2 { val := x, property := h }) fun f =>
    (fun x => f ↑x, fun x => f ↑x)

Next tactic:
rintro ⟨f, g⟩
/-- The type `∀ (i : α), β i` can be split as a product by separating the indices in `α`
depending on whether they satisfy a predicate `p` or not. -/
@[simps]
def piEquivPiSubtypeProd {α : Type*} (p : α → Prop) (β : α → Type*) [DecidablePred p] :
    (∀ i : α, β i) ≃ (∀ i : { x // p x }, β i) × ∀ i : { x // ¬p x }, β i where
  toFun f := (fun x => f x, fun x => f x)
  invFun f x := if h : p x then f.1 ⟨x, h⟩ else f.2 ⟨x, h⟩
  right_inv := by
    rintro ⟨f, g⟩
    

Proof state:
case mk
α : Type u_1
p : α → Prop
β : α → Type u_2
inst✝ : DecidablePred p
f : (i : { x // p x }) → β ↑i
g : (i : { x // ¬p x }) → β ↑i
⊢ (fun f => (fun x => f ↑x, fun x => f ↑x))
      ((fun f x => if h : p x then f.1 { val := x, property := h } else f.2 { val := x, property := h }) (f, g)) =
    (f, g)

Next tactic:
ext1
/-- The type `∀ (i : α), β i` can be split as a product by separating the indices in `α`
depending on whether they satisfy a predicate `p` or not. -/
@[simps]
def piEquivPiSubtypeProd {α : Type*} (p : α → Prop) (β : α → Type*) [DecidablePred p] :
    (∀ i : α, β i) ≃ (∀ i : { x // p x }, β i) × ∀ i : { x // ¬p x }, β i where
  toFun f := (fun x => f x, fun x => f x)
  invFun f x := if h : p x then f.1 ⟨x, h⟩ else f.2 ⟨x, h⟩
  right_inv := by
    rintro ⟨f, g⟩
    ext1 <;>
      · 

Proof state:
case mk.a
α : Type u_1
p : α → Prop
β : α → Type u_2
inst✝ : DecidablePred p
f : (i : { x // p x }) → β ↑i
g : (i : { x // ¬p x }) → β ↑i
⊢ ((fun f => (fun x => f ↑x, fun x => f ↑x))
        ((fun f x => if h : p x then f.1 { val := x, property := h } else f.2 { val := x, property := h }) (f, g))).1 =
    (f, g).1

Next tactic:
ext y
/-- The type `∀ (i : α), β i` can be split as a product by separating the indices in `α`
depending on whether they satisfy a predicate `p` or not. -/
@[simps]
def piEquivPiSubtypeProd {α : Type*} (p : α → Prop) (β : α → Type*) [DecidablePred p] :
    (∀ i : α, β i) ≃ (∀ i : { x // p x }, β i) × ∀ i : { x // ¬p x }, β i where
  toFun f := (fun x => f x, fun x => f x)
  invFun f x := if h : p x then f.1 ⟨x, h⟩ else f.2 ⟨x, h⟩
  right_inv := by
    rintro ⟨f, g⟩
    ext1 <;>
      · ext y
        

Proof state:
case mk.a.h
α : Type u_1
p : α → Prop
β : α → Type u_2
inst✝ : DecidablePred p
f : (i : { x // p x }) → β ↑i
g : (i : { x // ¬p x }) → β ↑i
y : { x // p x }
⊢ ((fun f => (fun x => f ↑x, fun x => f ↑x))
          ((fun f x => if h : p x then f.1 { val := x, property := h } else f.2 { val := x, property := h }) (f, g))).1
      y =
    (f, g).1 y

Next tactic:
rcases y with ⟨val, property⟩
/-- The type `∀ (i : α), β i` can be split as a product by separating the indices in `α`
depending on whether they satisfy a predicate `p` or not. -/
@[simps]
def piEquivPiSubtypeProd {α : Type*} (p : α → Prop) (β : α → Type*) [DecidablePred p] :
    (∀ i : α, β i) ≃ (∀ i : { x // p x }, β i) × ∀ i : { x // ¬p x }, β i where
  toFun f := (fun x => f x, fun x => f x)
  invFun f x := if h : p x then f.1 ⟨x, h⟩ else f.2 ⟨x, h⟩
  right_inv := by
    rintro ⟨f, g⟩
    ext1 <;>
      · ext y
        rcases y with ⟨val, property⟩
        

Proof state:
case mk.a.h.mk
α : Type u_1
p : α → Prop
β : α → Type u_2
inst✝ : DecidablePred p
f : (i : { x // p x }) → β ↑i
g : (i : { x // ¬p x }) → β ↑i
val : α
property : p val
⊢ ((fun f => (fun x => f ↑x, fun x => f ↑x))
          ((fun f x => if h : p x then f.1 { val := x, property := h } else f.2 { val := x, property := h }) (f, g))).1
      { val := val, property := property } =
    (f, g).1 { val := val, property := property }

Next tactic:
simp only [property, dif_pos, dif_neg, not_false_iff, Subtype.coe_mk]
/-- The type `∀ (i : α), β i` can be split as a product by separating the indices in `α`
depending on whether they satisfy a predicate `p` or not. -/
@[simps]
def piEquivPiSubtypeProd {α : Type*} (p : α → Prop) (β : α → Type*) [DecidablePred p] :
    (∀ i : α, β i) ≃ (∀ i : { x // p x }, β i) × ∀ i : { x // ¬p x }, β i where
  toFun f := (fun x => f x, fun x => f x)
  invFun f x := if h : p x then f.1 ⟨x, h⟩ else f.2 ⟨x, h⟩
  right_inv := by
    rintro ⟨f, g⟩
    ext1 <;>
      · 

Proof state:
case mk.a
α : Type u_1
p : α → Prop
β : α → Type u_2
inst✝ : DecidablePred p
f : (i : { x // p x }) → β ↑i
g : (i : { x // ¬p x }) → β ↑i
⊢ ((fun f => (fun x => f ↑x, fun x => f ↑x))
        ((fun f x => if h : p x then f.1 { val := x, property := h } else f.2 { val := x, property := h }) (f, g))).2 =
    (f, g).2

Next tactic:
ext y
/-- The type `∀ (i : α), β i` can be split as a product by separating the indices in `α`
depending on whether they satisfy a predicate `p` or not. -/
@[simps]
def piEquivPiSubtypeProd {α : Type*} (p : α → Prop) (β : α → Type*) [DecidablePred p] :
    (∀ i : α, β i) ≃ (∀ i : { x // p x }, β i) × ∀ i : { x // ¬p x }, β i where
  toFun f := (fun x => f x, fun x => f x)
  invFun f x := if h : p x then f.1 ⟨x, h⟩ else f.2 ⟨x, h⟩
  right_inv := by
    rintro ⟨f, g⟩
    ext1 <;>
      · ext y
        

Proof state:
case mk.a.h
α : Type u_1
p : α → Prop
β : α → Type u_2
inst✝ : DecidablePred p
f : (i : { x // p x }) → β ↑i
g : (i : { x // ¬p x }) → β ↑i
y : { x // ¬p x }
⊢ ((fun f => (fun x => f ↑x, fun x => f ↑x))
          ((fun f x => if h : p x then f.1 { val := x, property := h } else f.2 { val := x, property := h }) (f, g))).2
      y =
    (f, g).2 y

Next tactic:
rcases y with ⟨val, property⟩
/-- The type `∀ (i : α), β i` can be split as a product by separating the indices in `α`
depending on whether they satisfy a predicate `p` or not. -/
@[simps]
def piEquivPiSubtypeProd {α : Type*} (p : α → Prop) (β : α → Type*) [DecidablePred p] :
    (∀ i : α, β i) ≃ (∀ i : { x // p x }, β i) × ∀ i : { x // ¬p x }, β i where
  toFun f := (fun x => f x, fun x => f x)
  invFun f x := if h : p x then f.1 ⟨x, h⟩ else f.2 ⟨x, h⟩
  right_inv := by
    rintro ⟨f, g⟩
    ext1 <;>
      · ext y
        rcases y with ⟨val, property⟩
        

Proof state:
case mk.a.h.mk
α : Type u_1
p : α → Prop
β : α → Type u_2
inst✝ : DecidablePred p
f : (i : { x // p x }) → β ↑i
g : (i : { x // ¬p x }) → β ↑i
val : α
property : ¬p val
⊢ ((fun f => (fun x => f ↑x, fun x => f ↑x))
          ((fun f x => if h : p x then f.1 { val := x, property := h } else f.2 { val := x, property := h }) (f, g))).2
      { val := val, property := property } =
    (f, g).2 { val := val, property := property }

Next tactic:
simp only [property, dif_pos, dif_neg, not_false_iff, Subtype.coe_mk]
/-- A product of types can be split as the binary product of one of the types and the product
  of all the remaining types. -/
@[simps]
def piSplitAt {α : Type*} [DecidableEq α] (i : α) (β : α → Type*) :
    (∀ j, β j) ≃ β i × ∀ j : { j // j ≠ i }, β j where
  toFun f := ⟨f i, fun j => f j⟩
  invFun f j := if h : j = i then h.symm.rec f.1 else f.2 ⟨j, h⟩
  right_inv f := by
    ext x
    exacts [dif_pos rfl, (dif_neg x.2).trans (by cases x; rfl)]
  left_inv f := by
    

Proof state:
α : Type u_1
inst✝ : DecidableEq α
i : α
β : α → Type u_2
f : (j : α) → β j
⊢ (fun f j => if h : j = i then (_ : i = j) ▸ f.1 else f.2 { val := j, property := h })
      ((fun f => (f i, fun j => f ↑j)) f) =
    f

Next tactic:
ext x
/-- A product of types can be split as the binary product of one of the types and the product
  of all the remaining types. -/
@[simps]
def piSplitAt {α : Type*} [DecidableEq α] (i : α) (β : α → Type*) :
    (∀ j, β j) ≃ β i × ∀ j : { j // j ≠ i }, β j where
  toFun f := ⟨f i, fun j => f j⟩
  invFun f j := if h : j = i then h.symm.rec f.1 else f.2 ⟨j, h⟩
  right_inv f := by
    ext x
    exacts [dif_pos rfl, (dif_neg x.2).trans (by cases x; rfl)]
  left_inv f := by
    ext x
    

Proof state:
case h
α : Type u_1
inst✝ : DecidableEq α
i : α
β : α → Type u_2
f : (j : α) → β j
x : α
⊢ (fun f j => if h : j = i then (_ : i = j) ▸ f.1 else f.2 { val := j, property := h })
      ((fun f => (f i, fun j => f ↑j)) f) x =
    f x

Next tactic:
dsimp only
/-- A product of types can be split as the binary product of one of the types and the product
  of all the remaining types. -/
@[simps]
def piSplitAt {α : Type*} [DecidableEq α] (i : α) (β : α → Type*) :
    (∀ j, β j) ≃ β i × ∀ j : { j // j ≠ i }, β j where
  toFun f := ⟨f i, fun j => f j⟩
  invFun f j := if h : j = i then h.symm.rec f.1 else f.2 ⟨j, h⟩
  right_inv f := by
    ext x
    exacts [dif_pos rfl, (dif_neg x.2).trans (by cases x; rfl)]
  left_inv f := by
    ext x
    dsimp only
    

Proof state:
case h
α : Type u_1
inst✝ : DecidableEq α
i : α
β : α → Type u_2
f : (j : α) → β j
x : α
⊢ (if h : x = i then (_ : i = x) ▸ f i else f x) = f x

Next tactic:
split_ifs with h
/-- A product of types can be split as the binary product of one of the types and the product
  of all the remaining types. -/
@[simps]
def piSplitAt {α : Type*} [DecidableEq α] (i : α) (β : α → Type*) :
    (∀ j, β j) ≃ β i × ∀ j : { j // j ≠ i }, β j where
  toFun f := ⟨f i, fun j => f j⟩
  invFun f j := if h : j = i then h.symm.rec f.1 else f.2 ⟨j, h⟩
  right_inv f := by
    ext x
    exacts [dif_pos rfl, (dif_neg x.2).trans (by cases x; rfl)]
  left_inv f := by
    ext x
    dsimp only
    split_ifs with h
    · 

Proof state:
case pos
α : Type u_1
inst✝ : DecidableEq α
i : α
β : α → Type u_2
f : (j : α) → β j
x : α
h : x = i
⊢ (_ : i = x) ▸ f i = f x

Next tactic:
subst h