(*---------------------------------------------------------------------------*)
(*
   File:         mk_ensures.sml
   Description:  This file defines ENSURES and the theorems and corrollaries
                 described in [CM88].
   Author:       (c) Copyright 1989-2008 by Flemming Andersen
   Date:         June 29, 1989
   Last Update:  December 30, 2007
*)
(*---------------------------------------------------------------------------*)
(*---------------------------------------------------------------------------*)
(* The definition of ENSURES is based on the definition:
      p ensures q in Pr = <p unless q in Pr /\ (?s in Pr: {p /\ ~q} s {q})>
  where p and q are state dependent first order logic predicates and s
  in the program Pr are conditionally enabled statements transforming
  a state into a new state. ENSURES then requires safety and the
  existance of at least one state transition statement s which makes q
  valid.
*)
let EXIST_TRANSITION_term =
   `(!p q. EXIST_TRANSITION (p:'a->bool) q []         <=> F) /\
    (!p q. EXIST_TRANSITION p q (CONS (st:'a->'a) Pr) <=>
	  ((!s. (p s /\ ~q s) ==> q (st s)) \/ (EXIST_TRANSITION p q Pr)))`;;
parse_as_infix ( "EXIST_TRANSITION", (TL_FIX, "right") );;
let ENSURES = new_infix_definition
  ("ENSURES", "<=>",
   `!(p:'a->bool) q (Pr:('a->'a)list).
       ENSURES p q Pr = (((p UNLESS q) Pr) /\ ((p EXIST_TRANSITION q) Pr))`,
   TL_FIX);;
let ENSURES_STMT = new_infix_definition
  ("ENSURES_STMT", "<=>",
   `!(p:'a->bool) q (st:'a->'a).
        ENSURES_STMT p q st = (\s. p s /\ ~(q s) ==> q (st s))`,
   TL_FIX);;
(*-------------------------------------------------------------------------*)
(*
  Lemmas
*)
(*-------------------------------------------------------------------------*)
let ENSURES_lemma0 = TAC_PROOF
  (([],
   (`!(p:'a->bool) q r st.
          ((!s. p s /\ ~q s ==> q (st s)) /\ (!s. q s ==> r s)) ==>
           (!s. p s /\ ~r s ==> r (st s))`)),
    REPEAT STRIP_TAC THEN
    ASSUME_TAC (CONTRAPOS (SPEC_ALL (ASSUME (`!s:'a. q s ==> r s`)))) THEN
    ASSUME_TAC (SPEC (`(st:'a->'a) s`) (ASSUME (`!s:'a. q s ==> r s`))) THEN
    RES_TAC THEN
    RES_TAC);;
set_goal([],
   (`!(p:'a->bool) p' q q' h.
     (!s. (p  UNLESS_STMT q)  h s)     ==>
     (!s. (p' UNLESS_STMT q') h s)     ==>
     (!s. p' s /\ ~q' s ==> q' (h s))  ==>
     (!s. (p /\* p') s /\ ~((p /\* q' \/* p' /\* q) \/* q /\* q') s) ==>
     (((p /\* q' \/* p' /\* q) \/* q /\* q') (h s))`)
);;
 
let ENSURES_lemma1 = TAC_PROOF
  (([],
    `!(p:'a->bool) p' q q' h.
      (!s. (p  UNLESS_STMT q)  h s)     ==>
      (!s. (p' UNLESS_STMT q') h s)     ==>
      (!s. p' s /\ ~q' s ==> q' (h s))  ==>
      (!s. (p /\* p') s /\ ~((p /\* q' \/* p' /\* q) \/* q /\* q') s
               ==> ((p /\* q' \/* p' /\* q) \/* q /\* q') (h s))`),
    REWRITE_TAC [UNLESS_STMT; AND_def; OR_def] THEN
    CONV_TAC (DEPTH_CONV BETA_CONV) THEN
    MESON_TAC []);;
let ENSURES_lemma2 = TAC_PROOF
  (([],
   (`!(p:'a->bool) q r st.
       (!s. p s /\ ~q s ==> q (st s)) ==>
         (!s. (p s \/ r s) /\ ~(q s \/ r s) ==> q (st s) \/ r (st s))`)),
     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 []);;
let ENSURES_lemma3 = TAC_PROOF
  (([],
   (`!(p:'a->bool) q r Pr. (p ENSURES (q \/* r)) Pr ==>
              (((p /\* (Not q)) \/* (p /\* q)) ENSURES (q \/* r)) Pr`)),
   REWRITE_TAC [AND_COMPL_OR_lemma]);;
let ENSURES_lemma4 = TAC_PROOF
  (([],
    `!(p:'a->bool) q r (st:'a->'a).
         (!s. p s /\ ~q s ==> q (st s)) ==>
            (!s. (p \/* r) s /\ ~(q \/* r) s ==> (q \/* r) (st s))`),
    REPEAT GEN_TAC THEN
    REWRITE_TAC [OR_def] THEN
    MESON_TAC []);;
(*---------------------------------------------------------------------------*)
(*
  Theorems about EXIST_TRANSITION
*)
(*---------------------------------------------------------------------------*)
(*
  EXIST_TRANSITION Consequence Weakening Theorem:
               p EXIST_TRANSITION q in Pr; q ==> r
              -------------------------------------
                   p EXIST_TRANSITION r in Pr
*)
let EXIST_TRANSITION_thm1 = prove_thm
 ("EXIST_TRANSITION_thm1",
  (`!(p:'a->bool) q r Pr.
     ((p EXIST_TRANSITION q) Pr /\ (!s. (q s) ==> (r s))) ==>
       ((p EXIST_TRANSITION r) Pr)`),
   GEN_TAC THEN GEN_TAC THEN GEN_TAC THEN
   LIST_INDUCT_TAC THEN
   REWRITE_TAC [EXIST_TRANSITION] THEN
   STRIP_TAC THEN
   RES_TAC THEN
   ASM_REWRITE_TAC [] THEN
   REWRITE_TAC [REWRITE_RULE
    [ASSUME `!s:'a. p s /\ ~q s ==> q (h s)`; ASSUME `!s:'a. q s ==> r s`]
     (SPECL [`p:'a->bool`;`q:'a->bool`;`r:'a->bool`;`h:'a->'a`] ENSURES_lemma0)]);; 
(*
  Impossibility EXIST_TRANSITION Theorem:
               p EXIST_TRANSITION false in Pr
              --------------------------------
                          ~p 
*)
let EXIST_TRANSITION_thm2 = prove_thm
  ("EXIST_TRANSITION_thm2",
   (`!(p:'a->bool) Pr.
     ((p EXIST_TRANSITION False) Pr) ==> !s. (Not p) s`),
   GEN_TAC THEN
   LIST_INDUCT_TAC THEN
   REWRITE_TAC [EXIST_TRANSITION; NOT_def1] THEN
   STRIP_TAC THEN
   RES_TAC THEN
   ASM_REWRITE_TAC [] THENL
   [
     UNDISCH_TAC (`!s:'a. ((p:'a->bool) s) /\ ~(False s)
                          ==> (False ((h:'a->'a) s))`) THEN
     REWRITE_TAC [FALSE_def] THEN
     CONV_TAC (DEPTH_CONV BETA_CONV)
    ;
     UNDISCH_TAC (`!s:'a. (Not (p:'a->bool)) s`) THEN
     REWRITE_TAC [NOT_def1] THEN
     CONV_TAC (DEPTH_CONV BETA_CONV)
   ]);; 
(*
  Always EXIST_TRANSITION Theorem:
               false EXIST_TRANSITION p in Pr
*)
let EXIST_TRANSITION_thm4 = prove_thm
  ("EXIST_TRANSITION_thm4",
   (`!(p:'a->bool) q r Pr.
         (p EXIST_TRANSITION q) Pr ==>
            ((p \/* r) EXIST_TRANSITION (q \/* r)) Pr`),
   GEN_TAC THEN GEN_TAC THEN GEN_TAC THEN
   LIST_INDUCT_TAC THEN
   REWRITE_TAC [EXIST_TRANSITION] THEN
   STRIP_TAC THEN
   RES_TAC THEN
   ASM_REWRITE_TAC [] THEN
   REWRITE_TAC [REWRITE_RULE 
      [ASSUME `!s:'a. (p:'a->bool) s /\ ~q s ==> q (h s)`] 
        (SPECL [`p:'a->bool`;`q:'a->bool`;`r:'a->bool`;`h:'a->'a`]
            ENSURES_lemma4)]);; 
let APPEND_lemma01 = TAC_PROOF
  (([],
   `!(l:('a)list). (APPEND l []) = l`),
   LIST_INDUCT_TAC THEN
   ASM_REWRITE_TAC [APPEND]);;
let APPEND_lemma02 = TAC_PROOF
  (([],
   `!st (l:('a)list).  (APPEND [st] l) = (CONS st l)`),
   GEN_TAC THEN
   LIST_INDUCT_TAC THEN
   REWRITE_TAC [APPEND]);;   
let APPEND_lemma03 = TAC_PROOF
  (([],
   `!st (l1:('a)list) l2. 
       (APPEND (APPEND l1 [st]) l2) = (APPEND l1 (CONS st l2))`),
   GEN_TAC THEN
   LIST_INDUCT_TAC THEN
   LIST_INDUCT_TAC THEN
   REWRITE_TAC [APPEND] THEN
   REPEAT STRIP_TAC THEN
   RES_TAC THEN
   ASM_REWRITE_TAC [APPEND]);;
let APPEND_lemma04 = TAC_PROOF
  (([],
   `!st (l1:('a)list) l2. 
       (APPEND (CONS st l1) l2) = (CONS st (APPEND l1 l2))`),
   GEN_TAC THEN
   LIST_INDUCT_TAC THEN
   LIST_INDUCT_TAC THEN
   REWRITE_TAC [APPEND] THEN
   REPEAT STRIP_TAC THEN
   RES_TAC THEN
   ASM_REWRITE_TAC [APPEND]);;
let EXIST_TRANSITION_thm6 = prove_thm
  ("EXIST_TRANSITION_thm6",
   (`!(p:'a->bool) q st Pr1 Pr2.
       (!s. p s /\ ~q s ==> q (st s))
            ==> (p EXIST_TRANSITION q) (APPEND Pr1 (CONS st Pr2))`),
   GEN_TAC THEN GEN_TAC THEN GEN_TAC THEN
   LIST_INDUCT_TAC THEN
   LIST_INDUCT_TAC THEN
   REWRITE_TAC [EXIST_TRANSITION;APPEND] THEN
   REPEAT STRIP_TAC THEN
   RES_TAC THEN
   ASM_REWRITE_TAC []);; 
(*---------------------------------------------------------------------------*)
(*
  Theorems about ENSURES
*)
(*---------------------------------------------------------------------------*)
(*
  Reflexivity Theorem:
               p ensures p in Pr
  The theorem is only valid for non-empty programs
*)
let ENSURES_thm1 = prove_thm
  ("ENSURES_thm1",
   (`!(p:'a->bool) st Pr. (p ENSURES p) (CONS st Pr)`),
     REWRITE_TAC [ENSURES] THEN
     STRIP_TAC THEN
     REWRITE_TAC [UNLESS;EXIST_TRANSITION] THEN
     REWRITE_TAC [UNLESS_thm1;UNLESS_STMT] THEN
     REWRITE_TAC [BETA_CONV (`(\s:'a. (p s /\ ~p s) ==> p (st s))s`)] THEN
     REWRITE_TAC[NOT_AND;IMP_CLAUSES]);; 
(*
  Consequence Weakening Theorem:
               p ensures q in Pr; q ==> r
              ----------------------------
                   p ensures r in Pr
*)
let ENSURES_thm2 = prove_thm
  ("ENSURES_thm2",
   (`!(p:'a->bool) q r Pr.
         ((p ENSURES q) Pr /\ (!s:'a. (q s) ==> (r s)))
        ==>
	 ((p ENSURES r) Pr)`),
   REWRITE_TAC [ENSURES] THEN
   REPEAT STRIP_TAC THENL
     [
      ASSUME_TAC (UNDISCH_ALL (SPEC (`!s:'a. q s ==> r s`)
        (SPEC (`((p:'a->bool) UNLESS q) Pr`) AND_INTRO_THM))) THEN
      STRIP_ASSUME_TAC (UNDISCH_ALL (SPEC_ALL UNLESS_thm3))
     ;
      ASSUME_TAC (UNDISCH_ALL (SPEC (`!s:'a. q s ==> r s`)
        (SPEC (`((p:'a->bool) EXIST_TRANSITION q) Pr`) AND_INTRO_THM))) THEN
      STRIP_ASSUME_TAC (UNDISCH_ALL (SPEC_ALL EXIST_TRANSITION_thm1))
     ]);; 
(*
  Impossibility Theorem:
               p ensures false in Pr
              ----------------------
                       ~p 
*)
let ENSURES_thm3 = prove_thm
  ("ENSURES_thm3",
   (`!(p:'a->bool) Pr. ((p ENSURES False) Pr) ==> !s. (Not p)s`),
   GEN_TAC THEN
   LIST_INDUCT_TAC THEN
   ASM_REWRITE_TAC [ENSURES; UNLESS; EXIST_TRANSITION] THEN
   STRIP_TAC THEN
   ASM_REWRITE_TAC [] THENL
   [
     UNDISCH_TAC `!s:'a. (p:'a->bool) s /\ ~(False s) ==> False ((h:'a->'a) s)` THEN
     REWRITE_TAC [FALSE_def; NOT_def1] THEN
     CONV_TAC (DEPTH_CONV BETA_CONV)
    ;
     IMP_RES_TAC EXIST_TRANSITION_thm2
   ]);; 
(*
  Conjunction Theorem:
                   p unless q in Pr; p' ensures q' in Pr
              -----------------------------------------------
               p/\p' ensures (p/\q')\/(p'/\q)\/(q/\q') in Pr
*)
let ENSURES_thm4 = prove_thm
  ("ENSURES_thm4",
   (`!(p:'a->bool) q p' q' Pr.
    (p UNLESS q) Pr /\ (p' ENSURES q') Pr ==>
      ((p /\* p') ENSURES (((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 [ENSURES;UNLESS;EXIST_TRANSITION] THEN
   REPEAT STRIP_TAC THEN
   ASM_REWRITE_TAC [] THENL
   [
    REWRITE_TAC
      [REWRITE_RULE [ASSUME `!s:'a. ((p:'a->bool) UNLESS_STMT q)   (h:'a->'a) s`;
                     ASSUME `!s:'a. ((p':'a->bool) UNLESS_STMT q') (h:'a->'a) s`]
        (SPECL [`p:'a->bool`;`q:'a->bool`;`p':'a->bool`;`q':'a->bool`;`h:'a->'a`]
                UNLESS_STMT_thm3)]
   ;
    REWRITE_TAC
      [REWRITE_RULE [ASSUME `((p:'a->bool)  UNLESS q)  (t:('a->'a)list)`;
                     ASSUME `((p':'a->bool) UNLESS q') (t:('a->'a)list)`]
      (SPECL [`p:'a->bool`;`q:'a->bool`;`p':'a->bool`;`q':'a->bool`;`t:('a->'a)list`]
                UNLESS_thm4)]
   ;
    REWRITE_TAC [REWRITE_RULE
         [ASSUME `!s:'a. ((p:'a->bool) UNLESS_STMT q) (h:'a->'a) s`;
          ASSUME `!s:'a. ((p':'a->bool) UNLESS_STMT q') (h:'a->'a) s`;
          ASSUME `!s:'a. (p':'a->bool) s /\ ~(q' s) ==> q' ((h:'a->'a) s)`]
       (SPEC_ALL ENSURES_lemma1)]
   ;
    REWRITE_TAC
      [REWRITE_RULE [ASSUME `!s:'a. ((p:'a->bool) UNLESS_STMT q)   (h:'a->'a) s`;
                     ASSUME `!s:'a. ((p':'a->bool) UNLESS_STMT q') (h:'a->'a) s`]
        (SPECL [`p:'a->bool`;`q:'a->bool`;`p':'a->bool`;`q':'a->bool`;`h:'a->'a`]
                UNLESS_STMT_thm3)]
   ;
    UNDISCH_TAC `((p:'a->bool) UNLESS q) t /\ (p' ENSURES q') (t:('a->'a)list)
       ==> (p /\* p' ENSURES (p /\* q' \/* p' /\* q) \/* q /\* q') t` THEN
    ASM_REWRITE_TAC [ENSURES] THEN
    STRIP_TAC THEN
    ASM_REWRITE_TAC []
   ;
    UNDISCH_TAC `((p:'a->bool) UNLESS q) t /\ (p' ENSURES q') (t:('a->'a)list)
       ==> (p /\* p' ENSURES (p /\* q' \/* p' /\* q) \/* q /\* q') t` THEN
    ASM_REWRITE_TAC [ENSURES] THEN
    STRIP_TAC THEN
    ASM_REWRITE_TAC []
  ]);; 
(*
  Conjunction Theorem:
                   p ensures q in Pr
              -------------------------
               p\/r ensures q\/r in Pr
*)
let ENSURES_thm5 = prove_thm
  ("ENSURES_thm5",
   (`!(p:'a->bool) q r Pr.
      ((p ENSURES q) Pr) ==> (((p \/* r) ENSURES (q \/* r)) Pr)`),
   GEN_TAC THEN GEN_TAC THEN GEN_TAC THEN
   LIST_INDUCT_TAC THEN
   REWRITE_TAC [ENSURES;UNLESS;EXIST_TRANSITION] THEN
   REPEAT STRIP_TAC THEN
   ASM_REWRITE_TAC [] THENL
   [
     IMP_RES_TAC UNLESS_STMT_thm6 THEN
     ASM_REWRITE_TAC []
    ;
     IMP_RES_TAC UNLESS_cor23 THEN
     ASM_REWRITE_TAC []
    ;
     REWRITE_TAC [REWRITE_RULE 
      [ASSUME `!s:'a. (p:'a->bool) s /\ ~q s ==> q (h s)`] 
        (SPECL [`p:'a->bool`;`q:'a->bool`;`r:'a->bool`;`h:'a->'a`]
            ENSURES_lemma4)]
    ;
     IMP_RES_TAC UNLESS_STMT_thm6 THEN
     ASM_REWRITE_TAC []
    ;
     IMP_RES_TAC UNLESS_cor23 THEN
     ASM_REWRITE_TAC []
    ;
     IMP_RES_TAC EXIST_TRANSITION_thm4 THEN
     ASM_REWRITE_TAC []
   ]);; 
(*
 -----------------------------------------------------------------------------
  Corollaries about ENSURES
 -----------------------------------------------------------------------------
*)
(*
  Implies Corollary:
                   p => q
              -------------------
               p ensures q in Pr
  This corollary is only valid for non-empty programs.
*)
let ENSURES_cor1 = prove_thm
  ("ENSURES_cor1",
   (`!(p:'a->bool) q st Pr.
    (!s. p s ==> q s) ==> (p ENSURES q) (CONS st Pr)`),
   REPEAT GEN_TAC THEN
   DISCH_TAC THEN
   ASSUME_TAC (SPEC_ALL ENSURES_thm1) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`((p:'a->bool) ENSURES p)(CONS st Pr)`);(`!s:'a. p s ==> q s`)]
      AND_INTRO_THM)) THEN
   STRIP_ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`p:'a->bool`);(`p:'a->bool`);(`q:'a->bool`);
      (`CONS (st:'a->'a) Pr`)]
      ENSURES_thm2)));; 
let ENSURES_cor2 = prove_thm
  ("ENSURES_cor2",
   (`!(p:'a->bool) q Pr. (p ENSURES q) Pr ==> (p UNLESS q) Pr`),
   REWRITE_TAC [ENSURES] THEN
   REPEAT STRIP_TAC);; 
let ENSURES_cor3 = prove_thm
  ("ENSURES_cor3",
   (`!(p:'a->bool) q r Pr.
        ((p \/*  q) ENSURES r)Pr ==> (p ENSURES (q \/*  r))Pr`),
   REPEAT GEN_TAC THEN
   DISCH_TAC THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`((p:'a->bool) \/*  q)`);(`r:'a->bool`);
      (`Pr:('a->'a)list`)] ENSURES_cor2)) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`p:'a->bool`);(`q:'a->bool`);(`r:'a->bool`);
      (`Pr:('a->'a)list`)] UNLESS_cor4)) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`((p:'a->bool) UNLESS (q \/*  r))Pr`);
      (`(((p:'a->bool) \/*  q) ENSURES r)Pr`)]
      AND_INTRO_THM)) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`p:'a->bool`);(`((q:'a->bool) \/*  r)`);
      (`((p:'a->bool) \/*  q)`);(`r:'a->bool`);
      (`Pr:('a->'a)list`)] ENSURES_thm4)) THEN
   UNDISCH_TAC (`(((p:'a->bool) /\* (p \/*  q)) ENSURES
                (((p /\* r) \/*  ((p \/*  q) /\* (q \/*  r))) \/* 
                 ((q \/*  r) /\* r))) Pr`) THEN
   REWRITE_TAC [AND_OR_EQ_lemma] THEN
   REWRITE_TAC [OR_ASSOC_lemma;AND_ASSOC_lemma] THEN
   PURE_ONCE_REWRITE_TAC [SPECL
         [(`((q:'a->bool) \/*  r)`);
	  (`r:'a->bool`)] AND_COMM_lemma] THEN
   ONCE_REWRITE_TAC [AND_OR_EQ_AND_COMM_OR_lemma] THEN
   REWRITE_TAC [AND_OR_EQ_lemma] THEN
   DISCH_TAC THEN
   ASSUME_TAC (SPECL [(`p:'a->bool`);(`q:'a->bool`);(`r:'a->bool`)]
                           IMPLY_WEAK_lemma5) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
    [(`((p:'a->bool) ENSURES
      ((p /\* r) \/*  (((p \/*  q) /\* (q \/*  r)) \/*  r)))Pr`);
     (`!s:'a. ((p /\* r) \/*  (((p \/*  q) /\* (q \/*  r)) \/* r))s ==>
	 (q \/*  r)s`)]
     AND_INTRO_THM)) THEN
   STRIP_ASSUME_TAC (UNDISCH_ALL (SPECL
    [(`p:'a->bool`);
     (`(((p:'a->bool) /\* r) \/* (((p \/*  q) /\* (q \/*  r)) \/* r))`);
     (`((q:'a->bool) \/*  r)`);(`Pr:('a->'a)list`)]
     ENSURES_thm2)));; 
let ENSURES_cor4 = prove_thm
  ("ENSURES_cor4",
   (`!(p:'a->bool) q r Pr. (p ENSURES (q \/*  r)) Pr ==>
              ((p /\* (Not  q)) ENSURES (q \/*  r)) Pr`),
   REPEAT STRIP_TAC THEN
   ASSUME_TAC (UNDISCH_ALL (SPEC_ALL ENSURES_lemma3)) THEN
   ASSUME_TAC (UNDISCH_ALL (SPECL
     [(`((p:'a->bool) /\* (Not  q))`);(`((p:'a->bool) /\* q)`);
      (`((q:'a->bool) \/* r)`);(`Pr:('a->'a)list`)] ENSURES_cor3)) THEN
   UNDISCH_TAC
     (`(((p:'a->bool) /\* (Not  q)) ENSURES
	  ((p /\* q) \/* (q \/* r)))Pr`) THEN
   REWRITE_TAC [GEN_ALL (SYM (SPEC_ALL OR_ASSOC_lemma))] THEN
   REWRITE_TAC [P_AND_Q_OR_Q_lemma]);; 
(*
  Consequence Weakening Corollary:
                  p ensures q in Pr
              -------------------------
               p ensures (q \/ r) in Pr
*)
let ENSURES_cor5 = prove_thm
 ("ENSURES_cor5",
   (`!(p:'a->bool) q r Pr.
         (p ENSURES q) Pr ==> (p ENSURES (q \/*  r)) Pr`),
   REPEAT STRIP_TAC THEN
   ASSUME_TAC (SPECL [(`q:'a->bool`);(`r:'a->bool`)]
	       IMPLY_WEAK_lemma_b) THEN
   ASSUME_TAC (SPECL
     [(`p:'a->bool`);(`q:'a->bool`);(`(q:'a->bool) \/* r`)]
	       ENSURES_thm2) THEN
   RES_TAC);; 
(*
  Always Corollary:
                  false ensures p in Pr
*)