l3lab/ntp-mathlib huggingface dataset:
/-- In a *-monoid, `unitary R` is the submonoid consisting of all the elements `U` of
`R` such that `star U * U = 1` and `U * star U = 1`.
-/
def unitary (R : Type*) [Monoid R] [StarMul R] : Submonoid R where
  carrier := { U | star U * U = 1 ∧ U * star U = 1 }
  one_mem' := by simp only [mul_one, and_self_iff, Set.mem_setOf_eq, star_one]
  mul_mem' := @fun U B ⟨hA₁, hA₂⟩ ⟨hB₁, hB₂⟩ => by
    refine' ⟨_, _⟩
    · calc
        star (U * B) * (U * B) = star B * star U * U * B := by simp only [mul_assoc, star_mul]
        _ = star B * (star U * U) * B := by rw [← mul_assoc]
        _ = 1 := by rw [hA₁, mul_one, hB₁]
    · calc
        U * B * star (U * B) = U * B * (star B * star U) := by rw [star_mul]
        _ = U * (B * star B) * star U := by 

Proof state:
R : Type u_1
inst✝¹ : Monoid R
inst✝ : StarMul R
U B : R
x✝¹ : U ∈ {U | star U * U = 1 ∧ U * star U = 1}
x✝ : B ∈ {U | star U * U = 1 ∧ U * star U = 1}
hA₁ : star U * U = 1
hA₂ : U * star U = 1
hB₁ : star B * B = 1
hB₂ : B * star B = 1
⊢ U * B * (star B * star U) = U * (B * star B) * star U

Next tactic:
simp_rw [← mul_assoc]
/-- In a *-monoid, `unitary R` is the submonoid consisting of all the elements `U` of
`R` such that `star U * U = 1` and `U * star U = 1`.
-/
def unitary (R : Type*) [Monoid R] [StarMul R] : Submonoid R where
  carrier := { U | star U * U = 1 ∧ U * star U = 1 }
  one_mem' := by simp only [mul_one, and_self_iff, Set.mem_setOf_eq, star_one]
  mul_mem' := @fun U B ⟨hA₁, hA₂⟩ ⟨hB₁, hB₂⟩ => by
    refine' ⟨_, _⟩
    · calc
        star (U * B) * (U * B) = star B * star U * U * B := by simp only [mul_assoc, star_mul]
        _ = star B * (star U * U) * B := by rw [← mul_assoc]
        _ = 1 := by rw [hA₁, mul_one, hB₁]
    · calc
        U * B * star (U * B) = U * B * (star B * star U) := by rw [star_mul]
        _ = U * (B * star B) * star U := by simp_rw [← mul_assoc]
        _ = 1 := by 

Proof state:
R : Type u_1
inst✝¹ : Monoid R
inst✝ : StarMul R
U B : R
x✝¹ : U ∈ {U | star U * U = 1 ∧ U * star U = 1}
x✝ : B ∈ {U | star U * U = 1 ∧ U * star U = 1}
hA₁ : star U * U = 1
hA₂ : U * star U = 1
hB₁ : star B * B = 1
hB₂ : B * star B = 1
⊢ U * (B * star B) * star U = 1

Next tactic:
rw [hB₂, mul_one, hA₂]
/-- In a *-monoid, `unitary R` is the submonoid consisting of all the elements `U` of
`R` such that `star U * U = 1` and `U * star U = 1`.
-/
def unitary (R : Type*) [Monoid R] [StarMul R] : Submonoid R where
  carrier := { U | star U * U = 1 ∧ U * star U = 1 }
  one_mem' := by 

Proof state:
R : Type u_1
inst✝¹ : Monoid R
inst✝ : StarMul R
⊢ 1 ∈
    { carrier := {U | star U * U = 1 ∧ U * star U = 1},
        mul_mem' :=
          (_ :
            ∀ (U B : R),
              U ∈ {U | star U * U = 1 ∧ U * star U = 1} →
                B ∈ {U | star U * U = 1 ∧ U * star U = 1} → U * B ∈ {U | star U * U = 1 ∧ U * star U = 1}) }.carrier

Next tactic:
simp only [mul_one, and_self_iff, Set.mem_setOf_eq, star_one]
theorem star_mem {U : R} (hU : U ∈ unitary R) : star U ∈ unitary R :=
  ⟨by 

Proof state:
R : Type u_1
inst✝¹ : Monoid R
inst✝ : StarMul R
U : R
hU : U ∈ unitary R
⊢ star (star U) * star U = 1

Next tactic:
rw [star_star, mul_star_self_of_mem hU]
theorem star_mem {U : R} (hU : U ∈ unitary R) : star U ∈ unitary R :=
  ⟨by rw [star_star, mul_star_self_of_mem hU], by 

Proof state:
R : Type u_1
inst✝¹ : Monoid R
inst✝ : StarMul R
U : R
hU : U ∈ unitary R
⊢ star U * star (star U) = 1

Next tactic:
rw [star_star, star_mul_self_of_mem hU]
instance : InvolutiveStar (unitary R) :=
  ⟨by
    

Proof state:
R : Type u_1
inst✝¹ : Monoid R
inst✝ : StarMul R
⊢ Function.Involutive star

Next tactic:
intro x
instance : InvolutiveStar (unitary R) :=
  ⟨by
    intro x
    

Proof state:
R : Type u_1
inst✝¹ : Monoid R
inst✝ : StarMul R
x : ↥(unitary R)
⊢ star (star x) = x

Next tactic:
ext
instance : InvolutiveStar (unitary R) :=
  ⟨by
    intro x
    ext
    

Proof state:
case a
R : Type u_1
inst✝¹ : Monoid R
inst✝ : StarMul R
x : ↥(unitary R)
⊢ ↑(star (star x)) = ↑x

Next tactic:
rw [coe_star, coe_star, star_star]
instance : StarMul (unitary R) :=
  ⟨by
    

Proof state:
R : Type u_1
inst✝¹ : Monoid R
inst✝ : StarMul R
⊢ ∀ (r s : ↥(unitary R)), star (r * s) = star s * star r

Next tactic:
intro x y
instance : StarMul (unitary R) :=
  ⟨by
    intro x y
    

Proof state:
R : Type u_1
inst✝¹ : Monoid R
inst✝ : StarMul R
x y : ↥(unitary R)
⊢ star (x * y) = star y * star x

Next tactic:
ext
instance : StarMul (unitary R) :=
  ⟨by
    intro x y
    ext
    

Proof state:
case a
R : Type u_1
inst✝¹ : Monoid R
inst✝ : StarMul R
x y : ↥(unitary R)
⊢ ↑(star (x * y)) = ↑(star y * star x)

Next tactic:
rw [coe_star, Submonoid.coe_mul, Submonoid.coe_mul, coe_star, coe_star, star_mul]
@[norm_cast]
theorem coe_div (U₁ U₂ : unitary R) : ↑(U₁ / U₂) = (U₁ / U₂ : R) := by
  

Proof state:
R : Type u_1
inst✝¹ : GroupWithZero R
inst✝ : StarMul R
U₁ U₂ : ↥(unitary R)
⊢ ↑(U₁ / U₂) = ↑U₁ / ↑U₂

Next tactic:
simp only [div_eq_mul_inv, coe_inv, Submonoid.coe_mul]
@[norm_cast]
theorem coe_zpow (U : unitary R) (z : ℤ) : ↑(U ^ z) = (U : R) ^ z := by
  

Proof state:
R : Type u_1
inst✝¹ : GroupWithZero R
inst✝ : StarMul R
U : ↥(unitary R)
z : ℤ
⊢ ↑(U ^ z) = ↑U ^ z

Next tactic:
induction z
@[norm_cast]
theorem coe_zpow (U : unitary R) (z : ℤ) : ↑(U ^ z) = (U : R) ^ z := by
  induction z
  · 

Proof state:
case ofNat
R : Type u_1
inst✝¹ : GroupWithZero R
inst✝ : StarMul R
U : ↥(unitary R)
a✝ : ℕ
⊢ ↑(U ^ Int.ofNat a✝) = ↑U ^ Int.ofNat a✝

Next tactic:
simp [SubmonoidClass.coe_pow]
@[norm_cast]
theorem coe_zpow (U : unitary R) (z : ℤ) : ↑(U ^ z) = (U : R) ^ z := by
  induction z
  · simp [SubmonoidClass.coe_pow]
  · 

Proof state:
case negSucc
R : Type u_1
inst✝¹ : GroupWithZero R
inst✝ : StarMul R
U : ↥(unitary R)
a✝ : ℕ
⊢ ↑(U ^ Int.negSucc a✝) = ↑U ^ Int.negSucc a✝

Next tactic:
simp [coe_inv]
instance : Neg (unitary R) where
  neg U :=
    ⟨-U, by 

Proof state:
R : Type u_1
inst✝¹ : Ring R
inst✝ : StarRing R
U : ↥(unitary R)
⊢ -↑U ∈ unitary R

Next tactic:
simp [mem_iff, star_neg, neg_mul_neg]
theorem supported_eq_range_rename (s : Set σ) : supported R s = (rename ((↑) : s → σ)).range := by
  

Proof state:
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
p q : MvPolynomial σ R
s : Set σ
⊢ supported R s = AlgHom.range (rename Subtype.val)

Next tactic:
rw [supported, Set.image_eq_range, adjoin_range_eq_range_aeval, rename]
theorem supported_eq_range_rename (s : Set σ) : supported R s = (rename ((↑) : s → σ)).range := by
  rw [supported, Set.image_eq_range, adjoin_range_eq_range_aeval, rename]
  

Proof state:
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
p q : MvPolynomial σ R
s : Set σ
⊢ AlgHom.range (aeval fun x => X ↑x) = AlgHom.range (aeval (X ∘ Subtype.val))

Next tactic:
congr
@[simp, nolint simpNF]  -- porting note: the `simpNF` linter complained about this lemma.
theorem supportedEquivMvPolynomial_symm_C (s : Set σ) (x : R) :
    (supportedEquivMvPolynomial s).symm (C x) = algebraMap R (supported R s) x := by
  

Proof state:
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
p q : MvPolynomial σ R
s : Set σ
x : R
⊢ (AlgEquiv.symm (supportedEquivMvPolynomial s)) (C x) = (algebraMap R ↥(supported R s)) x

Next tactic:
ext1
@[simp, nolint simpNF]  -- porting note: the `simpNF` linter complained about this lemma.
theorem supportedEquivMvPolynomial_symm_C (s : Set σ) (x : R) :
    (supportedEquivMvPolynomial s).symm (C x) = algebraMap R (supported R s) x := by
  ext1
  

Proof state:
case a
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
p q : MvPolynomial σ R
s : Set σ
x : R
⊢ ↑((AlgEquiv.symm (supportedEquivMvPolynomial s)) (C x)) = ↑((algebraMap R ↥(supported R s)) x)

Next tactic:
simp [supportedEquivMvPolynomial, MvPolynomial.algebraMap_eq]
@[simp, nolint simpNF]  -- porting note: the `simpNF` linter complained about this lemma.
theorem supportedEquivMvPolynomial_symm_X (s : Set σ) (i : s) :
    (↑((supportedEquivMvPolynomial s).symm (X i : MvPolynomial s R)) : MvPolynomial σ R) = X ↑i :=
  by 

Proof state:
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
p q : MvPolynomial σ R
s : Set σ
i : ↑s
⊢ ↑((AlgEquiv.symm (supportedEquivMvPolynomial s)) (X i)) = X ↑i

Next tactic:
simp [supportedEquivMvPolynomial]
theorem mem_supported : p ∈ supported R s ↔ ↑p.vars ⊆ s := by
  

Proof state:
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
p q : MvPolynomial σ R
s t : Set σ
⊢ p ∈ supported R s ↔ ↑(vars p) ⊆ s

Next tactic:
classical
  rw [supported_eq_range_rename, AlgHom.mem_range]
  constructor
  · rintro ⟨p, rfl⟩
    refine' _root_.trans (Finset.coe_subset.2 (vars_rename _ _)) _
    simp
  · intro hs
    exact exists_rename_eq_of_vars_subset_range p ((↑) : s → σ) Subtype.val_injective (by simpa)
theorem mem_supported : p ∈ supported R s ↔ ↑p.vars ⊆ s := by
  classical
  

Proof state:
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
p q : MvPolynomial σ R
s t : Set σ
⊢ p ∈ supported R s ↔ ↑(vars p) ⊆ s

Next tactic:
rw [supported_eq_range_rename, AlgHom.mem_range]
theorem mem_supported : p ∈ supported R s ↔ ↑p.vars ⊆ s := by
  classical
  rw [supported_eq_range_rename, AlgHom.mem_range]
  

Proof state:
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
p q : MvPolynomial σ R
s t : Set σ
⊢ (∃ x, (rename Subtype.val) x = p) ↔ ↑(vars p) ⊆ s

Next tactic:
constructor
theorem mem_supported : p ∈ supported R s ↔ ↑p.vars ⊆ s := by
  classical
  rw [supported_eq_range_rename, AlgHom.mem_range]
  constructor
  · 

Proof state:
case mp
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
p q : MvPolynomial σ R
s t : Set σ
⊢ (∃ x, (rename Subtype.val) x = p) → ↑(vars p) ⊆ s

Next tactic:
rintro ⟨p, rfl⟩
theorem mem_supported : p ∈ supported R s ↔ ↑p.vars ⊆ s := by
  classical
  rw [supported_eq_range_rename, AlgHom.mem_range]
  constructor
  · rintro ⟨p, rfl⟩
    

Proof state:
case mp.intro
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
q : MvPolynomial σ R
s t : Set σ
p : MvPolynomial { x // x ∈ s } R
⊢ ↑(vars ((rename Subtype.val) p)) ⊆ s

Next tactic:
refine' _root_.trans (Finset.coe_subset.2 (vars_rename _ _)) _
theorem mem_supported : p ∈ supported R s ↔ ↑p.vars ⊆ s := by
  classical
  rw [supported_eq_range_rename, AlgHom.mem_range]
  constructor
  · rintro ⟨p, rfl⟩
    refine' _root_.trans (Finset.coe_subset.2 (vars_rename _ _)) _
    

Proof state:
case mp.intro
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
q : MvPolynomial σ R
s t : Set σ
p : MvPolynomial { x // x ∈ s } R
⊢ ↑(Finset.image Subtype.val (vars p)) ⊆ s

Next tactic:
simp
theorem mem_supported : p ∈ supported R s ↔ ↑p.vars ⊆ s := by
  classical
  rw [supported_eq_range_rename, AlgHom.mem_range]
  constructor
  · rintro ⟨p, rfl⟩
    refine' _root_.trans (Finset.coe_subset.2 (vars_rename _ _)) _
    simp
  · 

Proof state:
case mpr
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
p q : MvPolynomial σ R
s t : Set σ
⊢ ↑(vars p) ⊆ s → ∃ x, (rename Subtype.val) x = p

Next tactic:
intro hs
theorem mem_supported : p ∈ supported R s ↔ ↑p.vars ⊆ s := by
  classical
  rw [supported_eq_range_rename, AlgHom.mem_range]
  constructor
  · rintro ⟨p, rfl⟩
    refine' _root_.trans (Finset.coe_subset.2 (vars_rename _ _)) _
    simp
  · intro hs
    

Proof state:
case mpr
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
p q : MvPolynomial σ R
s t : Set σ
hs : ↑(vars p) ⊆ s
⊢ ∃ x, (rename Subtype.val) x = p

Next tactic:
exact exists_rename_eq_of_vars_subset_range p ((↑) : s → σ) Subtype.val_injective (by simpa)
theorem mem_supported : p ∈ supported R s ↔ ↑p.vars ⊆ s := by
  classical
  rw [supported_eq_range_rename, AlgHom.mem_range]
  constructor
  · rintro ⟨p, rfl⟩
    refine' _root_.trans (Finset.coe_subset.2 (vars_rename _ _)) _
    simp
  · intro hs
    exact exists_rename_eq_of_vars_subset_range p ((↑) : s → σ) Subtype.val_injective (by 

Proof state:
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
p q : MvPolynomial σ R
s t : Set σ
hs : ↑(vars p) ⊆ s
⊢ ↑(vars p) ⊆ Set.range Subtype.val

Next tactic:
simpa
@[simp]
theorem mem_supported_vars (p : MvPolynomial σ R) : p ∈ supported R (↑p.vars : Set σ) := by
  

Proof state:
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
p✝ q : MvPolynomial σ R
s t : Set σ
p : MvPolynomial σ R
⊢ p ∈ supported R ↑(vars p)

Next tactic:
rw [mem_supported]
@[simp]
theorem supported_univ : supported R (Set.univ : Set σ) = ⊤ := by
  

Proof state:
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
p q : MvPolynomial σ R
s t : Set σ
⊢ supported R Set.univ = ⊤

Next tactic:
simp [Algebra.eq_top_iff, mem_supported]
@[simp]
theorem supported_empty : supported R (∅ : Set σ) = ⊥ := by 

Proof state:
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝ : CommSemiring R
p q : MvPolynomial σ R
s t : Set σ
⊢ supported R ∅ = ⊥

Next tactic:
simp [supported_eq_adjoin_X]
@[simp]
theorem X_mem_supported [Nontrivial R] {i : σ} : X i ∈ supported R s ↔ i ∈ s := by
  

Proof state:
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝¹ : CommSemiring R
p q : MvPolynomial σ R
s t : Set σ
inst✝ : Nontrivial R
i : σ
⊢ X i ∈ supported R s ↔ i ∈ s

Next tactic:
simp [mem_supported]
@[simp]
theorem supported_le_supported_iff [Nontrivial R] : supported R s ≤ supported R t ↔ s ⊆ t := by
  

Proof state:
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝¹ : CommSemiring R
p q : MvPolynomial σ R
s t : Set σ
inst✝ : Nontrivial R
⊢ supported R s ≤ supported R t ↔ s ⊆ t

Next tactic:
constructor
@[simp]
theorem supported_le_supported_iff [Nontrivial R] : supported R s ≤ supported R t ↔ s ⊆ t := by
  constructor
  · 

Proof state:
case mp
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝¹ : CommSemiring R
p q : MvPolynomial σ R
s t : Set σ
inst✝ : Nontrivial R
⊢ supported R s ≤ supported R t → s ⊆ t

Next tactic:
intro h i
@[simp]
theorem supported_le_supported_iff [Nontrivial R] : supported R s ≤ supported R t ↔ s ⊆ t := by
  constructor
  · intro h i
    

Proof state:
case mp
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝¹ : CommSemiring R
p q : MvPolynomial σ R
s t : Set σ
inst✝ : Nontrivial R
h : supported R s ≤ supported R t
i : σ
⊢ i ∈ s → i ∈ t

Next tactic:
simpa using @h (X i)
@[simp]
theorem supported_le_supported_iff [Nontrivial R] : supported R s ≤ supported R t ↔ s ⊆ t := by
  constructor
  · intro h i
    simpa using @h (X i)
  · 

Proof state:
case mpr
σ : Type u_1
τ : Type u_2
R : Type u
S : Type v
r : R
e : ℕ
n m : σ
inst✝¹ : CommSemiring R
p q : MvPolynomial σ R
s t : Set σ
inst✝ : Nontrivial R
⊢ s ⊆ t → supported R s ≤ supported R t

Next tactic:
exact supported_mono
theorem exists_restrict_to_vars (R : Type*) [CommRing R] {F : MvPolynomial σ ℤ}
    (hF : ↑F.vars ⊆ s) : ∃ f : (s → R) → R, ∀ x : σ → R, f (x ∘ (↑) : s → R) = aeval x F := by
  

Proof state:
σ : Type u_1
τ : Type u_2
R✝ : Type u
S : Type v
r : R✝
e : ℕ
n m : σ
inst✝¹ : CommSemiring R✝
p q : MvPolynomial σ R✝
s t : Set σ
R : Type u_3
inst✝ : CommRing R
F : MvPolynomial σ ℤ
hF : ↑(vars F) ⊆ s
⊢ ∃ f, ∀ (x : σ → R), f (x ∘ Subtype.val) = (aeval x) F

Next tactic:
rw [← mem_supported, supported_eq_range_rename, AlgHom.mem_range] at hF
theorem exists_restrict_to_vars (R : Type*) [CommRing R] {F : MvPolynomial σ ℤ}
    (hF : ↑F.vars ⊆ s) : ∃ f : (s → R) → R, ∀ x : σ → R, f (x ∘ (↑) : s → R) = aeval x F := by
  rw [← mem_supported, supported_eq_range_rename, AlgHom.mem_range] at hF
  

Proof state:
σ : Type u_1
τ : Type u_2
R✝ : Type u
S : Type v
r : R✝
e : ℕ
n m : σ
inst✝¹ : CommSemiring R✝
p q : MvPolynomial σ R✝
s t : Set σ
R : Type u_3
inst✝ : CommRing R
F : MvPolynomial σ ℤ
hF : ∃ x, (rename Subtype.val) x = F
⊢ ∃ f, ∀ (x : σ → R), f (x ∘ Subtype.val) = (aeval x) F

Next tactic:
cases' hF with F' hF'
theorem exists_restrict_to_vars (R : Type*) [CommRing R] {F : MvPolynomial σ ℤ}
    (hF : ↑F.vars ⊆ s) : ∃ f : (s → R) → R, ∀ x : σ → R, f (x ∘ (↑) : s → R) = aeval x F := by
  rw [← mem_supported, supported_eq_range_rename, AlgHom.mem_range] at hF
  cases' hF with F' hF'
  

Proof state:
case intro
σ : Type u_1
τ : Type u_2
R✝ : Type u
S : Type v
r : R✝
e : ℕ
n m : σ
inst✝¹ : CommSemiring R✝
p q : MvPolynomial σ R✝
s t : Set σ
R : Type u_3
inst✝ : CommRing R
F : MvPolynomial σ ℤ
F' : MvPolynomial { x // x ∈ s } ℤ
hF' : (rename Subtype.val) F' = F
⊢ ∃ f, ∀ (x : σ → R), f (x ∘ Subtype.val) = (aeval x) F

Next tactic:
use fun z ↦ aeval z F'
theorem exists_restrict_to_vars (R : Type*) [CommRing R] {F : MvPolynomial σ ℤ}
    (hF : ↑F.vars ⊆ s) : ∃ f : (s → R) → R, ∀ x : σ → R, f (x ∘ (↑) : s → R) = aeval x F := by
  rw [← mem_supported, supported_eq_range_rename, AlgHom.mem_range] at hF
  cases' hF with F' hF'
  use fun z ↦ aeval z F'
  

Proof state:
case h
σ : Type u_1
τ : Type u_2
R✝ : Type u
S : Type v
r : R✝
e : ℕ
n m : σ
inst✝¹ : CommSemiring R✝
p q : MvPolynomial σ R✝
s t : Set σ
R : Type u_3
inst✝ : CommRing R
F : MvPolynomial σ ℤ
F' : MvPolynomial { x // x ∈ s } ℤ
hF' : (rename Subtype.val) F' = F
⊢ ∀ (x : σ → R), (aeval (x ∘ Subtype.val)) F' = (aeval x) F

Next tactic:
intro x
theorem exists_restrict_to_vars (R : Type*) [CommRing R] {F : MvPolynomial σ ℤ}
    (hF : ↑F.vars ⊆ s) : ∃ f : (s → R) → R, ∀ x : σ → R, f (x ∘ (↑) : s → R) = aeval x F := by
  rw [← mem_supported, supported_eq_range_rename, AlgHom.mem_range] at hF
  cases' hF with F' hF'
  use fun z ↦ aeval z F'
  intro x
  

Proof state:
case h
σ : Type u_1
τ : Type u_2
R✝ : Type u
S : Type v
r : R✝
e : ℕ
n m : σ
inst✝¹ : CommSemiring R✝
p q : MvPolynomial σ R✝
s t : Set σ
R : Type u_3
inst✝ : CommRing R
F : MvPolynomial σ ℤ
F' : MvPolynomial { x // x ∈ s } ℤ
hF' : (rename Subtype.val) F' = F
x : σ → R
⊢ (aeval (x ∘ Subtype.val)) F' = (aeval x) F

Next tactic:
simp only [← hF', aeval_rename]
/-- In a preadditive category, we can construct a biproduct for `f : J → C` from
any bicone `b` for `f` satisfying `total : ∑ j : J, b.π j ≫ b.ι j = 𝟙 b.X`.

(That is, such a bicone is a limit cone and a colimit cocone.)
-/
def isBilimitOfTotal {f : J → C} (b : Bicone f) (total : ∑ j : J, b.π j ≫ b.ι j = 𝟙 b.pt) :
    b.IsBilimit where
  isLimit :=
    { lift := fun s => ∑ j : J, s.π.app ⟨j⟩ ≫ b.ι j
      uniq := fun s m h => by
        erw [← Category.comp_id m, ← total, comp_sum]
        apply Finset.sum_congr rfl
        intro j _
        have reassoced : m ≫ Bicone.π b j ≫ Bicone.ι b j = s.π.app ⟨j⟩ ≫ Bicone.ι b j := by
          erw [← Category.assoc, eq_whisker (h ⟨j⟩)]
        rw [reassoced]
      fac := fun s j => by
        

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
f : J → C
b : Bicone f
total : ∑ j : J, Bicone.π b j ≫ Bicone.ι b j = 𝟙 b.pt
s : Cone (Discrete.functor f)
j : Discrete J
⊢ (fun s => ∑ j : J, s.π.app { as := j } ≫ Bicone.ι b j) s ≫ (Bicone.toCone b).π.app j = s.π.app j

Next tactic:
cases j
/-- In a preadditive category, we can construct a biproduct for `f : J → C` from
any bicone `b` for `f` satisfying `total : ∑ j : J, b.π j ≫ b.ι j = 𝟙 b.X`.

(That is, such a bicone is a limit cone and a colimit cocone.)
-/
def isBilimitOfTotal {f : J → C} (b : Bicone f) (total : ∑ j : J, b.π j ≫ b.ι j = 𝟙 b.pt) :
    b.IsBilimit where
  isLimit :=
    { lift := fun s => ∑ j : J, s.π.app ⟨j⟩ ≫ b.ι j
      uniq := fun s m h => by
        erw [← Category.comp_id m, ← total, comp_sum]
        apply Finset.sum_congr rfl
        intro j _
        have reassoced : m ≫ Bicone.π b j ≫ Bicone.ι b j = s.π.app ⟨j⟩ ≫ Bicone.ι b j := by
          erw [← Category.assoc, eq_whisker (h ⟨j⟩)]
        rw [reassoced]
      fac := fun s j => by
        cases j
        

Proof state:
case mk
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
f : J → C
b : Bicone f
total : ∑ j : J, Bicone.π b j ≫ Bicone.ι b j = 𝟙 b.pt
s : Cone (Discrete.functor f)
as✝ : J
⊢ (fun s => ∑ j : J, s.π.app { as := j } ≫ Bicone.ι b j) s ≫ (Bicone.toCone b).π.app { as := as✝ } =
    s.π.app { as := as✝ }

Next tactic:
simp only [sum_comp, Category.assoc, Bicone.toCone_π_app, b.ι_π, comp_dite]
/-- In a preadditive category, we can construct a biproduct for `f : J → C` from
any bicone `b` for `f` satisfying `total : ∑ j : J, b.π j ≫ b.ι j = 𝟙 b.X`.

(That is, such a bicone is a limit cone and a colimit cocone.)
-/
def isBilimitOfTotal {f : J → C} (b : Bicone f) (total : ∑ j : J, b.π j ≫ b.ι j = 𝟙 b.pt) :
    b.IsBilimit where
  isLimit :=
    { lift := fun s => ∑ j : J, s.π.app ⟨j⟩ ≫ b.ι j
      uniq := fun s m h => by
        erw [← Category.comp_id m, ← total, comp_sum]
        apply Finset.sum_congr rfl
        intro j _
        have reassoced : m ≫ Bicone.π b j ≫ Bicone.ι b j = s.π.app ⟨j⟩ ≫ Bicone.ι b j := by
          erw [← Category.assoc, eq_whisker (h ⟨j⟩)]
        rw [reassoced]
      fac := fun s j => by
        cases j
        simp only [sum_comp, Category.assoc, Bicone.toCone_π_app, b.ι_π, comp_dite]
        -- See note [dsimp, simp].
        

Proof state:
case mk
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
f : J → C
b : Bicone f
total : ∑ j : J, Bicone.π b j ≫ Bicone.ι b j = 𝟙 b.pt
s : Cone (Discrete.functor f)
as✝ : J
⊢ (∑ x : J, if h : x = as✝ then s.π.app { as := x } ≫ eqToHom (_ : f x = f as✝) else s.π.app { as := x } ≫ 0) =
    s.π.app { as := as✝ }

Next tactic:
dsimp
/-- In a preadditive category, we can construct a biproduct for `f : J → C` from
any bicone `b` for `f` satisfying `total : ∑ j : J, b.π j ≫ b.ι j = 𝟙 b.X`.

(That is, such a bicone is a limit cone and a colimit cocone.)
-/
def isBilimitOfTotal {f : J → C} (b : Bicone f) (total : ∑ j : J, b.π j ≫ b.ι j = 𝟙 b.pt) :
    b.IsBilimit where
  isLimit :=
    { lift := fun s => ∑ j : J, s.π.app ⟨j⟩ ≫ b.ι j
      uniq := fun s m h => by
        erw [← Category.comp_id m, ← total, comp_sum]
        apply Finset.sum_congr rfl
        intro j _
        have reassoced : m ≫ Bicone.π b j ≫ Bicone.ι b j = s.π.app ⟨j⟩ ≫ Bicone.ι b j := by
          erw [← Category.assoc, eq_whisker (h ⟨j⟩)]
        rw [reassoced]
      fac := fun s j => by
        cases j
        simp only [sum_comp, Category.assoc, Bicone.toCone_π_app, b.ι_π, comp_dite]
        -- See note [dsimp, simp].
        dsimp;
        

Proof state:
case mk
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
f : J → C
b : Bicone f
total : ∑ j : J, Bicone.π b j ≫ Bicone.ι b j = 𝟙 b.pt
s : Cone (Discrete.functor f)
as✝ : J
⊢ (∑ x : J, if h : x = as✝ then s.π.app { as := x } ≫ eqToHom (_ : f x = f as✝) else s.π.app { as := x } ≫ 0) =
    s.π.app { as := as✝ }

Next tactic:
simp
/-- In a preadditive category, we can construct a biproduct for `f : J → C` from
any bicone `b` for `f` satisfying `total : ∑ j : J, b.π j ≫ b.ι j = 𝟙 b.X`.

(That is, such a bicone is a limit cone and a colimit cocone.)
-/
def isBilimitOfTotal {f : J → C} (b : Bicone f) (total : ∑ j : J, b.π j ≫ b.ι j = 𝟙 b.pt) :
    b.IsBilimit where
  isLimit :=
    { lift := fun s => ∑ j : J, s.π.app ⟨j⟩ ≫ b.ι j
      uniq := fun s m h => by
        

Proof state:
C : Type u
inst✝² : Category.{v, u} C
inst✝¹ : Preadditive C
J : Type
inst✝ : Fintype J
f : J → C
b : Bicone f
total : ∑ j : J, Bicone.π b j ≫ Bicone.ι b j = 𝟙 b.pt
s : Cone (Discrete.functor f)
m : s.pt ⟶ (Bicone.toCone b).pt
h : ∀ (j : Discrete J), m ≫ (Bicone.toCone b).π.app j = s.π.app j
⊢ m = (fun s => ∑ j : J, s.π.app { as := j } ≫ Bicone.ι b j) s

Next tactic:
erw [← Category.comp_id m, ← total, comp_sum]