(* ---------------------------------------------------------------------- *)
(*  Reals                                                                 *)
(* ---------------------------------------------------------------------- *)
let real_ty = `:real`;;
let rx = `x:real`;;
let ry = `y:real`;;
let rz = `z:real`;;
let rzero = `&0`;;
let req = `(=):real->real->bool`;;
let rneq = `(<>):real->real->bool`;;
let rlt = `(<):real->real->bool`;;
let rgt = `(>):real->real->bool`;;
let rle = `(<=):real->real->bool`;;
let rge = `(>=):real->real->bool`;;
let rm = `( * ):real->real->real`;;
let rs = `(-):real->real->real`;;
let rn = `(--):real->real`;;
let rd = `(/):real->real->real`;;
let rp = `(+):real->real->real`;;
let rzero = `&0`;;
let rone = `&1`;;
let rlast = `LAST:(real) list -> real`;;
let rappend = `APPEND:(real) list -> real list -> real list`;;
let mk_rlist l = mk_list (l,real_ty);;
let diffl_tm = `(diffl)`;;
let dest_diffl tm =
  try
    let l,var = dest_comb tm in
    let dp,p' = dest_comb l in
    let d,p = dest_comb dp in
    if not (d = diffl_tm) then failwith "dest_diffl: not a diffl" else
    let _,bod = dest_abs p in
      bod,p'
  with _ -> failwith "dest_diffl";;
let dest_mult =
  try
    dest_binop rm
  with _ -> failwith "dest_mult";;
let mk_mult = mk_binop rm;;
let pow_tm = `(pow)`;;
let dest_pow =
  try
    dest_binop pow_tm
  with _ -> failwith "dest_pow";;
let mk_plus = mk_binop rp;;
let mk_negative = curry mk_comb rn;;
let dest_plus =
  try
    dest_binop rp
  with _ -> failwith "dest_plus";;
let REAL_DENSE = prove(
  `!x y. x < y ==> ?z. x < z /\ z < y`,
(* {{{ Proof *)
  REPEAT STRIP_TAC THEN
  CLAIM `&0 < y - x` THENL
  [REWRITE_TAC[
REAL_LT_SUB_LADD;REAL_ADD_LID] THEN
     POP_ASSUM MATCH_ACCEPT_TAC;
   DISCH_THEN (ASSUME_TAC o (MATCH_MP 
REAL_DOWN)) THEN
     POP_ASSUM MP_TAC THEN STRIP_TAC THEN
     EXISTS_TAC `e + x` THEN
     STRIP_TAC THENL
     [ONCE_REWRITE_TAC[REAL_ADD_SYM] THEN
      CONV_TAC (LAND_CONV (ONCE_REWRITE_CONV[GSYM 
REAL_ADD_RID])) THEN
      MATCH_MP_TAC 
REAL_LET_ADD2 THEN
      STRIP_TAC THENL
      [MATCH_ACCEPT_TAC 
REAL_LE_REFL;
       FIRST_ASSUM MATCH_ACCEPT_TAC];
      MATCH_EQ_MP_TAC ((GEN `y:real` (GEN `z:real` (ISPECL [`y:real`;`z:real`;`-- x`] 
REAL_LT_RADD)))) THEN
      REWRITE_TAC[GSYM REAL_ADD_ASSOC;
REAL_ADD_RINV;
REAL_ADD_RID] THEN
      REWRITE_TAC[GSYM 
real_sub] THEN
      FIRST_ASSUM MATCH_ACCEPT_TAC]]);;
 
let REAL_LT_EXISTS = prove(
  `!x. ?y. x < y`,
(* {{{ Proof *)
  GEN_TAC THEN
  EXISTS_TAC `x + &1` THEN
  REAL_ARITH_TAC);;
 
let REAL_GT_EXISTS = prove(
  `!x. ?y. y < x`,
(* {{{ Proof *)
  GEN_TAC THEN
  EXISTS_TAC `x - &1` THEN
  REAL_ARITH_TAC);;
 
let BINOMIAL_LEMMA_LT = prove_by_refinement(
   `!x y. &0 < x /\ &0 < y
           ==> !n. 0 < n ==> x pow n + y pow n <= (x + y) pow n`,
(* {{{ Proof *)
[
  REPEAT GEN_TAC;
  STRIP_TAC;
  INDUCT_TAC;
  ARITH_TAC;
  REWRITE_TAC[
real_pow];
  STRIP_TAC;
  CASES_ON `n = 0`;
  ASM_REWRITE_TAC[
real_pow;
REAL_MUL_RID;
REAL_LE_REFL];
  CLAIM `0 < n`;
  POP_ASSUM MP_TAC THEN ARITH_TAC;
  DISCH_THEN (fun x -> FIRST_ASSUM (fun y -> ASSUME_TAC (MATCH_MP y x)));
  MATCH_MP_TAC 
REAL_LE_TRANS;
  EXISTS_TAC `(x + y) * (x pow n + y pow n)`;
  STRIP_TAC;
  REWRITE_TAC[
REAL_ADD_RDISTRIB];
  MATCH_MP_TAC 
REAL_LE_ADD2;
  CONJ_TAC;
  MATCH_MP_TAC 
REAL_LE_LMUL;
  STRIP_TAC;
  FIRST_ASSUM (fun x -> MP_TAC x THEN ARITH_TAC);
  MATCH_MP_TAC (REAL_ARITH `&0 <= y ==> x <= x + y`);
  MATCH_MP_TAC 
REAL_POW_LE;
  FIRST_ASSUM (fun x -> MP_TAC x THEN ARITH_TAC);
  REWRITE_TAC[REAL_ADD_LDISTRIB];
  MATCH_MP_TAC (REAL_ARITH `&0 <= y ==> x <= y + x`);
  MATCH_MP_TAC 
REAL_LE_MUL;
  CONJ_TAC;
  FIRST_ASSUM (fun x -> MP_TAC x THEN REAL_ARITH_TAC);
  MATCH_MP_TAC (REAL_ARITH `x < y ==> x <= y`);
  MATCH_MP_TAC 
REAL_POW_LT;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
  MATCH_MP_TAC 
REAL_LE_LMUL;
  CONJ_TAC;
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  FIRST_ASSUM MATCH_ACCEPT_TAC;
]);;
 
let BINOMIAL_LEMMA = prove_by_refinement(
   `!x y. &0 <= x /\ &0 <= y
           ==> !n. 0 < n ==> x pow n + y pow n <= (x + y) pow n`,
(* {{{ Proof *)
[
  REPEAT GEN_TAC;
  STRIP_TAC;
  CASES_ON `(x = &0) \/ (y = &0)`;
  POP_ASSUM DISJ_CASES_TAC;
  ASM_REWRITE_TAC[
real_pow;REAL_ADD_LID;
POW_0];
  REPEAT STRIP_TAC;
  CLAIM `n = SUC (
PRE n)`;
  POP_ASSUM MP_TAC THEN ARITH_TAC;
  STRIP_TAC;
  ONCE_ASM_REWRITE_TAC[];
  ASM_REWRITE_TAC[
POW_0;REAL_ADD_LID;
real_pow;
REAL_LE_REFL];
  REPEAT STRIP_TAC;
  CLAIM `n = SUC (
PRE n)`;
  POP_ASSUM MP_TAC THEN ARITH_TAC;
  STRIP_TAC;
  ONCE_ASM_REWRITE_TAC[];
  ASM_REWRITE_TAC[
POW_0;REAL_ADD_LID;
REAL_ADD_RID;
real_pow;
REAL_LE_REFL];
  POP_ASSUM MP_TAC THEN REWRITE_TAC[DE_MORGAN_THM] THEN STRIP_TAC;
  MATCH_MP_TAC 
BINOMIAL_LEMMA_LT;
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
]);;
 
let REAL_MUL_LT = prove_by_refinement(
  `!x y. x * y < &0 <=> (x < &0 /\ &0 < y) \/ (&0 < x /\ y < &0)`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  EQ_TAC;
  REPEAT STRIP_TAC;
  CCONTR_TAC;
  REWRITE_ASSUMS ([
REAL_NOT_LT;DE_MORGAN_THM;] @ !REAL_REWRITES);
  POP_ASSUM MP_TAC THEN STRIP_TAC;
  CLAIM `x = &0`;
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  DISCH_THEN (REWRITE_ASSUMS o list);
  REWRITE_ASSUMS !REAL_REWRITES;
  ASM_MESON_TAC !REAL_REWRITES;
  CLAIM `&0 * &0 <= x * y`;
  MATCH_MP_TAC 
REAL_LE_MUL2;
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  REAL_SIMP_TAC;
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  CLAIM `&0 * &0 <= --x * --y`;
  MATCH_MP_TAC 
REAL_LE_MUL2;
  REAL_SIMP_TAC;
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  REAL_SIMP_TAC;
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  CLAIM `y = &0`;
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  DISCH_THEN (REWRITE_ASSUMS o list);
  REWRITE_ASSUMS !REAL_REWRITES;
  ASM_REWRITE_TAC[];
  EVERY_ASSUM MP_TAC THEN ARITH_TAC;
  (* save *)
  REPEAT STRIP_TAC;
  CLAIM `&0 < --x`;
  EVERY_ASSUM MP_TAC THEN ARITH_TAC;
  STRIP_TAC;
  CLAIM `&0 * &0 < --x * y`;
  MATCH_MP_TAC 
REAL_LT_MUL2;
  REAL_SIMP_TAC;
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  REAL_SIMP_TAC;
  REWRITE_TAC[REAL_ARITH `--y * x = --(y * x)`];
  REAL_ARITH_TAC;
  CLAIM `&0 < --y`;
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  STRIP_TAC;
  CLAIM `&0 * &0 < x * --y`;
  MATCH_MP_TAC 
REAL_LT_MUL2;
  REAL_SIMP_TAC;
  ASM_REWRITE_TAC[];
  REAL_SIMP_TAC;
  REWRITE_TAC[REAL_ARITH `x * --y = --(x * y)`];
  REAL_ARITH_TAC;
]);;
 
let REAL_MUL_GT = prove_by_refinement(
  `!x y. &0 < x * y <=> (x < &0 /\ y < &0) \/ (&0 < x /\ &0 < y)`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC;
  EQ_TAC;
  REPEAT STRIP_TAC;
  ONCE_REWRITE_ASSUMS[ARITH_RULE `x < y <=> -- y < -- x`];
  REWRITE_ASSUMS[GSYM 
REAL_MUL_RNEG];
  REWRITE_ASSUMS[REAL_ARITH `-- &0 = &0`; 
REAL_MUL_LT];
  POP_ASSUM MP_TAC THEN REPEAT STRIP_TAC;
  DISJ1_TAC;
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  REPEAT STRIP_TAC;
  ONCE_REWRITE_TAC [ARITH_RULE `x * y = --x * --y`];
  ONCE_REWRITE_TAC [ARITH_RULE `&0 = &0 * &0`];
  MATCH_MP_TAC 
REAL_LT_MUL2;
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
  ONCE_REWRITE_TAC [ARITH_RULE `&0 = &0 * &0`];
  MATCH_MP_TAC 
REAL_LT_MUL2;
  EVERY_ASSUM MP_TAC THEN REAL_ARITH_TAC;
]);;