l3lab/ntp-mathlib huggingface dataset:
theorem starAlgHomClass_ext [T2Space B] {F : Type*} {a : A}
    [StarAlgHomClass F R (elementalStarAlgebra R a) B] {φ ψ : F} (hφ : Continuous φ)
    (hψ : Continuous ψ) (h : φ ⟨a, self_mem R a⟩ = ψ ⟨a, self_mem R a⟩) : φ = ψ := by
  refine StarAlgHomClass.ext_topologicalClosure hφ hψ fun x => ?_
  apply adjoin_induction' x ?_ ?_ ?_ ?_ ?_
  exacts [fun y hy => by simpa only [Set.mem_singleton_iff.mp hy] using h, fun r => by
    simp only [AlgHomClass.commutes], fun x y hx hy => by simp only [map_add, hx, hy],
    fun x y hx hy => by 

Proof state:
R : Type u_1
A : Type u_2
B : Type u_3
inst✝¹⁴ : CommSemiring R
inst✝¹³ : StarRing R
inst✝¹² : TopologicalSpace A
inst✝¹¹ : Semiring A
inst✝¹⁰ : StarRing A
inst✝⁹ : TopologicalSemiring A
inst✝⁸ : ContinuousStar A
inst✝⁷ : Algebra R A
inst✝⁶ : StarModule R A
inst✝⁵ : TopologicalSpace B
inst✝⁴ : Semiring B
inst✝³ : StarRing B
inst✝² : Algebra R B
inst✝¹ : T2Space B
F : Type u_4
a : A
inst✝ : StarAlgHomClass F R (↥(elementalStarAlgebra R a)) B
φ ψ : F
hφ : Continuous ⇑φ
hψ : Continuous ⇑ψ
h :
  φ { val := a, property := (_ : a ∈ elementalStarAlgebra R a) } =
    ψ { val := a, property := (_ : a ∈ elementalStarAlgebra R a) }
x✝ x y : ↥(adjoin R {a})
hx :
  φ ((StarSubalgebra.inclusion (_ : adjoin R {a} ≤ topologicalClosure (adjoin R {a}))) x) =
    ψ ((StarSubalgebra.inclusion (_ : adjoin R {a} ≤ topologicalClosure (adjoin R {a}))) x)
hy :
  φ ((StarSubalgebra.inclusion (_ : adjoin R {a} ≤ topologicalClosure (adjoin R {a}))) y) =
    ψ ((StarSubalgebra.inclusion (_ : adjoin R {a} ≤ topologicalClosure (adjoin R {a}))) y)
⊢ φ ((StarSubalgebra.inclusion (_ : adjoin R {a} ≤ topologicalClosure (adjoin R {a}))) (x * y)) =
    ψ ((StarSubalgebra.inclusion (_ : adjoin R {a} ≤ topologicalClosure (adjoin R {a}))) (x * y))

Next tactic:
simp only [map_mul, hx, hy]
theorem starAlgHomClass_ext [T2Space B] {F : Type*} {a : A}
    [StarAlgHomClass F R (elementalStarAlgebra R a) B] {φ ψ : F} (hφ : Continuous φ)
    (hψ : Continuous ψ) (h : φ ⟨a, self_mem R a⟩ = ψ ⟨a, self_mem R a⟩) : φ = ψ := by
  refine StarAlgHomClass.ext_topologicalClosure hφ hψ fun x => ?_
  apply adjoin_induction' x ?_ ?_ ?_ ?_ ?_
  exacts [fun y hy => by simpa only [Set.mem_singleton_iff.mp hy] using h, fun r => by
    simp only [AlgHomClass.commutes], fun x y hx hy => by simp only [map_add, hx, hy],
    fun x y hx hy => by simp only [map_mul, hx, hy], fun x hx => by 

Proof state:
R : Type u_1
A : Type u_2
B : Type u_3
inst✝¹⁴ : CommSemiring R
inst✝¹³ : StarRing R
inst✝¹² : TopologicalSpace A
inst✝¹¹ : Semiring A
inst✝¹⁰ : StarRing A
inst✝⁹ : TopologicalSemiring A
inst✝⁸ : ContinuousStar A
inst✝⁷ : Algebra R A
inst✝⁶ : StarModule R A
inst✝⁵ : TopologicalSpace B
inst✝⁴ : Semiring B
inst✝³ : StarRing B
inst✝² : Algebra R B
inst✝¹ : T2Space B
F : Type u_4
a : A
inst✝ : StarAlgHomClass F R (↥(elementalStarAlgebra R a)) B
φ ψ : F
hφ : Continuous ⇑φ
hψ : Continuous ⇑ψ
h :
  φ { val := a, property := (_ : a ∈ elementalStarAlgebra R a) } =
    ψ { val := a, property := (_ : a ∈ elementalStarAlgebra R a) }
x✝ x : ↥(adjoin R {a})
hx :
  φ ((StarSubalgebra.inclusion (_ : adjoin R {a} ≤ topologicalClosure (adjoin R {a}))) x) =
    ψ ((StarSubalgebra.inclusion (_ : adjoin R {a} ≤ topologicalClosure (adjoin R {a}))) x)
⊢ φ ((StarSubalgebra.inclusion (_ : adjoin R {a} ≤ topologicalClosure (adjoin R {a}))) (star x)) =
    ψ ((StarSubalgebra.inclusion (_ : adjoin R {a} ≤ topologicalClosure (adjoin R {a}))) (star x))

Next tactic:
simp only [map_star, hx]
/-- The uniform structure coming from an absolute value. -/
def uniformSpace : UniformSpace R :=
  .ofFun (fun x y => abv (y - x)) (by 

Proof state:
𝕜 : Type u_1
inst✝¹ : LinearOrderedField 𝕜
R : Type u_2
inst✝ : CommRing R
abv : AbsoluteValue R 𝕜
⊢ ∀ (x : R), (fun x y => abv (y - x)) x x = 0

Next tactic:
simp
instance : OrderBot PrimeMultiset where
  bot_le := by 

Proof state:
⊢ ∀ (a : PrimeMultiset), ⊥ ≤ a

Next tactic:
simp only [bot_le, forall_const]
unsafe instance : Repr PrimeMultiset := by 

Proof state:
⊢ Repr PrimeMultiset

Next tactic:
delta PrimeMultiset
unsafe instance : Repr PrimeMultiset := by delta PrimeMultiset; 

Proof state:
⊢ Repr (Multiset Nat.Primes)

Next tactic:
infer_instance
theorem coeNat_prime (v : PrimeMultiset) (p : ℕ) (h : p ∈ (v : Multiset ℕ)) : p.Prime := by
  

Proof state:
v : PrimeMultiset
p : ℕ
h : p ∈ toNatMultiset v
⊢ Nat.Prime p

Next tactic:
rcases Multiset.mem_map.mp h with ⟨⟨_, hp'⟩, ⟨_, h_eq⟩⟩
theorem coeNat_prime (v : PrimeMultiset) (p : ℕ) (h : p ∈ (v : Multiset ℕ)) : p.Prime := by
  rcases Multiset.mem_map.mp h with ⟨⟨_, hp'⟩, ⟨_, h_eq⟩⟩
  

Proof state:
case intro.mk.intro
v : PrimeMultiset
p : ℕ
h : p ∈ toNatMultiset v
val✝ : ℕ
hp' : Nat.Prime val✝
left✝ : { val := val✝, property := hp' } ∈ v
h_eq : Coe.coe { val := val✝, property := hp' } = p
⊢ Nat.Prime p

Next tactic:
exact h_eq ▸ hp'
theorem coePNat_prime (v : PrimeMultiset) (p : ℕ+) (h : p ∈ (v : Multiset ℕ+)) : p.Prime := by
  

Proof state:
v : PrimeMultiset
p : ℕ+
h : p ∈ toPNatMultiset v
⊢ PNat.Prime p

Next tactic:
rcases Multiset.mem_map.mp h with ⟨⟨_, hp'⟩, ⟨_, h_eq⟩⟩
theorem coePNat_prime (v : PrimeMultiset) (p : ℕ+) (h : p ∈ (v : Multiset ℕ+)) : p.Prime := by
  rcases Multiset.mem_map.mp h with ⟨⟨_, hp'⟩, ⟨_, h_eq⟩⟩
  

Proof state:
case intro.mk.intro
v : PrimeMultiset
p : ℕ+
h : p ∈ toPNatMultiset v
val✝ : ℕ
hp' : Nat.Prime val✝
left✝ : { val := val✝, property := hp' } ∈ v
h_eq : Coe.coe { val := val✝, property := hp' } = p
⊢ PNat.Prime p

Next tactic:
exact h_eq ▸ hp'
theorem coePNat_nat (v : PrimeMultiset) : ((v : Multiset ℕ+) : Multiset ℕ) = (v : Multiset ℕ) := by
  

Proof state:
v : PrimeMultiset
⊢ Multiset.map PNat.val (toPNatMultiset v) = toNatMultiset v

Next tactic:
change (v.map (Coe.coe : Nat.Primes → ℕ+)).map Subtype.val = v.map Subtype.val
theorem coePNat_nat (v : PrimeMultiset) : ((v : Multiset ℕ+) : Multiset ℕ) = (v : Multiset ℕ) := by
  change (v.map (Coe.coe : Nat.Primes → ℕ+)).map Subtype.val = v.map Subtype.val
  

Proof state:
v : PrimeMultiset
⊢ Multiset.map Subtype.val (Multiset.map Coe.coe v) = Multiset.map Subtype.val v

Next tactic:
rw [Multiset.map_map]
theorem coePNat_nat (v : PrimeMultiset) : ((v : Multiset ℕ+) : Multiset ℕ) = (v : Multiset ℕ) := by
  change (v.map (Coe.coe : Nat.Primes → ℕ+)).map Subtype.val = v.map Subtype.val
  rw [Multiset.map_map]
  

Proof state:
v : PrimeMultiset
⊢ Multiset.map (Subtype.val ∘ Coe.coe) v = Multiset.map Subtype.val v

Next tactic:
congr
theorem coe_prod (v : PrimeMultiset) : (v.prod : ℕ) = (v : Multiset ℕ).prod := by
  

Proof state:
v : PrimeMultiset
⊢ ↑(prod v) = Multiset.prod (toNatMultiset v)

Next tactic:
let h : (v.prod : ℕ) = ((v.map Coe.coe).map Coe.coe).prod :=
    PNat.coeMonoidHom.map_multiset_prod v.toPNatMultiset
theorem coe_prod (v : PrimeMultiset) : (v.prod : ℕ) = (v : Multiset ℕ).prod := by
  let h : (v.prod : ℕ) = ((v.map Coe.coe).map Coe.coe).prod :=
    PNat.coeMonoidHom.map_multiset_prod v.toPNatMultiset
  

Proof state:
v : PrimeMultiset
h : ↑(prod v) = Multiset.prod (Multiset.map Coe.coe (Multiset.map Coe.coe v)) :=
  MonoidHom.map_multiset_prod PNat.coeMonoidHom (toPNatMultiset v)
⊢ ↑(prod v) = Multiset.prod (toNatMultiset v)

Next tactic:
rw [Multiset.map_map] at h
theorem coe_prod (v : PrimeMultiset) : (v.prod : ℕ) = (v : Multiset ℕ).prod := by
  let h : (v.prod : ℕ) = ((v.map Coe.coe).map Coe.coe).prod :=
    PNat.coeMonoidHom.map_multiset_prod v.toPNatMultiset
  rw [Multiset.map_map] at h
  

Proof state:
v : PrimeMultiset
h : ↑(prod v) = Multiset.prod (Multiset.map (Coe.coe ∘ Coe.coe) v)
⊢ ↑(prod v) = Multiset.prod (toNatMultiset v)

Next tactic:
have : (Coe.coe : ℕ+ → ℕ) ∘ (Coe.coe : Nat.Primes → ℕ+) = Coe.coe := funext fun p => rfl
theorem coe_prod (v : PrimeMultiset) : (v.prod : ℕ) = (v : Multiset ℕ).prod := by
  let h : (v.prod : ℕ) = ((v.map Coe.coe).map Coe.coe).prod :=
    PNat.coeMonoidHom.map_multiset_prod v.toPNatMultiset
  rw [Multiset.map_map] at h
  have : (Coe.coe : ℕ+ → ℕ) ∘ (Coe.coe : Nat.Primes → ℕ+) = Coe.coe := funext fun p => rfl
  

Proof state:
v : PrimeMultiset
h : ↑(prod v) = Multiset.prod (Multiset.map (Coe.coe ∘ Coe.coe) v)
this : Coe.coe ∘ Coe.coe = Coe.coe
⊢ ↑(prod v) = Multiset.prod (toNatMultiset v)

Next tactic:
rw [this] at h
theorem coe_prod (v : PrimeMultiset) : (v.prod : ℕ) = (v : Multiset ℕ).prod := by
  let h : (v.prod : ℕ) = ((v.map Coe.coe).map Coe.coe).prod :=
    PNat.coeMonoidHom.map_multiset_prod v.toPNatMultiset
  rw [Multiset.map_map] at h
  have : (Coe.coe : ℕ+ → ℕ) ∘ (Coe.coe : Nat.Primes → ℕ+) = Coe.coe := funext fun p => rfl
  rw [this] at h; 

Proof state:
v : PrimeMultiset
h : ↑(prod v) = Multiset.prod (Multiset.map Coe.coe v)
this : Coe.coe ∘ Coe.coe = Coe.coe
⊢ ↑(prod v) = Multiset.prod (toNatMultiset v)

Next tactic:
exact h
theorem to_ofNatMultiset (v : Multiset ℕ) (h) : (ofNatMultiset v h : Multiset ℕ) = v := by
  

Proof state:
v : Multiset ℕ
h : ∀ p ∈ v, Nat.Prime p
⊢ toNatMultiset (ofNatMultiset v h) = v

Next tactic:
dsimp [ofNatMultiset, toNatMultiset]
theorem to_ofNatMultiset (v : Multiset ℕ) (h) : (ofNatMultiset v h : Multiset ℕ) = v := by
  dsimp [ofNatMultiset, toNatMultiset]
  

Proof state:
v : Multiset ℕ
h : ∀ p ∈ v, Nat.Prime p
⊢ Multiset.map Coe.coe (Multiset.pmap (fun p hp => { val := p, property := hp }) v h) = v

Next tactic:
have : (fun p h => (Coe.coe : Nat.Primes → ℕ) ⟨p, h⟩) = fun p _ => id p := by
    funext p h
    rfl
theorem to_ofNatMultiset (v : Multiset ℕ) (h) : (ofNatMultiset v h : Multiset ℕ) = v := by
  dsimp [ofNatMultiset, toNatMultiset]
  have : (fun p h => (Coe.coe : Nat.Primes → ℕ) ⟨p, h⟩) = fun p _ => id p := by
    

Proof state:
v : Multiset ℕ
h : ∀ p ∈ v, Nat.Prime p
⊢ (fun p h => Coe.coe { val := p, property := h }) = fun p x => id p

Next tactic:
funext p h
theorem to_ofNatMultiset (v : Multiset ℕ) (h) : (ofNatMultiset v h : Multiset ℕ) = v := by
  dsimp [ofNatMultiset, toNatMultiset]
  have : (fun p h => (Coe.coe : Nat.Primes → ℕ) ⟨p, h⟩) = fun p _ => id p := by
    funext p h
    

Proof state:
case h.h
v : Multiset ℕ
h✝ : ∀ p ∈ v, Nat.Prime p
p : ℕ
h : Nat.Prime p
⊢ Coe.coe { val := p, property := h } = id p

Next tactic:
rfl
theorem to_ofNatMultiset (v : Multiset ℕ) (h) : (ofNatMultiset v h : Multiset ℕ) = v := by
  dsimp [ofNatMultiset, toNatMultiset]
  have : (fun p h => (Coe.coe : Nat.Primes → ℕ) ⟨p, h⟩) = fun p _ => id p := by
    funext p h
    rfl
  

Proof state:
v : Multiset ℕ
h : ∀ p ∈ v, Nat.Prime p
this : (fun p h => Coe.coe { val := p, property := h }) = fun p x => id p
⊢ Multiset.map Coe.coe (Multiset.pmap (fun p hp => { val := p, property := hp }) v h) = v

Next tactic:
rw [Multiset.map_pmap, this, Multiset.pmap_eq_map, Multiset.map_id]
theorem prod_ofNatMultiset (v : Multiset ℕ) (h) : ((ofNatMultiset v h).prod : ℕ) = (v.prod : ℕ) :=
  by 

Proof state:
v : Multiset ℕ
h : ∀ p ∈ v, Nat.Prime p
⊢ ↑(prod (ofNatMultiset v h)) = Multiset.prod v

Next tactic:
rw [coe_prod, to_ofNatMultiset]
theorem to_ofPNatMultiset (v : Multiset ℕ+) (h) : (ofPNatMultiset v h : Multiset ℕ+) = v := by
  

Proof state:
v : Multiset ℕ+
h : ∀ p ∈ v, PNat.Prime p
⊢ toPNatMultiset (ofPNatMultiset v h) = v

Next tactic:
dsimp [ofPNatMultiset, toPNatMultiset]
theorem to_ofPNatMultiset (v : Multiset ℕ+) (h) : (ofPNatMultiset v h : Multiset ℕ+) = v := by
  dsimp [ofPNatMultiset, toPNatMultiset]
  

Proof state:
v : Multiset ℕ+
h : ∀ p ∈ v, PNat.Prime p
⊢ Multiset.map Coe.coe (Multiset.pmap (fun p hp => { val := ↑p, property := hp }) v h) = v

Next tactic:
have : (fun (p : ℕ+) (h : p.Prime) => (Coe.coe : Nat.Primes → ℕ+) ⟨p, h⟩) = fun p _ => id p := by
    funext p h
    apply Subtype.eq
    rfl
theorem to_ofPNatMultiset (v : Multiset ℕ+) (h) : (ofPNatMultiset v h : Multiset ℕ+) = v := by
  dsimp [ofPNatMultiset, toPNatMultiset]
  have : (fun (p : ℕ+) (h : p.Prime) => (Coe.coe : Nat.Primes → ℕ+) ⟨p, h⟩) = fun p _ => id p := by
    

Proof state:
v : Multiset ℕ+
h : ∀ p ∈ v, PNat.Prime p
⊢ (fun p h => Coe.coe { val := ↑p, property := h }) = fun p x => id p

Next tactic:
funext p h
theorem to_ofPNatMultiset (v : Multiset ℕ+) (h) : (ofPNatMultiset v h : Multiset ℕ+) = v := by
  dsimp [ofPNatMultiset, toPNatMultiset]
  have : (fun (p : ℕ+) (h : p.Prime) => (Coe.coe : Nat.Primes → ℕ+) ⟨p, h⟩) = fun p _ => id p := by
    funext p h
    

Proof state:
case h.h
v : Multiset ℕ+
h✝ : ∀ p ∈ v, PNat.Prime p
p : ℕ+
h : PNat.Prime p
⊢ Coe.coe { val := ↑p, property := h } = id p

Next tactic:
apply Subtype.eq
theorem to_ofPNatMultiset (v : Multiset ℕ+) (h) : (ofPNatMultiset v h : Multiset ℕ+) = v := by
  dsimp [ofPNatMultiset, toPNatMultiset]
  have : (fun (p : ℕ+) (h : p.Prime) => (Coe.coe : Nat.Primes → ℕ+) ⟨p, h⟩) = fun p _ => id p := by
    funext p h
    apply Subtype.eq
    

Proof state:
case h.h.a
v : Multiset ℕ+
h✝ : ∀ p ∈ v, PNat.Prime p
p : ℕ+
h : PNat.Prime p
⊢ ↑(Coe.coe { val := ↑p, property := h }) = ↑(id p)

Next tactic:
rfl
theorem to_ofPNatMultiset (v : Multiset ℕ+) (h) : (ofPNatMultiset v h : Multiset ℕ+) = v := by
  dsimp [ofPNatMultiset, toPNatMultiset]
  have : (fun (p : ℕ+) (h : p.Prime) => (Coe.coe : Nat.Primes → ℕ+) ⟨p, h⟩) = fun p _ => id p := by
    funext p h
    apply Subtype.eq
    rfl
  

Proof state:
v : Multiset ℕ+
h : ∀ p ∈ v, PNat.Prime p
this : (fun p h => Coe.coe { val := ↑p, property := h }) = fun p x => id p
⊢ Multiset.map Coe.coe (Multiset.pmap (fun p hp => { val := ↑p, property := hp }) v h) = v

Next tactic:
rw [Multiset.map_pmap, this, Multiset.pmap_eq_map, Multiset.map_id]
theorem prod_ofPNatMultiset (v : Multiset ℕ+) (h) : ((ofPNatMultiset v h).prod : ℕ+) = v.prod := by
  

Proof state:
v : Multiset ℕ+
h : ∀ p ∈ v, PNat.Prime p
⊢ prod (ofPNatMultiset v h) = Multiset.prod v

Next tactic:
dsimp [prod]
theorem prod_ofPNatMultiset (v : Multiset ℕ+) (h) : ((ofPNatMultiset v h).prod : ℕ+) = v.prod := by
  dsimp [prod]
  

Proof state:
v : Multiset ℕ+
h : ∀ p ∈ v, PNat.Prime p
⊢ Multiset.prod (toPNatMultiset (ofPNatMultiset v h)) = Multiset.prod v

Next tactic:
rw [to_ofPNatMultiset]
theorem prod_ofNatList (l : List ℕ) (h) : ((ofNatList l h).prod : ℕ) = l.prod := by
  

Proof state:
l : List ℕ
h : ∀ p ∈ l, Nat.Prime p
⊢ ↑(prod (ofNatList l h)) = List.prod l

Next tactic:
have := prod_ofNatMultiset (l : Multiset ℕ) h
theorem prod_ofNatList (l : List ℕ) (h) : ((ofNatList l h).prod : ℕ) = l.prod := by
  have := prod_ofNatMultiset (l : Multiset ℕ) h
  

Proof state:
l : List ℕ
h : ∀ p ∈ l, Nat.Prime p
this : ↑(prod (ofNatMultiset (↑l) h)) = Multiset.prod ↑l
⊢ ↑(prod (ofNatList l h)) = List.prod l

Next tactic:
rw [Multiset.coe_prod] at this
theorem prod_ofNatList (l : List ℕ) (h) : ((ofNatList l h).prod : ℕ) = l.prod := by
  have := prod_ofNatMultiset (l : Multiset ℕ) h
  rw [Multiset.coe_prod] at this
  

Proof state:
l : List ℕ
h : ∀ p ∈ l, Nat.Prime p
this : ↑(prod (ofNatMultiset (↑l) h)) = List.prod l
⊢ ↑(prod (ofNatList l h)) = List.prod l

Next tactic:
exact this
theorem prod_ofPNatList (l : List ℕ+) (h) : (ofPNatList l h).prod = l.prod := by
  

Proof state:
l : List ℕ+
h : ∀ p ∈ l, PNat.Prime p
⊢ prod (ofPNatList l h) = List.prod l

Next tactic:
have := prod_ofPNatMultiset (l : Multiset ℕ+) h
theorem prod_ofPNatList (l : List ℕ+) (h) : (ofPNatList l h).prod = l.prod := by
  have := prod_ofPNatMultiset (l : Multiset ℕ+) h
  

Proof state:
l : List ℕ+
h : ∀ p ∈ l, PNat.Prime p
this : prod (ofPNatMultiset (↑l) h) = Multiset.prod ↑l
⊢ prod (ofPNatList l h) = List.prod l

Next tactic:
rw [Multiset.coe_prod] at this
theorem prod_ofPNatList (l : List ℕ+) (h) : (ofPNatList l h).prod = l.prod := by
  have := prod_ofPNatMultiset (l : Multiset ℕ+) h
  rw [Multiset.coe_prod] at this
  

Proof state:
l : List ℕ+
h : ∀ p ∈ l, PNat.Prime p
this : prod (ofPNatMultiset (↑l) h) = List.prod l
⊢ prod (ofPNatList l h) = List.prod l

Next tactic:
exact this
/-- The product map gives a homomorphism from the additive monoid
of multisets to the multiplicative monoid ℕ+. -/
theorem prod_zero : (0 : PrimeMultiset).prod = 1 := by
  

Proof state:
⊢ prod 0 = 1

Next tactic:
exact Multiset.prod_zero
theorem prod_add (u v : PrimeMultiset) : (u + v).prod = u.prod * v.prod := by
  

Proof state:
u v : PrimeMultiset
⊢ prod (u + v) = prod u * prod v

Next tactic:
change (coePNatMonoidHom (u + v)).prod = _
theorem prod_add (u v : PrimeMultiset) : (u + v).prod = u.prod * v.prod := by
  change (coePNatMonoidHom (u + v)).prod = _
  

Proof state:
u v : PrimeMultiset
⊢ Multiset.prod (coePNatMonoidHom (u + v)) = prod u * prod v

Next tactic:
rw [coePNatMonoidHom.map_add]
theorem prod_add (u v : PrimeMultiset) : (u + v).prod = u.prod * v.prod := by
  change (coePNatMonoidHom (u + v)).prod = _
  rw [coePNatMonoidHom.map_add]
  

Proof state:
u v : PrimeMultiset
⊢ Multiset.prod (coePNatMonoidHom u + coePNatMonoidHom v) = prod u * prod v

Next tactic:
exact Multiset.prod_add _ _
theorem prod_smul (d : ℕ) (u : PrimeMultiset) : (d • u).prod = Pow.pow u.prod d := by
  

Proof state:
d : ℕ
u : PrimeMultiset
⊢ prod (d • u) = Pow.pow (prod u) d

Next tactic:
induction' d with n ih
theorem prod_smul (d : ℕ) (u : PrimeMultiset) : (d • u).prod = Pow.pow u.prod d := by
  induction' d with n ih
  · 

Proof state:
case zero
u : PrimeMultiset
⊢ prod (Nat.zero • u) = Pow.pow (prod u) Nat.zero

Next tactic:
rfl
theorem prod_smul (d : ℕ) (u : PrimeMultiset) : (d • u).prod = Pow.pow u.prod d := by
  induction' d with n ih
  · rfl
  · 

Proof state:
case succ
u : PrimeMultiset
n : ℕ
ih : prod (n • u) = Pow.pow (prod u) n
⊢ prod (Nat.succ n • u) = Pow.pow (prod u) (Nat.succ n)

Next tactic:
have : ∀ n' : ℕ, Pow.pow (prod u) n' = Monoid.npow n' (prod u) := fun _ ↦ rfl
theorem prod_smul (d : ℕ) (u : PrimeMultiset) : (d • u).prod = Pow.pow u.prod d := by
  induction' d with n ih
  · rfl
  · have : ∀ n' : ℕ, Pow.pow (prod u) n' = Monoid.npow n' (prod u) := fun _ ↦ rfl
    

Proof state:
case succ
u : PrimeMultiset
n : ℕ
ih : prod (n • u) = Pow.pow (prod u) n
this : ∀ (n' : ℕ), Pow.pow (prod u) n' = Monoid.npow n' (prod u)
⊢ prod (Nat.succ n • u) = Pow.pow (prod u) (Nat.succ n)

Next tactic:
rw [succ_nsmul, prod_add, ih, this, this, Monoid.npow_succ, mul_comm]
/-- The product of the factors is the original number -/
theorem prod_factorMultiset (n : ℕ+) : (factorMultiset n).prod = n :=
  eq <| by
    

Proof state:
n : ℕ+
⊢ ↑(PrimeMultiset.prod (factorMultiset n)) = ↑n

Next tactic:
dsimp [factorMultiset]
/-- The product of the factors is the original number -/
theorem prod_factorMultiset (n : ℕ+) : (factorMultiset n).prod = n :=
  eq <| by
    dsimp [factorMultiset]
    

Proof state:
n : ℕ+
⊢ ↑(PrimeMultiset.prod (PrimeMultiset.ofNatList (Nat.factors ↑n) (_ : ∀ {p : ℕ}, p ∈ Nat.factors ↑n → Nat.Prime p))) =
    ↑n

Next tactic:
rw [PrimeMultiset.prod_ofNatList]
/-- The product of the factors is the original number -/
theorem prod_factorMultiset (n : ℕ+) : (factorMultiset n).prod = n :=
  eq <| by
    dsimp [factorMultiset]
    rw [PrimeMultiset.prod_ofNatList]
    

Proof state:
n : ℕ+
⊢ List.prod (Nat.factors ↑n) = ↑n

Next tactic:
exact Nat.prod_factors n.ne_zero
/-- If we start with a multiset of primes, take the product and
 then factor it, we get back the original multiset. -/
theorem factorMultiset_prod (v : PrimeMultiset) : v.prod.factorMultiset = v := by
  

Proof state:
v : PrimeMultiset
⊢ PNat.factorMultiset (prod v) = v

Next tactic:
apply PrimeMultiset.coeNat_injective
/-- If we start with a multiset of primes, take the product and
 then factor it, we get back the original multiset. -/
theorem factorMultiset_prod (v : PrimeMultiset) : v.prod.factorMultiset = v := by
  apply PrimeMultiset.coeNat_injective
  

Proof state:
case a
v : PrimeMultiset
⊢ Coe.coe (PNat.factorMultiset (prod v)) = Coe.coe v

Next tactic:
suffices toNatMultiset (PNat.factorMultiset (prod v)) = toNatMultiset v by exact this
/-- If we start with a multiset of primes, take the product and
 then factor it, we get back the original multiset. -/
theorem factorMultiset_prod (v : PrimeMultiset) : v.prod.factorMultiset = v := by
  apply PrimeMultiset.coeNat_injective
  suffices toNatMultiset (PNat.factorMultiset (prod v)) = toNatMultiset v by 

Proof state:
v : PrimeMultiset
this : toNatMultiset (PNat.factorMultiset (prod v)) = toNatMultiset v
⊢ Coe.coe (PNat.factorMultiset (prod v)) = Coe.coe v

Next tactic:
exact this
/-- If we start with a multiset of primes, take the product and
 then factor it, we get back the original multiset. -/
theorem factorMultiset_prod (v : PrimeMultiset) : v.prod.factorMultiset = v := by
  apply PrimeMultiset.coeNat_injective
  suffices toNatMultiset (PNat.factorMultiset (prod v)) = toNatMultiset v by exact this
  

Proof state:
case a
v : PrimeMultiset
⊢ toNatMultiset (PNat.factorMultiset (prod v)) = toNatMultiset v

Next tactic:
rw [v.prod.coeNat_factorMultiset, PrimeMultiset.coe_prod]
/-- If we start with a multiset of primes, take the product and
 then factor it, we get back the original multiset. -/
theorem factorMultiset_prod (v : PrimeMultiset) : v.prod.factorMultiset = v := by
  apply PrimeMultiset.coeNat_injective
  suffices toNatMultiset (PNat.factorMultiset (prod v)) = toNatMultiset v by exact this
  rw [v.prod.coeNat_factorMultiset, PrimeMultiset.coe_prod]
  

Proof state:
case a
v : PrimeMultiset
⊢ ↑(Nat.factors (Multiset.prod (toNatMultiset v))) = toNatMultiset v

Next tactic:
rcases v with ⟨l⟩
/-- If we start with a multiset of primes, take the product and
 then factor it, we get back the original multiset. -/
theorem factorMultiset_prod (v : PrimeMultiset) : v.prod.factorMultiset = v := by
  apply PrimeMultiset.coeNat_injective
  suffices toNatMultiset (PNat.factorMultiset (prod v)) = toNatMultiset v by exact this
  rw [v.prod.coeNat_factorMultiset, PrimeMultiset.coe_prod]
  rcases v with ⟨l⟩
  --unfold_coes
  

Proof state:
case a.mk
v : PrimeMultiset
l : List Nat.Primes
⊢ ↑(Nat.factors (Multiset.prod (toNatMultiset (Quot.mk Setoid.r l)))) = toNatMultiset (Quot.mk Setoid.r l)

Next tactic:
dsimp [PrimeMultiset.toNatMultiset]
/-- If we start with a multiset of primes, take the product and
 then factor it, we get back the original multiset. -/
theorem factorMultiset_prod (v : PrimeMultiset) : v.prod.factorMultiset = v := by
  apply PrimeMultiset.coeNat_injective
  suffices toNatMultiset (PNat.factorMultiset (prod v)) = toNatMultiset v by exact this
  rw [v.prod.coeNat_factorMultiset, PrimeMultiset.coe_prod]
  rcases v with ⟨l⟩
  --unfold_coes
  dsimp [PrimeMultiset.toNatMultiset]
  

Proof state:
case a.mk
v : PrimeMultiset
l : List Nat.Primes
⊢ ↑(Nat.factors (Multiset.prod ↑(List.map Coe.coe l))) = ↑(List.map Coe.coe l)

Next tactic:
rw [Multiset.coe_prod]
/-- If we start with a multiset of primes, take the product and
 then factor it, we get back the original multiset. -/
theorem factorMultiset_prod (v : PrimeMultiset) : v.prod.factorMultiset = v := by
  apply PrimeMultiset.coeNat_injective
  suffices toNatMultiset (PNat.factorMultiset (prod v)) = toNatMultiset v by exact this
  rw [v.prod.coeNat_factorMultiset, PrimeMultiset.coe_prod]
  rcases v with ⟨l⟩
  --unfold_coes
  dsimp [PrimeMultiset.toNatMultiset]
  rw [Multiset.coe_prod]
  

Proof state:
case a.mk
v : PrimeMultiset
l : List Nat.Primes
⊢ ↑(Nat.factors (List.prod (List.map Coe.coe l))) = ↑(List.map Coe.coe l)

Next tactic:
let l' := l.map (Coe.coe : Nat.Primes → ℕ)
/-- If we start with a multiset of primes, take the product and
 then factor it, we get back the original multiset. -/
theorem factorMultiset_prod (v : PrimeMultiset) : v.prod.factorMultiset = v := by
  apply PrimeMultiset.coeNat_injective
  suffices toNatMultiset (PNat.factorMultiset (prod v)) = toNatMultiset v by exact this
  rw [v.prod.coeNat_factorMultiset, PrimeMultiset.coe_prod]
  rcases v with ⟨l⟩
  --unfold_coes
  dsimp [PrimeMultiset.toNatMultiset]
  rw [Multiset.coe_prod]
  let l' := l.map (Coe.coe : Nat.Primes → ℕ)
  

Proof state:
case a.mk
v : PrimeMultiset
l : List Nat.Primes
l' : List ℕ := List.map Coe.coe l
⊢ ↑(Nat.factors (List.prod (List.map Coe.coe l))) = ↑(List.map Coe.coe l)

Next tactic:
have : ∀ p : ℕ, p ∈ l' → p.Prime := fun p hp => by
    rcases List.mem_map.mp hp with ⟨⟨_, hp'⟩, ⟨_, h_eq⟩⟩
    exact h_eq ▸ hp'