(* ========================================================================= *)
(* Euler's partition theorem and other elementary partition theorems.        *)
(* ========================================================================= *)
loadt "Library/binary.ml";;
(* ------------------------------------------------------------------------- *)
(* Some lemmas.                                                              *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Breaking a number up into 2^something * odd_number.                       *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Partitions.                                                               *)
(* ------------------------------------------------------------------------- *)
parse_as_infix("partitions",(12,"right"));;
let PARTITIONS_BOUND = prove
 (`!p n. p partitions n ==> !i. p(i) <= n`,
  REWRITE_TAC[GSYM 
NOT_LT] THEN SIMP_TAC[partitions] THEN REPEAT STRIP_TAC THEN
  SUBGOAL_THEN `1 <= i /\ i <= n` STRIP_ASSUME_TAC THENL
   [ASM_MESON_TAC[ARITH_RULE `m < n ==> ~(n = 0)`]; ALL_TAC] THEN
  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (ARITH_RULE
   `m = n ==> n < m ==> F`)) THEN
  MATCH_MP_TAC 
LET_TRANS THEN
  EXISTS_TAC `nsum(1..n) (\j. if j = i then n else 0)` THEN CONJ_TAC THENL
   [ASM_REWRITE_TAC[
NSUM_DELTA; 
IN_NUMSEG; 
LE_REFL]; ALL_TAC] THEN
  MATCH_MP_TAC 
NSUM_LT THEN REWRITE_TAC[
FINITE_NUMSEG; 
IN_NUMSEG] THEN
  CONJ_TAC THENL
   [GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[
LE_0] THEN
    MATCH_MP_TAC 
LT_IMP_LE;
    EXISTS_TAC `i:num` THEN ASM_REWRITE_TAC[]] THEN
  MATCH_MP_TAC(ARITH_RULE `n < p /\ p * 1 <= p * k ==> n < p * k`) THEN
  ASM_REWRITE_TAC[
LE_MULT_LCANCEL]);;
 
 
let FINITE_PARTITIONS_LEMMA = prove
 (`!m n. 
FINITE {p | (!i. p(i) <= n) /\ !i. m <= i ==> p(i) = 0}`,
  INDUCT_TAC THEN GEN_TAC THENL
   [SIMP_TAC[
LE_0; TAUT `a /\ b <=> ~(b ==> ~a)`] THEN
    SUBGOAL_THEN `{p | !i:num. p i = 0} = {(\n. 0)}`
     (fun th -> SIMP_TAC[th; 
FINITE_RULES]) THEN
    REWRITE_TAC[
EXTENSION; 
IN_ELIM_THM; 
IN_SING] THEN REWRITE_TAC[
FUN_EQ_THM];
    ALL_TAC] THEN
  SUBGOAL_THEN
   `{p | (!i. p i <= n) /\ (!i. SUC m <= i ==> p i = 0)} =
    
IMAGE (\(a,p) j. if j = m then a else p(j))
        {a,p | a 
IN 0..n /\
               p 
IN {p | (!i. p i <= n) /\ (!i. m <= i ==> p i = 0)}}`
   (fun t -> ASM_SIMP_TAC[t; 
FINITE_IMAGE; 
FINITE_PRODUCT; 
FINITE_NUMSEG]) THEN
  REWRITE_TAC[
EXTENSION; 
IN_ELIM_THM; 
IN_IMAGE; 
EXISTS_PAIR_THM] THEN
  CONV_TAC(ONCE_DEPTH_CONV GEN_BETA_CONV) THEN X_GEN_TAC `p:num->num` THEN
  EQ_TAC THENL
   [STRIP_TAC THEN MAP_EVERY EXISTS_TAC
     [`(p:num->num) m`; `\i:num. if i = m then 0 else p i`] THEN
    REWRITE_TAC[
FUN_EQ_THM] THEN CONJ_TAC THENL [MESON_TAC[]; ALL_TAC] THEN
    ONCE_REWRITE_TAC[
CONJ_SYM] THEN ONCE_REWRITE_TAC[
SWAP_EXISTS_THM] THEN
    REWRITE_TAC[
PAIR_EQ; 
UNWIND_THM1; GSYM 
CONJ_ASSOC; 
IN_NUMSEG; 
LE_0] THEN
    ASM_MESON_TAC[
LE; ARITH_RULE `m <= i /\ ~(i = m) ==> SUC m <= i`];
    REWRITE_TAC[
LEFT_IMP_EXISTS_THM] THEN
    MAP_EVERY X_GEN_TAC [`a:num`; `q:num->num`] THEN
    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
    POP_ASSUM SUBST_ALL_TAC THEN REWRITE_TAC[
IN_NUMSEG] THEN
    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SYM) THEN
    REWRITE_TAC[
PAIR_EQ] THEN DISCH_THEN(CONJUNCTS_THEN SUBST_ALL_TAC) THEN
    ASM_MESON_TAC[ARITH_RULE `SUC m <= i ==> m <= i /\ ~(i = m)`]]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Mappings between "odd only" and "all distinct" partitions.                *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* The critical properties.                                                  *)
(* ------------------------------------------------------------------------- *)
let SUPPORT_DISTINCT_OF_ODD = prove
 (`!p. (!i. p(i) * i <= n) /\
       (!i. ~(p i = 0) ==> 
ODD i)
       ==> !i. ~(
distinct_of_odd p i = 0) ==> 1 <= i /\ i <= n`,
  REWRITE_TAC[
distinct_of_odd] THEN
  REWRITE_TAC[ARITH_RULE `(if a then 1 else 0) = 0 <=> ~a`] THEN
  GEN_TAC THEN STRIP_TAC THEN X_GEN_TAC `i:num` THEN REPEAT STRIP_TAC THENL
   [REWRITE_TAC[ARITH_RULE `1 <= i <=> ~(i = 0)`] THEN
    DISCH_THEN SUBST_ALL_TAC THEN
    UNDISCH_TAC `index 0 
IN bitset (p (oddpart 0))` THEN
    REWRITE_TAC[index; oddpart; ARITH] THEN
    UNDISCH_THEN `!i. ~(p i = 0) ==> 
ODD i` (MP_TAC o SPEC `0`) THEN
    SIMP_TAC[ARITH; 
BITSET_0; 
NOT_IN_EMPTY];
    ALL_TAC] THEN
  FIRST_X_ASSUM(ASSUME_TAC o MATCH_MP 
BITSET_BOUND_LEMMA) THEN
  MATCH_MP_TAC 
LE_TRANS THEN EXISTS_TAC `p(oddpart i) * oddpart i` THEN
  ASM_REWRITE_TAC[] THEN
  GEN_REWRITE_TAC LAND_CONV [
INDEX_ODDPART_DECOMPOSITION] THEN
  ASM_REWRITE_TAC[
LE_MULT_RCANCEL]);;
 
 
(* ------------------------------------------------------------------------- *)
(* Euler's partition theorem:                                                *)
(*                                                                           *)
(* The number of partitions into distinct numbers is equal to the number of  *)
(* partitions into odd numbers (and there are only finitely many of each).   *)
(* ------------------------------------------------------------------------- *)