(*  Title:      IL_AF_Exec_Stream.thy
    Date:       Nov 2007
    Author:     David Trachtenherz
*)

section \<open>\textsc{AutoFocus} message stream processing and temporal logic on intervals\<close>

theory IL_AF_Stream_Exec
imports Main IL_AF_Stream AF_Stream_Exec
begin

subsection \<open>Correlation between Pre/Post-Conditions for \<open>f_Exec_Comp_Stream\<close> and \<open>f_Exec_Comp_Stream_Init\<close>\<close>

lemma i_Exec_Stream_Pre_Post1_iAll: "
  \<lbrakk> result = i_Exec_Comp_Stream trans_fun input c;
    \<forall>x_n c_n. P1 x_n \<and> P2 c_n \<longrightarrow> Q (trans_fun x_n c_n) \<rbrakk> \<Longrightarrow>
  \<box> t I. (P1 (input t) \<and> P2 (result\<^bsup>\<leftarrow> c\<^esup> t) \<longrightarrow> Q (result t))"
by (simp add: i_Exec_Stream_Pre_Post1)

text \<open>Direct relation between input and result after transition\<close>
lemma i_Exec_Stream_Pre_Post2_iAll: "
  \<lbrakk> result = i_Exec_Comp_Stream trans_fun input c;
    \<forall>x_n c_n. P c_n \<longrightarrow> Q x_n (trans_fun x_n c_n) \<rbrakk> \<Longrightarrow>
  \<box> t I. P (result\<^bsup>\<leftarrow> c\<^esup> t) \<longrightarrow> Q (input t) (result t)"
by (simp add: i_Exec_Stream_Pre_Post2)

lemma i_Exec_Stream_Pre_Post3_iAll_iNext: "
  \<lbrakk> result = i_Exec_Comp_Stream trans_fun input c;
    \<forall>x_n c_n. P c_n \<longrightarrow> Q x_n (trans_fun x_n c_n);
    \<forall>t\<in>I. inext t I' = Suc t \<rbrakk> \<Longrightarrow>
  \<box> t I. P (result t) \<longrightarrow> (\<circle> t1 t I'. Q (input t1) (result t1))"
by (rule iallI, simp add: iNext_def i_Exec_Stream_Pre_Post2_Suc)

lemma i_Exec_Stream_Init_Pre_Post1_iAll_iNext: "
  \<lbrakk> result = i_Exec_Comp_Stream_Init trans_fun input c;
    \<forall>x_n c_n. P1 x_n \<and> P2 c_n \<longrightarrow> Q (trans_fun x_n c_n);
    \<forall>t\<in>I. inext t I' = Suc t \<rbrakk> \<Longrightarrow>
  \<box> t I. (P1 (input t) \<and> P2 (result t) \<longrightarrow> (\<circle> t1 t I'. Q (result t1)))"
by (rule iallI, simp add: iNext_def i_Exec_Stream_Init_Pre_Post1)

text \<open>Direct relation between input and state before transition\<close>
lemma i_Exec_Stream_Init_Pre_Post2_iAll_iNext: "
  \<lbrakk> result = i_Exec_Comp_Stream_Init trans_fun input c;
    \<forall>x_n c_n. P x_n c_n \<longrightarrow> Q (trans_fun x_n c_n);
    \<forall>t\<in>I. inext t I' = Suc t \<rbrakk> \<Longrightarrow>
  \<box> t I. (P (input t) (result t) \<longrightarrow> (\<circle> t1 t I'. Q (result t1)))"
by (rule iallI, simp add: iNext_def i_Exec_Stream_Init_Pre_Post2)

text \<open>Relation between input and output\<close>
lemma i_Exec_Stream_Init_Pre_Post3_iAll_iNext: "
  \<lbrakk> result = i_Exec_Comp_Stream_Init trans_fun input c;
    \<forall>x_n c_n. P c_n \<longrightarrow> Q x_n (trans_fun x_n c_n);
    \<forall>t\<in>I. inext t I' = Suc t \<rbrakk> \<Longrightarrow>
  \<box> t I. (P (result t) \<longrightarrow> (\<circle> t1 t I'. Q (input\<^bsup>\<leftarrow> \<NoMsg>\<^esup> t1) (result t1)))"
apply (rule iallI, unfold iNext_def)
apply (simp add: ilist_Previous_Suc i_Exec_Stream_Init_nth_Suc_eq_i_Exec_Stream_nth i_Exec_Stream_Previous_i_Exec_Stream_Init)
apply (blast dest: i_Exec_Stream_Pre_Post2_iAll[OF refl])
done

subsection \<open>\<open>i_Exec_Comp_Stream_Acc_Output\<close> and temporal operators with bounded intervals.\<close>

text \<open>Temporal relation between uncompressed and compressed output of accelerated components.\<close>

lemma i_Exec_Comp_Stream_Acc_Output__eq_NoMsg_iAll_conv: "
  0 < k \<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = \<NoMsg>) =
  (\<box> t1 [t * k\<dots>,k - Suc 0]. (output_fun \<circ> i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c) t1 = \<NoMsg>)"
by (simp add: i_Exec_Comp_Stream_Acc_Output_def i_shrink_eq_NoMsg_iAll_conv)

lemma i_Exec_Comp_Stream_Acc_Output__eq_NoMsg_iAll_conv2: "
  0 < k \<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = \<NoMsg>) =
  (\<box> t1 [\<dots>k - Suc 0] \<oplus> (t * k). (output_fun \<circ> i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c) t1 = \<NoMsg>)"
by (simp add: iT_add i_Exec_Comp_Stream_Acc_Output__eq_NoMsg_iAll_conv)

lemma i_Exec_Comp_Stream_Acc_Output__Init__eq_NoMsg_iAll_conv: "
  0 < k \<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = \<NoMsg>) =
  (\<box> t1 [Suc (t * k)\<dots>,k - Suc 0]. (output_fun \<circ> i_Exec_Comp_Stream_Init trans_fun (input \<odot>\<^sub>i k) c) t1 = \<NoMsg>)"
apply (unfold i_Exec_Comp_Stream_Acc_Output_def)
apply (simp add: i_shrink_eq_NoMsg_iAll_conv i_Exec_Stream_Init_eq_i_Exec_Stream_Cons)
apply (rule_tac t="[Suc (t * k)\<dots>,k - Suc 0]" and s="[t * k\<dots>,k - Suc 0] \<oplus> 1" in subst)
 apply (simp add: iIN_add)
apply (simp add: iT_Plus_iAll_conv)
done

lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_iEx_iAll_cut_greater_conv: "
  \<lbrakk> 0 < k; m \<noteq> \<NoMsg>; s = (output_fun \<circ> i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk> \<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = m) =
  (\<diamond> t1 [t * k\<dots>,k - Suc 0]. (s t1 = m \<and>
    (\<box> t2 [t * k\<dots>,k - Suc 0] \<down>> t1 . s t2 = \<NoMsg>)))"
by (simp add: i_Exec_Comp_Stream_Acc_Output_def i_shrink_eq_Msg_iEx_iAll_cut_greater_conv)

lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_iEx_iAll_cut_greater_conv2: "
  \<lbrakk> 0 < k; m \<noteq> \<NoMsg>; s = (output_fun \<circ> i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk> \<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = m) =
  (\<diamond> t1 [\<dots>k - Suc 0] \<oplus> (t * k). (s t1 = m \<and>
    (\<box> t2 ([\<dots>k - Suc 0] \<oplus> (t * k)) \<down>> t1 . s t2 = \<NoMsg>)))"
by (simp add: i_Exec_Comp_Stream_Acc_Output_def i_shrink_eq_Msg_iEx_iAll_cut_greater_conv2)

lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_iSince_conv: "
  \<lbrakk> 0 < k; m \<noteq> \<NoMsg>; s = (output_fun \<circ> i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk> \<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = m) =
  (s t2 = \<NoMsg>. t2 \<S> t1 [t * k\<dots>,k - Suc 0]. s t1 = m)"
by (simp add: i_Exec_Comp_Stream_Acc_Output_def i_shrink_eq_Msg_iSince_conv)
lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_iSince_conv2: "
  \<lbrakk> 0 < k; m \<noteq> \<NoMsg>; s = (output_fun \<circ> i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk> \<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = m) =
  (s t2 = \<NoMsg>. t2 \<S> t1 [\<dots>k - Suc 0] \<oplus> (t * k). s t1 = m)"
by (simp add: i_Exec_Comp_Stream_Acc_Output__eq_Msg_iSince_conv iT_add)

lemma i_Exec_Comp_Stream_Acc_Output__Init__eq_Msg_iSince_conv: "
  \<lbrakk> 0 < k; m \<noteq> \<NoMsg>; s = (output_fun \<circ> i_Exec_Comp_Stream_Init trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk> \<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = m) =
  (s t2 = \<NoMsg>. t2 \<S> t1 [Suc (t * k)\<dots>,k - Suc 0]. s t1 = m)"
apply (unfold i_Exec_Comp_Stream_Acc_Output_def)
apply (simp add: i_shrink_eq_Msg_iSince_conv i_Exec_Stream_Init_eq_i_Exec_Stream_Cons)
apply (rule_tac t="[Suc (t * k)\<dots>,k - Suc 0]" and s="[t * k\<dots>,k - Suc 0] \<oplus> 1" in subst)
 apply (simp add: iIN_add)
apply (simp add: iT_Plus_iSince_conv)
done

lemma i_Exec_Comp_Stream_Acc_Output__eq_iAll_iSince_conv: "
  \<lbrakk> 0 < k; s = (output_fun \<circ> i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk> \<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = m) =
  ((m = \<NoMsg> \<longrightarrow> (\<box> t1 [t * k\<dots>,k - Suc 0]. s t1 = \<NoMsg>)) \<and>
  ((m \<noteq> \<NoMsg> \<longrightarrow> (s t2 = \<NoMsg>. t2 \<S> t1 [t * k\<dots>,k - Suc 0]. s t1 = m))))"
apply (case_tac "m = \<NoMsg>")
apply (simp add: i_Exec_Comp_Stream_Acc_Output__eq_NoMsg_iAll_conv)
apply (simp add: i_Exec_Comp_Stream_Acc_Output__eq_Msg_iSince_conv)
done

lemma i_Exec_Comp_Stream_Acc_Output__eq_iAll_iSince_conv2: "
  \<lbrakk> 0 < k; s = (output_fun \<circ> i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk> \<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = m) =
  ((m = \<NoMsg> \<longrightarrow> (\<box> t1 [\<dots>k - Suc 0] \<oplus> (t * k). s t1 = \<NoMsg>)) \<and>
  ((m \<noteq> \<NoMsg> \<longrightarrow> (s t2 = \<NoMsg>. t2 \<S> t1 [\<dots>k - Suc 0] \<oplus> (t * k). s t1 = m))))"
by (simp add: i_Exec_Comp_Stream_Acc_Output__eq_iAll_iSince_conv iT_add)

subsection \<open>\<open>i_Exec_Comp_Stream_Acc_Output\<close> and temporal operators with unbounded intervals and start/finish events.\<close>

lemma i_Exec_Comp_Stream_Acc_Output__eq_NoMsg_iAll_start_event_conv: "
  \<lbrakk> 0 < k; \<And> t. event t = (t mod k = 0); t0 = t * k;
    s = (output_fun \<circ> i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk>\<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = \<NoMsg>) =
  (s t0 = \<NoMsg> \<and> (\<circle> t' t0 [0\<dots>]. (s t1 = \<NoMsg>. t1 \<U> t2 [0\<dots>] \<oplus> t'. event t2)))"
by (simp add: i_Exec_Comp_Stream_Acc_Output_def i_shrink_eq_NoMsg_iAll_start_event_conv)

lemma i_Exec_Comp_Stream_Acc_Output__Init__eq_NoMsg_iAll_start_event_conv: "
  \<lbrakk> 0 < k; \<And> t. event t = ((t + k - Suc 0) mod k = 0); t0 = Suc (t * k);
    s = (output_fun \<circ> i_Exec_Comp_Stream_Init trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk>\<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = \<NoMsg>) =
  (s t0 = \<NoMsg> \<and> (\<circle> t' t0 [0\<dots>]. (s t1 = \<NoMsg>. t1 \<U> t2 [0\<dots>] \<oplus> t'. event t2)))"
apply (simp add: i_Exec_Comp_Stream_Acc_Output_def i_shrink_eq_NoMsg_iAll_start_event_conv)
apply (simp add: iT_add iNext_def iFROM_inext iT_iff)
apply (simp add: i_Exec_Stream_Init_eq_i_Exec_Stream_Cons)
apply (rule_tac t="[Suc (Suc (t*k))\<dots>]" and s="[Suc (t*k)\<dots>] \<oplus> Suc 0" in subst)
 apply (simp add: iFROM_add)
apply (simp add: iT_Plus_iUntil_conv)
done

lemma i_Exec_Comp_Stream_Acc_Output__Init__eq_NoMsg_iAll_start_event2_conv: "
  \<lbrakk> Suc 0 < k; \<And> t. event t = (t mod k = Suc 0); t0 = Suc (t * k);
    s = (output_fun \<circ> i_Exec_Comp_Stream_Init trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk>\<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = \<NoMsg>) =
  (s t0 = \<NoMsg> \<and> (\<circle> t' t0 [0\<dots>]. (s t1 = \<NoMsg>. t1 \<U> t2 [0\<dots>] \<oplus> t'. event t2)))"
by (simp add: i_Exec_Comp_Stream_Acc_Output__Init__eq_NoMsg_iAll_start_event_conv mod_eq_Suc_0_conv)

lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_iUntil_start_event_conv: "
  \<lbrakk> 0 < k; m \<noteq> \<NoMsg>; \<And>t. event t = (t mod k = 0); t0 = t * k;
    s = (output_fun \<circ> i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk> \<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = m) = (
  (s t0 = m \<and> (\<circle> t' t0 [0\<dots>]. (s t1 = \<NoMsg>. t1 \<U> t2 ([0\<dots>] \<oplus> t'). event t2))) \<or>
  (\<circle> t' t0 [0\<dots>]. (\<not> event t1. t1 \<U> t2 ([0\<dots>] \<oplus> t'). (
    s t2 = m \<and> \<not> event t2 \<and> (\<circle> t'' t2 [0\<dots>].
      (s t3 = \<NoMsg>. t3 \<U> t4 ([0\<dots>] \<oplus> t''). event t4))))))"
by (simp add: i_Exec_Comp_Stream_Acc_Output_def i_shrink_eq_Msg_iUntil_start_event_conv)

lemma i_Exec_Comp_Stream_Acc_Output__Init__eq_Msg_iUntil_start_event_conv: "
  \<lbrakk> 0 < k; m \<noteq> \<NoMsg>; \<And>t. event t = ((t + k - Suc 0) mod k = 0); t0 = Suc (t * k);
    s = (output_fun \<circ> i_Exec_Comp_Stream_Init trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk> \<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = m) = (
  (s t0 = m \<and> (\<circle> t' t0 [0\<dots>]. (s t1 = \<NoMsg>. t1 \<U> t2 ([0\<dots>] \<oplus> t'). event t2))) \<or>
  (\<circle> t' t0 [0\<dots>]. (\<not> event t1. t1 \<U> t2 ([0\<dots>] \<oplus> t'). (
    s t2 = m \<and> \<not> event t2 \<and> (\<circle> t'' t2 [0\<dots>].
      (s t3 = \<NoMsg>. t3 \<U> t4 ([0\<dots>] \<oplus> t''). event t4))))))"
apply (simp add: i_Exec_Comp_Stream_Acc_Output_def i_shrink_eq_Msg_iUntil_start_event_conv)
apply (simp add: iNext_def iFROM_inext iFROM_iff iT_add)
apply (simp add: i_Exec_Stream_Init_eq_i_Exec_Stream_Cons)
apply (simp only: Suc_eq_plus1 iFROM_add[symmetric])
apply (simp add: iT_Plus_iUntil_conv)
apply (simp only: Suc_eq_plus1 iFROM_add[symmetric])
apply (simp add: iT_Plus_iUntil_conv)
done

lemma i_Exec_Comp_Stream_Acc_Output__Init__eq_Msg_iUntil_start_event2_conv: "
  \<lbrakk> Suc 0 < k; m \<noteq> \<NoMsg>; \<And>t. event t = (t mod k = Suc 0); t0 = Suc (t * k);
    s = (output_fun \<circ> i_Exec_Comp_Stream_Init trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk> \<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = m) = (
  (s t0 = m \<and> (\<circle> t' t0 [0\<dots>]. (s t1 = \<NoMsg>. t1 \<U> t2 ([0\<dots>] \<oplus> t'). event t2))) \<or>
  (\<circle> t' t0 [0\<dots>]. (\<not> event t1. t1 \<U> t2 ([0\<dots>] \<oplus> t'). (
    s t2 = m \<and> \<not> event t2 \<and> (\<circle> t'' t2 [0\<dots>].
      (s t3 = \<NoMsg>. t3 \<U> t4 ([0\<dots>] \<oplus> t''). event t4))))))"
by (simp add: i_Exec_Comp_Stream_Acc_Output__Init__eq_Msg_iUntil_start_event_conv mod_eq_Suc_0_conv)

lemma i_Exec_Comp_Stream_Acc_Output__eq_NoMsg_iAll_finish_event_conv: "
  \<lbrakk> Suc 0 < k; \<And> t. event t = (t mod k = k - Suc 0); t0 = t * k;
    s = (output_fun \<circ> i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk>\<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = \<NoMsg>) =
  (s t0 = \<NoMsg> \<and> (\<circle> t' t0 [0\<dots>]. (s t1 = \<NoMsg>. t1 \<U> t2 [0\<dots>] \<oplus> t'. event t2 \<and> s t2 = \<NoMsg>)))"
by (simp add: i_Exec_Comp_Stream_Acc_Output_def i_shrink_eq_NoMsg_iAll_finish_event_conv)

lemma i_Exec_Comp_Stream_Acc_Output__Init__eq_NoMsg_iAll_finish_event_conv: "
  \<lbrakk> Suc 0 < k; \<And> t. event t = (t mod k = 0); t0 = Suc (t * k);
    s = (output_fun \<circ> i_Exec_Comp_Stream_Init trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk>\<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = \<NoMsg>) =
  (s t0 = \<NoMsg> \<and> (\<circle> t' t0 [0\<dots>]. (s t1 = \<NoMsg>. t1 \<U> t2 [0\<dots>] \<oplus> t'. event t2 \<and> s t2 = \<NoMsg>)))"
apply (simp add: i_Exec_Comp_Stream_Acc_Output__eq_NoMsg_iAll_finish_event_conv)
apply (simp add: iNext_def iFROM_inext iFROM_iff iT_add)
apply (simp add: i_Exec_Stream_Init_eq_i_Exec_Stream_Cons)
apply (rule_tac t="[Suc (Suc (t * k))\<dots>]" and s="[Suc (t * k)\<dots>] \<oplus> 1" in subst)
 apply (simp add: iFROM_add)
apply (simp add: iT_Plus_iUntil_conv)
apply (simp add: mod_eq_divisor_minus_Suc_0_conv)
done

lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_iUntil_finish_event_conv: "
  \<lbrakk> 0 < k; m \<noteq> \<NoMsg>; \<And> t. event t = (t mod k = k - Suc 0); t0 = t * k;
    s = (output_fun \<circ> i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk>\<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = m) =
  ((\<not> event t1. t1 \<U> t2 ([0\<dots>] \<oplus> t0). event t2 \<and> s t2 = m) \<or>
  (\<not> event t1. t1 \<U> t2 ([0\<dots>] \<oplus> t0). (\<not> event t2 \<and> s t2 = m \<and> (
    \<circle> t' t2 [0\<dots>]. (s t3 = \<NoMsg>. t3 \<U> t4 ([0\<dots>] \<oplus> t'). event t4 \<and> s t4 = \<NoMsg>)))))"
apply (case_tac "k = Suc 0")
 apply (simp add: iT_add iT_not_empty iFROM_Min)
apply (drule neq_le_trans[OF not_sym], simp)
apply (simp add: i_Exec_Comp_Stream_Acc_Output_def i_shrink_eq_Msg_iUntil_finish_event_conv)
done

lemma i_Exec_Comp_Stream_Acc_Output__Init__eq_Msg_iUntil_finish_event_conv: "
  \<lbrakk> Suc 0 < k; m \<noteq> \<NoMsg>; \<And> t. event t = (t mod k = 0); t0 = Suc (t * k);
    s = (output_fun \<circ> i_Exec_Comp_Stream_Init trans_fun (input \<odot>\<^sub>i k) c) \<rbrakk>\<Longrightarrow>
  ((i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c) t = m) =
  ((\<not> event t1. t1 \<U> t2 ([0\<dots>] \<oplus> t0). event t2 \<and> s t2 = m) \<or>
  (\<not> event t1. t1 \<U> t2 ([0\<dots>] \<oplus> t0). (\<not> event t2 \<and> s t2 = m \<and> (
    \<circle> t' t2 [0\<dots>]. (s t3 = \<NoMsg>. t3 \<U> t4 ([0\<dots>] \<oplus> t'). event t4 \<and> s t4 = \<NoMsg>)))))"
apply (simp add: i_Exec_Comp_Stream_Acc_Output__eq_Msg_iUntil_finish_event_conv)
apply (simp add: iNext_def iFROM_inext iT_iff)
apply (simp add: i_Exec_Stream_Init_eq_i_Exec_Stream_Cons)
apply (simp add: iT_Plus_iUntil_conv)
apply (simp add: mod_eq_divisor_minus_Suc_0_conv add_Suc[symmetric] del: add_Suc)
done

subsection \<open>\<open>i_Exec_Comp_Stream_Acc_Output\<close> and temporal operators with idle states.\<close>

lemma i_Exec_Comp_Stream_Acc_Output__eq_NoMsg_State_Idle_conv: "
  \<lbrakk> 0 < k;
    State_Idle localState output_fun trans_fun (
      i_Exec_Comp_Stream_Acc_LocalState k localState trans_fun input c t);
    t0 = t * k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c \<rbrakk> \<Longrightarrow>
  (i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = \<NoMsg>) =
  (output_fun (s t1) = \<NoMsg>. t1 \<U> t2 ([0\<dots>] \<oplus> t0). (
   output_fun (s t2) = \<NoMsg> \<and> State_Idle localState output_fun trans_fun (localState (s t2))))"
apply (case_tac "k = Suc 0")
 apply (simp add: iUntil_def)
 apply (rule iffI)
  apply (rule_tac t=t in iexI)
   apply (simp add: iT_add iT_cut_less)
  apply (simp add: iT_add iT_iff)
 apply (clarify, rename_tac t1)
 apply (simp add: iT_add iT_iff iT_cut_less)
 apply (drule order_le_less[THEN iffD1])
 apply (erule disjE)
  apply (drule_tac t=t in ispec)
  apply (simp add: iT_iff)+
apply (drule order_neq_le_trans[OF not_sym Suc_leI], assumption)
apply (simp add: i_Exec_Comp_Stream_Acc_Output__eq_NoMsg_iAll_conv)
apply (simp add: iT_add i_Exec_Stream_nth i_Exec_Stream_Acc_LocalState_nth)
apply (simp add: i_take_Suc_conv_app_nth[of t])
apply (simp add: i_expand_i_take_mult[symmetric] f_Exec_append)
apply (subgoal_tac "\<forall>t1 \<in> [t * k\<dots>,k - Suc 0]. input \<odot>\<^sub>i k \<Down> Suc t1 \<up> (t * k) = input t # \<NoMsg>\<^bsup>t1 - t * k\<^esup>")
 prefer 2
 apply (simp add: i_expand_nth_interval_eq_nth_append_replicate_NoMsg iIN_iff)
apply (case_tac "output_fun (f_Exec_Comp trans_fun (input \<odot>\<^sub>i k \<Down> Suc (t * k)) c) \<noteq> \<NoMsg>")
 apply (subgoal_tac "
   \<not> (\<box> t1 [t * k\<dots>,k - Suc 0]. output_fun (f_Exec_Comp trans_fun (input \<odot>\<^sub>i k \<Down> Suc t1) c) = \<NoMsg>)")
  prefer 2
  apply simp
  apply (rule_tac t="t * k" in iexI, assumption)
  apply (simp add: iIN_iff)
 apply (simp add: not_iUntil del: not_iAll)
 apply (clarsimp simp: iT_iff, rename_tac t1 t2)
 apply (case_tac "t1 = t * k", simp)
 apply (drule order_le_neq_trans[OF _ not_sym], assumption)
 apply (rule_tac t="t * k" in iexI, simp)
 apply (simp add: iFROM_cut_less1 iIN_iff)
apply (case_tac "
  State_Idle localState output_fun trans_fun
    (localState ((trans_fun (input t) (f_Exec_Comp trans_fun (input \<odot>\<^sub>i k \<Down> (t * k)) c))))")
 apply (subgoal_tac "
   (\<box> t1 [t * k\<dots>,k - Suc 0]. output_fun (f_Exec_Comp trans_fun (input \<odot>\<^sub>i k \<Down> Suc t1) c) = NoMsg)")
  prefer 2
  apply (clarsimp simp: iIN_iff, rename_tac t1)
  apply (rule_tac m="t * k" and n="Suc t1" in subst[OF i_take_drop_append, rule_format], simp)
  apply (drule_tac x=t1 in bspec, simp add: iT_iff)
  apply (simp add: f_Exec_append del: i_take_drop_append)
  apply (simp add: i_take_Suc_conv_app_nth f_Exec_append i_expand_nth_mult)
  apply (rule f_Exec_State_Idle_replicate_NoMsg_output, assumption+)
 apply (simp add: iUntil_def)
 apply (rule_tac t="t * k" in iexI)
  apply (simp add: i_take_Suc_conv_app_nth f_Exec_append i_expand_nth_mult iFROM_cut_less)
 apply (simp add: iFROM_iff)
apply (subgoal_tac "\<forall>i < k. input \<odot>\<^sub>i k \<Up> Suc (t * k) \<Down> i = NoMsg\<^bsup>i\<^esup>")
 prefer 2
 apply (simp add: list_eq_iff i_expand_nth_if)
apply (rule iffI)
 apply (frule State_Idle_imp_exists_state_change2, assumption)
 apply (elim exE conjE, rename_tac i)
 apply (frule Suc_less_pred_conv[THEN iffD2])
 apply (simp only: iUntil_def)
 apply (rule_tac t="Suc (t * k + i)" in iexI)
  apply (rule conjI)
   apply (drule_tac t="Suc (t * k + i)" in ispec)
    apply (simp add: iIN_iff)
   apply (rule conjI, simp)
   apply (rule_tac t="Suc (Suc (t * k + i))" and s="Suc (t * k) + Suc i" in subst, simp)
   apply (subst i_take_add)
   apply (drule_tac x="Suc i" in spec)+
   apply (simp add: i_take_Suc_conv_app_nth f_Exec_append i_expand_nth_mult)
  apply (rule iallI, rename_tac t1)
  apply (drule_tac t=t1 in ispec)
   apply (drule_tac m="Suc i" in less_imp_le_pred)
   apply (clarsimp simp: iIN_iff iFROM_cut_less1)
   apply (rule order_trans, assumption)
   apply simp
  apply assumption
 apply (simp add: iFROM_iff)
apply (rule iallI)
apply (unfold iUntil_def, elim iexE conjE, rename_tac t2)
apply (case_tac "t1 < t2")
 apply (drule_tac t=t1 in ispec)
  apply (simp add: cut_less_mem_iff iT_iff)
 apply simp
apply (simp add: linorder_not_less)
apply (case_tac "t1 = t2", simp)
apply (drule le_neq_trans[OF _ not_sym], assumption)
apply (drule_tac i=t2 in less_imp_add_positive, elim exE conjE, rename_tac i)
apply (drule_tac t=t1 in sym)
apply (simp del: add_Suc add: add_Suc[symmetric] i_take_add f_Exec_append iFROM_iff)
apply (rule_tac t="input \<odot>\<^sub>i k \<Up> Suc t2 \<Down> i" and s="\<NoMsg>\<^bsup>i\<^esup>" in subst)
 apply (rule list_eq_iff[THEN iffD2])
 apply simp
 apply (intro allI impI, rename_tac i1)
 apply (simp add: i_expand_nth_if)
 apply (subst imp_conv_disj, rule disjI1)
 apply simp
 apply (subgoal_tac "t * k < Suc (t2 + i1) \<and> Suc (t2 + i1) < t * k + k", elim conjE)
  prefer 2
  apply (simp add: iIN_iff)
 apply (simp only: mult.commute[of _ k])
 apply (rule between_imp_mod_gr0, assumption+)
apply (rule f_Exec_State_Idle_replicate_NoMsg_gr0_output, assumption+)
done

lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_with_State_Idle_imp: "
  \<lbrakk> 0 < k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c;
    t0 = t * k;
    t1 \<in> [0\<dots>, k - Suc 0] \<oplus> t0;
    State_Idle localState output_fun trans_fun (localState (s t1));
    output_fun (s t1) \<noteq> \<NoMsg> \<rbrakk> \<Longrightarrow>
  i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = output_fun (s t1)"
apply (case_tac "k = Suc 0")
 apply (simp add: iIN_0 iT_Plus_singleton)
apply (drule order_neq_le_trans[OF not_sym], rule Suc_leI, assumption)
apply (simp add: iT_add iT_iff, erule conjE)
apply (simp only: i_Exec_Stream_Acc_Output_nth i_Exec_Stream_nth)
apply (rule_tac t="Suc t1" and s="t * k + (Suc t1 - t * k)" in subst, simp)
apply (simp only: i_take_add f_Exec_append i_expand_i_take_mult)
apply (subgoal_tac "input \<odot>\<^sub>i k \<Up> (t * k) \<Down> (Suc t1 - t * k) = input t # \<NoMsg>\<^bsup>t1 - t * k\<^esup>")
 prefer 2
 apply (simp add: i_take_i_drop)
 apply (subst i_expand_nth_interval_eq_nth_append_replicate_NoMsg)
 apply (simp del: f_Exec_Comp_Stream.simps)+
apply (subgoal_tac "\<exists>i. k - Suc 0 = t1 - t * k + i")
 prefer 2
 apply (rule le_iff_add[THEN iffD1])
 apply (simp add: le_diff_conv)
apply (erule exE)
apply (simp only: replicate_add)
apply (subst append_Cons[symmetric])
apply (subst State_Idle_append_replicate_NoMsg_output_last_message)
 apply (simp only: f_Exec_append[symmetric])
 apply (rule_tac t="input \<Down> t \<odot>\<^sub>f k @ input t # NoMsg\<^bsup>t1 - t * k\<^esup>" and s="input \<odot>\<^sub>i k \<Down> Suc t1" in subst)
  apply (subst i_expand_i_take_mult[symmetric])
  apply (drule_tac t="input t # NoMsg\<^bsup>t1 - t * k\<^esup>" in sym)
  apply (simp add: i_take_add[symmetric])
 apply assumption
apply (subgoal_tac "
  f_Exec_Comp_Stream trans_fun (input t # NoMsg\<^bsup>t1 - t * k\<^esup>)
   (f_Exec_Comp trans_fun (input \<Down> t \<odot>\<^sub>f k) c) \<noteq> []")
 prefer 2
 apply (simp add: f_Exec_Stream_not_empty_conv)
apply (rule ssubst[OF last_message_Msg_eq_last])
  apply simp
 apply (subst map_last, simp)
 apply (subst f_Exec_eq_f_Exec_Stream_last2[symmetric], simp)
 apply (subst f_Exec_append[symmetric])
 apply (rule_tac t="input \<Down> t \<odot>\<^sub>f k @ input t # NoMsg\<^bsup>t1 - t * k\<^esup>" and s="input \<odot>\<^sub>i k \<Down> Suc t1" in subst)
  apply (subst i_expand_i_take_mult[symmetric])
  apply (rule_tac t="Suc t1" and s="t * k + (Suc t1 - t * k)" in subst, simp)
  apply (subst i_take_add, simp)
 apply assumption
apply (subst map_last, simp)
apply (subst f_Exec_eq_f_Exec_Stream_last2[symmetric], simp+)
done

lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_with_State_Idle_conv2: "
  \<lbrakk> 0 < k;
    State_Idle localState output_fun trans_fun (
      i_Exec_Comp_Stream_Acc_LocalState k localState trans_fun input c t);
    m \<noteq> \<NoMsg>;
    t0 = t * k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c;
    t1 \<in> [0\<dots>, k - Suc 0] \<oplus> t0;
    State_Idle localState output_fun trans_fun (localState (s t1));
    output_fun (s t1) \<noteq> \<NoMsg> \<rbrakk> \<Longrightarrow>
  (i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = m) =
  (\<diamond> t1 [0\<dots>, k - Suc 0] \<oplus> t0. (
      (output_fun (s t1) = m \<and> State_Idle localState output_fun trans_fun (localState (s t1)))))"
apply (case_tac "k = Suc 0")
 apply (simp add: iIN_0 iT_Plus_singleton)
apply (drule order_neq_le_trans[OF not_sym], rule Suc_leI, assumption)
apply simp
apply (simp add: i_Exec_Comp_Stream_Acc_Output__eq_Msg_with_State_Idle_imp)
apply (rule iffI)
 apply blast
apply (clarify, rename_tac t1')
apply (subgoal_tac "t1' = t1")
 prefer 2
 apply (rule ccontr)
 apply (simp add: i_Exec_Stream_nth)
 apply (subgoal_tac "
   \<And> n1 n2.
   \<lbrakk> n1 < n2; n1 \<in> [0\<dots>,k - Suc 0] \<oplus> t * k; n2 \<in> [0\<dots>,k - Suc 0] \<oplus> t * k;
     State_Idle localState output_fun trans_fun (localState (f_Exec_Comp trans_fun (input \<odot>\<^sub>i k \<Down> Suc n1) c));
     output_fun (f_Exec_Comp trans_fun (input \<odot>\<^sub>i k \<Down> Suc n2) c) \<noteq> NoMsg \<rbrakk> \<Longrightarrow>
   False")
  prefer 2
  apply (drule_tac i=n1 in less_imp_add_positive, elim exE conjE, rename_tac i)
  apply (drule_tac t=n2 in sym, simp)
  apply (simp only: add_Suc[symmetric] i_take_add f_Exec_append)
  apply (subgoal_tac "input \<odot>\<^sub>i k \<Up> Suc n1 \<Down> i = \<NoMsg>\<^bsup>i\<^esup>")
   prefer 2
   apply (subst i_take_i_drop)
   apply (rule_tac t="\<NoMsg>\<^bsup>i\<^esup>" and s="\<NoMsg>\<^bsup>i + Suc n1 - Suc n1\<^esup>" in subst, simp)
   apply (rule_tac t=t in i_expand_nth_interval_eq_replicate_NoMsg)
   apply (simp add: iT_add iT_iff)+
  apply (frule_tac c="f_Exec_Comp trans_fun (input \<odot>\<^sub>i k \<Down> Suc n1) c" and n=i
     in f_Exec_State_Idle_replicate_NoMsg_gr0_output)
  apply (fastforce dest: linorder_neq_iff[THEN iffD1])+
done

text \<open>Here the property to be checked uses only unbounded intervals suitable for LTL.\<close>
lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_with_State_Idle_conv: "
  \<lbrakk> 0 < k;
    State_Idle localState output_fun trans_fun (
      i_Exec_Comp_Stream_Acc_LocalState k localState trans_fun input c t);
    m \<noteq> \<NoMsg>;
    t0 = t * k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c;
    t1 \<in> [0\<dots>, k - Suc 0] \<oplus> t0;
    State_Idle localState output_fun trans_fun (localState (s t1));
    output_fun (s t1) \<noteq> \<NoMsg> \<rbrakk> \<Longrightarrow>
  (i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = m) =
  ((\<not> State_Idle localState output_fun trans_fun (localState (s t2))). t2 \<U> t1 [0\<dots>] \<oplus> t0. (
      (output_fun (s t1) = m \<and> State_Idle localState output_fun trans_fun (localState (s t1)))))"
apply (subst i_Exec_Comp_Stream_Acc_Output__eq_Msg_with_State_Idle_conv2, assumption+)
apply (unfold iUntil_def)
apply (rule iffI)
 apply (elim iexE conjE, rename_tac t2)
 apply (rule_tac t=t2 in iexI)
  prefer 2
  apply (simp add: iT_add iT_iff)
 apply simp
 apply (rule iallI, rename_tac t2')
 apply (rule ccontr)
 apply (simp add: cut_less_mem_iff iT_iff iT_add, elim conjE)
 apply (frule_tac n=t2' in le_imp_less_Suc)
 apply (frule_tac i=t2' in less_imp_add_positive, elim exE conjE, rename_tac i)
 apply (drule_tac t=t2 in sym)
 apply (simp only: i_Exec_Stream_nth add_Suc[symmetric] i_take_add f_Exec_append)
 apply (simp only: i_take_i_drop)
 apply (subgoal_tac "input \<odot>\<^sub>i k \<Down> (i + Suc t2') \<up> Suc t2' = \<NoMsg>\<^bsup>i\<^esup>")
  prefer 2
  apply (rule_tac t="\<NoMsg>\<^bsup>i\<^esup>" and s="\<NoMsg>\<^bsup>i + Suc t2' - Suc t2'\<^esup>" in subst, simp)
  apply (rule_tac t=t in i_expand_nth_interval_eq_replicate_NoMsg)
  apply simp+
 apply (drule_tac c="(f_Exec_Comp trans_fun (input \<odot>\<^sub>i k \<Down> Suc t2') c)" and n=i
   in f_Exec_State_Idle_replicate_NoMsg_gr0_output, assumption)
 apply simp
apply (fastforce simp: iT_add iT_iff i_Exec_Stream_Acc_LocalState_nth i_Exec_Stream_nth)
done

lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_before_State_Idle_imp2: "
  \<lbrakk> Suc 0 < k;
    State_Idle localState output_fun trans_fun (
      i_Exec_Comp_Stream_Acc_LocalState k localState trans_fun input c t);
    m \<noteq> \<NoMsg>;
    t0 = t * k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c;
    t1 \<in> [0\<dots>, k - Suc 0] \<oplus> t0;
    output_fun (s t1) = m;
    \<circle> t2 t1 [0\<dots>].
     ((output_fun (s t3) = \<NoMsg>. t3 \<U> t4 ([0\<dots>] \<oplus> t2).
      (output_fun (s t4) = \<NoMsg> \<and> State_Idle localState output_fun trans_fun (localState (s t4))))) \<rbrakk> \<Longrightarrow>
  i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = m"
apply (clarsimp simp: iUntil_def iNext_def iT_inext iT_iff, rename_tac t2)
apply (simp only: i_Exec_Stream_Acc_Output_nth i_Exec_Stream_Acc_LocalState_nth i_Exec_Stream_nth)
apply (rule last_message_conv[THEN iffD2], assumption)
apply (clarsimp simp: iT_add iT_iff simp del: f_Exec_Comp_Stream.simps)
apply (subgoal_tac "t1 - t * k < k")
 prefer 2
 apply simp
apply (rule_tac x="t1 - t * k" in exI)
apply (rule conjI, simp)
apply (rule conjI)
 apply (simp add: f_Exec_Stream_nth min_eqL del: f_Exec_Comp.simps f_Exec_Comp_Stream.simps)
 apply (simp only: f_Exec_append[symmetric])
 apply (subst i_expand_i_take_mult_Suc[symmetric], assumption)
 apply simp
apply (intro allI impI)
apply (simp only: f_Exec_Stream_length length_Cons length_replicate Suc_pred
  nth_map f_Exec_Stream_nth take_Suc_Cons take_replicate min_eqL[OF less_imp_le_pred])
apply (subst f_Exec_append[symmetric])
apply (subst i_expand_i_take_mult_Suc[symmetric], assumption)
apply (case_tac "t2 \<le> t * k + j")
 prefer 2
 apply fastforce
apply (drule_tac x=t2 in order_le_less[THEN iffD1, rule_format])
apply (erule disjE)
 prefer 2
 apply simp
apply (subgoal_tac "
  State_Idle localState output_fun trans_fun
    (localState (f_Exec_Comp trans_fun (input \<odot>\<^sub>i k \<Down> (t * k + Suc j)) c))")
 prefer 2
 apply (rule_tac t="t * k + Suc j" and s="Suc t2 + (t * k + j - t2)" in subst, simp)
 apply (simp only: i_take_add f_Exec_append)
 apply (simp only: i_take_i_drop)
 apply simp
 apply (rule_tac t=t in ssubst[OF i_expand_nth_interval_eq_replicate_NoMsg, rule_format], simp+)
 apply (simp add: f_Exec_State_Idle_replicate_NoMsg_state)
apply (subgoal_tac "t1 div k = t \<and> t2 div k = t", elim conjE)
 prefer 2
 apply (simp add: le_less_imp_div)
apply (simp only: i_expand_i_take_Suc i_expand_i_take_mult_Suc f_Exec_append)
apply (simp add: f_Exec_append)
apply (rule_tac m="t2 mod k" in f_Exec_State_Idle_replicate_NoMsg_gr_output, assumption)
apply (simp add: minus_div_mult_eq_mod [symmetric])
done

lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_before_State_Idle_conv2: "
  \<lbrakk> Suc 0 < k;
    State_Idle localState output_fun trans_fun (
      i_Exec_Comp_Stream_Acc_LocalState k localState trans_fun input c t);
    m \<noteq> \<NoMsg>;
    t0 = t * k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c;
    \<box> t1 [0\<dots>, k - Suc 0] \<oplus> t0. \<not> (
      State_Idle localState output_fun trans_fun (localState (s t1)) \<and>
      output_fun (s t1) \<noteq> \<NoMsg>) \<rbrakk> \<Longrightarrow>
  (i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = m) =
  (\<diamond> t1 [0\<dots>, k - Suc 0] \<oplus> t0. (
     (output_fun (s t1) = m) \<and>
     (\<circle> t2 t1 [0\<dots>].
      ((output_fun (s t3) = \<NoMsg>. t3 \<U> t4 ([0\<dots>] \<oplus> t2).
      (output_fun (s t4) = \<NoMsg> \<and> State_Idle localState output_fun trans_fun (localState (s t4))))))))"
apply (rule iffI)
 apply (simp only: i_Exec_Stream_Acc_Output_nth i_Exec_Stream_nth)
 apply (simp only: iNext_def iFROM_iff iFROM_inext)
 apply (frule last_message_conv[THEN iffD1], assumption)
 apply (elim exE conjE, rename_tac i)
 apply (simp add: f_Exec_Stream_nth min_eqL del: f_Exec_Comp.simps f_Exec_Comp_Stream.simps de_Morgan_conj)
 apply (subgoal_tac "
   \<box> t' ([0\<dots>] \<oplus> (Suc (t * k + i))) \<down>< (t * k + k).
   output_fun (f_Exec_Comp trans_fun (input \<odot>\<^sub>i k \<Down> Suc t') c) = \<NoMsg>")
  prefer 2
  apply (rule iallI, rename_tac t')
  apply (simp only: iT_add iT_iff cut_less_mem_iff, erule conjE)
  apply (drule_tac x="t' - t * k" in spec)
  apply (subgoal_tac "t' - t * k < k")
   prefer 2
   apply simp
  apply (simp add: f_Exec_Stream_nth min_eqL del: f_Exec_Comp_Stream.simps de_Morgan_conj)
  apply (subgoal_tac "t * k \<le> t'")
   prefer 2
   apply simp
  apply (rule_tac t="Suc t'" and s="t * k + (Suc t' - t * k)" in subst, simp)
  apply (simp only: i_take_add f_Exec_append i_expand_i_take_mult)
  apply (simp add: i_take_i_drop)
  apply (rule ssubst[OF i_expand_nth_interval_eq_nth_append_replicate_NoMsg])
  apply (simp del: f_Exec_Comp_Stream.simps de_Morgan_conj)+
 apply (rule_tac t="t * k + i" in iexI)
  prefer 2
  apply (simp add: iT_add iT_iff)
 apply (rule conjI)
  apply (simp add: add_Suc_right[symmetric] i_expand_i_take_mult_Suc f_Exec_append del: add_Suc_right)
 apply (simp only: i_Exec_Stream_Acc_LocalState_nth i_expand_i_take_mult[symmetric] mult_Suc add.commute[of k])
 apply (subgoal_tac "
   \<not> State_Idle localState output_fun trans_fun
       (localState (f_Exec_Comp trans_fun (input \<odot>\<^sub>i k \<Down> (t * k + Suc i)) c))")
  prefer 2
  apply (drule_tac t="t * k + i" in ispec)
   apply (simp add: iT_add iT_iff)
  apply (simp add: add_Suc_right[symmetric] i_expand_i_take_mult_Suc f_Exec_append i_expand_i_take_mult del: add_Suc_right)
 apply (thin_tac "last_message x = m" for x)
 apply (drule_tac
   a="t * k + k" and b="t * k + Suc (k - Suc 0)" and
   P="\<lambda>x. State_Idle localState output_fun trans_fun
          (localState (f_Exec_Comp trans_fun (input \<odot>\<^sub>i k \<Down> x) c))" in back_subst, simp)
  apply (simp only: i_expand_i_take_mult_Suc f_Exec_append)
 apply (frule_tac n="k - Suc 0 - i" in State_Idle_imp_exists_state_change)
  apply (simp add: f_Exec_append[symmetric] replicate_add[symmetric])
 apply (elim exE conjE, rename_tac i1)
 apply (frule_tac i=i1 in less_diff_conv[THEN iffD1, rule_format])
 apply (drule_tac a=i1 and P="\<lambda>x. (x < k - Suc 0)" in subst[OF add.commute, rule_format])
 apply (frule Suc_less_pred_conv[THEN iffD2])
 apply (simp only: iUntil_def)
 apply (rule_tac t="t * k + Suc (i + i1)" in iexI)
  prefer 2
  apply (simp add: iT_add iT_iff)
 apply (rule conjI)
  apply (drule_tac t="t * k + Suc (i + i1)" in ispec)
   apply (simp add: iT_add iT_iff cut_less_mem_iff)
  apply (subgoal_tac "Suc (t * k + Suc (i + i1)) = t * k + Suc (Suc (i + i1))")
   prefer 2
   apply simp
  apply (simp only: i_expand_i_take_mult_Suc f_Exec_append)
  apply (simp add: add_Suc_right[symmetric] replicate_add f_Exec_append del: add_Suc_right replicate.simps)
 apply (clarsimp simp: cut_less_mem_iff iT_add iT_iff simp del: f_Exec_Comp_Stream.simps, rename_tac t')
 apply (subgoal_tac "\<exists>i'>i. t' = t * k + i'")
  prefer 2
  apply (rule_tac x="t' - t * k" in exI)
  apply simp
 apply (thin_tac "iAll I P" for I P)+
 apply (elim exE conjE)
 apply (subgoal_tac "i' < k")
  prefer 2
  apply simp
 apply (simp add: add_Suc_right[symmetric] i_expand_i_take_mult_Suc f_Exec_append f_Exec_Stream_nth min_eqL i_expand_i_take_mult del: add_Suc_right f_Exec_Comp_Stream.simps)
apply (elim iexE conjE, rename_tac t1)
apply (rule i_Exec_Comp_Stream_Acc_Output__eq_Msg_before_State_Idle_imp2, assumption+)
done

text \<open>Here the property to be checked uses only unbounded intervals suitable for LTL.\<close>
lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_before_State_Idle_imp: "
  \<lbrakk> Suc 0 < k;
    State_Idle localState output_fun trans_fun (
      i_Exec_Comp_Stream_Acc_LocalState k localState trans_fun input c t);
    m \<noteq> \<NoMsg>;
    t0 = t * k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c;
    (\<not> State_Idle localState output_fun trans_fun (localState (s t1))). t1 \<U> t2 [0\<dots>] \<oplus> t0. (
    (output_fun (s t2) = m) \<and>
    (\<circle> t3 t2 [0\<dots>].
      ((output_fun (s t4) = \<NoMsg>. t4 \<U> t5 ([0\<dots>] \<oplus> t3).
       (output_fun (s t5) = \<NoMsg> \<and> State_Idle localState output_fun trans_fun (localState (s t5))))))) \<rbrakk> \<Longrightarrow>
  i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = m"
apply (case_tac "
  \<diamond> t1 [0\<dots>, k - Suc 0] \<oplus> t0. (
      State_Idle localState output_fun trans_fun (localState (s t1)) \<and>
      output_fun (s t1) \<noteq> \<NoMsg>)")
 apply (clarsimp, rename_tac t1)
 apply (frule i_Exec_Comp_Stream_Acc_Output__eq_Msg_with_State_Idle_imp[OF Suc_lessD refl refl], assumption+)
 apply (simp only: iNext_def iT_inext iT_iff iUntil_def)
 apply (elim iexE conjE, rename_tac t2 t3)
 apply (subgoal_tac "t2 \<le> t1")
  prefer 2
  apply (rule ccontr)
  apply (drule_tac t=t1 in ispec)
   apply (simp add: cut_less_mem_iff iT_add iT_iff)
  apply simp
 apply (thin_tac "iAll I P" for I P)
 apply (subgoal_tac "t1 \<le> t2")
  prefer 2
  apply (rule ccontr)
  apply (subgoal_tac "t3 < t1 \<longrightarrow> output_fun (i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c t1) = \<NoMsg>")
   prefer 2
   apply (rule impI)
   apply (subgoal_tac "t * k \<le> t3")
    prefer 2
    apply (simp add: iT_add iT_iff)
   apply (subgoal_tac "t1 div k = t \<and> t3 div k = t", elim conjE)
    prefer 2
    apply (simp add: iT_add iT_iff le_less_imp_div)
   apply (simp (no_asm_simp) add: i_Exec_Stream_nth i_expand_i_take_Suc f_Exec_append)
   apply (rule_tac m="t3 mod k" in f_Exec_State_Idle_replicate_NoMsg_gr_output[of localState output_fun trans_fun])
    apply (simp add: i_Exec_Stream_nth i_expand_i_take_Suc f_Exec_append)
   apply (simp add: minus_div_mult_eq_mod [symmetric])
  apply (case_tac "t1 < t3")
   apply (drule_tac t=t1 in ispec)
    apply (simp add: cut_less_mem_iff iT_add iT_iff)
   apply simp+
apply (rule ssubst[OF i_Exec_Comp_Stream_Acc_Output__eq_Msg_before_State_Idle_conv2], simp+)
apply (simp only: iNext_def iT_inext iT_iff iUntil_def)
apply (elim iexE conjE, rename_tac t1 t2)
apply (subgoal_tac "t1 \<le> t * k + (k - Suc 0)")
 prefer 2
 apply (rule ccontr)
 apply (simp add: i_Exec_Stream_Acc_LocalState_nth i_expand_i_take_mult[symmetric] add.commute[of k])
 apply (thin_tac "iAll I P" for I P)
 apply (drule_tac t="t * k + (k - Suc 0)" in ispec)
  apply (simp add: cut_less_mem_iff iT_add iT_iff)
 apply (simp add: i_Exec_Stream_nth)
apply (rule_tac t=t1 in iexI)
 prefer 2
 apply (simp add: iT_add iT_iff)
apply simp
apply (rule_tac t=t2 in iexI)
apply simp+
done
lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_before_State_Idle_conv: "
  \<lbrakk> Suc 0 < k;
    State_Idle localState output_fun trans_fun (
      i_Exec_Comp_Stream_Acc_LocalState k localState trans_fun input c t);
    m \<noteq> \<NoMsg>;
    t0 = t * k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c;
    \<box> t1 [0\<dots>, k - Suc 0] \<oplus> t0. \<not> (
      State_Idle localState output_fun trans_fun (localState (s t1)) \<and>
      output_fun (s t1) \<noteq> \<NoMsg>) \<rbrakk> \<Longrightarrow>
  (i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = m) =
  ((\<not> State_Idle localState output_fun trans_fun (localState (s t1))). t1 \<U> t2 [0\<dots>] \<oplus> t0. (
     (output_fun (s t2) = m) \<and>
     (\<circle> t3 t2 [0\<dots>].
       ((output_fun (s t4) = \<NoMsg>. t4 \<U> t5 ([0\<dots>] \<oplus> t3).
        (output_fun (s t5) = \<NoMsg> \<and> State_Idle localState output_fun trans_fun (localState (s t5))))))))"
apply (rule iffI)
 apply (frule subst[OF i_Exec_Comp_Stream_Acc_Output__eq_Msg_before_State_Idle_conv2, where P="\<lambda>x. x"], assumption+)
 apply (simp only: iNext_def iT_inext iT_iff iUntil_def)
 apply (elim iexE conjE, rename_tac t1 t2)
 apply (rule_tac t=t1 in iexI)
  prefer 2
  apply (simp add: iT_add iT_iff)
 apply (intro conjI)
   apply simp
  apply (rule_tac t=t2 in iexI)
   prefer 2
   apply (simp add: iT_add iT_iff)
  apply simp
 apply (rule iallI, rename_tac t')
 apply (rule ccontr)
 apply (clarsimp simp: cut_less_mem_iff)
 apply (drule_tac i=t' in less_imp_add_positive)
 apply (elim exE conjE, rename_tac i)
 apply (drule_tac t=t1 in sym)
 apply (simp only: i_Exec_Stream_nth)
 apply (simp only: add_Suc[symmetric] i_take_add f_Exec_append)
 apply (simp only: i_take_i_drop)
 apply (subgoal_tac "i + Suc t' \<le> t * k + k")
  prefer 2
  apply (simp add: iT_add iT_iff)
 apply (simp only: iT_add iT_iff)
 apply (simp only: i_expand_nth_interval_eq_replicate_NoMsg[of k t, OF _ le_imp_less_Suc le_add2])
 apply (drule_tac c="f_Exec_Comp trans_fun (input \<odot>\<^sub>i k \<Down> Suc t') c" and n=i in f_Exec_State_Idle_replicate_NoMsg_gr0_output)
 apply simp+
apply (rule i_Exec_Comp_Stream_Acc_Output__eq_Msg_before_State_Idle_imp, simp+)
done

lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_conv2: "
  \<lbrakk> Suc 0 < k;
    State_Idle localState output_fun trans_fun (
      i_Exec_Comp_Stream_Acc_LocalState k localState trans_fun input c t);
    m \<noteq> \<NoMsg>;
    t0 = t * k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c \<rbrakk> \<Longrightarrow>
  (i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = m) =
  (\<diamond> t1 [0\<dots>, k - Suc 0] \<oplus> t0. (
    output_fun (s t1) = m \<and>
    (State_Idle localState output_fun trans_fun (localState (s t1)) \<or>
    (\<circle> t2 t1 [0\<dots>].
      ((output_fun (s t3) = \<NoMsg>. t3 \<U> t4 ([0\<dots>] \<oplus> t2).
       (output_fun (s t4) = \<NoMsg> \<and> State_Idle localState output_fun trans_fun (localState (s t4)))))))))"
apply (subst conj_disj_distribL)
apply (case_tac "
  \<diamond> t1 [0\<dots>,k - Suc 0] \<oplus> t0.
    (State_Idle localState output_fun trans_fun (localState (s t1)) \<and> output_fun (s t1) \<noteq> \<NoMsg>)")
 apply (elim iexE conjE, rename_tac t1)
 apply (rule iffI)
  apply (frule i_Exec_Comp_Stream_Acc_Output__eq_Msg_with_State_Idle_conv2[THEN iffD1, OF Suc_lessD], assumption+)
  apply fastforce
 apply (elim iexE conjI, rename_tac t2)
 apply (erule disjE)
  apply (rule i_Exec_Comp_Stream_Acc_Output__eq_Msg_with_State_Idle_conv2[THEN iffD2], simp+)
  apply (rule_tac t=t2 in iexI, simp+)
 apply (rule_tac ?t1.0=t2 in i_Exec_Comp_Stream_Acc_Output__eq_Msg_before_State_Idle_imp2, simp+)
apply (rule ssubst[OF i_Exec_Comp_Stream_Acc_Output__eq_Msg_before_State_Idle_conv2[OF _ _ _ refl refl]], simp+)
apply fastforce
done

lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_conv2': "
  \<lbrakk> Suc 0 < k;
    State_Idle localState output_fun trans_fun (
      i_Exec_Comp_Stream_Acc_LocalState k localState trans_fun input c t);
    m \<noteq> \<NoMsg>;
    t0 = t * k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c \<rbrakk> \<Longrightarrow>
  (i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = m) =
  ((\<diamond> t1 [0\<dots>, k - Suc 0] \<oplus> t0. (
      output_fun (s t1) = m \<and> State_Idle localState output_fun trans_fun (localState (s t1)))) \<or>
  (\<diamond> t1 [0\<dots>, k - Suc 0] \<oplus> t0. (
      ((output_fun (s t1) = m) \<and>
        (\<circle> t2 t1 [0\<dots>].
          ((output_fun (s t3) = \<NoMsg>. t3 \<U> t4 ([0\<dots>] \<oplus> t2).
           (output_fun (s t4) = \<NoMsg> \<and> State_Idle localState output_fun trans_fun (localState (s t4))))))))))"
apply (subst i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_conv2, assumption+)
apply blast
done

lemma i_Exec_Comp_Stream_Acc_Output__eq_iAll_iUntil_State_Idle_conv2: "
  \<lbrakk> Suc 0 < k;
    State_Idle localState output_fun trans_fun (
      i_Exec_Comp_Stream_Acc_LocalState k localState trans_fun input c t);
    t0 = t * k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c \<rbrakk> \<Longrightarrow>
  (i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = m) = (
  (m = \<NoMsg> \<longrightarrow>
    (output_fun (s t1) = \<NoMsg>. t1 \<U> t2 ([0\<dots>] \<oplus> t0). (
     output_fun (s t2) = \<NoMsg> \<and> State_Idle localState output_fun trans_fun (localState (s t2))))) \<and>
  (m \<noteq> \<NoMsg> \<longrightarrow>
    (\<diamond> t1 [0\<dots>, k - Suc 0] \<oplus> t0. (
      output_fun (s t1) = m \<and>
      (State_Idle localState output_fun trans_fun (localState (s t1)) \<or>
      (\<circle> t2 t1 [0\<dots>].
        ((output_fun (s t3) = \<NoMsg>. t3 \<U> t4 ([0\<dots>] \<oplus> t2).
         (output_fun (s t4) = \<NoMsg> \<and> State_Idle localState output_fun trans_fun (localState (s t4)))))))))))"
apply (case_tac "m = \<NoMsg>")
 apply (simp add: i_Exec_Comp_Stream_Acc_Output__eq_NoMsg_State_Idle_conv)
apply (simp add: i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_conv2)
done

lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_conv': "
  \<lbrakk> Suc 0 < k;
    State_Idle localState output_fun trans_fun (
      i_Exec_Comp_Stream_Acc_LocalState k localState trans_fun input c t);
    m \<noteq> \<NoMsg>;
    t0 = t * k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c \<rbrakk> \<Longrightarrow>
  (i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = m) =
  (((\<not> State_Idle localState output_fun trans_fun (localState (s t2))). t2 \<U> t1 [0\<dots>] \<oplus> t0.
    (output_fun (s t1) = m \<and> State_Idle localState output_fun trans_fun (localState (s t1)))) \<or>
  ((\<not> State_Idle localState output_fun trans_fun (localState (s t2))). t2 \<U> t1 [0\<dots>] \<oplus> t0.
   (output_fun (s t1) = m \<and>
   (\<circle> t3 t1 [0\<dots>].
     ((output_fun (s t4) = \<NoMsg>. t4 \<U> t5 ([0\<dots>] \<oplus> t3).
      (output_fun (s t5) = \<NoMsg> \<and> State_Idle localState output_fun trans_fun (localState (s t5)))))))))"
apply (case_tac "
  \<diamond> t1 [0\<dots>,k - Suc 0] \<oplus> t0.
    (State_Idle localState output_fun trans_fun (localState (s t1)) \<and> output_fun (s t1) \<noteq> \<NoMsg>)")
 apply (elim iexE conjE, rename_tac t1)
 apply (rule iffI)
  apply (frule i_Exec_Comp_Stream_Acc_Output__eq_Msg_with_State_Idle_conv[THEN iffD1, OF Suc_lessD], simp+)
 apply (erule disjE)
  apply (rule i_Exec_Comp_Stream_Acc_Output__eq_Msg_with_State_Idle_conv[THEN iffD2], simp+)
 apply (rule_tac i_Exec_Comp_Stream_Acc_Output__eq_Msg_before_State_Idle_imp, simp+)
apply (subst i_Exec_Comp_Stream_Acc_Output__eq_Msg_before_State_Idle_conv[OF _ _ _ refl refl], simp+)
apply (rule iffI)
 apply simp
apply (unfold iUntil_def, erule disjE)
 apply (elim iexE conjE, rename_tac t1)
 apply (case_tac "t1 \<le> t * k + (k - Suc 0)")
  prefer 2
  apply (simp add: i_Exec_Stream_Acc_LocalState_nth i_Exec_Stream_nth i_expand_i_take_mult[symmetric])
  apply (thin_tac "iAll I P" for I P)
  apply (drule_tac t="t * k + (k - Suc 0)" in ispec)
   apply (simp add: cut_less_mem_iff iT_add iT_iff)
  apply (simp add: add.commute[of k])
 apply (fastforce simp: iT_add iT_iff)+
done

lemma i_Exec_Comp_Stream_Acc_Output__eq_iUntil_State_Idle_conv: "
  \<lbrakk> Suc 0 < k;
    State_Idle localState output_fun trans_fun (
      i_Exec_Comp_Stream_Acc_LocalState k localState trans_fun input c t);
    t0 = t * k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c \<rbrakk> \<Longrightarrow>
  (i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = m) = (
  (m = \<NoMsg> \<longrightarrow>
    (output_fun (s t1) = \<NoMsg>. t1 \<U> t2 ([0\<dots>] \<oplus> t0). (
     output_fun (s t2) = \<NoMsg> \<and> State_Idle localState output_fun trans_fun (localState (s t2))))) \<and>
  (m \<noteq> \<NoMsg> \<longrightarrow>
    (((\<not> State_Idle localState output_fun trans_fun (localState (s t2))). t2 \<U> t1 [0\<dots>] \<oplus> t0.
      (output_fun (s t1) = m \<and>
        (State_Idle localState output_fun trans_fun (localState (s t1)) \<or>
        (\<circle> t3 t1 [0\<dots>].
            ((output_fun (s t4) = \<NoMsg>. t4 \<U> t5 ([0\<dots>] \<oplus> t3).
             (output_fun (s t5) = \<NoMsg> \<and> State_Idle localState output_fun trans_fun (localState (s t5))))))))))))"
apply (case_tac "m = \<NoMsg>")
 apply (simp add: i_Exec_Comp_Stream_Acc_Output__eq_NoMsg_State_Idle_conv)
apply (simp add: i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_conv)
done

text \<open>Sufficient conditions for output messages.\<close>

corollary i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_iEx_imp1: "
  \<lbrakk> Suc 0 < k;
    State_Idle localState output_fun trans_fun (
      i_Exec_Comp_Stream_Acc_LocalState k localState trans_fun input c t);
    m \<noteq> \<NoMsg>;
    t0 = t * k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c;
    (\<diamond> t1 [0\<dots>, k - Suc 0] \<oplus> t0. (
       output_fun (s t1) = m \<and> State_Idle localState output_fun trans_fun (localState (s t1)))) \<rbrakk> \<Longrightarrow>
  i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = m"
by (blast intro: i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_conv2'[THEN iffD2])

corollary i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_iEx_imp2: "
  \<lbrakk> Suc 0 < k;
    State_Idle localState output_fun trans_fun (
      i_Exec_Comp_Stream_Acc_LocalState k localState trans_fun input c t);
    m \<noteq> \<NoMsg>;
    t0 = t * k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c;
    \<diamond> t1 [0\<dots>, k - Suc 0] \<oplus> t0. (
          ((output_fun (s t1) = m) \<and>
            (\<circle> t2 t1 [0\<dots>].
              ((output_fun (s t3) = \<NoMsg>. t3 \<U> t4 ([0\<dots>] \<oplus> t2).
               (output_fun (s t4) = \<NoMsg> \<and> State_Idle localState output_fun trans_fun (localState (s t4)))))))) \<rbrakk> \<Longrightarrow>
  i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = m"
by (blast intro: i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_conv2'[THEN iffD2])

lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_iUntil_imp1: "
  \<lbrakk> Suc 0 < k;
    State_Idle localState output_fun trans_fun (
      i_Exec_Comp_Stream_Acc_LocalState k localState trans_fun input c t);
    m \<noteq> \<NoMsg>;
    t0 = t * k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c;
    (\<not> State_Idle localState output_fun trans_fun (localState (s t2))). t2 \<U> t1 [0\<dots>] \<oplus> t0.
    (output_fun (s t1) = m \<and> State_Idle localState output_fun trans_fun (localState (s t1))) \<rbrakk> \<Longrightarrow>
  i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = m"
by (blast intro: i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_conv'[THEN iffD2])
lemma i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_iUntil_imp2: "
  \<lbrakk> Suc 0 < k;
    State_Idle localState output_fun trans_fun (
      i_Exec_Comp_Stream_Acc_LocalState k localState trans_fun input c t);
    m \<noteq> \<NoMsg>;
    t0 = t * k;
    s = i_Exec_Comp_Stream trans_fun (input \<odot>\<^sub>i k) c;
    (\<not> State_Idle localState output_fun trans_fun (localState (s t2))). t2 \<U> t1 [0\<dots>] \<oplus> t0.
    (output_fun (s t1) = m \<and>
    (\<circle> t3 t1 [0\<dots>].
      ((output_fun (s t4) = \<NoMsg>. t4 \<U> t5 ([0\<dots>] \<oplus> t3).
       (output_fun (s t5) = \<NoMsg> \<and> State_Idle localState output_fun trans_fun (localState (s t5))))))) \<rbrakk> \<Longrightarrow>
  i_Exec_Comp_Stream_Acc_Output k output_fun trans_fun input c t = m"
by (blast intro: i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_conv'[THEN iffD2])

text \<open>List of selected lemmas about output of accelerated components.\<close>

thm i_Exec_Comp_Stream_Acc_Output__eq_NoMsg_iAll_conv
thm i_Exec_Comp_Stream_Acc_Output__eq_Msg_iEx_iAll_cut_greater_conv
thm i_Exec_Comp_Stream_Acc_Output__eq_Msg_iSince_conv
thm i_Exec_Comp_Stream_Acc_Output__eq_iAll_iSince_conv

thm i_Exec_Comp_Stream_Acc_Output__eq_NoMsg_State_Idle_conv
thm i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_conv2
thm i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_conv
thm i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_conv2'
thm i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_conv'

thm i_Exec_Comp_Stream_Acc_Output__eq_iAll_iUntil_State_Idle_conv2
thm i_Exec_Comp_Stream_Acc_Output__eq_iUntil_State_Idle_conv

thm i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_iEx_imp1
thm i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_iEx_imp2
thm i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_iUntil_imp1
thm i_Exec_Comp_Stream_Acc_Output__eq_Msg_State_Idle_iUntil_imp2

end


(* Title: Refinement Component Based on KAT
   Author: Victor Gomes, Georg Struth
   Maintainer: Victor Gomes <victor.gomes@cl.cam.ac.uk>
               Georg Struth <g.struth@sheffield.ac.uk>
*)

theory VC_RKAT
  imports "../RKAT_Models"

begin

text \<open>This component supports the step-wise refinement of simple while programs
in a partial correctness setting.\<close>

subsubsection \<open>Assignment Laws\<close>

text \<open>The store model is taken from KAT\<close>

lemma R_assign: "(\<forall>s. P s \<longrightarrow> Q (s (v := e s))) \<Longrightarrow> (v ::= e) \<subseteq> rel_R \<lceil>P\<rceil> \<lceil>Q\<rceil>"
proof -
  assume "(\<forall>s. P s \<longrightarrow> Q (s (v := e s)))"
  hence "rel_kat.H \<lceil>P\<rceil> (v ::= e) \<lceil>Q\<rceil>"
    by (rule H_assign_var)
  thus ?thesis
    by (rule rel_rkat.R2)
qed

lemma R_assignr: "(\<forall>s. Q' s \<longrightarrow> Q (s (v := e s))) \<Longrightarrow> (rel_R \<lceil>P\<rceil> \<lceil>Q'\<rceil>) ; (v ::= e) \<subseteq> rel_R \<lceil>P\<rceil> \<lceil>Q\<rceil>"
  by (metis H_assign_var rel_kat.H_seq rel_rkat.R1 rel_rkat.R2)

lemma R_assignl: "(\<forall>s. P s \<longrightarrow> P' (s (v := e s))) \<Longrightarrow> (v ::= e) ; (rel_R \<lceil>P'\<rceil> \<lceil>Q\<rceil>) \<subseteq> rel_R \<lceil>P\<rceil> \<lceil>Q\<rceil>"
  by (metis H_assign_var rel_kat.H_seq rel_rkat.R1 rel_rkat.R2)

subsubsection \<open>Simplified Refinement Laws\<close>

lemma R_cons: "(\<forall>s. P s \<longrightarrow> P' s) \<Longrightarrow> (\<forall>s. Q' s \<longrightarrow> Q s) \<Longrightarrow> rel_R \<lceil>P'\<rceil> \<lceil>Q'\<rceil> \<subseteq> rel_R \<lceil>P\<rceil> \<lceil>Q\<rceil>"
  by (simp add: rel_rkat.R1 rel_rkat.R2 sH_cons_1 sH_cons_2)

lemma if_then_else_ref: "X \<subseteq> X' \<Longrightarrow> Y \<subseteq> Y' \<Longrightarrow> IF P THEN X ELSE Y FI \<subseteq> IF P THEN X' ELSE Y' FI"
  by (auto simp: rel_kat.ifthenelse_def)

lemma while_ref: "X \<subseteq> X' \<Longrightarrow> WHILE P DO X OD \<subseteq> WHILE P DO X' OD"
  by (simp add: rel_kat.while_def rel_dioid.mult_isol rel_dioid.mult_isor rel_kleene_algebra.star_iso)

end


(*  Title:      HOL/Auth/Kerberos_BAN_Gets.thy
    Author:     Giampaolo Bella, Catania University
*)

section{*The Kerberos Protocol, BAN Version, with Gets event*}

theory Kerberos_BAN_Gets imports Public begin

text{*From page 251 of
  Burrows, Abadi and Needham (1989).  A Logic of Authentication.
  Proc. Royal Soc. 426

  Confidentiality (secrecy) and authentication properties rely on
  temporal checks: strong guarantees in a little abstracted - but
  very realistic - model.
*}

(* Temporal modelization: session keys can be leaked
                          ONLY when they have expired *)

consts

    (*Duration of the session key*)
    sesKlife   :: nat

    (*Duration of the authenticator*)
    authlife :: nat

text{*The ticket should remain fresh for two journeys on the network at least*}
text{*The Gets event causes longer traces for the protocol to reach its end*}
specification (sesKlife)
  sesKlife_LB [iff]: "4 \<le> sesKlife"
    by blast

text{*The authenticator only for one journey*}
text{*The Gets event causes longer traces for the protocol to reach its end*}
specification (authlife)
  authlife_LB [iff]:    "2 \<le> authlife"
    by blast

abbreviation
  CT :: "event list=>nat" where
  "CT == length"

abbreviation
  expiredK :: "[nat, event list] => bool" where
  "expiredK T evs == sesKlife + T < CT evs"

abbreviation
  expiredA :: "[nat, event list] => bool" where
  "expiredA T evs == authlife + T < CT evs"

definition
 (* Yields the subtrace of a given trace from its beginning to a given event *)
  before :: "[event, event list] => event list" ("before _ on _")
  where "before ev on evs = takeWhile (% z. z ~= ev) (rev evs)"

definition
 (* States than an event really appears only once on a trace *)
  Unique :: "[event, event list] => bool" ("Unique _ on _")
  where "Unique ev on evs = (ev \<notin> set (tl (dropWhile (% z. z \<noteq> ev) evs)))"

inductive_set bankerb_gets :: "event list set"
 where

   Nil:  "[] \<in> bankerb_gets"

 | Fake: "\<lbrakk> evsf \<in> bankerb_gets;  X \<in> synth (analz (knows Spy evsf)) \<rbrakk>
          \<Longrightarrow> Says Spy B X # evsf \<in> bankerb_gets"

 | Reception: "\<lbrakk> evsr\<in> bankerb_gets; Says A B X \<in> set evsr \<rbrakk>
                \<Longrightarrow> Gets B X # evsr \<in> bankerb_gets"

 | BK1:  "\<lbrakk> evs1 \<in> bankerb_gets \<rbrakk>
          \<Longrightarrow> Says A Server \<lbrace>Agent A, Agent B\<rbrace> # evs1
                \<in>  bankerb_gets"

 | BK2:  "\<lbrakk> evs2 \<in> bankerb_gets;  Key K \<notin> used evs2; K \<in> symKeys;
             Gets Server \<lbrace>Agent A, Agent B\<rbrace> \<in> set evs2 \<rbrakk>
          \<Longrightarrow> Says Server A
                (Crypt (shrK A)
                   \<lbrace>Number (CT evs2), Agent B, Key K,
                    (Crypt (shrK B) \<lbrace>Number (CT evs2), Agent A, Key K\<rbrace>)\<rbrace>)
                # evs2 \<in> bankerb_gets"

 | BK3:  "\<lbrakk> evs3 \<in> bankerb_gets;
             Gets A (Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, Ticket\<rbrace>)
               \<in> set evs3;
             Says A Server \<lbrace>Agent A, Agent B\<rbrace> \<in> set evs3;
             \<not> expiredK Tk evs3 \<rbrakk>
          \<Longrightarrow> Says A B \<lbrace>Ticket, Crypt K \<lbrace>Agent A, Number (CT evs3)\<rbrace> \<rbrace>
               # evs3 \<in> bankerb_gets"

 | BK4:  "\<lbrakk> evs4 \<in> bankerb_gets;
             Gets B \<lbrace>(Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>),
                         (Crypt K \<lbrace>Agent A, Number Ta\<rbrace>) \<rbrace>: set evs4;
             \<not> expiredK Tk evs4;  \<not> expiredA Ta evs4 \<rbrakk>
          \<Longrightarrow> Says B A (Crypt K (Number Ta)) # evs4
                \<in> bankerb_gets"

        (*Old session keys may become compromised*)
 | Oops: "\<lbrakk> evso \<in> bankerb_gets;
         Says Server A (Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, Ticket\<rbrace>)
               \<in> set evso;
             expiredK Tk evso \<rbrakk>
          \<Longrightarrow> Notes Spy \<lbrace>Number Tk, Key K\<rbrace> # evso \<in> bankerb_gets"

declare Says_imp_knows_Spy [THEN parts.Inj, dest]
declare parts.Body [dest]
declare analz_into_parts [dest]
declare Fake_parts_insert_in_Un [dest]
declare knows_Spy_partsEs [elim]

text{*A "possibility property": there are traces that reach the end.*}
lemma "\<lbrakk>Key K \<notin> used []; K \<in> symKeys\<rbrakk>
       \<Longrightarrow> \<exists>Timestamp. \<exists>evs \<in> bankerb_gets.
             Says B A (Crypt K (Number Timestamp))
                  \<in> set evs"
apply (cut_tac sesKlife_LB)
apply (cut_tac authlife_LB)
apply (intro exI bexI)
apply (rule_tac [2]
           bankerb_gets.Nil [THEN bankerb_gets.BK1, THEN bankerb_gets.Reception,
                            THEN bankerb_gets.BK2, THEN bankerb_gets.Reception,
                            THEN bankerb_gets.BK3, THEN bankerb_gets.Reception,
                            THEN bankerb_gets.BK4])
apply (possibility, simp_all (no_asm_simp) add: used_Cons)
done

text{*Lemmas about reception invariant: if a message is received it certainly
was sent*}
lemma Gets_imp_Says :
     "\<lbrakk> Gets B X \<in> set evs; evs \<in> bankerb_gets \<rbrakk> \<Longrightarrow> \<exists>A. Says A B X \<in> set evs"
apply (erule rev_mp)
apply (erule bankerb_gets.induct)
apply auto
done

lemma Gets_imp_knows_Spy:
     "\<lbrakk> Gets B X \<in> set evs; evs \<in> bankerb_gets \<rbrakk>  \<Longrightarrow> X \<in> knows Spy evs"
apply (blast dest!: Gets_imp_Says Says_imp_knows_Spy)
done

lemma Gets_imp_knows_Spy_parts[dest]:
    "\<lbrakk> Gets B X \<in> set evs; evs \<in> bankerb_gets \<rbrakk>  \<Longrightarrow> X \<in> parts (knows Spy evs)"
apply (blast dest: Gets_imp_knows_Spy [THEN parts.Inj])
done

lemma Gets_imp_knows:
     "\<lbrakk> Gets B X \<in> set evs; evs \<in> bankerb_gets \<rbrakk>  \<Longrightarrow> X \<in> knows B evs"
by (metis Gets_imp_knows_Spy Gets_imp_knows_agents)

lemma Gets_imp_knows_analz:
    "\<lbrakk> Gets B X \<in> set evs; evs \<in> bankerb_gets \<rbrakk>  \<Longrightarrow> X \<in> analz (knows B evs)"
apply (blast dest: Gets_imp_knows [THEN analz.Inj])
done

text{*Lemmas for reasoning about predicate "before"*}
lemma used_Says_rev: "used (evs @ [Says A B X]) = parts {X} \<union> (used evs)"
apply (induct_tac "evs")
apply simp
apply (rename_tac a b)
apply (induct_tac "a")
apply auto
done

lemma used_Notes_rev: "used (evs @ [Notes A X]) = parts {X} \<union> (used evs)"
apply (induct_tac "evs")
apply simp
apply (rename_tac a b)
apply (induct_tac "a")
apply auto
done

lemma used_Gets_rev: "used (evs @ [Gets B X]) = used evs"
apply (induct_tac "evs")
apply simp
apply (rename_tac a b)
apply (induct_tac "a")
apply auto
done

lemma used_evs_rev: "used evs = used (rev evs)"
apply (induct_tac "evs")
apply simp
apply (rename_tac a b)
apply (induct_tac "a")
apply (simp add: used_Says_rev)
apply (simp add: used_Gets_rev)
apply (simp add: used_Notes_rev)
done

lemma used_takeWhile_used [rule_format]:
      "x : used (takeWhile P X) --> x : used X"
apply (induct_tac "X")
apply simp
apply (rename_tac a b)
apply (induct_tac "a")
apply (simp_all add: used_Nil)
apply (blast dest!: initState_into_used)+
done

lemma set_evs_rev: "set evs = set (rev evs)"
apply auto
done

lemma takeWhile_void [rule_format]:
      "x \<notin> set evs \<longrightarrow> takeWhile (\<lambda>z. z \<noteq> x) evs = evs"
apply auto
done

(**** Inductive proofs about bankerb_gets ****)

text{*Forwarding Lemma for reasoning about the encrypted portion of message BK3*}
lemma BK3_msg_in_parts_knows_Spy:
     "\<lbrakk>Gets A (Crypt KA \<lbrace>Timestamp, B, K, X\<rbrace>) \<in> set evs; evs \<in> bankerb_gets \<rbrakk>
      \<Longrightarrow> X \<in> parts (knows Spy evs)"
apply blast
done

lemma Oops_parts_knows_Spy:
     "Says Server A (Crypt (shrK A) \<lbrace>Timestamp, B, K, X\<rbrace>) \<in> set evs
      \<Longrightarrow> K \<in> parts (knows Spy evs)"
apply blast
done

text{*Spy never sees another agent's shared key! (unless it's bad at start)*}
lemma Spy_see_shrK [simp]:
     "evs \<in> bankerb_gets \<Longrightarrow> (Key (shrK A) \<in> parts (knows Spy evs)) = (A \<in> bad)"
apply (erule bankerb_gets.induct)
apply (frule_tac [8] Oops_parts_knows_Spy)
apply (frule_tac [6] BK3_msg_in_parts_knows_Spy, simp_all, blast+)
done

lemma Spy_analz_shrK [simp]:
     "evs \<in> bankerb_gets \<Longrightarrow> (Key (shrK A) \<in> analz (knows Spy evs)) = (A \<in> bad)"
by auto

lemma Spy_see_shrK_D [dest!]:
     "\<lbrakk> Key (shrK A) \<in> parts (knows Spy evs);
                evs \<in> bankerb_gets \<rbrakk> \<Longrightarrow> A:bad"
by (blast dest: Spy_see_shrK)

lemmas Spy_analz_shrK_D = analz_subset_parts [THEN subsetD, THEN Spy_see_shrK_D,  dest!]

text{*Nobody can have used non-existent keys!*}
lemma new_keys_not_used [simp]:
    "\<lbrakk>Key K \<notin> used evs; K \<in> symKeys; evs \<in> bankerb_gets\<rbrakk>
     \<Longrightarrow> K \<notin> keysFor (parts (knows Spy evs))"
apply (erule rev_mp)
apply (erule bankerb_gets.induct)
apply (frule_tac [8] Oops_parts_knows_Spy)
apply (frule_tac [6] BK3_msg_in_parts_knows_Spy, simp_all)
txt{*Fake*}
apply (force dest!: keysFor_parts_insert)
txt{*BK2, BK3, BK4*}
apply (force dest!: analz_shrK_Decrypt)+
done

subsection{* Lemmas concerning the form of items passed in messages *}

text{*Describes the form of K, X and K' when the Server sends this message.*}
lemma Says_Server_message_form:
     "\<lbrakk> Says Server A (Crypt K' \<lbrace>Number Tk, Agent B, Key K, Ticket\<rbrace>)
         \<in> set evs; evs \<in> bankerb_gets \<rbrakk>
      \<Longrightarrow> K' = shrK A & K \<notin> range shrK &
          Ticket = (Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>) &
          Key K \<notin> used(before
                  Says Server A (Crypt K' \<lbrace>Number Tk, Agent B, Key K, Ticket\<rbrace>)
                  on evs) &
          Tk = CT(before
                  Says Server A (Crypt K' \<lbrace>Number Tk, Agent B, Key K, Ticket\<rbrace>)
                  on evs)"
apply (unfold before_def)
apply (erule rev_mp)
apply (erule bankerb_gets.induct, simp_all)
txt{*We need this simplification only for Message 2*}
apply (simp (no_asm) add: takeWhile_tail)
apply auto
txt{*Two subcases of Message 2. Subcase: used before*}
apply (blast dest: used_evs_rev [THEN equalityD2, THEN contra_subsetD]
                   used_takeWhile_used)
txt{*subcase: CT before*}
apply (fastforce dest!: set_evs_rev [THEN equalityD2, THEN contra_subsetD, THEN takeWhile_void])
done

text{*If the encrypted message appears then it originated with the Server
  PROVIDED that A is NOT compromised!
  This allows A to verify freshness of the session key.
*}
lemma Kab_authentic:
     "\<lbrakk> Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, X\<rbrace>
           \<in> parts (knows Spy evs);
         A \<notin> bad;  evs \<in> bankerb_gets \<rbrakk>
       \<Longrightarrow> Says Server A (Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, X\<rbrace>)
             \<in> set evs"
apply (erule rev_mp)
apply (erule bankerb_gets.induct)
apply (frule_tac [8] Oops_parts_knows_Spy)
apply (frule_tac [6] BK3_msg_in_parts_knows_Spy, simp_all, blast)
done

text{*If the TICKET appears then it originated with the Server*}
text{*FRESHNESS OF THE SESSION KEY to B*}
lemma ticket_authentic:
     "\<lbrakk> Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace> \<in> parts (knows Spy evs);
         B \<notin> bad;  evs \<in> bankerb_gets \<rbrakk>
       \<Longrightarrow> Says Server A
            (Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K,
                          Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>\<rbrace>)
           \<in> set evs"
apply (erule rev_mp)
apply (erule bankerb_gets.induct)
apply (frule_tac [8] Oops_parts_knows_Spy)
apply (frule_tac [6] BK3_msg_in_parts_knows_Spy, simp_all, blast)
done

text{*EITHER describes the form of X when the following message is sent,
  OR     reduces it to the Fake case.
  Use @{text Says_Server_message_form} if applicable.*}
lemma Gets_Server_message_form:
     "\<lbrakk> Gets A (Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, X\<rbrace>)
            \<in> set evs;
         evs \<in> bankerb_gets \<rbrakk>
 \<Longrightarrow> (K \<notin> range shrK & X = (Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>))
          | X \<in> analz (knows Spy evs)"
apply (case_tac "A \<in> bad")
apply (force dest!: Gets_imp_knows_Spy [THEN analz.Inj])
apply (blast dest!: Kab_authentic Says_Server_message_form)
done

text{*Reliability guarantees: honest agents act as we expect*}

lemma BK3_imp_Gets:
   "\<lbrakk> Says A B \<lbrace>Ticket, Crypt K \<lbrace>Agent A, Number Ta\<rbrace>\<rbrace> \<in> set evs;
      A \<notin> bad; evs \<in> bankerb_gets \<rbrakk>
    \<Longrightarrow> \<exists> Tk. Gets A (Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, Ticket\<rbrace>)
      \<in> set evs"
apply (erule rev_mp)
apply (erule bankerb_gets.induct)
apply auto
done

lemma BK4_imp_Gets:
   "\<lbrakk> Says B A (Crypt K (Number Ta)) \<in> set evs;
      B \<notin> bad; evs \<in> bankerb_gets \<rbrakk>
  \<Longrightarrow> \<exists> Tk. Gets B \<lbrace>Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>,
                    Crypt K \<lbrace>Agent A, Number Ta\<rbrace>\<rbrace> \<in> set evs"
apply (erule rev_mp)
apply (erule bankerb_gets.induct)
apply auto
done

lemma Gets_A_knows_K:
  "\<lbrakk> Gets A (Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, Ticket\<rbrace>) \<in> set evs;
     evs \<in> bankerb_gets \<rbrakk>
 \<Longrightarrow> Key K \<in> analz (knows A evs)"
apply (force dest: Gets_imp_knows_analz)
done

lemma Gets_B_knows_K:
  "\<lbrakk> Gets B \<lbrace>Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>,
             Crypt K \<lbrace>Agent A, Number Ta\<rbrace>\<rbrace> \<in> set evs;
     evs \<in> bankerb_gets \<rbrakk>
 \<Longrightarrow> Key K \<in> analz (knows B evs)"
apply (force dest: Gets_imp_knows_analz)
done

(****
 The following is to prove theorems of the form

  Key K \<in> analz (insert (Key KAB) (knows Spy evs)) \<Longrightarrow>
  Key K \<in> analz (knows Spy evs)

 A more general formula must be proved inductively.

****)

text{* Session keys are not used to encrypt other session keys *}
lemma analz_image_freshK [rule_format (no_asm)]:
     "evs \<in> bankerb_gets \<Longrightarrow>
   \<forall>K KK. KK \<subseteq> - (range shrK) \<longrightarrow>
          (Key K \<in> analz (Key`KK Un (knows Spy evs))) =
          (K \<in> KK | Key K \<in> analz (knows Spy evs))"
apply (erule bankerb_gets.induct)
apply (drule_tac [8] Says_Server_message_form)
apply (erule_tac [6] Gets_Server_message_form [THEN disjE], analz_freshK, spy_analz, auto)
done

lemma analz_insert_freshK:
     "\<lbrakk> evs \<in> bankerb_gets;  KAB \<notin> range shrK \<rbrakk> \<Longrightarrow>
      (Key K \<in> analz (insert (Key KAB) (knows Spy evs))) =
      (K = KAB | Key K \<in> analz (knows Spy evs))"
by (simp only: analz_image_freshK analz_image_freshK_simps)

text{* The session key K uniquely identifies the message *}
lemma unique_session_keys:
     "\<lbrakk> Says Server A
           (Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, X\<rbrace>) \<in> set evs;
         Says Server A'
          (Crypt (shrK A') \<lbrace>Number Tk', Agent B', Key K, X'\<rbrace>) \<in> set evs;
         evs \<in> bankerb_gets \<rbrakk> \<Longrightarrow> A=A' & Tk=Tk' & B=B' & X = X'"
apply (erule rev_mp)
apply (erule rev_mp)
apply (erule bankerb_gets.induct)
apply (frule_tac [8] Oops_parts_knows_Spy)
apply (frule_tac [6] BK3_msg_in_parts_knows_Spy, simp_all)
txt{*BK2: it can't be a new key*}
apply blast
done

lemma unique_session_keys_Gets:
     "\<lbrakk> Gets A
           (Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, X\<rbrace>) \<in> set evs;
        Gets A
          (Crypt (shrK A) \<lbrace>Number Tk', Agent B', Key K, X'\<rbrace>) \<in> set evs;
        A \<notin> bad; evs \<in> bankerb_gets \<rbrakk> \<Longrightarrow> Tk=Tk' & B=B' & X = X'"
apply (blast dest!: Kab_authentic unique_session_keys)
done

lemma Server_Unique:
     "\<lbrakk> Says Server A
            (Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, Ticket\<rbrace>) \<in> set evs;
        evs \<in> bankerb_gets \<rbrakk> \<Longrightarrow>
   Unique Says Server A (Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, Ticket\<rbrace>)
   on evs"
apply (erule rev_mp, erule bankerb_gets.induct, simp_all add: Unique_def)
apply blast
done

subsection{*Non-temporal guarantees, explicitly relying on non-occurrence of
oops events - refined below by temporal guarantees*}

text{*Non temporal treatment of confidentiality*}

text{* Lemma: the session key sent in msg BK2 would be lost by oops
    if the spy could see it! *}
lemma lemma_conf [rule_format (no_asm)]:
     "\<lbrakk> A \<notin> bad;  B \<notin> bad;  evs \<in> bankerb_gets \<rbrakk>
  \<Longrightarrow> Says Server A
          (Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K,
                            Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>\<rbrace>)
         \<in> set evs \<longrightarrow>
      Key K \<in> analz (knows Spy evs) \<longrightarrow> Notes Spy \<lbrace>Number Tk, Key K\<rbrace> \<in> set evs"
apply (erule bankerb_gets.induct)
apply (frule_tac [8] Says_Server_message_form)
apply (frule_tac [6] Gets_Server_message_form [THEN disjE])
apply (simp_all (no_asm_simp) add: analz_insert_eq analz_insert_freshK pushes)
txt{*Fake*}
apply spy_analz
txt{*BK2*}
apply (blast intro: parts_insertI)
txt{*BK3*}
apply (case_tac "Aa \<in> bad")
 prefer 2 apply (blast dest: Kab_authentic unique_session_keys)
apply (blast dest: Gets_imp_knows_Spy [THEN analz.Inj] Crypt_Spy_analz_bad elim!: MPair_analz)
txt{*Oops*}
apply (blast dest: unique_session_keys)
done

text{*Confidentiality for the Server: Spy does not see the keys sent in msg BK2
as long as they have not expired.*}
lemma Confidentiality_S:
     "\<lbrakk> Says Server A
          (Crypt K' \<lbrace>Number Tk, Agent B, Key K, Ticket\<rbrace>) \<in> set evs;
        Notes Spy \<lbrace>Number Tk, Key K\<rbrace> \<notin> set evs;
         A \<notin> bad;  B \<notin> bad;  evs \<in> bankerb_gets
      \<rbrakk> \<Longrightarrow> Key K \<notin> analz (knows Spy evs)"
apply (frule Says_Server_message_form, assumption)
apply (blast intro: lemma_conf)
done

text{*Confidentiality for Alice*}
lemma Confidentiality_A:
     "\<lbrakk> Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, X\<rbrace> \<in> parts (knows Spy evs);
        Notes Spy \<lbrace>Number Tk, Key K\<rbrace> \<notin> set evs;
        A \<notin> bad;  B \<notin> bad;  evs \<in> bankerb_gets
      \<rbrakk> \<Longrightarrow> Key K \<notin> analz (knows Spy evs)"
by (blast dest!: Kab_authentic Confidentiality_S)

text{*Confidentiality for Bob*}
lemma Confidentiality_B:
     "\<lbrakk> Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>
          \<in> parts (knows Spy evs);
        Notes Spy \<lbrace>Number Tk, Key K\<rbrace> \<notin> set evs;
        A \<notin> bad;  B \<notin> bad;  evs \<in> bankerb_gets
      \<rbrakk> \<Longrightarrow> Key K \<notin> analz (knows Spy evs)"
by (blast dest!: ticket_authentic Confidentiality_S)

text{*Non temporal treatment of authentication*}

text{*Lemmas @{text lemma_A} and @{text lemma_B} in fact are common to both temporal and non-temporal treatments*}
lemma lemma_A [rule_format]:
     "\<lbrakk> A \<notin> bad; B \<notin> bad; evs \<in> bankerb_gets \<rbrakk>
      \<Longrightarrow>
         Key K \<notin> analz (knows Spy evs) \<longrightarrow>
         Says Server A (Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, X\<rbrace>)
         \<in> set evs \<longrightarrow>
          Crypt K \<lbrace>Agent A, Number Ta\<rbrace> \<in> parts (knows Spy evs) \<longrightarrow>
         Says A B \<lbrace>X, Crypt K \<lbrace>Agent A, Number Ta\<rbrace>\<rbrace>
             \<in> set evs"
apply (erule bankerb_gets.induct)
apply (frule_tac [8] Oops_parts_knows_Spy)
apply (frule_tac [6] Gets_Server_message_form)
apply (frule_tac [7] BK3_msg_in_parts_knows_Spy, analz_mono_contra)
apply (simp_all (no_asm_simp) add: all_conj_distrib)
txt{*Fake*}
apply blast
txt{*BK2*}
apply (force dest: Crypt_imp_invKey_keysFor)
txt{*BK3*}
apply (blast dest: Kab_authentic unique_session_keys)
done
lemma lemma_B [rule_format]:
     "\<lbrakk> B \<notin> bad;  evs \<in> bankerb_gets \<rbrakk>
      \<Longrightarrow> Key K \<notin> analz (knows Spy evs) \<longrightarrow>
          Says Server A (Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, X\<rbrace>)
          \<in> set evs \<longrightarrow>
          Crypt K (Number Ta) \<in> parts (knows Spy evs) \<longrightarrow>
          Says B A (Crypt K (Number Ta)) \<in> set evs"
apply (erule bankerb_gets.induct)
apply (frule_tac [8] Oops_parts_knows_Spy)
apply (frule_tac [6] Gets_Server_message_form)
apply (drule_tac [7] BK3_msg_in_parts_knows_Spy, analz_mono_contra)
apply (simp_all (no_asm_simp) add: all_conj_distrib)
txt{*Fake*}
apply blast
txt{*BK2*}
apply (force dest: Crypt_imp_invKey_keysFor)
txt{*BK4*}
apply (blast dest: ticket_authentic unique_session_keys
                   Gets_imp_knows_Spy [THEN analz.Inj] Crypt_Spy_analz_bad)
done

text{*The "r" suffix indicates theorems where the confidentiality assumptions are relaxed by the corresponding arguments.*}

text{*Authentication of A to B*}
lemma B_authenticates_A_r:
     "\<lbrakk> Crypt K \<lbrace>Agent A, Number Ta\<rbrace> \<in> parts (knows Spy evs);
         Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>  \<in> parts (knows Spy evs);
        Notes Spy \<lbrace>Number Tk, Key K\<rbrace> \<notin> set evs;
         A \<notin> bad;  B \<notin> bad;  evs \<in> bankerb_gets \<rbrakk>
      \<Longrightarrow> Says A B \<lbrace>Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>,
                     Crypt K \<lbrace>Agent A, Number Ta\<rbrace>\<rbrace> \<in> set evs"
by (blast dest!: ticket_authentic
          intro!: lemma_A
          elim!: Confidentiality_S [THEN [2] rev_notE])

text{*Authentication of B to A*}
lemma A_authenticates_B_r:
     "\<lbrakk> Crypt K (Number Ta) \<in> parts (knows Spy evs);
        Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, X\<rbrace> \<in> parts (knows Spy evs);
        Notes Spy \<lbrace>Number Tk, Key K\<rbrace> \<notin> set evs;
        A \<notin> bad;  B \<notin> bad;  evs \<in> bankerb_gets \<rbrakk>
      \<Longrightarrow> Says B A (Crypt K (Number Ta)) \<in> set evs"
by (blast dest!: Kab_authentic
          intro!: lemma_B elim!: Confidentiality_S [THEN [2] rev_notE])

lemma B_authenticates_A:
     "\<lbrakk> Crypt K \<lbrace>Agent A, Number Ta\<rbrace> \<in> parts (spies evs);
         Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>  \<in> parts (spies evs);
        Key K \<notin> analz (spies evs);
         A \<notin> bad;  B \<notin> bad;  evs \<in> bankerb_gets \<rbrakk>
      \<Longrightarrow> Says A B \<lbrace>Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>,
                     Crypt K \<lbrace>Agent A, Number Ta\<rbrace>\<rbrace> \<in> set evs"
apply (blast dest!: ticket_authentic intro!: lemma_A)
done

lemma A_authenticates_B:
     "\<lbrakk> Crypt K (Number Ta) \<in> parts (spies evs);
        Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, X\<rbrace> \<in> parts (spies evs);
        Key K \<notin> analz (spies evs);
        A \<notin> bad;  B \<notin> bad;  evs \<in> bankerb_gets \<rbrakk>
      \<Longrightarrow> Says B A (Crypt K (Number Ta)) \<in> set evs"
apply (blast dest!: Kab_authentic intro!: lemma_B)
done

subsection{*Temporal guarantees, relying on a temporal check that insures that
no oops event occurred. These are available in the sense of goal availability*}

text{*Temporal treatment of confidentiality*}

text{* Lemma: the session key sent in msg BK2 would be EXPIRED
    if the spy could see it! *}
lemma lemma_conf_temporal [rule_format (no_asm)]:
     "\<lbrakk> A \<notin> bad;  B \<notin> bad;  evs \<in> bankerb_gets \<rbrakk>
  \<Longrightarrow> Says Server A
          (Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K,
                            Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>\<rbrace>)
         \<in> set evs \<longrightarrow>
      Key K \<in> analz (knows Spy evs) \<longrightarrow> expiredK Tk evs"
apply (erule bankerb_gets.induct)
apply (frule_tac [8] Says_Server_message_form)
apply (frule_tac [6] Gets_Server_message_form [THEN disjE])
apply (simp_all (no_asm_simp) add: less_SucI analz_insert_eq analz_insert_freshK pushes)
txt{*Fake*}
apply spy_analz
txt{*BK2*}
apply (blast intro: parts_insertI less_SucI)
txt{*BK3*}
apply (case_tac "Aa \<in> bad")
 prefer 2 apply (blast dest: Kab_authentic unique_session_keys)
apply (blast dest: Gets_imp_knows_Spy [THEN analz.Inj] Crypt_Spy_analz_bad elim!: MPair_analz intro: less_SucI)
txt{*Oops: PROOF FAILS if unsafe intro below*}
apply (blast dest: unique_session_keys intro!: less_SucI)
done

text{*Confidentiality for the Server: Spy does not see the keys sent in msg BK2
as long as they have not expired.*}
lemma Confidentiality_S_temporal:
     "\<lbrakk> Says Server A
          (Crypt K' \<lbrace>Number T, Agent B, Key K, X\<rbrace>) \<in> set evs;
         \<not> expiredK T evs;
         A \<notin> bad;  B \<notin> bad;  evs \<in> bankerb_gets
      \<rbrakk> \<Longrightarrow> Key K \<notin> analz (knows Spy evs)"
apply (frule Says_Server_message_form, assumption)
apply (blast intro: lemma_conf_temporal)
done

text{*Confidentiality for Alice*}
lemma Confidentiality_A_temporal:
     "\<lbrakk> Crypt (shrK A) \<lbrace>Number T, Agent B, Key K, X\<rbrace> \<in> parts (knows Spy evs);
         \<not> expiredK T evs;
         A \<notin> bad;  B \<notin> bad;  evs \<in> bankerb_gets
      \<rbrakk> \<Longrightarrow> Key K \<notin> analz (knows Spy evs)"
by (blast dest!: Kab_authentic Confidentiality_S_temporal)

text{*Confidentiality for Bob*}
lemma Confidentiality_B_temporal:
     "\<lbrakk> Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>
          \<in> parts (knows Spy evs);
        \<not> expiredK Tk evs;
        A \<notin> bad;  B \<notin> bad;  evs \<in> bankerb_gets
      \<rbrakk> \<Longrightarrow> Key K \<notin> analz (knows Spy evs)"
by (blast dest!: ticket_authentic Confidentiality_S_temporal)

text{*Temporal treatment of authentication*}

text{*Authentication of A to B*}
lemma B_authenticates_A_temporal:
     "\<lbrakk> Crypt K \<lbrace>Agent A, Number Ta\<rbrace> \<in> parts (knows Spy evs);
         Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>
         \<in> parts (knows Spy evs);
         \<not> expiredK Tk evs;
         A \<notin> bad;  B \<notin> bad;  evs \<in> bankerb_gets \<rbrakk>
      \<Longrightarrow> Says A B \<lbrace>Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>,
                     Crypt K \<lbrace>Agent A, Number Ta\<rbrace>\<rbrace> \<in> set evs"
by (blast dest!: ticket_authentic
          intro!: lemma_A
          elim!: Confidentiality_S_temporal [THEN [2] rev_notE])

text{*Authentication of B to A*}
lemma A_authenticates_B_temporal:
     "\<lbrakk> Crypt K (Number Ta) \<in> parts (knows Spy evs);
         Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, X\<rbrace>
         \<in> parts (knows Spy evs);
         \<not> expiredK Tk evs;
         A \<notin> bad;  B \<notin> bad;  evs \<in> bankerb_gets \<rbrakk>
      \<Longrightarrow> Says B A (Crypt K (Number Ta)) \<in> set evs"
by (blast dest!: Kab_authentic
          intro!: lemma_B elim!: Confidentiality_S_temporal [THEN [2] rev_notE])

subsection{*Combined guarantees of key distribution and non-injective agreement on the session keys*}

lemma B_authenticates_and_keydist_to_A:
     "\<lbrakk> Gets B \<lbrace>Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>,
                Crypt K \<lbrace>Agent A, Number Ta\<rbrace>\<rbrace> \<in> set evs;
        Key K \<notin> analz (spies evs);
        A \<notin> bad;  B \<notin> bad;  evs \<in> bankerb_gets \<rbrakk>
    \<Longrightarrow> Says A B \<lbrace>Crypt (shrK B) \<lbrace>Number Tk, Agent A, Key K\<rbrace>,
                  Crypt K \<lbrace>Agent A, Number Ta\<rbrace>\<rbrace> \<in> set evs
     \<and>  Key K \<in> analz (knows A evs)"
apply (blast dest: B_authenticates_A BK3_imp_Gets Gets_A_knows_K)
done

lemma A_authenticates_and_keydist_to_B:
     "\<lbrakk> Gets A (Crypt (shrK A) \<lbrace>Number Tk, Agent B, Key K, Ticket\<rbrace>) \<in> set evs;
        Gets A (Crypt K (Number Ta)) \<in> set evs;
        Key K \<notin> analz (spies evs);
        A \<notin> bad;  B \<notin> bad;  evs \<in> bankerb_gets \<rbrakk>
    \<Longrightarrow> Says B A (Crypt K (Number Ta)) \<in> set evs
    \<and>   Key K \<in> analz (knows B evs)"
apply (blast dest: A_authenticates_B BK4_imp_Gets Gets_B_knows_K)
done

end


(*  Title:      Jinja/BV/SemiType.thy

    Author:     Tobias Nipkow, Gerwin Klein
    Copyright   2000 TUM
*)

section \<open> The Jinja Type System as a Semilattice \<close>

theory SemiType
imports "../Common/WellForm" Jinja.Semilattices
begin

definition super :: "'a prog \<Rightarrow> cname \<Rightarrow> cname"
where "super P C \<equiv> fst (the (class P C))"

lemma superI:
  "(C,D) \<in> subcls1 P \<Longrightarrow> super P C = D"
  by (unfold super_def) (auto dest: subcls1D)

primrec the_Class :: "ty \<Rightarrow> cname"
where
  "the_Class (Class C) = C"

definition sup :: "'c prog \<Rightarrow> ty \<Rightarrow> ty \<Rightarrow> ty err"
where
  "sup P T\<^sub>1 T\<^sub>2 \<equiv>
  if is_refT T\<^sub>1 \<and> is_refT T\<^sub>2 then
  OK (if T\<^sub>1 = NT then T\<^sub>2 else
      if T\<^sub>2 = NT then T\<^sub>1 else
      (Class (exec_lub (subcls1 P) (super P) (the_Class T\<^sub>1) (the_Class T\<^sub>2))))
  else
  (if T\<^sub>1 = T\<^sub>2 then OK T\<^sub>1 else Err)"

lemma sup_def':
  "sup P = (\<lambda>T\<^sub>1 T\<^sub>2.
  if is_refT T\<^sub>1 \<and> is_refT T\<^sub>2 then
  OK (if T\<^sub>1 = NT then T\<^sub>2 else
      if T\<^sub>2 = NT then T\<^sub>1 else
      (Class (exec_lub (subcls1 P) (super P) (the_Class T\<^sub>1) (the_Class T\<^sub>2))))
  else
  (if T\<^sub>1 = T\<^sub>2 then OK T\<^sub>1 else Err))"
  by (simp add: sup_def fun_eq_iff)

abbreviation
  subtype :: "'c prog \<Rightarrow> ty \<Rightarrow> ty \<Rightarrow> bool"
  where "subtype P \<equiv> widen P"

definition esl :: "'c prog \<Rightarrow> ty esl"
where
  "esl P \<equiv> (types P, subtype P, sup P)"

(* FIXME: move to wellform *)
lemma is_class_is_subcls:
  "wf_prog m P \<Longrightarrow> is_class P C = P \<turnstile> C \<preceq>\<^sup>* Object"
(*<*)by (fastforce simp:is_class_def
                  elim: subcls_C_Object converse_rtranclE subcls1I
                  dest: subcls1D)
(*>*)

(* FIXME: move to wellform *)
lemma subcls_antisym:
  "\<lbrakk>wf_prog m P; P \<turnstile> C \<preceq>\<^sup>* D; P \<turnstile> D \<preceq>\<^sup>* C\<rbrakk> \<Longrightarrow> C = D"
  (*<*) by (auto dest: acyclic_subcls1 acyclic_impl_antisym_rtrancl antisymD) (*>*)

(* FIXME: move to wellform *)
lemma widen_antisym:
  "\<lbrakk> wf_prog m P; P \<turnstile> T \<le> U; P \<turnstile> U \<le> T \<rbrakk> \<Longrightarrow> T = U"
(*<*)
apply (cases T)
 apply (cases U)
 apply auto
apply (cases U)
 apply (auto elim!: subcls_antisym)
done
(*>*)

lemma order_widen [intro,simp]:
  "wf_prog m P \<Longrightarrow> order (subtype P)  (types P)"
(*<*)
  apply (unfold Semilat.order_def lesub_def)
  apply (auto intro: widen_trans widen_antisym)
  done
(*>*)

(* FIXME: move to TypeRel *)
lemma NT_widen:
  "P \<turnstile> NT \<le> T = (T = NT \<or> (\<exists>C. T = Class C))"
(*<*) by (cases T) auto (*>*)

(* FIXME: move to TypeRel *)
lemma Class_widen2: "P \<turnstile> Class C \<le> T = (\<exists>D. T = Class D \<and> P \<turnstile> C \<preceq>\<^sup>* D)"
(*<*) by (cases T) auto (*>*)

lemma wf_converse_subcls1_impl_acc_subtype:
  "wf ((subcls1 P)^-1) \<Longrightarrow> acc (subtype P)"
(*<*)
apply (unfold Semilat.acc_def lesssub_def)
apply (drule_tac p = "(subcls1 P)^-1 - Id" in wf_subset)
 apply blast
apply (drule wf_trancl)
apply (simp add: wf_eq_minimal)
apply clarify
apply (unfold lesub_def)
apply (rename_tac M T)
apply (case_tac "\<exists>C. Class C \<in> M")
 prefer 2
 apply (case_tac T)
     apply fastforce
    apply fastforce
   apply fastforce
  apply simp
  apply (rule_tac x = NT in bexI)
   apply (rule allI)
   apply (rule impI, erule conjE)
   apply (clarsimp simp add: NT_widen)
  apply simp
 apply clarsimp
apply (erule_tac x = "{C. Class C : M}" in allE)
apply auto
apply (rename_tac D)
apply (rule_tac x = "Class D" in bexI)
 prefer 2
 apply assumption
apply clarify
apply (clarsimp simp: Class_widen2)
apply (insert rtrancl_r_diff_Id [symmetric, of "subcls1 P"])
apply simp
apply (erule rtranclE)
 apply blast
apply (drule rtrancl_converseI)
apply (subgoal_tac "((subcls1 P)-Id)^-1 = ((subcls1 P)^-1 - Id)")
 prefer 2
 apply blast
apply simp
apply (blast intro: rtrancl_into_trancl2)
done
(*>*)

lemma wf_subtype_acc [intro, simp]:
  "wf_prog wf_mb P \<Longrightarrow> acc (subtype P)"
(*<*) by (rule wf_converse_subcls1_impl_acc_subtype, rule wf_subcls1) (*>*)

lemma exec_lub_refl [simp]: "exec_lub r f T T = T"
(*<*) by (simp add: exec_lub_def while_unfold) (*>*)

lemma closed_err_types:
  "wf_prog wf_mb P \<Longrightarrow> closed (err (types P)) (lift2 (sup P))"
(*<*)
  apply (unfold closed_def plussub_def lift2_def sup_def')
  apply (frule acyclic_subcls1)
  apply (frule single_valued_subcls1)
  apply (auto simp: is_type_def is_refT_def is_class_is_subcls split: err.split ty.splits)
  apply (blast dest!: is_lub_exec_lub is_lubD is_ubD intro!: is_ubI superI)
  done
(*>*)

lemma sup_subtype_greater:
  "\<lbrakk> wf_prog wf_mb P; is_type P t1; is_type P t2; sup P t1 t2 = OK s \<rbrakk>
  \<Longrightarrow> subtype P t1 s \<and> subtype P t2 s"
(*<*)
proof -
  assume wf_prog: "wf_prog wf_mb P"

  { fix c1 c2
    assume is_class: "is_class P c1" "is_class P c2"
    with wf_prog
    obtain
      "P \<turnstile> c1 \<preceq>\<^sup>* Object"
      "P \<turnstile> c2 \<preceq>\<^sup>* Object"
      by (blast intro: subcls_C_Object)
    with single_valued_subcls1[OF wf_prog]
    obtain u where
      "is_lub ((subcls1 P)^* ) c1 c2 u"
      by (blast dest: single_valued_has_lubs)
    moreover
    note acyclic_subcls1[OF wf_prog]
    moreover
    have "\<forall>x y. (x, y) \<in> subcls1 P \<longrightarrow> super P x = y"
      by (blast intro: superI)
    ultimately
    have "P \<turnstile> c1 \<preceq>\<^sup>* exec_lub (subcls1 P) (super P) c1 c2 \<and>
          P \<turnstile> c2 \<preceq>\<^sup>* exec_lub (subcls1 P) (super P) c1 c2"
      by (simp add: exec_lub_conv) (blast dest: is_lubD is_ubD)
  } note this [simp]

  assume "is_type P t1" "is_type P t2" "sup P t1 t2 = OK s"
  thus ?thesis
    apply (unfold sup_def)
    apply (cases s)
    apply (auto simp add: is_refT_def split: if_split_asm)
    done
qed
(*>*)

lemma sup_subtype_smallest:
  "\<lbrakk> wf_prog wf_mb P; is_type P a; is_type P b; is_type P c;
      subtype P a c; subtype P b c; sup P a b = OK d \<rbrakk>
  \<Longrightarrow> subtype P d c"
(*<*)
proof -
  assume wf_prog: "wf_prog wf_mb P"

  { fix c1 c2 D
    assume is_class: "is_class P c1" "is_class P c2"
    assume le: "P \<turnstile> c1 \<preceq>\<^sup>* D" "P \<turnstile> c2 \<preceq>\<^sup>* D"
    from wf_prog is_class
    obtain
      "P \<turnstile> c1 \<preceq>\<^sup>* Object"
      "P \<turnstile> c2 \<preceq>\<^sup>* Object"
      by (blast intro: subcls_C_Object)
    with single_valued_subcls1[OF wf_prog]
    obtain u where
      lub: "is_lub ((subcls1 P)^* ) c1 c2 u"
      by (blast dest: single_valued_has_lubs)
    with acyclic_subcls1[OF wf_prog]
    have "exec_lub (subcls1 P) (super P) c1 c2 = u"
      by (blast intro: superI exec_lub_conv)
    moreover
    from lub le
    have "P \<turnstile> u \<preceq>\<^sup>* D"
      by (simp add: is_lub_def is_ub_def)
    ultimately
    have "P \<turnstile> exec_lub (subcls1 P) (super P) c1 c2 \<preceq>\<^sup>* D"
      by blast
  } note this [intro]

  have [dest!]:
    "\<And>C T. P \<turnstile> Class C \<le> T \<Longrightarrow> \<exists>D. T=Class D \<and> P \<turnstile> C \<preceq>\<^sup>* D"
    by (frule Class_widen, auto)

  assume "is_type P a" "is_type P b" "is_type P c"
         "subtype P a c" "subtype P b c" "sup P a b = OK d"
  thus ?thesis
    by (auto simp add: sup_def is_refT_def
             split: if_split_asm)
qed
(*>*)

lemma sup_exists:
  "\<lbrakk> subtype P a c; subtype P b c \<rbrakk> \<Longrightarrow> \<exists>T. sup P a b = OK T"
(*<*)
apply (unfold sup_def)
apply (cases b)
apply auto
apply (cases a)
apply auto
apply (cases a)
apply auto
done
(*>*)

lemma err_semilat_JType_esl:
  "wf_prog wf_mb P \<Longrightarrow> err_semilat (esl P)"
(*<*)
proof -
  assume wf_prog: "wf_prog wf_mb P"
  hence "order (subtype P) (types P)"..
  moreover from wf_prog
  have "closed (err (types P)) (lift2 (sup P))"
    by (rule closed_err_types)
  moreover
  from wf_prog have
    "(\<forall>x\<in>err (types P). \<forall>y\<in>err (types P). x \<sqsubseteq>\<^bsub>Err.le (subtype P)\<^esub> x \<squnion>\<^bsub>lift2 (sup P)\<^esub> y) \<and>
     (\<forall>x\<in>err (types P). \<forall>y\<in>err (types P). y \<sqsubseteq>\<^bsub>Err.le (subtype P)\<^esub> x \<squnion>\<^bsub>lift2 (sup P)\<^esub> y)"
    by (auto simp add: lesub_def plussub_def Err.le_def lift2_def sup_subtype_greater split: err.split)
  moreover from wf_prog have
    "\<forall>x\<in>err (types P). \<forall>y\<in>err (types P). \<forall>z\<in>err (types P).
    x \<sqsubseteq>\<^bsub>Err.le (subtype P)\<^esub> z \<and> y \<sqsubseteq>\<^bsub>Err.le (subtype P)\<^esub> z \<longrightarrow> x \<squnion>\<^bsub>lift2 (sup P)\<^esub> y \<sqsubseteq>\<^bsub>Err.le (subtype P)\<^esub> z"
    by (unfold lift2_def plussub_def lesub_def Err.le_def)
       (auto intro: sup_subtype_smallest dest:sup_exists split: err.split)
  ultimately show ?thesis by (simp add: esl_def semilat_def sl_def Err.sl_def)
qed
(*>*)

end


theory prop_21
imports Main
        "$HIPSTER_HOME/IsaHipster"
begin
  datatype Nat = Z | S "Nat"
  fun plus :: "Nat => Nat => Nat" where
  "plus (Z) y = y"
  | "plus (S z) y = S (plus z y)"
  fun le :: "Nat => Nat => bool" where
  "le (Z) y = True"
  | "le (S z) (Z) = False"
  | "le (S z) (S x2) = le z x2"

(*hipster plus*)

  (*hipster plus le *)
  theorem x0 :
    "le n (plus n m)"
    by (tactic \<open>Subgoal.FOCUS_PARAMS (K (Tactic_Data.hard_tac @{context})) @{context} 1\<close>)
end


theory goal
	imports "processDef"
begin

(*Assistance for defining goal, user may need to modify it for proof.*)
consts
pre :: fform
post :: fform
H :: fform

(*Goal for the whole process.*)
lemma goal : "{pre,pre} P {post,post; H,H}"
sorry

end


theory VDMRT
  imports SimpleFMI
begin

alphabet vrt_st =
  ctdown :: "real pos"

notation vrt_st_child_lens ("\<Sigma>\<^sub>v")

type_synonym '\<alpha> vrel = "('\<alpha> vrt_st_ext) trel"

translations
  (type) "'\<alpha> vrel" <= (type) "('\<alpha> vrt_st_ext) trel"

text {* A periodic thread takes a positive real $n$ denoting the period and a relation P acting on
  the VDM-RT state-space. It checks if the internal variable \emph{ctdown} is 0, and if so executes
  the body of the relation and afterwards sets the countdown to period $n$. If countdown is non-zero
  then it picks an amount of time strictly greater than 0 and less than or equal to the current
  countdown amount and decrements this. It also updates the global clock to reflect this. The
  behaviour is then iterated. *}

(*
definition PeriodicBody :: "real pos \<Rightarrow> '\<alpha> vrt_st_scheme hrel \<Rightarrow> '\<alpha> vrel" where
[upred_defs]:
  "PeriodicBody n P =
    ([P]\<^sub>S ;; ctdown :=\<^sub>r \<guillemotleft>n\<guillemotright>)
      \<triangleleft> &ctdown =\<^sub>u 0 \<triangleright>\<^sub>R
    (\<Sqinter> t | 0 <\<^sub>u \<guillemotleft>t\<guillemotright> \<and> \<guillemotleft>t\<guillemotright> \<le>\<^sub>u $st:ctdown \<bullet> ctdown :=\<^sub>r (&ctdown - \<guillemotleft>t\<guillemotright>) ;; wait\<^sub>r(\<guillemotleft>t\<guillemotright>))"
*)

definition PeriodicBody :: "real pos \<Rightarrow> '\<alpha> vrt_st_scheme hrel \<Rightarrow> '\<alpha> vrel" where
[upred_defs]:
  "PeriodicBody n P =
    (wait\<^sub>r(&ctdown) ;; [P]\<^sub>S ;; ctdown :=\<^sub>r \<guillemotleft>n\<guillemotright>)
     \<sqinter>
    (\<Sqinter> t | 0 <\<^sub>u \<guillemotleft>t\<guillemotright> \<and> \<guillemotleft>t\<guillemotright> <\<^sub>u $st:ctdown \<bullet> ctdown :=\<^sub>r (&ctdown - \<guillemotleft>t\<guillemotright>) ;; wait\<^sub>r(\<guillemotleft>t\<guillemotright>))"

definition Periodic :: "real pos \<Rightarrow> '\<alpha> vrt_st_scheme hrel \<Rightarrow> '\<alpha> vrel" where
[upred_defs]:
  "Periodic n P = (PeriodicBody n P)\<^sup>\<star>\<^sup>r"

lemma PeriodicBody_RR_closed [closure]:
  "PeriodicBody n P is RR"
  by (rel_auto)

lemma Periodic_RR_closed [closure]:
  "Periodic n P is RR"
  by (simp add: Periodic_def closure)

definition VDMRT_FMU :: "real pos \<Rightarrow> '\<alpha> vrt_st_scheme hrel \<Rightarrow> '\<alpha> vrt_st_scheme fmu" where
[upred_defs]:
"VDMRT_FMU n P = \<lparr> fmiInstantiate = (ctdown := \<guillemotleft>n\<guillemotright>)
                 , fmiDoStep = PeriodicBody n P \<rparr>"

lemma fmiInstantiate_VDMRT_FMU [simp]:
  "fmiInstantiate (VDMRT_FMU n P) = ctdown := \<guillemotleft>n\<guillemotright>"
  by (simp add: VDMRT_FMU_def)

lemma fmiDoStep_VDMRT_FMU [simp]:
  "fmiDoStep (VDMRT_FMU n P) = PeriodicBody n P"
  by (simp add: VDMRT_FMU_def)

text {* If a larger time step than the current countdown time is requested, or the time step is 0
  then the behaviour is miraculuous (it isn't possible). Otherwise, if the countdown timer is equal
  to the step then the thread body is executed and then the timer is reset. Otherwise the
  timer is decremented. *}

lemma Step_VDMRT [step_simps]:
      "Step t (VDMRT_FMU n P) =
       false \<triangleleft> &ctdown <\<^sub>u \<guillemotleft>t\<guillemotright> \<or> \<guillemotleft>t\<guillemotright> =\<^sub>u 0 \<triangleright>\<^sub>R
       (([P]\<^sub>S ;; ctdown :=\<^sub>r \<guillemotleft>n\<guillemotright>) \<triangleleft> &ctdown =\<^sub>u \<guillemotleft>t\<guillemotright> \<triangleright>\<^sub>R (ctdown :=\<^sub>r (&ctdown - \<guillemotleft>t\<guillemotright>)))"
  by (rel_auto, simp_all add: neq_zero_impl_greater)

end