Theory Augmenting_Path_BFS
section ‹Breadth First Search›
theory Augmenting_Path_BFS
imports
Flow_Networks.Refine_Add_Fofu
Flow_Networks.Graph_Impl
begin
text ‹
In this theory, we present a verified breadth-first search
with an efficient imperative implementation.
It is parametric in the successor function.
›
subsection ‹Algorithm›
locale pre_bfs_invar = Graph +
fixes src dst :: node
begin
abbreviation "ndist v ≡ min_dist src v"
definition Vd :: "nat ⇒ node set"
where
"⋀d. Vd d ≡ {v. connected src v ∧ ndist v = d}"
lemma Vd_disj: "⋀d d'. d≠d' ⟹ Vd d ∩ Vd d' = {}"
by (auto simp: Vd_def)
lemma src_Vd0[simp]: "Vd 0 = {src}"
by (auto simp: Vd_def)
lemma in_Vd_conv: "v∈Vd d ⟷ connected src v ∧ ndist v = d"
by (auto simp: Vd_def)
lemma Vd_succ:
assumes "u∈Vd d"
assumes "(u,v)∈E"
assumes "∀i≤d. v∉Vd i"
shows "v∈Vd (Suc d)"
using assms
by (metis connected_append_edge in_Vd_conv le_SucE min_dist_succ)
end
locale valid_PRED = pre_bfs_invar +
fixes PRED :: "node ⇀ node"
assumes SRC_IN_V[simp]: "src∈V"
assumes FIN_V[simp, intro!]: "finite V"
assumes PRED_src[simp]: "PRED src = Some src"
assumes PRED_dist: "⟦v≠src; PRED v = Some u⟧ ⟹ ndist v = Suc (ndist u)"
assumes PRED_E: "⟦v≠src; PRED v = Some u⟧ ⟹ (u,v)∈E"
assumes PRED_closed: "⟦ PRED v = Some u ⟧ ⟹ u∈dom PRED"
begin
lemma FIN_E[simp, intro!]: "finite E" using E_ss_VxV by simp
lemma FIN_succ[simp, intro!]: "finite (E``{u})"
by (auto intro: finite_Image)
end
locale nf_invar' = valid_PRED c src dst PRED for c src dst
and PRED :: "node ⇀ node"
and C N :: "node set"
and d :: nat
+
assumes VIS_eq: "dom PRED = N ∪ {u. ∃i≤d. u∈Vd i}"
assumes C_ss: "C ⊆ Vd d"
assumes N_eq: "N = Vd (d+1) ∩ E``(Vd d - C)"
assumes dst_ne_VIS: "dst ∉ dom PRED"
locale nf_invar = nf_invar' +
assumes empty_assm: "C={} ⟹ N={}"
locale f_invar = valid_PRED c src dst PRED for c src dst
and PRED :: "node ⇀ node"
and d :: nat
+
assumes dst_found: "dst ∈ dom PRED ∩ Vd d"
context Graph begin
abbreviation "outer_loop_invar src dst ≡ λ(f,PRED,C,N,d).
(f ⟶ f_invar c src dst PRED d) ∧
(¬f ⟶ nf_invar c src dst PRED C N d)
"
abbreviation "assn1 src dst ≡ λ(f,PRED,C,N,d).
¬f ∧ nf_invar' c src dst PRED C N d"
definition "add_succ_spec dst succ v PRED N ≡ ASSERT (N ⊆ dom PRED) ⪢
SPEC (λ(f,PRED',N').
case f of
False ⇒ dst ∉ succ - dom PRED
∧ PRED' = map_mmupd PRED (succ - dom PRED) v
∧ N' = N ∪ (succ - dom PRED)
| True ⇒ dst ∈ succ - dom PRED
∧ PRED ⊆⇩m PRED'
∧ PRED' ⊆⇩m map_mmupd PRED (succ - dom PRED) v
∧ dst∈dom PRED'
)"
definition pre_bfs :: "node ⇒ node ⇒ (nat × (node⇀node)) option nres"
where "pre_bfs src dst ≡ do {
(f,PRED,_,_,d) ← WHILEIT (outer_loop_invar src dst)
(λ(f,PRED,C,N,d). f=False ∧ C≠{})
(λ(f,PRED,C,N,d). do {
v ← SPEC (λv. v∈C); let C = C-{v};
ASSERT (v∈V);
let succ = (E``{v});
ASSERT (finite succ);
(f,PRED,N) ← add_succ_spec dst succ v PRED N;
if f then
RETURN (f,PRED,C,N,d+1)
else do {
ASSERT (assn1 src dst (f,PRED,C,N,d));
if (C={}) then do {
let C=N;
let N={};
let d=d+1;
RETURN (f,PRED,C,N,d)
} else RETURN (f,PRED,C,N,d)
}
})
(False,[src↦src],{src},{},0::nat);
if f then RETURN (Some (d, PRED)) else RETURN None
}"
subsection "Correctness Proof"
lemma (in nf_invar') ndist_C[simp]: "⟦v∈C⟧ ⟹ ndist v = d"
using C_ss by (auto simp: Vd_def)
lemma (in nf_invar) CVdI: "⟦u∈C⟧ ⟹ u∈Vd d"
using C_ss by (auto)
lemma (in nf_invar) inPREDD:
"⟦PRED v = Some u⟧ ⟹ v∈N ∨ (∃i≤d. v∈Vd i)"
using VIS_eq by (auto)
lemma (in nf_invar') C_ss_VIS: "⟦v∈C⟧ ⟹ v∈dom PRED"
using C_ss VIS_eq by blast
lemma (in nf_invar) invar_succ_step:
assumes "v∈C"
assumes "dst ∉ E``{v} - dom PRED"
shows "nf_invar' c src dst
(map_mmupd PRED (E``{v} - dom PRED) v)
(C-{v})
(N ∪ (E``{v} - dom PRED))
d"
proof -
from C_ss_VIS[OF ‹v∈C›] dst_ne_VIS have "v≠dst" by auto
show ?thesis
using ‹v∈C› ‹v≠dst›
apply unfold_locales
apply simp
apply simp
apply (auto simp: map_mmupd_def) []
apply (erule map_mmupdE)
using PRED_dist apply blast
apply (unfold VIS_eq) []
apply clarify
apply (metis CVdI Vd_succ in_Vd_conv)
using PRED_E apply (auto elim!: map_mmupdE) []
using PRED_closed apply (auto elim!: map_mmupdE dest: C_ss_VIS) []
using VIS_eq apply auto []
using C_ss apply auto []
apply (unfold N_eq) []
apply (frule CVdI)
apply (auto) []
apply (erule (1) Vd_succ)
using VIS_eq apply (auto) []
apply (auto dest!: inPREDD simp: N_eq in_Vd_conv) []
using dst_ne_VIS assms(2) apply auto []
done
qed
lemma invar_init: "⟦src≠dst; src∈V; finite V⟧
⟹ nf_invar c src dst [src ↦ src] {src} {} 0"
apply unfold_locales
apply (auto)
apply (auto simp: pre_bfs_invar.Vd_def split: if_split_asm)
done
lemma (in nf_invar) invar_exit:
assumes "dst∈C"
shows "f_invar c src dst PRED d"
apply unfold_locales
using assms VIS_eq C_ss by auto
lemma (in nf_invar) invar_C_ss_V: "u∈C ⟹ u∈V"
apply (drule CVdI)
apply (auto simp: in_Vd_conv connected_inV_iff)
done
lemma (in nf_invar) invar_N_ss_Vis: "u∈N ⟹ ∃v. PRED u = Some v"
using VIS_eq by auto
lemma (in pre_bfs_invar) Vdsucinter_conv[simp]:
"Vd (Suc d) ∩ E `` Vd d = Vd (Suc d)"
apply (auto)
by (metis Image_iff in_Vd_conv min_dist_suc)
lemma (in nf_invar') invar_shift:
assumes [simp]: "C={}"
shows "nf_invar c src dst PRED N {} (Suc d)"
apply unfold_locales
apply vc_solve
using VIS_eq N_eq[simplified] apply (auto simp add: le_Suc_eq) []
using N_eq apply auto []
using N_eq[simplified] apply auto []
using dst_ne_VIS apply auto []
done
lemma (in nf_invar') invar_restore:
assumes [simp]: "C≠{}"
shows "nf_invar c src dst PRED C N d"
apply unfold_locales by auto
definition "bfs_spec src dst r ≡ (
case r of None ⇒ ¬ connected src dst
| Some (d,PRED) ⇒ connected src dst
∧ min_dist src dst = d
∧ valid_PRED c src PRED
∧ dst∈dom PRED)"
lemma (in f_invar) invar_found:
shows "bfs_spec src dst (Some (d,PRED))"
unfolding bfs_spec_def
apply simp
using dst_found
apply (auto simp: in_Vd_conv)
by unfold_locales
lemma (in nf_invar) invar_not_found:
assumes [simp]: "C={}"
shows "bfs_spec src dst None"
unfolding bfs_spec_def
apply simp
proof (rule notI)
have [simp]: "N={}" using empty_assm by simp
assume C: "connected src dst"
then obtain d' where dstd': "dst ∈ Vd d'"
by (auto simp: in_Vd_conv)
txt ‹We make a case-distinction whether ‹d'≤d›:›
have "d'≤d ∨ Suc d ≤ d'" by auto
moreover {
assume "d'≤d"
with VIS_eq dstd' have "dst ∈ dom PRED" by auto
with dst_ne_VIS have False by auto
} moreover {
assume "Suc d ≤ d'"
txt ‹In the case ‹d+1 ≤ d'›, we also obtain a node
that has a shortest path of length ‹d+1›:›
with min_dist_le[OF C] dstd' obtain v' where "v' ∈ Vd (Suc d)"
by (auto simp: in_Vd_conv)
txt ‹However, the invariant states that such nodes are either in
‹N› or are successors of ‹C›. As ‹N›
and ‹C› are both empty, we again get a contradiction.›
with N_eq have False by auto
} ultimately show False by blast
qed
lemma map_le_mp: "⟦m⊆⇩mm'; m k = Some v⟧ ⟹ m' k = Some v"
by (force simp: map_le_def)
lemma (in nf_invar) dst_notin_Vdd[intro, simp]: "i≤d ⟹ dst∉Vd i"
using VIS_eq dst_ne_VIS by auto
lemma (in nf_invar) invar_exit':
assumes "u∈C" "(u,dst) ∈ E" "dst ∈ dom PRED'"
assumes SS1: "PRED ⊆⇩m PRED'"
and SS2: "PRED' ⊆⇩m map_mmupd PRED (E``{u} - dom PRED) u"
shows "f_invar c src dst PRED' (Suc d)"
apply unfold_locales
apply simp_all
using map_le_mp[OF SS1 PRED_src] apply simp
apply (drule map_le_mp[OF SS2])
apply (erule map_mmupdE)
using PRED_dist apply auto []
apply (unfold VIS_eq) []
apply clarify
using ‹u∈C›
apply (metis CVdI Vd_succ in_Vd_conv)
apply (drule map_le_mp[OF SS2])
using PRED_E apply (auto elim!: map_mmupdE) []
apply (drule map_le_mp[OF SS2])
apply (erule map_mmupdE)
using map_le_implies_dom_le[OF SS1]
using PRED_closed apply (blast) []
using C_ss_VIS[OF ‹u∈C›] map_le_implies_dom_le[OF SS1] apply blast
using ‹dst ∈ dom PRED'› apply simp
using ‹u∈C› CVdI[OF ‹u∈C›] ‹(u,dst)∈E›
apply (auto) []
apply (erule (1) Vd_succ)
using VIS_eq apply (auto) []
done
definition "max_dist src ≡ Max (min_dist src`V)"
definition "outer_loop_rel src ≡
inv_image (
less_than_bool
<*lex*> greater_bounded (max_dist src + 1)
<*lex*> finite_psubset)
(λ(f,PRED,C,N,d). (¬f,d,C))"
lemma outer_loop_rel_wf:
assumes "finite V"
shows "wf (outer_loop_rel src)"
using assms
unfolding outer_loop_rel_def
by auto
lemma (in nf_invar) C_ne_max_dist:
assumes "C≠{}"
shows "d ≤ max_dist src"
proof -
from assms obtain u where "u∈C" by auto
with C_ss have "u∈Vd d" by auto
hence "min_dist src u = d" "u∈V"
by (auto simp: in_Vd_conv connected_inV_iff)
thus "d≤max_dist src"
unfolding max_dist_def by auto
qed
lemma (in nf_invar) Vd_ss_V: "Vd d ⊆ V"
by (auto simp: Vd_def connected_inV_iff)
lemma (in nf_invar) finite_C[simp, intro!]: "finite C"
using C_ss FIN_V Vd_ss_V by (blast intro: finite_subset)
lemma (in nf_invar) finite_succ: "finite (E``{u})"
by auto
theorem pre_bfs_correct:
assumes [simp]: "src∈V" "src≠dst"
assumes [simp]: "finite V"
shows "pre_bfs src dst ≤ SPEC (bfs_spec src dst)"
unfolding pre_bfs_def add_succ_spec_def
apply (intro refine_vcg)
apply (rule outer_loop_rel_wf[where src=src])
apply (vc_solve simp:
invar_init
nf_invar.invar_exit'
nf_invar.invar_C_ss_V
nf_invar.invar_succ_step
nf_invar'.invar_shift
nf_invar'.invar_restore
f_invar.invar_found
nf_invar.invar_not_found
nf_invar.invar_N_ss_Vis
nf_invar.finite_succ
)
apply (vc_solve
simp: remove_subset outer_loop_rel_def
simp: nf_invar.C_ne_max_dist nf_invar.finite_C)
done
definition bfs_core :: "node ⇒ node ⇒ (nat × (node⇀node)) option nres"
where "bfs_core src dst ≡ do {
(f,P,_,_,d) ← while⇩T (λ(f,P,C,N,d). f=False ∧ C≠{})
(λ(f,P,C,N,d). do {
v ← spec v. v∈C; let C = C-{v};
let succ = (E``{v});
(f,P,N) ← add_succ_spec dst succ v P N;
if f then
return (f,P,C,N,d+1)
else do {
if (C={}) then do {
let C=N; let N={}; let d=d+1;
return (f,P,C,N,d)
} else return (f,P,C,N,d)
}
})
(False,[src↦src],{src},{},0::nat);
if f then return (Some (d, P)) else return None
}"
theorem
assumes "src∈V" "src≠dst" "finite V"
shows "bfs_core src dst ≤ (spec p. bfs_spec src dst p)"
apply (rule order_trans[OF _ pre_bfs_correct])
apply (rule refine_IdD)
unfolding bfs_core_def pre_bfs_def
apply refine_rcg
apply refine_dref_type
apply (vc_solve simp: assms)
done
subsection ‹Extraction of Result Path›
" src dst PRED ≡ do {
(_,p) ← WHILEIT
(λ(v,p).
v∈dom PRED
∧ isPath v p dst
∧ distinct (pathVertices v p)
∧ (∀v'∈set (pathVertices v p).
pre_bfs_invar.ndist c src v ≤ pre_bfs_invar.ndist c src v')
∧ pre_bfs_invar.ndist c src v + length p
= pre_bfs_invar.ndist c src dst)
(λ(v,p). v≠src) (λ(v,p). do {
ASSERT (v∈dom PRED);
let u=the (PRED v);
let p = (u,v)#p;
let v=u;
RETURN (v,p)
}) (dst,[]);
RETURN p
}"
end
context valid_PRED begin
lemma :
assumes "dst∈dom PRED"
shows "extract_rpath src dst PRED
≤ SPEC (λp. isSimplePath src p dst ∧ length p = ndist dst)"
using assms unfolding extract_rpath_def isSimplePath_def
apply (refine_vcg wf_measure[where f="λ(d,_). ndist d"])
apply (vc_solve simp: PRED_closed[THEN domD] PRED_E PRED_dist)
apply auto
done
end
context Graph begin
definition "bfs src dst ≡ do {
if src=dst then RETURN (Some [])
else do {
br ← pre_bfs src dst;
case br of
None ⇒ RETURN None
| Some (d,PRED) ⇒ do {
p ← extract_rpath src dst PRED;
RETURN (Some p)
}
}
}"
lemma bfs_correct:
assumes "src∈V" "finite V"
shows "bfs src dst
≤ SPEC (λ
None ⇒ ¬connected src dst
| Some p ⇒ isShortestPath src p dst)"
unfolding bfs_def
apply (refine_vcg
pre_bfs_correct[THEN order_trans]
valid_PRED.extract_rpath_correct[THEN order_trans]
)
using assms
apply (vc_solve
simp: bfs_spec_def isShortestPath_min_dist_def isSimplePath_def)
done
end
context Finite_Graph begin
interpretation Refine_Monadic_Syntax .
theorem
assumes "src∈V"
shows "bfs src dst ≤ (spec p. case p of
None ⇒ ¬connected src dst
| Some p ⇒ isShortestPath src p dst)"
unfolding bfs_def
apply (refine_vcg
pre_bfs_correct[THEN order_trans]
valid_PRED.extract_rpath_correct[THEN order_trans]
)
using assms
apply (vc_solve
simp: bfs_spec_def isShortestPath_min_dist_def isSimplePath_def)
done
end
subsection ‹Inserting inner Loop and Successor Function›
context Graph begin
definition "inner_loop dst succ u PRED N ≡ FOREACHci
(λit (f,PRED',N').
PRED' = map_mmupd PRED ((succ - it) - dom PRED) u
∧ N' = N ∪ ((succ - it) - dom PRED)
∧ f = (dst∈(succ - it) - dom PRED)
)
(succ)
(λ(f,PRED,N). ¬f)
(λv (f,PRED,N). do {
if v∈dom PRED then RETURN (f,PRED,N)
else do {
let PRED = PRED(v ↦ u);
ASSERT (v∉N);
let N = insert v N;
RETURN (v=dst,PRED,N)
}
})
(False,PRED,N)"
lemma inner_loop_refine[refine]:
assumes [simp]: "finite succ"
assumes [simplified, simp]:
"(succi,succ)∈Id" "(ui,u)∈Id" "(PREDi,PRED)∈Id" "(Ni,N)∈Id"
shows "inner_loop dst succi ui PREDi Ni
≤ ⇓Id (add_succ_spec dst succ u PRED N)"
unfolding inner_loop_def add_succ_spec_def
apply refine_vcg
apply (auto simp: it_step_insert_iff; fail) +
apply (auto simp: it_step_insert_iff fun_neq_ext_iff map_mmupd_def
split: if_split_asm) []
apply (auto simp: it_step_insert_iff split: bool.split; fail)
apply (auto simp: it_step_insert_iff split: bool.split; fail)
apply (auto simp: it_step_insert_iff split: bool.split; fail)
apply (auto simp: it_step_insert_iff intro: map_mmupd_update_less
split: bool.split; fail)
done
definition "inner_loop2 dst succl u PRED N ≡ nfoldli
(succl) (λ(f,_,_). ¬f) (λv (f,PRED,N). do {
if PRED v ≠ None then RETURN (f,PRED,N)
else do {
let PRED = PRED(v ↦ u);
ASSERT (v∉N);
let N = insert v N;
RETURN ((v=dst),PRED,N)
}
}) (False,PRED,N)"
lemma inner_loop2_refine:
assumes SR: "(succl,succ)∈⟨Id⟩list_set_rel"
shows "inner_loop2 dst succl u PRED N ≤ ⇓Id (inner_loop dst succ u PRED N)"
using assms
unfolding inner_loop2_def inner_loop_def
apply (refine_rcg LFOci_refine SR)
apply (vc_solve)
apply auto
done
thm conc_trans[OF inner_loop2_refine inner_loop_refine, no_vars]
lemma inner_loop2_correct:
assumes "(succl, succ) ∈ ⟨Id⟩list_set_rel"
assumes [simplified, simp]:
"(dsti,dst)∈Id" "(ui, u) ∈ Id" "(PREDi, PRED) ∈ Id" "(Ni, N) ∈ Id"
shows "inner_loop2 dsti succl ui PREDi Ni
≤ ⇓ Id (add_succ_spec dst succ u PRED N)"
apply simp
apply (rule conc_trans[OF inner_loop2_refine inner_loop_refine, simplified])
using assms(1-2)
apply (simp_all)
done
type_synonym bfs_state = "bool × (node ⇀ node) × node set × node set × nat"
context
fixes succ :: "node ⇒ node list nres"
begin
definition init_state :: "node ⇒ bfs_state nres"
where
"init_state src ≡ RETURN (False,[src↦src],{src},{},0::nat)"
definition pre_bfs2 :: "node ⇒ node ⇒ (nat × (node⇀node)) option nres"
where "pre_bfs2 src dst ≡ do {
s ← init_state src;
(f,PRED,_,_,d) ← WHILET (λ(f,PRED,C,N,d). f=False ∧ C≠{})
(λ(f,PRED,C,N,d). do {
ASSERT (C≠{});
v ← op_set_pick C; let C = C-{v};
ASSERT (v∈V);
sl ← succ v;
(f,PRED,N) ← inner_loop2 dst sl v PRED N;
if f then
RETURN (f,PRED,C,N,d+1)
else do {
ASSERT (assn1 src dst (f,PRED,C,N,d));
if (C={}) then do {
let C=N;
let N={};
let d=d+1;
RETURN (f,PRED,C,N,d)
} else RETURN (f,PRED,C,N,d)
}
})
s;
if f then RETURN (Some (d, PRED)) else RETURN None
}"
lemma pre_bfs2_refine:
assumes succ_impl: "⋀ui u. ⟦(ui,u)∈Id; u∈V⟧
⟹ succ ui ≤ SPEC (λl. (l,E``{u}) ∈ ⟨Id⟩list_set_rel)"
shows "pre_bfs2 src dst ≤⇓Id (pre_bfs src dst)"
unfolding pre_bfs_def pre_bfs2_def init_state_def
apply (subst nres_monad1)
apply (refine_rcg inner_loop2_correct succ_impl)
apply refine_dref_type
apply vc_solve
done
end
definition "bfs2 succ src dst ≡ do {
if src=dst then
RETURN (Some [])
else do {
br ← pre_bfs2 succ src dst;
case br of
None ⇒ RETURN None
| Some (d,PRED) ⇒ do {
p ← extract_rpath src dst PRED;
RETURN (Some p)
}
}
}"
lemma bfs2_refine:
assumes succ_impl: "⋀ui u. ⟦(ui,u)∈Id; u∈V⟧
⟹ succ ui ≤ SPEC (λl. (l,E``{u}) ∈ ⟨Id⟩list_set_rel)"
shows "bfs2 succ src dst ≤ ⇓Id (bfs src dst)"
unfolding bfs_def bfs2_def
apply (refine_vcg pre_bfs2_refine)
apply refine_dref_type
using assms
apply (vc_solve)
done
end
lemma bfs2_refine_succ:
assumes [refine]: "⋀ui u. ⟦(ui,u)∈Id; u∈Graph.V c⟧
⟹ succi ui ≤ ⇓Id (succ u)"
assumes [simplified, simp]: "(si,s)∈Id" "(ti,t)∈Id" "(ci,c)∈Id"
shows "Graph.bfs2 ci succi si ti ≤ ⇓Id (Graph.bfs2 c succ s t)"
unfolding Graph.bfs2_def Graph.pre_bfs2_def
apply (refine_rcg
param_nfoldli[param_fo, THEN nres_relD] nres_relI fun_relI)
apply refine_dref_type
apply vc_solve
done
subsection ‹Imperative Implementation›
context Impl_Succ begin
definition op_bfs :: "'ga ⇒ node ⇒ node ⇒ path option nres"
where [simp]: "op_bfs c s t ≡ Graph.bfs2 (absG c) (succ c) s t"
lemma pat_op_dfs[pat_rules]:
"Graph.bfs2$(absG$c)$(succ$c)$s$t ≡ UNPROTECT op_bfs$c$s$t" by simp
sepref_register "PR_CONST op_bfs"
:: "'ig ⇒ node ⇒ node ⇒ path option nres"
type_synonym ibfs_state
= "bool × (node,node) i_map × node set × node set × nat"
sepref_register Graph.init_state :: "node ⇒ ibfs_state nres"
schematic_goal init_state_impl:
fixes src :: nat
notes [id_rules] =
itypeI[Pure.of src "TYPE(nat)"]
shows "hn_refine (hn_val nat_rel src srci)
(?c::?'c Heap) ?Γ' ?R (Graph.init_state src)"
using [[id_debug, goals_limit = 1]]
unfolding Graph.init_state_def
apply (rewrite in "[src↦src]" iam.fold_custom_empty)
apply (subst ls.fold_custom_empty)
apply (subst ls.fold_custom_empty)
apply (rewrite in "insert src _" fold_set_insert_dj)
apply (rewrite in "_(⌑↦src)" fold_COPY)
apply sepref
done
concrete_definition (in -) init_state_impl uses Impl_Succ.init_state_impl
lemmas [sepref_fr_rules] = init_state_impl.refine[OF this_loc,to_hfref]
schematic_goal bfs_impl:
notes [sepref_opt_simps] = heap_WHILET_def
fixes s t :: nat
notes [id_rules] =
itypeI[Pure.of s "TYPE(nat)"]
itypeI[Pure.of t "TYPE(nat)"]
itypeI[Pure.of c "TYPE('ig)"]
shows "hn_refine (
hn_ctxt (isG) c ci
* hn_val nat_rel s si
* hn_val nat_rel t ti) (?c::?'c Heap) ?Γ' ?R (PR_CONST op_bfs c s t)"
unfolding op_bfs_def PR_CONST_def
unfolding Graph.bfs2_def Graph.pre_bfs2_def
Graph.inner_loop2_def Graph.extract_rpath_def
unfolding nres_monad_laws
apply (rewrite in "nfoldli _ _ ⌑ _" fold_set_insert_dj)
apply (subst HOL_list.fold_custom_empty)+
apply (rewrite in "let N={} in _" ls.fold_custom_empty)
using [[id_debug, goals_limit = 1]]
apply sepref
done
concrete_definition (in -) bfs_impl uses Impl_Succ.bfs_impl
prepare_code_thms (in -) bfs_impl_def
lemmas bfs_impl_fr_rule = bfs_impl.refine[OF this_loc,to_hfref]
end
export_code bfs_impl checking SML_imp
end