l3lab/ntp-mathlib huggingface dataset:
theorem lcm_apply_mul_gcd_apply [CommMonoidWithZero R] {f : ArithmeticFunction R}
    (hf : f.IsMultiplicative) {x y : ℕ} :
    f (x.lcm y) * f (x.gcd y) = f x * f y := by
  by_cases hx : x = 0
  · simp only [hx, f.map_zero, zero_mul, lcm_zero_left, gcd_zero_left]
  by_cases hy : y = 0
  · simp only [hy, f.map_zero, mul_zero, lcm_zero_right, gcd_zero_right, zero_mul]
  have hgcd_ne_zero : x.gcd y ≠ 0 := gcd_ne_zero_left hx
  have hlcm_ne_zero : x.lcm y ≠ 0 := lcm_ne_zero hx hy
  have hfi_zero : ∀ {i}, f (i ^ 0) = 1
  · intro i; rw [pow_zero, hf.1]
  iterate 4 rw [hf.multiplicative_factorization f (by assumption),
    Finsupp.prod_of_support_subset _ _ _ (fun _ _ => hfi_zero)
      (s := (x.primeFactors ⊔ y.primeFactors))]
  · rw [← Finset.prod_mul_distrib, ← Finset.prod_mul_distrib]
    apply Finset.prod_congr rfl
    intro p _
    rcases Nat.le_or_le (x.factorization p) (y.factorization p) with h | h <;>
      simp only [factorization_lcm hx hy, ge_iff_le, Finsupp.sup_apply, h, sup_of_le_right,
        sup_of_le_left, inf_of_le_right, Nat.factorization_gcd hx hy, Finsupp.inf_apply,
        inf_of_le_left, mul_comm]
  · apply Finset.subset_union_right
  · apply Finset.subset_union_left
  · rw [factorization_gcd hx hy, Finsupp.support_inf, Finset.sup_eq_union]
    apply Finset.inter_subset_union
  · 

Proof state:
R : Type u_1
inst✝ : CommMonoidWithZero R
f : ArithmeticFunction R
hf : IsMultiplicative f
x y : ℕ
hx : ¬x = 0
hy : ¬y = 0
hgcd_ne_zero : gcd x y ≠ 0
hlcm_ne_zero : lcm x y ≠ 0
hfi_zero : ∀ {i : ℕ}, f (i ^ 0) = 1
⊢ (factorization (lcm x y)).support ⊆ x.primeFactors ⊔ y.primeFactors

Next tactic:
simp [factorization_lcm hx hy]
@[simp]
theorem pow_apply {k n : ℕ} : pow k n = if k = 0 ∧ n = 0 then 0 else n ^ k := by
  

Proof state:
R : Type u_1
k n : ℕ
⊢ (pow k) n = if k = 0 ∧ n = 0 then 0 else n ^ k

Next tactic:
cases k
@[simp]
theorem pow_apply {k n : ℕ} : pow k n = if k = 0 ∧ n = 0 then 0 else n ^ k := by
  cases k
  · 

Proof state:
case zero
R : Type u_1
n : ℕ
⊢ (pow Nat.zero) n = if Nat.zero = 0 ∧ n = 0 then 0 else n ^ Nat.zero

Next tactic:
simp [pow]
@[simp]
theorem pow_apply {k n : ℕ} : pow k n = if k = 0 ∧ n = 0 then 0 else n ^ k := by
  cases k
  · simp [pow]
  

Proof state:
case succ
R : Type u_1
n n✝ : ℕ
⊢ (pow (succ n✝)) n = if succ n✝ = 0 ∧ n = 0 then 0 else n ^ succ n✝

Next tactic:
rename_i k
@[simp]
theorem pow_apply {k n : ℕ} : pow k n = if k = 0 ∧ n = 0 then 0 else n ^ k := by
  cases k
  · simp [pow]
  rename_i k  -- porting note: added
  

Proof state:
case succ
R : Type u_1
n k : ℕ
⊢ (pow (succ k)) n = if succ k = 0 ∧ n = 0 then 0 else n ^ succ k

Next tactic:
simp [pow, (ne_of_lt (Nat.succ_pos k)).symm]
theorem pow_zero_eq_zeta : pow 0 = ζ := by
  

Proof state:
R : Type u_1
⊢ pow 0 = ζ

Next tactic:
ext n
theorem pow_zero_eq_zeta : pow 0 = ζ := by
  ext n
  

Proof state:
case h
R : Type u_1
n : ℕ
⊢ (pow 0) n = ζ n

Next tactic:
simp
/-- `σ k n` is the sum of the `k`th powers of the divisors of `n` -/
def sigma (k : ℕ) : ArithmeticFunction ℕ :=
  ⟨fun n => ∑ d in divisors n, d ^ k, by 

Proof state:
R : Type u_1
k : ℕ
⊢ (fun n => ∑ d in divisors n, d ^ k) 0 = 0

Next tactic:
simp
theorem sigma_one_apply (n : ℕ) : σ 1 n = ∑ d in divisors n, d := by 

Proof state:
R : Type u_1
n : ℕ
⊢ (σ 1) n = ∑ d in divisors n, d

Next tactic:
simp [sigma_apply]
theorem sigma_zero_apply (n : ℕ) : σ 0 n = (divisors n).card := by 

Proof state:
R : Type u_1
n : ℕ
⊢ (σ 0) n = card (divisors n)

Next tactic:
simp [sigma_apply]
theorem sigma_zero_apply_prime_pow {p i : ℕ} (hp : p.Prime) : σ 0 (p ^ i) = i + 1 := by
  

Proof state:
R : Type u_1
p i : ℕ
hp : Prime p
⊢ (σ 0) (p ^ i) = i + 1

Next tactic:
rw [sigma_zero_apply, divisors_prime_pow hp, card_map, card_range]
theorem zeta_mul_pow_eq_sigma {k : ℕ} : ζ * pow k = σ k := by
  

Proof state:
R : Type u_1
k : ℕ
⊢ ζ * pow k = σ k

Next tactic:
ext
theorem zeta_mul_pow_eq_sigma {k : ℕ} : ζ * pow k = σ k := by
  ext
  

Proof state:
case h
R : Type u_1
k x✝ : ℕ
⊢ (ζ * pow k) x✝ = (σ k) x✝

Next tactic:
rw [sigma, zeta_mul_apply]
theorem zeta_mul_pow_eq_sigma {k : ℕ} : ζ * pow k = σ k := by
  ext
  rw [sigma, zeta_mul_apply]
  

Proof state:
case h
R : Type u_1
k x✝ : ℕ
⊢ ∑ i in divisors x✝, (pow k) i =
    { toFun := fun n => ∑ d in divisors n, d ^ k, map_zero' := (_ : ∑ d in divisors 0, d ^ k = 0) } x✝

Next tactic:
apply sum_congr rfl
theorem zeta_mul_pow_eq_sigma {k : ℕ} : ζ * pow k = σ k := by
  ext
  rw [sigma, zeta_mul_apply]
  apply sum_congr rfl
  

Proof state:
case h
R : Type u_1
k x✝ : ℕ
⊢ ∀ x ∈ divisors x✝, (pow k) x = x ^ k

Next tactic:
intro x hx
theorem zeta_mul_pow_eq_sigma {k : ℕ} : ζ * pow k = σ k := by
  ext
  rw [sigma, zeta_mul_apply]
  apply sum_congr rfl
  intro x hx
  

Proof state:
case h
R : Type u_1
k x✝ x : ℕ
hx : x ∈ divisors x✝
⊢ (pow k) x = x ^ k

Next tactic:
rw [pow_apply, if_neg (not_and_of_not_right _ _)]
theorem zeta_mul_pow_eq_sigma {k : ℕ} : ζ * pow k = σ k := by
  ext
  rw [sigma, zeta_mul_apply]
  apply sum_congr rfl
  intro x hx
  rw [pow_apply, if_neg (not_and_of_not_right _ _)]
  

Proof state:
R : Type u_1
k x✝ x : ℕ
hx : x ∈ divisors x✝
⊢ ¬x = 0

Next tactic:
contrapose! hx
theorem zeta_mul_pow_eq_sigma {k : ℕ} : ζ * pow k = σ k := by
  ext
  rw [sigma, zeta_mul_apply]
  apply sum_congr rfl
  intro x hx
  rw [pow_apply, if_neg (not_and_of_not_right _ _)]
  contrapose! hx
  

Proof state:
R : Type u_1
k x✝ x : ℕ
hx : x = 0
⊢ x ∉ divisors x✝

Next tactic:
simp [hx]
theorem isMultiplicative_one [MonoidWithZero R] : IsMultiplicative (1 : ArithmeticFunction R) :=
  IsMultiplicative.iff_ne_zero.2
    ⟨by 

Proof state:
R : Type u_1
inst✝ : MonoidWithZero R
⊢ 1 1 = 1

Next tactic:
simp
theorem isMultiplicative_one [MonoidWithZero R] : IsMultiplicative (1 : ArithmeticFunction R) :=
  IsMultiplicative.iff_ne_zero.2
    ⟨by simp, by
      

Proof state:
R : Type u_1
inst✝ : MonoidWithZero R
⊢ ∀ {m n : ℕ}, m ≠ 0 → n ≠ 0 → Coprime m n → 1 (m * n) = 1 m * 1 n

Next tactic:
intro m n hm _hn hmn
theorem isMultiplicative_one [MonoidWithZero R] : IsMultiplicative (1 : ArithmeticFunction R) :=
  IsMultiplicative.iff_ne_zero.2
    ⟨by simp, by
      intro m n hm _hn hmn
      

Proof state:
R : Type u_1
inst✝ : MonoidWithZero R
m n : ℕ
hm : m ≠ 0
_hn : n ≠ 0
hmn : Coprime m n
⊢ 1 (m * n) = 1 m * 1 n

Next tactic:
rcases eq_or_ne m 1 with (rfl | hm')
theorem isMultiplicative_one [MonoidWithZero R] : IsMultiplicative (1 : ArithmeticFunction R) :=
  IsMultiplicative.iff_ne_zero.2
    ⟨by simp, by
      intro m n hm _hn hmn
      rcases eq_or_ne m 1 with (rfl | hm')
      · 

Proof state:
case inl
R : Type u_1
inst✝ : MonoidWithZero R
n : ℕ
_hn : n ≠ 0
hm : 1 ≠ 0
hmn : Coprime 1 n
⊢ 1 (1 * n) = 1 1 * 1 n

Next tactic:
simp
theorem isMultiplicative_one [MonoidWithZero R] : IsMultiplicative (1 : ArithmeticFunction R) :=
  IsMultiplicative.iff_ne_zero.2
    ⟨by simp, by
      intro m n hm _hn hmn
      rcases eq_or_ne m 1 with (rfl | hm')
      · simp
      

Proof state:
case inr
R : Type u_1
inst✝ : MonoidWithZero R
m n : ℕ
hm : m ≠ 0
_hn : n ≠ 0
hmn : Coprime m n
hm' : m ≠ 1
⊢ 1 (m * n) = 1 m * 1 n

Next tactic:
rw [one_apply_ne, one_apply_ne hm', zero_mul]
theorem isMultiplicative_one [MonoidWithZero R] : IsMultiplicative (1 : ArithmeticFunction R) :=
  IsMultiplicative.iff_ne_zero.2
    ⟨by simp, by
      intro m n hm _hn hmn
      rcases eq_or_ne m 1 with (rfl | hm')
      · simp
      rw [one_apply_ne, one_apply_ne hm', zero_mul]
      

Proof state:
case inr
R : Type u_1
inst✝ : MonoidWithZero R
m n : ℕ
hm : m ≠ 0
_hn : n ≠ 0
hmn : Coprime m n
hm' : m ≠ 1
⊢ m * n ≠ 1

Next tactic:
rw [Ne.def, mul_eq_one, not_and_or]
theorem isMultiplicative_one [MonoidWithZero R] : IsMultiplicative (1 : ArithmeticFunction R) :=
  IsMultiplicative.iff_ne_zero.2
    ⟨by simp, by
      intro m n hm _hn hmn
      rcases eq_or_ne m 1 with (rfl | hm')
      · simp
      rw [one_apply_ne, one_apply_ne hm', zero_mul]
      rw [Ne.def, mul_eq_one, not_and_or]
      

Proof state:
case inr
R : Type u_1
inst✝ : MonoidWithZero R
m n : ℕ
hm : m ≠ 0
_hn : n ≠ 0
hmn : Coprime m n
hm' : m ≠ 1
⊢ ¬m = 1 ∨ ¬n = 1

Next tactic:
exact Or.inl hm'
theorem isMultiplicative_zeta : IsMultiplicative ζ :=
  IsMultiplicative.iff_ne_zero.2 ⟨by 

Proof state:
R : Type u_1
⊢ ζ 1 = 1

Next tactic:
simp
theorem isMultiplicative_zeta : IsMultiplicative ζ :=
  IsMultiplicative.iff_ne_zero.2 ⟨by simp, by 

Proof state:
R : Type u_1
⊢ ∀ {m n : ℕ}, m ≠ 0 → n ≠ 0 → Coprime m n → ζ (m * n) = ζ m * ζ n

Next tactic:
simp (config := { contextual := true })
theorem IsMultiplicative.ppow [CommSemiring R] {f : ArithmeticFunction R} (hf : f.IsMultiplicative)
    {k : ℕ} : IsMultiplicative (f.ppow k) := by
  

Proof state:
R : Type u_1
inst✝ : CommSemiring R
f : ArithmeticFunction R
hf : IsMultiplicative f
k : ℕ
⊢ IsMultiplicative (ArithmeticFunction.ppow f k)

Next tactic:
induction' k with k hi
theorem IsMultiplicative.ppow [CommSemiring R] {f : ArithmeticFunction R} (hf : f.IsMultiplicative)
    {k : ℕ} : IsMultiplicative (f.ppow k) := by
  induction' k with k hi
  · 

Proof state:
case zero
R : Type u_1
inst✝ : CommSemiring R
f : ArithmeticFunction R
hf : IsMultiplicative f
⊢ IsMultiplicative (ArithmeticFunction.ppow f Nat.zero)

Next tactic:
exact isMultiplicative_zeta.nat_cast
theorem IsMultiplicative.ppow [CommSemiring R] {f : ArithmeticFunction R} (hf : f.IsMultiplicative)
    {k : ℕ} : IsMultiplicative (f.ppow k) := by
  induction' k with k hi
  · exact isMultiplicative_zeta.nat_cast
  · 

Proof state:
case succ
R : Type u_1
inst✝ : CommSemiring R
f : ArithmeticFunction R
hf : IsMultiplicative f
k : ℕ
hi : IsMultiplicative (ArithmeticFunction.ppow f k)
⊢ IsMultiplicative (ArithmeticFunction.ppow f (succ k))

Next tactic:
rw [ppow_succ]
theorem IsMultiplicative.ppow [CommSemiring R] {f : ArithmeticFunction R} (hf : f.IsMultiplicative)
    {k : ℕ} : IsMultiplicative (f.ppow k) := by
  induction' k with k hi
  · exact isMultiplicative_zeta.nat_cast
  · rw [ppow_succ]
    

Proof state:
case succ
R : Type u_1
inst✝ : CommSemiring R
f : ArithmeticFunction R
hf : IsMultiplicative f
k : ℕ
hi : IsMultiplicative (ArithmeticFunction.ppow f k)
⊢ IsMultiplicative (ArithmeticFunction.pmul f (ArithmeticFunction.ppow f k))

Next tactic:
apply hf.pmul hi
theorem isMultiplicative_sigma {k : ℕ} : IsMultiplicative (σ k) := by
  

Proof state:
R : Type u_1
k : ℕ
⊢ IsMultiplicative (σ k)

Next tactic:
rw [← zeta_mul_pow_eq_sigma]
theorem isMultiplicative_sigma {k : ℕ} : IsMultiplicative (σ k) := by
  rw [← zeta_mul_pow_eq_sigma]
  

Proof state:
R : Type u_1
k : ℕ
⊢ IsMultiplicative (ζ * pow k)

Next tactic:
apply isMultiplicative_zeta.mul isMultiplicative_pow
/-- `Ω n` is the number of prime factors of `n`. -/
def cardFactors : ArithmeticFunction ℕ :=
  ⟨fun n => n.factors.length, by 

Proof state:
R : Type u_1
⊢ (fun n => List.length (factors n)) 0 = 0

Next tactic:
simp
@[simp]
theorem cardFactors_one : Ω 1 = 0 := by 

Proof state:
R : Type u_1
⊢ Ω 1 = 0

Next tactic:
simp [cardFactors]
theorem cardFactors_eq_one_iff_prime {n : ℕ} : Ω n = 1 ↔ n.Prime := by
  

Proof state:
R : Type u_1
n : ℕ
⊢ Ω n = 1 ↔ Prime n

Next tactic:
refine' ⟨fun h => _, fun h => List.length_eq_one.2 ⟨n, factors_prime h⟩⟩
theorem cardFactors_eq_one_iff_prime {n : ℕ} : Ω n = 1 ↔ n.Prime := by
  refine' ⟨fun h => _, fun h => List.length_eq_one.2 ⟨n, factors_prime h⟩⟩
  

Proof state:
R : Type u_1
n : ℕ
h : Ω n = 1
⊢ Prime n

Next tactic:
cases' n with n
theorem cardFactors_eq_one_iff_prime {n : ℕ} : Ω n = 1 ↔ n.Prime := by
  refine' ⟨fun h => _, fun h => List.length_eq_one.2 ⟨n, factors_prime h⟩⟩
  cases' n with n
  · 

Proof state:
case zero
R : Type u_1
h : Ω Nat.zero = 1
⊢ Prime Nat.zero

Next tactic:
contrapose! h
theorem cardFactors_eq_one_iff_prime {n : ℕ} : Ω n = 1 ↔ n.Prime := by
  refine' ⟨fun h => _, fun h => List.length_eq_one.2 ⟨n, factors_prime h⟩⟩
  cases' n with n
  · contrapose! h
    

Proof state:
case zero
R : Type u_1
h : ¬Prime Nat.zero
⊢ Ω Nat.zero ≠ 1

Next tactic:
simp
theorem cardFactors_eq_one_iff_prime {n : ℕ} : Ω n = 1 ↔ n.Prime := by
  refine' ⟨fun h => _, fun h => List.length_eq_one.2 ⟨n, factors_prime h⟩⟩
  cases' n with n
  · contrapose! h
    simp
  

Proof state:
case succ
R : Type u_1
n : ℕ
h : Ω (succ n) = 1
⊢ Prime (succ n)

Next tactic:
rcases List.length_eq_one.1 h with ⟨x, hx⟩
theorem cardFactors_eq_one_iff_prime {n : ℕ} : Ω n = 1 ↔ n.Prime := by
  refine' ⟨fun h => _, fun h => List.length_eq_one.2 ⟨n, factors_prime h⟩⟩
  cases' n with n
  · contrapose! h
    simp
  rcases List.length_eq_one.1 h with ⟨x, hx⟩
  

Proof state:
case succ.intro
R : Type u_1
n : ℕ
h : Ω (succ n) = 1
x : ℕ
hx : factors (succ n) = [x]
⊢ Prime (succ n)

Next tactic:
rw [← prod_factors n.succ_ne_zero, hx, List.prod_singleton]
theorem cardFactors_eq_one_iff_prime {n : ℕ} : Ω n = 1 ↔ n.Prime := by
  refine' ⟨fun h => _, fun h => List.length_eq_one.2 ⟨n, factors_prime h⟩⟩
  cases' n with n
  · contrapose! h
    simp
  rcases List.length_eq_one.1 h with ⟨x, hx⟩
  rw [← prod_factors n.succ_ne_zero, hx, List.prod_singleton]
  

Proof state:
case succ.intro
R : Type u_1
n : ℕ
h : Ω (succ n) = 1
x : ℕ
hx : factors (succ n) = [x]
⊢ Prime x

Next tactic:
apply prime_of_mem_factors
theorem cardFactors_eq_one_iff_prime {n : ℕ} : Ω n = 1 ↔ n.Prime := by
  refine' ⟨fun h => _, fun h => List.length_eq_one.2 ⟨n, factors_prime h⟩⟩
  cases' n with n
  · contrapose! h
    simp
  rcases List.length_eq_one.1 h with ⟨x, hx⟩
  rw [← prod_factors n.succ_ne_zero, hx, List.prod_singleton]
  apply prime_of_mem_factors
  

Proof state:
case succ.intro.h
R : Type u_1
n : ℕ
h : Ω (succ n) = 1
x : ℕ
hx : factors (succ n) = [x]
⊢ x ∈ factors ?succ.intro.n
case succ.intro.n R : Type u_1 n : ℕ h : Ω (succ n) = 1 x : ℕ hx : factors (succ n) = [x] ⊢ ℕ

Next tactic:
rw [hx, List.mem_singleton]
theorem cardFactors_mul {m n : ℕ} (m0 : m ≠ 0) (n0 : n ≠ 0) : Ω (m * n) = Ω m + Ω n := by
  

Proof state:
R : Type u_1
m n : ℕ
m0 : m ≠ 0
n0 : n ≠ 0
⊢ Ω (m * n) = Ω m + Ω n

Next tactic:
rw [cardFactors_apply, cardFactors_apply, cardFactors_apply, ← Multiset.coe_card, ← factors_eq,
    UniqueFactorizationMonoid.normalizedFactors_mul m0 n0, factors_eq, factors_eq,
    Multiset.card_add, Multiset.coe_card, Multiset.coe_card]
theorem cardFactors_multiset_prod {s : Multiset ℕ} (h0 : s.prod ≠ 0) :
    Ω s.prod = (Multiset.map Ω s).sum := by
  

Proof state:
R : Type u_1
s : Multiset ℕ
h0 : Multiset.prod s ≠ 0
⊢ Ω (Multiset.prod s) = Multiset.sum (Multiset.map (⇑Ω) s)

Next tactic:
revert h0
theorem cardFactors_multiset_prod {s : Multiset ℕ} (h0 : s.prod ≠ 0) :
    Ω s.prod = (Multiset.map Ω s).sum := by
  revert h0
  -- porting note: was `apply s.induction_on`
  

Proof state:
R : Type u_1
s : Multiset ℕ
⊢ Multiset.prod s ≠ 0 → Ω (Multiset.prod s) = Multiset.sum (Multiset.map (⇑Ω) s)

Next tactic:
refine s.induction_on ?_ ?_
theorem cardFactors_multiset_prod {s : Multiset ℕ} (h0 : s.prod ≠ 0) :
    Ω s.prod = (Multiset.map Ω s).sum := by
  revert h0
  -- porting note: was `apply s.induction_on`
  refine s.induction_on ?_ ?_
  · 

Proof state:
case refine_1
R : Type u_1
s : Multiset ℕ
⊢ Multiset.prod 0 ≠ 0 → Ω (Multiset.prod 0) = Multiset.sum (Multiset.map (⇑Ω) 0)

Next tactic:
simp
theorem cardFactors_multiset_prod {s : Multiset ℕ} (h0 : s.prod ≠ 0) :
    Ω s.prod = (Multiset.map Ω s).sum := by
  revert h0
  -- porting note: was `apply s.induction_on`
  refine s.induction_on ?_ ?_
  · simp
  

Proof state:
case refine_2
R : Type u_1
s : Multiset ℕ
⊢ ∀ ⦃a : ℕ⦄ {s : Multiset ℕ},
    (Multiset.prod s ≠ 0 → Ω (Multiset.prod s) = Multiset.sum (Multiset.map (⇑Ω) s)) →
      Multiset.prod (a ::ₘ s) ≠ 0 → Ω (Multiset.prod (a ::ₘ s)) = Multiset.sum (Multiset.map (⇑Ω) (a ::ₘ s))

Next tactic:
intro a t h h0
theorem cardFactors_multiset_prod {s : Multiset ℕ} (h0 : s.prod ≠ 0) :
    Ω s.prod = (Multiset.map Ω s).sum := by
  revert h0
  -- porting note: was `apply s.induction_on`
  refine s.induction_on ?_ ?_
  · simp
  intro a t h h0
  

Proof state:
case refine_2
R : Type u_1
s : Multiset ℕ
a : ℕ
t : Multiset ℕ
h : Multiset.prod t ≠ 0 → Ω (Multiset.prod t) = Multiset.sum (Multiset.map (⇑Ω) t)
h0 : Multiset.prod (a ::ₘ t) ≠ 0
⊢ Ω (Multiset.prod (a ::ₘ t)) = Multiset.sum (Multiset.map (⇑Ω) (a ::ₘ t))

Next tactic:
rw [Multiset.prod_cons, mul_ne_zero_iff] at h0
theorem cardFactors_multiset_prod {s : Multiset ℕ} (h0 : s.prod ≠ 0) :
    Ω s.prod = (Multiset.map Ω s).sum := by
  revert h0
  -- porting note: was `apply s.induction_on`
  refine s.induction_on ?_ ?_
  · simp
  intro a t h h0
  rw [Multiset.prod_cons, mul_ne_zero_iff] at h0
  

Proof state:
case refine_2
R : Type u_1
s : Multiset ℕ
a : ℕ
t : Multiset ℕ
h : Multiset.prod t ≠ 0 → Ω (Multiset.prod t) = Multiset.sum (Multiset.map (⇑Ω) t)
h0 : a ≠ 0 ∧ Multiset.prod t ≠ 0
⊢ Ω (Multiset.prod (a ::ₘ t)) = Multiset.sum (Multiset.map (⇑Ω) (a ::ₘ t))

Next tactic:
simp [h0, cardFactors_mul, h]
@[simp]
theorem cardFactors_apply_prime_pow {p k : ℕ} (hp : p.Prime) : Ω (p ^ k) = k := by
  

Proof state:
R : Type u_1
p k : ℕ
hp : Prime p
⊢ Ω (p ^ k) = k

Next tactic:
rw [cardFactors_apply, hp.factors_pow, List.length_replicate]
/-- `ω n` is the number of distinct prime factors of `n`. -/
def cardDistinctFactors : ArithmeticFunction ℕ :=
  ⟨fun n => n.factors.dedup.length, by 

Proof state:
R : Type u_1
⊢ (fun n => List.length (List.dedup (factors n))) 0 = 0

Next tactic:
simp
theorem cardDistinctFactors_zero : ω 0 = 0 := by 

Proof state:
R : Type u_1
⊢ ω 0 = 0

Next tactic:
simp
@[simp]
theorem cardDistinctFactors_one : ω 1 = 0 := by 

Proof state:
R : Type u_1
⊢ ω 1 = 0

Next tactic:
simp [cardDistinctFactors]
theorem cardDistinctFactors_eq_cardFactors_iff_squarefree {n : ℕ} (h0 : n ≠ 0) :
    ω n = Ω n ↔ Squarefree n := by
  

Proof state:
R : Type u_1
n : ℕ
h0 : n ≠ 0
⊢ ω n = Ω n ↔ Squarefree n

Next tactic:
rw [squarefree_iff_nodup_factors h0, cardDistinctFactors_apply]
theorem cardDistinctFactors_eq_cardFactors_iff_squarefree {n : ℕ} (h0 : n ≠ 0) :
    ω n = Ω n ↔ Squarefree n := by
  rw [squarefree_iff_nodup_factors h0, cardDistinctFactors_apply]
  

Proof state:
R : Type u_1
n : ℕ
h0 : n ≠ 0
⊢ List.length (List.dedup (factors n)) = Ω n ↔ List.Nodup (factors n)

Next tactic:
constructor
theorem cardDistinctFactors_eq_cardFactors_iff_squarefree {n : ℕ} (h0 : n ≠ 0) :
    ω n = Ω n ↔ Squarefree n := by
  rw [squarefree_iff_nodup_factors h0, cardDistinctFactors_apply]
  constructor <;> 

Proof state:
case mp
R : Type u_1
n : ℕ
h0 : n ≠ 0
⊢ List.length (List.dedup (factors n)) = Ω n → List.Nodup (factors n)

Next tactic:
intro h
theorem cardDistinctFactors_eq_cardFactors_iff_squarefree {n : ℕ} (h0 : n ≠ 0) :
    ω n = Ω n ↔ Squarefree n := by
  rw [squarefree_iff_nodup_factors h0, cardDistinctFactors_apply]
  constructor <;> 

Proof state:
case mpr
R : Type u_1
n : ℕ
h0 : n ≠ 0
⊢ List.Nodup (factors n) → List.length (List.dedup (factors n)) = Ω n

Next tactic:
intro h
theorem cardDistinctFactors_eq_cardFactors_iff_squarefree {n : ℕ} (h0 : n ≠ 0) :
    ω n = Ω n ↔ Squarefree n := by
  rw [squarefree_iff_nodup_factors h0, cardDistinctFactors_apply]
  constructor <;> intro h
  · 

Proof state:
case mp
R : Type u_1
n : ℕ
h0 : n ≠ 0
h : List.length (List.dedup (factors n)) = Ω n
⊢ List.Nodup (factors n)

Next tactic:
rw [← n.factors.dedup_sublist.eq_of_length h]
theorem cardDistinctFactors_eq_cardFactors_iff_squarefree {n : ℕ} (h0 : n ≠ 0) :
    ω n = Ω n ↔ Squarefree n := by
  rw [squarefree_iff_nodup_factors h0, cardDistinctFactors_apply]
  constructor <;> intro h
  · rw [← n.factors.dedup_sublist.eq_of_length h]
    

Proof state:
case mp
R : Type u_1
n : ℕ
h0 : n ≠ 0
h : List.length (List.dedup (factors n)) = Ω n
⊢ List.Nodup (List.dedup (factors n))

Next tactic:
apply List.nodup_dedup
theorem cardDistinctFactors_eq_cardFactors_iff_squarefree {n : ℕ} (h0 : n ≠ 0) :
    ω n = Ω n ↔ Squarefree n := by
  rw [squarefree_iff_nodup_factors h0, cardDistinctFactors_apply]
  constructor <;> intro h
  · rw [← n.factors.dedup_sublist.eq_of_length h]
    apply List.nodup_dedup
  · 

Proof state:
case mpr
R : Type u_1
n : ℕ
h0 : n ≠ 0
h : List.Nodup (factors n)
⊢ List.length (List.dedup (factors n)) = Ω n

Next tactic:
rw [h.dedup]
theorem cardDistinctFactors_eq_cardFactors_iff_squarefree {n : ℕ} (h0 : n ≠ 0) :
    ω n = Ω n ↔ Squarefree n := by
  rw [squarefree_iff_nodup_factors h0, cardDistinctFactors_apply]
  constructor <;> intro h
  · rw [← n.factors.dedup_sublist.eq_of_length h]
    apply List.nodup_dedup
  · rw [h.dedup]
    

Proof state:
case mpr
R : Type u_1
n : ℕ
h0 : n ≠ 0
h : List.Nodup (factors n)
⊢ List.length (factors n) = Ω n

Next tactic:
rfl
@[simp]
theorem cardDistinctFactors_apply_prime_pow {p k : ℕ} (hp : p.Prime) (hk : k ≠ 0) :
    ω (p ^ k) = 1 := by
  

Proof state:
R : Type u_1
p k : ℕ
hp : Prime p
hk : k ≠ 0
⊢ ω (p ^ k) = 1

Next tactic:
rw [cardDistinctFactors_apply, hp.factors_pow, List.replicate_dedup hk, List.length_singleton]
@[simp]
theorem cardDistinctFactors_apply_prime {p : ℕ} (hp : p.Prime) : ω p = 1 := by
  

Proof state:
R : Type u_1
p : ℕ
hp : Prime p
⊢ ω p = 1

Next tactic:
rw [← pow_one p, cardDistinctFactors_apply_prime_pow hp one_ne_zero]
/-- `μ` is the Möbius function. If `n` is squarefree with an even number of distinct prime factors,
  `μ n = 1`. If `n` is squarefree with an odd number of distinct prime factors, `μ n = -1`.
  If `n` is not squarefree, `μ n = 0`. -/
def moebius : ArithmeticFunction ℤ :=
  ⟨fun n => if Squarefree n then (-1) ^ cardFactors n else 0, by 

Proof state:
R : Type u_1
⊢ (fun n => if Squarefree n then (-1) ^ Ω n else 0) 0 = 0

Next tactic:
simp
theorem moebius_apply_one : μ 1 = 1 := by 

Proof state:
R : Type u_1
⊢ μ 1 = 1

Next tactic:
simp
theorem moebius_ne_zero_iff_squarefree {n : ℕ} : μ n ≠ 0 ↔ Squarefree n := by
  

Proof state:
R : Type u_1
n : ℕ
⊢ μ n ≠ 0 ↔ Squarefree n

Next tactic:
constructor
theorem moebius_ne_zero_iff_squarefree {n : ℕ} : μ n ≠ 0 ↔ Squarefree n := by
  constructor <;> 

Proof state:
case mp
R : Type u_1
n : ℕ
⊢ μ n ≠ 0 → Squarefree n

Next tactic:
intro h
theorem moebius_ne_zero_iff_squarefree {n : ℕ} : μ n ≠ 0 ↔ Squarefree n := by
  constructor <;> 

Proof state:
case mpr
R : Type u_1
n : ℕ
⊢ Squarefree n → μ n ≠ 0

Next tactic:
intro h
theorem moebius_ne_zero_iff_squarefree {n : ℕ} : μ n ≠ 0 ↔ Squarefree n := by
  constructor <;> intro h
  · 

Proof state:
case mp
R : Type u_1
n : ℕ
h : μ n ≠ 0
⊢ Squarefree n

Next tactic:
contrapose! h
theorem moebius_ne_zero_iff_squarefree {n : ℕ} : μ n ≠ 0 ↔ Squarefree n := by
  constructor <;> intro h
  · contrapose! h
    

Proof state:
case mp
R : Type u_1
n : ℕ
h : ¬Squarefree n
⊢ μ n = 0

Next tactic:
simp [h]
theorem moebius_ne_zero_iff_squarefree {n : ℕ} : μ n ≠ 0 ↔ Squarefree n := by
  constructor <;> intro h
  · contrapose! h
    simp [h]
  · 

Proof state:
case mpr
R : Type u_1
n : ℕ
h : Squarefree n
⊢ μ n ≠ 0

Next tactic:
simp [h, pow_ne_zero]
theorem moebius_ne_zero_iff_eq_or {n : ℕ} : μ n ≠ 0 ↔ μ n = 1 ∨ μ n = -1 := by
  

Proof state:
R : Type u_1
n : ℕ
⊢ μ n ≠ 0 ↔ μ n = 1 ∨ μ n = -1

Next tactic:
constructor
theorem moebius_ne_zero_iff_eq_or {n : ℕ} : μ n ≠ 0 ↔ μ n = 1 ∨ μ n = -1 := by
  constructor <;> 

Proof state:
case mp
R : Type u_1
n : ℕ
⊢ μ n ≠ 0 → μ n = 1 ∨ μ n = -1

Next tactic:
intro h
theorem moebius_ne_zero_iff_eq_or {n : ℕ} : μ n ≠ 0 ↔ μ n = 1 ∨ μ n = -1 := by
  constructor <;> 

Proof state:
case mpr
R : Type u_1
n : ℕ
⊢ μ n = 1 ∨ μ n = -1 → μ n ≠ 0

Next tactic:
intro h
theorem moebius_ne_zero_iff_eq_or {n : ℕ} : μ n ≠ 0 ↔ μ n = 1 ∨ μ n = -1 := by
  constructor <;> intro h
  · 

Proof state:
case mp
R : Type u_1
n : ℕ
h : μ n ≠ 0
⊢ μ n = 1 ∨ μ n = -1

Next tactic:
rw [moebius_ne_zero_iff_squarefree] at h
theorem moebius_ne_zero_iff_eq_or {n : ℕ} : μ n ≠ 0 ↔ μ n = 1 ∨ μ n = -1 := by
  constructor <;> intro h
  · rw [moebius_ne_zero_iff_squarefree] at h
    

Proof state:
case mp
R : Type u_1
n : ℕ
h : Squarefree n
⊢ μ n = 1 ∨ μ n = -1

Next tactic:
rw [moebius_apply_of_squarefree h]
theorem moebius_ne_zero_iff_eq_or {n : ℕ} : μ n ≠ 0 ↔ μ n = 1 ∨ μ n = -1 := by
  constructor <;> intro h
  · rw [moebius_ne_zero_iff_squarefree] at h
    rw [moebius_apply_of_squarefree h]
    

Proof state:
case mp
R : Type u_1
n : ℕ
h : Squarefree n
⊢ (-1) ^ Ω n = 1 ∨ (-1) ^ Ω n = -1

Next tactic:
apply neg_one_pow_eq_or