Theory Certified_Acyclic_EGraph
section ‹Certified acyclic e-graphs›
theory Certified_Acyclic_EGraph
imports Acyclic_EGraph_Extraction
begin
text ‹
The dynamic program establishes global optimality over the represented terms
of an acyclic e-class DAG. This theory additionally checks that every e-node
in a class is equal to a canonical e-node for that class.
Canonical terms are built bottom-up from the first e-node of every class.
The certificate list for a class is aligned with its e-node list; each flat
explanation must transform the canonical term into the corresponding e-node
instantiated with canonical child terms. Congruence of AFP conversions then
extends these finite certificates to every recursive combination represented
by the DAG.
›
type_synonym 'f dag_class_certificates =
"('f, unit) certificate_step list list"
type_synonym 'f dag_certificates =
"'f dag_class_certificates list"
fun canonical_prefix ::
"'f acyclic_egraph ⇒ nat ⇒ ('f, unit) term list"
where
"canonical_prefix G 0 = []"
| "canonical_prefix G (Suc i) =
(let memo = canonical_prefix G i
in memo @ [instantiate_enode memo (hd (G ! i))])"
definition canonical_eclass ::
"'f acyclic_egraph ⇒ nat ⇒ ('f, unit) term option"
where
"canonical_eclass G i =
(if wf_acyclic_egraph G ∧ i < length G
then Some (canonical_prefix G (length G) ! i)
else None)"
definition check_dag_class ::
"('f, unit) rule list ⇒ ('f, unit) term list ⇒
'f dag_eclass ⇒ 'f dag_class_certificates ⇒ bool"
where
"check_dag_class R memo cls certs ⟷
cls ≠ [] ∧
list_all2
(λnode sts.
check_explanation R [] sts
(instantiate_enode memo (hd cls))
(instantiate_enode memo node))
cls certs"
definition check_certified_egraph ::
"('f, unit) rule list ⇒ 'f acyclic_egraph ⇒
'f dag_certificates ⇒ bool"
where
"check_certified_egraph R G certs ⟷
wf_acyclic_egraph G ∧
length certs = length G ∧
list_all
(λi. check_dag_class R (canonical_prefix G i)
(G ! i) (certs ! i))
[0..<length G]"
lemma canonical_prefix_length [simp]:
"length (canonical_prefix G n) = n"
by (induction n) (simp_all add: Let_def)
lemma canonical_prefix_nth_stable:
assumes "j < n"
shows "canonical_prefix G n ! j = canonical_prefix G (Suc j) ! j"
using assms
proof (induction n)
case 0
then show ?case by simp
next
case (Suc n)
show ?case
proof (cases "j = n")
case True
then show ?thesis by simp
next
case False
with Suc.prems have jn: "j < n" by simp
then have "j < length (canonical_prefix G n)" by simp
then have "canonical_prefix G (Suc n) ! j = canonical_prefix G n ! j"
unfolding canonical_prefix.simps Let_def
by (rule nth_append_left)
also have "… = canonical_prefix G (Suc j) ! j"
by (rule Suc.IH[OF jn])
finally show ?thesis .
qed
qed
lemma canonical_prefix_step:
"canonical_prefix G (Suc i) ! i =
instantiate_enode (canonical_prefix G i) (hd (G ! i))"
proof -
let ?memo = "canonical_prefix G i"
have len: "i = length ?memo" by simp
have "(?memo @ [instantiate_enode ?memo (hd (G ! i))]) ! i =
instantiate_enode ?memo (hd (G ! i))"
using len by (metis nth_append_length)
then show ?thesis by (simp add: Let_def)
qed
lemma checked_egraph_wf:
"check_certified_egraph R G certs ⟹ wf_acyclic_egraph G"
unfolding check_certified_egraph_def by simp
lemma checked_dag_class_at:
assumes checked: "check_certified_egraph R G certs"
and i: "i < length G"
shows "check_dag_class R (canonical_prefix G i)
(G ! i) (certs ! i)"
using checked i
unfolding check_certified_egraph_def
by (auto simp: list_all_iff)
lemma check_dag_class_certificate:
assumes checked: "check_dag_class R memo cls certs"
and node: "node ∈ set cls"
obtains sts where
"check_explanation R [] sts
(instantiate_enode memo (hd cls))
(instantiate_enode memo node)"
proof -
from node obtain n where n: "n < length cls" and nth: "cls ! n = node"
unfolding set_conv_nth by blast
from checked have related:
"list_all2
(λnode sts.
check_explanation R [] sts
(instantiate_enode memo (hd cls))
(instantiate_enode memo node))
cls certs"
unfolding check_dag_class_def by simp
from list_all2_nthD[OF related n] nth have
"check_explanation R [] (certs ! n)
(instantiate_enode memo (hd cls))
(instantiate_enode memo node)"
by simp
from that[OF this] show thesis .
qed
lemma conversion_Fun_list_all2:
assumes
"list_all2
(λs t. (s, t) ∈ (rstep R)⇧↔⇧*) ss ts"
shows "(Fun f ss, Fun f ts) ∈ (rstep R)⇧↔⇧*"
proof (rule all_ctxt_closedD[OF all_ctxt_closed_rstep_conversion])
show "(f, length ts) ∈ UNIV" by simp
show "length ss = length ts"
using list_all2_lengthD[OF assms] .
fix i
assume "i < length ss"
from list_all2_nthD[OF assms this]
show "(ss ! i, ts ! i) ∈ (rstep R)⇧↔⇧*" .
qed auto
theorem checked_egraph_representation_sound:
assumes checked: "check_certified_egraph R G certs"
and i: "i < length G"
and represented: "represents_eclass G i t"
shows "(canonical_prefix G (Suc i) ! i, t)
∈ (rstep (set R))⇧↔⇧*"
using i represented
proof (induction i arbitrary: t rule: less_induct)
case (less i)
let ?memo = "canonical_prefix G i"
let ?cls = "G ! i"
from less.prems(2) obtain f children ts where
t: "t = Fun f ts" and node: "(f, children) ∈ set ?cls" and
related: "list_all2 (represents_eclass G) children ts"
using less.prems(1) by (cases rule: represents_eclass.cases) auto
have wf: "wf_acyclic_egraph G"
by (rule checked_egraph_wf[OF checked])
have children_lt: "∀j ∈ set children. j < i"
using wf less.prems(1) node unfolding wf_acyclic_egraph_def by auto
have canonical_children:
"list_all2
(λs u. (s, u) ∈ (rstep (set R))⇧↔⇧*)
(map ((!) ?memo) children) ts"
proof (rule list_all2_all_nthI)
show "length (map ((!) ?memo) children) = length ts"
using list_all2_lengthD[OF related] by simp
fix n
assume n: "n < length (map ((!) ?memo) children)"
then have nc: "n < length children" by simp
let ?j = "children ! n"
have j_mem: "?j ∈ set children" using nc by simp
with children_lt have ji: "?j < i" by blast
with less.prems(1) have jG: "?j < length G" by simp
have child_rep: "represents_eclass G ?j (ts ! n)"
using list_all2_nthD[OF related nc] .
have conv:
"(canonical_prefix G (Suc ?j) ! ?j, ts ! n)
∈ (rstep (set R))⇧↔⇧*"
by (rule less.IH[OF ji jG child_rep])
have "?memo ! ?j = canonical_prefix G (Suc ?j) ! ?j"
by (rule canonical_prefix_nth_stable[OF ji])
with conv show
"(map ((!) ?memo) children ! n, ts ! n)
∈ (rstep (set R))⇧↔⇧*"
using nc by simp
qed
have node_to_term:
"(instantiate_enode ?memo (f, children), t)
∈ (rstep (set R))⇧↔⇧*"
proof -
have "(Fun f (map ((!) ?memo) children), Fun f ts)
∈ (rstep (set R))⇧↔⇧*"
by (rule conversion_Fun_list_all2[OF canonical_children])
then show ?thesis
using t unfolding instantiate_enode_def by simp
qed
have class_checked:
"check_dag_class R ?memo ?cls (certs ! i)"
by (rule checked_dag_class_at[OF checked less.prems(1)])
from check_dag_class_certificate[OF class_checked node]
obtain sts where cert:
"check_explanation R [] sts
(instantiate_enode ?memo (hd ?cls))
(instantiate_enode ?memo (f, children))" .
have class_to_node:
"(instantiate_enode ?memo (hd ?cls),
instantiate_enode ?memo (f, children))
∈ (rstep (set R))⇧↔⇧*"
by (rule check_rule_explanation_sound[OF cert])
from class_to_node node_to_term have
"(instantiate_enode ?memo (hd ?cls), t)
∈ (rstep (set R))⇧↔⇧*"
unfolding conversion_def by (rule rtrancl_trans)
then show ?case unfolding canonical_prefix_step .
qed
theorem checked_egraph_eclass_sound:
assumes checked: "check_certified_egraph R G certs"
and i: "i < length G"
and s: "represents_eclass G i s"
and t: "represents_eclass G i t"
shows "(s, t) ∈ (rstep (set R))⇧↔⇧*"
proof -
have source_s:
"(canonical_prefix G (Suc i) ! i, s)
∈ (rstep (set R))⇧↔⇧*"
by (rule checked_egraph_representation_sound[OF checked i s])
have source_t:
"(canonical_prefix G (Suc i) ! i, t)
∈ (rstep (set R))⇧↔⇧*"
by (rule checked_egraph_representation_sound[OF checked i t])
have s_source:
"(s, canonical_prefix G (Suc i) ! i)
∈ (rstep (set R))⇧↔⇧*"
using source_s
by (rule conversion_sym[unfolded sym_def, rule_format])
from s_source source_t show ?thesis
unfolding conversion_def by (rule rtrancl_trans)
qed
theorem :
assumes checked: "check_certified_egraph R G certs"
and i: "i < length G"
obtains source chosen where
"canonical_eclass G i = Some source"
"extract_eclass w G i = Some chosen"
"(source, chosen) ∈ (rstep (set R))⇧↔⇧*"
"represents_eclass G i chosen"
"⋀u. represents_eclass G i u ⟹
term_cost w chosen ≤ term_cost w u"
proof -
have wf: "wf_acyclic_egraph G"
by (rule checked_egraph_wf[OF checked])
let ?source = "canonical_prefix G (length G) ! i"
from extract_eclass_global_minimum[OF wf i, of w]
obtain chosen where
extracted: "extract_eclass w G i = Some chosen" and
represented: "represents_eclass G i chosen" and
minimal: "⋀u. represents_eclass G i u ⟹
term_cost w chosen ≤ term_cost w u"
by blast
have source: "canonical_eclass G i = Some ?source"
using wf i unfolding canonical_eclass_def by simp
have stable:
"?source = canonical_prefix G (Suc i) ! i"
by (rule canonical_prefix_nth_stable[OF i])
have sound:
"(?source, chosen) ∈ (rstep (set R))⇧↔⇧*"
unfolding stable
by (rule checked_egraph_representation_sound[
OF checked i represented])
from that[OF source extracted sound represented minimal] show thesis .
qed
end