Theory Equality_Saturation_Checker

section ‹Equality-saturation explanation certificates›

theory Equality_Saturation_Checker
  imports
    First_Order_Rewriting.Trs
    First_Order_Terms.Term_Impl
begin

text ‹
  This development deliberately reuses the first-order terms, substitutions,
  positions, and contexts from the AFP session
  sessionFirst_Order_Terms.  It uses the rewrite relation from
  sessionFirst_Order_Rewriting.  In particular, the semantic target of
  the checker is the existing conversion relation
  term(rstep (set R))*; no separate term language or
  equational calculus is introduced here.

  What is specific to equality saturation is the certificate boundary.  A
  certificate is a flat path whose steps either apply a numbered input rule at
  an AFP position, or reuse a numbered equality recorded by an earlier checked
  e-class merge.  Recorded merges are concrete term equalities, as in an
  e-graph, and therefore need no substitution when reused.
›

datatype direction = Forward | Backward

fun orient_pair :: "direction  'a × 'a  'a × 'a" where
  "orient_pair Forward ab = ab"
| "orient_pair Backward (a, b) = (b, a)"

datatype ('f, 'v) certificate_step =
    Rule_At pos nat direction "('f, 'v) subst"
  | Merge_At pos nat direction

fun apply_step ::
  "('f, 'v) rule list  ('f, 'v) rule list 
    ('f, 'v) certificate_step  ('f, 'v) term 
    ('f, 'v) term option" where
  "apply_step R Γ (Rule_At p i d σ) t =
     (if i < length R  p  poss t 
          t |_ p = fst (orient_pair d (R ! i))  σ
      then Some (replace_at t p (snd (orient_pair d (R ! i))  σ))
      else None)"
| "apply_step R Γ (Merge_At p i d) t =
     (if i < length Γ  p  poss t 
          t |_ p = fst (orient_pair d (Γ ! i))
      then Some (replace_at t p (snd (orient_pair d (Γ ! i))))
      else None)"

fun apply_steps ::
  "('f, 'v) rule list  ('f, 'v) rule list 
    ('f, 'v) certificate_step list  ('f, 'v) term 
    ('f, 'v) term option" where
  "apply_steps R Γ [] t = Some t"
| "apply_steps R Γ (st # sts) t =
     (case apply_step R Γ st t of
        None  None
      | Some u  apply_steps R Γ sts u)"

definition check_explanation ::
  "('f, 'v) rule list  ('f, 'v) rule list 
    ('f, 'v) certificate_step list  ('f, 'v) term 
    ('f, 'v) term  bool" where
  "check_explanation R Γ sts t u 
     apply_steps R Γ sts t = Some u"

subsection ‹Soundness in the AFP rewrite relation›

lemma lift_conversion_at_position:
  assumes p: "p  poss t"
    and sub: "t |_ p = s"
    and conv: "(s, u)  (rstep R)*"
  shows "(t, replace_at t p u)  (rstep R)*"
proof -
  have "((ctxt_of_pos_term p t)s,
         (ctxt_of_pos_term p t)u)  (rstep R)*"
    by (rule conversion_ctxt_closed[OF conv])
  moreover have "(ctxt_of_pos_term p t)s = t"
    using ctxt_supt_id[OF p] sub by simp
  ultimately show ?thesis by simp
qed

lemma oriented_rule_conversion:
  assumes i: "i < length R"
  shows "(fst (orient_pair d (R ! i))  σ,
          snd (orient_pair d (R ! i))  σ)
          (rstep (set R))*"
proof -
  obtain l r where lr: "R ! i = (l, r)" by (cases "R ! i")
  have "R ! i  set R" by (rule nth_mem[OF i])
  then have mem: "(l, r)  set R" using lr by simp
  have step: "(l  σ, r  σ)  rstep (set R)"
    by (rule rstep_subst[OF rstep_rule[OF mem]])
  show ?thesis
  proof (cases d)
    case Forward
    with lr step show ?thesis
      unfolding conversion_def by auto
  next
    case Backward
    with lr step show ?thesis
      unfolding conversion_def by auto
  qed
qed

lemma apply_step_sound:
  assumes merges:
    "ab  set Γ. (fst ab, snd ab)  (rstep (set R))*"
    and step: "apply_step R Γ st t = Some u"
  shows "(t, u)  (rstep (set R))*"
proof (cases st)
  case (Rule_At p i d σ)
  from step Rule_At have i: "i < length R" and p: "p  poss t"
    and sub: "t |_ p = fst (orient_pair d (R ! i))  σ"
    and u: "u = replace_at t p (snd (orient_pair d (R ! i))  σ)"
    by (auto split: if_splits)
  have "(fst (orient_pair d (R ! i))  σ,
         snd (orient_pair d (R ! i))  σ)
         (rstep (set R))*"
    by (rule oriented_rule_conversion[OF i])
  from lift_conversion_at_position[OF p sub this] u show ?thesis by simp
next
  case (Merge_At p i d)
  from step Merge_At have i: "i < length Γ" and p: "p  poss t"
    and sub: "t |_ p = fst (orient_pair d (Γ ! i))"
    and u: "u = replace_at t p (snd (orient_pair d (Γ ! i)))"
    by (auto split: if_splits)
  have mem: "Γ ! i  set Γ" by (rule nth_mem[OF i])
  obtain a b where ab: "Γ ! i = (a, b)" by (cases "Γ ! i")
  have base:
    "(a, b)  (rstep (set R))*"
    using merges mem ab by fastforce
  have oriented:
    "(fst (orient_pair d (Γ ! i)), snd (orient_pair d (Γ ! i)))
       (rstep (set R))*"
  proof (cases d)
    case Forward
    with base ab show ?thesis by simp
  next
    case Backward
    have "(b, a)  (rstep (set R))*"
      using base
      by (rule conversion_sym[unfolded sym_def, rule_format])
    with Backward ab show ?thesis by simp
  qed
  from lift_conversion_at_position[OF p sub oriented] u show ?thesis by simp
qed

lemma apply_steps_sound:
  assumes merges:
    "ab  set Γ. (fst ab, snd ab)  (rstep (set R))*"
    and run: "apply_steps R Γ sts t = Some u"
  shows "(t, u)  (rstep (set R))*"
  using run
proof (induction sts arbitrary: t)
  case Nil
  then show ?case by simp
next
  case (Cons st sts)
  from Cons.prems obtain v where
    first: "apply_step R Γ st t = Some v" and
    rest: "apply_steps R Γ sts v = Some u"
    by (auto split: option.splits)
  have tv: "(t, v)  (rstep (set R))*"
    by (rule apply_step_sound[OF merges first])
  have vu: "(v, u)  (rstep (set R))*"
    by (rule Cons.IH[OF rest])
  from tv vu show ?case
    unfolding conversion_def by (rule rtrancl_trans)
qed

theorem check_explanation_sound:
  assumes "ab  set Γ.
      (fst ab, snd ab)  (rstep (set R))*"
    and "check_explanation R Γ sts t u"
  shows "(t, u)  (rstep (set R))*"
  using apply_steps_sound[OF assms(1) assms(2)[unfolded check_explanation_def]] .

corollary check_rule_explanation_sound:
  assumes "check_explanation R [] sts t u"
  shows "(t, u)  (rstep (set R))*"
  by (rule check_explanation_sound[OF _ assms]) simp

end