(* ========================================================================= *)
(* Perfect number theorems.                                                  *)
(* ========================================================================= *)
needs "Library/prime.ml";;
prioritize_num();;
(* ------------------------------------------------------------------------- *)
(* The sum-of-divisors function.                                             *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Definition of perfection.                                                 *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Various number-theoretic lemmas.                                          *)
(* ------------------------------------------------------------------------- *)
let EVEN_ODD_DECOMP = prove
 (`!n. ~(n = 0) ==> ?r s. 
ODD s /\ n = 2 
EXP r * s`,
  MATCH_MP_TAC 
num_WF THEN X_GEN_TAC `n:num` THEN
  MP_TAC(SPEC `n:num` 
EVEN_OR_ODD) THEN
  REWRITE_TAC[
EVEN_EXISTS; 
ODD_EXISTS] THEN
  DISCH_THEN(DISJ_CASES_THEN (X_CHOOSE_THEN `m:num` SUBST_ALL_TAC)) THENL
   [DISCH_THEN(MP_TAC o SPEC `m:num`) THEN
    REWRITE_TAC[
MULT_EQ_0; ARITH; ARITH_RULE `m < 2 * m <=> ~(m = 0)`] THEN
    ASM_CASES_TAC `m = 0` THEN ASM_REWRITE_TAC[] THEN
    ONCE_REWRITE_TAC[
SWAP_EXISTS_THM] THEN MATCH_MP_TAC 
MONO_EXISTS THEN
    X_GEN_TAC `s:num` THEN DISCH_THEN(X_CHOOSE_TAC `r:num`) THEN
    EXISTS_TAC `SUC r` THEN ASM_REWRITE_TAC[
EXP; GSYM 
MULT_ASSOC];
    REPEAT(DISCH_THEN(K ALL_TAC)) THEN EXISTS_TAC `0` THEN
    REWRITE_TAC[
EXP; 
MULT_CLAUSES] THEN MESON_TAC[]]);;
 
 
let MULT_EQ_COPRIME = prove
 (`!a b x y. a * b = x * y /\ coprime(a,x)
             ==> ?d. y = a * d /\ b = x * d`,
  REPEAT STRIP_TAC THEN
  MP_TAC(SPECL [`a:num`; `x:num`; `y:num`] 
COPRIME_DIVPROD) THEN
  MP_TAC(SPECL [`x:num`; `a:num`; `b:num`] 
COPRIME_DIVPROD) THEN
  REPEAT(ANTS_TAC THENL
   [ASM_MESON_TAC[
DIVIDES_REFL; 
DIVIDES_RMUL; 
COPRIME_SYM];
    REWRITE_TAC[divides] THEN STRIP_TAC]) THEN
  UNDISCH_TAC `a * b = x * y` THEN ASM_REWRITE_TAC[] THEN
  REWRITE_TAC[ARITH_RULE
    `(a * x * u = x * a * v) <=> (a * x) * u = (a * x) * v`] THEN
  REWRITE_TAC[
EQ_MULT_LCANCEL; 
MULT_EQ_0] THEN ASM_MESON_TAC[]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Some elementary properties of the sigma function.                         *)
(* ------------------------------------------------------------------------- *)
let SIGMA_PRIME_EQ = prove
 (`!p. prime(p) <=> sigma(p) = p + 1`,
  GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[
SIGMA_PRIME] THEN
  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN
  REWRITE_TAC[prime; DE_MORGAN_THM] THEN
  ASM_CASES_TAC `p = 1` THEN ASM_REWRITE_TAC[
SIGMA_1; ARITH] THEN
  REWRITE_TAC[
NOT_FORALL_THM; NOT_IMP; divides; DE_MORGAN_THM] THEN
  DISCH_THEN(X_CHOOSE_THEN `a:num` (CONJUNCTS_THEN2 MP_TAC ASSUME_TAC)) THEN
  DISCH_THEN(X_CHOOSE_THEN `b:num` SUBST_ALL_TAC) THEN
  MP_TAC(SPECL [`a:num`; `b:num`] 
SIGMA_MULT) THEN
  ASM_CASES_TAC `a = 0` THEN ASM_REWRITE_TAC[
MULT_CLAUSES; 
SIGMA_0; ARITH] THEN
  ASM_CASES_TAC `b = 0` THEN ASM_REWRITE_TAC[
MULT_CLAUSES; 
SIGMA_0; ARITH] THEN
  REPEAT(POP_ASSUM MP_TAC) THEN REWRITE_TAC[
MULT_EQ_1] THEN
  ONCE_REWRITE_TAC[ARITH_RULE `a = a * b <=> a * b = a * 1`] THEN
  REWRITE_TAC[
EQ_MULT_LCANCEL] THEN ARITH_TAC);;
 
 
(* ------------------------------------------------------------------------- *)
(* Multiplicativity of sigma, the most interesting property.                 *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Hence the main theorems.                                                  *)
(* ------------------------------------------------------------------------- *)
let PERFECT_EULER = prove
 (`!n. 
EVEN(n) /\ perfect(n)
       ==> ?k. prime(2 
EXP k - 1) /\ n = 2 
EXP (k - 1) * (2 
EXP k - 1)`,
  GEN_TAC THEN MP_TAC(SPEC `n:num` 
EVEN_ODD_DECOMP) THEN
  ASM_CASES_TAC `n = 0` THENL
   [ASM_REWRITE_TAC[perfect]; ASM_REWRITE_TAC[]] THEN
  REWRITE_TAC[
LEFT_IMP_EXISTS_THM; GSYM 
NOT_EVEN] THEN
  MAP_EVERY X_GEN_TAC [`r:num`; `s:num`] THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC SUBST_ALL_TAC) THEN
  ASM_REWRITE_TAC[
EVEN_EXP; 
EVEN_MULT; ARITH] THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  REWRITE_TAC[perfect] THEN
  ASM_SIMP_TAC[
SIGMA_MULTIPLICATIVE; 
SIGMA_POW2;
               
COPRIME_ODD_POW2; GSYM 
NOT_EVEN] THEN
  DISCH_TAC THEN EXISTS_TAC `r + 1` THEN
  REWRITE_TAC[
ADD_SUB; 
EQ_MULT_LCANCEL] THEN REWRITE_TAC[
EXP_EQ_0; ARITH] THEN
  FIRST_X_ASSUM(MP_TAC o check(is_eq o concl)) THEN
  REWRITE_TAC[
MULT_ASSOC; GSYM(CONJUNCT2 
EXP); 
ADD1] THEN
  DISCH_THEN(MP_TAC o MATCH_MP
    (REWRITE_RULE[
IMP_CONJ] 
MULT_EQ_COPRIME)) THEN
  ANTS_TAC THENL
   [ONCE_REWRITE_TAC[
COPRIME_SYM] THEN MATCH_MP_TAC 
COPRIME_ODD_POW2 THEN
    SIMP_TAC[
ODD_POW2_MINUS1; 
ADD_EQ_0; 
ARITH_EQ];
    ALL_TAC] THEN
  DISCH_THEN(X_CHOOSE_THEN `d:num` MP_TAC) THEN
  ASM_CASES_TAC `d = 0` THEN ASM_REWRITE_TAC[
MULT_CLAUSES] THENL
   [ASM_MESON_TAC[
EVEN]; ALL_TAC] THEN
  ASM_CASES_TAC `d = 1` THENL
   [ASM_REWRITE_TAC[
MULT_CLAUSES; 
SIGMA_PRIME_EQ] THEN
    DISCH_THEN(CONJUNCTS_THEN2 (ASSUME_TAC o SYM) ASSUME_TAC) THEN
    ASM_REWRITE_TAC[] THEN EXPAND_TAC "s" THEN
    MATCH_MP_TAC(GSYM 
SUB_ADD) THEN
    REWRITE_TAC[ARITH_RULE `1 <= n <=> ~(n = 0)`; 
EXP_EQ_0; ARITH];
    ALL_TAC] THEN
  DISCH_THEN(CONJUNCTS_THEN2 (ASSUME_TAC o SYM) ASSUME_TAC) THEN
  MP_TAC(SPECL [`2 
EXP (r + 1) - 1`; `d:num`] 
SIGMA_MULT) THEN
  ASM_REWRITE_TAC[] THEN
  MATCH_MP_TAC(TAUT `a /\ ~b ==> (a ==> b) ==> c`) THEN
  REPEAT CONJ_TAC THENL
   [MATCH_MP_TAC(ARITH_RULE `2 
EXP 1 < a ==> 1 < a - 1`) THEN
    REWRITE_TAC[
LT_EXP; ARITH] THEN
    UNDISCH_TAC `~(r = 0)` THEN ARITH_TAC;
    MAP_EVERY UNDISCH_TAC [`~(d = 0)`; `~(d = 1)`] THEN ARITH_TAC;
    REWRITE_TAC[
NOT_LE] THEN EXPAND_TAC "s" THEN
    REWRITE_TAC[
RIGHT_SUB_DISTRIB; 
MULT_CLAUSES] THEN
    MATCH_MP_TAC(ARITH_RULE `1 * d < x * d ==> x * d < 1 + d + x * d - d`) THEN
    ASM_REWRITE_TAC[
LT_MULT_RCANCEL] THEN
    MATCH_MP_TAC(ARITH_RULE `2 
EXP 0 < a ==> 1 < a`) THEN
    REWRITE_TAC[
LT_EXP] THEN UNDISCH_TAC `~(r = 0)` THEN ARITH_TAC]);;