1-- Coprime factors of a square are squares: a divisor whose square divides2-- a square divides its root, and when a * b is a square with gcd(a, b) = 13-- both a and b are squares4-- Part of Cumulus, the Grace17 mathematics library.5-- Copyright (c) 2026 Grant Passmore.6-- Released under the Apache License 2.0. See LICENSE in the repository root.7-- Authors: Grant Passmore89module Grace.Cumulus.NumberTheory.CoprimeSquares10import LCM11import PerfectSquares1213-- A divisor of a is coprime to b whenever a is.14theorem coprime.of_divides_left (a b g : Nat)15requires coprimeAB : gcd(a, b) =116requires divides : g ∣ a17shows gcd(g, b) =118proof19have every := gcd.eq_one_iff at g, b20apply every.backward21intros d dNat dg db22have da := divides.transitive at d, g, a with dg, divides23exact coprime.divisor_one at a, b, d with coprimeAB, da, db2425-- If d² divides c², then d divides c.26theorem divides.of_mul_self (d c : Nat)27requires squares : d * d ∣ c * c28shows d ∣ c29proof30havesplit : c =0∨ c ≠0bytauto31casessplitwith zero | nonzero32 . rw zero33exact divides.zero at d34 . have gcdNonzero := gcd.nonzero_right at d, c with nonzero35obtain⟨p, pNat, dShape⟩:= gcd.divides_left at d, c36obtain⟨q, qNat, cShape⟩:= gcd.divides_right at d, c37have cofactors := gcd.cofactor_coprime at d, c, p, q38with gcdNonzero, dShape, cShape39have squareNonzero := mul.nonzero at gcd(d, c), gcd(d, c)40with gcdNonzero, gcdNonzero41have cancel := divides.mul_cancel_left42at gcd(d, c) * gcd(d, c), p * p, q * q with squareNonzero43have regroup : gcd(d, c) * gcd(d, c) * (p * p) ∣44 gcd(d, c) * gcd(d, c) * (q * q)45have leftSide : gcd(d, c) * gcd(d, c) * (p * p) = d * d byring [dShape]46have rightSide : gcd(d, c) * gcd(d, c) * (q * q) = c * c byring [cShape]47rw [leftSide, rightSide]48exact squares49have cofactorSquares := cancel.forward with regroup50have pDivides := divides.of_mul_left at p, p, q * q with cofactorSquares51have coprimeSquare := coprime.pow_right at p, q, 2with cofactors52have two := pow.two at q53rw two at coprimeSquare54have pSelf := divides.reflexive at p55have pOne := coprime.divisor_one at p, q * q, p56with coprimeSquare, pSelf, pDivides57rw pOne at dShape58have unit : gcd(d, c) *1= gcd(d, c) byring59rw unit at dShape60rw← dShape61exact gcd.divides_right at d, c6263-- A coprime factor of a square is a square: with g = gcd(a, c), a = g p and64-- c = g q, the equation a b = c² reduces to p b = g q², and the coprimality65-- of p with q² and of g with b force p ∣ g and g ∣ p, so a = g².66theorem IsSquare.left_of_coprime_mul (a b c : Nat)67requires coprimeAB : gcd(a, b) =168requires product : a * b = c * c69shows IsSquare(a)70proof71havesplit : a =0∨ a ≠0bytauto72casessplitwith zero | nonzero73 . rw zero74exact IsSquare.zero75 . have gcdNonzero := gcd.nonzero at a, c with nonzero76obtain⟨p, pNat, aShape⟩:= gcd.divides_left at a, c77obtain⟨q, qNat, cShape⟩:= gcd.divides_right at a, c78have cofactors := gcd.cofactor_coprime at a, c, p, q79with gcdNonzero, aShape, cShape80have reduced : p * b = gcd(a, c) * (q * q)81have expanded : gcd(a, c) * (p * b) = gcd(a, c) * (gcd(a, c) * (q * q))82have leftSide : gcd(a, c) * (p * b) = a * b byring [aShape]83have rightSide : gcd(a, c) * (gcd(a, c) * (q * q)) = c * c84ring [cShape]85rw [leftSide, rightSide]86exact product87exact mul.left_cancel_positive at p * b, gcd(a, c) * (q * q), gcd(a, c)88with gcdNonzero, expanded89have coprimeSquare := coprime.pow_right at p, q, 2with cofactors90have two := pow.two at q91rw two at coprimeSquare92have pDividesProduct : p ∣ gcd(a, c) * (q * q)93rw← reduced94exact divides.mul_left_self at p, b95have coprimeSquareP := coprime.symmetric at p, q * q with coprimeSquare96have pDivides := coprime.cancel_right at q * q, p, gcd(a, c)97with coprimeSquareP, pDividesProduct98have gDividesA := gcd.divides_left at a, c99have coprimeGB := coprime.of_divides_left at a, b, gcd(a, c)100with coprimeAB, gDividesA101have gDividesProduct : gcd(a, c) ∣ p * b102rw reduced103exact divides.mul_left_self at gcd(a, c), q * q104have coprimeBG := coprime.symmetric at gcd(a, c), b with coprimeGB105have gDivides := coprime.cancel_right at b, gcd(a, c), p106with coprimeBG, gDividesProduct107have equal := divides.antisymmetric at p, gcd(a, c) with pDivides, gDivides108rw equal at aShape109witness gcd(a, c)110 symm111exact aShape112113theorem IsSquare.of_coprime_mul (a b c : Nat)114requires coprimeAB : gcd(a, b) =1115requires product : a * b = c * c116shows IsSquare(a) ∧ IsSquare(b)117proof118constructor119 . exact IsSquare.left_of_coprime_mul at a, b, c with coprimeAB, product120 . have coprimeBA := coprime.symmetric at a, b with coprimeAB121have commuted : b * a = c * c122rw← product123ring124exact IsSquare.left_of_coprime_mul at b, a, c with coprimeBA, commuted125