104 lines
3.3 KiB
Plaintext
104 lines
3.3 KiB
Plaintext
|
|
%% div.elf - Divisibility on Natural Numbers
|
||
|
|
%%
|
||
|
|
%% We define:
|
||
|
|
%% - divides D N: D divides N (D | N), meaning N = D * K for some K
|
||
|
|
|
||
|
|
%% ============================================================
|
||
|
|
%% DIVISIBILITY
|
||
|
|
%% ============================================================
|
||
|
|
|
||
|
|
%% D divides N if there exists K such that D * K = N
|
||
|
|
divides : nat -> nat -> type.
|
||
|
|
|
||
|
|
divides/intro : divides D N
|
||
|
|
<- mult D K N.
|
||
|
|
|
||
|
|
%% ============================================================
|
||
|
|
%% BASIC DIVISIBILITY FACTS
|
||
|
|
%% ============================================================
|
||
|
|
|
||
|
|
%% 1 divides everything: 1 | N
|
||
|
|
one-divides : {N:nat} divides (s z) N -> type.
|
||
|
|
%mode one-divides +N -D.
|
||
|
|
|
||
|
|
one-divides/base : one-divides N (divides/intro Dmult)
|
||
|
|
<- mult-left-one N Dmult.
|
||
|
|
|
||
|
|
%worlds () (one-divides _ _).
|
||
|
|
%total {} (one-divides _ _).
|
||
|
|
|
||
|
|
%% Everything divides 0: N | 0
|
||
|
|
divides-zero : {N:nat} divides N z -> type.
|
||
|
|
%mode divides-zero +N -D.
|
||
|
|
|
||
|
|
%% For any N, mult N z z holds (mult/z pattern doesn't work here)
|
||
|
|
%% We need to use mult-right-z
|
||
|
|
divides-zero/base : divides-zero N (divides/intro D)
|
||
|
|
<- mult-right-z N D.
|
||
|
|
|
||
|
|
%worlds () (divides-zero _ _).
|
||
|
|
%total {} (divides-zero _ _).
|
||
|
|
|
||
|
|
%% N divides itself: N | N (reflexivity)
|
||
|
|
divides-refl : {N:nat} divides N N -> type.
|
||
|
|
%mode divides-refl +N -D.
|
||
|
|
|
||
|
|
divides-refl/base : divides-refl N (divides/intro Dmult)
|
||
|
|
<- mult-right-one N Dmult.
|
||
|
|
|
||
|
|
%worlds () (divides-refl _ _).
|
||
|
|
%total {} (divides-refl _ _).
|
||
|
|
|
||
|
|
%% ============================================================
|
||
|
|
%% DIVISION WITH REMAINDER (EUCLIDEAN DIVISION)
|
||
|
|
%% ============================================================
|
||
|
|
|
||
|
|
%% For D > 0 and any N, there exist unique Q, R with N = D*Q + R and R < D
|
||
|
|
%% We represent this as: divmod N D Q R means N = D*Q + R and R < D
|
||
|
|
|
||
|
|
divmod : nat -> nat -> nat -> nat -> type.
|
||
|
|
|
||
|
|
%% Base case: if N < D, then Q = 0, R = N
|
||
|
|
divmod/lt : divmod N D z N
|
||
|
|
<- lt N D.
|
||
|
|
|
||
|
|
%% Recursive case: if N >= D, we need to compute (N - D) div D
|
||
|
|
%% This requires a subtraction relation, which we'll define
|
||
|
|
|
||
|
|
%% Subtraction: sub A B C means A = B + C (so C = A - B when B <= A)
|
||
|
|
sub : nat -> nat -> nat -> type.
|
||
|
|
sub/z : sub N z N.
|
||
|
|
sub/s : sub (s A) (s B) C
|
||
|
|
<- sub A B C.
|
||
|
|
|
||
|
|
%% Now we can define divmod for the recursive case
|
||
|
|
divmod/ge : divmod N D (s Q) R
|
||
|
|
<- le D N %% D <= N
|
||
|
|
<- sub N D M %% M = N - D
|
||
|
|
<- divmod M D Q R. %% M = D*Q + R, so N = D*(Q+1) + R
|
||
|
|
|
||
|
|
%% ============================================================
|
||
|
|
%% GCD (Greatest Common Divisor)
|
||
|
|
%% ============================================================
|
||
|
|
|
||
|
|
%% Euclidean algorithm: gcd(A, 0) = A, gcd(A, B) = gcd(B, A mod B)
|
||
|
|
%% We define gcd using the Euclidean algorithm
|
||
|
|
|
||
|
|
%% gcd A B G means G is the GCD of A and B
|
||
|
|
gcd : nat -> nat -> nat -> type.
|
||
|
|
|
||
|
|
gcd/z : gcd A z A. %% gcd(A, 0) = A
|
||
|
|
|
||
|
|
gcd/s : gcd A (s B) G
|
||
|
|
<- divmod A (s B) Q R %% A = (s B)*Q + R with R < s B
|
||
|
|
<- gcd (s B) R G. %% G = gcd(s B, R)
|
||
|
|
|
||
|
|
%% ============================================================
|
||
|
|
%% COPRIMALITY
|
||
|
|
%% ============================================================
|
||
|
|
|
||
|
|
%% A and B are coprime if gcd(A, B) = 1
|
||
|
|
coprime : nat -> nat -> type.
|
||
|
|
coprime/intro : coprime A B
|
||
|
|
<- gcd A B (s z).
|