{-# OPTIONS --cubical --safe #-} module Data.Fin.Injective where open import Prelude open import Data.Fin.Base open import Data.Fin.Properties using (discreteFin) open import Data.Nat open import Data.Nat.Properties using (+-comm) open import Data.Nat.Compare open import Function.Injective private variable n m : ℕ infix 4 _≢ᶠ_ _≡ᶠ_ _≢ᶠ_ _≡ᶠ_ : Fin n → Fin n → Type _ n ≢ᶠ m = T (not (discreteFin n m .does)) n ≡ᶠ m = T (discreteFin n m .does) _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 f0 (fs y) x≢y = y shift {suc _} (fs x) f0 x≢y = f0 shift {suc _} (fs x) (fs y) x≢y = fs (shift x y x≢y) shift-inj : ∀ (x y z : Fin (suc n)) x≢y x≢z → y ≢ᶠ z → shift x y x≢y ≢ᶠ shift x z x≢z shift-inj f0 (fs y) (fs z) x≢y x≢z x+y≢x+z = x+y≢x+z shift-inj {suc _} (fs x) f0 (fs z) x≢y x≢z x+y≢x+z = tt shift-inj {suc _} (fs x) (fs y) f0 x≢y x≢z x+y≢x+z = tt shift-inj {suc _} (fs x) (fs y) (fs z) x≢y x≢z x+y≢x+z = shift-inj x y z x≢y x≢z x+y≢x+z shrink : suc n F↣ suc m → n F↣ m shrink (f , inj) .fst x = shift (f f0) (f (fs x)) (inj tt) shrink (f , inj) .snd p = shift-inj (f f0) (f (fs _)) (f (fs _)) (inj tt) (inj tt) (inj p) ¬plus-inj : ∀ n m → ¬ (suc (n + m) F↣ m) ¬plus-inj zero zero (f , _) = f f0 ¬plus-inj zero (suc m) inj = ¬plus-inj zero m (shrink inj) ¬plus-inj (suc n) m (f , p) = ¬plus-inj n m (f ∘ fs , p) 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 discreteFin x y | discreteFin (f x) (f y) ... | no ¬p | yes p = ¬p (inj _ _ p) ... | no _ | no _ = tt 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)) refl-↣)) Fin-inj : Injective Fin Fin-inj n m eq with compare n m | comparing n m ... | equal | p = p ... | less k | p = ⊥-elim (n≢sn+m n k (eq ; cong Fin (sym p))) ... | greater k | p = ⊥-elim (n≢sn+m m k (sym eq ; cong Fin (sym p)))