Theory Bounded_Certificate_Search

section ‹A certificate-producing bounded search›

theory Bounded_Certificate_Search
  imports Equality_Saturation_Checker
begin

text ‹
  The trusted result in this theory is independent of matching and scheduling.
  An arbitrary generator proposes certificate steps; only proposals accepted by
  constapply_step enter the frontier.  Consequently every path emitted by
  the bounded search is accepted by the independent checker.
›

definition step_children ::
  "('f, 'v) rule list  ('f, 'v) rule list 
    (('f, 'v) term  ('f, 'v) certificate_step list) 
    ('f, 'v) term  ('f, 'v) certificate_step list 
    (('f, 'v) term × ('f, 'v) certificate_step list) list" where
  "step_children R Γ gen u sts =
     concat (map (λst. case apply_step R Γ st u of
                         None  []
                       | Some u'  [(u', sts @ [st])]) (gen u))"

definition expand ::
  "('f, 'v) rule list  ('f, 'v) rule list 
    (('f, 'v) term  ('f, 'v) certificate_step list) 
    (('f, 'v) term × ('f, 'v) certificate_step list) 
    (('f, 'v) term × ('f, 'v) certificate_step list) list" where
  "expand R Γ gen p = step_children R Γ gen (fst p) (snd p)"

fun iterate_search ::
  "('f, 'v) rule list  ('f, 'v) rule list 
    (('f, 'v) term  ('f, 'v) certificate_step list)  nat 
    (('f, 'v) term × ('f, 'v) certificate_step list) list 
    (('f, 'v) term × ('f, 'v) certificate_step list) list" where
  "iterate_search R Γ gen 0 F = F"
| "iterate_search R Γ gen (Suc n) F =
     iterate_search R Γ gen n
       (F @ concat (map (expand R Γ gen) F))"

definition run_bounded_search ::
  "('f, 'v) rule list  ('f, 'v) rule list 
    (('f, 'v) term  ('f, 'v) certificate_step list)  nat 
    ('f, 'v) term 
    (('f, 'v) term × ('f, 'v) certificate_step list) list" where
  "run_bounded_search R Γ gen n t =
    iterate_search R Γ gen n [(t, [])]"

lemma apply_steps_append:
  "apply_steps R Γ (as @ bs) t =
     (case apply_steps R Γ as t of
        None  None
      | Some u  apply_steps R Γ bs u)"
  by (induction as arbitrary: t) (auto split: option.splits)

lemma apply_steps_snoc:
  assumes "apply_steps R Γ sts t = Some u"
    and "apply_step R Γ st u = Some u'"
  shows "apply_steps R Γ (sts @ [st]) t = Some u'"
  using assms by (auto simp: apply_steps_append)

lemma step_children_accepted:
  assumes "apply_steps R Γ sts t = Some u"
    and "(u', sts')  set (step_children R Γ gen u sts)"
  shows "apply_steps R Γ sts' t = Some u'"
proof -
  from assms(2) obtain st where
    emit: "(u', sts') 
      set (case apply_step R Γ st u of
             None  []
           | Some v  [(v, sts @ [st])])"
    unfolding step_children_def by auto
  then obtain v where
    accepted: "apply_step R Γ st u = Some v" and
    pair: "(u', sts') = (v, sts @ [st])"
    by (auto split: option.splits)
  from apply_steps_snoc[OF assms(1) accepted] pair show ?thesis by simp
qed

lemma expand_accepted:
  assumes "apply_steps R Γ (snd p) t = Some (fst p)"
    and "q  set (expand R Γ gen p)"
  shows "apply_steps R Γ (snd q) t = Some (fst q)"
proof -
  obtain u sts where q: "q = (u, sts)" by (cases q)
  from assms(2) q have
    "(u, sts)  set (step_children R Γ gen (fst p) (snd p))"
    by (simp add: expand_def)
  from step_children_accepted[OF assms(1) this] q show ?thesis by simp
qed

lemma iterate_search_accepted:
  assumes "p  set F.
      apply_steps R Γ (snd p) t = Some (fst p)"
  shows "p  set (iterate_search R Γ gen n F).
      apply_steps R Γ (snd p) t = Some (fst p)"
  using assms
proof (induction n arbitrary: F)
  case 0
  then show ?case by simp
next
  case (Suc n)
  let ?F = "F @ concat (map (expand R Γ gen) F)"
  have "p  set ?F.
      apply_steps R Γ (snd p) t = Some (fst p)"
  proof
    fix p
    assume "p  set ?F"
    then consider "p  set F"
      | "p  set (concat (map (expand R Γ gen) F))"
      by auto
    then show "apply_steps R Γ (snd p) t = Some (fst p)"
    proof cases
      case 1
      then show ?thesis using Suc.prems by blast
    next
      case 2
      then obtain q where
        "q  set F" and "p  set (expand R Γ gen q)"
        by auto
      then show ?thesis using expand_accepted Suc.prems by blast
    qed
  qed
  from Suc.IH[OF this] show ?case by simp
qed

theorem run_bounded_search_accepted:
  assumes "(u, sts)  set (run_bounded_search R Γ gen n t)"
  shows "check_explanation R Γ sts t u"
proof -
  have "p  set [(t, [])].
      apply_steps R Γ (snd p) t = Some (fst p)"
    by simp
  from assms iterate_search_accepted[OF this]
  have "apply_steps R Γ sts t = Some u"
    by (fastforce simp: run_bounded_search_def)
  then show ?thesis by (simp add: check_explanation_def)
qed

corollary run_bounded_search_sound:
  assumes merges: "ab  set Γ.
      (fst ab, snd ab)  (rstep (set R))*"
    and result: "(u, sts)  set (run_bounded_search R Γ gen n t)"
  shows "(t, u)  (rstep (set R))*"
  by (rule check_explanation_sound[
        OF merges run_bounded_search_accepted[OF result]])

definition find_explanation ::
  "('f, 'v) rule list  ('f, 'v) rule list 
    (('f, 'v) term  ('f, 'v) certificate_step list)  nat 
    ('f, 'v) term  ('f, 'v) term 
    ('f, 'v) certificate_step list option" where
  "find_explanation R Γ gen n t u =
     (case filter (λp. fst p = u)
       (run_bounded_search R Γ gen n t) of
        []  None
      | p # _  Some (snd p))"

theorem find_explanation_accepted:
  assumes "find_explanation R Γ gen n t u = Some sts"
  shows "check_explanation R Γ sts t u"
proof -
  from assms have
    "filter (λp. fst p = u)
      (run_bounded_search R Γ gen n t)  []"
    unfolding find_explanation_def by (auto split: list.splits)
  then obtain p ps where
    filter: "filter (λp. fst p = u)
      (run_bounded_search R Γ gen n t) = p # ps"
    by (cases "filter (λp. fst p = u)
          (run_bounded_search R Γ gen n t)") auto
  from assms filter have snd_p: "snd p = sts"
    unfolding find_explanation_def by simp
  have in_filter:
    "p  set (filter (λp. fst p = u)
      (run_bounded_search R Γ gen n t))"
    using filter by simp
  then have mem:
    "p  set (run_bounded_search R Γ gen n t)" by simp
  from in_filter have fst_p: "fst p = u" by simp
  from fst_p snd_p have p: "p = (u, sts)" by (cases p) simp
  from mem p have
    "(u, sts)  set (run_bounded_search R Γ gen n t)" by simp
  then show ?thesis by (rule run_bounded_search_accepted)
qed

corollary find_explanation_sound:
  assumes "ab  set Γ.
      (fst ab, snd ab)  (rstep (set R))*"
    and "find_explanation R Γ gen n t u = Some sts"
  shows "(t, u)  (rstep (set R))*"
  by (rule check_explanation_sound[OF assms(1)
        find_explanation_accepted[OF assms(2)]])

end