(*-------------------------------------------------------------------------*)
(*
   File:         mk_unless.ml
   Description: 

   This file defines the theorems for the UNLESS definition.

   Author:       (c) Copyright 1989-2008 by Flemming Andersen
   Date:         June 29, 1989
   Last Update:  December 30, 2007
*)
(*-------------------------------------------------------------------------*)

#use "mk_state_logic.ml";;

(*-------------------------------------------------------------------------*)
(* The definition of UNLESS is based on the definition:

      p UNLESS q in Pr = <!s in Pr: {p /\ ~q} s {p \/ q}>

  where p and q are state dependent first order logic predicates or all
  s in the program Pr are conditionally enabled statements transforming
  a state into a new state.

  To define UNLESS as a relation UNLESS_STMT to be satisfied for a finite
  number of program statements, we define the UNLESS_STMT to be fulfilled as
  a separate HOARE tripple relation between pre- or post predicates to be
  satisfied for state transitions. The pre- or post predicates of the
  UNLESS_STMT relation must be satisfiable for all states possible in the
  finite state space of the program.
*)

let TL_FIX = 100;;

let UNLESS_STMT = new_infix_definition
  ("UNLESS_STMT", "<=>",
   `UNLESS_STMT (p:'a->bool) q st =
      \s:'a. (p s /\ ~q s) ==> (p (st s) \/ q (st s))`, TL_FIX);;

(*
  Since a program is defined as a set (list) of statements, we
  recursively define the UNLESS relation itself using the UNLESS_STMT
  relation to be satisfied for every statement in the program.

  As the bottom of the recursion we choose the empty program always to be
  satisfied. For every statement in the program the UNLESS_STMT relation
  must be satisfied in all possible states.
*)

let UNLESS_term =
  (`(!p q. UNLESS p q  []                   <=> T) /\
    (!p q. UNLESS p q (CONS (st:'a->'a) Pr) <=>
     ((!s:'a. (p UNLESS_STMT q) st s) /\ (UNLESS p q Pr)))`);;
let UNLESS = new_recursive_definition list_RECURSION UNLESS_term;;
parse_as_infix ( "UNLESS", (TL_FIX, "right") );;

let STABLE_STMT = new_infix_definition
  ("STABLE_STMT", "<=>",
   `STABLE_STMT (p:'a->bool) st = \s:'a. p s ==> p (st s)`, TL_FIX);;

(*
* The state predicate STABLE is a special case of UNLESS.
*
*       stable p in Pr = p unless false in Pr
*)
let STABLE = new_infix_definition
  ("STABLE", "<=>", `STABLE (p:'a->bool) Pr = (p UNLESS False) Pr`, TL_FIX);;

(*
*  The state predicate INVARIANT is a special case of UNLESS too.
*  However invariant is dependent of a program /\* its initial state.
*
*       invariant P in (initial condition, Pr) =
*           (initial condition ==> p) /\ (p stable in Pr)
*)
let INVARIANT = new_infix_definition
  ("INVARIANT", "<=>",
   `INVARIANT p (p0, Pr) = ((!s:'a. p0 s ==> p s) /\ (p STABLE Pr))`, TL_FIX);;

(************************************************************************
*									*
* Lemmas used in the UNLESS Theory					*
*									*
************************************************************************)

let s = `s:'a`;;
let p = `p:'a->bool`;;
let q = `q:'a->bool`;;
let r = `r:'a->bool`;;
let P = `P:num->'a->bool`;;

let IMP_IMP_CONJIMP_lemma = TAC_PROOF
  (([],
   (`!p q ps qs p' q' p's q's.
        (p /\ ~q ==> ps \/ qs) ==> (p' /\ ~q' ==> p's \/ q's) ==>
          (p /\ p' /\ (~p \/ ~q') /\ (~p' \/ ~q) /\ (~q \/ ~q') ==>
                ps /\ p's \/ ps /\ q's \/ p's /\ qs \/ qs /\ q's)`)),
   REPEAT STRIP_TAC THEN RES_TAC THEN ASM_REWRITE_TAC []);;

let NOT_NOT_OR_lemma = TAC_PROOF
  (([],
   (`!t1 t2 t3. t1 \/ t2 \/ t3 <=> ~(~t1 /\ ~t2) \/ t3`)),
   REWRITE_TAC [NOT_CLAUSES; DE_MORGAN_THM; (SYM (SPEC_ALL DISJ_ASSOC))]);;

let CONJ_IMPLY_THM = TAC_PROOF
  (([],
   (`!p p' q q'.
     ((p \/ p') /\ (p \/ ~q') /\ (p' \/ ~q) /\ (~q \/ ~q')) =
     ((p /\ ~q) \/ (p' /\ ~q'))`)),
    REPEAT GEN_TAC THEN
    EQ_TAC THEN
    REPEAT STRIP_TAC THEN REPEAT (ASM_REWRITE_TAC []));;

(************************************************************************
*									*
* Theorems about UNLESS_STMT						*
*									*
************************************************************************)

(*
 *  The reflexivity theorem:
 *
 *               p unless_stmt P in Prog
 *)
let UNLESS_STMT_thm0 = prove_thm
  ("UNLESS_STMT_thm0",
    `!p st (s:'a). (p UNLESS_STMT p)st s`,
    REPEAT STRIP_TAC THEN
    REWRITE_TAC [UNLESS_STMT] THEN
    REWRITE_TAC [BETA_CONV (`(\s:'a. p s /\ ~(p s) ==> p (st s))s`)] THEN
    REPEAT STRIP_TAC THEN
    RES_TAC);;

(*
 *  Theorem:
 *               p unless_stmt Q in stmt, q ==> r
 *              ------------------------------
 *                   p unless_stmt r in stmt
 *)

let UNLESS_STMT_thm1 = prove_thm
  ("UNLESS_STMT_thm1",
   `!(p:'a->bool) q r st.
      ((!s. (p UNLESS_STMT q) st s) /\ (!s. (q s) ==> (r s))) ==>
       (!s. (p UNLESS_STMT r) st s)`,
   REPEAT GEN_TAC THEN
   REWRITE_TAC [UNLESS_STMT] THEN
   REPEAT STRIP_TAC THEN
   ASSUME_TAC (REWRITE_RULE [ASSUME `~r (s:'a)`]
     ( CONTRAPOS (SPEC `s:'a` (ASSUME `!s:'a. q s ==> r s`)))) THEN
   STRIP_ASSUME_TAC (REWRITE_RULE [ASSUME `(p:'a->bool) s`; ASSUME `~q (s:'a)`]
     (SPEC `s:'a` (ASSUME `!s:'a. p s /\ ~q s ==> p (st s) \/ q (st s)`))) THEN
   ASM_REWRITE_TAC [] THEN
   STRIP_ASSUME_TAC (REWRITE_RULE [ASSUME `(q:'a->bool) ((st:'a->'a) s)`]
     (SPEC `(st:'a->'a) s` (ASSUME `!s:'a. q s ==> r s`))) THEN
   ASM_REWRITE_TAC []);;

(*
   Theorem:
                p unless_stmt Q in st, p' unless_stmt q' in st
               ------------------------------------------------
                        p\/p' unless_stmt q\/q' in st
*)
let UNLESS_STMT_thm2 = prove_thm
  ("UNLESS_STMT_thm2",
   `!p q p' q' (st:'a->'a).
    ((!s. (p UNLESS_STMT q) st s) /\ (!s. (p' UNLESS_STMT q') st s)) ==>
     (!s. ((p \/* p') UNLESS_STMT (q \/* q')) st s)`,
    REWRITE_TAC [UNLESS_STMT;OR_def] THEN
    CONV_TAC (DEPTH_CONV BETA_CONV) THEN
    REWRITE_TAC [GEN_ALL (SYM (SPEC_ALL CONJ_ASSOC));
                 (SYM (SPEC_ALL DISJ_ASSOC)); NOT_CLAUSES; DE_MORGAN_THM] THEN
    (REPEAT STRIP_TAC THEN RES_TAC THEN ASM_REWRITE_TAC []));;

(*
  Conjunction Theorem:
               p unless_stmt Q in stmt, p' unless_stmt q' in stmt
     ------------------------------------------------------------------
     (p /\ p') unless_stmt (p /\ q') \/ (p' /\ q) \/ (q /\ q') in stmt
*)
let UNLESS_STMT_thm3 = prove_thm
  ("UNLESS_STMT_thm3",
   `!p q p' q' (st:'a->'a).
     ((!s. (p UNLESS_STMT q) st s) /\ (!s. (p' UNLESS_STMT q') st s)) ==>
      (!s. ((p /\* p') UNLESS_STMT
           (((p /\* q') \/* (p' /\* q)) \/* (q /\* q'))) st s)`,
    PURE_REWRITE_TAC [UNLESS_STMT;AND_def;OR_def] THEN
    CONV_TAC (DEPTH_CONV BETA_CONV) THEN
    REWRITE_TAC [GEN_ALL (SYM (SPEC_ALL CONJ_ASSOC));
                 (SYM (SPEC_ALL DISJ_ASSOC)); NOT_CLAUSES; DE_MORGAN_THM] THEN
    STRIP_TAC THEN STRIP_TAC THEN STRIP_TAC THEN STRIP_TAC THEN STRIP_TAC THEN
    DISCH_TAC THEN STRIP_TAC THEN DISCH_TAC THEN
    ASSUME_TAC (CONJUNCT1 (ASSUME
       (`(!s. p s /\ ~q s ==> p ((st:'a->'a) s) \/ q (st s)) /\
           (!s. p' s /\ ~q' s ==> p'((st:'a->'a) s) \/ q'(st s))`))) THEN
    ASSUME_TAC (CONJUNCT2 (ASSUME
       (`(!s. p s /\ ~q s ==> p ((st:'a->'a) s) \/ q (st s)) /\
           (!s. p' s /\ ~q' s ==> p'((st:'a->'a) s) \/ q'(st s))`))) THEN
    STRIP_ASSUME_TAC (SPEC_ALL (ASSUME
       (`(!s. p s /\ ~q s ==> p ((st:'a->'a) s) \/ q (st s))`))) THEN
    STRIP_ASSUME_TAC (SPEC_ALL (ASSUME
       (`(!s. p' s /\ ~q' s ==> p'((st:'a->'a) s) \/ q'(st s))`))) THEN
    ASSUME_TAC (UNDISCH_ALL
     (SPEC (`(q':'a->bool) ((st:'a->'a) s)`)
      (SPEC (`(p':'a->bool) ((st:'a->'a) s)`)
       (SPEC (`(q':'a->bool) s`)
        (SPEC (`(p':'a->bool) s`)
         (SPEC (`(q:'a->bool) ((st:'a->'a) s)`)
          (SPEC (`(p:'a->bool) ((st:'a->'a) s)`)
           (SPEC (`(q:'a->bool) s`)
            (SPEC (`(p:'a->bool) s`)
             IMP_IMP_CONJIMP_lemma))))))))) THEN
    ASM_REWRITE_TAC []);;

(*
  Disjunction Theorem:
               p unless_stmt Q in stmt, p' unless_stmt q' in stmt
     ------------------------------------------------------------------
     (p \/ p') unless_stmt (~p /\ q') \/ (~p' /\ q) \/ (q /\ q') in stmt
*)
let UNLESS_STMT_thm4 = prove_thm
  ("UNLESS_STMT_thm4",
   `!p q p' q' (st:'a->'a).
     ((!s. (p UNLESS_STMT q) st s) /\ (!s. (p' UNLESS_STMT q') st s)) ==>
      (!s. ((p \/* p') UNLESS_STMT
            ((((Not p) /\* q') \/* ((Not p') /\* q)) \/* (q /\* q')))
           st s)`,
    REPEAT GEN_TAC THEN
    PURE_REWRITE_TAC [UNLESS_STMT;AND_def;OR_def;NOT_def1] THEN
    MESON_TAC []);;

let UNLESS_STMT_thm5_lemma1 = TAC_PROOF
  (([],
   `!p q r. (p ==> q) ==> (p \/ r ==> q \/ r)`),
   REPEAT STRIP_TAC THENL
     [RES_TAC THEN ASM_REWRITE_TAC []
     ;ASM_REWRITE_TAC []]);;

let UNLESS_STMT_thm5_lemma2 = TAC_PROOF
  (([],
   `!(P:num->('a->bool)) q s. ((?n. P n s) \/ q s) = (?n. P n s \/ q s)`),
   REPEAT GEN_TAC THEN EQ_TAC THEN REPEAT STRIP_TAC THENL
    [ EXISTS_TAC (`n:num`) THEN
      ASM_REWRITE_TAC []
    ; EXISTS_TAC (`n:num`) THEN
      ASM_REWRITE_TAC []
    ; DISJ1_TAC THEN
      EXISTS_TAC (`n:num`) THEN
      ASM_REWRITE_TAC []
    ; DISJ2_TAC THEN
      ASM_REWRITE_TAC []
    ]);;

let UNLESS_STMT_thm5 = prove_thm
  ("UNLESS_STMT_thm5",
   `!(P:num->('a->bool)) q st.
          (!m. (!s. ((P m) UNLESS_STMT q)st s)) ==>
               (!s. ((\s. ?n. P n s) UNLESS_STMT q)st s)`,
   REPEAT GEN_TAC THEN
   REWRITE_TAC [UNLESS_STMT] THEN
   BETA_TAC THEN
   REPEAT STRIP_TAC THEN
   REWRITE_TAC [UNLESS_STMT_thm5_lemma2] THEN
   EXISTS_TAC (`n:num`) THEN
   RES_TAC THEN
   ASM_REWRITE_TAC []);;

let UNLESS_STMT_thm6 = prove_thm
  ("UNLESS_STMT_thm6",
   `!(p:'a->bool) q r (st:'a->'a).
      (!s. (p UNLESS_STMT q) st s) ==>
         (!s. ((p \/* r) UNLESS_STMT (q \/* r)) st s)`,
   REPEAT GEN_TAC THEN
   REWRITE_TAC [UNLESS_STMT; OR_def] THEN
   MESON_TAC []);;

(*
 Theorems about UNLESS
*)

(*
  The reflexivity theorem:
               p unless p in Prog
*)

let UNLESS_thm1 = prove_thm
  ("UNLESS_thm1",
   `!(p:'a->bool) Pr. (p UNLESS p) Pr`,
   GEN_TAC THEN
   LIST_INDUCT_TAC THEN
   PURE_REWRITE_TAC [UNLESS] THEN
   ASM_REWRITE_TAC [] THEN
   PURE_REWRITE_TAC [UNLESS_STMT] THEN
   CONV_TAC (DEPTH_CONV BETA_CONV) THEN
   REPEAT STRIP_TAC THEN
   RES_TAC);;

(*
*  The anti reflexivity theorem:
*
*               p unless ~p in Prog
*)
let UNLESS_thm2 = prove_thm
  ("UNLESS_thm2",
   (`!(p:'a->bool) Pr. (p UNLESS (Not p)) Pr`),
   GEN_TAC THEN
   LIST_INDUCT_TAC THEN
   PURE_REWRITE_TAC [UNLESS] THEN
   ASM_REWRITE_TAC [] THEN
   PURE_REWRITE_TAC [UNLESS_STMT;NOT_def1] THEN
   CONV_TAC (DEPTH_CONV BETA_CONV) THEN
   REPEAT STRIP_TAC THEN
   REWRITE_TAC [EXCLUDED_MIDDLE]);;

(*
  The unless implies theorem:
               p unless q in Pr, q ==> r
              ---------------------------
                   p unless r in Pr
*)
let UNLESS_thm3 = prove_thm
  ("UNLESS_thm3",
   `!(p:'a->bool) q r Pr.
      (((p UNLESS q) Pr) /\ (!s. (q s) ==> (r s))) ==> ((p UNLESS r) Pr)`,
    GEN_TAC THEN GEN_TAC THEN GEN_TAC THEN
    LIST_INDUCT_TAC THEN
    REWRITE_TAC [UNLESS] THEN
    STRIP_TAC THEN
    ASM_REWRITE_TAC [] THEN
    RES_TAC THEN
    ASM_REWRITE_TAC [] THEN
    IMP_RES_TAC UNLESS_STMT_thm1);;

(*
  Conjunction Theorem:
               p unless q in Pr, p' unless q' in Pr
     -----------------------------------------------------------
     (p /\ p') unless (p /\ q') \/ (p' /\ q) \/ (q /\ q') in Pr
*)
let UNLESS_thm4 = prove_thm
  ("UNLESS_thm4",
   `!(p:'a->bool) q p' q' Pr.
      (((p UNLESS q) Pr) /\ ((p' UNLESS q') Pr)) ==>
        (((p /\* p') UNLESS
         (((p /\* q') \/* (p' /\* q)) \/* (q /\* q'))) Pr)`,
    GEN_TAC THEN GEN_TAC THEN GEN_TAC THEN GEN_TAC THEN
    LIST_INDUCT_TAC THEN
    REWRITE_TAC [UNLESS] THEN
    STRIP_TAC THEN
    ASM_REWRITE_TAC [] THEN
    RES_TAC THEN
    ASM_REWRITE_TAC [] THEN
    IMP_RES_TAC UNLESS_STMT_thm3);;

(*
  Disjunction Theorem:
               p unless q in Pr, p' unless q' in Pr
     -------------------------------------------------------------
     (p \/ p') unless (~p /\ q') \/ (~p' /\ q) \/ (q /\ q') in Pr
*)
let UNLESS_thm5 = prove_thm
  ("UNLESS_thm5",
   `!(p:'a->bool) q p' q' Pr.
        (((p UNLESS q) Pr) /\ ((p' UNLESS q') Pr))
      ==>
        (((p \/* p') UNLESS
	  ((((Not p) /\* q') \/* ((Not p') /\* q)) \/* (q /\* q'))) Pr)`,
    GEN_TAC THEN GEN_TAC THEN GEN_TAC THEN GEN_TAC THEN
    LIST_INDUCT_TAC THEN
    REWRITE_TAC [UNLESS] THEN
    STRIP_TAC THEN
    ASM_REWRITE_TAC [] THEN
    RES_TAC THEN
    ASM_REWRITE_TAC [] THEN
    IMP_RES_TAC UNLESS_STMT_thm4);;

(*
  Simple Conjunction Theorem:
               p unless q in Pr, p' unless q' in Pr
              -------------------------------------------
                    (p /\ p') unless (q \/ q') in Pr
*)
let UNLESS_thm6 = prove_thm
  ("UNLESS_thm6",
   `!(p:'a->bool) q p' q' Pr.
      (((p UNLESS q) Pr) /\ ((p' UNLESS q') Pr)) ==>
         (((p /\* p') UNLESS (q \/* q')) Pr)`,
    REPEAT STRIP_TAC THEN
    ASSUME_TAC (UNDISCH_ALL (SPECL
         [(`((p:'a->bool) UNLESS q)Pr`);
          (`((p':'a->bool) UNLESS q')Pr`)]
           AND_INTRO_THM)) THEN
    ASSUME_TAC (UNDISCH_ALL (SPEC_ALL UNLESS_thm4)) THEN
    ASSUME_TAC (SPECL [(`p:'a->bool`); (`q:'a->bool`);
                       (`p':'a->bool`); (`q':'a->bool`)]
                       IMPLY_WEAK_lemma1) THEN
    ASSUME_TAC (UNDISCH_ALL (SPECL
       [(`(((p:'a->bool) /\* p') UNLESS
	     (((p /\* q') \/* (p' /\* q)) \/* (q /\* q')))Pr`);
        (`!s. ((((p:'a->bool) /\* q') \/* (p' /\* q)) \/* (q /\* q'))s ==>
                (q \/* q')s`)]
        AND_INTRO_THM)) THEN
    ASM_REWRITE_TAC [UNDISCH_ALL (SPECL
         [(`(p:'a->bool) /\* p'`);
          (`((((p:'a->bool) /\* q') \/* (p' /\* q)) \/* (q /\* q'))`);
          (`(q:'a->bool) \/* q'`); (`Pr:('a->'a)list`)]
          UNLESS_thm3)]);;

(*
  Simple Disjunction Theorem:
               p unless Q in Pr, p' unless q' in Pr
             ---------------------------------------
                 (p \/ p') unless (q \/ q') in Pr
*)
let UNLESS_thm7 = prove_thm
  ("UNLESS_thm7",
   `!(p:'a->bool) q p' q' Pr.
         (((p UNLESS q) Pr) /\ ((p' UNLESS q') Pr)) ==>
             (((p \/* p') UNLESS (q \/* q')) Pr)`,
    REPEAT STRIP_TAC THEN
    ASSUME_TAC (UNDISCH_ALL (SPECL
        [(`((p:'a->bool) UNLESS q)Pr`); (`((p':'a->bool) UNLESS q')Pr`)]
         AND_INTRO_THM)) THEN
    ASSUME_TAC (UNDISCH_ALL (SPEC_ALL UNLESS_thm5)) THEN
    ASSUME_TAC (SPECL [(`p:'a->bool`);  (`q:'a->bool`);
                       (`p':'a->bool`); (`q':'a->bool`)]
                       IMPLY_WEAK_lemma2) THEN
    ASSUME_TAC (UNDISCH_ALL (SPECL
         [(`(((p:'a->bool) \/* p') UNLESS
               ((((Not p) /\* q') \/* ((Not p') /\* q)) \/* (q /\* q')))
               Pr`);
          (`!s. ((((Not (p:'a->bool)) /\* q') \/* ((Not p') /\* q)) \/*
                    (q /\* q'))s ==> (q \/* q')s`)]
          AND_INTRO_THM)) THEN
    STRIP_ASSUME_TAC (UNDISCH_ALL (SPECL
         [`(p:'a->bool) \/* p'`;
          `(((Not (p:'a->bool)) /\* q') \/* ((Not p') /\* q)) \/* (q /\* q')`;
          `(q:'a->bool) \/* q'`;
          `Pr:('a->'a)list`]
           UNLESS_thm3)));;

(*
  Cancellation Theorem:
               p unless Q in Pr, q unless r in Pr
              ------------------------------------
                    (p \/ q) unless r in Pr
*)
let UNLESS_thm8 = prove_thm
  ("UNLESS_thm8",
   `!(p:'a->bool) q r Pr.
     (((p UNLESS q) Pr) /\ ((q UNLESS r) Pr)) ==>
     (((p \/* q) UNLESS r) Pr)`,
    REPEAT STRIP_TAC THEN
    ASSUME_TAC (UNDISCH_ALL (SPECL
         [`((p:'a->bool) UNLESS q)Pr`; `((q:'a->bool) UNLESS r)Pr`]
          AND_INTRO_THM)) THEN
    ASSUME_TAC (UNDISCH_ALL (SPEC_ALL (SPECL
         [(`p:'a->bool`); (`q:'a->bool`);
          (`q:'a->bool`); (`r:'a->bool`)]
          UNLESS_thm5))) THEN
    ASSUME_TAC (SPECL
         [(`p:'a->bool`); (`q:'a->bool`); (`r:'a->bool`)]
          IMPLY_WEAK_lemma3) THEN
    ASSUME_TAC (UNDISCH_ALL (SPECL
         [(`(((p:'a->bool) \/* q) UNLESS
           ((((Not p) /\* r) \/* ((Not q) /\* q)) \/* (q /\* r))) Pr`);
          (`!s:'a. ((((Not p) /\* r) \/* ((Not q) /\* q)) \/*
                      (q /\* r))s ==> r s`)]
          AND_INTRO_THM)) THEN
    STRIP_ASSUME_TAC (UNDISCH_ALL (SPEC_ALL (SPECL
         [(`((p:'a->bool) \/* q)`);
          (`((((Not (p:'a->bool)) /\* r) \/* ((Not q) /\* q)) \/*
               (q /\* r))`);
          (`r:'a->bool`)]
          UNLESS_thm3))));;

(*
  Corollaries
*)
let UNLESS_cor1 = prove_thm
  ("UNLESS_cor1",
   `!(p:'a->bool) q Pr. (!s. p s ==> q s) ==> ((p UNLESS q) Pr)`,
    REPEAT STRIP_TAC THEN
    ASSUME_TAC (SPEC_ALL UNLESS_thm1) THEN
    ASSUME_TAC (UNDISCH_ALL (SPECL
      [`((p:'a->bool) UNLESS p)Pr`; `!s:'a. p s ==> q s`]
       AND_INTRO_THM)) THEN
    ASM_REWRITE_TAC [UNDISCH_ALL (SPECL
      [(`p:'a->bool`); (`p:'a->bool`); (`q:'a->bool`);
       (`Pr:('a->'a)list`)] UNLESS_thm3)]);;

let UNLESS_cor2 = prove_thm
  ("UNLESS_cor2",
   (`!(p:'a->bool) q Pr. (!s. (Not p)s ==> q s) ==> ((p UNLESS q) Pr)`),
    REPEAT STRIP_TAC THEN
    ASSUME_TAC (SPEC_ALL UNLESS_thm2) THEN
    ASSUME_TAC (UNDISCH_ALL (SPECL
      [(`((p:'a->bool) UNLESS (Not p))Pr`);
       (`!s:'a. (Not p) s ==> q s`)]
       AND_INTRO_THM)) THEN
    ASM_REWRITE_TAC [UNDISCH_ALL (SPECL
       [(`p:'a->bool`); (`Not (p:'a->bool)`);
        (`q:'a->bool`); (`Pr:('a->'a)list`)]
        UNLESS_thm3)]);;

let UNLESS_cor3a = TAC_PROOF
  (([],
   (`!(p:'a->bool) q r Pr.
          (p UNLESS (q \/* r)) Pr ==>
          ((p /\* (Not q)) UNLESS (q \/* r)) Pr`)),
   REPEAT GEN_TAC THEN
   ASSUME_TAC (SPECL [(`Not (q:'a->bool)`);
                      (`Pr:('a->'a)list`)] UNLESS_thm2) THEN
   UNDISCH_TAC (`((Not (q:'a->bool)) UNLESS (Not(Not q)))Pr`) THEN
   REWRITE_TAC [NOT_NOT_lemma] THEN
   REPEAT STRIP_TAC THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`((p:'a->bool) UNLESS (q \/* r))Pr`);
      (`((Not (q:'a->bool)) UNLESS q)Pr`)]
      AND_INTRO_THM)) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`p:'a->bool`); (`((q:'a->bool) \/* r)`);
      (`(Not (q:'a->bool))`); (`q:'a->bool`); (`Pr:('a->'a)list`)]
      UNLESS_thm6)) THEN
   UNDISCH_TAC (`(((p:'a->bool) /\* (Not q)) UNLESS
                    ((q \/* r) \/* q))Pr`) THEN
   PURE_ONCE_REWRITE_TAC
      [SPECL [(`(q:'a->bool) \/* r`);
              (`q:'a->bool`)] OR_COMM_lemma] THEN
   REWRITE_TAC [GEN_ALL (SYM (SPEC_ALL OR_ASSOC_lemma))] THEN
   REWRITE_TAC [OR_OR_lemma]);;

let UNLESS_cor3b = TAC_PROOF
  (([],
   (`!(p:'a->bool) q r Pr.
      ((p /\* (Not q)) UNLESS (q \/* r)) Pr ==> (p UNLESS (q \/* r)) Pr`)),
   REPEAT STRIP_TAC THEN
   ASSUME_TAC (SPECL [(`(p:'a->bool) /\* q`);
                      (`Pr:('a->'a)list`)] UNLESS_thm1) THEN
   ASSUME_TAC (SPECL [(`p:'a->bool`); (`q:'a->bool`)]
                 AND_IMPLY_WEAK_lemma) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`(((p:'a->bool) /\* q) UNLESS (p /\* q))Pr`);
      (`!s:'a. (p /\* q)s ==> q s`)]
      AND_INTRO_THM)) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`(p:'a->bool) /\* q`); (`(p:'a->bool) /\* q`);
      (`q:'a->bool`); (`Pr:('a->'a)list`)]
      UNLESS_thm3)) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`(((p:'a->bool) /\* (Not q)) UNLESS (q \/* r))Pr`);
      (`(((p:'a->bool) /\* q) UNLESS q)Pr`)]
      AND_INTRO_THM)) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`((p:'a->bool) /\* (Not q))`); (`((q:'a->bool) \/* r)`);
      (`((p:'a->bool) /\* q)`); (`q:'a->bool`); (`Pr:('a->'a)list`)]
      UNLESS_thm7)) THEN
   UNDISCH_TAC
   (`((((p:'a->bool) /\* (Not q)) \/* (p /\* q)) UNLESS
        ((q \/* r) \/* q))Pr`) THEN
   REWRITE_TAC [AND_COMPL_OR_lemma] THEN
   ONCE_REWRITE_TAC [OR_COMM_lemma] THEN
   REWRITE_TAC [GEN_ALL (SYM (SPEC_ALL (OR_ASSOC_lemma)))] THEN
   REWRITE_TAC [OR_OR_lemma] THEN
   STRIP_TAC THEN
   ONCE_REWRITE_TAC [OR_COMM_lemma] THEN
   ASM_REWRITE_TAC []);;

let UNLESS_cor3 = prove_thm
  ("UNLESS_cor3",
   (`!(p:'a->bool) q r Pr.
         ((p /\* (Not q)) UNLESS (q \/* r)) Pr = (p UNLESS (q \/* r)) Pr`),
   REWRITE_TAC [IMP_ANTISYM_RULE
                 (SPEC_ALL UNLESS_cor3b) (SPEC_ALL UNLESS_cor3a)]);;

let UNLESS_cor4 = prove_thm
  ("UNLESS_cor4",
   (`!(p:'a->bool) q r Pr.
               ((p \/* q) UNLESS r) Pr ==> (p UNLESS (q \/* r)) Pr`),
   REPEAT STRIP_TAC THEN
   ASSUME_TAC (SPEC_ALL ((SPEC (`Not (q:'a->bool)`) UNLESS_thm2))) THEN
   UNDISCH_TAC (`((Not (q:'a->bool)) UNLESS (Not(Not q)))Pr`) THEN
   REWRITE_TAC [NOT_NOT_lemma] THEN
   STRIP_TAC THEN
   ASSUME_TAC (UNDISCH_ALL (SPEC_ALL (SPECL
         [(`(((p:'a->bool) \/* q) UNLESS r)Pr`);
          (`((Not (q:'a->bool)) UNLESS q)Pr`)]
          AND_INTRO_THM))) THEN
   ASSUME_TAC (UNDISCH_ALL (SPEC_ALL (SPECL
         [(`((p:'a->bool) \/* q)`); (`r:'a->bool`);
          (`(Not (q:'a->bool))`); (`q:'a->bool`)]
          UNLESS_thm6))) THEN
   UNDISCH_TAC (`((((p:'a->bool) \/* q) /\* (Not q)) UNLESS
                    (r \/* q))Pr`) THEN
   REWRITE_TAC [OR_NOT_AND_lemma] THEN
   PURE_ONCE_REWRITE_TAC [SPECL [(`r:'a->bool`); (`q:'a->bool`)]
       OR_COMM_lemma] THEN
   REWRITE_TAC [UNLESS_cor3] THEN
   STRIP_TAC THEN
   PURE_ONCE_REWRITE_TAC [SPECL [(`r:'a->bool`); (`q:'a->bool`)]
       OR_COMM_lemma] THEN
   ASM_REWRITE_TAC []);;

let UNLESS_cor5 = prove_thm
  ("UNLESS_cor5",
   (`!(p:'a->bool) Pr. (p UNLESS True) Pr`),
   REPEAT GEN_TAC THEN
   ASSUME_TAC (SPEC_ALL UNLESS_thm1) THEN
   ASSUME_TAC (SPEC_ALL UNLESS_thm2) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
         [(`((p:'a->bool) UNLESS p)Pr`);
          (`((p:'a->bool) UNLESS (Not p))Pr`)]
          AND_INTRO_THM)) THEN
   ASSUME_TAC (UNDISCH_ALL (SPEC_ALL (SPECL
         [(`p:'a->bool`); (`p:'a->bool`);
          (`p:'a->bool`); (`(Not (p:'a->bool))`)]
          UNLESS_thm6))) THEN
   UNDISCH_TAC (`(((p:'a->bool) /\* p) UNLESS (p \/* (Not p)))Pr`) THEN
   REWRITE_TAC [AND_AND_lemma;P_OR_NOT_P_lemma]);;

let UNLESS_cor6 = prove_thm
  ("UNLESS_cor6",
   (`!(p:'a->bool) Pr. (True UNLESS p) Pr`),
   REPEAT GEN_TAC THEN
   ASSUME_TAC (SPEC_ALL UNLESS_thm1) THEN
   ASSUME_TAC (SPEC_ALL (SPEC (`(Not (p:'a->bool))`) UNLESS_thm2)) THEN
   UNDISCH_TAC (`((Not (p:'a->bool)) UNLESS (Not(Not p)))Pr`) THEN
   REWRITE_TAC [NOT_NOT_lemma] THEN
   DISCH_TAC THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
         [(`((Not (p:'a->bool)) UNLESS p)Pr`);
	  (`((p:'a->bool) UNLESS p)Pr`)]
          AND_INTRO_THM)) THEN
   ASSUME_TAC (UNDISCH_ALL (SPEC_ALL (SPECL
         [(`(Not (p:'a->bool))`); (`p:'a->bool`);
	  (`p:'a->bool`); (`p:'a->bool`)]
          UNLESS_thm7))) THEN
   UNDISCH_TAC (`(((Not (p:'a->bool)) \/* p) UNLESS (p \/* p))Pr`) THEN
   PURE_ONCE_REWRITE_TAC [OR_COMM_lemma] THEN
   REWRITE_TAC [OR_OR_lemma;P_OR_NOT_P_lemma]);;

let UNLESS_cor7 = prove_thm
  ("UNLESS_cor7",
   (`!(p:'a->bool) Pr. (False UNLESS p) Pr`),
   REPEAT GEN_TAC THEN
   ASSUME_TAC (SPEC_ALL UNLESS_thm1) THEN
   ASSUME_TAC (SPEC_ALL (SPEC (`(Not (p:'a->bool))`) UNLESS_thm2)) THEN
   UNDISCH_TAC (`((Not (p:'a->bool)) UNLESS (Not(Not p)))Pr`) THEN
   REWRITE_TAC [NOT_NOT_lemma] THEN
   DISCH_TAC THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
         [(`((Not (p:'a->bool)) UNLESS p)Pr`);
	  (`((p:'a->bool) UNLESS p)Pr`)]
          AND_INTRO_THM)) THEN
   ASSUME_TAC (UNDISCH_ALL (SPEC_ALL (SPECL
         [(`(Not (p:'a->bool))`); (`p:'a->bool`);
	  (`p:'a->bool`); (`p:'a->bool`)]
          UNLESS_thm6))) THEN
   UNDISCH_TAC (`(((Not (p:'a->bool)) /\* p) UNLESS (p \/* p))Pr`) THEN
   PURE_ONCE_REWRITE_TAC [AND_COMM_lemma] THEN
   REWRITE_TAC [OR_OR_lemma;P_AND_NOT_P_lemma]);;

let HeJiFeng_lemma1 = TAC_PROOF
  (([],
   (`!(p:'a->bool) q p'.
     (!s. p s /\ ~q s) ==> (!s. p' s) ==> (!s. p s \/ q s) ==>
         (!s. p s /\ ~q s ==> p' s /\ ~q s)`)),
   REPEAT STRIP_TAC THEN RES_TAC THEN ASM_REWRITE_TAC []);;

let HeJiFeng_lemma2 = TAC_PROOF
  (([],
   (`!(p:'a->bool) q p'.
     (!s. p s /\ ~q s) ==> (!s. p' s) ==> (!s. p s \/ q s) ==>
         (!s. p' s /\ ~q s ==> p s /\ ~q s)`)),
   REPEAT STRIP_TAC THEN RES_TAC THEN ASM_REWRITE_TAC []);;

let HeJiFeng_lemma = TAC_PROOF
  (([],
   (`!(p:'a->bool) q p'.
     (!s. p s /\ ~q s) ==> (!s. p' s) ==> (!s. p s \/ q s) ==>
         (!s. p s /\ ~q s <=> p' s /\ ~q s)`)),
   REPEAT STRIP_TAC THEN
   REWRITE_TAC [IMP_ANTISYM_RULE
     (SPEC_ALL (UNDISCH (UNDISCH (UNDISCH (SPEC_ALL HeJiFeng_lemma1)))))
     (SPEC_ALL (UNDISCH (UNDISCH (UNDISCH (SPEC_ALL HeJiFeng_lemma2)))))]);;

let HeJiFeng_lemma_f = MK_ABS (UNDISCH_ALL (SPEC_ALL HeJiFeng_lemma));;

let UNLESS_cor8 = prove_thm
  ("UNLESS_cor8",
   (`!(p:'a->bool) q p' Pr.
       (!s. p s /\ ~q s) ==> (!s. p' s) ==> (!s. p s \/ q s)
            ==> (((p  /\* (Not q)) UNLESS q) Pr =
                 ((p' /\* (Not q)) UNLESS q) Pr)`),
   REPEAT STRIP_TAC THEN
   REWRITE_TAC [AND_def;OR_def;NOT_def1] THEN
   CONV_TAC (DEPTH_CONV BETA_CONV) THEN
   REWRITE_TAC [HeJiFeng_lemma_f]);;

(*
  Corollary of generalized cancellation
*)
let UNLESS_cor9 = prove_thm
  ("UNLESS_cor9",
   (`!(p:'a->bool) q p' q' r r' Pr.
     ((p \/* p') UNLESS (q \/* r)) Pr /\ ((q \/* q') UNLESS (p \/* r')) Pr ==>
            ((p \/* p' \/* q \/* q') UNLESS ((p /\* q) \/* r \/* r')) Pr`),
   REPEAT GEN_TAC THEN DISCH_TAC THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
         [(`((p:'a->bool) \/* p')`); (`((q:'a->bool) \/* r)`);
          (`((q:'a->bool) \/* q')`); (`((p:'a->bool) \/* r')`);
	  (`Pr:('a->'a)list`)]
          UNLESS_thm5)) THEN
   ASSUME_TAC (SPECL
        [(`p:'a->bool`); (`q:'a->bool`);
	 (`p':'a->bool`); (`q':'a->bool`);
         (`r:'a->bool`); (`r':'a->bool`)] IMPLY_WEAK_lemma4) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
      [(`((((p:'a->bool) \/* p') \/* (q \/* q')) UNLESS
        ((((Not(p \/* p')) /\* (p \/* r')) \/*
          ((Not(q \/* q')) /\* (q \/* r))) \/*
         ((q \/* r) /\* (p \/* r')))) Pr`);
       (`!s:'a. ((((Not(p \/* p')) /\* (p \/* r')) \/*
              ((Not(q \/* q')) /\* (q \/* r))) \/*
              ((q \/* r) /\* (p \/* r'))) s ==>
                  ((p /\* q) \/* (r \/* r'))s`)]
       AND_INTRO_THM)) THEN
   STRIP_ASSUME_TAC (UNDISCH_ALL (SPEC_ALL (SPECL
        [(`(((p:'a->bool) \/* p') \/* (q \/* q'))`);
         (`((((Not((p:'a->bool) \/* p')) /\* (p \/* r')) \/*
          ((Not(q \/* q')) /\* (q \/* r))) \/*
          ((q \/* r) /\* (p \/* r')))`);
         (`(((p:'a->bool) /\* q) \/* (r \/* r'))`)]
         UNLESS_thm3))) THEN
   UNDISCH_TAC (`((((p:'a->bool) \/* p') \/* (q \/* q')) UNLESS
                ((p /\* q) \/* (r \/* r')))Pr`) THEN
   REWRITE_TAC [OR_ASSOC_lemma]);;

let UNLESS_cor10 = prove_thm
  ("UNLESS_cor10",
   (`!(p:'a->bool) q Pr. (p \/* q) STABLE Pr ==> (p UNLESS q) Pr`),
   REPEAT GEN_TAC THEN
   REWRITE_TAC [STABLE] THEN
   DISCH_TAC THEN
   STRIP_ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`p:'a->bool`); (`q:'a->bool`);
      (`False:'a->bool`); (`Pr:('a->'a)list`)]
      UNLESS_cor4)) THEN
   UNDISCH_TAC (`((p:'a->bool) UNLESS (q \/* False))Pr`) THEN
   REWRITE_TAC [OR_False_lemma]);;


let UNLESS_cor11 = prove_thm
  ("UNLESS_cor11",
   (`!(p:'a->bool) Pr. (!s. (Not p)s) ==> p STABLE Pr`),
   GEN_TAC THEN
   REWRITE_TAC [STABLE] THEN
   LIST_INDUCT_TAC THEN
   REWRITE_TAC [UNLESS] THEN
   STRIP_TAC THEN
   RES_TAC THEN
   ASM_REWRITE_TAC [] THEN
   GEN_TAC THEN
   REWRITE_TAC [UNLESS_STMT; FALSE_def] THEN
   STRIP_ASSUME_TAC (REWRITE_RULE [NOT_def1]
       (SPEC `s:'a` (ASSUME `!s:'a. Not (p:'a->bool) s`))) THEN
   STRIP_TAC THEN
   RES_TAC);;

let UNLESS_cor12 = prove_thm
  ("UNLESS_cor12",
   (`!(p:'a->bool) Pr. (!s. (Not p)s) ==> (Not p) STABLE Pr`),
   GEN_TAC THEN
   REWRITE_TAC [STABLE] THEN
   LIST_INDUCT_TAC THEN
   REWRITE_TAC [UNLESS] THEN
   STRIP_TAC THEN
   RES_TAC THEN
   ASM_REWRITE_TAC [UNLESS_STMT]);;

let UNLESS_cor13 = prove_thm
  ("UNLESS_cor13",
   (`!(p:'a->bool) q Pr.
        (p UNLESS q) Pr /\ (q UNLESS p) Pr /\ (!s. Not (p /\* q) s) ==>
                (p \/* q) STABLE Pr`),
   REPEAT STRIP_TAC THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
         [(`((p:'a->bool) /\* q)`);
	  (`Pr:('a->'a)list`)] UNLESS_cor11)) THEN
   UNDISCH_TAC (`((p:'a->bool) /\* q) STABLE Pr`) THEN
   REWRITE_TAC [STABLE] THEN
   DISCH_TAC THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
      [(`((p:'a->bool) UNLESS q)Pr`); (`((q:'a->bool) UNLESS p)Pr`)]
       AND_INTRO_THM)) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
      [(`(p:'a->bool)`); (`(q:'a->bool)`);
       (`(q:'a->bool)`); (`(p:'a->bool)`); (`Pr:('a->'a)list`)]
       UNLESS_thm5)) THEN
   UNDISCH_TAC (`(((p:'a->bool) \/* q) UNLESS
                    ((((Not p) /\* p) \/* ((Not q) /\* q)) \/* (q /\* p))
                   ) Pr`) THEN
   PURE_ONCE_REWRITE_TAC [AND_COMM_lemma] THEN
   REWRITE_TAC [P_AND_NOT_P_lemma;OR_False_lemma] THEN
   PURE_ONCE_REWRITE_TAC [OR_COMM_lemma] THEN
   REWRITE_TAC [OR_False_lemma] THEN
   DISCH_TAC THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
        [(`(((q:'a->bool) \/* p) UNLESS (p /\* q))Pr`);
         (`(((p:'a->bool) /\* q) UNLESS False)Pr`)]
         AND_INTRO_THM)) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`((q:'a->bool) \/* p)`); (`((p:'a->bool) /\* q)`);
      (`False:'a->bool`); (`Pr:('a->'a)list`)]
       UNLESS_thm8)) THEN
   UNDISCH_TAC
     (`((((q:'a->bool) \/* p) \/* (p /\* q)) UNLESS False)Pr`) THEN
   REWRITE_TAC [OR_AND_DISTR_lemma] THEN
   REWRITE_TAC [OR_ASSOC_lemma;OR_OR_lemma] THEN
   PURE_ONCE_REWRITE_TAC [OR_COMM_lemma] THEN
   REWRITE_TAC [OR_ASSOC_lemma;OR_OR_lemma;AND_AND_lemma]);;

let UNLESS_cor14 = prove_thm
  ("UNLESS_cor14",
   (`!(p:'a->bool) q Pr. (p UNLESS (Not q)) Pr /\ q STABLE Pr ==>
                               (p UNLESS (p /\* (Not q))) Pr`),
   REWRITE_TAC [STABLE] THEN
   REPEAT GEN_TAC THEN DISCH_TAC THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
    [(`p:'a->bool`); (`Not (q:'a->bool)`);
     (`q:'a->bool`); (`False:'a->bool`); (`Pr:('a->'a)list`)]
      UNLESS_thm4)) THEN
   UNDISCH_TAC (`(((p:'a->bool) /\* q) UNLESS
                     (((p /\* False) \/* (q /\* (Not q))) \/*
                      ((Not q) /\* False)))Pr`) THEN
   REWRITE_TAC [AND_False_lemma;P_AND_NOT_P_lemma;OR_False_lemma] THEN
   DISCH_TAC THEN
   ASSUME_TAC (SPECL
     [(`(p:'a->bool) /\* (Not q)`);
      (`Pr:('a->'a)list`)] UNLESS_thm1) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`(((p:'a->bool) /\* q) UNLESS False)Pr`);
      (`(((p:'a->bool) /\* (Not q)) UNLESS (p /\* (Not q)))Pr`)]
      AND_INTRO_THM)) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`(p:'a->bool) /\* q`); (`False:'a->bool`);
      (`(p:'a->bool) /\* (Not q)`); (`(p:'a->bool) /\* (Not q)`);
      (`Pr:('a->'a)list`)]
      UNLESS_thm5)) THEN
   UNDISCH_TAC (`((((p:'a->bool) /\* q) \/* (p /\* (Not q))) UNLESS
                 ((((Not(p /\* q)) /\* (p /\* (Not q))) \/*
                   ((Not(p /\* (Not q))) /\* False)) \/*
                    (False /\* (p /\* (Not q)))))Pr`) THEN
   REWRITE_TAC [AND_False_lemma;OR_False_lemma] THEN
   ONCE_REWRITE_TAC [OR_COMM_lemma] THEN
   REWRITE_TAC [AND_COMPL_OR_lemma] THEN
   ONCE_REWRITE_TAC [AND_COMM_lemma] THEN
   REWRITE_TAC [AND_False_lemma] THEN
   ONCE_REWRITE_TAC [OR_COMM_lemma] THEN
   REWRITE_TAC [OR_False_lemma] THEN
   REWRITE_TAC [NOT_AND_OR_NOT_lemma] THEN
   REWRITE_TAC [AND_OR_DISTR_lemma] THEN
   REWRITE_TAC [AND_ASSOC_lemma] THEN
   REWRITE_TAC [AND_AND_lemma] THEN
   ONCE_REWRITE_TAC [AND_AND_COMM_lemma] THEN
   REWRITE_TAC [GEN_ALL (SYM (SPEC_ALL AND_ASSOC_lemma))] THEN
   REWRITE_TAC [P_AND_NOT_P_lemma] THEN
   ONCE_REWRITE_TAC [AND_COMM_OR_lemma] THEN
   REWRITE_TAC [AND_False_lemma] THEN
   ONCE_REWRITE_TAC [OR_COMM_lemma] THEN
   REWRITE_TAC [OR_False_lemma] THEN
   DISCH_TAC THEN
   ONCE_REWRITE_TAC [AND_COMM_lemma] THEN
   ASM_REWRITE_TAC []);;

let UNLESS_cor15_lem1 = TAC_PROOF
  (([],
   (`!p q. p /\ (~p \/ ~q) <=> p /\ ~q`)),
   REPEAT GEN_TAC THEN
   EQ_TAC THEN
   REPEAT STRIP_TAC THEN
     (RES_TAC THEN ASM_REWRITE_TAC []));;

let UNLESS_cor15_lem2 = TAC_PROOF
  (([],
   (`!p q. p \/ (p /\ q) <=> p`)),
   REPEAT GEN_TAC THEN
   EQ_TAC THEN
   REPEAT STRIP_TAC THEN
   ASM_REWRITE_TAC []);;

let UNLESS_cor15_lem3 = TAC_PROOF
  (([],
   (`!P Q. (!(i:num). (P i) /\ (Q i)) <=> ((!i. P i) /\ (!i. Q i))`)),
   REPEAT GEN_TAC THEN
   EQ_TAC THEN
   REPEAT STRIP_TAC THEN
   ASM_REWRITE_TAC []);;

(*
   MESON_TAC is powerful, but I should change this proof to not use
   MESON_TAC as a detailed proof will better show why the UNLESS_STMT
   property holds
*)
let UNLESS_STMT_cor15 = prove_thm
  ("UNLESS_STMT_cor15",
   `!(P:num->('a->bool)) Q st.
            (!i s. (P i UNLESS_STMT P i /\* Q i) st s) ==>
               (!s. ((!*) P UNLESS_STMT (!*) P /\* (?*) Q) st s)`,
   REPEAT GEN_TAC THEN
   REWRITE_TAC [FORALL_def; EXISTS_def; UNLESS_STMT; AND_def] THEN
   CONV_TAC (DEPTH_CONV BETA_CONV) THEN
   MESON_TAC []);;

let UNLESS_cor15 = prove_thm
  ("UNLESS_cor15",
   `!(P:num->('a->bool)) Q Pr.
       (!i. ((P i) UNLESS ((P i) /\* (Q i))) Pr) ==>
           (((!*) P) UNLESS (((!*) P) /\* ((?*) Q))) Pr`,
   GEN_TAC THEN GEN_TAC THEN
   LIST_INDUCT_TAC THEN
   REWRITE_TAC [UNLESS] THEN
   STRIP_TAC THEN
   RES_TAC THEN
   ASM_REWRITE_TAC [] THEN
   STRIP_ASSUME_TAC (REWRITE_RULE [UNLESS_cor15_lem3] (ASSUME
    `!i:num. (!s:'a. (P i UNLESS_STMT P i /\* Q i) h s) /\
                  (P i UNLESS P i /\* Q i) t`)) THEN
   RES_TAC THEN
   ASM_REWRITE_TAC [] THEN
   IMP_RES_TAC UNLESS_STMT_cor15);;

let UNLESS_cor16 = prove_thm
  ("UNLESS_cor16",
   `!(P:num->('a->bool)) Q Pr.
    (!i. ((P i) UNLESS (Q i))Pr) ==>
      (!i. ((/<=\* P i) UNLESS (\<=/* Q i))Pr)`,
   REPEAT GEN_TAC THEN
   DISCH_TAC THEN
   INDUCT_TAC THENL
     [
      ASM_REWRITE_TAC [AND_LE_N_def;OR_LE_N_def]
     ;
      REWRITE_TAC [AND_LE_N_def;OR_LE_N_def] THEN
      ASSUME_TAC (SPEC (`SUC i`) (ASSUME
        (`!i. (((P:num->('a->bool)) i) UNLESS (Q i))Pr`))) THEN
      STRIP_ASSUME_TAC (UNDISCH_ALL (hd (IMP_CANON (SPECL
        [(`/<=\* (P:num->('a->bool)) i`);
	 (`\<=/* (Q:num->('a->bool)) i`);
         (`(P:num->('a->bool))(SUC i)`); (`(Q:num->('a->bool))(SUC i)`);
         (`Pr:('a->'a)list`)]
         UNLESS_thm6))))
     ]);;

let UNLESS_cor17 = prove_thm
  ("UNLESS_cor17",
   (`!(P:num->('a->bool)) q Pr.
       (!i. ((P i) UNLESS q)Pr) ==> (!i. ((/<=\* P i) UNLESS q)Pr)`),
   REPEAT GEN_TAC THEN
   DISCH_TAC THEN
   INDUCT_TAC THENL
     [
      ASM_REWRITE_TAC [AND_LE_N_def;OR_LE_N_def]
     ;
      REWRITE_TAC [AND_LE_N_def;OR_LE_N_def] THEN
      ASSUME_TAC (SPEC (`SUC i`) (ASSUME
        (`!i. (((P:num->('a->bool)) i) UNLESS q)Pr`))) THEN
      ASSUME_TAC (UNDISCH_ALL (hd (IMP_CANON (SPECL
        [(`/<=\* (P:num->('a->bool)) i`); (`q:'a->bool`);
         (`(P:num->('a->bool))(SUC i)`);
	 (`q:'a->bool`); (`Pr:('a->'a)list`)]
         UNLESS_thm6)))) THEN
      UNDISCH_ONE_TAC THEN
      REWRITE_TAC [OR_OR_lemma]
     ]);;

(*
   MESON_TAC is powerful, but I should change this proof to not use
   MESON_TAC as a detailed proof will better show why the UNLESS_STMT
   property holds
*)
let UNLESS_STMT_cor18 = prove_thm
  ("UNLESS_STMT_cor18",
   `!(P:num->('a->bool)) Q st.
         (!i s. ((P i) UNLESS_STMT q) st s) ==>
            (!s. (((?*) P) UNLESS_STMT q) st s)`,
   REPEAT GEN_TAC THEN
   REWRITE_TAC [FORALL_def; EXISTS_def; UNLESS_STMT; AND_def] THEN
   CONV_TAC (DEPTH_CONV BETA_CONV) THEN
   MESON_TAC []);;

let UNLESS_cor18 = prove_thm
  ("UNLESS_cor18",
   (`!(P:num->('a->bool)) q Pr.
        (!m. ((P m) UNLESS q) Pr) ==> (((?*) P) UNLESS q) Pr`),
   GEN_TAC THEN GEN_TAC THEN
   LIST_INDUCT_TAC THEN
   REWRITE_TAC [UNLESS] THEN
   STRIP_TAC THEN
   ASM_REWRITE_TAC [] THEN
   STRIP_ASSUME_TAC (REWRITE_RULE [UNLESS_cor15_lem3] (ASSUME
    `!m:num. (!s:'a. (P m UNLESS_STMT q) h s) /\ (P m UNLESS q) t`)) THEN
   RES_TAC THEN
   ASM_REWRITE_TAC [] THEN
   IMP_RES_TAC UNLESS_STMT_cor18);;

let UNLESS_cor19 = prove_thm
  ("UNLESS_cor19",
   (`!Pr. (False:'a->bool) STABLE Pr`),
   GEN_TAC THEN
   REWRITE_TAC [STABLE] THEN
   REWRITE_TAC [UNLESS_thm1]);;

let UNLESS_cor20 = prove_thm
  ("UNLESS_cor20",
   (`!(p:'a->bool) q Pr.
        (p STABLE Pr) /\ (q STABLE Pr) ==> ((p /\* q) STABLE Pr)`),
   REPEAT GEN_TAC THEN
   REWRITE_TAC [STABLE] THEN
   ACCEPT_TAC (REWRITE_RULE [AND_False_lemma;OR_False_lemma] (SPECL
     [(`p:'a->bool`); (`False:'a->bool`);
      (`q:'a->bool`); (`False:'a->bool`);
      (`Pr:('a->'a)list`)] UNLESS_thm4)));;

let UNLESS_cor21 = prove_thm
  ("UNLESS_cor21",
   (`!(p:'a->bool) q Pr.
        (p STABLE Pr) /\ (q STABLE Pr) ==> ((p \/* q) STABLE Pr)`),
   REPEAT GEN_TAC THEN
   REWRITE_TAC [STABLE] THEN
   ACCEPT_TAC (REWRITE_RULE [AND_False_lemma;OR_False_lemma] (SPECL
     [(`p:'a->bool`); (`False:'a->bool`);
      (`q:'a->bool`); (`False:'a->bool`);
      (`Pr:('a->'a)list`)] UNLESS_thm7)));;

let UNLESS_cor22 = prove_thm
  ("UNLESS_cor22",
   (`!(p:'a->bool) q r Pr.
          (p UNLESS q) Pr /\ (r STABLE Pr) ==>
          ((p /\* r) UNLESS (q /\* r))Pr`),
   REPEAT GEN_TAC THEN
   REWRITE_TAC [STABLE] THEN
   ACCEPT_TAC (REWRITE_RULE [OR_False_lemma] (ONCE_REWRITE_RULE [OR_COMM_lemma]
    (ONCE_REWRITE_RULE [OR_AND_COMM_lemma]
      (REWRITE_RULE [AND_False_lemma;OR_False_lemma] (SPECL
        [(`p:'a->bool`); (`q:'a->bool`);
	 (`r:'a->bool`); (`False:'a->bool`);
         (`Pr:('a->'a)list`)] UNLESS_thm4))))));;

let UNLESS_cor23 = prove_thm
  ("UNLESS_cor23",
   (`!(p:'a->bool) q r Pr.
         ((p UNLESS q) Pr) ==> ((p \/* r) UNLESS (q \/* r)) Pr`),
   GEN_TAC THEN GEN_TAC THEN GEN_TAC THEN
   LIST_INDUCT_TAC THEN
   REWRITE_TAC [UNLESS] THEN
   STRIP_TAC THEN
   RES_TAC THEN
   ASM_REWRITE_TAC [] THEN
   IMP_RES_TAC UNLESS_STMT_thm6 THEN
   ASM_REWRITE_TAC []);;
