Theory Check_Planarity_Verification
section ‹Verififcation of a Planarity Checker›
theory Check_Planarity_Verification
imports
"../Planarity/Graph_Genus"
Setup_AutoCorres
"HOL-Library.Rewrite"
begin
subsection ‹Implementation Types›
type_synonym IVert = "nat"
type_synonym IEdge = "IVert × IVert"
type_synonym IGraph = "IVert list × IEdge list"
abbreviation (input) ig_edges :: "IGraph ⇒ IEdge list" where
"ig_edges G ≡ snd G"
abbreviation (input) ig_verts :: "IGraph ⇒ IVert list" where
"ig_verts G ≡ fst G"
definition ig_tail :: "IGraph ⇒ nat ⇒ IVert" where
"ig_tail IG a = fst (ig_edges IG ! a)"
definition ig_head :: "IGraph ⇒ nat ⇒ IVert" where
"ig_head IG a = snd (ig_edges IG ! a)"
type_synonym IMap = "(nat ⇒ nat) × (nat ⇒ nat) × (nat ⇒ nat)"
definition im_rev :: "IMap ⇒ (nat ⇒ nat)" where
"im_rev iM = fst iM"
definition im_succ :: "IMap ⇒ (nat ⇒ nat)" where
"im_succ iM = fst (snd iM)"
definition im_pred :: "IMap ⇒ (nat ⇒ nat)" where
"im_pred iM = snd (snd iM)"
definition mk_graph :: "IGraph ⇒ (IVert, nat) pre_digraph" where
"mk_graph IG ≡ ⦇
verts = set (ig_verts IG),
arcs = {0..< length (ig_edges IG)},
tail = ig_tail IG,
head = ig_head IG
⦈"
lemma mkg_simps:
"verts (mk_graph IG) = set (ig_verts IG)"
"tail (mk_graph IG) = ig_tail IG"
"head (mk_graph IG) = ig_head IG"
by (auto simp: mk_graph_def)
lemma arcs_mkg: "arcs (mk_graph IG) = {0..< length (ig_edges IG)}"
by (auto simp: mk_graph_def)
lemma arc_to_ends_mkg: "arc_to_ends (mk_graph IG) a = ig_edges IG ! a"
by (auto simp: arc_to_ends_def mkg_simps ig_tail_def ig_head_def)
definition mk_map :: "(_, nat) pre_digraph ⇒ IMap ⇒ nat pre_map" where
"mk_map G iM ≡ ⦇
edge_rev = perm_restrict (im_rev iM) (arcs G),
edge_succ = perm_restrict (im_succ iM) (arcs G)
⦈"
lemma mkm_simps:
"edge_rev (mk_map G iM) = perm_restrict (im_rev iM) (arcs G)"
"edge_succ (mk_map G iM) = perm_restrict (im_succ iM) (arcs G)"
by (auto simp: mk_map_def)
lemma es_eq_im: "a ∈ arcs (mk_graph iG) ⟹ edge_succ (mk_map (mk_graph iG) iM) a = im_succ iM a"
by (auto simp: mkm_simps arcs_mkg perm_restrict_simps)
subsection ‹Implementation›
definition "is_map iG iM ≡
DO ecnt ← oreturn (length (snd iG));
vcnt ← oreturn (length (fst iG));
(i, revOk) ← owhile
(λ(i, ok) s. i < ecnt ∧ ok)
(λ(i, ok).
DO
j ← oreturn (im_rev iM i);
revIn ← oreturn (j < length (ig_edges iG));
revNeq ← oreturn (j ≠ i);
revRevs ← oreturn (ig_edges iG ! j = prod.swap (ig_edges iG ! i));
invol ← oreturn (im_rev iM j = i);
oreturn (i + 1, revIn ∧ revNeq ∧ revRevs ∧ invol)
OD)
(0, True);
(i, succPerm) ← owhile
(λ(i, ok) s. i < ecnt ∧ ok)
(λ(i, ok).
DO
j ← oreturn (im_succ iM i);
succIn ← oreturn (j < length (ig_edges iG));
succEnd ← oreturn (ig_tail iG i = ig_tail iG j);
isPerm ← oreturn (im_pred iM j = i);
oreturn (i + 1, succIn ∧ succEnd ∧ isPerm)
OD)
(0, True);
(i, succOrbits, V, A) ← owhile
(λ(i, ok, V, A) s. i < ecnt ∧ succPerm ∧ ok)
(λ(i, ok, V, A).
DO
(x,V,A) ← ocondition (λ_. ig_tail iG i ∈ V)
(oreturn (i ∈ A, V, A))
(DO
(A',j) ← owhile
(λ(A',j) s. j ∉ A')
(λ(A',j). DO
A' ← oreturn (insert j A');
j ← oreturn (im_succ iM j);
oreturn (A', j)
OD)
({},i);
V ← oreturn (insert (ig_tail iG j) V);
oreturn (True,V,A ∪ A')
OD);
oreturn (i + 1, x, V, A)
OD)
(0, True, {}, {});
oreturn (revOk ∧ succPerm ∧ succOrbits)
OD
"
definition isolated_nodes :: "IGraph ⇒ _ ⇒ nat option" where
"isolated_nodes iG ≡
DO ecnt ← oreturn (length (snd iG));
vcnt ← oreturn (length (fst iG));
(i, nz) ←
owhile
(λ(i, nz) a. i < vcnt)
(λ(i, nz).
DO v ← oreturn (fst iG ! i);
j ← oreturn 0;
ret ← ocondition (λs. j < ecnt) (oreturn (ig_tail iG j ≠ v)) (oreturn False);
ret ← ocondition (λs. ret) (oreturn (ig_head iG j ≠ v)) (oreturn ret);
(j, _) ←
owhile
(λ(j, cond) a. cond)
(λ(j, cond).
DO j ← oreturn (j + 1);
cond ← ocondition (λs. j < ecnt) (oreturn (ig_tail iG j ≠ v)) (oreturn False);
cond ← ocondition (λs. cond) (oreturn (ig_head iG j ≠ v)) (oreturn cond);
oreturn (j, cond)
OD)
(j, ret);
nz ← oreturn (if j = ecnt then nz + 1 else nz);
oreturn (i + 1, nz)
OD)
(0, 0);
oreturn nz
OD"
definition face_cycles :: "IGraph ⇒ nat pre_map ⇒ _ ⇒ nat option" where
"face_cycles iG iM ≡
DO ecnt ← oreturn (length (snd iG));
(edge_info, c, i) ←
owhile
(λ(edge_info, c, i) s. i < ecnt)
(λ(edge_info, c, i).
DO (edge_info, c) ←
ocondition (λs. i ∉ edge_info)
(DO j ← oreturn i;
edge_info ← oreturn (insert j edge_info);
ret' ← oreturn (pre_digraph_map.face_cycle_succ iM j);
(edge_info, j) ←
owhile
(λ(edge_info, j) s. i ≠ j)
(λ(edge_info, j).
oreturn (insert j edge_info, pre_digraph_map.face_cycle_succ iM j))
(edge_info, ret');
oreturn (edge_info, c + 1)
OD)
(oreturn (edge_info, c));
oreturn (edge_info, c, i + 1)
OD)
({}, 0, 0);
oreturn c
OD"
definition "euler_genus iG iM c ≡
DO n ← oreturn (length (ig_edges iG));
m ← oreturn (length (ig_verts iG));
nz ← isolated_nodes iG;
fc ← face_cycles iG iM;
oreturn ((int n div 2 + 2 * int c - int m - int nz - int fc) div 2)
OD"
definition "certify iG iM c ≡
DO
map ← is_map iG iM;
ocondition (λ_. map)
(DO
gen ← euler_genus iG (mk_map (mk_graph iG) iM) c;
oreturn (gen = 0)
OD)
(oreturn False)
OD"
subsection ‹Verification›
context begin
interpretation Labeling_Syntax .
lemma trivial_label: "P ⟹ CTXT IC CT OC P"
unfolding LABEL_simps .
end
lemma ovalidNF_wp:
assumes "ovalidNF P c (λr s. r = x)"
shows "ovalidNF (λs. Q x s ∧ P s) c Q"
using assms unfolding ovalidNF_def by auto
subsubsection ‹@{term is_map}›
definition "is_map_rev_ok_inv iG iM k ok ≡ ok ⟷ (∀i < k.
im_rev iM i < length (ig_edges iG)
∧ ig_edges iG ! im_rev iM i = prod.swap (ig_edges iG ! i)
∧ im_rev iM i ≠ i
∧ im_rev iM (im_rev iM i) = i)
"
definition "is_map_succ_perm_inv iG iM k ok ≡ ok ⟷ (∀i < k.
im_succ iM i < length (ig_edges iG)
∧ ig_tail iG (im_succ iM i) = ig_tail iG i
∧ im_pred iM (im_succ iM i) = i)
"
definition "is_map_succ_orbits_inv iG iM k ok V A ≡
A = (⋃i<(if ok then k else k - 1). orbit (im_succ iM) i) ∧
V = {ig_tail iG i | i. i<(if ok then k else k - 1)} ∧
ok = (∀i < k. ∀j < k. ig_tail iG i = ig_tail iG j ⟶ j ∈ orbit (im_succ iM) i)
"
definition "is_map_succ_orbits_inner_inv iG iM i j A' ≡
A' = (if i = j ∧ i ∉ A' then {} else {i} ∪ segment (im_succ iM) i j)
∧ j ∈ orbit (im_succ iM) i
"
definition "is_map_final iG k ok ≡ (ok ⟶ k = length (ig_edges iG)) ∧ k ≤ length (ig_edges iG)"
lemma bij_betwI_finite_dom:
assumes "finite A" "f ∈ A → A" "⋀a. a ∈ A ⟹ g (f a) = a"
shows "bij_betw f A A"
proof -
have "inj_on f A" by (metis assms(3) inj_onI)
moreover
then have "f ` A = A" by (metis Pi_iff assms(1-2) endo_inj_surj image_subsetI)
ultimately show ?thesis unfolding bij_betw_def by simp
qed
lemma permutesI_finite_dom:
assumes "finite A"
assumes "f ∈ A → A"
assumes "⋀a. a ∉ A ⟹ f a = a"
assumes "⋀a. a ∈ A ⟹ g (f a) = a"
shows "f permutes A"
using assms by (intro bij_imp_permutes bij_betwI_finite_dom)
lemma orbit_ss:
assumes "f ∈ A → A" "a ∈ A"
shows "orbit f a ⊆ A"
proof -
{ fix x assume "x ∈ orbit f a" then have "x ∈ A" using assms by induct auto }
then show ?thesis by blast
qed
lemma segment_eq_orbit:
assumes "y ∉ orbit f x" shows "segment f x y = orbit f x"
proof (intro set_eqI iffI)
fix z assume "z ∈ segment f x y" then show "z ∈ orbit f x" by (rule segmentD_orbit)
next
fix z assume "z ∈ orbit f x" then show "z ∈ segment f x y"
using assms by induct (auto intro: segment.intros orbit_eqI elim: orbit.cases)
qed
lemma funpow_in_funcset:
assumes "x ∈ A" "f ∈ A → A" shows "(f ^^ n) x ∈ A"
using assms by (induct n) auto
lemma funpow_eq_funcset:
assumes "x ∈ A" "f ∈ A → A" "⋀y. y ∈ A ⟹ f y = g y"
shows "(f ^^ n) x = (g ^^ n) x"
using assms by (induct n) (auto, metis funpow_in_funcset)
lemma funpow_dist1_eq_funcset:
assumes "y ∈ orbit f x" "x ∈ A" "f ∈ A → A" "⋀y. y ∈ A ⟹ f y = g y"
shows "funpow_dist1 f x y = funpow_dist1 g x y"
proof -
have "y = (f ^^ funpow_dist1 f x y) x" by (metis assms(1) funpow_dist1_prop)
also have "… = (g ^^ funpow_dist1 f x y) x" by (metis assms(2-) funpow_eq_funcset)
finally have *: "y = (g ^^ funpow_dist1 f x y) x" .
then have "(g ^^ funpow_dist1 g x y) x = y" by (metis funpow_dist1_prop1 zero_less_Suc)
with * have gf: "funpow_dist1 g x y ≤ funpow_dist1 f x y"
by (metis funpow_dist1_least not_le zero_less_Suc)
have "(f ^^ funpow_dist1 g x y) x = y"
using ‹(g ^^ funpow_dist1 g x y) x = y› by (metis assms(2-) funpow_eq_funcset)
then have fg: "funpow_dist1 f x y ≤ funpow_dist1 g x y"
using ‹y = (f ^^ _) x› by (metis funpow_dist1_least not_le zero_less_Suc)
from gf fg show ?thesis by simp
qed
lemma segment_cong0:
assumes "x ∈ A" "f ∈ A → A" "⋀y. y ∈ A ⟹ f y = g y" shows "segment f x y = segment g x y"
proof (cases "y ∈ orbit f x")
case True
moreover
from assms have "orbit f x = orbit g x" by (rule orbit_cong0)
moreover
have "(f ^^ n) x = (g ^^ n) x ∧ (f ^^ n) x ∈ A" for n
by (induct n rule: nat.induct) (insert assms, auto)
ultimately show ?thesis
using True by (auto simp: segment_altdef funpow_dist1_eq_funcset[OF _ assms])
next
case False
moreover from assms have "orbit f x = orbit g x" by (rule orbit_cong0)
ultimately show ?thesis by (simp add: segment_eq_orbit)
qed
lemma rev_ok_final:
assumes wf_iG: "wf_digraph (mk_graph iG)"
assumes rev: "is_map_rev_ok_inv iG iM rev_i rev_ok" "is_map_final iG rev_i rev_ok"
shows "rev_ok ⟷ bidirected_digraph (mk_graph iG) (edge_rev (mk_map (mk_graph iG) iM))" (is "?L ⟷ ?R")
proof
assume "rev_ok"
interpret wf_digraph "mk_graph iG" by (rule wf_iG)
have rev_inv_sep:
"⋀i. i < length (ig_edges iG) ⟹ im_rev iM i < length (ig_edges iG)"
"⋀i. i < length (ig_edges iG) ⟹ ig_edges iG ! im_rev iM i = prod.swap (ig_edges iG ! i)"
"⋀i. i < length (ig_edges iG) ⟹ im_rev iM i ≠ i"
"⋀i. i < length (ig_edges iG) ⟹ im_rev iM (im_rev iM i) = i"
using rev ‹rev_ok› by (auto simp: is_map_rev_ok_inv_def is_map_final_def)
moreover
{ fix i assume "i < length (ig_edges iG)"
then have "ig_tail iG (im_rev iM i) = ig_head iG i"
using rev_inv_sep(2) by (cases "ig_edges iG ! i") (auto simp: ig_head_def ig_tail_def)
}
ultimately show ?R
using wf by unfold_locales (auto simp: mkg_simps arcs_mkg mkm_simps perm_restrict_def)
next
assume ?R
let ?rev = "perm_restrict (im_rev iM) (arcs (mk_graph iG))"
interpret bidirected_digraph "mk_graph iG" "perm_restrict (im_rev iM) (arcs (mk_graph iG))"
using ‹?R› by (simp add: mkm_simps mkg_simps)
have "⋀a. a ∈ arcs (mk_graph iG) ⟹ ?rev a ∈ arcs (mk_graph iG)"
"⋀a. a ∈ arcs (mk_graph iG) ⟹
arc_to_ends (mk_graph iG) (?rev a) = prod.swap (arc_to_ends (mk_graph iG) a)"
"⋀a. a ∈ arcs (mk_graph iG) ⟹ ?rev a ≠ a"
"⋀a. a ∈ arcs (mk_graph iG) ⟹ ?rev (?rev a) = a"
by (auto simp: arev_dom)
then show rev_ok
using rev unfolding is_map_rev_ok_inv_def is_map_final_def
by (simp add: perm_restrict_simps arcs_mkg arc_to_ends_mkg)
qed
locale is_map_postcondition0 =
fixes iG iM rev_ok succ_i succ_ok
assumes succ_perm: "is_map_succ_perm_inv iG iM succ_i succ_ok" "is_map_final iG succ_i succ_ok"
begin
lemma succ_ok_tail_eq:
"succ_ok ⟹ i < length (ig_edges iG) ⟹ ig_tail iG (im_succ iM i) = ig_tail iG i "
using succ_perm unfolding is_map_succ_perm_inv_def is_map_final_def by auto
lemma succ_ok_imp_pred:
"succ_ok ⟹ i < length (ig_edges iG) ⟹ im_pred iM (im_succ iM i) = i"
using succ_perm unfolding is_map_succ_perm_inv_def is_map_final_def by auto
lemma succ_ok_imp_permutes:
assumes "succ_ok"
shows "edge_succ (mk_map (mk_graph iG) iM) permutes arcs (mk_graph iG)"
proof -
from assms have "∀a ∈ arcs (mk_graph iG). edge_succ (mk_map (mk_graph iG) iM) a ∈ arcs (mk_graph iG)"
using succ_perm unfolding is_map_succ_perm_inv_def is_map_final_def
by (auto simp: mkg_simps mkm_simps arcs_mkg perm_restrict_def)
with succ_ok_imp_pred[OF assms] show ?thesis
by - (rule permutesI_finite_dom[where g="im_pred iM"], auto simp: perm_restrict_simps mkm_simps arcs_mkg)
qed
lemma es_A2A: "succ_ok ⟹ edge_succ (mk_map (mk_graph iG) iM) ∈ arcs (mk_graph iG) → arcs (mk_graph iG)"
using succ_ok_imp_permutes by (auto dest: permutes_in_image)
lemma im_succ_le_length: "succ_ok ⟹ i < length (ig_edges iG) ⟹ im_succ iM i < length (ig_edges iG)"
using is_map_final_def is_map_succ_perm_inv_def succ_perm(1) succ_perm(2) by auto
lemma orbit_es_eq_im:
"succ_ok ⟹ a ∈ arcs (mk_graph iG) ⟹ orbit (edge_succ (mk_map (mk_graph iG) iM)) a = orbit (im_succ iM) a"
using _ es_A2A es_eq_im by (rule orbit_cong0)
lemma segment_es_eq_im:
"succ_ok ⟹ a ∈ arcs (mk_graph iG) ⟹ segment (edge_succ (mk_map (mk_graph iG) iM)) a b = segment (im_succ iM) a b"
using _ es_A2A es_eq_im by (rule segment_cong0)
lemma in_orbit_im_succE:
assumes "j ∈ orbit (im_succ iM) i" "succ_ok" "i < length (ig_edges iG)"
obtains "ig_tail iG j = ig_tail iG i" "j < length (ig_edges iG)"
using assms es_A2A by induct (force simp add: succ_ok_tail_eq es_eq_im arcs_mkg)+
lemma self_in_orbit_im_succ:
assumes "succ_ok" "i < length (ig_edges iG)" shows "i ∈ orbit (im_succ iM) i"
proof -
have "i ∈ orbit (edge_succ (mk_map (mk_graph iG) iM)) i"
using assms succ_ok_imp_permutes
by (intro permutation_self_in_orbit) (auto simp: permutation_permutes arcs_mkg)
with assms show ?thesis by (simp add:orbit_es_eq_im arcs_mkg)
qed
end
locale is_map_postcondition = is_map_postcondition0 +
fixes so_i so_ok V A
assumes rev: "rev_ok ⟷ bidirected_digraph (mk_graph iG) (edge_rev (mk_map (mk_graph iG) iM))"
assumes succ_orbits: "is_map_succ_orbits_inv iG iM so_i so_ok V A" "succ_ok ⟶ is_map_final iG so_i so_ok"
begin
lemma ok_imp_digraph:
assumes rev_ok succ_ok so_ok
shows "digraph_map (mk_graph iG) (mk_map (mk_graph iG) iM)"
proof -
interpret bidirected_digraph "mk_graph iG" "edge_rev (mk_map (mk_graph iG) iM)"
using ‹rev_ok› by (simp add: rev)
from ‹succ_ok› have perm: "edge_succ (mk_map (mk_graph iG) iM) permutes arcs (mk_graph iG)"
by (simp add: succ_ok_imp_permutes)
from ‹succ_ok› have ig_tail: "⋀a. a ∈ arcs (mk_graph iG) ⟹ ig_tail iG (im_succ iM a) = ig_tail iG a"
by (simp_all add: succ_ok_tail_eq arcs_mkg)
{ fix v assume "v ∈ verts (mk_graph iG)" "out_arcs (mk_graph iG) v ≠ {}"
then obtain a where a: "a ∈ arcs (mk_graph iG)" "tail (mk_graph iG) a = v" by auto metis
then have "out_arcs (mk_graph iG) v = {b ∈ arcs (mk_graph iG). ig_tail iG a = ig_tail iG b}"
by (auto simp: mkg_simps)
also have "… ⊆ orbit (im_succ iM) a"
proof -
have "(∀i<length (snd iG). ∀j<length (snd iG).
ig_tail iG i = ig_tail iG j ⟶ j ∈ orbit (im_succ iM) i)"
using ‹succ_ok ›‹so_ok› succ_orbits unfolding is_map_succ_orbits_inv_def is_map_final_def by metis
with a show ?thesis by (auto simp: arcs_mkg)
qed
finally have "out_arcs (mk_graph iG) v ⊆ orbit (im_succ iM) a" .
moreover
have "orbit (im_succ iM) a ⊆ out_arcs (mk_graph iG) v"
proof -
{ fix x assume "x ∈ orbit (im_succ iM) a" then have "tail (mk_graph iG) x = v"
using a ig_tail
apply induct
apply (auto simp: mkg_simps intro: orbit.intros)
by (metis ‹succ_ok› contra_subsetD orbit_es_eq_im permutes_orbit_subset perm)
} moreover
have "orbit (im_succ iM) a ⊆ arcs (mk_graph iG)"
using _ a(1) apply (rule orbit_ss)
using assms arcs_mkg is_map_final_def is_map_succ_perm_inv_def succ_perm(1) succ_perm(2) by auto
ultimately
show ?thesis by auto
qed
ultimately
have "out_arcs (mk_graph iG) v = orbit (edge_succ (mk_map (mk_graph iG) iM)) a"
using ‹succ_ok› a by (auto simp: orbit_es_eq_im)
then
have "cyclic_on (edge_succ (mk_map (mk_graph iG) iM)) (out_arcs (mk_graph iG) v)"
unfolding cyclic_on_def using a by force
}
with perm show ?thesis
using ‹rev_ok› by unfold_locales (auto simp: mkg_simps arcs_mkg)
qed
lemma digraph_imp_ok:
assumes dm: "digraph_map (mk_graph iG) (mk_map (mk_graph iG) iM)"
assumes pred: "⋀i. i < length (ig_edges iG) ⟹ im_pred iM (im_succ iM i) = i"
obtains rev_ok succ_ok so_ok
proof
interpret dm: digraph_map "mk_graph iG" "mk_map (mk_graph iG) iM" by (fact dm)
show rev_ok unfolding rev by unfold_locales
show succ_ok
proof -
{ fix i assume "i ∈ arcs (mk_graph iG)"
then have
"edge_succ (mk_map (mk_graph iG) iM) i ∈ arcs (mk_graph iG)"
"tail (mk_graph iG) (edge_succ (mk_map (mk_graph iG) iM) i) = tail (mk_graph iG) i"
by auto
then have
"im_succ iM i < length (snd iG)"
"ig_tail iG (im_succ iM i) = ig_tail iG i"
unfolding es_eq_im[OF ‹i ∈ arcs _›] by (auto simp: arcs_mkg mkg_simps)
}
then have "(∀i<length (ig_edges iG).
im_succ iM i < length (snd iG) ∧
ig_tail iG (im_succ iM i) = ig_tail iG i ∧ im_pred iM (im_succ iM i) = i)"
using pred by (auto simp: arcs_mkg es_eq_im)
with succ_perm show ?thesis
unfolding is_map_succ_perm_inv_def is_map_final_def by simp
qed
show so_ok
proof -
{ fix i j assume "i < length (ig_edges iG)" "j < length (ig_edges iG)" "ig_tail iG i = ig_tail iG j"
then have A: "i ∈ arcs (mk_graph iG)" "j ∈ arcs (mk_graph iG)" "tail (mk_graph iG) i = tail (mk_graph iG) j"
by (auto simp: mkg_simps arcs_mkg)
then have "cyclic_on (edge_succ (mk_map (mk_graph iG) iM)) (out_arcs (mk_graph iG) (tail (mk_graph iG) i))"
by (auto intro!: dm.edge_succ_cyclic)
then have "orbit (edge_succ (mk_map (mk_graph iG) iM)) i = out_arcs (mk_graph iG) (ig_tail iG i)"
by (simp add: ‹i ∈ arcs (mk_graph iG)› mkg_simps orbit_cyclic_eq3)
then have "j ∈ orbit (edge_succ (mk_map (mk_graph iG) iM)) i" using A by (simp add: mkg_simps)
also have "orbit (edge_succ (mk_map (mk_graph iG) iM)) i = orbit (im_succ iM) i"
using ‹i ∈ arcs _›
by (rule orbit_cong0) (fastforce, simp add: es_eq_im)
finally have "j ∈ orbit (im_succ iM) i" .
}
then show ?thesis
using succ_orbits unfolding is_map_succ_orbits_inv_def is_map_final_def
by safe (simp_all only: ‹succ_ok› simp_thms)
qed
qed
end
lemma all_less_Suc_eq: "(∀x < Suc n. P x) ⟷ (∀x < n. P x) ∧ P n"
by (auto elim: less_SucE)
lemma in_orbit_imp_in_segment:
assumes "y ∈ orbit f x" "x ≠ y" "bij f" shows "y ∈ segment f x (f y)"
using assms
proof induct
case base then show ?case by (auto intro: segment.intros simp: bij_iff)
next
case (step y)
show ?case
proof (cases "x = y")
case True then show ?thesis using step by (auto intro: segment.intros simp: bij_iff)
next
case False
with step have "f y ≠ f (f y)" by (metis bij_is_inj inv_f_f not_in_segment2)
then show ?thesis using step False
by (auto intro: segment.intros segment_step_2 bij_is_inj)
qed
qed
lemma ovalidNF_is_map: "
ovalidNF (λs. distinct (ig_verts iG) ∧ wf_digraph (mk_graph iG))
(is_map iG iM)
(λr s. r ⟷ digraph_map (mk_graph iG) (mk_map (mk_graph iG) iM) ∧ (∀i < length (ig_edges iG). im_pred iM (im_succ iM i) = i))
"
unfolding is_map_def
apply (rewrite
in "oreturn (length (ig_edges iG)) |>> (λecnt. ⌑)"
to "owhile_inv _ _ _
(λ(i, ok) s. is_map_rev_ok_inv iG iM i ok
∧ i ≤ ecnt ∧ wf_digraph (mk_graph iG))
(measure (λ(i, ok). ecnt - i))
" owhile_inv_def[symmetric] )
apply (rewrite
in "owhile_inv _ _ _ _ _ |>> (λ(rev_i, rev_ok). ⌑)"
in "oreturn (length (ig_edges iG)) |>> (λecnt. ⌑)"
to "owhile_inv _ _ _
(λ(i, ok) s. is_map_succ_perm_inv iG iM i ok
∧ rev_ok = bidirected_digraph (mk_graph iG) (edge_rev (mk_map (mk_graph iG) iM))
∧ i ≤ ecnt ∧ wf_digraph (mk_graph iG))
(measure (λ(i, ok). ecnt - i))
" owhile_inv_def[symmetric] )
apply (rewrite
in "owhile_inv _ _ _ _ _ |>> (λ(succ_i, succ_ok). ⌑)"
in "owhile_inv _ _ _ _ _ |>> (λ(rev_i, rev_ok). ⌑)"
in "oreturn (length (ig_edges iG)) |>> (λecnt. ⌑)"
to "owhile_inv _ _ _
(λ(i, ok, V, A) s. is_map_succ_orbits_inv iG iM i ok V A
∧ rev_ok = bidirected_digraph (mk_graph iG) (edge_rev (mk_map (mk_graph iG) iM))
∧ is_map_succ_perm_inv iG iM succ_i succ_ok ∧ is_map_final iG succ_i succ_ok
∧ i ≤ ecnt ∧ wf_digraph (mk_graph iG))
(measure (λ(i, ok, V, A). ecnt - i))
" owhile_inv_def[symmetric] )
apply (rewrite
in "owhile_inv _ (λ(i, ok, V, A). ⌑) _ _ _"
in "owhile_inv _ _ _ _ _ |>> (λ(succ_i, succ_ok). ⌑)"
in "owhile_inv _ _ _ _ _ |>> (λ(rev_i, rev_ok). ⌑)"
in "oreturn (length (ig_edges iG)) |>> (λecnt. ⌑)"
to "owhile_inv _ _ _
(λ(A', j) s. is_map_succ_orbits_inner_inv iG iM i j A'
∧ ig_tail iG i ∉ V ∧ succ_ok ∧ ok ∧ is_map_succ_orbits_inv iG iM i ok V A
∧ rev_ok = bidirected_digraph (mk_graph iG) (edge_rev (mk_map (mk_graph iG) iM))
∧ is_map_succ_perm_inv iG iM succ_i succ_ok ∧ is_map_final iG succ_i succ_ok
∧ i < ecnt ∧ wf_digraph (mk_graph iG))
(measure (λ(A',j). length (ig_edges iG) - card A'))
" owhile_inv_def[symmetric] )
proof vcg_casify
let ?es = "edge_succ (mk_map (mk_graph iG) iM)"
{ case weaken then show ?case by (auto simp: is_map_rev_ok_inv_def)
}
{ case (while i ok)
{ case invariant
case weaken then show ?case by (auto simp: is_map_rev_ok_inv_def elim: less_SucE)
}
{ case wf show ?case by auto
}
{ case postcondition
then have "ok ⟷ bidirected_digraph (mk_graph iG) (edge_rev (mk_map (mk_graph iG) iM))"
by (intro rev_ok_final) (auto simp: is_map_final_def)
with postcondition show ?case by (auto simp: is_map_succ_perm_inv_def)
}
}
case (bind _ rev_ok)
{ case (while i ok)
{ case invariant case weaken
then show ?case by (auto simp: is_map_succ_perm_inv_def elim: less_SucE)
}
{ case wf show ?case by auto
}
{ case postcondition
then show ?case by (auto simp: is_map_final_def is_map_succ_orbits_inv_def)
}
}
case (bind succ_i succ_ok)
{ case (while i ok V A)
{ case invariant
{ case weaken
then interpret pc0: is_map_postcondition0 iG iM rev_ok succ_i succ_ok
by unfold_locales auto
from weaken.loop_cond have "i < length (ig_edges iG)" succ_ok ok by auto
with weaken.loop_inv have
V: "V = {ig_tail iG k |k. k < i}" and
A: "A = (⋃ k<i. orbit (im_succ iM) k)"
by (simp_all add: is_map_succ_orbits_inv_def)
show ?case
proof branch_casify
case "then" case g
have V': "V = {ig_tail iG ia |ia. ia < (if i ∈ A then Suc i else Suc i - 1)}"
using g ‹V = _› by (auto elim: less_SucE)
have "is_map_succ_orbits_inv iG iM (Suc i) (i ∈ A) V A"
proof (cases "i ∈ A")
case True
obtain j where j: "j < i" "i ∈ orbit (im_succ iM) j"
using True ‹A = _› by auto
have i_in_less_i: "∃x∈{..<i}. i ∈ orbit (im_succ iM) x"
using True ‹A = _› by auto
have A': "A = (⋃ i<if True then Suc i else Suc i - 1. orbit (im_succ iM) i)"
using True unfolding ‹A = _› by (auto 4 3 intro: orbit_trans elim: less_SucE)
have X: "∀k<i. ∀l<i. ig_tail iG k = ig_tail iG l ⟶ l ∈ orbit (im_succ iM) k"
using weaken unfolding is_map_succ_orbits_inv_def by metis
moreover
{ fix j assume j: "j < i" "ig_tail iG j = ig_tail iG i"
from i_in_less_i obtain k where k: "k < i" "i ∈ orbit (im_succ iM) k" by auto
then have "ig_tail iG k = ig_tail iG i"
using ‹succ_ok› ‹i < _› by (auto elim: pc0.in_orbit_im_succE)
then have "k ∈ orbit (im_succ iM) j"
using j ‹ig_tail iG k = _› k X by auto
then have "i ∈ orbit (im_succ iM) j" using k by (auto intro: orbit_trans)
}
ultimately
have "∀k<Suc i. ∀l<Suc i. ig_tail iG k = ig_tail iG l ⟶ l ∈ orbit (im_succ iM) k"
unfolding all_less_Suc_eq using ‹i < _› ‹succ_ok›
by (auto intro: orbit_swap pc0.self_in_orbit_im_succ)
with True show ?thesis
by (simp only: A' V' simp_thms is_map_succ_orbits_inv_def)
next
case False
from V g obtain j where j: "j < i" "ig_tail iG j = ig_tail iG i" by auto
with False show ?thesis
by (auto 0 3 simp: is_map_succ_orbits_inv_def V' A intro: exI[where x=j] exI[where x=i])
qed
then show ?case using weaken by auto
next
case "else" case g
have "is_map_succ_orbits_inner_inv iG iM i i {}"
unfolding is_map_succ_orbits_inner_inv_def
using ‹succ_ok› ‹i < _› by (auto simp: pc0.self_in_orbit_im_succ)
with g weaken show ?case by blast
qed
}
{ case "if" case else case (while A' i')
{ case invariant case weaken
then interpret pc0: is_map_postcondition0 iG iM rev_ok succ_i succ_ok
by unfold_locales auto
have "succ_ok" "i < length (ig_edges iG)" "i' ∈ orbit (im_succ iM) i"
using weaken by (auto simp: is_map_succ_orbits_inner_inv_def)
have "i' < length (ig_edges iG)"
using ‹i' ∈ _› ‹succ_ok› ‹i < _› by (rule pc0.in_orbit_im_succE)
{ assume "i' ∈ orbit (im_succ iM) i" "i ≠ i'"
then have "i' ∈ orbit (?es) i"
by (subst pc0.orbit_es_eq_im) (auto simp add: ‹succ_ok› ‹i < _› arcs_mkg)
then have "i' ∈ segment (?es) i (?es i')"
using ‹i ≠ i'› pc0.succ_ok_imp_permutes ‹succ_ok ›
by (intro in_orbit_imp_in_segment) (auto simp: permutes_conv_has_dom)
then have "i' ∈ segment (im_succ iM) i (im_succ iM i')"
by (subst pc0.segment_es_eq_im[symmetric] es_eq_im[symmetric];
auto simp add: ‹succ_ok› ‹i < _› ‹i' < _› arcs_mkg)+
} note X = this
{ fix x assume "x ∈ segment (im_succ iM) i i'" "i ≠ i'"
then have "x ∈ segment (?es) i i'"
by (subst pc0.segment_es_eq_im) (auto simp add: ‹succ_ok› ‹i < _› ‹i' < _› arcs_mkg)
then have "x ∈ segment (?es) i (?es i')"
using ‹i ≠ i'› pc0.succ_ok_imp_permutes ‹succ_ok ›
by (auto simp: permutes_conv_has_dom bij_is_inj intro: segment_step_2)
then have "x ∈ segment (im_succ iM) i (im_succ iM i')"
by (subst pc0.segment_es_eq_im[symmetric] es_eq_im[symmetric];
auto simp add: ‹succ_ok› ‹i < _› ‹i' < _› arcs_mkg)+
} note Y = this
have Z: "is_map_succ_orbits_inner_inv iG iM i (im_succ iM i') (insert i' A')"
using weaken unfolding is_map_succ_orbits_inner_inv_def
by (auto dest: segment_step_2D X Y simp: orbit.intros segment1_empty split: if_splits)
have "A' ⊆ orbit (im_succ iM) i"
using weaken unfolding is_map_succ_orbits_inner_inv_def
by (auto simp: pc0.self_in_orbit_im_succ dest: segmentD_orbit split: if_splits)
also have "… ⊆ arcs (mk_graph iG)"
by (rule orbit_ss) (auto simp: arcs_mkg pc0.im_succ_le_length ‹succ_ok› ‹i < _›)
finally have "card A' < card (arcs (mk_graph iG))" "finite A'"
using ‹i' ∉ A'› ‹i' < _›
by - (intro psubset_card_mono, auto simp: arcs_mkg intro: finite_subset)
then have "card A' < length (ig_edges iG)" by (simp add: arcs_mkg)
show ?case
using weaken Z ‹card A' < length _› by (auto simp: card_insert_if ‹finite A'›)
}
{ case wf show ?case by simp
}
{ case postcondition
then interpret pc0: is_map_postcondition0 iG iM rev_ok succ_i succ_ok
by unfold_locales auto
from postcondition have "ok" "succ_ok" "i < length (ig_edges iG)" by simp_all
from postcondition
have "i' ∈ A'"
"A' = (if i = i' ∧ i ∉ A' then {} else {i} ∪ segment (im_succ iM) i i')"
"i' ∈ orbit (im_succ iM) i"
"ig_tail iG i ∉ V"
by (simp_all add: is_map_succ_orbits_inner_inv_def)
moreover
then have "i = i'" by (simp split: if_splits add: not_in_segment2)
ultimately
have "A' = {i} ∪ segment (im_succ iM) i i" by simp
also have "segment (im_succ iM) i i = segment ?es i i"
by (auto simp: pc0.segment_es_eq_im ‹succ_ok› ‹i < _› arcs_mkg)
also have "… = orbit ?es i - {i}"
using pc0.succ_ok_imp_permutes ‹succ_ok›
by (auto simp: permutation_permutes arcs_mkg intro!: segment_x_x_eq)
also have "… = orbit (im_succ iM) i - {i}"
by (auto simp: pc0.orbit_es_eq_im ‹succ_ok› ‹i < _› arcs_mkg)
finally
have A': "A' = orbit (im_succ iM) i"
using ‹i < _› ‹succ_ok› by (auto simp: pc0.self_in_orbit_im_succ)
from postcondition
have "A = (⋃k<i. orbit (im_succ iM) k)"
unfolding is_map_succ_orbits_inner_inv_def by (simp add: is_map_succ_orbits_inv_def)
have "A ∪ A' = (⋃k<Suc i. orbit (im_succ iM) k)"
unfolding A' ‹A = _› by (auto 2 3 elim: less_SucE)
from postcondition have "V = {ig_tail iG ia |ia. ia < i}"
by (auto simp: ‹ok› is_map_succ_orbits_inv_def)
then have V': "insert (ig_tail iG i') V = {ig_tail iG ia |ia. ia < Suc i}"
by (auto simp add: ‹i = i'› elim: less_SucE)
have *: "⋀k. k < i ⟹ ig_tail iG k ≠ ig_tail iG i"
using ‹V = _› ‹ig_tail iG i ∉ V› by auto
from postcondition have "(∀k<i. ∀l<i. ig_tail iG k = ig_tail iG l ⟶ l ∈ orbit (im_succ iM) k)"
by (simp add: is_map_succ_orbits_inv_def ‹ok›)
then have X: "(∀k<Suc i. ∀l<Suc i. ig_tail iG k = ig_tail iG l ⟶ l ∈ orbit (im_succ iM) k)"
by (auto simp add: all_less_Suc_eq pc0.self_in_orbit_im_succ ‹succ_ok› ‹i < _› dest: *)
have "is_map_succ_orbits_inv iG iM (i + 1) True (insert (ig_tail iG i') V) (A ∪ A')"
unfolding is_map_succ_orbits_inv_def by (simp add: ‹A ∪ A' = _› V' X)
then show ?case
using postcondition ‹i < _› by auto
}
}
}
{ case wf show ?case by auto
}
{ case postcondition
interpret pc: is_map_postcondition iG iM rev_ok succ_i succ_ok i ok V A
using postcondition by unfold_locales (auto simp: is_map_final_def)
show ?case (is "?L = ?R")
by (auto simp add: pc.ok_imp_digraph dest: pc.succ_ok_imp_pred elim: pc.digraph_imp_ok)
}
}
qed
declare ovalidNF_is_map[THEN ovalidNF_wp, THEN trivial_label, vcg_l]
subsubsection ‹@{term isolated_nodes}›
definition "inv_isolated_nodes s iG vcnt ecnt ≡
vcnt = length (ig_verts iG)
∧ ecnt = length (ig_edges iG)
∧ distinct (ig_verts iG)
∧ sym_digraph (mk_graph iG)
"
definition "inv_isolated_nodes_outer iG i nz ≡
nz = card (pre_digraph.isolated_verts (mk_graph iG) ∩ set (take i (ig_verts iG)))"
definition "inv_isolated_nodes_inner iG v j ≡
∀k < j. v ≠ ig_tail iG k ∧ v ≠ ig_head iG k"
lemma (in sym_digraph) in_arcs_empty_iff:
"in_arcs G v = {} ⟷ out_arcs G v = {}"
by (auto simp: out_arcs_def in_arcs_def)
(metis graph_symmetric in_arcs_imp_in_arcs_ends reachableE)+
lemma take_nth_distinct:
"⟦distinct xs; n < length xs; xs ! n ∈ set (take n xs)⟧ ⟹ False"
by (fastforce simp: distinct_conv_nth in_set_conv_nth)
lemma ovalidNF_isolated_nodes: "
ovalidNF (λs. distinct (ig_verts iG) ∧ sym_digraph (mk_graph iG))
(isolated_nodes iG)
(λr s. r = (card (pre_digraph.isolated_verts (mk_graph iG))))"
unfolding isolated_nodes_def
apply (rewrite
in "oreturn (length (ig_verts iG)) |>> (λvcnt. ⌑)"
in "oreturn (length (ig_edges iG)) |>> (λecnt. ⌑)"
to "owhile_inv _ _ _
(λ(i, nz) s. inv_isolated_nodes s iG vcnt ecnt
∧ inv_isolated_nodes_outer iG i nz
∧ i ≤ vcnt)
(measure (λ(i, nz). vcnt - i))
" owhile_inv_def[symmetric] )
apply (rewrite
in "oreturn (fst iG ! i) |>> (λv. ⌑)"
in "owhile_inv _ (λ(i, nz). ⌑)"
in "oreturn (length (ig_verts iG)) |>> (λvcnt. ⌑)"
in "oreturn (length (ig_edges iG)) |>> (λecnt. ⌑)"
to "owhile_inv _ _ _
(λ(j, ret) s. inv_isolated_nodes s iG vcnt ecnt
∧ inv_isolated_nodes_inner iG v j
∧ inv_isolated_nodes_outer iG i nz
∧ v = ig_verts iG ! i
∧ ret = (j < ecnt ∧ ig_tail iG j ≠ v ∧ ig_head iG j ≠ v)
∧ i < vcnt
∧ j ≤ ecnt)
(measure (λ(j, ret). ecnt - j))
" owhile_inv_def[symmetric])
proof vcg_casify
case (weaken s)
then show ?case
by (auto simp: inv_isolated_nodes_def inv_isolated_nodes_outer_def)
next
case (while i nz)
{ case invariant
{ case (weaken s')
then show ?case unfolding BRANCH_def by (auto simp: inv_isolated_nodes_inner_def)
next
case bind
case bind
case (while j cond)
{ case invariant
{ case weaken
show ?case
proof branch_casify
case "else" case "else" case g
with weaken have "length (ig_edges iG) = j + 1" by linarith
with weaken show ?case
by (auto simp: inv_isolated_nodes_inner_def elim: less_SucE)
qed (insert weaken, auto simp: inv_isolated_nodes_inner_def elim: less_SucE)
}
next
case wf show ?case by auto
next
case postcondition
interpret G: sym_digraph "mk_graph iG" using postcondition by (simp add: inv_isolated_nodes_def)
have ?var using postcondition by auto
let ?v = "ig_verts iG ! i"
{ assume A: "j = length (snd iG)"
have "?v ∈ pre_digraph.isolated_verts (mk_graph iG)"
using A postcondition by (auto simp: pre_digraph.isolated_verts_def mkg_simps inv_isolated_nodes_inner_def arcs_mkg)
have "distinct (ig_verts iG)" "?v = ig_verts iG ! i" "i < length (ig_verts iG)"
using postcondition by (auto simp: inv_isolated_nodes_def)
then have "?v ∉ set (take i (ig_verts iG))"
by (metis take_nth_distinct)
have "Suc (card (pre_digraph.isolated_verts (mk_graph iG) ∩ set (take i (fst iG))))
= card (insert ?v (pre_digraph.isolated_verts (mk_graph iG) ∩ set (take i (fst iG))))" (is "_ = card ?S")
using ‹?v ∉ _› by simp
also have "?S = pre_digraph.isolated_verts (mk_graph iG) ∩ set (take (Suc i) (fst iG))"
using ‹?v ∈ _› ‹i < _› ‹?v = _› by (auto simp: take_Suc_conv_app_nth)
finally
have "inv_isolated_nodes_outer iG (Suc i) (Suc nz)"
using postcondition by (auto simp: inv_isolated_nodes_outer_def)
}
moreover
{ assume A: "j ≠ length (snd iG)"
then have *: "j ∈ (out_arcs (mk_graph iG) ?v ∪ in_arcs (mk_graph iG) ?v)"
using postcondition by (auto simp: arcs_mkg mkg_simps ig_tail_def ig_head_def)
then have "out_arcs (mk_graph iG) ?v ≠ {}"
by (auto simp del: in_in_arcs_conv in_out_arcs_conv)
(auto simp: G.in_arcs_empty_iff[symmetric])
then have "?v ∉ pre_digraph.isolated_verts (mk_graph iG)"
by (auto simp: pre_digraph.isolated_verts_def)
then have "inv_isolated_nodes_outer iG (Suc i) nz"
using postcondition by (auto simp: inv_isolated_nodes_outer_def take_Suc_conv_app_nth)
}
ultimately
have ?inv using postcondition by auto
from ‹?var› ‹?inv› show ?case by blast
}
}
next
case wf show ?case by auto
next
case postcondition
have "pre_digraph.isolated_verts (mk_graph iG) ∩ set (fst iG) = pre_digraph.isolated_verts (mk_graph iG)"
by (auto simp: pre_digraph.isolated_verts_def mkg_simps)
with postcondition show ?case
by (auto simp: inv_isolated_nodes_def inv_isolated_nodes_outer_def)
}
qed
declare ovalidNF_isolated_nodes[THEN ovalidNF_wp, THEN trivial_label, vcg_l]
subsubsection ‹@{term face_cycles}›
definition "inv_face_cycles s iG iM ecnt ≡
ecnt = length (ig_edges iG)
∧ digraph_map (mk_graph iG) iM
"
definition fcs_upto :: "nat pre_map ⇒ nat ⇒ nat set set" where
"fcs_upto iM i ≡ {pre_digraph_map.face_cycle_set iM k | k. k < i}"
definition "inv_face_cycles_outer s iG iM i c edge_info ≡
let fcs = fcs_upto iM i in
c = card fcs
∧ (∀k < length (ig_edges iG). k ∈ edge_info ⟷ k ∈ ⋃fcs)"
definition "inv_face_cycles_inner s iG iM i j c edge_info ≡
j ∈ pre_digraph_map.face_cycle_set iM i
∧ c = card (fcs_upto iM i)
∧ i ∉ ⋃(fcs_upto iM i)
∧ (∀k < length (ig_edges iG). k ∈ edge_info ⟷
(k ∈ ⋃(fcs_upto iM i)
∨ (∃l < funpow_dist1 (pre_digraph_map.face_cycle_succ iM) i j. (pre_digraph_map.face_cycle_succ iM ^^ l) i = k)))"
lemma finite_fcs_upto: "finite (fcs_upto iM i)"
by (auto simp: fcs_upto_def)
lemma card_orbit_eq_funpow_dist1:
assumes "x ∈ orbit f x" shows "card (orbit f x) = funpow_dist1 f x x"
proof -
have "card (orbit f x) = card ((λn. (f ^^ n) x) ` {0..<funpow_dist1 f x x})"
using assms by (simp only: orbit_conv_funpow_dist1[symmetric])
also have "… = card {0..<funpow_dist1 f x x}"
using assms by (intro card_image inj_on_funpow_dist1)
finally show ?thesis by simp
qed
lemma funpow_dist1_le:
assumes "y ∈ orbit f x" "x ∈ orbit f x"
shows "funpow_dist1 f x y ≤ funpow_dist1 f x x"
using assms by (intro funpow_dist1_le_self funpow_dist1_prop) simp_all
lemma funpow_dist1_le_card:
assumes "y ∈ orbit f x" "x ∈ orbit f x"
shows "funpow_dist1 f x y ≤ card (orbit f x)"
using funpow_dist1_le[OF assms] using assms
by (simp add: card_orbit_eq_funpow_dist1)
lemma (in digraph_map) funpow_dist1_le_card_fcs:
assumes "b ∈ face_cycle_set a"
shows "funpow_dist1 face_cycle_succ a b ≤ card (face_cycle_set a)"
by (metis assms face_cycle_set_def face_cycle_set_self funpow_dist1_le_card)
lemma funpow_dist1_f_eq:
assumes "b ∈ orbit f a" "a ∈ orbit f a" "a ≠ b"
shows "funpow_dist1 f a (f b) = Suc (funpow_dist1 f a b)"
proof -
have f_inj: "inj_on (λn. (f ^^ n) a) {0..<funpow_dist1 f a a}"
by (rule inj_on_funpow_dist1) (rule assms)
have "funpow_dist1 f a b ≤ funpow_dist1 f a a"
using assms by (intro funpow_dist1_le)
moreover
have "funpow_dist1 f a b ≠ funpow_dist1 f a a"
by (metis assms funpow_dist1_prop)
ultimately
have f_less: "funpow_dist1 f a b < funpow_dist1 f a a" by simp
have f_Suc_eq: "(f ^^ Suc (funpow_dist1 f a b)) a = f b"
using assms by (metis funpow.simps(2) o_apply funpow_dist1_prop)
show ?thesis
proof (cases "f b = a")
case True
then show ?thesis
by (metis Suc_lessI f_Suc_eq f_less assms(2) funpow.simps(1) funpow_neq_less_funpow_dist1 id_apply old.nat.distinct(1) zero_less_Suc)
next
case False
then have *: "Suc (funpow_dist1 f a b) < funpow_dist1 f a a"
using f_Suc_eq by (metis assms(2) f_less funpow_dist1_prop le_less_Suc_eq less_Suc_eq_le not_less_eq)
from f_inj have **: "⋀n. n < funpow_dist1 f a a ⟹ n ≠ Suc (funpow_dist1 f a b) ⟹ (f ^^ n) a ≠ f b"
using f_Suc_eq by (auto dest!: inj_onD) (metis * assms(2) f_Suc_eq funpow_neq_less_funpow_dist1)
show ?thesis
proof (rule ccontr)
assume A: "¬?thesis"
have "(f ^^ (funpow_dist1 f a (f b))) a = f b"
using assms by (intro funpow_dist1_prop) (simp add: orbit.intros)
with A ** have "funpow_dist1 f a a ≤ (funpow_dist1 f a (f b))"
by (metis less_Suc_eq_le not_less_eq)
then have "Suc (funpow_dist1 f a b) < (funpow_dist1 f a (f b))" using * by linarith
then have "(f ^^ Suc (funpow_dist1 f a b)) a ≠ f b"
by (intro funpow_dist1_least) simp_all
then show False using f_Suc_eq by simp
qed
qed
qed
lemma (in -) funpow_dist1_less_f:
assumes "b ∈ orbit f a" "a ∈ orbit f a" "a ≠ b"
shows "funpow_dist1 f a b < funpow_dist1 f a (f b)"
using assms by (simp add: funpow_dist1_f_eq)
lemma ovalidNF_face_cycles: "
ovalidNF (λs. digraph_map (mk_graph iG) iM)
(face_cycles iG iM)
(λr s. r = card (pre_digraph_map.face_cycle_sets (mk_graph iG) iM))
"
unfolding face_cycles_def
apply (rewrite
in "oreturn (length (ig_edges iG)) |>> (λecnt. ⌑)"
to "owhile_inv _ _ _
(λ(edge_info, c, i) s. inv_face_cycles s iG iM ecnt
∧ inv_face_cycles_outer s iG iM i c edge_info
∧ i ≤ ecnt)
(measure (λ(edge_info, c, i). ecnt - i))
" owhile_inv_def[symmetric]
)
apply (rewrite
in "owhile_inv _ (λ(_, c, i). ⌑)"
in "oreturn (length (ig_edges iG)) |>> (λecnt. ⌑)"
to "owhile_inv _ _ _
(λ(edge_info, j) s. inv_face_cycles s iG iM ecnt
∧ inv_face_cycles_inner s iG iM i j c edge_info
∧ i < ecnt)
(measure (λ(edge_info, j). card (pre_digraph_map.face_cycle_set iM i) - funpow_dist1 (pre_digraph_map.face_cycle_succ iM) i j))
" owhile_inv_def[symmetric]
)
proof vcg_casify
{ case (weaken s)
then show ?case by (auto simp add: inv_face_cycles_def inv_face_cycles_outer_def fcs_upto_def)
}
{ case (while edge_info c i)
{ case (postcondition s)
moreover have "fcs_upto iM (length (ig_edges iG))
= pre_digraph_map.face_cycle_sets (mk_graph iG) iM"
by (auto simp: pre_digraph_map.face_cycle_sets_def arcs_mkg fcs_upto_def)
ultimately show ?case by (auto simp: inv_face_cycles_outer_def Let_def)
}
{ case (invariant s)
{ case (weaken s')
interpret G: digraph_map "mk_graph iG" iM
using weaken by (auto simp: inv_face_cycles_def)
show ?case
proof branch_casify
case else case g
then have "G.face_cycle_set i ∈ {G.face_cycle_set k |k. k < i}"
using weaken by (auto simp: inv_face_cycles_outer_def fcs_upto_def dest: G.face_cycle_eq)
then have "{G.face_cycle_set k |k. k < Suc i} = {G.face_cycle_set k |k. k < i}"
by (auto elim: less_SucE)
then have "inv_face_cycles_outer s' iG iM (i + 1) c edge_info"
using weaken unfolding inv_face_cycles_outer_def by (auto simp: fcs_upto_def)
then have ?inv using weaken by auto
then show ?case using weaken by auto
next
case "then" case g
have fd1_triv: "⋀f x. funpow_dist1 f x (f x) = 1"
by (simp add: funpow_dist_0)
have fcs_in: "G.face_cycle_succ i ∈ G.face_cycle_set i"
by (simp add: G.face_cycle_succ_inI)
have i_not_in_fcs: "i ∉ ⋃(fcs_upto iM i)"
using g weaken
by (auto simp: inv_face_cycles_outer_def fcs_upto_def)
from weaken show ?case
unfolding inv_face_cycles_inner_def inv_face_cycles_outer_def
using i_not_in_fcs by (auto simp: fd1_triv fcs_in fcs_upto_def)
qed
}
{ case "if" case "then"
{ case (while edge_info j)
{ case (postcondition s')
interpret G: digraph_map "mk_graph iG" iM
using postcondition by (auto simp: inv_face_cycles_def)
have ?var using postcondition by auto
have fu_Suc: "fcs_upto iM (Suc j) = fcs_upto iM j ∪ {G.face_cycle_set j}"
by (auto simp: fcs_upto_def elim: less_SucE)
moreover
have "G.face_cycle_set j ∉ fcs_upto iM j" "c = card (fcs_upto iM j)"
using postcondition by (auto simp: inv_face_cycles_inner_def)
ultimately
have "Suc c = card (fcs_upto iM (Suc j))" by (simp add: finite_fcs_upto)
have *: "∀k<length (snd iG). k ∈ edge_info ⟷ (∃x∈fcs_upto iM (Suc j). k ∈ x)"
proof -
have *: "j ∈ orbit G.face_cycle_succ j"
by (simp add: G.face_cycle_set_def[symmetric])
have "⋀k. (∃l<funpow_dist1 G.face_cycle_succ j j. (G.face_cycle_succ ^^ l) j = k) ⟷ (k ∈ G.face_cycle_set j)"
by (auto simp: G.face_cycle_set_def orbit_conv_funpow_dist1[OF *])
moreover
from postcondition have "inv_face_cycles_inner s' iG iM j j c edge_info"
by auto
ultimately
show ?thesis unfolding inv_face_cycles_inner_def fu_Suc by auto
qed
have ?inv using postcondition *
by (auto simp: inv_face_cycles_outer_def ‹Suc c = _›)
with ‹?var› show ?case by blast
}
{ case (invariant s')
{ case (weaken s'')
interpret G: digraph_map "mk_graph iG" iM
using weaken by (auto simp: inv_face_cycles_def)
have "j ∈ G.face_cycle_set i"
using weaken by (auto simp: inv_face_cycles_inner_def)
then have "j ∈ arcs (mk_graph iG)"
by (metis G.face_cycle_set_def G.funpow_face_cycle_succ_no_arc G.in_face_cycle_setD
funpow_dist1_prop weaken.loop_cond)
have A: "j ∈ pre_digraph_map.face_cycle_set iM i"
using weaken by (auto simp: inv_face_cycles_inner_def)
then have A': "(G.face_cycle_succ ^^ funpow_dist1 G.face_cycle_succ i j) i = j"
by (intro funpow_dist1_prop) (simp add: G.face_cycle_set_def[symmetric])
{ fix k
have *: "⋀i n f x . i < n ⟹ ∃j<n. (f ^^ j) x = (f ^^ i) x" by auto
have "(∃l<funpow_dist1 G.face_cycle_succ i (G.face_cycle_succ j). (G.face_cycle_succ ^^ l) i = k)
⟷ (∃l<Suc (funpow_dist1 G.face_cycle_succ i j). (G.face_cycle_succ ^^ l) i = k)" (is "?L ⟷ _")
using A ‹i ≠ j›
by (subst funpow_dist1_f_eq) (simp_all add: G.face_cycle_set_def[symmetric])
also have "… ⟷ (∃l<funpow_dist1 G.face_cycle_succ i j. (G.face_cycle_succ ^^ l) i = k) ∨ k = j" (is "_ ⟷ ?R")
using A' by (fastforce elim: less_SucE
intro: * exI[where x="(funpow_dist1 G.face_cycle_succ i j)"])
finally have "?L ⟷ ?R" .
} note B = this
have ?inv
using weaken unfolding inv_face_cycles_inner_def B
by (auto simp: G.face_cycle_succ_inI)
have X: "funpow_dist1 G.face_cycle_succ i j < card (G.face_cycle_set i)"
proof -
have "funpow_dist1 G.face_cycle_succ i j ≤ funpow_dist1 G.face_cycle_succ i i"
using _ _ A unfolding G.face_cycle_set_def
apply (rule funpow_dist1_le_self)
apply (rule funpow_dist1_prop)
unfolding G.face_cycle_set_def[symmetric]
by simp_all
moreover have "funpow_dist1 G.face_cycle_succ i j ≠ funpow_dist1 G.face_cycle_succ i i"
by (metis A G.face_cycle_set_def G.face_cycle_set_self funpow_dist1_prop
weaken.loop_cond)
ultimately
have "funpow_dist1 G.face_cycle_succ i j < funpow_dist1 G.face_cycle_succ i i"
by simp
also have "… ≤ card (G.face_cycle_set i)"
by (rule G.funpow_dist1_le_card_fcs) simp
finally show ?thesis .
qed
have ?var
apply simp
using _ X apply (rule diff_less_mono2)
apply (rule funpow_dist1_less_f)
using ‹i ≠ j› A by (auto simp: G.face_cycle_set_def[symmetric])
with ‹?inv› show ?case by blast
}
}
}
}
}
}
qed auto
declare ovalidNF_face_cycles[THEN ovalidNF_wp, THEN trivial_label, vcg_l]
lemma ovalidNF_euler_genus: "
ovalidNF (λs. distinct (ig_verts iG) ∧ digraph_map (mk_graph iG) iM ∧ c = card (pre_digraph.sccs (mk_graph iG)))
(euler_genus iG iM c)
(λr s. r = pre_digraph_map.euler_genus (mk_graph iG) iM)
"
unfolding euler_genus_def
proof vcg_casify
case weaken
have "distinct (ig_verts iG)" using weaken by simp
interpret G: digraph_map "mk_graph iG" iM using weaken by simp
have len_card:
"length (ig_verts iG) = card (verts (mk_graph iG))"
"length (ig_edges iG) = card (arcs (mk_graph iG))"
using ‹distinct _› by (auto simp: mkg_simps arcs_mkg distinct_card)
show ?case
using weaken by (auto simp: G.euler_genus_def G.euler_char_def len_card)
qed
declare ovalidNF_euler_genus[THEN ovalidNF_wp, THEN trivial_label, vcg_l]
lemma ovalidNF_certify: "
ovalidNF (λs. distinct (ig_verts iG) ∧ fin_digraph (mk_graph iG) ∧ c = card (pre_digraph.sccs (mk_graph iG)))
(certify iG iM c)
(λr s. r ⟷ pre_digraph_map.euler_genus (mk_graph iG) (mk_map (mk_graph iG) iM) = 0
∧ digraph_map (mk_graph iG) (mk_map (mk_graph iG) iM)
∧ (∀i < length (ig_edges iG). im_pred iM (im_succ iM i) = i) )
"
unfolding certify_def
proof vcg_casify
case weaken
then interpret fin_digraph "mk_graph iG" by auto
from weaken show ?case by (auto simp: BRANCH_def intro: wf_digraph)
qed
end