1-- Multiplicativity of the Möbius function: a product of coprime squarefree2-- numbers is squarefree, the prime divisors of a product are the union of3-- the prime divisors of the factors, disjoint for coprime factors, and4-- μ(a · b) = μ(a) · μ(b) whenever gcd(a, b) = 15-- Part of Cumulus, the Grace17 mathematics library.6-- Copyright (c) 2026 Grant Passmore.7-- Released under the Apache License 2.0. See LICENSE in the repository root.8-- Authors: Grant Passmore910module Grace.Cumulus.Combinatorics.MoebiusMultiplicative11import Moebius1213theorem Squarefree.mul (a b : Nat)14requires squarefreeA : Squarefree(a)15requires squarefreeB : Squarefree(b)16requires coprime : gcd(a, b) =117shows Squarefree(a * b)18proof19intros q qMember qPrime square20have qNat := nat.omega.backward with qMember21have qDivides := divides.of_mul_left with square22have alternatives := Prime.divides_mul with qPrime, qDivides23cases alternatives with dividesA | dividesB24 . have notB : ¬(q ∣ b)25intro dividesB26have one := coprime.divisor_one with coprime, dividesA, dividesB27exact Prime.ne_one with qPrime, one28have coprimeQB := Prime.gcd_of_not_divides with qPrime, notB29have characterization := coprime.mul_iff at q, q, b30have coprimeSquare := characterization.backward with⟨coprimeQB, coprimeQB⟩31have coprimeSym := coprime.symmetric with coprimeSquare32have squareDividesA := coprime.cancel_right with coprimeSym, square33have absent := Squarefree.not_divides with squarefreeA, qPrime34exact absent with squareDividesA35 . have notA : ¬(q ∣ a)36intro dividesA37have one := coprime.divisor_one with coprime, dividesA, dividesB38exact Prime.ne_one with qPrime, one39have coprimeQA := Prime.gcd_of_not_divides with qPrime, notA40have characterization := coprime.mul_iff at q, q, a41have coprimeSquare := characterization.backward with⟨coprimeQA, coprimeQA⟩42have coprimeSym := coprime.symmetric with coprimeSquare43have commuted : a * b = b * a byring44rw commuted at square45have squareDividesB := coprime.cancel_right with coprimeSym, square46have absent := Squarefree.not_divides with squarefreeB, qPrime47exact absent with squareDividesB4849theorem primeDivisors.mul (a b : Nat)50requires nonzeroA : a ≠051requires nonzeroB : b ≠052shows primeDivisors(a * b) = primeDivisors(a) ∪ primeDivisors(b)53proof54have productNonzero : a * b ≠055intro zero56have characterization := mul.eq_zero_iff at a, b57have alternatives := characterization.forward with zero58cases alternatives with aZero | bZero59 . exact nonzeroA with aZero60 . exact nonzeroB with bZero61ext q62constructor63 . intro member64have both := primeDivisors.membership.forward with member65have inDivisors := both.left66have qPrime := both.right67have qNat := divisors.natural with inDivisors68have factor := divisors.divides with inDivisors69have alternatives := Prime.divides_mul with qPrime, factor70apply union2.membership.backward71cases alternatives with dividesA | dividesB72 . left73have below := divides.le with dividesA, nonzeroA74have characterization := divisors.membership_le at a, q75have inA := characterization.backward with⟨below, dividesA⟩76have membershipA := primeDivisors.membership at a, q77exact membershipA.backward with⟨inA, qPrime⟩78 . right79have below := divides.le with dividesB, nonzeroB80have characterization := divisors.membership_le at b, q81have inB := characterization.backward with⟨below, dividesB⟩82have membershipB := primeDivisors.membership at b, q83exact membershipB.backward with⟨inB, qPrime⟩84 . intro member85have alternatives := union2.membership.forward with member86have membershipProduct := primeDivisors.membership at a * b, q87cases alternatives with inA | inB88 . have both := primeDivisors.membership.forward with inA89have inDivisors := both.left90have qPrime := both.right91have qNat := divisors.natural with inDivisors92have factor := divisors.divides with inDivisors93have multiple := divides.mul_left_self at a, b94have chained := divides.transitive with factor, multiple95have below := divides.le with chained, productNonzero96have characterization := divisors.membership_le at a * b, q97have inProduct := characterization.backward with⟨below, chained⟩98exact membershipProduct.backward with⟨inProduct, qPrime⟩99 . have both := primeDivisors.membership.forward with inB100have inDivisors := both.left101have qPrime := both.right102have qNat := divisors.natural with inDivisors103have factor := divisors.divides with inDivisors104have multiple := divides.mul_right_self at b, a105have chained := divides.transitive with factor, multiple106have below := divides.le with chained, productNonzero107have characterization := divisors.membership_le at a * b, q108have inProduct := characterization.backward with⟨below, chained⟩109exact membershipProduct.backward with⟨inProduct, qPrime⟩110111theorem primeDivisors.disjoint (a b : Nat)112requires coprime : gcd(a, b) =1113shows Disjoint(primeDivisors(a), primeDivisors(b))114proof115apply Disjoint.iff.backward116intros q inA inB117have bothA := primeDivisors.membership.forward with inA118have bothB := primeDivisors.membership.forward with inB119have qNat := divisors.natural with bothA.left120have qPrime := bothA.right121have dividesA := divisors.divides with bothA.left122have dividesB := divisors.divides with bothB.left123have one := coprime.divisor_one with coprime, dividesA, dividesB124exact Prime.ne_one with qPrime, one125126theorem primeDivisorCount.mul_coprime (a b : Nat)127requires nonzeroA : a ≠0128requires nonzeroB : b ≠0129requires coprime : gcd(a, b) =1130shows primeDivisorCount(a * b) = primeDivisorCount(a) + primeDivisorCount(b)131proof132have same := primeDivisors.mul with nonzeroA, nonzeroB133have disjoint := primeDivisors.disjoint with coprime134have finiteA := primeDivisors.finite at a135have finiteB := primeDivisors.finite at b136have count := cardinality.union_disjoint with finiteA, finiteB, disjoint137unfold primeDivisorCount138cc139140-- The Möbius function is multiplicative.141theorem moebius.multiplicative (a b : Nat)142requires coprime : gcd(a, b) =1143shows moebius(a * b) = integerMulValue(moebius(a), moebius(b))144proof145have aInteger := moebius.integer at a146have bInteger := moebius.integer at b147have alternativesA : Squarefree(a) ∨¬Squarefree(a) bytauto148cases alternativesA with squarefreeA | notA149 . have alternativesB : Squarefree(b) ∨¬Squarefree(b) bytauto150cases alternativesB with squarefreeB | notB151 . have nonzeroA := Squarefree.nonzero with squarefreeA152have nonzeroB := Squarefree.nonzero with squarefreeB153have squarefreeProduct := Squarefree.mul with squarefreeA, squarefreeB,154 coprime155have valueA := moebius.of_squarefree with squarefreeA156have valueB := moebius.of_squarefree with squarefreeB157have valueProduct := moebius.of_squarefree with squarefreeProduct158have count := primeDivisorCount.mul_coprime with nonzeroA, nonzeroB,159 coprime160have countA := primeDivisorCount.natural at a161have countB := primeDivisorCount.natural at b162havesplit:= integerPow.add at -integerOne, primeDivisorCount(a),163 primeDivisorCount(b)164rw [valueProduct, count, split, valueA, valueB]165rfl166 . have notProduct : ¬Squarefree(a * b)167intro squarefreeProduct168have multiple := divides.mul_right_self at b, a169have squarefreeB := Squarefree.of_divides with squarefreeProduct,170 multiple171exact notB with squarefreeB172have valueB := moebius.of_not_squarefree with notB173have valueProduct := moebius.of_not_squarefree with notProduct174rw [valueProduct, valueB]175ring176 . have notProduct : ¬Squarefree(a * b)177intro squarefreeProduct178have multiple := divides.mul_left_self at a, b179have squarefreeA := Squarefree.of_divides with squarefreeProduct, multiple180exact notA with squarefreeA181have valueA := moebius.of_not_squarefree with notA182have valueProduct := moebius.of_not_squarefree with notProduct183rw [valueProduct, valueA]184ring185