Theory Compactification_Synchronization_Product

(***********************************************************************************
 * Copyright (c) 2025 Université Paris-Saclay
 *
 * Author: Benoît Ballenghien, Université Paris-Saclay,
 *         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
 ***********************************************************************************)


chapter ‹Compactification of Synchronization Product›

(*<*)
theory Compactification_Synchronization_Product
  imports Combining_Synchronization_Product Process_Normalization_Properties
begin
  (*>*)


section ‹Iterated Combine›

subsection ‹Definitions›

fun iterated_combined_Sync :: 'e set  (, 'e, 'r) Ad list  ( list, 'e, 'r) Ad (d⨂⟦_ _ [0, 0])
  where d⨂⟦E [] = τ = λσs a. , ω = λσs. 
  |     d⨂⟦E [A0] = dA0σσs
  |     d⨂⟦E A0 # A1 # As = A0 d⊗⟦ERlist d⨂⟦E A1 # As

fun iterated_combinend_Sync :: 'e set  (, 'e, 'r) And list  ( list, 'e, 'r) And (nd⨂⟦_ _ [0, 0])
  where nd⨂⟦E [] = τ = λσs a. {}, ω = λσs. {}
  |     nd⨂⟦E [A0] = ndA0σσs
  |     nd⨂⟦E A0 # A1 # As = A0 nd⊗⟦ERlist nd⨂⟦E A1 # As


lemma iterated_combined_Sync_simps_bis: As  []  d⨂⟦E A0 # As = A0 d⊗⟦ERlist d⨂⟦E As
  and iterated_combinend_Sync_simps_bis: Bs  []  nd⨂⟦E B0 # Bs = B0 nd⊗⟦ERlist nd⨂⟦E Bs
  by (induct As, simp_all) (induct Bs, simp_all)


fun iterated_combined_Sync_ε :: (, 'e, 'r, ) Ad_scheme list  'e set   list  'e set
  where iterated_combined_Sync_ε [] E σs = {} 
  |     iterated_combined_Sync_ε [A0] E σs = ε A0 (hd σs)
  |     iterated_combined_Sync_ε (A0 # A1 # As) E σs = 
         combine_sets_Sync (ε A0 (hd σs)) E (iterated_combined_Sync_ε (A1 # As) E (tl σs))

fun iterated_combinend_Sync_ε :: (, 'e, 'r, ) And_scheme list  'e set   list  'e set
  where iterated_combinend_Sync_ε [] E σs = {} 
  |     iterated_combinend_Sync_ε [A0] E σs = ε A0 (hd σs)
  |     iterated_combinend_Sync_ε (A0 # A1 # As) E σs = 
         combine_sets_Sync (ε A0 (hd σs)) E (iterated_combinend_Sync_ε (A1 # As) E (tl σs))


lemma iterated_combined_Sync_ε_simps_bis:
  As  []  iterated_combined_Sync_ε (A0 # As) E σs = 
                combine_sets_Sync (ε A0 (hd σs)) E (iterated_combined_Sync_ε As E (tl σs))
  and iterated_combinend_Sync_ε_simps_bis: 
  Bs  []  iterated_combinend_Sync_ε (B0 # Bs) E σs = 
                 combine_sets_Sync (ε B0 (hd σs)) E (iterated_combinend_Sync_ε Bs E (tl σs))
  by (induct As, simp_all) (induct Bs, simp_all)



subsection ‹First Results›

lemma ε_iterated_combined_Sync:
  length σs = length As  ε d⨂⟦E As σs = iterated_combined_Sync_ε As E σs
  by (induct σs As rule: induct_2_lists012)
    (simp_all add: ε_combineRlist_Sync combine_Sync_ε_def)

lemma ε_iterated_combinend_Sync:
  length σs = length Bs  ε nd⨂⟦E Bs σs = iterated_combinend_Sync_ε Bs E σs
  by (induct σs Bs rule: induct_2_lists012)
    (simp_all add: ε_combineRlist_Sync combine_Sync_ε_def)


lemma combineListslenL_Sync_combineRlist_Sync_eq:
  ε dA0σσs d⊗⟦1, EListslenL A1 σs = ε A0 d⊗⟦ERlist A1 σs
  τ dA0σσs d⊗⟦1, EListslenL A1 (s0 # σs) e = τ A0 d⊗⟦ERlist A1 (s0 # σs) e
  ε ndB0σσs nd⊗⟦1, EListslenL B1 σs = ε B0 nd⊗⟦ERlist B1 σs
  τ ndB0σσs nd⊗⟦1, EListslenL B1 (s0 # σs) e = τ B0 nd⊗⟦ERlist B1 (s0 # σs) e
  by (simp_all add: ε_combineListslenL_Sync ε_combineRlist_Sync drop_Suc combine_Sync_ε_def,
      auto simp add: combineListslenL_Sync_defs combineRlist_Sync_defs σ_σs_conv_defs ε_simps) 
    (metis append_Cons append_Nil)



lemma combinePairlist_Sync_and_iterated_combinend_Sync_eq:
  ε A0 d⊗⟦EPairlist A1 [s0, s1] = ε d⨂⟦E [A0, A1] [s0, s1]
  τ A0 d⊗⟦EPairlist A1 [s0, s1] e = τ d⨂⟦E [A0, A1] [s0, s1] e
  ε B0 nd⊗⟦EPairlist B1 [s0, s1] = ε nd⨂⟦E [B0, B1] [s0, s1]
  τ B0 nd⊗⟦EPairlist B1 [s0, s1] e = τ nd⨂⟦E [B0, B1] [s0, s1] e
  by (simp_all add: ε_combinePairlist_Sync ε_combineRlist_Sync)
    (auto simp add: combinePairlist_Sync_defs combineRlist_Sync_defs σ_σs_conv_defs 
      option.case_eq_if ε_simps combine_Sync_ε_def)



lemmas combinePairlist_Sync_and_combineRlist_Sync_eq =
  combinePairlist_Sync_and_iterated_combinend_Sync_eq[simplified]



subsection ‹Reachability›

lemma same_length_ℛd_iterated_combined_Sync_description:
  length σs = length As  σs'  d d⨂⟦E As σs 
   length σs' = length As  (i < length As. σs' ! i  d (As ! i) (σs ! i))
proof (induct σs As arbitrary: σs' rule: induct_2_lists012)
  case Nil thus ?case by simp
next
  case (single σ1 A1)
  thus ?case by (auto simp add: d_from_σ_to_σs_description)
next
  case (Cons σ1 σ2 σs A1 A2 As)
  from set_mp[OF d_combinedRlist_Sync_subset, OF Cons.prems[simplified]]
  obtain σ1' σs'' where σs' = σ1' # σs'' σ1'  d A1 σ1
    σs''  d d⨂⟦E A2 # As (σ2 # σs) by blast
  from Cons.hyps(3)[OF this(3)] this(1, 2)
  show ?case using less_Suc_eq_0_disj nth_Cons_0 nth_Cons_Suc by simp auto
qed


lemma same_length_ℛnd_iterated_combinend_Sync_description:
  length σs = length Bs  σs'  nd nd⨂⟦E Bs σs 
   length σs' = length Bs  (i < length Bs. σs' ! i  nd (Bs ! i) (σs ! i))
proof (induct σs Bs arbitrary: σs' rule: induct_2_lists012)
  case Nil thus ?case by simp
next
  case (single σ1 B1)
  thus ?case by (auto simp add: nd_from_σ_to_σs_description)
next
  case (Cons σ1 σ2 σs A1 A2 As)
  from set_mp[OF nd_combinendRlist_Sync_subset, OF Cons.prems[simplified]]
  obtain σ1' σs'' where σs' = σ1' # σs'' σ1'  nd A1 σ1
    σs''  nd nd⨂⟦E A2 # As (σ2 # σs) by blast
  from Cons.hyps(3)[OF this(3)] this(1, 2)
  show ?case using less_Suc_eq_0_disj nth_Cons_0 nth_Cons_Suc by simp auto
qed



subsection ‹Transmission of Properties›

lemma finite_trans_transmission_to_iterated_combinend_Sync:
  (A. A  set As  finite_trans A)  finite_trans nd⨂⟦E As
  by (induct As rule: induct_list012) 
    (auto simp add: σ_σs_conv_defs combineRlist_Sync_defs finite_trans_def finite_image_set2)

lemma ρ_disjoint_ε_transmission_to_iterated_combined_Sync:
  (A. A  set As  ρ_disjoint_ε A)  ρ_disjoint_ε d⨂⟦E As
  by (induct As rule: induct_list012)
    (simp_all add: ρ_combineRlist_Sync ε_combineRlist_Sync ρ_disjoint_ε_def combine_Sync_ε_def)

lemma ρ_disjoint_ε_transmission_to_iterated_combinend_Sync:
  (A. A  set As  ρ_disjoint_ε A)  ρ_disjoint_ε nd⨂⟦E As
  by (induct As rule: induct_list012)
    (simp_all add: ρ_combineRlist_Sync ε_combineRlist_Sync ρ_disjoint_ε_def combine_Sync_ε_def)

lemma at_most_1_elem_term_transmission_to_iterated_combinend_Sync:
  (A. A  set As  at_most_1_elem_term A)  at_most_1_elem_term nd⨂⟦E As
  by (induct As rule: induct_list012,
      simp_all add: at_most_1_elem_term_def σ_σs_conv_defs combineRlist_Sync_defs)
    fastforce


lemma same_length_indep_transmission_to_iterated_combined_Sync:
  length σs = length As 
   (i j. i  length As  j  length As  i  j  
   indep_enabl ((A0 # As) ! i) ((s0 # σs) ! i) E ((A0 # As) ! j) ((s0 # σs) ! j)) 
   indep_enabl A0 s0 E d⨂⟦E As σs
proof (induct σs As rule: induct_2_lists012)
  case Nil
  then show ?case by (simp add: indep_enablI)
next
  case (single σ1 A1)
  from single.prems[of 0 1] show ?case
    by (auto simp add: d_from_σ_to_σs_description
        intro!: indep_enablI dest!: indep_enablD)
next
  case (Cons σ1 σ2 σs A1 A2 As)
  show ?case
  proof (rule indep_enablI)
    fix t0 ts assume assms : t0  d A0 s0 ts  d d⨂⟦E A1 # A2 # As (σ1 # σ2 # σs)
    from assms(2) obtain t1 ts' where ts = t1 # ts'
      by (metis Cons.hyps(1) Zero_not_Suc length_Cons list.exhaust_sel list.size(3)
          same_length_ℛd_iterated_combined_Sync_description)
    with assms(2)[simplified, THEN set_mp[OF d_combinedRlist_Sync_subset]]
    have ts'  d d⨂⟦E A2 # As (σ2 # σs) by simp

    have indep_enabl A0 s0 E d⨂⟦E A2 # As (σ2 # σs)
    proof (rule Cons.hyps(3))
      show i  length (A2 # As)  j  length (A2 # As)  i  j 
            indep_enabl ((A0 # A2 # As) ! i) ((s0 # σ2 # σs) ! i) E
                            ((A0 # A2 # As) ! j) ((s0 # σ2 # σs) ! j) for i j
        using Cons.prems[of if i = 0 then 0 else Suc i if j = 0 then 0 else Suc j]
        by (cases i; cases j) simp_all
    qed
    from this[THEN indep_enablD, OF assms(1) ts'  d d⨂⟦E A2 # As (σ2 # σs)]
    have ε A0 t0  ε d⨂⟦E A2 # As ts'  E .
    moreover from Cons.prems[THEN indep_enablD, of 0 Suc 0 t0 t1]
      assms(2)[simplified, THEN set_mp[OF d_combinedRlist_Sync_subset]] assms(1)
    have ε A0 t0  ε A1 t1  E by (simp add: ts = t1 # ts')
    ultimately show ε A0 t0  ε d⨂⟦E A1 # A2 # As ts  E
      by (auto simp add: ε_combineRlist_Sync ts = t1 # ts' combine_Sync_ε_def)
  qed
qed


lemma ω_iterated_combined_Sync :
  length σs = length As 
   ω d⨂⟦E As σs = (case those (map2 ω As σs) of   
    | terms  if card (set terms) = Suc 0 then THE r. set terms = {r} else )
  by (induct σs As rule: induct_2_lists012)
    (auto simp add: σ_σs_conv_defs combineRlist_Sync_defs card_1_singleton_iff the_equality split: option.split)

lemma ω_iterated_combinend_Sync :
  length σs = length As 
   ω nd⨂⟦E As σs = (if As = [] then {} else {r. i < length As. r  ω (As ! i) (σs ! i)})
proof (induct σs As rule: induct_2_lists012)
  case Nil show ?case by simp
next
  case (single σ1 A1)
  from length_Suc_conv show ?case
    by (auto simp add: σ_σs_conv_defs)
next
  case (Cons σ1 σ2 σs A1 A2 As)
  show ?case (is _ = ?rhs σ1 σ2 σs A1 A2 As)
  proof (intro subset_antisym subsetI)
    fix r assume r  ω nd⨂⟦E A1 # A2 # As (σ1 # σ2 # σs)
    hence r  ω A1 σ1 r  ω nd⨂⟦E A2 # As (σ2 # σs)
      by (simp_all add: combineRlist_Sync_defs split: if_split_asm)
    from this(2) have i<Suc (length As). r  ω ((A2 # As) ! i) ((σ2 # σs) ! i)
      by (simp add: Cons.hyps(3))
    with r  ω A1 σ1 show r  ?rhs σ1 σ2 σs A1 A2 As
      by (auto simp add: less_Suc_eq_0_disj)
  next
    from Cons.hyps(3)
    show r  ?rhs σ1 σ2 σs A1 A2 As 
          r  ω nd⨂⟦E A1 # A2 # As (σ1 # σ2 # σs) for r
      by (auto simp add: combineRlist_Sync_defs)
  qed
qed


subsection ‹Normalization›

lemma ω_iterated_combinend_Sync_det_ndet_conv:
  length σs = length As 
   ω nd⨂⟦E map (λA. Adnd) As σs = ω d⨂⟦E Asdnd σs
proof (induct σs As rule: induct_2_lists012)
  case Nil
  show ?case by (simp add: base_trans_det_ndet_conv(1))
next
  case (single σ1 A1)
  show ?case by (simp add: from_det_to_ndet_σ_σs_conv_commute)
next
  case (Cons σ1 σ2 σs A1 A2 As)
  thus ?case
    by (auto simp add: det_ndet_conv_defs combineRlist_Sync_defs split: option.split)
qed

lemma τ_iterated_combinend_Sync_behaviour_when_indep:
  length σs = length As 
   (i j. i < length As; j < length As; i  j
     indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j))  
   τ d⨂⟦E Asdnd σs e = τ nd⨂⟦E map (λA. Adnd) As σs e
proof (induct σs As rule: induct_2_lists012)
  case Nil
  show ?case by simp
next
  case (single σ1 A1)
  show ?case by (simp add: from_det_to_ndet_σ_σs_conv_commute(1))
next
  case (Cons σ1 σ2 σs A1 A2 As)
  have * : τ d⨂⟦E A2 # Asdnd (σ2 # σs) e =
            τ nd⨂⟦E map (λA. Adnd) (A2 # As) (σ2 # σs) e
  proof (rule Cons.hyps(3))
    show i < length (A2 # As); j < length (A2 # As); i  j
           indep_enabl ((A2 # As) ! i) ((σ2 # σs) ! i) E
                              ((A2 # As) ! j) ((σ2 # σs) ! j) for i j
      using Cons.prems[of Suc i Suc j] by simp
  qed
  have τ d⨂⟦E A1 # A2 # Asdnd (σ1 # σ2 # σs) e =
        τ A1dnd nd⊗⟦ERlist d⨂⟦E A2 # Asdnd (σ1 # σ2 # σs) e
  proof (subst iterated_combined_Sync.simps(3), rule τ_combineRlist_Sync_behaviour_when_indep)
    show ε A1 σ1  ε d⨂⟦E A2 # As (σ2 # σs)  E
    proof (rule indep_enablD[OF _ d.init d.init])
      show indep_enabl A1 σ1 E d⨂⟦E A2 # As (σ2 # σs)
        by (simp add: Cons.hyps(1) Cons.prems order_le_less_trans
            same_length_indep_transmission_to_iterated_combined_Sync)
    qed
  qed
  also have  = τ nd⨂⟦E map (λA. Adnd) (A1 # A2 # As) (σ1 # σ2 # σs) e
    by (use "*" in simp add: combineRlist_Sync_defs ε_simps)
      (metis empty_from_det_to_ndet_is_None_trans option.exhaust)
  finally show ?case .
qed



lemma PSKIPS_iterated_combinend_Sync_behaviour_when_indep:
  assumes same_length: length σs = length As
    and indep: i j. i < length As; j < length As; i  j 
                      indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)
  shows PSKIPSd⨂⟦E Asd σs = PSKIPSnd⨂⟦E map (λA. Adnd) Asnd σs
proof (fold PSKIPS_nd_from_det_to_ndet_is_PSKIPS_d, rule PSKIPS_nd_eqI_strong_id)
  show σs'  nd d⨂⟦E Asdnd σs 
        τ nd⨂⟦E map (λA. Adnd) As σs' e = τ d⨂⟦E Asdnd σs' e for σs' e
  proof (rule τ_iterated_combinend_Sync_behaviour_when_indep[symmetric])
    show σs'  nd d⨂⟦E Asdnd σs  length σs' = length As
      by (metis nd_from_det_to_ndet same_length same_length_ℛd_iterated_combined_Sync_description)
  next
    show σs'  nd d⨂⟦E Asdnd σs; i < length As; j < length As; i  j
           indep_enabl (As ! i) (σs' ! i) E (As ! j) (σs' ! j) for i j
      by (subst (asm) nd_from_det_to_ndet,
          drule same_length_ℛd_iterated_combined_Sync_description[OF same_length])
        (meson d_trans indep_enabl_def indep)
  qed
next
  show σs'  nd d⨂⟦E Asdnd σs 
        ω nd⨂⟦E map (λA. Adnd) As σs' = ω d⨂⟦E Asdnd σs' for σs'
    by (metis nd_from_det_to_ndet ω_iterated_combinend_Sync_det_ndet_conv same_length
        same_length_ℛd_iterated_combined_Sync_description)
qed


lemma P_d_iterated_combinend_Sync_behaviour_when_indep:
  assumes same_length: length σs = length As
    and indep: i j. i < length As; j < length As; i  j 
                      indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)
  shows P⟪d⨂⟦E Asd σs = P⟪nd⨂⟦E map (λA. Adnd) Asnd σs
proof (fold P_nd_from_det_to_ndet_is_P_d, rule P_nd_eqI_strong_id)
  show σs'  nd d⨂⟦E Asdnd σs 
        τ nd⨂⟦E map (λA. Adnd) As σs' e = τ d⨂⟦E Asdnd σs' e for σs' e
  proof (rule τ_iterated_combinend_Sync_behaviour_when_indep[symmetric])
    show σs'  nd d⨂⟦E Asdnd σs  length σs' = length As
      by (metis nd_from_det_to_ndet same_length same_length_ℛd_iterated_combined_Sync_description)
  next
    show σs'  nd d⨂⟦E Asdnd σs; i < length As; j < length As; i  j
           indep_enabl (As ! i) (σs' ! i) E (As ! j) (σs' ! j) for i j
      by (subst (asm) nd_from_det_to_ndet,
          drule same_length_ℛd_iterated_combined_Sync_description[OF same_length])
        (meson d_trans indep_enabl_def indep)
  qed
qed



section ‹Compactification Theorems›

subsection ‹Binary›

subsubsection ‹Pair›

theorem PSKIPS_nd_combinePair_Sync :
  fixes E :: 'a set and A0 :: (, 'a, 'r, ) And_scheme
  assumes ρ_disjoint_ε : ρ_disjoint_ε A0 ρ_disjoint_ε A1
    and at_most_1_elem_term : at_most_1_elem_term A0 at_most_1_elem_term A1
  defines A_def: A  A0 nd⊗⟦EPair A1      
  defines P_def: P  PSKIPSA0nd and Q_def: Q  PSKIPSA1nd and S_def: S  PSKIPSAnd
  shows P σ0 E Q σ1 = S (σ0, σ1)
proof -
  let ?f = PSKIPS_nd_step (ε A) (τ A) (ω A) (λσ'. case σ' of (σ0, σ1)  P σ0 E Q σ1)
  note cartprod_rwrt = GlobalNdet_cartprod[of _ _ λx y. _ (x, y), simplified]
  note Ndet_and_Sync = Sync_distrib_GlobalNdet_left
    Sync_distrib_GlobalNdet_right
  note Mprefix_Sync_constant =
    SKIP_Sync_Mprefix Mprefix_Sync_SKIP
    STOP_Sync_Mprefix Mprefix_Sync_STOP
  note P_rec = restriction_fix_eq[OF PSKIPS_nd_step_constructive_bis[of A0], folded PSKIPS_nd_def P_def, THEN fun_cong]
  note Q_rec = restriction_fix_eq[OF PSKIPS_nd_step_constructive_bis[of A1], folded PSKIPS_nd_def Q_def, THEN fun_cong]
  have ω_A : ω A (σ0', σ1') = ω A0 σ0'  ω A1 σ1' for σ0' σ1'
    by (auto simp add: A_def combinePair_Sync_defs)
  have ε_A : ε A (σ0', σ1') = combine_sets_Sync (ε A0 σ0') E (ε A1 σ1') for σ0' σ1'
    by (simp add: A_def ε_combinePair_Sync combine_Sync_ε_def)
  have Mprefix_Sync_Mprefix_for_procomata :
    aA  P a E bB  Q b =
     (a(A - E - B)  (P a E bB  Q b))                            
     (b(B - E - A)  (aA  P a E Q b))                            
     (x(A  B - E)  (P x E bB  Q b)  (aA  P a E Q x)) 
     (x(A  B  E)  (P x E Q x)) (is ?eq) for A B and P Q :: 'a  ('a, 'r) processptick
  proof -
    have  * : a(A - E)  (P a E bB  Q b) =
              (a(A - E - B)  (P a E bB  Q b)) 
              (a(A  B - E)  (P a E bB  Q b))
      by (metis Diff_Int2 Diff_Int_distrib2 Mprefix_Un_distrib Un_Diff_Int)
    have ** : b(B - E)  (aA  P a E Q b) =
               (b(B - E - A)  (aA  P a E Q b)) 
               (b(A  B - E)  (aA  P a E Q b))
      by (metis (no_types) Int_Diff Int_commute Mprefix_Un_distrib Un_Diff_Int)
    have aA  P a E bB  Q b =
          (a(A - E - B)  (P a E bB  Q b))    
          (b(B - E - A)  (aA  P a E Q b))    
          ((a(A  B - E)  (P a E bB  Q b))   
           (b(A  B - E)  (aA  P a E Q b)))  
          (x(A  B  E)  (P x E Q x))
      unfolding Mprefix_Sync_Mprefix
      by (auto simp add: "**" Det_assoc intro!: arg_cong[where f = λP. P  _])
        (subst (3) Det_commute, subst Det_assoc,
          auto simp add: "*" Det_commute intro: arg_cong[where f = λP. P  _])
    also have (a(A  B - E)  (P a E bB  Q b)) 
                (b(A  B - E)  (aA  P a E Q b)) =
                x(A  B - E)  ((P x E bB  Q b))  (aA  P a E Q x)
      by (simp add: Mprefix_Det_Mprefix, rule mono_Mprefix_eq, simp)
    finally show ?thesis .
  qed
  show P σ0 E Q σ1 = S (σ0, σ1)
  proof (rule fun_cong[of λ(σ0, σ1). P σ0 E Q σ1 _ (σ0, σ1), simplified])
    show (λ(σ0, σ1). P σ0 E Q σ1) = S
    proof (rule restriction_fix_unique[OF PSKIPS_nd_step_constructive_bis[of A],
          symmetric, folded PSKIPS_nd_def S_def])
      show ?f = (λ(σ0, σ1). P σ0 E Q σ1)
      proof (rule ext, clarify)
        have ρ_disjoint_ε_bis : ω A0 σ0  {}  ε A0 σ0 = {}
          ω A1 σ1  {}  ε A1 σ1 = {} for σ0 σ1
          by (simp_all add: ρ_simps ρ_disjoint_εD ρ_disjoint_ε)
        show ?f (σ0, σ1) = P σ0 E Q σ1 for σ0 σ1
        proof (cases ω A0 σ0 = {}; cases ω A1 σ1 = {})
          assume ω A0 σ0 = {} ω A1 σ1 = {}
          hence P_rec' : P σ0 = P_nd_step (ε A0) (τ A0) P σ0
            and Q_rec' : Q σ1 = P_nd_step (ε A1) (τ A1) Q σ1
            and S_rec' : PSKIPS_nd_step (ε A) (τ A) (ω A) (λ(σ0, σ1). P σ0 E Q σ1) (σ0, σ1) =
                        P_nd_step (ε A) (τ A) (λ(σ0, σ1). P σ0 E Q σ1) (σ0, σ1)
            by (simp_all add: P_rec[of σ0] Q_rec[of σ1] ω_A)
          show ?f (σ0, σ1) = P σ0 E Q σ1
            unfolding P_rec' Q_rec' S_rec' Mprefix_Sync_Mprefix_for_procomata
            unfolding ε_A Mprefix_Un_distrib
            by (intro arg_cong2[where f = (□)] mono_Mprefix_eq, fold P_rec' Q_rec',
                auto simp add: A_def Ndet_and_Sync cartprod_rwrt
                combinePair_Sync_defs ε_simps GlobalNdet_sets_commute[of τ A1 _ _]
                simp flip: GlobalNdet_factorization_union
                intro!: mono_GlobalNdet_eq arg_cong2[where f = (⊓)])
        next
          assume ω A0 σ0  {} ω A1 σ1 = {}
          from ρ_disjoint_ε(1) ω A0 σ0  {} have ε A0 σ0 = {}
            by (simp add: ρ_disjoint_ε_def ρ_simps)
          have ?f (σ0, σ1) = b(ε A1 σ1 - E)  (σ1'τ A1 σ1 b. (SKIPS (ω A0 σ0) E Q σ1'))
            by (auto simp add: ω_A ε_A ω A1 σ1 = {} ε A0 σ0 = {} intro!: mono_Mprefix_eq,
                auto simp add: A_def combinePair_Sync_defs ω A0 σ0  {}
                ε A0 σ0 = {} cartprod_rwrt P_rec[of σ0] intro!: mono_GlobalNdet_eq)
          also have  = P σ0 E Q σ1
            by (unfold P_rec[of σ0] Q_rec[of σ1])
              (auto simp add: SKIPS_def Ndet_and_Sync Mprefix_Sync_constant ω A0 σ0  {}
                GlobalNdet_Mprefix_distr GlobalNdet_sets_commute[of τ A1 _ _] ω A1 σ1 = {}
                intro!: mono_Mprefix_eq mono_GlobalNdet_eq)
          finally show ?f (σ0, σ1) =  .
        next
          assume ω A0 σ0 = {} ω A1 σ1  {}
          from ρ_disjoint_ε(2) ω A1 σ1  {} have ε A1 σ1 = {}
            by (simp add: ρ_disjoint_ε_def ρ_simps)
          have ?f (σ0, σ1) = a(ε A0 σ0 - E)  (σ0'τ A0 σ0 a. (P σ0' E SKIPS (ω A1 σ1)))
            by (auto simp add: ω_A ε_A ω A0 σ0 = {} ε A1 σ1 = {} intro!: mono_Mprefix_eq,
                auto simp add: A_def combinePair_Sync_defs ω A1 σ1  {}
                ε A1 σ1 = {} cartprod_rwrt Q_rec[of σ1] intro!: mono_GlobalNdet_eq)
          also have  = P σ0 E Q σ1
            by (unfold P_rec[of σ0] Q_rec[of σ1])
              (auto simp add: SKIPS_def Ndet_and_Sync Mprefix_Sync_constant ω A1 σ1  {}
                GlobalNdet_Mprefix_distr GlobalNdet_sets_commute[of τ A0 _ _] ω A0 σ0 = {}
                intro!: mono_Mprefix_eq mono_GlobalNdet_eq)
          finally show ?f (σ0, σ1) =  .
        next
          assume ω A0 σ0  {} ω A1 σ1  {}
          with ρ_disjoint_ε have ε A0 σ0 = {} ε A1 σ1 = {}
            by (simp_all add: ρ_disjoint_ε_def ρ_simps)
          from at_most_1_elem_term
          show ω A0 σ0  {}  ω A1 σ1  {}  ?f (σ0, σ1) = P σ0 E Q σ1
            by (auto simp add: ω A0 σ0  {} ω A1 σ1  {} ω_A P_rec[of σ0] Q_rec[of σ1]
                SKIPS_def Ndet_and_Sync cartprod_rwrt GlobalNdet_sets_commute[of ω A0 _]
                ε_A ε A0 σ0 = {} ε A1 σ1 = {} elim!: at_most_1_elem_termE)
        qed
      qed
    qed
  qed
qed

corollary P_nd_combinePair_Sync :
  P⟪A0nd σ0 E P⟪A1nd σ1 = P⟪A0 nd⊗⟦EPair A1nd (σ0, σ1)
proof -
  have P⟪A0nd σ0 E P⟪A1nd σ1 =
        PSKIPSA0ω := λσ. {}nd σ0 E PSKIPSA1ω := λσ. {}nd σ1
    by (simp add: PSKIPS_nd_updated_ω)
  also have  = PSKIPSA0ω := λσ. {} nd⊗⟦EPair A1ω := λσ. {}nd (σ0, σ1)
    by (rule PSKIPS_nd_combinePair_Sync) simp_all
  also have A0ω := λσ. {} nd⊗⟦EPair A1ω := λσ. {} = A0 nd⊗⟦EPair A1ω := λσ. {}
    by (simp add: combinePair_Sync_defs, intro ext, simp)
  also have PSKIPSA0 nd⊗⟦EPair A1ω := λσ. {}nd = P⟪A0 nd⊗⟦EPair A1nd
    by (simp add: PSKIPS_nd_updated_ω)
  finally show ?thesis .
qed

corollary PSKIPS_d_combinePair_Sync:
  PSKIPSA0d σ0 E PSKIPSA1d σ1 = PSKIPSA0 d⊗⟦EPair A1d (σ0, σ1)
  if ρ_disjoint_ε A0 and ρ_disjoint_ε A1 and indep_enabl A0 σ0 E A1 σ1
proof -
  have PSKIPSA0d σ0 E PSKIPSA1d σ1 = PSKIPSA0dndnd σ0 E PSKIPSA1dndnd σ1
    by (simp flip: PSKIPS_nd_from_det_to_ndet_is_PSKIPS_d)
  also from that(1, 2) have  = PSKIPSA0dnd nd⊗⟦EPair A1dndnd (σ0, σ1)
    by (auto intro: PSKIPS_nd_combinePair_Sync)
  also have  = PSKIPSA0 d⊗⟦EPair A1d (σ0, σ1)
    by (simp add: PSKIPS_combinePair_Sync_behaviour_when_indep indep_enabl A0 σ0 E A1 σ1)
  finally show ?thesis .
qed

corollary P_d_combinePair_Sync:
  P⟪A0d σ0 E P⟪A1d σ1 = P⟪A0 d⊗⟦EPair A1d (σ0, σ1)
  if indep_enabl A0 σ0 E A1 σ1
proof -
  have P⟪A0d σ0 E P⟪A1d σ1 =
        PSKIPSA0ω := λσ. d σ0 E PSKIPSA1ω := λσ. d σ1
    by (simp add: PSKIPS_d_updated_ω)
  also have  = PSKIPSA0ω := λσ.  d⊗⟦EPair A1ω := λσ. d (σ0, σ1)
    by (subst PSKIPS_d_combinePair_Sync, simp_all add: ρ_simps ρ_disjoint_ε_def)
      (rule indep_enablI,
        use indep_enabl A0 σ0 E A1 σ1[THEN indep_enablD] in simp add: ε_simps)
  also have A0ω := λσ.  d⊗⟦EPair A1ω := λσ.  = A0 d⊗⟦EPair A1ω := λσ. 
    by (simp add: combinePair_Sync_defs, intro ext, simp)
  also have PSKIPSA0 d⊗⟦EPair A1ω := λσ. d = P⟪A0 d⊗⟦EPair A1d
    by (simp add: PSKIPS_d_updated_ω)
  finally show ?thesis .
qed



subsubsection ‹Pairlist›

theorem PSKIPS_nd_combinePairlist_Sync :
  PSKIPSA0nd σ0 E PSKIPSA1nd σ1 = PSKIPSA0 nd⊗⟦EPairlist A1nd [σ0, σ1]
  if ρ_disjoint_ε A0 ρ_disjoint_ε A1 at_most_1_elem_term A0 at_most_1_elem_term A1
proof -
  from PSKIPS_nd_combinePair_Sync that
  have PSKIPSA0nd σ0 E PSKIPSA1nd σ1 = PSKIPSA0 nd⊗⟦EPair A1nd (σ0, σ1) .
  also have  = PSKIPSA0 nd⊗⟦EPairlist A1nd [σ0, σ1]
    by (auto intro!: PSKIPS_nd_eqI_strong[of λ(r, s). [r, s] _ (σ0, σ1), simplified] inj_onI)
      (auto simp add: combine_Sync_defs split: if_split_asm)
  finally show ?thesis .
qed

corollary P_nd_combinePairlist_Sync :
  P⟪A0nd σ0 E P⟪A1nd σ1 = P⟪A0 nd⊗⟦EPairlist A1nd [σ0, σ1]
proof -
  have P⟪A0nd σ0 E P⟪A1nd σ1 =
        PSKIPSA0ω := λσ. {}nd σ0 E PSKIPSA1ω := λσ. {}nd σ1
    by (simp only: PSKIPS_nd_updated_ω)
  also have  = PSKIPSA0ω := λσ. {} nd⊗⟦EPairlist A1ω := λσ. {}nd [σ0, σ1]
    by (rule PSKIPS_nd_combinePairlist_Sync) simp_all
  also have A0ω := λσ. {} nd⊗⟦EPairlist A1ω := λσ. {} = A0 nd⊗⟦EPairlist A1ω := λσ. {}
    by (simp add: combinePairlist_Sync_defs, intro ext, simp)
  also have PSKIPSA0 nd⊗⟦EPairlist A1ω := λσ. {}nd = P⟪A0 nd⊗⟦EPairlist A1nd
    by (simp only: PSKIPS_nd_updated_ω)
  finally show ?thesis .
qed

corollary PSKIPS_d_combinePairlist_Sync :
  PSKIPSA0d σ0 E PSKIPSA1d σ1 = PSKIPSA0 d⊗⟦EPairlist A1d [σ0, σ1]
  if ρ_disjoint_ε A0 and ρ_disjoint_ε A1 and indep_enabl A0 σ0 E A1 σ1
proof -
  have PSKIPSA0d σ0 E PSKIPSA1d σ1 = PSKIPSA0dndnd σ0 E PSKIPSA1dndnd σ1
    by (simp flip: PSKIPS_nd_from_det_to_ndet_is_PSKIPS_d)
  also from that(1, 2) have  = PSKIPSA0dnd nd⊗⟦EPairlist A1dndnd [σ0, σ1]
    by (auto intro: PSKIPS_nd_combinePairlist_Sync)
  also have  = PSKIPSA0 d⊗⟦EPairlist A1d [σ0, σ1]
    by (simp add: PSKIPS_combinePairlist_Sync_behaviour_when_indep indep_enabl A0 σ0 E A1 σ1)
  finally show ?thesis .
qed

corollary P_d_combinePairlist_Sync :
  P⟪A0d σ0 E P⟪A1d σ1 = P⟪A0 d⊗⟦EPairlist A1d [σ0, σ1]
  if indep_enabl A0 σ0 E A1 σ1
proof -
  have P⟪A0d σ0 E P⟪A1d σ1 =
        PSKIPSA0ω := λσ. d σ0 E PSKIPSA1ω := λσ. d σ1
    by (simp only: PSKIPS_d_updated_ω)
  also have  = PSKIPSA0ω := λσ.  d⊗⟦EPairlist A1ω := λσ. d [σ0, σ1]
    by (subst PSKIPS_d_combinePairlist_Sync, simp_all)
      (rule indep_enablI,
        use indep_enabl A0 σ0 E A1 σ1[THEN indep_enablD] in simp)
  also have A0ω := λσ.  d⊗⟦EPairlist A1ω := λσ.  = A0 d⊗⟦EPairlist A1ω := λσ. 
    by (simp add: combinePairlist_Sync_defs, intro ext, simp)
  also have PSKIPSA0 d⊗⟦EPairlist A1ω := λσ. d = P⟪A0 d⊗⟦EPairlist A1d
    by (simp only: PSKIPS_d_updated_ω)
  finally show ?thesis .
qed



subsection ‹Rlist›

theorem PSKIPS_nd_combineRlist_Sync :
  PSKIPSA0nd σ0 E PSKIPSA1nd σ1 = PSKIPSA0 nd⊗⟦ERlist A1nd (σ0 # σ1)
  if ρ_disjoint_ε A0 ρ_disjoint_ε A1 at_most_1_elem_term A0 at_most_1_elem_term A1
proof -
  from PSKIPS_nd_combinePair_Sync that
  have PSKIPSA0nd σ0 E PSKIPSA1nd σ1 = PSKIPSA0 nd⊗⟦EPair A1nd (σ0, σ1) .
  also have  = PSKIPSA0 nd⊗⟦ERlist A1nd (σ0 # σ1)
    by (auto intro!: PSKIPS_nd_eqI_strong[of λ(r, s). r # s _ (σ0, σ1), simplified] inj_onI)
      (auto simp add: combine_Sync_defs split: if_split_asm)
  finally show ?thesis .
qed

corollary P_nd_combineRlist_Sync :
  P⟪A0nd σ0 E P⟪A1nd σ1 = P⟪A0 nd⊗⟦ERlist A1nd (σ0 # σ1)
proof -
  have P⟪A0nd σ0 E P⟪A1nd σ1 =
        PSKIPSA0ω := λσ. {}nd σ0 E PSKIPSA1ω := λσ. {}nd σ1
    by (simp only: PSKIPS_nd_updated_ω)
  also have  = PSKIPSA0ω := λσ. {} nd⊗⟦ERlist A1ω := λσ. {}nd (σ0 # σ1)
    by (rule PSKIPS_nd_combineRlist_Sync) simp_all
  also have A0ω := λσ. {} nd⊗⟦ERlist A1ω := λσ. {} = A0 nd⊗⟦ERlist A1ω := λσ. {}
    by (simp add: combineRlist_Sync_defs, intro ext, simp)
  also have PSKIPSA0 nd⊗⟦ERlist A1ω := λσ. {}nd = P⟪A0 nd⊗⟦ERlist A1nd
    by (simp only: PSKIPS_nd_updated_ω)
  finally show ?thesis .
qed

corollary PSKIPS_d_combineRlist_Sync :
  PSKIPSA0d σ0 E PSKIPSA1d σ1 = PSKIPSA0 d⊗⟦ERlist A1d (σ0 # σ1)
  if ρ_disjoint_ε A0 and ρ_disjoint_ε A1 and indep_enabl A0 σ0 E A1 σ1
proof -
  have PSKIPSA0d σ0 E PSKIPSA1d σ1 = PSKIPSA0dndnd σ0 E PSKIPSA1dndnd σ1
    by (simp flip: PSKIPS_nd_from_det_to_ndet_is_PSKIPS_d)
  also from that(1, 2) have  = PSKIPSA0dnd nd⊗⟦ERlist A1dndnd (σ0 # σ1)
    by (auto intro: PSKIPS_nd_combineRlist_Sync)
  also have  = PSKIPSA0 d⊗⟦ERlist A1d (σ0 # σ1)
    by (simp add: PSKIPS_combineRlist_Sync_behaviour_when_indep indep_enabl A0 σ0 E A1 σ1)
  finally show ?thesis .
qed

corollary P_d_combineRlist_Sync :
  P⟪A0d σ0 E P⟪A1d σ1 = P⟪A0 d⊗⟦ERlist A1d (σ0 # σ1)
  if indep_enabl A0 σ0 E A1 σ1
proof -
  have P⟪A0d σ0 E P⟪A1d σ1 =
        PSKIPSA0ω := λσ. d σ0 E PSKIPSA1ω := λσ. d σ1
    by (simp only: PSKIPS_d_updated_ω)
  also have  = PSKIPSA0ω := λσ.  d⊗⟦ERlist A1ω := λσ. d (σ0 # σ1)
    by (subst PSKIPS_d_combineRlist_Sync, simp_all)
      (rule indep_enablI,
        use indep_enabl A0 σ0 E A1 σ1[THEN indep_enablD] in simp)
  also have A0ω := λσ.  d⊗⟦ERlist A1ω := λσ.  = A0 d⊗⟦ERlist A1ω := λσ. 
    by (simp add: combineRlist_Sync_defs, intro ext, simp)
  also have PSKIPSA0 d⊗⟦ERlist A1ω := λσ. d = P⟪A0 d⊗⟦ERlist A1d
    by (simp only: PSKIPS_d_updated_ω)
  finally show ?thesis .
qed



subsection ‹ListslenL›

theorem PSKIPS_nd_combineListslenL_Sync :
  assumes same_length_reach0 : σ0'. σ0'  nd A0 σ0  length σ0' = len0
    and ρ_disjoint_ε : ρ_disjoint_ε A0 ρ_disjoint_ε A1 at_most_1_elem_term A0 at_most_1_elem_term A1
  shows PSKIPSA0nd σ0 E PSKIPSA1nd σ1 = PSKIPSA0 nd⊗⟦len0, EListslenL A1nd (σ0 @ σ1)
proof -
  from set_mp[OF nd_combinendPair_Sync_subset]
  have * : σ'  nd A0 nd⊗⟦EPair A1 (σ0, σ1) 
            σ0' σ1'. σ' = (σ0', σ1')  σ0'  nd A0 σ0  σ1'  nd A1 σ1 for σ' by fast
  from PSKIPS_nd_combinePair_Sync assms(2-5)
  have PSKIPSA0nd σ0 E PSKIPSA1nd σ1 = PSKIPSA0 nd⊗⟦EPair A1nd (σ0, σ1) .
  also have  = PSKIPSA0 nd⊗⟦len0, EListslenL A1nd (σ0 @ σ1)
    by  (auto intro!: PSKIPS_nd_eqI_strong[of λ(r, s). r @ s _ (σ0, σ1), simplified] inj_onI
        dest!: "*" same_length_reach0 simp add: same_length_reach0 image_iff)
      (auto simp add: combine_Sync_defs ε_simps split: if_split_asm,
        (metis SigmaI UnCI case_prod_conv insertI1)+)
  finally show ?thesis .
qed

corollary P_nd_combineListslenL_Sync :
  P⟪A0nd σ0 E P⟪A1nd σ1 = P⟪A0 nd⊗⟦len0, EListslenL A1nd (σ0 @ σ1)
  if σ0'. σ0'  nd A0 σ0  length σ0' = len0
proof -
  have P⟪A0nd σ0 E P⟪A1nd σ1 =
        PSKIPSA0ω := λσ. {}nd σ0 E PSKIPSA1ω := λσ. {}nd σ1
    by (simp only: PSKIPS_nd_updated_ω)
  also have  = PSKIPSA0ω := λσ. {} nd⊗⟦len0, EListslenL A1ω := λσ. {}nd (σ0 @ σ1)
    by (rule PSKIPS_nd_combineListslenL_Sync) (simp_all add: that)
  also have A0ω := λσ. {} nd⊗⟦len0, EListslenL A1ω := λσ. {} = A0 nd⊗⟦len0, EListslenL A1ω := λσ. {}
    by (simp add: combineListslenL_Sync_defs, intro ext, simp)
  also have PSKIPSA0 nd⊗⟦len0, EListslenL A1ω := λσ. {}nd = P⟪A0 nd⊗⟦len0, EListslenL A1nd
    by (simp only: PSKIPS_nd_updated_ω)
  finally show ?thesis .
qed

corollary PSKIPS_d_combineListslenL_Sync :
  PSKIPSA0d σ0 E PSKIPSA1d σ1 = PSKIPSA0 d⊗⟦len0, EListslenL A1d (σ0 @ σ1)
  if σ0'. σ0'  d A0 σ0  length σ0' = len0
    ρ_disjoint_ε A0 ρ_disjoint_ε A1 indep_enabl A0 σ0 E A1 σ1
proof -
  have PSKIPSA0d σ0 E PSKIPSA1d σ1 = PSKIPSA0dndnd σ0 E PSKIPSA1dndnd σ1
    by (simp flip: PSKIPS_nd_from_det_to_ndet_is_PSKIPS_d)
  also from that(1-3) have  = PSKIPSA0dnd nd⊗⟦len0, EListslenL A1dndnd (σ0 @ σ1)
    by (auto simp add: nd_from_det_to_ndet intro!: PSKIPS_nd_combineListslenL_Sync)
  also have  = PSKIPSA0 d⊗⟦len0, EListslenL A1d (σ0 @ σ1)
    by (simp add: PSKIPS_combineListslenL_Sync_behaviour_when_indep that(1, 4))
  finally show ?thesis .
qed

corollary P_d_combineListslenL_Sync :
  P⟪A0d σ0 E P⟪A1d σ1 = P⟪A0 d⊗⟦len0, EListslenL A1d (σ0 @ σ1)
  if σ0'. σ0'  d A0 σ0  length σ0' = len0 indep_enabl A0 σ0 E A1 σ1
proof -
  have P⟪A0d σ0 E P⟪A1d σ1 =
        PSKIPSA0ω := λσ. d σ0 E PSKIPSA1ω := λσ. d σ1
    by (simp only: PSKIPS_d_updated_ω)
  also have  = PSKIPSA0ω := λσ.  d⊗⟦len0, EListslenL A1ω := λσ. d (σ0 @ σ1)
    by (subst PSKIPS_d_combineListslenL_Sync) (simp_all add: that)
  also have A0ω := λσ.  d⊗⟦len0, EListslenL A1ω := λσ.  = A0 d⊗⟦len0, EListslenL A1ω := λσ. 
    by (simp add: combineListslenL_Sync_defs, intro ext, simp)
  also have PSKIPSA0 d⊗⟦len0, EListslenL A1ω := λσ. d = P⟪A0 d⊗⟦len0, EListslenL A1d
    by (simp only: PSKIPS_d_updated_ω)
  finally show ?thesis .
qed



subsection ‹Multiple›

theorem PSKIPS_nd_compactification_Sync:
  length σs = length As; A. A  set As  ρ_disjoint_ε A;
    A. A  set As  at_most_1_elem_term A
    E (σ, A) ∈# mset (zip σs As). PSKIPSAnd σ = PSKIPSnd⨂⟦E Asnd σs
proof (induct σs As rule: induct_2_lists012)
  case Nil show ?case by (simp, subst PSKIPS_nd_rec, simp)
next
  case (single σ0 A0) show ?case
    by (auto simp add: σ_σs_conv_defs intro!: inj_onI PSKIPS_nd_eqI_strong)
next
  case (Cons σ0 σ1 σs A0 A1 As)
  have E (σ, A) ∈# mset (zip (σ0 # σ1 # σs) (A0 # A1 # As)). PSKIPSAnd σ =
        PSKIPSA0nd σ0 E E (σ, A) ∈# mset (zip (σ1 # σs) (A1 # As)). PSKIPSAnd σ by simp
  also have E (σ, A) ∈# mset (zip (σ1 # σs) (A1 # As)). PSKIPSAnd σ =
             PSKIPSnd⨂⟦E A1 # Asnd (σ1 # σs)
    by (rule Cons.hyps(3)) (simp_all add: Cons.prems)
  also have PSKIPSA0nd σ0 E PSKIPSnd⨂⟦E A1 # Asnd (σ1 # σs) =
             PSKIPSA0 nd⊗⟦ERlist nd⨂⟦E A1 # Asnd (σ0 # σ1 # σs)
    by (rule PSKIPS_nd_combineRlist_Sync
        [OF _ ρ_disjoint_ε_transmission_to_iterated_combinend_Sync
          _ at_most_1_elem_term_transmission_to_iterated_combinend_Sync])
      (simp_all add: Cons.prems)
  also have A0 nd⊗⟦ERlist nd⨂⟦E A1 # As = nd⨂⟦E A0 # A1 # As by simp
  finally show ?case .
qed

lemma P_nd_compactification_Sync:
  length σs = length As 
   E (σ, A) ∈# mset (zip σs As). P⟪And σ = P⟪nd⨂⟦E Asnd σs
proof (induct σs As rule: induct_2_lists012)
  case Nil show ?case by (simp, subst P_nd_rec, simp)
next
  case (single σ0 A0) show ?case
    by (simp add: P_nd_from_σ_to_σs_is_P_nd)
next
  case (Cons σ0 σ1 σs A0 A1 As) thus ?case
    by (simp add: P_nd_combineRlist_Sync)
qed

lemma PSKIPS_d_compactification_Sync:
  length σs = length As; A. A  set As  ρ_disjoint_ε A;
    i j. i < length As; j < length As; i  j 
          indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j) 
   E (σ, A) ∈# mset (zip σs As). PSKIPSAd σ = PSKIPSd⨂⟦E Asd σs
proof (induct σs As rule: induct_2_lists012)
  case Nil show ?case by (simp, subst PSKIPS_d_rec, simp)
next
  case (single σ0 A0) show ?case
    by (auto simp add: RenamingTick_PSKIPS_d σ_σs_conv_defs
        intro!: inj_onI PSKIPS_d_eqI_strong split: option.split)
next
  case (Cons σ0 σ1 σs A0 A1 As)
  have ρ_disjoint_ε : A  set (A1 # As)  ρ_disjoint_ε A for A
    by (simp add: Cons.prems(1))
  have indep_enabl :
    i < length (A1 # As); j < length (A1 # As); i  j 
     indep_enabl ((A1 # As) ! i) ((σ1 # σs) ! i) E ((A1 # As) ! j) ((σ1 # σs) ! j) for i j
    by (metis Cons.prems(2) Suc_less_eq length_Cons nat.inject nth_Cons_Suc)
  have ρ_disjoint_ε A0 by (simp add: Cons.prems(1))
  moreover have ρ_disjoint_ε d⨂⟦E A1 # As
    by (meson ρ_disjoint_ε ρ_disjoint_ε_transmission_to_iterated_combined_Sync)
  moreover have indep_enabl A0 σ0 E d⨂⟦E A1 # As (σ1 # σs)
    by (metis Cons.hyps(1) Cons.prems(2) length_Cons less_Suc_eq_le
        same_length_indep_transmission_to_iterated_combined_Sync)
  ultimately show ?case 
    by (simp add: PSKIPS_d_combineRlist_Sync
        Cons.hyps(3)[OF ρ_disjoint_ε indep_enabl, simplified])
qed

lemma P_d_compactification_Sync:
  length σs = length As;
    i j. i < length As; j < length As; i  j 
          indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j) 
   E (σ, A) ∈# mset (zip σs As). P⟪Ad σ = P⟪d⨂⟦E Asd σs
proof (induct σs As rule: induct_2_lists012)
  case Nil show ?case by (simp, subst P_d_rec, simp)
next
  case (single σ0 A0) show ?case
    by (simp, subst (1 2) PSKIPS_d_updated_ω)
      (auto simp add: RenamingTick_PSKIPS_d σ_σs_conv_defs
        intro!: inj_onI PSKIPS_d_eqI_strong split: option.split)
next
  case (Cons σ0 σ1 σs A0 A1 As)
  have indep_enabl :
    i < length (A1 # As); j < length (A1 # As); i  j 
     indep_enabl ((A1 # As) ! i) ((σ1 # σs) ! i) E ((A1 # As) ! j) ((σ1 # σs) ! j) for i j
    by (metis Cons.prems Suc_less_eq length_Cons nat.inject nth_Cons_Suc)
  have indep_enabl A0 σ0 E d⨂⟦E A1 # As (σ1 # σs)
    by (metis Cons.hyps(1) Cons.prems length_Cons less_Suc_eq_le
        same_length_indep_transmission_to_iterated_combined_Sync)
  thus ?case 
    by (simp add: P_d_combineRlist_Sync
        Cons.hyps(3)[OF indep_enabl, simplified])
qed




corollary PSKIPS_nd_compactification_Sync_order_is_arbitrary:
  PSKIPSnd⨂⟦E Asnd σs = PSKIPSnd⨂⟦E As'nd σs'
  if length σs = length As length σs' = length As'
    mset (zip σs As) = mset (zip σs' As') 
    A. A  set As  ρ_disjoint_ε A
    A. A  set As  at_most_1_elem_term A
proof -
  have PSKIPSnd⨂⟦E Asnd σs = E (σ, A)∈#mset (zip σs As). PSKIPSAnd σ
    by (rule PSKIPS_nd_compactification_Sync[OF that(1, 4, 5), symmetric])
  also have  = E (σ, A)∈#mset (zip σs' As'). PSKIPSAnd σ
    by (simp only: that(3))
  also have  = PSKIPSnd⨂⟦E As'nd σs'
  proof (rule PSKIPS_nd_compactification_Sync[OF that(2)])
    show A  set As'  ρ_disjoint_ε A for A
      by (metis in_set_impl_in_set_zip2 set_mset_mset set_zip_rightD that(2-4))
  next
    show A  set As'  at_most_1_elem_term A for A
      by (metis in_set_impl_in_set_zip2 set_mset_mset set_zip_rightD that(2, 3, 5))
  qed
  finally show ?thesis .
qed

corollary P_nd_compactification_Sync_order_is_arbitrary:
  P⟪nd⨂⟦E Asnd σs = P⟪nd⨂⟦E As'nd σs'
  if length σs = length As length σs' = length As'
    mset (zip σs As) = mset (zip σs' As') 
proof -
  have P⟪nd⨂⟦E Asnd σs = E (σ, A)∈#mset (zip σs As). P⟪And σ
    by (fact P_nd_compactification_Sync[OF that(1), symmetric])
  also have  = E (σ, A)∈#mset (zip σs' As'). P⟪And σ
    by (simp only: that(3))
  also have  = P⟪nd⨂⟦E As'nd σs'
    by (fact P_nd_compactification_Sync[OF that(2)])
  finally show ?thesis .
qed

corollary PSKIPS_d_compactification_Sync_order_is_arbitrary:
  PSKIPSd⨂⟦E Asd σs = PSKIPSd⨂⟦E As'd σs'
  if length σs = length As length σs' = length As'
    mset (zip σs As) = mset (zip σs' As') 
    A. A  set As  ρ_disjoint_ε A
    i j. i < length As; j < length As; i  j 
            indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)
proof -
  have PSKIPSd⨂⟦E Asd σs = E (σ, A)∈#mset (zip σs As). PSKIPSAd σ
    by (rule PSKIPS_d_compactification_Sync[OF that(1, 4, 5), symmetric])
  also have  = E (σ, A)∈#mset (zip σs' As'). PSKIPSAd σ
    by (simp only: that(3))
  also have  = PSKIPSd⨂⟦E As'd σs'
  proof (rule PSKIPS_d_compactification_Sync[OF that(2)])
    show A  set As'  ρ_disjoint_ε A for A
      by (metis in_set_impl_in_set_zip2 set_mset_mset set_zip_rightD that(2-4))
  next
    from length σs = length As length σs' = length As' mset (zip σs As) = mset (zip σs' As')
    obtain n where * : length σs = n length σs' = n length As = n length As' = n
      by (metis length_zip min_less_iff_conj nat_neq_iff size_mset)
    from that(3)[symmetric, THEN permutation_Ex_bij] obtain f
      where ** : bij_betw f {..<n} {..<n}
        i < n  zip σs' As' ! i = zip σs As ! f i for i by (auto simp add: "*")
    { fix i assume i < n
      hence f i < n using "**"(1) bij_betwE by blast
      from i < n have zip σs' As' ! i = (σs' ! i, As' ! i) by (simp add: "*"(2, 4))
      moreover from f i < n have zip σs As ! f i = (σs ! f i, As ! f i)
        by (simp add: "*"(1, 3))
      ultimately have σs' ! i = σs ! f i As' ! i = As ! f i
        using "**"(2)[OF i < n] by simp_all
    } note *** = this
    fix i j assume i < length As' j < length As' i  j
    hence i < n j < n by (simp_all add: "*"(2, 4))
    with bij_betw_imp_surj_on[OF "**"(1)] bij_betw_imp_inj_on[OF "**"(1)] i  j
    have f i < length As f j < length As f i  f j
      by (auto simp add: "*" dest: inj_onD)
    from that(5)[OF this]
    show indep_enabl (As' ! i) (σs' ! i) E (As' ! j) (σs' ! j)
      by (simp add: "***"(1, 2) i < n j < n)
  qed
  finally show ?thesis .
qed

corollary P_d_compactification_Sync_order_is_arbitrary:
  P⟪d⨂⟦E Asd σs = P⟪d⨂⟦E As'd σs'
  if length σs = length As length σs' = length As'
    mset (zip σs As) = mset (zip σs' As') 
    i j. i < length As; j < length As; i  j 
            indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)
proof -
  have P⟪d⨂⟦E Asd σs = E (σ, A)∈#mset (zip σs As). P⟪Ad σ
    by (rule P_d_compactification_Sync[OF that(1, 4), symmetric])
  also have  = E (σ, A)∈#mset (zip σs' As'). P⟪Ad σ
    by (simp only: that(3))
  also have  = P⟪d⨂⟦E As'd σs'
  proof (rule P_d_compactification_Sync[OF that(2)])
    from length σs = length As length σs' = length As' mset (zip σs As) = mset (zip σs' As')
    obtain n where * : length σs = n length σs' = n length As = n length As' = n
      by (metis length_zip min_less_iff_conj nat_neq_iff size_mset)
    from that(3)[symmetric, THEN permutation_Ex_bij] obtain f
      where ** : bij_betw f {..<n} {..<n}
        i < n  zip σs' As' ! i = zip σs As ! f i for i by (auto simp add: "*")
    { fix i assume i < n
      hence f i < n using "**"(1) bij_betwE by blast
      from i < n have zip σs' As' ! i = (σs' ! i, As' ! i) by (simp add: "*"(2, 4))
      moreover from f i < n have zip σs As ! f i = (σs ! f i, As ! f i)
        by (simp add: "*"(1, 3))
      ultimately have σs' ! i = σs ! f i As' ! i = As ! f i
        using "**"(2)[OF i < n] by simp_all
    } note *** = this
    fix i j assume i < length As' j < length As' i  j
    hence i < n j < n by (simp_all add: "*"(2, 4))
    with bij_betw_imp_surj_on[OF "**"(1)] bij_betw_imp_inj_on[OF "**"(1)] i  j
    have f i < length As f j < length As f i  f j
      by (auto simp add: "*" dest: inj_onD)
    from that(4)[OF this]
    show indep_enabl (As' ! i) (σs' ! i) E (As' ! j) (σs' ! j)
      by (simp add: "***"(1, 2) i < n j < n)
  qed
  finally show ?thesis .
qed



section ‹Derived Versions›

lemma PSKIPS_nd_compactification_Sync_upt_version:
  E P ∈# mset (map Q [0..<n]). P = PSKIPSnd⨂⟦E map A [0..<n]nd (replicate n 0)
  if i. i < n  ρ_disjoint_ε (A i)
    i. i < n  at_most_1_elem_term (A i)
    i. i < n  PSKIPSA ind 0 = Q i
proof -
  have E P ∈# mset (map Q [0..<n]). P = E i ∈# (mset_set {0..<n}). Q i
    by (auto intro: mono_MultiSync_eq2)
  also have  = E i ∈# (mset_set {0..<n}). PSKIPSA ind 0
    by (auto simp add: that(3) intro: mono_MultiSync_eq)
  also have  = E (σ, A)∈#mset (zip (replicate n 0) (map A [0..<n])). PSKIPSAnd σ
  proof (induct n rule: nat_induct_012)
    case (Suc k)
    have E i∈#mset_set {0..<Suc k}. PSKIPSA ind 0 =
          PSKIPSA knd 0 E E i∈#mset_set {0..<k}. PSKIPSA ind 0
      by (subst atLeastLessThanSuc, simp, rule MultiSync_add)
        (metis Suc.hyps(1) atLeastLessThan_empty_iff2 finite_lessThan
          gr0_conv_Suc lessThan_atLeast0 mset_set_empty_iff order_less_le_trans)
    also have  = PSKIPSA knd 0 E
                    E (σ, A)∈#mset (zip (replicate k 0) (map A [0..<k])). PSKIPSAnd σ
      by (simp only: Suc.hyps(2))
    also have  = E (σ, A)∈#mset (zip (replicate (Suc k) 0) (map A [0..<Suc k])). PSKIPSAnd σ
      by (simp flip: replicate_append_same, subst MultiSync_add)
        (use Suc.hyps(1) in auto)
    finally show ?case .
  qed (simp_all add: atLeastLessThanSuc Sync_commute)
  also have  = PSKIPSnd⨂⟦E map A [0..<n]nd (replicate n 0)
    by (rule PSKIPS_nd_compactification_Sync)
      (auto simp add: that(1, 2))
  finally show ?thesis .
qed

lemma P_nd_compactification_Sync_upt_version:
  E P ∈# mset (map Q [0..<n]). P = P⟪nd⨂⟦E map A [0..<n]nd (replicate n 0)
  if i. i < n  P⟪A ind 0 = Q i
proof -
  have E P ∈# mset (map Q [0..<n]). P = E i ∈# (mset_set {0..<n}). Q i
    by (auto intro: mono_MultiSync_eq2)
  also have  = E i ∈# (mset_set {0..<n}). P⟪A ind 0
    by (auto simp add: that(1) intro: mono_MultiSync_eq)
  also have  = E (σ, A)∈#mset (zip (replicate n 0) (map A [0..<n])). P⟪And σ
  proof (induct n rule: nat_induct_012)
    case (Suc k)
    have E i∈#mset_set {0..<Suc k}. P⟪A ind 0 =
          P⟪A knd 0 E E i∈#mset_set {0..<k}. P⟪A ind 0
      by (subst atLeastLessThanSuc, simp, rule MultiSync_add)
        (metis Suc.hyps(1) atLeastLessThan_empty_iff2 finite_lessThan
          gr0_conv_Suc lessThan_atLeast0 mset_set_empty_iff order_less_le_trans)
    also have  = P⟪A knd 0 E E (σ, A)∈#mset (zip (replicate k 0) (map A [0..<k])). P⟪And σ
      by (simp only: Suc.hyps(2))
    also have  = E (σ, A)∈#mset (zip (replicate (Suc k) 0) (map A [0..<Suc k])). P⟪And σ
      by (simp flip: replicate_append_same, subst MultiSync_add)
        (use Suc.hyps(1) in auto)
    finally show ?case .
  qed (simp_all add: atLeastLessThanSuc Sync_commute)
  also have  = P⟪nd⨂⟦E map A [0..<n]nd (replicate n 0)
    by (auto intro: P_nd_compactification_Sync)
  finally show ?thesis .
qed

lemma PSKIPS_d_compactification_Sync_upt_version:
  E P ∈# mset (map Q [0..<n]). P = PSKIPSd⨂⟦E map A [0..<n]d (replicate n 0)
  if i. i < n  ρ_disjoint_ε (A i)
    i j. i < n  j < n  i  j  indep_enabl (A i) 0 E (A j) 0
    i. i < n  PSKIPSA id 0 = Q i
proof -
  have E P ∈# mset (map Q [0..<n]). P = E i ∈# (mset_set {0..<n}). Q i
    by (auto intro: mono_MultiSync_eq2)
  also have  = E i ∈# (mset_set {0..<n}). PSKIPSA id 0
    by (auto simp add: that(3) intro: mono_MultiSync_eq)
  also have  = E (σ, A)∈#mset (zip (replicate n 0) (map A [0..<n])). PSKIPSAd σ
  proof (induct n rule: nat_induct_012)
    case (Suc k)
    have E i∈#mset_set {0..<Suc k}. PSKIPSA id 0 =
          PSKIPSA kd 0 E E i∈#mset_set {0..<k}. PSKIPSA id 0
      by (subst atLeastLessThanSuc, simp, rule MultiSync_add)
        (metis Suc.hyps(1) atLeastLessThan_empty_iff2 finite_lessThan
          gr0_conv_Suc lessThan_atLeast0 mset_set_empty_iff order_less_le_trans)
    also have  = PSKIPSA kd 0 E
                    E (σ, A)∈#mset (zip (replicate k 0) (map A [0..<k])). PSKIPSAd σ
      by (simp only: Suc.hyps(2))
    also have  = E (σ, A)∈#mset (zip (replicate (Suc k) 0) (map A [0..<Suc k])). PSKIPSAd σ
      by (simp flip: replicate_append_same, subst MultiSync_add)
        (use Suc.hyps(1) in auto)
    finally show ?case .
  qed (simp_all add: atLeastLessThanSuc Sync_commute)
  also have  = PSKIPSd⨂⟦E map A [0..<n]d (replicate n 0)
    by (rule PSKIPS_d_compactification_Sync)
      (auto simp add: that(1, 2))
  finally show ?thesis .
qed

lemma P_d_compactification_Sync_upt_version:
  E P ∈# mset (map Q [0..<n]). P = P⟪d⨂⟦E map A [0..<n]d (replicate n 0)
  if i. i < n  P⟪A id 0 = Q i
    i j. i < n  j < n  i  j  indep_enabl (A i) 0 E (A j) 0
proof -
  have E P ∈# mset (map Q [0..<n]). P = E i ∈# (mset_set {0..<n}). Q i
    by (auto intro: mono_MultiSync_eq2)
  also have  = E i ∈# (mset_set {0..<n}). P⟪A id 0
    by (auto simp add: that(1) intro: mono_MultiSync_eq)
  also have  = E (σ, A)∈#mset (zip (replicate n 0) (map A [0..<n])). P⟪Ad σ
  proof (induct n rule: nat_induct_012)
    case (Suc k)
    have E i∈#mset_set {0..<Suc k}. P⟪A id 0 =
          P⟪A kd 0 E E i∈#mset_set {0..<k}. P⟪A id 0
      by (subst atLeastLessThanSuc, simp, rule MultiSync_add)
        (metis Suc.hyps(1) atLeastLessThan_empty_iff2 finite_lessThan
          gr0_conv_Suc lessThan_atLeast0 mset_set_empty_iff order_less_le_trans)
    also have  = P⟪A kd 0 E E (σ, A)∈#mset (zip (replicate k 0) (map A [0..<k])). P⟪Ad σ
      by (simp only: Suc.hyps(2))
    also have  = E (σ, A)∈#mset (zip (replicate (Suc k) 0) (map A [0..<Suc k])). P⟪Ad σ
      by (simp flip: replicate_append_same, subst MultiSync_add)
        (use Suc.hyps(1) in auto)
    finally show ?case .
  qed (simp_all add: atLeastLessThanSuc Sync_commute)
  also have  = P⟪d⨂⟦E map A [0..<n]d (replicate n 0)
    by (rule P_d_compactification_Sync) (simp_all add: that(2))
  finally show ?thesis .
qed



section ‹More on Iterated Combine›

lemma ε_iterated_combinend_Sync_general_form:
  length σs = length As  ε nd⨂⟦E As σs =
   (if As = [] then {}
    else (i < length As. ε (As ! i) (σs ! i)) - E  (i < length As. ε (As ! i) (σs ! i)))
  for As :: (, 'e, 'r) And list
proof (subst ε_iterated_combinend_Sync, assumption, induct σs As rule: induct_2_lists012)
  case Nil show ?case by simp
next
  case (single σ0 A0) show ?case by auto
next
  case (Cons σ0 σ1 σs A0 A1 As)
  define U and I
    where U_def : U As σs  i<length As. ε (As ! i) (σs ! i)
      and I_def : I As σs  i<length As. ε (As ! i) (σs ! i)
    for As :: (, 'e, 'r) And list and σs
  have * : U (A0 # A1 # As) (σ0 # σ1 # σs) = ε A0 σ0  U (A1 # As) (σ1 # σs)
    by (auto simp add: U_def nth_Cons split: nat.split_asm)
  have ** : I (A0 # A1 # As) (σ0 # σ1 # σs) = ε A0 σ0  I (A1 # As) (σ1 # σs)
    by (auto simp add: I_def nth_Cons split: nat.splits)
  have iterated_combinend_Sync_ε (A0 # A1 # As) E (σ0 # σ1 # σs) =
        combine_sets_Sync (ε A0 σ0) E (U (A1 # As) (σ1 # σs) - E  (I (A1 # As) (σ1 # σs)))
    by (simp add: U_def I_def Cons.hyps(3))
  also have  = U (A0 # A1 # As) (σ0 # σ1 # σs) - E  I (A0 # A1 # As) (σ0 # σ1 # σs)
    unfolding "*" "**" by (auto simp add: U_def I_def)
  finally show ?case by (simp add: U_def I_def)
qed

lemma ε_iterated_combined_Sync_general_form:
  length σs = length As  ε d⨂⟦E As σs =
   (if As = [] then {}
    else (i < length As. ε (As ! i) (σs ! i)) - E  (i < length As. ε (As ! i) (σs ! i)))
  for As :: (, 'e, 'r) Ad list
proof (subst ε_iterated_combined_Sync, assumption, induct σs As rule: induct_2_lists012)
  case Nil show ?case by simp
next
  case (single σ0 A0) show ?case by auto
next
  case (Cons σ0 σ1 σs A0 A1 As)
  define U and I
    where U_def : U As σs  i<length As. ε (As ! i) (σs ! i)
      and I_def : I As σs  i<length As. ε (As ! i) (σs ! i)
    for As :: (, 'e, 'r) Ad list and σs
  have * : U (A0 # A1 # As) (σ0 # σ1 # σs) = ε A0 σ0  U (A1 # As) (σ1 # σs)
    by (auto simp add: U_def nth_Cons split: nat.split_asm)
  have ** : I (A0 # A1 # As) (σ0 # σ1 # σs) = ε A0 σ0  I (A1 # As) (σ1 # σs)
    by (auto simp add: I_def nth_Cons split: nat.splits)
  have iterated_combined_Sync_ε (A0 # A1 # As) E (σ0 # σ1 # σs) =
        combine_sets_Sync (ε A0 σ0) E (U (A1 # As) (σ1 # σs) - E  (I (A1 # As) (σ1 # σs)))
    by (simp add: U_def I_def Cons.hyps(3))
  also have  = U (A0 # A1 # As) (σ0 # σ1 # σs) - E  I (A0 # A1 # As) (σ0 # σ1 # σs)
    unfolding "*" "**" by (auto simp add: U_def I_def)
  finally show ?case by (simp add: U_def I_def)
qed


lemma τ_iterated_combinend_Sync_general_form:
  length σs = length As; σs'  τ nd⨂⟦E As σs a; i < length As 
   σs' ! i  insert (σs ! i) (τ (As ! i) (σs ! i) a)
proof (induct σs As arbitrary: σs' i rule: induct_2_lists012)
  case Nil thus ?case by simp
next
  case (single σ0 A0)
  from single.prems show ?case by (auto simp add: behaviour_σ_σs_conv)
next
  case (Cons σ0 σ1 σs A0 A1 As)
  from length σs = length As have length (σ0 # σ1 # σs) = length (A0 # A1 # As) by simp
  from same_length_ℛnd_iterated_combinend_Sync_description[OF this]
  have length σs' = length (A0 # A1 # As)
    by (metis Cons.prems(1) nd.init nd.step)
  then obtain σ0' σ1' σs'' where σs' = σ0' # σ1' # σs'' by (metis length_Suc_conv)
  with Cons.prems Cons.hyps(3)[of σ1' # σs'' nat.pred i] show ?case
    by (auto simp add: combine_Sync_defs nth_Cons split: if_split_asm nat.splits)
qed


lemma τ_iterated_combined_Sync_general_form:
  length σs = length As 
   τ d⨂⟦E As σs a =
   (if As = [] then  else
    if a  (i < length As. ε (As ! i) (σs ! i)) - E  (i < length As. ε (As ! i) (σs ! i))
    then map2 (λσ A. if a  ε A σ then τ A σ a else σ) σs As else )
  for As :: (, 'e, 'r) Ad list
proof (induct σs As rule: induct_2_lists012)
  case Nil show ?case by simp
next
  case (single σ0 A0) show ?case by (auto simp add: behaviour_σ_σs_conv ε_simps)
next
  case (Cons σ0 σ1 σs A0 A1 As)
  let ?U = λAs σs. i<length As. ε (As ! i) (σs ! i)
  let ?I = λAs σs. i<length As. ε (As ! i) (σs ! i)
  show ?case
  proof (split if_split, split if_split, intro conjI impI)
    show A0 # A1 # As = []  τ d⨂⟦E A0 # A1 # As (σ0 # σ1 # σs) a = 
      and A0 # A1 # As = []  τ d⨂⟦E A0 # A1 # As (σ0 # σ1 # σs) a =  by simp_all
  next
    assume a  ?U (A0 # A1 # As) (σ0 # σ1 # σs) - E  ?I (A0 # A1 # As) (σ0 # σ1 # σs)
    hence a  ε d⨂⟦E A0 # A1 # As (σ0 # σ1 # σs)
      by (subst ε_iterated_combined_Sync_general_form)
        (simp_all add: Cons.hyps(1))
    thus τ d⨂⟦E A0 # A1 # As (σ0 # σ1 # σs) a = 
      by (simp add: ε_simps)
  next
    assume * : a  ?U (A0 # A1 # As) (σ0 # σ1 # σs) - E  ?I (A0 # A1 # As) (σ0 # σ1 # σs)
    have ** : ?U (A0 # A1 # As) (σ0 # σ1 # σs) = ε A0 σ0  ?U (A1 # As) (σ1 # σs)
      by (auto simp add: nth_Cons split: nat.split_asm)
    have *** : ?I (A0 # A1 # As) (σ0 # σ1 # σs) = ε A0 σ0  ?I (A1 # As) (σ1 # σs)
      by (auto simp add: nth_Cons split: nat.splits)
    have **** : ?U (A0 # A1 # As) (σ0 # σ1 # σs) - E  ?I (A0 # A1 # As) (σ0 # σ1 # σs) =
                 combine_sets_Sync (ε A0 σ0) E (?U (A1 # As) (σ1 # σs) - E  ?I (A1 # As) (σ1 # σs))
      unfolding "**" "***" by auto
    have $ : ?U (A1 # As) (σ1 # σs) - E  ?I (A1 # As) (σ1 # σs) = ε d⨂⟦E A1 # As (σ1 # σs)
      by (subst ε_iterated_combined_Sync_general_form)
        (simp_all add: Cons.hyps(1))

    from Cons.hyps(1) have a  ?U As σs 
            map2 (λσ A. if a  ε A σ then τ A σ a else σ) σs As = σs
      by (induct σs As rule: induct_2_lists012)
        (auto simp add: ε_simps lessThan_def, fastforce)
    moreover have ?U As σs  ?U (A1 # As) (σ1 # σs) by force
    ultimately show τ d⨂⟦E A0 # A1 # As (σ0 # σ1 # σs) a =
                  map2 (λx y. if a  ε y x then τ y x a else x) (σ0 # σ1 # σs) (A0 # A1 # As)
      using "*" unfolding "****" "$"
      by (simp add: ε_combineRlist_Sync combine_Sync_ε_def, safe,
          auto simp add: combineRlist_Sync_defs ε_simps Cons.hyps(3) lessThan_def subset_iff
          split: option.splits if_splits)
        (metis (no_types, lifting) not_less_eq nth_Cons_Suc)
  qed
qed


lemma indep_implies_only_one_enabled':
  ∃!i. i < length As  a  ε (As ! i) (σs ! i)
  if length σs = length As
    and i j. i < length As; j < length As; i  j 
            ε (As ! i) (σs ! i)  ε (As ! j) (σs ! j)  E
    and a  (i<length As. ε (As ! i) (σs ! i)) - E
proof (rule ex_ex1I)
  from that(3) show i<length As. a  ε (As ! i) (σs ! i) by auto
next
  fix i j assume i < length As  a  ε (As ! i) (σs ! i)
    j < length As  a  ε (As ! j) (σs ! j)
  moreover from that(3) have a  E by blast
  ultimately show i = j using that(2)[of i j] by auto
qed

lemma indep_implies_only_one_enabled:
  length σs = length As;
    i j. i < length As; j < length As; i  j 
           indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j);
    a  (i<length As. ε (As ! i) (σs ! i)) - E 
    ∃!i. i < length As  a  ε (As ! i) (σs ! i)
  by (erule indep_implies_only_one_enabled'[where E = E])
    (simp_all add: indep_enabl_def subset_iff, meson IntI d.init)


lemma τ_iterated_combined_Sync_general_form_when_indep:
  τ d⨂⟦E As σs a =
   (if As = [] then 
    else   if a  (i<length As. ε (As ! i) (σs ! i))
         then map2 (λσ A. τ A σ a) σs As
         else   if a  (i<length As. ε (As ! i) (σs ! i)) - E
              then let i = THE i. i < length As   a  ε (As ! i) (σs ! i)
                    in σs[i := τ (As ! i) (σs ! i) a]
              else )
  (is _ = (if As = [] then  else 
            if a  ?I As σs then map2 (λσ A. τ A σ a) σs As else
            if a  ?U As σs - E then ?upd As σs else ))
    if length σs = length As
      i j. i < length As; j < length As; i  j 
            indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)
proof (subst τ_iterated_combined_Sync_general_form[OF that(1)], rule if_cong)
  show (if a  ?U As σs - E  ?I As σs
         then map2 (λx y. if a  ε y x then τ y x a else x) σs As else ) =
        (if a  ?I As σs then map2 (λx y. τ y x a) σs As else
         if a  ?U As σs - E then ?upd As σs else )
  proof (split if_split, intro conjI impI)
    assume * : a  ?I As σs
    with that(1) have (σ, A)  set (zip σs As)  a  ε A σ for σ A
      by (induct σs As rule: list_induct2) (use lessThan_Suc_eq_insert_0 in auto)
    with "*" show (if a  ?U As σs - E  ?I As σs
                    then map2 (λx y. if a  ε y x then τ y x a else x) σs As else ) =
                   map2 (λx y. τ y x a) σs As by auto
  next
    assume * : a  ?I As σs
    show (if a  ?U As σs - E  ?I As σs
           then map2 (λx y. if a  ε y x then τ y x a else x) σs As else ) =
          (if a  ?U As σs - E then ?upd As σs else )
    proof (rule if_cong)
      assume a  ?U As σs - E
      from indep_implies_only_one_enabled[OF that this]
      obtain i where $ : i < length As  a  ε (As ! i) (σs ! i)
        j < length As  j  i  a  ε (As ! j) (σs ! j) for j by blast
      have $$ : (THE i. i < length As  a  ε (As ! i) (σs ! i)) = i
        using "$" by blast
      have map2 (λx y. if a  ε y x then τ y x a else x) σs As =
            σs[i := τ (As ! i) (σs ! i) a]
        by (auto intro!: nth_equalityI simp add: that(1))
          (use that(1) "$"(3) in fastforce, metis "$"(2) nth_list_update_neq)
      also have  = ?upd As σs
        using "$$" by auto
      finally show map2 (λx y. if a  ε y x then τ y x a else x) σs As = ?upd As σs .
    qed (use "*" in auto)
  qed
qed simp_all



section ‹More on Events›

lemma events_of_MultiSync_PSKIPS_nd : 
  α(E (σ, A) ∈# mset (zip σs As). PSKIPSAnd σ) =
   (if As = [] then {} else
     σs'  nd nd⨂⟦E As σs. (i<length As. ε (As ! i) (σs' ! i)) - E 
                                 (i<length As. ε (As ! i) (σs' ! i)))
  (is _ = ?rhs) if length σs = length As
  A. A  set As  ρ_disjoint_ε A A. A  set As  at_most_1_elem_term A
proof -
  have E (σ, A) ∈# mset (zip σs As). PSKIPSAnd σ = PSKIPSnd⨂⟦E Asnd σs
    by (simp only: PSKIPS_nd_compactification_Sync[OF that])
  also have α() =  (ε nd⨂⟦E As ` nd nd⨂⟦E As σs) 
  proof (rule events_of_PSKIPS_nd)
    show ρ_disjoint_ε nd⨂⟦E As
      by (simp only: ρ_disjoint_ε_transmission_to_iterated_combinend_Sync that(2))
  qed
  also from same_length_ℛnd_iterated_combinend_Sync_description[OF that(1)]
  have  = ?rhs by (auto simp add: ε_iterated_combinend_Sync_general_form)
  finally show ?thesis .
qed


lemma events_of_MultiSync_P_nd : 
  α(E (σ, A) ∈# mset (zip σs As). P⟪And σ) =
   (if As = [] then {} else
     σs'  nd nd⨂⟦E As σs. (i<length As. ε (As ! i) (σs' ! i)) - E 
                                 (i<length As. ε (As ! i) (σs' ! i)))
  (is _ = ?rhs) if length σs = length As
proof -
  have E (σ, A) ∈# mset (zip σs As). P⟪And σ = P⟪nd⨂⟦E Asnd σs
    by (fact P_nd_compactification_Sync[OF that])
  also have α() =  (ε nd⨂⟦E As ` nd nd⨂⟦E As σs) by (fact events_of_P_nd)
  also from same_length_ℛnd_iterated_combinend_Sync_description[OF that(1)]
  have  = ?rhs by (auto simp add: ε_iterated_combinend_Sync_general_form)
  finally show ?thesis .
qed



lemma events_of_MultiSync_PSKIPS_d : 
  α(E (σ, A) ∈# mset (zip σs As). PSKIPSAd σ) =
   (if As = [] then {} else
     σs'  d d⨂⟦E As σs. (i<length As. ε (As ! i) (σs' ! i) - E 
                               (i<length As. ε (As ! i) (σs' ! i))))
  (is _ = ?rhs) if length σs = length As A. A  set As  ρ_disjoint_ε A
  i j. i < length As; j < length As; i  j 
          indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)
proof -
  have E (σ, A) ∈# mset (zip σs As). PSKIPSAd σ = PSKIPSd⨂⟦E Asd σs
    by (simp add: PSKIPS_d_compactification_Sync[OF that])
  also have α() =  (ε d⨂⟦E As ` d d⨂⟦E As σs) 
  proof (rule events_of_PSKIPS_d)
    show ρ_disjoint_ε d⨂⟦E As
      by (simp only: ρ_disjoint_ε_transmission_to_iterated_combined_Sync that(2))
  qed
  also from same_length_ℛd_iterated_combined_Sync_description[OF that(1)]
  have  = ?rhs by (auto simp add: ε_iterated_combined_Sync_general_form)
  finally show ?thesis .
qed


lemma events_of_MultiSync_P_d : 
  α(E (σ, A) ∈# mset (zip σs As). P⟪Ad σ) =
   (if As = [] then {} else
     σs'  d d⨂⟦E As σs. (i<length As. ε (As ! i) (σs' ! i) - E 
                                (i<length As. ε (As ! i) (σs' ! i))))
  (is _ = ?rhs) if length σs = length As
  and i j. i < length As; j < length As; i  j 
             indep_enabl (As ! i) (σs ! i) E (As ! j) (σs ! j)
proof -
  have E (σ, A) ∈# mset (zip σs As). P⟪Ad σ = P⟪d⨂⟦E Asd σs
    by (simp add: P_d_compactification_Sync[OF that])
  also have α() =  (ε d⨂⟦E As ` d d⨂⟦E As σs) by (fact events_of_P_d)
  also from same_length_ℛd_iterated_combined_Sync_description[OF that(1)]
  have  = ?rhs by (auto simp add: ε_iterated_combined_Sync_general_form)
  finally show ?thesis .
qed



(*<*)
end
  (*>*)