{-# OPTIONS --cubical-compatible --safe #-}
module Data.Nat.Primality where
open import Data.List.Base using ([]; _∷_; product)
open import Data.List.Properties using (product≢0)
open import Data.List.Relation.Unary.All as All using (All; []; _∷_)
open import Data.Nat.Base
open import Data.Nat.Divisibility
open import Data.Nat.GCD using (module GCD; module Bézout)
open import Data.Nat.Properties
open import Data.Product.Base using (∃-syntax; _×_; map₂; _,_)
open import Data.Sum.Base using (_⊎_; inj₁; inj₂; [_,_]′)
open import Function.Base using (flip; _∘_; _∘′_)
open import Function.Bundles using (_⇔_; mk⇔)
open import Relation.Nullary.Decidable as Dec
using (yes; no; from-yes; from-no; ¬?; _×-dec_; _⊎-dec_; _→-dec_; decidable-stable)
open import Relation.Nullary.Negation using (¬_; contradiction; contradiction₂)
open import Relation.Unary using (Pred; Decidable)
open import Relation.Binary.Core using (Rel)
open import Relation.Binary.PropositionalEquality.Core
using (_≡_; _≢_; refl; cong)
private
variable
d m n o p : ℕ
recompute-nonTrivial : .{{NonTrivial n}} → NonTrivial n
recompute-nonTrivial {n} {{nontrivial}} =
Dec.recompute (nonTrivial? n) nontrivial
infix 10 _Rough_
_Rough_ : ℕ → Pred ℕ _
m Rough n = ¬ (n HasNonTrivialDivisorLessThan m)
Composite : Pred ℕ _
Composite n = n HasNonTrivialDivisorLessThan n
pattern
composite {d} d<n d∣n = hasNonTrivialDivisor {divisor = d} d<n d∣n
record Prime (p : ℕ) : Set where
constructor prime
field
.{{nontrivial}} : NonTrivial p
notComposite : ¬ Composite p
Irreducible : Pred ℕ _
Irreducible n = ∀ {d} → d ∣ n → d ≡ 1 ⊎ d ≡ n
rough-1 : ∀ n → n Rough 1
rough-1 _ (hasNonTrivialDivisor _ d∣1) =
contradiction (∣1⇒≡1 d∣1) nonTrivial⇒≢1
0-rough : 0 Rough n
0-rough (hasNonTrivialDivisor () _)
1-rough : 1 Rough n
1-rough (hasNonTrivialDivisor {{()}} z<s _)
2-rough : 2 Rough n
2-rough (hasNonTrivialDivisor {{()}} (s<s z<s) _)
rough⇒≤ : .{{NonTrivial n}} → m Rough n → m ≤ n
rough⇒≤ rough = ≮⇒≥ n≮m
where n≮m = λ m>n → rough (hasNonTrivialDivisor m>n ∣-refl)
∤⇒rough-suc : m ∤ n → m Rough n → (suc m) Rough n
∤⇒rough-suc m∤n r (hasNonTrivialDivisor d<1+m d∣n)
with m<1+n⇒m<n∨m≡n d<1+m
... | inj₁ d<m = r (hasNonTrivialDivisor d<m d∣n)
... | inj₂ d≡m@refl = contradiction d∣n m∤n
rough∧∣⇒rough : m Rough o → n ∣ o → m Rough n
rough∧∣⇒rough r n∣o bntd = r (hasNonTrivialDivisor-∣ bntd n∣o)
composite-≢ : ∀ d → .{{NonTrivial d}} → .{{NonZero n}} →
d ≢ n → d ∣ n → Composite n
composite-≢ d = hasNonTrivialDivisor-≢ {d}
composite-∣ : .{{NonZero n}} → Composite m → m ∣ n → Composite n
composite-∣ (composite {d} d<m d∣n) m∣n@(divides-refl q)
= composite (*-monoʳ-< q d<m) (*-monoʳ-∣ q d∣n)
where instance
_ = m≢0∧n>1⇒m*n>1 q d
_ = m*n≢0⇒m≢0 q
¬composite[0] : ¬ Composite 0
¬composite[0] = 0-rough
¬composite[1] : ¬ Composite 1
¬composite[1] = 1-rough
composite[4] : Composite 4
composite[4] = composite-≢ 2 (λ()) (divides-refl 2)
composite[6] : Composite 6
composite[6] = composite-≢ 3 (λ()) (divides-refl 2)
composite⇒nonZero : Composite n → NonZero n
composite⇒nonZero {suc _} _ = _
composite⇒nonTrivial : Composite n → NonTrivial n
composite⇒nonTrivial {1} composite[1] =
contradiction composite[1] ¬composite[1]
composite⇒nonTrivial {2+ _} _ = _
composite? : Decidable Composite
composite? n = Dec.map CompositeUpTo⇔Composite (compositeUpTo? n)
where
CompositeUpTo : Pred ℕ _
CompositeUpTo n = ∃[ d ] d < n × NonTrivial d × d ∣ n
comp-upto⇒comp : CompositeUpTo n → Composite n
comp-upto⇒comp (_ , d<n , ntd , d∣n) = composite d<n d∣n
where instance _ = ntd
comp⇒comp-upto : Composite n → CompositeUpTo n
comp⇒comp-upto (composite d<n d∣n) = _ , d<n , recompute-nonTrivial , d∣n
CompositeUpTo⇔Composite : CompositeUpTo n ⇔ Composite n
CompositeUpTo⇔Composite = mk⇔ comp-upto⇒comp comp⇒comp-upto
compositeUpTo? : Decidable CompositeUpTo
compositeUpTo? n = anyUpTo? (λ d → nonTrivial? d ×-dec d ∣? n) n
¬prime[0] : ¬ Prime 0
¬prime[0] ()
¬prime[1] : ¬ Prime 1
¬prime[1] ()
prime[2] : Prime 2
prime[2] = prime 2-rough
prime⇒nonZero : Prime p → NonZero p
prime⇒nonZero _ = nonTrivial⇒nonZero _
prime⇒nonTrivial : Prime p → NonTrivial p
prime⇒nonTrivial _ = recompute-nonTrivial
prime? : Decidable Prime
prime? 0 = no ¬prime[0]
prime? 1 = no ¬prime[1]
prime? n@(2+ _) = Dec.map PrimeUpTo⇔Prime (primeUpTo? n)
where
PrimeUpTo : Pred ℕ _
PrimeUpTo n = ∀ {d} → d < n → NonTrivial d → d ∤ n
prime⇒prime-upto : Prime n → PrimeUpTo n
prime⇒prime-upto (prime p) {d} d<n ntd d∣n
= p (composite d<n d∣n) where instance _ = ntd
prime-upto⇒prime : .{{NonTrivial n}} → PrimeUpTo n → Prime n
prime-upto⇒prime upto = prime
λ (composite d<n d∣n) → upto d<n recompute-nonTrivial d∣n
PrimeUpTo⇔Prime : .{{NonTrivial n}} → PrimeUpTo n ⇔ Prime n
PrimeUpTo⇔Prime = mk⇔ prime-upto⇒prime prime⇒prime-upto
primeUpTo? : Decidable PrimeUpTo
primeUpTo? n = allUpTo? (λ d → nonTrivial? d →-dec ¬? (d ∣? n)) n
euclidsLemma : ∀ m n {p} → Prime p → p ∣ m * n → p ∣ m ⊎ p ∣ n
euclidsLemma m n {p} pp@(prime pr) p∣m*n = result
where
open ∣-Reasoning
instance _ = prime⇒nonZero pp
p∣rmn : ∀ r → p ∣ r * m * n
p∣rmn r = begin
p ∣⟨ p∣m*n ⟩
m * n ∣⟨ n∣m*n r ⟩
r * (m * n) ≡⟨ *-assoc r m n ⟨
r * m * n ∎
result : p ∣ m ⊎ p ∣ n
result with Bézout.lemma m p
... | Bézout.result 0 g _ =
contradiction (0∣⇒≡0 (GCD.gcd∣n g)) (≢-nonZero⁻¹ _)
... | Bézout.result 1 _ (Bézout.+- r s 1+sp≡rm) =
inj₂ (flip ∣m+n∣m⇒∣n (n∣m*n*o s n) (begin
p ∣⟨ p∣rmn r ⟩
r * m * n ≡⟨ cong (_* n) 1+sp≡rm ⟨
n + s * p * n ≡⟨ +-comm n (s * p * n) ⟩
s * p * n + n ∎))
... | Bézout.result 1 _ (Bézout.-+ r s 1+rm≡sp) =
inj₂ (flip ∣m+n∣m⇒∣n (p∣rmn r) (begin
p ∣⟨ n∣m*n*o s n ⟩
s * p * n ≡⟨ cong (_* n) 1+rm≡sp ⟨
n + r * m * n ≡⟨ +-comm n (r * m * n) ⟩
r * m * n + n ∎))
... | Bézout.result d@(2+ _) g _ with d ≟ p
... | yes d≡p@refl = inj₁ (GCD.gcd∣m g)
... | no d≢p = contradiction (composite-≢ d d≢p (GCD.gcd∣n g)) pr
prime⇒rough : Prime p → p Rough p
prime⇒rough (prime pr) = pr
rough∧∣⇒prime : .{{NonTrivial p}} → p Rough n → p ∣ n → Prime p
rough∧∣⇒prime r p∣n = prime (rough∧∣⇒rough r p∣n)
rough∧square>⇒prime : .{{NonTrivial n}} → m Rough n → m * m > n → Prime n
rough∧square>⇒prime rough m*m>n = prime ¬composite
where
¬composite : ¬ Composite _
¬composite (composite d<n d∣n) = contradiction (m∣n⇒n≡quotient*m d∣n)
(<⇒≢ (<-≤-trans m*m>n (*-mono-≤
(rough⇒≤ (rough∧∣⇒rough rough (quotient-∣ d∣n)))
(rough⇒≤ (rough∧∣⇒rough rough d∣n)))))
where instance _ = n>1⇒nonTrivial (quotient>1 d∣n d<n)
composite⇒¬prime : Composite n → ¬ Prime n
composite⇒¬prime composite[d] (prime p) = p composite[d]
¬composite⇒prime : .{{NonTrivial n}} → ¬ Composite n → Prime n
¬composite⇒prime = prime
prime⇒¬composite : Prime n → ¬ Composite n
prime⇒¬composite (prime p) = p
¬prime⇒composite : .{{NonTrivial n}} → ¬ Prime n → Composite n
¬prime⇒composite {n} ¬prime[n] =
decidable-stable (composite? n) (¬prime[n] ∘′ ¬composite⇒prime)
productOfPrimes≢0 : ∀ {as} → All Prime as → NonZero (product as)
productOfPrimes≢0 pas = product≢0 (All.map prime⇒nonZero pas)
productOfPrimes≥1 : ∀ {as} → All Prime as → product as ≥ 1
productOfPrimes≥1 {as} pas = >-nonZero⁻¹ _ {{productOfPrimes≢0 pas}}
¬irreducible[0] : ¬ Irreducible 0
¬irreducible[0] irr[0] = contradiction₂ 2≡1⊎2≡0 (λ ()) (λ ())
where 2≡1⊎2≡0 = irr[0] {2} (divides-refl 0)
irreducible[1] : Irreducible 1
irreducible[1] m∣1 = inj₁ (∣1⇒≡1 m∣1)
irreducible[2] : Irreducible 2
irreducible[2] {zero} 0∣2 with () ← 0∣⇒≡0 0∣2
irreducible[2] {suc _} d∣2 with ∣⇒≤ d∣2
... | z<s = inj₁ refl
... | s<s z<s = inj₂ refl
irreducible⇒nonZero : Irreducible n → NonZero n
irreducible⇒nonZero {zero} = flip contradiction ¬irreducible[0]
irreducible⇒nonZero {suc _} _ = _
irreducible? : Decidable Irreducible
irreducible? zero = no ¬irreducible[0]
irreducible? n@(suc _) =
Dec.map IrreducibleUpTo⇔Irreducible (irreducibleUpTo? n)
where
IrreducibleUpTo : Pred ℕ _
IrreducibleUpTo n = ∀ {d} → d < n → d ∣ n → d ≡ 1 ⊎ d ≡ n
irr-upto⇒irr : .{{NonZero n}} → IrreducibleUpTo n → Irreducible n
irr-upto⇒irr irr-upto m∣n
= [ flip irr-upto m∣n , inj₂ ]′ (m≤n⇒m<n∨m≡n (∣⇒≤ m∣n))
irr⇒irr-upto : Irreducible n → IrreducibleUpTo n
irr⇒irr-upto irr m<n m∣n = irr m∣n
IrreducibleUpTo⇔Irreducible : .{{NonZero n}} →
IrreducibleUpTo n ⇔ Irreducible n
IrreducibleUpTo⇔Irreducible = mk⇔ irr-upto⇒irr irr⇒irr-upto
irreducibleUpTo? : Decidable IrreducibleUpTo
irreducibleUpTo? n = allUpTo?
(λ m → (m ∣? n) →-dec (m ≟ 1 ⊎-dec m ≟ n)) n
prime⇒irreducible : Prime p → Irreducible p
prime⇒irreducible {p} pp@(prime pr) = irr
where
instance _ = prime⇒nonZero pp
irr : .{{NonZero p}} → Irreducible p
irr {0} 0∣p = contradiction (0∣⇒≡0 0∣p) (≢-nonZero⁻¹ p)
irr {1} 1∣p = inj₁ refl
irr {2+ _} d∣p = inj₂ (≤∧≮⇒≡ (∣⇒≤ d∣p) d≮p)
where d≮p = λ d<p → pr (composite d<p d∣p)
irreducible⇒prime : .{{NonTrivial p}} → Irreducible p → Prime p
irreducible⇒prime irr = prime
λ (composite d<p d∣p) → [ nonTrivial⇒≢1 , (<⇒≢ d<p) ]′ (irr d∣p)
private
2-is-prime : Prime 2
2-is-prime = from-yes (prime? 2)
2-is-not-composite : ¬ Composite 2
2-is-not-composite = from-no (composite? 2)
4-is-composite : Composite 4
4-is-composite = from-yes (composite? 4)
4-is-not-prime : ¬ Prime 4
4-is-not-prime = from-no (prime? 4)
6-is-composite : Composite 6
6-is-composite = from-yes (composite? 6)
6-is-not-prime : ¬ Prime 6
6-is-not-prime = from-no (prime? 6)