Theory Process_Normalization_Properties

(***********************************************************************************
 * 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 ‹Advanced Properties of ProcOmata›

(*<*)
theory Process_Normalization_Properties
  imports Process_Normalization Deterministic_Processes
begin
  (*<*)


section ‹Determinism of deterministic ProcOmata›

lemma deterministic_PSKIPS_d : deterministic (PSKIPSAd σ)
proof (induct A arbitrary: σ rule: PSKIPS_d_induct)
  show adm (λf. x. deterministic (f x)) by simp
next
  show deterministic STOP by simp
next
  show (σ. deterministic (X σ)) 
        deterministic (PSKIPS_d_step (ε A) (τ A) (ω A) X σ) for X σ
    by (simp add: deterministic_Mprefix_iff split: option.split)
qed

corollary deterministic_P_d : deterministic (P⟪Ad σ)
  by (subst PSKIPS_d_updated_ω) (fact deterministic_PSKIPS_d)

corollary PSKIPS_d_FD_imp_eq_PSKIPS_d : PSKIPSAd σ FD P  P = PSKIPSAd σ
  using deterministic_iff_maximal_for_leFD[THEN iffD1, OF deterministic_PSKIPS_d] by fast

corollary P_d_FD_imp_eq_P_d : P⟪Ad σ FD P  P = P⟪Ad σ
  using deterministic_iff_maximal_for_leFD[THEN iffD1, OF deterministic_P_d] by fast



section ‹No Divergence for ProcOmata›

lemma div_free_PSKIPS_nd : 𝒟 (PSKIPSAnd σ) = {}
proof (induct A arbitrary: σ rule: PSKIPS_nd_induct)
  have adm (λX. σ t. t  𝒟 (X σ)  False)
    by (intro restriction_adm_all restriction_adm_imp) simp_all
  thus adm (λX. σ. 𝒟 (X σ) = {}) by simp
next
  from D_STOP show 𝒟 STOP = {} .
next
  show (σ. 𝒟 (X σ) = {})  𝒟 (PSKIPS_nd_step (ε A) (τ A) (ω A) X σ) = {} for X σ
    by (simp add: D_Mprefix D_GlobalNdet D_SKIPS)
qed

corollary div_free_PSKIPS_d : 𝒟 (PSKIPSAd σ) = {}
  by (simp add: deterministic_PSKIPS_d deterministic_div_free)

corollary div_free_P_nd : 𝒟 (P⟪And s) = {}
  by (simp add: PSKIPS_nd_updated_ω div_free_PSKIPS_nd)

corollary div_free_P_d : 𝒟 (P⟪Ad s) = {}
  by (simp add: deterministic_P_d deterministic_div_free)



section ‹Reachability and Path›

text ‹We first need a preliminary result on constnd: a state termt is reachable
      from a state terms if and only if there exists a path between terms and termt

(* we may want to formalize the definition of a path, but not for the moment *)

lemma nd_iff_Ex_path:
  σ'  nd A σ  (path. path  []  hd path = σ  last path = σ' 
                            (i < length path - 1. a. path ! Suc i  τ A (path ! i) a))
  (is _  (path. path  []  ?rhs path σ σ'))
proof (rule iffI)
  show σ'  nd A σ  path. path  []  ?rhs path σ σ'
  proof (induct rule: nd.induct)
    case init
    have [σ]  []  ?rhs [σ] σ σ by simp
    thus ?case ..
  next
    case (step σ' σ'' a)
    from this(2) obtain path where path  []  ?rhs path σ σ' ..
    with step.hyps(3) have path @ [σ'']  []  ?rhs (path @ [σ'']) σ σ''
      by (simp add: nth_append)
        (metis One_nat_def Suc_lessI diff_Suc_Suc diff_zero last_conv_nth)
    thus ?case ..
  qed
next
  assume path. path  []  ?rhs path σ σ'
  then obtain path where path  [] ?rhs path σ σ' by blast
  thus σ'  nd A σ
  proof (induct path arbitrary: σ rule: list_nonempty_induct)
    case (single u)
    thus ?case using nd.init by fastforce
  next
    case (cons σ'' path)
    have σ'  nd A (hd path)
      by (rule cons.hyps(2))
        (use cons.hyps(1) cons.prems in simp,
          metis Suc_pred length_greater_0_conv not_less_eq nth_Cons_Suc)
    moreover have hd path  nd A σ
      using nd.init nd.step cons.hyps(1) cons.prems hd_conv_nth by fastforce
    ultimately show ?case by (fact nd_trans)
  qed
qed

lemma d_iff_Ex_path: 
  σ'  d A σ  (path. path  []  hd path = σ  last path = σ' 
                            (i < length path - 1. a. Some (path ! Suc i) = τ A (path ! i) a))
  by (subst nd_from_det_to_ndet[symmetric], subst nd_iff_Ex_path)
    (simp add: from_det_to_ndet_def split: option.split, metis option.inject)



section ‹Deadlock Freeness and ProcOmata›

lemma deadlock_free_P_nd_step_iff :
  deadlock_free (P_nd_step (ε A) (τ A) X σ)  
      ε A σ  {}  (a  ε A σ. σ'  τ A σ a. deadlock_free (X σ'))
  and deadlock_freeSKIPS_P_nd_step_iff :
  deadlock_freeSKIPS (P_nd_step (ε A) (τ A) X σ)  
      ε A σ  {}  (a  ε A σ. σ'  τ A σ a. deadlock_freeSKIPS (X σ'))
  and deadlock_free_PSKIPS_nd_step_iff :
  deadlock_free (PSKIPS_nd_step (ε A) (τ A) (ω A) X σ) 
      σ  ρ A  ε A σ  {}  (a  ε A σ. σ'  τ A σ a. deadlock_free (X σ'))
  and deadlock_freeSKIPS_PSKIPS_nd_step_iff :
  deadlock_freeSKIPS (PSKIPS_nd_step (ε A) (τ A) (ω A) X σ) 
      σ  ρ A  ε A σ  {}  (a  ε A σ. σ'  τ A σ a. deadlock_freeSKIPS (X σ'))
  by (simp_all add: deadlock_free_Mprefix_iff deadlock_freeSKIPS_Mprefix_iff
      deadlock_free_GlobalNdet_iff deadlock_freeSKIPS_GlobalNdet_iff
      non_deadlock_free_SKIPS deadlock_freeSKIPS_SKIPS ε_simps ρ_simps)


lemma deadlock_free_P_d_step_iff :
  deadlock_free (P_d_step (ε A) (τ A) X σ)  
       ε A σ  {}  (a  ε A σ. deadlock_free (X τ A σ a))
  and deadlock_freeSKIPS_P_d_step_iff :
  deadlock_freeSKIPS (P_d_step (ε A) (τ A) X σ)  
      ε A σ  {}  (a  ε A σ. deadlock_freeSKIPS (X τ A σ a))
  and deadlock_free_PSKIPS_d_step_iff:
  deadlock_free (PSKIPS_d_step (ε A) (τ A) (ω A) X σ) 
      σ  ρ A  ε A σ  {}  (a  ε A σ. deadlock_free (X τ A σ a))
  and deadlock_freeSKIPS_PSKIPS_d_step_iff:
  deadlock_freeSKIPS (PSKIPS_d_step (ε A) (τ A) (ω A) X σ) 
      σ  ρ A  ε A σ  {}  (a  ε A σ. deadlock_freeSKIPS (X τ A σ a))
  by (simp_all add: deadlock_free_Mprefix_iff deadlock_freeSKIPS_Mprefix_iff
      non_deadlock_free_SKIP deadlock_freeSKIPS_SKIP ρ_simps
      split: option.split)


lemma deadlock_freeSKIPS_PSKIPS_nd :
  (σ'. σ'  nd A σ  σ'  ρ A  ε A σ'  {}) 
   deadlock_freeSKIPS (PSKIPSAnd σ)
proof (induct A arbitrary: σ rule: PSKIPS_nd_induct)
  case adm
  show ?case by (simp add: deadlock_freeSKIPS_def)  
next
  show deadlock_freeSKIPS (SKIP undefined)
    by (fact deadlock_freeSKIPS_SKIP)
next
  case (step X) thus ?case
    unfolding deadlock_freeSKIPS_PSKIPS_nd_step_iff
    by (meson nd.init nd.step nd_trans)
qed

lemma deadlock_freeSKIPS_PSKIPS_d :
  (σ'. σ'  d A σ  σ'  ρ A  ε A σ'  {}) 
   deadlock_freeSKIPS (PSKIPSAd σ)
proof (induct A arbitrary: σ rule: PSKIPS_d_induct)
  case adm
  show ?case by (simp add: deadlock_freeSKIPS_def)  
next
  show deadlock_freeSKIPS (SKIP undefined)
    by (fact deadlock_freeSKIPS_SKIP)
next
  case (step X)
  thus ?case
    unfolding deadlock_freeSKIPS_PSKIPS_d_step_iff
    by (simp add: ε_simps) (metis d.init d.step d_trans option.sel)
qed


lemma deadlock_freeSKIPS_PSKIPS_nd_iff :
  assumes ρ_disjoint_ε A
  shows deadlock_freeSKIPS (PSKIPSAnd σ)  (σ'  nd A σ. σ'  ρ A  ε A σ'  {})
proof (intro iffI ballI)
  have σ'  nd A σ  deadlock_freeSKIPS (PSKIPSAnd σ) 
        (σ'  ρ A  ε A σ'  {})  deadlock_freeSKIPS (PSKIPSAnd σ') for σ'
  proof (induct rule: nd.induct)
    case init
    thus ?case
      by (subst (asm) PSKIPS_nd_rec)
        (auto simp add: deadlock_freeSKIPS_PSKIPS_nd_step_iff init)
  next
    case (step σ' σ'' a)
    from step.hyps(2)[OF step.prems] step.hyps(3) ρ_disjoint_εD[OF assms]
    show ?case
      by (subst (asm) PSKIPS_nd_rec)
        (auto simp add: deadlock_freeSKIPS_PSKIPS_nd_step_iff ε_simps,
          metis (mono_tags, lifting) Mprefix_is_STOP_iff PSKIPS_nd_rec_notin_ρ
          SKIPS_empty ε_simps(2) deadlock_freeSKIPS_SKIPS empty_Collect_eq empty_iff)
  qed
  thus σ'  nd A σ  deadlock_freeSKIPS (PSKIPSAnd σ)  σ'  ρ A  ε A σ'  {} for σ' ..
next
  show σ'nd A σ. σ'  ρ A  ε A σ'  {}  deadlock_freeSKIPS (PSKIPSAnd σ)
    by (simp add: deadlock_freeSKIPS_PSKIPS_nd)
qed


lemma deadlock_freeSKIPS_PSKIPS_d_iff :
  ρ_disjoint_ε A 
   deadlock_freeSKIPS (PSKIPSAd σ)  (σ'  d A σ. σ'  ρ A  ε A σ'  {})
  by (fold PSKIPS_nd_from_det_to_ndet_is_PSKIPS_d, subst deadlock_freeSKIPS_PSKIPS_nd_iff)
    (simp_all add: ρ_disjoint_ε_def nd_from_det_to_ndet)




lemma deadlock_free_P_nd :
  (σ'. σ'  nd A σ  ε A σ'  {})  deadlock_free (P⟪And σ)
proof (induct A arbitrary: σ rule: P_nd_induct)
  case adm
  show ?case by (simp add: deadlock_free_def)  
next
  show deadlock_free (DF UNIV)
    by (simp add: deadlock_free_def)
next
  case (step X) thus ?case
    unfolding deadlock_free_P_nd_step_iff
    by (meson nd.init nd.step nd_trans)
qed

lemma deadlock_free_P_d :
  (σ'. σ'  d A σ  ε A σ'  {})  deadlock_free (P⟪Ad σ)
proof (induct A arbitrary: σ rule: P_d_induct)
  case adm
  show ?case by (simp add: deadlock_free_def)  
next
  show deadlock_free (DF UNIV)
    by (simp add: deadlock_free_def)
next
  case (step X) thus ?case
    unfolding deadlock_free_P_d_step_iff
    by (simp add: ε_simps)
      (metis d.init d.step d_trans option.sel)
qed


lemma deadlock_free_P_nd_iff:
  deadlock_free (P⟪And σ)  (σ'  nd A σ. ε A σ'  {})
proof (intro iffI ballI)
  have σ'  nd A σ  deadlock_free (P⟪And σ) 
        (ε A σ'  {})  deadlock_free (P⟪And σ') for σ'
  proof (induct rule: nd.induct)
    case init
    thus ?case
      by (subst (asm) P_nd_rec)
        (auto simp add: deadlock_free_P_nd_step_iff init)
  next
    case (step σ' σ'' a)
    from step.hyps(2)[OF step.prems] step.hyps(3)
    show ?case
      by (subst (asm) P_nd_rec, unfold deadlock_free_P_nd_step_iff)
        (simp add: ε_simps,
          metis (mono_tags, lifting) P_nd_rec ε_simps(2)
          deadlock_free_Mprefix_iff empty_Collect_eq empty_iff)
  qed
  thus σ'  nd A σ  deadlock_free (P⟪And σ)  ε A σ'  {} for σ' ..
next
  show σ'nd A σ. ε A σ'  {}  deadlock_free (P⟪And σ)
    by (simp add: deadlock_free_P_nd)
qed



lemma deadlock_free_P_d_iff :
  deadlock_free (P⟪Ad σ)  (σ'  d A σ. ε A σ'  {})
  by (fold P_nd_from_det_to_ndet_is_P_d, unfold deadlock_free_P_nd_iff)
    (simp add: nd_from_det_to_ndet)



section ‹Events and Ticks of ProcOmata›

subsection ‹Events›

lemma events_of_PSKIPS_nd_subset :
  α(PSKIPSAnd σ)  (σ'  nd A σ. ε A σ')
proof (rule subsetI)
  fix a assume a  α(PSKIPSAnd σ)
  then obtain t where t  [] t  𝒯 (PSKIPSAnd σ) ev a  set t 
    by (metis empty_iff empty_set events_of_memD)
  thus a  (σ'  nd A σ. ε A σ')
  proof (induct t arbitrary: σ rule: list_nonempty_induct)
    case (single t0)
    thus ?case by (subst (asm) PSKIPS_nd_rec)
        (auto simp add: T_SKIPS T_Mprefix nd.init split: if_split_asm)
  next
    case (cons t0 t)
    from cons.prems(1) obtain b
      where b  ε A σ t0 = ev b t  𝒯 (σ'  τ A σ b. PSKIPSAnd σ')
      by (subst (asm) (3) PSKIPS_nd_rec)
        (auto simp add: T_Mprefix T_GlobalNdet T_SKIPS cons.hyps(1) ε_simps split: if_split_asm)
    thus ?case
      by (simp add: T_GlobalNdet cons.hyps(1) split: if_split_asm)
        (metis (no_types, lifting) UN_iff nd.simps nd_trans cons.hyps(2)
          cons.prems(2) eventptick.inject(1) set_ConsD)
  qed
qed

corollary events_of_PSKIPS_d_subset :
  α(PSKIPSAd σ)  (σ'  d A σ. ε A σ')
  by (metis PSKIPS_nd_from_det_to_ndet_is_PSKIPS_d nd_from_det_to_ndet
      det_ndet_conv_ε(1) events_of_PSKIPS_nd_subset)


lemma events_of_PSKIPS_nd :
  α(PSKIPSAnd σ) = (σ'  nd A σ. ε A σ')
  if ρ_disjoint_ε : ρ_disjoint_ε A
proof (intro subset_antisym subsetI)
  show a  α(PSKIPSAnd σ)  a   (ε A ` nd A σ) for a
    by (meson events_of_PSKIPS_nd_subset in_mono)
next
  fix a assume a  (σ'  nd A σ. ε A σ')
  then obtain σ' where a1: σ'  nd A σ and a2: a  ε A σ' by blast
  from a1[simplified nd_iff_Ex_path] obtain path
    where path  [] hd path = σ  last path = σ'  
           (i<length path - 1. e. path ! Suc i  τ A (path ! i) e) by blast
  from this a2 show a  α(PSKIPSAnd σ)
  proof (induct path arbitrary: σ rule: list_nonempty_induct)
    case (single p)
    with ρ_disjoint_ε[THEN ρ_disjoint_εD] show ?case
      by (subst PSKIPS_nd_rec)
        (auto simp add: events_of_Mprefix events_of_SKIPS ρ_simps)
  next
    case (cons p path)
    from cons(3) obtain b where b  ε A σ hd path  τ A σ b
      by (auto simp add: ε_simps) (metis cons(1) empty_iff hd_conv_nth length_greater_0_conv nth_Cons_0)
    moreover have a  α(PSKIPSAnd (hd path))
      using a2 cons.hyps(1, 2) cons.prems(1) less_diff_conv by fastforce
    ultimately show ?case
      using ρ_disjoint_ε[THEN ρ_disjoint_εD]
      by (subst PSKIPS_nd_rec)
        (auto simp add: events_of_Mprefix events_of_GlobalNdet events_of_SKIPS ρ_simps)
  qed
qed

corollary events_of_PSKIPS_d: ρ_disjoint_ε A  α(PSKIPSAd σ) =  (ε A ` d A σ)
  by (fold PSKIPS_nd_from_det_to_ndet_is_PSKIPS_d, subst events_of_PSKIPS_nd)
    (simp_all add: ρ_disjoint_ε_def nd_from_det_to_ndet)



lemma events_of_P_nd: α(P⟪And σ) =  (ε A ` nd A σ)
  by (unfold PSKIPS_nd_updated_ω, subst events_of_PSKIPS_nd)
    (auto simp add: ρ_disjoint_ε_def ρ_simps ε_simps)


lemma events_of_P_d: α(P⟪Ad σ) =  (ε A ` d A σ)
  by (metis P_nd_from_det_to_ndet_is_P_d nd_from_det_to_ndet
      det_ndet_conv_ε(1) events_of_P_nd)



subsection ‹Strict Events›

corollary strict_events_of_PSKIPS_nd_subset :
  α(PSKIPSAnd σ)  (σ'  nd A σ. ε A σ')
  by (meson events_of_PSKIPS_nd_subset order_trans strict_events_of_subset_events_of)

corollary strict_events_of_PSKIPS_d_subset :
  α(PSKIPSAd σ)  (σ'  d A σ. ε A σ')
  by (meson events_of_PSKIPS_d_subset order_trans strict_events_of_subset_events_of)

lemma strict_events_of_PSKIPS_nd :
  ρ_disjoint_ε A  α(PSKIPSAnd σ) = (σ'  nd A σ. ε A σ')
  by (metis div_free_PSKIPS_nd events_of_PSKIPS_nd events_of_is_strict_events_of_or_UNIV)

corollary strict_events_of_PSKIPS_d:
  ρ_disjoint_ε A  α(PSKIPSAd σ) = (σ'  d A σ. ε A σ')
  by (metis div_free_PSKIPS_d events_of_PSKIPS_d events_of_is_strict_events_of_or_UNIV)

lemma strict_events_of_P_nd: α(P⟪And σ) = (σ'  nd A σ. ε A σ')
  by (metis div_free_P_nd events_of_P_nd events_of_is_strict_events_of_or_UNIV)

lemma strict_events_of_P_d: α(P⟪Ad σ) = (σ'  d A σ. ε A σ')
  by (metis div_free_P_d events_of_P_d events_of_is_strict_events_of_or_UNIV)



subsection ‹Ticks›

lemma ticks_of_PSKIPS_nd_subset :
  ✓s(PSKIPSAnd σ)  (σ'  nd A σ. ω A σ')
proof (rule subsetI)
  fix r assume r  ✓s(PSKIPSAnd σ)
  then obtain t where t @ [✓(r)]  𝒯 (PSKIPSAnd σ)
    by (blast dest: ticks_of_memD)
  thus r  (σ'  nd A σ. ω A σ')
  proof (induct t arbitrary: σ)
    case Nil thus ?case
      by (subst (asm) PSKIPS_nd_rec)
        (auto simp add: T_SKIPS nd.init split: if_split_asm)
  next
    case (Cons t0 t)
    from Cons.prems(1) obtain b
      where b  ε A σ t0 = ev b t @ [✓(r)]  𝒯 (σ'  τ A σ b. PSKIPSAnd σ')
      by (subst (asm) (3) PSKIPS_nd_rec)
        (auto simp add: T_Mprefix T_GlobalNdet T_SKIPS Cons.hyps(1) ε_simps split: if_split_asm)
    thus ?case
      by (simp add: T_GlobalNdet Cons.hyps(1) split: if_split_asm)
        (metis nd.init[of σ A] UN_iff[of r ω A nd A _]
          nd_trans[of _ A _ σ] nd.step[of σ A σ _ b] Cons.hyps)
  qed
qed

corollary ticks_of_PSKIPS_d_subset :
  ✓s(PSKIPSAd σ)  {ω A σ' |σ'. σ'  d A σ  ω A σ'  }
proof (fold PSKIPS_nd_from_det_to_ndet_is_PSKIPS_d,
    rule subset_trans[OF ticks_of_PSKIPS_nd_subset])
  show (σ'  nd Adnd σ. ω Adnd σ')  {ω A σ' |σ'. σ'  d A σ  ω A σ'  }
    by (simp add: nd_from_det_to_ndet subset_iff)
      (simp add: from_det_to_ndet_def split: option.split, metis option.sel)
qed


lemma ticks_of_PSKIPS_nd :
  ✓s(PSKIPSAnd σ) = (σ'  nd A σ. ω A σ')
  if ρ_disjoint_ε : ρ_disjoint_ε A
proof (intro subset_antisym subsetI)
  show r  ✓s(PSKIPSAnd σ)  r  (σ'  nd A σ. ω A σ') for r
    by (meson in_mono ticks_of_PSKIPS_nd_subset)
next
  fix r assume r  (σ'  nd A σ. ω A σ')
  then obtain σ' where a1: σ'  nd A σ and a2: r  ω A σ' by blast
  from a1[simplified nd_iff_Ex_path] obtain path
    where path  [] hd path = σ  last path = σ'  
           (i<length path - 1. e. path ! Suc i  τ A (path ! i) e) by blast
  from this a2 show r  ✓s(PSKIPSAnd σ)
  proof (induct path arbitrary: σ rule: list_nonempty_induct)
    case (single p)
    thus ?case
      by (subst PSKIPS_nd_rec)
        (auto simp add: ticks_of_SKIPS)
  next
    case (cons p path)
    from cons(3) obtain b where b  ε A σ hd path  τ A σ b
      by (auto simp add: ε_simps) (metis cons(1) empty_iff hd_conv_nth length_greater_0_conv nth_Cons_0)
    moreover have r  ✓s(PSKIPSAnd (hd path))
      using a2 cons.hyps(1, 2) cons.prems(1) less_diff_conv by fastforce
    ultimately show ?case
      using ρ_disjoint_ε[THEN ρ_disjoint_εD]
      by (subst PSKIPS_nd_rec)
        (auto simp add: ticks_of_Mprefix ticks_of_GlobalNdet events_of_SKIPS ρ_simps)
  qed
qed

corollary ticks_of_PSKIPS_d :
  ρ_disjoint_ε A  ✓s(PSKIPSAd σ) = {ω A σ' |σ'. σ'  d A σ  ω A σ'  }
  by (fold PSKIPS_nd_from_det_to_ndet_is_PSKIPS_d, subst ticks_of_PSKIPS_nd,
      simp_all add: ρ_disjoint_ε_def nd_from_det_to_ndet)
    (auto simp add: from_det_to_ndet_def split: option.split_asm, metis option.sel)


lemma ticks_of_P_nd : ✓s(P⟪And σ) = {}
  by (simp add: PSKIPS_nd_updated_ω ticks_of_PSKIPS_nd)

lemma ticks_of_P_d: ✓s(P⟪Ad σ) = {}
  by (metis P_nd_from_det_to_ndet_is_P_d ticks_of_P_nd)



lemma non_terminating_iff_empty_ticks_of :
  non_terminating P  ✓s(P) = {}
  by (simp add: non_terminating_is_right tickFree_traces_iff_empty_ticks_of)



corollary non_terminating_P_nd : non_terminating (P⟪And σ)
  by (simp add: non_terminating_iff_empty_ticks_of ticks_of_P_nd)

corollary non_terminating_P_d : non_terminating (P⟪Ad σ)
  by (metis P_nd_from_det_to_ndet_is_P_d non_terminating_P_nd)

corollary non_terminating_PSKIPS_nd :
  ρ A  nd A σ = {}  non_terminating (PSKIPSAnd σ)
  by (simp add: PSKIPS_nd_empty_ρ_inter_ℛnd non_terminating_P_nd)

corollary non_terminating_PSKIPS_nd_iff :
  ρ_disjoint_ε A  non_terminating (PSKIPSAnd σ)  ρ A  nd A σ = {}
  by (auto simp add: non_terminating_iff_empty_ticks_of ticks_of_PSKIPS_nd ρ_simps)

corollary non_terminating_PSKIPS_d :
  ρ A  d A σ = {}  non_terminating (PSKIPSAd σ)
  by (simp add: PSKIPS_d_empty_ρ_inter_ℛd non_terminating_P_d)

corollary non_terminating_PSKIPS_d_iff :
  ρ_disjoint_ε A  non_terminating (PSKIPSAd σ)  ρ A  d A σ = {}
  by (auto simp add: non_terminating_iff_empty_ticks_of ticks_of_PSKIPS_d ρ_simps)



subsection ‹Strict Ticks›

corollary strict_ticks_of_PSKIPS_nd_subset :
  s(PSKIPSAnd σ)  (σ'  nd A σ. ω A σ')
  by (metis div_free_PSKIPS_nd ticks_of_PSKIPS_nd_subset ticks_of_is_strict_ticks_of_or_UNIV)

corollary strict_ticks_of_PSKIPS_d_subset :
  s(PSKIPSAd σ)  {ω A σ' |σ'. σ'  d A σ  ω A σ'  }
  by (metis (mono_tags, lifting) strict_ticks_of_subset_ticks_of subset_trans ticks_of_PSKIPS_d_subset)

lemma strict_ticks_of_PSKIPS_nd :
  ρ_disjoint_ε A  s(PSKIPSAnd σ) = (σ'  nd A σ. ω A σ')
  by (metis div_free_PSKIPS_nd ticks_of_PSKIPS_nd ticks_of_is_strict_ticks_of_or_UNIV)

corollary strict_ticks_of_PSKIPS_d :
  ρ_disjoint_ε A  s(PSKIPSAd σ) = {ω A σ' |σ'. σ'  d A σ  ω A σ'  }
  by (metis (mono_tags, lifting) div_free_PSKIPS_d ticks_of_PSKIPS_d ticks_of_is_strict_ticks_of_or_UNIV)

lemma strict_ticks_of_P_nd: s(P⟪And σ) = {}
  by (metis div_free_P_nd ticks_of_P_nd ticks_of_is_strict_ticks_of_or_UNIV)

lemma strict_ticks_of_P_d: s(P⟪Ad σ) = {}
  by (metis P_nd_from_det_to_ndet_is_P_d strict_ticks_of_P_nd)



subsection ‹Ticks length›

lemma is_ticks_length_PSKIPS_nd :
  σ' rs. σ'  nd A σ  rs  ω A σ'  length rs = n
    lengthn(PSKIPSAnd σ)
  by (auto simp add: is_ticks_length_def
      dest!: set_mp[OF strict_ticks_of_PSKIPS_nd_subset])

lemma is_ticks_length_PSKIPS_nd_iff :
  ρ_disjoint_ε A 
   lengthn(PSKIPSAnd σ)  (σ'  nd A σ. rs  ω A σ'. length rs = n)
  by (simp add: is_ticks_length_def strict_ticks_of_PSKIPS_nd)

lemma is_ticks_length_PSKIPS_d :
  σ'. σ'  d A σ  ω A σ'    length ω A σ' = n
    lengthn(PSKIPSAd σ)
  by (auto simp add: is_ticks_length_def
      dest!: set_mp[OF strict_ticks_of_PSKIPS_d_subset])

lemma is_ticks_length_PSKIPS_d_iff :
  ρ_disjoint_ε A 
   lengthn(PSKIPSAd σ)  (σ'  d A σ. ω A σ'    length ω A σ' = n)
  by (auto simp add: is_ticks_length_def strict_ticks_of_PSKIPS_d)



(*<*)
end
  (*>*)