Theory Traces

theory Traces 
imports Main HOL.Lattices HOL.List 
begin

chapter ‹Traces and Definitive Prefixes›

section ‹Traces›

typedecl Σ
type_synonym 'a finite_trace = 'a list
type_synonym 'a infinite_trace = nat  'a
datatype 'a trace = Finite 'a finite_trace | Infinite 'a infinite_trace

fun thead :: 'a trace  'a where
  thead (Finite t) = t ! 0
| thead (Infinite t) = t 0

fun append :: 'a trace  'a trace  'a trace (infixr  80) where
  (Finite t)    (Infinite ω) = Infinite (λn. if n < length t then t!n else ω (n - length t))
| (Finite t)    (Finite u)   = Finite (t @ u)
| (Infinite t)  u            = Infinite t

definition ε :: 'a trace where
  ε = Finite []

definition singleton :: 'a  'a trace where
  singleton σ = Finite [σ]

interpretation trace: monoid_list (⌢) ε
proof unfold_locales
  fix a :: 'a trace show ε  a = a
    by (cases a; simp add: ε_def)
next
  fix a :: 'a trace show a  ε = a 
    by (cases a; simp add: ε_def)
next
  fix a b c :: 'a trace show (a  b)  c = a  (b  c)
    apply (cases a; simp)
    apply (cases b; simp)
    apply (cases c; simp)
    apply (rule ext; simp)
    by (smt (verit, ccfv_threshold) 
            add.commute add_diff_inverse_nat add_less_cancel_left 
            nth_append trans_less_add2)
qed

lemma finite_empty_suffix: 
  assumes Finite xs = Finite xs  t
  shows t = ε
  using assms by (cases t) (simp_all add: ε_def)

lemma finite_empty_prefix: 
  assumes Finite xs = t  Finite xs
  shows t = ε
  using assms by (cases t) (simp_all add: ε_def)

lemma finite_finite_suffix: 
  assumes Finite xs = Finite ys  t
  obtains zs where t = Finite zs
  using assms by (cases t) (simp_all)

lemma finite_finite_prefix:
  assumes Finite xs = t  Finite ys
  obtains zs where t = Finite zs
  using assms by (cases t) (simp_all)

lemma append_is_empty:
  assumes t  u = ε
  shows   t = ε
  and     u = ε
  using assms by (simp add: ε_def; cases t; cases u; simp)+

fun ttake :: nat  'a trace  'a finite_trace where
  ttake k (Finite xs) = take k xs
| ttake k (Infinite xs) = map xs [0..<k]


definition itdrop :: nat  'a infinite_trace  'a infinite_trace where
  itdrop k xs = (λi. xs (i + k))

lemma itdrop_itdrop[simp]: itdrop i (itdrop j x) = itdrop (i + j) x
  by (simp add: itdrop_def add.commute add.left_commute)

lemma itdrop_zero[simp]: itdrop 0 x = x
  by (simp add: itdrop_def)


fun tdrop :: nat  'a trace  'a trace where
  tdrop k (Finite xs) = Finite (drop k xs)
| tdrop k (Infinite xs) = Infinite (itdrop k xs)

lemma ttake_simp[simp]: ttake (length xs) (Finite xs  t) = xs
  by (cases t, auto intro:  list_eq_iff_nth_eq[THEN iffD2])

lemma ttake_tdrop[simp]: Finite (ttake k t)  tdrop k t = t
  by (cases t, auto simp: itdrop_def)

definition prefixes :: 'a trace  'a trace set ( _› [80] 80) where
   t = { u | u v. t = u  v }

definition extensions :: 'a trace  'a trace set ( _› [80] 80) where
   t = { t  u | u. True }

lemma prefixes_extensions: t   u  u   t
  unfolding prefixes_def extensions_def by simp

interpretation prefixes: order λ t u. t   u λ t u. t   u  t  u
proof 
  (* Reflexivity *)
  fix x :: 'a trace 
  show x   x
    unfolding prefixes_def
    by (simp, metis trace.right_neutral)
next
  (* Strict Ordering *)
  fix x y :: 'a trace
  show (x   y  x  y) = (x   y  ¬ y   x)
    unfolding prefixes_def
    by (simp, metis append.simps(3) append_is_empty(1) finite_empty_suffix 
                    trace.assoc trace.exhaust)
next
  (* Antisymmetry *)
  fix x y :: 'a trace
  assume assms: x   y y   x
  show x = y 
  proof (cases y)
    case Finite note yfinite = this 
    show ?thesis
    proof (cases x)
      case Finite
      with assms(2) obtain z where x = y  z 
        unfolding  prefixes_def
        by auto
      with assms(1) yfinite show ?thesis
        unfolding  prefixes_def
        by (force simp: trace.assoc dest: finite_empty_suffix append_is_empty)
    qed (smt (verit, del_insts) CollectD append.simps(3) assms(1) prefixes_def)
  qed (smt (verit, del_insts) CollectD append.simps(3) assms(2) prefixes_def)
next
  (* Transitivity *)
  fix x y z :: 'a trace
  assume x   y y   z
  then show x   z
  unfolding  prefixes_def by (force simp: trace.assoc)
qed

lemma prefixes_empty_least : ε   t
  by (simp add: prefixes_def)
  
lemma prefixes_infinite_greatest : Infinite x   t  t = Infinite x
  by (simp add: prefixes_def)



lemma prefixes_finite : Finite xs   Finite ys  ( zs. ys = xs @ zs)
proof (rule iffI)
  show Finite xs   Finite ys  zs. ys = xs @ zs
    using finite_finite_suffix by (fastforce simp: prefixes_def)
next
  show zs. ys = xs @ zs  Finite xs   Finite ys
    by (clarsimp simp: prefixes_def) (metis Traces.append.simps(2))
qed

lemma ttake_take : take n (ttake m t) = ttake (min n m) t
  by (cases t) (simp_all add: min_def take_map)

lemma tdrop_tdrop : tdrop n (tdrop m t) = tdrop (n + m) t
  by (cases t) (simp_all add: add.commute add.left_commute)


lemma tdrop_mono: t   u  tdrop k t   tdrop k u
proof -
  { fix v assume A: u = t  v then have va. tdrop k (t  v) = tdrop k t  va
  proof (cases t; cases v)
    fix x1 x2 assume t = Finite x1 and v = Finite x2 with A show ?thesis
      by (simp, metis Traces.append.simps(2))
  next
    fix x1 x2 assume t = Finite x1 and v = Infinite x2 with A
     have tdrop k (t  v) = tdrop k t  Infinite (itdrop (k - length x1) x2)
      apply simp
      apply (rule ext)
      apply clarsimp
      apply (rule conjI)      
       apply (simp add: add.commute itdrop_def less_diff_conv)
      by (smt (z3) add.commute add_diff_cancel_left' add_diff_inverse_nat diff_is_0_eq' 
                   diff_right_commute itdrop_def linorder_not_less nat_less_le)
    then show va. tdrop k (t  v) = tdrop k t  va
      by auto
  qed auto } note A = this
  assume t   u with A show ?thesis unfolding prefixes_def by clarsimp
qed

lemma ttake_finite_prefixes : Finite xs   t  xs = ttake (length xs) t
proof (rule iffI)
  show Finite xs   t  xs = ttake (length xs) t
    by (clarsimp simp: prefixes_def)
next
  show xs = ttake (length xs) t  Finite xs   t
    unfolding prefixes_def using ttake_tdrop
    by (metis (full_types) mem_Collect_eq)
qed

lemma ttake_prefixes : a  b  Finite (ttake a t)   Finite (ttake b t)
  by (cases t; simp add: ttake_finite_prefixes min_def take_map)

lemma finite_directed:
assumes Finite xs   t Finite ys   t
shows zs. (xs = ys @ zs)  (ys = xs @ zs)
proof (cases length xs > length ys)
  case True
  with assms show ?thesis 
    apply (simp add: ttake_finite_prefixes)
    using ttake_prefixes[simplified prefixes_finite]
    by (metis less_le_not_le) 
next
  case False
  from assms this[THEN leI] show ?thesis 
    apply (simp add: ttake_finite_prefixes)
    using ttake_prefixes[simplified prefixes_finite]
    by (metis)
qed


lemma prefixes_directed: u   t  v   t  u   v  v   u
proof (cases v; cases u)
  { fix a b assume Finite a   t Finite b   t 
  then have Finite a   Finite b  Finite b   Finite a
    using finite_directed prefixes_finite by blast } note X = this
  fix a b show u   t  v   t  v = Finite a  u = Finite b  u   v  v   u 
    using X by auto
qed (auto simp: prefixes_def dest: prefixes_infinite_greatest)

interpretation extensions: order λ t u. t   u λ t u. t   u  t  u
proof
qed (auto simp: prefixes_extensions[THEN sym] dest: prefixes.leD intro:prefixes.order.trans)

lemma extensions_infinite[simp]:  Infinite xs = { Infinite xs }
  by (simp add: extensions_def)

lemma extensions_empty[simp]:  ε = UNIV
  by (simp add: extensions_def)

lemma prefixes_empty:  ε = {ε}
  apply (clarsimp simp add: set_eq_iff ε_def prefixes_def)
  apply (rule iffI)
  apply (metis ε_def append_is_empty(1))
  by (metis ε_def trace.left_neutral)


section ‹Prefix Closure›

definition prefix_closure :: 'a trace set  'a trace set (s _› [80] 80) where
  s X = ( t  X. prefixes t)

lemma prefix_closure_subset: X  s X
  unfolding prefix_closure_def
  by auto 

lemma prefix_closure_infinite: Infinite x  s X  Infinite x  X
proof
  assume Infinite x  s X then show Infinite x  X
    by (metis UN_E prefix_closure_def prefixes_infinite_greatest)
next
  assume Infinite x  X then show Infinite x  s X
    by (meson in_mono prefix_closure_subset)
qed

lemma prefix_closure_idem: s s X = s X
  unfolding prefix_closure_def
  using prefixes.order.trans by blast

lemma prefix_closure_mono: X  Y  s X  s Y
  unfolding prefix_closure_def
  by blast

lemma prefix_closure_union_distrib: s (X  Y) = s X  s Y
  unfolding prefix_closure_def
  by simp

lemma prefix_closure_Union_distrib: s ( S) =  (prefix_closure ` S)
  unfolding prefix_closure_def
  by simp

lemma prefix_closure_Inter: s ( (prefix_closure ` S)) =  (prefix_closure ` S)
  unfolding prefix_closure_def
  using prefixes.dual_order.trans by fastforce

lemma prefix_closure_inter: s (s X  s Y) = s X  s Y
  by (rule prefix_closure_Inter[where S = {X,Y}, simplified])

lemma prefix_closure_UNIV: s UNIV = UNIV
  unfolding prefix_closure_def by blast

lemma prefix_closure_empty: s {} = {}
  unfolding prefix_closure_def by blast

lemma prefix_closure_extensions: s ( t) =  t   t
  by (force intro: prefix_closure_subset dest: prefixes_directed
            simp: prefixes_extensions[THEN sym] prefix_closure_def)

lemma prefix_closure_prefixes: s ( t) =  t
  unfolding prefix_closure_def
  by (force intro: prefixes.dual_order.trans)

section ‹Definitive Prefixes›

definition dprefixes :: 'a trace set  'a trace set  (d _› [80] 80) where
  d X = { t | t.  t  s X }

lemma dprefixes_are_prefixes : d X  s X
  unfolding dprefixes_def
  using extensions.order.refl by blast

lemma prefix_closure_dprefixes : s (d X)  s X
  using dprefixes_are_prefixes prefix_closure_idem prefix_closure_mono 
  by blast

lemma dprefixes_idem: d d X = d X
proof
  show d d X  d X
    using prefix_closure_dprefixes 
    by (force simp: dprefixes_def)
next
  show d X  d d X 
    using extensions.order.trans prefix_closure_subset 
    by (force simp: dprefixes_def)
qed

lemma dprefixes_contains_extensions: t  d X   t  d X
  unfolding dprefixes_def
  using extensions.dual_order.trans by auto

lemma dprefixes_infinite: Infinite x  d X  Infinite x  X
proof
  show Infinite x  X  Infinite x  d X
  unfolding dprefixes_def
  using prefix_closure_subset by fastforce
next
  show Infinite x  d X  Infinite x  X
  unfolding dprefixes_def
  by (clarsimp simp: prefix_closure_infinite)
qed


lemma dprefixes_UNIV: d UNIV = UNIV
  unfolding dprefixes_def
  using prefix_closure_UNIV by force

lemma dprefixes_empty: d {} = {}
  unfolding dprefixes_def
  using prefix_closure_empty by blast

lemma dprefixes_Inter_distrib: d ( S)   (dprefixes ` S)
  unfolding dprefixes_def prefix_closure_def
  by auto

lemma dprefixes_Inter: d ( (dprefixes ` S)) =  (dprefixes ` S)
proof
  show  (dprefixes ` S)  d  (dprefixes ` S)
    unfolding dprefixes_def prefix_closure_def
    using prefixes.order.refl extensions.dual_order.trans 
    by force
next
  show d  (dprefixes ` S)   (dprefixes ` S)
    using dprefixes_idem  dprefixes_Inter_distrib 
    by blast
qed

lemma dprefixes_mono: 
  assumes X  Y
  shows d X  d Y
  using assms
  apply (simp add: dprefixes_def)
  apply (simp add: prefix_closure_def)
  apply (rule subsetI)
  using prefixes_extensions by blast


lemma dprefixes_inter: d (d X  d Y) = (d X  d Y)
  by (rule dprefixes_Inter[where S = {X,Y}, simplified])

lemma dprefixes_inter_distrib: d (X  Y)  d X  d Y
  using dprefixes_Inter_distrib[where S = {X,Y}] by auto

section ‹Definitive Sets›

definition definitive:: 'a trace set  bool where
  definitive X  d X = X

lemma definitive_image: X  S. definitive X  dprefixes ` S = S
  unfolding definitive_def by auto

lemma definitive_dprefixes: definitive (d X)
  unfolding definitive_def by (rule dprefixes_idem)

lemma definitive_contains_extensions: definitive X  t  X   t  X
  unfolding definitive_def using dprefixes_contains_extensions by blast

lemma definitive_UNIV: definitive UNIV
  unfolding definitive_def by (rule dprefixes_UNIV)

lemma definitive_empty: definitive {}
  unfolding definitive_def by (rule dprefixes_empty)

lemma definitive_Inter: X  S. definitive X  definitive ( S)
  unfolding definitive_def using dprefixes_Inter definitive_image[simplified definitive_def]
  by metis

lemma definitive_inter: definitive X  definitive Y  definitive (X  Y)
  using definitive_Inter[where S = {X,Y}, simplified] by blast

lemma definitive_infinite_extension:
  assumes definitive X and t  X 
  shows  f. Infinite f  X  t   Infinite f
using assms proof (cases t)
  case (Finite xs) then show ?thesis
    apply (intro exI[where x=λn. if n < length xs then xs!n else undefined])
    by (force simp:   prefixes_extensions[THEN sym] prefixes_def 
              intro!: definitive_contains_extensions[THEN subsetD, OF assms] 
              intro:  exI[where x=Infinite (λ_. undefined)])
qed auto

lemma definitive_elemI:
  assumes definitive X  t  s X 
  shows t  X
  using assms
  by (auto simp add: definitive_def dprefixes_def)


definition dUnion :: 'a trace set set  'a trace set (d) where
  d X = d  X

abbreviation dunion :: 'a trace set  'a trace set  'a trace set  (infixl d 65) where
  X d Y  d {X,Y}

lemma dprefixes_dUnion: d d S = d S
  by (simp add: dUnion_def dprefixes_idem)

lemma definitive_dUnion: definitive (d S)
  by (simp add: dprefixes_dUnion definitive_def)

lemma dUnion_contains_dprefixes: t  S  d t  d S
  by (auto simp: dUnion_def dprefixes_def prefix_closure_def)

lemma dUnion_contains_definitive: X  S  definitive X  X  d S
  unfolding definitive_def
  using dUnion_contains_dprefixes by blast

lemma dUnion_empty[simp]: d {} = {}
  unfolding dUnion_def
  by (simp add: dprefixes_empty)

lemma dUnion_least_dprefixes: (X. X  S  X  d Z)   d ( (dprefixes ` S))  d Z
  unfolding dprefixes_def prefix_closure_def
  by (simp add: subset_iff, meson extensions.order_refl prefixes.order.trans)

lemma dUnion_least_definitive: 
  assumes all_defn: X  S. definitive X
  shows (X. X  S  X  Z)  definitive Z  d  S  Z
  using  definitive_image[OF all_defn,THEN sym] dUnion_least_dprefixes definitive_def
  by metis

section ‹A type for definitive sets›

typedef 'a dset = {p :: 'a trace set. definitive p }
  using definitive_UNIV by blast

setup_lifting type_definition_dset

lift_definition Inter_dset :: 'a dset set  'a dset () is λ ss.  ss
  by (simp add: definitive_Inter)

abbreviation inter_dset :: 'a dset  'a dset  'a dset  (infixl  66)  where
  X  Y   {X,Y}

lift_definition Union_cset :: 'a dset set  'a dset () is λ ss. d ss
  by (rule definitive_dUnion)

abbreviation union_dset :: 'a dset  'a dset  'a dset  (infixl  65)  where
  X  Y   {X,Y}

lift_definition empty_dset :: 'a dset () is {}
  by (rule definitive_empty)

lift_definition univ_dset :: 'a dset (Σ∞) is UNIV 
  by (rule definitive_UNIV)

lift_definition subset_dset :: 'a dset  'a dset  bool (infix  50) is (⊆) 
  done

lift_definition strict_subset_cset :: 'a dset  'a dset  bool  (infix  50) is (⊂) 
  done

lift_definition in_dset :: 'a trace  'a dset  bool is (∈)
  done

lift_definition notin_dset :: 'a trace  'a dset  bool is (∉)
  done



lemma in_dset_ε: in_dset ε A  A = Σ∞
  apply (transfer)
  using definitive_contains_extensions extensions_empty by blast

lemma in_dset_UNIV: in_dset x Σ∞
  by (transfer, simp)

lemma in_dset_subset: A  B  in_dset x A  in_dset x B
  by (transfer, auto)

lemma in_dset_inter: in_dset x A  in_dset x B  in_dset x (A  B)
  by (transfer, simp)


interpretation dset: complete_lattice   (⊓) (⊑) (⊏) (⊔)  Σ∞
proof (unfold_locales;transfer)
  fix X Y Z :: 'a trace set assume definitive X definitive Y definitive Z
  then show Y  X  Z  X  (Y d Z)  X
    by (metis dUnion_def dUnion_least_definitive insert_iff singletonD)
next
  fix A :: 'a trace set set and Z :: 'a trace set 
  assume XA. definitive X definitive Z (X. definitive X  X  A  X  Z)
  then show d A  Z
    by (simp add: dUnion_def dUnion_least_definitive)
qed (auto simp: dUnion_contains_definitive)

section ‹Isomorphism of definitive sets and LTL properties›

definition infinites :: 'a trace set  'a infinite_trace set where
  infinites X = (x  X. case x of Finite xs  {} | Infinite xs  {xs})

lemma infinites_alt: Infinite ` infinites A = A  range Infinite
unfolding set_eq_iff proof 
  fix x { assume (x  Infinite ` infinites A) hence (x  A  range Infinite)
    by (clarsimp simp: infinites_def split!: trace.split_asm)
  } moreover { assume (x  A  range Infinite) hence (x  Infinite ` infinites A)
      by (force simp: infinites_def split!: trace.split intro!: imageI)
  } ultimately show (x  Infinite ` infinites A) = (x  A  range Infinite)
    by blast
qed

lemma infinites_append_right: t  Infinite ω  range Infinite
  by (cases t; auto)

lemma infinites_prefix_closure:
  assumes definitive X
  shows s Infinite ` infinites X = s X
  unfolding prefix_closure_def infinites_def
  using definitive_infinite_extension[OF assms] prefixes.order.trans 
  by (force split: trace.split_asm)

lemma infinites_UNIV[simp]: infinites UNIV = UNIV
 by (auto simp: infinites_def split: trace.split)

lemma infinites_empty[simp]: infinites {} = {}
  by (auto simp: infinites_def)
 
lemma infinites_Inter: infinites ( S) =  (infinites ` S)
  unfolding infinites_def
  apply (rule set_eqI; rule iffI)
   apply (force)
   apply (simp split: trace.split trace.split_asm)
  by (metis InterI trace.distinct(1) trace.exhaust trace.inject(2))

lemma infinites_Union: infinites ( S) =  (infinites ` S)
  unfolding infinites_def
  by auto

lemma infinites_dprefixes: infinites (d X) = infinites X
  unfolding infinites_def
   by (force simp: dprefixes_infinite split: trace.split trace.split_asm)

lemma infinites_dprefixes_Infinite: infinites (d Infinite ` X) = X
proof
  show infinites (d Infinite ` X)  X
    unfolding infinites_def
    using prefixes_infinite_greatest
    by (force split: trace.split_asm simp: dprefixes_def prefix_closure_def)
next
  show X  infinites (d Infinite ` X)
    by (force simp: infinites_def dprefixes_def prefix_closure_def split: trace.split)
qed

lift_definition property :: 'a dset  'a infinite_trace set is infinites
  done

lift_definition definitives :: 'a infinite_trace set  'a dset is λx. d (Infinite ` x)
  by (rule definitive_dprefixes)

lemma property_inverse: property (definitives X) = X
  by (transfer, simp add: infinites_dprefixes_Infinite)

lemma definitives_inverse: definitives (property X) = X
proof (rule dset.order_antisym)
  show definitives (property X)  X
    by (transfer, force simp: dprefixes_def infinites_prefix_closure 
                        intro: definitive_elemI)
next
  show X  definitives (property X)
    apply transfer
    using definitive_contains_extensions definitive_infinite_extension 
    by (force simp: dprefixes_def prefix_closure_def infinites_def)
qed

lemma definitives_mono: A  B  definitives A  definitives B
  by (transfer, metis dprefixes_inter_distrib image_mono inf.order_iff le_infE)

lemma property_mono: A  B  property A  property B
  by (transfer, auto simp: infinites_def)

lemma definitives_reflecting: definitives A  definitives B  A  B
  using property_inverse property_mono by metis

lemma completions_reflecting: property A  property B  A  B
  using definitives_inverse definitives_mono by metis

lemma property_Inter: property ( S) =  (property ` S)
  by (transfer, simp add: infinites_Inter)

lemma property_Union: property ( S) =  (property ` S)
  by (transfer, simp add: dUnion_def infinites_dprefixes infinites_Union)



interpretation dset: complete_distrib_lattice   (⊓) (⊑) (⊏) (⊔)  Σ∞
  by (unfold_locales)
     (auto intro: completions_reflecting simp add: property_Inter property_Union INF_SUP_set)


definition iprepend :: 'a infinite_trace set  'a infinite_trace set where
  iprepend X = {t. itdrop 1 t  X }

lemma iprepend_itdrop: itdrop k x  iprepend B  itdrop (Suc k) x  B
  by (simp add: iprepend_def)

lemmas iprepend_itdrop_0[simp] = iprepend_itdrop[where k = 0,simplified]

definition prepend' :: 'a trace set  'a trace set where
  prepend' X = {t. tdrop 1 t  X }

lemma trace_uncons_cases [case_names Cons Nil]: 
  assumes σ t. x = singleton σ  t  P 
  and x = ε  P 
  shows P
proof (cases x)
  case (Finite xs)
  then show ?thesis 
    by (cases xs; 
        force simp: assms(2)[simplified ε_def] 
              intro: assms(1)[where t = Finite ts for ts,
                     simplified singleton_def append.simps List.append.simps])
next
  case (Infinite f) note A = this
  have f = (λn. if n = 0 then [f 0] ! n else (f  Suc) (n - length [f 0]))
    by (rule ext, simp)
  with A show ?thesis 
    using assms(1)[where σ = f 0 and t = Infinite (f  Suc),
                   simplified singleton_def append.simps, simplified]
    by simp
qed

lemma append_prefixes_left: a   b  c  a   c  b
  by (simp add: prefixes_def) (metis trace.assoc)

lemma tdrop_singleton_append[simp]: tdrop (Suc n) (singleton σ  t) = tdrop n t
  by (cases t, simp_all add: singleton_def itdrop_def)
lemma tdrop_zero[simp]: tdrop 0 t = t
  by (cases t; simp)
lemma tdrop_ε[simp]: tdrop k ε = ε
  by (simp add: ε_def)

lemma prepend'_prefix_closure: s (prepend' X)  prepend' (s X)
proof (rule subsetI)
  fix x 
  assume A: x  s prepend' X 
  show x  prepend' (s X)
  proof (cases x rule: trace_uncons_cases)
    case (Cons σ t)
    with A show ?thesis 
      unfolding prefix_closure_def prepend'_def prefixes_def 
      by (fastforce simp: trace.assoc)
  next
    case Nil
    with A show ?thesis 
      unfolding prefix_closure_def prepend'_def
      by (force simp: prefixes_empty_least)
  qed
qed

lemma prepend'_dprefixes : 
assumes definitive X
shows d prepend' X = prepend' X
proof
  show d prepend' X  prepend' X
  proof (rule subsetI)
    fix x assume A: x  d prepend' X show x  prepend' X
    proof (cases x rule: trace_uncons_cases)
      case (Cons σ t)
      with A show ?thesis 
        unfolding dprefixes_def
        apply (subst assms[simplified definitive_def, THEN sym])
        apply (clarsimp dest!: subset_trans[OF _ prepend'_prefix_closure])
        using append_prefixes_left 
        by (force simp: dprefixes_def prepend'_def prefix_closure_def subset_iff 
                        prefixes_extensions[THEN sym])
    next
      case Nil
      with A show ?thesis 
        apply (subst assms[simplified definitive_def, THEN sym])
        apply (clarsimp simp: prefixes_empty_least prefixes_def dprefixes_def 
                              prepend'_def prefix_closure_def subset_iff
                              prefixes_extensions[THEN sym])
        by (metis tdrop_singleton_append tdrop_zero trace.assoc)
    qed
  qed
next
  show prepend' X  d prepend' X
  proof (rule subsetI)
    fix x assume A: x  prepend' X show x  d prepend' X
    proof (cases x rule: trace_uncons_cases)
      case (Cons σ t)
      with A show ?thesis
        by (clarsimp simp: dprefixes_def prefixes_def prepend'_def 
                              prefix_closure_def prefixes_extensions[THEN sym])
           (metis (mono_tags, lifting) assms definitive_contains_extensions 
                  mem_Collect_eq prefixes_def prefixes_extensions subset_eq 
                  tdrop_singleton_append tdrop_zero trace.assoc)
    next
      case Nil
      with A show ?thesis
        using assms definitive_contains_extensions 
        by (force simp: dprefixes_def prepend'_def prefix_closure_def)
    qed
  qed
qed

lemma prepend'_definitive : 
  assumes definitive X 
  shows definitive (prepend' X)
  unfolding definitive_def using assms
  by (rule prepend'_dprefixes)

lift_definition prepend :: 'a dset  'a dset is prepend'
  by (rule prepend'_definitive)

lemma prepend_Inter:  (prepend ` S) = prepend ( S)
  apply transfer
  by (auto simp add: prepend'_def)

lemma in_dset_prependD: in_dset (Finite [a]  x) (prepend A)  in_dset x A
  by (transfer, metis One_nat_def Traces.singleton_def mem_Collect_eq prepend'_def 
                      tdrop_singleton_append tdrop_zero)

lemma in_dset_prependI: in_dset x A  in_dset (Finite [a]  x) (prepend A)
  by (transfer, metis One_nat_def Traces.singleton_def mem_Collect_eq prepend'_def 
                      tdrop_singleton_append tdrop_zero)

lemma prepend'_mono: 
  assumes A  B 
  shows   prepend' A  prepend' B
  using assms unfolding prepend'_def
  by blast

lemma property_prepend: property (prepend X) = iprepend (property X)
  apply transfer
  by (clarsimp simp: definitive_def infinites_def prepend'_def 
               split!: trace.split_asm trace.split intro!: set_eqI; 
      blast)

lemma iprepend_Union:  (iprepend ` S) = iprepend ( S)
  by fastforce

lemma definitives_inverse_eqI: definitives (property X) = definitives (property Y)  X = Y
  by (simp add: definitives_inverse)

lemma prepend_Union:  (prepend ` S) = prepend ( S)
  apply (rule definitives_inverse_eqI)
  apply (simp add: property_Union property_prepend)
  by (metis UN_extend_simps(10) iprepend_Union)

lemma non_empty_trace: x  ε  (σ x'. x = Finite [σ]  x')
  apply (cases x rule: trace_uncons_cases; clarsimp)
   apply (metis Traces.singleton_def ε_def append_is_empty(1) not_Cons_self2 trace.inject(1))
  by (metis ε_def append_is_empty(1) list.discI trace.inject(1))

lemma thead_append: x  ε  thead (x  y) = thead x
  by (cases x; cases y; simp add: ε_def nth_append)

lemma thead_prefix: x   y  x  ε  thead x = thead y
  apply (simp add: prefixes_def non_empty_trace)
  using thead_append [where x = Finite [_], simplified ε_def, simplified]
  by (metis append_is_empty(1) thead_append)

lemma compr'_inter_thead: 
    d {x. x  ε  P (thead x)}  d {x.  x  ε  Q (thead x)} 
   = d {x. x  ε  P (thead x)  Q (thead x)}
proof (rule antisym)
{ fix x t
  assume t. x   t  (x. x  ε  P (thead x)  t   x)
  and    t. x   t  (x. x  ε  Q (thead x)  t   x)
  and    x   t
  then have x. x  ε  P (thead x)  Q (thead x)  t   x
    by (cases t = ε; fastforce dest: thead_prefix simp: prefixes_empty prefixes_empty_least)
} then show d {x. x  ε  P (thead x)}  d {x.  x  ε  Q (thead x)}  d {x. x  ε  P (thead x)  Q (thead x)} 
  by (clarsimp simp: set_eq_iff subset_iff dprefixes_def prefix_closure_def prefixes_extensions[THEN sym])
next
{ fix x
  assume t. x   t  (x. x  ε  P (thead x)  Q (thead x)  t   x)
  then have (t. x   t  (x. x  ε  P (thead x)  t   x)) 
             (t. x   t  (x. x  ε  Q (thead x)  t   x))
    by fastforce }
  then show d {x. x  ε  P (thead x)}  d {x.  x  ε  Q (thead x)}  d {x. x  ε  P (thead x)  Q (thead x)} 
  by (clarsimp simp: set_eq_iff subset_iff dprefixes_def prefix_closure_def prefixes_extensions[THEN sym])
qed

lift_definition compr :: ('a trace  bool)  'a dset is λp. d {x. p x }
  by (rule definitive_dprefixes)


lift_definition complement :: 'a dset  'a dset is λp. d (range Infinite - p)
  by (rule definitive_dprefixes)


lemma property_complement[simp]: property (complement X) = UNIV - property X
  by (transfer, force simp: infinites_dprefixes[simplified infinites_def] infinites_def 
                      split: trace.split_asm trace.split)

end