header {* Simple DFS Algorithm *}
theory Sepref_DFS
imports
"../../CAVA_Automata/CAVA_Base/CAVA_Base"
"../../../DFS_Framework/Misc/DFS_Framework_Refine_Aux"
"../Sepref"
Sepref_Graph
begin
lemma REC_rule_arb':
fixes x::"'x" and arb::'arb
assumes M: "trimono body"
assumes I0: "pre arb x"
assumes IS: "!!f arb x. [|
!!arb' x. pre arb' x ==> f x ≤ M arb' x; pre arb x
|] ==> body f x ≤ M arb x"
shows "REC body x ≤ M arb x"
apply (rule REC_rule_arb[where M=M and pre=pre])
apply fact
apply fact
apply (rule IS)
apply assumption+
done
lemma RECT_rule_arb':
fixes x::"'x" and arb::'arb
assumes "trimono body"
and "wf V"
and "pre arb x"
and
IS: "!!f arb x.
[|!!arb' x'. [|pre arb' x'; (x', x) ∈ V|] ==> f x' ≤ M arb' x'; pre arb x;
f ≤ REC⇩T body|]
==> body f x ≤ M arb x"
shows "REC⇩T body x ≤ M arb x"
apply (rule RECT_rule_arb[where M=M and pre=pre])
apply fact
apply fact
apply fact
apply (rule IS)
apply assumption+
apply simp
done
text {*
We define a simple DFS-algorithm, prove a simple correctness
property, and do data refinement to an efficient implementation.
*}
subsection {* Definition *}
text {* Recursive DFS-Algorithm.
@{text "E"} is the edge relation of the graph, @{text "vd"} the node to
search for, and @{text "v0"} the start node.
Already explored nodes are stored in @{text "V"}.*}
context
fixes E :: "'v rel" and v0 :: 'v and tgt :: 'v
begin
definition dfs :: "bool nres" where
"dfs ≡ do {
(_,r) \<leftarrow> RECT (λdfs (V,v).
if v∈V then RETURN (V,False)
else do {
let V=insert v V;
if v = tgt then
RETURN (V,True)
else
FOREACH⇩C (E``{v}) (λ(_,b). ¬b) (λv' (V,_). dfs (V,v')) (V,False)
}
) ({},v0);
RETURN r
}"
definition "reachable ≡ {v. (v0,v)∈E⇧*}"
lemma dfs_correct:
assumes fr: "finite reachable"
shows "dfs ≤ SPEC (λr. r <-> (v0,tgt)∈E⇧*)"
proof -
have F: "!!v. v∈reachable ==> finite (E``{v})"
using fr
apply (auto simp: reachable_def)
by (metis (mono_tags) Image_singleton Image_singleton_iff
finite_subset rtrancl.rtrancl_into_rtrancl subsetI)
def rpre ≡ "λS (V,v).
v∈reachable
∧ V⊆reachable
∧ S⊆V
∧ tgt∉V
∧ E``(V-S) ⊆ V"
def rpost ≡ "λS (V,v) (V',r).
(r<->tgt∈V')
∧ V⊆V'
∧ v∈V'
∧ V'⊆reachable
∧ (¬r --> (E``(V'-S) ⊆ V'))
"
def fe_inv ≡ "λS V v it (V',r).
(r<->tgt∈V')
∧ insert v V⊆V'
∧ E``{v} - it ⊆ V'
∧ V'⊆reachable
∧ S⊆insert v V
∧ (¬r --> E``(V'-S) ⊆ V' ∪ it ∧ E``(V'-insert v S) ⊆ V')"
have vc_pre_initial: "rpre {} ({}, v0)"
by (auto simp: rpre_def reachable_def)
{
fix S V v
assume "rpre S (V,v)"
and "v∈V"
hence "rpost S (V,v) (V,False)"
unfolding rpre_def rpost_def
by auto
} note vc_node_visited = this
{
fix S V
assume "rpre S (V,tgt)"
hence "rpost S (V,tgt) (insert tgt V, True)"
unfolding rpre_def rpost_def
by auto
} note vc_node_found = this
{
fix S V v
assume "rpre S (V, v)"
hence "finite (E``{v})"
unfolding rpre_def using F by (auto)
} note vc_foreach_finite = this
{
fix S V v
assume A: "v ∉ V" "v ≠ tgt"
and PRE: "rpre S (V, v)"
hence "fe_inv S V v (E``{v}) (insert v V, False)"
unfolding fe_inv_def rpre_def by (auto)
} note vc_enter_foreach = this
{
fix S V v v' it V'
assume A: "v ∉ V" "v ≠ tgt" "v' ∈ it" "it ⊆ E``{v}"
and FEI: "fe_inv S V v it (V', False)"
and PRE: "rpre S (V, v)"
from A have "v' ∈ E``{v}" by auto
moreover from PRE have "v ∈ reachable" by (auto simp: rpre_def)
hence "E``{v} ⊆ reachable" by (auto simp: reachable_def)
ultimately have [simp]: "v'∈reachable" by blast
have "rpre (insert v S) (V', v')"
unfolding rpre_def
using FEI PRE by (auto simp: fe_inv_def rpre_def) []
} note vc_rec_pre = this
{
fix S V V' v v' it Vr''
assume "fe_inv S V v it (V', False)"
and "rpost (insert v S) (V', v') Vr''"
hence "fe_inv S V v (it - {v'}) Vr''"
unfolding rpre_def rpost_def fe_inv_def
by clarsimp blast
} note vc_iterate_foreach = this
{
fix S V v V'
assume PRE: "rpre S (V, v)"
assume A: "v ∉ V" "v ≠ tgt"
assume FEI: "fe_inv S V v {} (V', False)"
have "rpost S (V, v) (V', False)"
unfolding rpost_def
using FEI by (auto simp: fe_inv_def) []
} note vc_foreach_completed_imp_post = this
{
fix S V v V' it
assume PRE: "rpre S (V, v)"
and A: "v ∉ V" "v ≠ tgt" "it ⊆ E``{v}"
and FEI: "fe_inv S V v it (V', True)"
hence "rpost S (V, v) (V', True)"
by (auto simp add: rpre_def rpost_def fe_inv_def) []
} note vc_foreach_interrupted_imp_post = this
{
fix V r
assume "rpost {} ({}, v0) (V, r)"
hence "r = ((v0, tgt) ∈ E⇧*)"
by (auto
simp: rpost_def reachable_def
dest: Image_closed_trancl
intro: rev_ImageI)
} note vc_rpost_imp_spec = this
show ?thesis
unfolding dfs_def
apply (refine_rcg refine_vcg)
apply (rule order_trans)
apply(rule RECT_rule_arb'[where
pre=rpre
and M="λa x. SPEC (rpost a x)"
and V="finite_psupset reachable <*lex*> {}"
])
apply refine_mono
apply (blast intro: fr)
apply (rule vc_pre_initial)
apply (refine_rcg refine_vcg
FOREACHc_rule'[where I="fe_inv S v s" for S v s]
)
apply (simp_all add: vc_node_visited vc_node_found)
apply (simp add: vc_foreach_finite)
apply (auto intro: vc_enter_foreach) []
apply (rule order_trans)
apply (rprems)
apply (erule (5) vc_rec_pre)
apply (auto simp add: fe_inv_def finite_psupset_def) []
apply (refine_rcg refine_vcg)
apply (simp add: vc_iterate_foreach)
apply (auto simp add: vc_foreach_completed_imp_post) []
apply (auto simp add: vc_foreach_interrupted_imp_post) []
apply (auto simp add: vc_rpost_imp_spec) []
done
qed
end
subsection ‹Refinement to Imperative/HOL›
text ‹We set up a schematic proof goal,
and use the sepref-tool to synthesize the implementation.
›
schematic_lemma dfs_impl:
fixes s t :: nat
notes [sepref_opt_simps del] = imp_nfoldli_def
-- ‹Prevent the foreach-loop to be unfolded to a fixed-point,
to produce more readable code for presentation purposes.›
notes [id_rules] =
itypeI[of s "TYPE(nat)"]
itypeI[of t "TYPE(nat)"]
itypeI[of E "TYPE(nat i_slg)"]
-- ‹Declare parameters to operation identification›
shows "hn_refine (
hn_ctxt (is_graph nat_rel) E Ei
* hn_val nat_rel s si
* hn_val nat_rel t ti) (?c::?'c Heap) ?Γ' ?R (dfs E s t)"
unfolding dfs_def -- ‹Unfold definition of DFS›
apply sepref -- ‹Invoke sepref-tool›
done
concrete_definition dfs_impl uses dfs_impl
-- ‹Extract generated implementation into constant›
prepare_code_thms dfs_impl_def
-- ‹Set up code equations for recursion combinators›
export_code dfs_impl checking SML_imp
-- ‹Generate SML code with Imperative/HOL›
text ‹Finally, correctness is shown by combining the
generated refinement theorem with the abstract correctness theorem.›
corollary dfs_impl_correct:
"finite (reachable E s) ==>
<is_graph nat_rel E Ei>
dfs_impl Ei s t
< λr. is_graph nat_rel E Ei * \<up>(r <-> (s,t)∈E⇧* ) >⇩t"
proof -
assume FIN: "finite (reachable E s)"
note aux = hn_refine_ref[OF dfs_correct dfs_impl.refine,
unfolded hn_refine_def, simplified, OF FIN]
show ?thesis
apply (rule cons_rule[OF _ _ aux])
apply (sep_auto simp: hn_ctxt_def pure_def)+
done
qed
end