(* ========================================================================= *)
(* 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). *)
(* ------------------------------------------------------------------------- *)