(* ========================================================================= *)
(* Calculation with integer-valued reals. *)
(* *)
(* John Harrison, University of Cambridge Computer Laboratory *)
(* *)
(* (c) Copyright, University of Cambridge 1998 *)
(* (c) Copyright, John Harrison 1998-2007 *)
(* ========================================================================= *)
needs "realax.ml";;
(* ------------------------------------------------------------------------- *)
(* Syntax operations on integer constants of type ":real". *)
(* ------------------------------------------------------------------------- *)
let is_realintconst tm =
match tm with
Comb(Const("real_of_num",_),n) -> is_numeral n
| Comb(Const("real_neg",_),Comb(Const("real_of_num",_),n)) ->
is_numeral n & not(dest_numeral n = num_0)
| _ -> false;;
let dest_realintconst tm =
match tm with
Comb(Const("real_of_num",_),n) -> dest_numeral n
| Comb(Const("real_neg",_),Comb(Const("real_of_num",_),n)) ->
let nn = dest_numeral n in
if nn <>/ num_0 then minus_num(dest_numeral n)
else failwith "dest_realintconst"
| _ -> failwith "dest_realintconst";;
let mk_realintconst =
let cast_tm = `real_of_num` and neg_tm = `(--)` in
let mk_numconst n = mk_comb(cast_tm,mk_numeral n) in
fun x -> if x </ num_0 then mk_comb(neg_tm,mk_numconst(minus_num x))
else mk_numconst x;;
let is_ratconst tm =
match tm with
Comb(Comb(Const("real_div",_),p),q) ->
is_realintconst p & is_realintconst q &
(let m = dest_realintconst p and n = dest_realintconst q in
n >/ num_1 & gcd_num m n =/ num_1)
| _ -> is_realintconst tm;;
let rat_of_term tm =
match tm with
Comb(Comb(Const("real_div",_),p),q) ->
let m = dest_realintconst p and n = dest_realintconst q in
if n >/ num_1 & gcd_num m n =/ num_1 then m // n
else failwith "rat_of_term"
| _ -> dest_realintconst tm;;
let term_of_rat =
let div_tm = `(/)` in
fun x ->
let p,q = numdom x in
let ptm = mk_realintconst p in
if q = num_1 then ptm
else mk_comb(mk_comb(div_tm,ptm),mk_realintconst q);;
(* ------------------------------------------------------------------------- *)
(* Some elementary "bootstrapping" lemmas we need below. *)
(* ------------------------------------------------------------------------- *)
let REAL_ADD_AC = prove
(`(m + n = n + m) /\
((m + n) + p = m + (n + p)) /\
(m + (n + p) = n + (m + p))`,
MESON_TAC[REAL_ADD_ASSOC; REAL_ADD_SYM]);;
let REAL_EQ_ADD_LCANCEL = prove
(`!x y z. (x + y = x + z) <=> (y = z)`,
REPEAT GEN_TAC THEN EQ_TAC THEN DISCH_TAC THEN ASM_REWRITE_TAC[] THEN
POP_ASSUM(MP_TAC o AP_TERM `(+) (--x)`) THEN
REWRITE_TAC[REAL_ADD_ASSOC; REAL_ADD_LINV; REAL_ADD_LID]);;
let REAL_NEG_ADD = prove
(`!x y. --(x + y) = --x + --y`,
REPEAT GEN_TAC THEN
MATCH_MP_TAC(GEN_ALL(fst(EQ_IMP_RULE(SPEC_ALL
REAL_EQ_ADD_RCANCEL)))) THEN
EXISTS_TAC `x + y` THEN REWRITE_TAC[REAL_ADD_LINV] THEN
ONCE_REWRITE_TAC[AC
REAL_ADD_AC `(a + b) + (c + d) = (a + c) + (b + d)`] THEN
REWRITE_TAC[REAL_ADD_LINV; REAL_ADD_LID]);;
let REAL_LE_LNEG = prove
(`!x y. --x <= y <=> &0 <= x + y`,
REPEAT GEN_TAC THEN EQ_TAC THEN
DISCH_THEN(MP_TAC o MATCH_MP REAL_LE_LADD_IMP) THENL
[DISCH_THEN(MP_TAC o SPEC `x:real`) THEN
REWRITE_TAC[ONCE_REWRITE_RULE[REAL_ADD_SYM] REAL_ADD_LINV];
DISCH_THEN(MP_TAC o SPEC `--x`) THEN
REWRITE_TAC[REAL_ADD_LINV; REAL_ADD_ASSOC; REAL_ADD_LID;
ONCE_REWRITE_RULE[REAL_ADD_SYM] REAL_ADD_LID]]);;
let REAL_LE_NEG2 = prove
(`!x y. --x <= --y <=> y <= x`,
REPEAT GEN_TAC THEN
GEN_REWRITE_TAC (RAND_CONV o LAND_CONV) [GSYM
REAL_NEG_NEG] THEN
REWRITE_TAC[
REAL_LE_LNEG] THEN
AP_TERM_TAC THEN MATCH_ACCEPT_TAC REAL_ADD_SYM);;
(* ------------------------------------------------------------------------- *)
(* First, the conversions on integer constants. *)
(* ------------------------------------------------------------------------- *)
let REAL_INT_LE_CONV,REAL_INT_LT_CONV,
REAL_INT_GE_CONV,REAL_INT_GT_CONV,REAL_INT_EQ_CONV =
let tth =
TAUT `(F /\ F <=> F) /\ (F /\ T <=> F) /\
(T /\ F <=> F) /\ (T /\ T <=> T)` in
let nth = TAUT `(~T <=> F) /\ (~F <=> T)` in
let NUM2_EQ_CONV = BINOP_CONV NUM_EQ_CONV THENC GEN_REWRITE_CONV I [tth] in
let NUM2_NE_CONV =
RAND_CONV NUM2_EQ_CONV THENC
GEN_REWRITE_CONV I [nth] in
let [pth_le1; pth_le2a; pth_le2b; pth_le3] = (CONJUNCTS o prove)
(`(--(&m) <= &n <=> T) /\
(&m <= &n <=> m <= n) /\
(--(&m) <= --(&n) <=> n <= m) /\
(&m <= --(&n) <=> (m = 0) /\ (n = 0))`,
REWRITE_TAC[REAL_LE_NEG2] THEN
REWRITE_TAC[REAL_LE_LNEG; REAL_LE_RNEG] THEN
REWRITE_TAC[REAL_OF_NUM_ADD; REAL_OF_NUM_LE; LE_0] THEN
REWRITE_TAC[LE; ADD_EQ_0]) in
let REAL_INT_LE_CONV = FIRST_CONV
[GEN_REWRITE_CONV I [pth_le1];
GEN_REWRITE_CONV I [pth_le2a; pth_le2b] THENC NUM_LE_CONV;
GEN_REWRITE_CONV I [pth_le3] THENC NUM2_EQ_CONV] in
let [pth_lt1; pth_lt2a; pth_lt2b; pth_lt3] = (CONJUNCTS o prove)
(`(&m < --(&n) <=> F) /\
(&m < &n <=> m < n) /\
(--(&m) < --(&n) <=> n < m) /\
(--(&m) < &n <=> ~((m = 0) /\ (n = 0)))`,
REWRITE_TAC[pth_le1; pth_le2a; pth_le2b; pth_le3;
GSYM NOT_LE; real_lt] THEN
CONV_TAC TAUT) in
let REAL_INT_LT_CONV = FIRST_CONV
[GEN_REWRITE_CONV I [pth_lt1];
GEN_REWRITE_CONV I [pth_lt2a; pth_lt2b] THENC NUM_LT_CONV;
GEN_REWRITE_CONV I [pth_lt3] THENC NUM2_NE_CONV] in
let [pth_ge1; pth_ge2a; pth_ge2b; pth_ge3] = (CONJUNCTS o prove)
(`(&m >= --(&n) <=> T) /\
(&m >= &n <=> n <= m) /\
(--(&m) >= --(&n) <=> m <= n) /\
(--(&m) >= &n <=> (m = 0) /\ (n = 0))`,
REWRITE_TAC[pth_le1; pth_le2a; pth_le2b; pth_le3; real_ge] THEN
CONV_TAC TAUT) in
let REAL_INT_GE_CONV = FIRST_CONV
[GEN_REWRITE_CONV I [pth_ge1];
GEN_REWRITE_CONV I [pth_ge2a; pth_ge2b] THENC NUM_LE_CONV;
GEN_REWRITE_CONV I [pth_ge3] THENC NUM2_EQ_CONV] in
let [pth_gt1; pth_gt2a; pth_gt2b; pth_gt3] = (CONJUNCTS o prove)
(`(--(&m) > &n <=> F) /\
(&m > &n <=> n < m) /\
(--(&m) > --(&n) <=> m < n) /\
(&m > --(&n) <=> ~((m = 0) /\ (n = 0)))`,
REWRITE_TAC[pth_lt1; pth_lt2a; pth_lt2b; pth_lt3; real_gt] THEN
CONV_TAC TAUT) in
let REAL_INT_GT_CONV = FIRST_CONV
[GEN_REWRITE_CONV I [pth_gt1];
GEN_REWRITE_CONV I [pth_gt2a; pth_gt2b] THENC NUM_LT_CONV;
GEN_REWRITE_CONV I [pth_gt3] THENC NUM2_NE_CONV] in
let [pth_eq1a; pth_eq1b; pth_eq2a; pth_eq2b] = (CONJUNCTS o prove)
(`((&m = &n) <=> (m = n)) /\
((--(&m) = --(&n)) <=> (m = n)) /\
((--(&m) = &n) <=> (m = 0) /\ (n = 0)) /\
((&m = --(&n)) <=> (m = 0) /\ (n = 0))`,
REWRITE_TAC[GSYM REAL_LE_ANTISYM; GSYM LE_ANTISYM] THEN
REWRITE_TAC[pth_le1; pth_le2a; pth_le2b; pth_le3; LE; LE_0] THEN
CONV_TAC TAUT) in
let REAL_INT_EQ_CONV = FIRST_CONV
[GEN_REWRITE_CONV I [pth_eq1a; pth_eq1b] THENC NUM_EQ_CONV;
GEN_REWRITE_CONV I [pth_eq2a; pth_eq2b] THENC NUM2_EQ_CONV] in
REAL_INT_LE_CONV,REAL_INT_LT_CONV,
REAL_INT_GE_CONV,REAL_INT_GT_CONV,REAL_INT_EQ_CONV;;
let REAL_INT_NEG_CONV =
let REAL_INT_MUL_CONV =
let pth0 = prove
(`(&0 * &x = &0) /\
(&0 * --(&x) = &0) /\
(&x * &0 = &0) /\
(--(&x) * &0 = &0)`,
REWRITE_TAC[
REAL_MUL_LZERO;
REAL_MUL_RZERO])
and pth1,pth2 = (CONJ_PAIR o
prove)
(`((&m * &n = &(m * n)) /\
(--(&m) * --(&n) = &(m * n))) /\
((--(&m) * &n = --(&(m * n))) /\
(&m * --(&n) = --(&(m * n))))`,
REWRITE_TAC[
REAL_MUL_LNEG;
REAL_MUL_RNEG;
REAL_NEG_NEG] THEN
REWRITE_TAC[REAL_OF_NUM_MUL]) in
FIRST_CONV
[GEN_REWRITE_CONV I [pth0];
GEN_REWRITE_CONV I [pth1] THENC RAND_CONV NUM_MULT_CONV;
GEN_REWRITE_CONV I [pth2] THENC RAND_CONV(RAND_CONV NUM_MULT_CONV)];;
let REAL_INT_ADD_CONV =
let neg_tm = `(--)` in
let amp_tm = `&` in
let add_tm = `(+)` in
let dest = dest_binop `(+)` in
let m_tm = `m:num` and n_tm = `n:num` in
let pth0 = prove
(`(--(&m) + &m = &0) /\
(&m + --(&m) = &0)`,
REWRITE_TAC[REAL_ADD_LINV;
REAL_ADD_RINV]) in
let [pth1; pth2; pth3; pth4; pth5; pth6] = (CONJUNCTS o
prove)
(`(--(&m) + --(&n) = --(&(m + n))) /\
(--(&m) + &(m + n) = &n) /\
(--(&(m + n)) + &m = --(&n)) /\
(&(m + n) + --(&m) = &n) /\
(&m + --(&(m + n)) = --(&n)) /\
(&m + &n = &(m + n))`,
REWRITE_TAC[GSYM REAL_OF_NUM_ADD;
REAL_NEG_ADD] THEN
REWRITE_TAC[REAL_ADD_ASSOC; REAL_ADD_LINV; REAL_ADD_LID] THEN
REWRITE_TAC[
REAL_ADD_RINV; REAL_ADD_LID] THEN
ONCE_REWRITE_TAC[REAL_ADD_SYM] THEN
REWRITE_TAC[REAL_ADD_ASSOC; REAL_ADD_LINV; REAL_ADD_LID] THEN
REWRITE_TAC[
REAL_ADD_RINV; REAL_ADD_LID]) in
GEN_REWRITE_CONV I [pth0] ORELSEC
(fun tm ->
try let l,r = dest tm in
if rator l = neg_tm then
if rator r = neg_tm then
let th1 = INST [rand(rand l),m_tm; rand(rand r),n_tm] pth1 in
let tm1 = rand(rand(rand(concl th1))) in
let th2 = AP_TERM neg_tm (AP_TERM amp_tm (NUM_ADD_CONV tm1)) in
TRANS th1 th2
else
let m = rand(rand l) and n = rand r in
let m' = dest_numeral m and n' = dest_numeral n in
if m' <=/ n' then
let p = mk_numeral (n' -/ m') in
let th1 = INST [m,m_tm; p,n_tm] pth2 in
let th2 = NUM_ADD_CONV (rand(rand(lhand(concl th1)))) in
let th3 = AP_TERM (rator tm) (AP_TERM amp_tm (SYM th2)) in
TRANS th3 th1
else
let p = mk_numeral (m' -/ n') in
let th1 = INST [n,m_tm; p,n_tm] pth3 in
let th2 = NUM_ADD_CONV (rand(rand(lhand(lhand(concl th1))))) in
let th3 = AP_TERM neg_tm (AP_TERM amp_tm (SYM th2)) in
let th4 = AP_THM (AP_TERM add_tm th3) (rand tm) in
TRANS th4 th1
else
if rator r = neg_tm then
let m = rand l and n = rand(rand r) in
let m' = dest_numeral m and n' = dest_numeral n in
if n' <=/ m' then
let p = mk_numeral (m' -/ n') in
let th1 = INST [n,m_tm; p,n_tm] pth4 in
let th2 = NUM_ADD_CONV (rand(lhand(lhand(concl th1)))) in
let th3 = AP_TERM add_tm (AP_TERM amp_tm (SYM th2)) in
let th4 = AP_THM th3 (rand tm) in
TRANS th4 th1
else
let p = mk_numeral (n' -/ m') in
let th1 = INST [m,m_tm; p,n_tm] pth5 in
let th2 = NUM_ADD_CONV (rand(rand(rand(lhand(concl th1))))) in
let th3 = AP_TERM neg_tm (AP_TERM amp_tm (SYM th2)) in
let th4 = AP_TERM (rator tm) th3 in
TRANS th4 th1
else
let th1 = INST [rand l,m_tm; rand r,n_tm] pth6 in
let tm1 = rand(rand(concl th1)) in
let th2 = AP_TERM amp_tm (NUM_ADD_CONV tm1) in
TRANS th1 th2
with Failure _ -> failwith "REAL_INT_ADD_CONV");;
let REAL_INT_SUB_CONV =
GEN_REWRITE_CONV I [real_sub] THENC
TRY_CONV(RAND_CONV REAL_INT_NEG_CONV) THENC
REAL_INT_ADD_CONV;;
let REAL_INT_POW_CONV =
let pth1,pth2 = (CONJ_PAIR o prove)
(`(&x pow n = &(x EXP n)) /\
((--(&x)) pow n = if EVEN n then &(x EXP n) else --(&(x EXP n)))`,
REWRITE_TAC[REAL_OF_NUM_POW; REAL_POW_NEG]) in
let tth = prove
(`((if T then x:real else y) = x) /\ ((if F then x:real else y) = y)`,
REWRITE_TAC[]) in
let neg_tm = `(--)` in
(GEN_REWRITE_CONV I [pth1] THENC RAND_CONV NUM_EXP_CONV) ORELSEC
(GEN_REWRITE_CONV I [pth2] THENC
RATOR_CONV(RATOR_CONV(RAND_CONV NUM_EVEN_CONV)) THENC
GEN_REWRITE_CONV I [tth] THENC
(fun tm -> if rator tm = neg_tm then RAND_CONV(RAND_CONV NUM_EXP_CONV) tm
else RAND_CONV NUM_EXP_CONV tm));;
let REAL_INT_ABS_CONV =
let REAL_INT_RED_CONV =
let gconv_net = itlist (uncurry net_of_conv)
[`x <= y`,REAL_INT_LE_CONV;
`x < y`,REAL_INT_LT_CONV;
`x >= y`,REAL_INT_GE_CONV;
`x > y`,REAL_INT_GT_CONV;
`x:real = y`,REAL_INT_EQ_CONV;
`--x`,CHANGED_CONV REAL_INT_NEG_CONV;
`abs(x)`,REAL_INT_ABS_CONV;
`x + y`,REAL_INT_ADD_CONV;
`x - y`,REAL_INT_SUB_CONV;
`x * y`,REAL_INT_MUL_CONV;
`x pow n`,REAL_INT_POW_CONV]
(basic_net()) in
REWRITES_CONV gconv_net;;
let REAL_INT_REDUCE_CONV = DEPTH_CONV REAL_INT_RED_CONV;;