1-- Executable Euclidean GCD with a proved sufficient iteration bound2-- Part of Cumulus, the Grace17 mathematics library.3-- Copyright (c) 2026 Grant Passmore.4-- Released under the Apache License 2.0. See LICENSE in the repository root.5-- Authors: Grant Passmore67module Grace.Cumulus.NumberTheory.Euclidean8import GCD9import Nat.Division1011-- The second input strictly decreases on each nonterminal Euclidean step.12-- The public function uses b steps; correctness below proves this sufficient.13def gcdSteps (fuel a b : Nat) →Nat14| zero, a, b => a15| succ(fuel), a, b => chooseNat(isZero(b), a, gcdSteps(fuel, b, a % b))1617def gcd (a b : Nat) : Nat:= gcdSteps(b, a, b)1819theorem gcdSteps.zero_right (a fuel : Nat)20shows gcdSteps(fuel, a, 0) = a21proof22induction fuel23| zero =>settlewith gcdSteps24| succ(k) using ih =>settlewith gcdSteps, isZero, chooseNat2526theorem gcdSteps.successor (fuel a b : Nat)27shows gcdSteps(succ(fuel), a, succ(b)) = gcdSteps(fuel, succ(b), a % succ(b))28proof29simp [gcdSteps, isZero, chooseNat]3031theorem gcdSteps.natural (fuel a b : Nat)32showsNat(gcdSteps(fuel, a, b))33proof34induction fuel generalizing a b35| zero =>36intros a b aNat bNat37simp [gcdSteps, isZero, chooseNat]38| succ(k) using ih =>39intros a b aNat bNat40have remainderNat := mod.natural at b, a with*41have recursive := ih with b, a % b, bNat, remainderNat42have boolean := isZero.boolean at b with*43have natural := chooseNat.natural at isZero(b), a, gcdSteps(k, b, a % b) with*44 simpa [gcdSteps] using natural4546theorem gcdSteps.correct (fuel a b : Nat)47shows b ≤ fuel → IsGCD(a, b, gcdSteps(fuel, a, b))48proof49induction fuel generalizing a b50| zero =>51intros a b aNat bNat bound52have bZero : b =053 . have lower := Grace.Cumulus.Nat.Order.LessEqual.zero at b with*54exact LessEqual.antisymmetric at b, 0with*55rw bZero56have terminal := IsGCD.zero_right at a with*57 simpa [gcdSteps, isZero, chooseNat] using terminal58| succ(k) using ih =>59intros a b aNat bNat bound60have shape := natural.zero_or_successor at b with*61cases shape with zero | successor62 . rw zero63have terminal := IsGCD.zero_right at a with*64have value := gcdSteps.zero_right at a, succ(k) with*65 rwa value66 . obtain⟨j, jNat, bShape⟩:= successor67rw bShape at bound68rw bShape69have nonzero : succ(j) ≠070 . intro equal71have distinct := Naturals.disjoint.zero.succ at j72 symm at equal73exact distinct with equal74have remainderNat := mod.natural at succ(j), a with*75have remainderBound := mod.less at a, succ(j) with*76have enough : a % succ(j) ≤ k77 . arith78have recursive := ih with succ(j), a % succ(j), assumption, remainderNat, enough79obtain⟨q, qNat, equation⟩:= mod.equation at a, succ(j) with*80have preserved := IsGCD.euclidean_backward at a, succ(j), q, a % succ(j), gcdSteps(k, succ(j), a % succ(j)) with*81have value := gcdSteps.successor at k, a, j with*82 rwa value8384theorem gcd.natural (a b : Nat)85showsNat(gcd(a, b))86proof87unfold gcd88exact gcdSteps.natural with*8990theorem gcd.correct (a b : Nat)91shows IsGCD(a, b, gcd(a, b))92proof93have bound := LessEqual.reflexive at b with*94have correct := gcdSteps.correct at b, a, b with*, bound95 simpa [gcd] using correct9697theorem gcd.unique (a b g : Nat)98requires certificate : IsGCD(a, b, g)99shows gcd(a, b) = g100proof101have correct := gcd.correct at a, b with*102exact IsGCD.unique with*103104theorem IsGCD.exists (a b : Nat)105shows∃ g, Nat(g) ∧ IsGCD(a, b, g)106proof107have natural := gcd.natural at a, b with*108have correct := gcd.correct at a, b with*109refine⟨gcd(a, b), natural, correct⟩110111theorem gcd.zero_right (a : Nat)112shows gcd(a, 0) = a113proof114have certificate := IsGCD.zero_right with*115exact gcd.unique with*116117theorem gcd.zero_left (a : Nat)118shows gcd(0, a) = a119proof120have certificate := IsGCD.zero_left with*121exact gcd.unique with*122123theorem gcd.commutative (a b : Nat)124shows gcd(a, b) = gcd(b, a)125proof126have reverse := gcd.correct at b, a with*127have certificate := IsGCD.symmetric with*128exact gcd.unique with*129130theorem gcd.divides_left (a b : Nat)131shows gcd(a, b) ∣ a132proof133have correct := gcd.correct at a, b with*134exact IsGCD.divides_left with*135136theorem gcd.divides_right (a b : Nat)137shows gcd(a, b) ∣ b138proof139have correct := gcd.correct at a, b with*140exact IsGCD.divides_right with*141142theorem gcd.greatest (a b d : Nat)143requiresleft : d ∣ a144requiresright : d ∣ b145shows d ∣ gcd(a, b)146proof147have correct := gcd.correct at a, b with*148exact IsGCD.greatest with*149150theorem gcd.euclidean (a b : Nat)151requires nonzero : b ≠0152shows gcd(a, b) = gcd(b, a % b)153proof154have recursive := gcd.correct at b, a % b with*155obtain⟨q, qNat, equation⟩:= mod.equation at a, b with*156have certificate := IsGCD.euclidean_backward with*157exact gcd.unique with*158159theorem gcd.of_divides (a b : Nat)160requires divides : a ∣ b161shows gcd(a, b) = a162proof163have certificate := IsGCD.of_divides with*164exact gcd.unique with*165166theorem gcd.zero_iff (a b : Nat)167shows gcd(a, b) =0↔ (a =0∧ b =0)168proof169constructor170 . intro zero171haveleft:= gcd.divides_left at a, b with*172haveright:= gcd.divides_right at a, b with*173rw zero atleft174rw zero atright175have aZero := zero.divides_only_zero at a with*176have bZero := zero.divides_only_zero at b with*177tauto178 . intro zeros179rcases zeros with⟨aZero, bZero⟩180rw [aZero, bZero]181exact gcd.zero_right with*182