(* ========================================================================= *)
(* Basic divisibility notions over the integers. *)
(* *)
(* This is similar to stuff in Library/prime.ml etc. for natural numbers. *)
(* ========================================================================= *)
prioritize_int();;
(* ------------------------------------------------------------------------- *)
(* Basic properties of divisibility. *)
(* ------------------------------------------------------------------------- *)
let INT_DIVIDES_REFL = INTEGER_RULE
`!d. d divides d`;;
let INT_DIVIDES_TRANS = INTEGER_RULE
`!x y z. x divides y /\ y divides z ==> x divides z`;;
let INT_DIVIDES_ADD = INTEGER_RULE
`!d a b. d divides a /\ d divides b ==> d divides (a + b)`;;
let INT_DIVIDES_SUB = INTEGER_RULE
`!d a b. d divides a /\ d divides b ==> d divides (a - b)`;;
let INT_DIVIDES_0 = INTEGER_RULE
`!d. d divides &0`;;
let INT_DIVIDES_ZERO = INTEGER_RULE
`!x. &0 divides x <=> x = &0`;;
let INT_DIVIDES_LNEG = INTEGER_RULE
`!d x. (--d) divides x <=> d divides x`;;
let INT_DIVIDES_RNEG = INTEGER_RULE
`!d x. d divides (--x) <=> d divides x`;;
let INT_DIVIDES_RMUL = INTEGER_RULE
`!d x y. d divides x ==> d divides (x * y)`;;
let INT_DIVIDES_LMUL = INTEGER_RULE
`!d x y. d divides y ==> d divides (x * y)`;;
let INT_DIVIDES_1 = INTEGER_RULE
`!x. &1 divides x`;;
let INT_DIVIDES_ADD_REVR = INTEGER_RULE
`!d a b. d divides a /\ d divides (a + b) ==> d divides b`;;
let INT_DIVIDES_ADD_REVL = INTEGER_RULE
`!d a b. d divides b /\ d divides (a + b) ==> d divides a`;;
let INT_DIVIDES_MUL_L = INTEGER_RULE
`!a b c. a divides b ==> (c * a) divides (c * b)`;;
let INT_DIVIDES_MUL_R = INTEGER_RULE
`!a b c. a divides b ==> (a * c) divides (b * c)`;;
let INT_DIVIDES_LMUL2 = INTEGER_RULE
`!d a x. (x * d) divides a ==> d divides a`;;
let INT_DIVIDES_RMUL2 = INTEGER_RULE
`!d a x. (d * x) divides a ==> d divides a`;;
let INT_DIVIDES_CMUL2 = INTEGER_RULE
`!a b c. (c * a) divides (c * b) /\ ~(c = &0) ==> a divides b`;;
let INT_DIVIDES_LMUL2_EQ = INTEGER_RULE
`!a b c. ~(c = &0) ==> ((c * a) divides (c * b) <=> a divides b)`;;
let INT_DIVIDES_RMUL2_EQ = INTEGER_RULE
`!a b c. ~(c = &0) ==> ((a * c) divides (b * c) <=> a divides b)`;;
let INT_DIVIDES_MUL2 = INTEGER_RULE
`!a b c d. a divides b /\ c divides d ==> (a * c) divides (b * d)`;;
let INT_DIVIDES_ABS = prove
(`(!d n. abs(d) divides n <=> d divides n) /\
(!d n. d divides (abs n) <=> d divides n)`,
let INT_DIVIDES_RPOW = prove
(`!x y n. x divides y /\ ~(n = 0) ==> x divides (y pow n)`,
GEN_TAC THEN GEN_TAC THEN INDUCT_TAC THEN
SIMP_TAC[INT_DIVIDES_RMUL;
INT_POW]);;
(* ------------------------------------------------------------------------- *)
(* Now carefully distinguish signs. *)
(* ------------------------------------------------------------------------- *)
let INT_DIVIDES_ANTISYM_ASSOCIATED = prove
(`!x y. x divides y /\ y divides x <=> ?u. u divides &1 /\ x = y * u`,
REPEAT GEN_TAC THEN EQ_TAC THENL [ALL_TAC; INTEGER_TAC] THEN
ASM_CASES_TAC `x = &0` THEN ASM_SIMP_TAC[INT_DIVIDES_ZERO;
INT_MUL_LZERO] THEN
ASM_MESON_TAC[
int_divides; INT_DIVIDES_REFL;
INTEGER_RULE `y = x * d /\ x = y * e /\ ~(y = &0) ==> d divides &1`]);;
(* ------------------------------------------------------------------------- *)
(* Lemmas about GCDs. *)
(* ------------------------------------------------------------------------- *)
let INT_GCD = INTEGER_RULE
`!a b. (gcd(a,b) divides a /\ gcd(a,b) divides b) /\
(!e. e divides a /\ e divides b ==> e divides gcd(a,b))`;;
let INT_GCD_UNIQUE = prove
(`!a b d. gcd(a,b) = d <=> &0 <= d /\ d divides a /\ d divides b /\
!e. e divides a /\ e divides b ==> e divides d`,
let INT_GCD_UNIQUE_ABS = prove
(`!a b d. gcd(a,b) = abs(d) <=>
d divides a /\ d divides b /\
!e. e divides a /\ e divides b ==> e divides d`,
let INT_GCD_MULTIPLE =
(`!a b. gcd(a,a * b) = abs(a) /\ gcd(b,a * b) = abs(b)`,
REWRITE_TAC[INT_GCD_UNIQUE_ABS] THEN INTEGER_TAC);;
let INT_GCD_ADD = prove
(`(!a b. gcd(a + b,b) = gcd(a,b)) /\
(!a b. gcd(b + a,b) = gcd(a,b)) /\
(!a b. gcd(a,a + b) = gcd(a,b)) /\
(!a b. gcd(a,b + a) = gcd(a,b))`,
let INT_GCD_SUB = prove
(`(!a b. gcd(a - b,b) = gcd(a,b)) /\
(!a b. gcd(b - a,b) = gcd(a,b)) /\
(!a b. gcd(a,a - b) = gcd(a,b)) /\
(!a b. gcd(a,b - a) = gcd(a,b))`,
(* ------------------------------------------------------------------------- *)
(* More lemmas about coprimality. *)
(* ------------------------------------------------------------------------- *)
let int_coprime = prove
(`!a b. coprime(a,b) <=> !d. d divides a /\ d divides b ==> d divides &1`,
let COPRIME = prove
(`!a b. coprime(a,b) <=> !d. d divides a /\ d divides b <=> d divides &1`,
MESON_TAC[INT_DIVIDES_1; INT_DIVIDES_TRANS;
int_coprime]);;
let INT_GCD_COPRIME = prove
(`!a b a' b'. ~(gcd(a,b) = &0) /\ a = a' * gcd(a,b) /\ b = b' * gcd(a,b)
==> coprime(a',b')`,
INTEGER_TAC);;
let INT_COPRIME_0 = prove
(`(!a. coprime(a,&0) <=> a divides &1) /\
(!a. coprime(&0,a) <=> a divides &1)`,
INTEGER_TAC);;
let INT_DIVISION_DECOMP = prove
(`!a b c. a divides (b * c)
==> ?b' c'. (a = b' * c') /\ b' divides b /\ c' divides c`,
REPEAT STRIP_TAC THEN EXISTS_TAC `gcd(a,b)` THEN
ASM_CASES_TAC `gcd(a,b) = &0` THEN REPEAT(POP_ASSUM MP_TAC) THENL
[SIMP_TAC[
INT_GCD_EQ_0;
INT_GCD_0;
INT_ABS_NUM]; INTEGER_TAC] THEN
REWRITE_TAC[
INT_MUL_LZERO] THEN MESON_TAC[INT_DIVIDES_REFL]);;
let INT_DIVIDES_MUL = prove
(`!m n r. m divides r /\ n divides r /\ coprime(m,n) ==> (m * n) divides r`,
INTEGER_TAC);;
let INT_CHINESE_REMAINDER = prove
(`!a b u v. coprime(a,b) /\ ~(a = &0) /\ ~(b = &0)
==> ?x q1 q2. (x = u + q1 * a) /\ (x = v + q2 * b)`,
INTEGER_TAC);;
let INT_COPRIME_NEG = prove
(`(!a b. coprime(--a,b) <=> coprime(a,b)) /\
(!a b. coprime(a,--b) <=> coprime(a,b))`,
INTEGER_TAC);;
let INT_COPRIME_ABS = prove
(`(!a b. coprime(abs a,b) <=> coprime(a,b)) /\
(!a b. coprime(a,abs b) <=> coprime(a,b))`,
(* ------------------------------------------------------------------------- *)
(* More lemmas about congruences. *)
(* ------------------------------------------------------------------------- *)
let INT_CONG = prove
(`!x y n. (x == y) (mod n) <=> n divides (x - y)`,
INTEGER_TAC);;
let INT_CONG_TRANS = prove
(`!x y z n. (x == y) (mod n) /\ (y == z) (mod n) ==> (x == z) (mod n)`,
INTEGER_TAC);;
let INT_CONG_ADD = prove
(`!x x' y y'.
(x == x') (mod n) /\ (y == y') (mod n) ==> (x + y == x' + y') (mod n)`,
INTEGER_TAC);;
let INT_CONG_SUB = prove
(`!x x' y y'.
(x == x') (mod n) /\ (y == y') (mod n) ==> (x - y == x' - y') (mod n)`,
INTEGER_TAC);;
let INT_CONG_MUL = prove
(`!x x' y y'.
(x == x') (mod n) /\ (y == y') (mod n) ==> (x * y == x' * y') (mod n)`,
INTEGER_TAC);;
let INT_CONG_SOLVE_UNIQUE = prove
(`!a b n. coprime(a,n)
==> !x y. (a * x == b) (mod n) /\ (a * y == b) (mod n)
==> (x == y) (mod n)`,
INTEGER_TAC);;
let INT_CONG_CHINESE = prove
(`coprime(a,b) /\ (x == y) (mod a) /\ (x == y) (mod b)
==> (x == y) (mod (a * b))`,
INTEGER_TAC);;
let INT_CHINESE_REMAINDER_COPRIME = prove
(`!a b m n.
coprime(a,b) /\ ~(a = &0) /\ ~(b = &0) /\ coprime(m,a) /\ coprime(n,b)
==> ?x. coprime(x,a * b) /\
(x == m) (mod a) /\ (x == n) (mod b)`,
INTEGER_TAC);;
let INT_LINEAR_CONG_POS = prove
(`!n a x:int. ~(n = &0) ==> ?y. &0 <= y /\ (a * x == a * y) (mod n)`,
REPEAT STRIP_TAC THEN EXISTS_TAC `x + abs(x * n):int` THEN CONJ_TAC THENL
[MATCH_MP_TAC(INT_ARITH `abs(x:int) * &1 <= y ==> &0 <= x + y`) THEN
REWRITE_TAC[
INT_ABS_MUL] THEN MATCH_MP_TAC
INT_LE_LMUL THEN
ASM_INT_ARITH_TAC;
MATCH_MP_TAC(INTEGER_RULE
`n divides y ==> (a * x:int == a * (x + y)) (mod n)`) THEN
REWRITE_TAC[
INT_DIVIDES_RABS] THEN INTEGER_TAC]);;
let INT_CONG_IMP_EQ = prove
(`!x y n:int. abs(x - y) < n /\ (x == y) (mod n) ==> x = y`,
REPEAT GEN_TAC THEN
DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
ONCE_REWRITE_TAC[
int_congruent; GSYM
INT_SUB_0] THEN
DISCH_THEN(X_CHOOSE_THEN `q:int` SUBST_ALL_TAC) THEN
FIRST_X_ASSUM(MP_TAC o MATCH_MP (ARITH_RULE
`abs(n * q) < n ==> abs(n * q) < abs n * &1`)) THEN
REWRITE_TAC[
INT_ABS_MUL;
INT_ENTIRE] THEN
REWRITE_TAC[INT_ARITH
`abs n * (q:int) < abs n * &1 <=> ~(&0 <= abs n * (q - &1))`] THEN
ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[DE_MORGAN_THM] THEN
STRIP_TAC THEN MATCH_MP_TAC
INT_LE_MUL THEN ASM_INT_ARITH_TAC);;
(* ------------------------------------------------------------------------- *)
(* A stronger form of the CRT. *)
(* ------------------------------------------------------------------------- *)
let INT_CRT_STRONG = prove
(`!a1 a2 n1 n2:int.
(a1 == a2) (mod (gcd(n1,n2)))
==> ?x. (x == a1) (mod n1) /\ (x == a2) (mod n2)`,
INTEGER_TAC);;
let INT_CRT_STRONG_IFF = prove
(`!a1 a2 n1 n2:int.
(?x. (x == a1) (mod n1) /\ (x == a2) (mod n2)) <=>
(a1 == a2) (mod (gcd(n1,n2)))`,
INTEGER_TAC);;
(* ------------------------------------------------------------------------- *)
(* Other miscellaneous lemmas. *)
(* ------------------------------------------------------------------------- *)
let INT_DIVIDES_LE = prove
(`!x y. x divides y ==> abs(x) <= abs(y) \/ y = &0`,
REWRITE_TAC[
int_divides;
LEFT_IMP_EXISTS_THM] THEN
MAP_EVERY X_GEN_TAC [`x:int`; `y:int`; `z:int`] THEN
DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[
INT_ABS_MUL;
INT_ENTIRE] THEN
REWRITE_TAC[INT_ARITH `x <= x * z <=> &0 <= x * (z - &1)`] THEN
ASM_CASES_TAC `x = &0` THEN ASM_REWRITE_TAC[] THEN
ASM_CASES_TAC `z = &0` THEN ASM_REWRITE_TAC[] THEN
MATCH_MP_TAC
INT_LE_MUL THEN ASM_INT_ARITH_TAC);;
(* ------------------------------------------------------------------------- *)
(* Integer primality / irreducibility. *)
(* ------------------------------------------------------------------------- *)
let int_prime = new_definition
`int_prime p <=> abs(p) > &1 /\
!x. x divides p ==> abs(x) = &1 \/ abs(x) = abs(p)`;;
let INT_PRIME_2 = prove
(`
int_prime(&2)`,
REWRITE_TAC[
int_prime] THEN CONV_TAC INT_REDUCE_CONV THEN
X_GEN_TAC `x:int` THEN
ASM_CASES_TAC `x = &0` THEN ASM_REWRITE_TAC[INT_DIVIDES_ZERO] THEN
CONV_TAC INT_REDUCE_CONV THEN
DISCH_THEN(MP_TAC o MATCH_MP
INT_DIVIDES_LE) THEN ASM_INT_ARITH_TAC);;
let INT_PRIME_FACTOR = prove
(`!x. ~(abs x = &1) ==> ?p.
int_prime p /\ p divides x`,
MATCH_MP_TAC
WF_INT_MEASURE THEN EXISTS_TAC `abs` THEN
REWRITE_TAC[
INT_ABS_POS] THEN X_GEN_TAC `x:int` THEN
REPEAT STRIP_TAC THEN ASM_CASES_TAC `
int_prime x` THENL
[EXISTS_TAC `x:int` THEN ASM_REWRITE_TAC[] THEN
REPEAT(POP_ASSUM MP_TAC) THEN INTEGER_TAC;
ALL_TAC] THEN
ASM_CASES_TAC `x = &0` THEN ASM_REWRITE_TAC[] THENL
[EXISTS_TAC `&2` THEN ASM_REWRITE_TAC[
INT_PRIME_2; INT_DIVIDES_0];
ALL_TAC] THEN
FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE RAND_CONV [
int_prime]) THEN
ASM_SIMP_TAC[INT_ARITH `~(x = &0) /\ ~(abs x = &1) ==> abs x > &1`] THEN
REWRITE_TAC[
NOT_FORALL_THM; NOT_IMP; DE_MORGAN_THM] THEN
DISCH_THEN(X_CHOOSE_THEN `y:int` STRIP_ASSUME_TAC) THEN
FIRST_X_ASSUM(MP_TAC o SPEC `y:int`) THEN ASM_REWRITE_TAC[] THEN
ANTS_TAC THENL
[FIRST_X_ASSUM(MP_TAC o MATCH_MP
INT_DIVIDES_LE) THEN ASM_INT_ARITH_TAC;
MATCH_MP_TAC
MONO_EXISTS THEN GEN_TAC THEN SIMP_TAC[] THEN
UNDISCH_TAC `y divides x` THEN INTEGER_TAC]);;
let INT_PRIME_FACTOR_LT = prove
(`!n m p.
int_prime(p) /\ ~(n = &0) /\ n = p * m ==> abs m < abs n`,
REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[
INT_ABS_MUL] THEN
MATCH_MP_TAC(INT_ARITH `&0 < m * (p - &1) ==> m < p * m`) THEN
MATCH_MP_TAC
INT_LT_MUL THEN
UNDISCH_TAC `~(n = &0)` THEN ASM_CASES_TAC `m = &0` THEN
ASM_REWRITE_TAC[
INT_MUL_RZERO] THEN DISCH_THEN(K ALL_TAC) THEN
CONJ_TAC THENL [ASM_INT_ARITH_TAC; ALL_TAC] THEN
FIRST_ASSUM(MP_TAC o MATCH_MP
INT_PRIME_GE_2) THEN INT_ARITH_TAC);;
let INT_PRIME_FACTOR_INDUCT = prove
(`!P. P(&0) /\ P(&1) /\ P(-- &1) /\
(!p n.
int_prime p /\ ~(n = &0) /\ P n ==> P(p * n))
==> !n. P n`,
GEN_TAC THEN STRIP_TAC THEN
MATCH_MP_TAC
WF_INT_MEASURE THEN EXISTS_TAC `abs` THEN
REWRITE_TAC[
INT_ABS_POS] THEN X_GEN_TAC `n:int` THEN DISCH_TAC THEN
ASM_CASES_TAC `n = &0` THEN ASM_REWRITE_TAC[] THEN
ASM_CASES_TAC `abs n = &1` THENL
[ASM_MESON_TAC[INT_ARITH `abs x = &a <=> x = &a \/ x = -- &a`];
ALL_TAC] THEN
FIRST_ASSUM(X_CHOOSE_THEN `p:int`
STRIP_ASSUME_TAC o MATCH_MP
INT_PRIME_FACTOR) THEN
FIRST_X_ASSUM(X_CHOOSE_THEN `d:int` SUBST_ALL_TAC o
GEN_REWRITE_RULE I [
int_divides]) THEN
FIRST_X_ASSUM(MP_TAC o SPECL [`p:int`; `d:int`]) THEN
RULE_ASSUM_TAC(REWRITE_RULE[
INT_ENTIRE; DE_MORGAN_THM]) THEN
DISCH_THEN MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
FIRST_X_ASSUM MATCH_MP_TAC THEN
ASM_MESON_TAC[
INT_PRIME_FACTOR_LT;
INT_ENTIRE]);;
(* ------------------------------------------------------------------------- *)
(* Infinitude. *)
(* ------------------------------------------------------------------------- *)
let INT_DIVIDES_FACT = prove
(`!n x. &1 <= abs(x) /\ abs(x) <= &n ==> x divides &(
FACT n)`,
INDUCT_TAC THENL [INT_ARITH_TAC; ALL_TAC] THEN
REWRITE_TAC[
FACT; INT_ARITH `x <= &n <=> x = &n \/ x < &n`] THEN
REWRITE_TAC[GSYM
INT_OF_NUM_SUC; INT_ARITH `x < &m + &1 <=> x <= &m`] THEN
REWRITE_TAC[
INT_OF_NUM_SUC; GSYM
INT_OF_NUM_MUL] THEN REPEAT STRIP_TAC THEN
ASM_SIMP_TAC[INT_DIVIDES_LMUL] THEN
MATCH_MP_TAC INT_DIVIDES_RMUL THEN
ASM_MESON_TAC[
INT_DIVIDES_LABS; INT_DIVIDES_REFL]);;
let INT_DIVIDES_POW2_REV = prove
(`!n a b. (a pow n) divides (b pow n) /\ ~(n = 0) ==> a divides b`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `gcd(a,b) = &0` THENL
[ASM_MESON_TAC[
INT_GCD_EQ_0; INT_DIVIDES_REFL]; ALL_TAC] THEN
FIRST_ASSUM(MP_TAC o MATCH_MP
INT_GCD_COPRIME_EXISTS) THEN
STRIP_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
ONCE_ASM_REWRITE_TAC[] THEN REWRITE_TAC[
INT_POW_MUL] THEN
ASM_SIMP_TAC[
INT_POW_EQ_0; INT_DIVIDES_RMUL2_EQ] THEN
DISCH_THEN(MP_TAC o MATCH_MP (INTEGER_RULE
`a divides b ==> coprime(a,b) ==> a divides &1`)) THEN
ASM_SIMP_TAC[
INT_COPRIME_POW2] THEN
ASM_MESON_TAC[
INT_DIVIDES_POW2; INT_DIVIDES_TRANS; INT_DIVIDES_1]);;