module Data.Fin where
open import Data.Empty using (⊥-elim)
open import Data.Nat as Nat
using (ℕ; zero; suc; z≤n; s≤s)
renaming ( _+_ to _N+_; _∸_ to _N∸_
; _≤_ to _N≤_; _≥_ to _N≥_; _<_ to _N<_; _≤?_ to _N≤?_)
open import Function
import Level
open import Relation.Nullary
open import Relation.Nullary.Decidable
open import Relation.Binary
open import Relation.Binary.PropositionalEquality
using (_≡_; _≢_; refl; cong)
data Fin : ℕ → Set where
zero : {n : ℕ} → Fin (suc n)
suc : {n : ℕ} (i : Fin n) → Fin (suc n)
toℕ : ∀ {n} → Fin n → ℕ
toℕ zero = 0
toℕ (suc i) = suc (toℕ i)
Fin′ : ∀ {n} → Fin n → Set
Fin′ i = Fin (toℕ i)
fromℕ : (n : ℕ) → Fin (suc n)
fromℕ zero = zero
fromℕ (suc n) = suc (fromℕ n)
fromℕ≤ : ∀ {m n} → m N< n → Fin n
fromℕ≤ (Nat.s≤s Nat.z≤n) = zero
fromℕ≤ (Nat.s≤s (Nat.s≤s m≤n)) = suc (fromℕ≤ (Nat.s≤s m≤n))
fromℕ≤″ : ∀ m {n} → m Nat.<″ n → Fin n
fromℕ≤″ zero (Nat.less-than-or-equal refl) = zero
fromℕ≤″ (suc m) (Nat.less-than-or-equal refl) =
suc (fromℕ≤″ m (Nat.less-than-or-equal refl))
infix 10 #_
#_ : ∀ m {n} {m<n : True (suc m N≤? n)} → Fin n
#_ _ {m<n = m<n} = fromℕ≤ (toWitness m<n)
raise : ∀ {m} n → Fin m → Fin (n N+ m)
raise zero i = i
raise (suc n) i = suc (raise n i)
reduce≥ : ∀ {m n} (i : Fin (m N+ n)) (i≥m : toℕ i N≥ m) → Fin n
reduce≥ {zero} i i≥m = i
reduce≥ {suc m} zero ()
reduce≥ {suc m} (suc i) (s≤s i≥m) = reduce≥ i i≥m
inject : ∀ {n} {i : Fin n} → Fin′ i → Fin n
inject {i = zero} ()
inject {i = suc i} zero = zero
inject {i = suc i} (suc j) = suc (inject j)
inject! : ∀ {n} {i : Fin (suc n)} → Fin′ i → Fin n
inject! {n = zero} {i = suc ()} _
inject! {i = zero} ()
inject! {n = suc _} {i = suc _} zero = zero
inject! {n = suc _} {i = suc _} (suc j) = suc (inject! j)
inject+ : ∀ {m} n → Fin m → Fin (m N+ n)
inject+ n zero = zero
inject+ n (suc i) = suc (inject+ n i)
inject₁ : ∀ {m} → Fin m → Fin (suc m)
inject₁ zero = zero
inject₁ (suc i) = suc (inject₁ i)
inject≤ : ∀ {m n} → Fin m → m N≤ n → Fin n
inject≤ zero (Nat.s≤s le) = zero
inject≤ (suc i) (Nat.s≤s le) = suc (inject≤ i le)
strengthen : ∀ {n} (i : Fin n) → Fin′ (suc i)
strengthen zero = zero
strengthen (suc i) = suc (strengthen i)
fold : ∀ (T : ℕ → Set) {m} →
(∀ {n} → T n → T (suc n)) →
(∀ {n} → T (suc n)) →
Fin m → T m
fold T f x zero = x
fold T f x (suc i) = f (fold T f x i)
fold′ : ∀ {n t} (T : Fin (suc n) → Set t) →
(∀ i → T (inject₁ i) → T (suc i)) →
T zero →
∀ i → T i
fold′ T f x zero = x
fold′ {n = zero} T f x (suc ())
fold′ {n = suc n} T f x (suc i) =
f i (fold′ (T ∘ inject₁) (f ∘ inject₁) x i)
lift : ∀ {m n} k → (Fin m → Fin n) → Fin (k N+ m) → Fin (k N+ n)
lift zero f i = f i
lift (suc k) f zero = zero
lift (suc k) f (suc i) = suc (lift k f i)
infixl 6 _+_
_+_ : ∀ {m n} (i : Fin m) (j : Fin n) → Fin (toℕ i N+ n)
zero + j = j
suc i + j = suc (i + j)
infixl 6 _-_
_-_ : ∀ {m} (i : Fin m) (j : Fin′ (suc i)) → Fin (m N∸ toℕ j)
i - zero = i
zero - suc ()
suc i - suc j = i - j
infixl 6 _ℕ-_
_ℕ-_ : (n : ℕ) (j : Fin (suc n)) → Fin (suc n N∸ toℕ j)
n ℕ- zero = fromℕ n
zero ℕ- suc ()
suc n ℕ- suc i = n ℕ- i
infixl 6 _ℕ-ℕ_
_ℕ-ℕ_ : (n : ℕ) → Fin (suc n) → ℕ
n ℕ-ℕ zero = n
zero ℕ-ℕ suc ()
suc n ℕ-ℕ suc i = n ℕ-ℕ i
pred : ∀ {n} → Fin n → Fin n
pred zero = zero
pred (suc i) = inject₁ i
punchOut : ∀ {m} {i j : Fin (suc m)} → i ≢ j → Fin m
punchOut {_} {zero} {zero} i≢j = ⊥-elim (i≢j refl)
punchOut {_} {zero} {suc j} _ = j
punchOut {zero} {suc ()}
punchOut {suc m} {suc i} {zero} _ = zero
punchOut {suc m} {suc i} {suc j} i≢j = suc (punchOut (i≢j ∘ cong suc))
punchIn : ∀ {m} → Fin (suc m) → Fin m → Fin (suc m)
punchIn zero j = suc j
punchIn (suc i) zero = zero
punchIn (suc i) (suc j) = suc (punchIn i j)
infix 4 _≤_ _<_
_≤_ : ∀ {n} → Rel (Fin n) Level.zero
_≤_ = _N≤_ on toℕ
_≤?_ : ∀ {n} → (a : Fin n) → (b : Fin n) → Dec (a ≤ b)
a ≤? b = toℕ a N≤? toℕ b
_<_ : ∀ {n} → Rel (Fin n) Level.zero
_<_ = _N<_ on toℕ
data _≺_ : ℕ → ℕ → Set where
_≻toℕ_ : ∀ n (i : Fin n) → toℕ i ≺ n
data Ordering {n : ℕ} : Fin n → Fin n → Set where
less : ∀ greatest (least : Fin′ greatest) →
Ordering (inject least) greatest
equal : ∀ i → Ordering i i
greater : ∀ greatest (least : Fin′ greatest) →
Ordering greatest (inject least)
compare : ∀ {n} (i j : Fin n) → Ordering i j
compare zero zero = equal zero
compare zero (suc j) = less (suc j) zero
compare (suc i) zero = greater (suc i) zero
compare (suc i) (suc j) with compare i j
compare (suc .(inject least)) (suc .greatest) | less greatest least =
less (suc greatest) (suc least)
compare (suc .greatest) (suc .(inject least)) | greater greatest least =
greater (suc greatest) (suc least)
compare (suc .i) (suc .i) | equal i = equal (suc i)