Theory Earley_Parser

theory Earley_Parser
  imports
    Earley_Recognizer
    "HOL-Library.Monad_Syntax"
begin

section ‹Earley parser›

subsection ‹Pointer lemmas›

definition predicts :: "'a item  bool" where
  "predicts x  start_item x = end_item x  dot_item x = 0"

definition scans :: "'a list  nat  'a item  'a item  bool" where
  "scans ω k x y  y = inc_item x k  (a. next_symbol x = Some a  ω!(k-1) = a)"

definition completes :: "nat  'a item  'a item  'a item  bool" where
  "completes k x y z  y = inc_item x k  is_complete z  start_item z = end_item x 
    (N. next_symbol x = Some N  N = lhs_item z)"

definition sound_null_ptr :: "'a item × pointer  bool" where
  "sound_null_ptr e  (snd e = Null  predicts (fst e))"

definition sound_pre_ptr :: "'a list  'a bins  nat  'a item × pointer  bool" where
  "sound_pre_ptr ω bs k e  pre. snd e = Pre pre 
    k > 0  pre < length (bs!(k-1))  scans ω k (fst (bs!(k-1)!pre)) (fst e)"

definition sound_prered_ptr :: "'a bins  nat  'a item × pointer  bool" where
  "sound_prered_ptr bs k e  p ps k' pre red. snd e = PreRed p ps  (k', pre, red)  set (p#ps) 
    k' < k  pre < length (bs!k')  red < length (bs!k)  completes k (fst (bs!k'!pre)) (fst e) (fst (bs!k!red))"

definition sound_ptrs :: "'a list  'a bins  bool" where
  "sound_ptrs ω bs  k < length bs. e  set (bs!k).
    sound_null_ptr e  sound_pre_ptr ω bs k e  sound_prered_ptr bs k e"

definition mono_red_ptr :: "'a bins  bool" where
  "mono_red_ptr bs  k < length bs. i < length (bs!k).
    k' pre red ps. snd (bs!k!i) = PreRed (k', pre, red) ps  red < i"

lemma nth_item_upd_bin:
  "n < length es  fst (upd_bin e es ! n) = fst (es!n)"
  by (induction es arbitrary: e n) (auto simp: less_Suc_eq_0_disj split: prod.splits pointer.splits)

lemma upd_bin_append:
  "fst e  set (items es)  upd_bin e es = es @ [e]"
  by (induction es arbitrary: e) (auto simp: items_def split: prod.splits pointer.splits)

lemma upd_bin_null_pre:
  "fst e  set (items es)  snd e = Null  snd e = Pre pre  upd_bin e es = es"
  by (induction es arbitrary: e) (auto simp: items_def split: prod.splits, fastforce+)

lemma upd_bin_prered_nop:
  assumes "distinct (items es)" "i < length es"
  assumes "fst e = fst (es!i)" "snd e = PreRed p ps" "p ps. snd (es!i) = PreRed p ps"
  shows "upd_bin e es = es"
  using assms
  by (induction es arbitrary: e i) (auto simp: less_Suc_eq_0_disj items_def split: prod.splits pointer.splits)

lemma upd_bin_prered_upd:
  assumes "distinct (items es)" "i < length es"
  assumes "fst e = fst (es!i)" "snd e = PreRed p rs" "snd (es!i) = PreRed p' rs'" "upd_bin e es = es'"
  shows "snd (es'!i) = PreRed p' (p#rs@rs')  (j < length es'. ij  es'!j = es!j)  length (upd_bin e es) = length es"
  using assms
proof (induction es arbitrary: e i es')
  case (Cons e' es)
  show ?case
  proof cases
    assume *: "fst e = fst e'"
    show ?thesis
    proof (cases "x xp xs y yp ys. e = (x, PreRed xp xs)  e' = (y, PreRed yp ys)")
      case True
      then obtain x xp xs y yp ys where ee': "e = (x, PreRed xp xs)" "e' = (y, PreRed yp ys)" "x = y"
        using * by auto
      have simp: "upd_bin e (e' # es') = (x, PreRed yp (xp # xs @ ys)) # es'"
        using True ee' by simp
      show ?thesis
        using Cons simp ee' apply (auto simp: items_def)
        using less_Suc_eq_0_disj by fastforce+
    next
      case False
      hence "upd_bin e (e' # es') = e' # es'"
        using * by (auto split: pointer.splits prod.splits)
      thus ?thesis
        using False * Cons.prems(1,2,3,4,5) by (auto simp: less_Suc_eq_0_disj items_def split: prod.splits)
    qed
  next
    assume *: "fst e  fst e'"
    have simp: "upd_bin e (e' # es) = e' # upd_bin e es"
      using * by (auto split: pointer.splits prod.splits)
    have 0: "distinct (items es)"
      using Cons.prems(1) unfolding items_def by simp
    have 1: "i-1 < length es"
      using Cons.prems(2,3) * by (metis One_nat_def leI less_diff_conv2 less_one list.size(4) nth_Cons_0)
    have 2: "fst e = fst (es!(i-1))"
      using Cons.prems(3) * by (metis nth_Cons')
    have 3: "snd e = PreRed p rs"
      using Cons.prems(4) by simp
    have 4: "snd (es!(i-1)) = PreRed p' rs' "
      using Cons.prems(3,5) * by (metis nth_Cons')
    have "snd (upd_bin e es!(i-1)) = PreRed p' (p # rs @ rs') 
      (j < length (upd_bin e es). i-1  j  (upd_bin e es) ! j = es ! j)"
      using Cons.IH[OF 0 1 2 3 4] by blast
    hence "snd ((e' # upd_bin e es) ! i) = PreRed p' (p # rs @ rs') 
      (j < length (e' # upd_bin e es). i  j  (e' # upd_bin e es) ! j = (e' # es) ! j)"
      using * Cons.prems(2,3) less_Suc_eq_0_disj by auto
    moreover have "e' # upd_bin e es = es'"
      using Cons.prems(6) simp by auto
    ultimately show ?thesis
      by (metis 0 1 2 3 4 Cons.IH Cons.prems(6) length_Cons)
  qed
qed simp

lemma sound_ptrs_upd_bin:
  assumes "sound_ptrs ω bs" "k < length bs" "es = bs!k" "distinct (items es)"
  assumes "sound_null_ptr e" "sound_pre_ptr ω bs k e" "sound_prered_ptr bs k e"
  shows "sound_ptrs ω (bs[k := upd_bin e es])"
  unfolding sound_ptrs_def
proof (standard, standard, standard)
  fix idx elem
  let ?bs = "bs[k := upd_bin e es]"
  assume a0: "idx < length ?bs"
  assume a1: "elem  set (?bs ! idx)"
  show "sound_null_ptr elem  sound_pre_ptr ω ?bs idx elem  sound_prered_ptr ?bs idx elem"
  proof cases
    assume a2: "idx = k"
    have "elem  set es  sound_pre_ptr ω bs idx elem"
      using a0 a2 assms(1-3) sound_ptrs_def by blast
    hence pre_es: "elem  set es  sound_pre_ptr ω ?bs idx elem"
      using a2 unfolding sound_pre_ptr_def by force
    have "elem = e  sound_pre_ptr ω bs idx elem"
      using a2 assms(6) by auto
    hence pre_e: "elem = e  sound_pre_ptr ω ?bs idx elem"
      using a2 unfolding sound_pre_ptr_def by force
    have "elem  set es  sound_prered_ptr bs idx elem"
      using a0 a2 assms(1-3) sound_ptrs_def by blast
    hence prered_es: "elem  set es  sound_prered_ptr (bs[k := upd_bin e es]) idx elem"
      using a2 assms(2,3) length_upd_bin nth_item_upd_bin unfolding sound_prered_ptr_def
      by (smt (verit, ccfv_SIG) dual_order.strict_trans1 nth_list_update)
    have "elem = e  sound_prered_ptr bs idx elem"
      using a2 assms(7) by auto
    hence prered_e: "elem = e  sound_prered_ptr ?bs idx elem"
      using a2 assms(2,3) length_upd_bin nth_item_upd_bin unfolding sound_prered_ptr_def
      by (smt (verit, best) dual_order.strict_trans1 nth_list_update)
    consider (A) "fst e  set (items es)" |
      (B) "fst e  set (items es)  (pre. snd e = Null  snd e = Pre pre)" |
      (C) "fst e  set (items es)  ¬ (pre. snd e = Null  snd e = Pre pre)"
      by blast
    thus ?thesis
    proof cases
      case A
      hence "elem  set (es @ [e])"
        using a1 a2 upd_bin_append assms(2) by fastforce
      thus ?thesis
        using assms(1-3,5) pre_e pre_es prered_e prered_es sound_ptrs_def by auto
    next
      case B
      hence "elem  set es"
        using a1 a2 upd_bin_null_pre assms(2) by fastforce
      thus ?thesis
        using assms(1-3) pre_es prered_es sound_ptrs_def by blast
    next
      case C
      then obtain i p ps where C: "i < length es  fst e = fst (es!i)  snd e = PreRed p ps"
        by (metis assms(4) distinct_Ex1 items_def length_map nth_map pointer.exhaust)
      show ?thesis
      proof cases
        assume "p' ps'. snd (es!i) = PreRed p' ps'"
        hence C: "elem  set es"
          using a1 a2 C upd_bin_prered_nop assms(2,4) by (metis nth_list_update_eq)
        thus ?thesis
          using assms(1-3) sound_ptrs_def pre_es prered_es by blast
      next
        assume "¬ (p' ps'. snd (es!i) = PreRed p' ps')"
        then obtain p' ps' where D: "snd (es!i) = PreRed p' ps'"
          by blast
        hence 0: "snd (upd_bin e es!i) = PreRed p' (p#ps@ps')  (j < length (upd_bin e es). ij  upd_bin e es!j = es!j)"
          using C assms(4) upd_bin_prered_upd by blast
        obtain j where 1: "j < length es  elem = upd_bin e es!j"
          using a1 a2 assms(2) C items_def bin_eq_items_upd_bin by (metis in_set_conv_nth length_map nth_list_update_eq nth_map)
        show ?thesis
        proof cases
          assume a3: "i=j"
          hence a3: "snd elem = PreRed p' (p#ps@ps')"
            using 0 1 by blast
          have "sound_null_ptr elem"
            using a3 unfolding sound_null_ptr_def by simp
          moreover have "sound_pre_ptr ω ?bs idx elem"
            using a3 unfolding sound_pre_ptr_def by simp
          moreover have "sound_prered_ptr ?bs idx elem"
            unfolding sound_prered_ptr_def
          proof (standard, standard, standard, standard, standard, standard)
            fix P PS k' pre red
            assume a4: "snd elem = PreRed P PS  (k', pre, red)  set (P#PS)"
            show "k' < idx  pre < length (bs[k := upd_bin e es]!k')  red < length (bs[k := upd_bin e es]!idx) 
              completes idx (fst (bs[k := upd_bin e es]!k'!pre)) (fst elem) (fst (bs[k := upd_bin e es]!idx!red))"
            proof cases
              assume a5: "(k', pre, red)  set (p#ps)"
              show ?thesis
                using 0 1 C a2 a4 a5 prered_es assms(2,3,7) sound_prered_ptr_def length_upd_bin nth_item_upd_bin
                by (smt (verit) dual_order.strict_trans1 nth_list_update_eq nth_list_update_neq nth_mem)
            next
              assume a5: "(k', pre, red)  set (p#ps)"
              hence a5: "(k', pre, red)  set (p'#ps')"
                using a3 a4 by auto
              have "k' < idx  pre < length (bs!k')  red < length (bs!idx) 
                completes idx (fst (bs!k'!pre)) (fst e) (fst (bs!idx!red))"
                using assms(1-3) C D a2 a5 unfolding sound_ptrs_def sound_prered_ptr_def by (metis nth_mem)
              thus ?thesis
                using 0 1 C a4 assms(2,3) length_upd_bin nth_item_upd_bin prered_es sound_prered_ptr_def
                by (smt (verit, best) dual_order.strict_trans1 nth_list_update_eq nth_list_update_neq nth_mem)
            qed
          qed
          ultimately show ?thesis
            by blast
        next
          assume a3: "ij"
          hence "elem  set es"
            using 0 1 by (metis length_upd_bin nth_mem order_less_le_trans)
          thus ?thesis
            using assms(1-3) pre_es prered_es sound_ptrs_def by blast
        qed
      qed
    qed
  next
    assume a2: "idx  k"
    have null: "sound_null_ptr elem"
      using a0 a1 a2 assms(1) sound_ptrs_def by auto
    have "sound_pre_ptr ω bs idx elem"
      using a0 a1 a2 assms(1,2) unfolding sound_ptrs_def by simp
    hence pre: "sound_pre_ptr ω ?bs idx elem"
      using assms(2,3) length_upd_bin nth_item_upd_bin unfolding sound_pre_ptr_def
      using dual_order.strict_trans1 nth_list_update by (metis (no_types, lifting))
    have "sound_prered_ptr bs idx elem"
      using a0 a1 a2 assms(1,2) unfolding sound_ptrs_def by simp
    hence prered: "sound_prered_ptr ?bs idx elem"
      using assms(2,3) length_upd_bin nth_item_upd_bin unfolding sound_prered_ptr_def
      by (smt (verit, best) dual_order.strict_trans1 nth_list_update)
    show ?thesis
      using null pre prered by blast
  qed
qed

lemma mono_red_ptr_upd_bin:
  assumes "mono_red_ptr bs" "k < length bs" "es = bs!k" "distinct (items es)"
  assumes "k' pre red ps. snd e = PreRed (k', pre, red) ps  red < length es"
  shows "mono_red_ptr (bs[k := upd_bin e es])"
  unfolding mono_red_ptr_def
proof (standard, standard)
  fix idx
  let ?bs = "bs[k := upd_bin e es]"
  assume a0: "idx < length ?bs"
  show "i < length (?bs!idx). k' pre red ps. snd (?bs!idx!i) = PreRed (k', pre, red) ps  red < i"
  proof cases
    assume a1: "idx=k"
    consider (A) "fst e  set (items es)" |
      (B) "fst e  set (items es)  (pre. snd e = Null  snd e = Pre pre)" |
      (C) "fst e  set (items es)  ¬ (pre. snd e = Null  snd e = Pre pre)"
      by blast
    thus ?thesis
    proof cases
      case A
      hence "upd_bin e es = es @ [e]"
        using upd_bin_append by blast
      thus ?thesis
        using a1 assms(1-3,5) mono_red_ptr_def
        by (metis length_append_singleton less_antisym nth_append nth_append_length nth_list_update_eq)
    next
      case B
      hence "upd_bin e es = es"
        using upd_bin_null_pre by blast
      thus ?thesis
        using a1 assms(1-3) mono_red_ptr_def by force
    next
      case C
      then obtain i p ps where C: "i < length es" "fst e = fst (es!i)" "snd e = PreRed p ps"
        by (metis in_set_conv_nth items_def length_map nth_map pointer.exhaust)
      show ?thesis
      proof cases
        assume "p' ps'. snd (es!i) = PreRed p' ps'"
        hence "upd_bin e es = es"
          using upd_bin_prered_nop C assms(4) by blast
        thus ?thesis
          using a1 assms(1-3) mono_red_ptr_def by (metis nth_list_update_eq)
      next
        assume "¬ (p' ps'. snd (es!i) = PreRed p' ps')"
        then obtain p' ps' where D: "snd (es!i) = PreRed p' ps'"
          by blast
        have 0: "snd (upd_bin e es!i) = PreRed p' (p#ps@ps') 
          (j < length (upd_bin e es). i  j  upd_bin e es!j = es!j) 
          length (upd_bin e es) = length es"
          using C D assms(4) upd_bin_prered_upd by blast
        show ?thesis
        proof (standard, standard, standard, standard, standard, standard, standard)
          fix j k' pre red PS
          assume a2: "j < length (?bs!idx)"
          assume a3: "snd (?bs!idx!j) = PreRed (k', pre, red) PS"
          have 1: "?bs!idx = upd_bin e es"
            by (simp add: a1 assms(2))
          show "red < j"
          proof cases
            assume a4: "i=j"
            show ?thesis
              using 0 1 C(1) D a3 a4 assms(1-3) unfolding mono_red_ptr_def by (metis pointer.inject(2))
          next
            assume a4: "ij"
            thus ?thesis
              using 0 1 a2 a3 assms(1) assms(2) assms(3) mono_red_ptr_def by force
          qed
        qed
      qed
    qed
  next
    assume a1: "idxk"
    show ?thesis
      using a0 a1 assms(1) mono_red_ptr_def by fastforce
  qed
qed

lemma sound_mono_ptrs_upds_bin:
  assumes "sound_ptrs ω bs" "mono_red_ptr bs" "k < length bs" "b = bs!k" "distinct (items b)"
  assumes "e  set es. sound_null_ptr e  sound_pre_ptr ω bs k e  sound_prered_ptr bs k e"
  assumes "e  set es. k' pre red ps. snd e = PreRed (k', pre, red) ps  red < length b"
  shows "sound_ptrs ω (bs[k := upds_bin es b])  mono_red_ptr (bs[k := upds_bin es b])"
  using assms
proof (induction es arbitrary: b bs)
  case (Cons e es)
  let ?bs = "bs[k := upd_bin e b]"
  have 0: "sound_ptrs ω ?bs"
    using sound_ptrs_upd_bin Cons.prems(1,3-5,6) by (metis list.set_intros(1))
  have 1: "mono_red_ptr ?bs"
    using mono_red_ptr_upd_bin Cons.prems(2-5,7) by (metis list.set_intros(1))
  have 2: "k < length ?bs"
    using Cons.prems(3) by simp
  have 3: "upd_bin e b = ?bs!k"
    using Cons.prems(3) by simp
  have 4: "e'  set es. sound_null_ptr e'  sound_pre_ptr ω ?bs k e'  sound_prered_ptr ?bs k e'"
    using Cons.prems(3,4,6) length_upd_bin nth_item_upd_bin sound_pre_ptr_def sound_prered_ptr_def
    by (smt (verit, ccfv_threshold) list.set_intros(2) nth_list_update order_less_le_trans)
  have 5: "e'  set es. k' pre red ps. snd e' = PreRed (k', pre, red) ps  red < length (upd_bin e b)"
    by (meson Cons.prems(7) length_upd_bin order_less_le_trans set_subset_Cons subsetD)
  have "sound_ptrs ω ((bs[k := upd_bin e b])[k := upds_bin es (upd_bin e b)]) 
    mono_red_ptr (bs[k := upd_bin e b, k := upds_bin es (upd_bin e b)])"
    using Cons.IH[OF 0 1 2 3 _ _] distinct_upd_bin Cons.prems(4,5,6) items_def 4 5 by blast
  thus ?case
    by simp
qed simp

lemma sound_mono_ptrs_EarleyL_bin':
  assumes "(k, 𝒢, ω, bs)  wf_earley_input"
  assumes "sound_ptrs ω bs" "x  bins bs. sound_item 𝒢 ω x"
  assumes "mono_red_ptr bs"
  assumes "nonempty_derives 𝒢"
  shows "sound_ptrs ω (EarleyL_bin' k 𝒢 ω bs i)  mono_red_ptr (EarleyL_bin' k 𝒢 ω bs i)"
  using assms
proof (induction i rule: EarleyL_bin'_induct[OF assms(1), case_names Base CompleteF ScanF Pass PredictF])
  case (CompleteF k 𝒢 ω bs i x)
  let ?bs' = "upd_bins bs k (CompleteL k x bs i)"
  have x: "x  set (items (bs ! k))"
    using CompleteF.hyps(1,2) by force
  hence "x  set (items (CompleteL k x bs i)). sound_item 𝒢 ω x"
    using sound_CompleteL CompleteF.hyps(3) CompleteF.prems wf_earley_input_elim wf_bins_impl_wf_items x
    by (metis dual_order.refl)
  hence sound: "x  bins ?bs'. sound_item 𝒢 ω x"
    by (metis CompleteF.prems(1,3) UnE bins_upd_bins wf_earley_input_elim)
  have 0: "k < length bs"
    using CompleteF.prems(1) wf_earley_input_elim by auto
  have 1: "e  set (CompleteL k x bs i). sound_null_ptr e"
    unfolding CompleteL_def sound_null_ptr_def by auto
  have 2: "e  set (CompleteL k x bs i). sound_pre_ptr ω bs k e"
    unfolding CompleteL_def sound_pre_ptr_def by auto
  {
    fix e
    assume a0: "e  set (CompleteL k x bs i)"
    fix p ps k' pre red
    assume a1: "snd e = PreRed p ps" "(k', pre, red)  set (p#ps)"
    have "k' = start_item x"
      using a0 a1 unfolding CompleteL_def by auto
    moreover have "wf_item 𝒢 ω x" "end_item x = k"
      using CompleteF.prems(1) x wf_earley_input_elim wf_bins_kth_bin by blast+
    ultimately have 0: "k'  k"
      using wf_item_def by blast
    have 1: "k'  k"
    proof (rule ccontr)
      assume "¬ k'  k"
      have "sound_item 𝒢 ω x"
        using CompleteF.prems(1,3) x kth_bin_sub_bins wf_earley_input_elim by (metis subset_eq)
      moreover have "is_complete x"
        using CompleteF.hyps(3) by (auto simp: next_symbol_def split: if_splits)
      moreover have "start_item x = k"
        using ¬ k'  k k' = start_item x by auto
      ultimately show False
        using impossible_complete_item CompleteF.prems(1,5) wf_earley_input_elim end_item x = k wf_item 𝒢 ω x by blast
    qed
    have 2: "pre < length (bs!k')"
      using a0 a1 index_filter_with_index_lt_length unfolding CompleteL_def by (auto simp: items_def; fastforce)
    have 3: "red < i+1"
      using a0 a1 unfolding CompleteL_def by auto

    have "fst e = inc_item (fst (bs!k'!pre)) k"
      using a0 a1 0 2 CompleteF.hyps(1,2,3) CompleteF.prems(1) k' = start_item x unfolding CompleteL_def
      by (auto simp: items_def, metis filter_with_index_nth nth_map)
    moreover have "is_complete (fst (bs!k!red))"
      using a0 a1 0 2 CompleteF.hyps(1,2,3) CompleteF.prems(1) k' = start_item x unfolding CompleteL_def
      by (auto simp: next_symbol_def items_def split: if_splits)
    moreover have "start_item (fst (bs!k!red)) = end_item (fst (bs!k'!pre))"
      using a0 a1 0 2 CompleteF.hyps(1,2,3) CompleteF.prems(1) k' = start_item x unfolding CompleteL_def
      apply (auto simp: items_def)
      by (metis dual_order.strict_trans index_filter_with_index_lt_length items_def le_neq_implies_less nth_map nth_mem wf_bins_kth_bin wf_earley_input_elim)
    moreover have "(N. next_symbol (fst (bs ! k' ! pre)) = Some N  N = lhs_item (fst (bs ! k ! red)))"
      using a0 a1 0 2 CompleteF.hyps(1,2,3) CompleteF.prems(1) k' = start_item x unfolding CompleteL_def
      by (auto simp: items_def, metis (mono_tags, lifting) filter_with_index_P filter_with_index_nth nth_map)
    ultimately have 4: "completes k (fst (bs!k'!pre)) (fst e) (fst (bs!k!red))"
      unfolding completes_def by blast
    have "k' < k" "pre < length (bs!k')" "red < i+1" "completes k (fst (bs!k'!pre)) (fst e) (fst (bs!k!red))"
      using 0 1 2 3 4 by simp_all
  }
  hence "e  set (CompleteL k x bs i). p ps k' pre red. snd e = PreRed p ps  (k', pre, red)  set (p#ps) 
    k' < k  pre < length (bs!k')  red < i+1  completes k (fst (bs!k'!pre)) (fst e) (fst (bs!k!red))"
    by force
  hence 3: "e  set (CompleteL k x bs i). sound_prered_ptr bs k e"
    unfolding sound_prered_ptr_def using CompleteF.hyps(1) items_def
    by (smt (verit, del_insts) le_antisym le_eq_less_or_eq le_trans length_map length_pos_if_in_set less_imp_add_positive less_one nat_add_left_cancel_le nat_neq_iff plus_nat.add_0)
  have "sound_ptrs ω ?bs'  mono_red_ptr ?bs'"
    using sound_mono_ptrs_upds_bin[OF CompleteF.prems(2) CompleteF.prems(4) 0] 1 2 3 sound_prered_ptr_def
      CompleteF.prems(1) upd_bins_def wf_earley_input_elim wf_bin_def wf_bins_def
    by (smt (verit, ccfv_SIG) list.set_intros(1))
  moreover have "(k, 𝒢, ω, ?bs')  wf_earley_input"
    using CompleteF.hyps CompleteF.prems(1) wf_earley_input_CompleteL by blast
  ultimately have "sound_ptrs ω (EarleyL_bin' k 𝒢 ω ?bs' (i+1))  mono_red_ptr (EarleyL_bin' k 𝒢 ω ?bs' (i+1))"
    using CompleteF.IH CompleteF.prems(4-5) sound by blast
  thus ?case
    using CompleteF.hyps by simp
next
  case (ScanF k 𝒢 ω bs i x a)
  let ?bs' = "upd_bins bs (k+1) (ScanL k ω a x i)"
  have "x  set (items (bs ! k))"
    using ScanF.hyps(1,2) by force
  hence "x  set (items (ScanL k ω a x i)). sound_item 𝒢 ω x"
    using sound_ScanL ScanF.hyps(3,5) ScanF.prems(1,2,3) wf_earley_input_elim wf_bins_impl_wf_items wf_bins_impl_wf_items by fast
  hence sound: "x  bins ?bs'. sound_item 𝒢 ω x"
    using ScanF.hyps(5) ScanF.prems(1,3) bins_upd_bins wf_earley_input_elim
    by (metis UnE add_less_cancel_right)
  have 0: "k+1 < length bs"
    using ScanF.hyps(5) ScanF.prems(1) wf_earley_input_elim by force
  have 1: "e  set (ScanL k ω a x i). sound_null_ptr e"
    unfolding ScanL_def sound_null_ptr_def by auto
  have 2: "e  set (ScanL k ω a x i). sound_pre_ptr ω bs (k+1) e"
    using ScanF.hyps(1,2,3) unfolding sound_pre_ptr_def ScanL_def scans_def items_def by auto
  have 3: "e  set (ScanL k ω a x i). sound_prered_ptr bs (k+1) e"
    unfolding ScanL_def sound_prered_ptr_def by simp
  have "sound_ptrs ω ?bs'  mono_red_ptr ?bs'"
    using sound_mono_ptrs_upds_bin[OF ScanF.prems(2) ScanF.prems(4) 0] 0 1 2 3 sound_prered_ptr_def
      ScanF.prems(1) upd_bins_def wf_earley_input_elim wf_bin_def wf_bins_def
    by (smt (verit, ccfv_threshold) list.set_intros(1))
  moreover have "(k, 𝒢, ω, ?bs')  wf_earley_input"
    using ScanF.hyps ScanF.prems(1) wf_earley_input_ScanL by metis
  ultimately have "sound_ptrs ω (EarleyL_bin' k 𝒢 ω ?bs' (i+1))  mono_red_ptr (EarleyL_bin' k 𝒢 ω ?bs' (i+1))"
    using ScanF.IH ScanF.prems(4-5) sound by blast
  thus ?case
    using ScanF.hyps by simp
next
  case (PredictF k 𝒢 ω bs i x a)
  let ?bs' = "upd_bins bs k (PredictL k 𝒢 a)"
  have "x  set (items (bs ! k))"
    using PredictF.hyps(1,2) by force
  hence "x  set (items(PredictL k 𝒢 a)). sound_item 𝒢 ω x"
    using sound_PredictL PredictF.hyps(3) PredictF.prems wf_earley_input_elim wf_bins_impl_wf_items by fast
  hence sound: "x  bins ?bs'. sound_item 𝒢 ω x"
    using PredictF.prems(1,3) UnE bins_upd_bins wf_earley_input_elim by metis
  have 0: "k < length bs"
    using PredictF.prems(1) wf_earley_input_elim by force
  have 1: "e  set (PredictL k 𝒢 a). sound_null_ptr e"
    unfolding sound_null_ptr_def PredictL_def predicts_def by (auto simp: init_item_def)
  have 2: "e  set (PredictL k 𝒢 a). sound_pre_ptr ω bs k e"
    unfolding sound_pre_ptr_def PredictL_def by simp
  have 3: "e  set (PredictL k 𝒢 a). sound_prered_ptr bs k e"
    unfolding sound_prered_ptr_def PredictL_def by simp
  have "sound_ptrs ω ?bs'  mono_red_ptr ?bs'"
    using sound_mono_ptrs_upds_bin[OF PredictF.prems(2) PredictF.prems(4) 0] 0 1 2 3 sound_prered_ptr_def
      PredictF.prems(1) upd_bins_def wf_earley_input_elim wf_bin_def wf_bins_def
    by (smt (verit, ccfv_threshold) list.set_intros(1))
  moreover have "(k, 𝒢, ω, ?bs')  wf_earley_input"
    using PredictF.hyps PredictF.prems(1) wf_earley_input_PredictL by metis
  ultimately have "sound_ptrs ω (EarleyL_bin' k 𝒢 ω ?bs' (i+1))  mono_red_ptr (EarleyL_bin' k 𝒢 ω ?bs' (i+1))"
    using PredictF.IH PredictF.prems(4-5) sound by blast
  thus ?case
    using PredictF.hyps by simp
qed simp_all

lemma sound_mono_ptrs_EarleyL_bin:
  assumes "(k, 𝒢, ω, bs)  wf_earley_input"
  assumes "sound_ptrs ω bs" "x  bins bs. sound_item 𝒢 ω x"
  assumes "mono_red_ptr bs"
  assumes "nonempty_derives 𝒢"
  shows "sound_ptrs ω (EarleyL_bin k 𝒢 ω bs)  mono_red_ptr (EarleyL_bin k 𝒢 ω bs)"
  using assms sound_mono_ptrs_EarleyL_bin' EarleyL_bin_def by metis

lemma sound_ptrs_InitL:
  "sound_ptrs ω (InitL 𝒢 ω)"
  unfolding sound_ptrs_def sound_null_ptr_def sound_pre_ptr_def sound_prered_ptr_def
    predicts_def scans_def completes_def InitL_def
  by (auto simp: init_item_def less_Suc_eq_0_disj)

lemma mono_red_ptr_InitL:
  "mono_red_ptr (InitL 𝒢 ω)"
  unfolding mono_red_ptr_def InitL_def
  by (auto simp: init_item_def less_Suc_eq_0_disj)

lemma sound_mono_ptrs_EarleyL_bins:
  assumes "k  length ω" "nonempty_derives 𝒢"
  shows "sound_ptrs ω (EarleyL_bins k 𝒢 ω)  mono_red_ptr (EarleyL_bins k 𝒢 ω)"
  using assms
proof (induction k)
  case 0
  have "(0, 𝒢, ω, (InitL 𝒢 ω))  wf_earley_input"
    using assms(2) wf_earley_input_InitL by blast
  moreover have "x  bins (InitL 𝒢 ω). sound_item 𝒢 ω x"
    by (metis InitL_eq_InitF InitF_sub_Earley sound_Earley subsetD wf_Earley)
  ultimately show ?case
    using sound_mono_ptrs_EarleyL_bin sound_ptrs_InitL mono_red_ptr_InitL "0.prems" by fastforce
next
  case (Suc k)
  have "(Suc k, 𝒢, ω, EarleyL_bins k 𝒢 ω)  wf_earley_input"
    by (simp add: Suc.prems(1) Suc_leD assms(2) wf_earley_input_intro)
  moreover have "sound_ptrs ω (EarleyL_bins k 𝒢 ω)"
    using Suc by simp
  moreover have "x  bins (EarleyL_bins k 𝒢 ω). sound_item 𝒢 ω x"
    by (meson Suc.prems(1) Suc_leD EarleyL_bins_sub_EarleyF_bins EarleyF_bins_sub_Earley assms(2)
        sound_Earley subsetD wf_bins_EarleyL_bins wf_bins_impl_wf_items)
  ultimately show ?case
    using Suc.prems sound_mono_ptrs_EarleyL_bin Suc.IH by fastforce
qed

lemma sound_mono_ptrs_EarleyL:
  assumes "nonempty_derives 𝒢"
  shows "sound_ptrs ω (EarleyL 𝒢 ω)  mono_red_ptr (EarleyL 𝒢 ω)"
  using assms sound_mono_ptrs_EarleyL_bins EarleyL_def by (metis dual_order.refl)


subsection ‹Common Definitions›

datatype 'a tree =
  Leaf 'a
  | Branch 'a "'a tree list"

fun yield :: "'a tree  'a list" where
  "yield (Leaf a) = [a]"
| "yield (Branch _ ts) = concat (map yield ts)"

fun root :: "'a tree  'a" where
  "root (Leaf a) = a"
| "root (Branch N _) = N"

fun wf_rule_tree :: "'a cfg  'a tree  bool" where
  "wf_rule_tree _ (Leaf a)  True"
| "wf_rule_tree 𝒢 (Branch N ts)  (
    (r  set ( 𝒢). N = lhs_rule r  map root ts = rhs_rule r) 
    (t  set ts. wf_rule_tree 𝒢 t))"

fun wf_item_tree :: "'a cfg  'a item  'a tree  bool" where
  "wf_item_tree 𝒢 _ (Leaf a)  True"
| "wf_item_tree 𝒢 x (Branch N ts)  (
    N = lhs_item x  map root ts = take (dot_item x) (rhs_item x) 
    (t  set ts. wf_rule_tree 𝒢 t))"

definition wf_yield :: "'a list  'a item  'a tree  bool" where
  "wf_yield ω x t  yield t = slice ω (start_item x) (end_item x)"


subsection ‹foldl lemmas›

lemma foldl_add_nth:
  "k < length xs  foldl (+) z (map length (take k xs)) + length (xs!k) = foldl (+) z (map length (take (k+1) xs))"
proof (induction xs arbitrary: k z)
  case (Cons x xs)
  then show ?case
  proof (cases "k = 0")
    case False
    thus ?thesis
      using Cons by (auto simp add: take_Cons')
  qed simp
qed simp

lemma foldl_acc_mono:
  "a  b  foldl (+) a xs  foldl (+) b xs" for a :: nat
  by (induction xs arbitrary: a b) auto

lemma foldl_ge_z_nth:
  "j < length xs  z + length (xs!j)  foldl (+) z (map length (take (j+1) xs))"
proof (induction xs arbitrary: j z)
  case (Cons x xs)
  show ?case
  proof (cases "j = 0")
    case False
    have "z + length ((x # xs) ! j) = z + length (xs!(j-1))"
      using False by simp
    also have "...  foldl (+) z (map length (take (j-1+1) xs))"
      using Cons False by (metis add_diff_inverse_nat length_Cons less_one nat_add_left_cancel_less plus_1_eq_Suc)
    also have "... = foldl (+) z (map length (take j xs))"
      using False by simp
    also have "...  foldl (+) (z + length x) (map length (take j xs))"
      using foldl_acc_mono by force
    also have "... = foldl (+) z (map length (take (j+1) (x#xs)))"
      by simp
    finally show ?thesis
      by blast
  qed simp
qed simp

lemma foldl_add_nth_ge:
  "i  j  j < length xs  foldl (+) z (map length (take i xs)) + length (xs!j)  foldl (+) z (map length (take (j+1) xs))"
proof (induction xs arbitrary: i j z)
  case (Cons x xs)
  show ?case
  proof (cases "i = 0")
    case True
    have "foldl (+) z (map length (take i (x # xs))) + length ((x # xs) ! j) = z + length ((x # xs) ! j)"
      using True by simp
    also have "...  foldl (+) z (map length (take (j+1) (x#xs)))"
      using foldl_ge_z_nth Cons.prems(2) by blast
    finally show ?thesis
      by blast
  next
    case False
    have "i-1  j-1"
      by (simp add: Cons.prems(1) diff_le_mono)
    have "j-1 < length xs"
      using Cons.prems(1,2) False by fastforce
    have "foldl (+) z (map length (take i (x # xs))) + length ((x # xs) ! j) =
      foldl (+) (z + length x) (map length (take (i-1) xs)) + length ((x#xs)!j)"
      using False by (simp add: take_Cons')
    also have "... = foldl (+) (z + length x) (map length (take (i-1) xs)) + length (xs!(j-1))"
      using Cons.prems(1) False by auto
    also have "...  foldl (+) (z + length x) (map length (take (j-1+1) xs))"
      using Cons.IH i - 1  j - 1 j - 1 < length xs by blast
    also have "... = foldl (+) (z + length x) (map length (take j xs))"
      using Cons.prems(1) False by fastforce
    also have "... = foldl (+) z (map length (take (j+1) (x#xs)))"
      by fastforce
    finally show ?thesis
      by blast
  qed
qed simp

lemma foldl_ge_acc:
  "foldl (+) z (map length xs)  z"
  by (induction xs arbitrary: z) (auto elim: add_leE)

lemma foldl_take_mono:
  "i  j  foldl (+) z (map length (take i xs))  foldl (+) z (map length (take j xs))"
proof (induction xs arbitrary: z i j)
  case (Cons x xs)
  show ?case
  proof (cases "i = 0")
    case True
    have "foldl (+) z (map length (take i (x # xs))) = z"
      using True by simp
    also have "...  foldl (+) z (map length (take j (x # xs)))"
      by (simp add: foldl_ge_acc)
    ultimately show ?thesis
      by simp
  next
    case False
    then show ?thesis
      using Cons by (simp add: take_Cons')
  qed
qed simp


subsection ‹Parse tree›

partial_function (option) build_tree' :: "'a bins  'a list  nat  nat  'a tree option" where
  "build_tree' bs ω k i = (
    let e = bs!k!i in (
    case snd e of
      Null  Some (Branch (lhs_item (fst e)) []) ―‹start building sub-tree›
    | Pre pre  ( ―‹add sub-tree starting from terminal›
        do {
          t  build_tree' bs ω (k-1) pre;
          case t of
            Branch N ts  Some (Branch N (ts @ [Leaf (ω!(k-1))]))
          | _  undefined ―‹impossible case›
        })
    | PreRed (k', pre, red) _  ( ―‹add sub-tree starting from non-terminal›
        do {
          t  build_tree' bs ω k' pre;
          case t of
            Branch N ts 
              do {
                t  build_tree' bs ω k red;
                Some (Branch N (ts @ [t]))
              }
          | _  undefined ―‹impossible case›
        })
  ))"

declare build_tree'.simps [code]

definition build_tree :: "'a cfg  'a list  'a bins  'a tree option" where
  "build_tree 𝒢 ω bs = (
    let k = length bs - 1 in (
    case filter_with_index (λx. is_finished 𝒢 ω x) (items (bs!k)) of
      []  None
    | (_, i)#_  build_tree' bs ω k i
  ))"

lemma build_tree'_simps[simp]:
  "e = bs!k!i  snd e = Null  build_tree' bs ω k i = Some (Branch (lhs_item (fst e)) [])"
  "e = bs!k!i  snd e = Pre pre  build_tree' bs ω (k-1) pre = None 
   build_tree' bs ω k i = None"
  "e = bs!k!i  snd e = Pre pre  build_tree' bs ω (k-1) pre = Some (Branch N ts) 
   build_tree' bs ω k i = Some (Branch N (ts @ [Leaf (ω!(k-1))]))"
  "e = bs!k!i  snd e = Pre pre  build_tree' bs ω (k-1) pre = Some (Leaf a) 
   build_tree' bs ω k i = undefined"
  "e = bs!k!i  snd e = PreRed (k', pre, red) reds  build_tree' bs ω k' pre = None 
   build_tree' bs ω k i = None"
  "e = bs!k!i  snd e = PreRed (k', pre, red) reds  build_tree' bs ω k' pre = Some (Branch N ts) 
   build_tree' bs ω k red = None  build_tree' bs ω k i = None"
  "e = bs!k!i  snd e = PreRed (k', pre, red) reds  build_tree' bs ω k' pre = Some (Leaf a) 
   build_tree' bs ω k i = undefined"
  "e = bs!k!i  snd e = PreRed (k', pre, red) reds  build_tree' bs ω k' pre = Some (Branch N ts) 
   build_tree' bs ω k red = Some t 
   build_tree' bs ω k i = Some (Branch N (ts @ [t]))"
  by (subst build_tree'.simps, simp)+

definition wf_tree_input :: "('a bins × 'a list × nat × nat) set" where
  "wf_tree_input = {
    (bs, ω, k, i) | bs ω k i.
      sound_ptrs ω bs 
      mono_red_ptr bs 
      k < length bs 
      k  length ω 
      i < length (bs!k)
  }"

fun build_tree'_measure :: "('a bins × 'a list × nat × nat)  nat" where
  "build_tree'_measure (bs, ω, k, i) = foldl (+) 0 (map length (take k bs)) + i"

lemma wf_tree_input_pre:
  assumes "(bs, ω, k, i)  wf_tree_input"
  assumes "e = bs!k!i" "snd e = Pre pre"
  shows "(bs, ω, (k-1), pre)  wf_tree_input"
  using assms unfolding wf_tree_input_def
  apply (auto simp: sound_ptrs_def sound_pre_ptr_def)
  apply (metis nth_mem)
  done

lemma wf_tree_input_prered_pre:
  assumes "(bs, ω, k, i)  wf_tree_input"
  assumes "e = bs!k!i" "snd e = PreRed (k', pre, red) ps"
  shows "(bs, ω, k', pre)  wf_tree_input"
  using assms unfolding wf_tree_input_def
  apply (auto simp: sound_ptrs_def sound_prered_ptr_def)
  apply (metis fst_conv snd_conv)+
  apply (metis dual_order.strict_trans nth_mem)
  apply fastforce
  by (metis nth_mem)

lemma wf_tree_input_prered_red:
  assumes "(bs, ω, k, i)  wf_tree_input"
  assumes "e = bs!k!i" "snd e = PreRed (k', pre, red) ps"
  shows "(bs, ω, k, red)  wf_tree_input"
  using assms unfolding wf_tree_input_def
  apply (auto simp add: sound_ptrs_def sound_prered_ptr_def)
  apply (metis fst_conv snd_conv nth_mem)+
  done

lemma build_tree'_induct:
  assumes "(bs, ω, k, i)  wf_tree_input"
  assumes "bs ω k i.
    (e pre. e = bs!k!i  snd e = Pre pre  P bs ω (k-1) pre) 
    (e k' pre red ps. e = bs!k!i  snd e = PreRed (k', pre, red) ps  P bs ω k' pre) 
    (e k' pre red ps. e = bs!k!i  snd e = PreRed (k', pre, red) ps  P bs ω k red) 
    P bs ω k i" 
  shows "P bs ω k i"
  using assms(1)
proof (induction n"build_tree'_measure (bs, ω, k, i)" arbitrary: k i rule: nat_less_induct)
  case 1
  obtain e where entry: "e = bs!k!i"
    by simp
  consider (Null) "snd e = Null"
    | (Pre) "pre. snd e = Pre pre"
    | (PreRed) "k' pre red reds. snd e = PreRed (k', pre, red) reds"
    by (metis pointer.exhaust surj_pair)
  thus ?case
  proof cases
    case Null
    thus ?thesis
      using assms(2) entry by fastforce
  next
    case Pre
    then obtain pre where pre: "snd e = Pre pre"
      by blast
    define n where n: "n = build_tree'_measure (bs, ω, (k-1), pre)"
    have "0 < k" "pre < length (bs!(k-1))"
      using 1(2) entry pre unfolding wf_tree_input_def sound_ptrs_def sound_pre_ptr_def
      by (smt (verit) mem_Collect_eq nth_mem prod.inject)+
    have "k < length bs"
      using 1(2) unfolding wf_tree_input_def by blast+
    have "foldl (+) 0 (map length (take k bs)) + i - (foldl (+) 0 (map length (take (k-1) bs)) + pre) =
      foldl (+) 0 (map length (take (k-1) bs)) + length (bs!(k-1)) + i - (foldl (+) 0 (map length (take (k-1) bs)) + pre)"
      using foldl_add_nth[of k-1 bs 0] by (simp add: 0 < k k < length bs less_imp_diff_less)
    also have "... = length (bs!(k-1)) + i - pre"
      by simp
    also have "... > 0"
      using pre < length (bs!(k-1)) by auto
    finally have "build_tree'_measure (bs, ω, k, i) - build_tree'_measure (bs, ω, (k-1), pre) > 0"
      by simp
    hence "P bs ω (k-1) pre"
      using 1 n wf_tree_input_pre entry pre zero_less_diff by blast
    thus ?thesis
      using assms(2) entry pre pointer.distinct(5) pointer.inject(1) by presburger
  next
    case PreRed
    then obtain k' pre red ps where prered: "snd e = PreRed (k', pre, red) ps"
      by blast
    have "k' < k" "pre < length (bs!k')"
      using 1(2) entry prered unfolding wf_tree_input_def sound_ptrs_def sound_prered_ptr_def
      apply simp_all
      apply (metis nth_mem)+
      done
    have "red < i"
      using 1(2) entry prered unfolding wf_tree_input_def mono_red_ptr_def by blast
    have "k < length bs" "i < length (bs!k)"
      using 1(2) unfolding wf_tree_input_def by blast+
    define n_pre where n_pre: "n_pre = build_tree'_measure (bs, ω, k', pre)"
    have "0 < length (bs!k') + i - pre"
      by (simp add: pre < length (bs!k') add.commute trans_less_add2)
    also have "... = foldl (+) 0 (map length (take k' bs)) + length (bs!k') + i - (foldl (+) 0 (map length (take k' bs)) + pre)"
      by simp
    also have "...  foldl (+) 0 (map length (take (k'+1) bs)) + i - (foldl (+) 0 (map length (take k' bs)) + pre)"
      using foldl_add_nth_ge[of k' k' bs 0] k < length bs k' < k by simp
    also have "...  foldl (+) 0 (map length (take k bs)) + i - (foldl (+) 0 (map length (take k' bs)) + pre)"
      using foldl_take_mono by (metis Suc_eq_plus1 Suc_leI k' < k add.commute add_le_cancel_left diff_le_mono)
    finally have "build_tree'_measure (bs, ω, k, i) - build_tree'_measure (bs, ω, k', pre) > 0"
      by simp
    hence x: "P bs ω k' pre"
      using 1(1) zero_less_diff by (metis "1.prems" entry prered wf_tree_input_prered_pre)
    define n_red where n_red: "n_red = build_tree'_measure (bs, ω, k, red)"
    have "build_tree'_measure (bs, ω, k, i) - build_tree'_measure (bs, ω, k, red) > 0"
      using red < i by simp
    hence y: "P bs ω k red"
      using "1.hyps" "1.prems" entry prered wf_tree_input_prered_red zero_less_diff by blast
    show ?thesis
      using assms(2) x y entry prered 
      by (smt (verit, best) Pair_inject filter_cong pointer.distinct(5) pointer.inject(2))
  qed
qed

lemma build_tree'_termination:
  assumes "(bs, ω, k, i)  wf_tree_input"
  shows "N ts. build_tree' bs ω k i = Some (Branch N ts)"
proof -
  have "N ts. build_tree' bs ω k i = Some (Branch N ts)"
    apply (induction rule: build_tree'_induct[OF assms(1)])
    subgoal premises IH for bs ω k i
    proof -
      define e where entry: "e = bs!k!i"
      consider (Null) "snd e = Null"
        | (Pre) "pre. snd e = Pre pre"
        | (PreRed) "k' pre red ps. snd e = PreRed (k', pre, red) ps"
        by (metis pointer.exhaust surj_pair)
      thus ?thesis
      proof cases
        case Null
        thus ?thesis
          using build_tree'_simps(1) entry by simp
      next
        case Pre
        then obtain pre where pre: "snd e = Pre pre"
          by blast
        obtain N ts where Nts: "build_tree' bs ω (k-1) pre = Some (Branch N ts)"
          using IH(1) entry pre by blast
        have "build_tree' bs ω k i = Some (Branch N (ts @ [Leaf (ω!(k-1))]))"
          using build_tree'_simps(3) entry pre Nts by simp         
        thus ?thesis
          by simp
      next
        case PreRed
        then obtain k' pre red ps where prered: "snd e = PreRed (k', pre, red) ps"
          by blast
        then obtain N ts where Nts: "build_tree' bs ω k' pre = Some (Branch N ts)"
          using IH(2) entry prered by blast
        obtain t_red where t_red: "build_tree' bs ω k red = Some t_red"
          using IH(3) entry prered Nts by (metis option.exhaust)
        have "build_tree' bs ω k i = Some (Branch N (ts @ [t_red]))"
          using build_tree'_simps(8) entry prered Nts t_red by auto
        thus ?thesis
          by blast
      qed
    qed
    done
  thus ?thesis
    by blast
qed

lemma wf_item_tree_build_tree':
  assumes "(bs, ω, k, i)  wf_tree_input"
  assumes "wf_bins 𝒢 ω bs"
  assumes "build_tree' bs ω k i = Some t"
  shows "wf_item_tree 𝒢 (fst (bs!k!i)) t"
proof -
  have "wf_item_tree 𝒢 (fst (bs!k!i)) t"
    using assms
    apply (induction arbitrary: t rule: build_tree'_induct[OF assms(1)])
    subgoal premises prems for bs ω k i t
    proof -
      define e where entry: "e = bs!k!i"
      have bounds: "k < length bs" "k  length ω" "i < length (bs!k)"
        using prems(4) wf_tree_input_def by force+
      consider (Null) "snd e = Null"
        | (Pre) "pre. snd e = Pre pre"
        | (PreRed) "k' pre red ps. snd e = PreRed (k', pre, red) ps"
        by (metis pointer.exhaust surj_pair)
      thus ?thesis
      proof cases
        case Null
        hence "build_tree' bs ω k i = Some (Branch (lhs_item (fst e)) [])"
          using entry by simp
        have simp: "t = Branch (lhs_item (fst e)) []"
          using build_tree'_simps(1) Null prems(6) entry by simp
        have "sound_ptrs ω bs"
          using prems(4) unfolding wf_tree_input_def by blast
        hence "predicts (fst e)"
          using Null nth_mem entry bounds unfolding sound_ptrs_def sound_null_ptr_def by blast
        hence "dot_item (fst e) = 0"
          unfolding predicts_def by blast
        thus ?thesis
          using simp entry by simp
      next
        case Pre
        then obtain pre where pre: "snd e = Pre pre"
          by blast
        obtain N ts where Nts: "build_tree' bs ω (k-1) pre = Some (Branch N ts)"
          using build_tree'_termination entry pre prems(4) wf_tree_input_pre by blast
        have simp: "build_tree' bs ω k i = Some (Branch N (ts @ [Leaf (ω!(k-1))]))"
          using build_tree'_simps(3) entry pre Nts by simp
        have "sound_ptrs ω bs"
          using prems(4) unfolding wf_tree_input_def by blast
        hence "pre < length (bs!(k-1))"
          using entry pre bounds unfolding sound_ptrs_def sound_pre_ptr_def by (metis nth_mem)
        moreover have "k-1 < length bs"
          by (simp add: bounds less_imp_diff_less)
        ultimately have IH: "wf_item_tree 𝒢 (fst (bs!(k-1)!pre)) (Branch N ts)"
          using prems(1,2,4,5) entry pre Nts by (meson wf_tree_input_pre)
        have scans: "scans ω k (fst (bs!(k-1)!pre)) (fst e)"
          using entry pre bounds sound_ptrs ω bs unfolding sound_ptrs_def sound_pre_ptr_def by simp
        hence *: 
          "lhs_item (fst (bs!(k-1)!pre)) = lhs_item (fst e)"
          "rhs_item (fst (bs!(k-1)!pre)) = rhs_item (fst e)"
          "dot_item (fst (bs!(k-1)!pre)) + 1 = dot_item (fst e)"
          "next_symbol (fst (bs!(k-1)!pre)) = Some (ω!(k-1))"
          unfolding scans_def inc_item_def by (simp_all add: lhs_item_def rhs_item_def)
        have "map root (ts @ [Leaf (ω!(k-1))]) = map root ts @ [ω!(k-1)]"
          by simp
        also have "... = take (dot_item (fst (bs!(k-1)!pre))) (rhs_item (fst (bs!(k-1)!pre))) @ [ω!(k-1)]"
          using IH by simp
        also have "... = take (dot_item (fst (bs!(k-1)!pre))) (rhs_item (fst e)) @ [ω!(k-1)]"
          using *(2) by simp
        also have "... = take (dot_item (fst e)) (rhs_item (fst e))"
          using *(2-4) by (auto simp: next_symbol_def is_complete_def split: if_splits; metis leI take_Suc_conv_app_nth)
        finally have "map root (ts @ [Leaf (ω!(k-1))]) = take (dot_item (fst e)) (rhs_item (fst e))" .
        hence "wf_item_tree 𝒢 (fst e) (Branch N (ts @ [Leaf (ω!(k-1))]))"
          using IH *(1) by simp
        thus ?thesis
          using entry prems(6) simp by auto
      next
        case PreRed
        then obtain k' pre red ps where prered: "snd e = PreRed (k', pre, red) ps"
          by blast
        obtain N ts where Nts: "build_tree' bs ω k' pre = Some (Branch N ts)"
          using build_tree'_termination entry prems(4) prered wf_tree_input_prered_pre by blast
        obtain N_red ts_red where Nts_red: "build_tree' bs ω k red = Some (Branch N_red ts_red)"
          using build_tree'_termination entry prems(4) prered wf_tree_input_prered_red by blast
        have simp: "build_tree' bs ω k i = Some (Branch N (ts @ [Branch N_red ts_red]))"
          using build_tree'_simps(8) entry prered Nts Nts_red by auto
        have "sound_ptrs ω bs"
          using prems(4) wf_tree_input_def by fastforce
        have bounds': "k' < k" "pre < length (bs!k')" "red < length (bs!k)"
          using prered entry bounds sound_ptrs ω bs
          unfolding sound_prered_ptr_def sound_ptrs_def by fastforce+
        have completes: "completes k (fst (bs!k'!pre)) (fst e) (fst (bs!k!red))"
          using prered entry bounds sound_ptrs ω bs
          unfolding sound_ptrs_def sound_prered_ptr_def by force
        have *: 
          "lhs_item (fst (bs!k'!pre)) = lhs_item (fst e)"
          "rhs_item (fst (bs!k'!pre)) = rhs_item (fst e)"
          "dot_item (fst (bs!k'!pre)) + 1 = dot_item (fst e)"
          "next_symbol (fst (bs!k'!pre)) = Some (lhs_item (fst (bs!k!red)))"
          "is_complete (fst (bs!k!red))"
          using completes unfolding completes_def inc_item_def
          by (auto simp: lhs_item_def rhs_item_def is_complete_def)
        have "(bs, ω, k', pre)  wf_tree_input"
          using wf_tree_input_prered_pre[OF prems(4) entry prered] by blast
        hence IH_pre: "wf_item_tree 𝒢 (fst (bs!k'!pre)) (Branch N ts)"
          using prems(2)[OF entry prered _ prems(5)] Nts bounds(1,2) order_less_trans prems(6) by blast
        have "(bs, ω, k, red)  wf_tree_input"
          using wf_tree_input_prered_red[OF prems(4) entry prered] by blast   
        hence IH_r: "wf_item_tree 𝒢 (fst (bs!k!red)) (Branch N_red ts_red)"
          using bounds'(3) entry prems(3,5,6) prered Nts_red by blast
        have "map root (ts @ [Branch N_red ts_red]) = map root ts @ [root (Branch N_red ts)]"
          by simp
        also have "... = take (dot_item (fst (bs!k'!pre))) (rhs_item (fst (bs!k'!pre))) @ [root (Branch N_red ts)]"
          using IH_pre by simp
        also have "... = take (dot_item (fst (bs!k'!pre))) (rhs_item (fst (bs!k'!pre))) @ [lhs_item (fst (bs!k!red))]"
          using IH_r by simp
        also have "... = take (dot_item (fst e)) (rhs_item (fst e))"
          using * by (auto simp: next_symbol_def is_complete_def split: if_splits; metis leI take_Suc_conv_app_nth)
        finally have roots: "map root (ts @ [Branch N_red ts]) = take (dot_item (fst e)) (rhs_item (fst e))" by simp
        have "wf_item 𝒢 ω (fst (bs!k!red))"
          using bounds bounds'(3) prems(5) wf_bins_def wf_bin_def wf_bin_items_def
          by (metis items_def length_map nth_map nth_mem)
        moreover have "N_red = lhs_item (fst (bs!k!red))"
          using IH_r by fastforce
        moreover have "map root ts_red = rhs_item (fst (bs!k!red))"
          using IH_r *(5) by (auto simp: is_complete_def)
        ultimately have "r  set ( 𝒢). N_red = lhs_rule r  map root ts_red = rhs_rule r"
          unfolding wf_item_def rhs_item_def lhs_item_def by blast
        hence "wf_rule_tree 𝒢 (Branch N_red ts_red)"
          using IH_r by simp
        hence "wf_item_tree 𝒢 (fst (bs!k!i)) (Branch N (ts @ [Branch N_red ts_red]))"
          using "*"(1) roots IH_pre entry by simp
        thus ?thesis
          using Nts_red prems(6) simp by auto
      qed
    qed
    done
  thus ?thesis
    using assms(2) by blast
qed

lemma wf_yield_build_tree':
  assumes "(bs, ω, k, i)  wf_tree_input"
  assumes "wf_bins 𝒢 ω bs"
  assumes "build_tree' bs ω k i = Some t"
  shows "wf_yield ω (fst (bs!k!i)) t"
proof -
  have "wf_yield ω (fst (bs!k!i)) t"
    using assms
    apply (induction arbitrary: t rule: build_tree'_induct[OF assms(1)])
    subgoal premises prems for bs ω k i t
    proof -
      define e where entry: "e = bs!k!i"
      have bounds: "k < length bs" "k  length ω" "i < length (bs!k)"
        using prems(4) wf_tree_input_def by force+
      consider (Null) "snd e = Null"
        | (Pre) "pre. snd e = Pre pre"
        | (PreRed) "k' pre red reds. snd e = PreRed (k', pre, red) reds"
        by (metis pointer.exhaust surj_pair)
      thus ?thesis
      proof cases
        case Null
        hence "build_tree' bs ω k i = Some (Branch (lhs_item (fst e)) [])"
          using entry by simp
        have simp: "t = Branch (lhs_item (fst e)) []"
          using build_tree'_simps(1) Null prems(6) entry by simp
        have "sound_ptrs ω bs"
          using prems(4) unfolding wf_tree_input_def by blast
        hence "predicts (fst e)"
          using Null bounds nth_mem entry unfolding sound_ptrs_def sound_null_ptr_def by blast
        thus ?thesis
          unfolding wf_yield_def predicts_def using simp entry by (auto simp: slice_empty)
      next
        case Pre
        then obtain pre where pre: "snd e = Pre pre"
          by blast
        obtain N ts where Nts: "build_tree' bs ω (k-1) pre = Some (Branch N ts)"
          using build_tree'_termination entry pre prems(4) wf_tree_input_pre by blast
        have simp: "build_tree' bs ω k i = Some (Branch N (ts @ [Leaf (ω!(k-1))]))"
          using build_tree'_simps(3) entry pre Nts by simp
        have "sound_ptrs ω bs"
          using prems(4) unfolding wf_tree_input_def by blast
        hence bounds': "k > 0" "pre < length (bs!(k-1))"
          using entry pre bounds unfolding sound_ptrs_def sound_pre_ptr_def by (metis nth_mem)+
        moreover have "k-1 < length bs"
          by (simp add: bounds less_imp_diff_less)
        ultimately have IH: "wf_yield ω (fst (bs!(k-1)!pre)) (Branch N ts)"
          using prems(1) entry pre Nts wf_tree_input_pre prems(4,5,6) by fastforce
        have scans: "scans ω k (fst (bs!(k-1)!pre)) (fst e)"
          using entry pre bounds sound_ptrs ω bs unfolding sound_ptrs_def sound_pre_ptr_def by simp
        have wf: 
          "start_item (fst (bs!(k-1)!pre))  end_item (fst (bs!(k-1)!pre))"
          "end_item (fst (bs!(k-1)!pre)) = k-1"
          "end_item (fst e) = k"
          using entry prems(5) bounds' bounds unfolding wf_bins_def wf_bin_def wf_bin_items_def items_def wf_item_def
          by (auto, meson less_imp_diff_less nth_mem)
        have "yield (Branch N (ts @ [Leaf (ω!(k-1))])) = concat (map yield (ts @ [Leaf (ω!(k-1))]))"
          by simp
        also have "... = concat (map yield ts) @ [ω!(k-1)]"
          by simp
        also have "... = slice ω (start_item (fst (bs!(k-1)!pre))) (end_item (fst (bs!(k-1)!pre))) @ [ω!(k-1)]"
          using IH by (simp add: wf_yield_def)
        also have "... = slice ω (start_item (fst (bs!(k-1)!pre))) (end_item (fst (bs!(k-1)!pre)) + 1)"
          using slice_append_nth wf k > 0
          by (metis One_nat_def Suc_pred bounds(2) le_neq_implies_less lessI less_imp_diff_less)
        also have "... = slice ω (start_item (fst e)) (end_item (fst (bs!(k-1)!pre)) + 1)"
          using scans unfolding scans_def inc_item_def by simp
        also have "... = slice ω (start_item (fst e)) k"
          using scans wf unfolding scans_def by (metis Suc_diff_1 Suc_eq_plus1 bounds'(1))
        also have "... = slice ω (start_item (fst e)) (end_item (fst e))"
          using wf by auto
        finally show ?thesis
          using wf_yield_def entry prems(6) simp by force
      next
        case PreRed
        then obtain k' pre red ps where prered: "snd e = PreRed (k', pre, red) ps"
          by blast
        obtain N ts where Nts: "build_tree' bs ω k' pre = Some (Branch N ts)"
          using build_tree'_termination entry prems(4) prered wf_tree_input_prered_pre by blast
        obtain N_red ts_red where Nts_red: "build_tree' bs ω k red = Some (Branch N_red ts_red)"
          using build_tree'_termination entry prems(4) prered wf_tree_input_prered_red by blast
        have simp: "build_tree' bs ω k i = Some (Branch N (ts @ [Branch N_red ts_red]))"
          using build_tree'_simps(8) entry prered Nts Nts_red by auto
        have "sound_ptrs ω bs"
          using prems(4) wf_tree_input_def by fastforce
        have bounds': "k' < k" "pre < length (bs!k')" "red < length (bs!k)"
          using prered entry bounds sound_ptrs ω bs
          unfolding sound_ptrs_def sound_prered_ptr_def by fastforce+
        have completes: "completes k (fst (bs!k'!pre)) (fst e) (fst (bs!k!red))"
          using prered entry bounds sound_ptrs ω bs
          unfolding sound_ptrs_def sound_prered_ptr_def by fastforce
        have "(bs, ω, k', pre)  wf_tree_input"
          using wf_tree_input_prered_pre[OF prems(4) entry prered] by blast
        hence IH_pre: "wf_yield ω (fst (bs!k'!pre)) (Branch N ts)"
          using prems(2)[OF entry prered _ prems(5)] Nts bounds'(1,2) prems(6)
          by (meson dual_order.strict_trans1 nat_less_le)
        have "(bs, ω, k, red)  wf_tree_input"
          using wf_tree_input_prered_red[OF prems(4) entry prered] by blast
        hence IH_r: "wf_yield ω (fst (bs!k!red)) (Branch N_red ts_red)"
          using bounds(3) entry prems(3,5,6) prered Nts_red by blast
        have wf1: 
          "start_item (fst (bs!k'!pre))  end_item (fst (bs!k'!pre))"
          "start_item (fst (bs!k!red))  end_item (fst (bs!k!red))"
          using prems(5) bounds bounds' unfolding wf_bins_def wf_bin_def wf_bin_items_def items_def wf_item_def
          by (metis length_map nth_map nth_mem order.strict_trans)+
        have wf2:
          "end_item (fst (bs!k!red)) = k"
          "end_item (fst (bs!k!i)) = k"
          using prems(5) bounds bounds' unfolding wf_bins_def wf_bin_def wf_bin_items_def items_def by simp_all
        have "yield (Branch N (ts @ [Branch N_red ts_red])) = concat (map yield (ts @ [Branch N_red ts_red]))"
          by (simp add: Nts_red)
        also have "... = concat (map yield ts) @ yield (Branch N_red ts_red)"
          by simp
        also have "... = slice ω (start_item (fst (bs!k'!pre))) (end_item (fst (bs!k'!pre))) @ 
          slice ω (start_item (fst (bs!k!red))) (end_item (fst (bs!k!red)))"
          using IH_pre IH_r by (simp add: wf_yield_def)
        also have "... = slice ω (start_item (fst (bs!k'!pre))) (end_item (fst (bs!k!red)))"
          using slice_concat wf1 completes_def completes by (metis (no_types, lifting))
        also have "... = slice ω (start_item (fst e)) (end_item (fst (bs!k!red)))"
          using completes unfolding completes_def inc_item_def by simp
        also have "... = slice ω (start_item (fst e)) (end_item (fst e))"
          using wf2 entry by presburger
        finally show ?thesis
          using wf_yield_def entry prems(6) simp by force
      qed
    qed
    done
  thus ?thesis
    using assms(2) by blast
qed

theorem wf_rule_root_yield_build_tree:
  assumes "wf_bins 𝒢 ω bs" "sound_ptrs ω bs" "mono_red_ptr bs" "length bs = length ω + 1"
  assumes "build_tree 𝒢 ω bs = Some t"
  shows "wf_rule_tree 𝒢 t  root t = 𝔖 𝒢  yield t = ω"
proof -
  let ?k = "length bs - 1"
  define finished where finished_def: "finished = filter_with_index (is_finished 𝒢 ω) (items (bs!?k))"
  then obtain x i where *: "(x,i)  set finished" "Some t = build_tree' bs ω ?k i"
    using assms(5) unfolding finished_def build_tree_def by (auto simp: Let_def split: list.splits, presburger)
  have k: "?k < length bs" "?k  length ω"
    using assms(4) by simp_all
  have i: "i < length (bs!?k)"
    using index_filter_with_index_lt_length * items_def finished_def by (metis length_map)
  have x: "x = fst (bs!?k!i)"
    using * i filter_with_index_nth items_def nth_map finished_def by metis
  have finished: "is_finished 𝒢 ω x"
    using * filter_with_index_P finished_def by metis
  have wf_trees_input: "(bs, ω, ?k, i)  wf_tree_input"
    unfolding wf_tree_input_def using assms(2,3) i k by blast
  hence wf_item_tree: "wf_item_tree 𝒢 x t"
    using wf_item_tree_build_tree' assms(1,2) i k(1) x *(2) by metis
  have wf_item: "wf_item 𝒢 ω (fst (bs!?k!i))"
    using k(1) i assms(1) unfolding wf_bins_def wf_bin_def wf_bin_items_def by (simp add: items_def)
  obtain N ts where t: "t = Branch N ts"
    by (metis *(2) build_tree'_termination option.inject wf_trees_input)
  hence "N = lhs_item x"
    "map root ts = rhs_item x"
    using finished wf_item_tree by (auto simp: is_finished_def is_complete_def)
  hence "r  set ( 𝒢). N = lhs_rule r  map root ts = rhs_rule r"
    using wf_item x unfolding wf_item_def rhs_item_def lhs_item_def by blast
  hence wf_rule: "wf_rule_tree 𝒢 t"
    using wf_item_tree t by simp
  have root: "root t = 𝔖 𝒢"
    using finished t N = lhs_item x by (auto simp: is_finished_def)
  have "yield t = slice ω (start_item (fst (bs!?k!i))) (end_item (fst (bs!?k!i)))"
    using k i assms(1) wf_trees_input wf_yield_build_tree' wf_yield_def *(2) by (metis (no_types, lifting))
  hence yield: "yield t = ω"
    using finished x unfolding is_finished_def by simp
  show ?thesis
    using * wf_rule root yield assms(4) unfolding build_tree_def by simp
qed

corollary wf_rule_root_yield_build_tree_EarleyL:
  assumes "ε_free 𝒢"
  assumes "build_tree 𝒢 ω (EarleyL 𝒢 ω) = Some t"
  shows "wf_rule_tree 𝒢 t  root t = 𝔖 𝒢  yield t = ω"
  using assms wf_rule_root_yield_build_tree wf_bins_EarleyL sound_mono_ptrs_EarleyL EarleyL_def
    length_EarleyL_bins length_bins_InitL by (metis ε_free_impl_nonempty_derives le_refl)

theorem correctness_build_tree_EarleyL:
  assumes "is_word 𝒢 ω" "ε_free 𝒢"
  shows "(t. build_tree 𝒢 ω (EarleyL 𝒢 ω) = Some t)  𝒢  [𝔖 𝒢] * ω" (is "?L  ?R")
proof standard
  assume *: ?L
  let ?k = "length (EarleyL 𝒢 ω) - 1"
  define finished where finished_def: "finished = filter_with_index (is_finished 𝒢 ω) (items ((EarleyL 𝒢 ω)!?k))"
  then obtain t x i where *: "(x,i)  set finished" "Some t = build_tree' (EarleyL 𝒢 ω) ω ?k i"
    using * unfolding finished_def build_tree_def by (auto simp: Let_def split: list.splits, presburger)
  have k: "?k < length (EarleyL 𝒢 ω)" "?k  length ω"
    by (simp_all add: EarleyL_def assms(1))
  have i: "i < length ((EarleyL 𝒢 ω) ! ?k)"
    using index_filter_with_index_lt_length * items_def finished_def by (metis length_map)
  have x: "x = fst ((EarleyL 𝒢 ω)!?k!i)"
    using * i filter_with_index_nth items_def nth_map finished_def by metis
  have finished: "is_finished 𝒢 ω x"
    using * filter_with_index_P finished_def by metis
  moreover have "x  set (items ((EarleyL 𝒢 ω) ! ?k))"
    using x by (auto simp: items_def; metis One_nat_def i imageI nth_mem)
  ultimately have "recognizing (bins (EarleyL 𝒢 ω)) 𝒢 ω"
    by (meson k(1) kth_bin_sub_bins recognizing_def subsetD)
  thus ?R
    using soundness_EarleyL by blast
next
  assume *: ?R
  let ?k = "length (EarleyL 𝒢 ω) - 1"
  define finished where finished_def: "finished = filter_with_index (is_finished 𝒢 ω) (items ((EarleyL 𝒢 ω)!?k))"
  have "recognizing (bins (EarleyL 𝒢 ω)) 𝒢 ω"
    using assms * completeness_EarleyL by blast
  moreover have "?k = length ω"
    by (simp add: EarleyL_def assms(1))
  ultimately have "x  set (items ((EarleyL 𝒢 ω)!?k)). is_finished 𝒢 ω x"
    unfolding recognizing_def using assms(1) is_finished_def wf_bins_EarleyL wf_item_in_kth_bin by metis
  then obtain x i xs where xis: "finished = (x,i)#xs"
    using filter_with_index_Ex_first by (metis finished_def)
  hence simp: "build_tree 𝒢 ω (EarleyL 𝒢 ω) = build_tree' (EarleyL 𝒢 ω) ω ?k i"
    unfolding build_tree_def finished_def by auto
  have "(x,i)  set finished"
    using xis by simp
  hence "i < length ((EarleyL 𝒢 ω)!?k)"
    using index_filter_with_index_lt_length by (metis finished_def items_def length_map)
  moreover have "?k < length (EarleyL 𝒢 ω)"
    by (simp add: EarleyL_def assms(1))
  ultimately have "(EarleyL 𝒢 ω, ω, ?k, i)  wf_tree_input"
    unfolding wf_tree_input_def using sound_mono_ptrs_EarleyL assms ε_free_impl_nonempty_derives
    using length (EarleyL 𝒢 ω) - 1 = length ω by auto
  then obtain N ts where "build_tree' (EarleyL 𝒢 ω) ω ?k i = Some (Branch N ts)"
    using build_tree'_termination by blast
  thus ?L
    using simp by simp
qed

end