(* ========================================================================= *)
(* Binomial coefficients and the binomial theorem.                           *)
(* ========================================================================= *)
prioritize_num();;
(* ------------------------------------------------------------------------- *)
(* Binomial coefficients.                                                    *)
(* ------------------------------------------------------------------------- *)
let binom = define
  `(!n. binom(n,0) = 1) /\
   (!k. binom(0,SUC(k)) = 0) /\
   (!n k. binom(SUC(n),SUC(k)) = binom(n,SUC(k)) + binom(n,k))`;;
let BINOM_0 = prove
 (`!n. binom(0,n) = if n = 0 then 1 else 0`,
  INDUCT_TAC THEN REWRITE_TAC[binom; 
NOT_SUC]);;
 
let BINOM_LT = prove
 (`!n k. n < k ==> (binom(n,k) = 0)`,
  INDUCT_TAC THEN INDUCT_TAC THEN REWRITE_TAC[binom; ARITH; 
LT_SUC; 
LT] THEN
  ASM_SIMP_TAC[ARITH_RULE `n < k ==> n < SUC(k)`; ARITH]);;
 
let BINOM_1 = prove
 (`!n. binom(n,1) = n`,
  REWRITE_TAC[num_CONV `1`] THEN
  INDUCT_TAC THEN ASM_REWRITE_TAC[binom] THEN ARITH_TAC);;
 
let BINOM_GE_TOP = prove
 (`!m n. 1 <= m /\ m < n ==> n <= binom(n,m)`,
  INDUCT_TAC THEN INDUCT_TAC THEN REWRITE_TAC[binom] THEN
  CONV_TAC NUM_REDUCE_CONV THEN STRIP_TAC THEN ASM_CASES_TAC `m = 0` THEN
  ASM_SIMP_TAC[
BINOM_1; 
ARITH_SUC; binom] THEN REWRITE_TAC[
ADD1; 
LE_REFL] THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `n:num`) THEN
  ANTS_TAC THENL [ASM_ARITH_TAC; ALL_TAC] THEN
  MATCH_MP_TAC(ARITH_RULE `~(c = 0) ==> n <= b ==> n + 1 <= c + b`) THEN
  REWRITE_TAC[
BINOM_EQ_0] THEN ASM_ARITH_TAC);;
 
let BINOM_TOP_STEP_REAL = prove
 (`!n k. &(binom(n + 1,k)) =
           if k = n + 1 then &1
           else (&n + &1) / (&n + &1 - &k) * &(binom(n,k))`,
  REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[
BINOM_REFL] THEN
  FIRST_X_ASSUM(STRIP_ASSUME_TAC o MATCH_MP (ARITH_RULE
   `~(k = n + 1) ==> n < k /\ n + 1 < k \/ k <= n /\ k <= n + 1`)) THEN
  ASM_SIMP_TAC[
BINOM_LT; 
REAL_MUL_RZERO] THEN
  MP_TAC(SPECL [`n:num`; `k:num`] 
BINOM_TOP_STEP) THEN
  ASM_SIMP_TAC[GSYM REAL_OF_NUM_EQ; GSYM REAL_OF_NUM_MUL; GSYM REAL_OF_NUM_ADD;
               GSYM 
REAL_OF_NUM_SUB] THEN
  UNDISCH_TAC `k <= n:num` THEN REWRITE_TAC[GSYM REAL_OF_NUM_LE] THEN
  CONV_TAC REAL_FIELD);;
 
let BINOM_BOTTOM_STEP_REAL = prove
 (`!n k. &(binom(n,k+1)) = (&n - &k) / (&k + &1) * &(binom(n,k))`,
  REPEAT GEN_TAC THEN DISJ_CASES_TAC(ARITH_RULE `n:num < k \/ k <= n`) THENL
   [ASM_SIMP_TAC[
BINOM_LT; ARITH_RULE `n < k ==> n < k + 1`; 
REAL_MUL_RZERO];
    MP_TAC(SPECL [`n:num`; `k:num`] 
BINOM_BOTTOM_STEP) THEN
    ASM_SIMP_TAC[GSYM REAL_OF_NUM_EQ; GSYM REAL_OF_NUM_MUL;
                 GSYM REAL_OF_NUM_ADD; GSYM 
REAL_OF_NUM_SUB] THEN
    CONV_TAC REAL_FIELD]);;
 
let BINOM_BOTH_STEP = prove
 (`!p k. (k + 1) * binom(p + 1,k + 1) = (p + 1) * binom(p,k)`,
  REWRITE_TAC[GSYM REAL_OF_NUM_EQ; GSYM REAL_OF_NUM_MUL] THEN
  REWRITE_TAC[
BINOM_BOTH_STEP_REAL; GSYM REAL_OF_NUM_ADD] THEN
  CONV_TAC REAL_FIELD);;
 
let BINOM_SYM = prove
 (`!n k. binom(n,n-k) = if k <= n then binom(n,k) else 1`,
  REPEAT GEN_TAC THEN COND_CASES_TAC THEN
  ASM_SIMP_TAC[binom; ARITH_RULE `~(k <= n) ==> n - k = 0`] THEN
  REWRITE_TAC[GSYM REAL_OF_NUM_EQ; 
REAL_OF_NUM_BINOM] THEN
  ASM_REWRITE_TAC[ARITH_RULE `n - k:num <= n`] THEN
  ASM_SIMP_TAC[ARITH_RULE `k:num <= n ==> n - (n - k) = k`] THEN
  REWRITE_TAC[REAL_OF_NUM_MUL; 
MULT_SYM]);;
 
let BINOM_MUL_SHIFT = prove
 (`!m n k. k <= m
           ==> binom(n,m) * binom(m,k) = binom(n,k) * binom(n - k,m - k)`,
  REPEAT STRIP_TAC THEN
  SIMP_TAC[GSYM REAL_OF_NUM_EQ; GSYM REAL_OF_NUM_MUL; 
REAL_OF_NUM_BINOM] THEN
  ASM_CASES_TAC `n:num < m` THENL
   [REPEAT(COND_CASES_TAC THEN
      ASM_REWRITE_TAC[
REAL_MUL_LZERO; 
REAL_MUL_RZERO]) THEN
    MATCH_MP_TAC(TAUT `F ==> p`) THEN ASM_ARITH_TAC;
    REPEAT(COND_CASES_TAC THENL
     [ALL_TAC; MATCH_MP_TAC(TAUT `F ==> p`) THEN  ASM_ARITH_TAC]) THEN
    RULE_ASSUM_TAC(REWRITE_RULE[
NOT_LT]) THEN
    ASM_SIMP_TAC[ARITH_RULE
     `k:num <= m /\ m <= n ==> n - k - (m - k) = n - m`] THEN
    MAP_EVERY (MP_TAC o C SPEC 
FACT_NZ)
     [`n:num`; `m:num`; `n - m:num`; `n - k:num`; `m - k:num`] THEN
    REWRITE_TAC[GSYM REAL_OF_NUM_EQ] THEN CONV_TAC REAL_FIELD]);;
 
let APPELL_SEQUENCE = prove
 (`!c n x y. sum (0..n)
               (\k.  &(binom(n,k)) *
                     sum(0..k)
                        (\l. &(binom(k,l)) * c l * x pow (k - l)) *
                     y pow (n - k)) =
           sum (0..n) (\k. &(binom(n,k)) * c k * (x + y) pow (n - k))`,
 
let pth_step = prove
   (`binom(n,k) = y
     ==> k <= n
         ==> (SUC n) * y = ((n + 1) - k) * x ==> binom(SUC n,k) = x`,
    DISCH_THEN(SUBST1_TAC o SYM) THEN
    REWRITE_TAC[
ADD1; GSYM 
BINOM_TOP_STEP; 
EQ_MULT_LCANCEL; 
SUB_EQ_0] THEN
    ARITH_TAC)
  and 
pth_0 = 
prove
   (`n < k ==> binom(n,k) = 0`,
    REWRITE_TAC[
BINOM_LT])
  and 
pth_1 = 
prove
   (`binom(n,n) = 1`,
    REWRITE_TAC[
BINOM_REFL])
  and pth_swap = 
prove
   (`k <= n ==> binom(n,k) = binom(n,n - k)`,
    MESON_TAC[
BINOM_SYM])
  and k_tm = `k:num` and n_tm = `n:num`
  and x_tm = `x:num` and y_tm = `y:num`
  and binom_tm = `binom` in
  let rec BINOM_RULE(n,k) =
    if n </ k then
      let th = INST [mk_numeral n,n_tm; mk_numeral k,k_tm] 
pth_0 in
      MP_CONV NUM_LT_CONV th
    else if n =/ k then
      INST [mk_numeral n,n_tm] 
pth_1
    else if Int 2 */ k </ n then
      let th1 = INST [mk_numeral n,n_tm; mk_numeral k,k_tm] pth_swap in
      let th2 = MP th1 (EQT_ELIM(NUM_LE_CONV (lhand(concl th1)))) in
      let th3 = CONV_RULE(funpow 3 RAND_CONV NUM_SUB_CONV) th2 in
      TRANS th3 (BINOM_RULE(n,n -/ k))
    else
      let th1 = BINOM_RULE(n -/ Int 1,k) in
      let y = dest_numeral(rand(concl th1)) in
      let x = (n // (n -/ k)) */ y in
      let th2 = INST [mk_numeral(n -/ Int 1),n_tm; mk_numeral k,k_tm;
                      mk_numeral x,x_tm; mk_numeral y,y_tm] 
pth_step in
      let th3 = MP_CONV NUM_REDUCE_CONV (MP_CONV NUM_LE_CONV (MP th2 th1)) in
      CONV_RULE (LAND_CONV(RAND_CONV(LAND_CONV NUM_SUC_CONV))) th3 in
  fun tm ->
    let bop,nkp = dest_comb tm in
    if bop <> binom_tm then failwith "NUM_BINOM_CONV" else
    let nt,kt = dest_pair nkp in
    BINOM_RULE(dest_numeral nt,dest_numeral kt);;