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'. i≠j ⟶ 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). i≠j ⟶ 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: "i≠j"
          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: "i≠j"
            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: "idx≠k"
    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