Theory Project

(*  Title:      HOL/UNITY/Project.thy
    Author:     Lawrence C Paulson, Cambridge University Computer Laboratory
    Copyright   1999  University of Cambridge

Projections of state sets (also of actions and programs).

Inheritance of GUARANTEES properties under extension.
*)

section‹Projections of State Sets›

theory Project imports Extend begin

definition projecting :: "['c program => 'c set, 'a*'b => 'c, 
                  'a program, 'c program set, 'a program set] => bool" where
    "projecting C h F X' X ==
       G. extend h FG  X' --> Fproject h (C G) G  X"

definition extending :: "['c program => 'c set, 'a*'b => 'c, 'a program, 
                 'c program set, 'a program set] => bool" where
    "extending C h F Y' Y ==
       G. extend h F  ok G --> Fproject h (C G) G  Y
              --> extend h FG  Y'"

definition subset_closed :: "'a set set => bool" where
    "subset_closed U == A  U. Pow A  U"  


context Extend
begin

lemma project_extend_constrains_I:
     "F  A co B ==> project h C (extend h F)  A co B"
apply (auto simp add: extend_act_def project_act_def constrains_def)
done


subsection‹Safety›

(*used below to prove Join_project_ensures*)
lemma project_unless:
     "[| G  stable C;  project h C G  A unless B |]  
      ==> G  (C  extend_set h A) unless (extend_set h B)"
apply (simp add: unless_def project_constrains)
apply (blast dest: stable_constrains_Int intro: constrains_weaken)
done

(*Generalizes project_constrains to the program F⊔project h C G
  useful with guarantees reasoning*)
lemma Join_project_constrains:
     "(Fproject h C G  A co B)  =   
        (extend h FG  (C  extend_set h A) co (extend_set h B) &   
         F  A co B)"
apply (simp (no_asm) add: project_constrains)
apply (blast intro: extend_constrains [THEN iffD2, THEN constrains_weaken] 
             dest: constrains_imp_subset)
done

(*The condition is required to prove the left-to-right direction
  could weaken it to G ∈ (C ∩ extend_set h A) co C*)
lemma Join_project_stable: 
     "extend h FG  stable C  
      ==> (Fproject h C G  stable A)  =   
          (extend h FG  stable (C  extend_set h A) &   
           F  stable A)"
apply (unfold stable_def)
apply (simp only: Join_project_constrains)
apply (blast intro: constrains_weaken dest: constrains_Int)
done

(*For using project_guarantees in particular cases*)
lemma project_constrains_I:
     "extend h FG  extend_set h A co extend_set h B  
      ==> Fproject h C G  A co B"
apply (simp add: project_constrains extend_constrains)
apply (blast intro: constrains_weaken dest: constrains_imp_subset)
done

lemma project_increasing_I: 
     "extend h FG  increasing (func o f)  
      ==> Fproject h C G  increasing func"
apply (unfold increasing_def stable_def)
apply (simp del: Join_constrains
            add: project_constrains_I extend_set_eq_Collect)
done

lemma Join_project_increasing:
     "(Fproject h UNIV G  increasing func)  =   
      (extend h FG  increasing (func o f))"
apply (rule iffI)
apply (erule_tac [2] project_increasing_I)
apply (simp del: Join_stable
            add: increasing_def Join_project_stable)
apply (auto simp add: extend_set_eq_Collect extend_stable [THEN iffD1])
done

(*The UNIV argument is essential*)
lemma project_constrains_D:
     "Fproject h UNIV G  A co B  
      ==> extend h FG  extend_set h A co extend_set h B"
by (simp add: project_constrains extend_constrains)

end


subsection‹"projecting" and union/intersection (no converses)›

lemma projecting_Int: 
     "[| projecting C h F XA' XA;  projecting C h F XB' XB |]  
      ==> projecting C h F (XA'  XB') (XA  XB)"
by (unfold projecting_def, blast)

lemma projecting_Un: 
     "[| projecting C h F XA' XA;  projecting C h F XB' XB |]  
      ==> projecting C h F (XA'  XB') (XA  XB)"
by (unfold projecting_def, blast)

lemma projecting_INT: 
     "[| !!i. i  I ==> projecting C h F (X' i) (X i) |]  
      ==> projecting C h F (i  I. X' i) (i  I. X i)"
by (unfold projecting_def, blast)

lemma projecting_UN: 
     "[| !!i. i  I ==> projecting C h F (X' i) (X i) |]  
      ==> projecting C h F (i  I. X' i) (i  I. X i)"
by (unfold projecting_def, blast)

lemma projecting_weaken: 
     "[| projecting C h F X' X;  U'<=X';  X  U |] ==> projecting C h F U' U"
by (unfold projecting_def, auto)

lemma projecting_weaken_L: 
     "[| projecting C h F X' X;  U'<=X' |] ==> projecting C h F U' X"
by (unfold projecting_def, auto)

lemma extending_Int: 
     "[| extending C h F YA' YA;  extending C h F YB' YB |]  
      ==> extending C h F (YA'  YB') (YA  YB)"
by (unfold extending_def, blast)

lemma extending_Un: 
     "[| extending C h F YA' YA;  extending C h F YB' YB |]  
      ==> extending C h F (YA'  YB') (YA  YB)"
by (unfold extending_def, blast)

lemma extending_INT: 
     "[| !!i. i  I ==> extending C h F (Y' i) (Y i) |]  
      ==> extending C h F (i  I. Y' i) (i  I. Y i)"
by (unfold extending_def, blast)

lemma extending_UN: 
     "[| !!i. i  I ==> extending C h F (Y' i) (Y i) |]  
      ==> extending C h F (i  I. Y' i) (i  I. Y i)"
by (unfold extending_def, blast)

lemma extending_weaken: 
     "[| extending C h F Y' Y;  Y'<=V';  V  Y |] ==> extending C h F V' V"
by (unfold extending_def, auto)

lemma extending_weaken_L: 
     "[| extending C h F Y' Y;  Y'<=V' |] ==> extending C h F V' Y"
by (unfold extending_def, auto)

lemma projecting_UNIV: "projecting C h F X' UNIV"
by (simp add: projecting_def)

context Extend
begin

lemma projecting_constrains: 
     "projecting C h F (extend_set h A co extend_set h B) (A co B)"
apply (unfold projecting_def)
apply (blast intro: project_constrains_I)
done

lemma projecting_stable: 
     "projecting C h F (stable (extend_set h A)) (stable A)"
apply (unfold stable_def)
apply (rule projecting_constrains)
done

lemma projecting_increasing: 
     "projecting C h F (increasing (func o f)) (increasing func)"
apply (unfold projecting_def)
apply (blast intro: project_increasing_I)
done

lemma extending_UNIV: "extending C h F UNIV Y"
apply (simp (no_asm) add: extending_def)
done

lemma extending_constrains: 
     "extending (%G. UNIV) h F (extend_set h A co extend_set h B) (A co B)"
apply (unfold extending_def)
apply (blast intro: project_constrains_D)
done

lemma extending_stable: 
     "extending (%G. UNIV) h F (stable (extend_set h A)) (stable A)"
apply (unfold stable_def)
apply (rule extending_constrains)
done

lemma extending_increasing: 
     "extending (%G. UNIV) h F (increasing (func o f)) (increasing func)"
by (force simp only: extending_def Join_project_increasing)


subsection‹Reachability and project›

(*In practice, C = reachable(...): the inclusion is equality*)
lemma reachable_imp_reachable_project:
     "[| reachable (extend h FG)  C;   
         z  reachable (extend h FG) |]  
      ==> f z  reachable (Fproject h C G)"
apply (erule reachable.induct)
apply (force intro!: reachable.Init simp add: split_extended_all, auto)
 apply (rule_tac act = x in reachable.Acts)
 apply auto
 apply (erule extend_act_D)
apply (rule_tac act1 = "Restrict C act"
       in project_act_I [THEN [3] reachable.Acts], auto) 
done

lemma project_Constrains_D: 
     "Fproject h (reachable (extend h FG)) G  A Co B   
      ==> extend h FG  (extend_set h A) Co (extend_set h B)"
apply (unfold Constrains_def)
apply (simp del: Join_constrains
            add: Join_project_constrains, clarify)
apply (erule constrains_weaken)
apply (auto intro: reachable_imp_reachable_project)
done

lemma project_Stable_D: 
     "Fproject h (reachable (extend h FG)) G  Stable A   
      ==> extend h FG  Stable (extend_set h A)"
apply (unfold Stable_def)
apply (simp (no_asm_simp) add: project_Constrains_D)
done

lemma project_Always_D: 
     "Fproject h (reachable (extend h FG)) G  Always A   
      ==> extend h FG  Always (extend_set h A)"
apply (unfold Always_def)
apply (force intro: reachable.Init simp add: project_Stable_D split_extended_all)
done

lemma project_Increasing_D: 
     "Fproject h (reachable (extend h FG)) G  Increasing func   
      ==> extend h FG  Increasing (func o f)"
apply (unfold Increasing_def, auto)
apply (subst extend_set_eq_Collect [symmetric])
apply (simp (no_asm_simp) add: project_Stable_D)
done


subsection‹Converse results for weak safety: benefits of the argument C›

(*In practice, C = reachable(...): the inclusion is equality*)
lemma reachable_project_imp_reachable:
     "[| C  reachable(extend h FG);    
         x  reachable (Fproject h C G) |]  
      ==> y. h(x,y)  reachable (extend h FG)"
apply (erule reachable.induct)
apply  (force intro: reachable.Init)
apply (auto simp add: project_act_def)
apply (force del: Id_in_Acts intro: reachable.Acts extend_act_D)+
done

lemma project_set_reachable_extend_eq:
     "project_set h (reachable (extend h FG)) =  
      reachable (Fproject h (reachable (extend h FG)) G)"
by (auto dest: subset_refl [THEN reachable_imp_reachable_project] 
               subset_refl [THEN reachable_project_imp_reachable])

(*UNUSED*)
lemma reachable_extend_Join_subset:
     "reachable (extend h FG)  C   
      ==> reachable (extend h FG)   
          extend_set h (reachable (Fproject h C G))"
apply (auto dest: reachable_imp_reachable_project)
done

lemma project_Constrains_I: 
     "extend h FG  (extend_set h A) Co (extend_set h B)   
      ==> Fproject h (reachable (extend h FG)) G  A Co B"
apply (unfold Constrains_def)
apply (simp del: Join_constrains
            add: Join_project_constrains extend_set_Int_distrib)
apply (rule conjI)
 prefer 2 
 apply (force elim: constrains_weaken_L
              dest!: extend_constrains_project_set
                     subset_refl [THEN reachable_project_imp_reachable])
apply (blast intro: constrains_weaken_L)
done

lemma project_Stable_I: 
     "extend h FG  Stable (extend_set h A)   
      ==> Fproject h (reachable (extend h FG)) G  Stable A"
apply (unfold Stable_def)
apply (simp (no_asm_simp) add: project_Constrains_I)
done

lemma project_Always_I: 
     "extend h FG  Always (extend_set h A)   
      ==> Fproject h (reachable (extend h FG)) G  Always A"
apply (unfold Always_def)
apply (auto simp add: project_Stable_I)
apply (unfold extend_set_def, blast)
done

lemma project_Increasing_I: 
    "extend h FG  Increasing (func o f)   
     ==> Fproject h (reachable (extend h FG)) G  Increasing func"
apply (unfold Increasing_def, auto)
apply (simp (no_asm_simp) add: extend_set_eq_Collect project_Stable_I)
done

lemma project_Constrains:
     "(Fproject h (reachable (extend h FG)) G  A Co B)  =   
      (extend h FG  (extend_set h A) Co (extend_set h B))"
apply (blast intro: project_Constrains_I project_Constrains_D)
done

lemma project_Stable: 
     "(Fproject h (reachable (extend h FG)) G  Stable A)  =   
      (extend h FG  Stable (extend_set h A))"
apply (unfold Stable_def)
apply (rule project_Constrains)
done

lemma project_Increasing: 
   "(Fproject h (reachable (extend h FG)) G  Increasing func)  =  
    (extend h FG  Increasing (func o f))"
apply (simp (no_asm_simp) add: Increasing_def project_Stable extend_set_eq_Collect)
done

subsection‹A lot of redundant theorems: all are proved to facilitate reasoning
    about guarantees.›

lemma projecting_Constrains: 
     "projecting (%G. reachable (extend h FG)) h F  
                 (extend_set h A Co extend_set h B) (A Co B)"

apply (unfold projecting_def)
apply (blast intro: project_Constrains_I)
done

lemma projecting_Stable: 
     "projecting (%G. reachable (extend h FG)) h F  
                 (Stable (extend_set h A)) (Stable A)"
apply (unfold Stable_def)
apply (rule projecting_Constrains)
done

lemma projecting_Always: 
     "projecting (%G. reachable (extend h FG)) h F  
                 (Always (extend_set h A)) (Always A)"
apply (unfold projecting_def)
apply (blast intro: project_Always_I)
done

lemma projecting_Increasing: 
     "projecting (%G. reachable (extend h FG)) h F  
                 (Increasing (func o f)) (Increasing func)"
apply (unfold projecting_def)
apply (blast intro: project_Increasing_I)
done

lemma extending_Constrains: 
     "extending (%G. reachable (extend h FG)) h F  
                  (extend_set h A Co extend_set h B) (A Co B)"
apply (unfold extending_def)
apply (blast intro: project_Constrains_D)
done

lemma extending_Stable: 
     "extending (%G. reachable (extend h FG)) h F  
                  (Stable (extend_set h A)) (Stable A)"
apply (unfold extending_def)
apply (blast intro: project_Stable_D)
done

lemma extending_Always: 
     "extending (%G. reachable (extend h FG)) h F  
                  (Always (extend_set h A)) (Always A)"
apply (unfold extending_def)
apply (blast intro: project_Always_D)
done

lemma extending_Increasing: 
     "extending (%G. reachable (extend h FG)) h F  
                  (Increasing (func o f)) (Increasing func)"
apply (unfold extending_def)
apply (blast intro: project_Increasing_D)
done


subsection‹leadsETo in the precondition (??)›

subsubsection‹transient›

lemma transient_extend_set_imp_project_transient: 
     "[| G  transient (C  extend_set h A);  G  stable C |]   
      ==> project h C G  transient (project_set h C  A)"
apply (auto simp add: transient_def Domain_project_act)
apply (subgoal_tac "act `` (C  extend_set h A)  - extend_set h A")
 prefer 2
 apply (simp add: stable_def constrains_def, blast) 
(*back to main goal*)
apply (erule_tac V = "AA  -C  BB" for AA BB in thin_rl)
apply (drule bspec, assumption) 
apply (simp add: extend_set_def project_act_def, blast)
done

(*converse might hold too?*)
lemma project_extend_transient_D: 
     "project h C (extend h F)  transient (project_set h C  D)  
      ==> F  transient (project_set h C  D)"
apply (simp add: transient_def Domain_project_act, safe)
apply blast+
done


subsubsection‹ensures -- a primitive combining progress with safety›

(*Used to prove project_leadsETo_I*)
lemma ensures_extend_set_imp_project_ensures:
     "[| extend h F  stable C;  G  stable C;   
         extend h FG  A ensures B;  A-B = C  extend_set h D |]   
      ==> Fproject h C G   
             (project_set h C  project_set h A) ensures (project_set h B)"
apply (simp add: ensures_def project_constrains extend_transient,
       clarify)
apply (intro conjI) 
(*first subgoal*)
apply (blast intro: extend_stable_project_set 
                  [THEN stableD, THEN constrains_Int, THEN constrains_weaken] 
             dest!: extend_constrains_project_set equalityD1)
(*2nd subgoal*)
apply (erule stableD [THEN constrains_Int, THEN constrains_weaken])
    apply assumption
   apply (simp (no_asm_use) add: extend_set_def)
   apply blast
 apply (simp add: extend_set_Int_distrib extend_set_Un_distrib)
 apply (blast intro!: extend_set_project_set [THEN subsetD], blast)
(*The transient part*)
apply auto
 prefer 2
 apply (force dest!: equalityD1
              intro: transient_extend_set_imp_project_transient
                         [THEN transient_strengthen])
apply (simp (no_asm_use) add: Int_Diff)
apply (force dest!: equalityD1 
             intro: transient_extend_set_imp_project_transient 
               [THEN project_extend_transient_D, THEN transient_strengthen])
done

text‹Transferring a transient property upwards›
lemma project_transient_extend_set:
     "project h C G  transient (project_set h C  A - B)
      ==> G  transient (C  extend_set h A - extend_set h B)"
apply (simp add: transient_def project_set_def extend_set_def project_act_def)
apply (elim disjE bexE)
 apply (rule_tac x=Id in bexI)  
  apply (blast intro!: rev_bexI )+
done

lemma project_unless2:
     "[| G  stable C;  project h C G  (project_set h C  A) unless B |]  
      ==> G  (C  extend_set h A) unless (extend_set h B)"
by (auto dest: stable_constrains_Int intro: constrains_weaken
         simp add: unless_def project_constrains Diff_eq Int_assoc 
                   Int_extend_set_lemma)


lemma extend_unless:
   "[|extend h F  stable C; F  A unless B|]
    ==> extend h F  C  extend_set h A unless extend_set h B"
apply (simp add: unless_def stable_def)
apply (drule constrains_Int) 
apply (erule extend_constrains [THEN iffD2]) 
apply (erule constrains_weaken, blast) 
apply blast 
done

(*Used to prove project_leadsETo_D*)
lemma Join_project_ensures:
     "[| extend h FG  stable C;   
         Fproject h C G  A ensures B |]  
      ==> extend h FG  (C  extend_set h A) ensures (extend_set h B)"
apply (auto simp add: ensures_eq extend_unless project_unless)
apply (blast intro:  extend_transient [THEN iffD2] transient_strengthen)  
apply (blast intro: project_transient_extend_set transient_strengthen)  
done

text‹Lemma useful for both STRONG and WEAK progress, but the transient
    condition's very strong›

(*The strange induction formula allows induction over the leadsTo
  assumption's non-atomic precondition*)
lemma PLD_lemma:
     "[| extend h FG  stable C;   
         Fproject h C G  (project_set h C  A) leadsTo B |]  
      ==> extend h FG   
          C  extend_set h (project_set h C  A) leadsTo (extend_set h B)"
apply (erule leadsTo_induct)
  apply (blast intro: Join_project_ensures)
 apply (blast intro: psp_stable2 [THEN leadsTo_weaken_L] leadsTo_Trans)
apply (simp del: UN_simps add: Int_UN_distrib leadsTo_UN extend_set_Union)
done

lemma project_leadsTo_D_lemma:
     "[| extend h FG  stable C;   
         Fproject h C G  (project_set h C  A) leadsTo B |]  
      ==> extend h FG  (C  extend_set h A) leadsTo (extend_set h B)"
apply (rule PLD_lemma [THEN leadsTo_weaken])
apply (auto simp add: split_extended_all)
done

lemma Join_project_LeadsTo:
     "[| C = (reachable (extend h FG));  
         Fproject h C G  A LeadsTo B |]  
      ==> extend h FG  (extend_set h A) LeadsTo (extend_set h B)"
by (simp del: Join_stable    add: LeadsTo_def project_leadsTo_D_lemma
                                  project_set_reachable_extend_eq)


subsection‹Towards the theorem project_Ensures_D›

lemma project_ensures_D_lemma:
     "[| G  stable ((C  extend_set h A) - (extend_set h B));   
         Fproject h C G  (project_set h C  A) ensures B;   
         extend h FG  stable C |]  
      ==> extend h FG  (C  extend_set h A) ensures (extend_set h B)"
(*unless*)
apply (auto intro!: project_unless2 [unfolded unless_def] 
            intro: project_extend_constrains_I 
            simp add: ensures_def)
(*transient*)
(*A G-action cannot occur*)
 prefer 2
 apply (blast intro: project_transient_extend_set) 
(*An F-action*)
apply (force elim!: extend_transient [THEN iffD2, THEN transient_strengthen]
             simp add: split_extended_all)
done

lemma project_ensures_D:
     "[| Fproject h UNIV G  A ensures B;   
         G  stable (extend_set h A - extend_set h B) |]  
      ==> extend h FG  (extend_set h A) ensures (extend_set h B)"
apply (rule project_ensures_D_lemma [of _ UNIV, elim_format], auto)
done

lemma project_Ensures_D: 
     "[| Fproject h (reachable (extend h FG)) G  A Ensures B;   
         G  stable (reachable (extend h FG)  extend_set h A -  
                     extend_set h B) |]  
      ==> extend h FG  (extend_set h A) Ensures (extend_set h B)"
apply (unfold Ensures_def)
apply (rule project_ensures_D_lemma [elim_format])
apply (auto simp add: project_set_reachable_extend_eq [symmetric])
done


subsection‹Guarantees›

lemma project_act_Restrict_subset_project_act:
     "project_act h (Restrict C act)  project_act h act"
apply (auto simp add: project_act_def)
done
                                           
                                                           
lemma subset_closed_ok_extend_imp_ok_project:
     "[| extend h F ok G; subset_closed (AllowedActs F) |]  
      ==> F ok project h C G"
apply (auto simp add: ok_def)
apply (rename_tac act) 
apply (drule subsetD, blast)
apply (rule_tac x = "Restrict C  (extend_act h act)" in rev_image_eqI)
apply simp +
apply (cut_tac project_act_Restrict_subset_project_act)
apply (auto simp add: subset_closed_def)
done


(*Weak precondition and postcondition
  Not clear that it has a converse [or that we want one!]*)

(*The raw version; 3rd premise could be weakened by adding the
  precondition extend h F⊔G ∈ X' *)
lemma project_guarantees_raw:
 assumes xguary:  "F  X guarantees Y"
     and closed:  "subset_closed (AllowedActs F)"
     and project: "!!G. extend h FG  X' 
                        ==> Fproject h (C G) G  X"
     and extend:  "!!G. [| Fproject h (C G) G  Y |]  
                        ==> extend h FG  Y'"
 shows "extend h F  X' guarantees Y'"
apply (rule xguary [THEN guaranteesD, THEN extend, THEN guaranteesI])
apply (blast intro: closed subset_closed_ok_extend_imp_ok_project)
apply (erule project)
done

lemma project_guarantees:
     "[| F  X guarantees Y;  subset_closed (AllowedActs F);  
         projecting C h F X' X;  extending C h F Y' Y |]  
      ==> extend h F  X' guarantees Y'"
apply (rule guaranteesI)
apply (auto simp add: guaranteesD projecting_def extending_def
                      subset_closed_ok_extend_imp_ok_project)
done


(*It seems that neither "guarantees" law can be proved from the other.*)


subsection‹guarantees corollaries›

subsubsection‹Some could be deleted: the required versions are easy to prove›

lemma extend_guar_increasing:
     "[| F  UNIV guarantees increasing func;   
         subset_closed (AllowedActs F) |]  
      ==> extend h F  X' guarantees increasing (func o f)"
apply (erule project_guarantees)
apply (rule_tac [3] extending_increasing)
apply (rule_tac [2] projecting_UNIV, auto)
done

lemma extend_guar_Increasing:
     "[| F  UNIV guarantees Increasing func;   
         subset_closed (AllowedActs F) |]  
      ==> extend h F  X' guarantees Increasing (func o f)"
apply (erule project_guarantees)
apply (rule_tac [3] extending_Increasing)
apply (rule_tac [2] projecting_UNIV, auto)
done

lemma extend_guar_Always:
     "[| F  Always A guarantees Always B;   
         subset_closed (AllowedActs F) |]  
      ==> extend h F                    
             Always(extend_set h A) guarantees Always(extend_set h B)"
apply (erule project_guarantees)
apply (rule_tac [3] extending_Always)
apply (rule_tac [2] projecting_Always, auto)
done


subsubsection‹Guarantees with a leadsTo postcondition›

lemma project_leadsTo_D:
     "Fproject h UNIV G  A leadsTo B
      ==> extend h FG  (extend_set h A) leadsTo (extend_set h B)"
apply (rule_tac C1 = UNIV in project_leadsTo_D_lemma [THEN leadsTo_weaken], auto)
done

lemma project_LeadsTo_D:
     "Fproject h (reachable (extend h FG)) G  A LeadsTo B   
       ==> extend h FG  (extend_set h A) LeadsTo (extend_set h B)"
apply (rule refl [THEN Join_project_LeadsTo], auto)
done

lemma extending_leadsTo: 
     "extending (%G. UNIV) h F  
                (extend_set h A leadsTo extend_set h B) (A leadsTo B)"
apply (unfold extending_def)
apply (blast intro: project_leadsTo_D)
done

lemma extending_LeadsTo: 
     "extending (%G. reachable (extend h FG)) h F  
                (extend_set h A LeadsTo extend_set h B) (A LeadsTo B)"
apply (unfold extending_def)
apply (blast intro: project_LeadsTo_D)
done

end

end