------------------------------------------------------------------------
-- Coprimality
------------------------------------------------------------------------

module Data.Nat.Coprimality where

open import Data.Nat
open import Data.Nat.Divisibility
open import Data.Nat.GCD hiding (refl; sym)
open import Data.Product
open import Data.Function
open import Data.Empty
open import Relation.Binary.PropositionalEquality using (_≡_; refl)

-- Coprime m n is inhabited iff m and n are coprime (relatively
-- prime), i.e. if their only common divisor is 1.

Coprime : (m n : )  Set
Coprime m n =  {i}  i Divides m And n  i  1

-- Coprime numbers have 1 as their gcd.

coprime-gcd :  {m n}  Coprime m n  GCD m n 1
coprime-gcd {m} {n} c = isGCD (1-divides m , 1-divides n) (div _)
  where
  div :  d  d Divides m And n  d Divides 1
  div  d cd with c cd
  div .1 cd | refl = 1-divides 1

-- If two numbers have 1 as their gcd, then they are coprime.

gcd-coprime :  {m n}  GCD m n 1  Coprime m n
gcd-coprime g  {i} cd with largest g cd
gcd-coprime g .{1} cd | s≤s z≤n = refl
gcd-coprime g .{0} cd | z≤n     =
  ⊥-elim {0  1} $ 0-doesNotDivide (proj₁ cd)

-- The coprimality relation is symmetric.

sym :  {m n}  Coprime m n  Coprime n m
sym c = c  swap

-- Everything is coprime to 1.

1-coprimeTo :  m  Coprime 1 m
1-coprimeTo m = c _  proj₁
  where
  c :  i  i Divides 1  i  1
  c 0             ()
  c 1             _                    = refl
  c (suc (suc _)) (divides 0       ())
  c (suc (suc _)) (divides (suc _) ())

-- Nothing is coprime to 0, except for 1.

0-coprimeTo-1 :  {m}  Coprime 0 m  m  1
0-coprimeTo-1 {1}           _ = refl
0-coprimeTo-1 {zero}        c with c (1 +1-divides-0 , 1 +1-divides-0)
... | ()
0-coprimeTo-1 {suc (suc m)} c with c ( (1 + m) +1-divides-0
                                     , divides-refl (1 + m) )
... | ()

-- If m and n are coprime, then n + m and n are also coprime.

coprime-+ :  {m n}  Coprime m n  Coprime (n + m) n
coprime-+ {m = zero} {n}           c with 0-coprimeTo-1 c
coprime-+ {m = zero} {1}           c | refl = 1-coprimeTo 1
coprime-+ {m = zero} {zero}        c | ()
coprime-+ {m = zero} {suc (suc _)} c | ()
coprime-+ {m = suc _}              c =
  λ d  c (divides-∸ (proj₁ d) (proj₂ d) , proj₂ d)