Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Z mod n as Fin #2073

Closed
wants to merge 25 commits into from
Closed
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ Deprecated names
New modules
-----------

* Added new files `Data.Fin.Mod` and `Data.Fin.Mod.Properties`

Additions to existing modules
-----------------------------

Expand Down Expand Up @@ -80,3 +82,31 @@ Additions to existing modules
pred-injective : .{{NonZero m}} → .{{NonZero n}} → pred m ≡ pred n → m ≡ n
pred-cancel-≡ : pred m ≡ pred n → ((m ≡ 0 × n ≡ 1) ⊎ (m ≡ 1 × n ≡ 0)) ⊎ m ≡ n
```

* In `Data.Fin.Properties`:
```agda
zeroFromNonZero : .⦃ NonZero n ⦄ → Fin n
```

* In `Data.Fin.Mod`:
```agda
sucAbsorb : Fin n → Fin n
predAbsorb : Fin n → Fin n
_ℕ+_ : ℕ → Fin n → Fin n
_+_ : Fin m → Fin n → Fin n
_-_ : Fin m → Fin n → Fin m
```

* In `Data.Fin.Mod.Properties`:
```agda
suc-inject₁ : ∀ i → sucAbsorb (inject₁ i) ≡ F.suc i
suc-fromℕ : ∀ n → sucAbsorb (fromℕ n) ≡ zero
pred-sucAbsorb : ∀ i → predAbsorb (F.suc i) ≡ inject₁ i
suc-pred≡id : ∀ i → sucAbsorb (predAbsorb i) ≡ i
pred-suc : ∀ i → predAbsorb (sucAbsorb i) ≡ i
+-identityˡ : .⦃ NonZero n ⦄ → LeftIdentity zeroFromNonZero _+_
+ℕ-identityʳ-toℕ : m ℕ.≤ n → toℕ (m ℕ+ zero {n}) ≡ m
+ℕ-identityʳ : ∀ m≤n → m ℕ+ zero ≡ fromℕ< (s≤s m≤n)
+-identityʳ : .⦃ NonZero n ⦄ → RightIdentity zeroFromNonZero _+_
induction : ∀ P → P zero → (P i → P (sucAbsorb i)) → ∀ i → P i
```
38 changes: 38 additions & 0 deletions src/Data/Fin/Mod.agda
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
------------------------------------------------------------------------
-- The Agda standard library
--
-- ℕ module n
------------------------------------------------------------------------

{-# OPTIONS --cubical-compatible --safe #-}

module Data.Fin.Mod where

open import Data.Nat.Base using (ℕ; zero; suc)
open import Data.Fin.Base
using (Fin; zero; suc; toℕ; fromℕ; inject₁; opposite)
open import Data.Fin.Relation.Unary.Top

private variable
m n : ℕ
guilhermehas marked this conversation as resolved.
Show resolved Hide resolved

infixl 6 _+_ _-_

sucMod : Fin n → Fin n
sucMod i with view i
... | ‵fromℕ = zero
... | ‵inj₁ i = suc ⟦ i ⟧

predMod : Fin n → Fin n
predMod zero = fromℕ _
predMod (suc i) = inject₁ i

_ℕ+_ : ℕ → Fin n → Fin n
guilhermehas marked this conversation as resolved.
Show resolved Hide resolved
zero ℕ+ i = i
suc n ℕ+ i = sucMod (n ℕ+ i)

_+_ : Fin m → Fin n → Fin n
Copy link
Contributor

@MatthewDaggitt MatthewDaggitt Jan 15, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give me an example of a use-case of this operation? Seems a little unnatural to me adding together two numbers of different mods and arbitrarily returning the result mod the right one?

And why does _-_ return the result mod the left one?

i + j = toℕ i ℕ+ j

_-_ : Fin m → Fin n → Fin m
i - j = opposite j + i
104 changes: 104 additions & 0 deletions src/Data/Fin/Mod/Properties.agda
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
------------------------------------------------------------------------
-- The Agda standard library
--
-- Properties related to mod fin
------------------------------------------------------------------------

{-# OPTIONS --cubical-compatible --safe #-}

module Data.Fin.Mod.Properties where

open import Function.Base using (id; _$_; _∘_)
open import Data.Bool.Base using (true; false)
open import Data.Nat.Base as ℕ using (ℕ; zero; suc; z≤n; s≤s; NonZero)
open import Data.Nat.Properties as ℕ
using (m≤n⇒m≤1+n; 1+n≰n; module ≤-Reasoning)
open import Data.Fin.Base hiding (_+_; _-_)
open import Data.Fin.Properties
open import Data.Fin.Induction using (<-weakInduction)
open import Data.Fin.Relation.Unary.Top
open import Data.Fin.Mod
open import Relation.Nullary.Decidable.Core using (Dec; yes; no)
open import Relation.Nullary.Negation.Core using (contradiction)
open import Relation.Binary.PropositionalEquality
using (_≡_; _≢_; refl; sym; trans; cong; module ≡-Reasoning)
open import Relation.Unary using (Pred)

module _ {n : ℕ} where
open import Algebra.Definitions {A = Fin n} _≡_ public

open ≡-Reasoning

private variable
m n : ℕ

------------------------------------------------------------------------
-- sucMod

sucMod-inject₁ : (i : Fin n) → sucMod (inject₁ i) ≡ suc i
sucMod-inject₁ i rewrite view-inject₁ i =
cong suc (view-complete (view i))

sucMod-fromℕ : ∀ n → sucMod (fromℕ n) ≡ zero
sucMod-fromℕ n rewrite view-fromℕ n = refl

------------------------------------------------------------------------
-- predMod

predMod-suc : (i : Fin n) → predMod (suc i) ≡ inject₁ i
predMod-suc _ = refl

predMod-sucMod : (i : Fin n) → predMod (sucMod i) ≡ i
predMod-sucMod i with view i
... | ‵fromℕ = refl
... | ‵inj₁ p = cong inject₁ (view-complete p)

sucMod-predMod : (i : Fin n) → sucMod (predMod i) ≡ i
sucMod-predMod zero = sucMod-fromℕ _
sucMod-predMod (suc i) = sucMod-inject₁ i

------------------------------------------------------------------------
-- _+ℕ_

+ℕ-identityʳ-toℕ : m ℕ.≤ n → toℕ (m ℕ+ zero {n}) ≡ m
+ℕ-identityʳ-toℕ {zero} m≤n = refl
+ℕ-identityʳ-toℕ {suc m} 1+m≤1+n@(s≤s m≤n) = begin
toℕ (sucMod (m ℕ+ zero)) ≡⟨ cong (toℕ ∘ sucMod) (toℕ-injective toℕm≡fromℕ<) ⟩
toℕ (sucMod (inject₁ (fromℕ< 1+m≤1+n))) ≡⟨ cong toℕ (sucMod-inject₁ _) ⟩
suc (toℕ (fromℕ< 1+m≤1+n)) ≡⟨ cong suc (toℕ-fromℕ< _) ⟩
suc m ∎
where

toℕm≡fromℕ< = begin
toℕ (m ℕ+ zero) ≡⟨ +ℕ-identityʳ-toℕ (m≤n⇒m≤1+n m≤n) ⟩
m ≡⟨ toℕ-fromℕ< _ ⟨
toℕ (fromℕ< 1+m≤1+n) ≡⟨ toℕ-inject₁ _ ⟨
toℕ (inject₁ (fromℕ< 1+m≤1+n)) ∎

+ℕ-identityʳ : (m≤n : m ℕ.≤ n) → m ℕ+ zero ≡ fromℕ< (s≤s m≤n)
+ℕ-identityʳ {m} m≤n = toℕ-injective (begin
toℕ (m ℕ+ zero) ≡⟨ +ℕ-identityʳ-toℕ m≤n ⟩
m ≡⟨ toℕ-fromℕ< _ ⟨
toℕ (fromℕ< (s≤s m≤n)) ∎)

------------------------------------------------------------------------
-- _+_

+-identityˡ : .{{ _ : NonZero n }} → LeftIdentity zeroFromNonZero _+_
+-identityˡ {suc _} _ = refl

+-identityʳ : .{{ _ : NonZero n }} → RightIdentity zeroFromNonZero _+_
+-identityʳ {suc n} i rewrite +ℕ-identityʳ {m = toℕ i} {n} _ = fromℕ<-toℕ _ (toℕ≤pred[n] _)

induction :
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be moved to a new file Data.Fin.Mod.Induction (i.e. along the lines of https://github.com/agda/agda-stdlib/blob/master/src/Data/Fin/Induction.agda).

Also I think this proof should be strengthened. Surely this should hold for any exists j . P j, not just P zero?

∀ {ℓ} (P : Pred (Fin (ℕ.suc n)) ℓ) →
P zero →
(∀ {i} → P i → P (sucMod i)) →
∀ i → P i
induction P P₀ Pᵢ⇒Pᵢ₊₁ i = <-weakInduction P P₀ Pᵢ⇒Pᵢ₊₁′ i
where
PInj : ∀ {i} → P (sucMod (inject₁ i)) → P (suc i)
PInj {i} rewrite sucMod-inject₁ i = id

Pᵢ⇒Pᵢ₊₁′ : ∀ i → P (inject₁ i) → P (suc i)
Pᵢ⇒Pᵢ₊₁′ _ Pᵢ = PInj (Pᵢ⇒Pᵢ₊₁ Pᵢ)
3 changes: 3 additions & 0 deletions src/Data/Fin/Properties.agda
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ private
nonZeroIndex : Fin n → ℕ.NonZero n
nonZeroIndex {n = suc _} _ = _

zeroFromNonZero : .⦃ _ : ℕ.NonZero n ⦄ → Fin n
zeroFromNonZero {n = suc _} = zero
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Anyone have any bright ideas for what this could be called? @jamesmckinna etc?

It should also live in Data.Fin.Base I think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, the abandoned #1847 , tackling #1686 , called this concept "homogeneous zero" (and its friend "homogeneous successor", on the model of n : Nat, i : Fin n being a 'homogeneous' telescope; of course, the {{NonZero n}} precondition spoils things, but hey ;-)), and gave it the terrible name zero\' in the PR.

👍 to its being in Data.Fin.Base, as in that PR.

Better name(s): hzero? zeroNZ? zero⁺?

I ran out of mental strength/inspiration working on that PR, and I find it slightly hard to revisit the discussion/thought processes again now...


------------------------------------------------------------------------
-- Bundles

Expand Down