------------------------------------------------------------------------ -- The Agda standard library -- -- Finite sets ------------------------------------------------------------------------ -- Note that elements of Fin n can be seen as natural numbers in the -- set {m | m < n}. The notation "m" in comments below refers to this -- natural number view. {-# OPTIONS --cubical-compatible --safe #-} module Data.Fin.Base where open import Data.Bool.Base using (Bool; T) open import Data.Nat.Base as ℕ using (ℕ; zero; suc) open import Data.Product.Base as Product using (_×_; _,_; proj₁; proj₂) open import Data.Sum.Base as Sum using (_⊎_; inj₁; inj₂; [_,_]′) open import Function.Base using (id; _∘_; _on_; flip) open import Level using (0ℓ) open import Relation.Binary.Core open import Relation.Binary.PropositionalEquality.Core using (_≡_; _≢_; refl; cong) open import Relation.Binary.Indexed.Heterogeneous.Core using (IRel) open import Relation.Nullary.Negation.Core using (contradiction) private variable m n : ℕ ------------------------------------------------------------------------ -- Types -- Fin n is a type with n elements. data Fin : ℕ → Set where zero : Fin (suc n) suc : (i : Fin n) → Fin (suc n) -- A conversion: toℕ "i" = i. toℕ : Fin n → ℕ toℕ zero = 0 toℕ (suc i) = suc (toℕ i) -- A Fin-indexed variant of Fin. Fin′ : Fin n → Set Fin′ i = Fin (toℕ i) ------------------------------------------------------------------------ -- A cast that actually computes on constructors (as opposed to subst) cast : .(m ≡ n) → Fin m → Fin n cast {zero} {zero} eq k = k cast {suc m} {suc n} eq zero = zero cast {suc m} {suc n} eq (suc k) = suc (cast (cong ℕ.pred eq) k) ------------------------------------------------------------------------ -- Conversions -- toℕ is defined above. -- fromℕ n = "n". fromℕ : (n : ℕ) → Fin (suc n) fromℕ zero = zero fromℕ (suc n) = suc (fromℕ n) -- fromℕ< {m} _ = "m". fromℕ< : .(m ℕ.< n) → Fin n fromℕ< {zero} {suc _} _ = zero fromℕ< {suc m} {suc _} m<n = suc (fromℕ< (ℕ.s<s⁻¹ m<n)) -- fromℕ<″ m _ = "m". fromℕ<″ : ∀ m {n} → .(m ℕ.<″ n) → Fin n fromℕ<″ zero {suc _} _ = zero fromℕ<″ (suc m) {suc _} m<″n = suc (fromℕ<″ m (ℕ.s<″s⁻¹ m<″n)) -- canonical liftings of i:Fin m to larger index -- injection on the left: "i" ↑ˡ n = "i" in Fin (m + n) infixl 5 _↑ˡ_ _↑ˡ_ : ∀ {m} → Fin m → ∀ n → Fin (m ℕ.+ n) zero ↑ˡ n = zero (suc i) ↑ˡ n = suc (i ↑ˡ n) -- injection on the right: n ↑ʳ "i" = "n + i" in Fin (n + m) infixr 5 _↑ʳ_ _↑ʳ_ : ∀ {m} n → Fin m → Fin (n ℕ.+ m) zero ↑ʳ i = i (suc n) ↑ʳ i = suc (n ↑ʳ i) -- reduce≥ "m + i" _ = "i". reduce≥ : ∀ (i : Fin (m ℕ.+ n)) → .(m ℕ.≤ toℕ i) → Fin n reduce≥ {zero} i _ = i reduce≥ {suc _} (suc i) m≤i = reduce≥ i (ℕ.s≤s⁻¹ m≤i) -- inject⋆ m "i" = "i". inject : ∀ {i : Fin n} → Fin′ i → Fin n inject {i = suc i} zero = zero inject {i = suc i} (suc j) = suc (inject j) inject! : ∀ {i : Fin (suc n)} → Fin′ i → Fin n inject! {n = suc _} {i = suc _} zero = zero inject! {n = suc _} {i = suc _} (suc j) = suc (inject! j) inject₁ : Fin n → Fin (suc n) inject₁ zero = zero inject₁ (suc i) = suc (inject₁ i) inject≤ : Fin m → .(m ℕ.≤ n) → Fin n inject≤ {n = suc _} zero _ = zero inject≤ {n = suc _} (suc i) m≤n = suc (inject≤ i (ℕ.s≤s⁻¹ m≤n)) -- lower₁ "i" _ = "i". lower₁ : ∀ (i : Fin (suc n)) → n ≢ toℕ i → Fin n lower₁ {zero} zero ne = contradiction refl ne lower₁ {suc n} zero _ = zero lower₁ {suc n} (suc i) ne = suc (lower₁ i (ne ∘ cong suc)) -- A strengthening injection into the minimal Fin fibre. strengthen : ∀ (i : Fin n) → Fin′ (suc i) strengthen zero = zero strengthen (suc i) = suc (strengthen i) -- splitAt m "i" = inj₁ "i" if i < m -- inj₂ "i - m" if i ≥ m -- This is dual to splitAt from Data.Vec. splitAt : ∀ m {n} → Fin (m ℕ.+ n) → Fin m ⊎ Fin n splitAt zero i = inj₂ i splitAt (suc m) zero = inj₁ zero splitAt (suc m) (suc i) = Sum.map suc id (splitAt m i) -- inverse of above function join : ∀ m n → Fin m ⊎ Fin n → Fin (m ℕ.+ n) join m n = [ _↑ˡ n , m ↑ʳ_ ]′ -- quotRem k "i" = "i % k" , "i / k" -- This is dual to group from Data.Vec. quotRem : ∀ n → Fin (m ℕ.* n) → Fin n × Fin m quotRem {suc m} n i with splitAt n i ... | inj₁ j = j , zero ... | inj₂ j = Product.map₂ suc (quotRem {m} n j) -- a variant of quotRem the type of whose result matches the order of multiplication remQuot : ∀ n → Fin (m ℕ.* n) → Fin m × Fin n remQuot i = Product.swap ∘ quotRem i quotient : ∀ n → Fin (m ℕ.* n) → Fin m quotient n = proj₁ ∘ remQuot n remainder : ∀ n → Fin (m ℕ.* n) → Fin n remainder {m} n = proj₂ ∘ remQuot {m} n -- inverse of remQuot combine : Fin m → Fin n → Fin (m ℕ.* n) combine {suc m} {n} zero j = j ↑ˡ (m ℕ.* n) combine {suc m} {n} (suc i) j = n ↑ʳ (combine i j) -- Next in progression after splitAt and remQuot finToFun : Fin (m ℕ.^ n) → (Fin n → Fin m) finToFun {m} {suc n} i zero = quotient (m ℕ.^ n) i finToFun {m} {suc n} i (suc j) = finToFun (remainder {m} (m ℕ.^ n) i) j -- inverse of above function funToFin : (Fin m → Fin n) → Fin (n ℕ.^ m) funToFin {zero} f = zero funToFin {suc m} f = combine (f zero) (funToFin (f ∘ suc)) ------------------------------------------------------------------------ -- Operations -- Folds. fold : ∀ {t} (T : ℕ → Set t) {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 = suc n} T f x (suc i) = f i (fold′ (T ∘ inject₁) (f ∘ inject₁) x i) -- Lifts functions. lift : ∀ k → (Fin m → Fin n) → Fin (k ℕ.+ m) → Fin (k ℕ.+ n) lift zero f i = f i lift (suc k) f zero = zero lift (suc k) f (suc i) = suc (lift k f i) -- "i" + "j" = "i + j". infixl 6 _+_ _+_ : ∀ (i : Fin m) (j : Fin n) → Fin (toℕ i ℕ.+ n) zero + j = j suc i + j = suc (i + j) -- "i" - "j" = "i ∸ j". infixl 6 _-_ _-_ : ∀ (i : Fin n) (j : Fin′ (suc i)) → Fin (n ℕ.∸ toℕ j) i - zero = i suc i - suc j = i - j -- m ℕ- "i" = "m ∸ i". infixl 6 _ℕ-_ _ℕ-_ : (n : ℕ) (j : Fin (suc n)) → Fin (suc n ℕ.∸ toℕ j) n ℕ- zero = fromℕ n suc n ℕ- suc i = n ℕ- i -- m ℕ-ℕ "i" = m ∸ i. infixl 6 _ℕ-ℕ_ _ℕ-ℕ_ : (n : ℕ) → Fin (suc n) → ℕ n ℕ-ℕ zero = n suc n ℕ-ℕ suc i = n ℕ-ℕ i -- pred "i" = "pred i". pred : Fin n → Fin n pred zero = zero pred (suc i) = inject₁ i -- opposite "i" = "n - i" (i.e. the additive inverse). opposite : Fin n → Fin n opposite {suc n} zero = fromℕ n opposite {suc n} (suc i) = inject₁ (opposite i) -- The function f(i,j) = if j>i then j-1 else j -- This is a variant of the thick function from Conor -- McBride's "First-order unification by structural recursion". punchOut : ∀ {i j : Fin (suc n)} → i ≢ j → Fin n punchOut {_} {zero} {zero} i≢j = contradiction refl i≢j punchOut {_} {zero} {suc j} _ = j punchOut {suc _} {suc i} {zero} _ = zero punchOut {suc _} {suc i} {suc j} i≢j = suc (punchOut (i≢j ∘ cong suc)) -- The function f(i,j) = if j≥i then j+1 else j punchIn : Fin (suc n) → Fin n → Fin (suc n) punchIn zero j = suc j punchIn (suc i) zero = zero punchIn (suc i) (suc j) = suc (punchIn i j) -- The function f(i,j) such that f(i,j) = if j≤i then j else j-1 pinch : Fin n → Fin (suc n) → Fin n pinch {suc n} _ zero = zero pinch {suc n} zero (suc j) = j pinch {suc n} (suc i) (suc j) = suc (pinch i j) ------------------------------------------------------------------------ -- Order relations infix 4 _≤_ _≥_ _<_ _>_ _≤_ : IRel Fin 0ℓ i ≤ j = toℕ i ℕ.≤ toℕ j _≥_ : IRel Fin 0ℓ i ≥ j = toℕ i ℕ.≥ toℕ j _<_ : IRel Fin 0ℓ i < j = toℕ i ℕ.< toℕ j _>_ : IRel Fin 0ℓ i > j = toℕ i ℕ.> toℕ j ------------------------------------------------------------------------ -- An ordering view. 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 : ∀ (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 ... | less greatest least = less (suc greatest) (suc least) ... | greater greatest least = greater (suc greatest) (suc least) ... | equal i = equal (suc i) ------------------------------------------------------------------------ -- DEPRECATED NAMES ------------------------------------------------------------------------ -- Please use the new names as continuing support for the old names is -- not guaranteed. -- Version 2.0 raise = _↑ʳ_ {-# WARNING_ON_USAGE raise "Warning: raise was deprecated in v2.0. Please use _↑_ʳ instead." #-} inject+ : ∀ {m} n → Fin m → Fin (m ℕ.+ n) inject+ n i = i ↑ˡ n {-# WARNING_ON_USAGE inject+ "Warning: inject+ was deprecated in v2.0. Please use _↑ˡ_ instead. NB argument order has been flipped: the left-hand argument is the Fin m the right-hand is the Nat index increment." #-} data _≺_ : ℕ → ℕ → Set where _≻toℕ_ : ∀ n (i : Fin n) → toℕ i ≺ n {-# WARNING_ON_USAGE _≺_ "Warning: _≺_ was deprecated in v2.0. Please use equivalent relation _<_ instead." #-} {-# WARNING_ON_USAGE _≻toℕ_ "Warning: _≻toℕ_ was deprecated in v2.0. Please use toℕ<n from Data.Fin.Properties instead." #-}