-
Notifications
You must be signed in to change notification settings - Fork 260
Add prime factorization and its properties #1969
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 20 commits
98dff4f
54ed74c
9c05449
6c9a9e1
7ec3801
8e0d749
f77023e
2f4193c
1b45ff5
cec5fac
4c8b43e
dd898f9
b330ae5
bec7b21
294bdad
8796eee
f0948e8
2a1ab80
7e73c8d
c2a712f
6262285
4073e5f
8afce74
87022d8
ea1142d
58a71c5
230d498
1f1ed8e
8b34d27
7482c46
20d8d66
aca45ad
e24f0be
fd4e806
510b7ec
9f2ef51
217d0cd
286bc7e
5063190
cf8a9c4
35153ca
578718d
a556522
cc8cef2
7dcd066
eb893ed
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,218 @@ | ||
| ------------------------------------------------------------------------ | ||
| -- The Agda standard library | ||
| -- | ||
| -- Prime factorisation of natural numbers and its properties | ||
| ------------------------------------------------------------------------ | ||
|
|
||
| {-# OPTIONS --cubical-compatible --safe #-} | ||
|
|
||
| module Data.Nat.Primality.Factorisation where | ||
|
|
||
| open import Data.Empty using (⊥-elim) | ||
| open import Data.Nat.Base | ||
| open import Data.Nat.Divisibility using (_∣_; _∣?_; quotient; quotient∣n; ∣-trans; ∣1⇒≡1; divides) | ||
| open import Data.Nat.Properties | ||
| open import Data.Nat.Induction using (<-Rec; <-rec) | ||
| open import Data.Nat.Primality using (Prime; euclidsLemma; ∣p⇒≡1∨≡p; Prime⇒NonZero) | ||
| open import Data.Nat.Primality.Rough using (_Rough_; 2-rough-n; extend-∤; roughn∧∣n⇒prime) | ||
| open import Data.Product as Π using (∃-syntax; _,_; proj₁; proj₂) | ||
| open import Data.List.Base using (List; []; _∷_; product) | ||
| open import Data.List.Relation.Unary.All as All using (All; []; _∷_) | ||
| open import Data.List.Relation.Binary.Permutation.Propositional as ↭ | ||
| using (_↭_; prep; swap; ↭-refl; refl; module PermutationReasoning) | ||
| open import Data.List.Relation.Binary.Permutation.Propositional.Properties using (product-↭; All-resp-↭) | ||
| open import Data.Sum.Base using (inj₁; inj₂) | ||
| open import Function.Base using (_$_; _∘_; _|>_; flip) | ||
| open import Relation.Nullary.Decidable using (yes; no) | ||
| open import Relation.Nullary.Negation using (contradiction) | ||
| open import Relation.Binary.PropositionalEquality using (_≡_; refl; cong; module ≡-Reasoning) | ||
|
|
||
| ------------------------------------------------------------------------ | ||
| -- Core definition | ||
|
|
||
| record PrimeFactorisation (n : ℕ) : Set where | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The 'traditional' notion of PrimeFactorisation uses a list of (multiplicity, prime) pairs and has the extra invariant that all primes are distinct. I am not suggesting you change this definition - but you should probably comment on your design choice, so that this aspect doesn't puzzle a maintainer years down the road. |
||
| field | ||
| factors : List ℕ | ||
| isFactorisation : product factors ≡ n | ||
MatthewDaggitt marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| factorsPrime : All Prime factors | ||
|
|
||
MatthewDaggitt marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| open PrimeFactorisation public using (factors) | ||
| open PrimeFactorisation | ||
|
|
||
| ------------------------------------------------------------------------ | ||
| -- Finding a factorisation | ||
Taneb marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| -- this builds up three important things: | ||
| -- * a proof that every number we've gotten to so far has increasingly higher | ||
| -- possible least prime factor, so we don't have to repeat smaller factores | ||
MatthewDaggitt marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| -- over and over (this is the "k" and "k-rough-n" parameters) | ||
| -- * a witness that this limit is getting closer to the number of interest, in a | ||
| -- way that helps the termination checker (the k≤n parameter) | ||
| -- * a proof that we can factorise any smaller number, which is useful when we | ||
| -- encounter a factor, as we can then divide by that factor and continue from | ||
| -- there without termination issues | ||
|
|
||
| private | ||
| pattern 2+ n = suc (suc n) | ||
| pattern 2≤2+n = s≤s (s≤s z≤n) | ||
| pattern 1<2+n = 2≤2+n | ||
|
||
|
|
||
| factorise : ∀ n → .{{NonZero n}} → PrimeFactorisation n | ||
| factorise 1 = record | ||
| { factors = [] | ||
| ; isFactorisation = refl | ||
| ; factorsPrime = [] | ||
| } | ||
| factorise (2+ n) = <-rec P factoriseRec (2 + n) {2} 2≤2+n (≤⇒≤‴ 2≤2+n) (2-rough-n (2 + n)) | ||
| where | ||
|
|
||
| P : ℕ → Set | ||
| P n′ = ∀ {k} → 2 ≤ n′ → k ≤‴ n′ → k Rough n′ → PrimeFactorisation n′ | ||
|
|
||
| factoriseRec : ∀ n → <-Rec P n → P n | ||
| factoriseRec (2+ n) rec (s≤s (s≤s n≤z)) ≤‴-refl k-rough-n = record | ||
| { factors = 2 + n ∷ [] | ||
| ; isFactorisation = *-identityʳ (2 + n) | ||
|
||
| ; factorsPrime = k-rough-n ∷ [] | ||
| } | ||
| factoriseRec (2+ n) rec {0} 2≤2+n (≤‴-step (≤‴-step k<n)) k-rough-n = | ||
| factoriseRec (2+ n) rec 2≤2+n k<n (2-rough-n (2+ n)) | ||
| factoriseRec (2+ n) rec {1} 2≤2+n (≤‴-step k<n) k-rough-n = | ||
| factoriseRec (2+ n) rec 2≤2+n k<n (2-rough-n (2+ n)) | ||
| factoriseRec (2+ n) rec {suc (suc k)} 2≤2+n (≤‴-step k<n) k-rough-n with 2 + k ∣? 2+ n | ||
| ... | no k∤n = factoriseRec (2+ n) rec {3 + k} 2≤2+n k<n (extend-∤ k-rough-n k∤n) | ||
| ... | yes k∣n = record | ||
| { factors = 2 + k ∷ factors res | ||
| ; isFactorisation = prop | ||
| ; factorsPrime = roughn∧∣n⇒prime k-rough-n 2≤2+n k∣n ∷ factorsPrime res | ||
| } | ||
| where | ||
| open ≤-Reasoning | ||
|
|
||
| q : ℕ | ||
| q = quotient k∣n | ||
|
|
||
| -- we know that k < n, so if q is 0 or 1 then q * k < n | ||
| 2≤q : 2 ≤ q | ||
| 2≤q = ≮⇒≥ (λ q<2 → contradiction (_∣_.equality k∣n) (>⇒≢ (prf (≤-pred q<2)))) where | ||
Taneb marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| prf : q ≤ 1 → q * 2+ k < 2 + n | ||
| prf q≤1 = begin-strict | ||
| q * 2+ k ≤⟨ *-monoˡ-≤ (2 + k) q≤1 ⟩ | ||
| 2 + k + 0 ≡⟨ +-identityʳ (2 + k) ⟩ | ||
| 2 + k <⟨ ≤‴⇒≤ k<n ⟩ | ||
| 2 + n ∎ | ||
|
|
||
| 0<q : 0 < q | ||
| 0<q = begin-strict | ||
| 0 <⟨ s≤s z≤n ⟩ | ||
| 2 ≤⟨ 2≤q ⟩ | ||
| q ∎ | ||
|
|
||
| q<n : q < 2 + n | ||
| q<n = begin-strict | ||
| q <⟨ m<m*n q (2 + k) ⦃ >-nonZero 0<q ⦄ 2≤2+n ⟩ | ||
| q * (2 + k) ≡˘⟨ _∣_.equality k∣n ⟩ | ||
| 2 + n ∎ | ||
|
|
||
| q≮2+k : q ≮ 2 + k | ||
| q≮2+k q<k = k-rough-n 2≤q q<k (quotient∣n k∣n) | ||
|
|
||
| res : PrimeFactorisation q | ||
| res = rec q q<n {2 + k} 2≤q (≤⇒≤‴ (≮⇒≥ q≮2+k)) | ||
| $ λ {d} d<k d-prime → k-rough-n d<k d-prime ∘ flip ∣-trans (quotient∣n k∣n) | ||
|
|
||
| prop : (2 + k) * product (factors res) ≡ 2 + n | ||
| prop = begin-equality | ||
| (2 + k) * product (factors res) | ||
| ≡⟨ cong ((2 + k) *_) (isFactorisation res) ⟩ | ||
| (2 + k) * q | ||
| ≡⟨ *-comm (2 + k) q ⟩ | ||
| q * (2 + k) | ||
| ≡˘⟨ _∣_.equality k∣n ⟩ | ||
| 2 + n ∎ | ||
|
|
||
| ------------------------------------------------------------------------ | ||
| -- Properties of a factorisation | ||
|
|
||
| factorisation≥1 : ∀ {as} → All Prime as → product as ≥ 1 | ||
MatthewDaggitt marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| factorisation≥1 {[]} [] = s≤s z≤n | ||
| factorisation≥1 {suc a ∷ as} (pa ∷ asPrime) = *-mono-≤ {1} {1 + a} (s≤s z≤n) (factorisation≥1 asPrime) | ||
MatthewDaggitt marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| factorisationPullToFront : ∀ {as} {p} → Prime p → p ∣ product as → All Prime as → ∃[ as′ ] as ↭ (p ∷ as′) | ||
|
||
| factorisationPullToFront {[]} {suc (suc p)} pPrime p∣Πas asPrime = contradiction (∣1⇒≡1 p∣Πas) λ () | ||
| factorisationPullToFront {a ∷ as} {p} pPrime p∣aΠas (aPrime ∷ asPrime) | ||
| with euclidsLemma a (product as) pPrime p∣aΠas | ||
| ... | inj₂ p∣Πas = Π.map (a ∷_) step ih | ||
| where | ||
| ih : ∃[ as′ ] as ↭ (p ∷ as′) | ||
| ih = factorisationPullToFront pPrime p∣Πas asPrime | ||
|
|
||
| step : ∀ {as′} → as ↭ p ∷ as′ → a ∷ as ↭ p ∷ a ∷ as′ | ||
| step {as′} as↭p∷as′ = begin | ||
| a ∷ as ↭⟨ prep a as↭p∷as′ ⟩ | ||
| a ∷ p ∷ as′ ↭⟨ swap a p refl ⟩ | ||
| p ∷ a ∷ as′ ∎ | ||
| where open PermutationReasoning | ||
|
|
||
| ... | inj₁ p∣a with ∣p⇒≡1∨≡p p aPrime p∣a | ||
| ... | inj₁ refl = ⊥-elim pPrime | ||
| ... | inj₂ refl = as , ↭-refl | ||
|
|
||
| factorisationUnique′ : (as bs : List ℕ) → product as ≡ product bs → All Prime as → All Prime bs → as ↭ bs | ||
MatthewDaggitt marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| factorisationUnique′ [] [] Πas≡Πbs asPrime bsPrime = refl | ||
JacquesCarette marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| factorisationUnique′ [] (suc (suc b) ∷ bs) Πas≡Πbs asPrime (bPrime ∷ bsPrime) = | ||
| contradiction Πas≡Πbs (<⇒≢ Πas<Πbs) | ||
| where | ||
| Πas<Πbs : product [] < product (2+ b ∷ bs) | ||
| Πas<Πbs = begin-strict | ||
| 1 ≡⟨⟩ | ||
| 1 * 1 <⟨ *-monoˡ-< 1 {1} {2 + b} 1<2+n ⟩ | ||
| (2 + b) * 1 ≤⟨ *-monoʳ-≤ (2 + b) (factorisation≥1 bsPrime) ⟩ | ||
| 2+ b * product bs ≡⟨⟩ | ||
| product (2+ b ∷ bs) ∎ | ||
jamesmckinna marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| where open ≤-Reasoning | ||
|
|
||
| factorisationUnique′ (a ∷ as) bs Πas≡Πbs (aPrime ∷ asPrime) bsPrime = a∷as↭bs | ||
| where | ||
| a∣Πbs : a ∣ product bs | ||
| a∣Πbs = divides (product as) $ begin | ||
| product bs ≡˘⟨ Πas≡Πbs ⟩ | ||
| product (a ∷ as) ≡⟨⟩ | ||
| a * product as ≡⟨ *-comm a (product as) ⟩ | ||
| product as * a ∎ | ||
| where open ≡-Reasoning | ||
|
|
||
| shuffle : ∃[ bs′ ] bs ↭ a ∷ bs′ | ||
| shuffle = factorisationPullToFront aPrime a∣Πbs bsPrime | ||
|
|
||
| bs′ = proj₁ shuffle | ||
| bs↭a∷bs′ = proj₂ shuffle | ||
|
|
||
| Πas≡Πbs′ : product as ≡ product bs′ | ||
| Πas≡Πbs′ = *-cancelˡ-≡ (product as) (product bs′) a {{Prime⇒NonZero aPrime}} $ begin | ||
| a * product as ≡⟨ Πas≡Πbs ⟩ | ||
| product bs ≡⟨ product-↭ bs↭a∷bs′ ⟩ | ||
| a * product bs′ ∎ | ||
| where open ≡-Reasoning | ||
|
|
||
| bs′Prime : All Prime bs′ | ||
| bs′Prime = All.tail (All-resp-↭ bs↭a∷bs′ bsPrime) | ||
|
|
||
| a∷as↭bs : a ∷ as ↭ bs | ||
| a∷as↭bs = begin | ||
| a ∷ as <⟨ factorisationUnique′ as bs′ Πas≡Πbs′ asPrime bs′Prime ⟩ | ||
| a ∷ bs′ ↭˘⟨ bs↭a∷bs′ ⟩ | ||
| bs ∎ | ||
| where open PermutationReasoning | ||
|
|
||
| factorisationUnique : {n : ℕ} (f f′ : PrimeFactorisation n) → factors f ↭ factors f′ | ||
| factorisationUnique {n} f f′ = | ||
| factorisationUnique′ (factors f) (factors f′) Πf≡Πf′ (factorsPrime f) (factorsPrime f′) | ||
| where | ||
| Πf≡Πf′ : product (factors f) ≡ product (factors f′) | ||
| Πf≡Πf′ = begin | ||
| product (factors f) ≡⟨ isFactorisation f ⟩ | ||
| n ≡˘⟨ isFactorisation f′ ⟩ | ||
| product (factors f′) ∎ | ||
| where open ≡-Reasoning | ||
Uh oh!
There was an error while loading. Please reload this page.