(* ========================================================================= *)
(* Define integer sums, with most theorems derived automatically.            *)
(* ========================================================================= *)

let isum = new_definition
 `isum = iterate((+):int->int->int)`;;
let NEUTRAL_INT_ADD = 
prove (`neutral((+):int->int->int) = &0`,
REWRITE_TAC[neutral] THEN MATCH_MP_TAC SELECT_UNIQUE THEN MESON_TAC[INT_ADD_LID; INT_ADD_RID]);;
let MONOIDAL_INT_ADD = 
prove (`monoidal((+):int->int->int)`,
REWRITE_TAC[monoidal; NEUTRAL_INT_ADD] THEN INT_ARITH_TAC);;
let ISUM_SUPPORT = 
prove (`!f s. isum (support (+) f s) f = isum s f`,
REWRITE_TAC[isum; ITERATE_SUPPORT]);;
let int_isum = 
prove (`!f:A->int s. real_of_int(isum s f) = sum s (\x. real_of_int(f x))`,
REPEAT GEN_TAC THEN REWRITE_TAC[sum; isum] THEN ONCE_REWRITE_TAC[ITERATE_EXPAND_CASES] THEN SUBGOAL_THEN `support(+) (\x:A. real_of_int(f x)) s = support(+) f s` SUBST1_TAC THENL [REWRITE_TAC[support; NEUTRAL_REAL_ADD; NEUTRAL_INT_ADD] THEN REWRITE_TAC[GSYM int_of_num_th; GSYM int_eq]; ALL_TAC] THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[NEUTRAL_REAL_ADD; NEUTRAL_INT_ADD; int_of_num_th] THEN POP_ASSUM MP_TAC THEN SPEC_TAC(`support(+) (f:A->int) s`,`s:A->bool`) THEN MATCH_MP_TAC FINITE_INDUCT_STRONG THEN SIMP_TAC[ITERATE_CLAUSES; MONOIDAL_INT_ADD; MONOIDAL_REAL_ADD] THEN SIMP_TAC[NEUTRAL_INT_ADD; NEUTRAL_REAL_ADD; int_of_num_th; int_add_th]);;
(* ------------------------------------------------------------------------- *) (* Generalize INT_OF_REAL_THM for most common sum patterns. *) (* ------------------------------------------------------------------------- *) let INT_OF_REAL_THM = let dest = `real_of_int` and real_ty = `:real` and int_ty = `:int` and cond_th = prove (`real_of_int(if b then x else y) = if b then real_of_int x else real_of_int y`, COND_CASES_TAC THEN REWRITE_TAC[]) and compose_th = prove (`(\x. real_of_int((f o g) x)) = (\x. real_of_int(f x)) o g`, REWRITE_TAC[o_DEF]) in let thlist = map GSYM [int_eq; int_le; int_lt; int_ge; int_gt; int_of_num_th; int_neg_th; int_add_th; int_mul_th; int_sub_th; int_abs_th; int_max_th; int_min_th; int_pow_th; int_isum; GSYM BETA_THM; GSYM ETA_AX; compose_th; cond_th] in let REW_RULE = GEN_REWRITE_RULE REDEPTH_CONV thlist in let is_fun_into_real ty = try match dest_type ty with "fun",[s;t] when t = real_ty -> mk_fun_ty s int_ty | "real",[] -> int_ty | _ -> failwith "" with Failure _ -> ty in let int_of_real_ty ty = try match dest_type ty with "real",[] -> int_ty | "fun",[s;t] when t = real_ty -> mk_fun_ty s int_ty | _ -> ty with Failure _ -> ty in let int_tm_of_real_var v = let s,ty = dest_var v in let tys,rty = splitlist dest_fun_ty ty in if rty <> real_ty then v else let ity = itlist mk_fun_ty tys int_ty in let vs = map genvar tys in list_mk_abs(vs,mk_comb(dest,list_mk_comb(mk_var(s,ity),vs))) in let int_of_real_var v = let s,ty = dest_var v in let tys,rty = splitlist dest_fun_ty ty in if rty <> real_ty then v else let ity = itlist mk_fun_ty tys int_ty in mk_var(s,ity) in let INT_OF_REAL_THM1 th = let newavs = subtract (frees (concl th)) (freesl (hyp th)) in let avs,bod = strip_forall(concl th) in let allavs = newavs@avs in let avs' = map int_tm_of_real_var allavs in let avs'' = map int_of_real_var avs in GENL avs'' (REW_RULE(SPECL avs' (GENL newavs th))) in let rec INT_OF_REAL_THM th = if is_conj(concl th) then CONJ (INT_OF_REAL_THM1 (CONJUNCT1 th)) (INT_OF_REAL_THM1 (CONJUNCT2 th)) else INT_OF_REAL_THM1 th in INT_OF_REAL_THM;; (* ------------------------------------------------------------------------- *) (* Apply it in all the cases where it works. *) (* ------------------------------------------------------------------------- *)
let CARD_EQ_ISUM = INT_OF_REAL_THM CARD_EQ_SUM;;
let INT_SUB_POW = INT_OF_REAL_THM REAL_SUB_POW;;
let ISUM_0 = INT_OF_REAL_THM SUM_0;;
let ISUM_ABS = INT_OF_REAL_THM SUM_ABS;;
let ISUM_ABS_BOUND = INT_OF_REAL_THM SUM_ABS_BOUND;;
let ISUM_ABS_LE = INT_OF_REAL_THM SUM_ABS_LE;;
let ISUM_ABS_NUMSEG = INT_OF_REAL_THM SUM_ABS_NUMSEG;;
let ISUM_ADD = INT_OF_REAL_THM SUM_ADD;;
let ISUM_ADD_NUMSEG = INT_OF_REAL_THM SUM_ADD_NUMSEG;;
let ISUM_ADD_SPLIT = INT_OF_REAL_THM SUM_ADD_SPLIT;;
let ISUM_BIJECTION = INT_OF_REAL_THM SUM_BIJECTION;;
let ISUM_BOUND = INT_OF_REAL_THM SUM_BOUND;;
let ISUM_BOUND_LT = INT_OF_REAL_THM SUM_BOUND_LT;;
let ISUM_BOUND_LT_ALL = INT_OF_REAL_THM SUM_BOUND_LT_ALL;;
let ISUM_CASES = INT_OF_REAL_THM SUM_CASES;;
let ISUM_CLAUSES = INT_OF_REAL_THM SUM_CLAUSES;;
let ISUM_CLAUSES_LEFT = INT_OF_REAL_THM SUM_CLAUSES_LEFT;;
let ISUM_CLAUSES_NUMSEG = INT_OF_REAL_THM SUM_CLAUSES_NUMSEG;;
let ISUM_CLAUSES_RIGHT = INT_OF_REAL_THM SUM_CLAUSES_RIGHT;;
let ISUM_COMBINE_L = INT_OF_REAL_THM SUM_COMBINE_L;;
let ISUM_COMBINE_R = INT_OF_REAL_THM SUM_COMBINE_R;;
let ISUM_CONST = INT_OF_REAL_THM SUM_CONST;;
let ISUM_CONST_NUMSEG = INT_OF_REAL_THM SUM_CONST_NUMSEG;;
let ISUM_DELETE = INT_OF_REAL_THM SUM_DELETE;;
let ISUM_DELETE_CASES = INT_OF_REAL_THM SUM_DELETE_CASES;;
let ISUM_DELTA = INT_OF_REAL_THM SUM_DELTA;;
let ISUM_DIFF = INT_OF_REAL_THM SUM_DIFF;;
let ISUM_DIFFS = INT_OF_REAL_THM SUM_DIFFS;;
let ISUM_EQ = INT_OF_REAL_THM SUM_EQ;;
let ISUM_EQ_0 = INT_OF_REAL_THM SUM_EQ_0;;
let ISUM_EQ_0_NUMSEG = INT_OF_REAL_THM SUM_EQ_0_NUMSEG;;
let ISUM_EQ_GENERAL = INT_OF_REAL_THM SUM_EQ_GENERAL;;
let ISUM_EQ_GENERAL_INVERSES = INT_OF_REAL_THM SUM_EQ_GENERAL_INVERSES;;
let ISUM_EQ_NUMSEG = INT_OF_REAL_THM SUM_EQ_NUMSEG;;
let ISUM_EQ_SUPERSET = INT_OF_REAL_THM SUM_EQ_SUPERSET;;
let ISUM_GROUP = INT_OF_REAL_THM SUM_GROUP;;
let ISUM_IMAGE = INT_OF_REAL_THM SUM_IMAGE;;
let ISUM_IMAGE_GEN = INT_OF_REAL_THM SUM_IMAGE_GEN;;
let ISUM_IMAGE_LE = INT_OF_REAL_THM SUM_IMAGE_LE;;
let ISUM_IMAGE_NONZERO = INT_OF_REAL_THM SUM_IMAGE_NONZERO;;
let ISUM_INCL_EXCL = INT_OF_REAL_THM SUM_INCL_EXCL;;
let ISUM_INJECTION = INT_OF_REAL_THM SUM_INJECTION;;
let ISUM_LE = INT_OF_REAL_THM SUM_LE;;
let ISUM_LE_INCLUDED = INT_OF_REAL_THM SUM_LE_INCLUDED;;
let ISUM_LE_NUMSEG = INT_OF_REAL_THM SUM_LE_NUMSEG;;
let ISUM_LMUL = INT_OF_REAL_THM SUM_LMUL;;
let ISUM_LT = INT_OF_REAL_THM SUM_LT;;
let ISUM_LT_ALL = INT_OF_REAL_THM SUM_LT_ALL;;
let ISUM_MULTICOUNT = INT_OF_REAL_THM SUM_MULTICOUNT;;
let ISUM_MULTICOUNT_GEN = INT_OF_REAL_THM SUM_MULTICOUNT_GEN;;
let ISUM_NEG = INT_OF_REAL_THM SUM_NEG;;
let ISUM_OFFSET = INT_OF_REAL_THM SUM_OFFSET;;
let ISUM_OFFSET_0 = INT_OF_REAL_THM SUM_OFFSET_0;;
let ISUM_PARTIAL_PRE = INT_OF_REAL_THM SUM_PARTIAL_PRE;;
let ISUM_PARTIAL_SUC = INT_OF_REAL_THM SUM_PARTIAL_SUC;;
let ISUM_POS_BOUND = INT_OF_REAL_THM SUM_POS_BOUND;;
let ISUM_POS_EQ_0 = INT_OF_REAL_THM SUM_POS_EQ_0;;
let ISUM_POS_EQ_0_NUMSEG = INT_OF_REAL_THM SUM_POS_EQ_0_NUMSEG;;
let ISUM_POS_LE = INT_OF_REAL_THM SUM_POS_LE;;
let ISUM_POS_LE_NUMSEG = INT_OF_REAL_THM SUM_POS_LE_NUMSEG;;
let ISUM_RESTRICT = INT_OF_REAL_THM SUM_RESTRICT;;
let ISUM_RESTRICT_SET = INT_OF_REAL_THM SUM_RESTRICT_SET;;
let ISUM_RMUL = INT_OF_REAL_THM SUM_RMUL;;
let ISUM_SING = INT_OF_REAL_THM SUM_SING;;
let ISUM_SING_NUMSEG = INT_OF_REAL_THM SUM_SING_NUMSEG;;
let ISUM_SUB = INT_OF_REAL_THM SUM_SUB;;
let ISUM_SUBSET = INT_OF_REAL_THM SUM_SUBSET;;
let ISUM_SUBSET_SIMPLE = INT_OF_REAL_THM SUM_SUBSET_SIMPLE;;
let ISUM_SUB_NUMSEG = INT_OF_REAL_THM SUM_SUB_NUMSEG;;
let ISUM_ISUM_RESTRICT = INT_OF_REAL_THM SUM_SUM_RESTRICT;;
let ISUM_SUPERSET = INT_OF_REAL_THM SUM_SUPERSET;;
let ISUM_SWAP = INT_OF_REAL_THM SUM_SWAP;;
let ISUM_SWAP_NUMSEG = INT_OF_REAL_THM SUM_SWAP_NUMSEG;;
let ISUM_TRIV_NUMSEG = INT_OF_REAL_THM SUM_TRIV_NUMSEG;;
let ISUM_UNION = INT_OF_REAL_THM SUM_UNION;;
let ISUM_UNIONS_NONZERO = INT_OF_REAL_THM SUM_UNIONS_NONZERO;;
let ISUM_UNION_EQ = INT_OF_REAL_THM SUM_UNION_EQ;;
let ISUM_UNION_LZERO = INT_OF_REAL_THM SUM_UNION_LZERO;;
let ISUM_UNION_NONZERO = INT_OF_REAL_THM SUM_UNION_NONZERO;;
let ISUM_UNION_RZERO = INT_OF_REAL_THM SUM_UNION_RZERO;;
let ISUM_ZERO_EXISTS = INT_OF_REAL_THM SUM_ZERO_EXISTS;;
let REAL_OF_NUM_ISUM = INT_OF_REAL_THM REAL_OF_NUM_SUM;;
let REAL_OF_NUM_ISUM_NUMSEG = INT_OF_REAL_THM REAL_OF_NUM_SUM_NUMSEG;;
(* ------------------------------------------------------------------------- *) (* Manually derive the few cases where it doesn't. *) (* *) (* Note that SUM_BOUND_GEN and SUM_BOUND_LT_GEN don't seem to have immediate *) (* analogs over the integers since they involve division. *) (* *) (* Should really roll ADMISSIBLE_ISUM into "define" as well. *) (* ------------------------------------------------------------------------- *)
let ISUM_ISUM_PRODUCT = 
prove (`!s:A->bool t:A->B->bool x. FINITE s /\ (!i. i IN s ==> FINITE(t i)) ==> isum s (\i. isum (t i) (x i)) = isum {i,j | i IN s /\ j IN t i} (\(i,j). x i j)`,
REWRITE_TAC[isum] THEN MATCH_MP_TAC ITERATE_ITERATE_PRODUCT THEN REWRITE_TAC[MONOIDAL_INT_ADD]);;
let ADMISSIBLE_ISUM = 
prove (`!(<<) p:(B->C)->P->bool s:P->A h a b. admissible(<<) (\f (k,x). a(x) <= k /\ k <= b(x) /\ p f x) (\(k,x). s x) (\f (k,x). h f x k) ==> admissible(<<) p s (\f x. isum(a(x)..b(x)) (h f x))`,
REWRITE_TAC[admissible; FORALL_PAIR_THM] THEN REPEAT STRIP_TAC THEN MATCH_MP_TAC ISUM_EQ_NUMSEG THEN ASM_MESON_TAC[]);;
let INT_SUB_POW_L1 = 
prove (`!x n. 1 <= n ==> &1 - x pow n = (&1 - x) * isum (0..n - 1) (\i. x pow i)`,
SIMP_TAC[INT_OF_REAL_THM REAL_SUB_POW_L1; ETA_AX]);;
let INT_SUB_POW_R1 = 
prove (`!x n. 1 <= n ==> x pow n - &1 = (x - &1) * isum (0..n - 1) (\i. x pow i)`,
SIMP_TAC[INT_OF_REAL_THM REAL_SUB_POW_R1; ETA_AX]);;
(* ------------------------------------------------------------------------- *) (* Extend the congruences. *) (* ------------------------------------------------------------------------- *)
let th = 
prove (`(!f g s. (!x. x IN s ==> f(x) = g(x)) ==> isum s (\i. f(i)) = isum s g) /\ (!f g a b. (!i. a <= i /\ i <= b ==> f(i) = g(i)) ==> isum(a..b) (\i. f(i)) = isum(a..b) g) /\ (!f g p. (!x. p x ==> f x = g x) ==> isum {y | p y} (\i. f(i)) = isum {y | p y} g)`,
REPEAT STRIP_TAC THEN MATCH_MP_TAC ISUM_EQ THEN ASM_SIMP_TAC[IN_ELIM_THM; IN_NUMSEG]) in extend_basic_congs (map SPEC_ALL (CONJUNCTS th));;