l3lab/ntp-mathlib huggingface dataset:
/-- Witness that the limit cone in `MonCat` is a limit cone.
(Internal use only; use the limits API.)
-/
@[to_additive "(Internal use only; use the limits API.)"]
noncomputable def limitConeIsLimit (F : J ⥤ MonCatMax.{u,v}) : IsLimit (limitCone F) := by
  refine IsLimit.ofFaithful (forget MonCatMax) (Types.limitConeIsLimit.{v,u} _)
    (fun s => { toFun := _, map_one' := ?_, map_mul' := ?_ }) (fun s => rfl) <;>
  

Proof state:
case refine_2
J : Type v
inst✝ : SmallCategory J
F : J ⥤ MonCatMax
s : Cone F
⊢ ∀ (x y : ↑s.pt),
    OneHom.toFun
        {
          toFun := fun v =>
            { val := fun j => ((forget MonCatMax).mapCone s).π.app j v,
              property :=
                (_ :
                  ∀ {j j' : J} (f : j ⟶ j'),
                    (((forget MonCatMax).mapCone s).π.app j ≫ (F ⋙ forget MonCatMax).map f) v =
                      ((forget MonCatMax).mapCone s).π.app j' v) },
          map_one' :=
            (_ :
              { val := fun j => ((forget MonCatMax).mapCone s).π.app j 1,
                  property :=
                    (_ :
                      ∀ {j j' : J} (f : j ⟶ j'),
                        (((forget MonCatMax).mapCone s).π.app j ≫ (F ⋙ forget MonCatMax).map f) 1 =
                          ((forget MonCatMax).mapCone s).π.app j' 1) } =
                1) }
        (x * y) =
      OneHom.toFun
          {
            toFun := fun v =>
              { val := fun j => ((forget MonCatMax).mapCone s).π.app j v,
                property :=
                  (_ :
                    ∀ {j j' : J} (f : j ⟶ j'),
                      (((forget MonCatMax).mapCone s).π.app j ≫ (F ⋙ forget MonCatMax).map f) v =
                        ((forget MonCatMax).mapCone s).π.app j' v) },
            map_one' :=
              (_ :
                { val := fun j => ((forget MonCatMax).mapCone s).π.app j 1,
                    property :=
                      (_ :
                        ∀ {j j' : J} (f : j ⟶ j'),
                          (((forget MonCatMax).mapCone s).π.app j ≫ (F ⋙ forget MonCatMax).map f) 1 =
                            ((forget MonCatMax).mapCone s).π.app j' 1) } =
                  1) }
          x *
        OneHom.toFun
          {
            toFun := fun v =>
              { val := fun j => ((forget MonCatMax).mapCone s).π.app j v,
                property :=
                  (_ :
                    ∀ {j j' : J} (f : j ⟶ j'),
                      (((forget MonCatMax).mapCone s).π.app j ≫ (F ⋙ forget MonCatMax).map f) v =
                        ((forget MonCatMax).mapCone s).π.app j' v) },
            map_one' :=
              (_ :
                { val := fun j => ((forget MonCatMax).mapCone s).π.app j 1,
                    property :=
                      (_ :
                        ∀ {j j' : J} (f : j ⟶ j'),
                          (((forget MonCatMax).mapCone s).π.app j ≫ (F ⋙ forget MonCatMax).map f) 1 =
                            ((forget MonCatMax).mapCone s).π.app j' 1) } =
                  1) }
          y

Next tactic:
aesop_cat
@[to_additive]
instance commMonoidObj (F : J ⥤ CommMonCatMax.{u,v}) (j) :
    CommMonoid ((F ⋙ forget CommMonCatMax.{u,v}).obj j) := by
  

Proof state:
J : Type v
inst✝ : SmallCategory J
F : J ⥤ CommMonCatMax
j : J
⊢ CommMonoid ((F ⋙ forget CommMonCatMax).obj j)

Next tactic:
change CommMonoid (F.obj j)
@[to_additive]
instance commMonoidObj (F : J ⥤ CommMonCatMax.{u,v}) (j) :
    CommMonoid ((F ⋙ forget CommMonCatMax.{u,v}).obj j) := by
  change CommMonoid (F.obj j)
  

Proof state:
J : Type v
inst✝ : SmallCategory J
F : J ⥤ CommMonCatMax
j : J
⊢ CommMonoid ↑(F.obj j)

Next tactic:
infer_instance
/-- We show that the forgetful functor `CommMonCat ⥤ MonCat` creates limits.

All we need to do is notice that the limit point has a `CommMonoid` instance available,
and then reuse the existing limit. -/
@[to_additive "We show that the forgetful functor `AddCommMonCat ⥤ AddMonCat` creates limits.\n\n
All we need to do is notice that the limit point has an `AddCommMonoid` instance available,\n
and then reuse the existing limit."]
noncomputable instance forget₂CreatesLimit (F : J ⥤ CommMonCatMax.{u,v}) :
    CreatesLimit F (forget₂ CommMonCat MonCatMax.{u, v}) :=
  createsLimitOfReflectsIso fun c' t =>
    { liftedCone :=
        { pt := CommMonCat.of (Types.limitCone (F ⋙ forget CommMonCat)).pt
          π :=
            { app := MonCat.limitπMonoidHom (F ⋙ forget₂ CommMonCatMax.{u,v} MonCatMax.{u,v})
              naturality :=
                (MonCat.HasLimits.limitCone
                      (F ⋙ forget₂ CommMonCat MonCat.{max v u})).π.naturality } }
      validLift := by 

Proof state:
J : Type v
inst✝ : SmallCategory J
F : J ⥤ CommMonCatMax
c' : Cone (F ⋙ forget₂ CommMonCat MonCatMax)
t : IsLimit c'
⊢ (forget₂ CommMonCat MonCatMax).mapCone
      { pt := of (Types.limitCone (F ⋙ forget CommMonCat)).pt,
        π := NatTrans.mk (limitπMonoidHom (F ⋙ forget₂ CommMonCatMax MonCatMax)) } ≅
    c'

Next tactic:
apply IsLimit.uniqueUpToIso (MonCat.HasLimits.limitConeIsLimit _) t
/-- The forgetful functor from commutative monoids to monoids preserves all limits.

This means the underlying type of a limit can be computed as a limit in the category of monoids. -/
@[to_additive AddCommMonCat.forget₂AddMonPreservesLimits "The forgetful functor from additive\n
commutative monoids to additive monoids preserves all limits.\n\n
This means the underlying type of a limit can be computed as a limit in the category of additive\n
monoids."]
noncomputable instance forget₂MonPreservesLimitsOfSize :
    PreservesLimitsOfSize.{v, v} (forget₂ CommMonCatMax.{u,v} MonCatMax.{u,v}) where
  preservesLimitsOfShape {J} 𝒥 := { preservesLimit := fun {F} => by 

Proof state:
J✝ : Type v
inst✝ : SmallCategory J✝
J : Type v
𝒥 : Category.{v, v} J
F : J ⥤ CommMonCatMax
⊢ PreservesLimit F (forget₂ CommMonCatMax MonCatMax)

Next tactic:
infer_instance
@[to_additive]
theorem prod_bool [CommMonoid α] (f : Bool → α) : ∏ b, f b = f true * f false := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : CommMonoid α
f : Bool → α
⊢ ∏ b : Bool, f b = f true * f false

Next tactic:
simp
@[to_additive]
theorem prod_extend_by_one [CommMonoid α] (s : Finset ι) (f : ι → α) :
    ∏ i, (if i ∈ s then f i else 1) = ∏ i in s, f i := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
ι : Type u_4
inst✝² : DecidableEq ι
inst✝¹ : Fintype ι
inst✝ : CommMonoid α
s : Finset ι
f : ι → α
⊢ (∏ i : ι, if i ∈ s then f i else 1) = ∏ i in s, f i

Next tactic:
rw [← prod_filter, filter_mem_eq_inter, univ_inter]
@[to_additive]
theorem prod_eq_mul {f : α → M} (a b : α) (h₁ : a ≠ b) (h₂ : ∀ x, x ≠ a ∧ x ≠ b → f x = 1) :
    ∏ x, f x = f a * f b := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
M : Type u_4
inst✝¹ : Fintype α
inst✝ : CommMonoid M
f : α → M
a b : α
h₁ : a ≠ b
h₂ : ∀ (x : α), x ≠ a ∧ x ≠ b → f x = 1
⊢ ∏ x : α, f x = f a * f b

Next tactic:
apply Finset.prod_eq_mul a b h₁ fun x _ hx => h₂ x hx
@[to_additive]
theorem prod_eq_mul {f : α → M} (a b : α) (h₁ : a ≠ b) (h₂ : ∀ x, x ≠ a ∧ x ≠ b → f x = 1) :
    ∏ x, f x = f a * f b := by
  apply Finset.prod_eq_mul a b h₁ fun x _ hx => h₂ x hx <;>
    

Proof state:
case ha
α : Type u_1
β : Type u_2
γ : Type u_3
M : Type u_4
inst✝¹ : Fintype α
inst✝ : CommMonoid M
f : α → M
a b : α
h₁ : a ≠ b
h₂ : ∀ (x : α), x ≠ a ∧ x ≠ b → f x = 1
⊢ a ∉ Finset.univ → f a = 1

Next tactic:
exact fun hc => (hc (Finset.mem_univ _)).elim
@[to_additive]
theorem prod_eq_mul {f : α → M} (a b : α) (h₁ : a ≠ b) (h₂ : ∀ x, x ≠ a ∧ x ≠ b → f x = 1) :
    ∏ x, f x = f a * f b := by
  apply Finset.prod_eq_mul a b h₁ fun x _ hx => h₂ x hx <;>
    

Proof state:
case hb
α : Type u_1
β : Type u_2
γ : Type u_3
M : Type u_4
inst✝¹ : Fintype α
inst✝ : CommMonoid M
f : α → M
a b : α
h₁ : a ≠ b
h₂ : ∀ (x : α), x ≠ a ∧ x ≠ b → f x = 1
⊢ b ∉ Finset.univ → f b = 1

Next tactic:
exact fun hc => (hc (Finset.mem_univ _)).elim
@[simp]
theorem Fintype.card_piFinset [DecidableEq α] [Fintype α] {δ : α → Type*} (t : ∀ a, Finset (δ a)) :
    (Fintype.piFinset t).card = ∏ a, Finset.card (t a) := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝¹ : DecidableEq α
inst✝ : Fintype α
δ : α → Type u_4
t : (a : α) → Finset (δ a)
⊢ Finset.card (piFinset t) = ∏ a : α, Finset.card (t a)

Next tactic:
simp [Fintype.piFinset, card_map]
@[simp]
theorem Fintype.card_fun [DecidableEq α] [Fintype α] [Fintype β] :
    Fintype.card (α → β) = Fintype.card β ^ Fintype.card α := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : DecidableEq α
inst✝¹ : Fintype α
inst✝ : Fintype β
⊢ card (α → β) = card β ^ card α

Next tactic:
rw [Fintype.card_pi, Finset.prod_const]
@[simp]
theorem Fintype.card_fun [DecidableEq α] [Fintype α] [Fintype β] :
    Fintype.card (α → β) = Fintype.card β ^ Fintype.card α := by
  rw [Fintype.card_pi, Finset.prod_const]; 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : DecidableEq α
inst✝¹ : Fintype α
inst✝ : Fintype β
⊢ card β ^ Finset.card univ = card β ^ card α

Next tactic:
rfl
@[simp]
theorem card_vector [Fintype α] (n : ℕ) : Fintype.card (Vector α n) = Fintype.card α ^ n := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : Fintype α
n : ℕ
⊢ Fintype.card (Vector α n) = Fintype.card α ^ n

Next tactic:
rw [Fintype.ofEquiv_card]
@[simp]
theorem card_vector [Fintype α] (n : ℕ) : Fintype.card (Vector α n) = Fintype.card α ^ n := by
  rw [Fintype.ofEquiv_card]; 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝ : Fintype α
n : ℕ
⊢ Fintype.card (Fin n → α) = Fintype.card α ^ n

Next tactic:
simp
@[to_additive (attr := simp)]
theorem Finset.prod_attach_univ [Fintype α] [CommMonoid β] (f : { a : α // a ∈ @univ α _ } → β) :
    ∏ x in univ.attach, f x = ∏ x, f ⟨x, mem_univ _⟩ :=
  Fintype.prod_equiv (Equiv.subtypeUnivEquiv fun x => mem_univ _) _ _ fun x => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝¹ : Fintype α
inst✝ : CommMonoid β
f : { a // a ∈ univ } → β
x : { x // x ∈ univ }
⊢ f x =
    f
      { val := (Equiv.subtypeUnivEquiv (_ : ∀ (x : α), x ∈ univ)) x,
        property := (_ : (Equiv.subtypeUnivEquiv (_ : ∀ (x : α), x ∈ univ)) x ∈ univ) }

Next tactic:
simp
/-- Taking a product over `univ.pi t` is the same as taking the product over `Fintype.piFinset t`.
  `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`, but differ
  in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`. -/
@[to_additive "Taking a sum over `univ.pi t` is the same as taking the sum over
  `Fintype.piFinset t`. `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`,
  but differ in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`."]
theorem Finset.prod_univ_pi [DecidableEq α] [Fintype α] [CommMonoid β] {δ : α → Type*}
    {t : ∀ a : α, Finset (δ a)} (f : (∀ a : α, a ∈ (univ : Finset α) → δ a) → β) :
    ∏ x in univ.pi t, f x = ∏ x in Fintype.piFinset t, f fun a _ => x a := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : DecidableEq α
inst✝¹ : Fintype α
inst✝ : CommMonoid β
δ : α → Type u_4
t : (a : α) → Finset (δ a)
f : ((a : α) → a ∈ univ → δ a) → β
⊢ ∏ x in pi univ t, f x = ∏ x in Fintype.piFinset t, f fun a x_1 => x a

Next tactic:
refine prod_bij (fun x _ a => x a (mem_univ _)) ?_ (by simp)
    (by simp (config := { contextual := true }) [Function.funext_iff]) fun x hx =>
    ⟨fun a _ => x a, by simp_all⟩
/-- Taking a product over `univ.pi t` is the same as taking the product over `Fintype.piFinset t`.
  `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`, but differ
  in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`. -/
@[to_additive "Taking a sum over `univ.pi t` is the same as taking the sum over
  `Fintype.piFinset t`. `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`,
  but differ in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`."]
theorem Finset.prod_univ_pi [DecidableEq α] [Fintype α] [CommMonoid β] {δ : α → Type*}
    {t : ∀ a : α, Finset (δ a)} (f : (∀ a : α, a ∈ (univ : Finset α) → δ a) → β) :
    ∏ x in univ.pi t, f x = ∏ x in Fintype.piFinset t, f fun a _ => x a := by
  refine prod_bij (fun x _ a => x a (mem_univ _)) ?_ (by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : DecidableEq α
inst✝¹ : Fintype α
inst✝ : CommMonoid β
δ : α → Type u_4
t : (a : α) → Finset (δ a)
f : ((a : α) → a ∈ univ → δ a) → β
⊢ ∀ (a : (a : α) → a ∈ univ → δ a) (ha : a ∈ pi univ t),
    f a = f fun a_1 x => (fun x x_1 a => x a (_ : a ∈ univ)) a ha a_1

Next tactic:
simp
/-- Taking a product over `univ.pi t` is the same as taking the product over `Fintype.piFinset t`.
  `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`, but differ
  in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`. -/
@[to_additive "Taking a sum over `univ.pi t` is the same as taking the sum over
  `Fintype.piFinset t`. `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`,
  but differ in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`."]
theorem Finset.prod_univ_pi [DecidableEq α] [Fintype α] [CommMonoid β] {δ : α → Type*}
    {t : ∀ a : α, Finset (δ a)} (f : (∀ a : α, a ∈ (univ : Finset α) → δ a) → β) :
    ∏ x in univ.pi t, f x = ∏ x in Fintype.piFinset t, f fun a _ => x a := by
  refine prod_bij (fun x _ a => x a (mem_univ _)) ?_ (by simp)
    (by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : DecidableEq α
inst✝¹ : Fintype α
inst✝ : CommMonoid β
δ : α → Type u_4
t : (a : α) → Finset (δ a)
f : ((a : α) → a ∈ univ → δ a) → β
⊢ ∀ (a₁ a₂ : (a : α) → a ∈ univ → δ a) (ha₁ : a₁ ∈ pi univ t) (ha₂ : a₂ ∈ pi univ t),
    (fun x x_1 a => x a (_ : a ∈ univ)) a₁ ha₁ = (fun x x_1 a => x a (_ : a ∈ univ)) a₂ ha₂ → a₁ = a₂

Next tactic:
simp (config := { contextual := true }) [Function.funext_iff]
/-- Taking a product over `univ.pi t` is the same as taking the product over `Fintype.piFinset t`.
  `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`, but differ
  in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`. -/
@[to_additive "Taking a sum over `univ.pi t` is the same as taking the sum over
  `Fintype.piFinset t`. `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`,
  but differ in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`."]
theorem Finset.prod_univ_pi [DecidableEq α] [Fintype α] [CommMonoid β] {δ : α → Type*}
    {t : ∀ a : α, Finset (δ a)} (f : (∀ a : α, a ∈ (univ : Finset α) → δ a) → β) :
    ∏ x in univ.pi t, f x = ∏ x in Fintype.piFinset t, f fun a _ => x a := by
  refine prod_bij (fun x _ a => x a (mem_univ _)) ?_ (by simp)
    (by simp (config := { contextual := true }) [Function.funext_iff]) fun x hx =>
    ⟨fun a _ => x a, by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : DecidableEq α
inst✝¹ : Fintype α
inst✝ : CommMonoid β
δ : α → Type u_4
t : (a : α) → Finset (δ a)
f : ((a : α) → a ∈ univ → δ a) → β
x : (a : α) → δ a
hx : x ∈ Fintype.piFinset t
⊢ ∃ (ha : (fun a x_1 => x a) ∈ pi univ t), x = (fun x x_1 a => x a (_ : a ∈ univ)) (fun a x_1 => x a) ha

Next tactic:
simp_all
/-- Taking a product over `univ.pi t` is the same as taking the product over `Fintype.piFinset t`.
  `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`, but differ
  in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`. -/
@[to_additive "Taking a sum over `univ.pi t` is the same as taking the sum over
  `Fintype.piFinset t`. `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`,
  but differ in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`."]
theorem Finset.prod_univ_pi [DecidableEq α] [Fintype α] [CommMonoid β] {δ : α → Type*}
    {t : ∀ a : α, Finset (δ a)} (f : (∀ a : α, a ∈ (univ : Finset α) → δ a) → β) :
    ∏ x in univ.pi t, f x = ∏ x in Fintype.piFinset t, f fun a _ => x a := by
  refine prod_bij (fun x _ a => x a (mem_univ _)) ?_ (by simp)
    (by simp (config := { contextual := true }) [Function.funext_iff]) fun x hx =>
    ⟨fun a _ => x a, by simp_all⟩
  -- Porting note: old proof was `by simp`
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : DecidableEq α
inst✝¹ : Fintype α
inst✝ : CommMonoid β
δ : α → Type u_4
t : (a : α) → Finset (δ a)
f : ((a : α) → a ∈ univ → δ a) → β
⊢ ∀ (a : (a : α) → a ∈ univ → δ a) (ha : a ∈ pi univ t), (fun x x_1 a => x a (_ : a ∈ univ)) a ha ∈ Fintype.piFinset t

Next tactic:
intro a ha
/-- Taking a product over `univ.pi t` is the same as taking the product over `Fintype.piFinset t`.
  `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`, but differ
  in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`. -/
@[to_additive "Taking a sum over `univ.pi t` is the same as taking the sum over
  `Fintype.piFinset t`. `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`,
  but differ in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`."]
theorem Finset.prod_univ_pi [DecidableEq α] [Fintype α] [CommMonoid β] {δ : α → Type*}
    {t : ∀ a : α, Finset (δ a)} (f : (∀ a : α, a ∈ (univ : Finset α) → δ a) → β) :
    ∏ x in univ.pi t, f x = ∏ x in Fintype.piFinset t, f fun a _ => x a := by
  refine prod_bij (fun x _ a => x a (mem_univ _)) ?_ (by simp)
    (by simp (config := { contextual := true }) [Function.funext_iff]) fun x hx =>
    ⟨fun a _ => x a, by simp_all⟩
  -- Porting note: old proof was `by simp`
  intro a ha
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : DecidableEq α
inst✝¹ : Fintype α
inst✝ : CommMonoid β
δ : α → Type u_4
t : (a : α) → Finset (δ a)
f : ((a : α) → a ∈ univ → δ a) → β
a : (a : α) → a ∈ univ → δ a
ha : a ∈ pi univ t
⊢ (fun x x_1 a => x a (_ : a ∈ univ)) a ha ∈ Fintype.piFinset t

Next tactic:
simp only [Fintype.piFinset, mem_map, mem_pi, Function.Embedding.coeFn_mk]
/-- Taking a product over `univ.pi t` is the same as taking the product over `Fintype.piFinset t`.
  `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`, but differ
  in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`. -/
@[to_additive "Taking a sum over `univ.pi t` is the same as taking the sum over
  `Fintype.piFinset t`. `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`,
  but differ in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`."]
theorem Finset.prod_univ_pi [DecidableEq α] [Fintype α] [CommMonoid β] {δ : α → Type*}
    {t : ∀ a : α, Finset (δ a)} (f : (∀ a : α, a ∈ (univ : Finset α) → δ a) → β) :
    ∏ x in univ.pi t, f x = ∏ x in Fintype.piFinset t, f fun a _ => x a := by
  refine prod_bij (fun x _ a => x a (mem_univ _)) ?_ (by simp)
    (by simp (config := { contextual := true }) [Function.funext_iff]) fun x hx =>
    ⟨fun a _ => x a, by simp_all⟩
  -- Porting note: old proof was `by simp`
  intro a ha
  simp only [Fintype.piFinset, mem_map, mem_pi, Function.Embedding.coeFn_mk]
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : DecidableEq α
inst✝¹ : Fintype α
inst✝ : CommMonoid β
δ : α → Type u_4
t : (a : α) → Finset (δ a)
f : ((a : α) → a ∈ univ → δ a) → β
a : (a : α) → a ∈ univ → δ a
ha : a ∈ pi univ t
⊢ ∃ a_1, (∀ (a : α) (h : a ∈ univ), a_1 a h ∈ t a) ∧ (fun a => a_1 a (_ : a ∈ univ)) = fun a_2 => a a_2 (_ : a_2 ∈ univ)

Next tactic:
exact ⟨a, by simpa using ha, by simp⟩
/-- Taking a product over `univ.pi t` is the same as taking the product over `Fintype.piFinset t`.
  `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`, but differ
  in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`. -/
@[to_additive "Taking a sum over `univ.pi t` is the same as taking the sum over
  `Fintype.piFinset t`. `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`,
  but differ in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`."]
theorem Finset.prod_univ_pi [DecidableEq α] [Fintype α] [CommMonoid β] {δ : α → Type*}
    {t : ∀ a : α, Finset (δ a)} (f : (∀ a : α, a ∈ (univ : Finset α) → δ a) → β) :
    ∏ x in univ.pi t, f x = ∏ x in Fintype.piFinset t, f fun a _ => x a := by
  refine prod_bij (fun x _ a => x a (mem_univ _)) ?_ (by simp)
    (by simp (config := { contextual := true }) [Function.funext_iff]) fun x hx =>
    ⟨fun a _ => x a, by simp_all⟩
  -- Porting note: old proof was `by simp`
  intro a ha
  simp only [Fintype.piFinset, mem_map, mem_pi, Function.Embedding.coeFn_mk]
  exact ⟨a, by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : DecidableEq α
inst✝¹ : Fintype α
inst✝ : CommMonoid β
δ : α → Type u_4
t : (a : α) → Finset (δ a)
f : ((a : α) → a ∈ univ → δ a) → β
a : (a : α) → a ∈ univ → δ a
ha : a ∈ pi univ t
⊢ ∀ (a_1 : α) (h : a_1 ∈ univ), a a_1 h ∈ t a_1

Next tactic:
simpa using ha
/-- Taking a product over `univ.pi t` is the same as taking the product over `Fintype.piFinset t`.
  `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`, but differ
  in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`. -/
@[to_additive "Taking a sum over `univ.pi t` is the same as taking the sum over
  `Fintype.piFinset t`. `univ.pi t` and `Fintype.piFinset t` are essentially the same `Finset`,
  but differ in the type of their element, `univ.pi t` is a `Finset (Π a ∈ univ, t a)` and
  `Fintype.piFinset t` is a `Finset (Π a, t a)`."]
theorem Finset.prod_univ_pi [DecidableEq α] [Fintype α] [CommMonoid β] {δ : α → Type*}
    {t : ∀ a : α, Finset (δ a)} (f : (∀ a : α, a ∈ (univ : Finset α) → δ a) → β) :
    ∏ x in univ.pi t, f x = ∏ x in Fintype.piFinset t, f fun a _ => x a := by
  refine prod_bij (fun x _ a => x a (mem_univ _)) ?_ (by simp)
    (by simp (config := { contextual := true }) [Function.funext_iff]) fun x hx =>
    ⟨fun a _ => x a, by simp_all⟩
  -- Porting note: old proof was `by simp`
  intro a ha
  simp only [Fintype.piFinset, mem_map, mem_pi, Function.Embedding.coeFn_mk]
  exact ⟨a, by simpa using ha, by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝² : DecidableEq α
inst✝¹ : Fintype α
inst✝ : CommMonoid β
δ : α → Type u_4
t : (a : α) → Finset (δ a)
f : ((a : α) → a ∈ univ → δ a) → β
a : (a : α) → a ∈ univ → δ a
ha : a ∈ pi univ t
⊢ (fun a_1 => a a_1 (_ : a_1 ∈ univ)) = fun a_1 => a a_1 (_ : a_1 ∈ univ)

Next tactic:
simp
/-- The product over `univ` of a sum can be written as a sum over the product of sets,
  `Fintype.piFinset`. `Finset.prod_sum` is an alternative statement when the product is not
  over `univ` -/
theorem Finset.prod_univ_sum [DecidableEq α] [Fintype α] [CommSemiring β] {δ : α → Type u_1}
    [∀ a : α, DecidableEq (δ a)] {t : ∀ a : α, Finset (δ a)} {f : ∀ a : α, δ a → β} :
    (∏ a, ∑ b in t a, f a b) = ∑ p in Fintype.piFinset t, ∏ x, f x (p x) := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
inst✝³ : DecidableEq α
inst✝² : Fintype α
inst✝¹ : CommSemiring β
δ : α → Type u_1
inst✝ : (a : α) → DecidableEq (δ a)
t : (a : α) → Finset (δ a)
f : (a : α) → δ a → β
⊢ ∏ a : α, ∑ b in t a, f a b = ∑ p in Fintype.piFinset t, ∏ x : α, f x (p x)

Next tactic:
simp only [Finset.prod_attach_univ, prod_sum, Finset.sum_univ_pi]