(* ========================================================================= *)
(* Integer congruences. *)
(* ========================================================================= *)
prioritize_int();;
(* ------------------------------------------------------------------------- *)
(* Combined rewrite, for later proofs. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Trivial consequences. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Congruence is an equivalence relation. *)
(* ------------------------------------------------------------------------- *)
let CONG_SYM = prove
(`!n x y. (x == y) (mod n) ==> (y == x) (mod n)`,
INTEGER_TAC);;
let CONG_TRANS = prove
(`!n x y z. (x == y) (mod n) /\ (y == z) (mod n) ==> (x == z) (mod n)`,
INTEGER_TAC);;
(* ------------------------------------------------------------------------- *)
(* Congruences are indeed congruences. *)
(* ------------------------------------------------------------------------- *)
let CONG_ADD = prove
(`!n x1 x2 y1 y2.
(x1 == x2) (mod n) /\ (y1 == y2) (mod n) ==> (x1 + y1 == x2 + y2) (mod n)`,
INTEGER_TAC);;
let CONG_NEG = prove
(`!n x1 x2. (x1 == x2) (mod n) ==> (--x1 == --x2) (mod n)`,
INTEGER_TAC);;
let CONG_SUB = prove
(`!n x1 x2 y1 y2.
(x1 == x2) (mod n) /\ (y1 == y2) (mod n) ==> (x1 - y1 == x2 - y2) (mod n)`,
INTEGER_TAC);;
let CONG_MUL = prove
(`!n x1 x2 y1 y2.
(x1 == x2) (mod n) /\ (y1 == y2) (mod n) ==> (x1 * y1 == x2 * y2) (mod n)`,
INTEGER_TAC);;
(* ------------------------------------------------------------------------- *)
(* Various other trivial properties of congruences. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Can choose a representative, either positive or with minimal magnitude. *)
(* ------------------------------------------------------------------------- *)
let CONG_REP_POS = prove
(`!n x. ~(n = &0) ==> ?y. &0 <= y /\ y < abs(n) /\ (x == y) (mod n)`,
REPEAT STRIP_TAC THEN
DISJ_CASES_TAC(INT_ARITH `&0 <= x \/ &0 <= --x`) THEN
ASM_SIMP_TAC[
CONG_REP_POS_POS] THEN
MP_TAC(SPECL [`n:int`; `--x`]
CONG_REP_POS_POS) THEN
ASM_REWRITE_TAC[] THEN
DISCH_THEN(X_CHOOSE_THEN `y:int` STRIP_ASSUME_TAC) THEN
ASM_CASES_TAC `y = &0` THENL
[EXISTS_TAC `y:int` THEN
FIRST_ASSUM(MP_TAC o MATCH_MP
CONG_NEG) THEN
ASM_REWRITE_TAC[
INT_NEG_0;
INT_NEG_NEG];
ALL_TAC] THEN
EXISTS_TAC `abs(n) - y` THEN
ASM_SIMP_TAC[INT_ARITH `y < abs(n) ==> &0 <= abs(n) - y`;
INT_ARITH `&0 <= y /\ ~(y = &0) ==> abs(n) - y < abs(n)`] THEN
FIRST_ASSUM(MP_TAC o MATCH_MP
CONG_NEG) THEN
DISCH_THEN(MP_TAC o MATCH_MP
CONG_SYM) THEN
DISCH_THEN(MP_TAC o CONJ (SPEC `abs n`
CONG_SELF)) THEN
REWRITE_TAC[
CONG_MOD_ABS] THEN
DISCH_THEN(MP_TAC o MATCH_MP
CONG_ADD) THEN
REWRITE_TAC[
INT_NEG_NEG;
INT_ADD_LID] THEN
MESON_TAC[INT_ARITH `x + --y = x - y`;
CONG_SYM]);;
let CONG_REP_MIN = prove
(`!n x. ~(n = &0)
==> ?y. --(abs n) <= &2 * y /\ &2 * y < abs n /\ (x == y) (mod n)`,
REPEAT STRIP_TAC THEN FIRST_ASSUM(MP_TAC o MATCH_MP
CONG_REP_POS) THEN
DISCH_THEN(X_CHOOSE_THEN `y:int` STRIP_ASSUME_TAC o SPEC `x:int`) THEN
MP_TAC(INT_ARITH
`&0 <= y /\ y < abs n
==> --(abs n) <= &2 * y /\ &2 * y < abs(n) \/
--(abs n) <= &2 * (y - abs(n)) /\ &2 * (y - abs(n)) < abs(n)`) THEN
ASM_REWRITE_TAC[] THEN STRIP_TAC THENL
[ASM_MESON_TAC[
CONG_REP_POS;
INT_LT_IMP_LE]; ALL_TAC] THEN
EXISTS_TAC `y - abs(n)` THEN ASM_REWRITE_TAC[] THEN
MP_TAC(SPEC `n:int`
CONG_SELF_ABS) THEN
DISCH_THEN(MP_TAC o MATCH_MP
CONG_SYM) THEN
UNDISCH_TAC `(x == y) (mod n)` THEN
REWRITE_TAC[IMP_IMP] THEN
DISCH_THEN(MP_TAC o MATCH_MP
CONG_SUB) THEN
REWRITE_TAC[INT_ARITH `x - &0 = x`]);;
let CONG_REP_MIN_ABS = prove
(`!n x. ~(n = &0) ==> ?y. &2 * abs(y) <= abs(n) /\ (x == y) (mod n)`,
REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP
CONG_REP_MIN) THEN
DISCH_THEN(MP_TAC o SPEC `x:int`) THEN MATCH_MP_TAC
MONO_EXISTS THEN
SIMP_TAC[] THEN INT_ARITH_TAC);;