Theory RS_Trace_Model_CSP

(***********************************************************************************
 * Copyright (c) 2025 Université Paris-Saclay
 *
 * Author: Benoît Ballenghien, Université Paris-Saclay,
           CNRS, ENS Paris-Saclay, LMF
 * Author: Benjamin Puyobro, Université Paris-Saclay,
           IRT SystemX, CNRS, ENS Paris-Saclay, LMF
 * Author: Burkhart Wolff, Université Paris-Saclay,
           CNRS, ENS Paris-Saclay, LMF
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * SPDX-License-Identifier: BSD-2-Clause
 ***********************************************************************************)


section ‹Trace Model of CSP›

(*<*)
theory RS_Trace_Model_CSP
  imports Restriction_Spaces "HOL-Library.Prefix_Order"
begin 
  (*>*)

text ‹
In the AFP one can already find ‹HOL-CSP›, a shallow embedding of the failure-divergence
model of denotational semantics proposed by Hoare, Roscoe and Brookes in the eighties.
Here, we simplify the example by restraining ourselves to a trace model.›

subsection ‹Prerequisites›

datatype 'a event = ev (of_ev : 'a) | tick ()

type_synonym 'a trace = 'a event list


definition tickFree :: 'a trace  bool (tF)
  where tickFree t    set t

definition front_tickFree :: 'a trace  bool (ftF)
  where front_tickFree s  s = []  tickFree (tl (rev s))


lemma tickFree_Nil        [simp] : tF []
  and tickFree_Cons_iff   [simp] : tF (a # t)  a    tF t
  and tickFree_append_iff [simp] : tF (s @ t)  tF s     tF t
  and tickFree_rev_iff    [simp] : tF (rev t)  tF t
  and non_tickFree_tick   [simp] : ¬ tF []
  by (auto simp add: tickFree_def)

lemma tickFree_iff_is_map_ev : tF t  (u. t = map ev u)
  by (metis event.collapse event.distinct(1) ex_map_conv tickFree_def)

lemma front_tickFree_Nil   [simp] : ftF []
  and front_tickFree_single[simp] : ftF [a]
  by (simp_all add: front_tickFree_def)


lemma tickFree_tl : tF s  tF (tl s)
  by (cases s) simp_all

lemma non_tickFree_imp_not_Nil: ¬ tF s  s  []
  using tickFree_Nil by blast

lemma tickFree_butlast: tF s  tF (butlast s)  (s  []  last s  )
  by (induct s) simp_all

lemma front_tickFree_iff_tickFree_butlast: ftF s  tF (butlast s)
  by (induct s) (auto simp add: front_tickFree_def)

lemma front_tickFree_Cons_iff: ftF (a # s)  s = []  a    ftF s
  by (simp add: front_tickFree_iff_tickFree_butlast)

lemma front_tickFree_append_iff:
  ftF (s @ t)  (if t = [] then ftF s else tF s  ftF t)
  by (simp add: butlast_append front_tickFree_iff_tickFree_butlast)

lemma tickFree_imp_front_tickFree [simp] : tF s  ftF s
  by (simp add: front_tickFree_def tickFree_tl)

lemma front_tickFree_charn: ftF s  s = []  (a t. s = t @ [a]  tF t)
  by (cases s rule: rev_cases) (simp_all add: front_tickFree_def)


lemma nonTickFree_n_frontTickFree: ¬ tF s  ftF s  t r. s = t @ []
  by (metis front_tickFree_charn tickFree_Cons_iff
      tickFree_Nil tickFree_append_iff)

lemma front_tickFree_dw_closed : ftF (s @ t)  ftF s
  by (metis front_tickFree_append_iff tickFree_imp_front_tickFree)

lemma front_tickFree_append: tF s  ftF t  ftF (s @ t)
  by (simp add: front_tickFree_append_iff)

lemma tickFree_imp_front_tickFree_snoc: tF s  ftF (s @ [a])
  by (simp add: front_tickFree_append)

lemma front_tickFree_nonempty_append_imp: ftF (t @ r)  r  []  tF t  ftF r
  by (simp add: front_tickFree_append_iff)

lemma tickFree_map_ev [simp] : tF (map ev t)
  by (induct t) simp_all

lemma tickFree_map_ev_comp [simp] : tF (map (ev  f) t)
  by (metis list.map_comp tickFree_map_ev)

lemma front_tickFree_map_map_event_iff :
  ftF (map (map_event f) t)  ftF t
  by (induct t) (simp_all add: front_tickFree_Cons_iff)




definition is_process :: 'a trace set  bool
  where is_process T  []  T  (t. t  T  ftF t)  (t u. t @ u  T  t  T)

typedef 'a process = {T :: 'a trace set. is_process T}
  morphisms Traces to_process
proof (rule exI)
  show {[]}  {T. is_process T}
    by (simp add: is_process_def front_tickFree_def)
qed

setup_lifting type_definition_process


notation Traces (𝒯)

lemma is_process_inv :
  []  𝒯 P  (t. t  𝒯 P  ftF t)  (t u. t @ u  𝒯 P  t  𝒯 P)
  by (metis is_process_def mem_Collect_eq to_process_cases to_process_inverse)

lemma Nil_elem_T       : []  𝒯 P
  and front_tickFree_T : t  𝒯 P  ftF t
  and T_dw_closed      : t @ u  𝒯 P  t  𝒯 P
  by (simp_all add: is_process_inv)


lemma process_eq_spec : P = Q  𝒯 P = 𝒯 Q
  by transfer simp



subsection ‹First Processes›

lift_definition BOT :: 'a process is {t. ftF t}
  by (auto simp add: is_process_def front_tickFree_append_iff)

lemma T_BOT : 𝒯 BOT = {t. ftF t}
  by (simp add: BOT.rep_eq)


lift_definition SKIP :: 'a process is {[], []}
  by (simp add: is_process_def append_eq_Cons_conv)

lemma T_SKIP : 𝒯 SKIP = {[], []}
  by (simp add: SKIP.rep_eq)


lift_definition STOP :: 'a process is {[]}
  by (simp add: is_process_def)

lemma T_STOP : 𝒯 STOP = {[]}
  by (simp add: STOP.rep_eq)


lift_definition Sup_processes ::
  (nat  'a process)  'a process is λσ. i. 𝒯 (σ i)
proof -
  show is_process (i. 𝒯 (σ i)) for σ :: nat  'a process
  proof (unfold is_process_def, intro conjI allI impI)
    show []  (i. 𝒯 (σ i)) by (simp add: Nil_elem_T)
  next
    show t  (i. 𝒯 (σ i))  ftF t for t
      by (auto intro: front_tickFree_T)
  next
    show t @ u  (i. 𝒯 (σ i))  t  (i. 𝒯 (σ i)) for t u
      by (auto intro: T_dw_closed)
  qed
qed

lemma T_Sup_processes : 𝒯 (Sup_processes σ) = (i. 𝒯 (σ i))
  by (simp add: Sup_processes.rep_eq)



subsection ‹Instantiations›

instantiation process :: (type) order
begin

definition less_eq_process :: 'a process  'a process  bool
  where P  Q  𝒯 Q  𝒯 P

definition less_process :: 'a process  'a process  bool
  where P < Q  𝒯 Q  𝒯 P

instance
  by intro_classes
    (auto simp add: less_eq_process_def less_process_def process_eq_spec)

end


instantiation process :: (type) order_restriction_space
begin

lift_definition restriction_process :: 'a process  nat  'a process
  is λP n. 𝒯 P  {t @ u |t u. t  𝒯 P  length t = n  tF t  ftF u}
proof -
  show ?thesis P n (is is_process ?t) for P n
  proof (unfold is_process_def, intro conjI allI impI)
    show []  ?t by (simp add: Nil_elem_T)
  next
    show t  ?t  ftF t for t
      by (auto simp add: front_tickFree_append_iff front_tickFree_T)
  next
    fix t u assume t @ u  ?t
    then consider t @ u  𝒯 P
      | (@) t' u' where t @ u = t' @ u' t'  𝒯 P
        length t' = n tF t' ftF u' by blast
    thus t  ?t
    proof cases
      from T_dw_closed show t @ u  𝒯 P  t  ?t by blast
    next
      case @
      show t  ?t
      proof (cases length t  length t')
        assume length t  length t'
        with "@"(1) obtain t'' where t' = t @ t''
          by (metis append_eq_append_conv_if append_eq_conv_conj)
        with "@"(2) T_dw_closed show t  ?t by blast
      next
        assume ¬ length t  length t'
        hence length t'  length t by simp
        with "@"(1,4,5) ¬ length t  length t'
        obtain t'' where t = t' @ t'' ftF t''
          by (metis append_eq_conv_conj drop_eq_Nil front_tickFree_append
              front_tickFree_dw_closed front_tickFree_nonempty_append_imp
              take_all_iff take_append)
        with "@"(2,3,4) show t  ?t by blast
      qed
    qed
  qed
qed

lemma T_restriction_process :
  𝒯 (P  n) = 𝒯 P  {t @ u |t u. t  𝒯 P  length t = n  tF t  ftF u}
  by (simp add: restriction_process.rep_eq)


lemma restriction_process_0 [simp] : P  0 = BOT
  by transfer (auto simp add: front_tickFree_T Nil_elem_T)

lemma T_restriction_processE :
  t  𝒯 (P  n) 
   (t  𝒯 P  length t  n  thesis) 
   (u v. t = u @ v  u  𝒯 P  length u = n  tF u  ftF v  thesis) 
   thesis
  by (simp add: T_restriction_process)
    (metis (no_types) T_dw_closed append_take_drop_id drop_eq_Nil
      front_tickFree_T front_tickFree_nonempty_append_imp length_take min_def)


instance
proof intro_classes
  show P  0  Q  0 for P Q :: 'a process by simp
next
  show P  n  m = P  min n m for P :: 'a process and n m
  proof (subst process_eq_spec, intro subset_antisym subsetI)
    show t  𝒯 (P  n  m)  t  𝒯 (P  min n m) for t
      by (elim T_restriction_processE)
        (auto simp add: T_restriction_process intro: front_tickFree_append)
  next
    show t  𝒯 (P  min n m)  t  𝒯 (P  n  m) for t
      by (elim T_restriction_processE)
        (auto simp add: T_restriction_process min_def split: if_split_asm)
  qed
next
  show P  Q  P  n  Q  n for P Q :: 'a process and n
    by (auto simp add: less_eq_process_def T_restriction_process)
next
  fix P Q :: 'a process assume ¬ P  Q
  then obtain t where t  𝒯 Q t  𝒯 P
    unfolding less_eq_process_def by blast
  hence t  𝒯 (Q  Suc (length t))  t  𝒯 (P  Suc (length t))
    by (auto simp add: T_restriction_process) 
  hence ¬ P  Suc (length t)  Q  Suc (length t)
    unfolding less_eq_process_def by blast
  thus n. ¬ P  n  Q  n ..
qed


text ‹Of course, we recover the structure of classrestriction_space.›

lemma OFCLASS ('a process, restriction_space_class)
  by intro_classes

end


lemma restricted_Sup_processes_is :
  (λn. Sup_processes σ  n) = σ if restriction_chain σ
proof (subst (2) restricted_restriction_chain_is
    [OF restriction_chain σ, symmetric], rule ext)
  fix n
  have length t  n  t  𝒯 (σ n)  (i. t  𝒯 (σ i)) for t n
  proof safe
    show t  𝒯 (σ i) if length t  n t  𝒯 (σ n) for i
    proof (cases i  n)
      from restriction_chain_def_ter[THEN iffD1, OF restriction_chain σ]
      show i  n  t  𝒯 (σ i)
        by (metis (lifting) t  𝒯 (σ n) T_restriction_process Un_iff)
    next
      from length t  n t  𝒯 (σ n) show ¬ i  n  t  𝒯 (σ i)
        by (induct n, simp_all add: Nil_elem_T)
          (metis (no_types) T_restriction_processE
            append_eq_conv_conj linorder_linear take_all_iff
            restriction_chain_def_ter[THEN iffD1, OF restriction_chain σ])
    qed
  next
    show i. t  𝒯 (σ i)  t  𝒯 (σ n) by simp
  qed
  hence * : length t  n  t  𝒯 (σ n)  t  𝒯 (Sup_processes σ) for t n
    by (simp add: T_Sup_processes)

  show Sup_processes σ  n = σ n  n for n
  proof (subst process_eq_spec, intro subset_antisym subsetI)
    show t  𝒯 (Sup_processes σ  n)  t  𝒯 (σ n  n) for t
    proof (elim T_restriction_processE)
      show t  𝒯 (Sup_processes σ)  length t  n  t  𝒯 (σ n  n)
        by (simp add: "*" T_restriction_process)
    next
      show t = u @ v; u  𝒯 (Sup_processes σ); length u = n; tF u; ftF v
             t  𝒯 (σ n  n) for u v
        by (auto simp add: "*" T_restriction_process)
    qed
  next
    from "*" show t  𝒯 (σ n  n)  t  𝒯 (Sup_processes σ  n) for t
      by (elim T_restriction_processE)
        (auto simp add: T_restriction_process)
  qed
qed


instance process :: (type) complete_restriction_space 
proof intro_classes
  show restriction_convergent σ if restriction_chain σ
    for σ :: nat  'a process
  proof (rule restriction_convergentI)
    have σ = (λn. Sup_processes σ  n)
      by (simp add: restricted_Sup_processes_is restriction_chain σ)
    moreover have (λn. Sup_processes σ  n) ─↓→ Sup_processes σ
      by (fact restriction_tendsto_restrictions)
    ultimately show σ ─↓→ Sup_processes σ by simp
  qed
qed



subsection ‹Operators›

lift_definition Choice :: 'a process  'a process  'a process (infixl  82)
  is λP Q. 𝒯 P  𝒯 Q
  by (auto simp add: is_process_def Nil_elem_T front_tickFree_T intro: T_dw_closed)

lemma T_Choice : 𝒯 (P  Q) = 𝒯 P  𝒯 Q
  by (simp add: Choice.rep_eq)


lift_definition GlobalChoice :: ['b set, 'b  'a process]  'a process
  is λA P. if A = {} then {[]} else aA. 𝒯 (P a)
  by (auto simp add: is_process_def Nil_elem_T front_tickFree_T intro: T_dw_closed)

syntax "_GlobalChoice" :: [pttrn, 'b set, 'a process]  'a process
  ((3((_)/(_))./ (_)) [78,78,77] 77)
syntax_consts "_GlobalChoice"  GlobalChoice
translations  " a  A. P"  "CONST GlobalChoice A (λa. P)"

lemma T_GlobalChoice : 𝒯 (a  A. P a) = (if A = {} then {[]} else aA. 𝒯 (P a))
  by (simp add: GlobalChoice.rep_eq)


lift_definition Seq :: 'a process  'a process  'a process (infixl ; 74)
  is λP Q. {t  𝒯 P. tF t}  {t @ u |t u. t @ []  𝒯 P  u  𝒯 Q}
  by (auto simp add: is_process_def Nil_elem_T append_eq_append_conv2 intro: T_dw_closed)
    (metis front_tickFree_T front_tickFree_append_iff
      front_tickFree_dw_closed not_Cons_self,
      meson front_tickFree_append_iff is_process_inv snoc_eq_iff_butlast)

lemma T_Seq : 𝒯 (P ; Q) = {t  𝒯 P. tF t}  {t @ u |t u. t @ []  𝒯 P  u  𝒯 Q}
  by (simp add: Seq.rep_eq)


lift_definition Renaming :: ['a process, 'a  'b]  'b process
  is λP f. {map (map_event f) u |u. u  𝒯 P}
  by (auto simp add: is_process_def Nil_elem_T front_tickFree_map_map_event_iff
      front_tickFree_T append_eq_map_conv intro: T_dw_closed)

lemma T_Renaming : 𝒯 (Renaming P f) = {map (map_event f) u |u. u  𝒯 P}
  by (simp add: Renaming.rep_eq)


lift_definition Mprefix :: ['a set, 'a  'a process]  'a process
  is λA P. insert [] {ev a # t |a t. a  A  t  𝒯 (P a)}
  by (auto simp add: is_process_def front_tickFree_Cons_iff
      front_tickFree_T append_eq_Cons_conv intro: T_dw_closed)

syntax "_Mprefix" :: [pttrn, 'a set, 'a process]  'a process	
  ((3((_)/(_))/  (_)) [78,78,77] 77)
syntax_consts "_Mprefix"  Mprefix
translations "aA  P"  "CONST Mprefix A (λa. P)"

lemma T_Mprefix : 𝒯 (a  A  P a) = insert [] {ev a # t |a t. a  A  t  𝒯 (P a)}
  by (simp add: Mprefix.rep_eq)






fun setinterleaving :: 'a trace × 'a set × 'a trace  'a trace set
  where Nil_setinterleaving_Nil : setinterleaving ([], A, []) = {[]}

|     ev_setinterleaving_Nil :
  setinterleaving (ev a # u, A, []) =
         (if a  A then {} else {ev a # t| t. t  setinterleaving (u, A, [])})
|     tick_setinterleaving_Nil : setinterleaving ( # u, A, []) = {}

|     Nil_setinterleaving_ev :
  setinterleaving ([], A, ev b # v) =
         (if b  A then {} else {ev b # t| t. t  setinterleaving ([], A, v)})
|     Nil_setinterleaving_tick  : setinterleaving ([], A,  # v) = {}

|     ev_setinterleaving_ev : 
  setinterleaving (ev a # u, A, ev b # v) =
         (  if a  A
          then   if b  A 
                then   if a = b
                     then {ev a # t |t. t  setinterleaving (u, A, v)}
                     else {}
                else {ev b # t |t. t  setinterleaving (ev a # u, A, v)}
           else   if b  A then {ev a # t |t. t  setinterleaving (u, A, ev b # v)}
                else {ev a # t |t. t  setinterleaving (u, A, ev b # v)} 
                     {ev b # t |t. t  setinterleaving (ev a # u, A, v)})
|     ev_setinterleaving_tick :
  setinterleaving (ev a # u, A,  # v) =
         (if a  A then {} else {ev a # t |t. t  setinterleaving (u, A,  # v)})
|     tick_setinterleaving_ev :
  setinterleaving ( # u, A, ev b # v) =
         (if b  A then {} else {ev b # t |t. t  setinterleaving ( # u, A, v)})
|     tick_setinterleaving_tick :
  setinterleaving ( # u, A,  # v) = { # t |t. t  setinterleaving (u, A, v)}


lemmas setinterleaving_induct
  [case_names Nil_setinterleaving_Nil ev_setinterleaving_Nil tick_setinterleaving_Nil
    Nil_setinterleaving_ev Nil_setinterleaving_tick ev_setinterleaving_ev
    ev_setinterleaving_tick tick_setinterleaving_ev tick_setinterleaving_tick] =
  setinterleaving.induct



lemma Cons_setinterleaving_Nil :
  setinterleaving (e # u, A, []) =
   (case e of ev a  (  if a  A then {}
                       else {ev a # t |t. t  setinterleaving (u, A, [])})
            |   {})
  by (cases e) simp_all

lemma Nil_setinterleaving_Cons :
  setinterleaving ([], A, e # v) =
   (case e of ev a  (  if a  A then {}
                       else {ev a # t |t. t  setinterleaving ([], A, v)})
            |   {})
  by (cases e) simp_all

lemma Cons_setinterleaving_Cons :
  setinterleaving (e # u, A, f # v) =
   (case e of ev a 
    (case f of ev b  
       if a  A
     then   if b  A 
           then   if a = b
                then {ev a # t |t. t  setinterleaving (u, A, v)}
                else {}
           else {ev b # t |t. t  setinterleaving (ev a # u, A, v)}
      else   if b  A then {ev a # t |t. t  setinterleaving (u, A, ev b # v)}
           else {ev a # t |t. t  setinterleaving (u, A, ev b # v)} 
                {ev b # t |t. t  setinterleaving (ev a # u, A, v)}
             |     if a  A then {}
                    else {ev a # t |t. t  setinterleaving (u, A,  # v)})
            |  
    (case f of ev b    if b  A then {}
                       else {ev b # t| t. t  setinterleaving ( # u, A, v)}
             |   { # t |t. t  setinterleaving (u, A, v)}))
  by (cases e; cases f) simp_all


lemmas setinterleaving_simps =
  Cons_setinterleaving_Nil Nil_setinterleaving_Cons Cons_setinterleaving_Cons 



abbreviation setinterleaves ::
  ['a trace, 'a trace, 'a trace, 'a set]  bool
  ((_ /(setinterleaves)/ '(()'(_, _')(), _')) [63,0,0,0] 64)
  where t setinterleaves ((u, v), A)  t  setinterleaving (u, A, v)




lemma tickFree_setinterleaves_iff :
  t setinterleaves ((u, v), A)  tF t  tF u  tF v
  by (induct (u, A, v) arbitrary: t u v rule: setinterleaving_induct)
    (auto split: if_split_asm)

lemma setinterleaves_tickFree_imp :
  tF u  tF v  t setinterleaves ((u, v), A)  tF t  tF u  tF v
  by (elim disjE; induct (u, A, v) arbitrary: t u v rule: setinterleaving_induct)
    (auto split: if_split_asm)



lemma setinterleaves_NilL_iff :
  t setinterleaves (([], v), A) 
   tF v  set v  ev ` A = {}  t = map ev (map of_ev v)
  by (induct ([] :: 'a trace, A, v) arbitrary: t v rule: setinterleaving_induct)
    (auto split: if_split_asm)

lemma setinterleaves_NilR_iff :
  t setinterleaves ((u, []), A) 
   tF u  set u  ev ` A = {}  t = map ev (map of_ev u)
  by (induct (u, A, [] :: 'a trace)
      arbitrary: t u rule: setinterleaving_induct)
    (auto split: if_split_asm)

lemma Nil_setinterleaves :
  [] setinterleaves ((u, v), A)  u = []  v = []
  by (induct (u, A, v) arbitrary: u v rule: setinterleaving_induct)
    (simp_all split: if_split_asm)


lemma front_tickFree_setinterleaves_iff :
  t setinterleaves ((u, v), A)  ftF t  ftF u  ftF v
proof (induct (u, A, v) arbitrary: t u v rule: setinterleaving_induct)
  case (tick_setinterleaving_tick u v) thus ?case
    by (simp add: split: if_split_asm)
      (metis Nil_setinterleaves Nil_setinterleaving_Nil front_tickFree_Cons_iff singletonD)
qed (simp add: setinterleaves_NilL_iff setinterleaves_NilR_iff split: if_split_asm;
    metis event.simps(3) front_tickFree_Cons_iff front_tickFree_Nil)+


lemma setinterleaves_snoc_notinL :
  t setinterleaves ((u, v), A)  a  A 
   t @ [ev a] setinterleaves ((u @ [ev a], v), A)
  by (induct (u, A, v) arbitrary: t u v rule: setinterleaving_induct)
    (auto split: if_split_asm)

lemma setinterleaves_snoc_notinR :
  t setinterleaves ((u, v), A)  a  A 
   t @ [ev a] setinterleaves ((u, v @ [ev a]), A)
  by (induct (u, A, v) arbitrary: t u v rule: setinterleaving_induct)
    (auto split: if_split_asm)

lemma setinterleaves_snoc_inside :
  t setinterleaves ((u, v), A)  a  A 
   t @ [ev a] setinterleaves ((u @ [ev a], v @ [ev a]), A)
  by (induct (u, A, v) arbitrary: t u v rule: setinterleaving_induct)
    (auto split: if_split_asm)


lemma setinterleaves_snoc_tick :
  t setinterleaves ((u, v), A)  t @ [] setinterleaves ((u @ [], v @ []), A)
  by (induct (u, A, v) arbitrary: t u v rule: setinterleaving_induct)
    (auto split: if_split_asm)


lemma Cons_tick_setinterleavesE :
   # t setinterleaves ((u, v), A) 
   (u' v' r s. u =  # u'; v =  # v'; t setinterleaves ((u', v'), A)  thesis)  thesis
  by (induct (u, A, v) arbitrary: t u v rule: setinterleaving_induct)
    (simp_all split: if_split_asm)

lemma Cons_ev_setinterleavesE :
  ev a # t setinterleaves ((u, v), A) 
   (u'. a  A  u = ev a # u'  t setinterleaves ((u', v), A)  thesis) 
   (v'. a  A  v = ev a # v'  t setinterleaves ((u, v'), A)  thesis) 
   (u' v'. a  A  u = ev a # u'  v = ev a # v' 
             t setinterleaves ((u', v'), A)  thesis)  thesis
proof (induct (u, A, v) arbitrary: u v t rule: setinterleaving_induct)
  case Nil_setinterleaving_Nil thus ?case by simp
next
  case (ev_setinterleaving_Nil b u)
  from ev_setinterleaving_Nil.prems(1) show ?case
    by (simp add: ev_setinterleaving_Nil.prems(2) split: if_split_asm)
next
  case (tick_setinterleaving_Nil r u) thus ?case by simp
next
  case (Nil_setinterleaving_ev c v)
  from Nil_setinterleaving_ev.prems(1) show ?case
    by (simp add: Nil_setinterleaving_ev.prems(3) split: if_split_asm)
next
  case (Nil_setinterleaving_tick s v) thus ?case by simp
next
  case (ev_setinterleaving_ev b u c v)
  from ev_setinterleaving_ev.prems(1) show ?case
    by (simp add: ev_setinterleaving_ev.prems(2, 3, 4) split: if_split_asm)
      (use ev_setinterleaving_ev.prems(2, 3) in presburger)
next
  case (ev_setinterleaving_tick b u s v)
  from ev_setinterleaving_tick.prems(1) show ?case
    by (simp add: ev_setinterleaving_tick.prems(2) split: if_split_asm)
next
  case (tick_setinterleaving_ev r u c v)
  from tick_setinterleaving_ev.prems(1) show ?case
    by (simp add: tick_setinterleaving_ev.prems(3) split: if_split_asm)
next
  case (tick_setinterleaving_tick u v) thus ?case by simp
qed


lemma rev_setinterleaves_rev_rev_iff :
  rev t setinterleaves ((rev u, rev v), A)
    t setinterleaves ((u, v), A)
proof (rule iffI)
  show t setinterleaves ((u, v), A) 
        rev t setinterleaves ((rev u, rev v), A) for t u v
    by (induct (u, A, v) arbitrary: t u v rule: setinterleaving_induct)
      (auto simp add: setinterleaves_snoc_notinL setinterleaves_snoc_notinR
        setinterleaves_snoc_inside setinterleaves_snoc_tick split: if_split_asm)
  from this[of rev t rev u rev v, simplified]
  show rev t setinterleaves ((rev u, rev v), A) 
        t setinterleaves ((u, v), A) .
qed


lemma setinterleaves_preserves_ev_notin_set :
  ev a  set u; ev a  set v; t setinterleaves ((u, v), A)  ev a  set t
  by (induct (u, A, v) arbitrary: t u v rule: setinterleaving_induct)
    (auto split: if_split_asm)



lemma setinterleaves_preserves_ev_inside_set :
  ev a  set u; ev a  set v; t setinterleaves ((u, v), A)  ev a  set t
proof (induct (u, A, v) arbitrary: t u v rule: setinterleaving_induct)
  case Nil_setinterleaving_Nil
  then show ?case by simp
next
  case (ev_setinterleaving_Nil a u)
  then show ?case by simp
next
  case (tick_setinterleaving_Nil u)
  then show ?case by simp
next
  case (Nil_setinterleaving_ev b v)
  then show ?case by simp
next
  case (Nil_setinterleaving_tick v)
  then show ?case by simp
next
  case (ev_setinterleaving_ev a u b v)
  from ev_setinterleaving_ev.prems show ?case
    by (simp_all split: if_split_asm)
      (insert ev_setinterleaving_ev.hyps; metis list.set_intros(1,2))+
next
  case (ev_setinterleaving_tick a u v)
  then show ?case by (auto split: if_split_asm)
next
  case (tick_setinterleaving_ev u b v)
  then show ?case by (auto split: if_split_asm)
next
  case (tick_setinterleaving_tick u v)
  then show ?case by auto
qed


lemma ev_notin_both_sets_imp_empty_setinterleaving :
  ev a  set u  ev a  set v  ev a  set u  ev a  set v; a  A 
   setinterleaving (u, A, v) = {}
  by (induct (u, A, v) arbitrary: u v rule: setinterleaving_induct)
    (simp_all, safe, auto)


lemma append_setinterleaves_imp :
  t setinterleaves ((u, v), A)  t'  t 
   u'  u. v'  v. t' setinterleaves ((u', v'), A)
proof (induct (u, A, v) arbitrary: t u v t' rule: setinterleaving_induct)
  case Nil_setinterleaving_Nil thus ?case by auto
next
  case (ev_setinterleaving_Nil a u)
  from ev_setinterleaving_Nil.prems
  obtain w w' where a  A t = ev a # w t' = []  t' = ev a # w'
    w'  w w setinterleaves ((u, []), A)
    by (simp split: if_split_asm) (metis (no_types) Prefix_Order.prefix_Cons Nil_prefix)
  from t' = []  t' = ev a # w' show ?case
  proof (elim disjE)
    show t' = []  ?case by auto
  next
    assume t' = ev a # w'
    from ev_setinterleaving_Nil.hyps[OF a  A w setinterleaves ((u, []), A) w'  w]
    obtain u' v' where u'  u  v'  []  w' setinterleaves ((u', v'), A) by blast
    hence ev a # u'  ev a # u  v'  []  t' setinterleaves ((ev a # u', v'), A)
      by (auto simp add: a  A t' = ev a # w')
    thus ?case by blast
  qed
next
  case (tick_setinterleaving_Nil r u) thus ?case by simp
next
  case (Nil_setinterleaving_ev b v)
  from Nil_setinterleaving_ev.prems
  obtain w w' where b  A t = ev b # w t' = []  t' = ev b # w'
    w'  w w setinterleaves (([], v), A)
    by (simp split: if_split_asm) (metis (no_types) Prefix_Order.prefix_Cons Nil_prefix)
  from t' = []  t' = ev b # w' show ?case
  proof (elim disjE)
    show t' = []  ?case by auto
  next
    assume t' = ev b # w'
    from Nil_setinterleaving_ev.hyps[OF b  A w setinterleaves (([], v), A) w'  w]
    obtain u' v' where u'  []  v'  v  w' setinterleaves ((u', v'), A) by blast
    hence u'  []  ev b # v'  ev b # v  t' setinterleaves ((u', ev b # v'), A)
      by (auto simp add: b  A t' = ev b # w')
    thus ?case by blast
  qed
next
  case (Nil_setinterleaving_tick s v) thus ?case by simp
next
  case (ev_setinterleaving_ev a u b v)
  from ev_setinterleaving_ev.prems
  consider t' = []
    |      (both_in)   w w' where a  A b  A a = b t = ev a # w t' = ev a # w'
      w setinterleaves ((u, v), A) w'  w
    |      (inR_mvL)   w w' where a  A b  A t = ev a # w t' = ev a # w'
      w setinterleaves ((u, ev b # v), A) w'  w
    |      (inL_mvR)   w w' where a  A b  A t = ev b # w t' = ev b # w'
      w setinterleaves ((ev a # u, v), A) w'  w
    |      (notin_mvL) w w' where a  A b  A t = ev a # w t' = ev a # w'
      w setinterleaves ((u, ev b # v), A) w'  w
    |      (notin_mvR) w w' where a  A b  A t = ev b # w t' = ev b # w'
      w setinterleaves ((ev a # u, v), A) w'  w
    by (cases t') (auto split: if_split_asm)
  thus ?case
  proof cases
    from Nil_setinterleaving_Nil show t' = []  ?thesis by blast
  next
    case both_in
    from ev_setinterleaving_ev(1)[OF both_in(1-3, 6-7)]
    obtain u' v' where u'  u  v'  v  w' setinterleaves ((u', v'), A) by blast
    hence ev a # u'  ev a # u  ev b # v'  ev b # v  t' setinterleaves ((ev a # u', ev b # v'), A)
      by (auto simp add: both_in(2, 3) t' = ev a # w')
    thus ?thesis by blast
  next
    case inR_mvL
    from ev_setinterleaving_ev(3)[OF inR_mvL(1, 2, 5, 6)]
    obtain u' v' where u'  u  v'  ev b # v  w' setinterleaves ((u', v'), A) by blast
    hence ev a # u'  ev a # u  v'  ev b # v  t' setinterleaves ((ev a # u', v'), A)
      by (cases v') (auto simp add: inR_mvL(1, 4))
    thus ?thesis by blast
  next
    case inL_mvR
    from ev_setinterleaving_ev(2)[OF inL_mvR(1, 2, 5, 6)]
    obtain u' v' where u'  ev a # u  v'  v  w' setinterleaves ((u', v'), A) by blast
    hence u'  ev a # u  ev b # v'  ev b # v  t' setinterleaves ((u', ev b # v'), A)
      by (cases u') (auto simp add: inL_mvR(2, 4))
    thus ?thesis by blast
  next
    case notin_mvL
    from ev_setinterleaving_ev(4)[OF notin_mvL(1, 2, 5, 6)]
    obtain u' v' where u'  u  v'  ev b # v  w' setinterleaves ((u', v'), A) by blast
    hence ev a # u'  ev a # u  v'  ev b # v  t' setinterleaves ((ev a # u', v'), A)
      by (cases v') (auto simp add: notin_mvL(1, 4))
    thus ?thesis by blast
  next
    case notin_mvR
    from ev_setinterleaving_ev(5)[OF notin_mvR(1, 2, 5, 6)]
    obtain u' v' where u'  ev a # u  v'  v  w' setinterleaves ((u', v'), A) by blast
    hence u'  ev a # u  ev b # v'  ev b # v  t' setinterleaves ((u', ev b # v'), A)
      by (cases u') (auto simp add: notin_mvR(2, 4))
    thus ?thesis by blast
  qed
next
  case (ev_setinterleaving_tick a u v)
  from ev_setinterleaving_tick.prems
  obtain w w' where a  A t = ev a # w t' = []  t' = ev a # w'
    w'  w w setinterleaves ((u,  # v), A)
    by (simp split: if_split_asm) (metis (no_types) Prefix_Order.prefix_Cons Nil_prefix)
  from t' = []  t' = ev a # w' show ?case
  proof (elim disjE)
    from Nil_setinterleaving_Nil show t' = []  ?case by blast
  next
    assume t' = ev a # w'
    from ev_setinterleaving_tick.hyps[OF a  A w setinterleaves ((u,  # v), A) w'  w]
    obtain u' v' where u'  u  v'   # v  w' setinterleaves ((u', v'), A) by blast
    hence ev a # u'  ev a # u  v'   # v  t' setinterleaves ((ev a # u', v'), A)
      by (cases v') (simp_all add: a  A t' = ev a # w')
    thus ?case by blast
  qed
next
  case (tick_setinterleaving_ev u b v)
  from tick_setinterleaving_ev.prems
  obtain w w' where b  A t = ev b # w t' = []  t' = ev b # w'
    w'  w w setinterleaves (( # u, v), A)
    by (simp split: if_split_asm) (metis (no_types) Prefix_Order.prefix_Cons Nil_prefix)
  from t' = []  t' = ev b # w' show ?case
  proof (elim disjE)
    from Nil_setinterleaving_Nil show t' = []  ?case by blast
  next
    assume t' = ev b # w'
    from tick_setinterleaving_ev.hyps[OF b  A w setinterleaves (( # u, v), A) w'  w]
    obtain u' v' where u'   # u  v'  v  w' setinterleaves ((u', v'), A) by blast
    hence u'   # u  ev b # v'  ev b # v  t' setinterleaves ((u', ev b # v'), A)
      by (cases u') (simp_all add: b  A t' = ev b # w')
    thus ?case by blast
  qed
next
  case (tick_setinterleaving_tick u v)
  from tick_setinterleaving_tick.prems obtain w w'
    where t =  # w t' = []  t' =  # w'
      w'  w w setinterleaves ((u, v), A)
    by (cases t') (auto split: option.split_asm)
  from t' = []  t' =  # w' show ?case
  proof (elim disjE)
    from Nil_setinterleaving_Nil show t' = []  ?case by blast
  next
    assume t' =  # w'
    from tick_setinterleaving_tick.hyps
      [OF w setinterleaves ((u, v), A) w'  w]
    obtain u' v' where u'  u  v'  v  w' setinterleaves ((u', v'), A) by blast
    hence  # u'   # u   # v'   # v 
           t' setinterleaves (( # u',  # v'), A)
      by (simp add: t' =  # w')
    thus ?case by blast
  qed
qed



lift_definition Sync :: 'a process  'a set  'a process  'a process
  ((3(_ _/ _)) [70, 0, 71] 70)
  is λP A Q. {t. t_P t_Q. t_P  𝒯 P  t_Q  𝒯 Q  t setinterleaves ((t_P, t_Q), A)}
proof -
  show ?thesis P A Q (is is_process ?t) for P A Q
  proof (unfold is_process_def, intro conjI allI impI)
    from Nil_elem_T Nil_setinterleaving_Nil show []  ?t by blast
  next
    fix t assume t  ?t
    then obtain t_P t_Q where t_P  𝒯 P t_Q  𝒯 Q
      t setinterleaves ((t_P, t_Q), A) by blast
    from t_P  𝒯 P t_Q  𝒯 Q front_tickFree_T
    have ftF t_P ftF t_Q by auto
    with t setinterleaves ((t_P, t_Q), A)
    show ftF t by (simp add: front_tickFree_setinterleaves_iff)
  next
    fix t u assume t @ u  ?t
    then obtain t_P t_Q where t_P  𝒯 P t_Q  𝒯 Q
      t @ u setinterleaves ((t_P, t_Q), A) by blast
    from this(3) obtain t_P' t_P'' t_Q' t_Q''
      where t_P = t_P' @ t_P'' t_Q = t_Q' @ t_Q''
        t setinterleaves ((t_P', t_Q'), A)
      by (meson Prefix_Order.prefixE Prefix_Order.prefixI append_setinterleaves_imp)
    from t_P  𝒯 P t_Q  𝒯 Q this(1, 2) have t_P'  𝒯 P t_Q'  𝒯 Q
      by (auto intro: T_dw_closed)
    with t setinterleaves ((t_P', t_Q'), A) show t  ?t by blast
  qed
qed

lemma T_Sync :
  𝒯 (P A Q) = {t. t_P t_Q. t_P  𝒯 P  t_Q  𝒯 Q  t setinterleaves ((t_P, t_Q), A)}
  by (simp add: Sync.rep_eq)


lift_definition Interrupt :: 'a process  'a process  'a process (infixl  81)
  is λP Q. 𝒯 P  {t @ u |t u. t  𝒯 P  tF t  u  𝒯 Q}
proof -
  show ?thesis P Q (is is_process ?t) for P Q
  proof (unfold is_process_def, intro conjI allI impI)
    show []  ?t by (simp add: Nil_elem_T)
  next
    show t  ?t  ftF t for t
      by (auto simp add: front_tickFree_append_iff intro: front_tickFree_T)
  next
    show t @ u  ?t  t  ?t for t u
      by (auto simp add: append_eq_append_conv2 intro: T_dw_closed)
  qed
qed





subsection ‹Constructiveness›

lemma restriction_process_Mprefix :
  a  A  P a  n = (case n of 0  BOT | Suc m  aA  (P a  m))
  by (auto simp add: process_eq_spec T_restriction_process T_Mprefix T_BOT
      Nil_elem_T nat.case_eq_if front_tickFree_Cons_iff front_tickFree_T)
    (metis Cons_eq_append_conv Suc_length_conv event.distinct(1) length_greater_0_conv
      list.size(3) nat.exhaust_sel tickFree_Cons_iff)


lemma constructive_Mprefix [simp] :
  constructive (λb. aA  f a b) if a. a  A  non_destructive (f a)
proof -
  have aA  f a b = aA  (if a  A then f a b else STOP) for b
    by (auto simp add: process_eq_spec T_Mprefix)
  moreover have constructive (λb. aA  (if a  A then f a b else STOP))
  proof (rule constructive_comp_non_destructive[of λP. aA  P a])
    show constructive (λP. aA  P a)
      by (rule constructiveI) (simp add: restriction_process_Mprefix restriction_fun_def)
  next
    show non_destructive (λb a. if a  A then f a b else STOP)
      by (simp add: non_destructive_fun_iff, intro allI non_destructive_if_then_else)
        (simp_all add: a. a  A  non_destructive (f a) non_destructiveI)
  qed
  ultimately show constructive (λb. aA  f a b) by simp
qed






subsection ‹Non Destructiveness›

lemma non_destructive_Choice [simp] :
  non_destructive (λx. f x  g x)
  if non_destructive f non_destructive g
  for f g :: 'a :: restriction  'b process
proof -
  have * : non_destructive (λ(P, Q). P  Q :: 'b process)
  proof (rule order_non_destructiveI, clarify)
    fix P Q P' Q' :: 'b process and n
    assume (P, Q)  n = (P', Q')  n
    hence P  n = P'  n Q  n = Q'  n
      by (simp_all add: restriction_prod_def)
    show P  Q  n  P'  Q'  n
    proof (unfold less_eq_process_def, rule subsetI)
      show t  𝒯 (P'  Q'  n)  t  𝒯 (P  Q  n) for t
      proof (elim T_restriction_processE)
        show t  𝒯 (P'  Q')  length t  n  t  𝒯 (P  Q  n)
          by (simp add: T_restriction_process T_Choice)
            (metis (lifting) T_restriction_process T_restriction_processE
              Un_iff P  n = P'  n Q  n = Q'  n)
      next
        show t = u @ v; u  𝒯 (P'  Q'); length u = n; tF u; ftF v
               t  𝒯 (P  Q  n) for u v
          by (simp add: T_restriction_process T_Choice)
            (metis (lifting) T_restriction_process T_restriction_processE Un_iff
              P  n = P'  n Q  n = Q'  n append.right_neutral append_eq_conv_conj)
      qed
    qed
  qed
  have ** : non_destructive (λx. (f x, g x))
    by (fact non_destructive_prod_codomain[OF that])
  from non_destructive_comp_non_destructive[OF * **, simplified]
  show non_destructive (λx. f x  g x) .
qed


lemma restriction_process_GlobalChoice :
  a  A. P a  n = (if A = {} then case n of 0  BOT | Suc m  STOP else a  A. (P a  n))
  by (auto simp add: process_eq_spec T_restriction_process T_GlobalChoice T_BOT T_STOP
      split: nat.split)


lemma non_destructive_GlobalChoice [simp] :
  non_destructive (λb. aA. f a b) if a. a  A  non_destructive (f a)
proof -
  have aA. f a b = aA. (if a  A then f a b else STOP) for b
    by (auto simp add: process_eq_spec T_GlobalChoice)
  moreover have non_destructive (λb. aA. (if a  A then f a b else STOP))
  proof (rule non_destructive_comp_non_destructive[of λP. aA. P a])
    show non_destructive (λP. aA. P a)
      by (rule non_destructiveI) (simp add: restriction_process_GlobalChoice restriction_fun_def)
  next
    show non_destructive (λb a. if a  A then f a b else STOP)
      by (simp add: non_destructive_fun_iff, intro allI non_destructive_if_then_else)
        (simp_all add: a. a  A  non_destructive (f a) non_destructiveI)
  qed
  ultimately show non_destructive (λb. aA. f a b) by simp
qed



subsection ‹Examples›

notepad begin
  fix A B :: 'b  'a set
  define P :: 'b  'a process
    where P  υ X. (λs.  a  A s  X s  ( b  B s  X s)) (is P  υ X. ?f X)
  have P = ?f P
    by (unfold P_def, subst restriction_fix_eq) simp_all

end


lemma constructive (λX σ.  e  f σ   σ'  g σ e. X σ')
  by simp



lemma length_le_T_restriction_process_iff_T :
  length t  n  t  𝒯 (P  n)  t  𝒯 P
  by (auto simp add: T_restriction_process)



lemma restriction_adm_notin_T [simp] : adm (λa. t  𝒯 a)
proof (rule restriction_admI)
  fix σ and Σ assume σ ─↓→ Σ n. t  𝒯 (σ n)
  from σ ─↓→ Σ obtain n0 where kn0. Σ  length t = σ k  length t
    by (blast dest: restriction_tendstoD)
  hence kn0. 𝒯 (Σ  length t) = 𝒯 (σ k  length t) by simp
  hence kn0. t  𝒯 Σ  t  𝒯 (σ k)
    by (metis dual_order.refl length_le_T_restriction_process_iff_T)
  with n. t  𝒯 (σ n) show t  𝒯 Σ by blast
qed


lemma restriction_adm_in_T [simp] : adm (λa. t  𝒯 a)
proof (rule restriction_admI)
  fix σ and Σ assume σ ─↓→ Σ n. t  𝒯 (σ n)
  from σ ─↓→ Σ obtain n0 where kn0. Σ  length t = σ k  length t
    by (blast dest: restriction_tendstoD)
  hence kn0. 𝒯 (Σ  length t) = 𝒯 (σ k  length t) by simp
  hence kn0. t  𝒯 Σ  t  𝒯 (σ k)
    by (metis dual_order.refl length_le_T_restriction_process_iff_T)
  with n. t  𝒯 (σ n) show t  𝒯 Σ by blast
qed


(*<*)
end
  (*>*)