override_interface ("-->",`(tends_num_real)`);;
prioritize_real();;
(* ---------------------------------------------------------------------- *)
(*  properites of num sequences                                           *)
(* ---------------------------------------------------------------------- *)
(* }}} *)
let LIM_INV_CONST = prove_by_refinement(
  `!c. (\n. c / &n) --> &0`,
(* {{{ Proof *)
[
  ONCE_REWRITE_TAC[REAL_ARITH  `c / &n = c * &1 / &n`];
  STRIP_TAC;
  CONV_TAC (RAND_CONV (ONCE_REWRITE_CONV[REAL_ARITH `&0 = c * &0`]));
  MATCH_MP_TAC 
SEQ_MUL;
  CONJ_TAC THENL [MATCH_ACCEPT_TAC 
SEQ_CONST;MATCH_ACCEPT_TAC 
LIM_INV_1N];
]);;
 
let LIM_MONO = prove_by_refinement(
  `!c d a b. ~(d = &0) /\ a < b ==> (\n. (c * &n pow a) / (d * &n pow b)) --> &0`,
(* {{{ Proof *)
[
  STRIP_TAC THEN STRIP_TAC;
  INDUCT_TAC;
  REPEAT STRIP_TAC;
  REWRITE_TAC[
real_pow;
REAL_MUL_RID];
  POP_ASSUM MP_TAC THEN MATCH_ACCEPT_TAC 
LIM_INV_CON;
  REPEAT STRIP_TAC;
  REWRITE_TAC[
real_pow];
  CLAIM `(b = SUC(
PRE b))`;
  POP_ASSUM MP_TAC THEN ARITH_TAC;
  STRIP_TAC;
  ONCE_ASM_REWRITE_TAC[];
  REWRITE_TAC[
real_pow];
  ONCE_REWRITE_TAC[ARITH_RULE `a * b * c = b * a * c`];
  ONCE_REWRITE_TAC[
REAL_DIV_DISTRIB_2];
  ONCE_REWRITE_TAC[REAL_ARITH `&0 = &1 * &0`];
  MATCH_MP_TAC 
SEQ_MUL;
  CONJ_TAC;
  MATCH_ACCEPT_TAC 
LIM_NN;
  FIRST_ASSUM MATCH_MP_TAC;
  ASM_REWRITE_TAC[];
  LABEL_ALL_TAC;
  USE_THEN "Z-1" MP_TAC;
  ARITH_TAC;
]);;
 
let LIM_POLY_LT = prove_by_refinement(
  `!p k. 
LENGTH p <= k ==> (\n. poly p (&n) / &n pow k) --> &0`,
(* {{{ Proof *)
[
  LIST_INDUCT_TAC;
  REWRITE_TAC[poly;
LENGTH];
  REPEAT STRIP_TAC;
  REWRITE_TAC[
REAL_DIV_LZERO;
SEQ_CONST];
  REWRITE_TAC[poly;
LENGTH];
  REPEAT STRIP_TAC;
  CLAIM `~(k = 0)`;
  POP_ASSUM MP_TAC THEN ARITH_TAC;
  STRIP_TAC;
  LABEL_ALL_TAC;
  CLAIM `
LENGTH t <= 
PRE k`;
  USE_THEN "Z-1" MP_TAC THEN ARITH_TAC;
  DISCH_THEN (fun x -> FIRST_ASSUM (fun y -> MP_TAC (MATCH_MP y x)));
  STRIP_TAC;
  REWRITE_TAC[
REAL_DIV_ADD_DISTRIB];
  ONCE_REWRITE_TAC[REAL_ARITH `&0 = &0 + &0`];
  MATCH_MP_TAC 
SEQ_ADD;
  CONJ_TAC;
  ONCE_REWRITE_TAC[ARITH_RULE `n pow k = &1 * n pow k`];
  MATCH_MP_TAC 
LIM_INV_CON;
  USE_THEN "Z-0" MP_TAC THEN ARITH_TAC;
  CLAIM `k = SUC (
PRE k)`;
  USE_THEN "Z-0" MP_TAC THEN ARITH_TAC;
  STRIP_TAC;
  ONCE_ASM_REWRITE_TAC[];
  REWRITE_TAC[
real_pow];
  REWRITE_TAC[
REAL_DIV_DISTRIB_2];
  ONCE_REWRITE_TAC[REAL_ARITH `&0 = &1 * &0`];
  MATCH_MP_TAC 
SEQ_MUL;
  CONJ_TAC;
  MATCH_ACCEPT_TAC 
LIM_NN;
  FIRST_ASSUM MATCH_MP_TAC;
  USE_THEN "Z-1" MP_TAC THEN ARITH_TAC;
]);;
 
let mono_inc = new_definition(
  `mono_inc (f:num -> real) = !(m:num) n. m <= n ==> f m <= f n`);;
let mono_dec = new_definition(
  `mono_dec (f:num -> real) = !(m:num) n. m <= n ==> f n <= f m`);;
let mono_unbounded_below_neg = prove_by_refinement(
 `
mono_unbounded_below (f:num -> real) = !c. c <= &0 ==> ?N. !n. N <= n ==> f n < c`,
(* {{{ Proof *)
[
  REWRITE_TAC[
mono_unbounded_below];
  EQ_TAC THENL [ASM_MESON_TAC[];ALL_TAC];
  REPEAT STRIP_TAC;
  POP_ASSUM (ASSUME_TAC o ISPEC `-- (abs c)`);
  POP_ASSUM (MP_TAC o (C MATCH_MP) (ISPEC `c:real` 
NEG_ABS));
  STRIP_TAC;
  EXISTS_TAC `N`;
  GEN_TAC;
  DISCH_THEN (fun x -> POP_ASSUM (fun y -> ASSUME_TAC (MATCH_MP y x)));
  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
]);;
 
let mua_quotient_limit = prove_by_refinement(
 `!k f g. &0 < k /\ (\n. f n / g n) --> k /\ 
mono_unbounded_above g
    ==> 
mono_unbounded_above f`,
(* {{{ Proof *)
[
  REWRITE_TAC[
SEQ;
mono_unbounded_above_pos;AND_IMP_THM];
  REPEAT GEN_TAC;
  STRIP_TAC;
  CLAIM `&0 < k / &2`;
  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  DISCH_THEN (fun x -> DISCH_THEN (fun y -> (ASSUME_TAC (MATCH_MP (ISPEC `k / &2` y) x))));
  POP_ASSUM (X_CHOOSE_TAC `M:num`);
  STRIP_TAC;
  X_GEN_TAC `d:real`;
  STRIP_TAC;
  CLAIM `&0 <= &2 * d / k`;
  MATCH_MP_TAC 
REAL_LE_MUL;
  CONJ_TAC THENL [REAL_ARITH_TAC;ALL_TAC];
  MATCH_MP_TAC 
REAL_LE_DIV;
  CONJ_TAC THENL [FIRST_ASSUM MATCH_ACCEPT_TAC;ASM_MESON_TAC[
REAL_LT_LE]];
  STRIP_TAC;
  LABEL_ALL_TAC;
  MOVE_TO_FRONT "Z-2";
 
let NORMALIZE_PAIR = prove_by_refinement(
  `!x y. ~(y = &0) <=> (normalize [x; y] = [x; y])`,
(* {{{ Proof *)
[
  REWRITE_TAC[normalize;
NOT_CONS_NIL];
  REPEAT GEN_TAC;
  COND_CASES_TAC;
  CLAIM `y = &0`;
  ASM_MESON_TAC !LIST_REWRITES;
  DISCH_THEN SUBST1_TAC;
  ASM_MESON_TAC !LIST_REWRITES;
  ASM_MESON_TAC !LIST_REWRITES;
]);;
 
let POLY_NORMALIZE = prove
 (`!p. poly (normalize p) = poly p`,
(* {{{ Proof *)
  LIST_INDUCT_TAC THEN REWRITE_TAC[normalize; poly] THEN
  ASM_CASES_TAC `h = &0` THEN ASM_REWRITE_TAC[] THEN
  COND_CASES_TAC THEN ASM_REWRITE_TAC[poly; 
FUN_EQ_THM] THEN
  UNDISCH_TAC `poly (normalize t) = poly t` THEN
  DISCH_THEN(SUBST1_TAC o SYM) THEN ASM_REWRITE_TAC[poly] THEN
  REWRITE_TAC[
REAL_MUL_RZERO; REAL_ADD_LID]);;
 
let LIM_POLY2 = prove_by_refinement(
  `!p. normal p ==> (\n. poly p (&n) / (
LAST p * &n pow (degree p))) --> &1`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  REWRITE_TAC[degree];
  CLAIM `normalize p = p`;
  ASM_MESON_TAC[normal];
  DISCH_THEN SUBST1_TAC;
  MATCH_MP_TAC 
LIM_POLY;
  ASM_MESON_TAC[
NORMAL_ID];
]);;
 
let POLY_LAST_GT = prove_by_refinement(
  `!p. normal p /\ (?X. !x. X < x ==> &0 < poly p x) ==> &0 < 
LAST p`,
(* {{{ Proof *)
[
  GEN_TAC;
  CASES_ON `
LENGTH p = 1`;
  RULE_ASSUM_TAC (REWRITE_RULE[
LENGTH_1]);
  POP_ASSUM MP_TAC THEN STRIP_TAC;
  ASM_REWRITE_TAC[
LAST_SING;
POLY_SING];
  REPEAT STRIP_TAC;
  FIRST_ASSUM MATCH_MP_TAC;
  EXISTS_TAC `X + &1`;
  REAL_ARITH_TAC;
  (* *)
  REWRITE_TAC[AND_IMP_THM;];
  DISCH_THEN (fun x -> MP_TAC (MATCH_MP 
LIM_POLY2 x) THEN ASSUME_TAC x);
  REPEAT STRIP_TAC;
  DISJ_CASES_TAC (ISPECL [`&0`;`
LAST (p:real list)`] 
REAL_LT_TOTAL);
  ASM_MESON_TAC[
NORMAL_ID];
  POP_ASSUM DISJ_CASES_TAC;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
  (* save *)
  CLAIM `
mono_unbounded_below (\n. 
LAST p * &n pow degree p)`;
  MATCH_MP_TAC 
POW_UNBB_CON;
  REWRITE_TAC[degree];
  CONJ_TAC THENL [ALL_TAC;FIRST_ASSUM MATCH_ACCEPT_TAC];
  CLAIM `normalize p = p`;
  ASM_MESON_TAC[normal];
  DISCH_THEN SUBST1_TAC;
  CLAIM `~(
LENGTH p = 0)`;
  ASM_MESON_TAC[normal;
LENGTH_EQ_NIL];
  LABEL_ALL_TAC;
  USE_THEN "Z-4" MP_TAC;
  ARITH_TAC;
  (* save *)
  STRIP_TAC;
  CLAIM `
mono_unbounded_below (\n. poly p (&n))`;
  MATCH_MP_TAC 
mua_quotient_limit_neg;
  BETA_TAC;
  EXISTS_TAC `&1`;
  EXISTS_TAC `(\n. 
LAST p * &n pow degree p)`;
  REPEAT STRIP_TAC;
  REAL_ARITH_TAC;
  BETA_TAC;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
  REWRITE_TAC[
mono_unbounded_below];
  DISCH_THEN (MP_TAC o ISPEC `&0`);
  STRIP_TAC;
  LABEL_ALL_TAC;
  USE_THEN "Z-3" MP_TAC;
  POP_ASSUM MP_TAC;
  POP_ASSUM_LIST (fun x -> ALL_TAC);
  MP_TAC (ISPEC `X:real` 
REAL_ARCH_SIMPLE);
  STRIP_TAC;
  DISCH_THEN (ASSUME_TAC o ISPEC `1 + nmax N n`);
  DISCH_THEN (ASSUME_TAC o ISPEC `&1 + &(nmax N n)`);
  POP_ASSUM MP_TAC THEN ANTS_TAC;
  REWRITE_TAC[nmax];
  COND_CASES_TAC;
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  RULE_ASSUM_TAC (REWRITE_RULE[
NOT_LE;GSYM 
REAL_LT]);
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  POP_ASSUM MP_TAC THEN ANTS_TAC;
  REWRITE_TAC[nmax];
  ARITH_TAC;
  ASM_MESON_TAC[ARITH_RULE `~(x < y /\ y < x)`;GSYM REAL_OF_NUM_ADD];
]);;
 
let POLY_LAST_LT = prove_by_refinement(
  `!p. normal p /\ (?X. !x. X < x ==> poly p x < &0) ==> 
LAST p < &0`,
(* {{{ Proof *)
[
  GEN_TAC;
  CASES_ON `
LENGTH p = 1`;
  RULE_ASSUM_TAC (REWRITE_RULE[
LENGTH_1]);
  POP_ASSUM MP_TAC THEN STRIP_TAC;
  ASM_REWRITE_TAC[
LAST_SING;
POLY_SING];
  REPEAT STRIP_TAC;
  FIRST_ASSUM MATCH_MP_TAC;
  EXISTS_TAC `X + &1`;
  REAL_ARITH_TAC;
  (* *)
  REWRITE_TAC[AND_IMP_THM;];
  DISCH_THEN (fun x -> MP_TAC (MATCH_MP 
LIM_POLY2 x) THEN ASSUME_TAC x);
  REPEAT STRIP_TAC;
  DISJ_CASES_TAC (ISPECL [`&0`;`
LAST (p:real list)`] 
REAL_LT_TOTAL);
  ASM_MESON_TAC[
NORMAL_ID];
  POP_ASSUM DISJ_CASES_TAC THENL [ALL_TAC;FIRST_ASSUM MATCH_ACCEPT_TAC];
  (* save *)
  CLAIM `
mono_unbounded_above (\n. 
LAST p * &n pow degree p)`;
  MATCH_MP_TAC 
POW_UNB_CON;
  REWRITE_TAC[degree];
  CONJ_TAC THENL [ALL_TAC;FIRST_ASSUM MATCH_ACCEPT_TAC];
  CLAIM `normalize p = p`;
  ASM_MESON_TAC[normal];
  DISCH_THEN SUBST1_TAC;
  CLAIM `~(
LENGTH p = 0)`;
  ASM_MESON_TAC[normal;
LENGTH_EQ_NIL];
  LABEL_ALL_TAC;
  USE_THEN "Z-4" MP_TAC;
  ARITH_TAC;
  (* save *)
  STRIP_TAC;
  CLAIM `
mono_unbounded_above (\n. poly p (&n))`;
  MATCH_MP_TAC 
mua_quotient_limit;
  BETA_TAC;
  EXISTS_TAC `&1`;
  EXISTS_TAC `(\n. 
LAST p * &n pow degree p)`;
  REPEAT STRIP_TAC;
  REAL_ARITH_TAC;
  BETA_TAC;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
  REWRITE_TAC[
mono_unbounded_above];
  DISCH_THEN (MP_TAC o ISPEC `&0`);
  STRIP_TAC;
  LABEL_ALL_TAC;
  USE_THEN "Z-3" MP_TAC;
  POP_ASSUM MP_TAC;
  POP_ASSUM_LIST (fun x -> ALL_TAC);
  MP_TAC (ISPEC `X:real` 
REAL_ARCH_SIMPLE);
  STRIP_TAC;
  DISCH_THEN (ASSUME_TAC o ISPEC `1 + nmax N n`);
  DISCH_THEN (ASSUME_TAC o ISPEC `&1 + &(nmax N n)`);
  POP_ASSUM MP_TAC THEN ANTS_TAC;
  REWRITE_TAC[nmax];
  COND_CASES_TAC;
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  RULE_ASSUM_TAC (REWRITE_RULE[
NOT_LE;GSYM 
REAL_LT]);
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  POP_ASSUM MP_TAC THEN ANTS_TAC;
  REWRITE_TAC[nmax];
  ARITH_TAC;
  ASM_MESON_TAC[ARITH_RULE `~(x < y /\ y < x)`;GSYM REAL_OF_NUM_ADD];
]);;
 
let DEGREE_SING = prove_by_refinement(
  `!x. (degree [x] = 0)`,
(* {{{ Proof *)
[
  REWRITE_TAC[degree];
  STRIP_TAC;
  CASES_ON `x = &0`;
  ASM_REWRITE_TAC[normalize;
LENGTH];
  ARITH_TAC;
  CLAIM `normalize [x] = [x]`;
  ASM_MESON_TAC[
NORMALIZE_SING];
  DISCH_THEN SUBST1_TAC;
  REWRITE_TAC[
LENGTH];
  ARITH_TAC;
]);;
 
let DEGREE_CONS = prove_by_refinement(
  `!h t. normal t ==> (degree (CONS h t) = 1 + degree t)`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  CLAIM `normal (CONS h t)`;
  ASM_MESON_TAC[
NORMAL_CONS];
  REWRITE_TAC[normal;degree];
  STRIP_TAC;
  ASM_REWRITE_TAC[];
  RULE_ASSUM_TAC (REWRITE_RULE[normal]);
  CLAIM `~(
LENGTH t = 0)`;
  ASM_MESON_TAC[
LENGTH_0];
  STRIP_TAC;
  ASM_REWRITE_TAC[
LENGTH];
  POP_ASSUM MP_TAC THEN ARITH_TAC;
]);;
 
let NONCONSTANT_DEGREE = prove_by_refinement(
  `!p. nonconstant p ==> 0 < degree p`,
(* {{{ Proof *)
[
  GEN_TAC;
  DISCH_THEN (fun x -> ASSUME_TAC x THEN MP_TAC x);
  REWRITE_TAC[nonconstant;degree];
  REPEAT STRIP_TAC;
  CLAIM `normalize p = p`;
  ASM_MESON_TAC[normal];
  STRIP_TAC;
  ASM_REWRITE_TAC[];
  CLAIM `1 < 
LENGTH p`;
  ASM_MESON_TAC[
NONCONSTANT_LENGTH];
  ARITH_TAC;
]);;
 
let NONCONSTANT_DIFF_0 = prove_by_refinement(
  `!p. nonconstant p ==> ~(
poly_diff p = [&0])`,
(* {{{ Proof *)
[
  STRIP_TAC;
  DISCH_THEN (fun x -> MP_TAC x THEN ASSUME_TAC x);
  REWRITE_TAC[nonconstant];
  REPEAT STRIP_TAC;
  CLAIM `~(p = [])`;
  ASM_MESON_TAC[normal];
  DISCH_THEN (fun x -> RULE_ASSUM_TAC (REWRITE_RULE[x]) THEN ASSUME_TAC x);
  CLAIM `~(
LAST p = &0)`;
  MATCH_MP_TAC 
NORMAL_LAST_NONZERO;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
  STRIP_TAC;
  CLAIM `
LAST p * &(degree p) = &0`;
  ASM_SIMP_TAC[GSYM 
POLY_DIFF_LAST_LEM];
  REWRITE_TAC[
LAST];
  STRIP_TAC;
  CLAIM `(
LAST p = &0) \/ (&(degree p) = &0)`;
  ASM_MESON_TAC[
REAL_ENTIRE];
  STRIP_TAC;
  ASM_MESON_TAC[];
  CLAIM `?h t. p = CONS h t`;
  ASM_MESON_TAC[
list_CASES];
  STRIP_TAC;
  CLAIM `normal t`;
  ASM_MESON_TAC[
NORMAL_TAIL];
  STRIP_TAC;
  FIRST_ASSUM (MP_TAC o (MATCH_MP (ISPECL [`h:real`;`t:real list`] 
DEGREE_CONS)));
  STRIP_TAC;
  CLAIM `degree p = 0`;
  ASM_MESON_TAC [REAL_OF_NUM_EQ];
  ASM_REWRITE_TAC[];
  ARITH_TAC;
]);;
 
let POLY_DIFF_UP_RIGHT = prove_by_refinement(
 `nonconstant p /\ (?X. !x. X < x ==> &0 < poly (
poly_diff p) x) ==>
   (?Y. !y. Y < y ==> &0 < poly p y)`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  CLAIM `
mono_unbounded_above (\n. poly p (&n))`;
  MATCH_MP_TAC 
LAST_UNB;
  ASM_MESON_TAC[
PDIFF_POS_LAST];
  REWRITE_TAC[
mono_unbounded_above];
  DISCH_THEN (MP_TAC o (ISPEC `&0`));
  STRIP_TAC;
  CLAIM `?K. max X (&N) < &K`;
  ASM_MESON_TAC[
REAL_ARCH_SIMPLE_LT];
  STRIP_TAC;
  EXISTS_TAC `&K`;
  REPEAT STRIP_TAC;
  CCONTR_TAC;
  REWRITE_ASSUMS[
REAL_NOT_LT];
  CLAIM `&N < y /\ X < y`;
  ASM_MESON_TAC([
REAL_MAX_MAX] @ !REAL_REWRITES);
  REPEAT STRIP_TAC;
  MP_TAC (ISPECL [`p:real list`;`&K`;`y:real`] 
POLY_MVT);
  ANTS_TAC;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
  STRIP_TAC;
  CLAIM `poly p y - poly p (&K) <= &0`;
  MATCH_MP_TAC (REAL_ARITH `x <= &0 /\ &0 < y ==> x - y <= &0`);
  ASM_REWRITE_TAC[];
  FIRST_ASSUM MATCH_MP_TAC;
  CLAIM `&N < &K`;
  ASM_MESON_TAC [
REAL_MAX_MAX;
REAL_LET_TRANS];
  STRIP_TAC;
  CLAIM `N:num < K`;
  ASM_MESON_TAC [
REAL_OF_NUM_LT];
  ARITH_TAC;
  STRIP_TAC;
  CLAIM `&0 < y - &K`;
  LABEL_ALL_TAC;
  USE_THEN "Z-7" MP_TAC;
  REAL_ARITH_TAC;
  STRIP_TAC;
  CLAIM `&0 < poly (
poly_diff p) x`;
  FIRST_ASSUM MATCH_MP_TAC;
  ASM_MESON_TAC[
REAL_MAX_MAX;
REAL_LET_TRANS;
REAL_LT_TRANS];
  STRIP_TAC;
  CLAIM `&0 < (y - &K) * poly (
poly_diff p) x`;
  ONCE_REWRITE_TAC [ARITH_RULE `&0 = &0 * &0`];
  MATCH_MP_TAC 
REAL_LT_MUL2 THEN REPEAT STRIP_TAC THEN TRY REAL_ARITH_TAC THEN FIRST_ASSUM MATCH_ACCEPT_TAC;
  STRIP_TAC;
  REAL_SOLVE_TAC;
]);;
 
let POLY_DIFF_DOWN_RIGHT = prove_by_refinement(
 `nonconstant p /\ (?X. !x. X < x ==> poly (
poly_diff p) x < &0) ==>
   (?Y. !y. Y < y ==> poly p y < &0)`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  CLAIM `
mono_unbounded_below (\n. poly p (&n))`;
  MATCH_MP_TAC 
LAST_UNB_NEG;
  ASM_MESON_TAC[
PDIFF_NEG_LAST];
  REWRITE_TAC[
mono_unbounded_below];
  DISCH_THEN (MP_TAC o (ISPEC `&0`));
  STRIP_TAC;
  CLAIM `?K. max X (&N) < &K`;
  ASM_MESON_TAC[
REAL_ARCH_SIMPLE_LT];
  STRIP_TAC;
  EXISTS_TAC `&K`;
  REPEAT STRIP_TAC;
  CCONTR_TAC;
  REWRITE_ASSUMS[
REAL_NOT_LT];
  CLAIM `&N < y /\ X < y`;
  ASM_MESON_TAC([
REAL_MAX_MAX] @ !REAL_REWRITES);
  REPEAT STRIP_TAC;
  MP_TAC (ISPECL [`p:real list`;`&K`;`y:real`] 
POLY_MVT);
  ANTS_TAC;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
  STRIP_TAC;
  CLAIM `&0 <= poly p y - poly p (&K)`;
  MATCH_MP_TAC (REAL_ARITH `&0 <= x /\ y < &0 ==> &0 <= x - y`);
  ASM_REWRITE_TAC[];
  FIRST_ASSUM MATCH_MP_TAC;
  CLAIM `&N < &K`;
  ASM_MESON_TAC (!REAL_REWRITES @ !NUM_REWRITES);
  STRIP_TAC;
  CLAIM `N:num < K`;
  ASM_MESON_TAC [
REAL_OF_NUM_LT];
  ARITH_TAC;
  STRIP_TAC;
  CLAIM `&0 < y - &K`;
  LABEL_ALL_TAC;
  USE_THEN "Z-7" MP_TAC;
  REAL_ARITH_TAC;
  STRIP_TAC;
  CLAIM `poly (
poly_diff p) x < &0`;
  FIRST_ASSUM MATCH_MP_TAC;
  REAL_SOLVE_TAC;
  STRIP_TAC;
  CLAIM `(y - &K) * poly (
poly_diff p) x < &0`;
  ASM_MESON_TAC[
REAL_MUL_LT];
  REPEAT STRIP_TAC;
  REAL_SOLVE_TAC;
]);;
 
let MUA_DIV_CONST = prove_by_refinement(
  `!a b p. 
mono_unbounded_above (\n. p n) ==> (\n. a / (b + p n)) --> &0`,
(* {{{ Proof *)
[
  REWRITE_TAC[
mono_unbounded_above;
SEQ];
  REPEAT STRIP_TAC;
  REAL_SIMP_TAC;
  CASES_ON `a = &0`;
  ASM_REWRITE_TAC[
real_div;
REAL_MUL_LZERO;
ABS_0];
  ABBREV_TAC `k = (max (&1) (abs a / e - b))`;
  FIRST_ASSUM (MP_TAC o (ISPEC `k:real`));
  STRIP_TAC;
  EXISTS_TAC `N`;
  REPEAT STRIP_TAC;
  REWRITE_ASSUMS (!REAL_REWRITES @ !NUM_REWRITES);
  POP_ASSUM (fun x -> POP_ASSUM (fun y -> ASSUME_TAC (MATCH_MP y x)));
  REWRITE_TAC[
REAL_ABS_DIV];
  MATCH_MP_TAC 
REAL_LTE_TRANS;
  EXISTS_TAC `abs a / (b + k)`;
  STRIP_TAC;
  MATCH_MP_TAC 
REAL_DIV_DENOM_LT;
  REPEAT STRIP_TAC;
  ASM_MESON_TAC[
REAL_ABS_NZ];
  LABEL_ALL_TAC;
  CLAIM `(abs a / e - b) <= k`;
  ASM_MESON_TAC[
REAL_MAX_MAX];
  STRIP_TAC;
  CLAIM `&0 < abs a / e`;
  REWRITE_TAC[
real_div];
  MATCH_MP_TAC 
REAL_LT_MUL;
  ASM_MESON_TAC[
REAL_INV_POS;
REAL_ABS_NZ];
  STRIP_TAC;
  POP_ASSUM MP_TAC THEN POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  CLAIM `-- b < p n`;
  MATCH_MP_TAC 
REAL_LET_TRANS;
  EXISTS_TAC `k`;
  ASM_REWRITE_TAC[];
  CLAIM `(abs a / e - b) <= k`;
  ASM_MESON_TAC[
REAL_MAX_MAX];
  STRIP_TAC;
  CLAIM `&0 < abs a / e`;
  REWRITE_TAC[
real_div];
  MATCH_MP_TAC 
REAL_LT_MUL;
  ASM_MESON_TAC[
REAL_INV_POS;
REAL_ABS_NZ];
  STRIP_TAC;
  POP_ASSUM MP_TAC THEN POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  STRIP_TAC;
  CLAIM `abs (b + p n) = b + p n`;
  MATCH_EQ_MP_TAC 
REAL_ABS_REFL;
  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  DISCH_THEN SUBST1_TAC;
  POP_ASSUM MP_TAC THEN POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  CLAIM `(abs a / e - b) <= k`;
  ASM_MESON_TAC[
REAL_MAX_MAX];
  STRIP_TAC;
  CLAIM `&0 < abs a / e`;
  REWRITE_TAC[
real_div];
  MATCH_MP_TAC 
REAL_LT_MUL;
  ASM_MESON_TAC[
REAL_INV_POS;
REAL_ABS_NZ];
  STRIP_TAC;
  LABEL_ALL_TAC;
  CLAIM `abs a / e <= b + k`;
  USE_THEN "Z-1" MP_TAC THEN REAL_ARITH_TAC;
  STRIP_TAC;
  CASES_ON `&1 <= abs a / e - b`;
  CLAIM `k = abs a / e - b`;
  USE_THEN "Z-3" (SUBST1_TAC o GSYM);
  ASM_REWRITE_TAC[
real_max];
  ASM_MESON_TAC[
real_max];
  DISCH_THEN SUBST1_TAC;
  REWRITE_TAC[ARITH_RULE `b + a - b = a`];
  REWRITE_TAC[
real_div;];
  REAL_SIMP_TAC;
  REWRITE_TAC[REAL_MUL_ASSOC];
  CLAIM `~(abs a = &0)`;
  ASM_MESON_TAC[
REAL_ABS_NZ;
REAL_LT_LE];
  STRIP_TAC;
  ASM_SIMP_TAC[
REAL_MUL_RINV];
  REAL_SIMP_TAC;
  (* save *)
  REWRITE_ASSUMS !REAL_REWRITES;
  CLAIM `k = &1`;
  ASM_MESON_TAC([
real_max] @ !REAL_REWRITES);
  STRIP_TAC;
  CLAIM `&0 < b + k`;
  MATCH_MP_TAC 
REAL_LTE_TRANS;
  EXISTS_TAC `abs a / e`;
  ASM_MESON_TAC[];
  STRIP_TAC;
  MATCH_MP_TAC 
REAL_LE_RCANCEL_IMP;
  EXISTS_TAC `b + k`;
  ASM_REWRITE_TAC[];
  REWRITE_TAC[
real_div];
  REWRITE_TAC[GSYM REAL_MUL_ASSOC];
  CLAIM `inv (b + &1) * (b + &1) = &1`;
  LABEL_ALL_TAC;
  POP_ASSUM MP_TAC;
  ASM_REWRITE_TAC[];
  STRIP_TAC;
  ASM_MESON_TAC[REAL_MUL_LINV;
REAL_LT_LE];
  DISCH_THEN SUBST1_TAC;
  REWRITE_TAC[
REAL_MUL_RID];
  MATCH_MP_TAC 
REAL_LE_LCANCEL_IMP;
  EXISTS_TAC `inv e`;
  REPEAT STRIP_TAC;
  USE_THEN "Z-5" MP_TAC;
  MESON_TAC[
REAL_INV_POS;
REAL_LT_LE];
  REWRITE_TAC[REAL_MUL_ASSOC];
  CLAIM `~(e = &0)`;
  ASM_MESON_TAC[REAL_INV_NZ;
REAL_LT_LE];
  STRIP_TAC;
  ASM_SIMP_TAC[REAL_MUL_LINV];
  REAL_SIMP_TAC;
  ASM_MESON_TAC[
real_div;REAL_MUL_SYM]
]);;
 
let SEQ_0_NEG = prove_by_refinement(
  `!p. (\n. p n) --> &0 <=> (\n. -- p n) --> &0`,
(* {{{ Proof *)
[
  REWRITE_TAC[
SEQ];
  GEN_TAC THEN EQ_TAC;
  REPEAT STRIP_TAC;
  LABEL_ALL_TAC;
  USE_THEN "Z-0" (fun x -> FIRST_ASSUM (fun y -> MP_TAC (MATCH_MP y x)));
  STRIP_TAC;
  EXISTS_TAC `N`;
  REPEAT STRIP_TAC;
  POP_ASSUM  (fun x -> FIRST_ASSUM (fun y -> MP_TAC (MATCH_MP y x)));
  REAL_SIMP_TAC;
  STRIP_TAC;
  ASM_MESON_TAC[
REAL_ABS_NEG];
  REPEAT STRIP_TAC;
  LABEL_ALL_TAC;
  USE_THEN "Z-0" (fun x -> FIRST_ASSUM (fun y -> MP_TAC (MATCH_MP y x)));
  STRIP_TAC;
  EXISTS_TAC `N`;
  REPEAT STRIP_TAC;
  POP_ASSUM  (fun x -> FIRST_ASSUM (fun y -> MP_TAC (MATCH_MP y x)));
  REAL_SIMP_TAC;
  STRIP_TAC;
  ASM_MESON_TAC[
REAL_ABS_NEG];
]);;
 
let lem = prove_by_refinement(
  `!x y z. --(x / (y + z)) = x / (-- y + -- z)`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  REWRITE_TAC[
real_div];
  REWRITE_TAC[ARITH_RULE `--(x * y) = x * -- y`];
  REWRITE_TAC[ARITH_RULE `-- y + -- z = --(y + z)`];
  REWRITE_TAC[
REAL_INV_NEG];
]);;
 
let MUA_MUA = prove_by_refinement(
  `!p q. 
mono_unbounded_above (\n. p n) /\ 
mono_unbounded_above (\n. q n) ==>
           
mono_unbounded_above (\n. p n * q n)`,
(* {{{ Proof *)
[
  REWRITE_TAC[
mono_unbounded_above_pos];
  REPEAT STRIP_TAC;
  CLAIM `&0 <= max c (&1)`;
  REWRITE_TAC[
real_max];
  COND_CASES_TAC;
  REAL_ARITH_TAC;
  ASM_REWRITE_TAC[];
  DISCH_THEN (fun y -> POP_ASSUM (fun x -> RULE_ASSUM_TAC (C MATCH_MP y) THEN ASSUME_TAC x));
  EVERY_ASSUM MP_TAC THEN REPEAT STRIP_TAC;
  EXISTS_TAC `nmax N N'`;
  REPEAT STRIP_TAC;
  MATCH_MP_TAC 
REAL_LET_TRANS;
  EXISTS_TAC `max c (&1)`;
  ASM_REWRITE_TAC[
REAL_MAX_MAX];
  MATCH_MP_TAC 
REAL_LET_TRANS;
  EXISTS_TAC `max c (&1) * max c (&1)`;
  REPEAT STRIP_TAC;
  CONV_TAC (LAND_CONV (ONCE_REWRITE_CONV [GSYM 
REAL_MUL_RID]));
  MATCH_MP_TAC 
REAL_LE_MUL2;
  REPEAT STRIP_TAC;
  REAL_SOLVE_TAC;
  REAL_SIMP_TAC;
  REAL_ARITH_TAC;
  REAL_SOLVE_TAC;
  MATCH_MP_TAC 
REAL_LT_MUL2;
  REPEAT STRIP_TAC;
  REAL_SOLVE_TAC;
  CLAIM `N <= n /\ N' <= (n:num)`;
  POP_ASSUM MP_TAC;
  REWRITE_TAC[nmax];
  COND_CASES_TAC;
  REPEAT STRIP_TAC;
  POP_ASSUM MP_TAC THEN POP_ASSUM MP_TAC THEN ARITH_TAC;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
  REPEAT STRIP_TAC;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
  POP_ASSUM MP_TAC THEN POP_ASSUM MP_TAC THEN ARITH_TAC;
  REPEAT STRIP_TAC;
  FIRST_ASSUM MATCH_MP_TAC;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
  REAL_SOLVE_TAC;
  FIRST_ASSUM MATCH_MP_TAC;
  POP_ASSUM MP_TAC THEN REWRITE_TAC[nmax] THEN ARITH_TAC;
]);;
 
let POLY_PNEG_AUX = prove_by_refinement(
 `!k p n. 
EVEN n ==> (poly p (-- k) = poly (
pneg_aux n p) k)`,
(* {{{ Proof *)
[
  STRIP_TAC;
  LIST_INDUCT_TAC;
  REPEAT STRIP_TAC;
  REWRITE_TAC[
pneg_aux;poly];
  REPEAT STRIP_TAC;
  POP_ASSUM (fun x -> RULE_ASSUM_TAC (fun y -> MATCH_MP y x) THEN ASSUME_TAC x);
  REWRITE_TAC[poly;
pneg_aux];
  REAL_SIMP_TAC;
  ASM_REWRITE_TAC[];
  REAL_SIMP_TAC;
  CLAIM `-- &1 pow n = &1`;
  REWRITE_TAC[
REAL_POW_NEG];
  ASM_REWRITE_TAC[];
  REAL_SIMP_TAC;
  DISCH_THEN SUBST1_TAC;
  REAL_SIMP_TAC;
  AP_TERM_TAC;
  CONV_TAC (LAND_CONV (ONCE_REWRITE_CONV[GSYM 
POLY_PNEG_NEG]));
  REWRITE_TAC[
POLY_NEG];
  REAL_SIMP_TAC;
]);;
 
let POLY_PNEG = prove_by_refinement(
 `!p x. poly p (-- x) = poly (pneg p) x`,
(* {{{ Proof *)
[
  LIST_INDUCT_TAC;
  REWRITE_TAC[pneg;poly];
  REWRITE_TAC[pneg;poly];
  REPEAT STRIP_TAC;
  CLAIM `poly (
pneg_aux 0 (CONS h t)) x = poly (CONS h t) (--x)`;
  ASM_MESON_TAC[
POLY_PNEG_AUX;
EVEN];
  DISCH_THEN SUBST1_TAC;
  REWRITE_TAC[poly];
]);;
 
let PNEG_LAST = prove_by_refinement(
  `!p. ~(p = []) ==> (
LAST (pneg p) = 
LAST p) \/ (
LAST (pneg p) = -- 
LAST p)`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  CASES_ON `normal p`;
  MP_TAC (ISPEC `p:real list` 
POLY_PNEG_LAST);
  ASM_REWRITE_TAC[];
  STRIP_TAC;
  DISJ_CASES_TAC (ISPEC `degree p` 
EVEN_OR_ODD);
  ASM_MESON_TAC[];
  ASM_MESON_TAC !REAL_REWRITES;
  REWRITE_ASSUMS[
NORMAL_ID;DE_MORGAN_THM;];
  POP_ASSUM MP_TAC THEN STRIP_TAC;
  CLAIM `
LENGTH p = 0`;
  POP_ASSUM MP_TAC THEN ARITH_TAC;
  ASM_MESON_TAC[
LENGTH_0];
  ASM_REWRITE_TAC[];
  DISJ1_TAC;
  ASM_MESON_TAC[
LAST_PNEG_0];
]);;
 
let NORMAL_PNEG = prove_by_refinement(
 `!p. normal p = normal (pneg p)`,
(* {{{ Proof *)
[
  REWRITE_TAC[
NORMAL_ID];
  REPEAT STRIP_TAC;
  EQ_TAC;
  REPEAT STRIP_TAC;
  ASM_MESON_TAC[
PNEG_LENGTH];
  MP_TAC (ISPEC `p:real list` 
PNEG_LAST);
  CLAIM `~(p = [])`;
  ASM_MESON_TAC[
LENGTH_NZ];
  STRIP_TAC;
  ASM_REWRITE_TAC[];
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  (* save *)
  REPEAT STRIP_TAC;
  ONCE_REWRITE_TAC[GSYM 
PNEG_LENGTH];
  ASM_REWRITE_TAC[];
  MP_TAC (ISPEC `p:real list` 
PNEG_LAST);
  CLAIM `~(p = [])`;
  ASM_MESON_TAC[
LENGTH_NZ;
PNEG_LENGTH];
  STRIP_TAC;
  ASM_REWRITE_TAC[];
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
]);;
 
let PNEG_SING = prove_by_refinement(
 `!p. (pneg p = [x]) <=> (p = [x])`,
(* {{{ Proof *)
[
  LIST_INDUCT_TAC;
  REWRITE_TAC[pneg;
pneg_aux];
  EQ_TAC;
  REPEAT STRIP_TAC;
  LIST_SIMP_TAC;
  STRIP_TAC;
  REWRITE_ASSUMS[pneg;
pneg_aux];
  POP_ASSUM MP_TAC;
  REAL_SIMP_TAC;
  LIST_SIMP_TAC;
  MESON_TAC[];
  POP_ASSUM MP_TAC;
  REWRITE_TAC[pneg;
pneg_aux];
  LIST_SIMP_TAC;
  ASM_MESON_TAC[
PNEG_AUX_NIL];
  REWRITE_TAC[pneg;
pneg_aux];
  REAL_SIMP_TAC;
  LIST_SIMP_TAC;
  STRIP_TAC;
  ASM_MESON_TAC[
pneg_aux];
]);;
 
let PNEG_NONCONSTANT = prove_by_refinement(
 `!p. nonconstant (pneg p) = nonconstant p`,
(* {{{ Proof *)
[
  REWRITE_TAC[nonconstant];
  STRIP_TAC THEN EQ_TAC;
  REPEAT STRIP_TAC;
  ASM_MESON_TAC[
NORMAL_PNEG];
  POP_ASSUM (REWRITE_ASSUMS o list);
  REWRITE_ASSUMS[pneg;
pneg_aux];
  POP_ASSUM MP_TAC;
  REAL_SIMP_TAC;
  MESON_TAC[];
  REPEAT STRIP_TAC;
  ASM_MESON_TAC[
NORMAL_PNEG];
  ASM_MESON_TAC[
PNEG_SING];
]);;
 
let poly_diff_aux_odd = prove_by_refinement(
 `!p n. nonconstant p ==>
  (
EVEN (degree p) = 
EVEN (degree (
poly_diff_aux n p))) /\
  (
ODD (degree p) = 
ODD (degree (
poly_diff_aux n p)))`,
(* {{{ Proof *)
[
  LIST_INDUCT_TAC;
  REWRITE_TAC[normal;nonconstant;];
  STRIP_TAC;
  DISCH_THEN (fun x -> ASSUME_TAC x THEN MP_TAC x);
  REWRITE_TAC[nonconstant];
  STRIP_TAC;
  CASES_ON `t = []`;
  ASM_MESON_TAC[nonconstant;normal];
  REWRITE_TAC[
poly_diff_aux];
  CLAIM `normal t`;
  ASM_MESON_TAC[
NORMAL_TAIL];
  STRIP_TAC;
  CLAIM `normal (
poly_diff_aux (SUC n) t)`;
  ASM_MESON_TAC[nonconstant;normal;
POLY_DIFF_AUX_NORMAL;
NOT_SUC];
  STRIP_TAC;
  CASES_ON `?x. t = [x]`;
  POP_ASSUM MP_TAC THEN STRIP_TAC THEN ASM_REWRITE_TAC[];
  CLAIM `~(x = &0)`;
  ASM_MESON_TAC[normal;normalize];
  STRIP_TAC;
  CLAIM `degree [h; x] = 1`;
  CLAIM `normalize [h; x] = [h; x]`;
  ASM_MESON_TAC[normal];
  DISCH_THEN SUBST1_TAC;
  CLAIM `
LENGTH [h; x] = 2`;
  ASM_MESON_TAC[
LENGTH_PAIR];
  STRIP_TAC;
  REWRITE_TAC[degree];
  CLAIM `normal [h; x]`;
  ASM_MESON_TAC[normal;normalize];
  DISCH_THEN (fun x -> ASSUME_TAC x THEN MP_TAC x);
  REWRITE_TAC[normal];
  STRIP_TAC;
  ASM_REWRITE_TAC[];
  ARITH_TAC;
  STRIP_TAC;
  ASM_REWRITE_TAC[
poly_diff_aux;];
  CLAIM `~(&(SUC n) * x = &0)`;
  ASM_MESON_TAC[normal;normalize;
REAL_ENTIRE;ARITH_RULE `~(SUC n = 0)`;
REAL_INJ];
  STRIP_TAC;
  CLAIM `degree [&n * h; &(SUC n) * x] = 1`;
  REWRITE_TAC[degree];
  ASM_REWRITE_TAC[normalize;
NOT_CONS_NIL;
LENGTH;];
  ARITH_TAC;
  STRIP_TAC;
  ASM_REWRITE_TAC[];
  ASM_SIMP_TAC[
DEGREE_CONS];
  CLAIM `nonconstant t`;
  ASM_MESON_TAC[nonconstant];
  STRIP_TAC;
  ONCE_REWRITE_TAC[
ADD_SYM];
  REWRITE_TAC[GSYM 
ADD1];
  ASM_SIMP_TAC[
EVEN;
ODD];
  ASM_MESON_TAC[
POLY_DIFF_AUX_DEGREE];
]);;
 
let nmax_le = prove_by_refinement(
 `!n m. n <= nmax n m /\ m <= nmax n m`,
(* {{{ Proof *)
[
  REWRITE_TAC[nmax];
  REPEAT STRIP_TAC;
  COND_CASES_TAC;
  ARITH_TAC;
  ARITH_TAC;
]);;
 
let POLY_DIFF_UP_LEFT = prove_by_refinement(
 `!p. nonconstant p /\ (?X. !x. x < X ==> poly (
poly_diff p) x < &0) ==>
   (?Y. !y. y < Y ==> &0 < poly p y)`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  CLAIM `
mono_unbounded_above (\n. poly p (-- &n))`;
  REWRITE_TAC[
POLY_PNEG];
  DISJ_CASES_TAC (ISPEC `degree p` 
EVEN_OR_ODD);
  MATCH_MP_TAC 
mua_quotient_limit;
  EXISTS_TAC `&1`;
  EXISTS_TAC `(\n. 
LAST (pneg p) * &n pow degree (pneg p))`;
  REPEAT STRIP_TAC;
  REAL_ARITH_TAC;
  BETA_TAC;
  MATCH_MP_TAC 
LIM_POLY2;
  MATCH_EQ_MP_TAC 
NORMAL_PNEG;
  ASM_MESON_TAC[nonconstant];
  MATCH_MP_TAC 
POW_UNB_CON;
  STRIP_TAC;
  REWRITE_TAC[
DEGREE_PNEG];
  REWRITE_TAC[degree];
  CLAIM `normalize p = p`;
  ASM_MESON_TAC[nonconstant;normal];
  DISCH_THEN SUBST1_TAC;
  CLAIM `~(
LENGTH p = 0)`;
  ASM_MESON_TAC[nonconstant;normal;
LENGTH_NZ;
LENGTH_0;degree];
  STRIP_TAC;
  CLAIM `~(
LENGTH p = 1)`;
  ASM_MESON_TAC[nonconstant;normal;
LENGTH_NZ;
LENGTH_1;degree];
  POP_ASSUM MP_TAC THEN ARITH_TAC;
  (* save *)
  CLAIM `
LAST (pneg p) = 
LAST p`;
  ASM_MESON_TAC[GSYM 
POLY_PNEG_LAST;nonconstant;];
  DISCH_THEN SUBST1_TAC;
  ONCE_REWRITE_TAC[REAL_ARITH `x < y <=> ~(x = y) /\ ~(y < x)`];
  STRIP_TAC;
  ASM_MESON_TAC[
NORMAL_ID;nonconstant];
  STRIP_TAC;
  CLAIM `
ODD (degree (
poly_diff p))`;
  ASM_SIMP_TAC[
poly_diff_parity2];
  STRIP_TAC;
  CLAIM `nonconstant (
poly_diff p)`;
  MATCH_MP_TAC 
normal_nonconstant;
  STRIP_TAC;
  MATCH_MP_TAC 
NONCONSTANT_DIFF_NORMAL;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
  POP_ASSUM MP_TAC THEN ARITH_TAC;
  STRIP_TAC;
  CLAIM `
mono_unbounded_above (\n. poly (
poly_diff p) (-- &n))`;
  MATCH_MP_TAC 
LAST_UNB_ODD_NEG;
  ASM_REWRITE_TAC[];
  ASM_MESON_TAC[
POLY_DIFF_LAST_LT];
  REWRITE_TAC[
mono_unbounded_above];
  DISCH_THEN (MP_TAC o ISPEC `&0`);
  STRIP_TAC;
  (* save *)
  MP_TAC (ISPEC `-- (X - &1)` 
REAL_ARCH_SIMPLE);
  DISCH_THEN (X_CHOOSE_TAC `M:num`);
  CLAIM `-- &M <= X - &1`;
  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  STRIP_TAC;
  LABEL_ALL_TAC;
  USE_THEN "Z-2" (MP_TAC o ISPEC `nmax M N`);
  STRIP_TAC;
  CLAIM `N <= nmax M N`;
  REWRITE_TAC[
nmax_le];
  DISCH_THEN (REWRITE_ASSUMS o list);
  CLAIM `-- &(nmax M N) < X`;
  MATCH_MP_TAC 
REAL_LET_TRANS;
  EXISTS_TAC `-- &M`;
  STRIP_TAC;
  REWRITE_TAC[nmax];
  REWRITE_TAC[
REAL_LE_NEG2; REAL_OF_NUM_LE] THEN ARITH_TAC;
  USE_THEN "Z-0" MP_TAC THEN ARITH_TAC;
  STRIP_TAC;
  ASM_MESON_TAC[ARITH_RULE `~(x < &0 /\ &0 < x)`];
  (* save *)
  REWRITE_TAC[GSYM 
POLY_PNEG];
  MATCH_MP_TAC 
LAST_UNB_ODD_NEG;
  ASM_REWRITE_TAC[];
  ASM_SIMP_TAC[GSYM 
POLY_DIFF_LAST_LT];
  CASES_ON `?x. 
poly_diff p = [x]`;
  POP_ASSUM MP_TAC THEN STRIP_TAC;
  ASM_REWRITE_TAC[
LAST];
  LABEL_ALL_TAC;
  USE_THEN "Z-2" MP_TAC;
  POP_ASSUM (fun x -> REWRITE_TAC[x] THEN ASSUME_TAC x);
  REWRITE_TAC[poly];
  REAL_SIMP_TAC;
  REPEAT STRIP_TAC;
  FIRST_ASSUM MATCH_MP_TAC;
  EXISTS_TAC `X - &1`;
  REAL_ARITH_TAC;
  CLAIM `nonconstant (
poly_diff p)`;
  REWRITE_TAC[nonconstant];
  STRIP_TAC;
  MATCH_MP_TAC 
POLY_DIFF_NORMAL;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
  ASM_MESON_TAC[];
  STRIP_TAC;
  CLAIM `
EVEN (degree (
poly_diff p))`;
  ASM_MESON_TAC[
poly_diff_parity];
  STRIP_TAC;
  ONCE_REWRITE_TAC[ARITH_RULE `x < y <=> ~(y < x) /\ ~(y = x)`];
  REPEAT STRIP_TAC;
  CLAIM `
mono_unbounded_above (\n. poly (
poly_diff p) (-- (&n)))`;
  MATCH_MP_TAC 
LAST_UNB_EVEN_POS;
  ASM_REWRITE_TAC[];
  REWRITE_TAC[
mono_unbounded_above];
  DISCH_THEN (MP_TAC o ISPEC `&0`);
  STRIP_TAC;
  (* save *)
  MP_TAC (ISPEC `-- (X - &1)` 
REAL_ARCH_SIMPLE);
  DISCH_THEN (X_CHOOSE_TAC `M:num`);
  CLAIM `-- &M <= X - &1`;
  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  STRIP_TAC;
  LABEL_ALL_TAC;
  USE_THEN "Z-2" (MP_TAC o ISPEC `nmax M N`);
  STRIP_TAC;
  CLAIM `N <= nmax M N`;
  REWRITE_TAC[
nmax_le];
  DISCH_THEN (REWRITE_ASSUMS o list);
  CLAIM `-- &(nmax M N) < X`;
  MATCH_MP_TAC 
REAL_LET_TRANS;
  EXISTS_TAC `-- &M`;
  STRIP_TAC;
  REWRITE_TAC[nmax];
  REWRITE_TAC[
REAL_LE_NEG2; REAL_OF_NUM_LE] THEN ARITH_TAC;
  USE_THEN "Z-0" MP_TAC THEN ARITH_TAC;
  STRIP_TAC;
  ASM_MESON_TAC[ARITH_RULE `~(x < &0 /\ &0 < x)`];
  ASM_MESON_TAC[nonconstant;
NORMAL_ID];
  (* save xxx *)
  REWRITE_TAC[
mono_unbounded_above];
  DISCH_THEN (MP_TAC o ISPEC `&0`);
  STRIP_TAC;
  MP_TAC (ISPEC `-- (X - &1)` 
REAL_ARCH_SIMPLE);
  DISCH_THEN (X_CHOOSE_TAC `M:num`);
  ABBREV_TAC `k = nmax N M`;
  EXISTS_TAC `-- &k`;
  REPEAT STRIP_TAC;
  REWRITE_TAC [ARITH_RULE `x < y <=> ~(y <= x)`];
  STRIP_TAC;
  MP_TAC (ISPECL [`p:real list`;`y:real`;`-- &k`] 
POLY_MVT);
  ASM_REWRITE_TAC[];
  STRIP_TAC;
  LABEL_ALL_TAC;
  CLAIM `&0 < (-- &k) - y`;
  USE_THEN "Z-4" MP_TAC THEN REAL_ARITH_TAC;
  STRIP_TAC;
  CLAIM `poly (
poly_diff p) x < &0`;
  FIRST_ASSUM MATCH_MP_TAC;
  MATCH_MP_TAC 
REAL_LTE_TRANS;
  EXISTS_TAC `-- &k`;
  ASM_REWRITE_TAC[];
  MATCH_MP_TAC 
REAL_LE_TRANS;
  EXISTS_TAC `-- &M`;
  STRIP_TAC;
  USE_THEN "Z-5" (SUBST1_TAC o GSYM);
  REWRITE_TAC[nmax];
  REWRITE_TAC[
REAL_LE_NEG2; REAL_OF_NUM_LE] THEN ARITH_TAC;
  USE_THEN "Z-6" MP_TAC THEN REAL_ARITH_TAC;
  STRIP_TAC;
  (* save *)
  CLAIM `N <= k:num`;
  USE_THEN "Z-5" (SUBST1_TAC o GSYM);
  REWRITE_TAC[nmax] THEN ARITH_TAC;
  STRIP_TAC;
  CLAIM `&0 < poly p (-- &k)`;
  ASM_MESON_TAC[];
  STRIP_TAC;
  CLAIM `&0 < poly p (-- &k) - poly p y`;
  LABEL_ALL_TAC;
  USE_ASSUM_LIST ["Z-10";
 
let POLY_DIFF_DOWN_LEFT = prove_by_refinement(
 `!p. nonconstant p /\ (?X. !x. x < X ==> &0 < poly (
poly_diff p) x) ==>
   (?Y. !y. y < Y ==> poly p y < &0)`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  CLAIM `
mono_unbounded_below (\n. poly p (-- &n))`;
  REWRITE_TAC[
POLY_PNEG];
  DISJ_CASES_TAC (ISPEC `degree p` 
EVEN_OR_ODD);
  MATCH_MP_TAC 
mua_quotient_limit_neg;
  EXISTS_TAC `&1`;
  EXISTS_TAC `(\n. 
LAST (pneg p) * &n pow degree (pneg p))`;
  REPEAT STRIP_TAC;
  REAL_ARITH_TAC;
  BETA_TAC;
  MATCH_MP_TAC 
LIM_POLY2;
  MATCH_EQ_MP_TAC 
NORMAL_PNEG;
  ASM_MESON_TAC[nonconstant];
  MATCH_MP_TAC 
POW_UNBB_CON;
  STRIP_TAC;
  REWRITE_TAC[
DEGREE_PNEG];
  REWRITE_TAC[degree];
  CLAIM `normalize p = p`;
  ASM_MESON_TAC[nonconstant;normal];
  DISCH_THEN SUBST1_TAC;
  CLAIM `~(
LENGTH p = 0)`;
  ASM_MESON_TAC[nonconstant;normal;
LENGTH_NZ;
LENGTH_0;degree];
  STRIP_TAC;
  CLAIM `~(
LENGTH p = 1)`;
  ASM_MESON_TAC[nonconstant;normal;
LENGTH_NZ;
LENGTH_1;degree];
  POP_ASSUM MP_TAC THEN ARITH_TAC;
  (* save *)
  CLAIM `
LAST (pneg p) = 
LAST p`;
  ASM_MESON_TAC[GSYM 
POLY_PNEG_LAST;nonconstant;];
  DISCH_THEN SUBST1_TAC;
  ONCE_REWRITE_TAC[REAL_ARITH `x < y <=> ~(x = y) /\ ~(y < x)`];
  STRIP_TAC;
  ASM_MESON_TAC[
NORMAL_ID;nonconstant];
  STRIP_TAC;
  CLAIM `
ODD (degree (
poly_diff p))`;
  ASM_SIMP_TAC[
poly_diff_parity2];
  STRIP_TAC;
  CLAIM `nonconstant (
poly_diff p)`;
  MATCH_MP_TAC 
normal_nonconstant;
  STRIP_TAC;
  MATCH_MP_TAC 
NONCONSTANT_DIFF_NORMAL;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
  POP_ASSUM MP_TAC THEN ARITH_TAC;
  STRIP_TAC;
  CLAIM `
mono_unbounded_below (\n. poly (
poly_diff p) (-- &n))`;
  MATCH_MP_TAC 
LAST_UNB_ODD_POS;
  ASM_REWRITE_TAC[];
  ASM_MESON_TAC[
POLY_DIFF_LAST_GT];
  REWRITE_TAC[
mono_unbounded_below];
  DISCH_THEN (MP_TAC o ISPEC `&0`);
  STRIP_TAC;
  (* save *)
  MP_TAC (ISPEC `-- (X - &1)` 
REAL_ARCH_SIMPLE);
  DISCH_THEN (X_CHOOSE_TAC `M:num`);
  CLAIM `-- &M <= X - &1`;
  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  STRIP_TAC;
  LABEL_ALL_TAC;
  USE_THEN "Z-2" (MP_TAC o ISPEC `nmax M N`);
  STRIP_TAC;
  CLAIM `N <= nmax M N`;
  REWRITE_TAC[
nmax_le];
  DISCH_THEN (REWRITE_ASSUMS o list);
  CLAIM `-- &(nmax M N) < X`;
  MATCH_MP_TAC 
REAL_LET_TRANS;
  EXISTS_TAC `-- &M`;
  STRIP_TAC;
  REWRITE_TAC[nmax];
  REWRITE_TAC[
REAL_LE_NEG2; REAL_OF_NUM_LE] THEN ARITH_TAC;
  USE_THEN "Z-0" MP_TAC THEN ARITH_TAC;
  STRIP_TAC;
  ASM_MESON_TAC[ARITH_RULE `~(x < &0 /\ &0 < x)`];
  (* save *)
  REWRITE_TAC[GSYM 
POLY_PNEG];
  MATCH_MP_TAC 
LAST_UNB_ODD_POS;
  ASM_REWRITE_TAC[];
  ASM_SIMP_TAC[GSYM 
POLY_DIFF_LAST_GT];
  CASES_ON `?x. 
poly_diff p = [x]`;
  POP_ASSUM MP_TAC THEN STRIP_TAC;
  ASM_REWRITE_TAC[
LAST];
  LABEL_ALL_TAC;
  USE_THEN "Z-2" MP_TAC;
  POP_ASSUM (fun x -> REWRITE_TAC[x] THEN ASSUME_TAC x);
  REWRITE_TAC[poly];
  REAL_SIMP_TAC;
  REPEAT STRIP_TAC;
  FIRST_ASSUM MATCH_MP_TAC;
  EXISTS_TAC `X - &1`;
  REAL_ARITH_TAC;
  CLAIM `nonconstant (
poly_diff p)`;
  REWRITE_TAC[nonconstant];
  STRIP_TAC;
  MATCH_MP_TAC 
POLY_DIFF_NORMAL;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
  ASM_MESON_TAC[];
  STRIP_TAC;
  CLAIM `
EVEN (degree (
poly_diff p))`;
  ASM_MESON_TAC[
poly_diff_parity];
  STRIP_TAC;
  ONCE_REWRITE_TAC[ARITH_RULE `x < y <=> ~(y < x) /\ ~(y = x)`];
  REPEAT STRIP_TAC;
  CLAIM `
mono_unbounded_below (\n. poly (
poly_diff p) (-- (&n)))`;
  MATCH_MP_TAC 
LAST_UNBB_EVEN_NEG;
  ASM_REWRITE_TAC[];
  REWRITE_TAC[
mono_unbounded_below];
  DISCH_THEN (MP_TAC o ISPEC `&0`);
  STRIP_TAC;
  (* save *)
  MP_TAC (ISPEC `-- (X - &1)` 
REAL_ARCH_SIMPLE);
  DISCH_THEN (X_CHOOSE_TAC `M:num`);
  CLAIM `-- &M <= X - &1`;
  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  STRIP_TAC;
  LABEL_ALL_TAC;
  USE_THEN "Z-2" (MP_TAC o ISPEC `nmax M N`);
  STRIP_TAC;
  CLAIM `N <= nmax M N`;
  REWRITE_TAC[
nmax_le];
  DISCH_THEN (REWRITE_ASSUMS o list);
  CLAIM `-- &(nmax M N) < X`;
  MATCH_MP_TAC 
REAL_LET_TRANS;
  EXISTS_TAC `-- &M`;
  STRIP_TAC;
  REWRITE_TAC[nmax];
  REWRITE_TAC[
REAL_LE_NEG2; REAL_OF_NUM_LE] THEN ARITH_TAC;
  USE_THEN "Z-0" MP_TAC THEN ARITH_TAC;
  STRIP_TAC;
  ASM_MESON_TAC[ARITH_RULE `~(x < &0 /\ &0 < x)`];
  ASM_MESON_TAC[nonconstant;
NORMAL_ID];
  (* save *)
  REWRITE_TAC[
mono_unbounded_below];
  DISCH_THEN (MP_TAC o ISPEC `&0`);
  STRIP_TAC;
  MP_TAC (ISPEC `-- (X - &1)` 
REAL_ARCH_SIMPLE);
  DISCH_THEN (X_CHOOSE_TAC `M:num`);
  ABBREV_TAC `k = nmax N M`;
  EXISTS_TAC `-- &k`;
  REPEAT STRIP_TAC;
  REWRITE_TAC [ARITH_RULE `x < y <=> ~(y <= x)`];
  STRIP_TAC;
  MP_TAC (ISPECL [`p:real list`;`y:real`;`-- &k`] 
POLY_MVT);
  ASM_REWRITE_TAC[];
  STRIP_TAC;
  LABEL_ALL_TAC;
  CLAIM `&0 < (-- &k) - y`;
  USE_THEN "Z-4" MP_TAC THEN REAL_ARITH_TAC;
  STRIP_TAC;
  CLAIM `&0 < poly (
poly_diff p) x`;
  FIRST_ASSUM MATCH_MP_TAC;
  MATCH_MP_TAC 
REAL_LTE_TRANS;
  EXISTS_TAC `-- &k`;
  ASM_REWRITE_TAC[];
  MATCH_MP_TAC 
REAL_LE_TRANS;
  EXISTS_TAC `-- &M`;
  STRIP_TAC;
  USE_THEN "Z-5" (SUBST1_TAC o GSYM);
  REWRITE_TAC[nmax];
  REWRITE_TAC[
REAL_LE_NEG2; REAL_OF_NUM_LE] THEN ARITH_TAC;
  USE_THEN "Z-6" MP_TAC THEN REAL_ARITH_TAC;
  STRIP_TAC;
  (* save *)
  CLAIM `N <= k:num`;
  USE_THEN "Z-5" (SUBST1_TAC o GSYM);
  REWRITE_TAC[nmax] THEN ARITH_TAC;
  STRIP_TAC;
  CLAIM `poly p (-- &k) < &0`;
  ASM_MESON_TAC[];
  STRIP_TAC;
  CLAIM `poly p (-- &k) - poly p y < &0`;
  LABEL_ALL_TAC;
  USE_ASSUM_LIST ["Z-10";
 
let POLY_DIFF_DOWN_LEFT2 = prove_by_refinement(
 `!p X. nonconstant p /\ (!x. x < X ==> &0 < poly (
poly_diff p) x) ==>
   (?Y. Y < X /\ (!y. y < Y ==> poly p y < &0))`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  MP_TAC (ISPEC `p:real list` 
POLY_DIFF_DOWN_LEFT);
  ASM_REWRITE_TAC[];
  ANTS_TAC;
  ASM_MESON_TAC[];
  STRIP_TAC;
  EXISTS_TAC `min X Y - &1`;
  REPEAT STRIP_TAC;
  REAL_ARITH_TAC;
  FIRST_ASSUM MATCH_MP_TAC;
  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
]);;
 
let POLY_DIFF_UP_LEFT2 = prove_by_refinement(
 `!p X. nonconstant p /\ (!x. x < X ==> poly (
poly_diff p) x < &0) ==>
   (?Y. Y < X /\ (!y. y < Y ==> &0 < poly p y))`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  MP_TAC (ISPEC `p:real list` 
POLY_DIFF_UP_LEFT);
  ASM_REWRITE_TAC[];
  ANTS_TAC;
  ASM_MESON_TAC[];
  STRIP_TAC;
  EXISTS_TAC `min X Y - &1`;
  REPEAT STRIP_TAC;
  REAL_ARITH_TAC;
  FIRST_ASSUM MATCH_MP_TAC;
  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
]);;
 
let POLY_DIFF_DOWN_LEFT3 = prove_by_refinement(
 `!p p' X. nonconstant p ==> (
poly_diff p = p') ==>
   (!x. x < X ==> &0 < poly p' x) ==>
     (?Y. Y < X /\ (!y. y < Y ==> poly p y < &0))`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  MP_TAC (ISPEC `p:real list` 
POLY_DIFF_DOWN_LEFT);
  ASM_REWRITE_TAC[];
  ANTS_TAC;
  ASM_MESON_TAC[];
  STRIP_TAC;
  EXISTS_TAC `min X Y - &1`;
  REPEAT STRIP_TAC;
  REAL_ARITH_TAC;
  FIRST_ASSUM MATCH_MP_TAC;
  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
]);;
 
let POLY_DIFF_UP_LEFT3 = prove_by_refinement(
 `!p p' X. nonconstant p ==> (
poly_diff p = p') ==>
   (!x. x < X ==> poly p' x < &0) ==>
     (?Y. Y < X /\ (!y. y < Y ==> &0 < poly p y))`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  MP_TAC (ISPEC `p:real list` 
POLY_DIFF_UP_LEFT);
  ASM_REWRITE_TAC[];
  ANTS_TAC;
  ASM_MESON_TAC[];
  STRIP_TAC;
  EXISTS_TAC `min X Y - &1`;
  REPEAT STRIP_TAC;
  REAL_ARITH_TAC;
  FIRST_ASSUM MATCH_MP_TAC;
  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
]);;
 
let POLY_DIFF_DOWN_LEFT4 = prove_by_refinement(
 `!p p' X. nonconstant p ==> (
poly_diff p = p') ==>
   (!x. x < X ==> &0 < poly p' x) ==>
     (?Y. Y < X /\ (!y. y <= Y ==> poly p y < &0))`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  MP_TAC (ISPECL[ `p:real list`;`p':real list`;`X:real`] 
POLY_DIFF_DOWN_LEFT3);
  ASM_REWRITE_TAC[];
  REPEAT STRIP_TAC;
  EXISTS_TAC `Y - &1`;
  STRIP_TAC;
  POP_ASSUM IGNORE;
  POP_ASSUM MP_TAC;
  REAL_ARITH_TAC;
  REPEAT STRIP_TAC;
  FIRST_ASSUM MATCH_MP_TAC;
  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
]);;
 
let POLY_DIFF_UP_LEFT4 = prove_by_refinement(
 `!p p' X. nonconstant p ==> (
poly_diff p = p') ==>
   (!x. x < X ==> poly p' x < &0) ==>
     (?Y. Y < X /\ (!y. y <= Y ==> &0 < poly p y))`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  MP_TAC (ISPECL[ `p:real list`;`p':real list`;`X:real`] 
POLY_DIFF_UP_LEFT3);
  ASM_REWRITE_TAC[];
  REPEAT STRIP_TAC;
  EXISTS_TAC `Y - &1`;
  STRIP_TAC;
  POP_ASSUM IGNORE;
  POP_ASSUM MP_TAC;
  REAL_ARITH_TAC;
  REPEAT STRIP_TAC;
  FIRST_ASSUM MATCH_MP_TAC;
  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
]);;
 
let POLY_DIFF_UP_RIGHT2 = prove_by_refinement(
 `!p p' X. nonconstant p ==> (
poly_diff p = p') ==>
     (!x. X < x ==> &0 < poly p' x) ==>
     (?Y. X < Y /\ (!y. Y <= y ==> &0 < poly p y))`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  MP_TAC (ISPECL[ `p:real list`] (GEN_ALL 
POLY_DIFF_UP_RIGHT));
  ASM_REWRITE_TAC[];
  ANTS_TAC;
  ASM_MESON_TAC[];
  REPEAT STRIP_TAC;
  EXISTS_TAC `(max X Y) + &1`;
  STRIP_TAC;
  REAL_ARITH_TAC;
  REPEAT STRIP_TAC;
  FIRST_ASSUM MATCH_MP_TAC;
  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
]);;
 
let POLY_DIFF_DOWN_RIGHT2 = prove_by_refinement(
 `!p p' X. nonconstant p ==> (
poly_diff p = p') ==>
     (!x. X < x ==> poly p' x < &0) ==>
     (?Y. X < Y /\ (!y. Y <= y ==> poly p y < &0))`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  MP_TAC (ISPECL[ `p:real list`] (GEN_ALL 
POLY_DIFF_DOWN_RIGHT));
  ASM_REWRITE_TAC[];
  ANTS_TAC;
  ASM_MESON_TAC[];
  REPEAT STRIP_TAC;
  EXISTS_TAC `(max X Y) + &1`;
  STRIP_TAC;
  REAL_ARITH_TAC;
  REPEAT STRIP_TAC;
  FIRST_ASSUM MATCH_MP_TAC;
  POP_ASSUM MP_TAC THEN REAL_ARITH_TAC;
]);;