(* ======================================================================== *)
(* Properties of power series.                                              *)
(* ======================================================================== *)
needs "Library/analysis.ml";;
(* ------------------------------------------------------------------------ *)
(* More theorems about rearranging finite sums                              *)
(* ------------------------------------------------------------------------ *)
let POWDIFF_LEMMA = prove(
  `!n x y. sum(0,SUC n)(\p. (x pow p) * y pow ((SUC n) - p)) =
                y * sum(0,SUC n)(\p. (x pow p) * (y pow (n - p)))`,
  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM 
SUM_CMUL] THEN
  MATCH_MP_TAC 
SUM_SUBST THEN X_GEN_TAC `p:num` THEN DISCH_TAC THEN
  BETA_TAC THEN GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
  REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN AP_TERM_TAC THEN
  SUBGOAL_THEN `~(n < p:num)` ASSUME_TAC THENL
   [POP_ASSUM(MP_TAC o CONJUNCT2) THEN REWRITE_TAC[
ADD_CLAUSES] THEN
    REWRITE_TAC[
NOT_LT; CONJUNCT2 
LT] THEN
    DISCH_THEN(DISJ_CASES_THEN2 SUBST1_TAC MP_TAC) THEN
    REWRITE_TAC[
LE_REFL; 
LT_IMP_LE];
    ASM_REWRITE_TAC[
SUB_OLD] THEN REWRITE_TAC[pow] THEN
    MATCH_ACCEPT_TAC REAL_MUL_SYM]);;
 
let POWDIFF = prove(
  `!n x y. (x pow (SUC n)) - (y pow (SUC n)) =
                (x - y) * sum(0,SUC n)(\p. (x pow p) * (y pow (n - p)))`,
  INDUCT_TAC THENL
   [REPEAT GEN_TAC THEN REWRITE_TAC[sum] THEN
    REWRITE_TAC[REAL_ADD_LID; 
ADD_CLAUSES; 
SUB_0] THEN
    BETA_TAC THEN REWRITE_TAC[pow] THEN
    REWRITE_TAC[
REAL_MUL_RID];
    REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[sum] THEN
    REWRITE_TAC[
ADD_CLAUSES] THEN BETA_TAC THEN
    REWRITE_TAC[
POWDIFF_LEMMA] THEN REWRITE_TAC[REAL_LDISTRIB] THEN
    ONCE_REWRITE_TAC[AC 
REAL_MUL_AC
      `a * (b * c) = b * (a * c)`] THEN
    POP_ASSUM(fun th -> ONCE_REWRITE_TAC[GSYM th]) THEN
    REWRITE_TAC[
SUB_REFL] THEN
    SPEC_TAC(`SUC n`,`n:num`) THEN GEN_TAC THEN
    REWRITE_TAC[pow; 
REAL_MUL_RID] THEN
    REWRITE_TAC[REAL_LDISTRIB; 
REAL_SUB_LDISTRIB] THEN
    REWRITE_TAC[
real_sub] THEN
    ONCE_REWRITE_TAC[AC 
REAL_ADD_AC
      `(a + b) + (c + d) = (d + a) + (c + b)`] THEN
    GEN_REWRITE_TAC (funpow 2 LAND_CONV) [REAL_MUL_SYM] THEN
    CONV_TAC SYM_CONV THEN REWRITE_TAC[
REAL_ADD_LID_UNIQ] THEN
    GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [REAL_MUL_SYM] THEN
    REWRITE_TAC[REAL_ADD_LINV]]);;
 
let POWREV = prove(
  `!n x y. sum(0,SUC n)(\p. (x pow p) * (y pow (n - p))) =
                sum(0,SUC n)(\p. (x pow (n - p)) * (y pow p))`,
  let REAL_EQ_LMUL2' = CONV_RULE(REDEPTH_CONV FORALL_IMP_CONV) 
REAL_EQ_LMUL2 in
  REPEAT GEN_TAC THEN ASM_CASES_TAC `x:real = y` THENL
   [ASM_REWRITE_TAC[GSYM 
POW_ADD] THEN
    MATCH_MP_TAC 
SUM_SUBST THEN X_GEN_TAC `p:num` THEN
    BETA_TAC THEN DISCH_TAC THEN AP_TERM_TAC THEN
    MATCH_ACCEPT_TAC 
ADD_SYM;
    GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [REAL_MUL_SYM] THEN
    RULE_ASSUM_TAC(ONCE_REWRITE_RULE[GSYM 
REAL_SUB_0]) THEN
    FIRST_ASSUM(fun th -> GEN_REWRITE_TAC I [MATCH_MP REAL_EQ_LMUL2' th]) THEN
    GEN_REWRITE_TAC RAND_CONV [GSYM 
REAL_NEGNEG] THEN
    ONCE_REWRITE_TAC[
REAL_NEG_LMUL] THEN
    ONCE_REWRITE_TAC[
REAL_NEG_SUB] THEN
    REWRITE_TAC[GSYM 
POWDIFF] THEN REWRITE_TAC[
REAL_NEG_SUB]]);;
 
let POWSER_INSIDEA = prove(
  `!f x z. summable (\n. f(n) * (x pow n)) /\ abs(z) < abs(x)
        ==> summable (\n. abs(f(n)) * (z pow n))`,
  let th = (GEN_ALL o CONV_RULE LEFT_IMP_EXISTS_CONV o snd o
              EQ_IMP_RULE o SPEC_ALL) convergent in
  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
SER_ZERO) THEN
  DISCH_THEN(MP_TAC o MATCH_MP th) THEN REWRITE_TAC[GSYM 
SEQ_CAUCHY] THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
SEQ_CBOUNDED) THEN
  REWRITE_TAC[
SEQ_BOUNDED] THEN BETA_TAC THEN
  DISCH_THEN(X_CHOOSE_TAC `K:real`) THEN MATCH_MP_TAC 
SER_COMPAR THEN
  EXISTS_TAC `\n. (K * abs(z pow n)) / abs(x pow n)` THEN CONJ_TAC THENL
   [EXISTS_TAC `0` THEN X_GEN_TAC `n:num` THEN DISCH_THEN(K ALL_TAC) THEN
    BETA_TAC THEN MATCH_MP_TAC 
REAL_LE_RDIV THEN CONJ_TAC THENL
     [REWRITE_TAC[GSYM 
ABS_NZ] THEN MATCH_MP_TAC 
POW_NZ THEN
      REWRITE_TAC[
ABS_NZ] THEN MATCH_MP_TAC 
REAL_LET_TRANS THEN
      EXISTS_TAC `abs(z)` THEN ASM_REWRITE_TAC[
ABS_POS];
      REWRITE_TAC[
ABS_MUL; 
ABS_ABS; GSYM REAL_MUL_ASSOC] THEN
      ONCE_REWRITE_TAC[AC 
REAL_MUL_AC
       `a * b * c = (a * c) * b`] THEN
      DISJ_CASES_TAC(SPEC `z pow n` 
ABS_CASES) THEN
      ASM_REWRITE_TAC[
ABS_0; 
REAL_MUL_RZERO; 
REAL_LE_REFL] THEN
      FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP 
REAL_LE_RMUL_EQ th]) THEN
      MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ASM_REWRITE_TAC[GSYM 
ABS_MUL]];
    REWRITE_TAC[summable] THEN
    EXISTS_TAC `K * inv(&1 - (abs(z) / abs(x)))` THEN
    REWRITE_TAC[
real_div; GSYM REAL_MUL_ASSOC] THEN
    CONV_TAC(ONCE_DEPTH_CONV HABS_CONV) THEN REWRITE_TAC[] THEN
    MATCH_MP_TAC 
SER_CMUL THEN
    GEN_REWRITE_TAC (RATOR_CONV o ONCE_DEPTH_CONV) [GSYM 
real_div] THEN
    SUBGOAL_THEN `!n. abs(z pow n) / abs(x pow n) =
                        (abs(z) / abs(x)) pow n`
    (fun th -> ONCE_REWRITE_TAC[th]) THENL
     [ALL_TAC; REWRITE_TAC[GSYM 
real_div] THEN
      MATCH_MP_TAC 
GP THEN REWRITE_TAC[
real_div; 
ABS_MUL] THEN
      SUBGOAL_THEN `~(abs(x) = &0)` (SUBST1_TAC o MATCH_MP 
ABS_INV) THENL
       [DISCH_THEN SUBST_ALL_TAC THEN UNDISCH_TAC `abs(z) < &0` THEN
        REWRITE_TAC[
REAL_NOT_LT; 
ABS_POS];
        REWRITE_TAC[
ABS_ABS; GSYM 
real_div] THEN
        MATCH_MP_TAC 
REAL_LT_1 THEN ASM_REWRITE_TAC[
ABS_POS]]] THEN
    REWRITE_TAC[GSYM 
POW_ABS] THEN X_GEN_TAC `n:num` THEN
    REWRITE_TAC[
real_div; 
POW_MUL] THEN AP_TERM_TAC THEN
    MATCH_MP_TAC 
POW_INV THEN CONV_TAC(RAND_CONV SYM_CONV) THEN
    MATCH_MP_TAC 
REAL_LT_IMP_NE THEN
    MATCH_MP_TAC 
REAL_LET_TRANS THEN EXISTS_TAC `abs(z)` THEN
    ASM_REWRITE_TAC[
ABS_POS]]);;
 
let POWSER_INSIDE = prove(
  `!f x z. summable (\n. f(n) * (x pow n)) /\ abs(z) < abs(x)
        ==> summable (\n. f(n) * (z pow n))`,
  REPEAT GEN_TAC THEN
  SUBST1_TAC(SYM(SPEC `z:real` 
ABS_ABS)) THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
POWSER_INSIDEA) THEN
  REWRITE_TAC[
POW_ABS; GSYM 
ABS_MUL] THEN
  DISCH_THEN((then_) (MATCH_MP_TAC 
SER_ACONV) o MP_TAC) THEN
  BETA_TAC THEN DISCH_THEN ACCEPT_TAC);;
 
let DIFFS_NEG = prove(
  `!c. diffs(\n. --(c n)) = \n. --((diffs c) n)`,
  GEN_TAC THEN REWRITE_TAC[diffs] THEN BETA_TAC THEN
  REWRITE_TAC[
REAL_NEG_RMUL]);;
 
let DIFFS_LEMMA = prove(
  `!n c x. sum(0,n) (\n. (diffs c)(n) * (x pow n)) =
           sum(0,n) (\n. &n * c(n) * (x pow (n - 1))) +
             (&n * c(n) * x pow (n - 1))`,
  INDUCT_TAC THEN ASM_REWRITE_TAC[sum; 
REAL_MUL_LZERO; REAL_ADD_LID] THEN
  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM REAL_ADD_ASSOC] THEN
  AP_TERM_TAC THEN BETA_TAC THEN REWRITE_TAC[
ADD_CLAUSES] THEN
  AP_TERM_TAC THEN REWRITE_TAC[diffs] THEN BETA_TAC THEN
  REWRITE_TAC[
SUC_SUB1; REAL_MUL_ASSOC]);;
 
let DIFFS_LEMMA2 = prove(
  `!n c x. sum(0,n) (\n. &n * c(n) * (x pow (n - 1))) =
           sum(0,n) (\n. (diffs c)(n) * (x pow n)) -
                (&n * c(n) * x pow (n - 1))`,
 
let DIFFS_EQUIV = prove(
  `!c x. summable(\n. (diffs c)(n) * (x pow n)) ==>
      (\n. &n * c(n) * (x pow (n - 1))) sums
         (suminf(\n. (diffs c)(n) * (x pow n)))`,
  REPEAT GEN_TAC THEN DISCH_TAC THEN
  FIRST_ASSUM(MP_TAC o REWRITE_RULE[diffs] o MATCH_MP 
SER_ZERO) THEN
  BETA_TAC THEN REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN DISCH_TAC THEN
  SUBGOAL_THEN `(\n. &n * c(n) * (x pow (n - 1))) 
tends_num_real &0`
  MP_TAC THENL
   [ONCE_REWRITE_TAC[
SEQ_SUC] THEN BETA_TAC THEN
    ASM_REWRITE_TAC[
SUC_SUB1]; ALL_TAC] THEN
  DISCH_THEN(MP_TAC o CONJ (MATCH_MP 
SUMMABLE_SUM
   (ASSUME `summable(\n. (diffs c)(n) * (x pow n))`))) THEN
  REWRITE_TAC[sums] THEN DISCH_THEN(MP_TAC o MATCH_MP 
SEQ_SUB) THEN
  BETA_TAC THEN REWRITE_TAC[GSYM 
DIFFS_LEMMA2] THEN
  REWRITE_TAC[
REAL_SUB_RZERO]);;
 
let TERMDIFF_LEMMA1 = prove(
  `!m z h.
     sum(0,m)(\p. (((z + h) pow (m - p)) * (z pow p)) - (z pow m)) =
       sum(0,m)(\p. (z pow p) *
       (((z + h) pow (m - p)) - (z pow (m - p))))`,
  REPEAT GEN_TAC THEN MATCH_MP_TAC 
SUM_SUBST THEN
  X_GEN_TAC `p:num` THEN DISCH_TAC THEN BETA_TAC THEN
  REWRITE_TAC[
REAL_SUB_LDISTRIB; GSYM 
POW_ADD] THEN BINOP_TAC THENL
   [MATCH_ACCEPT_TAC REAL_MUL_SYM;
    AP_TERM_TAC THEN ONCE_REWRITE_TAC[
ADD_SYM] THEN
    CONV_TAC SYM_CONV THEN MATCH_MP_TAC 
SUB_ADD THEN
    MATCH_MP_TAC 
LT_IMP_LE THEN
    POP_ASSUM(MP_TAC o CONJUNCT2) THEN REWRITE_TAC[
ADD_CLAUSES]]);;
 
let TERMDIFF_LEMMA2 = prove(
  `!z h. ~(h = &0) ==>
       (((((z + h) pow n) - (z pow n)) / h) - (&n * (z pow (n - 1))) =
        h * sum(0,n - 1)(\p. (z pow p) *
              sum(0,(n - 1) - p)
                (\q. ((z + h) pow q) *
                       (z pow (((n - 2) - p) - q)))))`,
 
let TERMDIFF_LEMMA3 = prove(
  `!z h n K. ~(h = &0) /\ abs(z) <= K /\ abs(z + h) <= K ==>
    abs(((((z + h) pow n) - (z pow n)) / h) - (&n * (z pow (n - 1))))
        <= &n * &(n - 1) * (K pow (n - 2)) * abs(h)`,
  let tac = W((then_) (MATCH_MP_TAC 
REAL_LE_TRANS) o
           EXISTS_TAC o rand o concl o PART_MATCH (rand o rator) 
ABS_SUM o
           rand o rator o snd)  THEN REWRITE_TAC[
ABS_SUM] in
  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN ASSUME_TAC) THEN
  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP 
TERMDIFF_LEMMA2 th]) THEN
  REWRITE_TAC[
ABS_MUL] THEN REWRITE_TAC[REAL_MUL_ASSOC] THEN
  GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
  REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN
  FIRST_ASSUM(ASSUME_TAC o CONV_RULE(REWR_CONV 
ABS_NZ)) THEN
  FIRST_ASSUM(fun th -> GEN_REWRITE_TAC I [MATCH_MP 
REAL_LE_LMUL_LOCAL th]) THEN
  tac THEN REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN
  GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
  REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN
  MATCH_MP_TAC 
SUM_BOUND THEN X_GEN_TAC `p:num` THEN
  REWRITE_TAC[
ADD_CLAUSES] THEN DISCH_THEN STRIP_ASSUME_TAC THEN
  BETA_TAC THEN REWRITE_TAC[
ABS_MUL] THEN
  DISJ_CASES_THEN2 SUBST1_TAC (X_CHOOSE_THEN `r:num` SUBST_ALL_TAC)
  (SPEC `n:num` 
num_CASES) THENL
   [REWRITE_TAC[
SUB_0; sum; 
ABS_0; 
REAL_MUL_RZERO; 
REAL_LE_REFL];
    ALL_TAC] THEN
  REWRITE_TAC[
SUC_SUB1; num_CONV `2`; 
SUB_SUC] THEN
  RULE_ASSUM_TAC(REWRITE_RULE[
SUC_SUB1]) THEN
  SUBGOAL_THEN `p < r:num` MP_TAC THENL
   [FIRST_ASSUM MATCH_ACCEPT_TAC; ALL_TAC] THEN
  DISCH_THEN(X_CHOOSE_THEN `d:num` SUBST_ALL_TAC o MATCH_MP 
LESS_ADD_1) THEN
  REWRITE_TAC[GSYM 
ADD1] THEN ONCE_REWRITE_TAC[
ADD_SYM] THEN
  REWRITE_TAC[
ADD_SUB] THEN REWRITE_TAC[
ADD_CLAUSES; 
SUC_SUB1; 
ADD_SUB] THEN
  REWRITE_TAC[
POW_ADD] THEN GEN_REWRITE_TAC RAND_CONV
   [AC 
REAL_MUL_AC
        `(a * b) * c = b * (c * a)`] THEN
  MATCH_MP_TAC 
REAL_LE_MUL2V THEN REWRITE_TAC[
ABS_POS] THEN CONJ_TAC THENL
   [REWRITE_TAC[GSYM 
POW_ABS] THEN MATCH_MP_TAC 
POW_LE THEN
    ASM_REWRITE_TAC[
ABS_POS]; ALL_TAC] THEN
  MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `&(SUC d) * (K pow d)` THEN
  CONJ_TAC THENL
   [ALL_TAC; SUBGOAL_THEN `&0 <= K` MP_TAC THENL
     [MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `abs z` THEN
      ASM_REWRITE_TAC[
ABS_POS];
      DISCH_THEN(MP_TAC o SPEC `d:num` o MATCH_MP 
POW_POS) THEN
      DISCH_THEN(DISJ_CASES_THEN MP_TAC o REWRITE_RULE[
REAL_LE_LT]) THENL
       [DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP 
REAL_LE_RMUL_EQ th]) THEN
        REWRITE_TAC[
REAL_LE; 
LE_SUC] THEN
        MATCH_MP_TAC 
LE_TRANS THEN EXISTS_TAC `SUC d` THEN
        REWRITE_TAC[
LE_SUC; 
LE_ADD] THEN
        MATCH_MP_TAC 
LT_IMP_LE THEN REWRITE_TAC[
LESS_SUC_REFL];
        DISCH_THEN(SUBST1_TAC o SYM) THEN
        REWRITE_TAC[
REAL_MUL_RZERO; 
REAL_LE_REFL]]]] THEN
  tac THEN MATCH_MP_TAC 
SUM_BOUND THEN X_GEN_TAC `q:num` THEN
  REWRITE_TAC[
ADD_CLAUSES] THEN STRIP_TAC THEN BETA_TAC THEN
  UNDISCH_TAC `q < (SUC d)` THEN
  DISCH_THEN(X_CHOOSE_THEN `e:num` MP_TAC o MATCH_MP 
LESS_ADD_1) THEN
  REWRITE_TAC[GSYM 
ADD1; 
ADD_CLAUSES; 
SUC_INJ] THEN
  DISCH_THEN SUBST_ALL_TAC THEN REWRITE_TAC[
POW_ADD] THEN
  ONCE_REWRITE_TAC[
ADD_SYM] THEN REWRITE_TAC[
ADD_SUB] THEN
  REWRITE_TAC[
ABS_MUL] THEN MATCH_MP_TAC 
REAL_LE_MUL2V THEN
  REWRITE_TAC[
ABS_POS; GSYM 
POW_ABS] THEN
  CONJ_TAC THEN MATCH_MP_TAC 
POW_LE THEN ASM_REWRITE_TAC[
ABS_POS]);;
 
let TERMDIFF_LEMMA4 = prove(
  `!f K k. &0 < k /\
           (!h. &0 < abs(h) /\ abs(h) < k ==> abs(f h) <= K * abs(h))
        ==> (f 
tends_real_real &0)(&0)`,
  REPEAT GEN_TAC THEN STRIP_TAC THEN
  REWRITE_TAC[
LIM; 
REAL_SUB_RZERO] THEN
  SUBGOAL_THEN `&0 <= K` MP_TAC THENL
   [FIRST_ASSUM(MP_TAC o SPEC `k / &2`) THEN
    MP_TAC(ONCE_REWRITE_RULE[GSYM 
REAL_LT_HALF1] (ASSUME `&0 < k`)) THEN
    DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC th) THEN
    DISCH_THEN(MP_TAC o MATCH_MP 
REAL_LT_IMP_LE) THEN
    DISCH_THEN(fun th -> REWRITE_TAC[th; 
real_abs]) THEN
    REWRITE_TAC[GSYM 
real_abs] THEN
    ASM_REWRITE_TAC[
REAL_LT_HALF1; 
REAL_LT_HALF2] THEN DISCH_TAC THEN
    MP_TAC(GEN_ALL(MATCH_MP 
REAL_LE_RMUL_EQ (ASSUME `&0 < k / &2`))) THEN
    DISCH_THEN(fun th -> GEN_REWRITE_TAC I [GSYM th]) THEN
    MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `abs(f(k / &2))` THEN
    ASM_REWRITE_TAC[
REAL_MUL_LZERO; 
ABS_POS]; ALL_TAC] THEN
  DISCH_THEN(DISJ_CASES_TAC o REWRITE_RULE[
REAL_LE_LT]) THEN
  X_GEN_TAC `e:real` THEN DISCH_TAC THENL
   [ALL_TAC; EXISTS_TAC `k:real` THEN REWRITE_TAC[ASSUME `&0 < k`] THEN
    GEN_TAC THEN DISCH_THEN(fun th -> FIRST_ASSUM(MP_TAC o C MATCH_MP th)) THEN
    FIRST_ASSUM(SUBST1_TAC o SYM) THEN REWRITE_TAC[
REAL_MUL_LZERO] THEN
    DISCH_THEN(MP_TAC o C CONJ(SPEC `(f:real->real) x` 
ABS_POS)) THEN
    REWRITE_TAC[REAL_LE_ANTISYM] THEN DISCH_THEN SUBST1_TAC THEN
    FIRST_ASSUM ACCEPT_TAC] THEN
  SUBGOAL_THEN `&0 < (e / K) / &2` ASSUME_TAC THENL
   [REWRITE_TAC[
real_div] THEN
    REPEAT(MATCH_MP_TAC 
REAL_LT_MUL THEN CONJ_TAC) THEN
    TRY(MATCH_MP_TAC 
REAL_INV_POS) THEN ASM_REWRITE_TAC[] THEN
    REWRITE_TAC[
REAL_LT; num_CONV `2`; 
LT_0]; ALL_TAC] THEN
  MP_TAC(SPECL [`(e / K) / &2`; `k:real`] 
REAL_DOWN2) THEN
  ASM_REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
  EXISTS_TAC `d:real` THEN ASM_REWRITE_TAC[] THEN
  X_GEN_TAC `h:real` THEN DISCH_TAC THEN
  MATCH_MP_TAC 
REAL_LET_TRANS THEN EXISTS_TAC `K * abs(h)` THEN CONJ_TAC THENL
   [FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
    MATCH_MP_TAC 
REAL_LT_TRANS THEN EXISTS_TAC `d:real` THEN
    ASM_REWRITE_TAC[];
    MATCH_MP_TAC 
REAL_LT_TRANS THEN EXISTS_TAC `K * d` THEN
    ASM_REWRITE_TAC[MATCH_MP 
REAL_LT_LMUL_EQ (ASSUME `&0 < K`)] THEN
    ONCE_REWRITE_TAC[GSYM(MATCH_MP 
REAL_LT_RDIV (ASSUME `&0 < K`))] THEN
    REWRITE_TAC[
real_div] THEN
    ONCE_REWRITE_TAC[AC 
REAL_MUL_AC
      `(a * b) * c = (c * a) * b`] THEN
    ASSUME_TAC(GSYM(MATCH_MP 
REAL_LT_IMP_NE (ASSUME `&0 < K`))) THEN
    REWRITE_TAC[MATCH_MP REAL_MUL_LINV (ASSUME `~(K = &0)`)] THEN
    REWRITE_TAC[REAL_MUL_LID] THEN
    MATCH_MP_TAC 
REAL_LT_TRANS THEN EXISTS_TAC `(e / K) / &2` THEN
    ASM_REWRITE_TAC[GSYM 
real_div] THEN REWRITE_TAC[
REAL_LT_HALF2] THEN
    ONCE_REWRITE_TAC[GSYM 
REAL_LT_HALF1] THEN ASM_REWRITE_TAC[]]);;
 
let TERMDIFF_LEMMA5 = prove(
  `!f g k. &0 < k /\
         summable(f) /\
         (!h. &0 < abs(h) /\ abs(h) < k ==> !n. abs(g(h) n) <= (f(n) * abs(h)))
             ==> ((\h. suminf(g h)) 
tends_real_real &0)(&0)`,
  REPEAT GEN_TAC THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  DISCH_THEN(CONJUNCTS_THEN2 (ASSUME_TAC o MATCH_MP 
SUMMABLE_SUM) MP_TAC) THEN
  ASSUME_TAC((GEN `h:real` o SPEC `abs(h)` o
    MATCH_MP 
SER_CMUL) (ASSUME `f sums (suminf f)`)) THEN
  RULE_ASSUM_TAC(ONCE_REWRITE_RULE[REAL_MUL_SYM]) THEN
  FIRST_ASSUM(ASSUME_TAC o GEN `h:real` o
    MATCH_MP 
SUM_UNIQ o SPEC `h:real`) THEN DISCH_TAC THEN
  C SUBGOAL_THEN ASSUME_TAC `!h. &0 < abs(h) /\ abs(h) < k ==>
    abs(suminf(g h)) <= (suminf(f) * abs(h))` THENL
   [GEN_TAC THEN DISCH_THEN(fun th -> ASSUME_TAC th THEN
      FIRST_ASSUM(MP_TAC o C MATCH_MP th)) THEN DISCH_TAC THEN
    SUBGOAL_THEN `summable(\n. f(n) * abs(h))` ASSUME_TAC THENL
     [MATCH_MP_TAC 
SUM_SUMMABLE THEN
      EXISTS_TAC `suminf(f) * abs(h)` THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
    SUBGOAL_THEN `summable(\n. abs(g(h:real)(n:num)))` ASSUME_TAC THENL
     [MATCH_MP_TAC 
SER_COMPAR THEN
      EXISTS_TAC `\n:num. f(n) * abs(h)` THEN ASM_REWRITE_TAC[] THEN
      EXISTS_TAC `0` THEN X_GEN_TAC `n:num` THEN
      DISCH_THEN(K ALL_TAC) THEN BETA_TAC THEN REWRITE_TAC[
ABS_ABS] THEN
      FIRST_ASSUM(MATCH_MP_TAC o REWRITE_RULE[
RIGHT_IMP_FORALL_THM]) THEN
      ASM_REWRITE_TAC[]; ALL_TAC] THEN
    MATCH_MP_TAC 
REAL_LE_TRANS THEN
    EXISTS_TAC `suminf(\n. abs(g(h:real)(n:num)))` THEN CONJ_TAC THENL
     [MATCH_MP_TAC 
SER_ABS THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
SER_LE THEN
    REPEAT CONJ_TAC THEN TRY(FIRST_ASSUM ACCEPT_TAC) THEN
    GEN_TAC THEN BETA_TAC THEN
    FIRST_ASSUM(MATCH_MP_TAC o REWRITE_RULE[
RIGHT_IMP_FORALL_THM]) THEN
    ASM_REWRITE_TAC[]; ALL_TAC] THEN
  MATCH_MP_TAC 
TERMDIFF_LEMMA4 THEN
  MAP_EVERY EXISTS_TAC [`suminf(f)`; `k:real`] THEN
  BETA_TAC THEN ASM_REWRITE_TAC[]);;
 
let TERMDIFF = prove(
  `!c K. summable(\n. c(n) * (K pow n)) /\
         summable(\n. (diffs c)(n) * (K pow n)) /\
         summable(\n. (diffs(diffs c))(n) * (K pow n)) /\
         abs(x) < abs(K)
        ==> ((\x. suminf (\n. c(n) * (x pow n))) diffl
             (suminf (\n. (diffs c)(n) * (x pow n))))(x)`,
  REPEAT GEN_TAC THEN STRIP_TAC THEN
  REWRITE_TAC[diffl] THEN BETA_TAC THEN
  MATCH_MP_TAC 
LIM_TRANSFORM THEN
  EXISTS_TAC `\h. suminf(\n. ((c(n) * ((x + h) pow n)) -
                             (c(n) * (x pow n))) / h)` THEN CONJ_TAC THENL
   [BETA_TAC THEN REWRITE_TAC[
LIM] THEN BETA_TAC THEN
    REWRITE_TAC[
REAL_SUB_RZERO] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
    EXISTS_TAC `abs(K) - abs(x)` THEN REWRITE_TAC[
REAL_SUB_LT] THEN
    ASM_REWRITE_TAC[] THEN X_GEN_TAC `h:real` THEN
    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
    DISCH_THEN(ASSUME_TAC o MATCH_MP 
ABS_CIRCLE) THEN
    W(fun (asl,w) -> SUBGOAL_THEN (mk_eq(rand(rator w),`&0`)) SUBST1_TAC) THEN
    ASM_REWRITE_TAC[] THEN REWRITE_TAC[
ABS_ZERO] THEN
    REWRITE_TAC[
REAL_SUB_0] THEN C SUBGOAL_THEN MP_TAC
      `(\n. (c n) * (x pow n)) sums
           (suminf(\n. (c n) * (x pow n))) /\
       (\n. (c n) * ((x + h) pow n)) sums
           (suminf(\n. (c n) * ((x + h) pow n)))` THENL
     [CONJ_TAC THEN MATCH_MP_TAC 
SUMMABLE_SUM THEN
      MATCH_MP_TAC 
POWSER_INSIDE THEN EXISTS_TAC `K:real` THEN
      ASM_REWRITE_TAC[]; ALL_TAC] THEN
    ONCE_REWRITE_TAC[
CONJ_SYM] THEN
    DISCH_THEN(MP_TAC o MATCH_MP 
SER_SUB) THEN BETA_TAC THEN
    DISCH_THEN(MP_TAC o SPEC `h:real` o MATCH_MP 
SER_CDIV) THEN
    BETA_TAC THEN DISCH_THEN(ACCEPT_TAC o MATCH_MP 
SUM_UNIQ); ALL_TAC] THEN
  ONCE_REWRITE_TAC[
LIM_NULL] THEN BETA_TAC THEN
  MATCH_MP_TAC 
LIM_TRANSFORM THEN EXISTS_TAC
   `\h. suminf (\n. c(n) *
    (((((x + h) pow n) - (x pow n)) / h) - (&n * (x pow (n - 1)))))` THEN
  BETA_TAC THEN CONJ_TAC THENL
   [REWRITE_TAC[
LIM] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
    EXISTS_TAC `abs(K) - abs(x)` THEN REWRITE_TAC[
REAL_SUB_LT] THEN
    ASM_REWRITE_TAC[] THEN X_GEN_TAC `h:real` THEN
    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
    DISCH_THEN(ASSUME_TAC o MATCH_MP 
ABS_CIRCLE) THEN
    W(fun (asl,w) -> SUBGOAL_THEN (mk_eq(rand(rator w),`&0`)) SUBST1_TAC) THEN
    ASM_REWRITE_TAC[] THEN REWRITE_TAC[
REAL_SUB_RZERO; 
ABS_ZERO] THEN
    BETA_TAC THEN REWRITE_TAC[
REAL_SUB_0] THEN
    SUBGOAL_THEN `summable(\n. (diffs c)(n) * (x pow n))` MP_TAC THENL
     [MATCH_MP_TAC 
POWSER_INSIDE THEN EXISTS_TAC `K:real` THEN
      ASM_REWRITE_TAC[]; ALL_TAC] THEN
    DISCH_THEN(fun th -> ASSUME_TAC th THEN
        MP_TAC (MATCH_MP 
DIFFS_EQUIV th)) THEN
    DISCH_THEN(fun th -> SUBST1_TAC (MATCH_MP 
SUM_UNIQ th) THEN MP_TAC th) THEN
    RULE_ASSUM_TAC(REWRITE_RULE[
REAL_SUB_RZERO]) THEN C SUBGOAL_THEN MP_TAC
      `(\n. (c n) * (x pow n)) sums
           (suminf(\n. (c n) * (x pow n))) /\
       (\n. (c n) * ((x + h) pow n)) sums
           (suminf(\n. (c n) * ((x + h) pow n)))` THENL
     [CONJ_TAC THEN MATCH_MP_TAC 
SUMMABLE_SUM THEN
      MATCH_MP_TAC 
POWSER_INSIDE THEN EXISTS_TAC `K:real` THEN
      ASM_REWRITE_TAC[]; ALL_TAC] THEN
    ONCE_REWRITE_TAC[
CONJ_SYM] THEN
    DISCH_THEN(MP_TAC o MATCH_MP 
SER_SUB) THEN BETA_TAC THEN
    DISCH_THEN(MP_TAC o SPEC `h:real` o MATCH_MP 
SER_CDIV) THEN
    DISCH_THEN(MP_TAC o MATCH_MP 
SUMMABLE_SUM o MATCH_MP 
SUM_SUMMABLE) THEN
    BETA_TAC THEN DISCH_THEN(fun th -> DISCH_THEN (MP_TAC o
      MATCH_MP 
SUMMABLE_SUM o MATCH_MP 
SUM_SUMMABLE) THEN MP_TAC th) THEN
    DISCH_THEN(fun th1 -> DISCH_THEN(fun th2 -> MP_TAC(CONJ th1 th2))) THEN
    DISCH_THEN(MP_TAC o MATCH_MP 
SER_SUB) THEN BETA_TAC THEN
    DISCH_THEN(SUBST1_TAC o MATCH_MP 
SUM_UNIQ) THEN AP_TERM_TAC THEN
    ABS_TAC THEN REWRITE_TAC[
real_div] THEN
    REWRITE_TAC[
REAL_SUB_LDISTRIB; 
REAL_SUB_RDISTRIB] THEN
    REWRITE_TAC[REAL_MUL_ASSOC] THEN AP_TERM_TAC THEN
    AP_THM_TAC THEN AP_TERM_TAC THEN MATCH_ACCEPT_TAC REAL_MUL_SYM;
    ALL_TAC] THEN
  MP_TAC(SPECL [`abs(x)`; `abs(K)`] 
REAL_MEAN) THEN ASM_REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_THEN `R:real` STRIP_ASSUME_TAC) THEN
  MP_TAC(SPECL
   [`\n. abs(c n) * &n * &(n - 1) * (R pow (n - 2))`;
    `\h n. c(n) * (((((x + h) pow n) - (x pow n)) / h) -
                     (&n * (x pow (n - 1))))`;
    `R - abs(x)`] 
TERMDIFF_LEMMA5) THEN
  BETA_TAC THEN REWRITE_TAC[REAL_MUL_ASSOC] THEN
  DISCH_THEN MATCH_MP_TAC THEN REPEAT CONJ_TAC THENL
   [ASM_REWRITE_TAC[
REAL_SUB_LT];
    SUBGOAL_THEN `summable(\n. abs(diffs(diffs c) n) * (R pow n))` MP_TAC THENL
     [MATCH_MP_TAC 
POWSER_INSIDEA THEN
      EXISTS_TAC `K:real` THEN ASM_REWRITE_TAC[] THEN
      SUBGOAL_THEN `abs(R) = R` (fun th -> ASM_REWRITE_TAC[th]) THEN
      REWRITE_TAC[
ABS_REFL] THEN MATCH_MP_TAC 
REAL_LE_TRANS THEN
      EXISTS_TAC `abs(x)` THEN REWRITE_TAC[
ABS_POS] THEN
      MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
    REWRITE_TAC[diffs] THEN BETA_TAC THEN REWRITE_TAC[
ABS_MUL] THEN
    REWRITE_TAC[
ABS_N] THEN REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN
    C SUBGOAL_THEN (fun th -> ONCE_REWRITE_TAC[GSYM th])
      `!n. diffs(diffs (\n. abs(c n))) n * (R pow n) =
           &(SUC n) * &(SUC(SUC n)) * abs(c(SUC(SUC n))) * (R pow n)` THENL
     [GEN_TAC THEN REWRITE_TAC[diffs] THEN BETA_TAC THEN
      REWRITE_TAC[REAL_MUL_ASSOC]; ALL_TAC] THEN
    DISCH_THEN(MP_TAC o MATCH_MP 
DIFFS_EQUIV) THEN
    DISCH_THEN(MP_TAC o MATCH_MP 
SUM_SUMMABLE) THEN
    REWRITE_TAC[diffs] THEN BETA_TAC THEN REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN
    SUBGOAL_THEN `(\n. &n * &(SUC n) * abs(c(SUC n)) * (R pow (n - 1))) =
           \n. diffs(\m. &(m - 1) * abs(c m) / R) n * (R pow n)`
    SUBST1_TAC THENL
     [REWRITE_TAC[diffs] THEN BETA_TAC THEN REWRITE_TAC[
SUC_SUB1] THEN
      ABS_TAC THEN
      DISJ_CASES_THEN2 (SUBST1_TAC) (X_CHOOSE_THEN `m:num` SUBST1_TAC)
       (SPEC `n:num` 
num_CASES) THEN
      REWRITE_TAC[
REAL_MUL_LZERO; 
REAL_MUL_RZERO; 
SUC_SUB1] THEN
      REWRITE_TAC[
ADD1; 
POW_ADD] THEN REWRITE_TAC[GSYM 
ADD1; 
POW_1] THEN
      REWRITE_TAC[GSYM REAL_MUL_ASSOC; 
real_div] THEN
      ONCE_REWRITE_TAC[AC 
REAL_MUL_AC
        `a * b * c * d * e * f = b * a * c * e * d * f`] THEN
      REPEAT AP_TERM_TAC THEN SUBGOAL_THEN `inv(R) * R = &1` SUBST1_TAC THENL
       [MATCH_MP_TAC REAL_MUL_LINV THEN REWRITE_TAC[
ABS_NZ] THEN
        MATCH_MP_TAC 
REAL_LET_TRANS THEN EXISTS_TAC `abs(x)` THEN
        ASM_REWRITE_TAC[
ABS_POS] THEN MATCH_MP_TAC 
REAL_LTE_TRANS THEN
        EXISTS_TAC `R:real` THEN ASM_REWRITE_TAC[
ABS_LE];
        REWRITE_TAC[
REAL_MUL_RID]]; ALL_TAC] THEN
    DISCH_THEN(MP_TAC o MATCH_MP 
DIFFS_EQUIV) THEN BETA_TAC THEN
    DISCH_THEN(MP_TAC o MATCH_MP 
SUM_SUMMABLE) THEN
    MATCH_MP_TAC EQ_IMP THEN AP_TERM_TAC THEN
    CONV_TAC(X_FUN_EQ_CONV `n:num`) THEN BETA_TAC THEN GEN_TAC THEN
    REWRITE_TAC[
real_div; GSYM REAL_MUL_ASSOC] THEN
    GEN_REWRITE_TAC RAND_CONV
     [AC 
REAL_MUL_AC
      `a * b * c * d = b * c * a * d`] THEN
    DISJ_CASES_THEN2 SUBST1_TAC (X_CHOOSE_THEN `m:num` SUBST1_TAC)
     (SPEC `n:num` 
num_CASES) THEN REWRITE_TAC[
REAL_MUL_LZERO] THEN
    REWRITE_TAC[num_CONV `2`; 
SUC_SUB1; 
SUB_SUC] THEN AP_TERM_TAC THEN
    DISJ_CASES_THEN2 SUBST1_TAC (X_CHOOSE_THEN `n:num` SUBST1_TAC)
     (SPEC `m:num` 
num_CASES) THEN REWRITE_TAC[
REAL_MUL_LZERO] THEN
    REPEAT AP_TERM_TAC THEN REWRITE_TAC[
SUC_SUB1] THEN
    REWRITE_TAC[
ADD1; 
POW_ADD; 
POW_1] THEN
    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN
    SUBGOAL_THEN `R * inv(R) = &1`
    (fun th -> REWRITE_TAC[th; 
REAL_MUL_RID]) THEN
    MATCH_MP_TAC 
REAL_MUL_RINV THEN CONV_TAC(RAND_CONV SYM_CONV) THEN
    MATCH_MP_TAC 
REAL_LT_IMP_NE THEN MATCH_MP_TAC 
REAL_LET_TRANS THEN
    EXISTS_TAC `abs(x)` THEN ASM_REWRITE_TAC[
ABS_POS];
    X_GEN_TAC `h:real` THEN DISCH_TAC THEN X_GEN_TAC `n:num` THEN
    REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN ONCE_REWRITE_TAC[
ABS_MUL] THEN
    MATCH_MP_TAC 
REAL_LE_LMUL_IMP THEN REWRITE_TAC[
ABS_POS] THEN
    MATCH_MP_TAC 
TERMDIFF_LEMMA3 THEN ASM_REWRITE_TAC[
ABS_NZ] THEN
    CONJ_TAC THENL
     [MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ASM_REWRITE_TAC[];
      MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `abs(x) + abs(h)` THEN
      REWRITE_TAC[
ABS_TRIANGLE] THEN MATCH_MP_TAC 
REAL_LT_IMP_LE THEN
      ONCE_REWRITE_TAC[REAL_ADD_SYM] THEN
      ASM_REWRITE_TAC[GSYM 
REAL_LT_SUB_LADD]]]);;
 
let TERMDIFF_CONVERGES = prove
 (`!K. (!x. abs(x) < K ==> summable(\n. c(n) * x pow n))
       ==> !x. abs(x) < K ==> summable (\n. diffs c n * x pow n)`,
 
let TERMDIFF_STRONG = prove
 (`!c K x.
        summable(\n. c(n) * (K pow n)) /\ abs(x) < abs(K)
        ==> ((\x. suminf (\n. c(n) * (x pow n))) diffl
             (suminf (\n. (diffs c)(n) * (x pow n))))(x)`,
 
let POWSER_LIMIT_0 = prove
 (`!f a s. &0 < s /\
           (!x. abs(x) < s ==> (\n. a n * x pow n) sums (f x))
           ==> (f 
tends_real_real a(0))(&0)`,
  REPEAT STRIP_TAC THEN
  MP_TAC(SPECL [`a:num->real`; `s / &2`; `&0`] 
TERMDIFF_STRONG) THEN
  W(C SUBGOAL_THEN (fun th -> REWRITE_TAC[th]) o funpow 2 lhand o snd) THENL
   [ASM_SIMP_TAC[
REAL_ABS_NUM; 
REAL_ABS_DIV; 
REAL_LT_DIV; 
REAL_OF_NUM_LT;
                 ARITH; REAL_ARITH `&0 < x ==> &0 < abs(x)`] THEN
    MATCH_MP_TAC 
SUM_SUMMABLE THEN
    EXISTS_TAC `(f:real->real) (s / &2)` THEN
    FIRST_ASSUM MATCH_MP_TAC THEN
    ASM_SIMP_TAC[
REAL_ABS_DIV; 
REAL_ABS_NUM; 
REAL_LT_LDIV_EQ; 
REAL_OF_NUM_LT;
                 ARITH] THEN
    UNDISCH_TAC `&0 < s` THEN REAL_ARITH_TAC; ALL_TAC] THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
DIFF_CONT) THEN REWRITE_TAC[contl] THEN
  SUBGOAL_THEN `suminf (\n. a n * &0 pow n) = a(0)` SUBST1_TAC THENL
   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC 
SUM_UNIQ THEN
    REWRITE_TAC[
POWSER_0]; ALL_TAC] THEN
  MATCH_MP_TAC(ONCE_REWRITE_RULE[
IMP_CONJ]
               
LIM_TRANSFORM) THEN
  REWRITE_TAC[REAL_ADD_LID; 
LIM] THEN
  REPEAT STRIP_TAC THEN EXISTS_TAC `s:real` THEN
  ASM_REWRITE_TAC[
REAL_SUB_RZERO] THEN
  REPEAT STRIP_TAC THEN
  MATCH_MP_TAC(REAL_ARITH `(a = b) /\ &0 < e ==> abs(a - b) < e`) THEN
  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
SUM_UNIQ THEN ASM_SIMP_TAC[]);;
 
let POWSER_EQUAL_0 = prove
 (`!f a b P.
        (!e. &0 < e ==> ?x. P x /\ &0 < abs x /\ abs(x) < e) /\
        (!x. &0 < abs(x) /\ P x
             ==> (\n. a n * x pow n) sums (f x) /\
                 (\n. b n * x pow n) sums (f x))
        ==> (a(0) = b(0))`,
  REPEAT STRIP_TAC THEN
  SUBGOAL_THEN
   `?s. &0 < s /\
        !x. abs(x) < s
            ==> summable (\n. a n * x pow n) /\ summable (\n. b n * x pow n)`
  MP_TAC THENL
   [FIRST_ASSUM(MP_TAC o C MATCH_MP 
REAL_LT_01) THEN
    DISCH_THEN(X_CHOOSE_THEN `k:real` STRIP_ASSUME_TAC) THEN
    EXISTS_TAC `abs(k)` THEN ASM_REWRITE_TAC[] THEN
    REPEAT STRIP_TAC THEN MATCH_MP_TAC 
POWSER_INSIDE THEN
    EXISTS_TAC `k:real` THEN
    ASM_REWRITE_TAC[summable] THEN
    EXISTS_TAC `(f:real->real) k` THEN ASM_SIMP_TAC[]; ALL_TAC] THEN
  REWRITE_TAC[summable; 
LEFT_AND_EXISTS_THM] THEN
  REWRITE_TAC[
RIGHT_AND_EXISTS_THM; 
RIGHT_IMP_EXISTS_THM] THEN
  DISCH_THEN(X_CHOOSE_THEN `s:real` MP_TAC) THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  REWRITE_TAC[
SKOLEM_THM] THEN
  DISCH_THEN(X_CHOOSE_THEN `g:real->real` MP_TAC) THEN
  DISCH_THEN(X_CHOOSE_THEN `h:real->real` MP_TAC) THEN DISCH_TAC THEN
  MATCH_MP_TAC(REAL_ARITH `~(&0 < abs(x - y)) ==> (x = y)`) THEN
  ABBREV_TAC `e = abs(a 0 - b 0)` THEN DISCH_TAC THEN
  MP_TAC(SPECL [`g:real->real`; `a:num->real`; `s:real`]
    
POWSER_LIMIT_0_STRONG) THEN
  ASM_SIMP_TAC[
LIM] THEN DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN
  ASM_SIMP_TAC[
REAL_LT_DIV; 
REAL_OF_NUM_LT; ARITH; 
REAL_SUB_RZERO] THEN
  DISCH_THEN(X_CHOOSE_THEN `d1:real` STRIP_ASSUME_TAC) THEN
  MP_TAC(SPECL [`h:real->real`; `b:num->real`; `s:real`]
    
POWSER_LIMIT_0_STRONG) THEN
  ASM_SIMP_TAC[
LIM] THEN DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN
  ASM_SIMP_TAC[
REAL_LT_DIV; 
REAL_OF_NUM_LT; ARITH; 
REAL_SUB_RZERO] THEN
  DISCH_THEN(X_CHOOSE_THEN `d2:real` STRIP_ASSUME_TAC) THEN
  MP_TAC(SPECL [`d1:real`; `d2:real`] 
REAL_DOWN2) THEN
  ASM_REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_THEN `d0:real` STRIP_ASSUME_TAC) THEN
  MP_TAC(SPECL [`d0:real`; `s:real`] 
REAL_DOWN2) THEN
  ASM_REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
  UNDISCH_TAC `!e. &0 < e ==> ?x. P x /\ &0 < abs x /\ abs x < e` THEN
  DISCH_THEN(MP_TAC o SPEC `d:real`) THEN ASM_REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_THEN `x:real` STRIP_ASSUME_TAC) THEN
  SUBGOAL_THEN `abs(a 0 - b 0) < e` MP_TAC THENL
   [ALL_TAC; ASM_REWRITE_TAC[
REAL_LT_REFL]] THEN
  MATCH_MP_TAC 
REAL_LTE_TRANS THEN
  EXISTS_TAC `e / &2 + e / &2` THEN CONJ_TAC THENL
   [ALL_TAC;
    SIMP_TAC[GSYM 
REAL_MUL_2; 
REAL_DIV_LMUL; REAL_OF_NUM_EQ; 
ARITH_EQ] THEN
    REWRITE_TAC[
REAL_LE_REFL]] THEN
  MATCH_MP_TAC(REAL_ARITH
   `!f g h. abs(g - a) < e2 /\ abs(h - b) < e2 /\ (g = f) /\ (h = f)
            ==> abs(a - b) < e2 + e2`) THEN
  MAP_EVERY EXISTS_TAC
   [`(f:real->real) x`; `(g:real->real) x`; `(h:real->real) x`] THEN
  CONJ_TAC THENL [ASM_MESON_TAC[
REAL_LT_TRANS]; ALL_TAC] THEN
  CONJ_TAC THENL [ASM_MESON_TAC[
REAL_LT_TRANS]; ALL_TAC] THEN
  CONJ_TAC THENL
   [MATCH_MP_TAC 
EQ_TRANS THEN EXISTS_TAC `suminf(\n. a n * x pow n)` THEN
    CONJ_TAC THENL
     [MATCH_MP_TAC 
SUM_UNIQ;
      MATCH_MP_TAC(GSYM 
SUM_UNIQ)] THEN
    ASM_SIMP_TAC[] THEN
    SUBGOAL_THEN `abs(x) < s` (fun th -> ASM_SIMP_TAC[th]) THEN
    ASM_MESON_TAC[
REAL_LT_TRANS];
    MATCH_MP_TAC 
EQ_TRANS THEN EXISTS_TAC `suminf(\n. b n * x pow n)` THEN
    CONJ_TAC THENL
     [MATCH_MP_TAC 
SUM_UNIQ;
      MATCH_MP_TAC(GSYM 
SUM_UNIQ)] THEN
    ASM_SIMP_TAC[] THEN
    SUBGOAL_THEN `abs(x) < s` (fun th -> ASM_SIMP_TAC[th]) THEN
    ASM_MESON_TAC[
REAL_LT_TRANS]]);;
 
let POWSER_EQUAL = prove
 (`!f a b P.
        (!e. &0 < e ==> ?x. P x /\ &0 < abs x /\ abs(x) < e) /\
        (!x. P x ==> (\n. a n * x pow n) sums (f x) /\
                     (\n. b n * x pow n) sums (f x))
        ==> (a = b)`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[
FUN_EQ_THM] THEN
  GEN_REWRITE_TAC I [TAUT `p <=> ~ ~ p`] THEN
  GEN_REWRITE_TAC RAND_CONV [
NOT_FORALL_THM] THEN
  ONCE_REWRITE_TAC[
num_WOP] THEN
  DISCH_THEN(X_CHOOSE_THEN `n:num` MP_TAC) THEN REWRITE_TAC[] THEN
  REWRITE_TAC[TAUT `~(~a /\ b) <=> b ==> a`] THEN DISCH_TAC THEN
  SUBGOAL_THEN `(\m. a(m + n):real) 0 = (\m. b(m + n)) 0` MP_TAC THENL
   [ALL_TAC; REWRITE_TAC[
ADD_CLAUSES]] THEN
  MATCH_MP_TAC 
POWSER_EQUAL_0 THEN
  EXISTS_TAC `\x. inv(x pow n) * (f(x) - sum(0,n) (\n. b n * x pow n))` THEN
  EXISTS_TAC `P:real->bool` THEN ASM_REWRITE_TAC[] THEN
  X_GEN_TAC `x:real` THEN STRIP_TAC THEN
  SUBGOAL_THEN `!a m. a(m + n) * x pow m =
                      inv(x pow n) * a(m + n) * x pow (m + n)`
   (fun th -> GEN_REWRITE_TAC (BINOP_CONV o LAND_CONV o ONCE_DEPTH_CONV) [th])
  THENL
   [REPEAT GEN_TAC THEN REWRITE_TAC[
REAL_POW_ADD] THEN
    ONCE_REWRITE_TAC[AC 
REAL_MUL_AC `x' * a * b * x = (x * x') * a * b`] THEN
    ASM_SIMP_TAC[
REAL_MUL_RINV; 
REAL_POW_EQ_0;
                 REAL_ARITH `(x = &0) <=> ~(&0 < abs x)`] THEN
    REWRITE_TAC[REAL_MUL_LID]; ALL_TAC] THEN
  CONJ_TAC THEN MATCH_MP_TAC 
SER_CMUL THENL
   [SUBGOAL_THEN `sum(0,n) (\n. b n * x pow n) = sum(0,n) (\n. a n * x pow n)`
    SUBST1_TAC THENL
     [MATCH_MP_TAC 
SUM_EQ THEN ASM_SIMP_TAC[
ADD_CLAUSES]; ALL_TAC] THEN
    SUBGOAL_THEN `f x = suminf (\n. a n * x pow n)` SUBST1_TAC THENL
     [MATCH_MP_TAC 
SUM_UNIQ THEN ASM_SIMP_TAC[]; ALL_TAC] THEN
    MP_TAC(SPEC `\n. a n * x pow n` 
SER_OFFSET);
    SUBGOAL_THEN `f x = suminf (\n. b n * x pow n)` SUBST1_TAC THENL
     [MATCH_MP_TAC 
SUM_UNIQ THEN ASM_SIMP_TAC[]; ALL_TAC] THEN
    MP_TAC(SPEC `\n. b n * x pow n` 
SER_OFFSET)] THEN
  REWRITE_TAC[] THEN
  W(C SUBGOAL_THEN (fun th -> SIMP_TAC[th]) o funpow 2 lhand o snd) THEN
  MATCH_MP_TAC 
SUM_SUMMABLE THEN
  EXISTS_TAC `(f:real->real) x` THEN ASM_SIMP_TAC[]);;
 
let MULT_DIV_2 = prove
 (`!n. (2 * n) DIV 2 = n`,
  GEN_TAC THEN MATCH_MP_TAC DIV_MULT THEN
  REWRITE_TAC[ARITH]);;
 
let POW_ZERO = prove(
  `!n x. (x pow n = &0) ==> (x = &0)`,
  INDUCT_TAC THEN GEN_TAC THEN ONCE_REWRITE_TAC[pow] THEN
  REWRITE_TAC[REAL_10; 
REAL_ENTIRE] THEN
  DISCH_THEN(DISJ_CASES_THEN2 ACCEPT_TAC ASSUME_TAC) THEN
  FIRST_ASSUM MATCH_MP_TAC THEN FIRST_ASSUM ACCEPT_TAC);;
 
let POW_ZERO_EQ = prove(
  `!n x. (x pow (SUC n) = &0) <=> (x = &0)`,
  REPEAT GEN_TAC THEN EQ_TAC THEN REWRITE_TAC[
POW_ZERO] THEN
  DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[
POW_0]);;
 
let POW_LT = prove(
  `!n x y. &0 <= x /\ x < y ==> (x pow (SUC n)) < (y pow (SUC n))`,
  REPEAT STRIP_TAC THEN SPEC_TAC(`n:num`,`n:num`) THEN INDUCT_TAC THENL
   [ASM_REWRITE_TAC[pow; 
REAL_MUL_RID];
    ONCE_REWRITE_TAC[pow] THEN MATCH_MP_TAC 
REAL_LT_MUL2_ALT THEN
    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
POW_POS THEN ASM_REWRITE_TAC[]]);;
 
let POW_EQ = prove(
  `!n x y. &0 <= x /\ &0 <= y /\ (x pow (SUC n) = y pow (SUC n))
        ==> (x = y)`,
  REPEAT STRIP_TAC THEN REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC
    (SPECL [`x:real`; `y:real`] 
REAL_LT_TOTAL) THEN
  ASM_REWRITE_TAC[] THEN
  UNDISCH_TAC `x pow (SUC n) = y pow (SUC n)` THEN
  CONV_TAC CONTRAPOS_CONV THEN DISCH_THEN(K ALL_TAC) THENL
   [ALL_TAC; CONV_TAC(RAND_CONV SYM_CONV)] THEN
  MATCH_MP_TAC 
REAL_LT_IMP_NE THEN
  MATCH_MP_TAC 
POW_LT THEN ASM_REWRITE_TAC[]);;
 
let REAL_EXP_FDIFF = prove(
  `diffs (\n. inv(&(
FACT n))) = (\n. inv(&(
FACT n)))`,
  REWRITE_TAC[diffs] THEN BETA_TAC THEN
  CONV_TAC(X_FUN_EQ_CONV `n:num`) THEN GEN_TAC THEN BETA_TAC THEN
  REWRITE_TAC[
FACT; GSYM 
REAL_MUL] THEN
  SUBGOAL_THEN `~(&(SUC n) = &0) /\ ~(&(
FACT n) = &0)` ASSUME_TAC THENL
   [CONJ_TAC THEN CONV_TAC(RAND_CONV SYM_CONV) THEN
    MATCH_MP_TAC 
REAL_LT_IMP_NE THEN
    REWRITE_TAC[
REAL_LT; 
LT_0; 
FACT_LT];
    FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP 
REAL_INV_MUL_WEAK th]) THEN
    GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
    REWRITE_TAC[REAL_MUL_ASSOC; REAL_EQ_RMUL] THEN DISJ2_TAC THEN
    MATCH_MP_TAC 
REAL_MUL_RINV THEN ASM_REWRITE_TAC[]]);;
 
let SIN_FDIFF = prove(
  `diffs (\n. if 
EVEN n then &0 else ((--(&1)) pow ((n - 1) DIV 2)) / &(
FACT n))
   = (\n. if 
EVEN n then ((--(&1)) pow (n DIV 2)) / &(
FACT n) else &0)`,
  REWRITE_TAC[diffs] THEN BETA_TAC THEN
  CONV_TAC(X_FUN_EQ_CONV `n:num`) THEN GEN_TAC THEN BETA_TAC THEN
  COND_CASES_TAC THEN RULE_ASSUM_TAC(REWRITE_RULE[
EVEN]) THEN
  ASM_REWRITE_TAC[
REAL_MUL_RZERO] THEN REWRITE_TAC[
SUC_SUB1] THEN
  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
  REWRITE_TAC[
real_div; GSYM REAL_MUL_ASSOC] THEN AP_TERM_TAC THEN
  REWRITE_TAC[
FACT; GSYM 
REAL_MUL] THEN
  SUBGOAL_THEN `~(&(SUC n) = &0) /\ ~(&(
FACT n) = &0)` ASSUME_TAC THENL
   [CONJ_TAC THEN CONV_TAC(RAND_CONV SYM_CONV) THEN
    MATCH_MP_TAC 
REAL_LT_IMP_NE THEN
    REWRITE_TAC[
REAL_LT; 
LT_0; 
FACT_LT];
    FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP 
REAL_INV_MUL_WEAK th]) THEN
    REWRITE_TAC[REAL_MUL_ASSOC] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
    GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
    REWRITE_TAC[REAL_MUL_ASSOC; REAL_EQ_RMUL] THEN DISJ2_TAC THEN
    MATCH_MP_TAC 
REAL_MUL_RINV THEN ASM_REWRITE_TAC[]]);;
 
let COS_FDIFF = prove(
  `diffs (\n. if 
EVEN n then ((--(&1)) pow (n DIV 2)) / &(
FACT n) else &0) =
  (\n. --(((\n. if 
EVEN n then &0 else ((--(&1)) pow ((n - 1) DIV 2)) /
   &(
FACT n))) n))`,
  REWRITE_TAC[diffs] THEN BETA_TAC THEN
  CONV_TAC(X_FUN_EQ_CONV `n:num`) THEN GEN_TAC THEN BETA_TAC THEN
  COND_CASES_TAC THEN RULE_ASSUM_TAC(REWRITE_RULE[
EVEN]) THEN
  ASM_REWRITE_TAC[
REAL_MUL_RZERO; 
REAL_NEG_0] THEN
  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
  REWRITE_TAC[
real_div; 
REAL_NEG_LMUL] THEN
  REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN BINOP_TAC THENL
   [POP_ASSUM(SUBST1_TAC o MATCH_MP 
EVEN_DIV2) THEN
    REWRITE_TAC[pow] THEN REWRITE_TAC[GSYM 
REAL_NEG_MINUS1];
    REWRITE_TAC[
FACT; GSYM 
REAL_MUL] THEN
    SUBGOAL_THEN `~(&(SUC n) = &0) /\ ~(&(
FACT n) = &0)` ASSUME_TAC THENL
     [CONJ_TAC THEN CONV_TAC(RAND_CONV SYM_CONV) THEN
      MATCH_MP_TAC 
REAL_LT_IMP_NE THEN
      REWRITE_TAC[
REAL_LT; 
LT_0; 
FACT_LT];
      FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP 
REAL_INV_MUL_WEAK th]) THEN
      REWRITE_TAC[REAL_MUL_ASSOC] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
      GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
      REWRITE_TAC[REAL_MUL_ASSOC; REAL_EQ_RMUL] THEN DISJ2_TAC THEN
      MATCH_MP_TAC 
REAL_MUL_RINV THEN ASM_REWRITE_TAC[]]]);;
 
let SIN_NEGLEMMA = prove(
  `!x. --(sin x) = suminf (\n. --(((\n. if 
EVEN n then &0 else ((--(&1))
        pow ((n - 1) DIV 2)) / &(
FACT n))) n * (x pow n)))`,
 
let DIFF_COMPOSITE = prove
 (`((f diffl l)(x) /\ ~(f(x) = &0) ==>
        ((\x. inv(f x)) diffl --(l / (f(x) pow 2)))(x)) /\
   ((f diffl l)(x) /\ (g diffl m)(x) /\ ~(g(x) = &0) ==>
    ((\x. f(x) / g(x)) diffl (((l * g(x)) - (m * f(x))) / (g(x) pow 2)))(x)) /\
   ((f diffl l)(x) /\ (g diffl m)(x) ==>
                   ((\x. f(x) + g(x)) diffl (l + m))(x)) /\
   ((f diffl l)(x) /\ (g diffl m)(x) ==>
                   ((\x. f(x) * g(x)) diffl ((l * g(x)) + (m * f(x))))(x)) /\
   ((f diffl l)(x) /\ (g diffl m)(x) ==>
                   ((\x. f(x) - g(x)) diffl (l - m))(x)) /\
   ((f diffl l)(x) ==> ((\x. --(f x)) diffl --l)(x)) /\
   ((g diffl m)(x) ==>
         ((\x. (g x) pow n) diffl ((&n * (g x) pow (n - 1)) * m))(x)) /\
   ((g diffl m)(x) ==> ((\x. exp(g x)) diffl (exp(g x) * m))(x)) /\
   ((g diffl m)(x) ==> ((\x. sin(g x)) diffl (cos(g x) * m))(x)) /\
   ((g diffl m)(x) ==> ((\x. cos(g x)) diffl (--(sin(g x)) * m))(x))`,
 
let pth = prove
   (`(f diffl l) x ==> f differentiable x`,
 MESON_TAC[differentiable]) in
  let match_pth = MATCH_MP pth in
  fun tm ->
    let tb,y = dest_comb tm in
    let tm' = rand tb in
    match_pth (SPEC y (DIFF_CONV tm'));;
 
let pth = prove
   (`!f x. f differentiable x ==> f contl x`,
    MESON_TAC[differentiable; 
DIFF_CONT]) in
  let match_pth = PART_MATCH rand pth in
  fun tm ->
   let th1 = match_pth tm in
   MP th1 (DIFFERENTIABLE_RULE(lhand(concl th1)));;
 
let REAL_EXP_0 = prove(
  `exp(&0) = &1`,
  REWRITE_TAC[exp] THEN CONV_TAC SYM_CONV THEN
  MATCH_MP_TAC 
SUM_UNIQ THEN BETA_TAC THEN
  W(MP_TAC o C SPEC 
SER_0 o rand o rator o snd) THEN
  DISCH_THEN(MP_TAC o SPEC `1`) THEN
  REWRITE_TAC[num_CONV `1`; sum] THEN
  REWRITE_TAC[
ADD_CLAUSES; REAL_ADD_LID] THEN BETA_TAC THEN
  REWRITE_TAC[
FACT; pow; 
REAL_MUL_RID; 
REAL_INV1] THEN
  REWRITE_TAC[SYM(num_CONV `1`)] THEN DISCH_THEN MATCH_MP_TAC THEN
  X_GEN_TAC `n:num` THEN REWRITE_TAC[num_CONV `1`; 
LE_SUC_LT] THEN
  DISCH_THEN(CHOOSE_THEN SUBST1_TAC o MATCH_MP 
LESS_ADD_1) THEN
  REWRITE_TAC[GSYM 
ADD1; 
POW_0; 
REAL_MUL_RZERO; 
ADD_CLAUSES]);;
 
let REAL_EXP_ADD = prove(
  `!x y. exp(x + y) = exp(x) * exp(y)`,
  REPEAT GEN_TAC THEN
  MP_TAC(SPECL [`x:real`; `y:real`] 
REAL_EXP_ADD_MUL) THEN
  DISCH_THEN(MP_TAC o C AP_THM `exp(x)` o AP_TERM `(*)`) THEN
  REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN
  REWRITE_TAC[ONCE_REWRITE_RULE[REAL_MUL_SYM] REAL_EXP_NEG_MUL; REAL_MUL_RID] THEN
  DISCH_THEN SUBST1_TAC THEN MATCH_ACCEPT_TAC REAL_MUL_SYM);;
let REAL_EXP_POS_LE = prove(
  `!x. &0 <= exp(x)`,
  GEN_TAC THEN
  GEN_REWRITE_TAC (funpow 2 RAND_CONV) [GSYM REAL_HALF_DOUBLE] THEN
  REWRITE_TAC[REAL_EXP_ADD] THEN MATCH_ACCEPT_TAC REAL_LE_SQUARE);;
let REAL_EXP_NZ = prove(
  `!x. ~(exp(x) = &0)`,
  GEN_TAC THEN DISCH_TAC THEN
  MP_TAC(SPEC `x:real` REAL_EXP_NEG_MUL) THEN
  ASM_REWRITE_TAC[REAL_MUL_LZERO] THEN
  CONV_TAC(RAND_CONV SYM_CONV) THEN
  MATCH_ACCEPT_TAC REAL_10);;
let REAL_EXP_POS_LT = prove(
  `!x. &0 < exp(x)`,
  GEN_TAC THEN REWRITE_TAC[REAL_LT_LE] THEN
  CONV_TAC(ONCE_DEPTH_CONV SYM_CONV) THEN
  REWRITE_TAC[REAL_EXP_POS_LE; REAL_EXP_NZ]);;
let REAL_EXP_N = prove(
  `!n x. exp(&n * x) = exp(x) pow n`,
  INDUCT_TAC THEN REWRITE_TAC[REAL_MUL_LZERO; REAL_EXP_0; pow] THEN
  REWRITE_TAC[ADD1] THEN ONCE_REWRITE_TAC[ADD_SYM] THEN
  REWRITE_TAC[GSYM REAL_ADD; REAL_EXP_ADD; REAL_RDISTRIB] THEN
  GEN_TAC THEN ASM_REWRITE_TAC[REAL_MUL_LID]);;
let REAL_EXP_SUB = prove(
  `!x y. exp(x - y) = exp(x) / exp(y)`,
  REPEAT GEN_TAC THEN
  REWRITE_TAC[real_sub; real_div; REAL_EXP_ADD; REAL_EXP_NEG]);;
let REAL_EXP_MONO_IMP = prove(
  `!x y. x < y ==> exp(x) < exp(y)`,
  REPEAT GEN_TAC THEN DISCH_THEN(MP_TAC o
    MATCH_MP REAL_EXP_LT_1 o ONCE_REWRITE_RULE[GSYM REAL_SUB_LT]) THEN
  REWRITE_TAC[REAL_EXP_SUB] THEN
  SUBGOAL_THEN `&1 < exp(y) / exp(x) <=>
                 (&1 * exp(x)) < ((exp(y) / exp(x)) * exp(x))` SUBST1_TAC THENL
   [CONV_TAC SYM_CONV THEN MATCH_MP_TAC REAL_LT_RMUL_EQ THEN
    MATCH_ACCEPT_TAC REAL_EXP_POS_LT;
    REWRITE_TAC[real_div; GSYM REAL_MUL_ASSOC; REAL_EXP_NEG_MUL2;
                GSYM REAL_EXP_NEG] THEN
    REWRITE_TAC[REAL_MUL_LID; REAL_MUL_RID]]);;
let REAL_EXP_MONO_LT = prove(
  `!x y. exp(x) < exp(y) <=> x < y`,
  REPEAT GEN_TAC THEN EQ_TAC THENL
   [CONV_TAC CONTRAPOS_CONV THEN REWRITE_TAC[REAL_NOT_LT] THEN
    REWRITE_TAC[REAL_LE_LT] THEN
    DISCH_THEN(DISJ_CASES_THEN2 ASSUME_TAC SUBST1_TAC) THEN
    REWRITE_TAC[] THEN DISJ1_TAC THEN MATCH_MP_TAC REAL_EXP_MONO_IMP THEN
    POP_ASSUM ACCEPT_TAC;
    MATCH_ACCEPT_TAC REAL_EXP_MONO_IMP]);;
let REAL_EXP_MONO_LE = prove(
  `!x y. exp(x) <= exp(y) <=> x <= y`,
  REPEAT GEN_TAC THEN REWRITE_TAC[GSYM REAL_NOT_LT] THEN
  REWRITE_TAC[REAL_EXP_MONO_LT]);;
let REAL_EXP_INJ = prove(
  `!x y. (exp(x) = exp(y)) <=> (x = y)`,
  REPEAT GEN_TAC THEN ONCE_REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN
  REWRITE_TAC[REAL_EXP_MONO_LE]);;
let REAL_EXP_TOTAL_LEMMA = prove(
  `!y. &1 <= y ==> ?x. &0 <= x /\ x <= y - &1 /\ (exp(x) = y)`,
  GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC IVT THEN
  ASM_REWRITE_TAC[REAL_EXP_0; REAL_LE_SUB_LADD; REAL_ADD_LID] THEN CONJ_TAC THENL
   [RULE_ASSUM_TAC(ONCE_REWRITE_RULE[GSYM REAL_SUB_LE]) THEN
    POP_ASSUM(MP_TAC o MATCH_MP REAL_EXP_LE_X) THEN REWRITE_TAC[REAL_SUB_ADD2];
    X_GEN_TAC `x:real` THEN DISCH_THEN(K ALL_TAC) THEN
    MATCH_MP_TAC DIFF_CONT THEN EXISTS_TAC `exp(x)` THEN
    MATCH_ACCEPT_TAC DIFF_EXP]);;
let REAL_EXP_TOTAL = prove(
  `!y. &0 < y ==> ?x. exp(x) = y`,
  GEN_TAC THEN DISCH_TAC THEN
  DISJ_CASES_TAC(SPECL [`&1`; `y:real`] REAL_LET_TOTAL) THENL
   [FIRST_ASSUM(X_CHOOSE_TAC `x:real` o MATCH_MP REAL_EXP_TOTAL_LEMMA) THEN
    EXISTS_TAC `x:real` THEN ASM_REWRITE_TAC[];
    MP_TAC(SPEC `y:real` REAL_INV_LT1) THEN ASM_REWRITE_TAC[] THEN
    DISCH_THEN(MP_TAC o MATCH_MP REAL_LT_IMP_LE) THEN
    DISCH_THEN(X_CHOOSE_TAC `x:real` o MATCH_MP REAL_EXP_TOTAL_LEMMA) THEN
    EXISTS_TAC `--x` THEN ASM_REWRITE_TAC[REAL_EXP_NEG] THEN
    MATCH_MP_TAC REAL_INVINV THEN CONV_TAC(RAND_CONV SYM_CONV) THEN
    MATCH_MP_TAC REAL_LT_IMP_NE THEN ASM_REWRITE_TAC[]]);;
let REAL_EXP_BOUND_LEMMA = prove
 (`!x. &0 <= x /\ x <= inv(&2) ==> exp(x) <= &1 + &2 * x`,
  GEN_TAC THEN DISCH_TAC THEN
  MATCH_MP_TAC REAL_LE_TRANS THEN
  EXISTS_TAC `suminf (\n. x pow n)` THEN CONJ_TAC THENL
   [REWRITE_TAC[exp; BETA_THM] THEN MATCH_MP_TAC SER_LE THEN
    REWRITE_TAC[summable; BETA_THM] THEN REPEAT CONJ_TAC THENL
     [GEN_TAC THEN
      GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
      MATCH_MP_TAC REAL_LE_RMUL_IMP THEN CONJ_TAC THENL
       [MATCH_MP_TAC REAL_POW_LE THEN ASM_REWRITE_TAC[];
        MATCH_MP_TAC REAL_INV_LE_1 THEN
        REWRITE_TAC[REAL_OF_NUM_LE; num_CONV `1`; LE_SUC_LT] THEN
        REWRITE_TAC[FACT_LT]];
      EXISTS_TAC `exp x` THEN REWRITE_TAC[BETA_RULE REAL_EXP_CONVERGES];
      EXISTS_TAC `inv(&1 - x)` THEN MATCH_MP_TAC GP THEN
      ASM_REWRITE_TAC[real_abs] THEN
      MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `inv(&2)` THEN
      ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV];
    SUBGOAL_THEN `suminf (\n. x pow n) = inv (&1 - x)` SUBST1_TAC THENL
     [CONV_TAC SYM_CONV THEN MATCH_MP_TAC SUM_UNIQ THEN
      MATCH_MP_TAC GP THEN
      ASM_REWRITE_TAC[real_abs] THEN
      MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `inv(&2)` THEN
      ASM_REWRITE_TAC[] THEN CONV_TAC REAL_RAT_REDUCE_CONV;
      MATCH_MP_TAC REAL_LE_LCANCEL_IMP THEN
      EXISTS_TAC `&1 - x` THEN
      SUBGOAL_THEN `(&1 - x) * inv (&1 - x) = &1` SUBST1_TAC THENL
       [MATCH_MP_TAC REAL_MUL_RINV THEN
        REWRITE_TAC[REAL_ARITH `(&1 - x = &0) <=> (x = &1)`] THEN
        DISCH_THEN SUBST_ALL_TAC THEN
        POP_ASSUM MP_TAC THEN CONV_TAC REAL_RAT_REDUCE_CONV;
        CONJ_TAC THENL
         [MATCH_MP_TAC REAL_LET_TRANS THEN
          EXISTS_TAC `inv(&2) - x` THEN
          ASM_REWRITE_TAC[REAL_ARITH `&0 <= x - y <=> y <= x`] THEN
          ASM_REWRITE_TAC[REAL_ARITH `a - x < b - x <=> a < b`] THEN
          CONV_TAC REAL_RAT_REDUCE_CONV;
          REWRITE_TAC[REAL_ADD_LDISTRIB; REAL_SUB_RDISTRIB] THEN
          REWRITE_TAC[REAL_MUL_RID; REAL_MUL_LID] THEN
          REWRITE_TAC[REAL_ARITH `&1 <= (&1 + &2 * x) - (x + x * &2 * x) <=>
                                  x * (&2 * x) <= x * &1`] THEN
          MATCH_MP_TAC REAL_LE_LMUL_IMP THEN ASM_REWRITE_TAC[] THEN
          MATCH_MP_TAC REAL_LE_LCANCEL_IMP THEN EXISTS_TAC `inv(&2)` THEN
          REWRITE_TAC[REAL_MUL_ASSOC] THEN
          CONV_TAC REAL_RAT_REDUCE_CONV THEN
          ASM_REWRITE_TAC[REAL_MUL_LID; real_div]]]]]);;
(* ------------------------------------------------------------------------ *)
(* Properties of the logarithmic function                                   *)
(* ------------------------------------------------------------------------ *)
 
let LN_EXP = prove(
  `!x. ln(exp x) = x`,
  GEN_TAC THEN REWRITE_TAC[ln; 
REAL_EXP_INJ] THEN
  CONV_TAC SYM_CONV THEN CONV_TAC(RAND_CONV(ONCE_DEPTH_CONV SYM_CONV)) THEN
  CONV_TAC(ONCE_DEPTH_CONV ETA_CONV) THEN MATCH_MP_TAC SELECT_AX THEN
  EXISTS_TAC `x:real` THEN REFL_TAC);;
 
let REAL_EXP_LN = prove(
  `!x. (exp(ln x) = x) <=> &0 < x`,
  GEN_TAC THEN EQ_TAC THENL
   [DISCH_THEN(SUBST1_TAC o SYM) THEN MATCH_ACCEPT_TAC 
REAL_EXP_POS_LT;
    DISCH_THEN(X_CHOOSE_THEN `y:real` MP_TAC o MATCH_MP REAL_EXP_TOTAL) THEN
    DISCH_THEN(SUBST1_TAC o SYM) THEN REWRITE_TAC[
REAL_EXP_INJ; 
LN_EXP]]);;
 
let LN_MUL = prove(
  `!x y. &0 < x /\ &0 < y ==> (ln(x * y) = ln(x) + ln(y))`,
  REPEAT GEN_TAC THEN STRIP_TAC THEN ONCE_REWRITE_TAC[GSYM 
REAL_EXP_INJ] THEN
  REWRITE_TAC[
REAL_EXP_ADD] THEN SUBGOAL_THEN `&0 < x * y` ASSUME_TAC THENL
   [MATCH_MP_TAC 
REAL_LT_MUL THEN ASM_REWRITE_TAC[];
    EVERY_ASSUM(fun th -> REWRITE_TAC[ONCE_REWRITE_RULE[GSYM 
REAL_EXP_LN] th])]);;
 
let LN_INJ = prove(
  `!x y. &0 < x /\ &0 < y ==> ((ln(x) = ln(y)) <=> (x = y))`,
  REPEAT GEN_TAC THEN STRIP_TAC THEN
  EVERY_ASSUM(fun th -> GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV)
    [SYM(REWRITE_RULE[GSYM 
REAL_EXP_LN] th)]) THEN
  CONV_TAC SYM_CONV THEN MATCH_ACCEPT_TAC 
REAL_EXP_INJ);;
 
let LN_INV = prove(
  `!x. &0 < x ==> (ln(inv x) = --(ln x))`,
  GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[GSYM 
REAL_RNEG_UNIQ] THEN
  SUBGOAL_THEN `&0 < x /\ &0 < inv(x)` MP_TAC THENL
   [CONJ_TAC THEN TRY(MATCH_MP_TAC 
REAL_INV_POS) THEN ASM_REWRITE_TAC[];
    DISCH_THEN(fun th -> REWRITE_TAC[GSYM(MATCH_MP 
LN_MUL th)]) THEN
    SUBGOAL_THEN `x * (inv x) = &1` SUBST1_TAC THENL
     [MATCH_MP_TAC 
REAL_MUL_RINV THEN
      POP_ASSUM(ACCEPT_TAC o MATCH_MP 
REAL_POS_NZ);
      REWRITE_TAC[
LN_1]]]);;
 
let LN_DIV = prove(
  `!x. &0 < x /\ &0 < y ==> (ln(x / y) = ln(x) - ln(y))`,
  GEN_TAC THEN STRIP_TAC THEN
  SUBGOAL_THEN `&0 < x /\ &0 < inv(y)` MP_TAC THENL
   [CONJ_TAC THEN TRY(MATCH_MP_TAC 
REAL_INV_POS) THEN ASM_REWRITE_TAC[];
    REWRITE_TAC[
real_div] THEN
    DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP 
LN_MUL th]) THEN
    REWRITE_TAC[MATCH_MP 
LN_INV (ASSUME `&0 < y`)] THEN
    REWRITE_TAC[
real_sub]]);;
 
let LN_MONO_LT = prove(
  `!x y. &0 < x /\ &0 < y ==> (ln(x) < ln(y) <=> x < y)`,
  REPEAT GEN_TAC THEN STRIP_TAC THEN
  EVERY_ASSUM(fun th -> GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV)
    [SYM(REWRITE_RULE[GSYM 
REAL_EXP_LN] th)]) THEN
  CONV_TAC SYM_CONV THEN MATCH_ACCEPT_TAC 
REAL_EXP_MONO_LT);;
 
let LN_MONO_LE = prove(
  `!x y. &0 < x /\ &0 < y ==> (ln(x) <= ln(y) <=> x <= y)`,
  REPEAT GEN_TAC THEN STRIP_TAC THEN
  EVERY_ASSUM(fun th -> GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV)
    [SYM(REWRITE_RULE[GSYM 
REAL_EXP_LN] th)]) THEN
  CONV_TAC SYM_CONV THEN MATCH_ACCEPT_TAC 
REAL_EXP_MONO_LE);;
 
let LN_POW = prove(
  `!n x. &0 < x ==> (ln(x pow n) = &n * ln(x))`,
  REPEAT GEN_TAC THEN
  DISCH_THEN(CHOOSE_THEN (SUBST1_TAC o SYM) o MATCH_MP REAL_EXP_TOTAL) THEN
  REWRITE_TAC[GSYM 
REAL_EXP_N; 
LN_EXP]);;
 
let LN_LE = prove(
  `!x. &0 <= x ==> ln(&1 + x) <= x`,
  GEN_TAC THEN DISCH_TAC THEN
  GEN_REWRITE_TAC RAND_CONV  [GSYM 
LN_EXP] THEN
  MP_TAC(SPECL [`&1 + x`; `exp(x)`] 
LN_MONO_LE) THEN
  W(C SUBGOAL_THEN (fun t -> REWRITE_TAC[t]) o funpow 2 (fst o dest_imp) o snd) THENL
   [REWRITE_TAC[
REAL_EXP_POS_LT] THEN MATCH_MP_TAC 
REAL_LET_TRANS THEN
    EXISTS_TAC `x:real` THEN ASM_REWRITE_TAC[
REAL_LT_ADDL; 
REAL_LT_01];
    DISCH_THEN SUBST1_TAC THEN MATCH_MP_TAC 
REAL_EXP_LE_X THEN ASM_REWRITE_TAC[]]);;
 
let DIFF_LN = prove(
  `!x. &0 < x ==> (ln diffl (inv x))(x)`,
  GEN_TAC THEN DISCH_TAC THEN
  FIRST_ASSUM(ASSUME_TAC o REWRITE_RULE[GSYM 
REAL_EXP_LN]) THEN
  FIRST_ASSUM (fun th ->  GEN_REWRITE_TAC RAND_CONV  [GSYM th]) THEN
  MATCH_MP_TAC 
DIFF_INVERSE_LT THEN
  FIRST_ASSUM(ASSUME_TAC o MATCH_MP 
REAL_POS_NZ) THEN
  ASM_REWRITE_TAC[MATCH_MP 
DIFF_CONT (SPEC_ALL 
DIFF_EXP)] THEN
  MP_TAC(SPEC `ln(x)` 
DIFF_EXP) THEN ASM_REWRITE_TAC[] THEN
  DISCH_TAC THEN ASM_REWRITE_TAC[
LN_EXP] THEN
  EXISTS_TAC `&1` THEN MATCH_ACCEPT_TAC 
REAL_LT_01);;
 
let sqrt_def = new_definition
  `sqrt(x) = @y. &0 <= y /\ (y pow 2 = x)`;;
let ROOT_LT_LEMMA = prove(
  `!n x. &0 < x ==> (exp(ln(x) / &(SUC n)) pow (SUC n) = x)`,
  REPEAT GEN_TAC THEN DISCH_TAC THEN
  REWRITE_TAC[GSYM 
REAL_EXP_N] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
  REWRITE_TAC[
real_div; GSYM REAL_MUL_ASSOC] THEN
  SUBGOAL_THEN `inv(&(SUC n)) * &(SUC n) = &1` SUBST1_TAC THENL
   [MATCH_MP_TAC REAL_MUL_LINV THEN REWRITE_TAC[
REAL_INJ; 
NOT_SUC];
    ASM_REWRITE_TAC[
REAL_MUL_RID; 
REAL_EXP_LN]]);;
 
let ROOT_LN = prove(
  `!x. &0 < x ==> !n. root(SUC n) x = exp(ln(x) / &(SUC n))`,
  GEN_TAC THEN DISCH_TAC THEN GEN_TAC THEN REWRITE_TAC[root] THEN
  MATCH_MP_TAC 
SELECT_UNIQUE THEN X_GEN_TAC `y:real` THEN BETA_TAC THEN
  ASM_REWRITE_TAC[] THEN EQ_TAC THENL
   [DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (SUBST1_TAC o SYM)) THEN
    SUBGOAL_THEN `!z. &0 < y /\ &0 < exp(z)` MP_TAC THENL
     [ASM_REWRITE_TAC[
REAL_EXP_POS_LT]; ALL_TAC] THEN
    DISCH_THEN(MP_TAC o GEN_ALL o SYM o MATCH_MP 
LN_INJ o SPEC_ALL) THEN
    DISCH_THEN(fun th -> GEN_REWRITE_TAC I [th]) THEN
    REWRITE_TAC[
LN_EXP] THEN
    SUBGOAL_THEN `ln(y) * &(SUC n) = (ln(y pow(SUC n)) / &(SUC n)) * &(SUC n)`
    MP_TAC THENL
     [REWRITE_TAC[
real_div; GSYM REAL_MUL_ASSOC] THEN
      SUBGOAL_THEN `inv(&(SUC n)) * &(SUC n) = &1` SUBST1_TAC THENL
       [MATCH_MP_TAC REAL_MUL_LINV THEN REWRITE_TAC[
REAL_INJ; 
NOT_SUC];
        REWRITE_TAC[
REAL_MUL_RID] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
        CONV_TAC SYM_CONV THEN MATCH_MP_TAC 
LN_POW THEN
        ASM_REWRITE_TAC[]];
      REWRITE_TAC[REAL_EQ_RMUL; 
REAL_INJ; 
NOT_SUC]];
    DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[
REAL_EXP_POS_LT] THEN
    MATCH_MP_TAC 
ROOT_LT_LEMMA THEN ASM_REWRITE_TAC[]]);;
 
let ROOT_0 = prove(
  `!n. root(SUC n) (&0) = &0`,
  GEN_TAC THEN REWRITE_TAC[root] THEN
  MATCH_MP_TAC 
SELECT_UNIQUE THEN X_GEN_TAC `y:real` THEN
  BETA_TAC THEN REWRITE_TAC[
REAL_LT_REFL] THEN EQ_TAC THENL
   [SPEC_TAC(`n:num`,`n:num`) THEN INDUCT_TAC THEN ONCE_REWRITE_TAC[pow] THENL
     [REWRITE_TAC[pow; 
REAL_MUL_RID];
      REWRITE_TAC[
REAL_ENTIRE] THEN DISCH_THEN DISJ_CASES_TAC THEN
      ASM_REWRITE_TAC[] THEN FIRST_ASSUM MATCH_MP_TAC THEN
      ASM_REWRITE_TAC[]];
    DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[pow; 
REAL_MUL_LZERO]]);;
 
let ROOT_POW_POS = prove(
  `!n x. &0 <= x ==> ((root(SUC n) x) pow (SUC n) = x)`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
REAL_LE_LT] THEN
  DISCH_THEN DISJ_CASES_TAC THENL
   [FIRST_ASSUM(fun th -> REWRITE_TAC
     [MATCH_MP 
ROOT_LN th; MATCH_MP 
ROOT_LT_LEMMA th]);
    FIRST_ASSUM(SUBST1_TAC o SYM) THEN REWRITE_TAC[
ROOT_0] THEN
    MATCH_ACCEPT_TAC 
POW_0]);;
 
let POW_ROOT_POS = prove(
  `!n x. &0 <= x ==> (root(SUC n)(x pow (SUC n)) = x)`,
  REPEAT GEN_TAC THEN DISCH_TAC THEN
  REWRITE_TAC[root] THEN MATCH_MP_TAC 
SELECT_UNIQUE THEN
  X_GEN_TAC `y:real` THEN BETA_TAC THEN EQ_TAC THEN
  DISCH_TAC THEN ASM_REWRITE_TAC[] THENL
   [DISJ_CASES_THEN MP_TAC (REWRITE_RULE[
REAL_LE_LT] (ASSUME `&0 <= x`)) THENL
     [DISCH_TAC THEN FIRST_ASSUM(UNDISCH_TAC o check is_conj o concl) THEN
      FIRST_ASSUM(fun th ->  REWRITE_TAC[MATCH_MP 
POW_POS_LT th]) THEN
      DISCH_TAC THEN MATCH_MP_TAC 
POW_EQ THEN EXISTS_TAC `n:num` THEN
      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
REAL_LT_IMP_LE THEN
      ASM_REWRITE_TAC[];
      DISCH_THEN(SUBST_ALL_TAC o SYM) THEN
      FIRST_ASSUM(UNDISCH_TAC o check is_conj o concl) THEN
      REWRITE_TAC[
POW_0; 
REAL_LT_REFL; 
POW_ZERO]];
    ASM_REWRITE_TAC[
REAL_LT_LE] THEN CONV_TAC CONTRAPOS_CONV THEN
    REWRITE_TAC[] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
    REWRITE_TAC[
POW_0]]);;
 
let ROOT_POS_UNIQ = prove
 (`!n x y. &0 <= x /\ &0 <= y /\ (y pow (SUC n) = x)
           ==> (root (SUC n) x = y)`,
  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  DISCH_THEN(CONJUNCTS_THEN2 MP_TAC (SUBST1_TAC o SYM)) THEN
  ASM_SIMP_TAC[
POW_ROOT_POS]);;
 
let ROOT_MUL = prove
 (`!n x y. &0 <= x /\ &0 <= y
           ==> (root(SUC n) (x * y) = root(SUC n) x * root(SUC n) y)`,
 
let ROOT_INV = prove
 (`!n x. &0 <= x ==> (root(SUC n) (inv x) = inv(root(SUC n) x))`,
 
let ROOT_DIV = prove
 (`!n x y. &0 <= x /\ &0 <= y
           ==> (root(SUC n) (x / y) = root(SUC n) x / root(SUC n) y)`,
 
let ROOT_MONO_LT = prove
 (`!x y. &0 <= x /\ x < y ==> root(SUC n) x < root(SUC n) y`,
  REPEAT STRIP_TAC THEN SUBGOAL_THEN `&0 <= y` ASSUME_TAC THENL
   [ASM_MESON_TAC[
REAL_LE_TRANS; 
REAL_LT_IMP_LE]; ALL_TAC] THEN
  UNDISCH_TAC `x < y` THEN CONV_TAC CONTRAPOS_CONV THEN
  REWRITE_TAC[
REAL_NOT_LT] THEN DISCH_TAC THEN
  SUBGOAL_THEN `(x = (root(SUC n) x) pow (SUC n)) /\
                (y = (root(SUC n) y) pow (SUC n))`
   (CONJUNCTS_THEN SUBST1_TAC)
  THENL [ASM_SIMP_TAC[GSYM 
ROOT_POW_POS]; ALL_TAC] THEN
  MATCH_MP_TAC 
REAL_POW_LE2 THEN
  ASM_SIMP_TAC[
NOT_SUC; 
ROOT_POS_POSITIVE]);;
 
let ROOT_INJ = prove
 (`!x y. &0 <= x /\ &0 <= y ==> ((root(SUC n) x = root(SUC n) y) <=> (x = y))`,
 
let SQRT_MUL = prove
 (`!x y. &0 <= x /\ &0 <= y
           ==> (sqrt(x * y) = sqrt x * sqrt y)`,
  REWRITE_TAC[sqrt; num_CONV `2`; 
ROOT_MUL]);;
 
let SQRT_DIV = prove
 (`!x y. &0 <= x /\ &0 <= y
           ==> (sqrt (x / y) = sqrt x / sqrt y)`,
  REWRITE_TAC[sqrt; num_CONV `2`; 
ROOT_DIV]);;
 
let SQRT_INJ = prove
 (`!x y. &0 <= x /\ &0 <= y ==> ((sqrt(x) = sqrt(y)) <=> (x = y))`,
  REWRITE_TAC[sqrt; num_CONV `2`; 
ROOT_INJ]);;
 
let SIN_0 = prove(
  `sin(&0) = &0`,
  REWRITE_TAC[sin] THEN CONV_TAC SYM_CONV THEN
  MATCH_MP_TAC 
SUM_UNIQ THEN BETA_TAC THEN
  W(MP_TAC o C SPEC 
SER_0 o rand o rator o snd) THEN
  DISCH_THEN(MP_TAC o SPEC `0`) THEN REWRITE_TAC[
LE_0] THEN
  BETA_TAC THEN
  REWRITE_TAC[sum] THEN DISCH_THEN MATCH_MP_TAC THEN
  X_GEN_TAC `n:num` THEN COND_CASES_TAC THEN
  ASM_REWRITE_TAC[
REAL_MUL_LZERO] THEN
  MP_TAC(SPEC `n:num` 
ODD_EXISTS) THEN ASM_REWRITE_TAC[GSYM 
NOT_EVEN] THEN
  DISCH_THEN(CHOOSE_THEN SUBST1_TAC) THEN
  REWRITE_TAC[GSYM 
ADD1; 
POW_0; 
REAL_MUL_RZERO]);;
 
let COS_0 = prove(
  `cos(&0) = &1`,
  REWRITE_TAC[cos] THEN CONV_TAC SYM_CONV THEN
  MATCH_MP_TAC 
SUM_UNIQ THEN BETA_TAC THEN
  W(MP_TAC o C SPEC 
SER_0 o rand o rator o snd) THEN
  DISCH_THEN(MP_TAC o SPEC `1`) THEN
  REWRITE_TAC[num_CONV `1`; sum; 
ADD_CLAUSES] THEN BETA_TAC THEN
  REWRITE_TAC[
EVEN; pow; 
FACT] THEN
  REWRITE_TAC[REAL_ADD_LID; 
REAL_MUL_RID] THEN
  SUBGOAL_THEN `0 DIV 2 = 0` SUBST1_TAC THENL
   [MATCH_MP_TAC 
DIV_UNIQ THEN EXISTS_TAC `0` THEN
    REWRITE_TAC[
MULT_CLAUSES; 
ADD_CLAUSES] THEN
    REWRITE_TAC[num_CONV `2`; 
LT_0];
    REWRITE_TAC[pow]] THEN
  SUBGOAL_THEN `&1 / &1 = &(SUC 0)` SUBST1_TAC THENL
   [REWRITE_TAC[SYM(num_CONV `1`)] THEN MATCH_MP_TAC 
REAL_DIV_REFL THEN
    MATCH_ACCEPT_TAC REAL_10;
    DISCH_THEN MATCH_MP_TAC] THEN
  X_GEN_TAC `n:num` THEN REWRITE_TAC[
LE_SUC_LT] THEN
  DISCH_THEN(CHOOSE_THEN SUBST1_TAC o MATCH_MP 
LESS_ADD_1) THEN
  REWRITE_TAC[GSYM 
ADD1; 
POW_0; 
REAL_MUL_RZERO; 
ADD_CLAUSES]);;
 
let SIN_CIRCLE = prove(
  `!x. (sin(x) pow 2) + (cos(x) pow 2) = &1`,
  GEN_TAC THEN CONV_TAC(LAND_CONV(X_BETA_CONV `x:real`)) THEN
  SUBGOAL_THEN `&1 = (\x.(sin(x) pow 2) + (cos(x) pow 2))(&0)` SUBST1_TAC THENL
   [BETA_TAC THEN REWRITE_TAC[
SIN_0; 
COS_0] THEN
    REWRITE_TAC[num_CONV `2`; 
POW_0] THEN
    REWRITE_TAC[pow; 
POW_1] THEN REWRITE_TAC[REAL_ADD_LID; REAL_MUL_LID];
    MATCH_MP_TAC 
DIFF_ISCONST_ALL THEN X_GEN_TAC `x:real` THEN
    W(MP_TAC o DIFF_CONV o rand o funpow 2 rator o snd) THEN
    DISCH_THEN(MP_TAC o SPEC `x:real`) THEN
    MATCH_MP_TAC EQ_IMP THEN AP_THM_TAC THEN
    AP_TERM_TAC THEN REWRITE_TAC[GSYM 
REAL_NEG_LMUL; GSYM 
REAL_NEG_RMUL] THEN
    REWRITE_TAC[GSYM 
real_sub; 
REAL_SUB_0] THEN
    REWRITE_TAC[GSYM REAL_MUL_ASSOC; 
REAL_MUL_RID] THEN
    AP_TERM_TAC THEN REWRITE_TAC[num_CONV `2`; 
SUC_SUB1] THEN
    REWRITE_TAC[
POW_1] THEN MATCH_ACCEPT_TAC REAL_MUL_SYM]);;
 
let SIN_COS_ADD = prove(
  `!x y. ((sin(x + y) - ((sin(x) * cos(y)) + (cos(x) * sin(y)))) pow 2) +
         ((cos(x + y) - ((cos(x) * cos(y)) - (sin(x) * sin(y)))) pow 2) = &0`,
 
let SIN_COS_NEG = prove(
  `!x. ((sin(--x) + (sin x)) pow 2) +
       ((cos(--x) - (cos x)) pow 2) = &0`,
 
let SIN_ADD = prove(
  `!x y. sin(x + y) = (sin(x) * cos(y)) + (cos(x) * sin(y))`,
 
let COS_ADD = prove(
  `!x y. cos(x + y) = (cos(x) * cos(y)) - (sin(x) * sin(y))`,
 
let SIN_PAIRED = prove(
  `!x. (\n. (((--(&1)) pow n) / &(
FACT((2 * n) + 1)))
         * (x pow ((2 * n) + 1))) sums (sin x)`,
 
let SIN_POS = prove(
  `!x. &0 < x /\ x < &2 ==> &0 < sin(x)`,
  GEN_TAC THEN STRIP_TAC THEN MP_TAC(SPEC `x:real` 
SIN_PAIRED) THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
SUM_SUMMABLE) THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
SER_PAIR) THEN
  REWRITE_TAC[SYM(MATCH_MP 
SUM_UNIQ (SPEC `x:real` 
SIN_PAIRED))] THEN
  REWRITE_TAC[
SUM_2] THEN BETA_TAC THEN REWRITE_TAC[GSYM 
ADD1] THEN
  REWRITE_TAC[pow; GSYM 
REAL_NEG_MINUS1; 
POW_MINUS1] THEN
  REWRITE_TAC[
real_div; GSYM 
REAL_NEG_LMUL; GSYM 
real_sub] THEN
  REWRITE_TAC[REAL_MUL_LID] THEN REWRITE_TAC[
ADD1] THEN DISCH_TAC THEN
  FIRST_ASSUM(SUBST1_TAC o MATCH_MP 
SUM_UNIQ) THEN
  W(C SUBGOAL_THEN SUBST1_TAC o curry mk_eq `&0` o curry mk_comb `sum(0,0)` o
  funpow 2 rand o snd) THENL [REWRITE_TAC[sum]; ALL_TAC] THEN
  MATCH_MP_TAC 
SER_POS_LT THEN
  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP 
SUM_SUMMABLE th]) THEN
  X_GEN_TAC `n:num` THEN DISCH_THEN(K ALL_TAC) THEN BETA_TAC THEN
  REWRITE_TAC[GSYM 
ADD1; 
MULT_CLAUSES] THEN
  REWRITE_TAC[num_CONV `2`; 
ADD_CLAUSES; pow; 
FACT; GSYM 
REAL_MUL] THEN
  REWRITE_TAC[SYM(num_CONV `2`)] THEN
  REWRITE_TAC[num_CONV `1`; 
ADD_CLAUSES; pow; 
FACT; GSYM 
REAL_MUL] THEN
  REWRITE_TAC[
REAL_SUB_LT] THEN ONCE_REWRITE_TAC[GSYM pow] THEN
  REWRITE_TAC[REAL_MUL_ASSOC] THEN
  MATCH_MP_TAC 
REAL_LT_RMUL_IMP THEN CONJ_TAC THENL
   [ALL_TAC; MATCH_MP_TAC 
POW_POS_LT THEN ASM_REWRITE_TAC[]] THEN
  REWRITE_TAC[GSYM REAL_MUL_ASSOC; GSYM 
POW_2] THEN
  SUBGOAL_THEN `!n. &0 < &(SUC n)` ASSUME_TAC THENL
   [GEN_TAC THEN REWRITE_TAC[
REAL_LT; 
LT_0]; ALL_TAC] THEN
  SUBGOAL_THEN `!n. &0 < &(
FACT n)` ASSUME_TAC THENL
   [GEN_TAC THEN REWRITE_TAC[
REAL_LT; 
FACT_LT]; ALL_TAC] THEN
  SUBGOAL_THEN `!n. ~(&(SUC n) = &0)` ASSUME_TAC THENL
   [GEN_TAC THEN REWRITE_TAC[
REAL_INJ; 
NOT_SUC]; ALL_TAC] THEN
  SUBGOAL_THEN `!n. ~(&(
FACT n) = &0)` ASSUME_TAC THENL
   [GEN_TAC THEN MATCH_MP_TAC 
REAL_POS_NZ THEN
    REWRITE_TAC[
REAL_LT; 
FACT_LT]; ALL_TAC] THEN
  REPEAT(IMP_SUBST_TAC 
REAL_INV_MUL_WEAK THEN ASM_REWRITE_TAC[
REAL_ENTIRE]) THEN
  REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN
  ONCE_REWRITE_TAC[AC 
REAL_MUL_AC
    `a * b * c * d * e = (a * b * e) * (c * d)`] THEN
  GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
  MATCH_MP_TAC 
REAL_LT_RMUL_IMP THEN CONJ_TAC THENL
   [ALL_TAC; MATCH_MP_TAC 
REAL_LT_MUL THEN CONJ_TAC THEN
    MATCH_MP_TAC 
REAL_INV_POS THEN ASM_REWRITE_TAC[]] THEN
  REWRITE_TAC[REAL_MUL_ASSOC] THEN
  IMP_SUBST_TAC ((CONV_RULE(RAND_CONV SYM_CONV) o SPEC_ALL) 
REAL_INV_MUL_WEAK) THEN
  ASM_REWRITE_TAC[
REAL_ENTIRE] THEN ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
  REWRITE_TAC[GSYM 
real_div] THEN MATCH_MP_TAC 
REAL_LT_1 THEN
  REWRITE_TAC[
POW_2] THEN CONJ_TAC THENL
   [MATCH_MP_TAC 
REAL_LE_MUL THEN CONJ_TAC;
    MATCH_MP_TAC 
REAL_LT_MUL2_ALT THEN REPEAT CONJ_TAC] THEN
  TRY(MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ASM_REWRITE_TAC[] THEN NO_TAC) THENL
   [W((then_) (MATCH_MP_TAC 
REAL_LT_TRANS) o EXISTS_TAC o
      curry mk_comb `&` o funpow 3 rand o snd) THEN
    REWRITE_TAC[
REAL_LT; 
LESS_SUC_REFL]; ALL_TAC] THEN
  MATCH_MP_TAC 
REAL_LTE_TRANS THEN EXISTS_TAC `&2` THEN
  ASM_REWRITE_TAC[] THEN CONV_TAC(REDEPTH_CONV num_CONV) THEN
  REWRITE_TAC[
REAL_LE; 
LE_SUC; 
LE_0]);;
 
let COS_ISZERO = prove(
  `?!x. &0 <= x /\ x <= &2 /\ (cos x = &0)`,
  REWRITE_TAC[EXISTS_UNIQUE_DEF] THEN BETA_TAC THEN
  W(C SUBGOAL_THEN ASSUME_TAC o hd o conjuncts o snd) THENL
   [MATCH_MP_TAC 
IVT2 THEN REPEAT CONJ_TAC THENL
     [REWRITE_TAC[
REAL_LE; 
LE_0];
      MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ACCEPT_TAC 
COS_2;
      REWRITE_TAC[
COS_0; 
REAL_LE_01];
      X_GEN_TAC `x:real` THEN DISCH_THEN(K ALL_TAC) THEN
      MATCH_MP_TAC 
DIFF_CONT THEN EXISTS_TAC `--(sin x)` THEN
      REWRITE_TAC[
DIFF_COS]];
    ASM_REWRITE_TAC[] THEN BETA_TAC THEN
    MAP_EVERY X_GEN_TAC [`x1:real`; `x2:real`] THEN
    GEN_REWRITE_TAC I [TAUT `a <=> ~ ~a`] THEN
    PURE_REWRITE_TAC[NOT_IMP] THEN REWRITE_TAC[] THEN STRIP_TAC THEN
    MP_TAC(SPECL [`x1:real`; `x2:real`] 
REAL_LT_TOTAL) THEN
    SUBGOAL_THEN `(!x. cos differentiable x) /\
                  (!x. cos contl x)` STRIP_ASSUME_TAC THENL
     [CONJ_TAC THEN GEN_TAC THENL
       [REWRITE_TAC[differentiable]; MATCH_MP_TAC 
DIFF_CONT] THEN
      EXISTS_TAC `--(sin x)` THEN REWRITE_TAC[
DIFF_COS]; ALL_TAC] THEN
    ASM_REWRITE_TAC[] THEN DISCH_THEN DISJ_CASES_TAC THENL
     [MP_TAC(SPECL [`cos`; `x1:real`; `x2:real`] 
ROLLE);
      MP_TAC(SPECL [`cos`; `x2:real`; `x1:real`] 
ROLLE)] THEN
    ASM_REWRITE_TAC[] THEN
    DISCH_THEN(X_CHOOSE_THEN `x:real` MP_TAC) THEN REWRITE_TAC[
CONJ_ASSOC] THEN
    DISCH_THEN(CONJUNCTS_THEN2 STRIP_ASSUME_TAC MP_TAC) THEN
    DISCH_THEN(MP_TAC o CONJ(SPEC `x:real` 
DIFF_COS)) THEN
    DISCH_THEN(MP_TAC o MATCH_MP 
DIFF_UNIQ) THEN
    REWRITE_TAC[
REAL_NEG_EQ0] THEN MATCH_MP_TAC 
REAL_POS_NZ THEN
    MATCH_MP_TAC 
SIN_POS THENL
     [CONJ_TAC THENL
       [MATCH_MP_TAC 
REAL_LET_TRANS THEN EXISTS_TAC `x1:real` THEN
        ASM_REWRITE_TAC[];
        MATCH_MP_TAC 
REAL_LTE_TRANS THEN EXISTS_TAC `x2:real` THEN
        ASM_REWRITE_TAC[]];
      CONJ_TAC THENL
       [MATCH_MP_TAC 
REAL_LET_TRANS THEN EXISTS_TAC `x2:real` THEN
        ASM_REWRITE_TAC[];
        MATCH_MP_TAC 
REAL_LTE_TRANS THEN EXISTS_TAC `x1:real` THEN
        ASM_REWRITE_TAC[]]]]);;
 
let PI2 = prove(
  `pi / &2 = @x. &0 <= x /\ x <= &2 /\ (cos(x) = &0)`,
  REWRITE_TAC[pi; 
real_div] THEN
  ONCE_REWRITE_TAC[AC 
REAL_MUL_AC
    `(a * b) * c = (c * a) * b`] THEN
  IMP_SUBST_TAC REAL_MUL_LINV THEN REWRITE_TAC[
REAL_INJ] THEN
  NUM_REDUCE_TAC THEN REWRITE_TAC[REAL_MUL_LID]);;
 
let COS_PI2 = prove(
  `cos(pi / &2) = &0`,
  MP_TAC(SELECT_RULE (EXISTENCE 
COS_ISZERO)) THEN
  REWRITE_TAC[GSYM 
PI2] THEN
  DISCH_THEN(fun th -> REWRITE_TAC[th]));;
 
let PI2_BOUNDS = prove(
  `&0 < (pi / &2) /\ (pi / &2) < &2`,
  MP_TAC(SELECT_RULE (EXISTENCE 
COS_ISZERO)) THEN
  REWRITE_TAC[GSYM 
PI2] THEN DISCH_TAC THEN
  ASM_REWRITE_TAC[
REAL_LT_LE] THEN CONJ_TAC THENL
   [DISCH_TAC THEN MP_TAC 
COS_0 THEN ASM_REWRITE_TAC[] THEN
    FIRST_ASSUM(SUBST1_TAC o SYM) THEN REWRITE_TAC[GSYM REAL_10];
    DISCH_TAC THEN MP_TAC 
COS_PI2 THEN FIRST_ASSUM SUBST1_TAC THEN
    REWRITE_TAC[] THEN MATCH_MP_TAC 
REAL_LT_IMP_NE THEN
    MATCH_ACCEPT_TAC 
COS_2]);;
 
let COS_POS_PI2 = prove(
  `!x. &0 < x /\ x < pi / &2 ==> &0 < cos(x)`,
  GEN_TAC THEN STRIP_TAC THEN
  GEN_REWRITE_TAC I [TAUT `a <=> ~ ~a`] THEN
  PURE_REWRITE_TAC[
REAL_NOT_LT] THEN DISCH_TAC THEN
  MP_TAC(SPECL [`cos`; `&0`; `x:real`; `&0`] 
IVT2) THEN
  ASM_REWRITE_TAC[
COS_0; 
REAL_LE_01; NOT_IMP] THEN REPEAT CONJ_TAC THENL
   [MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ASM_REWRITE_TAC[];
    X_GEN_TAC `z:real` THEN DISCH_THEN(K ALL_TAC) THEN
    MATCH_MP_TAC 
DIFF_CONT THEN EXISTS_TAC `--(sin z)` THEN
    REWRITE_TAC[
DIFF_COS];
    DISCH_THEN(X_CHOOSE_TAC `z:real`) THEN
    MP_TAC(CONJUNCT2 (CONV_RULE EXISTS_UNIQUE_CONV 
COS_ISZERO)) THEN
    DISCH_THEN(MP_TAC o SPECL [`z:real`; `pi / &2`]) THEN
    ASM_REWRITE_TAC[
COS_PI2] THEN REWRITE_TAC[NOT_IMP] THEN
    REPEAT CONJ_TAC THENL
     [MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `x:real` THEN
      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
REAL_LE_TRANS THEN
      EXISTS_TAC `pi / &2` THEN ASM_REWRITE_TAC[] THEN CONJ_TAC;
      ALL_TAC;
      ALL_TAC;
      DISCH_THEN SUBST_ALL_TAC THEN UNDISCH_TAC `x < pi / &2` THEN
      ASM_REWRITE_TAC[
REAL_NOT_LT]] THEN
    MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ASM_REWRITE_TAC[
PI2_BOUNDS]]);;
 
let COS_TOTAL = prove(
  `!y. --(&1) <= y /\ y <= &1 ==> ?!x. &0 <= x /\ x <= pi /\ (cos(x) = y)`,
  GEN_TAC THEN STRIP_TAC THEN
  CONV_TAC EXISTS_UNIQUE_CONV THEN CONJ_TAC THENL
   [MATCH_MP_TAC 
IVT2 THEN ASM_REWRITE_TAC[
COS_0; 
COS_PI] THEN
    REWRITE_TAC[MATCH_MP 
REAL_LT_IMP_LE PI_POS] THEN
    GEN_TAC THEN DISCH_THEN(K ALL_TAC) THEN
    MATCH_MP_TAC 
DIFF_CONT THEN EXISTS_TAC `--(sin x)` THEN
    REWRITE_TAC[
DIFF_COS];
    MAP_EVERY X_GEN_TAC [`x1:real`; `x2:real`] THEN STRIP_TAC THEN
    REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC
         (SPECL [`x1:real`; `x2:real`] 
REAL_LT_TOTAL) THENL
     [FIRST_ASSUM ACCEPT_TAC;
      MP_TAC(SPECL [`cos`; `x1:real`; `x2:real`] 
ROLLE);
      MP_TAC(SPECL [`cos`; `x2:real`; `x1:real`] 
ROLLE)]] THEN
  ASM_REWRITE_TAC[] THEN
  (W(C SUBGOAL_THEN (fun t -> REWRITE_TAC[t]) o funpow 2
                    (fst o dest_imp) o snd) THENL
    [CONJ_TAC THEN X_GEN_TAC `x:real` THEN DISCH_THEN(K ALL_TAC) THEN
     TRY(MATCH_MP_TAC 
DIFF_CONT) THEN REWRITE_TAC[differentiable] THEN
     EXISTS_TAC `--(sin x)` THEN REWRITE_TAC[
DIFF_COS]; ALL_TAC]) THEN
  DISCH_THEN(X_CHOOSE_THEN `x:real` STRIP_ASSUME_TAC) THEN
  UNDISCH_TAC `(cos diffl &0)(x)` THEN
  DISCH_THEN(MP_TAC o CONJ (SPEC `x:real` 
DIFF_COS)) THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
DIFF_UNIQ) THEN
  REWRITE_TAC[
REAL_NEG_EQ0] THEN DISCH_TAC THEN
  MP_TAC(SPEC `x:real` 
SIN_POS_PI) THEN
  ASM_REWRITE_TAC[
REAL_LT_REFL] THEN
  CONV_TAC CONTRAPOS_CONV THEN DISCH_THEN(K ALL_TAC) THEN
  REWRITE_TAC[] THEN CONJ_TAC THENL
   [MATCH_MP_TAC 
REAL_LET_TRANS THEN EXISTS_TAC `x1:real`;
    MATCH_MP_TAC 
REAL_LTE_TRANS THEN EXISTS_TAC `x2:real`;
    MATCH_MP_TAC 
REAL_LET_TRANS THEN EXISTS_TAC `x2:real`;
    MATCH_MP_TAC 
REAL_LTE_TRANS THEN EXISTS_TAC `x1:real`] THEN
  ASM_REWRITE_TAC[]);;
 
let SIN_TOTAL = prove(
  `!y. --(&1) <= y /\ y <= &1 ==>
        ?!x.  --(pi / &2) <= x /\ x <= pi / &2 /\ (sin(x) = y)`,
  GEN_TAC THEN DISCH_TAC THEN
  SUBGOAL_THEN `!x. --(pi / &2) <= x /\ x <= pi / &2 /\ (sin(x) = y) <=>
    &0 <= (x + pi / &2) /\ (x + pi / &2) <= pi /\ (cos(x + pi / &2) = --y)`
  (fun th -> REWRITE_TAC[th]) THENL
   [GEN_TAC THEN REWRITE_TAC[
COS_ADD; 
SIN_PI2; 
COS_PI2] THEN
    REWRITE_TAC[
REAL_MUL_RZERO; 
REAL_MUL_RZERO; 
REAL_MUL_RID] THEN
    REWRITE_TAC[
REAL_SUB_LZERO] THEN
    REWRITE_TAC[GSYM 
REAL_LE_SUB_RADD; GSYM 
REAL_LE_SUB_LADD] THEN
    REWRITE_TAC[
REAL_SUB_LZERO] THEN AP_TERM_TAC THEN
    REWRITE_TAC[
REAL_EQ_NEG] THEN AP_THM_TAC THEN
    REPEAT AP_TERM_TAC THEN
    GEN_REWRITE_TAC (RAND_CONV o LAND_CONV) [GSYM 
REAL_HALF_DOUBLE] THEN
    REWRITE_TAC[
REAL_ADD_SUB]; ALL_TAC] THEN
  MP_TAC(SPEC `--y` 
COS_TOTAL) THEN ASM_REWRITE_TAC[
REAL_LE_NEG] THEN
  ONCE_REWRITE_TAC[GSYM 
REAL_LE_NEG] THEN ASM_REWRITE_TAC[
REAL_NEGNEG] THEN
  REWRITE_TAC[
REAL_LE_NEG] THEN
  CONV_TAC(ONCE_DEPTH_CONV EXISTS_UNIQUE_CONV) THEN
  DISCH_THEN((then_) CONJ_TAC o MP_TAC) THENL
   [DISCH_THEN(X_CHOOSE_TAC `x:real` o CONJUNCT1) THEN
    EXISTS_TAC `x - pi / &2` THEN ASM_REWRITE_TAC[
REAL_SUB_ADD];
    POP_ASSUM(K ALL_TAC) THEN DISCH_THEN(ASSUME_TAC o CONJUNCT2) THEN
    REPEAT GEN_TAC THEN
    DISCH_THEN(fun th -> FIRST_ASSUM(MP_TAC o C MATCH_MP th)) THEN
    REWRITE_TAC[
REAL_EQ_RADD]]);;
 
let COS_ZERO = prove(
  `!x. (cos(x) = &0) <=> (?n. ~EVEN n /\ (x = &n * (pi / &2))) \/
                         (?n. ~EVEN n /\ (x = --(&n * (pi / &2))))`,
 
let SIN_ZERO = prove(
  `!x. (sin(x) = &0) <=> (?n. 
EVEN n /\ (x = &n * (pi / &2))) \/
                         (?n. 
EVEN n /\ (x = --(&n * (pi / &2))))`,
 
let COS_ONE_2PI = prove
 (`!x. (cos(x) = &1) <=> (?n. x = &n * &2 * pi) \/ (?n. x = --(&n * &2 * pi))`,
 
let TAN_ADD = prove(
  `!x y. ~(cos(x) = &0) /\ ~(cos(y) = &0) /\ ~(cos(x + y) = &0) ==>
           (tan(x + y) = (tan(x) + tan(y)) / (&1 - tan(x) * tan(y)))`,
  REPEAT GEN_TAC THEN STRIP_TAC THEN REWRITE_TAC[tan] THEN
  MP_TAC(SPECL [`cos(x) * cos(y)`;
                `&1 - (sin(x) / cos(x)) * (sin(y) / cos(y))`]
         
REAL_DIV_MUL2) THEN ASM_REWRITE_TAC[
REAL_ENTIRE] THEN
  W(C SUBGOAL_THEN MP_TAC o funpow 2 (fst o dest_imp) o snd) THENL
   [DISCH_THEN(MP_TAC o AP_TERM `(*) (cos(x) * cos(y))`) THEN
    REWRITE_TAC[real_div; REAL_SUB_LDISTRIB; GSYM REAL_MUL_ASSOC] THEN
    REWRITE_TAC[REAL_MUL_RID; REAL_MUL_RZERO] THEN
    UNDISCH_TAC `~(cos(x + y) = &0)` THEN
    MATCH_MP_TAC EQ_IMP THEN
    AP_TERM_TAC THEN AP_THM_TAC THEN AP_TERM_TAC THEN
    REWRITE_TAC[COS_ADD] THEN AP_TERM_TAC;
    DISCH_THEN(fun th -> DISCH_THEN(MP_TAC o C MATCH_MP th)) THEN
    DISCH_THEN(fun th -> ONCE_REWRITE_TAC[th]) THEN BINOP_TAC THENL
     [REWRITE_TAC[real_div; REAL_LDISTRIB; GSYM REAL_MUL_ASSOC] THEN
      REWRITE_TAC[SIN_ADD] THEN BINOP_TAC THENL
       [ONCE_REWRITE_TAC[AC REAL_MUL_AC
          `a * b * c * d = (d * a) * (c * b)`] THEN
        IMP_SUBST_TAC REAL_MUL_LINV THEN ASM_REWRITE_TAC[REAL_MUL_LID];
        ONCE_REWRITE_TAC[AC REAL_MUL_AC
          `a * b * c * d = (d * b) * (a * c)`] THEN
        IMP_SUBST_TAC REAL_MUL_LINV THEN ASM_REWRITE_TAC[REAL_MUL_LID]];
      REWRITE_TAC[COS_ADD; REAL_SUB_LDISTRIB; REAL_MUL_RID] THEN
      AP_TERM_TAC THEN REWRITE_TAC[real_div; GSYM REAL_MUL_ASSOC]]] THEN
  ONCE_REWRITE_TAC[AC REAL_MUL_AC
    `a * b * c * d * e * f = (f * b) * (d * a) * (c * e)`] THEN
  REPEAT(IMP_SUBST_TAC REAL_MUL_LINV THEN ASM_REWRITE_TAC[]) THEN
  REWRITE_TAC[REAL_MUL_LID]);;
let TAN_DOUBLE = prove(
  `!x. ~(cos(x) = &0) /\ ~(cos(&2 * x) = &0) ==>
            (tan(&2 * x) = (&2 * tan(x)) / (&1 - (tan(x) pow 2)))`,
  GEN_TAC THEN STRIP_TAC THEN
  MP_TAC(SPECL [`x:real`; `x:real`] TAN_ADD) THEN
  ASM_REWRITE_TAC[REAL_DOUBLE; POW_2]);;
let TAN_POS_PI2 = prove(
  `!x. &0 < x /\ x < pi / &2 ==> &0 < tan(x)`,
  GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[tan; real_div] THEN
  MATCH_MP_TAC REAL_LT_MUL THEN CONJ_TAC THENL
   [MATCH_MP_TAC SIN_POS_PI2;
    MATCH_MP_TAC REAL_INV_POS THEN MATCH_MP_TAC COS_POS_PI2] THEN
  ASM_REWRITE_TAC[]);;
let DIFF_TAN = prove(
  `!x. ~(cos(x) = &0) ==> (tan diffl inv(cos(x) pow 2))(x)`,
  GEN_TAC THEN DISCH_TAC THEN MP_TAC(DIFF_CONV `\x. sin(x) / cos(x)`) THEN
  DISCH_THEN(MP_TAC o SPEC `x:real`) THEN ASM_REWRITE_TAC[REAL_MUL_RID] THEN
  REWRITE_TAC[GSYM tan; GSYM REAL_NEG_LMUL; REAL_NEGNEG; real_sub] THEN
  CONV_TAC(ONCE_DEPTH_CONV ETA_CONV) THEN ONCE_REWRITE_TAC[REAL_ADD_SYM] THEN
  REWRITE_TAC[GSYM POW_2; SIN_CIRCLE; GSYM REAL_INV_1OVER]);;
let DIFF_TAN_COMPOSITE = prove
 (`(g diffl m)(x) /\ ~(cos(g x) = &0)
   ==> ((\x. tan(g x)) diffl (inv(cos(g x) pow 2) * m))(x)`,
  ASM_SIMP_TAC[DIFF_CHAIN; DIFF_TAN]) in
add_to_diff_net DIFF_TAN_COMPOSITE;;
let TAN_TOTAL_LEMMA = prove(
  `!y. &0 < y ==> ?x. &0 < x /\ x < pi / &2 /\ y < tan(x)`,
  GEN_TAC THEN DISCH_TAC THEN
  SUBGOAL_THEN `((\x. cos(x) / sin(x)) tends_real_real &0)(pi / &2)`
  MP_TAC THENL
   [SUBST1_TAC(SYM(SPEC `&1` REAL_DIV_LZERO)) THEN
    CONV_TAC(ONCE_DEPTH_CONV HABS_CONV) THEN MATCH_MP_TAC LIM_DIV THEN
    REWRITE_TAC[REAL_10] THEN CONV_TAC(ONCE_DEPTH_CONV ETA_CONV) THEN
    SUBST1_TAC(SYM COS_PI2) THEN SUBST1_TAC(SYM SIN_PI2) THEN
    REWRITE_TAC[GSYM CONTL_LIM] THEN CONJ_TAC THEN MATCH_MP_TAC DIFF_CONT THENL
     [EXISTS_TAC `--(sin(pi / &2))`;
      EXISTS_TAC `cos(pi / &2)`] THEN
    REWRITE_TAC[DIFF_SIN; DIFF_COS]; ALL_TAC] THEN
  REWRITE_TAC[LIM] THEN DISCH_THEN(MP_TAC o SPEC `inv(y)`) THEN
  FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP REAL_INV_POS th]) THEN
  BETA_TAC THEN REWRITE_TAC[REAL_SUB_RZERO] THEN
  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
  MP_TAC(SPECL [`d:real`; `pi / &2`] REAL_DOWN2) THEN
  ASM_REWRITE_TAC[PI2_BOUNDS] THEN
  DISCH_THEN(X_CHOOSE_THEN `e:real` STRIP_ASSUME_TAC) THEN
  EXISTS_TAC `(pi / &2) - e` THEN ASM_REWRITE_TAC[REAL_SUB_LT] THEN
  CONJ_TAC THENL
   [REWRITE_TAC[real_sub; GSYM REAL_NOT_LE; REAL_LE_ADDR; REAL_NEG_GE0] THEN
    ASM_REWRITE_TAC[REAL_NOT_LE]; ALL_TAC] THEN
  FIRST_ASSUM(UNDISCH_TAC o check is_forall o concl) THEN
  DISCH_THEN(MP_TAC o SPEC `(pi / &2) - e`) THEN
  REWRITE_TAC[REAL_SUB_SUB; ABS_NEG] THEN
  SUBGOAL_THEN `abs(e) = e` (fun th -> ASM_REWRITE_TAC[th]) THENL
   [REWRITE_TAC[ABS_REFL] THEN MATCH_MP_TAC REAL_LT_IMP_LE THEN
    FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN
  SUBGOAL_THEN `&0 < cos((pi / &2) - e) / sin((pi / &2) - e)`
  MP_TAC THENL
   [ONCE_REWRITE_TAC[real_div] THEN
    MATCH_MP_TAC REAL_LT_MUL THEN CONJ_TAC THENL
     [MATCH_MP_TAC COS_POS_PI2;
      MATCH_MP_TAC REAL_INV_POS THEN MATCH_MP_TAC SIN_POS_PI2] THEN
    ASM_REWRITE_TAC[REAL_SUB_LT] THEN
    REWRITE_TAC[GSYM REAL_NOT_LE; real_sub; REAL_LE_ADDR; REAL_NEG_GE0] THEN
    ASM_REWRITE_TAC[REAL_NOT_LE]; ALL_TAC] THEN
  DISCH_THEN(fun th -> ASSUME_TAC th THEN MP_TAC(MATCH_MP REAL_POS_NZ th)) THEN
  REWRITE_TAC[ABS_NZ; IMP_IMP] THEN
  DISCH_THEN(MP_TAC o MATCH_MP REAL_LT_INV2) THEN REWRITE_TAC[tan] THEN
  MATCH_MP_TAC EQ_IMP THEN BINOP_TAC THENL
   [MATCH_MP_TAC REAL_INVINV THEN MATCH_MP_TAC REAL_POS_NZ THEN
    FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN
  MP_TAC(ASSUME `&0 < cos((pi / &2) - e) / sin((pi / &2) - e)`) THEN
  DISCH_THEN(MP_TAC o MATCH_MP REAL_LT_IMP_LE) THEN
  REWRITE_TAC[GSYM ABS_REFL] THEN DISCH_THEN SUBST1_TAC THEN
  REWRITE_TAC[real_div] THEN IMP_SUBST_TAC REAL_INV_MUL_WEAK THENL
   [REWRITE_TAC[GSYM DE_MORGAN_THM; GSYM REAL_ENTIRE; GSYM real_div] THEN
    MATCH_MP_TAC REAL_POS_NZ THEN FIRST_ASSUM ACCEPT_TAC;
    GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN AP_TERM_TAC THEN
    MATCH_MP_TAC REAL_INVINV THEN MATCH_MP_TAC REAL_POS_NZ THEN
    MATCH_MP_TAC SIN_POS_PI2 THEN REWRITE_TAC[REAL_SUB_LT; GSYM real_div] THEN
    REWRITE_TAC[GSYM REAL_NOT_LE; real_sub; REAL_LE_ADDR; REAL_NEG_GE0] THEN
    ASM_REWRITE_TAC[REAL_NOT_LE]]);;
let TAN_TOTAL_POS = prove(
  `!y. &0 <= y ==> ?x. &0 <= x /\ x < pi / &2 /\ (tan(x) = y)`,
  GEN_TAC THEN DISCH_THEN(DISJ_CASES_TAC o REWRITE_RULE[REAL_LE_LT]) THENL
   [FIRST_ASSUM(MP_TAC o MATCH_MP TAN_TOTAL_LEMMA) THEN
    DISCH_THEN(X_CHOOSE_THEN `x:real` STRIP_ASSUME_TAC) THEN
    MP_TAC(SPECL [`tan`; `&0`; `x:real`; `y:real`] IVT) THEN
    W(C SUBGOAL_THEN (fun th -> DISCH_THEN(MP_TAC o C MATCH_MP th)) o
         funpow 2 (fst o dest_imp) o snd) THENL
     [REPEAT CONJ_TAC THEN TRY(MATCH_MP_TAC REAL_LT_IMP_LE) THEN
      ASM_REWRITE_TAC[TAN_0] THEN X_GEN_TAC `z:real` THEN STRIP_TAC THEN
      MATCH_MP_TAC DIFF_CONT THEN EXISTS_TAC `inv(cos(z) pow 2)` THEN
      MATCH_MP_TAC DIFF_TAN THEN UNDISCH_TAC `&0 <= z` THEN
      REWRITE_TAC[REAL_LE_LT] THEN DISCH_THEN(DISJ_CASES_THEN MP_TAC) THENL
       [DISCH_TAC THEN MATCH_MP_TAC REAL_POS_NZ THEN
        MATCH_MP_TAC COS_POS_PI2 THEN ASM_REWRITE_TAC[] THEN
        MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `x:real` THEN
        ASM_REWRITE_TAC[];
        DISCH_THEN(SUBST1_TAC o SYM) THEN REWRITE_TAC[COS_0; REAL_10]];
      DISCH_THEN(X_CHOOSE_THEN `z:real` STRIP_ASSUME_TAC) THEN
      EXISTS_TAC `z:real` THEN ASM_REWRITE_TAC[] THEN
      MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `x:real` THEN
      ASM_REWRITE_TAC[]];
    POP_ASSUM(SUBST1_TAC o SYM) THEN EXISTS_TAC `&0` THEN
    REWRITE_TAC[TAN_0; REAL_LE_REFL; PI2_BOUNDS]]);;
let TAN_TOTAL = prove(
  `!y. ?!x. --(pi / &2) < x /\ x < (pi / &2) /\ (tan(x) = y)`,
  GEN_TAC THEN CONV_TAC EXISTS_UNIQUE_CONV THEN CONJ_TAC THENL
   [DISJ_CASES_TAC(SPEC `y:real` REAL_LE_NEGTOTAL) THEN
    POP_ASSUM(X_CHOOSE_TAC `x:real` o MATCH_MP TAN_TOTAL_POS) THENL
     [EXISTS_TAC `x:real` THEN ASM_REWRITE_TAC[] THEN
      MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `&0` THEN
      ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[GSYM REAL_LT_NEG] THEN
      REWRITE_TAC[REAL_NEGNEG; REAL_NEG_0; PI2_BOUNDS];
      EXISTS_TAC `--x` THEN ASM_REWRITE_TAC[REAL_LT_NEG] THEN
      ASM_REWRITE_TAC[TAN_NEG; REAL_NEG_EQ; REAL_NEGNEG] THEN
      ONCE_REWRITE_TAC[GSYM REAL_LT_NEG] THEN
      REWRITE_TAC[REAL_LT_NEG] THEN MATCH_MP_TAC REAL_LET_TRANS THEN
      EXISTS_TAC `x:real` THEN ASM_REWRITE_TAC[REAL_LE_NEGL]];
    MAP_EVERY X_GEN_TAC [`x1:real`; `x2:real`] THEN
    REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC
         (SPECL [`x1:real`; `x2:real`] REAL_LT_TOTAL) THENL
     [DISCH_THEN(K ALL_TAC) THEN POP_ASSUM ACCEPT_TAC;
      ALL_TAC;
      POP_ASSUM MP_TAC THEN SPEC_TAC(`x1:real`,`z1:real`) THEN
      SPEC_TAC(`x2:real`,`z2:real`) THEN
      MAP_EVERY X_GEN_TAC [`x1:real`; `x2:real`] THEN DISCH_TAC THEN
      CONV_TAC(RAND_CONV SYM_CONV) THEN ONCE_REWRITE_TAC[CONJ_SYM]] THEN
    (STRIP_TAC THEN MP_TAC(SPECL [`tan`; `x1:real`; `x2:real`] ROLLE) THEN
     ASM_REWRITE_TAC[] THEN CONV_TAC CONTRAPOS_CONV THEN
     DISCH_THEN(K ALL_TAC) THEN REWRITE_TAC[NOT_IMP] THEN
     REPEAT CONJ_TAC THENL
      [X_GEN_TAC `x:real` THEN STRIP_TAC THEN MATCH_MP_TAC DIFF_CONT THEN
       EXISTS_TAC `inv(cos(x) pow 2)` THEN MATCH_MP_TAC DIFF_TAN;
       X_GEN_TAC `x:real` THEN
       DISCH_THEN(CONJUNCTS_THEN (ASSUME_TAC o MATCH_MP REAL_LT_IMP_LE)) THEN
       REWRITE_TAC[differentiable] THEN EXISTS_TAC `inv(cos(x) pow 2)` THEN
       MATCH_MP_TAC DIFF_TAN;
       REWRITE_TAC[CONJ_ASSOC] THEN DISCH_THEN(X_CHOOSE_THEN `x:real`
         (CONJUNCTS_THEN2 (CONJUNCTS_THEN (ASSUME_TAC o MATCH_MP
          REAL_LT_IMP_LE)) ASSUME_TAC)) THEN
       MP_TAC(SPEC `x:real` DIFF_TAN) THEN
       SUBGOAL_THEN `~(cos(x) = &0)` ASSUME_TAC THENL
        [ALL_TAC;
         ASM_REWRITE_TAC[] THEN
         DISCH_THEN(MP_TAC o C CONJ (ASSUME `(tan diffl &0)(x)`)) THEN
         DISCH_THEN(MP_TAC o MATCH_MP DIFF_UNIQ) THEN REWRITE_TAC[] THEN
         MATCH_MP_TAC REAL_INV_NZ THEN MATCH_MP_TAC POW_NZ THEN
         ASM_REWRITE_TAC[]]] THEN
     (MATCH_MP_TAC REAL_POS_NZ THEN MATCH_MP_TAC COS_POS_PI THEN
      CONJ_TAC THENL
       [MATCH_MP_TAC REAL_LTE_TRANS THEN EXISTS_TAC `x1:real`;
        MATCH_MP_TAC REAL_LET_TRANS THEN EXISTS_TAC `x2:real`] THEN
     ASM_REWRITE_TAC[]))]);;
let PI2_PI4 = prove
 (`pi / &2 = &2 * pi / &4`,
  ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
  REWRITE_TAC[real_div; GSYM REAL_MUL_ASSOC] THEN
  CONV_TAC REAL_RAT_REDUCE_CONV);;
let TAN_PI4 = prove
 (`tan(pi / &4) = &1`,
  REWRITE_TAC[tan; COS_SIN; real_div; GSYM REAL_SUB_LDISTRIB] THEN
  CONV_TAC REAL_RAT_REDUCE_CONV THEN MATCH_MP_TAC REAL_MUL_RINV THEN
  REWRITE_TAC[SIN_ZERO] THEN
  REWRITE_TAC[real_div; GSYM REAL_MUL_LNEG] THEN
  ONCE_REWRITE_TAC[AC REAL_MUL_AC `a * b * c = b * a * c`] THEN
  SIMP_TAC[REAL_MUL_LID; REAL_EQ_MUL_LCANCEL; PI_POS; REAL_LT_IMP_NZ] THEN
  SIMP_TAC[GSYM real_div; REAL_EQ_RDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN
  CONV_TAC REAL_RAT_REDUCE_CONV THEN
  SIMP_TAC[REAL_EQ_LDIV_EQ; REAL_OF_NUM_LT; ARITH] THEN
  REWRITE_TAC[REAL_MUL_LNEG; REAL_OF_NUM_MUL; REAL_OF_NUM_EQ] THEN
  SIMP_TAC[REAL_ARITH `&0 <= x ==> ~(&1 = --x)`; REAL_POS] THEN
  STRIP_TAC THEN FIRST_ASSUM(MP_TAC o AP_TERM `EVEN`) THEN
  REWRITE_TAC[EVEN_MULT; ARITH_EVEN]);;
let TAN_COT = prove
 (`!x. tan(pi / &2 - x) = inv(tan x)`,
  REWRITE_TAC[tan; GSYM SIN_COS; GSYM COS_SIN; REAL_INV_DIV]);;
let TAN_BOUND_PI2 = prove
 (`!x. abs(x) < pi / &4 ==> abs(tan x) < &1`,
  REPEAT GEN_TAC THEN
  SUBGOAL_THEN
   `!x. &0 < x /\ x < pi / &4 ==> &0 < tan(x) /\ tan(x) < &1`
  ASSUME_TAC THENL
   [REPEAT STRIP_TAC THENL
     [ASM_SIMP_TAC[tan; REAL_LT_DIV; SIN_POS_PI2; COS_POS_PI2; PI2_PI4;
                   REAL_ARITH `&0 < x /\ x < a ==> x < &2 * a`];
      ALL_TAC] THEN
    MP_TAC(SPECL [`tan`; `\x. inv(cos(x) pow 2)`;
                  `x:real`; `pi / &4`] MVT_ALT) THEN
    W(C SUBGOAL_THEN (fun th -> REWRITE_TAC[th]) o funpow 2 lhand o snd) THENL
     [ASM_REWRITE_TAC[BETA_THM] THEN X_GEN_TAC `z:real` THEN STRIP_TAC THEN
      MATCH_MP_TAC DIFF_TAN THEN MATCH_MP_TAC REAL_LT_IMP_NZ THEN
      MATCH_MP_TAC COS_POS_PI2 THEN REWRITE_TAC[PI2_PI4] THEN
      MAP_EVERY UNDISCH_TAC [`x <= z`; `z <= pi / &4`; `&0 < x`] THEN
      REAL_ARITH_TAC;
      ALL_TAC] THEN
    SIMP_TAC[TAN_PI4; REAL_ARITH `x < &1 <=> &0 < &1 - x`;
             LEFT_IMP_EXISTS_THM] THEN
    X_GEN_TAC `z:real` THEN REPEAT STRIP_TAC THEN
    MATCH_MP_TAC REAL_LT_MUL THEN ASM_REWRITE_TAC[REAL_SUB_LT] THEN
    REWRITE_TAC[REAL_LT_INV_EQ; BETA_THM] THEN
    MATCH_MP_TAC REAL_POW_LT THEN MATCH_MP_TAC COS_POS_PI2 THEN
    REWRITE_TAC[PI2_PI4] THEN
    MAP_EVERY UNDISCH_TAC [`x < z`; `z < pi / &4`; `&0 < x`] THEN
    REAL_ARITH_TAC; ALL_TAC] THEN
  GEN_REWRITE_TAC (LAND_CONV o ONCE_DEPTH_CONV) [real_abs] THEN
  REWRITE_TAC[REAL_LE_LT] THEN
  ASM_CASES_TAC `x = &0` THEN
  ASM_REWRITE_TAC[TAN_0; REAL_ABS_NUM; REAL_LT_01] THEN
  COND_CASES_TAC THEN
  ASM_SIMP_TAC[REAL_ARITH `&0 < x /\ x < &1 ==> abs(x) < &1`] THEN
  ONCE_REWRITE_TAC[GSYM REAL_ABS_NEG] THEN REWRITE_TAC[GSYM TAN_NEG] THEN
  ASM_SIMP_TAC[REAL_ARITH `&0 < x /\ x < &1 ==> abs(x) < &1`;
               REAL_ARITH `~(x = &0) /\ ~(&0 < x) ==> &0 < --x`]);;
let TAN_ABS_GE_X = prove
 (`!x. abs(x) < pi / &2 ==> abs(x) <= abs(tan x)`,
  SUBGOAL_THEN `!y. &0 < y /\ y < pi / &2 ==> y <= tan(y)` ASSUME_TAC THENL
   [ALL_TAC;
    GEN_TAC THEN
    REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC (SPEC `x:real` REAL_LT_NEGTOTAL) THEN
    ASM_REWRITE_TAC[TAN_0; REAL_ABS_0; REAL_LE_REFL] THENL
     [ALL_TAC;
      ONCE_REWRITE_TAC[GSYM REAL_ABS_NEG] THEN REWRITE_TAC[GSYM TAN_NEG]] THEN
    MATCH_MP_TAC(REAL_ARITH
     `&0 < x /\ (x < p ==> x <= tx)
      ==> abs(x) < p ==> abs(x) <= abs(tx)`) THEN ASM_SIMP_TAC[]] THEN
  GEN_TAC THEN STRIP_TAC THEN
  MP_TAC(SPECL [`tan`; `\x. inv(cos(x) pow 2)`; `&0`; `y:real`] MVT_ALT) THEN
  ASM_REWRITE_TAC[TAN_0; REAL_SUB_RZERO] THEN
  MATCH_MP_TAC(TAUT `a /\ (b ==> c) ==> (a ==> b) ==> c`) THEN CONJ_TAC THENL
   [REPEAT STRIP_TAC THEN BETA_TAC THEN MATCH_MP_TAC DIFF_TAN THEN
    MATCH_MP_TAC REAL_LT_IMP_NZ THEN MATCH_MP_TAC COS_POS_PI THEN
    POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN REAL_ARITH_TAC;
    DISCH_THEN(X_CHOOSE_THEN `z:real` STRIP_ASSUME_TAC) THEN
    ASM_REWRITE_TAC[BETA_THM] THEN
    GEN_REWRITE_TAC LAND_CONV [GSYM REAL_MUL_RID] THEN
    MATCH_MP_TAC REAL_LE_LMUL THEN ASM_SIMP_TAC[REAL_LT_IMP_LE] THEN
    MATCH_MP_TAC REAL_INV_1_LE THEN CONJ_TAC THENL
     [MATCH_MP_TAC REAL_POW_LT;
      MATCH_MP_TAC REAL_POW_1_LE THEN REWRITE_TAC[COS_BOUNDS] THEN
      MATCH_MP_TAC REAL_LT_IMP_LE] THEN
    MATCH_MP_TAC COS_POS_PI THEN
    POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN REAL_ARITH_TAC]);;
(* ------------------------------------------------------------------------ *)
(* Inverse trig functions                                                   *)
(* ------------------------------------------------------------------------ *)
 
let ASN = prove(
  `!y. --(&1) <= y /\ y <= &1 ==>
     --(pi / &2) <= asn(y) /\ asn(y) <= pi / &2 /\ (sin(asn y) = y)`,
  GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP 
SIN_TOTAL) THEN
  DISCH_THEN(MP_TAC o CONJUNCT1 o CONV_RULE EXISTS_UNIQUE_CONV) THEN
  DISCH_THEN(MP_TAC o SELECT_RULE) THEN REWRITE_TAC[GSYM asn]);;
 
let ASN_SIN = prove(
  `!y. --(&1) <= y /\ y <= &1 ==> (sin(asn(y)) = y)`,
  GEN_TAC THEN DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP 
ASN th]));;
 
let ASN_BOUNDS = prove(
  `!y. --(&1) <= y /\ y <= &1 ==> --(pi / &2) <= asn(y) /\ asn(y) <= pi / &2`,
  GEN_TAC THEN DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP 
ASN th]));;
 
let ASN_BOUNDS_LT = prove(
  `!y. --(&1) < y /\ y < &1 ==> --(pi / &2) < asn(y) /\ asn(y) < pi / &2`,
  GEN_TAC THEN STRIP_TAC THEN
  EVERY_ASSUM(ASSUME_TAC o MATCH_MP 
REAL_LT_IMP_LE) THEN
  MP_TAC(SPEC `y:real` 
ASN_BOUNDS) THEN ASM_REWRITE_TAC[] THEN
  STRIP_TAC THEN ASM_REWRITE_TAC[
REAL_LT_LE] THEN
  CONJ_TAC THEN DISCH_THEN(MP_TAC o AP_TERM `sin`) THEN
  IMP_SUBST_TAC 
ASN_SIN THEN ASM_REWRITE_TAC[
SIN_NEG; 
SIN_PI2] THEN
  DISCH_THEN((then_) (POP_ASSUM_LIST (MP_TAC o end_itlist CONJ)) o
    ASSUME_TAC) THEN ASM_REWRITE_TAC[
REAL_LT_REFL]);;
 
let SIN_ASN = prove(
  `!x. --(pi / &2) <= x /\ x <= pi / &2 ==> (asn(sin(x)) = x)`,
  GEN_TAC THEN DISCH_TAC THEN
  MP_TAC(MATCH_MP 
SIN_TOTAL (SPEC `x:real` 
SIN_BOUNDS)) THEN
  DISCH_THEN(MATCH_MP_TAC o CONJUNCT2 o CONV_RULE EXISTS_UNIQUE_CONV) THEN
  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
ASN THEN
  MATCH_ACCEPT_TAC 
SIN_BOUNDS);;
 
let ACS = prove(
  `!y. --(&1) <= y /\ y <= &1 ==>
     &0 <= acs(y) /\ acs(y) <= pi  /\ (cos(acs y) = y)`,
  GEN_TAC THEN DISCH_THEN(MP_TAC o MATCH_MP 
COS_TOTAL) THEN
  DISCH_THEN(MP_TAC o CONJUNCT1 o CONV_RULE EXISTS_UNIQUE_CONV) THEN
  DISCH_THEN(MP_TAC o SELECT_RULE) THEN REWRITE_TAC[GSYM acs]);;
 
let ACS_COS = prove(
  `!y. --(&1) <= y /\ y <= &1 ==> (cos(acs(y)) = y)`,
  GEN_TAC THEN DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP 
ACS th]));;
 
let ACS_BOUNDS = prove(
  `!y. --(&1) <= y /\ y <= &1 ==> &0 <= acs(y) /\ acs(y) <= pi`,
  GEN_TAC THEN DISCH_THEN(fun th -> REWRITE_TAC[MATCH_MP 
ACS th]));;
 
let ACS_BOUNDS_LT = prove(
  `!y. --(&1) < y /\ y < &1 ==> &0 < acs(y) /\ acs(y) < pi`,
  GEN_TAC THEN STRIP_TAC THEN
  EVERY_ASSUM(ASSUME_TAC o MATCH_MP 
REAL_LT_IMP_LE) THEN
  MP_TAC(SPEC `y:real` 
ACS_BOUNDS) THEN ASM_REWRITE_TAC[] THEN
  STRIP_TAC THEN ASM_REWRITE_TAC[
REAL_LT_LE] THEN
  CONJ_TAC THEN DISCH_THEN(MP_TAC o AP_TERM `cos`) THEN
  IMP_SUBST_TAC 
ACS_COS THEN ASM_REWRITE_TAC[
COS_0; 
COS_PI] THEN
  DISCH_THEN((then_) (POP_ASSUM_LIST (MP_TAC o end_itlist CONJ)) o
    ASSUME_TAC) THEN ASM_REWRITE_TAC[
REAL_LT_REFL]);;
 
let COS_ACS = prove(
  `!x. &0 <= x /\ x <= pi ==> (acs(cos(x)) = x)`,
  GEN_TAC THEN DISCH_TAC THEN
  MP_TAC(MATCH_MP 
COS_TOTAL (SPEC `x:real` 
COS_BOUNDS)) THEN
  DISCH_THEN(MATCH_MP_TAC o CONJUNCT2 o CONV_RULE EXISTS_UNIQUE_CONV) THEN
  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
ACS THEN
  MATCH_ACCEPT_TAC 
COS_BOUNDS);;
 
let ATN = prove(
  `!y. --(pi / &2) < atn(y) /\ atn(y) < (pi / &2) /\ (tan(atn y) = y)`,
  GEN_TAC THEN MP_TAC(SPEC `y:real` 
TAN_TOTAL) THEN
  DISCH_THEN(MP_TAC o CONJUNCT1 o CONV_RULE EXISTS_UNIQUE_CONV) THEN
  DISCH_THEN(MP_TAC o SELECT_RULE) THEN REWRITE_TAC[GSYM atn]);;
 
let TAN_ATN = prove(
  `!x. --(pi / &2) < x /\ x < (pi / &2) ==> (atn(tan(x)) = x)`,
  GEN_TAC THEN DISCH_TAC THEN MP_TAC(SPEC `tan(x)` 
TAN_TOTAL) THEN
  DISCH_THEN(MATCH_MP_TAC o CONJUNCT2 o CONV_RULE EXISTS_UNIQUE_CONV) THEN
  ASM_REWRITE_TAC[
ATN]);;
 
let ATN_NEG = prove
 (`!x. atn(--x) = --(atn x)`,
  GEN_TAC THEN MP_TAC(SPEC `atn(x)` 
TAN_NEG) THEN
  REWRITE_TAC[
ATN_TAN] THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
  MATCH_MP_TAC 
TAN_ATN THEN
  MATCH_MP_TAC(REAL_ARITH
   `--a < x /\ x < a ==> --a < --x /\ --x < a`) THEN
  REWRITE_TAC[
ATN_BOUNDS]);;
 
let COS_ATN_NZ = prove(
  `!x. ~(cos(atn(x)) = &0)`,
  GEN_TAC THEN REWRITE_TAC[
COS_ZERO; DE_MORGAN_THM] THEN CONJ_TAC THEN
  CONV_TAC NOT_EXISTS_CONV THEN X_GEN_TAC `n:num` THEN
  STRUCT_CASES_TAC(SPEC `n:num` 
num_CASES) THEN
  REWRITE_TAC[
EVEN; DE_MORGAN_THM] THEN DISJ2_TAC THEN
  DISCH_TAC THEN MP_TAC(SPEC `x:real` 
ATN_BOUNDS) THEN
  ASM_REWRITE_TAC[DE_MORGAN_THM] THENL
   [DISJ2_TAC; DISJ1_TAC THEN REWRITE_TAC[
REAL_LT_NEG]] THEN
  GEN_REWRITE_TAC (RAND_CONV o RAND_CONV)  [GSYM REAL_MUL_LID] THEN
  REWRITE_TAC[MATCH_MP 
REAL_LT_RMUL_EQ (CONJUNCT1 
PI2_BOUNDS)] THEN
  REWRITE_TAC[
ADD1; GSYM 
REAL_ADD; 
REAL_NOT_LT] THEN
  ONCE_REWRITE_TAC[REAL_ADD_SYM] THEN
  REWRITE_TAC[
REAL_LE_ADDR; 
REAL_LE; 
LE_0]);;
 
let TAN_SEC = prove(
  `!x. ~(cos(x) = &0) ==> (&1 + (tan(x) pow 2) = inv(cos x) pow 2)`,
  GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[tan] THEN
  FIRST_ASSUM(fun th ->  ONCE_REWRITE_TAC[GSYM
   (MATCH_MP 
REAL_DIV_REFL (SPEC `2` (MATCH_MP 
POW_NZ th)))]) THEN
  REWRITE_TAC[
real_div; 
POW_MUL] THEN
  POP_ASSUM(fun th ->  REWRITE_TAC[MATCH_MP 
POW_INV th]) THEN
  ONCE_REWRITE_TAC[REAL_ADD_SYM] THEN
  REWRITE_TAC[GSYM 
REAL_RDISTRIB; 
SIN_CIRCLE; REAL_MUL_LID]);;
 
let DIFF_ATN = prove(
  `!x. (atn diffl (inv(&1 + (x pow 2))))(x)`,
  GEN_TAC THEN
  SUBGOAL_THEN `(atn diffl (inv(&1 + (x pow 2))))(tan(atn x))`
  MP_TAC THENL [MATCH_MP_TAC 
DIFF_INVERSE_LT; REWRITE_TAC[
ATN_TAN]] THEN
  SUBGOAL_THEN
    `?d. &0 < d /\
         !z. abs(z - atn(x)) < d ==>  (--(pi / (& 2))) < z /\ z < (pi / (& 2))`
  (X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THENL
   [ONCE_REWRITE_TAC[
ABS_SUB] THEN MATCH_MP_TAC 
INTERVAL_LEMMA_LT THEN
    MATCH_ACCEPT_TAC 
ATN_BOUNDS;
    EXISTS_TAC `d:real` THEN ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THENL
     [MATCH_MP_TAC 
TAN_ATN THEN FIRST_ASSUM MATCH_MP_TAC THEN
      ASM_REWRITE_TAC[];
      MATCH_MP_TAC 
DIFF_CONT THEN EXISTS_TAC `inv(cos(z) pow 2)` THEN
      MATCH_MP_TAC DIFF_TAN THEN MATCH_MP_TAC 
REAL_POS_NZ THEN
      MATCH_MP_TAC 
COS_POS_PI THEN FIRST_ASSUM MATCH_MP_TAC THEN
      ASM_REWRITE_TAC[];
      ASSUME_TAC(SPEC `x:real` 
COS_ATN_NZ) THEN
      FIRST_ASSUM(MP_TAC o MATCH_MP DIFF_TAN) THEN
      FIRST_ASSUM(ASSUME_TAC o SYM o MATCH_MP 
TAN_SEC) THEN
      FIRST_ASSUM(ASSUME_TAC o MATCH_MP 
POW_INV) THEN
      ASM_REWRITE_TAC[
ATN_TAN];
      UNDISCH_TAC `&1 + (x pow 2) = &0` THEN REWRITE_TAC[] THEN
      MATCH_MP_TAC 
REAL_POS_NZ THEN
      MATCH_MP_TAC 
REAL_LTE_ADD THEN
      REWRITE_TAC[
REAL_LT_01; 
REAL_LE_SQUARE; 
POW_2]]]);;
 
let ATN_MONO_LT = prove
 (`!x y. x < y ==> atn(x) < atn(y)`,
  REPEAT STRIP_TAC THEN
  MP_TAC(SPECL [`atn`; `\x. inv(&1 + x pow 2)`; `x:real`; `y:real`]
               
MVT_ALT) THEN
  BETA_TAC THEN ASM_REWRITE_TAC[
DIFF_ATN] THEN STRIP_TAC THEN
  FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
    `(l - r = d) ==> l < d + e ==> r < e`)) THEN
  REWRITE_TAC[REAL_ARITH `a < b + a <=> &0 < b`] THEN
  MATCH_MP_TAC 
REAL_LT_MUL THEN
  ASM_REWRITE_TAC[
REAL_LT_SUB_LADD; REAL_ADD_LID] THEN
  REWRITE_TAC[
REAL_LT_INV_EQ] THEN
  MATCH_MP_TAC(REAL_ARITH `&0 <= x ==> &0 < &1 + x`) THEN
  REWRITE_TAC[REAL_POW_2; 
REAL_LE_SQUARE]);;
 
let ATN_LT_PI4 = prove
 (`!x. abs(x) < &1 ==> abs(atn x) < pi / &4`,
  GEN_TAC THEN
  MATCH_MP_TAC(REAL_ARITH
   `(&0 < x ==> &0 < y) /\
    (x < &0 ==> y < &0) /\
    ((x = &0) ==> (y = &0)) /\
    (x < a ==> y < b) /\
    (--a < x ==> --b < y)
    ==> abs(x) < a ==> abs(y) < b`) THEN
  SIMP_TAC[
ATN_LT_PI4_POS; 
ATN_LT_PI4_NEG; 
ATN_0] THEN CONJ_TAC THEN
  GEN_REWRITE_TAC (RAND_CONV o ONCE_DEPTH_CONV) [GSYM 
ATN_0] THEN
  SIMP_TAC[
ATN_MONO_LT]);;
 
let COS_SIN_SQRT = prove(
  `!x. &0 <= cos(x) ==> (cos(x) = sqrt(&1 - (sin(x) pow 2)))`,
  GEN_TAC THEN DISCH_TAC THEN
  MP_TAC (ONCE_REWRITE_RULE[REAL_ADD_SYM] (SPEC `x:real` 
SIN_CIRCLE)) THEN
  REWRITE_TAC[GSYM 
REAL_EQ_SUB_LADD] THEN
  DISCH_THEN(SUBST1_TAC o SYM) THEN
  REWRITE_TAC[sqrt; num_CONV `2`] THEN
  CONV_TAC SYM_CONV THEN MATCH_MP_TAC 
POW_ROOT_POS THEN
  ASM_REWRITE_TAC[]);;
 
let DIFF_ASN_COS = prove(
  `!x. --(&1) < x /\ x < &1 ==> (asn diffl (inv(cos(asn x))))(x)`,
  REPEAT STRIP_TAC THEN
  EVERY_ASSUM(ASSUME_TAC o MATCH_MP 
REAL_LT_IMP_LE) THEN
  MP_TAC(SPEC `x:real` 
ASN_SIN) THEN ASM_REWRITE_TAC[] THEN
  DISCH_TAC THEN
  FIRST_ASSUM(fun th ->  GEN_REWRITE_TAC RAND_CONV  [GSYM th]) THEN
  MATCH_MP_TAC 
DIFF_INVERSE_LT THEN
  MP_TAC(SPEC `x:real` 
ASN_BOUNDS_LT) THEN ASM_REWRITE_TAC[] THEN
  DISCH_THEN(fun th ->  STRIP_ASSUME_TAC th THEN
    MP_TAC(MATCH_MP 
INTERVAL_LEMMA_LT th)) THEN
  DISCH_THEN(X_CHOOSE_THEN `d:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
  DISCH_THEN(ASSUME_TAC o ONCE_REWRITE_RULE[
ABS_SUB]) THEN
  EXISTS_TAC `d:real` THEN ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THENL
   [MATCH_MP_TAC 
SIN_ASN THEN
    FIRST_ASSUM(UNDISCH_TAC o check is_forall o concl) THEN
    DISCH_THEN(MP_TAC o SPEC `z:real`) THEN ASM_REWRITE_TAC[] THEN
    DISCH_TAC THEN CONJ_TAC THEN
    MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ASM_REWRITE_TAC[];
    MATCH_MP_TAC 
DIFF_CONT THEN EXISTS_TAC `cos(z)` THEN
    REWRITE_TAC[
DIFF_SIN];
    REWRITE_TAC[
DIFF_SIN];
    POP_ASSUM MP_TAC THEN REWRITE_TAC[] THEN MATCH_MP_TAC 
COS_ASN_NZ THEN
    ASM_REWRITE_TAC[]]);;
 
let DIFF_ASN = prove(
  `!x. --(&1) < x /\ x < &1 ==> (asn diffl (inv(sqrt(&1 - (x pow 2)))))(x)`,
  GEN_TAC THEN DISCH_TAC THEN
  FIRST_ASSUM(MP_TAC o MATCH_MP 
DIFF_ASN_COS) THEN
  MATCH_MP_TAC EQ_IMP THEN
  AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
  SUBGOAL_THEN `sin(asn x) = x` MP_TAC THENL
   [MATCH_MP_TAC 
ASN_SIN THEN CONJ_TAC THEN
    MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ASM_REWRITE_TAC[];
    DISCH_THEN(fun th ->  GEN_REWRITE_TAC
      (RAND_CONV o ONCE_DEPTH_CONV)  [GSYM th]) THEN
    MATCH_MP_TAC 
COS_SIN_SQRT THEN
    FIRST_ASSUM(ASSUME_TAC o MATCH_MP 
ASN_BOUNDS_LT) THEN
    MATCH_MP_TAC 
REAL_LT_IMP_LE THEN MATCH_MP_TAC 
COS_POS_PI THEN
    ASM_REWRITE_TAC[]]);;
 
let DIFF_ASN_COMPOSITE = prove
 (`(g diffl m)(x) /\ -- &1 < g(x) /\ g(x) < &1
   ==> ((\x. asn(g x)) diffl (inv(sqrt (&1 - g(x) pow 2)) * m))(x)`,
 
let SIN_COS_SQRT = prove(
  `!x. &0 <= sin(x) ==> (sin(x) = sqrt(&1 - (cos(x) pow 2)))`,
  GEN_TAC THEN DISCH_TAC THEN
  MP_TAC (SPEC `x:real` 
SIN_CIRCLE) THEN
  REWRITE_TAC[GSYM 
REAL_EQ_SUB_LADD] THEN
  DISCH_THEN(SUBST1_TAC o SYM) THEN
  REWRITE_TAC[sqrt; num_CONV `2`] THEN
  CONV_TAC SYM_CONV THEN MATCH_MP_TAC 
POW_ROOT_POS THEN
  ASM_REWRITE_TAC[]);;
 
let DIFF_ACS_SIN = prove(
  `!x. --(&1) < x /\ x < &1 ==> (acs diffl (inv(--(sin(acs x)))))(x)`,
  REPEAT STRIP_TAC THEN
  EVERY_ASSUM(ASSUME_TAC o MATCH_MP 
REAL_LT_IMP_LE) THEN
  MP_TAC(SPEC `x:real` 
ACS_COS) THEN ASM_REWRITE_TAC[] THEN
  DISCH_TAC THEN
  FIRST_ASSUM(fun th ->  GEN_REWRITE_TAC RAND_CONV  [GSYM th]) THEN
  MATCH_MP_TAC 
DIFF_INVERSE_LT THEN
  MP_TAC(SPEC `x:real` 
ACS_BOUNDS_LT) THEN ASM_REWRITE_TAC[] THEN
  DISCH_THEN(fun th ->  STRIP_ASSUME_TAC th THEN
    MP_TAC(MATCH_MP 
INTERVAL_LEMMA_LT th)) THEN
  DISCH_THEN(X_CHOOSE_THEN `d:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
  DISCH_THEN(ASSUME_TAC o ONCE_REWRITE_RULE[
ABS_SUB]) THEN
  EXISTS_TAC `d:real` THEN ASM_REWRITE_TAC[] THEN REPEAT STRIP_TAC THENL
   [MATCH_MP_TAC 
COS_ACS THEN
    FIRST_ASSUM(UNDISCH_TAC o check is_forall o concl) THEN
    DISCH_THEN(MP_TAC o SPEC `z:real`) THEN ASM_REWRITE_TAC[] THEN
    DISCH_TAC THEN CONJ_TAC THEN
    MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ASM_REWRITE_TAC[];
    MATCH_MP_TAC 
DIFF_CONT THEN EXISTS_TAC `--(sin(z))` THEN
    REWRITE_TAC[
DIFF_COS];
    REWRITE_TAC[
DIFF_COS];
    POP_ASSUM MP_TAC THEN REWRITE_TAC[] THEN
    ONCE_REWRITE_TAC[GSYM 
REAL_EQ_NEG] THEN
    REWRITE_TAC[
REAL_NEGNEG; 
REAL_NEG_0] THEN
    MATCH_MP_TAC 
SIN_ACS_NZ THEN ASM_REWRITE_TAC[]]);;
 
let DIFF_ACS = prove(
  `!x. --(&1) < x /\ x < &1 ==> (acs diffl --(inv(sqrt(&1 - (x pow 2)))))(x)`,
  GEN_TAC THEN DISCH_TAC THEN
  FIRST_ASSUM(MP_TAC o MATCH_MP 
DIFF_ACS_SIN) THEN
  MATCH_MP_TAC EQ_IMP THEN
  AP_THM_TAC THEN AP_TERM_TAC THEN
  IMP_SUBST_TAC (GSYM REAL_NEG_INV) THENL
   [CONV_TAC(RAND_CONV SYM_CONV) THEN
    MATCH_MP_TAC 
SIN_ACS_NZ THEN ASM_REWRITE_TAC[];
    REPEAT AP_TERM_TAC] THEN
  SUBGOAL_THEN `cos(acs x) = x` MP_TAC THENL
   [MATCH_MP_TAC 
ACS_COS THEN CONJ_TAC THEN
    MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ASM_REWRITE_TAC[];
    DISCH_THEN(fun th ->  GEN_REWRITE_TAC
      (RAND_CONV o ONCE_DEPTH_CONV)  [GSYM th]) THEN
    MATCH_MP_TAC 
SIN_COS_SQRT THEN
    FIRST_ASSUM(ASSUME_TAC o MATCH_MP 
ACS_BOUNDS_LT) THEN
    MATCH_MP_TAC 
REAL_LT_IMP_LE THEN MATCH_MP_TAC 
SIN_POS_PI THEN
    ASM_REWRITE_TAC[]]);;
 
let DIFF_ACS_COMPOSITE = prove
 (`(g diffl m)(x) /\ -- &1 < g(x) /\ g(x) < &1
   ==> ((\x. acs(g x)) diffl (--inv(sqrt(&1 - g(x) pow 2)) * m))(x)`,
 
let CIRCLE_SINCOS = prove
 (`!x y. (x pow 2 + y pow 2 = &1) ==> ?t. (x = cos(t)) /\ (y = sin(t))`,
  REPEAT STRIP_TAC THEN
  SUBGOAL_THEN `abs(x) <= &1 /\ abs(y) <= &1` STRIP_ASSUME_TAC THENL
   [MATCH_MP_TAC(REAL_ARITH
     `(&1 < x ==> &1 < x pow 2) /\ (&1 < y ==> &1 < y pow 2) /\
      &0 <= x pow 2 /\ &0 <= y pow 2 /\ x pow 2 + y pow 2 <= &1
      ==> x <= &1 /\ y <= &1`) THEN
    ASM_REWRITE_TAC[
REAL_POW2_ABS; 
REAL_LE_REFL] THEN
    REWRITE_TAC[REAL_POW_2; 
REAL_LE_SQUARE] THEN
    REWRITE_TAC[GSYM REAL_POW_2] THEN
    ONCE_REWRITE_TAC[GSYM 
REAL_POW2_ABS] THEN REWRITE_TAC[REAL_POW_2] THEN
    CONJ_TAC THEN DISCH_TAC THEN
    SUBST1_TAC(SYM(REAL_RAT_REDUCE_CONV `&1 * &1`)) THEN
    MATCH_MP_TAC 
REAL_LT_MUL2 THEN ASM_REWRITE_TAC[
REAL_POS];
    ALL_TAC] THEN
  SUBGOAL_THEN `&0 <= sin(acs x)` MP_TAC THENL
   [MATCH_MP_TAC 
SIN_POS_PI_LE THEN
    MATCH_MP_TAC 
ACS_BOUNDS THEN
    POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN REAL_ARITH_TAC;
    ALL_TAC] THEN
  DISCH_THEN(ASSUME_TAC o MATCH_MP 
SIN_COS_SQRT) THEN
  SUBGOAL_THEN `abs(y) = sqrt(&1 - x pow 2)` ASSUME_TAC THENL
   [REWRITE_TAC[GSYM 
POW_2_SQRT_ABS] THEN AP_TERM_TAC THEN
    UNDISCH_TAC `x pow 2 + y pow 2 = &1` THEN REAL_ARITH_TAC;
    ALL_TAC] THEN
  ASM_CASES_TAC `&0 <= y` THENL
   [EXISTS_TAC `acs x`; EXISTS_TAC `--(acs x)`] THEN
  ASM_SIMP_TAC[
COS_NEG; 
SIN_NEG; 
ACS_COS; REAL_ARITH
   `abs(x) <= &1 ==> --(&1) <= x /\ x <= &1`]
  THENL
   [MATCH_MP_TAC(REAL_ARITH `&0 <= y /\ (abs(y) = x) ==> (y = x)`);
    MATCH_MP_TAC(REAL_ARITH `~(&0 <= y) /\ (abs(y) = x) ==> (y = --x)`)] THEN
  ASM_REWRITE_TAC[]);;
 
let ACS_MONO_LT = prove
 (`!x y. --(&1) < x /\ x < y /\ y < &1 ==> acs(y) < acs(x)`,
  REPEAT STRIP_TAC THEN
  MP_TAC(SPECL [`acs`; `\x. --inv(sqrt(&1 - x pow 2))`; `x:real`; `y:real`]
               
MVT_ALT) THEN
  ANTS_TAC THENL
   [REPEAT STRIP_TAC THEN ASM_SIMP_TAC[] THEN
    MATCH_MP_TAC 
DIFF_ACS THEN
    ASM_MESON_TAC[
REAL_LET_TRANS; 
REAL_LTE_TRANS];
    REWRITE_TAC[
REAL_EQ_SUB_RADD]] THEN
  DISCH_THEN(X_CHOOSE_THEN `z:real` STRIP_ASSUME_TAC) THEN
  ASM_REWRITE_TAC[REAL_ARITH `a * --c + x < x <=> &0 < a * c`] THEN
  MATCH_MP_TAC 
REAL_LT_MUL THEN ASM_REWRITE_TAC[
REAL_SUB_LT] THEN
  MATCH_MP_TAC 
REAL_LT_INV THEN MATCH_MP_TAC 
SQRT_POS_LT THEN
  ONCE_REWRITE_TAC[GSYM 
REAL_POW2_ABS] THEN REWRITE_TAC[REAL_POW_2] THEN
  REWRITE_TAC[REAL_ARITH `&0 < &1 - z * z <=> z * z < &1 * &1`] THEN
  MATCH_MP_TAC 
REAL_LT_MUL2 THEN REWRITE_TAC[
REAL_ABS_POS] THEN
  POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN REAL_ARITH_TAC);;
 
let LESS_SUC_EQ = prove(
  `!m n. m < SUC n <=> m <= n`,
  REPEAT GEN_TAC THEN REWRITE_TAC[CONJUNCT2 
LT; 
LE_LT] THEN
  EQ_TAC THEN DISCH_THEN(DISJ_CASES_THEN(fun th -> REWRITE_TAC[th])));;
 
let defint = new_definition
  `defint(a,b) f k <=>
     !e. &0 < e ==>
        ?g. gauge(\x. a <= x /\ x <= b) g /\
            !D p. tdiv(a,b) (D,p) /\ fine(g)(D,p) ==>
                abs(rsum(D,p) f - k) < e`;;let DIVISION_0 = prove(
  `!a b. (a = b) ==> (dsize(\n. if (n = 0) then a else b) = 0)`,
  REPEAT GEN_TAC THEN DISCH_THEN SUBST_ALL_TAC THEN REWRITE_TAC[
COND_ID] THEN
  REWRITE_TAC[dsize] THEN MATCH_MP_TAC 
SELECT_UNIQUE THEN
  X_GEN_TAC `n:num` THEN BETA_TAC THEN
  REWRITE_TAC[
REAL_LT_REFL; 
NOT_LT] THEN EQ_TAC THENL
   [DISCH_THEN(MP_TAC o SPEC `0`) THEN REWRITE_TAC[CONJUNCT1 
LE];
    DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[
LE_0]]);;
 
let DIVISION_1 = prove(
  `!a b. a < b ==> (dsize(\n. if (n = 0) then a else b) = 1)`,
  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[dsize] THEN
  MATCH_MP_TAC 
SELECT_UNIQUE THEN X_GEN_TAC `n:num` THEN BETA_TAC THEN
  REWRITE_TAC[
NOT_SUC] THEN EQ_TAC THENL
   [DISCH_TAC THEN MATCH_MP_TAC LESS_EQUAL_ANTISYM THEN CONJ_TAC THENL
     [POP_ASSUM(MP_TAC o SPEC `1` o CONJUNCT1) THEN
      REWRITE_TAC[ARITH] THEN
      REWRITE_TAC[
REAL_LT_REFL; 
NOT_LT];
      POP_ASSUM(MP_TAC o SPEC `2` o CONJUNCT2) THEN
      REWRITE_TAC[num_CONV `2`; 
GE] THEN
      CONV_TAC CONTRAPOS_CONV THEN
      REWRITE_TAC[num_CONV `1`; 
NOT_SUC_LESS_EQ; CONJUNCT1 
LE] THEN
      DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[
NOT_SUC; NOT_IMP] THEN
      REWRITE_TAC[
LE_0] THEN CONV_TAC(RAND_CONV SYM_CONV) THEN
      MATCH_MP_TAC 
REAL_LT_IMP_NE THEN POP_ASSUM ACCEPT_TAC];
    DISCH_THEN SUBST1_TAC THEN CONJ_TAC THENL
     [GEN_TAC THEN REWRITE_TAC[num_CONV `1`; CONJUNCT2 
LT; 
NOT_LESS_0] THEN
      DISCH_THEN SUBST1_TAC THEN ASM_REWRITE_TAC[];
      X_GEN_TAC `n:num` THEN REWRITE_TAC[
GE; num_CONV `1`] THEN
      ASM_CASES_TAC `n = 0` THEN
      ASM_REWRITE_TAC[CONJUNCT1 
LE; GSYM 
NOT_SUC; 
NOT_SUC]]]);;
 
let DIVISION_SINGLE = prove(
  `!a b. a <= b ==> division(a,b)(\n. if (n = 0) then a else b)`,
  REPEAT GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[division] THEN
  BETA_TAC THEN REWRITE_TAC[] THEN
  POP_ASSUM(DISJ_CASES_TAC o REWRITE_RULE[
REAL_LE_LT]) THENL
   [EXISTS_TAC `1` THEN CONJ_TAC THEN X_GEN_TAC `n:num` THENL
     [REWRITE_TAC[
LESS_1] THEN DISCH_THEN SUBST1_TAC THEN
      ASM_REWRITE_TAC[
NOT_SUC];
      REWRITE_TAC[
GE] THEN
      COND_CASES_TAC THEN ASM_REWRITE_TAC[num_CONV `1`] THEN
      REWRITE_TAC[GSYM 
NOT_LT; 
LESS_SUC_REFL]];
    EXISTS_TAC `0` THEN REWRITE_TAC[
NOT_LESS_0] THEN
    ASM_REWRITE_TAC[
COND_ID]]);;
 
let DIVISION_LHS = prove(
  `!D a b. division(a,b) D ==> (D(0) = a)`,
  REPEAT GEN_TAC THEN REWRITE_TAC[division] THEN
  DISCH_THEN(fun th -> REWRITE_TAC[th]));;
 
let DIVISION_THM = prove(
  `!D a b. division(a,b) D <=>
        (D(0) = a) /\
        (!n. n < (dsize D) ==> D(n) < D(SUC n)) /\
        (!n. n >= (dsize D) ==> (D(n) = b))`,
  REPEAT GEN_TAC THEN REWRITE_TAC[division] THEN
  EQ_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THENL
   [ALL_TAC; EXISTS_TAC `dsize D` THEN ASM_REWRITE_TAC[]] THEN
  POP_ASSUM(X_CHOOSE_THEN `N:num` STRIP_ASSUME_TAC o CONJUNCT2) THEN
  SUBGOAL_THEN `dsize D = N` (fun th -> ASM_REWRITE_TAC[th]) THEN
  REWRITE_TAC[dsize] THEN MATCH_MP_TAC 
SELECT_UNIQUE THEN
  X_GEN_TAC `M:num` THEN BETA_TAC THEN EQ_TAC THENL
   [ALL_TAC; DISCH_THEN SUBST1_TAC THEN ASM_REWRITE_TAC[] THEN
    MP_TAC(SPEC `N:num` (ASSUME `!n:num. n >= N ==> (D n :real = b)`)) THEN
    DISCH_THEN(MP_TAC o REWRITE_RULE[
GE; 
LE_REFL]) THEN
    DISCH_THEN SUBST1_TAC THEN FIRST_ASSUM MATCH_ACCEPT_TAC] THEN
  REPEAT_TCL DISJ_CASES_THEN ASSUME_TAC
   (SPECL [`M:num`; `N:num`] 
LESS_LESS_CASES) THEN
  ASM_REWRITE_TAC[] THENL
   [DISCH_THEN(MP_TAC o SPEC `SUC M` o CONJUNCT2) THEN
    REWRITE_TAC[
GE; 
LESS_EQ_SUC_REFL] THEN DISCH_TAC THEN
    UNDISCH_TAC `!n. n < N ==> (D n) < (D(SUC n))` THEN
    DISCH_THEN(MP_TAC o SPEC `M:num`) THEN ASM_REWRITE_TAC[
REAL_LT_REFL];
    DISCH_THEN(MP_TAC o SPEC `N:num` o CONJUNCT1) THEN ASM_REWRITE_TAC[] THEN
    UNDISCH_TAC `!n:num. n >= N ==> (D n :real = b)` THEN
    DISCH_THEN(fun th -> MP_TAC(SPEC `N:num` th) THEN
    MP_TAC(SPEC `SUC N` th)) THEN
    REWRITE_TAC[
GE; 
LESS_EQ_SUC_REFL; 
LE_REFL] THEN
    DISCH_THEN SUBST1_TAC THEN DISCH_THEN SUBST1_TAC THEN
    REWRITE_TAC[
REAL_LT_REFL]]);;
 
let DIVISION_RHS = prove(
  `!D a b. division(a,b) D ==> (D(dsize D) = b)`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
DIVISION_THM] THEN
  DISCH_THEN(MP_TAC o SPEC `dsize D` o last o CONJUNCTS) THEN
  REWRITE_TAC[
GE; 
LE_REFL]);;
 
let DIVISION_LT_GEN = prove(
  `!D a b m n. division(a,b) D /\
               m < n /\
               n <= (dsize D) ==> D(m) < D(n)`,
  REPEAT STRIP_TAC THEN UNDISCH_TAC `m:num < n` THEN
  DISCH_THEN(X_CHOOSE_THEN `d:num` MP_TAC o MATCH_MP 
LESS_ADD_1) THEN
  REWRITE_TAC[GSYM 
ADD1] THEN DISCH_THEN SUBST_ALL_TAC THEN
  UNDISCH_TAC `(m + (SUC d)) <= (dsize D)` THEN
  SPEC_TAC(`d:num`,`d:num`) THEN INDUCT_TAC THENL
   [REWRITE_TAC[
ADD_CLAUSES] THEN
    DISCH_THEN(MP_TAC o MATCH_MP OR_LESS) THEN
    RULE_ASSUM_TAC(REWRITE_RULE[
DIVISION_THM]) THEN
    ASM_REWRITE_TAC[];
    REWRITE_TAC[
ADD_CLAUSES] THEN
    DISCH_THEN(MP_TAC o MATCH_MP OR_LESS) THEN
    DISCH_TAC THEN MATCH_MP_TAC 
REAL_LT_TRANS THEN
    EXISTS_TAC `D(m + (SUC d)):real` THEN CONJ_TAC THENL
     [FIRST_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[
ADD_CLAUSES] THEN
      MATCH_MP_TAC 
LT_IMP_LE THEN ASM_REWRITE_TAC[];
      REWRITE_TAC[
ADD_CLAUSES] THEN
      FIRST_ASSUM(MATCH_MP_TAC o el 1 o
        CONJUNCTS o REWRITE_RULE[
DIVISION_THM]) THEN
      ASM_REWRITE_TAC[]]]);;
 
let DIVISION_LT = prove(
  `!D a b. division(a,b) D ==> !n. n < (dsize D) ==> D(0) < D(SUC n)`,
  REPEAT GEN_TAC THEN REWRITE_TAC[
DIVISION_THM] THEN STRIP_TAC THEN
  INDUCT_TAC THEN DISCH_THEN(fun th -> ASSUME_TAC th THEN
      FIRST_ASSUM(MP_TAC o C MATCH_MP th)) THEN
  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
  MATCH_MP_TAC 
REAL_LT_TRANS THEN EXISTS_TAC `D(SUC n):real` THEN
  ASM_REWRITE_TAC[] THEN UNDISCH_TAC `D(0):real = a` THEN
  DISCH_THEN(SUBST1_TAC o SYM) THEN FIRST_ASSUM MATCH_MP_TAC THEN
  MATCH_MP_TAC 
LT_TRANS THEN EXISTS_TAC `SUC n` THEN
  ASM_REWRITE_TAC[
LESS_SUC_REFL]);;
 
let DIVISION_LE = prove(
  `!D a b. division(a,b) D ==> a <= b`,
  REPEAT GEN_TAC THEN DISCH_TAC THEN
  FIRST_ASSUM(MP_TAC o MATCH_MP 
DIVISION_LT) THEN
  POP_ASSUM(STRIP_ASSUME_TAC o REWRITE_RULE[
DIVISION_THM]) THEN
  UNDISCH_TAC `D(0):real = a` THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
  UNDISCH_TAC `!n. n >= (dsize D) ==> (D n = b)` THEN
  DISCH_THEN(MP_TAC o SPEC `dsize D`) THEN
  REWRITE_TAC[
GE; 
LE_REFL] THEN
  DISCH_THEN(SUBST1_TAC o SYM) THEN
  DISCH_THEN(MP_TAC o SPEC `
PRE(dsize D)`) THEN
  STRUCT_CASES_TAC(SPEC `dsize D` 
num_CASES) THEN
  ASM_REWRITE_TAC[
PRE; 
REAL_LE_REFL; 
LESS_SUC_REFL; 
REAL_LT_IMP_LE]);;
 
let DIVISION_GT = prove(
  `!D a b. division(a,b) D ==> !n. n < (dsize D) ==> D(n) < D(dsize D)`,
  REPEAT STRIP_TAC THEN MATCH_MP_TAC 
DIVISION_LT_GEN THEN
  MAP_EVERY EXISTS_TAC [`a:real`; `b:real`] THEN
  ASM_REWRITE_TAC[
LE_REFL]);;
 
let DIVISION_EQ = prove(
  `!D a b. division(a,b) D ==> ((a = b) <=> (dsize D = 0))`,
  REPEAT GEN_TAC THEN DISCH_TAC THEN
  FIRST_ASSUM(MP_TAC o MATCH_MP 
DIVISION_LT) THEN
  POP_ASSUM(STRIP_ASSUME_TAC o REWRITE_RULE[
DIVISION_THM]) THEN
  UNDISCH_TAC `D(0):real = a` THEN DISCH_THEN(SUBST1_TAC o SYM) THEN
  UNDISCH_TAC `!n. n >= (dsize D) ==> (D n = b)` THEN
  DISCH_THEN(MP_TAC o SPEC `dsize D`) THEN
  REWRITE_TAC[
GE; 
LE_REFL] THEN
  DISCH_THEN(SUBST1_TAC o SYM) THEN
  DISCH_THEN(MP_TAC o SPEC `
PRE(dsize D)`) THEN
  STRUCT_CASES_TAC(SPEC `dsize D` 
num_CASES) THEN
  ASM_REWRITE_TAC[
PRE; 
NOT_SUC; 
LESS_SUC_REFL; 
REAL_LT_IMP_NE]);;
 
let DIVISION_LBOUND_LT = prove(
  `!D a b n. division(a,b) D /\ ~(dsize D = 0) ==> a < D(SUC n)`,
  REWRITE_TAC[
RIGHT_FORALL_IMP_THM] THEN REPEAT STRIP_TAC THEN
  FIRST_ASSUM(SUBST1_TAC o SYM o MATCH_MP 
DIVISION_LHS) THEN
  DISJ_CASES_TAC(SPECL [`dsize D`; `SUC n`] 
LTE_CASES) THENL
   [FIRST_ASSUM(MP_TAC o el 2 o CONJUNCTS o REWRITE_RULE[
DIVISION_THM]) THEN
    DISCH_THEN(MP_TAC o SPEC `SUC n`) THEN REWRITE_TAC[
GE] THEN
    IMP_RES_THEN ASSUME_TAC 
LT_IMP_LE THEN ASM_REWRITE_TAC[] THEN
    DISCH_THEN SUBST1_TAC THEN
    FIRST_ASSUM(SUBST1_TAC o SYM o MATCH_MP 
DIVISION_RHS) THEN
    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP 
DIVISION_GT) THEN
    ASM_REWRITE_TAC[GSYM 
NOT_LE; CONJUNCT1 
LE];
    FIRST_ASSUM(MATCH_MP_TAC o MATCH_MP 
DIVISION_LT) THEN
    MATCH_MP_TAC OR_LESS THEN ASM_REWRITE_TAC[]]);;
 
let DIVISION_UBOUND = prove(
  `!D a b r. division(a,b) D ==> D(r) <= b`,
  REWRITE_TAC[
DIVISION_THM] THEN REPEAT STRIP_TAC THEN
  DISJ_CASES_TAC(SPECL [`r:num`; `dsize D`] 
LTE_CASES) THENL
   [ALL_TAC;
    MATCH_MP_TAC 
REAL_EQ_IMP_LE THEN FIRST_ASSUM MATCH_MP_TAC THEN
    ASM_REWRITE_TAC[
GE]] THEN
  SUBGOAL_THEN `!r. D((dsize D) - r) <= b` MP_TAC THENL
   [ALL_TAC;
    DISCH_THEN(MP_TAC o SPEC `(dsize D) - r`) THEN
    MATCH_MP_TAC EQ_IMP THEN
    AP_THM_TAC THEN AP_TERM_TAC THEN AP_TERM_TAC THEN
    FIRST_ASSUM(fun th -> REWRITE_TAC[MATCH_MP 
SUB_SUB
      (MATCH_MP 
LT_IMP_LE th)]) THEN
    ONCE_REWRITE_TAC[
ADD_SYM] THEN REWRITE_TAC[
ADD_SUB]] THEN
  UNDISCH_TAC `r < (dsize D)` THEN DISCH_THEN(K ALL_TAC) THEN
  INDUCT_TAC THENL
   [REWRITE_TAC[
SUB_0] THEN MATCH_MP_TAC 
REAL_EQ_IMP_LE THEN
    FIRST_ASSUM MATCH_MP_TAC THEN REWRITE_TAC[
GE; 
LE_REFL];
    ALL_TAC] THEN
  DISJ_CASES_TAC(SPECL [`r:num`; `dsize D`] 
LTE_CASES) THENL
   [ALL_TAC;
    SUBGOAL_THEN `(dsize D) - (SUC r) = 0` SUBST1_TAC THENL
     [REWRITE_TAC[
SUB_EQ_0] THEN MATCH_MP_TAC 
LE_TRANS THEN
      EXISTS_TAC `r:num` THEN ASM_REWRITE_TAC[
LESS_EQ_SUC_REFL];
      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
DIVISION_LE THEN
      EXISTS_TAC `D:num->real` THEN ASM_REWRITE_TAC[
DIVISION_THM]]] THEN
  MATCH_MP_TAC 
REAL_LE_TRANS THEN
  EXISTS_TAC `D((dsize D) - r):real` THEN ASM_REWRITE_TAC[] THEN
  SUBGOAL_THEN `(dsize D) - r = SUC((dsize D) - (SUC r))`
  SUBST1_TAC THENL
   [ALL_TAC;
    MATCH_MP_TAC 
REAL_LT_IMP_LE THEN FIRST_ASSUM MATCH_MP_TAC THEN
    MATCH_MP_TAC 
LESS_CASES_IMP THEN
    REWRITE_TAC[
NOT_LT; 
LE_LT; 
SUB_LESS_EQ] THEN
    CONV_TAC(RAND_CONV SYM_CONV) THEN
    REWRITE_TAC[
SUB_EQ_EQ_0; 
NOT_SUC] THEN
    DISCH_THEN SUBST_ALL_TAC THEN
    UNDISCH_TAC `r < 0` THEN REWRITE_TAC[
NOT_LESS_0]] THEN
  MP_TAC(SPECL [`dsize D`; `SUC r`] (CONJUNCT2 
SUB_OLD)) THEN
  COND_CASES_TAC THENL
   [REWRITE_TAC[
SUB_EQ_0; 
LE_SUC] THEN
    ASM_REWRITE_TAC[GSYM 
NOT_LT];
    DISCH_THEN (SUBST1_TAC o SYM) THEN REWRITE_TAC[
SUB_SUC]]);;
 
let DIVISION_APPEND_LEMMA1 = prove(
  `!a b c D1 D2. division(a,b) D1 /\ division(b,c) D2 ==>
        (!n. n < ((dsize D1) + (dsize D2)) ==>
                (\n. if (n < (dsize D1)) then  D1(n) else
                     D2(n - (dsize D1)))(n) <
   (\n. if (n < (dsize D1)) then  D1(n) else D2(n - (dsize D1)))(SUC n)) /\
        (!n. n >= ((dsize D1) + (dsize D2)) ==>
               ((\n. if (n < (dsize D1)) then  D1(n) else
   D2(n - (dsize D1)))(n) = (\n. if (n < (dsize D1)) then  D1(n) else
   D2(n - (dsize D1)))((dsize D1) + (dsize D2))))`,
  REPEAT GEN_TAC THEN STRIP_TAC THEN CONJ_TAC THEN
  X_GEN_TAC `n:num` THEN DISCH_TAC THEN BETA_TAC THENL
   [ASM_CASES_TAC `(SUC n) < (dsize D1)` THEN ASM_REWRITE_TAC[] THENL
     [SUBGOAL_THEN `n < (dsize D1)` ASSUME_TAC THEN
      ASM_REWRITE_TAC[] THENL
       [MATCH_MP_TAC 
LT_TRANS THEN EXISTS_TAC `SUC n` THEN
        ASM_REWRITE_TAC[
LESS_SUC_REFL];
        UNDISCH_TAC `division(a,b) D1` THEN REWRITE_TAC[
DIVISION_THM] THEN
        STRIP_TAC THEN FIRST_ASSUM MATCH_MP_TAC THEN
        FIRST_ASSUM ACCEPT_TAC];
      ASM_CASES_TAC `n < (dsize D1)` THEN ASM_REWRITE_TAC[] THENL
       [RULE_ASSUM_TAC(REWRITE_RULE[
NOT_LT]) THEN
        MATCH_MP_TAC 
REAL_LTE_TRANS THEN EXISTS_TAC `b:real` THEN
        CONJ_TAC THENL
         [MATCH_MP_TAC 
DIVISION_UBOUND_LT THEN
          EXISTS_TAC `a:real` THEN ASM_REWRITE_TAC[];
          MATCH_MP_TAC 
DIVISION_LBOUND THEN
          EXISTS_TAC `c:real` THEN ASM_REWRITE_TAC[]];
        UNDISCH_TAC `~(n < (dsize D1))` THEN
        REWRITE_TAC[
NOT_LT] THEN
        DISCH_THEN(X_CHOOSE_THEN `d:num` SUBST_ALL_TAC o
          REWRITE_RULE[
LE_EXISTS]) THEN
        REWRITE_TAC[
SUB_OLD; GSYM 
NOT_LE; 
LE_ADD] THEN
        ONCE_REWRITE_TAC[
ADD_SYM] THEN REWRITE_TAC[
ADD_SUB] THEN
        FIRST_ASSUM(MATCH_MP_TAC o el 1 o CONJUNCTS o
          REWRITE_RULE[
DIVISION_THM]) THEN
        UNDISCH_TAC `((dsize D1) + d) <
                     ((dsize D1) + (dsize D2))` THEN
        ONCE_REWRITE_TAC[
ADD_SYM] THEN REWRITE_TAC[
LT_ADD_RCANCEL]]];
    REWRITE_TAC[GSYM 
NOT_LE; 
LE_ADD] THEN
    ONCE_REWRITE_TAC[
ADD_SYM] THEN REWRITE_TAC[
ADD_SUB] THEN
    REWRITE_TAC[
NOT_LE] THEN COND_CASES_TAC THEN
    UNDISCH_TAC `n >= ((dsize D1) + (dsize D2))` THENL
     [CONV_TAC CONTRAPOS_CONV THEN DISCH_TAC THEN
      REWRITE_TAC[
GE; 
NOT_LE] THEN
      MATCH_MP_TAC 
LTE_TRANS THEN EXISTS_TAC `dsize D1` THEN
      ASM_REWRITE_TAC[
LE_ADD];
      REWRITE_TAC[
GE; 
LE_EXISTS] THEN
      DISCH_THEN(X_CHOOSE_THEN `d:num` SUBST_ALL_TAC) THEN
      REWRITE_TAC[GSYM 
ADD_ASSOC] THEN ONCE_REWRITE_TAC[
ADD_SYM] THEN
      REWRITE_TAC[
ADD_SUB] THEN
      FIRST_ASSUM(CHANGED_TAC o
       (SUBST1_TAC o MATCH_MP 
DIVISION_RHS)) THEN
      FIRST_ASSUM(MATCH_MP_TAC o el 2 o CONJUNCTS o
        REWRITE_RULE[
DIVISION_THM]) THEN
      REWRITE_TAC[
GE; 
LE_ADD]]]);;
 
let DIVISION_APPEND_LEMMA2 = prove(
  `!a b c D1 D2. division(a,b) D1 /\ division(b,c) D2 ==>
                   (dsize(\n. if (n < (dsize D1)) then  D1(n) else
       D2(n - (dsize D1))) = dsize(D1) + dsize(D2))`,
  REPEAT STRIP_TAC THEN GEN_REWRITE_TAC LAND_CONV [dsize] THEN
  MATCH_MP_TAC 
SELECT_UNIQUE THEN
  X_GEN_TAC `N:num` THEN BETA_TAC THEN EQ_TAC THENL
   [DISCH_THEN((then_) (MATCH_MP_TAC LESS_EQUAL_ANTISYM) o MP_TAC) THEN
    CONV_TAC CONTRAPOS_CONV THEN
    REWRITE_TAC[DE_MORGAN_THM; 
NOT_LE] THEN
    DISCH_THEN DISJ_CASES_TAC THENL
     [DISJ1_TAC THEN
      DISCH_THEN(MP_TAC o SPEC `dsize(D1) + dsize(D2)`) THEN
      ASM_REWRITE_TAC[] THEN
      REWRITE_TAC[GSYM 
NOT_LE; 
LE_ADD] THEN
      SUBGOAL_THEN `!x y. x <= SUC(x + y)` ASSUME_TAC THENL
       [REPEAT GEN_TAC THEN MATCH_MP_TAC 
LE_TRANS THEN
        EXISTS_TAC `x + y:num` THEN
        REWRITE_TAC[
LE_ADD; 
LESS_EQ_SUC_REFL]; ALL_TAC] THEN
      ASM_REWRITE_TAC[] THEN REWRITE_TAC[
SUB_OLD; GSYM 
NOT_LE] THEN
      REWRITE_TAC[
LE_ADD] THEN ONCE_REWRITE_TAC[
ADD_SYM] THEN
      REWRITE_TAC[
ADD_SUB] THEN
      MP_TAC(ASSUME `division(b,c) D2`) THEN REWRITE_TAC[
DIVISION_THM] THEN
      DISCH_THEN(MP_TAC o SPEC `SUC(dsize D2)` o el 2 o CONJUNCTS) THEN
      REWRITE_TAC[
GE; 
LESS_EQ_SUC_REFL] THEN
      DISCH_THEN SUBST1_TAC THEN
      FIRST_ASSUM(CHANGED_TAC o SUBST1_TAC o MATCH_MP 
DIVISION_RHS) THEN
      REWRITE_TAC[
REAL_LT_REFL];
      DISJ2_TAC THEN
      DISCH_THEN(MP_TAC o SPEC `dsize(D1) + dsize(D2)`) THEN
      FIRST_ASSUM(ASSUME_TAC o MATCH_MP 
LT_IMP_LE) THEN
      ASM_REWRITE_TAC[
GE] THEN
      REWRITE_TAC[GSYM 
NOT_LE; 
LE_ADD] THEN
      ONCE_REWRITE_TAC[
ADD_SYM] THEN REWRITE_TAC[
ADD_SUB] THEN
      COND_CASES_TAC THENL
       [SUBGOAL_THEN `D1(N:num) < D2(dsize D2)` MP_TAC THENL
         [MATCH_MP_TAC 
REAL_LTE_TRANS THEN EXISTS_TAC `b:real` THEN
          CONJ_TAC THENL
           [MATCH_MP_TAC 
DIVISION_UBOUND_LT THEN EXISTS_TAC `a:real` THEN
            ASM_REWRITE_TAC[GSYM 
NOT_LE];
            MATCH_MP_TAC 
DIVISION_LBOUND THEN
            EXISTS_TAC `c:real` THEN ASM_REWRITE_TAC[]];
          CONV_TAC CONTRAPOS_CONV THEN ASM_REWRITE_TAC[] THEN
          DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[
REAL_LT_REFL]];
        RULE_ASSUM_TAC(REWRITE_RULE[]) THEN
        SUBGOAL_THEN `D2(N - (dsize D1)) < D2(dsize D2)` MP_TAC THENL
         [MATCH_MP_TAC 
DIVISION_LT_GEN THEN
          MAP_EVERY EXISTS_TAC [`b:real`; `c:real`] THEN
          ASM_REWRITE_TAC[
LE_REFL] THEN
          REWRITE_TAC[GSYM 
NOT_LE] THEN
          REWRITE_TAC[
SUB_LEFT_LESS_EQ; DE_MORGAN_THM] THEN
          ONCE_REWRITE_TAC[
ADD_SYM] THEN ASM_REWRITE_TAC[
NOT_LE] THEN
          UNDISCH_TAC `dsize(D1) <= N` THEN
          REWRITE_TAC[
LE_EXISTS] THEN
          DISCH_THEN(X_CHOOSE_THEN `d:num` SUBST_ALL_TAC) THEN
          RULE_ASSUM_TAC(ONCE_REWRITE_RULE[
ADD_SYM]) THEN
          RULE_ASSUM_TAC(REWRITE_RULE[
LT_ADD_RCANCEL]) THEN
          MATCH_MP_TAC 
LET_TRANS THEN EXISTS_TAC `d:num` THEN
          ASM_REWRITE_TAC[
LE_0];
          CONV_TAC CONTRAPOS_CONV THEN REWRITE_TAC[] THEN
          DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[
REAL_LT_REFL]]]];
  DISCH_THEN SUBST1_TAC THEN CONJ_TAC THENL
   [X_GEN_TAC `n:num` THEN DISCH_TAC THEN
    ASM_CASES_TAC `(SUC n) < (dsize(D1))` THEN
    ASM_REWRITE_TAC[] THENL
     [SUBGOAL_THEN `n < (dsize(D1))` ASSUME_TAC THENL
       [MATCH_MP_TAC 
LT_TRANS THEN EXISTS_TAC `SUC n` THEN
        ASM_REWRITE_TAC[
LESS_SUC_REFL]; ALL_TAC] THEN
      ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
DIVISION_LT_GEN THEN
      MAP_EVERY EXISTS_TAC [`a:real`; `b:real`] THEN
      ASM_REWRITE_TAC[
LESS_SUC_REFL] THEN
      MATCH_MP_TAC 
LT_IMP_LE THEN ASM_REWRITE_TAC[];
      COND_CASES_TAC THENL
       [MATCH_MP_TAC 
REAL_LTE_TRANS THEN EXISTS_TAC `b:real` THEN
        CONJ_TAC THENL
         [MATCH_MP_TAC 
DIVISION_UBOUND_LT THEN EXISTS_TAC `a:real` THEN
          ASM_REWRITE_TAC[];
          FIRST_ASSUM(MATCH_ACCEPT_TAC o MATCH_MP 
DIVISION_LBOUND)];
        MATCH_MP_TAC 
DIVISION_LT_GEN THEN
        MAP_EVERY EXISTS_TAC [`b:real`; `c:real`] THEN
        ASM_REWRITE_TAC[] THEN
        CONJ_TAC THENL [ASM_REWRITE_TAC[
SUB_OLD; 
LESS_SUC_REFL]; ALL_TAC] THEN
        REWRITE_TAC[REWRITE_RULE[
GE] 
SUB_LEFT_GREATER_EQ] THEN
        ONCE_REWRITE_TAC[
ADD_SYM] THEN ASM_REWRITE_TAC[
LE_SUC_LT]]];
    X_GEN_TAC `n:num` THEN REWRITE_TAC[
GE] THEN DISCH_TAC THEN
    REWRITE_TAC[GSYM 
NOT_LE; 
LE_ADD] THEN
    SUBGOAL_THEN `(dsize D1) <= n` ASSUME_TAC THENL
     [MATCH_MP_TAC 
LE_TRANS THEN
      EXISTS_TAC `dsize D1 + dsize D2` THEN
      ASM_REWRITE_TAC[
LE_ADD];
      ASM_REWRITE_TAC[] THEN ONCE_REWRITE_TAC[
ADD_SYM] THEN
      REWRITE_TAC[
ADD_SUB] THEN
      FIRST_ASSUM(CHANGED_TAC o SUBST1_TAC o MATCH_MP 
DIVISION_RHS) THEN
      FIRST_ASSUM(MATCH_MP_TAC o el 2 o
        CONJUNCTS o REWRITE_RULE[
DIVISION_THM]) THEN
      REWRITE_TAC[
GE; 
SUB_LEFT_LESS_EQ] THEN
      ONCE_REWRITE_TAC[
ADD_SYM] THEN ASM_REWRITE_TAC[]]]]);;
 
let DIVISION_APPEND_EXPLICIT = prove
 (`!a b c g d1 p1 d2 p2.
        tdiv(a,b) (d1,p1) /\
        fine g (d1,p1) /\
        tdiv(b,c) (d2,p2) /\
        fine g (d2,p2)
        ==> tdiv(a,c)
              ((\n. if n < dsize d1 then  d1(n) else d2(n - (dsize d1))),
               (\n. if n < dsize d1
                    then p1(n) else p2(n - (dsize d1)))) /\
            fine g ((\n. if n < dsize d1 then  d1(n) else d2(n - (dsize d1))),
               (\n. if n < dsize d1
                    then p1(n) else p2(n - (dsize d1)))) /\
            !f. rsum((\n. if n < dsize d1 then  d1(n) else d2(n - (dsize d1))),
                     (\n. if n < dsize d1
                          then p1(n) else p2(n - (dsize d1)))) f =
                rsum(d1,p1) f + rsum(d2,p2) f`,
  MAP_EVERY X_GEN_TAC
   [`a:real`; `b:real`; `c:real`; `g:real->real`;
    `D1:num->real`; `p1:num->real`; `D2:num->real`; `p2:num->real`] THEN
  STRIP_TAC THEN REWRITE_TAC[
CONJ_ASSOC] THEN CONJ_TAC THENL
   [ALL_TAC;
    GEN_TAC THEN REWRITE_TAC[rsum] THEN
    MP_TAC(SPECL [`a:real`; `b:real`; `c:real`;
                  `D1:num->real`; `D2:num->real`] 
DIVISION_APPEND_LEMMA2) THEN
    ANTS_TAC THENL [ASM_MESON_TAC[tdiv]; ALL_TAC] THEN
    DISCH_THEN SUBST1_TAC THEN REWRITE_TAC[GSYM 
SUM_SPLIT] THEN
    REWRITE_TAC[
SUM_REINDEX] THEN BINOP_TAC THEN MATCH_MP_TAC 
SUM_EQ THEN
    SIMP_TAC[
ADD_CLAUSES; ARITH_RULE `~(r + d < d:num)`;
             ARITH_RULE `~(SUC(r + d) < d)`; 
ADD_SUB;
             ARITH_RULE `SUC(r + d) - d = SUC r`] THEN
    X_GEN_TAC `k:num` THEN STRIP_TAC THEN AP_TERM_TAC THEN
    ASM_SIMP_TAC[ARITH_RULE `k < n ==> (SUC k < n <=> ~(n = SUC k))`] THEN
    ASM_CASES_TAC `dsize D1 = SUC k` THEN ASM_REWRITE_TAC[
SUB_REFL] THEN
    AP_THM_TAC THEN AP_TERM_TAC THEN
    ASM_MESON_TAC[tdiv; 
DIVISION_LHS; 
DIVISION_RHS]] THEN
  DISJ_CASES_TAC(GSYM (SPEC `dsize(D1)` 
LESS_0_CASES)) THENL
   [ASM_REWRITE_TAC[
NOT_LESS_0; 
SUB_0] THEN
    CONV_TAC(ONCE_DEPTH_CONV ETA_CONV) THEN
    SUBGOAL_THEN `a:real = b` (fun th -> ASM_REWRITE_TAC[th]) THEN
    MP_TAC(SPECL [`D1:num->real`; `a:real`; `b:real`] 
DIVISION_EQ) THEN
    RULE_ASSUM_TAC(REWRITE_RULE[tdiv]) THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
  CONJ_TAC THENL
   [ALL_TAC;
    REWRITE_TAC[fine] THEN X_GEN_TAC `n:num` THEN
    RULE_ASSUM_TAC(REWRITE_RULE[tdiv]) THEN
    MP_TAC(SPECL [`a:real`; `b:real`; `c:real`;
                  `D1:num->real`; `D2:num->real`] 
DIVISION_APPEND_LEMMA2) THEN
    ASM_REWRITE_TAC[] THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN BETA_TAC THEN
    DISCH_TAC THEN ASM_CASES_TAC `(SUC n) < (dsize D1)` THEN
    ASM_REWRITE_TAC[] THENL
     [SUBGOAL_THEN `n < (dsize D1)` ASSUME_TAC THENL
       [MATCH_MP_TAC 
LT_TRANS THEN EXISTS_TAC `SUC n` THEN
        ASM_REWRITE_TAC[
LESS_SUC_REFL]; ALL_TAC] THEN
      ASM_REWRITE_TAC[] THEN
      FIRST_ASSUM(MATCH_MP_TAC o REWRITE_RULE[fine]) THEN
      ASM_REWRITE_TAC[]; ALL_TAC] THEN
    ASM_CASES_TAC `n < (dsize D1)` THEN ASM_REWRITE_TAC[] THENL
     [SUBGOAL_THEN `SUC n = dsize D1` ASSUME_TAC THENL
       [MATCH_MP_TAC LESS_EQUAL_ANTISYM THEN
        ASM_REWRITE_TAC[GSYM 
NOT_LT] THEN
        REWRITE_TAC[
NOT_LT] THEN MATCH_MP_TAC 
LESS_OR THEN
        ASM_REWRITE_TAC[];
        ASM_REWRITE_TAC[
SUB_REFL] THEN
        FIRST_ASSUM(CHANGED_TAC o SUBST1_TAC o MATCH_MP 
DIVISION_LHS o
          CONJUNCT1) THEN
        FIRST_ASSUM(CHANGED_TAC o SUBST1_TAC o SYM o
          MATCH_MP 
DIVISION_RHS o  CONJUNCT1) THEN
        SUBST1_TAC(SYM(ASSUME `SUC n = dsize D1`)) THEN
        FIRST_ASSUM(MATCH_MP_TAC o REWRITE_RULE[fine]) THEN
        ASM_REWRITE_TAC[]];
      ASM_REWRITE_TAC[
SUB_OLD] THEN UNDISCH_TAC `~(n < (dsize D1))` THEN
      REWRITE_TAC[
LE_EXISTS; 
NOT_LT] THEN
      DISCH_THEN(X_CHOOSE_THEN `d:num` SUBST_ALL_TAC) THEN
      ONCE_REWRITE_TAC[
ADD_SYM] THEN REWRITE_TAC[
ADD_SUB] THEN
      FIRST_ASSUM(MATCH_MP_TAC o REWRITE_RULE[fine]) THEN
      RULE_ASSUM_TAC(ONCE_REWRITE_RULE[
ADD_SYM]) THEN
      RULE_ASSUM_TAC(REWRITE_RULE[
LT_ADD_RCANCEL]) THEN
      FIRST_ASSUM ACCEPT_TAC]] THEN
  REWRITE_TAC[tdiv] THEN BETA_TAC THEN CONJ_TAC THENL
   [RULE_ASSUM_TAC(REWRITE_RULE[tdiv]) THEN
    REWRITE_TAC[
DIVISION_THM] THEN CONJ_TAC THENL
     [BETA_TAC THEN ASM_REWRITE_TAC[] THEN
      MATCH_MP_TAC 
DIVISION_LHS THEN EXISTS_TAC `b:real` THEN
      ASM_REWRITE_TAC[]; ALL_TAC] THEN
    SUBGOAL_THEN `c = (\n. if (n < (dsize D1)) then  D1(n) else D2(n -
                  (dsize D1))) (dsize(D1) + dsize(D2))` SUBST1_TAC THENL
     [BETA_TAC THEN REWRITE_TAC[GSYM 
NOT_LE; 
LE_ADD] THEN
      ONCE_REWRITE_TAC[
ADD_SYM] THEN REWRITE_TAC[
ADD_SUB] THEN
      CONV_TAC SYM_CONV THEN MATCH_MP_TAC 
DIVISION_RHS THEN
      EXISTS_TAC `b:real` THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
    MP_TAC(SPECL [`a:real`; `b:real`; `c:real`;
                 `D1:num->real`; `D2:num->real`] 
DIVISION_APPEND_LEMMA2) THEN
    ASM_REWRITE_TAC[] THEN DISCH_THEN(fun th -> REWRITE_TAC[th]) THEN
    MATCH_MP_TAC (BETA_RULE 
DIVISION_APPEND_LEMMA1) THEN
    MAP_EVERY EXISTS_TAC [`a:real`; `b:real`; `c:real`] THEN
    ASM_REWRITE_TAC[]; ALL_TAC] THEN
  X_GEN_TAC `n:num` THEN RULE_ASSUM_TAC(REWRITE_RULE[tdiv]) THEN
  ASM_CASES_TAC `(SUC n) < (dsize D1)` THEN ASM_REWRITE_TAC[] THENL
   [SUBGOAL_THEN `n < (dsize D1)` ASSUME_TAC THENL
     [MATCH_MP_TAC 
LT_TRANS THEN EXISTS_TAC `SUC n` THEN
      ASM_REWRITE_TAC[
LESS_SUC_REFL]; ALL_TAC] THEN
    ASM_REWRITE_TAC[]; ALL_TAC] THEN
  COND_CASES_TAC THEN ASM_REWRITE_TAC[] THENL
   [ASM_REWRITE_TAC[
SUB_OLD] THEN
    FIRST_ASSUM(CHANGED_TAC o SUBST1_TAC o MATCH_MP 
DIVISION_LHS o
      CONJUNCT1) THEN
    FIRST_ASSUM(CHANGED_TAC o SUBST1_TAC o SYM o
      MATCH_MP 
DIVISION_RHS o  CONJUNCT1) THEN
    SUBGOAL_THEN `dsize D1 = SUC n` (fun th -> ASM_REWRITE_TAC[th]) THEN
    MATCH_MP_TAC LESS_EQUAL_ANTISYM THEN
    ASM_REWRITE_TAC[GSYM 
NOT_LT] THEN REWRITE_TAC[
NOT_LT] THEN
    MATCH_MP_TAC 
LESS_OR THEN ASM_REWRITE_TAC[];
    ASM_REWRITE_TAC[
SUB_OLD]]);;
 
let DIVISION_APPEND_STRONG = prove
 (`!a b c D1 p1 D2 p2.
        tdiv(a,b) (D1,p1) /\ fine(g) (D1,p1) /\
        tdiv(b,c) (D2,p2) /\ fine(g) (D2,p2)
        ==> ?D p. tdiv(a,c) (D,p) /\ fine(g) (D,p) /\
                  !f. rsum(D,p) f = rsum(D1,p1) f + rsum(D2,p2) f`,
  REPEAT STRIP_TAC THEN MAP_EVERY EXISTS_TAC
   [`\n. if n < dsize D1 then D1(n):real else D2(n - (dsize D1))`;
    `\n. if n < dsize D1 then p1(n):real else p2(n - (dsize D1))`] THEN
  MATCH_MP_TAC 
DIVISION_APPEND_EXPLICIT THEN ASM_MESON_TAC[]);;
 
let DIVISION_APPEND = prove(
  `!a b c.
      (?D1 p1. tdiv(a,b) (D1,p1) /\ fine(g) (D1,p1)) /\
      (?D2 p2. tdiv(b,c) (D2,p2) /\ fine(g) (D2,p2)) ==>
        ?D p. tdiv(a,c) (D,p) /\ fine(g) (D,p)`,
 
let DIVISION_EXISTS = prove(
  `!a b g. a <= b /\ gauge(\x. a <= x /\ x <= b) g ==>
        ?D p. tdiv(a,b) (D,p) /\ fine(g) (D,p)`,
  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
  (MP_TAC o C SPEC 
BOLZANO_LEMMA)
    `\(u,v). a <= u /\ v <= b ==> ?D p. tdiv(u,v) (D,p) /\ fine(g) (D,p)` THEN
  CONV_TAC(ONCE_DEPTH_CONV GEN_BETA_CONV) THEN
  W(C SUBGOAL_THEN (fun t ->REWRITE_TAC[t]) o
  funpow 2 (fst o dest_imp) o snd) THENL
   [CONJ_TAC;
    DISCH_THEN(MP_TAC o SPECL [`a:real`; `b:real`]) THEN
    REWRITE_TAC[
REAL_LE_REFL]]
  THENL
   [MAP_EVERY X_GEN_TAC [`u:real`; `v:real`; `w:real`] THEN
    REPEAT STRIP_TAC THEN MATCH_MP_TAC 
DIVISION_APPEND THEN
    EXISTS_TAC `v:real` THEN CONJ_TAC THEN
    FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THENL
     [MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `w:real`;
      MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `u:real`] THEN
    ASM_REWRITE_TAC[]; ALL_TAC] THEN
  X_GEN_TAC `x:real` THEN ASM_CASES_TAC `a <= x /\ x <= b` THENL
   [ALL_TAC;
    EXISTS_TAC `&1` THEN REWRITE_TAC[
REAL_LT_01] THEN
    MAP_EVERY X_GEN_TAC [`w:real`; `y:real`] THEN STRIP_TAC THEN
    CONV_TAC CONTRAPOS_CONV THEN DISCH_THEN(K ALL_TAC) THEN
    FIRST_ASSUM(UNDISCH_TAC o check is_neg o concl) THEN
    REWRITE_TAC[DE_MORGAN_THM; 
REAL_NOT_LE] THEN
    DISCH_THEN DISJ_CASES_TAC THENL
     [DISJ1_TAC THEN MATCH_MP_TAC 
REAL_LET_TRANS;
      DISJ2_TAC THEN MATCH_MP_TAC 
REAL_LTE_TRANS] THEN
    EXISTS_TAC `x:real` THEN ASM_REWRITE_TAC[]] THEN
  UNDISCH_TAC `gauge(\x. a <= x /\ x <= b) g` THEN
  REWRITE_TAC[gauge] THEN BETA_TAC THEN
  DISCH_THEN(fun th -> FIRST_ASSUM(ASSUME_TAC o MATCH_MP th)) THEN
  EXISTS_TAC `(g:real->real) x` THEN ASM_REWRITE_TAC[] THEN
  MAP_EVERY X_GEN_TAC [`w:real`; `y:real`] THEN REPEAT STRIP_TAC THEN
  EXISTS_TAC `\n. if (n = 0) then (w:real) else y` THEN
  EXISTS_TAC `\n. if (n = 0) then (x:real) else y` THEN
  SUBGOAL_THEN `w <= y` ASSUME_TAC THENL
   [MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `x:real` THEN
    ASM_REWRITE_TAC[]; ALL_TAC] THEN
  CONJ_TAC THENL
   [REWRITE_TAC[tdiv] THEN CONJ_TAC THENL
     [MATCH_MP_TAC 
DIVISION_SINGLE THEN FIRST_ASSUM ACCEPT_TAC;
      X_GEN_TAC `n:num` THEN BETA_TAC THEN REWRITE_TAC[
NOT_SUC] THEN
      COND_CASES_TAC THEN ASM_REWRITE_TAC[
REAL_LE_REFL]];
    REWRITE_TAC[fine] THEN BETA_TAC THEN REWRITE_TAC[
NOT_SUC] THEN
    X_GEN_TAC `n:num` THEN
    DISJ_CASES_THEN MP_TAC (REWRITE_RULE[
REAL_LE_LT] (ASSUME `w <= y`)) THENL
     [DISCH_THEN(ASSUME_TAC o MATCH_MP 
DIVISION_1) THEN
      ASM_REWRITE_TAC[num_CONV `1`; CONJUNCT2 
LT; 
NOT_LESS_0] THEN
      DISCH_THEN SUBST1_TAC THEN ASM_REWRITE_TAC[];
      DISCH_THEN(SUBST1_TAC o MATCH_MP 
DIVISION_0) THEN
      REWRITE_TAC[
NOT_LESS_0]]]);;
 
let GAUGE_MIN = prove(
  `!E g1 g2. gauge(E) g1 /\ gauge(E) g2 ==>
        gauge(E) (\x. if g1(x) < g2(x) then g1(x) else g2(x))`,
  REPEAT GEN_TAC THEN REWRITE_TAC[gauge] THEN STRIP_TAC THEN
  X_GEN_TAC `x:real` THEN BETA_TAC THEN DISCH_TAC THEN
  COND_CASES_TAC THEN FIRST_ASSUM MATCH_MP_TAC THEN
  FIRST_ASSUM ACCEPT_TAC);;
 
let FINE_MIN = prove(
  `!g1 g2 D p. fine (\x. if g1(x) < g2(x) then g1(x) else g2(x)) (D,p) ==>
        fine(g1) (D,p) /\ fine(g2) (D,p)`,
  REPEAT GEN_TAC THEN REWRITE_TAC[fine] THEN
  BETA_TAC THEN DISCH_TAC THEN CONJ_TAC THEN
  X_GEN_TAC `n:num` THEN DISCH_THEN(ANTE_RES_THEN MP_TAC) THEN
  COND_CASES_TAC THEN REWRITE_TAC[] THEN DISCH_TAC THENL
   [RULE_ASSUM_TAC(REWRITE_RULE[
REAL_NOT_LT]) THEN
    MATCH_MP_TAC 
REAL_LTE_TRANS;
    MATCH_MP_TAC 
REAL_LT_TRANS] THEN
  FIRST_ASSUM(fun th -> EXISTS_TAC(rand(concl th)) THEN
                   ASM_REWRITE_TAC[] THEN NO_TAC));;
 
let DINT_UNIQ = prove(
  `!a b f k1 k2. a <= b /\ defint(a,b) f k1 /\ defint(a,b) f k2 ==> (k1 = k2)`,
  REPEAT GEN_TAC THEN DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  GEN_REWRITE_TAC RAND_CONV [GSYM 
REAL_SUB_0] THEN
  CONV_TAC CONTRAPOS_CONV THEN ONCE_REWRITE_TAC[
ABS_NZ] THEN DISCH_TAC THEN
  REWRITE_TAC[defint] THEN
  DISCH_THEN(CONJUNCTS_THEN(MP_TAC o SPEC `abs(k1 - k2) / &2`)) THEN
  ASM_REWRITE_TAC[
REAL_LT_HALF1] THEN
  DISCH_THEN(X_CHOOSE_THEN `g1:real->real` STRIP_ASSUME_TAC) THEN
  DISCH_THEN(X_CHOOSE_THEN `g2:real->real` STRIP_ASSUME_TAC) THEN
  MP_TAC(SPECL [`\x. a <= x /\ x <= b`;
                `g1:real->real`; `g2:real->real`] 
GAUGE_MIN) THEN
  ASM_REWRITE_TAC[] THEN DISCH_TAC THEN
  MP_TAC(SPECL [`a:real`; `b:real`;
         `\x:real. if g1(x) < g2(x) then g1(x) else g2(x)`] 
DIVISION_EXISTS) THEN
  ASM_REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_THEN `D:num->real` (X_CHOOSE_THEN `p:num->real`
    STRIP_ASSUME_TAC)) THEN
  FIRST_ASSUM(STRIP_ASSUME_TAC o MATCH_MP 
FINE_MIN) THEN
  REPEAT(FIRST_ASSUM(UNDISCH_TAC o check is_forall o concl) THEN
    DISCH_THEN(MP_TAC o SPECL [`D:num->real`; `p:num->real`]) THEN
    ASM_REWRITE_TAC[] THEN DISCH_TAC) THEN
  SUBGOAL_THEN `abs((rsum(D,p) f - k2) - (rsum(D,p) f - k1)) < abs(k1 - k2)`
  MP_TAC THENL
   [MATCH_MP_TAC 
REAL_LET_TRANS THEN
    EXISTS_TAC `abs(rsum(D,p) f - k2) + abs(rsum(D,p) f - k1)` THEN
    CONJ_TAC THENL
     [GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [
real_sub] THEN
      GEN_REWRITE_TAC (funpow 2 RAND_CONV) [GSYM 
ABS_NEG] THEN
      MATCH_ACCEPT_TAC 
ABS_TRIANGLE;
      GEN_REWRITE_TAC RAND_CONV [GSYM 
REAL_HALF_DOUBLE] THEN
      MATCH_MP_TAC 
REAL_LT_ADD2 THEN ASM_REWRITE_TAC[]];
    REWRITE_TAC[
real_sub; 
REAL_NEG_ADD; 
REAL_NEG_SUB] THEN
    ONCE_REWRITE_TAC[AC 
REAL_ADD_AC
      `(a + b) + (c + d) = (d + a) + (c + b)`] THEN
    REWRITE_TAC[REAL_ADD_LINV; REAL_ADD_LID; 
REAL_LT_REFL]]);;
 
let INTEGRAL_NULL = prove(
  `!f a. defint(a,a) f (&0)`,
  REPEAT GEN_TAC THEN REWRITE_TAC[defint] THEN GEN_TAC THEN
  DISCH_TAC THEN EXISTS_TAC `\x:real. &1` THEN
  REWRITE_TAC[gauge; 
REAL_LT_01] THEN REPEAT GEN_TAC THEN
  REWRITE_TAC[tdiv] THEN STRIP_TAC THEN
  FIRST_ASSUM(MP_TAC o MATCH_MP 
DIVISION_EQ) THEN
  REWRITE_TAC[rsum] THEN DISCH_THEN SUBST1_TAC THEN
  ASM_REWRITE_TAC[sum; 
REAL_SUB_REFL; 
ABS_0]);;
 
let STRADDLE_LEMMA = prove(
  `!f f' a b e. (!x. a <= x /\ x <= b ==> (f diffl f'(x))(x)) /\ &0 < e
    ==> ?g. gauge(\x. a <= x /\ x <= b) g /\
            !x u v. a <= u /\ u <= x /\ x <= v /\ v <= b /\ (v - u) < g(x)
                ==> abs((f(v) - f(u)) - (f'(x) * (v - u))) <= e * (v - u)`,
  REPEAT STRIP_TAC THEN REWRITE_TAC[gauge] THEN BETA_TAC THEN
  SUBGOAL_THEN
   `!x. a <= x /\ x <= b ==>
        ?d. &0 < d /\
          !u v. u <= x /\ x <= v /\ (v - u) < d ==>
            abs((f(v) - f(u)) - (f'(x) * (v - u))) <= e * (v - u)` MP_TAC THENL
   [ALL_TAC;
    FIRST_ASSUM(UNDISCH_TAC o check is_forall o concl) THEN
    DISCH_THEN(K ALL_TAC) THEN
    DISCH_THEN(MP_TAC o CONV_RULE
      ((ONCE_DEPTH_CONV RIGHT_IMP_EXISTS_CONV) THENC OLD_SKOLEM_CONV)) THEN
    DISCH_THEN(X_CHOOSE_THEN `g:real->real` STRIP_ASSUME_TAC) THEN
    EXISTS_TAC `g:real->real` THEN CONJ_TAC THENL
     [GEN_TAC THEN
      DISCH_THEN(fun th -> FIRST_ASSUM(MP_TAC o C MATCH_MP th)) THEN
      DISCH_THEN(fun th -> REWRITE_TAC[th]);
      REPEAT STRIP_TAC THEN
      C SUBGOAL_THEN (fun th -> FIRST_ASSUM(MP_TAC o C MATCH_MP th))
      `a <= x /\ x <= b` THENL
       [CONJ_TAC THEN MATCH_MP_TAC 
REAL_LE_TRANS THENL
         [EXISTS_TAC `u:real`; EXISTS_TAC `v:real`] THEN
        ASM_REWRITE_TAC[];
        DISCH_THEN(MATCH_MP_TAC o CONJUNCT2) THEN ASM_REWRITE_TAC[]]]] THEN
  X_GEN_TAC `x:real` THEN
  DISCH_THEN(fun th -> STRIP_ASSUME_TAC th THEN
    FIRST_ASSUM(UNDISCH_TAC o check is_forall o concl) THEN
    DISCH_THEN(MP_TAC o C MATCH_MP th)) THEN
  REWRITE_TAC[diffl; 
LIM] THEN
  DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN
  ASM_REWRITE_TAC[
REAL_LT_HALF1] THEN
  BETA_TAC THEN REWRITE_TAC[
REAL_SUB_RZERO] THEN
  DISCH_THEN(X_CHOOSE_THEN `d:real` STRIP_ASSUME_TAC) THEN
  SUBGOAL_THEN `!z. abs(z - x) < d ==>
        abs((f(z) - f(x)) - (f'(x) * (z - x))) <= (e / &2) * abs(z - x)`
  ASSUME_TAC THENL
   [GEN_TAC THEN ASM_CASES_TAC `&0 < abs(z - x)` THENL
     [ALL_TAC;
      UNDISCH_TAC `~(&0 < abs(z - x))` THEN
      REWRITE_TAC[GSYM 
ABS_NZ; 
REAL_SUB_0] THEN
      DISCH_THEN SUBST1_TAC THEN
      REWRITE_TAC[
REAL_SUB_REFL; 
REAL_MUL_RZERO; 
ABS_0; 
REAL_LE_REFL]] THEN
    DISCH_THEN(MP_TAC o CONJ (ASSUME `&0 < abs(z - x)`)) THEN
    DISCH_THEN((then_) (MATCH_MP_TAC 
REAL_LT_IMP_LE) o MP_TAC) THEN
    DISCH_THEN(fun th -> FIRST_ASSUM(MP_TAC o C MATCH_MP th)) THEN
    FIRST_ASSUM(fun th -> GEN_REWRITE_TAC LAND_CONV
      [GSYM(MATCH_MP 
REAL_LT_RMUL_EQ th)]) THEN
    MATCH_MP_TAC EQ_IMP THEN
    AP_THM_TAC THEN AP_TERM_TAC THEN
    REWRITE_TAC[GSYM 
ABS_MUL] THEN AP_TERM_TAC THEN
    REWRITE_TAC[
REAL_SUB_RDISTRIB] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
    REWRITE_TAC[
REAL_SUB_ADD2] THEN MATCH_MP_TAC 
REAL_DIV_RMUL THEN
    ASM_REWRITE_TAC[
ABS_NZ]; ALL_TAC] THEN
  EXISTS_TAC `d:real` THEN ASM_REWRITE_TAC[] THEN
  REPEAT STRIP_TAC THEN
  SUBGOAL_THEN `u <= v` (DISJ_CASES_TAC o REWRITE_RULE[
REAL_LE_LT]) THENL
   [MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `x:real` THEN
    ASM_REWRITE_TAC[];
    ALL_TAC;
    ASM_REWRITE_TAC[
REAL_SUB_REFL; 
REAL_MUL_RZERO; 
ABS_0; 
REAL_LE_REFL]] THEN
  MATCH_MP_TAC 
REAL_LE_TRANS THEN
  EXISTS_TAC `abs((f(v) - f(x)) - (f'(x) * (v - x))) +
              abs((f(x) - f(u)) - (f'(x) * (x - u)))` THEN
  CONJ_TAC THENL
   [MP_TAC(SPECL[`(f(v) - f(x)) - (f'(x) * (v - x))`;
                 `(f(x) - f(u)) - (f'(x) * (x - u))`] 
ABS_TRIANGLE) THEN
    MATCH_MP_TAC EQ_IMP THEN
    AP_THM_TAC THEN REPEAT AP_TERM_TAC THEN
    ONCE_REWRITE_TAC[GSYM 
REAL_ADD2_SUB2] THEN
    REWRITE_TAC[
REAL_SUB_LDISTRIB] THEN
    SUBGOAL_THEN `!a b c. (a - b) + (b - c) = (a - c)`
      (fun th -> REWRITE_TAC[th]) THEN
    REPEAT GEN_TAC THEN REWRITE_TAC[
real_sub] THEN
    ONCE_REWRITE_TAC[AC 
REAL_ADD_AC
      `(a + b) + (c + d) = (b + c) + (a + d)`] THEN
    REWRITE_TAC[REAL_ADD_LINV; REAL_ADD_LID]; ALL_TAC] THEN
  GEN_REWRITE_TAC RAND_CONV [GSYM 
REAL_HALF_DOUBLE] THEN
  MATCH_MP_TAC 
REAL_LE_ADD2 THEN CONJ_TAC THENL
   [MATCH_MP_TAC 
REAL_LE_TRANS THEN
    EXISTS_TAC `(e / &2) * abs(v - x)` THEN CONJ_TAC THENL
     [FIRST_ASSUM MATCH_MP_TAC THEN
      ASM_REWRITE_TAC[
real_abs; 
REAL_SUB_LE] THEN
      MATCH_MP_TAC 
REAL_LET_TRANS THEN EXISTS_TAC `v - u` THEN
      ASM_REWRITE_TAC[] THEN REWRITE_TAC[
real_sub; 
REAL_LE_LADD] THEN
      ASM_REWRITE_TAC[
REAL_LE_NEG];
      ASM_REWRITE_TAC[
real_abs; 
REAL_SUB_LE] THEN REWRITE_TAC[
real_div] THEN
      GEN_REWRITE_TAC LAND_CONV
       [AC 
REAL_MUL_AC `(a * b) * c = (a * c) * b`] THEN
      REWRITE_TAC[GSYM REAL_MUL_ASSOC;
        MATCH_MP 
REAL_LE_LMUL_LOCAL (ASSUME `&0 < e`)] THEN
      SUBGOAL_THEN `!x y. (x * inv(&2)) <= (y * inv(&2)) <=> x <= y`
      (fun th -> ASM_REWRITE_TAC[th; 
real_sub; 
REAL_LE_LADD; 
REAL_LE_NEG]) THEN
      REPEAT GEN_TAC THEN MATCH_MP_TAC 
REAL_LE_RMUL_EQ THEN
      MATCH_MP_TAC 
REAL_INV_POS THEN
      REWRITE_TAC[
REAL_LT; num_CONV `2`; 
LT_0]];
    MATCH_MP_TAC 
REAL_LE_TRANS THEN
    EXISTS_TAC `(e / &2) * abs(x - u)` THEN CONJ_TAC THENL
     [GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [
real_sub] THEN
      ONCE_REWRITE_TAC[GSYM 
ABS_NEG] THEN
      REWRITE_TAC[
REAL_NEG_ADD; 
REAL_NEG_SUB] THEN
      ONCE_REWRITE_TAC[
REAL_NEG_RMUL] THEN
      REWRITE_TAC[
REAL_NEG_SUB] THEN REWRITE_TAC[GSYM 
real_sub] THEN
      FIRST_ASSUM MATCH_MP_TAC THEN ONCE_REWRITE_TAC[
ABS_SUB] THEN
      ASM_REWRITE_TAC[
real_abs; 
REAL_SUB_LE] THEN
      MATCH_MP_TAC 
REAL_LET_TRANS THEN EXISTS_TAC `v - u` THEN
      ASM_REWRITE_TAC[] THEN ASM_REWRITE_TAC[
real_sub; 
REAL_LE_RADD];
      ASM_REWRITE_TAC[
real_abs; 
REAL_SUB_LE] THEN REWRITE_TAC[
real_div] THEN
      GEN_REWRITE_TAC LAND_CONV
       [AC 
REAL_MUL_AC `(a * b) * c = (a * c) * b`] THEN
      REWRITE_TAC[GSYM REAL_MUL_ASSOC;
        MATCH_MP 
REAL_LE_LMUL_LOCAL (ASSUME `&0 < e`)] THEN
      SUBGOAL_THEN `!x y. (x * inv(&2)) <= (y * inv(&2)) <=> x <= y`
      (fun th -> ASM_REWRITE_TAC[th; 
real_sub; 
REAL_LE_RADD; 
REAL_LE_NEG]) THEN
      REPEAT GEN_TAC THEN MATCH_MP_TAC 
REAL_LE_RMUL_EQ THEN
      MATCH_MP_TAC 
REAL_INV_POS THEN
      REWRITE_TAC[
REAL_LT; num_CONV `2`; 
LT_0]]]);;
 
let FTC1 = prove(
  `!f f' a b. a <= b /\ (!x. a <= x /\ x <= b ==> (f diffl f'(x))(x))
        ==> defint(a,b) f' (f(b) - f(a))`,
  REPEAT STRIP_TAC THEN
  UNDISCH_TAC `a <= b` THEN REWRITE_TAC[
REAL_LE_LT] THEN
  DISCH_THEN DISJ_CASES_TAC THENL
   [ALL_TAC; ASM_REWRITE_TAC[
REAL_SUB_REFL; 
INTEGRAL_NULL]] THEN
  REWRITE_TAC[defint] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  SUBGOAL_THEN
    `!e. &0 < e ==>
      ?g. gauge(\x. a <= x /\ x <= b)g /\
          (!D p.
            tdiv(a,b)(D,p) /\ fine g(D,p) ==>
            (abs((rsum(D,p)f') - ((f b) - (f a)))) <= e)`
  MP_TAC THENL
   [ALL_TAC;
    DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN ASM_REWRITE_TAC[
REAL_LT_HALF1] THEN
    DISCH_THEN(X_CHOOSE_THEN `g:real->real` STRIP_ASSUME_TAC) THEN
    EXISTS_TAC `g:real->real` THEN ASM_REWRITE_TAC[] THEN
    REPEAT GEN_TAC THEN
    DISCH_THEN(fun th -> FIRST_ASSUM(ASSUME_TAC o C MATCH_MP th)) THEN
    MATCH_MP_TAC 
REAL_LET_TRANS THEN EXISTS_TAC `e / &2` THEN
    ASM_REWRITE_TAC[
REAL_LT_HALF2]] THEN
  UNDISCH_TAC `&0 < e` THEN DISCH_THEN(K ALL_TAC) THEN
  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  MP_TAC(SPECL [`f:real->real`; `f':real->real`;
    `a:real`; `b:real`; `e / (b - a)`] 
STRADDLE_LEMMA) THEN
  ASM_REWRITE_TAC[] THEN
  SUBGOAL_THEN `&0 < e / (b - a)` (fun th -> REWRITE_TAC[th]) THENL
   [REWRITE_TAC[
real_div] THEN MATCH_MP_TAC 
REAL_LT_MUL THEN
    ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
REAL_INV_POS THEN
    ASM_REWRITE_TAC[
REAL_SUB_LT]; ALL_TAC] THEN
  DISCH_THEN(X_CHOOSE_THEN `g:real->real` STRIP_ASSUME_TAC) THEN
  EXISTS_TAC `g:real->real` THEN ASM_REWRITE_TAC[] THEN
  MAP_EVERY X_GEN_TAC [`D:num->real`; `p:num->real`] THEN
  REWRITE_TAC[tdiv] THEN STRIP_TAC THEN REWRITE_TAC[rsum] THEN
  SUBGOAL_THEN `f(b) - f(a) = sum(0,dsize D)(\n. f(D(SUC n)) - f(D(n)))`
  SUBST1_TAC THENL
   [MP_TAC(SPECL [`\n:num. (f:real->real)(D(n))`; `0`; `dsize D`]
      
SUM_CANCEL) THEN BETA_TAC THEN DISCH_THEN SUBST1_TAC THEN
    ASM_REWRITE_TAC[
ADD_CLAUSES] THEN
    MAP_EVERY (IMP_RES_THEN SUBST1_TAC) [
DIVISION_LHS; 
DIVISION_RHS] THEN
    REFL_TAC; ALL_TAC] THEN
  ONCE_REWRITE_TAC[
ABS_SUB] THEN REWRITE_TAC[GSYM 
SUM_SUB] THEN BETA_TAC THEN
  LE_MATCH_TAC 
ABS_SUM THEN BETA_TAC THEN
  SUBGOAL_THEN `e = sum(0,dsize D)(\n. (e / (b - a)) * (D(SUC n) - D(n)))`
  SUBST1_TAC THENL
   [ONCE_REWRITE_TAC[SYM(BETA_CONV `(\n. (D(SUC n) - D(n))) n`)] THEN
    ASM_REWRITE_TAC[
SUM_CMUL; 
SUM_CANCEL; 
ADD_CLAUSES] THEN
    MAP_EVERY (IMP_RES_THEN SUBST1_TAC) [
DIVISION_LHS; 
DIVISION_RHS] THEN
    CONV_TAC SYM_CONV THEN MATCH_MP_TAC 
REAL_DIV_RMUL THEN
    REWRITE_TAC[
REAL_SUB_0] THEN CONV_TAC(RAND_CONV SYM_CONV) THEN
    MATCH_MP_TAC 
REAL_LT_IMP_NE THEN FIRST_ASSUM ACCEPT_TAC; ALL_TAC] THEN
  MATCH_MP_TAC 
SUM_LE THEN X_GEN_TAC `r:num` THEN
  REWRITE_TAC[
ADD_CLAUSES] THEN STRIP_TAC THEN BETA_TAC THEN
  FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN REPEAT CONJ_TAC THENL
   [IMP_RES_THEN (fun th -> REWRITE_TAC[th]) 
DIVISION_LBOUND;
    IMP_RES_THEN (fun th -> REWRITE_TAC[th]) 
DIVISION_UBOUND;
    UNDISCH_TAC `fine(g)(D,p)` THEN REWRITE_TAC[fine] THEN
    DISCH_THEN MATCH_MP_TAC THEN FIRST_ASSUM ACCEPT_TAC]);;
 
let INTEGRABLE_DEFINT = prove
 (`!f a b. integrable(a,b) f ==> defint(a,b) f (integral(a,b) f)`,
  REPEAT GEN_TAC THEN REWRITE_TAC[integrable; integral] THEN
  CONV_TAC(RAND_CONV SELECT_CONV) THEN REWRITE_TAC[]);;
 
let TDIV_BOUNDS = prove
 (`!d p a b. tdiv(a,b) (d,p)
             ==> !n. a <= d(n) /\ d(n) <= b /\ a <= p(n) /\ p(n) <= b`,
 
let DEFINT_WRONG = prove
 (`!a b f i. b < a ==> defint(a,b) f i`,
  REWRITE_TAC[defint; gauge] THEN REPEAT STRIP_TAC THEN
  EXISTS_TAC `\x:real. &0` THEN
  ASM_SIMP_TAC[REAL_ARITH `b < a ==> (a <= x /\ x <= b <=> F)`] THEN
  ASM_MESON_TAC[
REAL_NOT_LE; 
TDIV_LE]);;
 
let DEFINT_CONST = prove
 (`!a b c. defint(a,b) (\x. c) (c * (b - a))`,
  REPEAT GEN_TAC THEN
  MP_TAC(SPECL [`\x. c * x`; `\x:real. c:real`; `a:real`; `b:real`] 
FTC1) THEN
  DISJ_CASES_TAC(REAL_ARITH `b < a \/ a <= b`) THEN
  ASM_SIMP_TAC[
DEFINT_WRONG; 
REAL_SUB_LDISTRIB] THEN
  DISCH_THEN MATCH_MP_TAC THEN REPEAT STRIP_TAC THEN
  MP_TAC(SPEC `x:real` (DIFF_CONV `\x. c * x`)) THEN
  REWRITE_TAC[REAL_MUL_LID; 
REAL_MUL_LZERO; REAL_ADD_LID]);;
 
let DEFINT_NEG = prove
 (`!f a b i. defint(a,b) f i ==> defint(a,b) (\x. --f x) (--i)`,
  REPEAT GEN_TAC THEN REWRITE_TAC[defint] THEN
  REWRITE_TAC[rsum; 
REAL_MUL_LNEG; 
SUM_NEG] THEN
  REWRITE_TAC[REAL_ARITH `abs(--x - --y) = abs(x - y)`]);;
 
let DEFINT_ADD = prove
 (`!f g a b i j.
        defint(a,b) f i /\ defint(a,b) g j
        ==> defint(a,b) (\x. f x + g x) (i + j)`,
  REPEAT GEN_TAC THEN REWRITE_TAC[defint] THEN
  STRIP_TAC THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  REPEAT(FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`)) THEN
  ASM_SIMP_TAC[
REAL_LT_DIV; 
REAL_OF_NUM_LT; ARITH] THEN
  DISCH_THEN(X_CHOOSE_THEN `g1:real->real` STRIP_ASSUME_TAC) THEN
  DISCH_THEN(X_CHOOSE_THEN `g2:real->real` STRIP_ASSUME_TAC) THEN
  EXISTS_TAC `\x:real. if g1(x) < g2(x) then g1(x) else g2(x)` THEN
  ASM_SIMP_TAC[
GAUGE_MIN; rsum] THEN REPEAT STRIP_TAC THEN
  REWRITE_TAC[
REAL_ADD_RDISTRIB; 
SUM_ADD] THEN REWRITE_TAC[GSYM rsum] THEN
  MATCH_MP_TAC(REAL_ARITH
   `abs(x - i) < e / &2 /\ abs(y - j) < e / &2
    ==> abs((x + y) - (i + j)) < e`) THEN
  ASM_MESON_TAC[
FINE_MIN]);;
 
let DEFINT_SUB = prove
 (`!f g a b i j.
        defint(a,b) f i /\ defint(a,b) g j
        ==> defint(a,b) (\x. f x - g x) (i - j)`,
 
let INTEGRAL_LE = prove
 (`!f g a b i j.
        a <= b /\ integrable(a,b) f /\ integrable(a,b) g /\
        (!x. a <= x /\ x <= b ==> f(x) <= g(x))
        ==> integral(a,b) f <= integral(a,b) g`,
  REPEAT STRIP_TAC THEN
  REPEAT(FIRST_X_ASSUM(ASSUME_TAC o MATCH_MP 
INTEGRABLE_DEFINT)) THEN
  MATCH_MP_TAC(REAL_ARITH `~(&0 < x - y) ==> x <= y`) THEN
  ABBREV_TAC `e = integral(a,b) f - integral(a,b) g` THEN DISCH_TAC THEN
  REPEAT(FIRST_X_ASSUM(MP_TAC o
    SPEC `e / &2` o GEN_REWRITE_RULE I [defint])) THEN
  ASM_REWRITE_TAC[REAL_ARITH `&0 < e / &2 <=> &0 < e`] THEN
  DISCH_THEN(X_CHOOSE_THEN `g1:real->real` STRIP_ASSUME_TAC) THEN
  DISCH_THEN(X_CHOOSE_THEN `g2:real->real` STRIP_ASSUME_TAC) THEN
  MP_TAC(SPECL [`a:real`; `b:real`;
                `\x:real. if g1(x) < g2(x) then g1(x) else g2(x)`]
               
DIVISION_EXISTS) THEN
  ASM_SIMP_TAC[
GAUGE_MIN; 
NOT_EXISTS_THM] THEN
  MAP_EVERY X_GEN_TAC [`D:num->real`; `p:num->real`] THEN STRIP_TAC THEN
  REPEAT(FIRST_X_ASSUM(MP_TAC o SPECL [`D:num->real`; `p:num->real`])) THEN
  REPEAT(FIRST_X_ASSUM(MP_TAC o SPECL [`D:num->real`; `p:num->real`])) THEN
  FIRST_ASSUM(fun th -> ASM_REWRITE_TAC[MATCH_MP 
FINE_MIN th]) THEN
  MATCH_MP_TAC(REAL_ARITH
   `ih - ig = e /\ &0 < e /\ sh <= sg
    ==> abs(sg - ig) < e / &2 ==> ~(abs(sh - ih) < e / &2)`) THEN
  ASM_REWRITE_TAC[] THEN REWRITE_TAC[rsum] THEN MATCH_MP_TAC 
SUM_LE THEN
  X_GEN_TAC `r:num` THEN REWRITE_TAC[
ADD_CLAUSES] THEN STRIP_TAC THEN
  MATCH_MP_TAC 
REAL_LE_RMUL THEN REWRITE_TAC[
REAL_SUB_LE] THEN
  ASM_MESON_TAC[
TDIV_BOUNDS; 
REAL_LT_IMP_LE; 
DIVISION_THM; tdiv]);;
 
let DEFINT_LE = prove
 (`!f g a b i j. a <= b /\ defint(a,b) f i /\ defint(a,b) g j /\
                 (!x. a <= x /\ x <= b ==> f(x) <= g(x))
                 ==> i <= j`,
 
let DEFINT_TRIANGLE = prove
 (`!f a b i j. a <= b /\ defint(a,b) f i /\ defint(a,b) (\x. abs(f x)) j
               ==> abs(i) <= j`,
  REPEAT STRIP_TAC THEN MATCH_MP_TAC(REAL_ARITH
   `--a <= b /\ b <= a ==> abs(b) <= a`) THEN
  CONJ_TAC THEN MATCH_MP_TAC 
DEFINT_LE THENL
   [MAP_EVERY EXISTS_TAC [`\x:real. --abs(f x)`; `f:real->real`];
    MAP_EVERY EXISTS_TAC [`f:real->real`; `\x:real. abs(f x)`]] THEN
  MAP_EVERY EXISTS_TAC [`a:real`; `b:real`] THEN
  ASM_SIMP_TAC[
DEFINT_NEG] THEN REAL_ARITH_TAC);;
 
let DEFINT_EQ = prove
 (`!f g a b i j. a <= b /\ defint(a,b) f i /\ defint(a,b) g j /\
                 (!x. a <= x /\ x <= b ==> f(x) = g(x))
                 ==> i = j`,
  REWRITE_TAC[GSYM REAL_LE_ANTISYM] THEN MESON_TAC[
DEFINT_LE]);;
 
let INTEGRAL_EQ = prove
 (`!f g a b i. defint(a,b) f i /\
               (!x. a <= x /\ x <= b ==> f(x) = g(x))
               ==> defint(a,b) g i`,
  REPEAT STRIP_TAC THEN ASM_CASES_TAC `a <= b` THENL
   [ALL_TAC; ASM_MESON_TAC[
REAL_NOT_LE; 
DEFINT_WRONG]] THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [defint]) THEN
  REWRITE_TAC[defint] THEN MATCH_MP_TAC 
MONO_FORALL THEN
  X_GEN_TAC `e:real` THEN ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `d:real->real` THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN ASM_REWRITE_TAC[] THEN
  MATCH_MP_TAC 
MONO_FORALL THEN X_GEN_TAC `D:num->real` THEN
  MATCH_MP_TAC 
MONO_FORALL THEN X_GEN_TAC `p:num->real` THEN
  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN ASM_REWRITE_TAC[] THEN
  MATCH_MP_TAC(REAL_ARITH `x = y ==> abs(x - i) < e ==> abs(y - i) < e`) THEN
  REWRITE_TAC[rsum] THEN MATCH_MP_TAC 
SUM_EQ THEN
  REPEAT STRIP_TAC THEN REWRITE_TAC[] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
  FIRST_X_ASSUM MATCH_MP_TAC THEN
  ASM_MESON_TAC[tdiv; 
DIVISION_LBOUND; 
DIVISION_UBOUND; 
DIVISION_THM;
                
REAL_LE_TRANS]);;
 
let INTEGRATION_BY_PARTS = prove
 (`!f g f' g' a b.
        a <= b /\
        (!x. a <= x /\ x <= b ==> (f diffl f'(x))(x)) /\
        (!x. a <= x /\ x <= b ==> (g diffl g'(x))(x))
        ==> defint(a,b) (\x. f'(x) * g(x) + f(x) * g'(x))
                        (f(b) * g(b) - f(a) * g(a))`,
  REPEAT STRIP_TAC THEN MATCH_MP_TAC 
FTC1 THEN ASM_REWRITE_TAC[] THEN
  ONCE_REWRITE_TAC[REAL_ARITH `a + b * c = a + c * b`] THEN
  ASM_SIMP_TAC[
DIFF_MUL]);;
 
let DIVISION_INTERMEDIATE = prove
 (`!d a b c. division(a,b) d /\ a <= c /\ c <= b
             ==> ?n. n <= dsize d /\ d(n) <= c /\ c <= d(SUC n)`,
  REPEAT STRIP_TAC THEN
  MP_TAC(SPEC `\n. n <= dsize d /\ (d:num->real)(n) <= c` 
num_MAX) THEN
  DISCH_THEN(MP_TAC o fst o EQ_IMP_RULE) THEN ANTS_TAC THENL
   [ASM_MESON_TAC[
LE_0; 
DIVISION_THM]; ALL_TAC] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `n:num` THEN SIMP_TAC[] THEN
  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPEC `SUC n`) THEN
  REWRITE_TAC[ARITH_RULE `~(SUC n <= n)`] THEN
  ONCE_REWRITE_TAC[GSYM CONTRAPOS_THM] THEN REWRITE_TAC[
REAL_NOT_LE] THEN
  DISCH_TAC THEN ASM_SIMP_TAC[
REAL_LT_IMP_LE; 
LE_SUC_LT; 
LT_LE] THEN
  DISCH_THEN SUBST_ALL_TAC THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
DIVISION_THM]) THEN
  DISCH_THEN(MP_TAC o SPEC `SUC(dsize d)` o repeat CONJUNCT2) THEN
  REWRITE_TAC[
GE; 
LE; 
LE_REFL] THEN
  ASM_REAL_ARITH_TAC);;
 
let DIVISION_DSIZE_EQ = prove
 (`!a b d n. division(a,b) d /\ d(n) < d(SUC n) /\ d(SUC(SUC n)) = d(SUC n)
           ==> dsize d = SUC n`,
 
let DEFINT_COMBINE = prove
 (`!f a b c i j. a <= b /\ b <= c /\ defint(a,b) f i /\ defint(b,c) f j
                 ==> defint(a,c) f (i + j)`,
  REPEAT GEN_TAC THEN
  REPLICATE_TAC 2 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
  MP_TAC(ASSUME `a <= b`) THEN REWRITE_TAC[
REAL_LE_LT] THEN
  ASM_CASES_TAC `a:real = b` THEN ASM_REWRITE_TAC[] THENL
   [ASM_MESON_TAC[
INTEGRAL_NULL; 
DINT_UNIQ; 
REAL_LE_TRANS; REAL_ADD_LID];
    DISCH_TAC] THEN
  MP_TAC(ASSUME `b <= c`) THEN REWRITE_TAC[
REAL_LE_LT] THEN
  ASM_CASES_TAC `b:real = c` THEN ASM_REWRITE_TAC[] THENL
   [ASM_MESON_TAC[
INTEGRAL_NULL; 
DINT_UNIQ; 
REAL_LE_TRANS; 
REAL_ADD_RID];
    DISCH_TAC] THEN
  REWRITE_TAC[defint; 
AND_FORALL_THM] THEN
  DISCH_THEN(fun th -> X_GEN_TAC `e:real` THEN DISCH_TAC THEN MP_TAC th) THEN
  DISCH_THEN(MP_TAC o SPEC `e / &2`) THEN
  ASM_SIMP_TAC[
REAL_LT_DIV; 
REAL_OF_NUM_LT; ARITH] THEN
  DISCH_THEN(CONJUNCTS_THEN2
   (X_CHOOSE_THEN `g1:real->real` STRIP_ASSUME_TAC)
   (X_CHOOSE_THEN `g2:real->real` STRIP_ASSUME_TAC)) THEN
  EXISTS_TAC
   `\x. if x < b then min (g1 x) (b - x)
        else if b < x then min (g2 x) (x - b)
        else min (g1 x) (g2 x)` THEN
  CONJ_TAC THENL
   [REPEAT(FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [gauge])) THEN
    REWRITE_TAC[gauge] THEN REPEAT STRIP_TAC THEN
    REPEAT COND_CASES_TAC THEN ASM_SIMP_TAC[
REAL_LT_MIN; 
REAL_SUB_LT] THEN
    TRY CONJ_TAC THEN FIRST_X_ASSUM MATCH_MP_TAC THEN
    ASM_REAL_ARITH_TAC;
    ALL_TAC] THEN
  MAP_EVERY X_GEN_TAC [`d:num->real`; `p:num->real`] THEN
  REWRITE_TAC[tdiv; rsum] THEN STRIP_TAC THEN
  MP_TAC(SPECL [`d:num->real`; `a:real`; `c:real`; `b:real`]
               
DIVISION_INTERMEDIATE) THEN ASM_REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_THEN `m:num`
   (CONJUNCTS_THEN2 MP_TAC STRIP_ASSUME_TAC)) THEN REWRITE_TAC[
LE_EXISTS] THEN
  DISCH_THEN(X_CHOOSE_TAC `n:num`) THEN ASM_REWRITE_TAC[] THEN
  ASM_CASES_TAC `n = 0` THENL
   [FIRST_X_ASSUM SUBST_ALL_TAC THEN
    RULE_ASSUM_TAC(REWRITE_RULE[
ADD_CLAUSES]) THEN
    FIRST_X_ASSUM(SUBST_ALL_TAC o SYM) THEN
    ASM_MESON_TAC[
DIVISION_THM; 
GE; 
LE_REFL; 
REAL_NOT_LT];
    ALL_TAC] THEN
  REWRITE_TAC[GSYM 
SUM_SPLIT; 
ADD_CLAUSES] THEN
  FIRST_ASSUM(SUBST1_TAC o MATCH_MP (ARITH_RULE
   `~(n = 0) ==> n = 1 + 
PRE n`)) THEN
  REWRITE_TAC[GSYM 
SUM_SPLIT; 
SUM_1] THEN
  SUBGOAL_THEN `(p:num->real) m = b` ASSUME_TAC THENL
   [FIRST_X_ASSUM(MP_TAC o SPEC `m:num` o GEN_REWRITE_RULE I [fine]) THEN
    ASM_REWRITE_TAC[ARITH_RULE `m < m + n <=> ~(n = 0)`] THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `m:num`) THEN
    MAP_EVERY UNDISCH_TAC [`(d:num->real) m <= b`; `b:real <= d(SUC m)`] THEN
    REAL_ARITH_TAC;
    ALL_TAC] THEN
  MATCH_MP_TAC(REAL_ARITH
   `!b. abs((s1 + x * (b - a)) - i) < e / &2 /\
        abs((s2 + x * (c - b)) - j) < e / &2
        ==> abs((s1 + x * (c - a) + s2) - (i + j)) < e`) THEN
  EXISTS_TAC `b:real` THEN CONJ_TAC THENL
   [UNDISCH_TAC
     `!D p. tdiv(a,b) (D,p) /\ fine g1 (D,p)
            ==> abs(rsum(D,p) f - i) < e / &2` THEN
    DISCH_THEN(MP_TAC o SPEC `\i. if i <= m then (d:num->real)(i) else b`) THEN
    DISCH_THEN(MP_TAC o SPEC `\i. if i <= m then (p:num->real)(i) else b`) THEN
    MATCH_MP_TAC(TAUT `a /\ (a ==> b) /\ (a /\ c ==> d)
                       ==> (a /\ b ==> c) ==> d`) THEN
    CONJ_TAC THENL
     [REWRITE_TAC[tdiv; division] THEN REPEAT CONJ_TAC THENL
       [ASM_MESON_TAC[division; 
LE_0];
        ALL_TAC;
        X_GEN_TAC `k:num` THEN
        REWRITE_TAC[ARITH_RULE `SUC n <= m <=> n <= m /\ ~(m = n)`] THEN
        ASM_CASES_TAC `k:num = m` THEN
        ASM_REWRITE_TAC[
LE_REFL; 
REAL_LE_REFL] THEN
        COND_CASES_TAC THEN ASM_REWRITE_TAC[
REAL_LE_REFL]] THEN
      ASM_CASES_TAC `(d:num->real) m = b` THENL
       [EXISTS_TAC `m:num` THEN
        SIMP_TAC[ARITH_RULE `n < m ==> n <= m /\ SUC n <= m`] THEN
        SIMP_TAC[ARITH_RULE `n >= m ==> (n <= m <=> m = n:num)`] THEN
        CONJ_TAC THENL [ALL_TAC; ASM_MESON_TAC[]] THEN
        FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
DIVISION_THM]) THEN
        ASM_REWRITE_TAC[] THEN
        MESON_TAC[ARITH_RULE `i:num < m ==> i < m + n`];
        ALL_TAC] THEN
      EXISTS_TAC `SUC m` THEN
      SIMP_TAC[ARITH_RULE `n >= SUC m ==> ~(n <= m)`] THEN
      SIMP_TAC[ARITH_RULE `n < SUC m ==> n <= m`] THEN
      SIMP_TAC[ARITH_RULE `n < SUC m ==> (SUC n <= m <=> ~(m = n))`] THEN
      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
DIVISION_THM]) THEN
      ASM_REWRITE_TAC[] THEN
      ASM_MESON_TAC[ARITH_RULE `k < SUC m /\ ~(n = 0) ==> k < m + n`;
                    
REAL_LT_LE];
      ALL_TAC] THEN
    CONJ_TAC THENL
     [REWRITE_TAC[tdiv; fine] THEN STRIP_TAC THEN X_GEN_TAC `k:num` THEN
      REWRITE_TAC[ARITH_RULE `SUC n <= m <=> n <= m /\ ~(m = n)`] THEN
      FIRST_X_ASSUM(MP_TAC o SPEC `k:num` o GEN_REWRITE_RULE I [fine]) THEN
      MATCH_MP_TAC MONO_IMP THEN ASM_CASES_TAC `k:num = m` THENL
       [ASM_REWRITE_TAC[
LE_REFL; 
REAL_LT_REFL] THEN
        ASM_REWRITE_TAC[ARITH_RULE `m < m + n <=> ~(n = 0)`] THEN
        MAP_EVERY UNDISCH_TAC [`d(m:num) <= b`; `b <= d(SUC m)`] THEN
        REAL_ARITH_TAC;
        ALL_TAC] THEN
      ASM_CASES_TAC `k:num <= m` THEN ASM_REWRITE_TAC[] THENL
       [ASM_SIMP_TAC[ARITH_RULE `k <= m /\ ~(n = 0) ==> k < m + n`] THEN
        SUBGOAL_THEN `(p:num->real) k <= b` MP_TAC THENL
         [ALL_TAC; REAL_ARITH_TAC] THEN
        MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `(d:num->real) m` THEN
        ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
REAL_LE_TRANS THEN
        EXISTS_TAC `(d:num->real) (SUC k)` THEN ASM_REWRITE_TAC[] THEN
        ASM_MESON_TAC[
DIVISION_MONO_LE; ARITH_RULE
         `k <= m /\ ~(k = m) ==> SUC k <= m`];
        ALL_TAC] THEN
      CONJ_TAC THENL
       [MATCH_MP_TAC(ARITH_RULE
         `d:num <= SUC m /\ ~(n = 0) ==> k < d ==> k < m + n`) THEN
        ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
DIVISION_DSIZE_LE THEN
        MAP_EVERY EXISTS_TAC [`a:real`; `b:real`] THEN ASM_REWRITE_TAC[] THEN
        ARITH_TAC;
        ALL_TAC] THEN
      UNDISCH_TAC `gauge (\x. a <= x /\ x <= b) g1` THEN
      ASM_REWRITE_TAC[
REAL_SUB_REFL; gauge; 
REAL_LE_REFL] THEN
      DISCH_THEN(fun th -> DISCH_THEN(K ALL_TAC) THEN MP_TAC th) THEN
      ASM_MESON_TAC[
REAL_LE_REFL];
      ALL_TAC] THEN
    DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
    MATCH_MP_TAC(REAL_ARITH
     `x = y ==> abs(x - i) < e ==> abs(y - i) < e`) THEN
    REWRITE_TAC[rsum] THEN ASM_CASES_TAC `(d:num->real) m = b` THENL
     [SUBGOAL_THEN `dsize (\i. if i <= m then d i else b) = m` ASSUME_TAC THENL
       [ALL_TAC;
        ASM_REWRITE_TAC[
REAL_SUB_REFL; 
REAL_MUL_RZERO; 
REAL_ADD_RID] THEN
        MATCH_MP_TAC 
SUM_EQ THEN
        SIMP_TAC[
ADD_CLAUSES; 
LT_IMP_LE; 
LE_SUC_LT]] THEN
      MATCH_MP_TAC 
DIVISION_DSIZE_EQ_ALT THEN
      MAP_EVERY EXISTS_TAC [`a:real`; `b:real`] THEN
      CONJ_TAC THENL [ASM_MESON_TAC[tdiv]; ALL_TAC] THEN
      ASM_REWRITE_TAC[
LE_REFL; ARITH_RULE `~(SUC m <= m)`] THEN
      SIMP_TAC[
LT_IMP_LE; 
LE_SUC_LT] THEN
      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
DIVISION_THM]) THEN
      ASM_REWRITE_TAC[] THEN MESON_TAC[ARITH_RULE `i < m:num ==> i < m + n`];
      ALL_TAC] THEN
    SUBGOAL_THEN `dsize (\i. if i <= m then d i else b) = SUC m`
    ASSUME_TAC THENL
     [ALL_TAC;
      ASM_REWRITE_TAC[sum; 
ADD_CLAUSES; 
LE_REFL;
                      ARITH_RULE `~(SUC m <= m)`] THEN
      AP_THM_TAC THEN AP_TERM_TAC THEN MATCH_MP_TAC 
SUM_EQ THEN
      SIMP_TAC[
ADD_CLAUSES; 
LT_IMP_LE; 
LE_SUC_LT]] THEN
    MATCH_MP_TAC 
DIVISION_DSIZE_EQ THEN
    MAP_EVERY EXISTS_TAC [`a:real`; `b:real`] THEN
    CONJ_TAC THENL [ASM_MESON_TAC[tdiv]; ALL_TAC] THEN
    ASM_REWRITE_TAC[
LE_REFL; ARITH_RULE `~(SUC m <= m)`] THEN
    REWRITE_TAC[ARITH_RULE `~(SUC(SUC m) <= m)`] THEN
    ASM_REWRITE_TAC[
REAL_LT_LE];
    ALL_TAC] THEN
  ASM_CASES_TAC `d(SUC m):real = b` THEN ASM_REWRITE_TAC[] THENL
   [ASM_REWRITE_TAC[
REAL_SUB_REFL; 
REAL_MUL_RZERO; 
REAL_ADD_RID] THEN
    UNDISCH_TAC
     `!D p. tdiv(b,c) (D,p) /\ fine g2 (D,p)
            ==> abs(rsum(D,p) f - j) < e / &2` THEN
    DISCH_THEN(MP_TAC o SPEC `\i. (d:num->real) (i + SUC m)`) THEN
    DISCH_THEN(MP_TAC o SPEC `\i. (p:num->real) (i + SUC m)`) THEN
    MATCH_MP_TAC(TAUT `a /\ (a ==> b /\ (b /\ c ==> d))
                       ==> (a /\ b ==> c) ==> d`) THEN
    CONJ_TAC THENL
     [ASM_REWRITE_TAC[tdiv; division; 
ADD_CLAUSES] THEN EXISTS_TAC `
PRE n` THEN
      FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
DIVISION_THM]) THEN
      ASM_MESON_TAC[ARITH_RULE
                     `~(n = 0) /\ k < 
PRE n ==> SUC(k + m) < m + n`;
                    ARITH_RULE
                     `~(n = 0) /\ k >= 
PRE n ==> SUC(k + m) >= m + n`];
      DISCH_TAC] THEN
    SUBGOAL_THEN `dsize(\i. d (i + SUC m)) = 
PRE n` ASSUME_TAC THENL
     [MATCH_MP_TAC 
DIVISION_DSIZE_EQ_ALT THEN
      MAP_EVERY EXISTS_TAC [`b:real`; `c:real`] THEN
      CONJ_TAC THENL [ASM_MESON_TAC[tdiv]; ALL_TAC] THEN
      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
DIVISION_THM]) THEN
      DISCH_THEN(MP_TAC o CONJUNCT2) THEN ASM_REWRITE_TAC[
ADD_CLAUSES] THEN
      GEN_REWRITE_TAC RAND_CONV [
CONJ_SYM] THEN
      MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
       [ALL_TAC;
        ASM_MESON_TAC[ARITH_RULE `SUC(
PRE n + m) >= m + n /\
                                  SUC(SUC(
PRE n + m)) >= m + n`]] THEN
      DISCH_THEN(fun th -> X_GEN_TAC `k:num` THEN DISCH_TAC THEN
                           MATCH_MP_TAC th) THEN
      UNDISCH_TAC `k < 
PRE n` THEN ARITH_TAC;
      ALL_TAC] THEN
    CONJ_TAC THENL
     [ASM_REWRITE_TAC[fine] THEN X_GEN_TAC `k:num` THEN DISCH_TAC THEN
      FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [fine]) THEN
      DISCH_THEN(MP_TAC o SPEC `k + SUC m`) THEN
      ASM_REWRITE_TAC[
ADD_CLAUSES] THEN ANTS_TAC THENL
       [UNDISCH_TAC `k < 
PRE n` THEN ARITH_TAC; ALL_TAC] THEN
      MATCH_MP_TAC(REAL_ARITH `b <= a ==> x < b ==> x < a`) THEN
      SUBGOAL_THEN `~(p(SUC (k + m)) < b)`
        (fun th -> REWRITE_TAC[th] THEN REAL_ARITH_TAC) THEN
      REWRITE_TAC[
REAL_NOT_LT] THEN
      FIRST_ASSUM(MP_TAC o CONJUNCT1 o SPEC `SUC(k + m)`) THEN
      UNDISCH_TAC `b <= d (SUC m)` THEN
      FIRST_X_ASSUM(MP_TAC o MATCH_MP 
DIVISION_MONO_LE) THEN
      DISCH_THEN(MP_TAC o SPECL [`SUC m`; `k + SUC m`]) THEN
      ANTS_TAC THENL [ARITH_TAC; ALL_TAC] THEN
      REWRITE_TAC[
ADD_CLAUSES] THEN REAL_ARITH_TAC;
      ALL_TAC] THEN
     ASM_REWRITE_TAC[rsum] THEN
     DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
     SUBST1_TAC(ARITH_RULE `m + 1 = 0 + SUC m`) THEN
     REWRITE_TAC[
SUM_REINDEX] THEN
     MATCH_MP_TAC(REAL_ARITH
      `x = y ==> abs(x - i) < e ==> abs(y - i) < e`) THEN
     MATCH_MP_TAC 
SUM_EQ THEN REWRITE_TAC[
ADD_CLAUSES];
     ALL_TAC] THEN
  UNDISCH_TAC
   `!D p. tdiv(b,c) (D,p) /\ fine g2 (D,p)
          ==> abs(rsum(D,p) f - j) < e / &2` THEN
  DISCH_THEN(MP_TAC o SPEC `\i. if i = 0 then b:real else d(i + m)`) THEN
  DISCH_THEN(MP_TAC o SPEC `\i. if i = 0 then b:real else p(i + m)`) THEN
  MATCH_MP_TAC(TAUT `a /\ (a ==> b /\ (b /\ c ==> d))
                     ==> (a /\ b ==> c) ==> d`) THEN
  CONJ_TAC THENL
   [ASM_REWRITE_TAC[tdiv; division; 
ADD_CLAUSES] THEN CONJ_TAC THENL
     [ALL_TAC;
      GEN_TAC THEN REWRITE_TAC[
NOT_SUC] THEN
      COND_CASES_TAC THEN ASM_REWRITE_TAC[
REAL_LE_REFL] THEN
      FIRST_X_ASSUM(MP_TAC o CONJUNCT2 o SPEC `m:num`) THEN
      ASM_REWRITE_TAC[
ADD_CLAUSES]] THEN
    EXISTS_TAC `n:num` THEN REWRITE_TAC[
NOT_SUC] THEN
    FIRST_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
DIVISION_THM]) THEN
    DISCH_THEN(MP_TAC o CONJUNCT2) THEN MATCH_MP_TAC MONO_AND THEN
    ASM_REWRITE_TAC[] THEN CONJ_TAC THEN DISCH_THEN(fun th ->
      X_GEN_TAC `k:num` THEN MP_TAC(SPEC `k + m:num` th))
    THENL [ALL_TAC; UNDISCH_TAC `~(n = 0)` THEN ARITH_TAC] THEN
    ASM_CASES_TAC `k:num < n` THEN
    ASM_REWRITE_TAC[ARITH_RULE `k + m:num < m + n <=> k < n`] THEN
    COND_CASES_TAC THEN ASM_REWRITE_TAC[
ADD_CLAUSES] THEN
    ASM_REWRITE_TAC[
REAL_LT_LE];
    DISCH_TAC] THEN
  SUBGOAL_THEN `dsize(\i. if i = 0 then b else d (i + m)) = n` ASSUME_TAC
  THENL
   [MATCH_MP_TAC 
DIVISION_DSIZE_EQ_ALT THEN
    MAP_EVERY EXISTS_TAC [`b:real`; `c:real`] THEN
    CONJ_TAC THENL [ASM_MESON_TAC[tdiv]; ALL_TAC] THEN
    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
DIVISION_THM]) THEN
    DISCH_THEN(MP_TAC o CONJUNCT2) THEN ASM_REWRITE_TAC[
ADD_CLAUSES] THEN
    GEN_REWRITE_TAC RAND_CONV [
CONJ_SYM] THEN REWRITE_TAC[
NOT_SUC] THEN
    MATCH_MP_TAC MONO_AND THEN CONJ_TAC THENL
     [ALL_TAC; MESON_TAC[
GE; 
ADD_SYM; 
LE_REFL; 
LE]] THEN
    DISCH_THEN(fun th ->
      X_GEN_TAC `k:num` THEN MP_TAC(SPEC `k + m:num` th)) THEN
    ASM_CASES_TAC `k:num < n` THEN
    ASM_REWRITE_TAC[ARITH_RULE `k + m:num < m + n <=> k < n`] THEN
    COND_CASES_TAC THEN ASM_REWRITE_TAC[
ADD_CLAUSES] THEN
    ASM_REWRITE_TAC[
REAL_LT_LE];
    ALL_TAC] THEN
  CONJ_TAC THENL
   [ASM_REWRITE_TAC[fine] THEN X_GEN_TAC `k:num` THEN DISCH_TAC THEN
    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [fine]) THEN
    DISCH_THEN(MP_TAC o SPEC `k + m:num`) THEN
    ASM_REWRITE_TAC[
ADD_CLAUSES; 
NOT_SUC;
                    ARITH_RULE `k + m < m + n <=> k:num < n`] THEN
    ASM_CASES_TAC `k = 0` THEN ASM_REWRITE_TAC[] THENL
     [ASM_REWRITE_TAC[
ADD_CLAUSES; 
REAL_LT_REFL] THEN
      MAP_EVERY UNDISCH_TAC [`(d:num->real) m <= b`; `b <= d (SUC m)`] THEN
      REAL_ARITH_TAC;
      ALL_TAC] THEN
    MATCH_MP_TAC(REAL_ARITH `b <= a ==> x < b ==> x < a`) THEN
    SUBGOAL_THEN `~((p:num->real) (k + m) < b)`
     (fun th -> REWRITE_TAC[th] THEN REAL_ARITH_TAC) THEN
    REWRITE_TAC[
REAL_NOT_LT] THEN
    MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `d(SUC m):real` THEN
    ASM_REWRITE_TAC[] THEN
    MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `(d:num->real)(k + m)` THEN
    ASM_REWRITE_TAC[] THEN
    FIRST_X_ASSUM(MP_TAC o MATCH_MP 
DIVISION_MONO_LE) THEN
    DISCH_THEN MATCH_MP_TAC THEN UNDISCH_TAC `~(k = 0)` THEN ARITH_TAC;
    ALL_TAC] THEN
  ASM_REWRITE_TAC[rsum] THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC) THEN
  MATCH_MP_TAC(REAL_ARITH
   `x = y ==> abs(x - i) < e ==> abs(y - i) < e`) THEN
  SUBGOAL_THEN `n = 1 + 
PRE n`
   (fun th -> GEN_REWRITE_TAC (LAND_CONV o LAND_CONV o RAND_CONV) [th])
  THENL [UNDISCH_TAC `~(n = 0)` THEN ARITH_TAC; ALL_TAC] THEN
  REWRITE_TAC[GSYM 
SUM_SPLIT; 
SUM_1; 
NOT_SUC; 
ADD_CLAUSES] THEN
  MATCH_MP_TAC(REAL_ARITH `a = b ==> x + a = b + x`) THEN
  SUBST1_TAC(ARITH_RULE `1 = 0 + 1`) THEN
  SUBST1_TAC(ARITH_RULE `m + 0 + 1 = 0 + m + 1`) THEN
  ONCE_REWRITE_TAC[
SUM_REINDEX] THEN MATCH_MP_TAC 
SUM_EQ THEN
  REWRITE_TAC[
ADD_CLAUSES; 
ADD_EQ_0; ARITH] THEN REWRITE_TAC[
ADD_AC]);;
 
let DEFINT_DELTA_LEFT = prove
 (`!a b. defint(a,b) (\x. if x = a then &1 else &0) (&0)`,
  REPEAT GEN_TAC THEN DISJ_CASES_TAC(REAL_ARITH `b < a \/ a <= b`) THEN
  ASM_SIMP_TAC[
DEFINT_WRONG] THEN REWRITE_TAC[defint] THEN
  X_GEN_TAC `e:real` THEN DISCH_TAC THEN EXISTS_TAC `(\x. e):real->real` THEN
  ASM_SIMP_TAC[
REAL_LT_DIV; 
REAL_OF_NUM_LT; ARITH;
               gauge; fine; rsum; tdiv; 
REAL_SUB_RZERO] THEN
  MAP_EVERY X_GEN_TAC [`d:num->real`; `p:num->real`] THEN STRIP_TAC THEN
  ASM_CASES_TAC `dsize d = 0` THEN ASM_REWRITE_TAC[sum; 
REAL_ABS_NUM] THEN
  FIRST_ASSUM(SUBST1_TAC o MATCH_MP
   (ARITH_RULE `~(n = 0) ==> n = 1 + 
PRE n`)) THEN
  REWRITE_TAC[GSYM 
SUM_SPLIT; 
SUM_1; 
ADD_CLAUSES] THEN
  MATCH_MP_TAC(REAL_ARITH
   `(&0 <= x /\ x < e) /\ y = &0 ==> abs(x + y) < e`) THEN
  CONJ_TAC THENL
   [COND_CASES_TAC THEN ASM_REWRITE_TAC[
REAL_MUL_LZERO; 
REAL_LE_REFL] THEN
    REWRITE_TAC[REAL_MUL_LID; 
REAL_SUB_LE] THEN
    ASM_MESON_TAC[
DIVISION_THM; 
LE_0; 
LT_NZ];
    ALL_TAC] THEN
  MATCH_MP_TAC 
SUM_EQ_0 THEN X_GEN_TAC `r:num` THEN
  STRIP_TAC THEN REWRITE_TAC[] THEN
  COND_CASES_TAC THEN REWRITE_TAC[
REAL_MUL_LZERO] THEN
  FIRST_ASSUM(MP_TAC o SPECL [`1`; `r:num`] o MATCH_MP 
DIVISION_MONO_LE) THEN
  ASM_REWRITE_TAC[] THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [
DIVISION_THM]) THEN
  DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC (MP_TAC o CONJUNCT1)) THEN
  DISCH_THEN(MP_TAC o SPEC `0`) THEN ASM_REWRITE_TAC[ARITH; 
LT_NZ] THEN
  FIRST_X_ASSUM(MP_TAC o CONJUNCT1 o SPEC `r:num`) THEN
  ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
 
let DEFINT_DELTA_RIGHT = prove
 (`!a b. defint(a,b) (\x. if x = b then &1 else &0) (&0)`,
  REPEAT GEN_TAC THEN DISJ_CASES_TAC(REAL_ARITH `b < a \/ a <= b`) THEN
  ASM_SIMP_TAC[
DEFINT_WRONG] THEN REWRITE_TAC[defint] THEN
  X_GEN_TAC `e:real` THEN DISCH_TAC THEN EXISTS_TAC `(\x. e):real->real` THEN
  ASM_SIMP_TAC[
REAL_LT_DIV; 
REAL_OF_NUM_LT; ARITH;
               gauge; fine; rsum; tdiv; 
REAL_SUB_RZERO] THEN
  MAP_EVERY X_GEN_TAC [`d:num->real`; `p:num->real`] THEN STRIP_TAC THEN
  ASM_CASES_TAC `dsize d = 0` THEN ASM_REWRITE_TAC[sum; 
REAL_ABS_NUM] THEN
  FIRST_ASSUM(ASSUME_TAC o MATCH_MP
   (ARITH_RULE `~(n = 0) ==> n = 
PRE n + 1`)) THEN
  ABBREV_TAC `m = 
PRE(dsize d)` THEN
  ASM_REWRITE_TAC[GSYM 
SUM_SPLIT; 
SUM_1; 
ADD_CLAUSES] THEN
  MATCH_MP_TAC(REAL_ARITH
   `(&0 <= x /\ x < e) /\ y = &0 ==> abs(y + x) < e`) THEN
  CONJ_TAC THENL
   [COND_CASES_TAC THEN ASM_REWRITE_TAC[
REAL_MUL_LZERO; 
REAL_LE_REFL] THEN
    REWRITE_TAC[REAL_MUL_LID; 
REAL_SUB_LE] THEN
    ASM_MESON_TAC[
DIVISION_THM; ARITH_RULE `m < m + 1`; 
REAL_LT_IMP_LE];
    ALL_TAC] THEN
  MATCH_MP_TAC 
SUM_EQ_0 THEN X_GEN_TAC `r:num` THEN
  REWRITE_TAC[
ADD_CLAUSES] THEN STRIP_TAC THEN
  COND_CASES_TAC THEN REWRITE_TAC[
REAL_MUL_LZERO] THEN
  FIRST_X_ASSUM(MP_TAC o CONJUNCT2 o SPEC `r:num`) THEN
  FIRST_ASSUM(MP_TAC o SPECL [`SUC r`; `m:num`] o
    MATCH_MP 
DIVISION_MONO_LE) THEN
  ASM_REWRITE_TAC[
LE_SUC_LT] THEN
  FIRST_X_ASSUM(MP_TAC o CONJUNCT2 o GEN_REWRITE_RULE I [
DIVISION_THM]) THEN
  DISCH_THEN(CONJUNCTS_THEN2
   (MP_TAC o SPEC `m:num`) (MP_TAC o SPEC `m + 1`)) THEN
  ASM_REWRITE_TAC[
GE; 
LE_REFL; ARITH_RULE `x < x + 1`] THEN
  REWRITE_TAC[
ADD1] THEN REAL_ARITH_TAC);;
 
let DEFINT_POINT_SPIKE = prove
 (`!f g a b c i.
        (!x. a <= x /\ x <= b /\ ~(x = c) ==> (f x = g x)) /\ defint(a,b) f i
        ==> defint(a,b) g i`,
  REPEAT STRIP_TAC THEN ASM_CASES_TAC `a <= b` THENL
   [ALL_TAC; ASM_MESON_TAC[
REAL_NOT_LE; 
DEFINT_WRONG]] THEN
  MATCH_MP_TAC 
INTEGRAL_EQ THEN
  EXISTS_TAC `\x:real. f(x) + (g c - f c) * (if x = c then &1 else &0)` THEN
  ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
   [SUBST1_TAC(REAL_ARITH `i = i + ((g:real->real) c - f c) * &0`) THEN
    MATCH_MP_TAC 
DEFINT_ADD THEN ASM_REWRITE_TAC[] THEN
    MATCH_MP_TAC 
DEFINT_CMUL THEN REWRITE_TAC[
DEFINT_DELTA];
    REPEAT GEN_TAC THEN COND_CASES_TAC THEN
    ASM_SIMP_TAC[
REAL_MUL_RZERO; 
REAL_ADD_RID] THEN
    REAL_ARITH_TAC]);;
 
let DEFINT_FINITE_SPIKE = prove
 (`!f g a b s i.
        
FINITE s /\
        (!x. a <= x /\ x <= b /\ ~(x 
IN s) ==> (f x = g x)) /\
        defint(a,b) f i
        ==> defint(a,b) g i`,
  REPEAT GEN_TAC THEN
  REWRITE_TAC[TAUT `a /\ b /\ c ==> d <=> c ==> a ==> b ==> d`] THEN
  DISCH_TAC THEN MAP_EVERY (fun t -> SPEC_TAC(t,t))
   [`g:real->real`; `s:real->bool`] THEN
  REWRITE_TAC[
RIGHT_FORALL_IMP_THM] THEN MATCH_MP_TAC 
FINITE_INDUCT_STRONG THEN
  REWRITE_TAC[
NOT_IN_EMPTY] THEN
  CONJ_TAC THENL [ASM_MESON_TAC[
INTEGRAL_EQ]; ALL_TAC] THEN
  MAP_EVERY X_GEN_TAC [`c:real`; `s:real->bool`] THEN STRIP_TAC THEN
  X_GEN_TAC `g:real->real` THEN REWRITE_TAC[
IN_INSERT; DE_MORGAN_THM] THEN
  DISCH_TAC THEN MATCH_MP_TAC 
DEFINT_POINT_SPIKE THEN
  EXISTS_TAC `\x. if x = c then (f:real->real) x else g x` THEN
  EXISTS_TAC `c:real` THEN SIMP_TAC[] THEN
  FIRST_X_ASSUM MATCH_MP_TAC THEN ASM_MESON_TAC[]);;
 
let GAUGE_MIN_FINITE = prove
 (`!s gs n. (!m:num. m <= n ==> gauge s (gs m))
            ==> ?g. gauge s g /\
                    !d p. fine g (d,p) ==> !m. m <= n ==> fine (gs m) (d,p)`,
  GEN_TAC THEN GEN_TAC THEN INDUCT_TAC THEN REWRITE_TAC[
LE] THENL
   [MESON_TAC[]; ALL_TAC] THEN
  REWRITE_TAC[TAUT `a \/ b ==> c <=> (a ==> c) /\ (b ==> c)`] THEN
  SIMP_TAC[
FORALL_AND_THM; 
LEFT_FORALL_IMP_THM; 
EXISTS_REFL] THEN
  STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o check (is_imp o concl)) THEN
  ASM_REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_THEN `gm:real->real` STRIP_ASSUME_TAC) THEN
  EXISTS_TAC `\x:real. if gm x < gs(SUC n) x then gm x else gs(SUC n) x` THEN
  ASM_SIMP_TAC[
GAUGE_MIN; ETA_AX] THEN REPEAT GEN_TAC THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
FINE_MIN) THEN ASM_SIMP_TAC[ETA_AX]);;
 
let INTEGRABLE_CAUCHY = prove
 (`!f a b. integrable(a,b) f <=>
           !e. &0 < e
               ==> ?g. gauge (\x. a <= x /\ x <= b) g /\
                       !d1 p1 d2 p2.
                            tdiv (a,b) (d1,p1) /\ fine g (d1,p1) /\
                            tdiv (a,b) (d2,p2) /\ fine g (d2,p2)
                            ==> abs (rsum(d1,p1) f - rsum(d2,p2) f) < e`,
  REPEAT GEN_TAC THEN REWRITE_TAC[integrable] THEN EQ_TAC THENL
   [REWRITE_TAC[defint] THEN DISCH_THEN(X_CHOOSE_TAC `i:real`) THEN
    X_GEN_TAC `e:real` THEN DISCH_TAC THEN
    FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN
    ASM_SIMP_TAC[
REAL_LT_DIV; 
REAL_OF_NUM_LT; ARITH] THEN
    MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `g:real->real` THEN
    STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
    MAP_EVERY X_GEN_TAC
     [`d1:num->real`; `p1:num->real`; `d2:num->real`; `p2:num->real`] THEN
    STRIP_TAC THEN FIRST_X_ASSUM(fun th ->
      MP_TAC(SPECL [`d1:num->real`; `p1:num->real`] th) THEN
      MP_TAC(SPECL [`d2:num->real`; `p2:num->real`] th)) THEN
    ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC;
    ALL_TAC] THEN
  DISCH_TAC THEN DISJ_CASES_TAC(REAL_ARITH `b < a \/ a <= b`) THENL
   [ASM_MESON_TAC[
DEFINT_WRONG]; ALL_TAC] THEN
  FIRST_X_ASSUM(MP_TAC o GEN `n:num` o SPEC `&1 / &2 pow n`) THEN
  SIMP_TAC[
REAL_LT_DIV; 
REAL_POW_LT; 
REAL_OF_NUM_LT; ARITH] THEN
  REWRITE_TAC[
FORALL_AND_THM; 
SKOLEM_THM] THEN
  DISCH_THEN(X_CHOOSE_THEN `g:num->real->real` STRIP_ASSUME_TAC) THEN
  MP_TAC(GEN `n:num`
   (SPECL [`\x. a <= x /\ x <= b`; `g:num->real->real`; `n:num`]
          
GAUGE_MIN_FINITE)) THEN
  ASM_REWRITE_TAC[
SKOLEM_THM; 
FORALL_AND_THM] THEN
  DISCH_THEN(X_CHOOSE_THEN `G:num->real->real` STRIP_ASSUME_TAC) THEN
  MP_TAC(GEN `n:num`
    (SPECL [`a:real`; `b:real`; `(G:num->real->real) n`] 
DIVISION_EXISTS)) THEN
  ASM_REWRITE_TAC[
SKOLEM_THM; 
LEFT_IMP_EXISTS_THM; 
FORALL_AND_THM] THEN
  MAP_EVERY X_GEN_TAC [`d:num->num->real`; `p:num->num->real`] THEN
  STRIP_TAC THEN SUBGOAL_THEN `cauchy (\n. rsum(d n,p n) f)` MP_TAC THENL
   [REWRITE_TAC[cauchy] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
    MP_TAC(SPEC `&1 / e` 
REAL_ARCH_POW2) THEN MATCH_MP_TAC 
MONO_EXISTS THEN
    X_GEN_TAC `N:num` THEN ASM_SIMP_TAC[
REAL_LT_LDIV_EQ] THEN DISCH_TAC THEN
    REWRITE_TAC[
GE] THEN MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN
    STRIP_TAC THEN FIRST_X_ASSUM(MP_TAC o SPECL
     [`N:num`; `(d:num->num->real) m`; `(p:num->num->real) m`;
      `(d:num->num->real) n`; `(p:num->num->real) n`]) THEN
    ANTS_TAC THENL [ASM_MESON_TAC[]; ALL_TAC] THEN
    MATCH_MP_TAC(REAL_ARITH `d < e ==> x < d ==> x < e`) THEN
    ASM_SIMP_TAC[
REAL_LT_LDIV_EQ; 
REAL_POW_LT; 
REAL_OF_NUM_LT; ARITH] THEN
    ASM_MESON_TAC[REAL_MUL_SYM];
    ALL_TAC] THEN
  REWRITE_TAC[
SEQ_CAUCHY; convergent; 
SEQ; defint] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `i:real` THEN STRIP_TAC THEN
  X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN
  ASM_SIMP_TAC[
REAL_LT_DIV; 
REAL_OF_NUM_LT; ARITH] THEN
  DISCH_THEN(X_CHOOSE_THEN `N1:num` MP_TAC) THEN
  X_CHOOSE_TAC `N2:num` (SPEC `&2 / e` 
REAL_ARCH_POW2) THEN
  DISCH_THEN(MP_TAC o SPEC `N1 + N2:num`) THEN REWRITE_TAC[
GE; 
LE_ADD] THEN
  DISCH_TAC THEN EXISTS_TAC `(G:num->real->real)(N1 + N2)` THEN
  ASM_REWRITE_TAC[] THEN
  MAP_EVERY X_GEN_TAC [`dx:num->real`; `px:num->real`] THEN STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPECL
   [`N1 + N2:num`; `dx:num->real`; `px:num->real`;
    `(d:num->num->real)(N1 + N2)`; `(p:num->num->real)(N1 + N2)`]) THEN
  ANTS_TAC THENL [ASM_MESON_TAC[
LE_REFL]; ALL_TAC] THEN
  FIRST_X_ASSUM(MATCH_MP_TAC o MATCH_MP (REAL_ARITH
   `abs(s1 - i) < e / &2
    ==> d < e / &2
        ==> abs(s2 - s1) < d ==> abs(s2 - i) < e`)) THEN
  REWRITE_TAC[
real_div; REAL_MUL_LID] THEN REWRITE_TAC[GSYM 
real_div] THEN
  GEN_REWRITE_TAC RAND_CONV [GSYM 
REAL_INV_DIV] THEN
  MATCH_MP_TAC 
REAL_LT_INV2 THEN
  ASM_SIMP_TAC[
REAL_LT_DIV; 
REAL_OF_NUM_LT; ARITH] THEN
  MATCH_MP_TAC 
REAL_LTE_TRANS THEN EXISTS_TAC `&2 pow N2` THEN
  ASM_REWRITE_TAC[] THEN MATCH_MP_TAC 
REAL_POW_MONO THEN
  REWRITE_TAC[REAL_OF_NUM_LE] THEN ARITH_TAC);;
 
let RSUM_BOUND = prove
 (`!a b d p e f.
        tdiv(a,b) (d,p) /\
        (!x. a <= x /\ x <= b ==> abs(f x) <= e)
        ==> abs(rsum(d,p) f) <= e * (b - a)`,
 
let RSUM_DIFF_BOUND = prove
 (`!a b d p e f g.
        tdiv(a,b) (d,p) /\
        (!x. a <= x /\ x <= b ==> abs(f x - g x) <= e)
        ==> abs(rsum (d,p) f - rsum (d,p) g) <= e * (b - a)`,
 
let INTEGRABLE_LIMIT = prove
 (`!f a b. (!e. &0 < e
                ==> ?g. (!x. a <= x /\ x <= b ==> abs(f x - g x) <= e) /\
                        integrable(a,b) g)
           ==> integrable(a,b) f`,
  REPEAT STRIP_TAC THEN ASM_CASES_TAC `a <= b` THENL
   [ALL_TAC; ASM_MESON_TAC[
REAL_NOT_LE; 
DEFINT_WRONG; integrable]] THEN
  FIRST_X_ASSUM(MP_TAC o GEN `n:num` o SPEC `&1 / &2 pow n`) THEN
  SIMP_TAC[
REAL_LT_DIV; 
REAL_POW_LT; 
REAL_OF_NUM_LT; ARITH] THEN
  REWRITE_TAC[
FORALL_AND_THM; 
SKOLEM_THM; integrable] THEN
  DISCH_THEN(X_CHOOSE_THEN `g:num->real->real` (CONJUNCTS_THEN2
   ASSUME_TAC (X_CHOOSE_TAC `i:num->real`))) THEN
  SUBGOAL_THEN `cauchy i` MP_TAC THENL
   [REWRITE_TAC[cauchy] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
    MP_TAC(SPEC `(&4 * (b - a)) / e` 
REAL_ARCH_POW2) THEN
    MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `N:num` THEN DISCH_TAC THEN
    MAP_EVERY X_GEN_TAC [`m:num`; `n:num`] THEN REWRITE_TAC[
GE] THEN
    STRIP_TAC THEN
    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE BINDER_CONV [defint]) THEN
    ONCE_REWRITE_TAC[
SWAP_FORALL_THM] THEN
    DISCH_THEN(MP_TAC o SPEC `e / &4`) THEN
    ASM_SIMP_TAC[
REAL_LT_DIV; 
REAL_OF_NUM_LT; ARITH] THEN
    DISCH_THEN(fun th -> MP_TAC(SPEC `m:num` th) THEN
      MP_TAC(SPEC `n:num` th)) THEN
    DISCH_THEN(X_CHOOSE_THEN `gn:real->real` STRIP_ASSUME_TAC) THEN
    DISCH_THEN(X_CHOOSE_THEN `gm:real->real` STRIP_ASSUME_TAC) THEN
    MP_TAC(SPECL [`a:real`; `b:real`;
                  `\x:real. if gm x < gn x then gm x else gn x`]
                 
DIVISION_EXISTS) THEN
    ASM_SIMP_TAC[
GAUGE_MIN; 
LEFT_IMP_EXISTS_THM] THEN
    MAP_EVERY X_GEN_TAC [`d:num->real`; `p:num->real`] THEN
    STRIP_TAC THEN
    FIRST_X_ASSUM(CONJUNCTS_THEN ASSUME_TAC o MATCH_MP 
FINE_MIN) THEN
    REPEAT(FIRST_X_ASSUM(MP_TAC o SPECL [`d:num->real`; `p:num->real`])) THEN
    ASM_REWRITE_TAC[] THEN
    SUBGOAL_THEN `abs(rsum(d,p) (g(m:num)) - rsum(d,p) (g n)) <= e / &2`
     (fun th -> MP_TAC th THEN REAL_ARITH_TAC) THEN
    MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `&2 / &2 pow N * (b - a)` THEN
    CONJ_TAC THENL
     [MATCH_MP_TAC 
RSUM_DIFF_BOUND THEN ASM_REWRITE_TAC[] THEN
      REPEAT STRIP_TAC THEN MATCH_MP_TAC(REAL_ARITH
       `!f. abs(f - gm) <= inv(k) /\ abs(f - gn) <= inv(k)
            ==> abs(gm - gn) <= &2 / k`) THEN
      EXISTS_TAC `(f:real->real) x` THEN CONJ_TAC THEN
      MATCH_MP_TAC 
REAL_LE_TRANS THENL
       [EXISTS_TAC `&1 / &2 pow m`; EXISTS_TAC `&1 / &2 pow n`] THEN
      ASM_SIMP_TAC[] THEN REWRITE_TAC[
real_div; REAL_MUL_LID] THEN
      MATCH_MP_TAC 
REAL_LE_INV2 THEN
      ASM_SIMP_TAC[
REAL_POW_LT; 
REAL_POW_MONO; REAL_OF_NUM_LE;
                   
REAL_OF_NUM_LT; ARITH];
      ALL_TAC] THEN
    REWRITE_TAC[REAL_ARITH `&2 / n * x <= e / &2 <=> (&4 * x) / n <= e`] THEN
    SIMP_TAC[
REAL_LE_LDIV_EQ; 
REAL_POW_LT; 
REAL_OF_NUM_LT; ARITH] THEN
    GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
    ASM_SIMP_TAC[GSYM 
REAL_LE_LDIV_EQ; 
REAL_LT_IMP_LE];
    ALL_TAC] THEN
  REWRITE_TAC[
SEQ_CAUCHY; convergent] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `s:real` THEN DISCH_TAC THEN
  REWRITE_TAC[defint] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `e / &3` o GEN_REWRITE_RULE I [
SEQ]) THEN
  ASM_SIMP_TAC[
REAL_LT_DIV; 
REAL_OF_NUM_LT; ARITH; 
GE] THEN
  DISCH_THEN(X_CHOOSE_TAC `N1:num`) THEN
  MP_TAC(SPEC `(&3 * (b - a)) / e` 
REAL_ARCH_POW2) THEN
  DISCH_THEN(X_CHOOSE_TAC `N2:num`) THEN
  FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE BINDER_CONV [defint]) THEN
  DISCH_THEN(MP_TAC o SPECL [`N1 + N2:num`; `e / &3`]) THEN
  ASM_SIMP_TAC[
REAL_LT_DIV; 
REAL_OF_NUM_LT; ARITH] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN
  X_GEN_TAC `g:real->real` THEN STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
  MAP_EVERY X_GEN_TAC [`d:num->real`; `p:num->real`] THEN STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPECL [`d:num->real`; `p:num->real`]) THEN
  ASM_REWRITE_TAC[] THEN
  FIRST_X_ASSUM(MP_TAC o C MATCH_MP (ARITH_RULE `N1:num <= N1 + N2`)) THEN
  MATCH_MP_TAC(REAL_ARITH
   `abs(sf - sg) <= e / &3
    ==> abs(i - s) < e / &3 ==> abs(sg - i) < e / &3 ==> abs(sf - s) < e`) THEN
  MATCH_MP_TAC 
REAL_LE_TRANS THEN
  EXISTS_TAC `&1 / &2 pow (N1 + N2) * (b - a)` THEN CONJ_TAC THENL
   [MATCH_MP_TAC 
RSUM_DIFF_BOUND THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
  REWRITE_TAC[REAL_ARITH `&1 / n * x <= e / &3 <=> (&3 * x) / n <= e`] THEN
  SIMP_TAC[
REAL_LE_LDIV_EQ; 
REAL_POW_LT; 
REAL_OF_NUM_LT; ARITH] THEN
  GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
  ASM_SIMP_TAC[GSYM 
REAL_LE_LDIV_EQ; 
REAL_LT_IMP_LE] THEN
  MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `&2 pow N2` THEN
  ASM_SIMP_TAC[
REAL_LT_IMP_LE; 
REAL_POW_MONO; REAL_OF_NUM_LE; ARITH;
               ARITH_RULE `N2 <= N1 + N2:num`]);;
 
let INTEGRABLE_CONTINUOUS = prove
 (`!f a b. (!x. a <= x /\ x <= b ==> f contl x) ==> integrable(a,b) f`,
  REPEAT STRIP_TAC THEN DISJ_CASES_TAC(REAL_ARITH `b < a \/ a <= b`) THENL
   [ASM_MESON_TAC[integrable; 
DEFINT_WRONG]; ALL_TAC] THEN
  MATCH_MP_TAC 
INTEGRABLE_LIMIT THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  MP_TAC(SPECL [`f:real->real`; `a:real`; `b:real`] 
CONT_UNIFORM) THEN
  ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o SPEC `e:real`) THEN
  ASM_REWRITE_TAC[] THEN
  DISCH_THEN(X_CHOOSE_THEN `d:real` (CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
  UNDISCH_TAC `a <= b` THEN MAP_EVERY (fun t -> SPEC_TAC(t,t))
   [`b:real`; `a:real`] THEN
  MATCH_MP_TAC 
BOLZANO_LEMMA_ALT THEN CONJ_TAC THENL
   [MAP_EVERY X_GEN_TAC [`u:real`; `v:real`; `w:real`] THEN
    REPLICATE_TAC 2 (DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
    DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
    MATCH_MP_TAC(TAUT
      `(a /\ b) /\ (c /\ d ==> e) ==> (a ==> c) /\ (b ==> d) ==> e`) THEN
    CONJ_TAC THENL [ASM_MESON_TAC[
REAL_LE_TRANS]; ALL_TAC] THEN
    DISCH_THEN(CONJUNCTS_THEN2 (X_CHOOSE_TAC `g:real->real`)
                               (X_CHOOSE_TAC `h:real->real`)) THEN
    EXISTS_TAC `\x. if x <= v then g(x):real else h(x)` THEN
    REWRITE_TAC[] THEN CONJ_TAC THENL
     [ASM_MESON_TAC[
REAL_LE_TOTAL]; ALL_TAC] THEN
    MATCH_MP_TAC 
INTEGRABLE_COMBINE THEN EXISTS_TAC `v:real` THEN
    ASM_REWRITE_TAC[] THEN CONJ_TAC THEN
    MATCH_MP_TAC 
INTEGRABLE_POINT_SPIKE THENL
     [EXISTS_TAC `g:real->real`; EXISTS_TAC `h:real->real`] THEN
    EXISTS_TAC `v:real` THEN ASM_REWRITE_TAC[] THEN SIMP_TAC[] THEN
    ASM_MESON_TAC[REAL_ARITH `b <= x /\ x <= c /\ ~(x = b) ==> ~(x <= b)`];
    ALL_TAC] THEN
  X_GEN_TAC `x:real` THEN EXISTS_TAC `d:real` THEN ASM_REWRITE_TAC[] THEN
  MAP_EVERY X_GEN_TAC [`u:real`; `v:real`] THEN REPEAT STRIP_TAC THEN
  EXISTS_TAC `\x:real. (f:real->real) u` THEN
  ASM_REWRITE_TAC[
INTEGRABLE_CONST] THEN
  REPEAT STRIP_TAC THEN MATCH_MP_TAC 
REAL_LT_IMP_LE THEN
  FIRST_X_ASSUM MATCH_MP_TAC THEN
  ASM_REAL_ARITH_TAC);;
 
let INTEGRABLE_SPLIT_SIDES = prove
 (`!f a b c.
        a <= c /\ c <= b /\ integrable(a,b) f
        ==> ?i. !e. &0 < e
                    ==> ?g. gauge(\x. a <= x /\ x <= b) g /\
                            !d1 p1 d2 p2. tdiv(a,c) (d1,p1) /\
                                          fine g (d1,p1) /\
                                          tdiv(c,b) (d2,p2) /\
                                          fine g (d2,p2)
                                          ==> abs((rsum(d1,p1) f +
                                                   rsum(d2,p2) f) - i) < e`,
  REPEAT GEN_TAC THEN REWRITE_TAC[integrable; defint] THEN
  REPEAT(DISCH_THEN(CONJUNCTS_THEN2 ASSUME_TAC MP_TAC)) THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `i:real` THEN
  MATCH_MP_TAC 
MONO_FORALL THEN X_GEN_TAC `e:real` THEN
  ASM_CASES_TAC `&0 < e` THEN ASM_REWRITE_TAC[] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `g:real->real` THEN
  ASM_MESON_TAC[
DIVISION_APPEND_STRONG]);;
 
let INTEGRABLE_SUBINTERVAL_LEFT = prove
 (`!f a b c. a <= c /\ c <= b /\ integrable(a,b) f ==> integrable(a,c) f`,
  REPEAT GEN_TAC THEN DISCH_TAC THEN
  FIRST_ASSUM(X_CHOOSE_TAC `i:real` o MATCH_MP 
INTEGRABLE_SPLIT_SIDES) THEN
  REWRITE_TAC[
INTEGRABLE_CAUCHY] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN
  SIMP_TAC[ASSUME `&0 < e`; 
REAL_LT_DIV; 
REAL_OF_NUM_LT; ARITH] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `g:real->real` THEN
  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
  CONJ_TAC THENL
   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [gauge]) THEN
    REWRITE_TAC[gauge] THEN ASM_MESON_TAC[
REAL_LE_TRANS];
    ALL_TAC] THEN
  REPEAT STRIP_TAC THEN
  MP_TAC(SPECL [`c:real`; `b:real`; `g:real->real`] 
DIVISION_EXISTS) THEN
  ANTS_TAC THENL
   [ASM_REWRITE_TAC[] THEN
    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [gauge]) THEN
    REWRITE_TAC[gauge] THEN ASM_MESON_TAC[
REAL_LE_TRANS];
    ALL_TAC] THEN
  REWRITE_TAC[
LEFT_IMP_EXISTS_THM] THEN
  MAP_EVERY X_GEN_TAC [`d:num->real`; `p:num->real`] THEN STRIP_TAC THEN
  FIRST_X_ASSUM(fun th ->
   MP_TAC(SPECL [`d1:num->real`; `p1:num->real`] th) THEN
   MP_TAC(SPECL [`d2:num->real`; `p2:num->real`] th)) THEN
  REWRITE_TAC[IMP_IMP; 
AND_FORALL_THM] THEN
  DISCH_THEN(MP_TAC o SPECL [`d:num->real`; `p:num->real`]) THEN
  ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
 
let INTEGRABLE_SUBINTERVAL_RIGHT = prove
 (`!f a b c. a <= c /\ c <= b /\ integrable(a,b) f ==> integrable(c,b) f`,
  REPEAT GEN_TAC THEN DISCH_TAC THEN
  FIRST_ASSUM(X_CHOOSE_TAC `i:real` o MATCH_MP 
INTEGRABLE_SPLIT_SIDES) THEN
  REWRITE_TAC[
INTEGRABLE_CAUCHY] THEN X_GEN_TAC `e:real` THEN DISCH_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPEC `e / &2`) THEN
  SIMP_TAC[ASSUME `&0 < e`; 
REAL_LT_DIV; 
REAL_OF_NUM_LT; ARITH] THEN
  MATCH_MP_TAC 
MONO_EXISTS THEN X_GEN_TAC `g:real->real` THEN
  STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
  CONJ_TAC THENL
   [FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [gauge]) THEN
    REWRITE_TAC[gauge] THEN ASM_MESON_TAC[
REAL_LE_TRANS];
    ALL_TAC] THEN
  REPEAT STRIP_TAC THEN
  MP_TAC(SPECL [`a:real`; `c:real`; `g:real->real`] 
DIVISION_EXISTS) THEN
  ANTS_TAC THENL
   [ASM_REWRITE_TAC[] THEN
    FIRST_X_ASSUM(MP_TAC o GEN_REWRITE_RULE I [gauge]) THEN
    REWRITE_TAC[gauge] THEN ASM_MESON_TAC[
REAL_LE_TRANS];
    ALL_TAC] THEN
  REWRITE_TAC[
LEFT_IMP_EXISTS_THM] THEN
  MAP_EVERY X_GEN_TAC [`d:num->real`; `p:num->real`] THEN STRIP_TAC THEN
  FIRST_X_ASSUM(MP_TAC o SPECL [`d:num->real`; `p:num->real`]) THEN
  DISCH_THEN(fun th ->
   MP_TAC(SPECL [`d1:num->real`; `p1:num->real`] th) THEN
   MP_TAC(SPECL [`d2:num->real`; `p2:num->real`] th)) THEN
  ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
 
let pth = prove
   (`(!x. f contl x) ==> integrable(a,b) f`,
    MESON_TAC[
INTEGRABLE_CONTINUOUS]) in
  let match_pth = PART_MATCH rand pth
  and forsimp = GEN_REWRITE_RULE LAND_CONV [
FORALL_SIMP] in
  fun tm ->
    let th1 = match_pth tm in
    let th2 = CONV_RULE (LAND_CONV(BINDER_CONV CONTINUOUS_CONV)) th1 in
    MP (forsimp th2) TRUTH;;
 
let INTEGRAL_CMUL = prove
 (`!f c a b. a <= b /\ integrable(a,b) f
             ==> integral(a,b) (\x. c * f(x)) = c * integral(a,b) f`,
 
let INTEGRAL_ADD = prove
 (`!f g a b. a <= b /\ integrable(a,b) f /\ integrable(a,b) g
             ==> integral(a,b) (\x. f(x) + g(x)) =
                 integral(a,b) f + integral(a,b) g`,
 
let INTEGRAL_SUB = prove
 (`!f g a b. a <= b /\ integrable(a,b) f /\ integrable(a,b) g
             ==> integral(a,b) (\x. f(x) - g(x)) =
                 integral(a,b) f - integral(a,b) g`,
 
let INTEGRAL_BY_PARTS = prove
 (`!f g f' g' a b.
         a <= b /\
         (!x. a <= x /\ x <= b ==> (f diffl f' x) x) /\
         (!x. a <= x /\ x <= b ==> (g diffl g' x) x) /\
         integrable(a,b) (\x. f' x * g x) /\
         integrable(a,b) (\x. f x * g' x)
         ==> integral(a,b) (\x. f x * g' x) =
             (f b * g b - f a * g a) - integral(a,b) (\x. f' x * g x)`,
  MP_TAC 
INTEGRATION_BY_PARTS THEN
  REPEAT(MATCH_MP_TAC 
MONO_FORALL THEN GEN_TAC) THEN
  DISCH_THEN(fun th -> STRIP_TAC THEN MP_TAC th) THEN
  ASM_REWRITE_TAC[] THEN DISCH_THEN(MP_TAC o CONJ (ASSUME `a <= b`)) THEN
  DISCH_THEN(SUBST1_TAC o SYM o MATCH_MP 
DEFINT_INTEGRAL) THEN
  ASM_SIMP_TAC[
INTEGRAL_ADD] THEN REAL_ARITH_TAC);;
 
let MCLAURIN = prove(
  `!f diff h n.
    &0 < h /\
    0 < n /\
    (diff(0) = f) /\
    (!m t. m < n /\ &0 <= t /\ t <= h ==>
           (diff(m) diffl diff(SUC m)(t))(t)) ==>
   (?t. &0 < t /\ t < h /\
        (f(h) = sum(0,n)(\m. (diff(m)(&0) / &(
FACT m)) * (h pow m)) +
                ((diff(n)(t) / &(
FACT n)) * (h pow n))))`,
  REPEAT GEN_TAC THEN STRIP_TAC THEN
  UNDISCH_TAC `0 < n` THEN
  DISJ_CASES_THEN2 SUBST_ALL_TAC (X_CHOOSE_THEN `r:num` MP_TAC)
   (SPEC `n:num` 
num_CASES) THEN REWRITE_TAC[
LT_REFL] THEN
  DISCH_THEN(ASSUME_TAC o SYM) THEN DISCH_THEN(K ALL_TAC) THEN
  SUBGOAL_THEN `?B. f(h) = sum(0,n)(\m. (diff(m)(&0) / &(
FACT m)) * (h pow m))
                  + (B * ((h pow n) / &(
FACT n)))` MP_TAC THENL
   [ONCE_REWRITE_TAC[REAL_ADD_SYM] THEN
    ONCE_REWRITE_TAC[GSYM 
REAL_EQ_SUB_RADD] THEN
    EXISTS_TAC `(f(h) - sum(0,n)(\m. (diff(m)(&0) / &(
FACT m)) * (h pow m)))
        * &(
FACT n) / (h pow n)` THEN REWRITE_TAC[
real_div] THEN
    REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN
    GEN_REWRITE_TAC (RATOR_CONV o RAND_CONV) [GSYM 
REAL_MUL_RID] THEN
    AP_TERM_TAC THEN CONV_TAC SYM_CONV THEN
    ONCE_REWRITE_TAC[AC 
REAL_MUL_AC
      `a * b * c * d = (d * a) * (b * c)`] THEN
    GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN BINOP_TAC THEN
    MATCH_MP_TAC REAL_MUL_LINV THENL
     [MATCH_MP_TAC 
REAL_POS_NZ THEN REWRITE_TAC[
REAL_LT; 
FACT_LT];
      MATCH_MP_TAC 
POW_NZ THEN MATCH_MP_TAC 
REAL_POS_NZ THEN
      ASM_REWRITE_TAC[]]; ALL_TAC] THEN
  DISCH_THEN(X_CHOOSE_THEN `B:real` (ASSUME_TAC o SYM)) THEN
  ABBREV_TAC `g = \t. f(t) -
                      (sum(0,n)(\m. (diff(m)(&0) / &(
FACT m)) * (t pow m)) +
                       (B * ((t pow n) / &(
FACT n))))` THEN
  SUBGOAL_THEN `(g(&0) = &0) /\ (g(h) = &0)` ASSUME_TAC THENL
   [EXPAND_TAC "g" THEN BETA_TAC THEN ASM_REWRITE_TAC[
REAL_SUB_REFL] THEN
    EXPAND_TAC "n" THEN REWRITE_TAC[
POW_0; 
REAL_DIV_LZERO] THEN
    REWRITE_TAC[
REAL_MUL_RZERO; 
REAL_ADD_RID] THEN REWRITE_TAC[
REAL_SUB_0] THEN
    MP_TAC(GEN `j:num->real`
     (SPECL [`j:num->real`; `r:num`; `1`] 
SUM_OFFSET)) THEN
    REWRITE_TAC[
ADD1; 
REAL_EQ_SUB_LADD] THEN
    DISCH_THEN(fun th -> REWRITE_TAC[GSYM th]) THEN BETA_TAC THEN
    REWRITE_TAC[
SUM_1] THEN BETA_TAC THEN REWRITE_TAC[pow; 
FACT] THEN
    ASM_REWRITE_TAC[
real_div; 
REAL_INV1; 
REAL_MUL_RID] THEN
    CONV_TAC SYM_CONV THEN REWRITE_TAC[
REAL_ADD_LID_UNIQ] THEN
    REWRITE_TAC[GSYM 
ADD1; 
POW_0; 
REAL_MUL_RZERO; 
SUM_0]; ALL_TAC] THEN
  ABBREV_TAC `difg = \m t. diff(m) t -
      (sum(0,n - m)(\p. (diff(m + p)(&0) / &(
FACT p)) * (t pow p))
       + (B * ((t pow (n - m)) / &(
FACT(n - m)))))` THEN
  SUBGOAL_THEN `difg(0):real->real = g` ASSUME_TAC THENL
   [EXPAND_TAC "difg" THEN BETA_TAC THEN EXPAND_TAC "g" THEN
    CONV_TAC FUN_EQ_CONV THEN GEN_TAC THEN BETA_TAC THEN
    ASM_REWRITE_TAC[
ADD_CLAUSES; 
SUB_0]; ALL_TAC] THEN
  SUBGOAL_THEN `(!m t. m < n /\ (& 0) <= t /\ t <= h ==>
                   (difg(m) diffl difg(SUC m)(t))(t))` ASSUME_TAC THENL
   [REPEAT GEN_TAC THEN DISCH_TAC THEN EXPAND_TAC "difg" THEN BETA_TAC THEN
    CONV_TAC((funpow 2 RATOR_CONV o RAND_CONV) HABS_CONV) THEN
    MATCH_MP_TAC 
DIFF_SUB THEN CONJ_TAC THENL
     [CONV_TAC(ONCE_DEPTH_CONV ETA_CONV) THEN
      FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
    CONV_TAC((funpow 2 RATOR_CONV o RAND_CONV) HABS_CONV) THEN
    MATCH_MP_TAC 
DIFF_ADD THEN CONJ_TAC THENL
     [ALL_TAC;
      W(MP_TAC o DIFF_CONV o rand o funpow 2 rator o snd) THEN
      REWRITE_TAC[
REAL_MUL_LZERO; 
REAL_MUL_RID; REAL_ADD_LID] THEN
      REWRITE_TAC[
REAL_FACT_NZ; 
REAL_SUB_RZERO] THEN
      DISCH_THEN(MP_TAC o SPEC `t:real`) THEN
      MATCH_MP_TAC EQ_IMP THEN
      AP_THM_TAC THEN CONV_TAC(ONCE_DEPTH_CONV(ALPHA_CONV `t:real`)) THEN
      AP_TERM_TAC THEN GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
      AP_THM_TAC THEN AP_TERM_TAC THEN REWRITE_TAC[
real_div] THEN
      REWRITE_TAC[GSYM REAL_MUL_ASSOC; 
POW_2] THEN
      ONCE_REWRITE_TAC[AC 
REAL_MUL_AC
        `a * b * c * d = b * (a * (d * c))`] THEN
      FIRST_ASSUM(X_CHOOSE_THEN `d:num` SUBST1_TAC o
        MATCH_MP 
LESS_ADD_1 o CONJUNCT1) THEN
      ONCE_REWRITE_TAC[
ADD_SYM] THEN REWRITE_TAC[
ADD_SUB] THEN
      REWRITE_TAC[GSYM 
ADD_ASSOC] THEN
      REWRITE_TAC[ONCE_REWRITE_RULE[
ADD_SYM] (GSYM 
ADD1)] THEN
      REWRITE_TAC[
ADD_SUB] THEN AP_TERM_TAC THEN
      IMP_SUBST_TAC 
REAL_INV_MUL_WEAK THEN REWRITE_TAC[
REAL_FACT_NZ] THEN
      REWRITE_TAC[GSYM 
ADD1; 
FACT; GSYM 
REAL_MUL] THEN
      REPEAT(IMP_SUBST_TAC 
REAL_INV_MUL_WEAK THEN
             REWRITE_TAC[
REAL_FACT_NZ; 
REAL_INJ; 
NOT_SUC]) THEN
      REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN
      ONCE_REWRITE_TAC[AC 
REAL_MUL_AC
       `a * b * c * d * e * f * g = (b * a) * (d * f) * (c * g) * e`] THEN
      REPEAT(IMP_SUBST_TAC REAL_MUL_LINV THEN REWRITE_TAC[
REAL_FACT_NZ] THEN
             REWRITE_TAC[
REAL_INJ; 
NOT_SUC]) THEN
      REWRITE_TAC[REAL_MUL_LID]] THEN
    FIRST_ASSUM(X_CHOOSE_THEN `d:num` SUBST1_TAC o
        MATCH_MP 
LESS_ADD_1 o CONJUNCT1) THEN
    ONCE_REWRITE_TAC[
ADD_SYM] THEN REWRITE_TAC[
ADD_SUB] THEN
    REWRITE_TAC[GSYM 
ADD_ASSOC] THEN
    REWRITE_TAC[ONCE_REWRITE_RULE[
ADD_SYM] (GSYM 
ADD1)] THEN
    REWRITE_TAC[
ADD_SUB] THEN
    REWRITE_TAC[GSYM(REWRITE_RULE[
REAL_EQ_SUB_LADD] 
SUM_OFFSET)] THEN
    BETA_TAC THEN REWRITE_TAC[
SUM_1] THEN BETA_TAC THEN
    CONV_TAC (funpow 2 RATOR_CONV (RAND_CONV HABS_CONV)) THEN
    GEN_REWRITE_TAC (RATOR_CONV o RAND_CONV) [GSYM 
REAL_ADD_RID] THEN
    MATCH_MP_TAC 
DIFF_ADD THEN REWRITE_TAC[pow; 
DIFF_CONST] THEN
    (MP_TAC o C SPECL 
DIFF_SUM)
     [`\p x. (diff((p + 1) + m)(&0) / &(
FACT(p + 1)))
                * (x pow (p + 1))`;
      `\p x. (diff(p + (SUC m))(&0) / &(
FACT p)) * (x pow p)`;
      `0`; `d:num`; `t:real`] THEN BETA_TAC THEN
    DISCH_THEN MATCH_MP_TAC THEN REWRITE_TAC[
ADD_CLAUSES] THEN
    X_GEN_TAC `k:num` THEN STRIP_TAC THEN
    W(MP_TAC o DIFF_CONV o rand o funpow 2 rator o snd) THEN
    DISCH_THEN(MP_TAC o SPEC `t:real`) THEN
    MATCH_MP_TAC EQ_IMP THEN
    CONV_TAC(ONCE_DEPTH_CONV(ALPHA_CONV `z:real`)) THEN
    AP_THM_TAC THEN AP_TERM_TAC THEN
    REWRITE_TAC[
REAL_MUL_LZERO; REAL_ADD_LID; 
REAL_MUL_RID] THEN
    REWRITE_TAC[GSYM 
ADD1; 
ADD_CLAUSES; 
real_div; GSYM REAL_MUL_ASSOC] THEN
    REWRITE_TAC[
SUC_SUB1] THEN
    ONCE_REWRITE_TAC[AC 
REAL_MUL_AC `a * b * c * d = c * (a * d) * b`] THEN
    AP_TERM_TAC THEN REWRITE_TAC[REAL_MUL_ASSOC] THEN AP_THM_TAC THEN
    AP_TERM_TAC THEN
    SUBGOAL_THEN `&(SUC k) = inv(inv(&(SUC k)))` SUBST1_TAC THENL
     [CONV_TAC SYM_CONV THEN MATCH_MP_TAC 
REAL_INVINV THEN
      REWRITE_TAC[
REAL_INJ; 
NOT_SUC]; ALL_TAC] THEN
    IMP_SUBST_TAC(GSYM 
REAL_INV_MUL_WEAK) THENL
     [CONV_TAC(ONCE_DEPTH_CONV SYM_CONV) THEN REWRITE_TAC[
REAL_FACT_NZ] THEN
      MATCH_MP_TAC 
REAL_POS_NZ THEN MATCH_MP_TAC 
REAL_INV_POS THEN
      REWRITE_TAC[
REAL_LT; 
LT_0]; ALL_TAC] THEN
    AP_TERM_TAC THEN REWRITE_TAC[
FACT; GSYM 
REAL_MUL; REAL_MUL_ASSOC] THEN
    IMP_SUBST_TAC REAL_MUL_LINV THEN REWRITE_TAC[REAL_MUL_LID] THEN
    REWRITE_TAC[
REAL_INJ; 
NOT_SUC]; ALL_TAC] THEN
  SUBGOAL_THEN `!m. m < n ==>
        ?t. &0 < t /\ t < h /\ (difg(SUC m)(t) = &0)` MP_TAC THENL
   [ALL_TAC;
    DISCH_THEN(MP_TAC o SPEC `r:num`) THEN EXPAND_TAC "n" THEN
    REWRITE_TAC[
LESS_SUC_REFL] THEN
    DISCH_THEN(X_CHOOSE_THEN `t:real` STRIP_ASSUME_TAC) THEN
    EXISTS_TAC `t:real` THEN ASM_REWRITE_TAC[] THEN
    UNDISCH_TAC `difg(SUC r)(t:real) = &0` THEN EXPAND_TAC "difg" THEN
    ASM_REWRITE_TAC[
SUB_REFL; sum; pow; 
FACT] THEN
    REWRITE_TAC[
REAL_SUB_0; REAL_ADD_LID; 
real_div] THEN
    REWRITE_TAC[
REAL_INV1; 
REAL_MUL_RID] THEN DISCH_THEN SUBST1_TAC THEN
    GEN_REWRITE_TAC (funpow 2 RAND_CONV)
     [AC 
REAL_MUL_AC
      `(a * b) * c = a * (c * b)`] THEN
    ASM_REWRITE_TAC[GSYM 
real_div]] THEN
  SUBGOAL_THEN `!m:num. m < n ==> (difg(m)(&0) = &0)` ASSUME_TAC THENL
   [X_GEN_TAC `m:num` THEN EXPAND_TAC "difg" THEN
    DISCH_THEN(X_CHOOSE_THEN `d:num` SUBST1_TAC o MATCH_MP 
LESS_ADD_1) THEN
    ONCE_REWRITE_TAC[
ADD_SYM] THEN REWRITE_TAC[
ADD_SUB] THEN
    MP_TAC(GEN `j:num->real`
     (SPECL [`j:num->real`; `d:num`; `1`] 
SUM_OFFSET)) THEN
    REWRITE_TAC[
ADD1; 
REAL_EQ_SUB_LADD] THEN
    DISCH_THEN(fun th -> REWRITE_TAC[GSYM th]) THEN BETA_TAC THEN
    REWRITE_TAC[
SUM_1] THEN BETA_TAC THEN
    REWRITE_TAC[
FACT; pow; 
REAL_INV1; 
ADD_CLAUSES; 
real_div; 
REAL_MUL_RID] THEN
    REWRITE_TAC[GSYM 
ADD1; 
POW_0; 
REAL_MUL_RZERO; 
SUM_0; REAL_ADD_LID] THEN
    REWRITE_TAC[
REAL_MUL_LZERO; 
REAL_MUL_RZERO; 
REAL_ADD_RID] THEN
    REWRITE_TAC[
REAL_SUB_REFL]; ALL_TAC] THEN
  SUBGOAL_THEN `!m:num. m < n ==> ?t. &0 < t /\ t < h /\
                        (difg(m) diffl &0)(t)` MP_TAC THENL
   [ALL_TAC;
    DISCH_THEN(fun th -> GEN_TAC THEN
      DISCH_THEN(fun t -> ASSUME_TAC t THEN MP_TAC(MATCH_MP th t))) THEN
    DISCH_THEN(X_CHOOSE_THEN `t:real` STRIP_ASSUME_TAC) THEN
    EXISTS_TAC `t:real` THEN ASM_REWRITE_TAC[] THEN
    MATCH_MP_TAC 
DIFF_UNIQ THEN EXISTS_TAC `difg(m:num):real->real` THEN
    EXISTS_TAC `t:real` THEN ASM_REWRITE_TAC[] THEN
    FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
    CONJ_TAC THEN MATCH_MP_TAC 
REAL_LT_IMP_LE THEN
    FIRST_ASSUM ACCEPT_TAC] THEN
  INDUCT_TAC THENL
   [DISCH_TAC THEN MATCH_MP_TAC 
ROLLE THEN ASM_REWRITE_TAC[] THEN
    SUBGOAL_THEN `!t. &0 <= t /\ t <= h ==> g differentiable t` MP_TAC THENL
     [GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[differentiable] THEN
      EXISTS_TAC `difg(SUC 0)(t:real):real` THEN
      SUBST1_TAC(SYM(ASSUME `difg(0):real->real = g`)) THEN
      FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
    DISCH_TAC THEN CONJ_TAC THENL
     [GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC 
DIFF_CONT THEN
      REWRITE_TAC[GSYM differentiable] THEN FIRST_ASSUM MATCH_MP_TAC THEN
      ASM_REWRITE_TAC[];
      GEN_TAC THEN DISCH_TAC THEN FIRST_ASSUM MATCH_MP_TAC THEN
      CONJ_TAC THEN MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ASM_REWRITE_TAC[]];
    DISCH_TAC THEN
    SUBGOAL_THEN `m < n:num`
    (fun th -> FIRST_ASSUM(MP_TAC o C MATCH_MP th)) THENL
     [MATCH_MP_TAC 
LT_TRANS THEN EXISTS_TAC `SUC m` THEN
      ASM_REWRITE_TAC[
LESS_SUC_REFL]; ALL_TAC] THEN
    DISCH_THEN(X_CHOOSE_THEN `t0:real` STRIP_ASSUME_TAC) THEN
    SUBGOAL_THEN `?t. (& 0) < t /\ t < t0 /\ ((difg(SUC m)) diffl (& 0))t`
    MP_TAC THENL
     [MATCH_MP_TAC 
ROLLE THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
       [SUBGOAL_THEN `difg(SUC m)(&0) = &0` SUBST1_TAC THENL
         [FIRST_ASSUM MATCH_MP_TAC THEN FIRST_ASSUM ACCEPT_TAC;
          MATCH_MP_TAC 
DIFF_UNIQ THEN EXISTS_TAC `difg(m:num):real->real` THEN
          EXISTS_TAC `t0:real` THEN ASM_REWRITE_TAC[] THEN
          FIRST_ASSUM MATCH_MP_TAC THEN REPEAT CONJ_TAC THENL
           [MATCH_MP_TAC 
LT_TRANS THEN EXISTS_TAC `SUC m` THEN
            ASM_REWRITE_TAC[
LESS_SUC_REFL];
            MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ASM_REWRITE_TAC[];
            MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ASM_REWRITE_TAC[]]]; ALL_TAC] THEN
      SUBGOAL_THEN `!t. &0 <= t /\ t <= t0 ==>
                       difg(SUC m) differentiable t` ASSUME_TAC THENL
       [GEN_TAC THEN DISCH_TAC THEN REWRITE_TAC[differentiable] THEN
        EXISTS_TAC `difg(SUC(SUC m))(t:real):real` THEN
        FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[] THEN
        MATCH_MP_TAC 
REAL_LE_TRANS THEN EXISTS_TAC `t0:real` THEN
        ASM_REWRITE_TAC[] THEN
        MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
      CONJ_TAC THENL
       [GEN_TAC THEN DISCH_TAC THEN MATCH_MP_TAC 
DIFF_CONT THEN
        REWRITE_TAC[GSYM differentiable] THEN FIRST_ASSUM MATCH_MP_TAC THEN
        ASM_REWRITE_TAC[];
        GEN_TAC THEN DISCH_TAC THEN FIRST_ASSUM MATCH_MP_TAC THEN
        CONJ_TAC THEN MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ASM_REWRITE_TAC[]];
      DISCH_THEN(X_CHOOSE_THEN `t:real` STRIP_ASSUME_TAC) THEN
      EXISTS_TAC `t:real` THEN ASM_REWRITE_TAC[] THEN
      MATCH_MP_TAC 
REAL_LT_TRANS THEN EXISTS_TAC `t0:real` THEN
      ASM_REWRITE_TAC[]]]);;
 
let MCLAURIN_NEG = prove
 (`!f diff h n.
    h < &0 /\
    0 < n /\
    (diff(0) = f) /\
    (!m t. m < n /\ h <= t /\ t <= &0 ==>
           (diff(m) diffl diff(SUC m)(t))(t)) ==>
   (?t. h < t /\ t < &0 /\
        (f(h) = sum(0,n)(\m. (diff(m)(&0) / &(
FACT m)) * (h pow m)) +
                ((diff(n)(t) / &(
FACT n)) * (h pow n))))`,
  REPEAT GEN_TAC THEN STRIP_TAC THEN
  MP_TAC(SPECL [`\x. (f(--x):real)`;
                `\n x. ((--(&1)) pow n) * (diff:num->real->real)(n)(--x)`;
                `--h`; `n:num`] 
MCLAURIN) THEN
  BETA_TAC THEN ASM_REWRITE_TAC[
REAL_NEG_GT0; pow; REAL_MUL_LID] THEN
  ONCE_REWRITE_TAC[GSYM 
REAL_LE_NEG] THEN
  REWRITE_TAC[
REAL_NEGNEG; 
REAL_NEG_0] THEN
  ONCE_REWRITE_TAC[AC 
CONJ_ACI `a /\ b /\ c <=> a /\ c /\ b`] THEN
  W(C SUBGOAL_THEN (fun t -> REWRITE_TAC[t]) o
  funpow 2 (fst o dest_imp) o snd) THENL
   [REPEAT GEN_TAC THEN
    DISCH_THEN(fun th -> FIRST_ASSUM(MP_TAC o C MATCH_MP th)) THEN
    DISCH_THEN(MP_TAC o C CONJ (SPEC `t:real` (DIFF_CONV `\x. --x`))) THEN
    CONV_TAC(ONCE_DEPTH_CONV ETA_CONV) THEN
    DISCH_THEN(MP_TAC o MATCH_MP 
DIFF_CHAIN) THEN
    DISCH_THEN(MP_TAC o GEN_ALL o MATCH_MP 
DIFF_CMUL) THEN
    DISCH_THEN(MP_TAC o SPEC `(--(&1)) pow m`) THEN BETA_TAC THEN
    MATCH_MP_TAC EQ_IMP THEN
    CONV_TAC(ONCE_DEPTH_CONV(ALPHA_CONV `z:real`)) THEN
    AP_THM_TAC THEN AP_TERM_TAC THEN
    CONV_TAC(AC 
REAL_MUL_AC);
    DISCH_THEN(X_CHOOSE_THEN `t:real` STRIP_ASSUME_TAC)] THEN
  EXISTS_TAC `--t` THEN ONCE_REWRITE_TAC[GSYM 
REAL_LT_NEG] THEN
  ASM_REWRITE_TAC[
REAL_NEGNEG; 
REAL_NEG_0] THEN
  BINOP_TAC THENL
   [MATCH_MP_TAC 
SUM_EQ THEN
    X_GEN_TAC `m:num` THEN REWRITE_TAC[
ADD_CLAUSES] THEN
    DISCH_THEN(ASSUME_TAC o CONJUNCT2) THEN BETA_TAC; ALL_TAC] THEN
  REWRITE_TAC[
real_div; GSYM REAL_MUL_ASSOC] THEN
  ONCE_REWRITE_TAC[AC 
REAL_MUL_AC
    `a * b * c * d = (b * c) * (a * d)`] THEN
  REWRITE_TAC[GSYM 
POW_MUL; GSYM 
REAL_NEG_MINUS1; 
REAL_NEGNEG] THEN
  REWRITE_TAC[REAL_MUL_ASSOC]);;
 
let MCLAURIN_BI_LE = prove
 (`!f diff x n.
        (diff 0 = f) /\
        (!m t. m < n /\ abs(t) <= abs(x) ==> (diff m diffl diff (SUC m) t) t)
        ==> ?t. abs(t) <= abs(x) /\
                (f x = sum (0,n) (\m. diff m (&0) / &(
FACT m) * x pow m) +
                       diff n t / &(
FACT n) * x pow n)`,
  REPEAT STRIP_TAC THEN ASM_CASES_TAC `n = 0` THENL
   [ASM_REWRITE_TAC[sum; 
real_pow; 
FACT; 
REAL_DIV_1; 
REAL_MUL_RID;
                    REAL_ADD_LID] THEN
    EXISTS_TAC `x:real` THEN REWRITE_TAC[
REAL_LE_REFL]; ALL_TAC] THEN
  ASM_CASES_TAC `x = &0` THENL
   [EXISTS_TAC `&0` THEN ASM_REWRITE_TAC[
REAL_LE_REFL] THEN
    UNDISCH_TAC `~(n = 0)` THEN SPEC_TAC(`n:num`,`n:num`) THEN
    INDUCT_TAC THEN ASM_REWRITE_TAC[
NOT_SUC] THEN
    REWRITE_TAC[
ADD1] THEN
    REWRITE_TAC[REWRITE_RULE[
REAL_EQ_SUB_RADD] (GSYM 
SUM_OFFSET)] THEN
    REWRITE_TAC[
REAL_POW_ADD; 
REAL_POW_1; 
REAL_MUL_RZERO; 
SUM_0] THEN
    REWRITE_TAC[
REAL_ADD_RID; REAL_ADD_LID] THEN
    CONV_TAC(ONCE_DEPTH_CONV REAL_SUM_CONV) THEN
    ASM_REWRITE_TAC[
real_pow; 
FACT; 
REAL_MUL_RID; 
REAL_DIV_1]; ALL_TAC] THEN
  FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
   `~(x = &0) ==> &0 < x \/ x < &0`))
  THENL
   [MP_TAC(SPECL [`f:real->real`; `diff:num->real->real`; `x:real`; `n:num`]
                 
MCLAURIN) THEN
    ASM_SIMP_TAC[REAL_ARITH `&0 <= t /\ t <= x ==> abs(t) <= abs(x)`] THEN
    ASM_REWRITE_TAC[
LT_NZ] THEN MATCH_MP_TAC 
MONO_EXISTS THEN
    SIMP_TAC[REAL_ARITH `&0 < t /\ t < x ==> abs(t) <= abs(x)`];
    MP_TAC(SPECL [`f:real->real`; `diff:num->real->real`; `x:real`; `n:num`]
                 
MCLAURIN_NEG) THEN
    ASM_SIMP_TAC[REAL_ARITH `x <= t /\ t <= &0 ==> abs(t) <= abs(x)`] THEN
    ASM_REWRITE_TAC[
LT_NZ] THEN MATCH_MP_TAC 
MONO_EXISTS THEN
    SIMP_TAC[REAL_ARITH `x < t /\ t < &0 ==> abs(t) <= abs(x)`]]);;
 
let MCLAURIN_ALL_LT = prove
 (`!f diff.
      (diff 0 = f) /\
      (!m x. ((diff m) diffl (diff(SUC m) x)) x)
      ==> !x n. ~(x = &0) /\ 0 < n
            ==> ?t. &0 < abs(t) /\ abs(t) < abs(x) /\
                    (f(x) = sum(0,n)(\m. (diff m (&0) / &(
FACT m)) * x pow m) +
                            (diff n t / &(
FACT n)) * x pow n)`,
  REPEAT STRIP_TAC THEN
  REPEAT_TCL DISJ_CASES_THEN MP_TAC
   (SPECL [`x:real`; `&0`] 
REAL_LT_TOTAL) THEN
  ASM_REWRITE_TAC[] THEN DISCH_TAC THENL
   [MP_TAC(SPECL [`f:real->real`; `diff:num->real->real`;
                  `x:real`; `n:num`] 
MCLAURIN_NEG) THEN
    ASM_REWRITE_TAC[] THEN
    DISCH_THEN(X_CHOOSE_THEN `t:real` STRIP_ASSUME_TAC) THEN
    EXISTS_TAC `t:real` THEN ASM_REWRITE_TAC[] THEN
    UNDISCH_TAC `t < &0` THEN UNDISCH_TAC `x < t` THEN REAL_ARITH_TAC;
    MP_TAC(SPECL [`f:real->real`; `diff:num->real->real`;
                  `x:real`; `n:num`] 
MCLAURIN) THEN
    ASM_REWRITE_TAC[] THEN
    DISCH_THEN(X_CHOOSE_THEN `t:real` STRIP_ASSUME_TAC) THEN
    EXISTS_TAC `t:real` THEN ASM_REWRITE_TAC[] THEN
    UNDISCH_TAC `&0 < t` THEN UNDISCH_TAC `t < x` THEN REAL_ARITH_TAC]);;
 
let MCLAURIN_ZERO = prove
 (`!diff n x. (x = &0) /\ 0 < n ==>
       (sum(0,n)(\m. (diff m (&0) / &(
FACT m)) * x pow m) = diff 0 (&0))`,
 
let MCLAURIN_ALL_LE = prove
 (`!f diff.
      (diff 0 = f) /\
      (!m x. ((diff m) diffl (diff(SUC m) x)) x)
      ==> !x n. ?t. abs(t) <= abs(x) /\
                    (f(x) = sum(0,n)(\m. (diff m (&0) / &(
FACT m)) * x pow m) +
                            (diff n t / &(
FACT n)) * x pow n)`,
  REPEAT STRIP_TAC THEN
  DISJ_CASES_THEN MP_TAC(SPECL [`n:num`; `0`] 
LET_CASES) THENL
   [REWRITE_TAC[
LE] THEN DISCH_THEN SUBST1_TAC THEN
    ASM_REWRITE_TAC[sum; REAL_ADD_LID; 
FACT] THEN EXISTS_TAC `x:real` THEN
    REWRITE_TAC[
REAL_LE_REFL; 
real_pow; 
REAL_MUL_RID; 
REAL_DIV_1];
    DISCH_TAC THEN ASM_CASES_TAC `x = &0` THENL
     [MP_TAC(SPEC_ALL 
MCLAURIN_ZERO) THEN ASM_REWRITE_TAC[] THEN
      DISCH_THEN SUBST1_TAC THEN EXISTS_TAC `&0` THEN
      REWRITE_TAC[
REAL_LE_REFL] THEN
      SUBGOAL_THEN `&0 pow n = &0` SUBST1_TAC THENL
       [ASM_REWRITE_TAC[
REAL_POW_EQ_0; GSYM (CONJUNCT1 
LE); 
NOT_LE];
        REWRITE_TAC[
REAL_ADD_RID; 
REAL_MUL_RZERO]];
      MP_TAC(SPEC_ALL 
MCLAURIN_ALL_LT) THEN ASM_REWRITE_TAC[] THEN
      DISCH_THEN(MP_TAC o SPEC_ALL) THEN ASM_REWRITE_TAC[] THEN
      DISCH_THEN(X_CHOOSE_THEN `t:real` STRIP_ASSUME_TAC) THEN
      EXISTS_TAC `t:real` THEN ASM_REWRITE_TAC[] THEN
      MATCH_MP_TAC 
REAL_LT_IMP_LE THEN ASM_REWRITE_TAC[]]]);;
 
let MCLAURIN_EXP_LT = prove
 (`!x n. ~(x = &0) /\ 0 < n
         ==> ?t. &0 < abs(t) /\
                 abs(t) < abs(x) /\
                 (exp(x) = sum(0,n)(\m. x pow m / &(
FACT m)) +
                           (exp(t) / &(
FACT n)) * x pow n)`,
 
let MCLAURIN_LN_POS = prove
 (`!x n.
     &0 < x /\ 0 < n
     ==> ?t. &0 < t /\
             t < x /\
             (ln(&1 + x) = sum(0,n)
                           (\m. --(&1) pow (SUC m) * (x pow m) / &m) +
               --(&1) pow (SUC n) * x pow n / (&n * (&1 + t) pow n))`,
  REPEAT STRIP_TAC THEN
  MP_TAC(SPEC `\x. ln(&1 + x)` 
MCLAURIN) THEN
  DISCH_THEN(MP_TAC o SPEC
    `\n x. if n = 0 then ln(&1 + x)
           else --(&1) pow (SUC n) *
                &(
FACT(
PRE n)) * inv((&1 + x) pow n)`) THEN
  DISCH_THEN(MP_TAC o SPECL [`x:real`; `n:num`]) THEN
  ASM_REWRITE_TAC[] THEN
  REWRITE_TAC[
NOT_SUC; 
REAL_ADD_RID; 
REAL_POW_ONE] THEN
  REWRITE_TAC[
LN_1; 
REAL_INV_1; 
REAL_MUL_RID] THEN
  SUBGOAL_THEN `~(n = 0)` ASSUME_TAC THENL
   [UNDISCH_TAC `0 < n` THEN ARITH_TAC; ASM_REWRITE_TAC[]] THEN
  SUBGOAL_THEN `!p. ~(p = 0) ==> (&(
FACT(
PRE p)) / &(
FACT p) = inv(&p))`
  ASSUME_TAC THENL
   [INDUCT_TAC THEN REWRITE_TAC[
NOT_SUC; 
PRE] THEN
    REWRITE_TAC[
real_div; 
FACT; GSYM REAL_OF_NUM_MUL] THEN
    REWRITE_TAC[
REAL_INV_MUL] THEN
    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
    GEN_REWRITE_TAC RAND_CONV [GSYM 
REAL_MUL_RID] THEN
    REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN
    AP_TERM_TAC THEN MATCH_MP_TAC REAL_MUL_LINV THEN
    REWRITE_TAC[REAL_OF_NUM_EQ] THEN
    MP_TAC(SPEC `p:num` 
FACT_LT) THEN ARITH_TAC; ALL_TAC] THEN
  SUBGOAL_THEN
   `!p. (if p = 0 then &0 else --(&1) pow (SUC p) * &(
FACT (
PRE p))) /
        &(
FACT p) = --(&1) pow (SUC p) * inv(&p)`
  (fun th -> REWRITE_TAC[th]) THENL
   [INDUCT_TAC THENL
     [REWRITE_TAC[REAL_INV_0; 
real_div; 
REAL_MUL_LZERO; 
REAL_MUL_RZERO];
      REWRITE_TAC[
NOT_SUC] THEN
      REWRITE_TAC[
real_div; GSYM REAL_MUL_ASSOC] THEN
      AP_TERM_TAC THEN REWRITE_TAC[GSYM 
real_div] THEN
      FIRST_ASSUM MATCH_MP_TAC THEN
      REWRITE_TAC[
NOT_SUC]]; ALL_TAC] THEN
  SUBGOAL_THEN
    `!t. (--(&1) pow (SUC n) * &(
FACT(
PRE n)) * inv ((&1 + t) pow n)) /
         &(
FACT n) * x pow n = --(&1) pow (SUC n) *
                               x pow n / (&n * (&1 + t) pow n)`
  (fun th -> REWRITE_TAC[th]) THENL
   [GEN_TAC THEN REWRITE_TAC[
real_div; GSYM REAL_MUL_ASSOC] THEN
    AP_TERM_TAC THEN REWRITE_TAC[REAL_MUL_ASSOC] THEN
    GEN_REWRITE_TAC LAND_CONV [REAL_MUL_SYM] THEN AP_TERM_TAC THEN
    REWRITE_TAC[
REAL_INV_MUL] THEN
    GEN_REWRITE_TAC LAND_CONV [REAL_MUL_SYM] THEN
    REWRITE_TAC[REAL_MUL_ASSOC] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[GSYM 
real_div] THEN
    FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
  REWRITE_TAC[
real_div; 
REAL_MUL_AC] THEN
  DISCH_THEN MATCH_MP_TAC THEN
  X_GEN_TAC `m:num` THEN X_GEN_TAC `u:real` THEN STRIP_TAC THEN
  ASM_CASES_TAC `m = 0` THEN ASM_REWRITE_TAC[] THENL
   [W(MP_TAC o SPEC `u:real` o DIFF_CONV o lhand o rator o snd) THEN
    REWRITE_TAC[
PRE; 
real_pow; REAL_ADD_LID; 
REAL_MUL_RID] THEN
    REWRITE_TAC[
REAL_MUL_RNEG; 
REAL_MUL_LNEG; 
REAL_MUL_RID] THEN
    REWRITE_TAC[
FACT; 
REAL_MUL_RID; 
REAL_NEG_NEG] THEN
    DISCH_THEN MATCH_MP_TAC THEN UNDISCH_TAC `&0 <= u` THEN REAL_ARITH_TAC;
    W(MP_TAC o SPEC `u:real` o DIFF_CONV o lhand o rator o snd) THEN
    SUBGOAL_THEN `~((&1 + u) pow m = &0)` (fun th -> REWRITE_TAC[th]) THENL
     [REWRITE_TAC[
REAL_POW_EQ_0] THEN ASM_REWRITE_TAC[] THEN
      UNDISCH_TAC `&0 <= u` THEN REAL_ARITH_TAC;
      MATCH_MP_TAC EQ_IMP THEN
      AP_THM_TAC THEN AP_TERM_TAC THEN
      REWRITE_TAC[
REAL_MUL_LZERO; 
REAL_ADD_RID] THEN
      REWRITE_TAC[REAL_ADD_LID; 
REAL_MUL_RID] THEN
      REWRITE_TAC[
real_div; 
real_pow; 
REAL_MUL_LNEG; 
REAL_MUL_RNEG] THEN
      REWRITE_TAC[
REAL_NEG_NEG; 
REAL_MUL_RID; REAL_MUL_LID] THEN
      REWRITE_TAC[REAL_MUL_ASSOC] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
      UNDISCH_TAC `~(m = 0)` THEN SPEC_TAC(`m:num`,`p:num`) THEN
      INDUCT_TAC THEN REWRITE_TAC[
NOT_SUC] THEN
      REWRITE_TAC[
SUC_SUB1; 
PRE] THEN REWRITE_TAC[
FACT] THEN
      REWRITE_TAC[GSYM REAL_OF_NUM_MUL] THEN
      REWRITE_TAC[REAL_MUL_ASSOC] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
      GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
      REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN AP_TERM_TAC THEN
      REWRITE_TAC[
real_pow; REAL_POW_2] THEN REWRITE_TAC[
REAL_INV_MUL] THEN
      REWRITE_TAC[REAL_MUL_ASSOC] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
      REWRITE_TAC[REAL_MUL_ASSOC] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
      ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
      GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
      REWRITE_TAC[REAL_MUL_ASSOC] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
      MATCH_MP_TAC REAL_MUL_LINV THEN
      REWRITE_TAC[
REAL_POW_EQ_0] THEN ASM_REWRITE_TAC[] THEN
      REWRITE_TAC[DE_MORGAN_THM] THEN DISJ1_TAC THEN
      UNDISCH_TAC `&0 <= u` THEN REAL_ARITH_TAC]]);;
 
let MCLAURIN_LN_NEG = prove
 (`!x n. &0 < x /\ x < &1 /\ 0 < n
         ==> ?t. &0 < t /\
                 t < x /\
                 (--(ln(&1 - x)) = sum(0,n) (\m. (x pow m) / &m) +
                                    x pow n / (&n * (&1 - t) pow n))`,
  REPEAT STRIP_TAC THEN
  MP_TAC(SPEC `\x. --(ln(&1 - x))` 
MCLAURIN) THEN
  DISCH_THEN(MP_TAC o SPEC
    `\n x. if n = 0 then --(ln(&1 - x))
           else &(
FACT(
PRE n)) * inv((&1 - x) pow n)`) THEN
  DISCH_THEN(MP_TAC o SPECL [`x:real`; `n:num`]) THEN
  ASM_REWRITE_TAC[] THEN REWRITE_TAC[
REAL_SUB_RZERO] THEN
  REWRITE_TAC[
NOT_SUC; 
LN_1; 
REAL_POW_ONE] THEN
  SUBGOAL_THEN `~(n = 0)` ASSUME_TAC THENL
   [UNDISCH_TAC `0 < n` THEN ARITH_TAC; ASM_REWRITE_TAC[]] THEN
  REWRITE_TAC[
REAL_INV_1; 
REAL_MUL_RID; REAL_MUL_LID] THEN
  SUBGOAL_THEN `!p. ~(p = 0) ==> (&(
FACT(
PRE p)) / &(
FACT p) = inv(&p))`
  ASSUME_TAC THENL
   [INDUCT_TAC THEN REWRITE_TAC[
NOT_SUC; 
PRE] THEN
    REWRITE_TAC[
real_div; 
FACT; GSYM REAL_OF_NUM_MUL] THEN
    REWRITE_TAC[
REAL_INV_MUL] THEN
    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
    GEN_REWRITE_TAC RAND_CONV [GSYM 
REAL_MUL_RID] THEN
    REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN
    AP_TERM_TAC THEN MATCH_MP_TAC REAL_MUL_LINV THEN
    REWRITE_TAC[REAL_OF_NUM_EQ] THEN
    MP_TAC(SPEC `p:num` 
FACT_LT) THEN ARITH_TAC; ALL_TAC] THEN
  REWRITE_TAC[
REAL_NEG_0] THEN
  SUBGOAL_THEN `!p. (if p = 0 then &0 else &(
FACT (
PRE p))) / &(
FACT p) =
                    inv(&p)`
  (fun th -> REWRITE_TAC[th]) THENL
   [INDUCT_TAC THENL
     [REWRITE_TAC[REAL_INV_0; 
real_div; 
REAL_MUL_LZERO];
      REWRITE_TAC[
NOT_SUC] THEN FIRST_ASSUM MATCH_MP_TAC THEN
      REWRITE_TAC[
NOT_SUC]]; ALL_TAC] THEN
  SUBGOAL_THEN
    `!t. (&(
FACT(
PRE n)) * inv ((&1 - t) pow n)) / &(
FACT n) * x pow n
         = x pow n / (&n * (&1 - t) pow n)`
  (fun th -> REWRITE_TAC[th]) THENL
   [GEN_TAC THEN REWRITE_TAC[
real_div; REAL_MUL_ASSOC] THEN
    GEN_REWRITE_TAC LAND_CONV [REAL_MUL_SYM] THEN AP_TERM_TAC THEN
    REWRITE_TAC[
REAL_INV_MUL] THEN
    GEN_REWRITE_TAC LAND_CONV [REAL_MUL_SYM] THEN
    REWRITE_TAC[REAL_MUL_ASSOC] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
    ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN REWRITE_TAC[GSYM 
real_div] THEN
    FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]; ALL_TAC] THEN
  REWRITE_TAC[
real_div; 
REAL_MUL_AC] THEN
  DISCH_THEN MATCH_MP_TAC THEN
  X_GEN_TAC `m:num` THEN X_GEN_TAC `u:real` THEN STRIP_TAC THEN
  ASM_CASES_TAC `m = 0` THEN ASM_REWRITE_TAC[] THENL
   [W(MP_TAC o SPEC `u:real` o DIFF_CONV o lhand o rator o snd) THEN
    REWRITE_TAC[
PRE; pow; 
FACT; 
REAL_SUB_LZERO] THEN
    REWRITE_TAC[
REAL_MUL_RNEG; 
REAL_NEG_NEG; 
REAL_MUL_RID] THEN
    DISCH_THEN MATCH_MP_TAC THEN
    UNDISCH_TAC `x < &1` THEN UNDISCH_TAC `u:real <= x` THEN
    REAL_ARITH_TAC;
    W(MP_TAC o SPEC `u:real` o DIFF_CONV o lhand o rator o snd) THEN
    SUBGOAL_THEN `~((&1 - u) pow m = &0)` (fun th -> REWRITE_TAC[th]) THENL
     [REWRITE_TAC[
REAL_POW_EQ_0] THEN ASM_REWRITE_TAC[] THEN
      UNDISCH_TAC `x < &1` THEN UNDISCH_TAC `u:real <= x` THEN
      REAL_ARITH_TAC;
      MATCH_MP_TAC EQ_IMP THEN
      AP_THM_TAC THEN AP_TERM_TAC THEN
      REWRITE_TAC[
REAL_SUB_LZERO; 
real_div; 
PRE] THEN
      REWRITE_TAC[
REAL_MUL_LZERO; 
REAL_ADD_RID] THEN
      REWRITE_TAC
       [
REAL_MUL_RNEG; 
REAL_MUL_LNEG; 
REAL_NEG_NEG; 
REAL_MUL_RID] THEN
      UNDISCH_TAC `~(m = 0)` THEN SPEC_TAC(`m:num`,`p:num`) THEN
      INDUCT_TAC THEN REWRITE_TAC[
NOT_SUC] THEN
      REWRITE_TAC[
SUC_SUB1; 
PRE] THEN REWRITE_TAC[
FACT] THEN
      REWRITE_TAC[GSYM REAL_OF_NUM_MUL] THEN
      REWRITE_TAC[REAL_MUL_ASSOC] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
      GEN_REWRITE_TAC RAND_CONV [REAL_MUL_SYM] THEN
      REWRITE_TAC[GSYM REAL_MUL_ASSOC] THEN AP_TERM_TAC THEN
      REWRITE_TAC[
real_pow; REAL_POW_2] THEN REWRITE_TAC[
REAL_INV_MUL] THEN
      REWRITE_TAC[REAL_MUL_ASSOC] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
      REWRITE_TAC[REAL_MUL_ASSOC] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
      ONCE_REWRITE_TAC[REAL_MUL_SYM] THEN
      GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
      REWRITE_TAC[REAL_MUL_ASSOC] THEN AP_THM_TAC THEN AP_TERM_TAC THEN
      MATCH_MP_TAC REAL_MUL_LINV THEN
      REWRITE_TAC[
REAL_POW_EQ_0] THEN ASM_REWRITE_TAC[] THEN
      UNDISCH_TAC `x < &1` THEN UNDISCH_TAC `u:real <= x` THEN
      REAL_ARITH_TAC]]);;
 
let MCLAURIN_SIN = prove
 (`!x n. abs(sin x -
             sum(0,n) (\m. (if 
EVEN m then &0
                            else -- &1 pow ((m - 1) DIV 2) / &(
FACT m)) *
                            x pow m))
         <= inv(&(
FACT n)) * abs(x) pow n`,
  REPEAT STRIP_TAC THEN
  MP_TAC(SPECL [`sin`; `\n x. if n MOD 4 = 0 then sin(x)
                              else if n MOD 4 = 1 then cos(x)
                              else if n MOD 4 = 2 then --sin(x)
                              else --cos(x)`] 
MCLAURIN_ALL_LE) THEN
  W(C SUBGOAL_THEN (fun th -> REWRITE_TAC[th]) o funpow 2 lhand o snd) THENL
   [CONJ_TAC THENL
     [SIMP_TAC[MOD_0; 
ARITH_EQ; EQT_INTRO(SPEC_ALL ETA_AX)]; ALL_TAC] THEN
    X_GEN_TAC `m:num` THEN X_GEN_TAC `y:real` THEN REWRITE_TAC[] THEN
    MP_TAC(SPECL [`m:num`; `4`] 
DIVISION) THEN
    REWRITE_TAC[
ARITH_EQ] THEN ABBREV_TAC `d = m MOD 4` THEN
    DISCH_THEN(CONJUNCTS_THEN2 SUBST1_TAC MP_TAC) THEN
    REWRITE_TAC[
ADD1; GSYM 
ADD_ASSOC; 
MOD_MULT_ADD] THEN
    SPEC_TAC(`d:num`,`d:num`) THEN CONV_TAC EXPAND_CASES_CONV THEN
    CONV_TAC NUM_REDUCE_CONV THEN REWRITE_TAC[] THEN
    REPEAT CONJ_TAC THEN
    W(MP_TAC o DIFF_CONV o lhand o rator o snd) THEN
    SIMP_TAC[
REAL_MUL_RID; 
REAL_NEG_NEG]; ALL_TAC] THEN
  DISCH_THEN(MP_TAC o SPECL [`x:real`; `n:num`]) THEN
  DISCH_THEN(X_CHOOSE_THEN `t:real`
    (CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC)) THEN
  MATCH_MP_TAC(REAL_ARITH
    `(x = y) /\ abs(u) <= v ==> abs((x + u) - y) <= v`) THEN
  CONJ_TAC THENL
   [MATCH_MP_TAC 
SUM_EQ THEN X_GEN_TAC `r:num` THEN STRIP_TAC THEN
    REWRITE_TAC[
SIN_0; 
COS_0; 
REAL_NEG_0] THEN
    AP_THM_TAC THEN AP_TERM_TAC THEN
    MP_TAC(SPECL [`r:num`; `4`] 
DIVISION) THEN REWRITE_TAC[
ARITH_EQ] THEN
    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
    DISCH_THEN(fun th -> GEN_REWRITE_TAC
      (RAND_CONV o ONCE_DEPTH_CONV) [th] THEN
      MP_TAC(SYM th)) THEN
    REWRITE_TAC[
EVEN_ADD; 
EVEN_MULT; 
ARITH_EVEN] THEN
    UNDISCH_TAC `r MOD 4 < 4` THEN
    SPEC_TAC(`r MOD 4`,`d:num`) THEN CONV_TAC EXPAND_CASES_CONV THEN
    CONV_TAC NUM_REDUCE_CONV THEN REWRITE_TAC[] THEN
    REWRITE_TAC[
real_div; 
REAL_MUL_LZERO] THEN
    SIMP_TAC[ARITH_RULE `(x + 1) - 1 = x`;
             ARITH_RULE `(x + 3) - 1 = x + 2`;
             ARITH_RULE `x * 4 + 2 = 2 * (2 * x + 1)`;
             ARITH_RULE `x * 4 = 2 * 2 * x`] THEN
    SIMP_TAC[DIV_MULT; 
ARITH_EQ] THEN
    REWRITE_TAC[
REAL_POW_NEG; 
EVEN_ADD; 
EVEN_MULT; 
ARITH_EVEN; 
REAL_POW_ONE];
    ALL_TAC] THEN
  REWRITE_TAC[
REAL_ABS_MUL; 
REAL_INV_MUL] THEN
  MATCH_MP_TAC 
REAL_LE_MUL2 THEN REWRITE_TAC[
REAL_ABS_POS] THEN CONJ_TAC THENL
   [REWRITE_TAC[
real_div; 
REAL_ABS_MUL] THEN
    GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
    REWRITE_TAC[
REAL_ABS_INV; 
REAL_ABS_NUM] THEN
    MATCH_MP_TAC 
REAL_LE_RMUL THEN
    SIMP_TAC[
REAL_LE_INV_EQ; 
REAL_POS] THEN
    REPEAT COND_CASES_TAC THEN REWRITE_TAC[
REAL_ABS_NEG; 
SIN_BOUND; 
COS_BOUND];
    ALL_TAC] THEN
  REWRITE_TAC[
REAL_ABS_POW; 
REAL_LE_REFL]);;
 
let MCLAURIN_COS = prove
 (`!x n. abs(cos x -
                   sum(0,n) (\m. (if 
EVEN m
                                  then -- &1 pow (m DIV 2) / &(
FACT m)
                                  else &0) * x pow m))
               <= inv(&(
FACT n)) * abs(x) pow n`,
  REPEAT STRIP_TAC THEN
  MP_TAC(SPECL [`cos`; `\n x. if n MOD 4 = 0 then cos(x)
                              else if n MOD 4 = 1 then --sin(x)
                              else if n MOD 4 = 2 then --cos(x)
                              else sin(x)`] 
MCLAURIN_ALL_LE) THEN
  W(C SUBGOAL_THEN (fun th -> REWRITE_TAC[th]) o funpow 2 lhand o snd) THENL
   [CONJ_TAC THENL
     [SIMP_TAC[MOD_0; 
ARITH_EQ; EQT_INTRO(SPEC_ALL ETA_AX)]; ALL_TAC] THEN
    X_GEN_TAC `m:num` THEN X_GEN_TAC `y:real` THEN REWRITE_TAC[] THEN
    MP_TAC(SPECL [`m:num`; `4`] 
DIVISION) THEN
    REWRITE_TAC[
ARITH_EQ] THEN ABBREV_TAC `d = m MOD 4` THEN
    DISCH_THEN(CONJUNCTS_THEN2 SUBST1_TAC MP_TAC) THEN
    REWRITE_TAC[
ADD1; GSYM 
ADD_ASSOC; 
MOD_MULT_ADD] THEN
    SPEC_TAC(`d:num`,`d:num`) THEN CONV_TAC EXPAND_CASES_CONV THEN
    CONV_TAC NUM_REDUCE_CONV THEN REWRITE_TAC[] THEN
    REPEAT CONJ_TAC THEN
    W(MP_TAC o DIFF_CONV o lhand o rator o snd) THEN
    SIMP_TAC[
REAL_MUL_RID; 
REAL_NEG_NEG]; ALL_TAC] THEN
  DISCH_THEN(MP_TAC o SPECL [`x:real`; `n:num`]) THEN
  DISCH_THEN(X_CHOOSE_THEN `t:real`
    (CONJUNCTS_THEN2 ASSUME_TAC SUBST1_TAC)) THEN
  MATCH_MP_TAC(REAL_ARITH
    `(x = y) /\ abs(u) <= v ==> abs((x + u) - y) <= v`) THEN
  CONJ_TAC THENL
   [MATCH_MP_TAC 
SUM_EQ THEN X_GEN_TAC `r:num` THEN STRIP_TAC THEN
    REWRITE_TAC[
SIN_0; 
COS_0; 
REAL_NEG_0] THEN
    AP_THM_TAC THEN AP_TERM_TAC THEN
    MP_TAC(SPECL [`r:num`; `4`] 
DIVISION) THEN REWRITE_TAC[
ARITH_EQ] THEN
    DISCH_THEN(CONJUNCTS_THEN2 MP_TAC ASSUME_TAC) THEN
    DISCH_THEN(fun th -> GEN_REWRITE_TAC
      (RAND_CONV o ONCE_DEPTH_CONV) [th] THEN
      MP_TAC(SYM th)) THEN
    REWRITE_TAC[
EVEN_ADD; 
EVEN_MULT; 
ARITH_EVEN] THEN
    UNDISCH_TAC `r MOD 4 < 4` THEN
    SPEC_TAC(`r MOD 4`,`d:num`) THEN CONV_TAC EXPAND_CASES_CONV THEN
    CONV_TAC NUM_REDUCE_CONV THEN REWRITE_TAC[] THEN
    REWRITE_TAC[
real_div; 
REAL_MUL_LZERO] THEN
    REWRITE_TAC[ARITH_RULE `x * 4 + 2 = 2 * (2 * x + 1)`;
                ARITH_RULE `x * 4 + 0 = 2 * 2 * x`] THEN
    SIMP_TAC[DIV_MULT; 
ARITH_EQ] THEN
    REWRITE_TAC[
REAL_POW_NEG; 
EVEN_ADD; 
EVEN_MULT; 
ARITH_EVEN; 
REAL_POW_ONE];
    ALL_TAC] THEN
  REWRITE_TAC[
REAL_ABS_MUL; 
REAL_ABS_DIV; REAL_MUL_ASSOC; 
REAL_ABS_POW] THEN
  MATCH_MP_TAC 
REAL_LE_RMUL THEN SIMP_TAC[
REAL_POW_LE; 
REAL_ABS_POS] THEN
  REWRITE_TAC[
real_div; 
REAL_ABS_NUM] THEN
  GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
  MATCH_MP_TAC 
REAL_LE_RMUL THEN REWRITE_TAC[
REAL_LE_INV_EQ; 
REAL_POS] THEN
  REPEAT COND_CASES_TAC THEN REWRITE_TAC[
REAL_ABS_NEG; 
SIN_BOUND; 
COS_BOUND]);;
 
let REAL_ATN_POWSER_DIFFL = prove
 (`!x. abs(x) < &1
       ==> ((\x. suminf (\n. (if 
EVEN n then &0
                              else --(&1) pow ((n - 1) DIV 2) / &n) * x pow n))
            diffl (inv(&1 + x pow 2))) x`,
 
let REAL_ATN_POWSER = prove
 (`!x. abs(x) < &1
       ==> (\n. (if 
EVEN n then &0
                 else --(&1) pow ((n - 1) DIV 2) / &n) * x pow n)
           sums (atn x)`,
  REPEAT STRIP_TAC THEN
  FIRST_ASSUM(MP_TAC o MATCH_MP 
REAL_ATN_POWSER_SUMMABLE) THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
SUMMABLE_SUM) THEN
  SUBGOAL_THEN
   `suminf (\n. (if 
EVEN n then &0
                 else --(&1) pow ((n - 1) DIV 2) / &n) * x pow n) = atn(x)`
   (fun th -> REWRITE_TAC[th]) THEN
  ONCE_REWRITE_TAC[REAL_ARITH `(a = b) <=> (a - b = &0)`] THEN
  SUBGOAL_THEN
   `suminf (\n. (if 
EVEN n then &0
                 else --(&1) pow ((n - 1) DIV 2) / &n) * &0 pow n) -
    atn(&0) = &0`
  MP_TAC THENL
   [MATCH_MP_TAC(REAL_ARITH `(a = &0) /\ (b = &0) ==> (a - b = &0)`) THEN
    CONJ_TAC THENL
     [CONV_TAC SYM_CONV THEN MATCH_MP_TAC 
SUM_UNIQ THEN
      MP_TAC(SPEC `&0` 
GP) THEN
      REWRITE_TAC[
REAL_ABS_NUM; 
REAL_OF_NUM_LT; ARITH] THEN
      DISCH_THEN(MP_TAC o SPEC `&0` o MATCH_MP 
SER_CMUL) THEN
      REWRITE_TAC[
REAL_MUL_LZERO] THEN
      MATCH_MP_TAC EQ_IMP THEN
      AP_THM_TAC THEN AP_TERM_TAC THEN ABS_TAC THEN
      COND_CASES_TAC THEN ASM_REWRITE_TAC[
REAL_MUL_LZERO] THEN
      CONV_TAC SYM_CONV THEN
      REWRITE_TAC[
REAL_ENTIRE; 
REAL_POW_EQ_0] THEN ASM_MESON_TAC[
EVEN];
      GEN_REWRITE_TAC (LAND_CONV o RAND_CONV) [GSYM 
TAN_0] THEN
      MATCH_MP_TAC 
TAN_ATN THEN
      SIMP_TAC[
PI2_BOUNDS; REAL_ARITH `&0 < x ==> --x < &0`]];
    ALL_TAC] THEN
  ASM_CASES_TAC `x = &0` THEN ASM_REWRITE_TAC[] THEN
  DISCH_THEN(fun th -> GEN_REWRITE_TAC RAND_CONV [SYM th]) THEN
  MP_TAC(SPEC `\x. suminf (\n. (if 
EVEN n then &0
                       else --(&1) pow ((n - 1) DIV 2) / &n) * x pow n) -
          atn x` 
DIFF_ISCONST_END_SIMPLE) THEN
  FIRST_ASSUM(DISJ_CASES_TAC o MATCH_MP (REAL_ARITH
    `~(x = &0) ==> &0 < x \/ x < &0`))
  THENL
   [DISCH_THEN(MP_TAC o SPECL [`&0`; `x:real`]);
    CONV_TAC(RAND_CONV SYM_CONV) THEN
    DISCH_THEN(MP_TAC o SPECL [`x:real`; `&0`])] THEN
  (REWRITE_TAC[] THEN DISCH_THEN MATCH_MP_TAC THEN
   ASM_REWRITE_TAC[] THEN
   X_GEN_TAC `u:real` THEN REPEAT STRIP_TAC THEN
   SUBGOAL_THEN `abs(u) < &1` (MP_TAC o MATCH_MP 
REAL_ATN_POWSER_DIFFL) THENL
    [POP_ASSUM_LIST(MP_TAC o end_itlist CONJ) THEN REAL_ARITH_TAC;
     ALL_TAC] THEN
   DISCH_THEN(MP_TAC o C CONJ (SPEC `u:real` 
DIFF_ATN)) THEN
   DISCH_THEN(MP_TAC o MATCH_MP 
DIFF_SUB) THEN
   REWRITE_TAC[
REAL_SUB_REFL]));;
 
let MCLAURIN_ATN = prove
 (`!x n. abs(x) < &1
           ==> abs(atn x -
                   sum(0,n) (\m. (if 
EVEN m then &0
                                  else --(&1) pow ((m - 1) DIV 2) / &m) *
                                  x pow m))
               <= abs(x) pow n / (&1 - abs x)`,
  REPEAT STRIP_TAC THEN
  FIRST_ASSUM(MP_TAC o MATCH_MP 
REAL_ATN_POWSER) THEN
  DISCH_THEN(fun th -> ASSUME_TAC(SYM(MATCH_MP 
SUM_UNIQ th)) THEN
                       MP_TAC(MATCH_MP 
SUM_SUMMABLE th)) THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
SER_OFFSET) THEN
  DISCH_THEN(MP_TAC o SPEC `n:num`) THEN ASM_REWRITE_TAC[] THEN
  DISCH_THEN(MP_TAC o MATCH_MP 
SUM_UNIQ) THEN
  MATCH_MP_TAC(REAL_ARITH
   `abs(r) <= e ==> (f - s = r) ==> abs(f - s) <= e`) THEN
  SUBGOAL_THEN
   `(\m. abs(x) pow (m + n)) sums (abs(x) pow n) * inv(&1 - abs(x))`
  ASSUME_TAC THENL
   [FIRST_ASSUM(MP_TAC o MATCH_MP 
GP o MATCH_MP (REAL_ARITH
      `abs(x) < &1 ==> abs(abs x) < &1`)) THEN
    DISCH_THEN(MP_TAC o SPEC `abs(x) pow n` o MATCH_MP 
SER_CMUL) THEN
    ONCE_REWRITE_TAC[
ADD_SYM] THEN REWRITE_TAC[GSYM 
REAL_POW_ADD];
    ALL_TAC] THEN
  FIRST_ASSUM(SUBST1_TAC o MATCH_MP 
SUM_UNIQ o REWRITE_RULE[GSYM 
real_div]) THEN
  SUBGOAL_THEN
   `!m. abs((if 
EVEN (m + n) then &0
             else --(&1) pow (((m + n) - 1) DIV 2) / &(m + n)) *
             x pow (m + n))
        <= abs(x) pow (m + n)`
  ASSUME_TAC THENL
   [GEN_TAC THEN COND_CASES_TAC THEN
    SIMP_TAC[
REAL_MUL_LZERO; 
REAL_ABS_NUM; 
REAL_POW_LE; 
REAL_ABS_POS] THEN
    REWRITE_TAC[
REAL_ABS_MUL; 
REAL_ABS_DIV; 
REAL_ABS_POW; 
REAL_ABS_NEG] THEN
    REWRITE_TAC[
REAL_ABS_NUM; 
REAL_POW_ONE; REAL_MUL_LID] THEN
    GEN_REWRITE_TAC RAND_CONV [GSYM REAL_MUL_LID] THEN
    MATCH_MP_TAC 
REAL_LE_RMUL THEN SIMP_TAC[
REAL_POW_LE; 
REAL_ABS_POS] THEN
    REWRITE_TAC[
real_div; REAL_MUL_LID] THEN
    GEN_REWRITE_TAC RAND_CONV [GSYM 
REAL_INV_1] THEN
    MATCH_MP_TAC 
REAL_LE_INV2 THEN CONV_TAC REAL_RAT_REDUCE_CONV THEN
    REWRITE_TAC[REAL_OF_NUM_LE; ARITH_RULE `1 <= n <=> ~(n = 0)`] THEN
    ASM_MESON_TAC[
EVEN]; ALL_TAC] THEN
  MATCH_MP_TAC 
REAL_LE_TRANS THEN
  EXISTS_TAC
   `suminf (\m. abs((if 
EVEN (m + n) then &0
                     else --(&1) pow (((m + n) - 1) DIV 2) / &(m + n)) *
                    x pow (m + n)))` THEN
  CONJ_TAC THENL
   [MATCH_MP_TAC 
SER_ABS THEN MATCH_MP_TAC 
SER_COMPARA THEN
    EXISTS_TAC `\m. abs(x) pow (m + n)` THEN
    ASM_REWRITE_TAC[] THEN ASM_MESON_TAC[
SUM_SUMMABLE]; ALL_TAC] THEN
  MATCH_MP_TAC 
SER_LE THEN ASM_REWRITE_TAC[] THEN CONJ_TAC THENL
   [MATCH_MP_TAC 
SER_COMPARA THEN
    EXISTS_TAC `\m. abs(x) pow (m + n)` THEN
    ASM_REWRITE_TAC[]; ALL_TAC] THEN
  ASM_MESON_TAC[
SUM_SUMMABLE]);;