-
Notifications
You must be signed in to change notification settings - Fork 378
/
Factor.idr
474 lines (427 loc) · 21 KB
/
Factor.idr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
module Data.Nat.Factor
import Syntax.PreorderReasoning
import Control.WellFounded
import Data.Fin
import Data.Fin.Extra
import Data.Nat
import Data.Nat.Order.Properties
import Data.Nat.Equational
import Data.Nat.Division
%default total
||| Factor n p is a witness that p is indeed a factor of n,
||| i.e. there exists a q such that p * q = n.
public export
data Factor : Nat -> Nat -> Type where
CofactorExists : {p, n : Nat} -> (q : Nat) -> n = p * q -> Factor p n
||| NotFactor n p is a witness that p is NOT a factor of n,
||| i.e. there exist a q and an r, greater than 0 but smaller than p,
||| such that p * q + r = n.
public export
data NotFactor : Nat -> Nat -> Type where
ZeroNotFactorS : (n : Nat) -> NotFactor Z (S n)
ProperRemExists : {p, n : Nat} -> (q : Nat) ->
(r : Fin (pred p)) ->
n = p * q + S (finToNat r) ->
NotFactor p n
||| DecFactor n p is a result of the process which decides
||| whether or not p is a factor on n.
public export
data DecFactor : Nat -> Nat -> Type where
ItIsFactor : Factor p n -> DecFactor p n
ItIsNotFactor : NotFactor p n -> DecFactor p n
||| CommonFactor n m p is a witness that p is a factor of both n and m.
public export
data CommonFactor : Nat -> Nat -> Nat -> Type where
CommonFactorExists : {a, b : Nat} -> (p : Nat) -> Factor p a -> Factor p b -> CommonFactor p a b
||| GCD n m p is a witness that p is THE greatest common factor of both n and m.
||| The second argument to the constructor is a function which for all q being
||| a factor of both n and m, proves that q is a factor of p.
|||
||| This is equivalent to a more straightforward definition, stating that for
||| all q being a factor of both n and m, q is less than or equal to p, but more
||| powerful and therefore more useful for further proofs. See below for a proof
||| that if q is a factor of p then q must be less than or equal to p.
public export
data GCD : Nat -> Nat -> Nat -> Type where
MkGCD : {a, b, p : Nat} ->
{auto notBothZero : NotBothZero a b} ->
(Lazy (CommonFactor p a b)) ->
((q : Nat) -> CommonFactor q a b -> Factor q p) ->
GCD p a b
Uninhabited (Factor Z (S n)) where
uninhabited (CofactorExists q prf) = uninhabited prf
||| Given a statement that p is factor of n, return its cofactor.
export
cofactor : Factor p n -> (q : Nat ** Factor q n)
cofactor (CofactorExists q prf) =
(q ** CofactorExists p $ rewrite multCommutative q p in prf)
||| 1 is a factor of any natural number.
export
oneIsFactor : (n : Nat) -> Factor 1 n
oneIsFactor Z = CofactorExists Z Refl
oneIsFactor (S k) = CofactorExists (S k) (rewrite plusZeroRightNeutral k in Refl)
||| 1 is the only factor of itself
export
oneSoleFactorOfOne : (a : Nat) -> Factor a 1 -> a = 1
oneSoleFactorOfOne 0 (CofactorExists _ prf) = sym prf
oneSoleFactorOfOne 1 _ = Refl
oneSoleFactorOfOne (S (S k)) (CofactorExists Z prf) =
absurd . uninhabited $ trans prf $ multCommutative k 0
oneSoleFactorOfOne (S (S k)) (CofactorExists (S j) prf) =
absurd . uninhabited $
trans
(injective prf)
(plusCommutative j (S (j + (k * S j))))
||| Every natural number is factor of itself.
export
Reflexive Nat Factor where
reflexive = CofactorExists 1 $ rewrite multOneRightNeutral x in Refl
||| Factor relation is transitive. If b is factor of a and c is b factor of c
||| is also a factor of a.
export
Transitive Nat Factor where
transitive (CofactorExists qb prfAB) (CofactorExists qc prfBC) =
CofactorExists (qb * qc) $
rewrite prfBC in
rewrite prfAB in
rewrite multAssociative x qb qc in
Refl
export
Preorder Nat Factor where
multOneSoleNeutral : (a, b : Nat) -> S a = S a * b -> b = 1
multOneSoleNeutral Z b prf =
rewrite sym $ plusZeroRightNeutral b in
sym prf
multOneSoleNeutral (S k) Z prf =
absurd . uninhabited $ trans prf $ multCommutative k 0
multOneSoleNeutral (S k) (S Z) prf = Refl
multOneSoleNeutral (S k) (S (S j)) prf =
absurd . uninhabited .
subtractEqLeft k {c = S j + S (j + (k * S j))} $
rewrite plusSuccRightSucc j (S (j + (k * S j))) in
rewrite plusZeroRightNeutral k in
rewrite plusAssociative k j (S (S (j + (k * S j)))) in
rewrite sym $ plusCommutative j k in
rewrite sym $ plusAssociative j k (S (S (j + (k * S j)))) in
rewrite sym $ plusSuccRightSucc k (S (j + (k * S j))) in
rewrite sym $ plusSuccRightSucc k (j + (k * S j)) in
rewrite plusAssociative k j (k * S j) in
rewrite plusCommutative k j in
rewrite sym $ plusAssociative j k (k * S j) in
rewrite sym $ multRightSuccPlus k (S j) in
injective $ injective prf
||| If a is a factor of b and b is a factor of a, then a = b.
public export
Antisymmetric Nat Factor where
antisymmetric {x = Z} (CofactorExists _ prfAB) _ = sym prfAB
antisymmetric {y = Z} _ (CofactorExists _ prfBA) = prfBA
antisymmetric {x = S a} {y = S _} (CofactorExists qa prfAB) (CofactorExists qb prfBA) =
let qIs1 = multOneSoleNeutral a (qa * qb) $
rewrite multAssociative (S a) qa qb in
rewrite sym prfAB in
prfBA
in
rewrite prfAB in
rewrite oneSoleFactorOfOne qa . CofactorExists qb $ sym qIs1 in
rewrite multOneRightNeutral a in
Refl
PartialOrder Nat Factor where
||| No number can simultaneously be and not be a factor of another number.
export
factorNotFactorAbsurd : Factor p n -> Not (NotFactor p n)
factorNotFactorAbsurd (CofactorExists _ prf) (ZeroNotFactorS _) =
uninhabited prf
factorNotFactorAbsurd (CofactorExists q prf) (ProperRemExists q' r contra) with (cmp q q')
factorNotFactorAbsurd (CofactorExists q prf) (ProperRemExists (q + S d) r contra) | CmpLT d =
SIsNotZ .
subtractEqLeft (p * q) {b = S ((p * S d) + finToNat r)} $
rewrite plusZeroRightNeutral (p * q) in
rewrite plusSuccRightSucc (p * S d) (finToNat r) in
rewrite plusAssociative (p * q) (p * S d) (S (finToNat r)) in
rewrite sym $ multDistributesOverPlusRight p q (S d) in
rewrite sym contra in
rewrite sym prf in
Refl
factorNotFactorAbsurd (CofactorExists q prf) (ProperRemExists q r contra) | CmpEQ =
SIsNotZ $ sym $
plusLeftCancel (p * q) 0 (S (finToNat r)) $
trans (plusZeroRightNeutral (p * q)) $
trans (sym prf) contra
factorNotFactorAbsurd (CofactorExists (q + S d) prf) (ProperRemExists q r contra) | CmpGT d =
let srEQpPlusPD = the (p + (p * d) = S (finToNat r)) $
rewrite sym $ multRightSuccPlus p d in
subtractEqLeft (p * q) $
rewrite sym $ multDistributesOverPlusRight p q (S d) in
rewrite sym contra in
sym prf
in
case p of
Z => uninhabited srEQpPlusPD
(S k) =>
succNotLTEzero .
subtractLteLeft k {b = S (d + (k * d))} $
rewrite sym $ plusSuccRightSucc k (d + (k * d)) in
rewrite plusZeroRightNeutral k in
rewrite srEQpPlusPD in
elemSmallerThanBound r
||| Anything is a factor of 0.
export
anythingFactorZero : (a : Nat) -> Factor a 0
anythingFactorZero a = CofactorExists 0 (sym $ multZeroRightZero a)
||| For all natural numbers p and q, p is a factor of (p * q).
export
multFactor : (p, q : Nat) -> Factor p (p * q)
multFactor p q = CofactorExists q Refl
||| If n > 0 then any factor of n must be less than or equal to n.
export
factorLteNumber : Factor p n -> {auto positN : LTE 1 n} -> LTE p n
factorLteNumber (CofactorExists Z prf) =
let nIsZero = trans prf $ multCommutative p 0
oneLteZero = replace {p = LTE 1} nIsZero positN
in
absurd $ succNotLTEzero oneLteZero
factorLteNumber (CofactorExists (S k) prf) =
rewrite prf in
leftFactorLteProduct p k
||| If p is a factor of n, then it is also a factor of (n + p).
export
plusDivisorAlsoFactor : Factor p n -> Factor p (n + p)
plusDivisorAlsoFactor (CofactorExists q prf) =
CofactorExists (S q) $
rewrite plusCommutative n p in
rewrite multRightSuccPlus p q in
cong (plus p) prf
||| If p is NOT a factor of n, then it also is NOT a factor of (n + p).
export
plusDivisorNeitherFactor : NotFactor p n -> NotFactor p (n + p)
plusDivisorNeitherFactor (ZeroNotFactorS k) =
rewrite plusZeroRightNeutral k in
ZeroNotFactorS k
plusDivisorNeitherFactor (ProperRemExists q r remPrf) =
ProperRemExists (S q) r $
rewrite multRightSuccPlus p q in
rewrite sym $ plusAssociative p (p * q) (S $ finToNat r) in
rewrite plusCommutative p ((p * q) + S (finToNat r)) in
rewrite remPrf in
Refl
||| If p is a factor of n, then it is also a factor of any multiply of n.
export
multNAlsoFactor : Factor p n -> (a : Nat) -> {auto aok : LTE 1 a} -> Factor p (n * a)
multNAlsoFactor _ Z = absurd $ succNotLTEzero aok
multNAlsoFactor (CofactorExists q prf) (S a) =
CofactorExists (q * S a) $
rewrite prf in
sym $ multAssociative p q (S a)
||| If p is a factor of both n and m, then it is also a factor of their sum.
export
plusFactor : Factor p n -> Factor p m -> Factor p (n + m)
plusFactor (CofactorExists qn prfN) (CofactorExists qm prfM) =
rewrite prfN in
rewrite prfM in
rewrite sym $ multDistributesOverPlusRight p qn qm in
multFactor p (qn + qm)
||| If p is a factor of a sum (n + m) and a factor of n, then it is also
||| a factor of m. This could be expressed more naturally with minus, but
||| it would be more difficult to prove, since minus lacks certain properties
||| that one would expect from decent subtraction.
export
minusFactor : {b : Nat} -> Factor p (a + b) -> Factor p a -> Factor p b
minusFactor (CofactorExists qab prfAB) (CofactorExists qa prfA) =
CofactorExists (minus qab qa) $
rewrite multDistributesOverMinusRight p qab qa in
rewrite sym prfA in
rewrite sym prfAB in
replace {p = \x => b = minus (a + b) x} (plusZeroRightNeutral a) $
rewrite plusMinusLeftCancel a b 0 in
rewrite minusZeroRight b in
Refl
||| If p is a common factor of n and mod m n, then it is also a factor of m.
export
modFactorAlsoFactorOfDivider : {m, n, p : Nat} -> {auto 0 nNotZ : NonZero n} -> Factor p n -> Factor p (modNatNZ m n nNotZ) -> Factor p m
modFactorAlsoFactorOfDivider (CofactorExists qn prfN) (CofactorExists qModMN prfModMN) =
CofactorExists (qModMN + divNatNZ m n nNotZ * qn) $ Calc $
|~ m
~~ modNatNZ m n nNotZ + divNatNZ m n nNotZ * n ...(DivisionTheorem m n nNotZ nNotZ)
~~ qModMN * p + divNatNZ m n nNotZ * (qn * p)
...(rewrite multCommutative qModMN p in
rewrite multCommutative qn p in
cong2 (+) prfModMN $ cong ((*) (divNatNZ m n nNotZ)) prfN)
~~ qModMN * p + (divNatNZ m n nNotZ * qn) * p
...(cong ((+) (qModMN * p)) $ multAssociative (divNatNZ m n nNotZ) qn p)
~~ (qModMN + divNatNZ m n nNotZ * qn) * p ...(sym $ multDistributesOverPlusLeft qModMN _ p)
~~ p * (qModMN + divNatNZ m n nNotZ * qn) ...(multCommutative _ p)
||| If p is a common factor of m and n, then it is also a factor of their mod.
export
commonFactorAlsoFactorOfMod : {0 m, n, p : Nat} -> {auto 0 nNotZ : NonZero n} -> Factor p m -> Factor p n -> Factor p (modNatNZ m n nNotZ)
commonFactorAlsoFactorOfMod (CofactorExists qm prfM) (CofactorExists qn prfN) =
CofactorExists (qm `minus` divNatNZ (qm * p) n nNotZ * qn) $
rewrite prfM in
rewrite multCommutative p qm
in Calc $
|~ (modNatNZ (qm * p) n nNotZ)
~~ (qm * p `minus` divNatNZ (qm * p) n nNotZ * n) ...(modDividendMinusDivMultDivider (qm * p) n)
~~ (qm * p `minus` divNatNZ (qm * p) n nNotZ * (qn * p))
...(rewrite multCommutative qn p in
cong (\v => qm * p `minus` divNatNZ (qm * p) n nNotZ * v) prfN)
~~ (qm * p `minus` divNatNZ (qm * p) n nNotZ * qn * p)
...(cong (minus (qm * p)) $ multAssociative (divNatNZ (qm * p) n nNotZ) qn p)
~~ (qm `minus` (divNatNZ (qm * p) n nNotZ * qn)) * p
...(sym $ multDistributesOverMinusLeft qm (divNatNZ (qm * p) n nNotZ * qn) p)
~~ p * (qm `minus` (divNatNZ (qm * p) n nNotZ * qn)) ...(multCommutative _ p)
||| A decision procedure for whether of not p is a factor of n.
export
decFactor : (n, d : Nat) -> DecFactor d n
decFactor Z Z = ItIsFactor $ reflexive
decFactor (S k) Z = ItIsNotFactor $ ZeroNotFactorS k
decFactor n (S d) =
let Fraction n (S d) q r prf = Data.Fin.Extra.divMod n (S d) in
case r of
FZ =>
ItIsFactor $ CofactorExists q $
rewrite sym prf in
rewrite plusCommutative (q * (S d)) 0 in
multCommutative q (S d)
(FS pr) =>
ItIsNotFactor $ ProperRemExists q pr (
rewrite multCommutative d q in
rewrite sym $ multRightSuccPlus q d in
sym prf
)
||| For all p greater than 1, if p is a factor of n, then it is NOT a factor
||| of (n + 1).
export
factNotSuccFact : {p : Nat} -> GT p 1 -> Factor p n -> NotFactor p (S n)
factNotSuccFact {p = Z} pGt1 (CofactorExists q prf) =
absurd $ succNotLTEzero pGt1
factNotSuccFact {p = S Z} pGt1 (CofactorExists q prf) =
absurd . succNotLTEzero $ fromLteSucc pGt1
factNotSuccFact {p = S (S k)} pGt1 (CofactorExists q prf) =
ProperRemExists q FZ (
rewrite sym prf in
rewrite plusCommutative n 1 in
Refl
)
using (p : Nat)
||| The relation of common factor is symmetric, that is if p is a
||| common factor of n and m, then it is also a common factor of
||| m and n.
public export
Symmetric Nat (CommonFactor p) where
symmetric (CommonFactorExists p pfx pfy) = CommonFactorExists p pfy pfx
||| The relation of greatest common divisor is symmetric.
public export
Symmetric Nat (GCD p) where
symmetric {x = Z} {y = Z} (MkGCD _ _) impossible
symmetric {x = S _} (MkGCD cf greatest) =
MkGCD (symmetric cf) $ \q, cf => greatest q $ symmetric cf
symmetric {y = S _} (MkGCD cf greatest) =
MkGCD (symmetric cf) $ \q, cf => greatest q $ symmetric cf
||| If p is a common factor of a and b, then it is also a factor of their GCD.
||| This actually follows directly from the definition of GCD.
export
commonFactorAlsoFactorOfGCD : {p : Nat} -> Factor p a -> Factor p b -> GCD q a b -> Factor p q
commonFactorAlsoFactorOfGCD pfa pfb (MkGCD _ greatest) =
greatest p (CommonFactorExists p pfa pfb)
||| 1 is a common factor of any pair of natural numbers.
export
oneCommonFactor : (a, b : Nat) -> CommonFactor 1 a b
oneCommonFactor a b = CommonFactorExists 1
(CofactorExists a (rewrite plusZeroRightNeutral a in Refl))
(CofactorExists b (rewrite plusZeroRightNeutral b in Refl))
||| Any natural number is a common factor of itself and itself.
export
selfIsCommonFactor : (a : Nat) -> {auto ok : LTE 1 a} -> CommonFactor a a a
selfIsCommonFactor a = CommonFactorExists a reflexive reflexive
gcdUnproven' : (m, n : Nat) -> (0 sizeM : SizeAccessible m) -> (0 n_lt_m : LT n m) -> Nat
gcdUnproven' m Z _ _ = m
gcdUnproven' m (S n) (Access rec) n_lt_m =
let mod_lt_n = boundModNatNZ m (S n) SIsNonZero in
gcdUnproven' (S n) (modNatNZ m (S n) SIsNonZero) (rec _ n_lt_m) mod_lt_n
||| Total definition of the gcd function. Does not return GСD evidence, but is faster.
gcdUnproven : Nat -> Nat -> Nat
gcdUnproven m n with (isLT n m)
gcdUnproven m n | Yes n_lt_m = gcdUnproven' m n (wellFounded m) n_lt_m
gcdUnproven m n | No not_n_lt_m with (decomposeLte m n $ notLTImpliesGTE not_n_lt_m)
gcdUnproven m n | No not_n_lt_m | Left m_lt_n = gcdUnproven' n m (wellFounded n) m_lt_n
gcdUnproven m n | No not_n_lt_m | Right m_eq_n = m
gcdUnproven'Greatest : {m, n, c : Nat} -> (0 sizeM : SizeAccessible m) -> (0 n_lt_m : LT n m)
-> Factor c m -> Factor c n -> Factor c (gcdUnproven' m n sizeM n_lt_m)
gcdUnproven'Greatest {n = Z} _ _ cFactM _ = cFactM
gcdUnproven'Greatest {n = S n} (Access rec) n_lt_m cFactM cFactN =
gcdUnproven'Greatest (rec _ n_lt_m) (boundModNatNZ m (S n) SIsNonZero) cFactN (commonFactorAlsoFactorOfMod cFactM cFactN)
gcdUnprovenGreatest : (m, n : Nat) -> {auto 0 ok : NotBothZero m n} -> (q : Nat) -> CommonFactor q m n -> Factor q (gcdUnproven m n)
gcdUnprovenGreatest m n q (CommonFactorExists q qFactM qFactN) with (isLT n m)
gcdUnprovenGreatest m n q (CommonFactorExists q qFactM qFactN) | Yes n_lt_m
= gcdUnproven'Greatest (sizeAccessible m) n_lt_m qFactM qFactN
gcdUnprovenGreatest m n q (CommonFactorExists q qFactM qFactN) | No not_n_lt_m with (decomposeLte m n $ notLTImpliesGTE not_n_lt_m)
gcdUnprovenGreatest m n q (CommonFactorExists q qFactM qFactN) | No not_n_lt_m | Left m_lt_n
= gcdUnproven'Greatest (sizeAccessible n) m_lt_n qFactN qFactM
gcdUnprovenGreatest Z Z q (CommonFactorExists q qFactM qFactN) | No not_n_lt_m | Right m_eq_n impossible
gcdUnprovenGreatest (S m) (S n) q (CommonFactorExists q qFactM qFactN) | No not_n_lt_m | Right m_eq_n = qFactM
gcdUnproven'CommonFactor : {m, n : Nat} -> (0 sizeM : SizeAccessible m) -> (0 n_lt_m : LT n m) -> CommonFactor (gcdUnproven' m n sizeM n_lt_m) m n
gcdUnproven'CommonFactor {n = Z} _ _ = CommonFactorExists _ reflexive (anythingFactorZero m)
gcdUnproven'CommonFactor {n = S n} (Access rec) n_lt_m with (gcdUnproven'CommonFactor (rec _ n_lt_m) (boundModNatNZ m (S n) SIsNonZero))
gcdUnproven'CommonFactor (Access rec) n_lt_m | (CommonFactorExists _ factM factN)
= CommonFactorExists _ (modFactorAlsoFactorOfDivider factM factN) factM
gcdUnprovenCommonFactor : (m, n : Nat) -> {auto 0 ok : NotBothZero m n} -> CommonFactor (gcdUnproven m n) m n
gcdUnprovenCommonFactor m n with (isLT n m)
gcdUnprovenCommonFactor m n | Yes n_lt_m = gcdUnproven'CommonFactor (sizeAccessible m) n_lt_m
gcdUnprovenCommonFactor m n | No not_n_lt_m with (decomposeLte m n $ notLTImpliesGTE not_n_lt_m)
gcdUnprovenCommonFactor m n | No not_n_lt_m | Left m_lt_n = symmetric $ gcdUnproven'CommonFactor (sizeAccessible n) m_lt_n
gcdUnprovenCommonFactor Z Z | No not_n_lt_m | Right m_eq_n impossible
gcdUnprovenCommonFactor (S m) (S n) | No not_n_lt_m | Right m_eq_n = rewrite m_eq_n in selfIsCommonFactor (S n)
||| An implementation of Euclidean Algorithm for computing greatest common
||| divisors. It is proven correct and total; returns a proof that computed
||| number actually IS the GCD.
export
gcd : (a, b : Nat) -> {auto ok : NotBothZero a b} -> (f : Nat ** GCD f a b)
gcd a b = (_ ** MkGCD (gcdUnprovenCommonFactor a b) (gcdUnprovenGreatest a b))
||| For every two natural numbers there is a unique greatest common divisor.
export
gcdUnique : GCD p a b -> GCD q a b -> p = q
gcdUnique (MkGCD pCFab greatestP) (MkGCD qCFab greatestQ) =
antisymmetric (greatestQ p pCFab) (greatestP q qCFab)
divByGcdHelper : (a, b, c : Nat) -> GCD (S a) (S a * S b) (S a * c) -> GCD 1 (S b) c
divByGcdHelper a b c (MkGCD _ greatest) =
MkGCD (CommonFactorExists 1 (oneIsFactor (S b)) (oneIsFactor c)) $
\q, (CommonFactorExists q (CofactorExists qb prfQB) (CofactorExists qc prfQC)) =>
let qFab = CofactorExists qb $
rewrite multCommutative q (S a) in
rewrite sym $ multAssociative (S a) q qb in
rewrite sym $ prfQB in
Refl
qFac = CofactorExists qc $
rewrite multCommutative q (S a) in
rewrite sym $ multAssociative (S a) q qc in
rewrite sym $ prfQC in
Refl
CofactorExists f prfQAfA =
greatest (q * S a) (CommonFactorExists (q * S a) qFab qFac)
qf1 = multOneSoleNeutral a (f * q) $
rewrite multCommutative f q in
rewrite multAssociative (S a) q f in
rewrite sym $ multCommutative q (S a) in
prfQAfA
in
CofactorExists f $
rewrite multCommutative q f in
sym qf1
||| For every two natural numbers, if we divide both of them by their GCD,
||| the GCD of resulting numbers will always be 1.
export
divByGcdGcdOne : {a, b, c : Nat} -> GCD a (a * b) (a * c) -> GCD 1 b c
divByGcdGcdOne {a = Z} (MkGCD _ _) impossible
divByGcdGcdOne {a = S a} {b = Z} {c = Z} (MkGCD {notBothZero} _ _) =
case replace {p = \x => NotBothZero x x} (multZeroRightZero (S a)) notBothZero of
LeftIsNotZero impossible
RightIsNotZero impossible
divByGcdGcdOne {a = S a} {b = Z} {c = S c} gcdPrf@(MkGCD {notBothZero} _ _) =
case replace {p = \x => NotBothZero x (S a * S c)} (multZeroRightZero (S a)) notBothZero of
LeftIsNotZero impossible
RightIsNotZero => symmetric $ divByGcdHelper a c Z $ symmetric gcdPrf
divByGcdGcdOne {a = S a} {b = S b} {c = Z} gcdPrf@(MkGCD {notBothZero} _ _) =
case replace {p = \x => NotBothZero (S a * S b) x} (multZeroRightZero (S a)) notBothZero of
RightIsNotZero impossible
LeftIsNotZero => divByGcdHelper a b Z gcdPrf
divByGcdGcdOne {a = S a} {b = S b} {c = S c} gcdPrf =
divByGcdHelper a b (S c) gcdPrf