section\<open>The Powerset Axiom in $M[G]$\<close>

theory Powerset_Axiom
  imports
    Separation_Axiom Pairing_Axiom Union_Axiom
begin

simple_rename "perm_pow" src "[ss,p,l,o,fs,\<chi>]" tgt "[fs,ss,sp,p,l,o,\<chi>]"

context G_generic1
begin

lemma sats_fst_snd_in_M:
  assumes
    "A\<in>M" "B\<in>M" "\<phi> \<in> formula" "p\<in>M" "l\<in>M" "o\<in>M" "\<chi>\<in>M" "arity(\<phi>) \<le> 6"
  shows "{\<langle>s,q\<rangle>\<in>A\<times>B . M, [q,p,l,o,s,\<chi>] \<Turnstile> \<phi>} \<in> M" (is "?\<theta> \<in> M")
proof -
  let ?\<phi>' = "ren(\<phi>)`6`7`perm_pow_fn"
  from \<open>A\<in>M\<close> \<open>B\<in>M\<close>
  have "A\<times>B \<in> M"
    using cartprod_closed by simp
  from \<open>arity(\<phi>) \<le> 6\<close> \<open>\<phi>\<in> formula\<close>
  have "?\<phi>' \<in> formula" "arity(?\<phi>')\<le>7"
    unfolding perm_pow_fn_def
    using perm_pow_thm  arity_ren ren_tc Nil_type
    by auto
  with \<open>?\<phi>' \<in> formula\<close>
  have arty: "arity(Exists(Exists(And(pair_fm(0,1,2),?\<phi>'))))\<le>5" (is "arity(?\<psi>)\<le>5")
    using ord_simp_union pred_le
    by (auto simp:arity)
  {
    fix sp
    note \<open>A\<times>B \<in> M\<close> \<open>A\<in>M\<close> \<open>B\<in>M\<close>
    moreover
    assume "sp \<in> A\<times>B"
    moreover from calculation
    have "fst(sp) \<in> A" "snd(sp) \<in> B"
      using fst_type snd_type by simp_all
    ultimately
    have "sp \<in> M" "fst(sp) \<in> M" "snd(sp) \<in> M"
      using transitivity
      by simp_all
    note inM = \<open>A\<in>M\<close> \<open>B\<in>M\<close> \<open>p\<in>M\<close> \<open>l\<in>M\<close> \<open>o\<in>M\<close> \<open>\<chi>\<in>M\<close>
      \<open>sp\<in>M\<close> \<open>fst(sp)\<in>M\<close> \<open>snd(sp)\<in>M\<close>
    with arty \<open>sp \<in> M\<close> \<open>?\<phi>' \<in> formula\<close>
    have "(M, [sp,p,l,o,\<chi>]@[p] \<Turnstile> ?\<psi>) \<longleftrightarrow> M,[sp,p,l,o,\<chi>] \<Turnstile> ?\<psi>" (is "(M,?env0@ _\<Turnstile>_) \<longleftrightarrow> _")
      using arity_sats_iff[of ?\<psi> "[p]" M ?env0] by auto
    also from inM \<open>sp \<in> A\<times>B\<close>
    have "... \<longleftrightarrow> sats(M,?\<phi>',[fst(sp),snd(sp),sp,p,l,o,\<chi>])"
      by auto
    also from inM \<open>\<phi> \<in> formula\<close> \<open>arity(\<phi>) \<le> 6\<close>
    have "... \<longleftrightarrow> M, [snd(sp),p,l,o,fst(sp),\<chi>] \<Turnstile> \<phi>"
      (is "sats(_,_,?env1) \<longleftrightarrow> sats(_,_,?env2)")
      using sats_iff_sats_ren[of \<phi> 6 7 ?env2 M ?env1 perm_pow_fn] perm_pow_thm
      unfolding perm_pow_fn_def by simp
    finally
    have "(M,[sp,p,l,o,\<chi>,p] \<Turnstile> ?\<psi>) \<longleftrightarrow> M, [snd(sp),p,l,o,fst(sp),\<chi>] \<Turnstile> \<phi>"
      by simp
  }
  then
  have "?\<theta> = {sp\<in>A\<times>B . sats(M,?\<psi>,[sp,p,l,o,\<chi>,p])}"
    by auto
  with assms \<open>A\<times>B\<in>M\<close>
  show ?thesis
    using separation_ax separation_iff arty leI \<open>?\<phi>' \<in> formula\<close>
    by simp
qed

declare nat_into_M[rule del, simplified setclass_iff, intro]
lemmas ssimps = domain_closed cartprod_closed cons_closed Pow_rel_closed
declare ssimps [simp del, simplified setclass_iff, simp, intro]

\<comment> \<open>We keep \<^term>\<open>Pow(a) \<inter> M[G]\<close> to be consistent with Kunen.\<close>
lemma Pow_inter_MG:
  assumes "a\<in>M[G]"
  shows "Pow(a) \<inter> M[G] \<in> M[G]"
proof -
  from assms
  obtain \<tau> where "\<tau> \<in> M" "val(G, \<tau>) = a"
    using GenExtD by auto
  let ?Q="Pow\<^bsup>M\<^esup>(domain(\<tau>)\<times>\<bbbP>)"
  let ?\<pi>="?Q\<times>{\<one>}"
  let ?b="val(G,?\<pi>)"
  from \<open>\<tau>\<in>M\<close>
  have "domain(\<tau>)\<times>\<bbbP> \<in> M" "domain(\<tau>) \<in> M"
    by simp_all
  then
  have "?b \<in> M[G]"
    by (auto intro!:GenExtI)
  have "Pow(a) \<inter> M[G] \<subseteq> ?b"
  proof
    fix c
    assume "c \<in> Pow(a) \<inter> M[G]"
    then
    obtain \<chi> where "c\<in>M[G]" "\<chi> \<in> M" "val(G,\<chi>) = c"
      using GenExt_iff by auto
    let ?\<theta>="{\<langle>\<sigma>,p\<rangle> \<in>domain(\<tau>)\<times>\<bbbP> . p \<tturnstile> \<cdot>0 \<in> 1\<cdot> [\<sigma>,\<chi>] }"
    have "arity(forces( \<cdot>0 \<in> 1\<cdot> )) = 6"
      using arity_forces_at by auto
    with \<open>domain(\<tau>) \<in> M\<close> \<open>\<chi> \<in> M\<close>
    have "?\<theta> \<in> M"
      using sats_fst_snd_in_M
      by simp
    with \<open>domain(\<tau>)\<times>\<bbbP> \<in> M\<close>
    have "?\<theta> \<in> ?Q"
      using Pow_rel_char by auto
    have "val(G,?\<theta>) = c"
    proof(intro equalityI subsetI)
      fix x
      assume "x \<in> val(G,?\<theta>)"
      then
      obtain \<sigma> p where 1: "\<langle>\<sigma>,p\<rangle>\<in>?\<theta>" "p\<in>G" "val(G,\<sigma>) =  x"
        using elem_of_val_pair
        by blast
      moreover from \<open>\<langle>\<sigma>,p\<rangle>\<in>?\<theta>\<close> \<open>?\<theta> \<in> M\<close>
      have "\<sigma>\<in>M"
        using name_components_in_M[of _ _ ?\<theta>] by auto
      moreover from 1
      have "p \<tturnstile> \<cdot>0 \<in> 1\<cdot> [\<sigma>,\<chi>]" "p\<in>\<bbbP>"
        by simp_all
      moreover
      note \<open>val(G,\<chi>) = c\<close> \<open>\<chi> \<in> M\<close>
      ultimately
      have "M[G], [x, c] \<Turnstile> \<cdot>0 \<in> 1\<cdot>"
        using generic definition_of_forcing[where \<phi>="\<cdot>0 \<in> 1\<cdot>"] ord_simp_union
        by auto
      moreover from \<open>\<sigma>\<in>M\<close> \<open>\<chi>\<in>M\<close>
      have "x\<in>M[G]"
        using \<open>val(G,\<sigma>) = x\<close> GenExtI by blast
      ultimately
      show "x\<in>c"
        using \<open>c\<in>M[G]\<close> by simp
    next
      fix x
      assume "x \<in> c"
      with \<open>c \<in> Pow(a) \<inter> M[G]\<close>
      have "x \<in> a" "c\<in>M[G]" "x\<in>M[G]"
        using transitivity_MG by auto
      with \<open>val(G, \<tau>) = a\<close>
      obtain \<sigma> where "\<sigma>\<in>domain(\<tau>)" "val(G,\<sigma>) = x"
        using elem_of_val by blast
      moreover
      note \<open>x\<in>c\<close> \<open>val(G,\<chi>) = c\<close> \<open>c\<in>M[G]\<close> \<open>x\<in>M[G]\<close>
      moreover from calculation
      have "val(G,\<sigma>) \<in> val(G,\<chi>)"
        by simp
      moreover from calculation
      have "M[G], [x, c] \<Turnstile> \<cdot>0 \<in> 1\<cdot>"
        by simp
      moreover
      have "\<sigma>\<in>M"
      proof -
        from \<open>\<sigma>\<in>domain(\<tau>)\<close>
        obtain p where "\<langle>\<sigma>,p\<rangle> \<in> \<tau>"
          by auto
        with \<open>\<tau>\<in>M\<close>
        show ?thesis
          using name_components_in_M by blast
      qed
      moreover
      note \<open>\<chi> \<in> M\<close>
      ultimately
      obtain p where "p\<in>G" "p \<tturnstile> \<cdot>0 \<in> 1\<cdot> [\<sigma>,\<chi>]"
        using generic truth_lemma[of "\<cdot>0 \<in> 1\<cdot>" "[\<sigma>,\<chi>]" ] ord_simp_union
        by auto
      moreover from \<open>p\<in>G\<close>
      have "p\<in>\<bbbP>"
        using generic by blast
      ultimately
      have "\<langle>\<sigma>,p\<rangle>\<in>?\<theta>"
        using \<open>\<sigma>\<in>domain(\<tau>)\<close> by simp
      with \<open>val(G,\<sigma>) =  x\<close> \<open>p\<in>G\<close>
      show "x\<in>val(G,?\<theta>)"
        using val_of_elem [of _ _ "?\<theta>" G] by auto
    qed
    with \<open>?\<theta> \<in> ?Q\<close>
    show "c\<in>?b"
      using one_in_G generic val_of_elem [of ?\<theta> \<one> ?\<pi> G]
      by auto
  qed
  then
  have "Pow(a) \<inter> M[G] = {x\<in>?b . x\<subseteq>a \<and> x\<in>M[G]}"
    by auto
  also from \<open>a\<in>M[G]\<close>
  have " ... = {x\<in>?b . ( M[G], [x,a] \<Turnstile> \<cdot>0 \<subseteq> 1\<cdot> )} \<inter> M[G]"
    using Transset_MG by force
  also from \<open>?b\<in>M[G]\<close>
  have " ... = {x\<in>?b . ( M[G], [x,a] \<Turnstile> \<cdot>0 \<subseteq> 1\<cdot> )}"
    by (intro equalityI) (auto dest:ext.transM)
  also from \<open>?b\<in>M[G]\<close> \<open>a\<in>M[G]\<close>
  have " ... \<in> M[G]"
    using Collect_sats_in_MG GenExtI ord_simp_union by (simp add:arity)
  finally
  show ?thesis .
qed

end \<comment> \<open>\<^locale>\<open>G_generic1\<close>\<close>

sublocale G_generic1 \<subseteq> ext: M_trivial "##M[G]"
  using generic Union_MG pairing_in_MG
  by unfold_locales (simp; blast)

context G_generic1 begin

theorem power_in_MG : "power_ax(##(M[G]))"
  unfolding power_ax_def
proof (intro rallI, simp only:setclass_iff rex_setclass_is_bex)
  fix a
  text\<open>After simplification, we have to show that for every
  \<^term>\<open>a\<in>M[G]\<close> there exists some \<^term>\<open>x\<in>M[G]\<close> satisfying
  \<^term>\<open>powerset(##M[G],a,x)\<close>\<close>
  assume "a \<in> M[G]"
  have "{x\<in>Pow(a) . x \<in> M[G]} = Pow(a) \<inter> M[G]"
    by auto
  also from \<open>a\<in>M[G]\<close>
  have " ... \<in> M[G]"
    using Pow_inter_MG by simp
  finally
  have "{x\<in>Pow(a) . x \<in> M[G]} \<in> M[G]" .
  moreover from \<open>a\<in>M[G]\<close> this
  have "powerset(##M[G], a, {x\<in>Pow(a) . x \<in> M[G]})"
    using ext.powerset_abs
    by simp
  ultimately
  show "\<exists>x\<in>M[G] . powerset(##M[G], a, x)"
    by auto
qed

end \<comment> \<open>\<^locale>\<open>G_generic1\<close>\<close>

end


(*  Title:      ZF/Constructible/Rank_Separation.thy
    Author:     Lawrence C Paulson, Cambridge University Computer Laboratory
*)

section {*Separation for Facts About Order Types, Rank Functions and
      Well-Founded Relations*}

theory Rank_Separation imports Rank Rec_Separation begin

text{*This theory proves all instances needed for locales
 @{text "M_ordertype"} and  @{text "M_wfrank"}.  But the material is not
 needed for proving the relative consistency of AC.*}

subsection{*The Locale @{text "M_ordertype"}*}

subsubsection{*Separation for Order-Isomorphisms*}

lemma well_ord_iso_Reflects:
  "REFLECTS[\<lambda>x. x\<in>A \<longrightarrow>
                (\<exists>y[L]. \<exists>p[L]. fun_apply(L,f,x,y) & pair(L,y,x,p) & p \<in> r),
        \<lambda>i x. x\<in>A \<longrightarrow> (\<exists>y \<in> Lset(i). \<exists>p \<in> Lset(i).
                fun_apply(##Lset(i),f,x,y) & pair(##Lset(i),y,x,p) & p \<in> r)]"
by (intro FOL_reflections function_reflections)

lemma well_ord_iso_separation:
     "[| L(A); L(f); L(r) |]
      ==> separation (L, \<lambda>x. x\<in>A \<longrightarrow> (\<exists>y[L]. (\<exists>p[L].
                     fun_apply(L,f,x,y) & pair(L,y,x,p) & p \<in> r)))"
apply (rule gen_separation_multi [OF well_ord_iso_Reflects, of "{A,f,r}"],
       auto)
apply (rule_tac env="[A,f,r]" in DPow_LsetI)
apply (rule sep_rules | simp)+
done

subsubsection{*Separation for @{term "obase"}*}

lemma obase_reflects:
  "REFLECTS[\<lambda>a. \<exists>x[L]. \<exists>g[L]. \<exists>mx[L]. \<exists>par[L].
             ordinal(L,x) & membership(L,x,mx) & pred_set(L,A,a,r,par) &
             order_isomorphism(L,par,r,x,mx,g),
        \<lambda>i a. \<exists>x \<in> Lset(i). \<exists>g \<in> Lset(i). \<exists>mx \<in> Lset(i). \<exists>par \<in> Lset(i).
             ordinal(##Lset(i),x) & membership(##Lset(i),x,mx) & pred_set(##Lset(i),A,a,r,par) &
             order_isomorphism(##Lset(i),par,r,x,mx,g)]"
by (intro FOL_reflections function_reflections fun_plus_reflections)

lemma obase_separation:
     --{*part of the order type formalization*}
     "[| L(A); L(r) |]
      ==> separation(L, \<lambda>a. \<exists>x[L]. \<exists>g[L]. \<exists>mx[L]. \<exists>par[L].
             ordinal(L,x) & membership(L,x,mx) & pred_set(L,A,a,r,par) &
             order_isomorphism(L,par,r,x,mx,g))"
apply (rule gen_separation_multi [OF obase_reflects, of "{A,r}"], auto)
apply (rule_tac env="[A,r]" in DPow_LsetI)
apply (rule ordinal_iff_sats sep_rules | simp)+
done

subsubsection{*Separation for a Theorem about @{term "obase"}*}

lemma obase_equals_reflects:
  "REFLECTS[\<lambda>x. x\<in>A \<longrightarrow> ~(\<exists>y[L]. \<exists>g[L].
                ordinal(L,y) & (\<exists>my[L]. \<exists>pxr[L].
                membership(L,y,my) & pred_set(L,A,x,r,pxr) &
                order_isomorphism(L,pxr,r,y,my,g))),
        \<lambda>i x. x\<in>A \<longrightarrow> ~(\<exists>y \<in> Lset(i). \<exists>g \<in> Lset(i).
                ordinal(##Lset(i),y) & (\<exists>my \<in> Lset(i). \<exists>pxr \<in> Lset(i).
                membership(##Lset(i),y,my) & pred_set(##Lset(i),A,x,r,pxr) &
                order_isomorphism(##Lset(i),pxr,r,y,my,g)))]"
by (intro FOL_reflections function_reflections fun_plus_reflections)

lemma obase_equals_separation:
     "[| L(A); L(r) |]
      ==> separation (L, \<lambda>x. x\<in>A \<longrightarrow> ~(\<exists>y[L]. \<exists>g[L].
                              ordinal(L,y) & (\<exists>my[L]. \<exists>pxr[L].
                              membership(L,y,my) & pred_set(L,A,x,r,pxr) &
                              order_isomorphism(L,pxr,r,y,my,g))))"
apply (rule gen_separation_multi [OF obase_equals_reflects, of "{A,r}"], auto)
apply (rule_tac env="[A,r]" in DPow_LsetI)
apply (rule sep_rules | simp)+
done

subsubsection{*Replacement for @{term "omap"}*}

lemma omap_reflects:
 "REFLECTS[\<lambda>z. \<exists>a[L]. a\<in>B & (\<exists>x[L]. \<exists>g[L]. \<exists>mx[L]. \<exists>par[L].
     ordinal(L,x) & pair(L,a,x,z) & membership(L,x,mx) &
     pred_set(L,A,a,r,par) & order_isomorphism(L,par,r,x,mx,g)),
 \<lambda>i z. \<exists>a \<in> Lset(i). a\<in>B & (\<exists>x \<in> Lset(i). \<exists>g \<in> Lset(i). \<exists>mx \<in> Lset(i).
        \<exists>par \<in> Lset(i).
         ordinal(##Lset(i),x) & pair(##Lset(i),a,x,z) &
         membership(##Lset(i),x,mx) & pred_set(##Lset(i),A,a,r,par) &
         order_isomorphism(##Lset(i),par,r,x,mx,g))]"
by (intro FOL_reflections function_reflections fun_plus_reflections)

lemma omap_replacement:
     "[| L(A); L(r) |]
      ==> strong_replacement(L,
             \<lambda>a z. \<exists>x[L]. \<exists>g[L]. \<exists>mx[L]. \<exists>par[L].
             ordinal(L,x) & pair(L,a,x,z) & membership(L,x,mx) &
             pred_set(L,A,a,r,par) & order_isomorphism(L,par,r,x,mx,g))"
apply (rule strong_replacementI)
apply (rule_tac u="{A,r,B}" in gen_separation_multi [OF omap_reflects], auto)
apply (rule_tac env="[A,B,r]" in DPow_LsetI)
apply (rule sep_rules | simp)+
done

subsection{*Instantiating the locale @{text M_ordertype}*}
text{*Separation (and Strong Replacement) for basic set-theoretic constructions
such as intersection, Cartesian Product and image.*}

lemma M_ordertype_axioms_L: "M_ordertype_axioms(L)"
  apply (rule M_ordertype_axioms.intro)
       apply (assumption | rule well_ord_iso_separation
         obase_separation obase_equals_separation
         omap_replacement)+
  done

theorem M_ordertype_L: "PROP M_ordertype(L)"
  apply (rule M_ordertype.intro)
   apply (rule M_basic_L)
  apply (rule M_ordertype_axioms_L)
  done

subsection{*The Locale @{text "M_wfrank"}*}

subsubsection{*Separation for @{term "wfrank"}*}

lemma wfrank_Reflects:
 "REFLECTS[\<lambda>x. \<forall>rplus[L]. tran_closure(L,r,rplus) \<longrightarrow>
              ~ (\<exists>f[L]. M_is_recfun(L, %x f y. is_range(L,f,y), rplus, x, f)),
      \<lambda>i x. \<forall>rplus \<in> Lset(i). tran_closure(##Lset(i),r,rplus) \<longrightarrow>
         ~ (\<exists>f \<in> Lset(i).
            M_is_recfun(##Lset(i), %x f y. is_range(##Lset(i),f,y),
                        rplus, x, f))]"
by (intro FOL_reflections function_reflections is_recfun_reflection tran_closure_reflection)

lemma wfrank_separation:
     "L(r) ==>
      separation (L, \<lambda>x. \<forall>rplus[L]. tran_closure(L,r,rplus) \<longrightarrow>
         ~ (\<exists>f[L]. M_is_recfun(L, %x f y. is_range(L,f,y), rplus, x, f)))"
apply (rule gen_separation [OF wfrank_Reflects], simp)
apply (rule_tac env="[r]" in DPow_LsetI)
apply (rule sep_rules tran_closure_iff_sats is_recfun_iff_sats | simp)+
done

subsubsection{*Replacement for @{term "wfrank"}*}

lemma wfrank_replacement_Reflects:
 "REFLECTS[\<lambda>z. \<exists>x[L]. x \<in> A &
        (\<forall>rplus[L]. tran_closure(L,r,rplus) \<longrightarrow>
         (\<exists>y[L]. \<exists>f[L]. pair(L,x,y,z)  &
                        M_is_recfun(L, %x f y. is_range(L,f,y), rplus, x, f) &
                        is_range(L,f,y))),
 \<lambda>i z. \<exists>x \<in> Lset(i). x \<in> A &
      (\<forall>rplus \<in> Lset(i). tran_closure(##Lset(i),r,rplus) \<longrightarrow>
       (\<exists>y \<in> Lset(i). \<exists>f \<in> Lset(i). pair(##Lset(i),x,y,z)  &
         M_is_recfun(##Lset(i), %x f y. is_range(##Lset(i),f,y), rplus, x, f) &
         is_range(##Lset(i),f,y)))]"
by (intro FOL_reflections function_reflections fun_plus_reflections
             is_recfun_reflection tran_closure_reflection)

lemma wfrank_strong_replacement:
     "L(r) ==>
      strong_replacement(L, \<lambda>x z.
         \<forall>rplus[L]. tran_closure(L,r,rplus) \<longrightarrow>
         (\<exists>y[L]. \<exists>f[L]. pair(L,x,y,z)  &
                        M_is_recfun(L, %x f y. is_range(L,f,y), rplus, x, f) &
                        is_range(L,f,y)))"
apply (rule strong_replacementI)
apply (rule_tac u="{r,B}"
         in gen_separation_multi [OF wfrank_replacement_Reflects],
       auto)
apply (rule_tac env="[r,B]" in DPow_LsetI)
apply (rule sep_rules tran_closure_iff_sats is_recfun_iff_sats | simp)+
done

subsubsection{*Separation for Proving @{text Ord_wfrank_range}*}

lemma Ord_wfrank_Reflects:
 "REFLECTS[\<lambda>x. \<forall>rplus[L]. tran_closure(L,r,rplus) \<longrightarrow>
          ~ (\<forall>f[L]. \<forall>rangef[L].
             is_range(L,f,rangef) \<longrightarrow>
             M_is_recfun(L, \<lambda>x f y. is_range(L,f,y), rplus, x, f) \<longrightarrow>
             ordinal(L,rangef)),
      \<lambda>i x. \<forall>rplus \<in> Lset(i). tran_closure(##Lset(i),r,rplus) \<longrightarrow>
          ~ (\<forall>f \<in> Lset(i). \<forall>rangef \<in> Lset(i).
             is_range(##Lset(i),f,rangef) \<longrightarrow>
             M_is_recfun(##Lset(i), \<lambda>x f y. is_range(##Lset(i),f,y),
                         rplus, x, f) \<longrightarrow>
             ordinal(##Lset(i),rangef))]"
by (intro FOL_reflections function_reflections is_recfun_reflection
          tran_closure_reflection ordinal_reflection)

lemma  Ord_wfrank_separation:
     "L(r) ==>
      separation (L, \<lambda>x.
         \<forall>rplus[L]. tran_closure(L,r,rplus) \<longrightarrow>
          ~ (\<forall>f[L]. \<forall>rangef[L].
             is_range(L,f,rangef) \<longrightarrow>
             M_is_recfun(L, \<lambda>x f y. is_range(L,f,y), rplus, x, f) \<longrightarrow>
             ordinal(L,rangef)))"
apply (rule gen_separation [OF Ord_wfrank_Reflects], simp)
apply (rule_tac env="[r]" in DPow_LsetI)
apply (rule sep_rules tran_closure_iff_sats is_recfun_iff_sats | simp)+
done

subsubsection{*Instantiating the locale @{text M_wfrank}*}

lemma M_wfrank_axioms_L: "M_wfrank_axioms(L)"
  apply (rule M_wfrank_axioms.intro)
   apply (assumption | rule
     wfrank_separation wfrank_strong_replacement Ord_wfrank_separation)+
  done

theorem M_wfrank_L: "PROP M_wfrank(L)"
  apply (rule M_wfrank.intro)
   apply (rule M_trancl_L)
  apply (rule M_wfrank_axioms_L)
  done

lemmas exists_wfrank = M_wfrank.exists_wfrank [OF M_wfrank_L]
  and M_wellfoundedrank = M_wfrank.M_wellfoundedrank [OF M_wfrank_L]
  and Ord_wfrank_range = M_wfrank.Ord_wfrank_range [OF M_wfrank_L]
  and Ord_range_wellfoundedrank = M_wfrank.Ord_range_wellfoundedrank [OF M_wfrank_L]
  and function_wellfoundedrank = M_wfrank.function_wellfoundedrank [OF M_wfrank_L]
  and domain_wellfoundedrank = M_wfrank.domain_wellfoundedrank [OF M_wfrank_L]
  and wellfoundedrank_type = M_wfrank.wellfoundedrank_type [OF M_wfrank_L]
  and Ord_wellfoundedrank = M_wfrank.Ord_wellfoundedrank [OF M_wfrank_L]
  and wellfoundedrank_eq = M_wfrank.wellfoundedrank_eq [OF M_wfrank_L]
  and wellfoundedrank_lt = M_wfrank.wellfoundedrank_lt [OF M_wfrank_L]
  and wellfounded_imp_subset_rvimage = M_wfrank.wellfounded_imp_subset_rvimage [OF M_wfrank_L]
  and wellfounded_imp_wf = M_wfrank.wellfounded_imp_wf [OF M_wfrank_L]
  and wellfounded_on_imp_wf_on = M_wfrank.wellfounded_on_imp_wf_on [OF M_wfrank_L]
  and wf_abs = M_wfrank.wf_abs [OF M_wfrank_L]
  and wf_on_abs = M_wfrank.wf_on_abs [OF M_wfrank_L]

end


section {*Derivations\_Basics*}
theory
  Derivations_Basics

imports
  PRJ_06_01__ENTRY

begin

declare [[ hypsubst_thin = false ]]
datatype ('label,'conf) derivation_configuration = pair "'label option" "'conf"
declare [[ hypsubst_thin = true ]]

type_synonym ('label,'conf) derivation = "(nat \<Rightarrow> ('label,'conf)derivation_configuration option)"

lemma equal_derivation_conf_coincide: "
  f = g
  \<Longrightarrow> f x = Some (pair e1 a)
  \<Longrightarrow> g x = Some (pair e2 b)
  \<Longrightarrow> a = b"
  apply(force)
  done

definition maximum_of_domain :: "
  ('label,'conf)derivation
  \<Rightarrow> nat
  \<Rightarrow> bool"
  where
    "maximum_of_domain f n \<equiv>
  f n \<noteq> None
  \<and> f (Suc n) = None"

definition get_label :: "
  (('label,'conf) derivation_configuration) option
  \<Rightarrow> 'label option"
  where
    "get_label x \<equiv>
  case x of
  None \<Rightarrow> None
  | (Some (pair e c)) \<Rightarrow> e"

definition get_configuration :: "
  (('label,'conf)derivation_configuration) option
  \<Rightarrow> 'conf option"
  where
    "get_configuration x \<equiv>
  case x of
  None \<Rightarrow> None
  | (Some (pair e c)) \<Rightarrow> Some c"

definition get_labels :: "
  ('label,'conf)derivation
  \<Rightarrow> nat
  \<Rightarrow> 'label option list"
  where
    "get_labels f n \<equiv>
  map (\<lambda>i. get_label (f i)) (nat_seq (Suc 0) n)"

definition get_configurations :: "
  ('label,'conf)derivation
  \<Rightarrow> nat
  \<Rightarrow> 'conf option list"
  where
    "get_configurations f n \<equiv>
  map (\<lambda>i. get_configuration (f i)) (nat_seq 0 n)"

definition derivation_map :: "
  ('label,'confA)derivation
  \<Rightarrow> ('confA \<Rightarrow> 'confB)
  \<Rightarrow> ('label,'confB)derivation"
  where
    "derivation_map f C \<equiv>
  \<lambda>n.
  case f n of
  None \<Rightarrow> None
  | Some (pair e c) \<Rightarrow> Some (pair e (C c))"

definition derivation_append :: "
  ('label,'conf)derivation
  \<Rightarrow> ('label,'conf)derivation
  \<Rightarrow> nat
  \<Rightarrow> ('label,'conf)derivation"
  where
    "derivation_append f g fn \<equiv>
  \<lambda>x.
  if x \<le> fn
  then f x
  else g (x - fn)"

definition derivation_append_fit :: "
  ('label,'conf)derivation
  \<Rightarrow> ('label,'conf)derivation
  \<Rightarrow> nat
  \<Rightarrow> bool"
  where
    "derivation_append_fit f g fn \<equiv>
  case f fn of
  Some (pair e c) \<Rightarrow>
    (case g 0 of
    Some (pair None c') \<Rightarrow> c = c'
    | _ \<Rightarrow> False)
  | _ \<Rightarrow> False"

definition derivation_append_fit_ALT :: "
  ('label,'conf)derivation
  \<Rightarrow> ('label,'conf)derivation
  \<Rightarrow> nat
  \<Rightarrow> bool"
  where
    "derivation_append_fit_ALT f g fn \<equiv>
  get_configuration (f fn) = get_configuration (g 0)"

definition derivation_drop :: "
  ('label,'conf)derivation
  \<Rightarrow> nat
  \<Rightarrow> ('label,'conf)derivation"
  where
    "derivation_drop f m \<equiv>
  \<lambda>n.
  if n = 0
  then (case f m of
        Some (pair e c) \<Rightarrow> Some (pair None c))
  else f (n + m)"

definition derivation_take :: "
  ('label,'conf)derivation
  \<Rightarrow> nat
  \<Rightarrow> ('label,'conf)derivation"
  where
    "derivation_take f m \<equiv>
  \<lambda>n.
  if n \<le> m
  then f n
  else None"

lemma derivation_drop_id: "
  d 0 = Some (pair None c)
  \<Longrightarrow> derivation_drop d 0 = d"
  apply(rule ext)
  apply(rename_tac x)(*strict*)
  apply(simp add: derivation_drop_def)
  done

lemma get_labelsEmpty: "
  get_labels dp 0 = []"
  apply(simp add: get_labels_def)
  apply(rule nat_seqEmpty)
  apply(auto)
  done

lemma get_labelsLength: "
  n>0
  \<Longrightarrow> \<pi> = get_labels d n
  \<Longrightarrow> length \<pi> = n"
  apply(simp add: get_labels_def)
  apply(rule nat_seq_length_Suc0)
   apply(blast)+
  done

lemma get_labels_length: "
  w=get_labels d n
  \<Longrightarrow> length w = n"
  apply(case_tac n)
   apply(clarsimp)
   apply(rule get_labelsEmpty)
  apply(rename_tac nat)(*strict*)
  apply(rule get_labelsLength)
   apply(rename_tac nat)(*strict*)
   apply(force)
  apply(rename_tac nat)(*strict*)
  apply(force)
  done

lemma get_labels_None: "
  d (Suc i)=None
  \<Longrightarrow> i<n
  \<Longrightarrow> get_labels d n ! i = None"
  apply(subgoal_tac "length (nat_seq (Suc 0) n)=n-(Suc 0)+1")
   prefer 2
   apply(rule nat_seq_length)
   apply(force)
  apply(simp add: get_labels_def)
  apply(simp add: get_label_def)
  apply(rule_tac
      t="map (\<lambda>i. case d i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) n) ! i"
      and s="(\<lambda>i. case d i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) ((nat_seq (Suc 0) n) ! i)"
      in ssubst)
   apply(rule nth_map)
   apply(force)
  apply(subgoal_tac "(nat_seq (Suc 0) n ! i) = (Suc 0)+i")
   prefer 2
   apply(rule nat_seq_nth_compute)
    apply(force)
   apply(force)
  apply(clarsimp)
  done

lemma get_labels_Not_None: "
  d (Suc i)=Some (pair e b)
  \<Longrightarrow> i<n
  \<Longrightarrow> get_labels d n ! i = e"
  apply(subgoal_tac "length (nat_seq (Suc 0) n)=n-(Suc 0)+1")
   prefer 2
   apply(rule nat_seq_length)
   apply(force)
  apply(simp add: get_labels_def)
  apply(simp add: get_label_def)
  apply(rule_tac
      t="map (\<lambda>i. case d i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) n) ! i"
      and s="(\<lambda>i. case d i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) ((nat_seq (Suc 0) n) ! i)"
      in ssubst)
   apply(rule nth_map)
   apply(force)
  apply(subgoal_tac "(nat_seq (Suc 0) n ! i) = (Suc 0)+i")
   prefer 2
   apply(rule nat_seq_nth_compute)
    apply(force)
   apply(force)
  apply(clarsimp)
  done

lemma derivation_skip_get_labels: "
  d'=derivation_drop d m
  \<Longrightarrow> m\<le>n
  \<Longrightarrow> get_labels d n = (get_labels d m)@(get_labels d' (n-m))"
  apply(simp add: derivation_drop_def)
  apply(simp add: get_labels_def)
  apply(simp add: get_label_def)
  apply(clarsimp)
  apply(subgoal_tac "length (nat_seq (Suc 0) n)=n+1-(Suc 0)")
   prefer 2
   apply(case_tac "n")
    apply(clarsimp)
    apply(rule nat_seqEmpty)
    apply(force)
   apply(rename_tac nat)(*strict*)
   apply(rule_tac
      t="n + 1 - Suc 0"
      and s="n - Suc 0 + 1"
      in ssubst)
    apply(rename_tac nat)(*strict*)
    apply(force)
   apply(rename_tac nat)(*strict*)
   apply(rule nat_seq_length)
   apply(force)
  apply(subgoal_tac "length (nat_seq (Suc 0) m)=m+1-(Suc 0)")
   prefer 2
   apply(case_tac "m")
    apply(clarsimp)
    apply(rule nat_seqEmpty)
    apply(force)
   apply(rename_tac nat)(*strict*)
   apply(rule_tac
      t="m + 1 - Suc 0"
      and s="m - Suc 0 + 1"
      in ssubst)
    apply(rename_tac nat)(*strict*)
    apply(force)
   apply(rename_tac nat)(*strict*)
   apply(rule nat_seq_length)
   apply(force)
  apply(subgoal_tac "length (nat_seq (Suc 0) (n-m))=(n-m)+1-(Suc 0)")
   prefer 2
   apply(case_tac "n-m")
    apply(clarsimp)
    apply(rule nat_seqEmpty)
    apply(force)
   apply(rename_tac nat)(*strict*)
   apply(rule_tac
      t="(n-m) + 1 - Suc 0"
      and s="(n-m) - Suc 0 + 1"
      in ssubst)
    apply(rename_tac nat)(*strict*)
    apply(force)
   apply(rename_tac nat)(*strict*)
   apply(rule nat_seq_length)
   apply(force)
  apply(clarsimp)
  apply(rule listEqI)
   apply(clarsimp)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(rule_tac
      t="nat_seq (Suc 0) n ! i"
      and s="(Suc 0)+i"
      in ssubst)
   apply(rename_tac i)(*strict*)
   apply(rule nat_seq_nth_compute)
    apply(rename_tac i)(*strict*)
    apply(clarsimp)
   apply(rename_tac i)(*strict*)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(case_tac "i<m")
   apply(rename_tac i)(*strict*)
   apply(rule_tac
      t="(map (\<lambda>i. case d i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) m) @ map (\<lambda>i. case if i = 0 then case d m of Some (pair e c) \<Rightarrow> Some (pair None c) else d (i + m) of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) (n - m))) ! i"
      and s="map (\<lambda>i. case d i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) m)!i"
      in ssubst)
    apply(rename_tac i)(*strict*)
    apply(rule nth_append_1)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(clarsimp)
   apply(rule_tac
      t="nat_seq (Suc 0) m ! i"
      and s="(Suc 0)+i"
      in ssubst)
    apply(rename_tac i)(*strict*)
    apply(rule nat_seq_nth_compute)
     apply(rename_tac i)(*strict*)
     apply(clarsimp)
    apply(rename_tac i)(*strict*)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(clarsimp)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(rule_tac
      t="(map (\<lambda>i. case_option None (case_derivation_configuration (\<lambda>e c. e)) (d i)) (nat_seq (Suc 0) m) @ map (\<lambda>i. case_option None (case_derivation_configuration (\<lambda>e c. e)) (if i = 0 then case_option undefined (case_derivation_configuration (\<lambda>e c. Some (pair None c))) (d m) else d (i + m))) (nat_seq (Suc 0) (n - m))) ! i"
      and s="(map (\<lambda>i. case_option None (case_derivation_configuration (\<lambda>e c. e)) (if i = 0 then case_option undefined (case_derivation_configuration (\<lambda>e c. Some (pair None c))) (d m) else d (i + m))) (nat_seq (Suc 0) (n - m))) ! (i-(length(map (\<lambda>i. case_option None (case_derivation_configuration (\<lambda>e c. e)) (d i)) (nat_seq (Suc 0) m))))"
      in ssubst)
   apply(rename_tac i)(*strict*)
   apply(rule nth_append_2)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(case_tac "n-m")
   apply(rename_tac i)(*strict*)
   apply(clarsimp)
  apply(rename_tac i nat)(*strict*)
  apply(rule_tac
      t="nat_seq (Suc 0) (n-m) ! (i-m)"
      and s="(Suc 0)+(i-m)"
      in ssubst)
   apply(rename_tac i nat)(*strict*)
   apply(rule nat_seq_nth_compute)
    apply(rename_tac i nat)(*strict*)
    apply(clarsimp)
   apply(rename_tac i nat)(*strict*)
   apply(force)
  apply(rename_tac i nat)(*strict*)
  apply(clarsimp)
  done

lemma derivation_concat_get_labels: "
  n\<le>n1
  \<Longrightarrow> d=derivation_append d1 d2 n
  \<Longrightarrow> get_labels d (n+n2) = (get_labels d1 n)@(get_labels d2 n2)"
  apply(simp add: derivation_append_def)
  apply(simp add: get_labels_def)
  apply(simp add: get_label_def)
  apply(clarsimp)
  apply(subgoal_tac "length (nat_seq (Suc 0) (n+n2))=(n+n2)+1-(Suc 0)")
   prefer 2
   apply(case_tac "n+n2")
    apply(clarsimp)
    apply(rule nat_seqEmpty)
    apply(force)
   apply(rename_tac nat)(*strict*)
   apply(rule_tac
      t="n + n2 + 1 - Suc 0"
      and s="n + n2 - Suc 0 + 1"
      in ssubst)
    apply(rename_tac nat)(*strict*)
    apply(force)
   apply(rename_tac nat)(*strict*)
   apply(rule nat_seq_length)
   apply(force)
  apply(clarsimp)
  apply(subgoal_tac "length (nat_seq (Suc 0) n)=n+1-(Suc 0)")
   prefer 2
   apply(case_tac "n")
    apply(clarsimp)
    apply(rule nat_seqEmpty)
    apply(force)
   apply(rename_tac nat)(*strict*)
   apply(rule_tac
      t="n + 1 - Suc 0"
      and s="n - Suc 0 + 1"
      in ssubst)
    apply(rename_tac nat)(*strict*)
    apply(force)
   apply(rename_tac nat)(*strict*)
   apply(rule nat_seq_length)
   apply(force)
  apply(clarsimp)
  apply(subgoal_tac "length (nat_seq (Suc 0) n2)=n2+1-(Suc 0)")
   prefer 2
   apply(case_tac "n2")
    apply(clarsimp)
    apply(rule nat_seqEmpty)
    apply(force)
   apply(rename_tac nat)(*strict*)
   apply(rule_tac
      t="n2 + 1 - Suc 0"
      and s="n2 - Suc 0 + 1"
      in ssubst)
    apply(rename_tac nat)(*strict*)
    apply(force)
   apply(rename_tac nat)(*strict*)
   apply(rule nat_seq_length)
   apply(force)
  apply(clarsimp)
  apply(rule listEqI)
   apply(clarsimp)
  apply(rename_tac i)(*strict*)
  apply(rule impI)
  apply(subgoal_tac "i<n+n2")
   apply(rename_tac i)(*strict*)
   prefer 2
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(thin_tac "i < length (map (\<lambda>i. case if i \<le> n then d1 i else d2 (i - n) of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) (n + n2)))")
  apply(rename_tac i)(*strict*)
  apply(rule_tac
      t="map (\<lambda>i. case if i \<le> n then d1 i else d2 (i - n) of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) (n + n2)) ! i"
      and s="(\<lambda>i. case if i \<le> n then d1 i else d2 (i - n) of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) (n + n2) !i)"
      in ssubst)
   apply(rename_tac i)(*strict*)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(rule_tac
      t="nat_seq (Suc 0) (n + n2) ! i"
      and s="(Suc 0)+i"
      in ssubst)
   apply(rename_tac i)(*strict*)
   apply(rule nat_seq_nth_compute)
    apply(rename_tac i)(*strict*)
    apply(clarsimp)
   apply(rename_tac i)(*strict*)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(rule conjI)
   apply(rename_tac i)(*strict*)
   apply(clarsimp)
   apply(rule_tac
      t="(map (\<lambda>i. case_option None (case_derivation_configuration (\<lambda>e c. e)) (d1 i)) (nat_seq (Suc 0) n) @ map (\<lambda>i. case_option None (case_derivation_configuration (\<lambda>e c. e)) (d2 i)) (nat_seq (Suc 0) n2)) ! i"
      and s="(map (\<lambda>i. case_option None (case_derivation_configuration (\<lambda>e c. e)) (d1 i)) (nat_seq (Suc 0) n)) ! i"
      in ssubst)
    apply(rename_tac i)(*strict*)
    apply(rule nth_append_1)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(rule_tac
      t="map (\<lambda>i. case_option None (case_derivation_configuration (\<lambda>e c. e)) (d1 i)) (nat_seq (Suc 0) n) ! i"
      and s="(\<lambda>i. case_option None (case_derivation_configuration (\<lambda>e c. e)) (d1 i)) (nat_seq (Suc 0) n ! i)"
      in ssubst)
    apply(rename_tac i)(*strict*)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(rule_tac
      t="nat_seq (Suc 0) n ! i"
      and s="(Suc 0)+i"
      in ssubst)
    apply(rename_tac i)(*strict*)
    apply(rule nat_seq_nth_compute)
     apply(rename_tac i)(*strict*)
     apply(clarsimp)
    apply(rename_tac i)(*strict*)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(clarsimp)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(rule_tac
      t="(map (\<lambda>i. case d1 i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) n) @ map (\<lambda>i. case d2 i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) n2)) ! i"
      and s="map (\<lambda>i. case d2 i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) n2) ! (i-length (map (\<lambda>i. case d1 i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) n)))"
      in ssubst)
   apply(rename_tac i)(*strict*)
   apply(rule nth_append_2)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(rule_tac
      t="nat_seq (Suc 0) n2 ! (i-n)"
      and s="(Suc 0)+(i-n)"
      in ssubst)
   apply(rename_tac i)(*strict*)
   apply(rule nat_seq_nth_compute)
    apply(rename_tac i)(*strict*)
    apply(clarsimp)
   apply(rename_tac i)(*strict*)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(rule_tac
      t="Suc i - n"
      and s="Suc (i-n)"
      in ssubst)
   apply(rename_tac i)(*strict*)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(force)
  done

lemma derivation_append_preserves_get_labels: "
  get_labels (derivation_append d1 d2 n1) (n1+n2) = get_labels d1 n1 @ (get_labels d2 n2)"
  apply(simp add: get_labels_def derivation_append_def)
  apply(subgoal_tac "length (nat_seq (Suc 0) (n1 + n2)) = (n1+n2) + 1 - (Suc 0)")
   prefer 2
   apply(rule nat_seq_length_prime)
  apply(subgoal_tac "length (nat_seq (Suc 0) n1) = n1 + 1 - (Suc 0)")
   prefer 2
   apply(rule nat_seq_length_prime)
  apply(subgoal_tac "length (nat_seq (Suc 0) n2) = n2 + 1 - (Suc 0)")
   prefer 2
   apply(rule nat_seq_length_prime)
  apply(rule listEqI)
   apply(clarsimp)
  apply(rename_tac i)(*strict*)
  apply(rule impI)
  apply(clarsimp)
  apply(subgoal_tac "nat_seq (Suc 0) (n1 + n2) ! i = (Suc 0) + i")
   apply(rename_tac i)(*strict*)
   prefer 2
   apply(rule nat_seq_nth_compute)
    apply(rename_tac i)(*strict*)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(auto)
   apply(rename_tac i)(*strict*)
   apply(subgoal_tac "nat_seq (Suc 0) n1 ! i = (Suc 0) + i")
    apply(rename_tac i)(*strict*)
    prefer 2
    apply(rule nat_seq_nth_compute)
     apply(rename_tac i)(*strict*)
     apply(force)
    apply(rename_tac i)(*strict*)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(simp add: get_label_def)
   apply(rule_tac
      t="(map (\<lambda>i. case d1 i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) n1) @ map (\<lambda>i. case d2 i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) n2)) ! i"
      and s="(map (\<lambda>i. case d1 i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) n1))!i"
      in ssubst)
    apply(rename_tac i)(*strict*)
    apply(rule nth_append_1)
    apply(rule_tac
      t="length (map (\<lambda>i. case d1 i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) n1))"
      and s="length (nat_seq (Suc 0) n1)"
      in ssubst)
     apply(rename_tac i)(*strict*)
     apply(rule length_map)
    apply(rename_tac i)(*strict*)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(rule_tac
      t="map (\<lambda>i. case d1 i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) n1) ! i"
      and s="(\<lambda>i. case d1 i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) ((nat_seq (Suc 0) n1) ! i)"
      in ssubst)
    apply(rename_tac i)(*strict*)
    apply(rule nth_map)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(clarsimp)
  apply(rename_tac i)(*strict*)
  apply(subgoal_tac "nat_seq (Suc 0) n2 ! (i - n1) = (Suc 0) + (i - n1)")
   apply(rename_tac i)(*strict*)
   prefer 2
   apply(rule nat_seq_nth_compute)
    apply(rename_tac i)(*strict*)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(simp add: get_label_def)
  apply(rule_tac
      t="(map (\<lambda>i. case d1 i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) n1) @ map (\<lambda>i. case d2 i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) n2)) ! i"
      and s="(map (\<lambda>i. case d2 i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) n2))!(i - length(map (\<lambda>i. case d1 i of None \<Rightarrow> None | Some (pair e c) \<Rightarrow> e) (nat_seq (Suc 0) n1)))"
      in ssubst)
   apply(rename_tac i)(*strict*)
   apply(rule nth_append_2)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(rule_tac
      t="Suc i - n1"
      and s="Suc (i-n1)"
      in ssubst)
   apply(rename_tac i)(*strict*)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  done

lemma derivation_take_preserves_get_labels: "
  w=get_labels d (n+m)
  \<Longrightarrow> take m w= get_labels (derivation_take d m) m"
  apply(simp add: derivation_take_def)
  apply(simp add: get_labels_def)
  apply(clarsimp)
  apply(rule listEqI)
   apply(rule_tac
      t="length (take m (map (\<lambda>i. get_label (d i)) (nat_seq (Suc 0) (n + m))))"
      and s="m"
      in ssubst)
    apply(rule take_all_length)
    apply(rule_tac
      t="length (map (\<lambda>i. get_label (d i)) (nat_seq (Suc 0) (n + m)))"
      and s="length (nat_seq (Suc 0) (n + m))"
      in ssubst)
     apply(rule length_map)
    apply(rule_tac
      t="length (nat_seq (Suc 0) (n + m))"
      and s="(n+m) + 1 - (Suc 0)"
      in ssubst)
     apply(rule nat_seq_length_prime)
    apply(force)
   apply(rule_tac
      t="length (map (\<lambda>i. get_label (if i \<le> m then d i else None)) (nat_seq (Suc 0) m))"
      and s="length (nat_seq (Suc 0) m)"
      in ssubst)
    apply(rule length_map)
   apply(rule_tac
      t="length (nat_seq (Suc 0) m)"
      and s="m + 1 - (Suc 0)"
      in ssubst)
    apply(rule nat_seq_length_prime)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(thin_tac "i < length (nat_seq (Suc 0) (n + m))")
  apply(rule_tac
      t="map (\<lambda>i. get_label (if i \<le> m then d i else None)) (nat_seq (Suc 0) m) ! i"
      and s="(\<lambda>i. get_label (if i \<le> m then d i else None)) ((nat_seq (Suc 0) m) ! i)"
      in ssubst)
   apply(rename_tac i)(*strict*)
   apply(rule nth_map)
   apply(rule_tac
      t="length (nat_seq (Suc 0) m)"
      and s="m + 1 - (Suc 0)"
      in ssubst)
    apply(rename_tac i)(*strict*)
    apply(rule nat_seq_length_prime)
   apply(rename_tac i)(*strict*)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(rule_tac
      t="nat_seq (Suc 0) (n + m) ! i"
      and s="(Suc 0)+i"
      in ssubst)
   apply(rename_tac i)(*strict*)
   apply(rule nat_seq_nth_compute)
    apply(rename_tac i)(*strict*)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(rule_tac
      t="nat_seq (Suc 0) m ! i"
      and s="(Suc 0)+i"
      in ssubst)
   apply(rename_tac i)(*strict*)
   apply(rule nat_seq_nth_compute)
    apply(rename_tac i)(*strict*)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(force)
  done

lemma derivation_map_id: "
  derivation_map dh (\<lambda>x. x) = dh"
  apply(simp add: derivation_map_def)
  apply(rule ext)
  apply(rename_tac n)(*strict*)
  apply(case_tac "dh n")
   apply(rename_tac n)(*strict*)
   apply(clarsimp)
  apply(rename_tac n a)(*strict*)
  apply(clarsimp)
  apply(case_tac a)
  apply(rename_tac n a option b)(*strict*)
  apply(clarsimp)
  done

lemma derivation_map_preserves_maximum_of_domain: "
  maximum_of_domain d n
  \<Longrightarrow> maximum_of_domain (derivation_map d C) n"
  apply(simp add: derivation_map_def maximum_of_domain_def)
  apply(auto)
  apply(rename_tac y)(*strict*)
  apply(case_tac y)
  apply(rename_tac y option b)(*strict*)
  apply(auto)
  done

lemma derivation_take_conf_0: "
  d 0 = c
  \<Longrightarrow> (derivation_take d i) 0 = c"
  apply(simp add: derivation_take_def)
  done

lemma derivation_take_conf_end: "
  d i = c
  \<Longrightarrow> (derivation_take d i) i = c"
  apply(simp add: derivation_take_def)
  done

lemma maximum_of_domain_derivation_take: "
  d i\<noteq>None
  \<Longrightarrow> maximum_of_domain (derivation_take d i) i"
  apply(simp add: maximum_of_domain_def derivation_take_def)
  done

lemma derivation_drop_preserves_generates_maximum_of_domain: "
  maximum_of_domain d (Suc x)
  \<Longrightarrow> maximum_of_domain (derivation_drop d (Suc 0)) x"
  apply(simp add: derivation_drop_def)
  apply(simp add: maximum_of_domain_def)
  apply(auto)
  apply(rename_tac y)(*strict*)
  apply(case_tac y)
  apply(rename_tac y option b)(*strict*)
  apply(auto)
  done

lemma concat_has_max_dom: "
  maximum_of_domain d1 m1
  \<Longrightarrow> maximum_of_domain d2 m2
  \<Longrightarrow> maximum_of_domain (derivation_append d1 d2 m1) (m1 + m2)"
  apply(simp add: derivation_append_def)
  apply(simp add: maximum_of_domain_def)
  done

lemma get_configurations_length: "
  length (get_configurations d n) = Suc n"
  apply(simp add: get_configurations_def)
  apply(rule_tac
      t="Suc n"
      and s="n - 0 + 1"
      in ssubst)
   apply(force)
  apply(rule nat_seq_length)
  apply(blast)+
  done

lemma get_configurations_elem: "
  n>0
  \<Longrightarrow> get_configurations d n = z # zs
  \<Longrightarrow> length zs = n
  \<Longrightarrow> \<forall>i<length(z#zs). \<forall>c e. d i=Some (pair e c) \<longrightarrow> (z#zs)!i=Some c"
  apply(clarsimp)
  apply(rename_tac i c e)(*strict*)
  apply(rule_tac
      t="z#zs"
      and s="get_configurations d (length zs)"
      in ssubst)
   apply(rename_tac i c e)(*strict*)
   apply(force)
  apply(rename_tac i c e)(*strict*)
  apply(simp (no_asm) add: get_configurations_def)
  apply(rule_tac
      t="map (\<lambda>i. get_configuration (d i)) (nat_seq 0 (length zs)) ! i"
      and s="(\<lambda>i. get_configuration (d i)) ((nat_seq 0 (((length zs)))) ! i)"
      in ssubst)
   apply(rename_tac i c e)(*strict*)
   apply(rule nth_map)
   apply(rule_tac
      t="length (nat_seq 0 (((length zs))))"
      and s="(((length zs))) - 0 + 1"
      in ssubst)
    apply(rename_tac i c e)(*strict*)
    apply(rule nat_seq_length)
    apply(force)
   apply(rename_tac i c e)(*strict*)
   apply(force)
  apply(rename_tac i c e)(*strict*)
  apply(rule_tac
      t="(nat_seq 0 (((length zs))) ! i)"
      and s="0+i"
      in ssubst)
   apply(rename_tac i c e)(*strict*)
   apply(rule nat_seq_nth_compute)
    apply(rename_tac i c e)(*strict*)
    apply(force)
   apply(rename_tac i c e)(*strict*)
   apply(force)
  apply(rename_tac i c e)(*strict*)
  apply(simp add: get_configuration_def)
  done

lemma get_configurations_elem2: "
  n>0
  \<Longrightarrow> get_configurations d n = w
  \<Longrightarrow> length zs = n
  \<Longrightarrow> \<forall>i<length w. \<forall>c e. d i=Some (pair e c) \<longrightarrow> w!i=Some c"
  apply(subgoal_tac "length (get_configurations d (length zs)) = Suc (length zs)")
   prefer 2
   apply(rule get_configurations_length)
  apply(clarsimp)
  apply(rename_tac i c e)(*strict*)
  apply(simp (no_asm) add: get_configurations_def)
  apply(rule_tac
      t="map (\<lambda>i. get_configuration (d i)) (nat_seq 0 (length zs)) ! i"
      and s="(\<lambda>i. get_configuration (d i)) ((nat_seq 0 (((length zs)))) ! i)"
      in ssubst)
   apply(rename_tac i c e)(*strict*)
   apply(rule nth_map)
   apply(rule_tac
      t="length (nat_seq 0 (((length zs))))"
      and s="(((length zs))) - 0 + 1"
      in ssubst)
    apply(rename_tac i c e)(*strict*)
    apply(rule nat_seq_length)
    apply(force)
   apply(rename_tac i c e)(*strict*)
   apply(force)
  apply(rename_tac i c e)(*strict*)
  apply(rule_tac
      t="(nat_seq 0 (((length zs))) ! i)"
      and s="0+i"
      in ssubst)
   apply(rename_tac i c e)(*strict*)
   apply(rule nat_seq_nth_compute)
    apply(rename_tac i c e)(*strict*)
    apply(force)
   apply(rename_tac i c e)(*strict*)
   apply(force)
  apply(rename_tac i c e)(*strict*)
  apply(simp add: get_configuration_def)
  done

lemma derivation_take_id: "
  \<forall>m>n. d m = None
  \<Longrightarrow> derivation_take d n = d"
  apply(rule ext)
  apply(rename_tac x)(*strict*)
  apply(simp add: derivation_take_def)
  done

lemma Context_Crop_comm: "
  derivation_map (derivation_take d i) C = derivation_take (derivation_map d C) i"
  apply(rule ext)
  apply(rename_tac x)(*strict*)
  apply(simp add: derivation_map_def derivation_take_def)
  done

lemma Context_Skip_comm: "
  d i \<noteq> None
  \<Longrightarrow> derivation_map (derivation_drop d i) C = derivation_drop (derivation_map d C) i"
  apply(simp add: derivation_map_def derivation_drop_def)
  apply(rule ext)
  apply(rename_tac n)(*strict*)
  apply(clarsimp)
  apply(rename_tac y)(*strict*)
  apply(case_tac y)
  apply(rename_tac y option b)(*strict*)
  apply(clarsimp)
  done

lemma derivation_extend_with_maximum_of_domain: "
  d i \<noteq> None
  \<Longrightarrow> P d
  \<Longrightarrow> (P d \<Longrightarrow> P (derivation_take d i))
  \<Longrightarrow> \<exists>d'. P d' \<and> maximum_of_domain d' i"
  apply(rule_tac
      x="derivation_take d i"
      in exI)
  apply(rule conjI)
   apply(erule meta_impE)
    apply(force)
   apply(force)
  apply(rule maximum_of_domain_derivation_take)
  apply(force)
  done

lemma derivation_map_map_empty: "
  derivation_map Map.empty C = Map.empty"
  apply(simp add: derivation_map_def)
  done

lemma derivation_take_map_empty: "
  derivation_take Map.empty n = Map.empty"
  apply(simp add: derivation_take_def)
  done

lemma derivation_append_0: "
  d1 0 = d2 0
  \<Longrightarrow> derivation_append d1 d2 0 = d2"
  apply(rule ext)
  apply(rename_tac x)(*strict*)
  apply(simp add: derivation_append_def)
  done

lemma derivation_append_with_0: "
  d1 0 = d2 0
  \<Longrightarrow> derivation_append d1 d2 0 = d2"
  apply(rule ext)
  apply(rename_tac x)(*strict*)
  apply(simp add: derivation_append_def)
  done

lemma derivation_take_derivation_append_ignore: "
  n\<le>m
  \<Longrightarrow> derivation_take (derivation_append d1 d2 m) n = derivation_take d1 n"
  apply(rule ext)
  apply(rename_tac x)(*strict*)
  apply(simp add: derivation_take_def derivation_append_def)
  done

lemma derivation_take_twice: "
  n\<le>m
  \<Longrightarrow> derivation_take (derivation_take d m) n = derivation_take d n"
  apply(rule ext)
  apply(rename_tac x)(*strict*)
  apply(simp add: derivation_take_def)
  done

lemma derivation_take_twice_prime: "
  m\<le>n
  \<Longrightarrow> derivation_take (derivation_take d m) n = derivation_take d m"
  apply(rule ext)
  apply(rename_tac x)(*strict*)
  apply(simp add: derivation_take_def)
  done

definition der2 :: "
  'conf
  \<Rightarrow> 'label
  \<Rightarrow> 'conf
  \<Rightarrow> ('label,'conf)derivation"
  where
    "der2 c1 e c2 \<equiv>
  \<lambda>n.
  if n = 0
  then Some (pair None c1)
  else (if n = Suc 0
        then Some (pair (Some e) c2)
        else None)"

definition der1 :: "
  'conf
  \<Rightarrow> ('label,'conf)derivation"
  where
    "der1 c \<equiv>
  \<lambda>n.
  if n = 0
  then Some (pair None c)
  else None"

definition der3 :: "
  'conf
  \<Rightarrow> 'label
  \<Rightarrow> 'conf
  \<Rightarrow> 'label
  \<Rightarrow> 'conf
  \<Rightarrow> ('label,'conf)derivation"
  where
    "der3 c1 e1 c2 e2 c3 \<equiv>
  \<lambda>n.
  if n = 0
  then Some (pair None c1)
  else if n = 1
       then Some (pair (Some e1) c2)
       else if n = 2
            then Some (pair (Some e2) c3)
            else None"

lemma der3_maximum_of_domain: "
  maximum_of_domain (der3 c1 e1 c2 e2 c3) (Suc (Suc 0))"
  apply(simp add: maximum_of_domain_def der3_def)
  done

lemma der2_maximum_of_domain: "
  maximum_of_domain (der2 c1 e c2) (Suc 0)"
  apply(simp add: maximum_of_domain_def der2_def)
  done

lemma der1_maximum_of_domain: "
  maximum_of_domain (der1 c) 0"
  apply(simp add: maximum_of_domain_def der1_def)
  done

lemma derivationEQ_by_derivation_take_and_derivation_drop: "
  derivation_take d n = derivation_take d' n
  \<Longrightarrow> derivation_drop d n = derivation_drop d' n
  \<Longrightarrow> d = d'"
  apply(rule ext)
  apply(rename_tac x)(*strict*)
  apply(case_tac "x\<le>n")
   apply(rename_tac x)(*strict*)
   apply(thin_tac "derivation_drop d n = derivation_drop d' n")
   apply(rule_tac
      t="d x"
      and s="derivation_take d n x"
      in ssubst)
    apply(rename_tac x)(*strict*)
    apply(thin_tac "derivation_take d n = derivation_take d' n")
    apply(simp add: derivation_take_def)
   apply(rename_tac x)(*strict*)
   apply(rule_tac
      t="d' x"
      and s="derivation_take d' n x"
      in ssubst)
    apply(rename_tac x)(*strict*)
    apply(thin_tac "derivation_take d n = derivation_take d' n")
    apply(simp add: derivation_take_def)
   apply(rename_tac x)(*strict*)
   apply(force)
  apply(rename_tac x)(*strict*)
  apply(thin_tac "derivation_take d n = derivation_take d' n")
  apply(rule_tac
      t="d x"
      and s="derivation_drop d n (x-n)"
      in ssubst)
   apply(rename_tac x)(*strict*)
   apply(thin_tac "derivation_drop d n = derivation_drop d' n")
   apply(simp add: derivation_drop_def)
  apply(rename_tac x)(*strict*)
  apply(rule_tac
      t="d' x"
      and s="derivation_drop d' n (x-n)"
      in ssubst)
   apply(rename_tac x)(*strict*)
   apply(thin_tac "derivation_drop d n = derivation_drop d' n")
   apply(simp add: derivation_drop_def)
  apply(rename_tac x)(*strict*)
  apply(force)
  done

lemma get_labels_derivation_map: "
  get_labels (derivation_map d f) n = (get_labels d n)"
  apply(simp add: get_labels_def get_label_def derivation_map_def)
  apply(clarsimp)
  apply(rename_tac x)(*strict*)
  apply(case_tac "d x")
   apply(rename_tac x)(*strict*)
   apply(clarsimp)
  apply(rename_tac x a)(*strict*)
  apply(clarsimp)
  apply(case_tac a)
  apply(rename_tac x a option b)(*strict*)
  apply(clarsimp)
  done

lemma get_labels_derivation_drop: "
  get_labels(derivation_drop d n)m = drop n (get_labels d (n+m))"
  apply(simp add: get_labels_def)
  apply(subgoal_tac "length (nat_seq (Suc 0) m) = n + 1 - Suc 0" for n)
   prefer 2
   apply(rule nat_seq_length_prime)
  apply(subgoal_tac "length (nat_seq (Suc 0) (n+m)) = SSn + 1 - Suc 0" for SSn)
   prefer 2
   apply(rule nat_seq_length_prime)
  apply(clarsimp)
  apply(rule listEqI)
   apply(clarsimp)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(subgoal_tac "nat_seq (Suc 0) m ! i = SSn+SSi" for SSn SSi)
   apply(rename_tac i)(*strict*)
   prefer 2
   apply(rule nat_seq_nth_compute)
    apply(rename_tac i)(*strict*)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(subgoal_tac "nat_seq (Suc 0) (n+m) ! (n+i) = SSn+SSi" for SSn SSi)
   apply(rename_tac i)(*strict*)
   prefer 2
   apply(rule nat_seq_nth_compute)
    apply(rename_tac i)(*strict*)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(simp add: get_label_def derivation_drop_def)
  apply(rule_tac
      t = "n+i"
      and s = "i+n"
      in ssubst)
   apply(rename_tac i)(*strict*)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(force)
  done

lemma realiziable_implies_in_get_labels: "
  d i = Some (pair x c)
  \<Longrightarrow> Suc 0\<le>i
  \<Longrightarrow> i\<le>n
  \<Longrightarrow> x \<in> set (get_labels d n)"
  apply(simp add: get_labels_def)
  apply(rule inMap)
  apply(rule_tac
      x="i"
      in bexI)
   apply(simp add: get_label_def)
  apply(rule nat_seq_interval)
   apply(force)
  apply(force)
  done

lemma get_labels_der2_decompose: "
  get_labels
  (derivation_append (der2 c1 e c2) d (Suc 0))
  (Suc n) =
  Some e # get_labels d n"
  apply(rule listEqI)
   apply(simp add: get_labels_def)
   apply (metis list.size(3) nat_seqEmpty nat_seq_length_Suc0 neq0_conv zero_less_Suc)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(case_tac i)
   apply(rename_tac i)(*strict*)
   apply(clarsimp)
   apply(simp add: get_labels_def)
   apply(simp add: get_label_def)
   apply(simp add: derivation_append_def der2_def)
   apply(rule_tac
      t="nat_seq (Suc 0) (Suc n) ! 0"
      and s="Suc 0 + 0"
      in ssubst)
    apply (metis Nat.add_0_right Suc_le_lessD less_eq_nat.simps(1) nat_seq_nth_compute not_less0 not_less_eq_eq)
   apply(clarsimp)
  apply(rename_tac i nat)(*strict*)
  apply(clarsimp)
  apply(rename_tac nat)(*strict*)
  apply(simp add: get_labels_def)
  apply(simp add: get_label_def)
  apply(simp add: derivation_append_def der2_def)
  apply(rule_tac
      t="nat_seq (Suc 0) (Suc n) ! Suc nat"
      and s="Suc 0+Suc nat"
      in ssubst)
   apply(rename_tac nat)(*strict*)
   apply(rule nat_seq_nth_compute)
    apply(rename_tac nat)(*strict*)
    apply(force)
   apply(rename_tac nat)(*strict*)
   apply (metis One_nat_def Suc_less_eq diff_Suc_1 less_eq_Suc_le nat_seq_length_Suc0 zero_less_Suc)
  apply(rename_tac nat)(*strict*)
  apply(clarsimp)
  apply(rule_tac
      t="map (\<lambda>i. case_option None (case_derivation_configuration (\<lambda>e c. e)) (d i)) (nat_seq (Suc 0) n) ! nat"
      and s=" (\<lambda>i. case_option None (case_derivation_configuration (\<lambda>e c. e)) (d i)) ((nat_seq (Suc 0) n) ! nat)"
      in ssubst)
   apply(rename_tac nat)(*strict*)
   apply (metis get_label_def Suc_less_SucD Suc_less_eq less_trans_Suc nat_seq_length_Suc0 nth_map zero_less_Suc)
  apply(rename_tac nat)(*strict*)
  apply(rule_tac
      t="nat_seq (Suc 0) (Suc n) ! nat"
      and s="Suc 0+nat"
      in ssubst)
   apply(rename_tac nat)(*strict*)
   apply(rule nat_seq_nth_compute)
    apply(rename_tac nat)(*strict*)
    apply(force)
   apply(rename_tac nat)(*strict*)
   apply (metis Suc_lessD diff_Suc_Suc less_Suc_eq_le minus_nat.diff_0 nat_seq_length_Suc0 zero_less_Suc)
  apply(rename_tac nat)(*strict*)
  apply(rule_tac
      t="nat_seq (Suc 0) n ! nat"
      and s="Suc 0+nat"
      in ssubst)
   apply(rename_tac nat)(*strict*)
   apply(rule nat_seq_nth_compute)
    apply(rename_tac nat)(*strict*)
    apply (metis One_nat_def Suc_lessD less_Suc0 less_not_refl nat_seq_length_Suc0 trivNat)
   apply(rename_tac nat)(*strict*)
   apply (metis One_nat_def Suc_eq_plus1 add_leE diff_add_inverse le_diff_conv2 nat_seq_length_prime add.commute not_less_eq trivNat)
  apply(rename_tac nat)(*strict*)
  apply(force)
  done

lemma get_labels_derivation_drop_decompose: "
  d (Suc 0) = Some (pair (Some e) c)
  \<Longrightarrow> get_labels d (Suc (n1 + n2)) = Some e # get_labels (derivation_drop d (Suc 0)) (n1 + n2)"
  apply(rule listEqI)
   apply(clarsimp)
   apply (metis get_labels_length)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(simp add: get_labels_def)
  apply(simp add: get_label_def)
  apply(rule_tac
      t="nat_seq (Suc 0) (Suc (n1 + n2)) ! i"
      and s="Suc 0+i"
      in ssubst)
   apply(rename_tac i)(*strict*)
   apply(rule nat_seq_nth_compute)
    apply(rename_tac i)(*strict*)
    apply (metis One_nat_def Suc_lessD less_Suc0 less_not_refl trivNat)
   apply(rename_tac i)(*strict*)
   apply (metis One_nat_def Suc_eq_plus1 diff_add_inverse nat_seq_length_prime add.commute not_less_eq trivNat)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(case_tac i)
   apply(rename_tac i)(*strict*)
   apply(clarsimp)
  apply(rename_tac i nat)(*strict*)
  apply(clarsimp)
  apply(rename_tac nat)(*strict*)
  apply(rule_tac
      t="map (\<lambda>i. case_option None (case_derivation_configuration (\<lambda>e c. e)) (derivation_drop d (Suc 0) i)) (nat_seq (Suc 0) (n1 + n2)) ! nat"
      and s="(\<lambda>i. case_option None (case_derivation_configuration (\<lambda>e c. e)) (derivation_drop d (Suc 0) i)) ((nat_seq (Suc 0) (n1 + n2)) ! nat)"
      in ssubst)
   apply(rename_tac nat)(*strict*)
   apply(rule nth_map)
   apply (metis Suc_less_eq nat_seq_length_Suc0 neq0_conv not_less_eq zero_less_Suc)
  apply(rename_tac nat)(*strict*)
  apply(rule_tac
      t="nat_seq (Suc 0) (n1 + n2) ! nat"
      and s="Suc 0+nat"
      in ssubst)
   apply(rename_tac nat)(*strict*)
   apply(rule nat_seq_nth_compute)
    apply(rename_tac nat)(*strict*)
    apply (metis One_nat_def Suc_lessD less_Suc0 less_not_refl nat_seq_length_Suc0 trivNat)
   apply(rename_tac nat)(*strict*)
   apply (metis One_nat_def Suc_eq_plus1 add_leE diff_add_inverse le_diff_conv2 nat_seq_length_prime add.commute not_less_eq trivNat)
  apply(rename_tac nat)(*strict*)
  apply(clarsimp)
  apply(simp add: derivation_drop_def)
  done

lemma der2_get_labels: "
  get_labels (der2 c1 e c2) (Suc 0) = [Some e]"
  apply(simp add: get_labels_def)
  apply(subgoal_tac "nat_seq (Suc 0) (Suc 0)=[Suc 0]")
   apply(clarsimp)
   apply(simp add: der2_def get_label_def)
  apply (metis natUptTo_n_n)
  done

lemma der1_get_labels: "
  get_labels (der1 c) 0 = []"
  apply(rule get_labelsEmpty)
  done

definition sat_refined :: "'TSstructure \<Rightarrow> (nat \<Rightarrow> ('label,'conf)derivation_configuration option) \<Rightarrow> ('conf\<Rightarrow>'label\<Rightarrow>'conf\<Rightarrow>bool) \<Rightarrow> bool" where
  "sat_refined G d P = (\<forall>i.
  case d (Suc i) of None \<Rightarrow> True
  | Some (pair e' c') \<Rightarrow> (case d i of None \<Rightarrow> False
  | Some (pair e c) \<Rightarrow> (case e' of None \<Rightarrow> False | Some e' \<Rightarrow> P c e' c))
  )"

lemma get_labels_strict_prefix1: "
  strict_prefix (map the (get_labels d n)) (map the (get_labels d (Suc n)))"
  apply(simp add: get_labels_def strict_prefix_def)
  apply(rule_tac
      x="[the(get_label (d(Suc n)))]"
      in exI)
  apply(clarsimp)
  apply(rule_tac
      t="nat_seq (Suc 0) (Suc n)"
      and s="nat_seq (Suc 0) n@[Suc n]"
      in ssubst)
   apply (metis nat_seq_drop_last_prime)
  apply(clarsimp)
  done

lemma get_labels_strict_prefix: "
  strict_prefix (map the (get_labels d n)) (map the (get_labels d (Suc n+m)))"
  apply(induct m)
   apply(clarsimp)
   apply(rule get_labels_strict_prefix1)
  apply(rename_tac m)(*strict*)
  apply(clarsimp)
  apply(subgoal_tac "strict_prefix (map the (get_labels d (Suc (n + m)))) (map the (get_labels d (Suc (Suc (n + m)))))")
   apply(rename_tac m)(*strict*)
   apply(simp add: strict_prefix_def)
   apply(clarsimp)
   apply(rename_tac m c ca)(*strict*)
   apply(rule_tac
      x="c@ca"
      in exI)
   apply(clarsimp)
   apply(rule_tac
      t="map the (get_labels d (Suc (Suc (n + m))))"
      and s="map the (get_labels d (Suc (n + m))) @ ca"
      in ssubst)
    apply(rename_tac m c ca)(*strict*)
    apply(force)
   apply(rename_tac m c ca)(*strict*)
   apply(rule_tac
      t="map the (get_labels d (Suc (n + m)))"
      and s="map the (get_labels d n) @ c"
      in ssubst)
    apply(rename_tac m c ca)(*strict*)
    apply(force)
   apply(rename_tac m c ca)(*strict*)
   apply(simp (no_asm))
  apply(rename_tac m)(*strict*)
  apply(thin_tac "strict_prefix (map the (get_labels d n)) (map the (get_labels d (Suc (n + m))))")
  apply(rule get_labels_strict_prefix1)
  done

lemma get_labels_drop_tail: "
  get_labels d (n+m) = w@v
  \<Longrightarrow> length w=n
  \<Longrightarrow> get_labels d n = w"
  apply(simp add: get_labels_def)
  apply(clarsimp)
  apply(subgoal_tac "length (nat_seq (Suc 0) (length w)) = n + 1 - Suc 0" for n)
   prefer 2
   apply(rule nat_seq_length_prime)
  apply(subgoal_tac "length (nat_seq (Suc 0) (length w+m)) = n + 1 - Suc 0" for n)
   prefer 2
   apply(rule nat_seq_length_prime)
  apply(rule listEqI)
   apply(clarsimp)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(subgoal_tac "nat_seq (Suc 0) (length w) ! i = SSn+SSi" for SSn SSi)
   apply(rename_tac i)(*strict*)
   prefer 2
   apply(rule nat_seq_nth_compute)
    apply(rename_tac i)(*strict*)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(subgoal_tac "nat_seq (Suc 0) (length w+m) ! i = SSn+SSi" for SSn SSi)
   apply(rename_tac i)(*strict*)
   prefer 2
   apply(rule nat_seq_nth_compute)
    apply(rename_tac i)(*strict*)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(rule_tac
      t="w!i"
      and s="(w@v)!i"
      in subst)
   apply(rename_tac i)(*strict*)
   apply(rule nth_append_1)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(rule_tac
      t="get_label (d (Suc i))"
      and s="map (\<lambda>i. get_label (d i)) (nat_seq (Suc 0) (length w + m)) !i"
      in ssubst)
   apply(rename_tac i)(*strict*)
   prefer 2
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(thin_tac "map (\<lambda>i. get_label (d i)) (nat_seq (Suc 0) (length w + m)) = w @ v")
  apply(rule_tac
      t="map (\<lambda>i. get_label (d i)) (nat_seq (Suc 0) (length w + m)) ! i"
      and s="(\<lambda>i. get_label (d i)) ((nat_seq (Suc 0) (length w + m)) ! i)"
      in ssubst)
   apply(rename_tac i)(*strict*)
   apply(rule nth_map)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(force)
  done

lemma getLabel_at_pos: "
  get_labels d n = w
  \<Longrightarrow> d (Suc i) = Some (pair (Some e) c)
  \<Longrightarrow> i<n
  \<Longrightarrow> w!i=Some e"
  apply(simp add: get_labels_def)
  apply(clarsimp)
  apply(subgoal_tac "length (nat_seq (Suc 0) n) = SSn + 1 - Suc 0" for SSn)
   prefer 2
   apply(rule nat_seq_length_prime)
  apply(rule_tac
      t="map (\<lambda>i. get_label (d i)) (nat_seq (Suc 0) n) ! i"
      and s="(\<lambda>i. get_label (d i)) ((nat_seq (Suc 0) n) ! i)"
      in ssubst)
   apply(rule nth_map)
   apply(clarsimp)
  apply(subgoal_tac "nat_seq (Suc 0) n ! i = SSn+SSi" for SSn SSi)
   prefer 2
   apply(rule nat_seq_nth_compute)
    apply(force)
   apply(force)
  apply(clarsimp)
  apply(simp add: get_label_def)
  done

lemma get_labels_decomp: "
  get_labels d (n+m) = (get_labels d n) @ (drop n (get_labels d (n+m)))"
  apply(subgoal_tac "length (nat_seq (Suc 0) (n+m)) = SSn + 1 - Suc 0" for SSn)
   prefer 2
   apply(rule nat_seq_length_prime)
  apply(subgoal_tac "length (nat_seq (Suc 0) n) = SSn + 1 - Suc 0" for SSn)
   prefer 2
   apply(rule nat_seq_length_prime)
  apply(subgoal_tac "length (nat_seq (Suc 0) m) = SSn + 1 - Suc 0" for SSn)
   prefer 2
   apply(rule nat_seq_length_prime)
  apply(clarsimp)
  apply(simp add: get_labels_def)
  apply(rule listEqI)
   apply(clarsimp)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  apply(case_tac "i<n")
   apply(rename_tac i)(*strict*)
   apply(rule_tac
      t="(map (\<lambda>i. get_label (d i)) (nat_seq (Suc 0) n) @ drop n (map (\<lambda>i. get_label (d i)) (nat_seq (Suc 0) (n + m)))) ! i"
      and s="(map (\<lambda>i. get_label (d i)) (nat_seq (Suc 0) n) ) ! i"
      in ssubst)
    apply(rename_tac i)(*strict*)
    apply(rule nth_append_1)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(clarsimp)
   apply(subgoal_tac "nat_seq (Suc 0) (n+m) ! i = SSn+SSi" for SSn SSi)
    apply(rename_tac i)(*strict*)
    prefer 2
    apply(rule nat_seq_nth_compute)
     apply(rename_tac i)(*strict*)
     apply(force)
    apply(rename_tac i)(*strict*)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(clarsimp)
   apply(subgoal_tac "nat_seq (Suc 0) n ! i = SSn+SSi" for SSn SSi)
    apply(rename_tac i)(*strict*)
    prefer 2
    apply(rule nat_seq_nth_compute)
     apply(rename_tac i)(*strict*)
     apply(force)
    apply(rename_tac i)(*strict*)
    apply(force)
   apply(rename_tac i)(*strict*)
   apply(clarsimp)
  apply(rename_tac i)(*strict*)
  apply(rule_tac
      t="(map (\<lambda>i. get_label (d i)) (nat_seq (Suc 0) n) @ drop n (map (\<lambda>i. get_label (d i)) (nat_seq (Suc 0) (n + m)))) ! i"
      and s="(drop n (map (\<lambda>i. get_label (d i)) (nat_seq (Suc 0) (n + m)))) ! (i-length(map (\<lambda>i. get_label (d i)) (nat_seq (Suc 0) n)))"
      in ssubst)
   apply(rename_tac i)(*strict*)
   apply(rule nth_append_2)
   apply(force)
  apply(rename_tac i)(*strict*)
  apply(clarsimp)
  done

lemma der3_maximum_of_domain2: "
  maximum_of_domain (der3 c1 e1 c2 e2 c3) 2"
  apply(simp add: maximum_of_domain_def der3_def)
  done

lemma maximum_of_domain_derivation_append_der1: "
  maximum_of_domain d n
  \<Longrightarrow> maximum_of_domain (derivation_append d (der1 c) n) n"
  apply(simp add: maximum_of_domain_def)
  apply(clarsimp)
  apply(rename_tac y)(*strict*)
  apply(simp add: derivation_append_def)
  apply(simp add: der1_def)
  done

lemma maximum_of_domain_derivation_append_der2: "
  maximum_of_domain d n
  \<Longrightarrow> maximum_of_domain (derivation_append d (der2 c e c') n) (Suc n)"
  apply(simp add: maximum_of_domain_def)
  apply(clarsimp)
  apply(rename_tac y)(*strict*)
  apply(simp add: derivation_append_def)
  apply(simp add: der2_def)
  done

lemma derivation_map_Relects_None: "
  derivation_map d C n = None
  \<Longrightarrow> d n = None"
  apply(simp add: derivation_map_def)
  apply(case_tac "d n")
   apply(auto)
  apply(rename_tac a)(*strict*)
  apply(case_tac a)
  apply(rename_tac a option b)(*strict*)
  apply(auto)
  done

lemma get_labels__seperate_last: "
  d (Suc n) = Some (pair e c)
  \<Longrightarrow> get_labels d (Suc n) = get_labels d n @ [e]"
  apply(simp add: get_labels_def)
  apply(rule_tac t="nat_seq (Suc 0) (Suc n)" and s="nat_seq (Suc 0) n @[Suc n]" in ssubst)
   apply (metis nat_seq_drop_last_prime)
  apply(clarsimp)
  apply(simp add: get_label_def)
  done

lemma get_labels__derivation_append__trivial: "
  get_labels (derivation_append d1 d2 n) n = get_labels d1 n"
  apply(simp add: get_labels_def derivation_append_def)
  apply(clarsimp)
  apply (metis nat_seq_in_interval)
  done

end