1 | module Data.Nat.Division
3 | import Syntax.WithProof
4 | import Syntax.PreorderReasoning
5 | import Syntax.PreorderReasoning.Generic
7 | import Data.Nat.Equational
8 | import Data.Nat.Order.Strict
9 | import Data.Nat.Order.Properties
10 | import Decidable.Order.Strict
12 | import Data.Nat.Properties
20 | fuelLemma : (numer, predDenom , fuel : Nat)
21 | -> (enoughFuel : numer `LTE` (S fuel))
22 | -> (numer `minus` (S predDenom)) `LTE` fuel
23 | fuelLemma Z predDenom fuel enoughFuel = LTEZero
24 | fuelLemma (S numer) (S denom) fuel enoughFuel =
25 | fuelLemma numer denom fuel $
lteSuccLeft enoughFuel
26 | fuelLemma (S numer) Z fuel enoughFuel =
27 | rewrite minusZeroRight numer in fromLteSucc enoughFuel
32 | div'' : (fuel, numer, denom : Nat) -> Nat
33 | div'' fuel numer denom = fst (divmod' fuel numer denom)
35 | mod'' : (fuel, numer, denom : Nat) -> Nat
36 | mod'' fuel numer denom = snd (divmod' fuel numer denom)
39 | divmod'_eq_div'_mod' : (fuel, numer, denom : Nat)
40 | -> (divmod' fuel numer denom) = (div' fuel numer denom, mod' fuel numer denom)
41 | divmod'_eq_div'_mod' 0 numer denom = Refl
42 | divmod'_eq_div'_mod' (S fuel) numer denom with (Data.Nat.lte numer denom)
43 | divmod'_eq_div'_mod' (S fuel) numer denom | True = Refl
44 | divmod'_eq_div'_mod' (S fuel) numer denom | False =
45 | rewrite divmod'_eq_div'_mod' fuel (numer `minus` (S denom)) denom in
48 | div''_eq_div' : (fuel, numer, denom : Nat)
49 | -> div'' fuel numer denom = div' fuel numer denom
50 | div''_eq_div' fuel numer denom = cong fst $
51 | divmod'_eq_div'_mod' fuel numer denom
53 | mod''_eq_mod' : (fuel, numer, denom : Nat)
54 | -> mod'' fuel numer denom = mod' fuel numer denom
55 | mod''_eq_mod' fuel numer denom = cong snd $
56 | divmod'_eq_div'_mod' fuel numer denom
59 | divmodNatNZeqDivMod : (numer, denom : Nat) -> (0 prf1, prf2, prf3 : NonZero denom)
60 | -> (divmodNatNZ numer denom prf1) = (divNatNZ numer denom prf2, modNatNZ numer denom prf3)
61 | divmodNatNZeqDivMod numer (S denom) prf1 prf2 prf3 = divmod'_eq_div'_mod' numer numer denom
64 | fstDivmodNatNZeqDiv : (numer, denom : Nat) -> (0 prf1, prf2 : NonZero denom)
65 | -> (fst $
divmodNatNZ numer denom prf1) = divNatNZ numer denom prf2
66 | fstDivmodNatNZeqDiv numer denom prf1 prf2 =
67 | rewrite divmodNatNZeqDivMod numer denom prf1 prf2 prf2 in
71 | sndDivmodNatNZeqMod : (numer, denom : Nat) -> (0 prf1, prf2 : NonZero denom)
72 | -> (snd $
divmodNatNZ numer denom prf1) = modNatNZ numer denom prf2
73 | sndDivmodNatNZeqMod numer denom prf1 prf2 =
74 | rewrite divmodNatNZeqDivMod numer denom prf1 prf2 prf2 in
79 | bound_mod'' : (fuel, numer, predDenom : Nat) -> (numer `LTE` fuel)
80 | -> (mod'' fuel numer predDenom) `LTE` predDenom
81 | bound_mod'' 0 0 predDenom LTEZero = LTEZero
82 | bound_mod'' (S fuel) numer predDenom enough = case @@(Data.Nat.lte numer predDenom) of
83 | (
True ** numer_lte_predn)
=> rewrite numer_lte_predn in
84 | Properties.lteIsLTE _ _ numer_lte_predn
85 | (
False ** numer_gte_n )
=> rewrite numer_gte_n in
86 | bound_mod'' fuel (numer `minus` (S predDenom)) predDenom
87 | (fuelLemma numer predDenom fuel enough)
90 | boundModNatNZ : (numer, denom : Nat) -> (0 denom_nz : NonZero denom)
91 | -> (modNatNZ numer denom denom_nz) `LT` denom
92 | boundModNatNZ numer (S predDenom) denom_nz =
94 | rewrite sym $
mod''_eq_mod' numer numer predDenom in
95 | bound_mod'' numer numer predDenom $
reflexive
96 | divisionTheorem' : (numer, predDenom : Nat)
97 | -> (fuel : Nat) -> (enough : numer `LTE` fuel)
98 | -> numer = (mod'' fuel numer predDenom) + (div'' fuel numer predDenom) * (S predDenom)
100 | divisionTheorem' 0 predDenom 0 LTEZero = Refl
101 | divisionTheorem' numer predDenom (S fuel) enough with (@@(Data.Nat.lte numer predDenom))
102 | divisionTheorem' numer predDenom (S fuel) enough | (
True ** prf)
104 | rewrite plusZeroRightNeutral numer in Refl
105 | divisionTheorem' numer predDenom (S fuel) enough | (
False ** prf)
108 | denom = S predDenom
110 | numer' = numer `minus` denom
111 | denom_lte_numer : denom `LTE` numer
112 | denom_lte_numer = Properties.notlteIsLT numer predDenom prf
113 | enough' : numer' `LTE` fuel
114 | enough' = fuelLemma numer predDenom fuel enough
116 | inductionHypothesis : (numer'
117 | = (mod'' fuel numer' predDenom) + (div'' fuel numer' predDenom) * denom)
118 | inductionHypothesis = divisionTheorem' numer' predDenom fuel enough'
120 | |~ (mod'' fuel numer' predDenom) + (denom + (div'' fuel numer' predDenom) * denom)
121 | ~~ (mod'' fuel numer' predDenom) + ((div'' fuel numer' predDenom) * denom + denom)
122 | ...(cong ((mod'' fuel numer' predDenom) +) $
plusCommutative
124 | ((div'' fuel numer' predDenom) * denom))
125 | ~~((mod'' fuel numer' predDenom) + (div'' fuel numer' predDenom) * denom) + denom
126 | ...(plusAssociative
127 | (mod'' fuel numer' predDenom)
128 | ((div'' fuel numer' predDenom) * denom)
130 | ~~ numer' + denom ...(cong (+ denom) $
sym inductionHypothesis)
131 | ~~ numer ...(plusMinusLte denom numer denom_lte_numer)
136 | DivisionTheoremDivMod : (numer, denom : Nat) -> (0 prf : NonZero denom)
137 | -> numer = snd ( divmodNatNZ numer denom prf)
138 | + (fst $
divmodNatNZ numer denom prf)*denom
139 | DivisionTheoremDivMod numer (S predDenom) prf
140 | = divisionTheorem' numer predDenom numer reflexive
143 | DivisionTheorem : (numer, denom : Nat) -> (0 prf1, prf2 : NonZero denom)
144 | -> numer = (modNatNZ numer denom prf1) + (divNatNZ numer denom prf2)*denom
145 | DivisionTheorem numer denom prf1 prf2
146 | = rewrite sym $
fstDivmodNatNZeqDiv numer denom prf1 prf2 in
147 | rewrite sym $
sndDivmodNatNZeqMod numer denom prf1 prf1 in
148 | DivisionTheoremDivMod numer denom prf1
152 | divmodZeroZero : (denom, fuel : Nat)
153 | -> divmod' fuel 0 denom = (0,0)
154 | divmodZeroZero denom 0 = Refl
155 | divmodZeroZero denom (S fuel) = Refl
157 | modZeroZero : (denom, fuel : Nat)
158 | -> mod'' fuel 0 denom = 0
159 | modZeroZero denom fuel = rewrite divmodZeroZero denom fuel in Refl
161 | divZeroZero : (denom, fuel : Nat)
162 | -> div'' fuel 0 denom = 0
163 | divZeroZero denom fuel = rewrite divmodZeroZero denom fuel in Refl
166 | divmodFuelLemma : (numer, denom, fuel1, fuel2 : Nat)
167 | -> (enough1 : fuel1 `GTE` numer)
168 | -> (enough2 : fuel2 `GTE` numer)
169 | -> divmod' fuel1 numer denom = divmod' fuel2 numer denom
170 | divmodFuelLemma 0 denom 0 fuel2 LTEZero enough2 = rewrite divmodZeroZero denom fuel2 in
172 | divmodFuelLemma 0 denom (S fuel1) 0 enough1 LTEZero = Refl
173 | divmodFuelLemma numer denom (S fuel1) (S fuel2) enough1 enough2 with (@@(Data.Nat.lte numer denom))
174 | divmodFuelLemma numer denom (S fuel1) (S fuel2) enough1 enough2 | (
True ** prf)
=
175 | rewrite prf in Refl
176 | divmodFuelLemma numer denom (S fuel1) (S fuel2) enough1 enough2 | (
False ** prf)
=
178 | rewrite divmodFuelLemma (numer `minus` (S denom)) denom fuel1 fuel2
179 | (fuelLemma numer denom fuel1 enough1)
180 | (fuelLemma numer denom fuel2 enough2) in
184 | multiplicationLemma : (q, predn, r : Nat) -> q * (S predn) + r `LTE` 0 -> (q = 0, r = 0)
185 | multiplicationLemma q predn r bound =
186 | let r_eq_z : (r = 0)
187 | r_eq_z = zeroPlusRightZero (q * (S predn)) r (sym $
lteZeroIsZero bound)
188 | qn_eq_z : (q * (S predn) = 0)
189 | qn_eq_z = zeroPlusLeftZero (q * (S predn)) r (sym $
lteZeroIsZero bound)
191 | q_eq_z = case zeroMultEitherZero q (S predn) qn_eq_z of
192 | Left q_eq_0 => q_eq_0
193 | Right spred_eq_z impossible
194 | in (q_eq_z, r_eq_z)
196 | multiplesModuloZero : (fuel, predn, k : Nat)
197 | -> (enough : fuel `GTE` k * (S predn) )
198 | -> mod' fuel (k * (S predn)) predn = 0
199 | multiplesModuloZero 0 predn k enough =
200 | let (k_eq_z, _) = multiplicationLemma k predn 0 $
201 | rewrite plusZeroRightNeutral (k * (S predn)) in
203 | in rewrite k_eq_z in
205 | multiplesModuloZero (S fuel) predn 0 enough = Refl
206 | multiplesModuloZero (S fuel) predn (S k) enough =
209 | n_lte_skn : n `LTE` (1 + k)*n
210 | n_lte_skn = CalcWith {leq = LTE} $
212 | ~~ n + 0 ...(sym $
plusZeroRightNeutral n)
213 | ~~ (1 + 0)*n ...(Refl)
214 | <~ (1 + k)*n ...(multLteMonotoneLeft (1+0) (1+k) n $
215 | plusLteMonotoneLeft 1 0 k LTEZero)
216 | in case @@(Data.Nat.lte ((1 + k)*n) predn) of
217 | (
True ** skn_lte_predn)
=> absurd $
irreflexive {rel = Data.Nat.LT}
218 | $
CalcWith {leq = LTE} $
221 | ~~ n + 0 ...(sym $
plusZeroRightNeutral n)
222 | ~~ (1 + 0)*n ...(Refl)
223 | <~ (1 + k)*n ...(multLteMonotoneLeft (1+0) (1+k) n $
225 | <~ predn ...(Properties.lteIsLTE _ _ skn_lte_predn)
228 | let skn_minus_n_eq_kn : ((1 + k)*n `minus` n = k*n)
229 | skn_minus_n_eq_kn = Calc $
230 | |~ ((1+k)*n `minus` n)
231 | ~~ ((1+k)*n `minus` (n + 0)) ...(cong ((1+k)*n `minus`) $
sym $
plusZeroRightNeutral n)
232 | ~~ (n + k*n `minus` (n + 0)) ...(Refl)
233 | ~~ (k*n `minus` 0) ...(plusMinusLeftCancel n (k*n) 0)
234 | ~~ k*n ...(minusZeroRight (k*n))
235 | in rewrite skn_minus_n_eq_kn in
236 | multiplesModuloZero fuel predn k $
237 | (rewrite sym $
skn_minus_n_eq_kn in
238 | fuelLemma ((1 + k)*n) predn fuel enough)
242 | addMultipleMod': (fuel1, fuel2, predn, a, b : Nat) -> (enough1 : fuel1 `GTE` b * (S predn) + a)
243 | -> (enough2 : fuel2 `GTE` a)
244 | -> mod'' fuel1 (b * (S predn) + a) predn = mod'' fuel2 a predn
245 | addMultipleMod' 0 fuel2 predn a b enough1 enough2
246 | = let (b_eq_z, a_eq_z) = multiplicationLemma b predn a enough1
247 | in rewrite a_eq_z in
249 | rewrite modZeroZero predn fuel2 in
251 | addMultipleMod' fuel1@(S _) fuel2 predn a 0 enough1 enough2 =
252 | rewrite divmodFuelLemma a predn fuel1 fuel2 enough1 enough2 in
254 | addMultipleMod' (S fuel1) fuel2 predn a (S k) enough1 enough2 =
257 | lhsarg_geq_predn : ((1 + k)*n + a) `GT` predn
258 | lhsarg_geq_predn = CalcWith {leq = LTE} $
260 | ~~ (1+0)*n ...(sym $
plusZeroRightNeutral n)
261 | <~ (1+k)*n ...(multLteMonotoneLeft 1 (1+k) n $
263 | <~ (1+k)*n + a ...(lteAddRight $
(1+k)*n)
264 | prf1 : lte ((1 + k)*n + a) predn = False
265 | prf1 = GTIsnotlte ((1 + k)*n + a) predn lhsarg_geq_predn
266 | argsimplify : (((1 + k) *n + a ) `minus` n = k*n + a)
267 | argsimplify = Calc $
268 | |~ (((1+k)*n + a) `minus` n)
269 | ~~ (((n + k*n) + a) `minus` n) ...(Refl)
270 | ~~ ((n + (k*n + a)) `minus` (n + 0)) ...(cong2 minus
271 | (sym $
plusAssociative n (k*n) a)
272 | (sym $
plusZeroRightNeutral n))
273 | ~~ ((k*n + a) `minus` 0) ...(plusMinusLeftCancel n (k*n + a) 0)
274 | ~~ k*n + a ...(minusZeroRight (k*n + a))
276 | rewrite argsimplify in
277 | addMultipleMod' fuel1 fuel2 predn a k
278 | (rewrite sym argsimplify in
279 | fuelLemma ((1+k)*n + a) predn fuel1 enough1)
282 | addMultipleMod : (a, b, n : Nat) -> (0 n_neq_z1, n_neq_z2 : NonZero n)
283 | -> snd (divmodNatNZ (a*n + b) n n_neq_z1) = snd (divmodNatNZ b n n_neq_z2)
284 | addMultipleMod a b n@(S predn) n_neq_z1 n_neq_z2 =
285 | addMultipleMod' (a*n + b) b predn b a reflexive reflexive
287 | modBelowDenom : (r, n : Nat) -> (0 n_neq_z : NonZero n)
289 | -> snd (divmodNatNZ r n n_neq_z) = r
290 | modBelowDenom 0 (S predn) n_neq_0 (LTESucc r_lte_predn) = Refl
291 | modBelowDenom r@(S _) (S predn) n_neq_0 (LTESucc r_lte_predn) =
292 | rewrite LteIslte r predn r_lte_predn in
295 | modInjective : (r1, r2, n : Nat) -> (0 n_neq_z1, n_neq_z2 : NonZero n)
298 | -> snd (divmodNatNZ r1 n n_neq_z1) = snd (divmodNatNZ r2 n n_neq_z2)
300 | modInjective r1 r2 n n_neq_z1 n_neq_z2 r1_lt_n r2_lt_n ri_mod_eq = Calc $
302 | ~~ snd (divmodNatNZ r1 n n_neq_z1) ...(sym $
modBelowDenom r1 n n_neq_z1 r1_lt_n)
303 | ~~ snd (divmodNatNZ r2 n n_neq_z2) ...(ri_mod_eq)
304 | ~~ r2 ...( modBelowDenom r2 n n_neq_z2 r2_lt_n)
307 | step1 : (numer : Nat) -> (denom : Nat) -> (0 denom_nz : NonZero denom)
308 | -> (q, r : Nat) -> (r `LT` denom) -> (numer = q * denom + r)
309 | -> snd (divmodNatNZ numer denom denom_nz) = r
310 | step1 x n n_nz q r r_lt_n x_eq_qnpr = Calc $
311 | |~ snd(divmodNatNZ x n n_nz)
312 | ~~ snd(divmodNatNZ (q*n + r) n n_nz) ...(cong (\u => snd $
divmodNatNZ u n n_nz) $
x_eq_qnpr)
313 | ~~ snd(divmodNatNZ r n n_nz) ...(addMultipleMod q r n n_nz n_nz)
314 | ~~ r ...(modBelowDenom r n n_nz r_lt_n)
316 | step2 : (numer : Nat) -> (denom : Nat) -> (0 denom_nz : NonZero denom)
317 | -> (q, r : Nat) -> (r `LT` denom) -> (numer = q * denom + r)
318 | -> fst (divmodNatNZ numer denom denom_nz) = q
319 | step2 x n n_nz q r r_lt_n x_eq_qnr =
320 | let mod_eq_r : (snd (divmodNatNZ x n n_nz) = r)
321 | mod_eq_r = step1 x n n_nz q r r_lt_n x_eq_qnr
323 | two_decompositions : (fst $
divmodNatNZ x n n_nz) * n + r = q * n + r
324 | two_decompositions = Calc $
325 | |~ (fst $
divmodNatNZ x n n_nz) * n + r
326 | ~~ (fst $
divmodNatNZ x n n_nz) * n + (snd $
divmodNatNZ x n n_nz)
328 | (fst $
divmodNatNZ x n n_nz)* n + u)
330 | ~~ snd(divmodNatNZ x n n_nz) + fst (divmodNatNZ x n n_nz) * n
331 | ...(plusCommutative _ _)
332 | ~~ x ...(sym $
DivisionTheoremDivMod x n n_nz)
333 | ~~ q*n + r ...(x_eq_qnr)
335 | in multRightCancel (fst $
divmodNatNZ x n n_nz) q n n_nz
336 | $
plusRightCancel ((fst $
divmodNatNZ x n n_nz)* n) (q*n) r
337 | $
two_decompositions
340 | DivisionTheoremUniquenessDivMod : (numer : Nat) -> (denom : Nat) -> (0 denom_nz : NonZero denom)
341 | -> (q, r : Nat) -> (r `LT` denom) -> (numer = q * denom + r)
342 | -> divmodNatNZ numer denom denom_nz = (q, r)
343 | DivisionTheoremUniquenessDivMod numer denom denom_nz q r x prf =
344 | rewrite sym $
step1 numer denom denom_nz q r x prf in
345 | rewrite sym $
step2 numer denom denom_nz q r x prf in
350 | pair_eta : (x : (a,b)) -> x = (fst x, snd x)
351 | pair_eta (x,y) = Refl
354 | DivisionTheoremUniqueness : (numer : Nat) -> (denom : Nat) -> (0 denom_nz : NonZero denom)
355 | -> (q, r : Nat) -> (r `LT` denom) -> (numer = q * denom + r)
356 | -> (divNatNZ numer denom denom_nz = q, modNatNZ numer denom denom_nz = r)
357 | DivisionTheoremUniqueness numer denom denom_nz q r x prf =
358 | rewrite sym $
fstDivmodNatNZeqDiv numer denom denom_nz denom_nz in
359 | rewrite sym $
sndDivmodNatNZeqMod numer denom denom_nz denom_nz in
360 | rewrite DivisionTheoremUniquenessDivMod numer denom denom_nz q r x prf in
364 | modDividendMinusDivMultDivider : (0 numer, denom : Nat) -> {auto 0 denom_nz : NonZero denom} ->
365 | modNatNZ numer denom denom_nz = numer `minus` divNatNZ numer denom denom_nz * denom
366 | modDividendMinusDivMultDivider numer denom = Calc $
367 | |~ (modNatNZ numer denom denom_nz)
368 | ~~ (divNatNZ numer denom denom_nz * denom + modNatNZ numer denom denom_nz `minus` divNatNZ numer denom denom_nz * denom)
369 | ...(sym $
minusPlus $
divNatNZ numer denom denom_nz * denom)
370 | ~~ (modNatNZ numer denom denom_nz + divNatNZ numer denom denom_nz * denom `minus` divNatNZ numer denom denom_nz * denom)
371 | ...(rewrite plusCommutative (divNatNZ numer denom denom_nz * denom) (modNatNZ numer denom denom_nz)
373 | ~~ (numer `minus` divNatNZ numer denom denom_nz * denom)
374 | ...(sym $
cong (`minus` (divNatNZ numer denom denom_nz * denom))
375 | (DivisionTheorem numer denom denom_nz denom_nz))