(* ------------------------------------------------------------------ *)
(* Author and Copyright: Thomas C. Hales                              *)
(* License: GPL http://www.gnu.org/copyleft/gpl.html                  *)
(* Project: FLYSPECK http://www.math.pitt.edu/~thales/flyspeck/       *)
(* ------------------------------------------------------------------ *)
prioritize_real();;
let add_test,test = new_test_suite();;
(*--------------------------------------------------------------------*)
let mk_interval a b ex =
   mk_comb(mk_comb (mk_comb (`interval`,a),b),ex);;
add_test("mk_interval",
   mk_interval `#3` `#4` `#1` = `interval #3 #4 #1`);;
let dest_interval intv =
   let (h1,ex) = dest_comb intv in
   let (h2,f) = dest_comb h1 in
   let (h3,a) = dest_comb h2 in
   let _ = assert(h3 = `interval`) in
   (a,f,ex);;
add_test("dest_interval",
   let a = `#3` and b = `#4` and c = `#1` in
   dest_interval (mk_interval a b c) = (a,b,c));;
(*--------------------------------------------------------------------*)
let (dest_int:term-> Num.num) =
  fun b ->
  let dest_pos_int a =
    let (op,nat) = dest_comb a in
    if (fst (dest_const op) = "int_of_num") then (dest_numeral nat)
      else fail() in
    let (op',u) = (dest_comb b) in
    try (if (fst (dest_const op') = "int_neg") then
           minus_num (dest_pos_int u) else
             dest_pos_int b) with
        Failure _ -> failwith "dest_int ";;
let (mk_int:Num.num -> term) =
  fun a ->
    let sgn = Num.sign_num a in
    let abv = Num.abs_num a in
    let r = mk_comb(`&:`,mk_numeral abv) in
    try (if (sgn<0) then mk_comb (`--:`,r) else r) with
        Failure _ -> failwith ("dest_int "^(string_of_num a));;
add_test("mk_int",
   (mk_int (Int (-1443)) = `--: (&:1443)`) &&
   (mk_int (Int 37) = `(&:37)`));;
(* ------------------------------------------------------------------ *)
let (split_ratio:Num.num -> Num.num*Num.num) =
  function
    (Ratio r) -> (Big_int (Ratio.numerator_ratio r)),
         (Big_int (Ratio.denominator_ratio r))|
    u -> (u,(Int 1));;
add_test("split_ratio",
   let (a,b) = split_ratio ((Int 4)//(Int 20)) in
   (a =/ (Int 1)) && (b =/ (Int 5)));;
(* ------------------------------------------------------------------ *)
(* break nonzero int r into a*(C**b) with a prime to C . *)
let (factor_C:int -> Num.num -> Num.num*Num.num) =
  function c ->
  let intC = (Int c) in
  let rec divC (a,b) =
    if ((Int 0) =/ mod_num a intC) then (divC (a//intC,b+/(Int 1)))
      else (a,b) in
  function r->
  if ((Num.is_integer_num r)&& not((Num.sign_num r) = 0)) then
    divC (r,(Int 0)) else failwith "factor_C";;
add_test("factor_C",
   (factor_C 2 (Int (4096+32)) = (Int 129,Int 5)) &&
   (factor_C 10 (Int (5000)) = (Int 5,Int 3)) &&
   (cannot (factor_C 2) ((Int 50)//(Int 3))));;
(*--------------------------------------------------------------------*)
let (dest_float:term -> Num.num) =
  fun f ->
    let (a,b) = dest_binop `float` f in
    (dest_int a)*/ ((Int 2) **/ (dest_int b));;
add_test("dest_float",
   dest_float `float (&:3) (&:17)` = (Int 393216));;
add_test("dest_float2", (* must express as numeral first *)
   cannot dest_float `float ((&:3)+:(&:1)) (&:17)`);;
(* ------------------------------------------------------------------ *)
(* creates float of the form `float a b` with a odd *)
let (mk_float:Num.num -> term) =
  function r ->
    let (a,b) = split_ratio r in
    let (a',exp_a) = if (a=/(Int 0)) then ((Int 0),(Int 0)) else factor_C 2 a in
    let (b',exp_b) = factor_C 2 b in
    let c = a'//b' in
    if (Num.is_integer_num c) then
          mk_binop `float` (mk_int c) (mk_int (exp_a -/ exp_b))
          else failwith "mk_float";;
add_test("mk_float",
   mk_float (Int (4096+32)) = `float (&:129) (&:5)` &&
   (mk_float (Int 0) = `float (&:0) (&:0)`));;
add_test("mk_float2",  (* throws exception exactly when denom != 2^k *)
   let rtest = fun t -> (t =/ dest_float (mk_float t)) in
   rtest ((Int 3)//(Int 1024)) &&
  (cannot rtest ((Int 1)//(Int 3))));;
add_test("mk_float dest_float",  (* constructs canonical form of float *)
  mk_float (dest_float `float (&:4) (&:3)`) = `float (&:1) (&:5)`);;
(* ------------------------------------------------------------------ *)
(* creates decimal of the form `DECIMAL a b` with a prime to 10 *)
let (mk_pos_decimal:Num.num -> term) =
  function r ->
    let _ = assert (r >=/ (Int 0)) in
    let (a,b) = split_ratio r in
    if (a=/(Int 0)) then `#0` else
    let (a1,exp_a5) = factor_C 5 a in
    let (a2,exp_a2) = factor_C 2 a1 in
    let (b1,exp_b5) = factor_C 5 b in
    let (b2,exp_b2) = factor_C 2 b1 in
    let _ = assert(b2 =/ (Int 1)) in
    let c = end_itlist Num.max_num [exp_b5-/exp_a5;exp_b2-/exp_a2;(Int 0)] in
    let a' = a2*/((Int 2)**/ (c +/ exp_a2 -/ exp_b2))*/
             ((Int 5)**/(c +/ exp_a5 -/ exp_b5)) in
    let b' = (Int 10) **/ c in
    mk_binop `DECIMAL` (mk_numeral a') (mk_numeral b');;
add_test("mk_pos_decimal",
   mk_pos_decimal (Int (5000)) = `#5000` &&
   (mk_pos_decimal ((Int 30)//(Int 40)) = `#0.75`) &&
   (mk_pos_decimal (Int 0) = `#0`) &&
   (mk_pos_decimal ((Int 15)//(Int 25)) = `#0.6`) &&
   (mk_pos_decimal ((Int 25)//(Int 4)) = `#6.25`) &&
   (mk_pos_decimal ((Int 2)//(Int 25)) = `#0.08`));;
let (mk_decimal:Num.num->term) =
  function r ->
  let a = Num.sign_num r in
  let b = mk_pos_decimal (Num.abs_num r) in
  if (a < 0) then (mk_comb (`--.`, b)) else b;;
add_test("mk_decimal",
  (mk_decimal (Int 3) = `#3`) &&
  (mk_decimal (Int (-3)) = `--. (#3)`));;
(*--------------------------------------------------------------------*)
let (dest_decimal:term -> Num.num) =
  fun f ->
    let (a,b) = dest_binop `DECIMAL` f in
    let a1 = dest_numeral a in
    let b1 = dest_numeral b in
        a1//b1;;
add_test("dest_decimal",
   dest_decimal `#3.4` =/ ((Int 34)//(Int 10)));;
add_test("dest_decimal2",
   cannot dest_decimal `--. (#3.4)`);;
(*--------------------------------------------------------------------*)
(*   Properties of integer powers of 2.                               *)
(* ------------------------------------------------------------------ *)
let TWOPOW_POS = prove(`!n. (twopow (
int_of_num n) = (&2) pow n)`,
        (REWRITE_TAC[twopow])
        THEN GEN_TAC
        THEN COND_CASES_TAC
        THENL [AP_TERM_TAC;ALL_TAC]
        THEN (REWRITE_TAC[
NABS_POS])
        THEN (UNDISCH_EL_TAC 0)
        THEN (TAUT_TAC (` ( A    ) ==> (~ A ==> B)`))
        THEN (MESON_TAC[]));;
 
let TWOPOW_NEG = prove(`!n. (twopow (--(
int_of_num n)) = inv((&2) pow n))`,
        GEN_TAC
        THEN (REWRITE_TAC[twopow])
        THEN (COND_CASES_TAC THENL [ALL_TAC;REWRITE_TAC[
NABS_NEG]])
        THEN (POP_ASSUM CHOOSE_TAC)
        THEN (REWRITE_TAC[
NABS_NEG])
        THEN (UNDISCH_EL_TAC 0)
        THEN (REWRITE_TAC[
int_eq;
int_neg_th;
INT_NUM_REAL])
        THEN (REWRITE_TAC[
prove (`! u y.((--(real_of_num u) = (real_of_num y))=
                ((real_of_num u) +(real_of_num y) = (&0)))`,REAL_ARITH_TAC)])
        THEN (REWRITE_TAC[REAL_OF_NUM_ADD;REAL_OF_NUM_EQ;
ADD_EQ_0])
        THEN (DISCH_TAC)
        THEN (ASM_REWRITE_TAC[
real_pow;
REAL_INV_1]));;
 
let INT_REP3 = prove(`!a .(?n.( (a = &: n) \/ (a = --: (&: (n+1)))))`,
(GEN_TAC)
THEN ((ASSUME_TAC (SPEC `a:int` 
INT_REP2)))
THEN ((POP_ASSUM CHOOSE_TAC))
THEN ((DISJ_CASES_TAC (
prove (`((a:int) = (&: 0)) \/ ~((a:int) =(&: 0))`, MESON_TAC[]))))
(* cases *)
THENL[ ((EXISTS_TAC `0`)) THEN ((ASM_REWRITE_TAC[]));ALL_TAC]
THEN ((UNDISCH_EL_TAC 0))
THEN ((POP_ASSUM DISJ_CASES_TAC))
THENL [DISCH_TAC THEN ((ASM MESON_TAC)[]);ALL_TAC]
THEN (DISCH_TAC)
THEN ((EXISTS_TAC `
PRE n`))
THEN ((DISJ2_TAC))
THEN ((ASM_REWRITE_TAC[
INT_EQ_NEG2]))
(*** Changed by JRH, 2006/03/28 to avoid PRE_ELIM_TAC ***)
THEN (FIRST_X_ASSUM(MP_TAC o check(is_neg o concl)))
THEN (ASM_REWRITE_TAC[
INT_NEG_EQ_0; 
INT_OF_NUM_EQ])
THEN (ARITH_TAC));;
 
let REAL_EQ_INV = prove(`!x y. ((x:real = y) <=> (inv(x) = inv (y)))`,
((REPEAT GEN_TAC))
THEN (EQ_TAC)
THENL [((DISCH_TAC THEN (ASM_REWRITE_TAC[])));
 (* branch 2*) ((DISCH_TAC))
THEN ((ONCE_REWRITE_TAC [(GSYM 
REAL_INV_INV)]))
THEN ((ASM_REWRITE_TAC[]))]);;
 
let REAL_INV2 = prove(
  `(inv(&. 2)*(&. 2) = (&.1)) /\ ((&. 2)*inv(&. 2) = (&.1))`,
  SUBGOAL_TAC `~((&.2) = (&.0))`
THENL[
  REAL_ARITH_TAC;
  SIMP_TAC[
REAL_MUL_RINV;REAL_MUL_LINV]]);;
 
let TWOPOW_ADD_INT = prove(
  `!a b. (twopow (a +: b) = twopow(a) *. (twopow(b)))`,
 ((REPEAT GEN_TAC))
THEN ((ASSUME_TAC (SPEC `a:int` 
INT_REP)))
THEN ((POP_ASSUM CHOOSE_TAC))
THEN ((POP_ASSUM CHOOSE_TAC))
THEN ((ASSUME_TAC (SPEC `b:int` 
INT_REP)))
THEN ((REPEAT (POP_ASSUM CHOOSE_TAC)))
THEN ((ASM_REWRITE_TAC[]))
THEN ((SUBGOAL_TAC `&: n -: &: m +: &: n' -: &: m' = (&: (n+n')) -: (&: (m+m'))`))
(* branch *)
THENL[ ((REWRITE_TAC[GSYM 
INT_OF_NUM_ADD]))
THEN ((INT_ARITH_TAC));ALL_TAC]
(* 2nd *)
THEN ((DISCH_TAC))
THEN ((ASM_REWRITE_TAC[
TWOPOW_SUB_NUM;
TWOPOW_INV;
TWOPOW_POS;
REAL_POW_ADD;
REAL_INV_MUL;GSYM REAL_MUL_ASSOC]))
THEN ((ABBREV_TAC `a':real = inv ((&. 2) pow m)`))
THEN ((ABBREV_TAC `c :real = (&. 2) pow n`))
THEN ((ABBREV_TAC `d :real = (&. 2) pow n'`))
THEN ((ABBREV_TAC `e :real = inv ((&. 2) pow m')`))
THEN (MESON_TAC[
REAL_MUL_AC]));;
 
let FLOAT_MUL = prove(`!a b m n. (float a m) *. (float b n) = (float (a *: b) (m +: n))`,
 
let FLOAT_ADD = prove(
  `!a b c m. (float a (m+: (&:c))) +. (float b m)
     = (float ( (&:(2 
EXP c))*a +: b) m)`,
 
let FLOAT_ADD_NP = prove(
  `!a b m n.  (float b (--:(&: n))) +. (float a (&: m)) = (float a (&: m)) +. (float b (--:(&: n)))`,
 
let FLOAT_ADD_PN = prove(
  `!a b m n. (float a (&: m)) +. (float b (--(&: n))) = (float ( (&:(2 
EXP (m+| n)))*a + b) (--:(&: n)))`,
((REPEAT GEN_TAC))
THEN ((SUBGOAL_TAC `&: m = (--:(&: n)) + (&:(m+n))`))
THENL[ ((REWRITE_TAC[GSYM 
INT_OF_NUM_ADD]))
THEN ((INT_ARITH_TAC));
(* branch *)
((DISCH_TAC))
THEN ((ASM_REWRITE_TAC[
FLOAT_ADD]))]);;
 
let FLOAT_ADD_PP = prove(
  `!a b m n. ((n <=| m) ==>( (float a (&: m)) +. (float b (&: n)) = (float  ((&:(2 
EXP (m -| n))) *a + b) (&: n))))`,
((REPEAT GEN_TAC))
THEN (DISCH_TAC)
THEN ((SUBGOAL_TAC `&: m = (&: n) + (&: (m-n))`))
THENL[ ((REWRITE_TAC[
INT_OF_NUM_ADD]))
THEN (AP_TERM_TAC)
THEN ((REWRITE_TAC[
prove (`!(m:num) n. (n+m-n) = (m-n)+n`,REWRITE_TAC[
ADD_AC])]))
THEN ((UNDISCH_EL_TAC 0))
THEN ((MATCH_ACCEPT_TAC(GSYM 
SUB_ADD)));
(* branch *)
((DISCH_TAC))
THEN ((ASM_REWRITE_TAC[
FLOAT_ADD]))]);;
 
let FLOAT_ADD_PPv2 = prove(
  `!a b m n. ((m <| n) ==>( (float a (&: m)) +. (float b (&: n)) = (float  ((&:(2 
EXP (n -| m))) *b + a) (&: m))))`,
((REPEAT GEN_TAC))
THEN (DISCH_TAC)
THEN ((H_MATCH_MP (THM (
prove(`!m n. m<|n ==> m <=|n`,MESON_TAC[
LT_LE]))) (HYP_INT 0)))
THEN ((UNDISCH_EL_TAC 0))
THEN ((SIMP_TAC[GSYM 
FLOAT_ADD_PP]))
THEN (DISCH_TAC)
THEN ((REWRITE_TAC[
REAL_ADD_AC])));;
 
let FLOAT_ADD_NN = prove(
`!a b m n. ((n <=| m) ==>( (float a (--:(&: m))) +. (float b (--:(&: n)))
     = (float  ((&:(2 
EXP (m -| n))) *b + a) (--:(&: m)))))`,
((REPEAT GEN_TAC))
THEN (DISCH_TAC)
THEN ((SUBGOAL_TAC `--: (&: n) = --: (&: m) + (&: (m-n))`))
THENL [((UNDISCH_EL_TAC 0))
THEN ((SIMP_TAC [INT_OF_REAL_THM (GSYM 
REAL_OF_NUM_SUB)]))
THEN (DISCH_TAC)
THEN ((INT_ARITH_TAC));
(*branch*)
((DISCH_TAC))
THEN (ASM_REWRITE_TAC[GSYM 
FLOAT_ADD;
REAL_ADD_AC])]);;
 
let FLOAT_ADD_NNv2 = prove(
`!a b m n. ((m <| n) ==>( (float a (--:(&: m))) +. (float b (--:(&: n)))
     = (float  ((&:(2 
EXP (n -| m))) *a + b) (--:(&: n)))))`,
((REPEAT GEN_TAC))
THEN (DISCH_TAC)
THEN (((H_MATCH_MP (THM (
prove(`!m n. m<|n ==> m <=|n`,MESON_TAC[
LT_LE]))) (HYP_INT 0))))
THEN (((UNDISCH_EL_TAC 0)))
THEN (((SIMP_TAC[GSYM 
FLOAT_ADD_NN])))
THEN ((DISCH_TAC))
THEN (((REWRITE_TAC[
REAL_ADD_AC]))));;
 
let FLOAT_SUB = prove(
  `!a b n m. (float a n) -. (float b m)
     = (float a n) +. (float (--: b) m)`,
 
let INT_ADD_NEG = prove(
 `!x y. (x < y ==> ((&: x) +: (--: (&: y)) = --: (&: (y - x))))`,
((REPEAT GEN_TAC))
THEN ((DISCH_TAC))
THEN ((SUBGOAL_TAC `&: (y-x ) = (&: y) - (&: x)`))
THENL [((SUBGOAL_TAC `x <=| y`))
         (* branch *)
         THENL [(((ASM MESON_TAC)[
LE_LT]));((SIMP_TAC[GSYM (INT_OF_REAL_THM 
REAL_OF_NUM_SUB)]))]
(* branch *)
; ((DISCH_TAC))
THEN ((ASM_REWRITE_TAC[]))
THEN (ACCEPT_TAC(INT_ARITH `&: x +: --: (&: y) = --: (&: y -: &: x)`))]);;
 
let INT_ADD_NEGv2 = prove(
 `!x y. (y <= x ==> ((&: x) +: (--: (&: y)) = (&: (x - y))))`,
 ((REPEAT GEN_TAC))
 THEN ((DISCH_TAC))
 THEN ((SUBGOAL_TAC `&: (x - y) = (&: x) - (&: y)`))
 THENL[
  ((UNDISCH_EL_TAC 0)) THEN ((SIMP_TAC[GSYM (INT_OF_REAL_THM 
REAL_OF_NUM_SUB)]));
  ((DISCH_TAC)) THEN ((ASM_REWRITE_TAC[
INT_SUB]))
     ]
);;
 
let REAL_ADD_LE_SUBST_RHS = prove(
  `!a b c P. ((a <=. ((P b)) /\ (!x. (P x) =  x + (P (&. 0))) /\ (b <=. c)) ==> (a <=. (P c)))`,
(((REPEAT GEN_TAC)))
THEN (((REPEAT (TAUT_TAC `(b ==> a==> c) ==> (a /\ b ==> c)`))))
THEN (((REPEAT DISCH_TAC)))
THEN ((((H_RULER(ONCE_REWRITE_RULE))[HYP_INT 1] (HYP_INT 0))))
THEN ((((ASM ONCE_REWRITE_TAC)[])))
THEN ((((ASM MESON_TAC)[
REAL_LE_RADD;
REAL_LE_TRANS]))));;
 
let REAL_ADD_LE_SUBST_LHS = prove(
  `!a b c P. (((P(a) <=. b /\ (!x. (P x) =  x + (P (&. 0))) /\ (c <=. a)))
     ==> ((P c) <=. b))`,
(REP_GEN_TAC)
THEN (DISCH_ALL_TAC)
THEN (((H_RULER(ONCE_REWRITE_RULE)) [HYP_INT 1] (HYP_INT 0)))
THEN (((ASM ONCE_REWRITE_TAC)[]))
THEN (((ASM MESON_TAC)[
REAL_LE_RADD;
REAL_LE_TRANS])));;
 
let INTERVAL_ADD = prove(
   `!x f ex y g ey. interval x f ex /\ interval y g ey ==>
                         interval (x +. y) (f +. g) (ex +. ey)`,
EVERY[
 REPEAT GEN_TAC;
 TAUT_TAC `(A==>B==>C)==>(A/\ B ==> C)`;
 REWRITE_TAC[interval];
 REWRITE_TAC[
prove(`(x+.y) -. (f+.g) = (x-.f) +. (y-.g)`,REAL_ARITH_TAC)];
 ABBREV_TAC `a = x-.f`;
 ABBREV_TAC `b = y-.g`;
 ASSUME_TAC (SPEC `b:real` (SPEC `a:real` 
ABS_TRIANGLE));
 UNDISCH_EL_TAC 0;
 ABBREV_TAC `a':real = abs a`;
 ABBREV_TAC `b':real = abs b`;
 REPEAT DISCH_TAC;
 (H_VAL2(IWRITE_REAL_LE_RHS)) (HYP_INT 0) (HYP_INT 2);
 (H_VAL2(IWRITE_REAL_LE_RHS)) (HYP_INT 2) (HYP_INT 0);
 ASM_REWRITE_TAC[]]);;
 
let INTERVAL_NEG = prove(
  `!x f ex. interval x f ex = interval (--. x) (--. f) ex`,
(REWRITE_TAC[interval;
REAL_ABS_NEG;REAL_ARITH `!x y. -- x -. (-- y) = --. (x -. y)`]));;
 
let INTERVAL_NEG2 = prove(
  `!x f ex. interval (--. x) f ex = interval x (--. f) ex`,
 (REWRITE_TAC[interval;
REAL_ABS_NEG;REAL_ARITH `!x y. -- x -. y = --. (x -. (--. y))`]));;
 
let INTERVAL_SUB = prove(
   `!x f ex y g ey. interval x f ex /\ interval y g ey ==> interval (x -. y) (f -. g) (ex +. ey)`,
 
let REAL_LE_ABS_MUL = prove(
  `!x y z w. (( x <=. y) /\ (abs z <=. w)) ==> (x*.w <=. y*.w) `,
(DISCH_ALL_TAC)
THEN ((ASSUME_TAC (REAL_ARITH `abs z <=. w ==> (&.0) <=. w`)))
THEN (((ASM MESON_TAC)[
REAL_LE_RMUL_IMP])));;
 
let INTERVAL_MUL = prove(
  `!x f ex y g ey. (interval x f ex) /\ (interval y g ey) ==>
         (interval (x *. y) (f *. g) (abs(f)*.ey +. ex*. abs(g) +. ex*.ey))`,
(REP_GEN_TAC)
THEN ((REWRITE_TAC[interval]))
THEN ((REWRITE_TAC[REAL_ARITH `(x*. y -. f*. g) = (f *.(y -. g) +. (x -. f)*.g +. (x-.f)*.(y-. g))`]))
THEN (DISCH_ALL_TAC)
THEN ((ASSUME_TAC (SPECL [`f*.(y-g)`;`(x-f)*g +. (x-f)*.(y-g)`] 
ABS_TRIANGLE)))
THEN ((ASSUME_TAC (SPECL [`(x-f)*.g`;`(x-f)*.(y-g)`] 
ABS_TRIANGLE)))
THEN (((H_VAL2(IWRITE_REAL_LE_RHS)) (HYP_INT 0) (HYP_INT 1)))
THEN ((H_REWRITE_RULE [THM 
ABS_MUL] (HYP_INT 0)))
THEN ((H_MATCH_MP (THM (SPECL [`g:real`; `abs (x -. f)`; `ex:real`] 
REAL_PROP_LE_RABS)) (HYP_INT 4)))
THEN (((H_VAL2(IWRITE_REAL_LE_RHS)) (HYP_INT 0) (HYP_INT 1)))
THEN ((H_MATCH_MP (THM (SPECL [`f:real`; `abs (y -. g)`; `ey:real`] 
REAL_PROP_LE_LABS)) (HYP_INT 7)))
THEN (((H_VAL2 (IWRITE_REAL_LE_RHS)) (HYP_INT 0) (HYP_INT 1)))
THEN ((H_MATCH_MP (THM (SPECL [`x-.f`; `abs (y -. g)`; `ey:real`] 
REAL_PROP_LE_LABS)) (HYP_INT 9)))
THEN (((H_VAL2(IWRITE_REAL_LE_RHS)) (HYP_INT 0) (HYP_INT 1)))
THEN ((ASSUME_TAC (SPECL [`abs(x-.f)`;`ex:real`;`y-.g`;`ey:real`] 
REAL_LE_ABS_MUL)))
THEN ((H_CONJ (HYP_INT 11) (HYP_INT 12)))
THEN ((H_MATCH_MP (HYP_INT 1) (HYP_INT 0)))
THEN (((H_VAL2(IWRITE_REAL_LE_RHS)) (HYP_INT 0) (HYP_INT 3)))
THEN ((POP_ASSUM ACCEPT_TAC)));;
 
let INTERVAL_CENTER = prove(
  `!x f ex g. (interval x f ex) ==> (interval x g (abs(f-g)+.ex))`,
((REWRITE_TAC[interval]))
THEN (DISCH_ALL_TAC)
THEN ((ASSUME_TAC (REAL_ARITH `abs(x -. g) <=. abs(f-.g) +. abs(x -. f)`)))
THEN ((H_VAL2 IWRITE_REAL_LE_RHS (HYP_INT 1) (HYP_INT 0)))
THEN ((ASM_REWRITE_TAC[])));;
 
let INTERVAL_WIDTH = prove(
  `!x f ex ex'. (ex <=. ex') ==> (interval x f ex) ==> (interval x f ex')`,
((REWRITE_TAC[interval]))
THEN (DISCH_ALL_TAC)
THEN ((H_VAL2 IWRITE_REAL_LE_RHS (HYP_INT 1) (HYP_INT 0)))
THEN ((ASM_REWRITE_TAC[])));;
 
let INTERVAL_MAX = prove(
  `!x f ex. interval x f ex ==> (x <=. f+.ex)`,
(REWRITE_TAC[interval]) THEN REAL_ARITH_TAC);;
 
let INTERVAL_MIN = prove(
  `!x f ex. interval x f ex ==> (f-. ex <=. x)`,
(REWRITE_TAC[interval]) THEN REAL_ARITH_TAC);;
 
let INTERVAL_ABS_MIN = prove(
  `!x f ex. interval x f ex ==> (abs(f)-. ex <=. abs(x))`,
  (REWRITE_TAC[interval] THEN REAL_ARITH_TAC)
);;
 
let INTERVAL_ABS_MAX = prove(
  `!x f ex. interval x f ex ==> (abs(x) <=. abs(f)+. ex)`,
  (REWRITE_TAC[interval] THEN REAL_ARITH_TAC)
);;
 
let INTERVAL_MK = prove(
   `let half = float(&:1)(--:(&:1)) in
    !x xmin xmax. ((xmin <=. x) /\ (x <=. xmax)) ==>
      interval x
         ((xmin+.xmax)*.half)
         ((xmax-.xmin)*.half)`,
 
let INTERVAL_DIV = prove(`!x f ex y g ey h ez.
  (((interval x f ex) /\ (interval y g ey) /\ (ey <. (abs g)) /\
  ((ex +. (abs (f -. (h*.g))) +. (abs h)*. ey) <=. (ez*.((abs g) -. ey))))
  ==> (interval (x / y) h ez))`,
let lemma1 = prove( `&.0 < u /\ ||. z <=. e*. u ==> (&.0) <=. e`,
  EVERY[
    DISCH_ALL_TAC;
    ASSUME_TAC (SPEC `z:real` REAL_MK_NN_ABS);
    H_MATCH_MP (THM REAL_LE_TRANS) (H_RULE2 CONJ (HYP_INT 0) (HYP_INT 2));
    H_MATCH_MP (THM REAL_PROP_NN_RCANCEL) (H_RULE2 CONJ (HYP_INT 2) (HYP_INT 0));
    ASM_REWRITE_TAC[]
  ]) in
EVERY[
  DISCH_ALL_TAC;
  SUBGOAL_TAC `~(y= (&.0))`
  THENL[
    EVERY[
      UNDISCH_LIST[1;2];
      REWRITE_TAC[interval];
      REAL_ARITH_TAC
    ];
    EVERY[
      REWRITE_TAC[interval];
      DISCH_TAC THEN (H I (HYP_INT 0)) THEN (UNDISCH_EL_TAC 0);
      DISCH_THEN (fun th -> (MP_TAC(MATCH_MP REAL_MK_POS_ABS_' th)));
      MATCH_MP_TAC REAL_MUL_RTIMES_LE;
      REWRITE_TAC[GSYM ABS_MUL;REAL_SUB_RDISTRIB;real_div;GSYM REAL_MUL_ASSOC];
      ASM_SIMP_TAC[REAL_MUL_LINV;REAL_MUL_RID];
      H (REWRITE_RULE[interval]) (HYP_INT 1);
      H (REWRITE_RULE[interval]) (HYP_INT 3);
      H (MATCH_MP INTERVAL_ABS_MIN) (HYP_INT 4);
      POPL_TAC[3;4;5];
      H_VAL2 (IWRITE_REAL_LE_LHS) (HYP_INT 2) (HYP_INT 4);
      H (REWRITE_RULE[ REAL_ADD_ASSOC]) (HYP_INT 0);
      H_VAL2 (IWRITE_REAL_LE_LHS) (THM (SPEC `f-. h*g` (SPEC `x-.f` ABS_TRIANGLE))) (HYP_INT 0);
      H (ONCE_REWRITE_RULE[REAL_ABS_SUB]) (HYP_INT 4);
      H (MATCH_MP (SPEC `h:real` REAL_PROP_LE_LABS)) (HYP_INT 0);
      H (REWRITE_RULE[GSYM ABS_MUL]) (HYP_INT 0);
      H_VAL2 (IWRITE_REAL_LE_LHS) (HYP_INT 0) (HYP_INT 3);
      H_VAL2 (IWRITE_REAL_LE_LHS) (THM (SPEC `h*.(g-.y)` (SPEC`(x-.f)+(f-. h*g)`  ABS_TRIANGLE))) (HYP_INT 0);
      POPL_TAC[1;2;3;4;5;6;7;9;10;12];
      H (ONCE_REWRITE_RULE[REAL_ARITH `((x-.f) +. (f -. h*. g)) +. h*.(g-. y) = x -. h*. y `]) (HYP_INT 0);
      ABBREV_TAC `z = x -. h*.y`;
      H (ONCE_REWRITE_RULE[GSYM REAL_SUB_LT]) (HYP_INT 4);
      ABBREV_TAC `u = abs(g) -. ey`;
      POPL_TAC[0;2;4;6];
      H (MATCH_MP lemma1 ) (H_RULE2 CONJ (HYP_INT 0) (HYP_INT 1));
      H (MATCH_MP REAL_PROP_LE_LMUL) (H_RULE2 CONJ (HYP_INT 0) (HYP_INT 3));
      H (MATCH_MP REAL_LE_TRANS) (H_RULE2 CONJ (HYP_INT 3) (HYP_INT 0));
      ASM_REWRITE_TAC[]
  ];
  ]]);;  
let REAL_SSQRT_NEG = prove(`!x. (x <. (&.0)) ==> (ssqrt x = (&.0))`,
  EVERY[
    DISCH_ALL_TAC;
    REWRITE_TAC[ssqrt];
    COND_CASES_TAC
    THENL[
      ACCEPT_TAC (REFL `&.0`);
      ASM_MESON_TAC[]
    ]
  ]);;
 
let REAL_SSQRT_NN = prove(`!x. (&.0) <=. x ==> (ssqrt x = (sqrt x))`,
  EVERY[
  DISCH_ALL_TAC;
  REWRITE_TAC[ssqrt];
  COND_CASES_TAC
  THENL[
    ASM_MESON_TAC[
real_lt];
    ACCEPT_TAC (REFL `sqrt x`)
  ]
  ]);;
 
let INTERVAL_SSQRT = prove(`!x f ex u ey ez v. (interval x f ex) /\ (interval (u*.u) f ey) /\
  (ex +.ey <=. ez*.(v+.u)) /\ (v*.v <=. f-.ex) /\ (&.0 <. u) /\ (&.0 <=. v) ==>
  (interval (ssqrt x) u ez)`,
EVERY[
  DISCH_ALL_TAC;
  H (MATCH_MP 
REAL_LE_TRANS) (H_RULE2 CONJ (THM (SPEC `v:real` REAL_MK_NN_SQUARE)) (HYP_INT 3));
  H (MATCH_MP (
INTERVAL_MIN)) (HYP_INT 1);
  H (MATCH_MP 
REAL_LE_TRANS)  (H_RULE2 CONJ (HYP_INT 1) (HYP_INT 0));
  H (MATCH_MP 
INTERVAL_EPS_POS) (HYP_INT 3);
  H (MATCH_MP 
INTERVAL_EPS_POS) (HYP_INT 5);
  H (MATCH_MP REAL_PROP_NN_ADD2) (H_RULE2 CONJ (HYP_INT 1) (HYP_INT 0));
  H (MATCH_MP REAL_PROP_POS_LADD) (H_RULE2 CONJ (HYP_INT 11) (HYP_INT 10));
  H (MATCH_MP REAL_PROP_POS_LADD) (H_RULE2 CONJ (THM (SPEC `x:real` 
REAL_MK_NN_SSQRT)) (HYP_INT 11));
  H (MATCH_MP REAL_PROP_POS_INV) (HYP_INT 0);
  ASSUME_TAC (REAL_ARITH  `(ssqrt x -. u) = (ssqrt x -. u)*.(&.1)`);
  H (MATCH_MP REAL_MK_NZ_POS) (HYP_INT 2);
  H (MATCH_MP 
REAL_MUL_RINV) (HYP_INT 0);
  H_REWRITE_RULE[(H_RULE GSYM) (HYP_INT 0)] (HYP_INT 2);
  POPL_TAC[1;2;3];
  H (REWRITE_RULE[REAL_MUL_ASSOC]) (HYP_INT 0);
  H (REWRITE_RULE[ONCE_REWRITE_RULE[REAL_MUL_SYM] 
REAL_DIFFSQ]) (HYP_INT 0);
  POPL_TAC[1;2];
  H_SIMP_RULE[HYP_INT 7;THM 
REAL_SSQRT_SQUARE] (HYP_INT 0);
  ASSUME_TAC (REAL_ARITH `abs(x -. u*.u) <=. abs(x -. f) + abs(f-. u*.u)`);
  H (REWRITE_RULE[interval]) (HYP_INT 12);
  H (ONCE_REWRITE_RULE[interval]) (HYP_INT 14);
  H (ONCE_REWRITE_RULE[
REAL_ABS_SUB]) (HYP_INT 0);
  POPL_TAC[1;5;15;16];
  H (MATCH_MP 
REAL_LE_ADD2) (H_RULE2 CONJ (HYP_INT 1) (HYP_INT 0));
  H (MATCH_MP 
REAL_LE_TRANS) (H_RULE2 CONJ (HYP_INT 3) (HYP_INT 0));
  POPL_TAC[1;2;3;4];
  H (AP_TERM `||.`) (HYP_INT 1);
  H (REWRITE_RULE[
ABS_MUL]) (HYP_INT 0);
  H (MATCH_MP 
REAL_LT_IMP_LE)  (HYP_INT 4);
  H (REWRITE_RULE[GSYM 
REAL_ABS_REFL]) (HYP_INT 0);
  H_REWRITE_RULE [HYP_INT 0] (HYP_INT 2);
  H (MATCH_MP 
REAL_LE_RMUL) (H_RULE2 CONJ (HYP_INT 5) (HYP_INT 2));
  H_REWRITE_RULE [H_RULE GSYM (HYP_INT 1)] (HYP_INT 0);
  POPL_TAC[1;2;3;5;6;7;8];
  H (MATCH_MP 
REAL_LE_TRANS) (H_RULE2 CONJ (HYP_INT 12) (HYP_INT 9));
  H (MATCH_MP 
REAL_SSQRT_MONO) (HYP_INT 0);
  H (MATCH_MP REAL_SSQRT_SQUARE') (HYP_INT 16);
  H_REWRITE_RULE [HYP_INT 0] (HYP_INT 1);
  H (ONCE_REWRITE_RULE[GSYM (SPECL[`v:real`;`ssqrt x`;`u:real`] 
REAL_LE_RADD)]) (HYP_INT 0);
  H (MATCH_MP 
REAL_LE_INV2) (H_RULE2 CONJ (HYP_INT 9) (HYP_INT 0));
  POPL_TAC[1;2;3;4;5;7;8;9;12;13];
  H (MATCH_MP 
REAL_LE_LMUL) (H_RULE2 CONJ (HYP_INT 3) (HYP_INT 0));
  H (MATCH_MP 
REAL_LE_TRANS) (H_RULE2 CONJ (HYP_INT 2) (HYP_INT 0));
  H (MATCH_MP REAL_PROP_POS_INV) (HYP_INT 4);
  H (MATCH_MP 
REAL_LT_IMP_LE) (HYP_INT 0);
  H (MATCH_MP 
REAL_LE_RMUL) (H_RULE2 CONJ (HYP_INT 11) (HYP_INT 0));
  H (REWRITE_RULE[GSYM REAL_MUL_ASSOC]) (HYP_INT 0);
  H (MATCH_MP REAL_MK_NZ_POS) (HYP_INT 8);
  H (MATCH_MP 
REAL_MUL_RINV) (HYP_INT 0);
  H_REWRITE_RULE[HYP_INT 0; THM 
REAL_MUL_RID] (HYP_INT 2);
  H (MATCH_MP 
REAL_LE_TRANS) (H_RULE2 CONJ (HYP_INT 7) (HYP_INT 0));
  ASM_REWRITE_TAC[interval]
  ]);;
 
let FLOAT_EQ = prove(
  `!a b a' b'.  (float a b = (float a'  b')) <=>
        ((float a b) -. (float a' b') = (&.0))`,
 
let FLOAT_LT = prove(
  `!a b a' b'. (float a b <. (float a' b')) <=>
        ((&.0) <. (float a' b') -. (float a b))`,
 
let FLOAT_LE = prove(
  `!a b a' b'. (float a b <=. (float a' b')) <=>
        ((&.0) <=. (float a' b') -. (float a b))`,
 
let RAT_LEMMA1_SUB = prove(`~(y1 = &0) /\ ~(y2 = &0) ==>
      ((x1 / y1) - (x2 / y2) = (x1 * y2 - x2 * y1) * inv(y1) * inv(y2))`,
 
let ABS_NUM = prove (`!m n. abs (&. n -. (&. m)) = &.((m-|n) + (n-|m))`,
  REPEAT GEN_TAC THEN
  DISJ_CASES_TAC (SPECL [`m:num`;`n:num`] 
LTE_CASES) THENL[
  (* first case *)
  EVERY[ LABEL_ALL_TAC;
  H_REWRITE_RULE [THM (GSYM 
REAL_OF_NUM_LT)] (HYP "0");
  LABEL_ALL_TAC;
  H_ONCE_REWRITE_RULE[THM (GSYM 
REAL_SUB_LT)] (HYP "1");
  LABEL_ALL_TAC;
  H_MATCH_MP (THM 
REAL_LT_IMP_LE) (HYP "2");
  LABEL_ALL_TAC;
  H_REWRITE_RULE [THM (GSYM 
ABS_REFL)] (HYP "3");
  ASM_REWRITE_TAC[];
  H_MATCH_MP (THM 
LT_IMP_LE) (HYP "0");
  ASM_SIMP_TAC[
REAL_OF_NUM_SUB];
  REWRITE_TAC[REAL_OF_NUM_EQ];
  ONCE_REWRITE_TAC[ARITH_RULE `!x:num y:num. (x = y) = (y  = x)`];
  REWRITE_TAC[
EQ_ADD_RCANCEL_0];
  ASM_REWRITE_TAC[
SUB_EQ_0]];
  (* second case *)
  EVERY[LABEL_ALL_TAC;
  H_REWRITE_RULE [THM (GSYM REAL_OF_NUM_LE)] (HYP "0");
  LABEL_ALL_TAC;
  H_ONCE_REWRITE_RULE[THM (GSYM 
REAL_SUB_LE)] (HYP "1");
  LABEL_ALL_TAC;
  H_REWRITE_RULE [THM (GSYM 
ABS_REFL)] (HYP "2");
  ONCE_REWRITE_TAC[GSYM 
REAL_ABS_NEG];
  REWRITE_TAC[REAL_ARITH `!x y. --.(x -. y) = (y-x)`];
  ASM_REWRITE_TAC[];
  ASM_SIMP_TAC[
REAL_OF_NUM_SUB];
  REWRITE_TAC[REAL_OF_NUM_EQ];
  ONCE_REWRITE_TAC[ARITH_RULE `!x:num y:num. (x = y) <=> (y  = x)`];
  REWRITE_TAC[
EQ_ADD_LCANCEL_0];
  ASM_REWRITE_TAC[
SUB_EQ_0]]]);;
 
let INTERVAL_TO_LESS = prove(
  `!a f ex b g ey. ((interval a f ex) /\ (interval b g ey) /\
      (&.0 <. (g -. (ey +. ex +. f)))) ==> (a <. b)`,
   let lemma1 = REAL_ARITH `!ex ey f g. (&.0 <.
     (g -. (ey +. ex +. f))) ==> ((f +. ex)<. (g -. ey)) ` in
   EVERY[
   REPEAT GEN_TAC;
   DISCH_ALL_TAC;
   H_MATCH_MP (THM lemma1) (HYP "2");
   H_MATCH_MP (THM 
INTERVAL_MAX) (HYP "0");
   H_MATCH_MP (THM 
INTERVAL_MIN) (HYP "1");
   LABEL_ALL_TAC;
   H_MATCH_MP (THM 
REAL_LET_TRANS) (H_RULE2 CONJ (HYP "4") (HYP "5"));
   LABEL_ALL_TAC;
   H_MATCH_MP (THM 
REAL_LTE_TRANS) (H_RULE2 CONJ (HYP "6") (HYP "3"));
   ASM_REWRITE_TAC[]
   ]);;
 
let ABS_TO_INTERVAL = prove(
  `!c u k. (abs (c - u) <=. k) ==> (!f g ex ey.((interval u f ex) /\ (interval k g ey) ==> (interval c f (g+.ey+.ex))))`,
   EVERY[
   REWRITE_TAC[interval];
   DISCH_ALL_TAC;
   REPEAT GEN_TAC;
   DISCH_ALL_TAC;
   ONCE_REWRITE_TAC [REAL_ARITH `c -. f = (c-. u) + (u-. f)`];
   ONCE_REWRITE_TAC [REAL_ADD_ASSOC];
   ASSUME_TAC (SPECL [`c-.u`;`u-.f`] 
ABS_TRIANGLE);
   IMP_RES_THEN ASSUME_TAC (REAL_ARITH `||.(k-.g) <=. ey ==> (k <=. (g +. ey))`);
   MATCH_MP_TAC (REAL_ARITH `(?a b.((x <=. (a+.b)) /\ (a <=. u) /\ (b <=. v)))  ==> (x <=. (u +. v))`);
   EXISTS_TAC `abs (c-.u)`;
   EXISTS_TAC `abs(u-.f)`;
   ASM_REWRITE_TAC[];
   ASM_MESON_TAC[
REAL_LE_TRANS];
   ]);;
 
let lemma1 = prove(
  `!n m p. ((&.p/(&.m)) <= (&.n)) <=> ((&.p/(&.m)) <= (&.n)/(&.1))`,
 
let lemma2 = prove(
  `!n m p. ((&.p) <= ((&.n)/(&.m))) <=> ((&.p/(&.1)) <= (&.n)/(&.m))`,
 
let lemma3 = prove(`!a b c d. (
   ((0<b) /\ (0<d) /\ (a*d <=| c*b))
    ==> (&.a/(&.b) <=. ((&.c)/(&.d))))`,
 
let INTERVAL_MINMAX = prove(`!x f ex.
   ((f -. ex) <= x) /\ (x <=. (f +. ex)) ==> (interval x f ex)`,
   EVERY[REPEAT GEN_TAC;
   REWRITE_TAC[interval;
ABS_BOUNDS];
   REAL_ARITH_TAC]);;
 
let thm2 = prove(hyp2,REWRITE_TAC[interval] THEN
                       (CONV_TAC FLOAT_INEQ_CONV)) in
    let thm3 = FLOAT_INEQ_CONV hyp3 in
    let thm4 = FLOAT_INEQ_CONV hyp4 in
    let float_tac = REWRITE_TAC[FLOAT_NN;FLOAT_POS;INT_NN;INT_NN_NEG;
                       INT_POS';let thm5 = prove( hyp5,float_tac) in
    let thm6 = prove( hyp6,float_tac) in
    let ant  = end_itlist CONJ[x_int;thm2;thm3;thm4;thm5;thm6] in
    MATCH_MP thm ant
    )
    with _ -> failwith "INTERVAL_OF_TERM : SSQRT"
    end
  else failwith "INTERVAL_OF_TERM : case not installed";