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

Modular arithmetic based on Data.Nat.Bounded #2257 #2292

Draft
wants to merge 30 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1054d17
sketch of arithmetic mod n, based on `Data.Nat.Bounded`
jamesmckinna Jan 25, 2024
96d851e
`RawRing`, not only `RawSemiring`
jamesmckinna Jan 25, 2024
edfe817
tweaks
jamesmckinna Jan 25, 2024
5808442
streamline the quotient map
jamesmckinna Feb 1, 2024
7fbcb46
start of proving the `IsRing` property
jamesmckinna Feb 1, 2024
a019dbe
rename projections
jamesmckinna Feb 4, 2024
aa7b2bf
more properties
jamesmckinna Feb 5, 2024
9d855cb
progress
jamesmckinna Feb 5, 2024
0c9eed6
shim for `Data.Nat.Bounded`
jamesmckinna Feb 9, 2024
d5bed3a
local change to `Bounded` shim
jamesmckinna Feb 9, 2024
0f9ec78
incremental progress
jamesmckinna Feb 9, 2024
532e3ed
revised to reflect improvements to `ℕ<`
jamesmckinna Feb 10, 2024
e3bf662
remove shim dependency
jamesmckinna Feb 10, 2024
b299856
remove shim dependency
jamesmckinna Feb 10, 2024
8caf9ac
further revised to reflect improvements to `ℕ<`
jamesmckinna Feb 11, 2024
d7447d0
committed `Data.Nat.Bounded.*` against subsequent PR
jamesmckinna Feb 12, 2024
508249f
tweak syntax to distinguish from `Data.Integer.Modulo`
jamesmckinna Feb 12, 2024
cccf3a8
tweaks
jamesmckinna Feb 12, 2024
b51bc24
refactoring `Data.Integer.Modulo.Properties` via revised `Data.Nat.Bo…
jamesmckinna Feb 12, 2024
e235c9a
`nonZeroModulus`
jamesmckinna Feb 12, 2024
4e9921a
using `nonZeroModulus`
jamesmckinna Feb 12, 2024
fbcec66
refactoring
jamesmckinna Feb 12, 2024
6d7e7ac
refactoring lemmas
jamesmckinna Feb 12, 2024
e3d3243
arithmetic `mod n` lemmas
jamesmckinna Feb 12, 2024
692e847
additional arithmetic
jamesmckinna Feb 12, 2024
0f6f0ce
integers `mod n` form a `Ring`
jamesmckinna Feb 12, 2024
8cf05cb
moved `Modulo` to `Modulo.Base`
jamesmckinna Feb 12, 2024
b78f407
knock-on from moving `Modulo` to `Modulo.Base`; `CHANGELOG`
jamesmckinna Feb 12, 2024
aa22e03
Merge branch 'master' into modular-arithmetic
jamesmckinna Feb 12, 2024
4ab04f1
'rebasing' against revised /updated #2257
jamesmckinna Feb 13, 2024
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
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ New modules

* `Algebra.Module.Bundles.Raw`: raw bundles for module-like algebraic structures

* Integer arithmetic modulo `n`, based on `Data.Nat.Bounded.*`:
```agda
Data.Integer.Modulo.Base
Data.Integer.Modulo.Literals
Data.Integer.Modulo.Properties
```

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

Expand Down
118 changes: 118 additions & 0 deletions src/Data/Integer/Modulo/Base.agda
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
------------------------------------------------------------------------
-- The Agda standard library
--
-- Integers mod n, type and basic operations
------------------------------------------------------------------------

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

open import Data.Nat.Base as ℕ
using (ℕ; zero; suc; NonZero; NonTrivial; nonTrivial⇒nonZero; _<_; _∸_)

module Data.Integer.Modulo.Base n .{{_ : NonTrivial n}} where

open import Algebra.Bundles.Raw
using (RawMagma; RawMonoid; RawNearSemiring; RawSemiring; RawRing)
open import Data.Integer.Base as ℤ using (ℤ; _◂_; signAbs)
open import Data.Nat.Bounded.Base as ℕ< hiding (fromℕ; _∼_; ≡-Modℕ)
import Data.Nat.Properties as ℕ
open import Data.Sign.Base as Sign using (Sign)
open import Data.Unit.Base using (⊤)
open import Function.Base using (id; _∘_; _$_; _on_)
open import Relation.Binary.Core using (Rel)
open import Relation.Binary.PropositionalEquality.Core using (_≡_)

private
variable
m o : ℕ
i j : ℕ< n

instance
_ = nonTrivial⇒nonZero n

m∸n<m : ∀ m n → .{{NonZero m}} → .{{NonZero n}} → m ∸ n < m
m∸n<m m@(suc _) n@(suc o) = ℕ.s≤s (ℕ.m∸n≤m _ o)

------------------------------------------------------------------------
-- Definition

-- Infixes
infix 8 -_
infixl 7 _*_
infixl 6 _+_

-- Type definition
ℤmod : Set
ℤmod = ℕ< n

-- Re-export
fromℕ : ℕ → ℤmod
fromℕ = ℕ<.fromℕ

-- Negation
-_ : ℤmod → ℤmod
- ⟦ m@zero ⟧< _ = ⟦0⟧<
- ⟦ m@(suc _) ⟧< _ = ⟦ n ∸ m ⟧< m∸n<m _ _

-- Addition
_+_ : ℤmod → ℤmod → ℤmod
i + j = fromℕ (⟦ i ⟧ ℕ.+ ⟦ j ⟧)

-- Multiplication
_*_ : ℤmod → ℤmod → ℤmod
i * j = fromℕ (⟦ i ⟧ ℕ.* ⟦ j ⟧)

------------------------------------------------------------------------
-- Quotient map from ℤ

_◃_ : Sign → ℤmod → ℤmod
Sign.+ ◃ j = j
Sign.- ◃ j = - j

fromℤ : ℤ → ℤmod
fromℤ i with s ◂ ∣i∣ ← signAbs i = s ◃ fromℕ ∣i∣

-- the _mod_ syntax

Mod : ℤ → ℤmod
Mod = fromℤ

syntax Mod {n = n} i = i mod n

-- Quotient equivalence relation on ℤ induced by `fromℤ`

_∼_ : Rel ℤ _
_∼_ = _≡_ on fromℤ

≡-Mod : Rel ℤ _
≡-Mod i j = i ∼ j

syntax ≡-Mod n i j = i ≡ j mod n

------------------------------------------------------------------------
-- Raw bundles

+-*-rawRing : RawRing _ _
+-*-rawRing = record
{ _≈_ = _≡_
; _+_ = _+_
; _*_ = _*_
; -_ = -_
; 0# = ⟦0⟧<
; 1# = ⟦1⟧<
}

open RawRing +-*-rawRing public
using (+-rawMagma; *-rawMagma)
renaming ( +-rawMonoid to +-0-rawMonoid
; *-rawMonoid to *-1-rawMonoid
--; rawNearSemiring to +-*-rawNearSemiring
; rawSemiring to +-*-rawSemiring
)

------------------------------------------------------------------------
-- -- Postfix notation for when opening the module unparameterised

0ℤmod = ⟦0⟧<
1ℤmod = ⟦1⟧<

27 changes: 27 additions & 0 deletions src/Data/Integer/Modulo/Literals.agda
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
------------------------------------------------------------------------
-- The Agda standard library
--
-- Literals for integers mod n
------------------------------------------------------------------------

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

open import Data.Nat.Base using (ℕ; NonTrivial)

module Data.Integer.Modulo.Literals n .{{_ : NonTrivial n}} where

open import Agda.Builtin.FromNat using (Number)
open import Data.Unit.Base using (⊤)
open import Data.Integer.Modulo.Base using (ℤmod; fromℕ)

------------------------------------------------------------------------
-- Definitions

Constraint : ℕ → Set
Constraint _ = ⊤

fromNat : ∀ m → {{Constraint m}} → ℤmod n
fromNat m = fromℕ n m

number : Number (ℤmod n)
number = record { Constraint = Constraint ; fromNat = fromNat }
178 changes: 178 additions & 0 deletions src/Data/Integer/Modulo/Properties.agda
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
------------------------------------------------------------------------
-- The Agda standard library
--
-- Integers mod n, properties
------------------------------------------------------------------------

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

open import Data.Nat.Base as ℕ
using (ℕ; zero; suc; NonZero; NonTrivial; _<_; _∸_; _%_)

module Data.Integer.Modulo.Properties n .{{_ : NonTrivial n}} where

open import Algebra.Bundles.Raw
using (RawMagma; RawMonoid; RawNearSemiring; RawSemiring; RawRing)
open import Algebra.Bundles
using (Magma; Monoid; NearSemiring; Semiring; Ring)
import Algebra.Definitions as Definitions
import Algebra.Structures as Structures
open import Data.Integer.Base as ℤ using (ℤ; _◂_; signAbs)
open import Data.Nat.Bounded.Base as ℕ< hiding (fromℕ; _∼_)
import Data.Nat.Bounded.Properties as ℕ<
import Data.Nat.DivMod as ℕ
import Data.Nat.Properties as ℕ
open import Data.Product.Base as Product using (_,_)
open import Data.Sign.Base as Sign using (Sign)
open import Function.Base using (_$_)
open import Relation.Binary.PropositionalEquality
using (_≡_; refl; sym; trans; cong; cong₂; isEquivalence; module ≡-Reasoning)

open import Data.Integer.Modulo.Base n as Modulo
using (ℤmod; fromℕ; fromℤ; _∼_; ≡-Mod; +-*-rawRing)

open Definitions (_≡_ {A = ℤmod})
open Structures (_≡_ {A = ℤmod})
using ( IsMagma; IsSemigroup; IsMonoid
; IsGroup; IsAbelianGroup
; IsNearSemiring; IsSemiring
; IsRing)

private
variable
m o : ℕ
i j k : ℤmod

instance
_ = ℕ.nonTrivial⇒nonZero n

open RawRing +-*-rawRing
open ≡-Reasoning

+-cong₂ : Congruent₂ _+_
+-cong₂ = cong₂ _+_

+-isMagma : IsMagma _+_
+-isMagma = record { isEquivalence = isEquivalence ; ∙-cong = +-cong₂ }

+-assoc : Associative _+_
+-assoc i j k = begin
i + j + k
≡⟨⟩
fromℕ (((⟦ i ⟧ ℕ.+ ⟦ j ⟧) % n) ℕ.+ ⟦ k ⟧)
≡⟨ ℕ<.≡-mod⇒fromℕ≡fromℕ ≡-mod ⟩
fromℕ (⟦ i ⟧ ℕ.+ ((⟦ j ⟧ ℕ.+ ⟦ k ⟧) % n))
≡⟨⟩
i + (j + k) ∎
where
≡-mod : (((⟦ i ⟧ ℕ.+ ⟦ j ⟧) % n) ℕ.+ ⟦ k ⟧)
(⟦ i ⟧ ℕ.+ ((⟦ j ⟧ ℕ.+ ⟦ k ⟧) % n))
modℕ n
≡-mod = ℕ<.≡-mod-trans (ℕ<.+-distribˡ-% (⟦ i ⟧ ℕ.+ ⟦ j ⟧) ⟦ k ⟧)
(ℕ<.≡-mod-trans (ℕ<.≡-mod-reflexive (ℕ.+-assoc ⟦ i ⟧ ⟦ j ⟧ ⟦ k ⟧))
(ℕ<.≡-mod-sym (ℕ<.+-distribʳ-% ⟦ i ⟧ (⟦ j ⟧ ℕ.+ ⟦ k ⟧))))

+-isSemigroup : IsSemigroup _+_
+-isSemigroup = record { isMagma = +-isMagma ; assoc = +-assoc }

+-identityˡ : LeftIdentity 0# _+_
+-identityˡ = ℕ<.fromℕ∘toℕ≐id

+-identityʳ : RightIdentity 0# _+_
+-identityʳ i = trans (cong fromℕ (ℕ.+-identityʳ _)) (ℕ<.fromℕ∘toℕ≐id i)

+-identity : Identity 0# _+_
+-identity = +-identityˡ , +-identityʳ

+-isMonoid : IsMonoid _+_ 0#
+-isMonoid = record { isSemigroup = +-isSemigroup ; identity = +-identity }

+-inverseˡ : LeftInverse 0# -_ _+_
+-inverseˡ (⟦ zero ⟧< _) = +-identityˡ 0#
+-inverseˡ i@(⟦ suc _ ⟧< _) = ℕ<.+-inverseˡ (ℕ<.isBounded i)

+-inverseʳ : RightInverse 0# -_ _+_
+-inverseʳ (⟦ zero ⟧< _) = +-identityʳ 0#
+-inverseʳ i@(⟦ m@(suc _) ⟧< _) = ℕ<.+-inverseʳ (ℕ<.isBounded i)

+-inverse : Inverse 0# -_ _+_
+-inverse = +-inverseˡ , +-inverseʳ

+-0-isGroup : IsGroup _+_ 0# -_
+-0-isGroup = record { isMonoid = +-isMonoid ; inverse = +-inverse ; ⁻¹-cong = cong -_ }

+-comm : Commutative _+_
+-comm i j = cong fromℕ (ℕ.+-comm ⟦ i ⟧ ⟦ j ⟧)

+-0-isAbelianGroup : IsAbelianGroup _+_ 0# -_
+-0-isAbelianGroup = record { isGroup = +-0-isGroup ; comm = +-comm }

*-cong₂ : Congruent₂ _*_
*-cong₂ = cong₂ _*_

*-assoc : Associative _*_
*-assoc i j k = begin
i * j * k
≡⟨⟩
fromℕ (((⟦ i ⟧ ℕ.* ⟦ j ⟧) % n) ℕ.* ⟦ k ⟧)
≡⟨ ℕ<.≡-mod⇒fromℕ≡fromℕ ≡-mod ⟩
fromℕ (⟦ i ⟧ ℕ.* ((⟦ j ⟧ ℕ.* ⟦ k ⟧) % n))
≡⟨⟩
i * (j * k) ∎
where
≡-mod : (((⟦ i ⟧ ℕ.* ⟦ j ⟧) % n) ℕ.* ⟦ k ⟧)
(⟦ i ⟧ ℕ.* ((⟦ j ⟧ ℕ.* ⟦ k ⟧) % n))
modℕ n
≡-mod = ℕ<.≡-mod-trans (ℕ<.*-distribˡ-% (⟦ i ⟧ ℕ.* ⟦ j ⟧) ⟦ k ⟧)
(ℕ<.≡-mod-trans (ℕ<.≡-mod-reflexive (ℕ.*-assoc ⟦ i ⟧ ⟦ j ⟧ ⟦ k ⟧))
(ℕ<.≡-mod-sym (ℕ<.*-distribʳ-% ⟦ i ⟧ (⟦ j ⟧ ℕ.* ⟦ k ⟧))))

*-identityˡ : LeftIdentity 1# _*_
*-identityˡ i with eq ← ℕ<.⟦1⟧≡1 {n = n} rewrite eq
= trans (cong fromℕ (ℕ.*-identityˡ _)) (ℕ<.fromℕ≐⟦⟧< (ℕ<.isBounded i))

*-identityʳ : RightIdentity 1# _*_
*-identityʳ i with eq ← ℕ<.⟦1⟧≡1 {n = n} rewrite eq
= trans (cong fromℕ (ℕ.*-identityʳ _)) (ℕ<.fromℕ≐⟦⟧< (ℕ<.isBounded i))

*-identity : Identity 1# _*_
*-identity = *-identityˡ , *-identityʳ

*-distribˡ-+ : _*_ DistributesOverˡ _+_
*-distribˡ-+ i j k = ℕ<.≡-mod⇒fromℕ≡fromℕ ≡-mod
where
≡-mod : (⟦ i ⟧ ℕ.* ⟦ j + k ⟧)
(⟦ i * j ⟧ ℕ.+ ⟦ i * k ⟧)
modℕ n
≡-mod = ℕ<.≡-mod-trans (ℕ<.*-distribʳ-% ⟦ i ⟧ (⟦ j ⟧ ℕ.+ ⟦ k ⟧))
(ℕ<.≡-mod-trans (ℕ<.≡-mod-reflexive (ℕ.*-distribˡ-+ ⟦ i ⟧ ⟦ j ⟧ ⟦ k ⟧))
(ℕ<.≡-mod-sym (ℕ<.+-distrib-% (⟦ i ⟧ ℕ.* ⟦ j ⟧) (⟦ i ⟧ ℕ.* ⟦ k ⟧))))

*-distribʳ-+ : _*_ DistributesOverʳ _+_
*-distribʳ-+ i j k = ℕ<.≡-mod⇒fromℕ≡fromℕ ≡-mod
where
≡-mod : (⟦ j + k ⟧ ℕ.* ⟦ i ⟧)
(⟦ j * i ⟧ ℕ.+ ⟦ k * i ⟧)
modℕ n
≡-mod = ℕ<.≡-mod-trans (ℕ<.*-distribˡ-% (⟦ j ⟧ ℕ.+ ⟦ k ⟧) ⟦ i ⟧)
(ℕ<.≡-mod-trans (ℕ<.≡-mod-reflexive (ℕ.*-distribʳ-+ ⟦ i ⟧ ⟦ j ⟧ ⟦ k ⟧))
(ℕ<.≡-mod-sym (ℕ<.+-distrib-% (⟦ j ⟧ ℕ.* ⟦ i ⟧) (⟦ k ⟧ ℕ.* ⟦ i ⟧))))

*-distrib-+ : _*_ DistributesOver _+_
*-distrib-+ = *-distribˡ-+ , *-distribʳ-+

+-*-isRing : IsRing _+_ _*_ -_ 0# 1#
+-*-isRing = record
{ +-isAbelianGroup = +-0-isAbelianGroup
; *-cong = *-cong₂
; *-assoc = *-assoc
; *-identity = *-identity
; distrib = *-distrib-+
}

ring : Ring _ _
ring = record { isRing = +-*-isRing }
Loading
Loading