(* ========================================================================= *)
(* Natural number arithmetic. *)
(* *)
(* John Harrison, University of Cambridge Computer Laboratory *)
(* *)
(* (c) Copyright, University of Cambridge 1998 *)
(* (c) Copyright, John Harrison 1998-2007 *)
(* ========================================================================= *)
needs "recursion.ml";;
(* ------------------------------------------------------------------------- *)
(* Note: all the following proofs are intuitionistic and intensional, except *)
(* for the least number principle num_WOP. *)
(* (And except the arith rewrites at the end; these could be done that way *)
(* but they use the conditional anyway.) In fact, one could very easily *)
(* write a "decider" returning P \/ ~P for quantifier-free P. *)
(* ------------------------------------------------------------------------- *)
parse_as_infix("<",(12,"right"));;
parse_as_infix("<=",(12,"right"));;
parse_as_infix(">",(12,"right"));;
parse_as_infix(">=",(12,"right"));;
parse_as_infix("+",(16,"right"));;
parse_as_infix("-",(18,"left"));;
parse_as_infix("*",(20,"right"));;
parse_as_infix("EXP",(24,"left"));;
parse_as_infix("DIV",(22,"left"));;
parse_as_infix("MOD",(22,"left"));;
(* ------------------------------------------------------------------------- *)
(* The predecessor function. *)
(* ------------------------------------------------------------------------- *)
let PRE = new_recursive_definition num_RECURSION
`(PRE 0 = 0) /\
(!n. PRE (SUC n) = n)`;;
(* ------------------------------------------------------------------------- *)
(* Addition. *)
(* ------------------------------------------------------------------------- *)
let ADD = new_recursive_definition num_RECURSION
`(!n. 0 + n = n) /\
(!m n. (SUC m) + n = SUC(m + n))`;;
let ADD_SUC = prove
(`!m n. m + (SUC n) = SUC(m + n)`,
INDUCT_TAC THEN ASM_REWRITE_TAC[
ADD]);;
let ADD_CLAUSES = prove
(`(!n. 0 + n = n) /\
(!m. m + 0 = m) /\
(!m n. (SUC m) + n = SUC(m + n)) /\
(!m n. m + (SUC n) = SUC(m + n))`,
let ADD_AC = prove
(`(m + n = n + m) /\
((m + n) + p = m + (n + p)) /\
(m + (n + p) = n + (m + p))`,
(* ------------------------------------------------------------------------- *)
(* Now define "bitwise" binary representation of numerals. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Following is handy before num_CONV arrives. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* One immediate consequence. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Multiplication. *)
(* ------------------------------------------------------------------------- *)
let MULT = new_recursive_definition num_RECURSION
`(!n. 0 * n = 0) /\
(!m n. (SUC m) * n = (m * n) + n)`;;
let MULT_CLAUSES = prove
(`(!n. 0 * n = 0) /\
(!m. m * 0 = 0) /\
(!n. 1 * n = n) /\
(!m. m * 1 = m) /\
(!m n. (SUC m) * n = (m * n) + n) /\
(!m n. m * (SUC n) = m + (m * n))`,
let MULT_AC = prove
(`(m * n = n * m) /\
((m * n) * p = m * (n * p)) /\
(m * (n * p) = n * (m * p))`,
(* ------------------------------------------------------------------------- *)
(* Exponentiation. *)
(* ------------------------------------------------------------------------- *)
let EXP = new_recursive_definition num_RECURSION
`(!m. m EXP 0 = 1) /\
(!m n. m EXP (SUC n) = m * (m EXP n))`;;
(* ------------------------------------------------------------------------- *)
(* Define the orderings recursively too. *)
(* ------------------------------------------------------------------------- *)
let LE = new_recursive_definition num_RECURSION
`(!m. (m <= 0) <=> (m = 0)) /\
(!m n. (m <= SUC n) <=> (m = SUC n) \/ (m <= n))`;;
let LT = new_recursive_definition num_RECURSION
`(!m. (m < 0) <=> F) /\
(!m n. (m < SUC n) <=> (m = n) \/ (m < n))`;;
let GE = new_definition
`m >= n <=> n <= m`;;
let GT = new_definition
`m > n <=> n < m`;;
(* ------------------------------------------------------------------------- *)
(* Maximum and minimum of natural numbers. *)
(* ------------------------------------------------------------------------- *)
let MAX = new_definition
`!m n. MAX m n = if m <= n then n else m`;;
let MIN = new_definition
`!m n. MIN m n = if m <= n then m else n`;;
(* ------------------------------------------------------------------------- *)
(* Step cases. *)
(* ------------------------------------------------------------------------- *)
let LT_SUC_LE = prove
(`!m n. (m < SUC n) <=> (m <= n)`,
GEN_TAC THEN INDUCT_TAC THEN ONCE_REWRITE_TAC[
LT;
LE] THEN
ASM_REWRITE_TAC[] THEN REWRITE_TAC[
LT]);;
(* ------------------------------------------------------------------------- *)
(* Base cases. *)
(* ------------------------------------------------------------------------- *)
let LE_0 = prove
(`!n. 0 <= n`,
INDUCT_TAC THEN ASM_REWRITE_TAC[
LE]);;
(* ------------------------------------------------------------------------- *)
(* Reflexivity. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Antisymmetry. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Transitivity. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Totality. *)
(* ------------------------------------------------------------------------- *)
let LT_CASES = prove
(`!m n. (m < n) \/ (n < m) \/ (m = n)`,
REPEAT INDUCT_TAC THEN ASM_REWRITE_TAC[
LT_SUC;
SUC_INJ] THEN
REWRITE_TAC[
LT;
NOT_SUC; GSYM
NOT_SUC] THEN
W(W (curry SPEC_TAC) o hd o frees o snd) THEN
INDUCT_TAC THEN REWRITE_TAC[
LT_0]);;
(* ------------------------------------------------------------------------- *)
(* Relationship between orderings. *)
(* ------------------------------------------------------------------------- *)
let LT_LE = prove
(`!m n. (m < n) <=> (m <= n) /\ ~(m = n)`,
REWRITE_TAC[
LE_LT] THEN REPEAT GEN_TAC THEN EQ_TAC THENL
[DISCH_TAC THEN ASM_REWRITE_TAC[] THEN DISCH_THEN SUBST_ALL_TAC THEN
POP_ASSUM MP_TAC THEN REWRITE_TAC[
LT_REFL];
DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
ASM_REWRITE_TAC[]]);;
let LT_IMP_LE = prove
(`!m n. m < n ==> m <= n`,
REWRITE_TAC[
LT_LE] THEN REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[]);;
(* ------------------------------------------------------------------------- *)
(* Often useful to shuffle between different versions of "0 < n". *)
(* ------------------------------------------------------------------------- *)
let LE_1 = prove
(`(!n. ~(n = 0) ==> 0 < n) /\
(!n. ~(n = 0) ==> 1 <= n) /\
(!n. 0 < n ==> ~(n = 0)) /\
(!n. 0 < n ==> 1 <= n) /\
(!n. 1 <= n ==> 0 < n) /\
(!n. 1 <= n ==> ~(n = 0))`,
(* ------------------------------------------------------------------------- *)
(* Relate the orderings to arithmetic operations. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Interaction with addition. *)
(* ------------------------------------------------------------------------- *)
let LE_ADD2 = prove
(`!m n p q. m <= p /\ n <= q ==> m + n <= p + q`,
REPEAT GEN_TAC THEN REWRITE_TAC[
LE_EXISTS] THEN
DISCH_THEN(CONJUNCTS_THEN2
(X_CHOOSE_TAC `a:num`) (X_CHOOSE_TAC `b:num`)) THEN
EXISTS_TAC `a + b` THEN ASM_REWRITE_TAC[
ADD_AC]);;
let LT_ADD2 = prove
(`!m n p q. m < p /\ n < q ==> m + n < p + q`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC
LTE_ADD2 THEN
ASM_REWRITE_TAC[] THEN MATCH_MP_TAC
LT_IMP_LE THEN
ASM_REWRITE_TAC[]);;
(* ------------------------------------------------------------------------- *)
(* And multiplication. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Useful "without loss of generality" lemmas. *)
(* ------------------------------------------------------------------------- *)
let WLOG_LE = prove
(`(!m n. P m n <=> P n m) /\ (!m n. m <= n ==> P m n) ==> !m n. P m n`,
let WLOG_LT = prove
(`(!m. P m m) /\ (!m n. P m n <=> P n m) /\ (!m n. m < n ==> P m n)
==> !m y. P m y`,
(* ------------------------------------------------------------------------- *)
(* Existence of least and greatest elements of (finite) set. *)
(* ------------------------------------------------------------------------- *)
let num_WF = prove
(`!P. (!n. (!m. m < n ==> P m) ==> P n) ==> !n. P n`,
let num_WOP = prove
(`!P. (?n. P n) <=> (?n. P(n) /\ !m. m < n ==> ~P(m))`,
GEN_TAC THEN EQ_TAC THENL [ALL_TAC; MESON_TAC[]] THEN
CONV_TAC CONTRAPOS_CONV THEN REWRITE_TAC[
NOT_EXISTS_THM] THEN
DISCH_TAC THEN MATCH_MP_TAC
num_WF THEN ASM_MESON_TAC[]);;
let num_MAX = prove
(`!P. (?x. P x) /\ (?M. !x. P x ==> x <= M) <=>
?m. P m /\ (!x. P x ==> x <= m)`,
GEN_TAC THEN EQ_TAC THENL
[DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `a:num`) MP_TAC) THEN
DISCH_THEN(X_CHOOSE_THEN `m:num` MP_TAC o ONCE_REWRITE_RULE[
num_WOP]) THEN
DISCH_THEN(fun th -> EXISTS_TAC `m:num` THEN MP_TAC th) THEN
REWRITE_TAC[TAUT `(a /\ b ==> c /\ a) <=> (a /\ b ==> c)`] THEN
SPEC_TAC(`m:num`,`m:num`) THEN INDUCT_TAC THENL
[REWRITE_TAC[
LE;
LT] THEN DISCH_THEN(IMP_RES_THEN SUBST_ALL_TAC) THEN
POP_ASSUM ACCEPT_TAC;
DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o SPEC `m:num`)) THEN
REWRITE_TAC[
LT] THEN CONV_TAC CONTRAPOS_CONV THEN
DISCH_TAC THEN REWRITE_TAC[] THEN X_GEN_TAC `p:num` THEN
FIRST_ASSUM(MP_TAC o SPEC `p:num`) THEN REWRITE_TAC[
LE] THEN
ASM_CASES_TAC `p = SUC m` THEN ASM_REWRITE_TAC[]];
REPEAT STRIP_TAC THEN EXISTS_TAC `m:num` THEN ASM_REWRITE_TAC[]]);;
(* ------------------------------------------------------------------------- *)
(* Oddness and evenness (recursively rather than inductively!) *)
(* ------------------------------------------------------------------------- *)
let EVEN = new_recursive_definition num_RECURSION
`(EVEN 0 <=> T) /\
(!n. EVEN (SUC n) <=> ~(EVEN n))`;;
let ODD = new_recursive_definition num_RECURSION
`(ODD 0 <=> F) /\
(!n. ODD (SUC n) <=> ~(ODD n))`;;
let EVEN_EXISTS_LEMMA = prove
(`!n. (
EVEN n ==> ?m. n = 2 * m) /\
(~EVEN n ==> ?m. n = SUC(2 * m))`,
INDUCT_TAC THEN REWRITE_TAC[
EVEN] THENL
[EXISTS_TAC `0` THEN REWRITE_TAC[
MULT_CLAUSES];
POP_ASSUM STRIP_ASSUME_TAC THEN CONJ_TAC THEN
DISCH_THEN(ANTE_RES_THEN(X_CHOOSE_TAC `m:num`)) THENL
[EXISTS_TAC `SUC m` THEN ASM_REWRITE_TAC[] THEN
REWRITE_TAC[
MULT_2] THEN REWRITE_TAC[
ADD_CLAUSES];
EXISTS_TAC `m:num` THEN ASM_REWRITE_TAC[]]]);;
(* ------------------------------------------------------------------------- *)
(* Cutoff subtraction, also defined recursively. (Not the HOL88 defn.) *)
(* ------------------------------------------------------------------------- *)
let SUB = new_recursive_definition num_RECURSION
`(!m. m - 0 = m) /\
(!m n. m - (SUC n) = PRE(m - n))`;;
let SUB_0 = prove
(`!m. (0 - m = 0) /\ (m - 0 = m)`,
REWRITE_TAC[
SUB] THEN INDUCT_TAC THEN ASM_REWRITE_TAC[
SUB;
PRE]);;
let EVEN_SUB = prove
(`!m n.
EVEN(m - n) <=> m <= n \/ (
EVEN(m) <=>
EVEN(n))`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `m <= n:num` THENL
[ASM_MESON_TAC[
SUB_EQ_0;
EVEN]; ALL_TAC] THEN
DISJ_CASES_TAC(SPECL [`m:num`; `n:num`]
LE_CASES) THEN ASM_SIMP_TAC[] THEN
FIRST_ASSUM(MP_TAC o AP_TERM `
EVEN` o MATCH_MP
SUB_ADD) THEN
ASM_MESON_TAC[
EVEN_ADD]);;
(* ------------------------------------------------------------------------- *)
(* The factorial function. *)
(* ------------------------------------------------------------------------- *)
let FACT = new_recursive_definition num_RECURSION
`(FACT 0 = 1) /\
(!n. FACT (SUC n) = (SUC n) * FACT(n))`;;
(* ------------------------------------------------------------------------- *)
(* More complicated theorems about exponential. *)
(* ------------------------------------------------------------------------- *)
let LT_EXP = prove
(`!x m n. x
EXP m < x
EXP n <=> 2 <= x /\ m < n \/
(x = 0) /\ ~(m = 0) /\ (n = 0)`,
let LE_EXP = prove
(`!x m n. x
EXP m <= x
EXP n <=>
if x = 0 then (m = 0) ==> (n = 0)
else (x = 1) \/ m <= n`,
REPEAT GEN_TAC THEN REWRITE_TAC[GSYM
NOT_LT;
LT_EXP; DE_MORGAN_THM] THEN
COND_CASES_TAC THEN ASM_REWRITE_TAC[
TWO;
LT;
ONE] THEN
CONV_TAC(EQT_INTRO o TAUT));;
let EQ_EXP = prove
(`!x m n. x
EXP m = x
EXP n <=>
if x = 0 then (m = 0 <=> n = 0)
else (x = 1) \/ m = n`,
REPEAT GEN_TAC THEN GEN_REWRITE_TAC LAND_CONV [GSYM
LE_ANTISYM;
LE_EXP] THEN
COND_CASES_TAC THEN ASM_REWRITE_TAC[
LE_EXP] THEN
REWRITE_TAC[GSYM
LE_ANTISYM] THEN CONV_TAC TAUT);;
(* ------------------------------------------------------------------------- *)
(* Division and modulus, via existence proof of their basic property. *)
(* ------------------------------------------------------------------------- *)
let DIVMOD_EXIST = prove
(`!m n. ~(n = 0) ==> ?q r. (m = q * n + r) /\ r < n`,
REPEAT STRIP_TAC THEN MP_TAC(SPEC `\r. ?q. m = q * n + r`
num_WOP) THEN
BETA_TAC THEN DISCH_THEN(MP_TAC o fst o EQ_IMP_RULE) THEN
REWRITE_TAC[
LEFT_IMP_EXISTS_THM] THEN
DISCH_THEN(MP_TAC o SPECL [`m:num`; `0`]) THEN
REWRITE_TAC[
MULT_CLAUSES;
ADD_CLAUSES] THEN
DISCH_THEN(X_CHOOSE_THEN `r:num` MP_TAC) THEN
DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `q:num`) MP_TAC) THEN
DISCH_THEN(fun th ->
MAP_EVERY EXISTS_TAC [`q:num`; `r:num`] THEN MP_TAC th) THEN
CONV_TAC CONTRAPOS_CONV THEN ASM_REWRITE_TAC[
NOT_LT] THEN
DISCH_THEN(X_CHOOSE_THEN `d:num` SUBST_ALL_TAC o
REWRITE_RULE[
LE_EXISTS]) THEN
REWRITE_TAC[
NOT_FORALL_THM] THEN EXISTS_TAC `d:num` THEN
REWRITE_TAC[NOT_IMP;
RIGHT_AND_EXISTS_THM] THEN
EXISTS_TAC `q + 1` THEN REWRITE_TAC[
RIGHT_ADD_DISTRIB] THEN
REWRITE_TAC[
MULT_CLAUSES;
ADD_ASSOC;
LT_ADDR] THEN
ASM_REWRITE_TAC[GSYM
NOT_LE;
LE]);;
"MOD"]
(REWRITE_RULE[SKOLEM_THM] DIVMOD_EXIST_0);;
let DIVISION = prove
(`!m n. ~(n = 0) ==> (m = m DIV n * n + m MOD n) /\ m MOD n < n`,
let DIVISION_SIMP = prove
(`(!m n. ~(n = 0) ==> m DIV n * n + m MOD n = m) /\
(!m n. ~(n = 0) ==> n * m DIV n + m MOD n = m)`,
let DIVMOD_UNIQ_LEMMA = prove
(`!m n q1 r1 q2 r2. ((m = q1 * n + r1) /\ r1 < n) /\
((m = q2 * n + r2) /\ r2 < n)
==> (q1 = q2) /\ (r1 = r2)`,
REPEAT GEN_TAC THEN STRIP_TAC THEN
SUBGOAL_THEN `r1:num = r2` MP_TAC THENL
[UNDISCH_TAC `m = q2 * n + r2` THEN
ASM_REWRITE_TAC[] THEN
DISJ_CASES_THEN MP_TAC (SPECL [`q1:num`; `q2:num`]
LE_CASES) THEN
DISCH_THEN(X_CHOOSE_THEN `d:num` SUBST1_TAC o REWRITE_RULE[
LE_EXISTS]) THEN
REWRITE_TAC[
RIGHT_ADD_DISTRIB; GSYM
ADD_ASSOC;
EQ_ADD_LCANCEL] THENL
[DISCH_TAC THEN UNDISCH_TAC `r1 < n`;
DISCH_THEN(ASSUME_TAC o SYM) THEN UNDISCH_TAC `r2 < n`] THEN
ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[
MULT_SYM] THEN
SPEC_TAC(`d:num`,`d:num`) THEN INDUCT_TAC THEN
REWRITE_TAC[
ADD_CLAUSES;
MULT_CLAUSES;
GSYM
NOT_LE;
LE_ADD; GSYM
ADD_ASSOC];
DISCH_THEN SUBST_ALL_TAC THEN REWRITE_TAC[] THEN
CONV_TAC SYM_CONV THEN
UNDISCH_TAC `m = q1 * n + r2` THEN
ASM_REWRITE_TAC[
EQ_ADD_RCANCEL;
EQ_MULT_RCANCEL] THEN
REPEAT (UNDISCH_TAC `r2 < n`) THEN
ASM_CASES_TAC `n = 0` THEN ASM_REWRITE_TAC[GSYM
NOT_LE;
LE_0]]);;
let DIVMOD_UNIQ = prove
(`!m n q r. (m = q * n + r) /\ r < n ==> (m DIV n = q) /\ (m MOD n = r)`,
REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN ASSUME_TAC o GSYM) THEN
MATCH_MP_TAC
DIVMOD_UNIQ_LEMMA THEN
MAP_EVERY EXISTS_TAC [`m:num`; `n:num`] THEN ASM_REWRITE_TAC[] THEN
MATCH_MP_TAC
DIVISION THEN
DISCH_TAC THEN UNDISCH_TAC `r < n` THEN
ASM_REWRITE_TAC[GSYM
NOT_LE;
LE_0]);;
let MOD_UNIQ = prove
(`!m n q r. (m = q * n + r) /\ r < n ==> (m MOD n = r)`,
REPEAT GEN_TAC THEN
DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP
DIVMOD_UNIQ th]));;
let DIV_UNIQ = prove
(`!m n q r. (m = q * n + r) /\ r < n ==> (m DIV n = q)`,
REPEAT GEN_TAC THEN
DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP
DIVMOD_UNIQ th]));;
let DIV_MULT,MOD_MULT = (CONJ_PAIR o prove)
(`(!m n. ~(m = 0) ==> (m * n) DIV m = n) /\
(!m n. ~(m = 0) ==> (m * n) MOD m = 0)`,
SIMP_TAC[AND_FORALL_THM; TAUT `(a ==> b) /\ (a ==> c) <=> a ==> b /\ c`] THEN
REPEAT GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC DIVMOD_UNIQ THEN
ASM_REWRITE_TAC[MULT_CLAUSES; ADD_CLAUSES; MULT_AC; LT_NZ]);;
let MOD_EQ = prove
(`!m n p q. (m = n + q * p) ==> (m MOD p = n MOD p)`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `p = 0` THENL
[ASM_REWRITE_TAC[
MULT_CLAUSES;
ADD_CLAUSES] THEN
DISCH_THEN SUBST1_TAC THEN REFL_TAC;
DISCH_THEN SUBST1_TAC THEN
MATCH_MP_TAC
MOD_UNIQ THEN
EXISTS_TAC `q + n DIV p` THEN
POP_ASSUM(MP_TAC o MATCH_MP
DIVISION) THEN
DISCH_THEN(STRIP_ASSUME_TAC o GSYM o SPEC `n:num`) THEN
ASM_REWRITE_TAC[
RIGHT_ADD_DISTRIB; GSYM
ADD_ASSOC] THEN
MATCH_ACCEPT_TAC
ADD_SYM]);;
let DIV_LE = prove
(`!m n. ~(n = 0) ==> m DIV n <= m`,
REPEAT STRIP_TAC THEN
FIRST_ASSUM(fun th -> GEN_REWRITE_TAC RAND_CONV [MATCH_MP
DIVISION th]) THEN
UNDISCH_TAC `~(n = 0)` THEN SPEC_TAC(`n:num`,`n:num`) THEN
INDUCT_TAC THEN REWRITE_TAC[
MULT_CLAUSES; GSYM
ADD_ASSOC;
LE_ADD]);;
let DIV_MUL_LE = prove
(`!m n. n * (m DIV n) <= m`,
REPEAT GEN_TAC THEN ASM_CASES_TAC `n = 0` THEN
ASM_REWRITE_TAC[
MULT_CLAUSES;
LE_0] THEN
POP_ASSUM(MP_TAC o SPEC `m:num` o MATCH_MP
DIVISION) THEN
DISCH_THEN(fun th -> GEN_REWRITE_TAC RAND_CONV [CONJUNCT1 th]) THEN
REWRITE_TAC[
LE_ADD;
MULT_AC]);;
let DIV_0,MOD_0 = (CONJ_PAIR o prove)
(`(!n. ~(n = 0) ==> 0 DIV n = 0) /\
(!n. ~(n = 0) ==> 0 MOD n = 0)`,
SIMP_TAC[AND_FORALL_THM; TAUT `(a ==> b) /\ (a ==> c) <=> a ==> b /\ c`] THEN
GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC DIVMOD_UNIQ THEN
ASM_REWRITE_TAC[MULT_CLAUSES; ADD_CLAUSES; LT_NZ]);;
let DIV_1,MOD_1 = (CONJ_PAIR o prove)
(`(!n. n DIV 1 = n) /\ (!n. n MOD 1 = 0)`,
SIMP_TAC[AND_FORALL_THM] THEN GEN_TAC THEN MATCH_MP_TAC DIVMOD_UNIQ THEN
REWRITE_TAC[MULT_CLAUSES; ADD_CLAUSES] THEN REWRITE_TAC[ONE; LT]);;
let MOD_MOD = prove
(`!m n p. ~(n * p = 0) ==> ((m MOD (n * p)) MOD n = m MOD n)`,
REPEAT GEN_TAC THEN REWRITE_TAC[
MULT_EQ_0; DE_MORGAN_THM] THEN STRIP_TAC THEN
CONV_TAC SYM_CONV THEN MATCH_MP_TAC
MOD_EQ THEN
EXISTS_TAC `m DIV (n * p) * p` THEN
MP_TAC(SPECL [`m:num`; `n * p:num`]
DIVISION) THEN
ASM_REWRITE_TAC[
MULT_EQ_0;
MULT_AC;
ADD_AC] THEN
DISCH_THEN(fun th -> REWRITE_TAC[GSYM th]));;
let MOD_MULT2 = prove
(`!m n p. ~(m * p = 0) ==> ((m * n) MOD (m * p) = m * n MOD p)`,
let MOD_EXISTS = prove
(`!m n. (?q. m = n * q) <=> if n = 0 then (m = 0) else (m MOD n = 0)`,
REPEAT GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[
MULT_CLAUSES] THEN
EQ_TAC THEN STRIP_TAC THEN ASM_SIMP_TAC[MOD_MULT] THEN
EXISTS_TAC `m DIV n` THEN
SUBGOAL_THEN `m = (m DIV n) * n + m MOD n`
(fun th -> GEN_REWRITE_TAC LAND_CONV [th]) THENL
[ASM_MESON_TAC[
DIVISION]; ASM_REWRITE_TAC[
ADD_CLAUSES;
MULT_AC]]);;
let DIV_MONO = prove
(`!m n p. ~(p = 0) /\ m <= n ==> m DIV p <= n DIV p`,
REPEAT STRIP_TAC THEN
MATCH_MP_TAC(MESON[
LE_REFL] `(!k:num. k <= a ==> k <= b) ==> a <= b`) THEN
ASM_SIMP_TAC[
LE_RDIV_EQ] THEN ASM_MESON_TAC[
LE_TRANS]);;
let MOD_EXP_MOD = prove
(`!m n p. ~(n = 0) ==> (((m MOD n)
EXP p) MOD n = (m
EXP p) MOD n)`,
REPEAT STRIP_TAC THEN SPEC_TAC(`p:num`,`p:num`) THEN
INDUCT_TAC THEN ASM_REWRITE_TAC[
EXP] THEN ASM_SIMP_TAC[
MOD_MULT_LMOD] THEN
MATCH_MP_TAC
EQ_TRANS THEN
EXISTS_TAC `(m * ((m MOD n)
EXP p) MOD n) MOD n` THEN CONJ_TAC THENL
[ALL_TAC; ASM_REWRITE_TAC[]] THEN
ASM_SIMP_TAC[
MOD_MULT_RMOD]);;
let MOD_ADD_MOD = prove
(`!a b n. ~(n = 0) ==> ((a MOD n + b MOD n) MOD n = (a + b) MOD n)`,
REPEAT STRIP_TAC THEN CONV_TAC SYM_CONV THEN MATCH_MP_TAC
MOD_EQ THEN
EXISTS_TAC `a DIV n + b DIV n` THEN REWRITE_TAC[
RIGHT_ADD_DISTRIB] THEN
ONCE_REWRITE_TAC[AC
ADD_AC `(a + b) + (c + d) = (c + a) + (d + b)`] THEN
BINOP_TAC THEN ASM_SIMP_TAC[
DIVISION]);;
let DIV_ADD_MOD = prove
(`!a b n. ~(n = 0)
==> (((a + b) MOD n = a MOD n + b MOD n) <=>
((a + b) DIV n = a DIV n + b DIV n))`,
REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP
DIVISION) THEN
DISCH_THEN(fun th -> MAP_EVERY (MP_TAC o CONJUNCT1 o C SPEC th)
[`a + b:num`; `a:num`; `b:num`]) THEN
DISCH_THEN(fun th1 -> DISCH_THEN(fun th2 ->
MP_TAC(MK_COMB(AP_TERM `(+)` th2,th1)))) THEN
DISCH_THEN(fun th -> GEN_REWRITE_TAC (funpow 2 LAND_CONV) [th]) THEN
ONCE_REWRITE_TAC[AC
ADD_AC `(a + b) + c + d = (a + c) + (b + d)`] THEN
REWRITE_TAC[GSYM
RIGHT_ADD_DISTRIB] THEN
DISCH_THEN(fun th -> EQ_TAC THEN DISCH_TAC THEN MP_TAC th) THEN
ASM_REWRITE_TAC[
EQ_ADD_RCANCEL;
EQ_ADD_LCANCEL;
EQ_MULT_RCANCEL] THEN
REWRITE_TAC[
EQ_SYM_EQ]);;
let DIV_REFL = prove
(`!n. ~(n = 0) ==> (n DIV n = 1)`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC
DIV_UNIQ THEN
EXISTS_TAC `0` THEN REWRITE_TAC[
ADD_CLAUSES;
MULT_CLAUSES] THEN
POP_ASSUM MP_TAC THEN SPEC_TAC(`n:num`,`n:num`) THEN
INDUCT_TAC THEN REWRITE_TAC[
LT_0]);;
let MOD_LE = prove
(`!m n. ~(n = 0) ==> m MOD n <= m`,
REPEAT GEN_TAC THEN
DISCH_THEN(fun th -> GEN_REWRITE_TAC RAND_CONV
[MATCH_MP
DIVISION th]) THEN
ONCE_REWRITE_TAC[
ADD_SYM] THEN REWRITE_TAC[
LE_ADD]);;
let MULT_DIV_LE = prove
(`!m n p. ~(p = 0) ==> m * (n DIV p) <= (m * n) DIV p`,
REPEAT GEN_TAC THEN SIMP_TAC[
LE_RDIV_EQ] THEN
DISCH_THEN(MP_TAC o SPEC `n:num` o MATCH_MP
DIVISION) THEN
DISCH_THEN(fun th ->
GEN_REWRITE_TAC (RAND_CONV o RAND_CONV) [CONJUNCT1 th]) THEN
REWRITE_TAC[
LEFT_ADD_DISTRIB] THEN REWRITE_TAC[
MULT_AC;
LE_ADD]);;
let DIV_DIV = prove
(`!m n p. ~(n * p = 0) ==> ((m DIV n) DIV p = m DIV (n * p))`,
let DIV_MOD = prove
(`!m n p. ~(n * p = 0) ==> ((m DIV n) MOD p = (m MOD (n * p)) DIV n)`,
(* ------------------------------------------------------------------------- *)
(* Theorems for eliminating cutoff subtraction, predecessor, DIV and MOD. *)
(* We have versions that introduce universal or existential quantifiers. *)
(* ------------------------------------------------------------------------- *)
let DIVMOD_ELIM_THM = prove
(`P (m DIV n) (m MOD n) <=>
!q r. n = 0 /\ q = 0 /\ r = m \/ m = q * n + r /\ r < n ==> P q r`,
let DIVMOD_ELIM_THM' = prove
(`P (m DIV n) (m MOD n) <=>
?q r. (n = 0 /\ q = 0 /\ r = m \/ m = q * n + r /\ r < n) /\ P q r`,
MP_TAC(INST [`\x:num y:num. ~P x y`,`P:num->num->bool`]
DIVMOD_ELIM_THM) THEN
MESON_TAC[]);;
(* ------------------------------------------------------------------------- *)
(* Crude but useful conversion for cancelling down equations. *)
(* ------------------------------------------------------------------------- *)
let NUM_CANCEL_CONV =
let rec minter i l1' l2' l1 l2 =
if l1 = [] then (i,l1',l2'@l2)
else if l2 = [] then (i,l1@l1',l2') else
let h1 = hd l1 and h2 = hd l2 in
if h1 = h2 then minter (h1::i) l1' l2' (tl l1) (tl l2)
else if h1 < h2 then minter i (h1::l1') l2' (tl l1) l2
else minter i l1' (h2::l2') l1 (tl l2) in
let add_tm = `(+)` and eq_tm = `(=) :num->num->bool` in
let EQ_ADD_LCANCEL_0' =
GEN_REWRITE_RULE (funpow 2 BINDER_CONV o LAND_CONV) [EQ_SYM_EQ]
EQ_ADD_LCANCEL_0 in
let AC_RULE = AC ADD_AC in
fun tm ->
let l,r = dest_eq tm in
let lats = sort (<=) (binops `(+)` l)
and rats = sort (<=) (binops `(+)` r) in
let i,lats',rats' = minter [] [] [] lats rats in
let l' = list_mk_binop add_tm (i @ lats')
and r' = list_mk_binop add_tm (i @ rats') in
let lth = AC_RULE (mk_eq(l,l'))
and rth = AC_RULE (mk_eq(r,r')) in
let eth = MK_COMB(AP_TERM eq_tm lth,rth) in
GEN_REWRITE_RULE (RAND_CONV o REPEATC)
[EQ_ADD_LCANCEL; EQ_ADD_LCANCEL_0; EQ_ADD_LCANCEL_0'] eth;;
(* ------------------------------------------------------------------------- *)
(* This is handy for easing MATCH_MP on inequalities. *)
(* ------------------------------------------------------------------------- *)
let LE_IMP =
let pth = PURE_ONCE_REWRITE_RULE[IMP_CONJ] LE_TRANS in
fun th -> GEN_ALL(MATCH_MP pth (SPEC_ALL th));;
(* ------------------------------------------------------------------------- *)
(* Binder for "the minimal n such that". *)
(* ------------------------------------------------------------------------- *)
parse_as_binder "minimal";;
let MINIMAL = prove
(`!P. (?n. P n) <=> P((minimal) P) /\ (!m. m < (minimal) P ==> ~(P m))`,
GEN_TAC THEN REWRITE_TAC[minimal] THEN CONV_TAC(RAND_CONV SELECT_CONV) THEN
REWRITE_TAC[GSYM
num_WOP]);;
(* ------------------------------------------------------------------------- *)
(* A common lemma for transitive relations. *)
(* ------------------------------------------------------------------------- *)
let TRANSITIVE_STEPWISE_LE = prove
(`!R. (!x. R x x) /\ (!x y z. R x y /\ R y z ==> R x z) /\
(!n. R n (SUC n))
==> !m n. m <= n ==> R m n`,
REPEAT GEN_TAC THEN MATCH_MP_TAC(TAUT
`(a /\ a' ==> (c <=> b)) ==> a /\ a' /\ b ==> c`) THEN
MATCH_ACCEPT_TAC
TRANSITIVE_STEPWISE_LE_EQ);;