Theory OAWN_Convert

(*  Title:       OAWN_Convert.thy
    License:     BSD 2-Clause. See LICENSE.
    Author:      Timothy Bourke
*)

section "Transfer standard invariants into open invariants"

theory OAWN_Convert
imports AWN_SOS_Labels AWN_Invariants
        OAWN_SOS OAWN_Invariants
begin

definition initiali :: "'i ⇒ (('i ⇒ 'g) × 'l) set ⇒ ('g × 'l) set ⇒ bool"
where "initiali i OI CI ≡ ({(σ i, p)|σ p. (σ, p) ∈ OI} = CI)"

lemma initialiI [intro]:
  assumes OICI: "⋀σ p. (σ, p) ∈ OI ⟹ (σ i, p) ∈ CI"
      and CIOI: "⋀ξ p. (ξ, p) ∈ CI ⟹ ∃σ. ξ = σ i ∧ (σ, p) ∈ OI"
    shows "initiali i OI CI"
  unfolding initiali_def
  by (intro set_eqI iffI) (auto elim!: OICI CIOI)

lemma open_from_initialiD [dest]:
  assumes "initiali i OI CI"
      and "(σ, p) ∈ OI"
    shows "∃ξ. σ i = ξ ∧ (ξ, p) ∈ CI"
  using assms unfolding initiali_def by auto

lemma closed_from_initialiD [dest]:
  assumes "initiali i OI CI"
      and "(ξ, p) ∈ CI"
    shows "∃σ. σ i = ξ ∧ (σ, p) ∈ OI"
  using assms unfolding initiali_def by auto

definition
  seql :: "'i ⇒ (('s × 'l) ⇒ bool) ⇒ (('i ⇒ 's) × 'l) ⇒ bool"
where
  "seql i P ≡ (λ(σ, p). P (σ i, p))"

lemma seqlI [intro]:
  "P (fst s i, snd s) ⟹ seql i P s"
  by (clarsimp simp: seql_def)

lemma same_seql [elim]:
  assumes "∀j∈{i}. σ' j = σ j"
      and "seql i P (σ', s)"
    shows "seql i P (σ, s)"
  using assms unfolding seql_def by (clarsimp)

lemma seqlsimp:
  "seql i P (σ, p) = P (σ i, p)"
  unfolding seql_def by simp

lemma other_steps_resp_local [intro!, simp]: "other_steps (other A I) I"
  by (clarsimp elim!: otherE)

lemma seql_onl_swap:
  "seql i (onl Γ P) = onl Γ (seql i P)"
  unfolding seql_def onl_def by simp

lemma oseqp_sos_resp_local_steps [intro!, simp]:
  fixes Γ :: "'p ⇒ ('s, 'm, 'p, 'l) seqp"
  shows "local_steps (oseqp_sos Γ i) {i}"
  proof
    fix σ σ' ζ ζ' :: "nat ⇒ 's" and s a s'
    assume tr: "((σ, s), a, σ', s') ∈ oseqp_sos Γ i"
       and "∀j∈{i}. ζ j = σ j"
    thus "∃ζ'. (∀j∈{i}. ζ' j = σ' j) ∧ ((ζ, s), a, (ζ', s')) ∈ oseqp_sos Γ i"
    proof induction
      fix σ σ' l ms p
      assume "σ' i = σ i"
         and "∀j∈{i}. ζ j = σ j"
      hence "((ζ, {l}broadcast(ms).p), broadcast (ms (σ i)), (σ', p)) ∈ oseqp_sos Γ i"
        by (metis obroadcastT singleton_iff)
      with ‹∀j∈{i}. ζ j = σ j› show "∃ζ'. (∀j∈{i}. ζ' j = σ' j) ∧
            ((ζ, {l}broadcast(ms).p), broadcast (ms (σ i)), (ζ', p)) ∈ oseqp_sos Γ i"
        by blast
    next
      fix σ σ' :: "nat ⇒ 's" and fmsg :: "'m ⇒ 's ⇒ 's" and msg l p
      assume *:  "σ' i = fmsg msg (σ i)"
         and **: "∀j∈{i}. ζ j = σ j"
      hence "∀j∈{i}. (ζ(i := fmsg msg (ζ i))) j = σ' j" by clarsimp
      moreover from * **
        have "((ζ, {l}receive(fmsg).p), receive msg, (ζ(i := fmsg msg (ζ i)), p)) ∈ oseqp_sos Γ i"
        by (metis fun_upd_same oreceiveT)
      ultimately show "∃ζ'. (∀j∈{i}. ζ' j = σ' j) ∧
                            ((ζ, {l}receive(fmsg).p), receive msg, (ζ', p)) ∈ oseqp_sos Γ i"
        by blast
    next
      fix σ' σ l p and fas :: "'s ⇒ 's"
      assume *:  "σ' i = fas (σ i)"
         and **: "∀j∈{i}. ζ j = σ j"
      hence "∀j∈{i}. (ζ(i := fas (ζ i))) j = σ' j" by clarsimp
      moreover from * ** have "((ζ, {l}⟦fas⟧ p), τ, (ζ(i := fas (ζ i)), p)) ∈ oseqp_sos Γ i"
        by (metis fun_upd_same oassignT)
      ultimately show "∃ζ'. (∀j∈{i}. ζ' j = σ' j) ∧ ((ζ, {l}⟦fas⟧ p), τ, (ζ', p)) ∈ oseqp_sos Γ i"
        by blast
    next
      fix g :: "'s ⇒ 's set" and σ σ' l p
      assume *:  "σ' i ∈ g (σ i)"
         and **: "∀j∈{i}. ζ j = σ j"
      hence "∀j∈{i}. (SOME ζ'. ζ' i = σ' i) j = σ' j" by simp (metis (lifting, full_types) some_eq_ex)
      moreover with * ** have "((ζ, {l}⟨g⟩ p), τ, (SOME ζ'. ζ' i = σ' i, p)) ∈ oseqp_sos Γ i"
        by simp (metis oguardT step_seq_tau)
      ultimately show "∃ζ'. (∀j∈{i}. ζ' j = σ' j) ∧ ((ζ, {l}⟨g⟩ p), τ, (ζ', p)) ∈ oseqp_sos Γ i"
        by blast
    next
      fix σ pn a σ' p'
      assume "((σ, Γ pn), a, (σ', p')) ∈ oseqp_sos Γ i"
         and IH: "∀j∈{i}. ζ j = σ j ⟹ ∃ζ'. (∀j∈{i}. ζ' j = σ' j) ∧ ((ζ, Γ pn), a, (ζ', p')) ∈ oseqp_sos Γ i"
         and "∀j∈{i}. ζ j = σ j"
      then obtain ζ' where "∀j∈{i}. ζ' j = σ' j"
                       and "((ζ, Γ pn), a, (ζ', p')) ∈ oseqp_sos Γ i"
        by blast
      thus "∃ζ'. (∀j∈{i}. ζ' j = σ' j) ∧ ((ζ, call(pn)), a, (ζ', p')) ∈ oseqp_sos Γ i"
        by blast
    next
      fix σ p a σ' p' q
      assume "((σ, p), a, (σ', p')) ∈ oseqp_sos Γ i"
         and "∀j∈{i}. ζ j = σ j ⟹ ∃ζ'. (∀j∈{i}. ζ' j = σ' j) ∧ ((ζ, p), a, (ζ', p')) ∈ oseqp_sos Γ i"
         and "∀j∈{i}. ζ j = σ j"
      then obtain ζ' where "∀j∈{i}. ζ' j = σ' j"
                       and "((ζ, p), a, (ζ', p')) ∈ oseqp_sos Γ i"
        by blast
      thus "∃ζ'. (∀j∈{i}. ζ' j = σ' j) ∧ ((ζ, p ⊕ q), a, (ζ', p')) ∈ oseqp_sos Γ i"
        by blast
    next
      fix σ p a σ' q q'
      assume "((σ, q), a, (σ', q')) ∈ oseqp_sos Γ i"
         and "∀j∈{i}. ζ j = σ j ⟹ ∃ζ'. (∀j∈{i}. ζ' j = σ' j) ∧ ((ζ, q), a, (ζ', q')) ∈ oseqp_sos Γ i"
         and "∀j∈{i}. ζ j = σ j"
      then obtain ζ' where "∀j∈{i}. ζ' j = σ' j"
                       and "((ζ, q), a, (ζ', q')) ∈ oseqp_sos Γ i"
        by blast
      thus "∃ζ'. (∀j∈{i}. ζ' j = σ' j) ∧ ((ζ, p ⊕ q), a, (ζ', q')) ∈ oseqp_sos Γ i"
        by blast
    qed (simp_all, (metis ogroupcastT ounicastT onotunicastT osendT odeliverT)+)
  qed

lemma oseqp_sos_subreachable [intro!, simp]:
  assumes "trans OA = oseqp_sos Γ i"
    shows "subreachable OA (other ANY {i}) {i}"
  by rule (clarsimp simp add: assms(1))+

lemma oseq_step_is_seq_step:
    fixes σ :: "ip ⇒ 's"
  assumes "((σ, p), a :: 'm seq_action, (σ', p')) ∈ oseqp_sos Γ i"
      and "σ i = ξ"
    shows "∃ξ'. σ' i = ξ' ∧ ((ξ, p), a, (ξ', p')) ∈ seqp_sos Γ"
  using assms proof induction
    fix σ σ' l ms p
    assume "σ' i = σ i"
       and "σ i = ξ"
    hence "σ' i = ξ" by simp
    have "((ξ, {l}broadcast(ms).p), broadcast (ms ξ), (ξ, p)) ∈ seqp_sos Γ"
      by auto
    with ‹σ i = ξ› and ‹σ' i = ξ› show "∃ξ'. σ' i = ξ'
             ∧ ((ξ, {l}broadcast(ms).p), broadcast (ms (σ i)), (ξ', p)) ∈ seqp_sos Γ"
       by clarsimp
  next
    fix fmsg :: "'m ⇒ 's ⇒ 's" and msg :: 'm and σ' σ l p
    assume "σ' i = fmsg msg (σ i)"
       and "σ i = ξ"
    have "((ξ, {l}receive(fmsg).p), receive msg, (fmsg msg ξ, p)) ∈ seqp_sos Γ"
      by auto
    with ‹σ' i = fmsg msg (σ i)› and ‹σ i = ξ›
      show "∃ξ'. σ' i = ξ' ∧ ((ξ, {l}receive(fmsg).p), receive msg, (ξ', p)) ∈ seqp_sos Γ"
         by clarsimp
  qed (simp_all, (metis assignT choiceT1 choiceT2 groupcastT guardT
                        callT unicastT notunicastT sendT deliverT step_seq_tau)+)

lemma reachable_oseq_seqp_sos:
  assumes "(σ, p) ∈ reachable OA I"
      and "initiali i (init OA) (init A)"
      and spo: "trans OA = oseqp_sos Γ i"
      and sp: "trans A = seqp_sos Γ"
      shows "∃ξ. σ i = ξ ∧ (ξ, p) ∈ reachable A I"
  using assms(1) proof (induction rule: reachable_pair_induct)
    fix σ p
    assume "(σ, p) ∈ init OA"
    with ‹initiali i (init OA) (init A)› obtain ξ where "σ i = ξ"
                                                    and "(ξ, p) ∈ init A"
      by auto
    from ‹(ξ, p) ∈ init A› have "(ξ, p) ∈ reachable A I" ..
    with ‹σ i = ξ› show "∃ξ. σ i = ξ ∧ (ξ, p) ∈ reachable A I"
      by auto
  next
    fix σ p σ' p' a
    assume "(σ, p) ∈ reachable OA I"
       and IH: "∃ξ. σ i = ξ ∧ (ξ, p) ∈ reachable A I"
       and otr: "((σ, p), a, (σ', p')) ∈ trans OA"
       and "I a"
    from IH obtain ξ where "σ i = ξ"
                       and cr: "(ξ, p) ∈ reachable A I"
      by clarsimp
    from otr and spo have "((σ, p), a, (σ', p')) ∈ oseqp_sos Γ i" by simp
    with ‹σ i = ξ› obtain ξ' where "σ' i = ξ'"
                               and "((ξ, p), a, (ξ', p')) ∈ seqp_sos Γ"
        by (auto dest!: oseq_step_is_seq_step)
    from this(2) and sp have ctr: "((ξ, p), a, (ξ', p')) ∈ trans A" by simp
    from ‹(ξ, p) ∈ reachable A I› and ctr and ‹I a›
      have "(ξ', p') ∈ reachable A I" ..
    with ‹σ' i = ξ'› show "∃ξ. σ' i = ξ ∧ (ξ, p') ∈ reachable A I"
      by blast
  qed

lemma reachable_oseq_seqp_sos':
  assumes "s ∈ reachable OA I"
      and "initiali i (init OA) (init A)"
      and "trans OA = oseqp_sos Γ i"
      and "trans A = seqp_sos Γ"
    shows "∃ξ. (fst s) i = ξ ∧ (ξ, snd s) ∈ reachable A I"
  using assms
  by - (cases s, auto dest: reachable_oseq_seqp_sos)

text ‹
  Any invariant shown in the (simpler) closed semantics can be transferred to an invariant in
  the open semantics.
›

theorem open_seq_invariant [intro]:
  assumes "A ⊫ (I →) P"
      and "initiali i (init OA) (init A)"
      and spo: "trans OA = oseqp_sos Γ i"
      and sp: "trans A = seqp_sos Γ"
    shows "OA ⊨ (act I, other ANY {i} →) (seql i P)"
  proof -
    have "OA ⊫ (I →) (seql i P)"
      proof (rule invariant_arbitraryI)
        fix s                                      
        assume "s ∈ reachable OA I"
        with ‹initiali i (init OA) (init A)› obtain ξ where "(fst s) i = ξ"
                                                        and "(ξ, snd s) ∈ reachable A I"
          by (auto dest: reachable_oseq_seqp_sos' [OF _ _ spo sp])
        with ‹A ⊫ (I →) P› have "P (ξ, snd s)" by auto
        with ‹(fst s) i = ξ› show "seql i P s" by auto
      qed
    moreover from spo have "subreachable OA (other ANY {i}) {i}" ..
    ultimately show ?thesis
    proof (rule open_closed_invariant)
      fix σ σ' s
      assume "∀j∈{i}. σ' j = σ j"
         and "seql i P (σ', s)"
      thus "seql i P (σ, s)" ..
    qed
  qed

definition
  seqll :: "'i ⇒ ((('s × 'l) × 'a × ('s × 'l)) ⇒ bool)
               ⇒ ((('i ⇒ 's) × 'l) × 'a × (('i ⇒ 's) × 'l)) ⇒ bool"
where
  "seqll i P ≡ (λ((σ, p), a, (σ', p')). P ((σ i, p), a, (σ' i, p')))"

lemma same_seqll [elim]:
  assumes "∀j∈{i}. σ1' j = σ1 j"
      and "∀j∈{i}. σ2' j = σ2 j"
      and "seqll i P ((σ1', s), a, (σ2', s'))"
    shows "seqll i P ((σ1,  s), a, (σ2,  s'))"
  using assms unfolding seqll_def by (clarsimp)

lemma seqllI [intro!]:
  assumes "P ((σ i, p), a, (σ' i, p'))"
    shows "seqll i P ((σ, p), a, (σ', p'))"
  using assms unfolding seqll_def by simp

lemma seqllD [dest]:
  assumes "seqll i P ((σ, p), a, (σ', p'))"
    shows "P ((σ i, p), a, (σ' i, p'))"
  using assms unfolding seqll_def by simp

lemma seqllsimp:
  "seqll i P ((σ, p), a, (σ', p')) = P ((σ i, p), a, (σ' i, p'))"
  unfolding seqll_def by simp

lemma seqll_onll_swap:
  "seqll i (onll Γ P) = onll Γ (seqll i P)"
  unfolding seqll_def onll_def by simp

theorem open_seq_step_invariant [intro]:
  assumes "A ⊫A (I →) P"
      and "initiali i (init OA) (init A)"
      and spo: "trans OA = oseqp_sos Γ i"
      and sp: "trans A = seqp_sos Γ"
    shows "OA ⊨A (act I, other ANY {i} →) (seqll i P)"
  proof -
    have "OA ⊫A (I →) (seqll i P)"
    proof (rule step_invariant_arbitraryI)
      fix σ p a σ' p'
      assume or: "(σ, p) ∈ reachable OA I"
         and otr: "((σ, p), a, (σ', p')) ∈ trans OA"
         and "I a"
      from or ‹initiali i (init OA) (init A)› spo sp obtain ξ where "σ i = ξ"
                                                             and cr: "(ξ, p) ∈ reachable A I"
        by - (drule(3) reachable_oseq_seqp_sos', auto)
      from otr and spo have "((σ, p), a, (σ', p')) ∈ oseqp_sos Γ i" by simp
      with ‹σ i = ξ› obtain ξ' where "σ' i = ξ'"
                                 and ctr: "((ξ, p), a, (ξ', p')) ∈ seqp_sos Γ"
        by (auto dest!: oseq_step_is_seq_step)
      with sp have "((ξ, p), a, (ξ', p')) ∈ trans A" by simp
      with ‹A ⊫A (I →) P› cr have "P ((ξ, p), a, (ξ', p'))" using ‹I a› ..
      with ‹σ i = ξ› and ‹σ' i = ξ'› have "P ((σ i, p), a, (σ' i, p'))" by simp
      thus "seqll i P ((σ, p), a, (σ', p'))" ..
    qed
    moreover from spo have "local_steps (trans OA) {i}" by simp
    moreover have "other_steps (other ANY {i}) {i}" ..
    ultimately show ?thesis
    proof (rule open_closed_step_invariant)
      fix σ ζ a σ' ζ' s s'
      assume "∀j∈{i}. σ j = ζ j"
         and "∀j∈{i}. σ' j = ζ' j"
         and "seqll i P ((σ, s), a, (σ', s'))"
        thus "seqll i P ((ζ, s), a, (ζ', s'))" ..
    qed
  qed

end