(*File: HuntSands.thy*)
(*Authors: Lennart Beringer and Martin Hofmann, LMU Munich 2008*)
theory HuntSands imports VDM Lattice begin
section{*Flow-sensitivity a la Hunt and Sands*}

text{*\label{sec:HuntSands}\footnote{As the Isabelle theory representing this section is
dependent only on VDM.thy and Lattice.thy, name conflicts with
notions defined in Section \ref{sec:BaseLineNI} are avoided.} The
paper \cite{HuntSands:POPL2006} by Hunt and Sands presents a
generalisation of the type system of Volpano et al.~to
flow-sensitivity. Thus, programs such as $l:=h; l:=5$ are not rejected
any longer by the type system. Following the description in Section 4
of our paper~\cite{BeringerHofmann:CSF2007}, we embed Hunt and Sands'
type system into the program logic given in Section \ref{sec:VDM}.*}

subsection{*General $A; R \Rightarrow S$-security*}
text{*\label{sec:ARSsecurity}Again, we define the type $TT$ of
intermediate formulae $\Phi$, and an assertion operator
$\mathit{Sec}$. The latter is now parametrised not only by the
intermediate formulae but also by the (possibly differing) pre- and
post-relations $R$ and $S$ (both instantiated to $\approx$ in Section
\ref{sec:BaseLineNI}), and by a specification $A$ that directly links
pre- and post-states.*}

type_synonym TT = "(State \<times> State) \<Rightarrow> bool"

definition RSsecure::"(State \<Rightarrow> State \<Rightarrow> bool) \<Rightarrow>
                      (State \<Rightarrow> State \<Rightarrow> bool) \<Rightarrow> IMP \<Rightarrow> bool"
where "RSsecure R S c = (\<forall> s t ss tt . R s t \<longrightarrow> (s,c \<Down> ss) \<longrightarrow>
                          (t,c \<Down> tt) \<longrightarrow> S ss tt)"

definition ARSsecure::"VDMAssn \<Rightarrow> (State \<Rightarrow> State \<Rightarrow> bool) \<Rightarrow>
                      (State \<Rightarrow> State \<Rightarrow> bool) \<Rightarrow> IMP \<Rightarrow> bool"
where "ARSsecure A R S c = ((\<Turnstile> c : A) \<and> RSsecure R S c)"

text{*Definition 3 of our paper follows.*}

definition Sec :: "VDMAssn \<Rightarrow> (State \<Rightarrow> State \<Rightarrow> bool) \<Rightarrow>
                  (State \<Rightarrow> State \<Rightarrow> bool) \<Rightarrow> TT \<Rightarrow> VDMAssn"
where "Sec A R S \<Phi> s t = (A s t \<and>
                   (\<forall> r . R s r \<longrightarrow> \<Phi>(t,r)) \<and> (\<forall> r . \<Phi>(r,s) \<longrightarrow> S r t))"

text{*With these definitions, we can prove Proposition 4 of our
paper.*}

lemma Prop4A: "\<Turnstile> c : Sec A R S \<Phi> \<Longrightarrow> ARSsecure A R S c"
(*<*)
by (simp add:  VDM_valid_def Sec_def ARSsecure_def RSsecure_def)
(*>*)

lemma Prop4B : "ARSsecure A R S c \<Longrightarrow>
   \<Turnstile> c : Sec A R S (\<lambda> (r,t) . \<exists> s . (s , c \<Down> r) \<and> R s t)"
(*<*)
apply (simp add: VDM_valid_def Sec_def)
apply clarsimp
apply (unfold ARSsecure_def RSsecure_def VDM_valid_def)
apply rule apply fastforce
apply rule
apply (rule, rule) apply (rule_tac x=s in exI, rule, assumption+)
apply (rule, rule, erule exE, erule conjE) apply fast
done
(*>*)

subsection{*Basic definitions*}

text{*Contexts map program variables to lattice elements.*}

type_synonym "CONTEXT" = "Var \<Rightarrow> L"

definition upd ::"CONTEXT \<Rightarrow> Var \<Rightarrow> L \<Rightarrow> CONTEXT"
where "upd G x p = (\<lambda> y . if x=y then p else G y)"

text{*We also define the predicate $\mathit{EQ}$
%(in our paper denoted by the symbol $\ltimes$)
which expresses when two states agree on all
variables whose entry in a given context is below a certain security
level.*}

definition EQ:: "CONTEXT \<Rightarrow> L \<Rightarrow> State \<Rightarrow> State \<Rightarrow> bool"
where "EQ G p = (\<lambda> s t . \<forall> x . LEQ (G x) p \<longrightarrow>  s x = t x)"

lemma EQ_LEQ: "\<lbrakk>EQ G p s t; LEQ pp p\<rbrakk> \<Longrightarrow> EQ G pp s t"
(*<*)
apply (simp add: EQ_def, clarsimp)
apply (erule_tac x=x in allE, erule mp)
apply (erule LAT2, assumption)
done
(*>*)

text{*The assertion called $\mathcal{Q}$ in our paper:*}

definition Q::"L \<Rightarrow> CONTEXT \<Rightarrow> VDMAssn"
where "Q p H = (\<lambda> s t . \<forall> x . (\<not> LEQ p (H x)) \<longrightarrow> t x = s x)"

text{*$Q$ expresses the preservation of values in a single execution,
and corresponds to the first clause of Definition 3.2 in
\cite{HuntSands:POPL2006}. In accordance with this, the following
definition of security instantiates the $A$ position of $A; R
\Rightarrow S$-security with $Q$, while the context-dependent binary
state relations are plugged in as the $R$ and $S$ components.*}

definition secure :: "L \<Rightarrow> CONTEXT \<Rightarrow> IMP \<Rightarrow> CONTEXT \<Rightarrow> bool"
where "secure p G c H = (\<forall> q . ARSsecure (Q p H) (EQ G q) (EQ H q) c)"

text{*Indeed, one may show that this notion of security amounds to the
conjunction of a unary (i.e.~one-execution-)property and a binary
(i.e.~two-execution-) property, as expressed in Hunt \& Sands'
Definition 3.2.*}

definition secure1 :: "L \<Rightarrow> CONTEXT \<Rightarrow> IMP \<Rightarrow> CONTEXT \<Rightarrow> bool"
where "secure1 p G c H = (\<forall> s t . (s,c \<Down> t) \<longrightarrow> Q p H s t)"

definition secure2 :: "L \<Rightarrow> CONTEXT \<Rightarrow> IMP \<Rightarrow> CONTEXT \<Rightarrow> bool"
where "secure2 p G c H = ((\<forall> s t ss tt . (s,c \<Down> t) \<longrightarrow> (ss,c \<Down> tt) \<longrightarrow>
                                    EQ G p s ss \<longrightarrow> EQ H p t tt))"

lemma secureEQUIV:
  "secure p G c H = (\<forall> q . secure1 p G c H \<and> secure2 q G c H)"
(*<*)by (simp add: secure1_def secure2_def secure_def ARSsecure_def
              RSsecure_def Q_def VDM_valid_def, auto)
(*>*)

subsection{*Type system*}

text{*The type system of Hunt and Sands -- our language formalisation
uses a concrete datatype of expressions, so we add the obvious typing
rules for expressions and prove the expected evaluation lemmas.*}

inductive_set HS_E:: "(CONTEXT \<times> Expr \<times> L) set"
where
HS_E_var: "(G, varE x, G x) : HS_E"
| HS_E_val: "(G, valE c, bottom) : HS_E"
| HS_E_op: "\<lbrakk>(G, e1,p1):HS_E; (G, e2,p2):HS_E; p= LUB p1 p2\<rbrakk>
           \<Longrightarrow> (G,opE f e1 e2,p) : HS_E"
| HS_E_sup: "\<lbrakk>(G,e,p):HS_E; LEQ p q\<rbrakk> \<Longrightarrow> (G,e,q):HS_E"

lemma HS_E_eval[rule_format]:
"(G, e, t) \<in> HS_E \<Longrightarrow>
 \<forall> r s q. EQ G q r s \<longrightarrow> LEQ t q \<longrightarrow> evalE e r = evalE e s"
(*<*)
apply (erule HS_E.induct)
apply clarsimp  apply (simp add: EQ_def)
apply clarsimp
apply clarsimp
  apply (erule_tac x=r in allE, erule_tac x=r in allE)
  apply (erule_tac x=s in allE, erule_tac x=s in allE)
  apply (erule_tac x=q in allE, erule_tac x=q in allE, clarsimp)
  apply (erule impE) apply (rule LAT2) prefer 2 apply assumption
    apply (simp add: LAT3)
  apply (erule impE) apply (rule LAT2) prefer 2 apply assumption
    apply (subgoal_tac "LEQ p2 (LUB p2 p1)")
      apply (simp add: LAT4)
    apply (simp add: LAT3)
  apply clarsimp
apply clarsimp
  apply (erule_tac x=r in allE, erule_tac x=s in allE, erule_tac x=qa in allE, erule impE)
    apply clarsimp
  apply (erule mp) apply (erule LAT2, assumption)
done
(*>*)

text{*Likewise for boolean expressions: *}

inductive_set HS_B:: "(CONTEXT \<times> BExpr \<times> L) set"
where
HS_B_compB: "\<lbrakk>(G, e1,p1):HS_E; (G, e2,p2):HS_E; p= LUB p1 p2\<rbrakk>
             \<Longrightarrow> (G,compB f e1 e2,p) : HS_B"
| HS_B_sup: "\<lbrakk>(G,b,p):HS_B; LEQ p q\<rbrakk> \<Longrightarrow> (G,b,q):HS_B"

lemma HS_B_eval[rule_format]:
"(G, b, t) \<in> HS_B \<Longrightarrow>
 \<forall> r s pp . EQ G pp r s \<longrightarrow> LEQ t pp \<longrightarrow>  evalB b r = evalB b s"
(*<*)
apply (erule HS_B.induct)
apply clarsimp
  apply (subgoal_tac "evalE e1 r = evalE e1 s", clarsimp)
  prefer 2 apply (erule HS_E_eval) apply assumption
           apply (rule LAT2) prefer 2 apply assumption apply (simp add: LAT3)
  apply (subgoal_tac "evalE e2 r = evalE e2 s", clarsimp)
    apply (erule HS_E_eval) apply assumption
           apply (rule LAT2) prefer 2 apply assumption
           apply (subgoal_tac "LEQ p2 (LUB p2 p1)", simp add: LAT4)
           apply (simp add: LAT3)
apply clarsimp
  apply (erule_tac x=r in allE, erule_tac x=s in allE, erule_tac x=pp in allE, erule impE)
    apply clarsimp
  apply (erule mp) apply (erule LAT2, assumption)
done
(*>*)

text{*The typing rules for commands follow.*}

inductive_set HS::"(L \<times> CONTEXT \<times> IMP \<times> CONTEXT) set"
where
HS_Skip:   "(p,G,Skip,G):HS"

| HS_Assign:
  "(G,e,t):HS_E \<Longrightarrow> (p,G,Assign x e,upd G x (LUB p t)):HS"

| HS_Seq:
  "\<lbrakk>(p,G,c,K):HS; (p,K,d,H):HS\<rbrakk> \<Longrightarrow> (p,G, Comp c d,H):HS"

| HS_If:
  "\<lbrakk>(G,b,t):HS_B; (LUB p t,G,c,H):HS; (LUB p t,G,d,H):HS\<rbrakk> \<Longrightarrow>
   (p,G,Iff b c d,H):HS"

| HS_If_alg:
  "\<lbrakk>(G,b,p):HS_B; (p,G,c,H):HS; (p,G,d,H):HS\<rbrakk> \<Longrightarrow>
   (p,G,Iff b c d,H):HS"

| HS_While:
  "\<lbrakk>(G,b,t):HS_B; (LUB p t,G,c,H):HS;H=G\<rbrakk> \<Longrightarrow>
   (p,G,While b c,H):HS"

| HS_Sub:
  "\<lbrakk> (pp,GG,c,HH):HS; LEQ p pp; \<forall> x . LEQ (G x) (GG x);
       \<forall> x . LEQ (HH x) (H x)\<rbrakk> \<Longrightarrow>
   (p,G,c,H):HS"

text {*Using @{text HS_Sub}, rules @{text If} and @{text If_alg} are
inter-derivable.*}

lemma IF_derivable_from_If_alg:
  "\<lbrakk>(G,b,t):HS_B; (LUB p t,G,c1,H):HS; (LUB p t,G,c2,H):HS\<rbrakk>
   \<Longrightarrow> (p,G,Iff b c1 c2,H):HS"
apply (subgoal_tac "(LUB p t,G,Iff b c1 c2,H):HS")
  apply (erule HS_Sub) apply (rule LAT3)
    apply (clarsimp, rule LAT6) apply (clarsimp, rule LAT6)
apply (rule HS_If_alg) apply (erule HS_B_sup)
  apply (subgoal_tac "LEQ t (LUB t p)", simp add: LAT4)
  apply (rule LAT3) apply assumption+
done

lemma IF_alg_derivable_from_If:
  "\<lbrakk>(G,b,p):HS_B; (p,G,c1,H):HS; (p,G,c2,H):HS\<rbrakk>
  \<Longrightarrow> (p,G,Iff b c1 c2,H):HS"
apply (erule HS_If) apply (subgoal_tac "LUB p p = p", clarsimp)
  apply (subgoal_tac "p = LUB p p", fastforce) apply (rule LAT7)
apply (subgoal_tac "LUB p p = p", clarsimp)
  apply (subgoal_tac "p = LUB p p", fastforce) apply (rule LAT7)
done

text{*An easy induction on typing derivations shows the following property.*}

lemma HS_Aux1:
 "(p,G,c,H):HS \<Longrightarrow> \<forall> x. LEQ (G x) (H x) \<or> LEQ p (H x)"
(*<*)
apply (erule HS.induct)
(*Skip*)
apply (simp add: LAT6)
(*Assign*)
apply (simp add: upd_def) apply clarsimp apply rule
  apply clarsimp apply (simp add: LAT3)
  apply clarsimp apply (simp add: LAT6)
(*Seq*)
apply clarsimp
   apply (erule_tac x=x in allE, erule disjE)
   apply (erule_tac x=x in allE, erule disjE)
     apply (erule LAT2) apply assumption apply fast
   apply (erule_tac x=x in allE, erule disjE)
     apply(subgoal_tac "LEQ p (H x)", fast)
     apply (erule LAT2) apply assumption apply fast
(*If*)
apply clarsimp
   apply (erule_tac x=x in allE, erule disjE) apply assumption
     apply(subgoal_tac "LEQ p (H x)", fast)
     apply (subgoal_tac "LEQ p (LUB p t)", rotate_tac -1)
     apply (erule LAT2) apply assumption
     apply (rule LAT3)
(*If2*)
apply clarsimp
(*While*)
apply clarsimp
   apply (simp add: LAT6)
(*Sub*)
apply clarsimp
   apply (erule_tac x=x in allE, erule disjE)
   apply (erule_tac x=x in allE)
   apply (erule_tac x=x in allE)
     apply (erule LAT2)
     apply (erule LAT2) apply assumption
   apply (erule_tac x=x in allE)
     apply (erule LAT2)
   apply (erule_tac x=x in allE)
     apply (subgoal_tac "LEQ p (H x)", fast)
     apply (erule LAT2)
     apply (erule LAT2) apply assumption
done
(*>*)

subsection{*Derived proof rules*}

text{*In order to show the derivability of the properties given in
Theorem 3.3 of Hunt and Sands' paper, we give the following derived
proof rules. By including the $Q$ property in the $A$ position of
$Sec$, we prove both parts of theorem in one proof, and can exploit
the first property ($Q$) in the proof of the second. *}

lemma SKIP:
 "X \<rhd> Skip : Sec (Q p H) (EQ G q) (EQ G q)
                  (\<lambda> (s,t) . EQ G q s t)"
(*<*)
apply (rule VDMConseq, rule VDMSkip)
  apply (simp add: Sec_def EQ_def Q_def)
done
(*>*)

lemma ASSIGN:
  "\<lbrakk>H = upd G x (LUB p t);
    \<forall> s ss . EQ G t s ss \<longrightarrow> evalE e s = evalE e ss\<rbrakk>
  \<Longrightarrow> X \<rhd> Assign x e : Sec (Q p H) (EQ G q) (EQ H q)
            (\<lambda> (s,t) . \<exists> r . s = update r x (evalE e r) \<and> EQ G q r t)"
(*<*)
  apply (rule VDMConseq, rule VDMAssign) apply clarsimp
  apply (simp add: Sec_def EQ_def Q_def)
  apply (rule, clarsimp) apply (simp add: update_def upd_def)
    apply (case_tac "x=xa", clarsimp) apply (simp add: LAT3)
    apply clarsimp
  apply (rule, clarsimp) apply (rule_tac x=s in exI, simp)
  apply clarsimp
    apply (case_tac "x=xa", clarsimp, hypsubst_thin)
      apply (simp add: update_def upd_def)
        apply (erule_tac x=ra in allE, erule_tac x=s in allE, erule mp, clarsimp)
        apply (erule_tac x=x in allE, erule mp)
        apply (erule LAT2, rule LAT2) prefer 2 apply assumption
        apply (subgoal_tac "LEQ t (LUB t p)", simp add: LAT4)  apply (rule LAT3)
      apply (simp add: update_def upd_def)
done
(*>*)

lemma COMP:
  "\<lbrakk> X \<rhd> c1 : Sec (Q p K) (EQ G q) (EQ K q) \<Phi>;
     X \<rhd> c2 : Sec (Q p H) (EQ K q) (EQ H q) \<Psi>;
    \<forall> x . LEQ (G x) (K x) \<or> LEQ p (K x);
    \<forall> x . LEQ (K x) (H x) \<or> LEQ p (H x)\<rbrakk>
   \<Longrightarrow> X \<rhd> Comp c1 c2 : Sec (Q p H) (EQ G q) (EQ H q)
        (\<lambda> (x, y) . \<exists> z . \<Phi> (z, y) \<and>
                          (\<forall> w . EQ K q z w \<longrightarrow> \<Psi> (x, w)))"
(*<*)
  apply (rule VDMConseq, rule VDMComp, assumption, assumption, clarsimp)
    apply (erule thin_rl, erule thin_rl)
  apply (simp add: Sec_def, rule, clarsimp)
    apply (simp add: Q_def, clarsimp)
    apply (rotate_tac 3, erule_tac x=x in allE, erule impE, assumption)
    apply (erule_tac x=x in allE, clarsimp)
    apply (erule_tac x=x in allE, clarsimp)
    apply (subgoal_tac "LEQ p (H x)", fast)
    apply (erule LAT2) apply assumption
  apply (rule, clarsimp)
    apply (rule_tac x=r in exI, simp)
  apply clarsimp
done
(*>*)

text{*We distinguish, for any given $q$, \emph{parallel} conditionals
from \emph{diagonal} ones. Speaking operationally (i.e.~in terms of
two executions), conditionals of the former kind evaluate the branch
condition identically in both executions. The following rule
expresses this condition explicitly, in the first side condition. The
formula inside the $\mathit{Sec}$-operator of the conclusion resembles
the conclusion of the VDM rule for conditionals in that the formula
chosen depends on the outcome of the branch.*}

lemma IF_PARALLEL:
  "\<lbrakk> \<forall> s ss . EQ G p s ss \<longrightarrow> evalB b s = evalB b ss;
     \<forall> x. LEQ (G x) (H x) \<or> LEQ p (H x);
     \<exists> x . LEQ p (H x) \<and> LEQ (H x) q;
     X \<rhd> c1 : Sec (Q p H) (EQ G q) (EQ H q) \<Phi>;
     X \<rhd> c2 : Sec (Q p H) (EQ G q) (EQ H q) \<Psi>\<rbrakk>
  \<Longrightarrow> X \<rhd> Iff b c1 c2 : Sec (Q p H) (EQ G q) (EQ H q)
                       (\<lambda> (r, u) . (evalB b u \<longrightarrow> \<Phi> (r, u)) \<and>
                                   ( (\<not> evalB b u) \<longrightarrow> \<Psi> (r, u)))"
(*<*)
    apply (rule VDMConseq, rule VDMIff) apply (assumption, assumption) apply clarsimp
    apply (simp add: Sec_def Q_def)
    apply (subgoal_tac "(\<forall>x. \<not> LEQ p (H x) \<longrightarrow> t x = s x)", simp)
    prefer 2 apply (case_tac "evalB b s", clarsimp,clarsimp)
    apply (rule, clarsimp)
    (*left component of Sec*)
      apply (subgoal_tac "evalB b s = evalB b r")
      prefer 2 apply (erule_tac x=s in allE, rotate_tac -1, erule_tac x=r in allE, erule mp)
        apply (erule EQ_LEQ) apply (erule LAT2, assumption)
      apply (case_tac "evalB b s")
              apply clarsimp
              apply clarsimp
    (*right component of Sec*)
      apply clarsimp
      apply (case_tac "evalB b s")
        apply clarsimp
        apply clarsimp
done
(*>*)

text{*An alternative formulation replaces the first side condition
with a typing hypothesis on the branch condition, thus exploiting
lemma HS\_B\_eval.*}

lemma IF_PARALLEL_tp:
  "\<lbrakk> (G, b, p) \<in> HS_B; (p , G, c1, H) \<in> HS; (p, G, c2, H) \<in> HS;
     \<exists> x . LEQ p (H x) \<and> LEQ (H x) q;
     X \<rhd> c1 : Sec (Q p H) (EQ G q) (EQ H q) \<Phi>;
     X \<rhd> c2 : Sec (Q p H) (EQ G q) (EQ H q) \<Psi>\<rbrakk>
  \<Longrightarrow> X \<rhd> Iff b c1 c2 : Sec (Q p H) (EQ G q) (EQ H q)
                       (\<lambda> (r, u) . (evalB b u \<longrightarrow> \<Phi> (r, u)) \<and>
                                   ( (\<not> evalB b u) \<longrightarrow> \<Psi> (r, u)))"
(*<*)
  apply (rule IF_PARALLEL)
    apply (clarsimp, erule HS_B_eval) apply assumption apply (rule LAT6)
    apply (erule HS_Aux1)
    apply assumption+
done
(*>*)

text{*Diagonal conditionals, in contrast, capture cases where (from
the perspective of an observer at level $q$) the two executions may
evaluate the branch condition differently. In this case, the formula
inside the $\mathit{Sec}$-operator in the conclusion cannot depend
upon the branch outcome, so the least common denominator of the two
branches must be taken, which is given by the equality condition
w.r.t.~the post-context $H$. A side condition (the first one given in
the rule) ensures that indeed no information leaks during the
execution of either branch, by relating $G$ and $H$.*}

lemma IF_DIAGONAL:
  "\<lbrakk> \<forall>x. LEQ (G x) (H x) \<or> LEQ p (H x);
      \<not> (\<exists>x. LEQ p (H x) \<and> LEQ (H x) q);
      X \<rhd> c1 : Sec (Q p H) (EQ G q) (EQ H q) \<Phi>;
      X \<rhd> c2 : Sec (Q p H) (EQ G q) (EQ H q) \<Psi>\<rbrakk>
   \<Longrightarrow> X \<rhd> Iff b c1 c2 : Sec (Q p H) (EQ G q) (EQ H q)
                             (\<lambda> (s,t). EQ H q s t)"
(*<*)
  apply clarsimp
  apply (rule VDMConseq, rule VDMIff) apply (assumption, assumption) apply clarsimp
  apply (simp add: Sec_def Q_def)
  apply (subgoal_tac "(\<forall>x. \<not> LEQ p (H x) \<longrightarrow> t x = s x)", simp)
  prefer 2 apply (case_tac "evalB b s")
           apply clarsimp
           apply clarsimp
  apply (rule, clarsimp)
  (*Left component*)
    apply (simp (no_asm) add: EQ_def, clarsimp)
    apply (case_tac "LEQ p (H x)") apply clarsimp
    apply (rotate_tac -4, erule_tac x=x in allE, clarsimp)
    apply (simp add: EQ_def)
    apply (erule_tac x=x in allE, erule mp)
    apply (rotate_tac -4, erule_tac x=x in allE, clarsimp)
    apply (erule LAT2, assumption)
  (*right component*)
    apply clarsimp
    apply (simp add: EQ_def, clarsimp)
    apply (case_tac "LEQ p (H x)")
    apply clarsimp
    apply clarsimp
done
(*>*)

text{*Again, the first side condition of the rule may be replaced by a
typing condition, but now this condition is on the commands (instead
of the branch condition) -- in fact, a derivation for either branch
suffices.*}

lemma IF_DIAGONAL_tp:
  "\<lbrakk> (p, G, c1, H) \<in> HS \<or> (p, G, c2, H) \<in> HS;
      \<not> (\<exists>x. LEQ p (H x) \<and> LEQ (H x) q);
      X \<rhd> c1 : Sec (Q p H) (EQ G q) (EQ H q) \<Phi>;
      X \<rhd> c2 : Sec (Q p H) (EQ G q) (EQ H q) \<Psi>\<rbrakk>
   \<Longrightarrow> X \<rhd> Iff b c1 c2 : Sec (Q p H) (EQ G q) (EQ H q)
                             (\<lambda> (s,t). EQ H q s t)"
(*<*)
  apply (rule IF_DIAGONAL)
    apply (erule disjE) apply (erule HS_Aux1) apply (erule HS_Aux1)
    apply assumption+
done
(*>*)

text{*Obviously, given $q$, any conditional is either parallel or
diagonal as the second side conditions of the diagonal rules and the
parallel rules are exclusive.*}

lemma if_algorithmic:
  "\<lbrakk>\<exists> x . LEQ p (H x) \<and> LEQ (H x) q;
    \<not> (\<exists>x. LEQ p (H x) \<and> LEQ (H x) q)\<rbrakk>
   \<Longrightarrow> False"
(*<*) by simp (*>*)

text{*As in Section \ref{sec:BaseLineNI} we define a fixed point
construction, useful for the (parallel) while rule.*}

definition FIX::"(TT \<Rightarrow> TT) \<Rightarrow> TT"
where "FIX \<phi> = (\<lambda> (s,t). \<forall> \<Phi> . (\<forall> ss tt . \<phi> \<Phi> (ss, tt) \<longrightarrow> \<Phi> (ss, tt))
                            \<longrightarrow> \<Phi> (s, t))"

text{*For monotone invariant transformers, the construction indeed
yields a fixed point.*}

definition Monotone::"(TT \<Rightarrow> TT) \<Rightarrow> bool"
where "Monotone \<phi> = (\<forall> \<Phi> \<Psi> . (\<forall> s t . \<Phi>(s,t) \<longrightarrow> \<Psi>(s,t)) \<longrightarrow>
                        (\<forall> s t . \<phi> \<Phi> (s,t) \<longrightarrow> \<phi> \<Psi> (s,t)))"

(*<*)
lemma Fix2: "\<lbrakk>Monotone \<phi>; \<phi> (FIX \<phi>) (s, t)\<rbrakk> \<Longrightarrow> FIX \<phi> (s,t)"
apply (simp add: FIX_def) apply clarsimp
apply (subgoal_tac "\<phi> \<Phi> (s,t)", simp)
apply (subgoal_tac "\<forall> r u . FIX \<phi> (r,u) \<longrightarrow> \<Phi>(r,u)")
prefer 2 apply (erule thin_rl) apply (simp add: FIX_def) apply clarsimp
  apply (erule_tac x=\<Phi> in allE, simp)
apply (unfold Monotone_def)
  apply (erule_tac x="FIX \<phi>" in allE, erule_tac x=\<Phi> in allE)
  apply (erule impE) apply assumption
  apply (simp add: FIX_def)
done

lemma Fix1: "\<lbrakk>Monotone \<phi>; FIX \<phi> (s,t)\<rbrakk> \<Longrightarrow> \<phi> (FIX \<phi>) (s,t)"
apply (simp add: FIX_def)
apply (erule_tac x="\<phi>(FIX \<phi>)" in allE)
apply (erule impE)
prefer 2 apply (simp add: FIX_def)
apply (subgoal_tac "\<forall> r u . \<phi> (FIX \<phi>) (r,u) \<longrightarrow> FIX \<phi> (r,u)")
  prefer 2 apply clarsimp apply (erule Fix2) apply assumption
apply (unfold Monotone_def)
  apply (erule_tac x="\<phi>(FIX \<phi>)" in allE, erule_tac x="FIX \<phi>" in allE, erule impE) apply assumption
apply simp
done
(*>*)
lemma Fix_lemma:"Monotone \<phi> \<Longrightarrow> \<phi> (FIX \<phi>) = FIX \<phi>"
(*<*)
apply (rule ext, rule iffI)
apply clarsimp apply (erule Fix2) apply assumption
apply clarsimp apply (erule Fix1) apply assumption
done
(*>*)

text{*Next, the definition of a while-operator.*}

definition PhiWhilePOp::
          "VDMAssn \<Rightarrow> BExpr \<Rightarrow> TT \<Rightarrow> TT \<Rightarrow> TT"
where "PhiWhilePOp A b \<Phi> =
  (\<lambda> \<Psi> . (\<lambda>(r, u). (evalB b u \<longrightarrow> (\<exists>z. \<Phi> (z, u) \<and>
                                        (\<forall>w. A z w \<longrightarrow> \<Psi> (r, w)))) \<and>
                     ((\<not> evalB b u) \<longrightarrow> A r u)))"

text{*This operator is monotone in $\Phi$.*}

lemma PhiWhilePOp_Monotone:"Monotone (PhiWhilePOp A b \<Phi>)"
(*<*)
apply (simp add: PhiWhilePOp_def Monotone_def) apply clarsimp
  apply (rule_tac x=z in exI, simp)
done
(*>*)

text{*Therefore, we can define the following fixed point.*}

definition PhiWhileP::"VDMAssn \<Rightarrow> BExpr \<Rightarrow> TT \<Rightarrow> TT"
where "PhiWhileP A b \<Phi> = FIX (PhiWhilePOp A b \<Phi>)"

text{*As as a function on $\phi$, this PhiWhileP is itself monotone
in $\phi$:*}

lemma PhiWhilePMonotone: "Monotone (\<lambda> \<Phi> . PhiWhileP A b \<Phi>)"
(*<*)
apply (simp add: Monotone_def) apply clarsimp
apply (simp add: PhiWhileP_def)
apply (simp add: FIX_def) apply clarsimp
apply (erule_tac x=\<Phi>' in allE, erule mp)
apply (clarsimp) apply (erule_tac x=ss in allE, erule_tac x=tt in allE, erule mp)
apply (simp add: PhiWhilePOp_def) apply clarsimp
apply (rule_tac x=z in exI, simp)
done
(*>*)

text{*Now the rule for parallel while loops, i.e.~loops where the
branch condition evaluates identically in both executions.*}

lemma WHILE_PARALLEL:
 "\<lbrakk> X \<rhd> c : Sec (Q p G) (EQ G q) (EQ G q) \<Phi>;
    \<forall> s ss . EQ G p s ss \<longrightarrow> evalB b s = evalB b ss; LEQ p q\<rbrakk>
 \<Longrightarrow> X \<rhd> While b c : Sec (Q p G) (EQ G q) (EQ G q)
                         (PhiWhileP (EQ G q) b \<Phi>)"
(*<*)
apply (rule VDMConseq)
apply (rule VDMWhile)
prefer 4 apply (subgoal_tac "\<forall>s t. Sec (Q p G) (EQ G q) (EQ G q) (PhiWhilePOp (EQ G q) b \<Phi> (PhiWhileP (EQ G q) b \<Phi>)) s t \<and> \<not> evalB b t \<longrightarrow> Sec (Q p G) (EQ G q) (EQ G q) (PhiWhileP (EQ G q) b \<Phi>) s t") apply assumption
  apply clarsimp apply (subgoal_tac "PhiWhilePOp (EQ G q) b \<Phi> (PhiWhileP (EQ G q) b \<Phi>) = PhiWhileP (EQ G q) b \<Phi>", clarsimp)
                 apply (simp add: PhiWhileP_def) apply (rule Fix_lemma) apply (rule PhiWhilePOp_Monotone)
apply assumption
apply clarsimp apply (simp add: Sec_def)
  apply rule apply (simp add: Q_def)
  apply (rule, clarsimp) apply (simp add: PhiWhilePOp_def) apply clarsimp
      apply (erule_tac x=s in allE, erule_tac x=r in allE, erule impE) apply (erule EQ_LEQ) apply assumption apply clarsimp
  apply clarsimp apply (simp add: PhiWhilePOp_def)
apply clarsimp apply (simp add: Sec_def)
  apply rule apply clarsimp apply (simp add: Q_def)
  apply rule
  prefer 2 apply clarsimp
    apply (subgoal_tac "\<exists>r. \<Phi> (r, s) \<and> (\<forall>w. EQ G q r w \<longrightarrow> (PhiWhileP (EQ G q) b \<Phi>) (ra, w))")
    prefer 2 apply (simp add: PhiWhilePOp_def)
    apply clarsimp apply (rotate_tac -3, erule thin_rl)
    apply (rotate_tac -1, erule_tac x=ra in allE, erule mp)
    apply (rotate_tac 1, erule_tac x=r in allE, erule impE) apply fast
    apply (subgoal_tac "PhiWhilePOp (EQ G q) b \<Phi> (PhiWhileP (EQ G q) b \<Phi>) = PhiWhileP (EQ G q) b \<Phi>", clarsimp)
    apply (simp add: PhiWhileP_def)
    apply (rule Fix_lemma) apply (rule PhiWhilePOp_Monotone)
  apply clarsimp
    apply (simp (no_asm_simp) add: PhiWhilePOp_def)
    apply rule
    prefer 2  apply clarsimp
              apply (erule_tac x=s in allE, rotate_tac -1, erule_tac x=ra in allE, erule impE)
               apply (erule EQ_LEQ) apply assumption apply clarsimp
    apply clarsimp
    apply (rotate_tac 2, erule_tac x=ra in allE, clarsimp)
    apply (rule_tac x=r in exI, rule) apply simp
    apply clarsimp
    apply (rotate_tac 5, erule_tac x=w in allE, clarsimp)
    apply (subgoal_tac "PhiWhilePOp (EQ G q) b \<Phi> (PhiWhileP (EQ G q) b \<Phi>) = PhiWhileP (EQ G q) b \<Phi>", clarsimp)
    apply (simp add: PhiWhileP_def)
    apply (rule Fix_lemma) apply (rule PhiWhilePOp_Monotone)
done
(*>*)

text{*The side condition regarding the evalution of the branch
condsition may be replaced by a typing hypothesis, thanks to lemma
@{text HS_B_eval}.*}

lemma WHILE_PARALLEL_tp:
 "\<lbrakk> X \<rhd> c : Sec (Q p G) (EQ G q) (EQ G q) \<Phi>;
    (G, b, p) \<in> HS_B; LEQ p q\<rbrakk>
 \<Longrightarrow> X \<rhd> While b c : Sec (Q p G) (EQ G q) (EQ G q)
                         (PhiWhileP (EQ G q) b \<Phi>)"
(*<*)
apply (erule WHILE_PARALLEL)
apply clarsimp
  apply (erule HS_B_eval) apply assumption apply (rule LAT6)
apply assumption
done
(*>*)

text{*One may also give an inductive formulation of FIX:*}

inductive_set var::"(BExpr \<times> VDMAssn \<times> TT \<times> State \<times> State) set"
where
varFalse:
   "\<lbrakk>\<not> evalB b t; A s t\<rbrakk> \<Longrightarrow> (b,A,\<Phi>,s,t):var"
| varTrue:
   "\<lbrakk>evalB b t; \<Phi>(r,t); (\<forall> w . A r w \<longrightarrow>
    (b,A,\<Phi>,s,w): var) \<rbrakk> \<Longrightarrow> (b,A,\<Phi>,s,t):var"

(*<*)
lemma varFIX: "(b,A,\<Phi>,s,t):var \<Longrightarrow> PhiWhileP A b \<Phi> (s,t)"
apply (erule var.induct)
apply (simp add: PhiWhileP_def)
  apply (subgoal_tac "PhiWhilePOp A b \<Phi> (FIX (PhiWhilePOp A b \<Phi>)) (s,t)")
  apply (subgoal_tac "PhiWhilePOp A b \<Phi> (FIX (PhiWhilePOp A b \<Phi>)) = FIX (PhiWhilePOp A b \<Phi>)", clarsimp)
  apply (rule Fix_lemma) apply (rule PhiWhilePOp_Monotone)
  apply (simp add: PhiWhilePOp_def)
apply (simp (no_asm_simp) add: PhiWhileP_def)
apply (subgoal_tac "PhiWhilePOp A b \<Phi> (FIX (PhiWhilePOp A b \<Phi>)) (s,t)")
  apply (subgoal_tac "PhiWhilePOp A b \<Phi> (FIX (PhiWhilePOp A b \<Phi>)) = FIX (PhiWhilePOp A b \<Phi>)", clarsimp)
  apply (rule Fix_lemma) apply (rule PhiWhilePOp_Monotone)
  apply (simp add: PhiWhilePOp_def)
  apply (rule_tac x=r in exI, simp)
  apply clarsimp
  apply (erule_tac x=w in allE, clarsimp)
  apply (simp add: PhiWhileP_def)
  apply (simp add: PhiWhilePOp_def)
done

lemma FIXvar: "PhiWhileP A b \<Phi> (s,t) \<Longrightarrow> (b,A,\<Phi>,s,t):var"
apply (simp add: PhiWhileP_def)
apply (subgoal_tac "PhiWhilePOp A b \<Phi> (FIX (PhiWhilePOp A b \<Phi>)) (s, t)")
prefer 2
  apply (subgoal_tac "PhiWhilePOp A b \<Phi> (FIX (PhiWhilePOp A b \<Phi>)) = FIX (PhiWhilePOp A b \<Phi>)", clarsimp)
  apply (rule Fix_lemma) apply (rule PhiWhilePOp_Monotone)
apply (erule thin_rl, simp add: PhiWhilePOp_def) apply clarsimp
  apply (case_tac "evalB b t")
  prefer 2 apply clarsimp apply (rule varFalse) apply assumption+
  apply clarsimp apply (rule varTrue) apply assumption apply assumption
    apply clarsimp apply (erule_tac x=w in allE, clarsimp)
    apply (unfold FIX_def) apply clarify
    apply (erule_tac x="\<lambda> (x,y) . (b,A,\<Phi>,x,y):var" in allE, erule impE) prefer 2 apply simp
    apply clarsimp
    apply (case_tac "evalB b tt")
    prefer 2 apply clarsimp apply (rule varFalse) apply assumption+
    apply clarsimp apply (rule varTrue) apply assumption+
done
(*>*)

text{*The inductive formulation and the fixed point formulation are
equivalent.*}
(*<*)
lemma varFIXvar: "(PhiWhileP A b \<Phi> (s,t)) = ((b,A,\<Phi>,s,t):var)"
apply rule
apply (erule FIXvar)
apply (erule varFIX)
done
(*>*)
(*<*)
lemma FIXvarFIX': "(PhiWhileP A b \<Phi>) = (\<lambda> (s,t) . (b,A,\<Phi>,s,t):var)"
apply (rule ext, rule iffI)
apply (case_tac x, clarsimp) apply (erule FIXvar)
apply (case_tac x, clarsimp) apply (simp add: varFIXvar)
done
(*>*)
lemma FIXvarFIX:
"PhiWhileP A b = (\<lambda> \<Phi> . (\<lambda> (s,t) . (b,A,\<Phi>,s,t):var))"
(*<*)
by (rule, rule FIXvarFIX')
(*>*)

text{*Thus, the above while rule may also be written using the
inductive formulation.*}

lemma WHILE_PARALLEL_IND:
 "\<lbrakk> X \<rhd> c : Sec (Q p G) (EQ G q) (EQ G q) \<Phi>;
    \<forall> s ss . EQ G p s ss \<longrightarrow> evalB b s = evalB b ss; LEQ p q\<rbrakk> \<Longrightarrow>
   X \<rhd> While b c : (Sec (Q p G) (EQ G q) (EQ G q)
                    (\<lambda> (s,t) . (b,EQ G q,\<Phi>,s,t):var))"
(*<*)
apply (rule VDMConseq)
apply (rule WHILE_PARALLEL) apply assumption+
apply clarsimp
apply (simp add: FIXvarFIX)
done
(*>*)

text{*Again, we may replace the side condition regarding the branch
condition by a typing hypothesis.*}

lemma WHILE_PARALLEL_IND_tp:
 "\<lbrakk> X \<rhd> c : Sec (Q p G) (EQ G q) (EQ G q) \<Phi>;
    (G, b, p) \<in> HS_B; LEQ p q \<rbrakk> \<Longrightarrow>
 X \<rhd> (While b c) :
  (Sec (Q p G) (EQ G q) (EQ G q) (\<lambda> (s,t) . (b,EQ G q,\<Phi>,s,t):var))"
(*<*)
apply (erule WHILE_PARALLEL_IND)
apply clarsimp
  apply (erule HS_B_eval) apply assumption apply (rule LAT6)
apply assumption
done
(*>*)
(*<*)
lemma varMonotoneAux[rule_format]:
 "(b, A, \<Phi>, s, t) \<in> var \<Longrightarrow>
  (\<forall>s t. \<Phi> (s, t) \<longrightarrow> \<Psi> (s, t)) \<longrightarrow>
  (b, A, \<Psi>, s, t) \<in> var"
apply (erule var.induct)
apply clarsimp apply (erule varFalse, simp)
apply clarsimp apply (erule varTrue) apply fast apply simp
done
(*>*)
text{*Of course, the inductive formulation is also monotone:*}

lemma var_MonotoneInPhi:
  "Monotone (\<lambda> \<Phi> . (\<lambda> (s,t) .(b,A, \<Phi>,s,t):var))"
(*<*)
apply (simp add: Monotone_def)
apply clarsimp
apply (rule varMonotoneAux) apply assumption apply simp
done
(*>*)
(*<*)
lemma varMonotone_byFIX: "Monotone (\<lambda> \<Phi> . (\<lambda> (s,t) .(b,A, \<Phi>,s,t):var))"
apply (subgoal_tac "Monotone (\<lambda> \<Phi> . PhiWhileP A b \<Phi>)")
apply (simp add: FIXvarFIX)
apply (rule PhiWhilePMonotone)
done
(*>*)

text{*In order to derive a diagonal while rule, we directly define an
inductive relation that calculates the transitive closure of relation
$A$, such that all but the last state evaluate $b$ to
$\mathit{True}$.*}

inductive_set varD::"(BExpr \<times> VDMAssn \<times> State \<times> State) set"
where
varDFalse: "\<lbrakk>\<not> evalB b s; A s t\<rbrakk> \<Longrightarrow> (b,A,s,t):varD"
| varDTrue: "\<lbrakk>evalB b s; A s w; (b,A,w,t): varD \<rbrakk> \<Longrightarrow> (b,A,s,t):varD"

text{*Here is the obvious definition of transitivity for assertions.*}

definition transitive::"VDMAssn \<Rightarrow> bool"
where "transitive P = (\<forall> x y z . P x y \<longrightarrow> P y z \<longrightarrow> P x z)"

text{*The inductive relation satisfies the following property.*}

lemma varD_transitive[rule_format]:
 "(b,A,s,t):varD \<Longrightarrow> transitive A \<longrightarrow> A s t"
(*<*)
apply (erule varD.induct)
apply clarsimp
apply clarsimp
  apply (unfold transitive_def) apply (erule_tac x=s in allE, erule_tac x=w in allE, erule_tac x=t in allE, simp)
done
(*>*)

text{*On the other hand, the assertion $\mathit{Q}$ defined above is transitive,*}

lemma Q_transitive:"transitive (Q q G)"
(*<*)
by (simp add: Q_def transitive_def)
(*>*)

text{*and is hence respected by the inductive closure:*}

lemma varDQ:"(b,Q q G,s,t):varD \<Longrightarrow> Q q G s t"
(*<*)by (erule varD_transitive,rule Q_transitive)(*>*)

text{*The diagonal while rule has a conclusion that is independent of
$\phi$.*}

lemma WHILE_DIAGONAL:
 "\<lbrakk>X \<rhd> c : Sec (Q p G) (EQ G q) (EQ G q) \<Phi>; \<not> LEQ p q\<rbrakk>
       \<Longrightarrow> X \<rhd> While b c : Sec (Q p G) (EQ G q) (EQ G q)
                               (\<lambda> (s,t). EQ G q s t)"
(*<*)
apply (subgoal_tac "\<forall>x. LEQ p (G x) \<longrightarrow> \<not> LEQ (G x) q")
prefer 2 apply (case_tac "\<forall>x. LEQ p (G x) \<longrightarrow> \<not> LEQ (G x) q", assumption) apply clarsimp
  apply (subgoal_tac "LEQ p q", fast)
  apply (erule LAT2, assumption)
apply (rule VDMConseq)
apply (insert VDMWhile)
  apply (erule VDMWhile [of X c "Sec (Q p G) (EQ G q) (EQ G q) \<Phi>" b "(\<lambda> s t . (b,Q p G,s,t):varD)"])
    apply clarsimp apply (erule varDFalse) apply (simp add: Q_def)
    apply clarsimp apply (simp add: Sec_def) apply clarsimp
      apply (rule varDTrue) apply assumption prefer 2 apply assumption
        apply (erule_tac x=s in allE, erule impE, simp add: EQ_def) apply assumption
apply clarsimp
apply (simp add: Sec_def)
apply rule apply (erule varDQ)
apply (rule, clarsimp)
  apply (drule varDQ)  apply (simp add: Q_def EQ_def, clarsimp)
  apply (case_tac "LEQ p (G x)") prefer 2 apply simp
  apply (rotate_tac -1, drule LAT2) apply assumption apply fast
apply (drule varDQ)  apply (simp add: Q_def EQ_def, clarsimp)
  apply (case_tac "LEQ p (G x)") prefer 2 apply simp
  apply (rotate_tac -1, drule LAT2) apply assumption apply fast
done
(*>*)

text{*$\mathit{varD}$ is monotone in the assertion position.*}

(*<*)
text{*As $\mathit{varD}$ does not depend on $\Phi$, the monotonicity
property in this position is trivially fulfilled.*}

lemma varDMonotoneInPhi[rule_format]:
  "\<lbrakk>(b, A, s, t) \<in> varD; \<forall>s t. \<Phi>(s, t) \<longrightarrow> \<Psi>(s, t)\<rbrakk>
  \<Longrightarrow> (b, A, s, t) \<in> varD"
by simp
(*>*)

text{*Finally, the subsumption rule.*}

lemma SUB:
  "\<lbrakk> LEQ p pp; \<forall>x. LEQ (G x) (GG x); \<forall>x. LEQ (HH x) (H x);
     X \<rhd> c : Sec (Q pp HH) (EQ GG q) (EQ HH q) \<Phi>\<rbrakk>
   \<Longrightarrow> X \<rhd> c : Sec (Q p H) (EQ G q) (EQ H q) \<Phi>"
(*<*)
apply (erule VDMConseq)
  apply (simp add: Sec_def EQ_def, clarsimp)
  apply (rule, simp add: Q_def, clarsimp)
    apply (erule_tac x=x in allE, erule mp, clarsimp)
    apply (subgoal_tac "LEQ p (H x)", fast)
    apply (rotate_tac 2, erule_tac x=x in allE)
    apply (erule LAT2)
    apply (erule LAT2, assumption)
  apply (rule, clarsimp)
    apply (erule_tac x=r in allE, erule mp, clarsimp)
    apply (erule_tac x=x in allE, erule mp)
    apply (erule_tac x=x in allE, erule LAT2,assumption)
  apply clarsimp
    apply (erule_tac x=r in allE, erule impE, assumption)
    apply (erule_tac x=x in allE, erule mp)
    apply (erule_tac x=x in allE, erule LAT2, assumption)
done
(*>*)

subsection{*Soundness results*}

(*<*)
definition Theorem3derivProp::"VDMAssn set \<Rightarrow> L \<Rightarrow> CONTEXT \<Rightarrow> IMP \<Rightarrow> CONTEXT \<Rightarrow> L \<Rightarrow> bool"
where "Theorem3derivProp X p G c H q = (\<exists> \<Phi> . X \<rhd> c : (Sec (Q p H) (EQ G q) (EQ H q) \<Phi>))"

lemma Theorem3_derivAux[rule_format]:
"(p,G,c,H):HS \<Longrightarrow> Theorem3derivProp X p G c H q"
apply (erule HS.induct)
apply (simp_all add: Theorem3derivProp_def)
(*Skip*)
  apply (rule, rule SKIP)
(*Assign*)
  apply (rule, rule ASSIGN[simplified]) apply simp
  apply (clarsimp, erule HS_E_eval) apply assumption apply (rule LAT6)
(*COMP*)
apply clarsimp
  apply (rule, rule COMP) apply (assumption, assumption) apply (erule HS_Aux1)
  apply (erule HS_Aux1)
(*IFF*)
  apply clarsimp
  apply (subgoal_tac "(G, b, LUB p t) \<in> HS_B", erule thin_rl)
  prefer 2 apply (erule HS_B_sup) apply (subgoal_tac "LEQ t (LUB t p)", simp add: LAT4) apply (rule LAT3)
  apply (subgoal_tac "\<exists> psi. X \<rhd> Iff b c d : Sec (Q (LUB p t) H) (EQ G q) (EQ H q) psi", clarsimp)
  apply (rule_tac x=psi in exI, erule VDMConseq, clarsimp)
    apply (simp add: Sec_def, clarsimp)
    apply (simp add: Q_def, clarsimp)
    apply (erule_tac x=x in allE, erule mp, clarsimp)
    apply (subgoal_tac "LEQ p (LUB p t)")
    prefer 2 apply (rule LAT3)
    apply (rotate_tac -1, drule LAT2) apply assumption apply simp
  apply (case_tac "\<exists> x . LEQ (LUB p t) (H x) \<and> LEQ (H x) q")
    apply (rule, erule IF_PARALLEL_tp) apply assumption+
    apply (rule, rule IF_DIAGONAL) apply (erule HS_Aux1) apply assumption+
(*If2*)
  apply clarsimp
  apply (case_tac "\<exists> x . LEQ p (H x) \<and> LEQ (H x) q")
    apply (rule, erule IF_PARALLEL_tp) apply assumption+
    apply (rule, rule IF_DIAGONAL) apply (erule HS_Aux1) apply assumption+
(*While*)
  apply clarsimp
  apply (subgoal_tac "(G, b, LUB p t) \<in> HS_B", erule thin_rl)
  prefer 2 apply (erule HS_B_sup) apply (subgoal_tac "LEQ t (LUB t p)", simp add: LAT4) apply (rule LAT3)
  apply (subgoal_tac "\<exists> psi. X \<rhd> While b c : Sec (Q (LUB p t) G) (EQ G q) (EQ G q) psi", clarsimp)
  apply (rule_tac x=psi in exI, erule VDMConseq, clarsimp)
    apply (simp add: Sec_def, clarsimp)
    apply (simp add: Q_def, clarsimp)
    apply (erule_tac x=x in allE, erule mp, clarsimp)
    apply (subgoal_tac "LEQ p (LUB p t)")
    prefer 2 apply (rule LAT3)
    apply (rotate_tac -1, drule LAT2) apply assumption apply simp
  apply (case_tac "LEQ (LUB p t) q")
    apply (rule, rule WHILE_PARALLEL) apply assumption
      apply clarsimp apply (erule HS_B_eval)  apply assumption apply (rule LAT6) apply assumption
  (*OTHER CASE*)
  apply (rule, erule WHILE_DIAGONAL) apply assumption
(*Sub*)
  apply clarsimp
  apply (rule, erule SUB, assumption+)
done
(*>*)

text{*An induction on the typing rules now proves the main theorem
which was called Theorem 4 in~\cite{BeringerHofmann:CSF2007}.*}

theorem Theorem4[rule_format]:
  "(p,G,c,H):HS \<Longrightarrow>
  (\<exists> \<Phi> . X \<rhd> c : (Sec (Q p H) (EQ G q) (EQ H q) \<Phi>))"
(*<*)
by (drule Theorem3_derivAux, simp add: Theorem3derivProp_def)
(*>*)

text{*By the construction of the operator $\mathit{Sec}$ (lemmas
@{text Prop4A} and @{text Prop4A} in Section \ref{sec:ARSsecurity}) we
obtain the soundness property with respect to the oprational
semantics, i.e.~the result stated as Theorem 3.3 in
\cite{HuntSands:POPL2006}.*}

theorem HuntSands33: "(p,G,c,H):HS \<Longrightarrow> secure p G c H"
(*<*)
apply (simp add: secure_def, clarsimp)
apply (drule Theorem4, clarsimp)
apply (rule Prop4A)
apply (rule VDM_Sound_emptyCtxt)  apply fast
done
(*>*)

text {*Both parts of this theorem may also be shown
individually. We factor both proofs by the program logic.*}

lemma Sec1_deriv: "(p,G,c,H):HS \<Longrightarrow> X \<rhd> c : (Q p H)"
(*<*)
apply (drule Theorem4, clarsimp)
apply (erule VDMConseq)
apply (simp add: Sec_def) apply clarsimp
done
(*>*)

(*<*)
lemma
 "(p,G,c,H):HS \<Longrightarrow>
  X \<rhd> c : (\<lambda> s t . \<forall> x . \<not> LEQ p (H x) \<longrightarrow> s x = t x)"
apply (drule Sec1_deriv) apply (erule VDMConseq) apply (simp add: Q_def)
done
(*>*)

theorem HuntSands33_1:"(p,G,c,H):HS \<Longrightarrow> secure1 p G c H"
(*<*)
apply (subgoal_tac "{} \<rhd> c : Q p H")
apply (drule VDM_Sound)
  apply (simp add: Q_def secure1_def valid_def VDM_valid_def Ctxt_valid_def)
apply (erule Sec1_deriv)
done(*>*)

lemma Sec2_deriv:
  "(p,G,c,H):HS \<Longrightarrow>
  (\<exists> A . X \<rhd> c : (Sec (Q p H) (EQ G q) (EQ H q) A))"
(*<*)
by (drule Theorem4 [of p G c H "X" q], clarsimp)
(*>*)

(*<*)
lemma Sec2:
  "(p,G,c,H):HS \<Longrightarrow>
   (\<exists> \<Phi> . \<Turnstile> c : (Sec (Q p H) (EQ G q) (EQ H q) \<Phi>))"
apply (drule Theorem4 [of p G c H "{}" q], clarsimp)
apply (rule_tac x=\<Phi> in exI, erule VDM_Sound_emptyCtxt)
done
(*>*)

theorem HuntSands33_2: "(p,G,c,H):HS \<Longrightarrow> secure2 q G c H"
(*<*)
apply (subgoal_tac "\<forall> q . ARSsecure (Q p H) (EQ G q) (EQ H q) c")
prefer 2 apply clarsimp
         apply (drule Sec2_deriv[of p G c H "{}"], erule exE)
         apply (rule Prop4A) apply (erule VDM_Sound_emptyCtxt)
apply (insert secureEQUIV [of p G c H]) apply (simp add: secure_def)
done
(*>*)

text{*Again, the call rule is formulated for an arbitrary fixed point
of a monotone transformer.*}

lemma CALL:
  "\<lbrakk> ({B} \<union> X) \<rhd> body : Sec A R S (\<phi>(FIX \<phi>));
      Monotone \<phi>; B = Sec A R S (FIX \<phi>) \<rbrakk>
   \<Longrightarrow> X \<rhd> Call : B"
(*<*)
apply (rule VDMCall)
apply (subgoal_tac "\<phi> (FIX \<phi>) = FIX \<phi>", clarsimp)
apply (erule Fix_lemma)
done
(*>*)

(*<*)
text{*Monotonicity lemmas for the operators occurring in the derived proof rules.*}
lemma SkipMonotone:"Monotone (\<lambda> T (s,t). EQ G p s t)"
by (simp add: Monotone_def)

lemma AssignMonotone:"Monotone (\<lambda> T (s,t). \<exists>r. s = update r x (evalE e r) \<and> EQ G p r t)"
by (simp add: Monotone_def)

lemma CompMonotone: "Monotone (\<lambda> T (s,t). \<exists> r. A r t \<and> (\<forall>w. EQ K q r w \<longrightarrow> B s w))"
by (simp add: Monotone_def)

lemma IfPMonotone1: "Monotone (\<lambda> T (s,t). (evalB b t \<longrightarrow> T(s,t)) \<and> (\<not> evalB b t \<longrightarrow> B (s,t)))"
by (simp add: Monotone_def)

lemma IfPMonotone2: "Monotone (\<lambda> T (s,t). (evalB b t \<longrightarrow> A(s,t)) \<and> (\<not> evalB b t \<longrightarrow> T (s,t)))"
by (simp add: Monotone_def)

lemma IfDMonotone:"Monotone (\<lambda> T (s,t). EQ G p s t)"
by (simp add: Monotone_def)

lemma WhileDMonotone: "Monotone (\<lambda> T (s,t). EQ G q s t)"
by (simp add: Monotone_def)

lemma SubMonotone: "Monotone (\<lambda>T. T)"
by (simp add: Monotone_def)
(*>*)

text{*As in Section \ref{sec:BaseLineNI}, we define a formal derivation system
comprising all derived rules and show that all derivable judgements
are of the for $\mathit{Sec}(\Phi)$ for some monotone $\Phi$.*}

inductive_set Deriv:: "(VDMAssn set \<times> IMP \<times> VDMAssn) set"
where
D_SKIP:
  "\<Omega> = (\<lambda> (s,t). EQ G q s t)
 \<Longrightarrow> (X, Skip, Sec (Q p H) (EQ G q) (EQ G q) \<Omega>) : Deriv"

| D_ASSIGN:
  "\<lbrakk>H = upd G x (LUB p t);
    \<forall> s ss . EQ G t s ss \<longrightarrow> evalE e s = evalE e ss;
    \<Omega> = (\<lambda> (s, t) . \<exists> r . s = update r x (evalE e r) \<and> EQ G q r t)\<rbrakk>
\<Longrightarrow> (X, Assign x e, Sec (Q p H) (EQ G q) (EQ H q) \<Omega>) : Deriv"

| D_COMP:
  "\<lbrakk> (X, c, Sec (Q p K) (EQ G q) (EQ K q) \<Phi>) : Deriv;
     (X, d, Sec (Q p H) (EQ K q) (EQ H q) \<Psi>) : Deriv;
    \<forall> x . LEQ (G x) (K x) \<or> LEQ p (K x);
    \<forall> x . LEQ (K x) (H x) \<or> LEQ p (H x);
    \<Omega> = (\<lambda> (x, y) . \<exists> z . \<Phi>(z,y) \<and> (\<forall> w . EQ K q z w \<longrightarrow> \<Psi>(x,w)))\<rbrakk>
 \<Longrightarrow> (X, Comp c d, Sec (Q p H) (EQ G q) (EQ H q) \<Omega>) : Deriv"

| D_IF_PARALLEL:
  "\<lbrakk> \<forall> s ss . EQ G p s ss \<longrightarrow> evalB b s = evalB b ss;
     \<forall> x. LEQ (G x) (H x) \<or> LEQ p (H x);
     \<exists> x . LEQ p (H x) \<and> LEQ (H x) q;
     (X, c, Sec (Q p H) (EQ G q) (EQ H q) \<Phi>) : Deriv;
     (X, d, Sec (Q p H) (EQ G q) (EQ H q) \<Psi>) : Deriv;
     \<Omega> = (\<lambda> (r, u) . (evalB b u \<longrightarrow> \<Phi>(r,u)) \<and>
                      ( (\<not> evalB b u) \<longrightarrow> \<Psi>(r,u)))\<rbrakk>
  \<Longrightarrow> (X, Iff b c d, Sec (Q p H) (EQ G q) (EQ H q) \<Omega>) : Deriv"

| D_IF_DIAGONAL:
  "\<lbrakk> \<forall>x. LEQ (G x) (H x) \<or> LEQ p (H x);
     \<not> (\<exists>x. LEQ p (H x) \<and> LEQ (H x) q);
     (X, c, Sec (Q p H) (EQ G q) (EQ H q) \<Phi>) : Deriv;
     (X, d, Sec (Q p H) (EQ G q) (EQ H q) \<Psi>) : Deriv;
     \<Omega> = (\<lambda> (s,t) . EQ H q s t)\<rbrakk>
   \<Longrightarrow> (X, Iff b c d, Sec (Q p H) (EQ G q) (EQ H q) \<Omega>) : Deriv"

| D_WHILE_PARALLEL:
 "\<lbrakk> (X, c, Sec (Q p G) (EQ G q) (EQ G q) \<Phi>):Deriv;
    \<forall> s ss . EQ G p s ss \<longrightarrow> evalB b s = evalB b ss; LEQ p q;
    \<Omega> = (\<lambda> (s,t) . (b,EQ G q,\<Phi>,s,t):var)\<rbrakk>
   \<Longrightarrow> (X, While b c, Sec (Q p G) (EQ G q) (EQ G q) \<Omega>):Deriv"

| D_WHILE_DIAGONAL:
 "\<lbrakk>(X, c, Sec (Q p G) (EQ G q) (EQ G q) \<Phi>) : Deriv; \<not> LEQ p q;
   \<Omega> = (\<lambda> (s,t) . EQ G q s t)\<rbrakk>
 \<Longrightarrow> (X, While b c, Sec (Q p G) (EQ G q) (EQ G q) \<Omega>) : Deriv"

| D_SUB:
  "\<lbrakk> LEQ p pp; \<forall>x. LEQ (G x) (GG x); \<forall>x. LEQ (HH x) (H x);
     (X, c, Sec (Q pp HH) (EQ GG q) (EQ HH q) \<Phi>) : Deriv\<rbrakk>
   \<Longrightarrow> (X, c, Sec (Q p H) (EQ G q) (EQ H q) \<Phi>) :Deriv"

| D_CALL:
  "({A} \<union> X,body,A): Deriv \<Longrightarrow> (X,Call,A) : Deriv"

(*<*)
definition DProp :: "VDMAssn \<Rightarrow> bool"
where "DProp B = (\<exists> A R S \<phi> . B =  Sec A R S (\<phi> (FIX \<phi>)) \<and> Monotone \<phi>)"

lemma DerivProp_Aux: "(X,c,A):Deriv \<Longrightarrow> DProp A"
apply (erule Deriv.induct)
apply (simp_all add: DProp_def)
apply (rule_tac x="Q p H" in exI,
       rule_tac x="EQ G q" in exI,
       rule_tac x="EQ G q" in exI)
       apply rule apply rule
       apply simp
       apply (simp add: Monotone_def)
apply (rule_tac x="(Q p (upd G x (LUB p t)))" in exI,
       rule_tac x="EQ G q" in exI,
       rule_tac x="(EQ (upd G x (LUB p t)) q)" in exI)
       apply rule apply rule
       apply simp
       apply (simp add: Monotone_def)
apply clarsimp
apply (rule_tac x="Q p H" in exI,
       rule_tac x="EQ G q" in exI,
       rule_tac x="EQ H q" in exI)
       apply rule apply rule
       apply simp
       apply (simp add: Monotone_def)
apply clarsimp
apply (rule_tac x="Q p H" in exI,
       rule_tac x="EQ G q" in exI,
       rule_tac x="EQ H q" in exI)
       apply rule apply rule apply simp
       apply (simp add: Monotone_def)
apply clarsimp
apply (rule_tac x="Q p H" in exI,
       rule_tac x="EQ G q" in exI,
       rule_tac x="EQ H q" in exI)
       apply rule apply rule
       apply simp
       apply (simp add: Monotone_def)
apply clarsimp
apply (rule_tac x="Q p G" in exI,
       rule_tac x="EQ G q" in exI,
       rule_tac x="EQ G q" in exI)
       apply rule apply rule
       apply simp
       apply (simp add: Monotone_def)
apply clarsimp
apply (rule_tac x="Q p G" in exI,
       rule_tac x="EQ G q" in exI,
       rule_tac x="EQ G q" in exI)
       apply rule apply rule
       apply simp
       apply (simp add: Monotone_def)
apply clarsimp
apply (rule_tac x="Q p H" in exI,
       rule_tac x="EQ G q" in exI,
       rule_tac x="EQ H q" in exI)
       apply rule apply rule apply simp
       apply (simp add: Monotone_def)
done
(*>*)

lemma DerivMono:
 "(X,c,B):Deriv \<Longrightarrow>
  \<exists> A R S \<phi> . B =  Sec A R S (\<phi> (FIX \<phi>)) \<and> Monotone \<phi>"
(*<*)
by (drule DerivProp_Aux, simp add: DProp_def)
(*>*)

text{*Also, the @{text Deriv} is indeed a subsystem of the program
logic.*}

theorem Deriv_derivable: "(X,c,A):Deriv \<Longrightarrow> X \<rhd> c :A"
(*<*)
apply (erule Deriv.induct)
apply clarify apply (rule SKIP)
apply clarify apply (rule_tac t=t in ASSIGN) apply simp apply assumption
apply clarify apply (rule COMP) apply assumption apply assumption apply assumption apply assumption
apply clarify apply (rule IF_PARALLEL) apply assumption apply assumption apply (rule_tac x=x in exI, simp) apply assumption apply assumption
apply clarify apply (rule IF_DIAGONAL) apply assumption apply assumption apply assumption apply assumption
apply clarify apply (rule WHILE_PARALLEL_IND) apply assumption apply assumption apply assumption
apply clarify apply (rule WHILE_DIAGONAL) apply assumption apply assumption
apply (rule SUB) apply assumption apply assumption apply assumption apply assumption
apply (frule DerivMono) apply (erule exE)+ apply clarsimp
  apply (subgoal_tac "X \<rhd> Call : Sec Aa R S (FIX \<phi>)")
  prefer 2 apply (rule CALL)
    prefer 2 apply assumption
    apply (simp add: Fix_lemma)
    apply simp
  apply (simp add: Fix_lemma)
done
(*>*)
text{*End of theory HuntSands*}
end


(* Author: Dmitriy Traytel *)

section \<open>Monadic Second-Order Logic Formulas\<close>

(*<*)
theory Formula
imports Pi_Regular_Operators List_More
begin
(*>*)

subsection \<open>Interpretations and Encodings\<close>

type_synonym 'a interp = "'a list \<times> (nat + nat set) list"

abbreviation "enc_atom_bool I n \<equiv> map (\<lambda>x. case x of Inl p \<Rightarrow> n = p | Inr P \<Rightarrow> n \<in> P) I"

abbreviation "enc_atom I n a \<equiv> (a, enc_atom_bool I n)"

subsection \<open>Syntax and Semantics of MSO\<close>

datatype 'a formula =
  FQ 'a nat
| FLess nat nat
| FIn nat nat
| FNot "'a formula"
| FOr "'a formula" "'a formula"
| FAnd "'a formula" "'a formula"
| FExists "'a formula"
| FEXISTS "'a formula"

primrec FOV :: "'a formula \<Rightarrow> nat set" where
  "FOV (FQ a m) = {m}"
| "FOV (FLess m1 m2) = {m1, m2}"
| "FOV (FIn m M) = {m}"
| "FOV (FNot \<phi>) = FOV \<phi>"
| "FOV (FOr \<phi>\<^sub>1 \<phi>\<^sub>2) = FOV \<phi>\<^sub>1 \<union> FOV \<phi>\<^sub>2"
| "FOV (FAnd \<phi>\<^sub>1 \<phi>\<^sub>2) = FOV \<phi>\<^sub>1 \<union> FOV \<phi>\<^sub>2"
| "FOV (FExists \<phi>) = (\<lambda>x. x - 1) ` (FOV \<phi> - {0})"
| "FOV (FEXISTS \<phi>) = (\<lambda>x. x - 1) ` FOV \<phi>"

primrec SOV :: "'a formula \<Rightarrow> nat set" where
  "SOV (FQ a m) = {}"
| "SOV (FLess m1 m2) = {}"
| "SOV (FIn m M) = {M}"
| "SOV (FNot \<phi>) = SOV \<phi>"
| "SOV (FOr \<phi>\<^sub>1 \<phi>\<^sub>2) = SOV \<phi>\<^sub>1 \<union> SOV \<phi>\<^sub>2"
| "SOV (FAnd \<phi>\<^sub>1 \<phi>\<^sub>2) = SOV \<phi>\<^sub>1 \<union> SOV \<phi>\<^sub>2"
| "SOV (FExists \<phi>) = (\<lambda>x. x - 1) ` SOV \<phi>"
| "SOV (FEXISTS \<phi>) = (\<lambda>x. x - 1) ` (SOV \<phi> - {0})"

definition "\<sigma> = (\<lambda>\<Sigma> n. concat (map (\<lambda>bs. map (\<lambda>a. (a, bs)) \<Sigma>) (List.n_lists n [True, False])))"
definition "\<pi> = (\<lambda>(a, bs). (a, tl bs))"
definition "\<epsilon> = (\<lambda>\<Sigma> (a::'a, bs). if a \<in> set \<Sigma> then [(a, True # bs), (a, False # bs)] else [])"

datatype 'a atom =
    Singleton 'a "bool list"
  | AQ nat 'a
  | Arbitrary_Except nat bool
  | Arbitrary_Except2 nat nat
derive linorder atom

fun wf_atom where
  "wf_atom \<Sigma> n (Singleton a bs) = (a \<in> set \<Sigma> \<and> length bs = n)"
| "wf_atom \<Sigma> n (AQ m a) = (a \<in> set \<Sigma> \<and> m < n)"
| "wf_atom \<Sigma> n (Arbitrary_Except m _) = (m < n)"
| "wf_atom \<Sigma> n (Arbitrary_Except2 m1 m2) = (m1 < n \<and> m2 < n)"

fun lookup where
  "lookup (Singleton a' bs') (a, bs) = (a = a' \<and> bs = bs')"
| "lookup (AQ m a') (a, bs) = (a = a' \<and> bs ! m)"
| "lookup (Arbitrary_Except m b) (_, bs) = (bs ! m = b)"
| "lookup (Arbitrary_Except2 m1 m2) (_, bs) = (bs ! m1 \<and> bs ! m2)"

lemma \<pi>_\<sigma>: "\<pi> ` (set o \<sigma> \<Sigma>) (n + 1) = (set o \<sigma> \<Sigma>) n"
  unfolding \<pi>_def \<sigma>_def set_map[symmetric] o_apply map_concat by auto

locale formula = embed2 "set o (\<sigma> \<Sigma>)" "wf_atom \<Sigma>" \<pi> lookup "\<epsilon> \<Sigma>" "case_prod Singleton"
for \<Sigma> :: "'a :: linorder list" +
assumes nonempty: "\<Sigma> \<noteq> []"
begin

abbreviation "\<Sigma>_product_lists n \<equiv>
   List.maps (\<lambda>bools. map (\<lambda>a. (a, bools)) \<Sigma>) (bool_product_lists n)"

(* Normal form: quantified variables are used in the body *)
primrec pre_wf_formula :: "nat \<Rightarrow> 'a formula \<Rightarrow> bool" where
  "pre_wf_formula n (FQ a m) = (a \<in> set \<Sigma> \<and> m < n)"
| "pre_wf_formula n (FLess m1 m2) = (m1 < n \<and> m2 < n)"
| "pre_wf_formula n (FIn m M) = (m < n \<and> M < n)"
| "pre_wf_formula n (FNot \<phi>) = pre_wf_formula n \<phi>"
| "pre_wf_formula n (FOr \<phi>\<^sub>1 \<phi>\<^sub>2) = (pre_wf_formula n \<phi>\<^sub>1 \<and> pre_wf_formula n \<phi>\<^sub>2)"
| "pre_wf_formula n (FAnd \<phi>\<^sub>1 \<phi>\<^sub>2) = (pre_wf_formula n \<phi>\<^sub>1 \<and> pre_wf_formula n \<phi>\<^sub>2)"
| "pre_wf_formula n (FExists \<phi>) = (pre_wf_formula (n + 1) \<phi> \<and> 0 \<in> FOV \<phi> \<and> 0 \<notin> SOV \<phi>)"
| "pre_wf_formula n (FEXISTS \<phi>) = (pre_wf_formula (n + 1) \<phi> \<and> 0 \<notin> FOV \<phi> \<and> 0 \<in> SOV \<phi>)"

abbreviation "closed \<equiv> pre_wf_formula 0"

definition [simp]: "wf_formula n \<phi> \<equiv> pre_wf_formula n \<phi> \<and> FOV \<phi> \<inter> SOV \<phi> = {}"

lemma max_idx_vars: "pre_wf_formula n \<phi> \<Longrightarrow> \<forall>p \<in> FOV \<phi> \<union> SOV \<phi>. p < n"
  by (induct \<phi> arbitrary: n)
   (auto split: if_split_asm, (metis Un_iff diff_Suc_less less_SucE less_imp_diff_less)+)

lemma finite_FOV: "finite (FOV \<phi>)"
  by (induct \<phi>) (auto split: if_split_asm)

subsection \<open>ENC\<close>

definition valid_ENC :: "nat \<Rightarrow> nat \<Rightarrow> ('a atom) rexp" where
  "valid_ENC n p = (if n = 0 then Full else
    TIMES [
      Star (Atom (Arbitrary_Except p False)),
      Atom (Arbitrary_Except p True),
      Star (Atom (Arbitrary_Except p False))])"

lemma wf_rexp_valid_ENC: "n = 0 \<or> p < n \<Longrightarrow> wf n (valid_ENC n p)"
  unfolding valid_ENC_def by auto

definition ENC :: "nat \<Rightarrow> nat set \<Rightarrow> ('a atom) rexp" where
  "ENC n V = flatten INTERSECT (valid_ENC n ` V)"

lemma wf_rexp_ENC: "\<lbrakk>finite V; n = 0 \<or> (\<forall>v \<in> V. v < n)\<rbrakk> \<Longrightarrow> wf n (ENC n V)"
  unfolding ENC_def
  by (intro iffD2[OF wf_flatten_INTERSECT]) (auto simp: wf_rexp_valid_ENC)

lemma enc_atom_\<sigma>_eq: "i < length w \<Longrightarrow>
 (length I = n \<and> p \<in> set \<Sigma>) \<longleftrightarrow> enc_atom I i p \<in> set (\<sigma> \<Sigma> n)"
  by (auto simp: \<sigma>_def set_n_lists intro!: exI[of _ "enc_atom_bool I i"] imageI)

lemmas enc_atom_\<sigma> = iffD1[OF enc_atom_\<sigma>_eq, OF _ conjI]

lemma enc_atom_bool_take_drop_True:
  "\<lbrakk>r < length I; case I ! r of Inl p' \<Rightarrow> p = p' | Inr P \<Rightarrow> p \<in> P\<rbrakk> \<Longrightarrow>
    enc_atom_bool I p = take r (enc_atom_bool I p) @ True # drop (Suc r) (enc_atom_bool I p)"
  by (auto intro: trans[OF id_take_nth_drop])

lemma enc_atom_bool_take_drop_True2:
  "\<lbrakk>r < length I; case I ! r of Inl p' \<Rightarrow> p = p' | Inr P \<Rightarrow> p \<in> P;
    s < length I; case I ! s of Inl p' \<Rightarrow> p = p' | Inr P \<Rightarrow> p \<in> P; r < s\<rbrakk> \<Longrightarrow>
    enc_atom_bool I p = take r (enc_atom_bool I p) @ True #
      take (s - Suc r) (drop (Suc r) (enc_atom_bool I p)) @ True #
      drop (Suc s) (enc_atom_bool I p)"
  using id_take_nth_drop[of r "enc_atom_bool I p"]
      id_take_nth_drop[of "s - r - 1" "drop (Suc r) (enc_atom_bool I p)"]
  by auto

lemma enc_atom_bool_take_drop_False:
  "\<lbrakk>r < length I; case I ! r of Inl p' \<Rightarrow> p \<noteq> p' | Inr P \<Rightarrow> p \<notin> P\<rbrakk> \<Longrightarrow>
    enc_atom_bool I p = take r (enc_atom_bool I p) @ False # drop (Suc r) (enc_atom_bool I p)"
  by (auto intro: trans[OF id_take_nth_drop] split: sum.splits)

lemma enc_atom_lang_AQ: "\<lbrakk>r < length I;
   case I ! r of Inl p' \<Rightarrow> p = p' | Inr P \<Rightarrow> p \<in> P; length I = n; a \<in> set \<Sigma>\<rbrakk> \<Longrightarrow>
  [enc_atom I p a] \<in> lang n (Atom (AQ r a))"
  unfolding lang.simps
  by (force intro!: enc_atom_bool_take_drop_True
    image_eqI[of _ _ "(\<lambda>J. take r J @ drop (r + 1) J) (enc_atom_bool I p)"]
    simp: \<sigma>_def set_n_lists)

lemma enc_atom_lang_Arbitrary_Except_True: "\<lbrakk>r < length I;
   case I ! r of Inl p' \<Rightarrow> p = p' | Inr P \<Rightarrow> p \<in> P; length I = n; a \<in> set \<Sigma>\<rbrakk> \<Longrightarrow>
  [enc_atom I p a] \<in> lang n (Atom (Arbitrary_Except r True))"
  unfolding lang.simps
  by (force intro!: enc_atom_bool_take_drop_True
    image_eqI[of _ _ "(\<lambda>J. take r J @ drop (r + 1) J) (enc_atom_bool I p)"]
    simp: \<sigma>_def set_n_lists)

lemma enc_atom_lang_Arbitrary_Except2:"\<lbrakk>r < length I; s < length I;
  case I ! r of Inl p' \<Rightarrow> p = p' | Inr P \<Rightarrow> p \<in> P;
  case I ! s of Inl p' \<Rightarrow> p = p' | Inr P \<Rightarrow> p \<in> P; length I = n; a \<in> set \<Sigma>\<rbrakk> \<Longrightarrow>
  [enc_atom I p a] \<in> lang n (Atom (Arbitrary_Except2 r s))"
  unfolding lang.simps
  by (force intro!: enc_atom_bool_take_drop_True2
    simp: set_n_lists \<sigma>_def take_Cons' drop_Cons' numeral_eq_Suc)

lemma enc_atom_lang_Arbitrary_Except_False: "\<lbrakk>r < length I;
  case I ! r of Inl p' \<Rightarrow> p \<noteq> p' | Inr P \<Rightarrow> p \<notin> P; length I = n; a \<in> set \<Sigma>\<rbrakk> \<Longrightarrow>
  [enc_atom I p a] \<in> lang n (Atom (Arbitrary_Except r False))"
  unfolding lang.simps
  by (force intro!: enc_atom_bool_take_drop_False
    image_eqI[of _ _ "(\<lambda>J. take r J @ drop (r + 1) J) (enc_atom_bool I p)"]
    simp: set_n_lists \<sigma>_def split: sum.splits)

lemma AQ_D:
  assumes "v \<in> lang n (Atom (AQ m a))" "m < n" "a \<in> set \<Sigma>"
  shows "\<exists>x. v = [x] \<and> fst x = a \<and> snd x ! m"
  using assms by auto

lemma Arbitrary_ExceptD:
  assumes "v \<in> lang n (Atom (Arbitrary_Except r b))" "r < n"
  shows "\<exists>x. v = [x] \<and> snd x ! r = b"
  using assms by auto

lemma Arbitrary_Except2D:
  assumes "v \<in> lang n (Atom (Arbitrary_Except2 r s))" "r < n" "s < n"
  shows "\<exists>x. v = [x] \<and> snd x ! r \<and> snd x ! s"
  using assms by auto

end

end


theory Outer_Friend_Receiver
  imports
    "Outer_Friend_Receiver_Value_Setup"
    "Bounded_Deducibility_Security.Compositional_Reasoning"
begin

subsubsection \<open>Declassification bound\<close>

(* We verify the following:
   Given an arbitrary but fixed user UID at node AID (who is not an observer) and a set of
   observers at each network node, the observers may learn about the *occurrence* of remote
   friendship actions of UID (because network traffic is assumed to be observable), but they
   learn nothing about the *content* of those actions (who was added or deleted as a friend)
   beyond public knowledge (friendship addition and deletion occur alternatingly),
   except if the action adds or deletes one of the observers themselves as friend.
*)

context OuterFriendReceiver
begin

fun T :: "(state,act,out) trans \<Rightarrow> bool"
where "T trn = False"

text \<open>For each user \<open>uid\<close> at this receiver node \<open>AID'\<close>, the remote friendship updates with
the fixed user \<open>UID\<close> at the issuer node \<open>AID\<close> form an alternating sequence of friending and unfriending.

Note that actions involving remote users who are observers do not produce secret values;
instead, those actions are observable, and the property we verify does not protect their
confidentiality.

Moreover, there is no declassification trigger on the receiver side, so \<^term>\<open>OVal\<close> values
are never produced by receiver nodes, only by the issuer node.\<close>

definition friendsOfUID :: "state \<Rightarrow> userID set" where
  "friendsOfUID s = {uid. (AID,UID) \<in>\<in> recvOuterFriendIDs s uid \<and> uid \<notin> UIDs AID'}"

fun validValSeq :: "value list \<Rightarrow> userID set \<Rightarrow> bool" where
  "validValSeq [] _ = True"
| "validValSeq (FrVal aid uid True # vl) uids \<longleftrightarrow> uid \<notin> uids \<and> aid = AID' \<and> uid \<notin> UIDs AID' \<and> validValSeq vl (insert uid uids)"
| "validValSeq (FrVal aid uid False # vl) uids \<longleftrightarrow> uid \<in> uids \<and> aid = AID' \<and> uid \<notin> UIDs AID' \<and> validValSeq vl (uids - {uid})"
| "validValSeq (OVal ov # vl) uids \<longleftrightarrow> False"

abbreviation "validValSeqFrom vl s \<equiv> validValSeq vl (friendsOfUID s)"

text \<open>Observers may learn about the occurrence of
remote friendship actions (by observing network traffic), but not their content;
remote friendship actions at a receiver node \<open>AID'\<close> can be replaced by different actions
involving different users of that node (who are not observers)
without affecting the observations.\<close>

inductive BC :: "value list \<Rightarrow> value list \<Rightarrow> bool"
where
  BC_Nil[simp,intro]: "BC [] []"
| BC_FrVal[intro]:
    "BC vl vl1 \<Longrightarrow> uid' \<notin> UIDs AID' \<Longrightarrow> BC (FrVal aid uid st # vl) (FrVal AID' uid' st' # vl1)"

definition "B vl vl1 \<equiv> BC vl vl1 \<and> validValSeqFrom vl1 istate"

lemma BC_Nil_Nil: "BC vl vl1 \<Longrightarrow> vl1 = [] \<longleftrightarrow> vl = []"
by (induction rule: BC.induct) auto

lemma BC_id: "validValSeq vl uids \<Longrightarrow> BC vl vl"
by (induction rule: validValSeq.induct) auto

lemma BC_append: "BC vl vl1 \<Longrightarrow> BC vl' vl1' \<Longrightarrow> BC (vl @ vl') (vl1 @ vl1')"
by (induction rule: BC.induct) auto

sublocale BD_Security_IO where
istate = istate and step = step and
\<phi> = \<phi> and f = f and \<gamma> = \<gamma> and g = g and T = T and B = B
done

subsubsection \<open>Unwinding proof\<close>

definition \<Delta>0 :: "state \<Rightarrow> value list \<Rightarrow> state \<Rightarrow> value list \<Rightarrow> bool" where
"\<Delta>0 s vl s1 vl1 \<equiv> BC vl vl1 \<and> eqButUID s s1 \<and> validValSeqFrom vl1 s1"

lemma istate_\<Delta>0:
assumes B: "B vl vl1"
shows "\<Delta>0 istate vl istate vl1"
using assms unfolding \<Delta>0_def B_def
by auto

lemma friendsOfUID_cong:
assumes "recvOuterFriendIDs s = recvOuterFriendIDs s'"
shows "friendsOfUID s = friendsOfUID s'"
using assms unfolding friendsOfUID_def by auto

lemma friendsOfUID_step_not_UID:
assumes "uid \<noteq> UID \<or> aid \<noteq> AID \<or> uid' \<in> UIDs AID'"
shows "friendsOfUID (receiveCreateOFriend s aid sp uid uid') = friendsOfUID s"
and "friendsOfUID (receiveDeleteOFriend s aid sp uid uid') = friendsOfUID s"
using assms unfolding friendsOfUID_def by (auto simp: com_defs)

lemma friendsOfUID_step_Create_UID:
assumes "uid' \<notin> UIDs AID'"
shows "friendsOfUID (receiveCreateOFriend s AID sp UID uid') = insert uid' (friendsOfUID s)"
using assms unfolding friendsOfUID_def by (auto simp: com_defs)

lemma friendsOfUID_step_Delete_UID:
assumes "e_receiveDeleteOFriend s AID sp UID uid'"
and rs: "reach s"
shows "friendsOfUID (receiveDeleteOFriend s AID sp UID uid') = friendsOfUID s - {uid'}"
using assms reach_distinct_friends_reqs(4) unfolding friendsOfUID_def by (auto simp: com_defs)

lemma step_validValSeqFrom:
assumes step: "step s a = (ou, s')"
and rs: "reach s"
and c: "consume (Trans s a ou s') vl vl'" (is "consume ?trn vl vl'")
and vVS: "validValSeqFrom vl s"
shows "validValSeqFrom vl' s'"
proof cases
  assume "\<phi> ?trn"
  moreover then obtain v where "vl = v # vl'" using c by (cases vl, auto simp: consume_def)
  ultimately show ?thesis using assms
    by (elim \<phi>.elims) (auto simp: consume_def friendsOfUID_step_Create_UID friendsOfUID_step_Delete_UID)
next
  assume n\<phi>: "\<not>\<phi> ?trn"
  then have vl': "vl' = vl" using c by (auto simp: consume_def)
  then show ?thesis using vVS step proof (cases a)
    case (Sact sa) then show ?thesis using assms vl' by (cases sa) (auto simp: s_defs cong: friendsOfUID_cong) next
    case (Cact ca) then show ?thesis using assms vl' by (cases ca) (auto simp: c_defs cong: friendsOfUID_cong) next
    case (Dact da) then show ?thesis using assms vl' by (cases da) (auto simp: d_defs cong: friendsOfUID_cong) next
    case (Uact ua) then show ?thesis using assms vl' by (cases ua) (auto simp: u_defs cong: friendsOfUID_cong) next
    case (COMact ca)
      then show ?thesis using assms vl' n\<phi> proof (cases ca)
        case (comReceiveCreateOFriend aid sp uid uid')
          then show ?thesis using COMact assms n\<phi> by (auto simp: friendsOfUID_step_not_UID consume_def)
      next
        case (comReceiveDeleteOFriend aid sp uid uid')
          then show ?thesis using COMact assms n\<phi> by (auto simp: friendsOfUID_step_not_UID consume_def)
      qed (auto simp: com_defs cong: friendsOfUID_cong)
  qed auto
qed

lemma unwind_cont_\<Delta>0: "unwind_cont \<Delta>0 {\<Delta>0}"
proof(rule, simp)
  fix s s1 :: state and vl vl1 :: "value list"
  assume rsT: "reachNT s" and rs1: "reach s1" and \<Delta>0: "\<Delta>0 s vl s1 vl1"
  then have rs: "reach s" and ss1: "eqButUID s s1" and BC: "BC vl vl1"
        and vVS1: "validValSeqFrom vl1 s1"
    using reachNT_reach unfolding \<Delta>0_def by auto
  show "iaction \<Delta>0 s vl s1 vl1 \<or>
        ((vl = [] \<longrightarrow> vl1 = []) \<and> reaction \<Delta>0 s vl s1 vl1)" (is "?iact \<or> (_ \<and> ?react)")
  proof-
    have ?react proof
      fix a :: act and ou :: out and s' :: state and vl'
      let ?trn = "Trans s a ou s'"
      assume step: "step s a = (ou, s')" and T: "\<not> T ?trn" and c: "consume ?trn vl vl'"
      show "match \<Delta>0 s s1 vl1 a ou s' vl' \<or> ignore \<Delta>0 s s1 vl1 a ou s' vl'" (is "?match \<or> ?ignore")
      proof cases
        assume \<phi>: "\<phi> ?trn"
        with BC c have "?match" proof (cases rule: BC.cases)
          case (BC_FrVal vl'' vl1'' uid' aid uid st st')
            then show ?thesis proof (cases st')
              case True
                let ?a1 = "COMact (comReceiveCreateOFriend AID (serverPass s AID) UID uid')"
                let ?ou1 = "outOK"
                let ?s1' = "receiveCreateOFriend s1 AID (serverPass s AID) UID uid'"
                let ?trn1 = "Trans s1 ?a1 ?ou1 ?s1'"
                have c1: "consume ?trn1 vl1 vl1''" and "vl' = vl''" and "f ?trn = FrVal AID' uid st"
                  using \<phi> c BC_FrVal True by (auto elim: \<phi>.elims simp: consume_def)
                moreover then have a: "a = COMact (comReceiveCreateOFriend AID (serverPass s AID) UID uid)
                                     \<or> a = COMact (comReceiveDeleteOFriend AID (serverPass s AID) UID uid)"
                               and ou: "ou = outOK"
                               and IDs: "IDsOK s [] [] [(AID,[])] []"
                               and uid: "uid \<notin> UIDs AID'"
                  using \<phi> step rs by (auto elim!: \<phi>.elims split: prod.splits simp: com_defs)
                moreover have step1: "step s1 ?a1 = (?ou1, ?s1')"
                  using IDs vVS1 BC_FrVal True ss1 by (auto simp: com_defs eqButUID_def friendsOfUID_def)
                moreover then have "validValSeqFrom vl1'' ?s1'"
                  using vVS1 rs1 c1 by (intro step_validValSeqFrom[OF step1]) auto
                moreover have "eqButUID s' ?s1'"
                  using ss1 recvOFriend_eqButUID[OF step rs a uid]
                  using recvOFriend_eqButUID[OF step1 rs1, of "serverPass s AID" uid'] BC_FrVal(4)
                  by (auto intro: eqButUID_sym eqButUID_trans)
                moreover have "\<gamma> ?trn = \<gamma> ?trn1" and "g ?trn = g ?trn1"
                  using BC_FrVal a ou uid by (auto simp: com_defs)
                ultimately show "?match"
                  using BC_FrVal by (intro matchI[of s1 ?a1 ?ou1 ?s1' vl1 vl1'']) (auto simp: \<Delta>0_def)
            next
              case False
                let ?a1 = "COMact (comReceiveDeleteOFriend AID (serverPass s AID) UID uid')"
                let ?ou1 = "outOK"
                let ?s1' = "receiveDeleteOFriend s1 AID (serverPass s AID) UID uid'"
                let ?trn1 = "Trans s1 ?a1 ?ou1 ?s1'"
                have c1: "consume ?trn1 vl1 vl1''" and "vl' = vl''" and "f ?trn = FrVal AID' uid st"
                  using \<phi> c BC_FrVal False by (auto elim: \<phi>.elims simp: consume_def)
                moreover then have a: "a = COMact (comReceiveCreateOFriend AID (serverPass s AID) UID uid)
                                     \<or> a = COMact (comReceiveDeleteOFriend AID (serverPass s AID) UID uid)"
                               and ou: "ou = outOK"
                               and IDs: "IDsOK s [] [] [(AID,[])] []"
                               and uid: "uid \<notin> UIDs AID'"
                  using \<phi> step rs by (auto elim!: \<phi>.elims split: prod.splits simp: com_defs)
                moreover have step1: "step s1 ?a1 = (?ou1, ?s1')"
                  using IDs vVS1 BC_FrVal False ss1 by (auto simp: com_defs eqButUID_def friendsOfUID_def)
                moreover then have "validValSeqFrom vl1'' ?s1'"
                  using vVS1 rs1 c1 by (intro step_validValSeqFrom[OF step1]) auto
                moreover have "eqButUID s' ?s1'"
                  using ss1 recvOFriend_eqButUID[OF step rs a uid]
                  using recvOFriend_eqButUID[OF step1 rs1, of "serverPass s AID" uid'] BC_FrVal(4)
                  by (auto intro: eqButUID_sym eqButUID_trans)
                moreover have "\<gamma> ?trn = \<gamma> ?trn1" and "g ?trn = g ?trn1"
                  using BC_FrVal a ou uid by (auto simp: com_defs)
                ultimately show "?match"
                  using BC_FrVal by (intro matchI[of s1 ?a1 ?ou1 ?s1' vl1 vl1'']) (auto simp: \<Delta>0_def)
            qed
        qed (auto simp: consume_def)
        then show "?match \<or> ?ignore" ..
      next
        assume n\<phi>: "\<not>\<phi> ?trn"
        then have vl': "vl' = vl" using c by (auto simp: consume_def)
        obtain ou1 s1' where step1: "step s1 a = (ou1, s1')" by (cases "step s1 a")
        let ?trn1 = "Trans s1 a ou1 s1'"
        show "?match \<or> ?ignore"
        proof (cases "\<forall>uID'. uID' \<notin> UIDs AID' \<longrightarrow>
                             a \<noteq> COMact (comReceiveCreateOFriend AID (serverPass s1 AID) UID uID') \<and>
                             a \<noteq> COMact (comReceiveDeleteOFriend AID (serverPass s1 AID) UID uID')")
          case True
            then have n\<phi>1: "\<not>\<phi> ?trn1" using step1 by (auto elim!: \<phi>.elims simp: com_defs)
            have "?match" using step1 unfolding vl' proof (intro matchI[of s1 a ou1 s1' vl1 vl1])
              show c1: "consume ?trn1 vl1 vl1" using n\<phi>1 by (auto simp: consume_def)
              show "\<Delta>0 s' vl s1' vl1" using BC unfolding \<Delta>0_def proof (intro conjI)
                show "eqButUID s' s1'" using eqButUID_step[OF ss1 step step1 rs rs1] .
                show "validValSeqFrom vl1 s1'"
                  using c1 rs1 vVS1 by (intro step_validValSeqFrom[OF step1]) auto
              qed auto
              show "\<gamma> ?trn = \<gamma> ?trn1" using ss1 rs rs1 step step1 True n\<phi> n\<phi>1
                by (intro eqButUID_step_\<gamma>) auto
            next
              assume "\<gamma> ?trn"
              then have "ou = ou1" using n\<phi> n\<phi>1 by (intro eqButUID_step_\<gamma>_out[OF ss1 step step1]) auto
              then show "g ?trn = g ?trn1" by (cases a) auto
            qed auto
            then show "?match \<or> ?ignore" ..
        next
          case False
            with n\<phi> have "?ignore"
              using UID_UIDs BC step ss1 vVS1 unfolding vl'
              by (intro ignoreI) (auto simp: \<Delta>0_def split: prod.splits)
            then show "?match \<or> ?ignore" ..
        qed
      qed
    qed
    with BC show ?thesis by (cases rule: BC.cases) auto
  qed
qed

definition Gr where
"Gr =
 {
 (\<Delta>0, {\<Delta>0})
 }"

theorem secure: secure
apply (rule unwind_decomp_secure_graph[of Gr \<Delta>0])
unfolding Gr_def
(* apply (simp, smt insert_subset order_refl) *)
using
istate_\<Delta>0 unwind_cont_\<Delta>0
unfolding Gr_def by (auto intro: unwind_cont_mono)

end

end


(*section {* Verification Component Based on Bi-Semigroups *}*)
theory H_Semigroup
  imports Main GCD

begin

notation times (infixl "\<cdot>" 70)
  and relcomp (infixl ";" 70)

class H_monoid = monoid_mult + plus +
  fixes preo :: "'a \<Rightarrow> 'a \<Rightarrow> bool" (infixl "\<preceq>" 50)
  and star :: "'a \<Rightarrow> 'a" ("_\<^sup>\<star>" [101] 100)
  assumes preo_refl: "x \<preceq> x"
  and preo_trans: "x \<preceq> y \<Longrightarrow> y \<preceq> z \<Longrightarrow> x \<preceq> z"
  and add_isol: "x \<preceq> y \<Longrightarrow> z + x \<preceq> z + y"
  and add_isor: "x \<preceq> y \<Longrightarrow> x + z \<preceq> y + z"
  and mult_isol: "x \<preceq> y \<Longrightarrow> z \<cdot> x \<preceq> z \<cdot> y"
  and mult_isor: "x \<preceq> y \<Longrightarrow> x \<cdot> z \<preceq> y \<cdot> z"
  and star_sim: "y \<cdot> x \<preceq> x \<cdot> y \<Longrightarrow> y \<cdot> x\<^sup>\<star> \<preceq> x\<^sup>\<star> \<cdot> y"

begin

definition "H p x q \<equiv> p \<cdot> x \<preceq> x \<cdot> q"

lemma H_skip: "H p 1 p"
  by (simp add: H_def preo_refl)

lemma H_cons: "p \<preceq> p' \<Longrightarrow> H p' x q' \<Longrightarrow> q' \<preceq> q \<Longrightarrow> H p x q"
  by (meson H_def mult_isol mult_isor preo_trans)

lemma H_seq: " H r y q \<Longrightarrow> H p x r \<Longrightarrow> H p (x \<cdot> y) q"
  by (simp add: H_def, rule preo_trans, drule mult_isor, auto simp: mult_assoc mult_isol)

lemma H_cond:
assumes "\<And>x y. p \<cdot> (x + y) \<preceq> p \<cdot> x + p \<cdot> y" and "\<And>x y. x \<cdot> q + y \<cdot> q \<preceq> (x + y) \<cdot> q"
shows "H p v (p \<cdot> v) \<Longrightarrow> H p w (p \<cdot> w) \<Longrightarrow> H (p \<cdot> v) x q \<Longrightarrow> H (p \<cdot> w) y q \<Longrightarrow> H p (v \<cdot> x + w \<cdot> y) q"
  by (meson H_def assms add_isol add_isor preo_trans H_seq assms)

lemma H_loopi: "H i v (i \<cdot> v) \<Longrightarrow> H i w (i \<cdot> w) \<Longrightarrow> H (i \<cdot> v) x i \<Longrightarrow> p \<preceq> i \<Longrightarrow> i \<cdot> w \<preceq> q \<Longrightarrow> H p ((v \<cdot> x)\<^sup>\<star> \<cdot> w) q"
  by (meson H_cons H_def H_seq star_sim)

end

type_synonym 'a pred = "'a \<Rightarrow> bool"
type_synonym 'a store = "string  \<Rightarrow> 'a"

lemma rel_star_sim_aux: "Y ; X \<subseteq> X ; Y \<Longrightarrow> Y ; X ^^ i \<subseteq> X ^^ i ; Y"
  by (induct i, simp_all, blast)

interpretation rel_hm: H_monoid Id "op ;" "op \<union>" "op \<subseteq>" rtrancl
  by (standard, auto simp: SUP_subset_mono rtrancl_is_UN_relpow relcomp_UNION_distrib relcomp_UNION_distrib2 rel_star_sim_aux)

definition p2r :: "'a pred \<Rightarrow> 'a rel" ("\<lceil>_\<rceil>") where "\<lceil>P\<rceil> = {(s,s) |s. P s}"

lemma p2r_mult_hom [simp]: "\<lceil>P\<rceil> ; \<lceil>Q\<rceil> = \<lceil>\<lambda>s. P s \<and> Q s\<rceil>"
  by (auto simp: p2r_def)

definition gets :: "string \<Rightarrow> ('a store \<Rightarrow> 'a) \<Rightarrow> 'a store rel" ("_ ::= _" [70, 65] 61) where
  "v ::= e = {(s,s (v := e s)) |s. True}"

lemma H_assign: "(\<forall>s. P s \<longrightarrow> Q (s (v := e s))) \<Longrightarrow> rel_hm.H \<lceil>P\<rceil> (v ::= e) \<lceil>Q\<rceil>"
  by (auto simp: rel_hm.H_def p2r_def gets_def)

definition if_then_else :: "'a pred \<Rightarrow> 'a rel \<Rightarrow> 'a rel \<Rightarrow> 'a rel " ("if _ then _ else _ fi" [64,64,64] 63) where
  "if P then X else Y fi = \<lceil>P\<rceil> ; X \<union> \<lceil>\<lambda>s. \<not> P s\<rceil> ; Y"

definition while :: "'a pred \<Rightarrow> 'a rel \<Rightarrow> 'a rel" ("while _ do _ od" [64,64] 63) where
  "while P do X od = (\<lceil>P\<rceil> ; X)\<^sup>* ; \<lceil>\<lambda>s. \<not> P s\<rceil>"

definition while_inv :: "'a pred \<Rightarrow> 'a pred \<Rightarrow> 'a rel \<Rightarrow> 'a rel" ("while _ inv _ do _ od" [64,64,64] 63) where
  "while P inv I do X od = (\<lceil>P\<rceil> ; X)\<^sup>* ; \<lceil>\<lambda>s. \<not> P s\<rceil>"

lemma rel_ref: "rel_hm.H \<lceil>P\<rceil> \<lceil>Q\<rceil> (\<lceil>P\<rceil> ; \<lceil>Q\<rceil>)"
  by (auto simp: rel_hm.H_def p2r_def)

lemma sH_cons: "(\<forall>s. P s \<longrightarrow> P' s) \<Longrightarrow> rel_hm.H \<lceil>P'\<rceil> X \<lceil>Q\<rceil> \<Longrightarrow> (\<forall>s. Q' s \<longrightarrow> Q s) \<Longrightarrow> rel_hm.H \<lceil>P\<rceil> X \<lceil>Q\<rceil>"
  by (rule rel_hm.H_cons, auto simp: p2r_def)

lemma sH_cond: "rel_hm.H (\<lceil>P\<rceil> ; \<lceil>T\<rceil>) X \<lceil>Q\<rceil> \<Longrightarrow> rel_hm.H (\<lceil>P\<rceil> ; \<lceil>\<lambda>s.  \<not> T s\<rceil>) Y \<lceil>Q\<rceil> \<Longrightarrow> rel_hm.H \<lceil>P\<rceil> (if T then X else Y fi) \<lceil>Q\<rceil>"
  by (simp only: if_then_else_def, intro rel_hm.H_cond, auto, (metis p2r_mult_hom rel_ref)+)

lemma sH_whilei: "\<forall>s. P s \<longrightarrow> I s \<Longrightarrow> \<forall>s. I s \<and> \<not> R s \<longrightarrow> Q s \<Longrightarrow> rel_hm.H (\<lceil>I\<rceil>; \<lceil>R\<rceil>) X \<lceil>I\<rceil> \<Longrightarrow> rel_hm.H \<lceil>P\<rceil> (while R inv I do X od) \<lceil>Q\<rceil>"
  by (simp only: while_inv_def, intro rel_hm.H_loopi, auto simp: p2r_def, (metis p2r_def rel_ref)+)

lemma euclid:
  "rel_hm.H \<lceil>\<lambda>s::nat store. s ''x'' = x \<and> s ''y'' = y\<rceil>
   (while (\<lambda>s. s ''y'' \<noteq> 0) inv (\<lambda>s. gcd (s ''x'') (s ''y'') = gcd x y)
    do
     (''z'' ::= (\<lambda>s. s ''y''));
     (''y'' ::= (\<lambda>s. s ''x'' mod s ''y''));
     (''x'' ::= (\<lambda>s. s ''z''))
    od)
   \<lceil>\<lambda>s. s ''x'' = gcd x y\<rceil>"
  apply (rule sH_whilei, simp_all, clarsimp simp: p2r_def, intro rel_hm.H_seq)
  apply (rule H_assign, auto)+
  using gcd_red_nat by auto

end


section \<open>Fixpoint of Converging Program Transformations\<close>

theory Fixpoint
  imports Compiler
begin

context
  fixes
    m :: "'a \<Rightarrow> nat" and
    f :: "'a \<Rightarrow> 'a option"
begin

function fixpoint :: "'a \<Rightarrow> 'a option" where
  "fixpoint x = (
    case f x of
      None \<Rightarrow> None |
      Some x' \<Rightarrow> if m x' < m x then fixpoint x' else Some x'
  )"
by pat_completeness auto
termination
proof (relation "measure m")
  show "wf (measure m)" by auto
next
  fix x x'
  assume "f x = Some x'" and "m x' < m x"
  thus "(x', x) \<in> measure m" by simp
qed

end

lemma fixpoint_to_comp_pow:
  "fixpoint m f x = y \<Longrightarrow> \<exists>n. option_comp_pow f n x = y"
proof (induction x arbitrary: y rule: fixpoint.induct[where f = f and m = m])
  case (1 x)
  show ?case
  proof (cases "f x")
    case None
    then show ?thesis
      using "1.prems"
      by (metis (no_types, lifting) fixpoint.simps option.case_eq_if option_comp_pow.simps(1))
  next
    case (Some a)
    show ?thesis
    proof (cases "m a < m x")
      case True
      hence "fixpoint m f a = y"
        using "1.prems" Some by simp
      then show ?thesis
        using "1.IH"[OF Some True]
        by (metis Some bind.simps(2) old.nat.exhaust option_comp_def option_comp_pow.simps(1,3))
    next
      case False
      then show ?thesis
        using "1.prems" Some
        apply simp
        by (metis option_comp_pow.simps(2))
    qed
  qed
qed

lemma fixpoint_eq_comp_pow:
  "\<exists>n. fixpoint m f x = option_comp_pow f n x"
  by (metis fixpoint_to_comp_pow)

lemma compiler_composition_fixpoint:
  assumes
    "compiler step step final final load load order match compile"
  shows "compiler step step final final load load
    (lexp order\<^sup>+\<^sup>+) (rel_comp_pow match) (fixpoint m compile)"
proof (rule compiler.intro)
  show "compiler_axioms load load (rel_comp_pow match) (fixpoint m compile)"
  proof unfold_locales
    fix p1 p2 s2
    assume "fixpoint m compile p1 = Some p2" and "load p2 s2"
    obtain n where "fixpoint m compile p1 = option_comp_pow compile n p1"
      using fixpoint_eq_comp_pow by metis

    thus "\<exists>s1 i. load p1 s1 \<and> rel_comp_pow match i s1 s2"
      using \<open>fixpoint m compile p1 = Some p2\<close> assms compiler.compile_load compiler_composition_pow
      using \<open>load p2 s2\<close> by fastforce
  qed
qed (auto intro: assms compiler.axioms backward_simulation_pow)

end