(* ========================================================================= *)
(* Dense linear order decision procedure for reals, by Sean McLaughlin.      *)
(* ========================================================================= *)
prioritize_real();;
(* ---------------------------------------------------------------------- *)
(*  Util                                                                  *)
(* ---------------------------------------------------------------------- *)
let list_conj =
  let t_tm = `T` in
  fun l -> if l = [] then t_tm else end_itlist (curry mk_conj) l;;
let mk_lt = mk_binop `(<)`;;
(* ---------------------------------------------------------------------- *)
(*  cnnf                                                                  *)
(* ---------------------------------------------------------------------- *)
let DOUBLE_NEG_CONV =
  let dn_thm = TAUT `!x. ~(~ x) <=> x` in
  let dn_conv =
    fun tm ->
      let tm' = dest_neg (dest_neg tm) in
        ISPEC tm' dn_thm in
    dn_conv;;
let IMP_CONV =
  let i_thm = TAUT `!a b. (a ==> b) <=> (~a \/ b)` in
  let i_conv =
    fun tm ->
      let (a,b) = dest_imp tm in
        ISPECL [a;b] i_thm in
    i_conv;;
let BEQ_CONV =
  let beq_thm = TAUT `!a b. (a = b) <=> (a /\ b \/ ~a /\ ~b)` in
  let beq_conv =
    fun tm ->
      let (a,b) = dest_eq tm in
        ISPECL [a;b] beq_thm in
    beq_conv;;
let NEG_AND_CONV =
  let na_thm = TAUT `!a b. ~(a /\ b) <=> (~a \/ ~b)` in
  let na_conv =
    fun tm ->
      let (a,b) = dest_conj (dest_neg tm) in
        ISPECL [a;b] na_thm in
    na_conv;;
let NEG_OR_CONV =
  let no_thm = TAUT `!a b. ~(a \/ b) <=> (~a /\ ~b)` in
  let no_conv =
    fun tm ->
      let (a,b) = dest_disj (dest_neg tm) in
        ISPECL [a;b] no_thm in
    no_conv;;
let NEG_IMP_CONV =
  let ni_thm = TAUT `!a b. ~(a ==> b) <=> (a /\ ~b)` in
  let ni_conv =
    fun tm ->
      let (a,b) = dest_imp (dest_neg tm) in
        ISPECL [a;b] ni_thm in
    ni_conv;;
let NEG_BEQ_CONV =
  let nbeq_thm = TAUT `!a b. ~(a = b) <=> (a /\ ~b \/ ~a /\ b)` in
  let nbeq_conv =
    fun tm ->
      let (a,b) = dest_eq (dest_neg tm) in
        ISPECL [a;b] nbeq_thm in
    nbeq_conv;;
(* tm = (p /\ q0) \/ (~p /\ q1) *)
let dest_cases tm =
  try
    let (l,r) = dest_disj tm in
    let (p,q0) = dest_conj l in
    let (np,q1) = dest_conj r in
      if mk_neg p = np then (p,q0,q1) else failwith "not a cases term"
  with Failure _ -> failwith "not a cases term";;
let is_cases = can dest_cases;;
let CASES_CONV =
  let c_thm =
    TAUT `!p q0 q1. ~(p /\ q0 \/ ~p /\ q1) <=> (p /\ ~q0 \/ ~p /\ ~q1)` in
  let cc =
    fun tm ->
      let (p,q0,q1) = dest_cases tm in
        ISPECL [p;q0;q1] c_thm in
    cc;;
let QE_SIMPLIFY_CONV =
  
let CNNF_CONV =
  let refl_conj = REFL `(/\)`
  and refl_disj = REFL `(\/)` in
  fun lfn_conv ->
    let rec cnnf_conv tm =
      if is_conj tm  then
        let (p,q) = dest_conj tm in
        let thm1 = cnnf_conv p in
        let thm2 = cnnf_conv q in
          MK_COMB (MK_COMB (refl_conj,thm1),thm2)
      else if is_disj tm  then
        let (p,q) = dest_disj tm in
        let thm1 = cnnf_conv p in
        let thm2 = cnnf_conv q in
          MK_COMB (MK_COMB (refl_disj,thm1),thm2)
      else if is_imp tm then
        let (p,q) = dest_imp tm in
        let thm1 = cnnf_conv (mk_neg p) in
        let thm2 = cnnf_conv q in
          TRANS (IMP_CONV tm) (MK_COMB(MK_COMB(refl_disj,thm1),thm2))
      else if is_iff tm then
        let (p,q) = dest_eq tm in
        let pthm = cnnf_conv p in
        let qthm = cnnf_conv q in
        let npthm = cnnf_conv (mk_neg p) in
        let nqthm = cnnf_conv (mk_neg q) in
        let thm1 = MK_COMB(MK_COMB(refl_conj,pthm),qthm) in
        let thm2 = MK_COMB(MK_COMB(refl_conj,npthm),nqthm) in
          TRANS (BEQ_CONV tm) (MK_COMB(MK_COMB(refl_disj,thm1),thm2))
      else if is_neg tm then
        let tm' = dest_neg tm in
          if is_neg tm' then
            let tm'' = dest_neg tm' in
            let thm = cnnf_conv tm in
              TRANS (DOUBLE_NEG_CONV tm'') thm
          else if is_conj tm' then
            let (p,q) = dest_conj tm' in
            let thm1 = cnnf_conv (mk_neg p) in
            let thm2 = cnnf_conv (mk_neg q) in
              TRANS (NEG_AND_CONV tm) (MK_COMB(MK_COMB(refl_disj,thm1),thm2))
          else if is_cases tm' then
            let (p,q0,q1) = dest_cases tm in
            let thm1 = cnnf_conv (mk_conj(p,mk_neg q0)) in
            let thm2 = cnnf_conv (mk_conj(mk_neg p,mk_neg q1)) in
              TRANS (CASES_CONV tm) (MK_COMB(MK_COMB(refl_disj,thm1),thm2))
          else if is_disj tm' then
            let (p,q) = dest_disj tm' in
            let thm1 = cnnf_conv (mk_neg p) in
            let thm2 = cnnf_conv (mk_neg q) in
              TRANS (NEG_OR_CONV tm) (MK_COMB(MK_COMB(refl_conj,thm1),thm2))
          else if is_imp tm' then
            let (p,q) = dest_imp tm' in
            let thm1 = cnnf_conv p in
            let thm2 = cnnf_conv (mk_neg q) in
              TRANS (NEG_IMP_CONV tm) (MK_COMB(MK_COMB(refl_conj,thm1),thm2))
          else if is_iff tm' then
            let (p,q) = dest_eq tm' in
            let pthm = cnnf_conv p in
            let qthm = cnnf_conv q in
            let npthm = cnnf_conv (mk_neg p) in
            let nqthm = cnnf_conv (mk_neg q) in
            let thm1 = MK_COMB (MK_COMB(refl_conj,pthm),nqthm) in
            let thm2 = MK_COMB(MK_COMB(refl_conj,npthm),qthm) in
              TRANS (NEG_BEQ_CONV tm) (MK_COMB(MK_COMB(refl_disj,thm1),thm2))
          else lfn_conv tm
      else lfn_conv tm in
      QE_SIMPLIFY_CONV THENC cnnf_conv THENC QE_SIMPLIFY_CONV;;
(*
let tests = [
`~(a /\ b)`;
`~(a \/ b)`;
`~(a ==> b)`;
`~(a:bool <=> b)`;
`~ ~ a`;
];;
map (CNNF_CONV (fun x -> REFL x)) tests;;
*)
(* ---------------------------------------------------------------------- *)
(*  Real Lists                                                            *)
(* ---------------------------------------------------------------------- *)
let MINL = new_recursive_definition list_RECURSION
  `(MINL [] default = default) /\
   (MINL (CONS h t) default = min h (MINL t default))`;;
let MAXL = new_recursive_definition list_RECURSION
  `(MAXL [] default = default) /\
   (MAXL (CONS h t) default = max h (MAXL t default))`;;
let ALL_LT_LEMMA = prove
 (`!left x lefts. 
ALL (\l. l < x) (CONS left lefts) <=> 
MAXL lefts left < x`,
  GEN_TAC THEN GEN_TAC THEN LIST_INDUCT_TAC THEN REWRITE_TAC[
MAXL; 
ALL] THEN
  SPEC_TAC(`t:real list`,`t:real list`) THEN LIST_INDUCT_TAC THEN
  REWRITE_TAC[
ALL; 
MAXL; 
MAX_LT] THEN ASM_MESON_TAC[
MAX_LT]);;
 
let ALL_GT_LEMMA = prove
 (`!right x rights.
        
ALL (\r. x < r) (CONS right rights) <=> x < 
MINL rights right`,
  GEN_TAC THEN GEN_TAC THEN LIST_INDUCT_TAC THEN REWRITE_TAC[
MINL; 
ALL] THEN
  SPEC_TAC(`t:real list`,`t:real list`) THEN LIST_INDUCT_TAC THEN
  REWRITE_TAC[
ALL; 
MINL; 
MIN_GT] THEN ASM_MESON_TAC[
MIN_GT]);;
 
let pth_triv = prove
   (`((?x. x = x) <=> T) /\
     ((?x. x = t) <=> T) /\
     ((?x. t = x) <=> T) /\
     ((?x. (x = t) /\ P x) <=> P t) /\
     ((?x. (t = x) /\ P x) <=> P t)`,
    MESON_TAC[]) in
  GEN_REWRITE_CONV I [
pth_triv]
and eq_refl_conv =