(* ------------------------------------------------------------------------- *)
(* Find sign of polynomial, using modulo-constant lookup and computation.    *)
(* ------------------------------------------------------------------------- *)
let xterm_lt t1 t2 = 
  try
    let n1,_ = dest_var t1 in
    let n2,_ = dest_var t2 in
    let i1 = String.sub n1 2 (String.length n1 - 2) in
    let i2 = String.sub n2 2 (String.length n2 - 2) in
    let x1 = int_of_string i1 in
    let x2 = int_of_string i2 in
      x1 < x2
  with _ -> failwith "xterm_lt: not an xvar?";;
(*
String.sub n1 2 (String.length n1 - 2)
substring
let t1,t2 = `x_99:real`,`x_100:real`
xterm_sort t1 t2
t1 < t2
*)
let FINDSIGN =
  let p_tm = `p:real`
  and c_tm = `c:real`
  and fth = prove
   (`r (a * b * p) (&0) ==> (a * b = &1) ==> r p (&0)`,
    DISCH_THEN(fun th -> DISCH_TAC THEN MP_TAC th) THEN
    ASM_REWRITE_TAC[REAL_MUL_ASSOC; REAL_MUL_LID]) in
  let rec FINDSIGN vars sgns p =
  try
    try SIGN_CONST p with Failure _ ->
    let mth = MONIC_CONV vars p in
    let p' = rand(concl mth) in
    let pth = find (fun th -> lhand(concl th) = p') sgns in
    let c = lhand(lhand(concl mth)) in
    let c' = term_of_rat(Int 1 // rat_of_term c) in
    let sth = SIGN_CONST c' in
    let rel_c = funpow 2 rator (concl sth) in
    let rel_p = funpow 2 rator (concl pth) in  
    let th1 =
      if rel_p = req then if rel_c = rgt then pth_0g else pth_0l
      else if rel_p = rgt then if rel_c = rgt then pth_gg else pth_gl
      else if rel_p = rlt then if rel_c = rgt then pth_lg else pth_ll 
      else if rel_p = rneq then if rel_c = rgt then pth_nzg else pth_nzl 
      else failwith "FINDSIGN" in
    let th2 = MP (MP (INST [p',p_tm; c',c_tm] th1) pth) sth in
    let th3 = EQ_MP (LAND_CONV(RAND_CONV(K(SYM mth))) (concl th2)) th2 in
    let th4 = MATCH_MP fth th3 in
      MP th4 (EQT_ELIM(REAL_RAT_REDUCE_CONV(lhand(concl th4)))) 
  with Failure _ -> failwith "FINDSIGN" in
    FINDSIGN;;
(*
let vars = [`x:real`;`y:real`]
let p =   `&7 + x * (&11 + x * (&10 + y * &7))`
let sgns = [ASSUME `&1 + x * (&11 / &7 + x * (&10 / &7 + y * &1)) < &0`]  
let sgns = [ASSUME `&1 + x * (&11 / &7 + x * (&10 / &7 + y * &1)) = &0`]  
let sgns = [ASSUME `&1 + x * (&11 / &7 + x * (&10 / &7 + y * &1)) > &0`]  
let sgns = [ASSUME `&1 + x * (&11 / &7 + x * (&10 / &7 + y * &1)) <> &0`]  
FINDSIGN vars sgns p
FINDSIGN vars sgns `-- &1`
*)
(*
ASSERTSIGN [x,y] [] (|- &7 + x * (&11 + x * (&10 + y * -- &7)) < &0
-->
[-- &1 + x * (-- &11 / &7 + x * (-- &10 / &7 + y * &1)) > &0]
ASSERTSIGN [x,y] [] (|- &7 + x * (&11 + x * (&10 + y * &7)) < &0
-->
[&1 + x * (&11 / &7 + x * (&10 / &7 + y * &1)) < &0]
*)
let ASSERTSIGN vars sgns sgn_thm = 
  let op,l,r = get_binop (concl sgn_thm) in
  let p_thm = MONIC_CONV vars l in 
  let _,pl,pr = get_binop (concl p_thm) in
  let c,_ = dest_binop rm pl in
  let c_thm = SIGN_CONST c in  
  let c_op,_,_ = get_binop (concl c_thm) in  
  let sgn_thm' =
    if c_op = rlt & op = rlt then 
      MATCH_MPL[signs_lem01;c_thm;sgn_thm;p_thm]
    else if c_op = rgt & op = rlt then
      MATCH_MPL[signs_lem02;c_thm;sgn_thm;p_thm]
    else if c_op = rlt & op = rgt then
      MATCH_MPL[signs_lem03;c_thm;sgn_thm;p_thm]
    else if c_op = rgt & op = rgt then
      MATCH_MPL[signs_lem04;c_thm;sgn_thm;p_thm]
    else if c_op = rlt & op = req then 
      MATCH_MPL[signs_lem05;c_thm;sgn_thm;p_thm]
    else if c_op = rgt & op = req then
      MATCH_MPL[signs_lem06;c_thm;sgn_thm;p_thm]
    else if c_op = rlt & op = rneq then
      MATCH_MPL[signs_lem07;c_thm;sgn_thm;p_thm]
    else if c_op = rgt & op = rneq then
      MATCH_MPL[signs_lem08;c_thm;sgn_thm;p_thm]
    else failwith "ASSERTSIGN : 0" in
  try 
    let sgn_thm'' = find (fun th -> lhand(concl th) = pr) sgns in
    let op1,l1,r1 = get_binop (concl sgn_thm') in
    let op2,l2,r2 = get_binop (concl sgn_thm'') in
      if (concl sgn_thm') = (concl sgn_thm'') then sgns 
      else if op2 = rneq & (op1 = rlt or op1 = rgt) then sgn_thm'::snd (remove ((=) sgn_thm'') sgns) 
      else failwith "ASSERTSIGN : 1"
  with Failure "find" -> sgn_thm'::sgns;; 
      
      
(*
let k0 = `&7 + x * (&11 + x * (&10 + y * -- &7))` 
MONIC_CONV vars k0
let k1 = ASSUME `&7 + x * (&11 + x * (&10 + y * -- &7)) < &0` 
let k1 = ASSUME `&7 + x * (&11 + x * (&10 + y * &7)) < &0` 
let k1 = ASSUME `&7 + x * (&11 + x * (&10 + y * &7)) = &0` 
let k1 = ASSUME `&7 + x * (&11 + x * (&10 + y * &7)) <> &0` 
let sgn_thm = k1
ASSERTSIGN vars [ASSUME `&1 + x * (&11 / &7 + x * (&10 / &7 + y * &1)) <> &0`] k1
*)
(* ---------------------------------------------------------------------- *)
(*  Case splitting                                                        *)
(* ---------------------------------------------------------------------- *)
let SPLIT_ZERO vars sgns p cont_z cont_n ex_thms =   
  try 
    let sgn_thm = FINDSIGN vars sgns p in  
    let op,l,r = get_binop (concl sgn_thm) in 
      (if op = req then cont_z else cont_n) sgns ex_thms
  with Failure "FINDSIGN" ->   
    let eq_tm = mk_eq(p,rzero) in 
    let neq_tm = mk_neq(p,rzero) in 
    let or_thm = ISPEC p signs_lem002 in
    (* zero *)  
    let z_thm = cont_z (ASSERTSIGN vars sgns (ASSUME eq_tm)) ex_thms in 
    let z_thm' = DISCH eq_tm z_thm in  
    (* nonzero *)
    let nz_thm = cont_n (ASSERTSIGN vars sgns (ASSUME neq_tm)) ex_thms in 
    let nz_thm' = DISCH neq_tm nz_thm in  
    (* combine *)
    let ret = MATCH_MPL[signs_lem003;or_thm;z_thm';nz_thm'] in
    (* matching problem... must continue by hand *)
    let ldj,rdj = dest_disj (concl ret) in
    let lcj,rcj = dest_conj ldj in
    let a,_ = dest_binop req lcj in
    let p,p1 = dest_beq rcj in
    let _,rcj = dest_conj rdj in
    let p2 = rhs rcj in
    let pull_thm = ISPECL[a;p;p1;p2] PULL_CASES_THM in
    let ret' = MATCH_EQ_MP pull_thm ret in
      ret';;
(*
let ret = MATCH_MPL[lem3;or_thm]
MATCH_MP ret z_thm'
;nz_thm'] in
let vars,sgns,p,cont_z,cont_n,ex_thms = !sz_vars, !sz_sgns, !sz_p,!sz_cont_z, !sz_cont_n ,!sz_ex_thms
    let ret = MATCH_MPL[lem3;or_thm;] 
let mp_thm = MATCH_MPL[lem3;or_thm;] in
let vars, sgns, p,cont_z,  cont_n =  !sz_vars,!sz_sgns,!sz_p,!sz_cont_z,!sz_cont_n
let mp_thm = k1
let t1 = ISPECL[`(?y. &0 + y * (&0 + x * &1) = &0)`;`T`;`T`;`&0 + x * &1`;`T`] t0
MATCH_EQ_MP t1 k1
EQ_MP t1 k1
MATCH_EQ_MP PULL_CASES_THM k1
concl k1 = lhs (concl t1)
MATCH_EQ_MP PULL_CASES_THM k0
let k0 = ASSUME `(&0 + x * &1 = &0) /\ ((?y. &0 + y * (&0 + x * &1) = &0) <=> T) \/
     &0 + x * &1 <> &0 /\
     (&0 + x * &1 > &0 /\ ((?x_1089. &0 + x_1089 * (&0 + x * &1) = &0) <=> T) \/
      &0 + x * &1 < &0 /\ ((?x_1084. &0 + x_1084 * (&0 + x * &1) = &0) <=> T))`;;
let k1 = ASSUME `(&0 + x * &1 = &0) /\ ((?y. &0 + y * (&0 + x * &1) = &0) <=> T) \/
     &0 + x * &1 <> &0 /\
     (&0 + x * &1 > &0 /\ ((?y. &0 + y * (&0 + x * &1) = &0) <=> T) \/
      &0 + x * &1 < &0 /\ ((?y. &0 + y * (&0 + x * &1) = &0) <=> T))`;;
MATCH_MPL[PULL_CASES_THM;!sz_z_thm;!sz_nz_thm] in
let thm1 = ASSUME `(?x_32. (&0 + c * &1) + x_32 * ((&0 + b * &1) + x_32 * (&0 + a * &1)) = &0) <=> T`
let thm2 = 
ASSUME `(&0 + a * ((&0 + b * (&0 + b * -- &1)) + a * (&0 + c * &4)) < &0 ==> 
          ((?x. (&0 + c * &1) + x * ((&0 + b * &1) + x * (&0 + a * &1)) = &0) <=> F)) /\
        (&0 + a * ((&0 + b * (&0 + b * -- &1)) + a * (&0 + c * &4)) > &0 ==> 
          ((?x_26. (&0 + c * &1) + x_26 * ((&0 + b * &1) + x_26 * (&0 + a * &1)) = &0) <=> T)) `
MATCH_MPL 
(* let PULL_CASES_THM = prove_by_refinement( *)
(*   `((a = &0) ==> (p <=> p0)) ==> ((a <> &0) ==> (a < &0 ==> (p <=> p1)) /\ (a > &0 ==> (p <=> p2)))  *)
(*     ==> (p <=> ((a = &0) /\ p0) \/ ((a < &0) /\ p1) \/ (a > &0 /\ p2))`, *)
(* (\* {{{ Proof *\)
[
  REWRITE_TAC[NEQ] THEN 
  MAP_EVERY BOOL_CASES_TAC [`p:bool`; `p0:bool`; `p1:bool`; `p2:bool`] THEN
  ASM_REWRITE_TAC[NEQ] THEN TRY REAL_ARITH_TAC
]);;
(\* }}} *\) *)
let PULL_CASES_THM = prove
 (`!a p p0 p1 p2.
((a = &0) /\ (p <=> p0) \/
   (a <> &0) /\ (a > &0 /\ (p <=> p1) \/ a < &0 /\ (p <=> p2))) <=>
   ((p <=> (a = &0) /\ p0 \/ a > &0 /\ p1 \/ a < &0 /\ p2))`,
(* {{{ Proof *)
   REPEAT STRIP_TAC THEN  REWRITE_TAC[
NEQ] THEN MAP_EVERY BOOL_CASES_TAC [`p:bool`; `p0:bool`; `p1:bool`; `p2:bool`] THEN
  ASM_REWRITE_TAC[] THEN REAL_ARITH_TAC);;
 
 (* }}} *)
let vars, sgns, p, cont_z, cont_n =   
[`x:real`;`y:real`],
 empty_sgns,
`&0 + y * &1`,
(fun x -> (ASSUME `abc > def`,[])),
(fun x -> (ASSUME `sean > steph`,[]))
SPLIT_ZERO vars sgns p cont_z cont_n 
ASSERTSIGN vars empty_sgns (ASSUME `&0 + y * &1 = &0`) ,
let vars = [`x:real`;`y:real`]
let sgns = ASSERTSIGN vars [] (ASSUME `&7 + x * (&11 + x * (&10 + y * -- &7)) <> &0`)
let p = `&7 + x * (&11 + x * (&10 + y * -- &7))` 
let cont_z = hd
let cont_n = hd
SPLIT_ZERO vars sgns p cont_z cont_n
let k1 = ASSUME `&7 + x * (&11 + x * (&10 + y * &7)) < &0` 
let k1 = ASSUME `&7 + x * (&11 + x * (&10 + y * &7)) = &0` 
let k1 = ASSUME `&7 + x * (&11 + x * (&10 + y * &7)) <> &0` 
let sgn_thm = k1
ASSERTSIGN vars [] k1
  
*)
let SPLIT_SIGN vars sgns p cont_p cont_n ex_thms =   
  let sgn_thm = try FINDSIGN vars sgns p   
                with Failure "FINDSIGN" ->
                failwith "SPLIT_SIGN: no sign -- should have sign assumption by now" in
  let gt_tm = mk_binop rgt p rzero in 
  let lt_tm = mk_binop rlt p rzero in 
  let op,_,_ = get_binop (concl sgn_thm) in 
  if op = rgt then cont_p sgns ex_thms
  else if op = rlt then cont_n sgns ex_thms
  else if op = req then failwith "SPLIT_SIGN: lead coef is 0"
  else if op = rneq then 
    let or_thm = MATCH_MP signs_lem0002 sgn_thm in
    (* < *)  
    let lt_sgns = ASSERTSIGN vars sgns (ASSUME lt_tm) in
    let lt_thm = cont_n lt_sgns ex_thms in 
    let lt_thm' = DISCH lt_tm lt_thm in  
     (* > *)
    let gt_sgns = ASSERTSIGN vars sgns (ASSUME gt_tm) in
    let gt_thm = cont_p gt_sgns ex_thms in 
    let gt_thm' = DISCH gt_tm gt_thm in  
    (* combine *)
    let ret = MATCH_MPL[signs_lem0003;or_thm;gt_thm';lt_thm'] in  
    (* matching problem... must continue by hand *)
    let ldj,rdj = dest_disj (concl ret) in
    let lcj,rcj = dest_conj ldj in
    let a,_ = dest_binop rgt lcj in
    let p,p1 = dest_beq rcj in
    let _,rcj = dest_conj rdj in
    let p2 = rhs rcj in
    let pull_thm = ISPECL[a;p;p1;p2] PULL_CASES_THM_NZ in
    let ret' = MATCH_EQ_MP (MATCH_MP pull_thm sgn_thm) ret in
      ret'
  else failwith "SPLIT_SIGN: unknown op";;
(*
let vars, sgns, p,cont_p,  cont_n =  !ss_vars,!ss_sgns,!ss_p,!ss_cont_p,!ss_cont_n
[`x`],
[ASSUME `&0 + x * &1 <> &0`; ARITH_RULE ` &1 > &0`],
`&0 + x * &1`
let ss_vars, ss_sgns, ss_p,ss_cont_p, ss_cont_n =  ref [],ref [],ref `T`,ref (fun x -> TRUTH,[]),ref(fun x -> TRUTH,[]);;
  ss_vars := vars;
  ss_sgns := sgns;
  ss_p := p;
  ss_cont_p := cont_p;
  ss_cont_n := cont_n;
let vars, sgns, p, cont_p, cont_n =   
[`x:real`;`y:real`],
ASSERTSIGN vars empty_sgns (ASSUME `&0 + y * &1 <> &0`) ,
`&0 + y * &1`,
(fun x -> (ASSUME `P > def`,[])),
(fun x -> (ASSUME `sean > steph`,[]))
SPLIT_SIGN vars sgns p cont_z cont_n 
let vars = [`x:real`;`y:real`]
let sgns = ASSERTSIGN vars [] (ASSUME `&7 + x * (&11 + x * (&10 + y * -- &7)) <> &0`)
let p = `&7 + x * (&11 + x * (&10 + y * -- &7))` 
let cont_p = hd
let cont_n = hd
SPLIT_SIGN vars sgns p cont_p cont_n
let sgns = ASSERTSIGN vars [] (ASSUME `&7 + x * (&11 + x * (&10 + y * -- &7)) <> &0`)
let k1 = ASSUME `&7 + x * (&11 + x * (&10 + y * &7)) < &0` 
let k1 = ASSUME `&7 + x * (&11 + x * (&10 + y * &7)) = &0` 
let k1 = ASSUME `&7 + x * (&11 + x * (&10 + y * &7)) <> &0` 
let sgn_thm = k1
ASSERTSIGN vars [] k1
*)