{-# OPTIONS --safe #-}
module Data.Fin.Injective where
open import Prelude
open import Data.Fin
open import Data.Fin.Properties
open import Data.Nat.Properties
import Data.Nat.Order as ℕ
private variable n m : ℕ
open DiscreteFin
_≢ᶠ_ : Fin n → Fin n → Type
x ≢ᶠ y = T (! (x ≡ᴮ y))
_F↣_ : ℕ → ℕ → Type
n F↣ m = Σ[ f ⦂ (Fin n → Fin m) ] × ∀ {x y} → x ≢ᶠ y → f x ≢ᶠ f y
shift : (x y : Fin (suc n)) → x ≢ᶠ y → Fin n
shift zero (suc y) x≢y = y
shift {suc _} (suc x) zero x≢y = zero
shift {suc _} (suc x) (suc y) x≢y = suc (shift x y x≢y)
shift-inj : ∀ (x y z : Fin (suc n)) y≢x z≢x → y ≢ᶠ z → shift x y y≢x ≢ᶠ shift x z z≢x
shift-inj zero (suc y) (suc z) y≢x z≢x neq = neq
shift-inj {suc _} (suc x) zero (suc z) y≢x z≢x neq = tt
shift-inj {suc _} (suc x) (suc y) zero y≢x z≢x neq = tt
shift-inj {suc _} (suc x) (suc y) (suc z) y≢x z≢x neq = shift-inj x y z y≢x z≢x neq
shrink : suc n F↣ suc m → n F↣ m
shrink (f , inj) .fst x = shift (f zero) (f (suc x)) (inj tt)
shrink (f , inj) .snd p = shift-inj (f zero) (f (suc _)) (f (suc _)) (inj tt) (inj tt) (inj p)
¬plus-inj : ∀ n m → ¬ (suc (n + m) F↣ m)
¬plus-inj zero (suc m) inj = ¬plus-inj zero m (shrink inj)
¬plus-inj (suc n) m (f , inj) = ¬plus-inj n m (f ∘ suc , inj)
¬plus-inj zero zero (f , _) with f zero
... | ()
toFin-inj : (Fin n ↣ Fin m) → n F↣ m
toFin-inj f .fst = f .fst
toFin-inj (f , inj) .snd {x} {y} x≢ᶠy with x ≡ᴮ y | inspect (x ≡ᴮ_) y | f x ≡ᴮ f y | inspect (f x ≡ᴮ_) (f y)
... | false | _ | false | _ = tt
... | false | 〖 x≢y 〗 | true | 〖 fx≡fy 〗 =
let h = inj (sound (f x) (f y) (subst T (sym fx≡fy) tt))
in absurd (subst T x≢y (subst (T ∘ (x ≡ᴮ_)) h (complete x)))
n≢sn+m : ∀ n m → Fin n ≢ Fin (suc (n + m))
n≢sn+m n m n≡m =
¬plus-inj m n (toFin-inj (subst (_↣ Fin n)
(n≡m ; cong (Fin ∘ suc) (+-comm n m))
(id , id)))
Fin-inj : Injective Fin
Fin-inj {n} {m} n≡m with compare n m
... | equal _ = refl
... | less n k = absurd (n≢sn+m n k n≡m)
... | greater m k = absurd (n≢sn+m m k (sym n≡m))
compare-lt : ∀ n m → n ℕ.< suc (suc (n + m))
compare-lt zero m = tt
compare-lt (suc n) m = compare-lt n m
compare-eq : ∀ n → n ℕ.≤ n
compare-eq zero = tt
compare-eq (suc n) = compare-eq n
↣⇒≤ : Fin n ↣ Fin m → n ℕ.≤ m
↣⇒≤ {n} {m} inj with compare n m
↣⇒≤ {n} {.(suc (n + k))} inj | less .n k = compare-lt n k
↣⇒≤ {n} {.n} inj | equal .n = compare-eq n
↣⇒≤ {.(suc (m + k))} {m} inj | greater .m k =
absurd (¬plus-inj k m (toFin-inj (subst (_↣ _) (cong (Fin ∘ suc) (+-comm m k)) inj)))