l3lab/ntp-mathlib huggingface dataset:
/-- An additive functor which preserves homology preserves finite limits. -/
noncomputable def preservesFiniteLimitsOfPreservesHomology
    [HasFiniteProducts C] [HasKernels C] : PreservesFiniteLimits F := by
  have := fun {X Y : C} (f : X ⟶ Y) => PreservesHomology.preservesKernel F f
  have : HasBinaryBiproducts C := HasBinaryBiproducts.of_hasBinaryProducts
  have : HasEqualizers C := Preadditive.hasEqualizers_of_hasKernels
  have : HasZeroObject D :=
    ⟨F.obj 0, by 

Proof state:
C : Type u_1
D : Type u_2
inst✝⁸ : Category.{?u.289, u_1} C
inst✝⁷ : Category.{?u.293, u_2} D
inst✝⁶ : Preadditive C
inst✝⁵ : Preadditive D
F : C ⥤ D
inst✝⁴ : Additive F
inst✝³ : PreservesHomology F
inst✝² : HasZeroObject C
inst✝¹ : HasFiniteProducts C
inst✝ : HasKernels C
this✝¹ : {X Y : C} → (f : X ⟶ Y) → PreservesLimit (parallelPair f 0) F
this✝ : HasBinaryBiproducts C
this : HasEqualizers C
⊢ IsZero (F.obj 0)

Next tactic:
rw [IsZero.iff_id_eq_zero, ← F.map_id, id_zero, F.map_zero]
/-- An additive functor which preserves homology preserves finite limits. -/
noncomputable def preservesFiniteLimitsOfPreservesHomology
    [HasFiniteProducts C] [HasKernels C] : PreservesFiniteLimits F := by
  have := fun {X Y : C} (f : X ⟶ Y) => PreservesHomology.preservesKernel F f
  have : HasBinaryBiproducts C := HasBinaryBiproducts.of_hasBinaryProducts
  have : HasEqualizers C := Preadditive.hasEqualizers_of_hasKernels
  have : HasZeroObject D :=
    ⟨F.obj 0, by rw [IsZero.iff_id_eq_zero, ← F.map_id, id_zero, F.map_zero]⟩
  

Proof state:
C : Type u_1
D : Type u_2
inst✝⁸ : Category.{?u.289, u_1} C
inst✝⁷ : Category.{?u.293, u_2} D
inst✝⁶ : Preadditive C
inst✝⁵ : Preadditive D
F : C ⥤ D
inst✝⁴ : Additive F
inst✝³ : PreservesHomology F
inst✝² : HasZeroObject C
inst✝¹ : HasFiniteProducts C
inst✝ : HasKernels C
this✝² : {X Y : C} → (f : X ⟶ Y) → PreservesLimit (parallelPair f 0) F
this✝¹ : HasBinaryBiproducts C
this✝ : HasEqualizers C
this : HasZeroObject D
⊢ PreservesFiniteLimits F

Next tactic:
exact preservesFiniteLimitsOfPreservesKernels F
/-- An additive which preserves homology preserves finite colimits. -/
noncomputable def preservesFiniteColimitsOfPreservesHomology
    [HasFiniteCoproducts C] [HasCokernels C] : PreservesFiniteColimits F := by
  

Proof state:
C : Type u_1
D : Type u_2
inst✝⁸ : Category.{?u.2864, u_1} C
inst✝⁷ : Category.{?u.2868, u_2} D
inst✝⁶ : Preadditive C
inst✝⁵ : Preadditive D
F : C ⥤ D
inst✝⁴ : Additive F
inst✝³ : PreservesHomology F
inst✝² : HasZeroObject C
inst✝¹ : HasFiniteCoproducts C
inst✝ : HasCokernels C
⊢ PreservesFiniteColimits F

Next tactic:
have := fun {X Y : C} (f : X ⟶ Y) => PreservesHomology.preservesCokernel F f
/-- An additive which preserves homology preserves finite colimits. -/
noncomputable def preservesFiniteColimitsOfPreservesHomology
    [HasFiniteCoproducts C] [HasCokernels C] : PreservesFiniteColimits F := by
  have := fun {X Y : C} (f : X ⟶ Y) => PreservesHomology.preservesCokernel F f
  

Proof state:
C : Type u_1
D : Type u_2
inst✝⁸ : Category.{?u.2864, u_1} C
inst✝⁷ : Category.{?u.2868, u_2} D
inst✝⁶ : Preadditive C
inst✝⁵ : Preadditive D
F : C ⥤ D
inst✝⁴ : Additive F
inst✝³ : PreservesHomology F
inst✝² : HasZeroObject C
inst✝¹ : HasFiniteCoproducts C
inst✝ : HasCokernels C
this : {X Y : C} → (f : X ⟶ Y) → PreservesColimit (parallelPair f 0) F
⊢ PreservesFiniteColimits F

Next tactic:
have : HasBinaryBiproducts C := HasBinaryBiproducts.of_hasBinaryCoproducts
/-- An additive which preserves homology preserves finite colimits. -/
noncomputable def preservesFiniteColimitsOfPreservesHomology
    [HasFiniteCoproducts C] [HasCokernels C] : PreservesFiniteColimits F := by
  have := fun {X Y : C} (f : X ⟶ Y) => PreservesHomology.preservesCokernel F f
  have : HasBinaryBiproducts C := HasBinaryBiproducts.of_hasBinaryCoproducts
  

Proof state:
C : Type u_1
D : Type u_2
inst✝⁸ : Category.{?u.2864, u_1} C
inst✝⁷ : Category.{?u.2868, u_2} D
inst✝⁶ : Preadditive C
inst✝⁵ : Preadditive D
F : C ⥤ D
inst✝⁴ : Additive F
inst✝³ : PreservesHomology F
inst✝² : HasZeroObject C
inst✝¹ : HasFiniteCoproducts C
inst✝ : HasCokernels C
this✝ : {X Y : C} → (f : X ⟶ Y) → PreservesColimit (parallelPair f 0) F
this : HasBinaryBiproducts C
⊢ PreservesFiniteColimits F

Next tactic:
have : HasCoequalizers C := Preadditive.hasCoequalizers_of_hasCokernels
/-- An additive which preserves homology preserves finite colimits. -/
noncomputable def preservesFiniteColimitsOfPreservesHomology
    [HasFiniteCoproducts C] [HasCokernels C] : PreservesFiniteColimits F := by
  have := fun {X Y : C} (f : X ⟶ Y) => PreservesHomology.preservesCokernel F f
  have : HasBinaryBiproducts C := HasBinaryBiproducts.of_hasBinaryCoproducts
  have : HasCoequalizers C := Preadditive.hasCoequalizers_of_hasCokernels
  

Proof state:
C : Type u_1
D : Type u_2
inst✝⁸ : Category.{?u.2864, u_1} C
inst✝⁷ : Category.{?u.2868, u_2} D
inst✝⁶ : Preadditive C
inst✝⁵ : Preadditive D
F : C ⥤ D
inst✝⁴ : Additive F
inst✝³ : PreservesHomology F
inst✝² : HasZeroObject C
inst✝¹ : HasFiniteCoproducts C
inst✝ : HasCokernels C
this✝¹ : {X Y : C} → (f : X ⟶ Y) → PreservesColimit (parallelPair f 0) F
this✝ : HasBinaryBiproducts C
this : HasCoequalizers C
⊢ PreservesFiniteColimits F

Next tactic:
have : HasZeroObject D :=
    ⟨F.obj 0, by rw [IsZero.iff_id_eq_zero, ← F.map_id, id_zero, F.map_zero]⟩
/-- An additive which preserves homology preserves finite colimits. -/
noncomputable def preservesFiniteColimitsOfPreservesHomology
    [HasFiniteCoproducts C] [HasCokernels C] : PreservesFiniteColimits F := by
  have := fun {X Y : C} (f : X ⟶ Y) => PreservesHomology.preservesCokernel F f
  have : HasBinaryBiproducts C := HasBinaryBiproducts.of_hasBinaryCoproducts
  have : HasCoequalizers C := Preadditive.hasCoequalizers_of_hasCokernels
  have : HasZeroObject D :=
    ⟨F.obj 0, by 

Proof state:
C : Type u_1
D : Type u_2
inst✝⁸ : Category.{?u.2864, u_1} C
inst✝⁷ : Category.{?u.2868, u_2} D
inst✝⁶ : Preadditive C
inst✝⁵ : Preadditive D
F : C ⥤ D
inst✝⁴ : Additive F
inst✝³ : PreservesHomology F
inst✝² : HasZeroObject C
inst✝¹ : HasFiniteCoproducts C
inst✝ : HasCokernels C
this✝¹ : {X Y : C} → (f : X ⟶ Y) → PreservesColimit (parallelPair f 0) F
this✝ : HasBinaryBiproducts C
this : HasCoequalizers C
⊢ IsZero (F.obj 0)

Next tactic:
rw [IsZero.iff_id_eq_zero, ← F.map_id, id_zero, F.map_zero]
/-- An additive which preserves homology preserves finite colimits. -/
noncomputable def preservesFiniteColimitsOfPreservesHomology
    [HasFiniteCoproducts C] [HasCokernels C] : PreservesFiniteColimits F := by
  have := fun {X Y : C} (f : X ⟶ Y) => PreservesHomology.preservesCokernel F f
  have : HasBinaryBiproducts C := HasBinaryBiproducts.of_hasBinaryCoproducts
  have : HasCoequalizers C := Preadditive.hasCoequalizers_of_hasCokernels
  have : HasZeroObject D :=
    ⟨F.obj 0, by rw [IsZero.iff_id_eq_zero, ← F.map_id, id_zero, F.map_zero]⟩
  

Proof state:
C : Type u_1
D : Type u_2
inst✝⁸ : Category.{?u.2864, u_1} C
inst✝⁷ : Category.{?u.2868, u_2} D
inst✝⁶ : Preadditive C
inst✝⁵ : Preadditive D
F : C ⥤ D
inst✝⁴ : Additive F
inst✝³ : PreservesHomology F
inst✝² : HasZeroObject C
inst✝¹ : HasFiniteCoproducts C
inst✝ : HasCokernels C
this✝² : {X Y : C} → (f : X ⟶ Y) → PreservesColimit (parallelPair f 0) F
this✝¹ : HasBinaryBiproducts C
this✝ : HasCoequalizers C
this : HasZeroObject D
⊢ PreservesFiniteColimits F

Next tactic:
exact preservesFiniteColimitsOfPreservesCokernels F
theorem associated_tmul [Invertible (2 : A)] (Q₁ : QuadraticForm A M₁) (Q₂ : QuadraticForm R M₂) :
    associated (R := A) (Q₁.tmul Q₂)
      = (associated (R := A) Q₁).tmul (associated (R := R) Q₂) := by
  

Proof state:
R : Type uR
A : Type uA
M₁ : Type uM₁
M₂ : Type uM₂
inst✝¹² : CommRing R
inst✝¹¹ : CommRing A
inst✝¹⁰ : AddCommGroup M₁
inst✝⁹ : AddCommGroup M₂
inst✝⁸ : Algebra R A
inst✝⁷ : Module R M₁
inst✝⁶ : Module A M₁
inst✝⁵ : SMulCommClass R A M₁
inst✝⁴ : SMulCommClass A R M₁
inst✝³ : IsScalarTower R A M₁
inst✝² : Module R M₂
inst✝¹ : Invertible 2
inst✝ : Invertible 2
Q₁ : QuadraticForm A M₁
Q₂ : QuadraticForm R M₂
⊢ associated (QuadraticForm.tmul Q₁ Q₂) = BilinForm.tmul (associated Q₁) (associated Q₂)

Next tactic:
rw [QuadraticForm.tmul, tensorDistrib, BilinForm.tmul]
theorem associated_tmul [Invertible (2 : A)] (Q₁ : QuadraticForm A M₁) (Q₂ : QuadraticForm R M₂) :
    associated (R := A) (Q₁.tmul Q₂)
      = (associated (R := A) Q₁).tmul (associated (R := R) Q₂) := by
  rw [QuadraticForm.tmul, tensorDistrib, BilinForm.tmul]
  

Proof state:
R : Type uR
A : Type uA
M₁ : Type uM₁
M₂ : Type uM₂
inst✝¹² : CommRing R
inst✝¹¹ : CommRing A
inst✝¹⁰ : AddCommGroup M₁
inst✝⁹ : AddCommGroup M₂
inst✝⁸ : Algebra R A
inst✝⁷ : Module R M₁
inst✝⁶ : Module A M₁
inst✝⁵ : SMulCommClass R A M₁
inst✝⁴ : SMulCommClass A R M₁
inst✝³ : IsScalarTower R A M₁
inst✝² : Module R M₂
inst✝¹ : Invertible 2
inst✝ : Invertible 2
Q₁ : QuadraticForm A M₁
Q₂ : QuadraticForm R M₂
⊢ associated
      ((let toQ := BilinForm.toQuadraticFormLinearMap A A (M₁ ⊗[R] M₂);
        let tmulB := BilinForm.tensorDistrib R A;
        let toB := AlgebraTensorModule.map associated associated;
        LinearMap.comp toQ (LinearMap.comp tmulB toB))
        (Q₁ ⊗ₜ[R] Q₂)) =
    (BilinForm.tensorDistrib R A) (associated Q₁ ⊗ₜ[R] associated Q₂)

Next tactic:
dsimp
theorem associated_tmul [Invertible (2 : A)] (Q₁ : QuadraticForm A M₁) (Q₂ : QuadraticForm R M₂) :
    associated (R := A) (Q₁.tmul Q₂)
      = (associated (R := A) Q₁).tmul (associated (R := R) Q₂) := by
  rw [QuadraticForm.tmul, tensorDistrib, BilinForm.tmul]
  dsimp
  

Proof state:
R : Type uR
A : Type uA
M₁ : Type uM₁
M₂ : Type uM₂
inst✝¹² : CommRing R
inst✝¹¹ : CommRing A
inst✝¹⁰ : AddCommGroup M₁
inst✝⁹ : AddCommGroup M₂
inst✝⁸ : Algebra R A
inst✝⁷ : Module R M₁
inst✝⁶ : Module A M₁
inst✝⁵ : SMulCommClass R A M₁
inst✝⁴ : SMulCommClass A R M₁
inst✝³ : IsScalarTower R A M₁
inst✝² : Module R M₂
inst✝¹ : Invertible 2
inst✝ : Invertible 2
Q₁ : QuadraticForm A M₁
Q₂ : QuadraticForm R M₂
⊢ associated
      ((BilinForm.toQuadraticFormLinearMap A A (M₁ ⊗[R] M₂))
        ((BilinForm.tensorDistrib R A) (associated Q₁ ⊗ₜ[R] associated Q₂))) =
    (BilinForm.tensorDistrib R A) (associated Q₁ ⊗ₜ[R] associated Q₂)

Next tactic:
convert associated_left_inverse A ((associated_isSymm A Q₁).tmul (associated_isSymm R Q₂))
theorem polarBilin_tmul [Invertible (2 : A)] (Q₁ : QuadraticForm A M₁) (Q₂ : QuadraticForm R M₂) :
    polarBilin (Q₁.tmul Q₂) = ⅟(2 : A) • (polarBilin Q₁).tmul (polarBilin Q₂) := by
  

Proof state:
R : Type uR
A : Type uA
M₁ : Type uM₁
M₂ : Type uM₂
inst✝¹² : CommRing R
inst✝¹¹ : CommRing A
inst✝¹⁰ : AddCommGroup M₁
inst✝⁹ : AddCommGroup M₂
inst✝⁸ : Algebra R A
inst✝⁷ : Module R M₁
inst✝⁶ : Module A M₁
inst✝⁵ : SMulCommClass R A M₁
inst✝⁴ : SMulCommClass A R M₁
inst✝³ : IsScalarTower R A M₁
inst✝² : Module R M₂
inst✝¹ : Invertible 2
inst✝ : Invertible 2
Q₁ : QuadraticForm A M₁
Q₂ : QuadraticForm R M₂
⊢ polarBilin (QuadraticForm.tmul Q₁ Q₂) = ⅟2 • BilinForm.tmul (polarBilin Q₁) (polarBilin Q₂)

Next tactic:
simp_rw [← two_nsmul_associated A, ← two_nsmul_associated R, BilinForm.tmul, tmul_smul,
    ← smul_tmul', map_nsmul, associated_tmul]
theorem polarBilin_tmul [Invertible (2 : A)] (Q₁ : QuadraticForm A M₁) (Q₂ : QuadraticForm R M₂) :
    polarBilin (Q₁.tmul Q₂) = ⅟(2 : A) • (polarBilin Q₁).tmul (polarBilin Q₂) := by
  simp_rw [← two_nsmul_associated A, ← two_nsmul_associated R, BilinForm.tmul, tmul_smul,
    ← smul_tmul', map_nsmul, associated_tmul]
  

Proof state:
R : Type uR
A : Type uA
M₁ : Type uM₁
M₂ : Type uM₂
inst✝¹² : CommRing R
inst✝¹¹ : CommRing A
inst✝¹⁰ : AddCommGroup M₁
inst✝⁹ : AddCommGroup M₂
inst✝⁸ : Algebra R A
inst✝⁷ : Module R M₁
inst✝⁶ : Module A M₁
inst✝⁵ : SMulCommClass R A M₁
inst✝⁴ : SMulCommClass A R M₁
inst✝³ : IsScalarTower R A M₁
inst✝² : Module R M₂
inst✝¹ : Invertible 2
inst✝ : Invertible 2
Q₁ : QuadraticForm A M₁
Q₂ : QuadraticForm R M₂
⊢ 2 • BilinForm.tmul (associated Q₁) (associated Q₂) =
    ⅟2 • 2 • 2 • (BilinForm.tensorDistrib R A) ((associatedHom A) Q₁ ⊗ₜ[R] (associatedHom R) Q₂)

Next tactic:
rw [smul_comm (_ : A) (_ : ℕ), ← smul_assoc, two_smul _ (_ : A), invOf_two_add_invOf_two,
    one_smul]
theorem associated_baseChange [Invertible (2 : A)] (Q : QuadraticForm R M₂) :
    associated (R := A) (Q.baseChange A) = (associated (R := R) Q).baseChange A := by
  

Proof state:
R : Type uR
A : Type uA
M₁ : Type uM₁
M₂ : Type uM₂
inst✝¹² : CommRing R
inst✝¹¹ : CommRing A
inst✝¹⁰ : AddCommGroup M₁
inst✝⁹ : AddCommGroup M₂
inst✝⁸ : Algebra R A
inst✝⁷ : Module R M₁
inst✝⁶ : Module A M₁
inst✝⁵ : SMulCommClass R A M₁
inst✝⁴ : SMulCommClass A R M₁
inst✝³ : IsScalarTower R A M₁
inst✝² : Module R M₂
inst✝¹ : Invertible 2
inst✝ : Invertible 2
Q : QuadraticForm R M₂
⊢ associated (QuadraticForm.baseChange A Q) = BilinForm.baseChange A (associated Q)

Next tactic:
dsimp only [QuadraticForm.baseChange, BilinForm.baseChange]
theorem associated_baseChange [Invertible (2 : A)] (Q : QuadraticForm R M₂) :
    associated (R := A) (Q.baseChange A) = (associated (R := R) Q).baseChange A := by
  dsimp only [QuadraticForm.baseChange, BilinForm.baseChange]
  

Proof state:
R : Type uR
A : Type uA
M₁ : Type uM₁
M₂ : Type uM₂
inst✝¹² : CommRing R
inst✝¹¹ : CommRing A
inst✝¹⁰ : AddCommGroup M₁
inst✝⁹ : AddCommGroup M₂
inst✝⁸ : Algebra R A
inst✝⁷ : Module R M₁
inst✝⁶ : Module A M₁
inst✝⁵ : SMulCommClass R A M₁
inst✝⁴ : SMulCommClass A R M₁
inst✝³ : IsScalarTower R A M₁
inst✝² : Module R M₂
inst✝¹ : Invertible 2
inst✝ : Invertible 2
Q : QuadraticForm R M₂
⊢ associated (QuadraticForm.tmul sq Q) = BilinForm.tmul (LinearMap.toBilin (LinearMap.mul A A)) (associated Q)

Next tactic:
rw [associated_tmul (QuadraticForm.sq (R := A)) Q, associated_sq]
theorem polarBilin_baseChange [Invertible (2 : A)] (Q : QuadraticForm R M₂) :
    polarBilin (Q.baseChange A) = (polarBilin Q).baseChange A := by
  

Proof state:
R : Type uR
A : Type uA
M₁ : Type uM₁
M₂ : Type uM₂
inst✝¹² : CommRing R
inst✝¹¹ : CommRing A
inst✝¹⁰ : AddCommGroup M₁
inst✝⁹ : AddCommGroup M₂
inst✝⁸ : Algebra R A
inst✝⁷ : Module R M₁
inst✝⁶ : Module A M₁
inst✝⁵ : SMulCommClass R A M₁
inst✝⁴ : SMulCommClass A R M₁
inst✝³ : IsScalarTower R A M₁
inst✝² : Module R M₂
inst✝¹ : Invertible 2
inst✝ : Invertible 2
Q : QuadraticForm R M₂
⊢ polarBilin (QuadraticForm.baseChange A Q) = BilinForm.baseChange A (polarBilin Q)

Next tactic:
rw [QuadraticForm.baseChange, BilinForm.baseChange, polarBilin_tmul, BilinForm.tmul,
    ← LinearMap.map_smul, smul_tmul', ← two_nsmul_associated R, coe_associatedHom, associated_sq,
    smul_comm, ← smul_assoc, two_smul, invOf_two_add_invOf_two, one_smul]
/-- `n.factorization` is the finitely supported function `ℕ →₀ ℕ`
 mapping each prime factor of `n` to its multiplicity in `n`. -/
def factorization (n : ℕ) : ℕ →₀ ℕ where
  support := n.primeFactors
  toFun p := if p.Prime then padicValNat p n else 0
  mem_support_toFun := by 

Proof state:
a b m n✝ p n : ℕ
⊢ ∀ (a : ℕ), a ∈ n.primeFactors ↔ (fun p => if Prime p then padicValNat p n else 0) a ≠ 0

Next tactic:
simp [not_or]
/-- `n.factorization` is the finitely supported function `ℕ →₀ ℕ`
 mapping each prime factor of `n` to its multiplicity in `n`. -/
def factorization (n : ℕ) : ℕ →₀ ℕ where
  support := n.primeFactors
  toFun p := if p.Prime then padicValNat p n else 0
  mem_support_toFun := by simp [not_or]; 

Proof state:
a b m n✝ p n : ℕ
⊢ ∀ (a : ℕ), Prime a ∧ a ∣ n ∧ ¬n = 0 ↔ ¬a = 1 ∧ ¬n = 0 ∧ Prime a ∧ a ∣ n

Next tactic:
aesop
theorem factorization_def (n : ℕ) {p : ℕ} (pp : p.Prime) : n.factorization p = padicValNat p n := by
  

Proof state:
a b m n✝ p✝ n p : ℕ
pp : Prime p
⊢ (factorization n) p = padicValNat p n

Next tactic:
simpa [factorization] using absurd pp
/-- We can write both `n.factorization p` and `n.factors.count p` to represent the power
of `p` in the factorization of `n`: we declare the former to be the simp-normal form. -/
@[simp]
theorem factors_count_eq {n p : ℕ} : n.factors.count p = n.factorization p := by
  

Proof state:
a b m n✝ p✝ n p : ℕ
⊢ count p (factors n) = (factorization n) p

Next tactic:
rcases n.eq_zero_or_pos with (rfl | hn0)
/-- We can write both `n.factorization p` and `n.factors.count p` to represent the power
of `p` in the factorization of `n`: we declare the former to be the simp-normal form. -/
@[simp]
theorem factors_count_eq {n p : ℕ} : n.factors.count p = n.factorization p := by
  rcases n.eq_zero_or_pos with (rfl | hn0)
  · 

Proof state:
case inl
a b m n p✝ p : ℕ
⊢ count p (factors 0) = (factorization 0) p

Next tactic:
simp [factorization, count]
/-- We can write both `n.factorization p` and `n.factors.count p` to represent the power
of `p` in the factorization of `n`: we declare the former to be the simp-normal form. -/
@[simp]
theorem factors_count_eq {n p : ℕ} : n.factors.count p = n.factorization p := by
  rcases n.eq_zero_or_pos with (rfl | hn0)
  · simp [factorization, count]
  

Proof state:
case inr
a b m n✝ p✝ n p : ℕ
hn0 : n > 0
⊢ count p (factors n) = (factorization n) p

Next tactic:
by_cases pp : p.Prime
/-- We can write both `n.factorization p` and `n.factors.count p` to represent the power
of `p` in the factorization of `n`: we declare the former to be the simp-normal form. -/
@[simp]
theorem factors_count_eq {n p : ℕ} : n.factors.count p = n.factorization p := by
  rcases n.eq_zero_or_pos with (rfl | hn0)
  · simp [factorization, count]
  by_cases pp : p.Prime
  

Proof state:
case pos
a b m n✝ p✝ n p : ℕ
hn0 : n > 0
pp : Prime p
⊢ count p (factors n) = (factorization n) p
case neg a b m n✝ p✝ n p : ℕ hn0 : n > 0 pp : ¬Prime p ⊢ count p (factors n) = (factorization n) p

Next tactic:
case neg =>
    rw [count_eq_zero_of_not_mem (mt prime_of_mem_factors pp)]
    simp [factorization, pp]
/-- We can write both `n.factorization p` and `n.factors.count p` to represent the power
of `p` in the factorization of `n`: we declare the former to be the simp-normal form. -/
@[simp]
theorem factors_count_eq {n p : ℕ} : n.factors.count p = n.factorization p := by
  rcases n.eq_zero_or_pos with (rfl | hn0)
  · simp [factorization, count]
  by_cases pp : p.Prime
  

Proof state:
a b m n✝ p✝ n p : ℕ
hn0 : n > 0
pp : ¬Prime p
⊢ count p (factors n) = (factorization n) p

Next tactic:
case neg =>
    rw [count_eq_zero_of_not_mem (mt prime_of_mem_factors pp)]
    simp [factorization, pp]
/-- We can write both `n.factorization p` and `n.factors.count p` to represent the power
of `p` in the factorization of `n`: we declare the former to be the simp-normal form. -/
@[simp]
theorem factors_count_eq {n p : ℕ} : n.factors.count p = n.factorization p := by
  rcases n.eq_zero_or_pos with (rfl | hn0)
  · simp [factorization, count]
  by_cases pp : p.Prime
  case neg =>
    

Proof state:
a b m n✝ p✝ n p : ℕ
hn0 : n > 0
pp : ¬Prime p
⊢ count p (factors n) = (factorization n) p

Next tactic:
rw [count_eq_zero_of_not_mem (mt prime_of_mem_factors pp)]
/-- We can write both `n.factorization p` and `n.factors.count p` to represent the power
of `p` in the factorization of `n`: we declare the former to be the simp-normal form. -/
@[simp]
theorem factors_count_eq {n p : ℕ} : n.factors.count p = n.factorization p := by
  rcases n.eq_zero_or_pos with (rfl | hn0)
  · simp [factorization, count]
  by_cases pp : p.Prime
  case neg =>
    rw [count_eq_zero_of_not_mem (mt prime_of_mem_factors pp)]
    

Proof state:
a b m n✝ p✝ n p : ℕ
hn0 : n > 0
pp : ¬Prime p
⊢ 0 = (factorization n) p

Next tactic:
simp [factorization, pp]
/-- We can write both `n.factorization p` and `n.factors.count p` to represent the power
of `p` in the factorization of `n`: we declare the former to be the simp-normal form. -/
@[simp]
theorem factors_count_eq {n p : ℕ} : n.factors.count p = n.factorization p := by
  rcases n.eq_zero_or_pos with (rfl | hn0)
  · simp [factorization, count]
  by_cases pp : p.Prime
  case neg =>
    rw [count_eq_zero_of_not_mem (mt prime_of_mem_factors pp)]
    simp [factorization, pp]
  

Proof state:
case pos
a b m n✝ p✝ n p : ℕ
hn0 : n > 0
pp : Prime p
⊢ count p (factors n) = (factorization n) p

Next tactic:
simp only [factorization, coe_mk, pp, if_true]
/-- We can write both `n.factorization p` and `n.factors.count p` to represent the power
of `p` in the factorization of `n`: we declare the former to be the simp-normal form. -/
@[simp]
theorem factors_count_eq {n p : ℕ} : n.factors.count p = n.factorization p := by
  rcases n.eq_zero_or_pos with (rfl | hn0)
  · simp [factorization, count]
  by_cases pp : p.Prime
  case neg =>
    rw [count_eq_zero_of_not_mem (mt prime_of_mem_factors pp)]
    simp [factorization, pp]
  simp only [factorization, coe_mk, pp, if_true]
  

Proof state:
case pos
a b m n✝ p✝ n p : ℕ
hn0 : n > 0
pp : Prime p
⊢ count p (factors n) = padicValNat p n

Next tactic:
rw [← PartENat.natCast_inj, padicValNat_def' pp.ne_one hn0,
    UniqueFactorizationMonoid.multiplicity_eq_count_normalizedFactors pp hn0.ne']
/-- We can write both `n.factorization p` and `n.factors.count p` to represent the power
of `p` in the factorization of `n`: we declare the former to be the simp-normal form. -/
@[simp]
theorem factors_count_eq {n p : ℕ} : n.factors.count p = n.factorization p := by
  rcases n.eq_zero_or_pos with (rfl | hn0)
  · simp [factorization, count]
  by_cases pp : p.Prime
  case neg =>
    rw [count_eq_zero_of_not_mem (mt prime_of_mem_factors pp)]
    simp [factorization, pp]
  simp only [factorization, coe_mk, pp, if_true]
  rw [← PartENat.natCast_inj, padicValNat_def' pp.ne_one hn0,
    UniqueFactorizationMonoid.multiplicity_eq_count_normalizedFactors pp hn0.ne']
  

Proof state:
case pos
a b m n✝ p✝ n p : ℕ
hn0 : n > 0
pp : Prime p
⊢ ↑(count p (factors n)) = ↑(Multiset.count (normalize p) (UniqueFactorizationMonoid.normalizedFactors n))

Next tactic:
simp [factors_eq]
theorem factorization_eq_factors_multiset (n : ℕ) :
    n.factorization = Multiset.toFinsupp (n.factors : Multiset ℕ) := by
  

Proof state:
a b m n✝ p n : ℕ
⊢ factorization n = Multiset.toFinsupp ↑(factors n)

Next tactic:
ext p
theorem factorization_eq_factors_multiset (n : ℕ) :
    n.factorization = Multiset.toFinsupp (n.factors : Multiset ℕ) := by
  ext p
  

Proof state:
case h
a b m n✝ p✝ n p : ℕ
⊢ (factorization n) p = (Multiset.toFinsupp ↑(factors n)) p

Next tactic:
simp
theorem multiplicity_eq_factorization {n p : ℕ} (pp : p.Prime) (hn : n ≠ 0) :
    multiplicity p n = n.factorization p := by
  

Proof state:
a b m n✝ p✝ n p : ℕ
pp : Prime p
hn : n ≠ 0
⊢ multiplicity p n = ↑((factorization n) p)

Next tactic:
simp [factorization, pp, padicValNat_def' pp.ne_one hn.bot_lt]
@[simp]
theorem factorization_prod_pow_eq_self {n : ℕ} (hn : n ≠ 0) : n.factorization.prod (· ^ ·) = n := by
  

Proof state:
a b m n✝ p n : ℕ
hn : n ≠ 0
⊢ (Finsupp.prod (factorization n) fun x x_1 => x ^ x_1) = n

Next tactic:
rw [factorization_eq_factors_multiset n]
@[simp]
theorem factorization_prod_pow_eq_self {n : ℕ} (hn : n ≠ 0) : n.factorization.prod (· ^ ·) = n := by
  rw [factorization_eq_factors_multiset n]
  

Proof state:
a b m n✝ p n : ℕ
hn : n ≠ 0
⊢ (Finsupp.prod (Multiset.toFinsupp ↑(factors n)) fun x x_1 => x ^ x_1) = n

Next tactic:
simp only [← prod_toMultiset, factorization, Multiset.coe_prod, Multiset.toFinsupp_toMultiset]
@[simp]
theorem factorization_prod_pow_eq_self {n : ℕ} (hn : n ≠ 0) : n.factorization.prod (· ^ ·) = n := by
  rw [factorization_eq_factors_multiset n]
  simp only [← prod_toMultiset, factorization, Multiset.coe_prod, Multiset.toFinsupp_toMultiset]
  

Proof state:
a b m n✝ p n : ℕ
hn : n ≠ 0
⊢ List.prod (factors n) = n

Next tactic:
exact prod_factors hn
theorem eq_of_factorization_eq {a b : ℕ} (ha : a ≠ 0) (hb : b ≠ 0)
    (h : ∀ p : ℕ, a.factorization p = b.factorization p) : a = b :=
  eq_of_perm_factors ha hb (by 

Proof state:
a✝ b✝ m n p a b : ℕ
ha : a ≠ 0
hb : b ≠ 0
h : ∀ (p : ℕ), (factorization a) p = (factorization b) p
⊢ factors a ~ factors b

Next tactic:
simpa only [List.perm_iff_count, factors_count_eq] using h
/-- Every nonzero natural number has a unique prime factorization -/
theorem factorization_inj : Set.InjOn factorization { x : ℕ | x ≠ 0 } := fun a ha b hb h =>
  eq_of_factorization_eq ha hb fun p => by 

Proof state:
a✝ b✝ m n p✝ a : ℕ
ha : a ∈ {x | x ≠ 0}
b : ℕ
hb : b ∈ {x | x ≠ 0}
h : factorization a = factorization b
p : ℕ
⊢ (factorization a) p = (factorization b) p

Next tactic:
simp [h]
@[simp]
theorem factorization_zero : factorization 0 = 0 := by 

Proof state:
a b m n p : ℕ
⊢ factorization 0 = 0

Next tactic:
decide