(* ========================================================================= *)
(* Define integer sums, with most theorems derived automatically.            *)
(* ========================================================================= *)
let int_isum = prove
 (`!f:A->int s. real_of_int(isum s f) = sum s (\x. real_of_int(f x))`,
 
 
(* ------------------------------------------------------------------------- *)
(* 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.                                 *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* 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 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))`,
 
 
(* ------------------------------------------------------------------------- *)
(* 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));;