on master help sign in
Merge pull request #2084 from david-christiansen/contrib-nat-stuff

Division and modulus for Nat, plus associated utilities

commitce3b60b9052d3bc05e872c84c66049a3313f05f3 authorDavid Christiansen <david@davidchristiansen.dk> dateWed 1 Apr 2015, 11:45 (12 years ago) parente5384b96bc1859
5 files changed+270
libs/contrib/Control/WellFounded.idr+83 libs/contrib/Data/Nat.idr+165 libs/contrib/contrib.ipkg+2 libs/prelude/Prelude.idr+6 libs/prelude/Prelude/Nat.idr+14
libs/contrib/Control/WellFounded.idrnew file+83
@@ -0,0 +1,83 @@
1+||| Well-founded recursion.
2+|||
3+||| This is to let us implement some functions that don't have trivial
4+||| recursion patterns over datatypes, but instead are using some
5+||| other metric of size.
6+module Control.WellFounded
7+
8+%default total
9+
10+
11+||| Accessibility: some element `x` is accessible if all `y` such that
12+||| `rel y x` are themselves accessible.
13+|||
14+||| @ a the type of elements
15+||| @ rel a relation on a
16+||| @ x the acessible element
17+data Accessible : (rel : a -> a -> Type) -> (x : a) -> Type where
18+ ||| Accessibility
19+ |||
20+ ||| @ x the accessible element
21+ ||| @ acc' a demonstration that all smaller elements are also accessible
22+ Access : (acc' : (y : a) -> rel y x -> Accessible rel y) ->
23+ Accessible rel x
24+
25+||| A relation `rel` on `a` is well-founded if all elements of `a` are
26+||| acessible.
27+|||
28+||| @ rel the well-founded relation
29+class WellFounded (rel : a -> a -> Type) where
30+ wellFounded : (x : _) -> Accessible rel x
31+
32+
33+||| A recursor over accessibility.
34+|||
35+||| This allows us to recurse over the subset of some type that is
36+||| accessible according to some relation.
37+|||
38+||| @ rel the well-founded relation
39+||| @ step how to take steps on reducing arguments
40+||| @ z the starting point
41+accRec : {rel : a -> a -> Type} ->
42+ (step : (x : a) -> ((y : a) -> rel y x -> b) -> b) ->
43+ (z : a) -> Accessible rel z -> b
44+accRec step z (Access f) =
45+ step z $ \y, lt => accRec step y (f y lt)
46+
47+||| An induction principle for accessibility.
48+|||
49+||| This allows us to recurse over the subset of some type that is
50+||| accessible according to some relation, producing a dependent type
51+||| as a result.
52+|||
53+||| @ rel the well-founded relation
54+||| @ step how to take steps on reducing arguments
55+||| @ z the starting point
56+accInd : {rel : a -> a -> Type} -> {P : a -> Type} ->
57+ (step : (x : a) -> ((y : a) -> rel y x -> P y) -> P x) ->
58+ (z : a) -> Accessible rel z -> P z
59+accInd step z (Access f) =
60+ step z $ \y, lt => accInd step y (f y lt)
61+
62+
63+||| Use well-foundedness of a relation to write terminating operations.
64+|||
65+||| @ rel a well-founded relation
66+wfRec : WellFounded rel =>
67+ (step : (x : a) -> ((y : a) -> rel y x -> b) -> b) ->
68+ a -> b
69+wfRec {rel} step x = accRec step x (wellFounded {rel} x)
70+
71+
72+||| Use well-foundedness of a relation to write proofs
73+|||
74+||| @ rel a well-founded relation
75+||| @ P the motive for the induction
76+||| @ step the induction step: take an element and its accessibility,
77+||| and give back a demonstration of P for that element,
78+||| potentially using accessibility
79+wfInd : WellFounded rel => {P : a -> Type} ->
80+ (step : (x : a) -> ((y : a) -> rel y x -> P y) -> P x) ->
81+ (x : a) -> P x
82+wfInd {rel} step x = accInd step x (wellFounded {rel} x)
83+
libs/contrib/Data/Nat.idrnew file+165
@@ -0,0 +1,165 @@
1+||| Extra utilities for working with Nats
2+module Data.Nat
3+
4+import Data.Fin
5+import Data.So
6+
7+import Control.WellFounded
8+
9+%default total
10+
11+||| A strict less-than relation on `Nat`.
12+|||
13+||| @ n the smaller number
14+||| @ m the larger number
15+data LT' : (n,m : Nat) -> Type where
16+ ||| n < 1 + n
17+ LTSucc : LT' n (S n)
18+ ||| n < m implies that n < m + 1
19+ LTStep : LT' n m -> LT' n (S m)
20+
21+%name LT' lt, lt'
22+
23+||| Nothing is strictly less than zero
24+instance Uninhabited (LT' n 0) where
25+ uninhabited LTSucc impossible
26+
27+||| Zero is less than any non-zero number.
28+LTZeroLeast : LT' Z (S n)
29+LTZeroLeast {n = Z} = LTSucc
30+LTZeroLeast {n = S n} = LTStep LTZeroLeast
31+
32+||| If n < m, then 1 + n < 1 + m
33+ltSuccSucc : LT' n m -> LT' (S n) (S m)
34+ltSuccSucc LTSucc = LTSucc
35+ltSuccSucc (LTStep lt) = LTStep $ ltSuccSucc lt
36+
37+||| If n + 1 < m, then n < m
38+lteToLt' : LTE (S n) m -> LT' n m
39+lteToLt' {n = Z} (LTESucc x) = LTZeroLeast
40+lteToLt' {n = S k} (LTESucc x) = ltSuccSucc $ lteToLt' x
41+
42+||| Convert from LT' to LTE
43+ltToLTE : LT' n m -> LTE (S n) m
44+ltToLTE LTSucc = lteRefl
45+ltToLTE (LTStep lt) = lteSuccRight $ ltToLTE lt
46+
47+||| Subtraction gives a result that is actually smaller.
48+minusLT' : (x,y : Nat) -> x - y `LT'` S x
49+minusLT' Z y = LTSucc
50+minusLT' (S k) Z = LTSucc
51+minusLT' (S k) (S j) = LTStep (minusLT' k j)
52+
53+||| Strict less-than is well-founded, with the cascade stopping at
54+||| zero (because there's nothing less than zero). This can't be done
55+||| for LTE, because that one doesn't stop at zero (because `LTE 0 0`
56+||| is inhabited).
57+instance WellFounded LT' where
58+ wellFounded x = Access (acc x)
59+ where
60+ ||| Show accessibility by induction on the structure of the LT' witness
61+ acc : (x, y : Nat) -> LT' y x -> Accessible LT' y
62+ -- Zero is vacuously accessible: there's nothing smaller to check
63+ acc Z y lt = absurd lt
64+ -- If the element being accessed is one smaller, we're done
65+ acc (S y) y LTSucc = Access (acc y)
66+ -- If the element is more than one smaller, we need to go further
67+ acc (S k) y (LTStep smaller) = acc k y smaller
68+
69+||| The result of division on natural numbers.
70+|||
71+||| @ dividend the dividend
72+||| @ divisor the divisor
73+data DivMod : (dividend, divisor : Nat) -> Type where
74+ ||| The result of division, with a quotient and a remainder.
75+ |||
76+ ||| @ dividend the dividend
77+ ||| @ divisor the divisor
78+ ||| @ quotient the quotient
79+ ||| @ remainder the remainder (bounded by the divisor)
80+ ||| @ ok the fact that this is, in fact, a result of division
81+ DivModRes : {dividend, divisor : Nat} ->
82+ (quotient : Nat) -> (remainder : Fin divisor) ->
83+ (ok : dividend = finToNat remainder + quotient * divisor) ->
84+ DivMod dividend divisor
85+
86+
87+||| Any natural number can be a `Fin` where the bound is itself plus some difference.
88+private
89+toFin : (x : Nat) -> (diff : Nat) -> Fin (plus x (S diff))
90+toFin Z diff = FZ
91+toFin (S k) diff = FS $ toFin k diff
92+
93+||| Converting to a `Fin` and back to `Nat` preserves the input. This is a correctness proof for `toFin`.
94+private
95+toFinAndBack : (x : Nat) -> (diff : Nat) -> finToNat (toFin x diff) = x
96+toFinAndBack Z diff = Refl
97+toFinAndBack (S k) diff = cong (toFinAndBack k diff)
98+
99+
100+||| The accessibilty predicate used for division.
101+private
102+accPlusLT' : LT' (S j) (S (plus k (S j)))
103+accPlusLT' {j = Z} {k = Z} = LTSucc
104+accPlusLT' {j = Z} {k = S k} = LTStep (accPlusLT' {j = Z} {k = k})
105+accPlusLT' {j = S j} {k = k} = rewrite sym $ plusSuccRightSucc k (S j) in
106+ ltSuccSucc accPlusLT'
107+
108+
109+||| Division and modulus on `Nat`, inspired by the definition in the
110+||| Agda standard library.
111+|||
112+||| This uses well-founded recursion on `LT'`.
113+|||
114+||| @ dividend the dividend
115+||| @ divisor the divisor
116+||| @ nonzero division by zero is nonsense
117+total -- yay!
118+divMod : (dividend, divisor : Nat) ->
119+ {auto nonzero : So (not (decAsBool (decEq divisor Z)))} ->
120+ DivMod dividend divisor
121+divMod _ Z {nonzero} = absurd nonzero
122+divMod Z (S k) = DivModRes 0 FZ Refl
123+divMod (S j) (S k) {nonzero} = wfInd {P=P} stepDiv (S j) (S k) nonzero
124+ where
125+ ||| The goal passed to the accessibility eliminator.
126+ |||
127+ ||| This is responsible for generating the goal in the
128+ ||| well-founded fixed point.
129+ |||
130+ ||| @ dividend the dividend to recurse over
131+ P : (dividend : Nat) -> Type
132+ P dividend = (divisor : Nat) -> (nonzero : So (not (decAsBool (decEq divisor Z)))) -> DivMod dividend divisor
133+
134+
135+ ||| Well-founded recursion needs a recursion operator.
136+ |||
137+ ||| @ dividend the dividend we are recursing over
138+ ||| @ rec the recursive call provided by the well-founded induction operator
139+ stepDiv : (dividend : Nat) -> (rec : (d' : Nat) -> LT' d' dividend -> P d') -> P dividend
140+ -- We need not consider division by zero
141+ stepDiv dividend rec Z nonzero = absurd nonzero
142+ -- Dividing zero by anyting else gives 0, with 0 remainder
143+ stepDiv Z rec (S k) nonzero = DivModRes 0 0 Refl
144+ -- To divide two non-zero values, we must know which is larger
145+ stepDiv (S j) rec (S k) nonzero with (cmp j k)
146+ -- n / n = 1 remainder 0
147+ stepDiv (S j) rec (S j) nonzero | CmpEQ =
148+ DivModRes 1 0 (sym $ cong (plusZeroRightNeutral j))
149+ -- if n < m, then m = n + r, and the quotient is 0 with remainder r
150+ stepDiv (S j) rec (S (plus j (S diff))) nonzero | CmpLT diff =
151+ DivModRes 0 (toFin (S j) diff) $
152+ rewrite toFinAndBack j diff
153+ in sym $ cong (plusZeroRightNeutral j)
154+ -- if n > m, then n = m + d, and the quotient is 1 + ((n - m) / m) with the same remainder
155+ stepDiv (S (plus k (S diff))) rec (S k) nonzero | CmpGT diff =
156+ let res = rec (S diff) accPlusLT' (S k) Oh
157+ in case res of
158+ DivModRes quotient remainder ok =>
159+ DivModRes (S quotient) remainder $
160+ rewrite plusAssociative (finToNat remainder) (S k) (mult quotient (S k)) in
161+ rewrite plusCommutative (finToNat remainder) (S k) in
162+ rewrite sym $ plusAssociative (S k) (finToNat remainder) (mult quotient (S k)) in
163+ rewrite ok in Refl
164+
165+
libs/contrib/contrib.ipkg+2
@@ -3,9 +3,11 @@ package contrib
33opts = "--nobasepkgs --total -i ../prelude -i ../base"
44modules = Control.Algebra,
55 Control.Isomorphism.Primitives,
6+ Control.WellFounded,
67 Classes.Verified,
78 Data.Fun, Data.Rel,
89 Data.Hash, Data.Matrix,
10+ Data.Nat,
911 Data.ZZ, Data.Sign,
1012 Data.BoundedList,
1113 Data.Heap,
libs/prelude/Prelude.idr+6
@@ -31,6 +31,12 @@ import public Language.Reflection.Errors
3131%access public
3232%default total
3333
34+-- Things that can't be elsewhere for import cycle reasons
35+decAsBool : Dec p -> Bool
36+decAsBool (Yes _) = True
37+decAsBool (No _) = False
38+
39+
3440-- Show and instances
3541
3642class Show a where
libs/prelude/Prelude/Nat.idr+14
@@ -99,6 +99,9 @@ data LTE : (n, m : Nat) -> Type where
9999 ||| If n <= m, then n + 1 <= m + 1
100100 LTESucc : LTE left right -> LTE (S left) (S right)
101101
102+instance Uninhabited (LTE (S n) Z) where
103+ uninhabited LTEZero impossible
104+
102105||| Greater than or equal to
103106total GTE : Nat -> Nat -> Type
104107GTE left right = LTE right left
@@ -127,6 +130,17 @@ isLTE (S k) (S j) with (isLTE k j)
127130 isLTE (S k) (S j) | (Yes prf) = Yes (LTESucc prf)
128131 isLTE (S k) (S j) | (No contra) = No (contra . fromLteSucc)
129132
133+||| `LTE` is reflexive.
134+lteRefl : LTE n n
135+lteRefl {n = Z} = LTEZero
136+lteRefl {n = S k} = LTESucc lteRefl
137+
138+||| n < m implies n < m + 1
139+lteSuccRight : LTE n m -> LTE n (S m)
140+lteSuccRight LTEZero = LTEZero
141+lteSuccRight (LTESucc x) = LTESucc (lteSuccRight x)
142+
143+
130144||| Boolean test than one Nat is less than or equal to another
131145total lte : Nat -> Nat -> Bool
132146lte Z right = True