Theory BMSSP_Pull_Minimum
theory BMSSP_Pull_Minimum
imports BMSSP_Find_Pivots
begin
section ‹Pull Minimum›
text ‹
This theory starts replacing the abstract partition-loop contract by concrete
range-splitting lemmas. In the BMSSP loop, a partition Pull returns a
boundary and a lower batch of candidate sources. The recursive child call is
made below that boundary. To justify that call, we need to know that every
incomplete vertex below the boundary is still covered by a complete source in
the pulled lower part.
The rest of the theory is range algebra. It defines the half-open range tree
between two distance boundaries, proves that a monotone boundary list
partitions a bounded tree into disjoint child ranges, and assembles
completeness of the lower prefix and every child range into the BMSSP
postcondition. These lemmas are the semantic counterpart of the operational
partition loop and are later used by the concrete one-step assembly theory.
›
context unique_shortest_digraph
begin
definition split_below where
"split_below d S beta = {x ∈ S. d x < beta}"
lemma split_below_label_below:
assumes "x ∈ split_below d S beta"
shows "below_bound (d x) (Fin beta)"
using assms unfolding split_below_def by simp
lemma split_below_tree_antichain:
assumes anti: "tree_antichain S"
shows "tree_antichain (split_below d S beta)"
by (rule tree_antichain_subset[OF anti]) (simp add: split_below_def)
lemma split_below_scaled_card_le:
assumes S_subset: "S ⊆ V"
and S_k_cap: "k * card S ≤ cap"
shows "k * card (split_below d S beta) ≤ cap"
proof -
have finite_S: "finite S"
using finite_subset[OF S_subset finite_V] .
have "card (split_below d S beta) ≤ card S"
by (rule card_mono[OF finite_S]) (simp add: split_below_def)
then have "k * card (split_below d S beta) ≤ k * card S"
by simp
then show ?thesis
using S_k_cap by linarith
qed
text ‹
The set @{const split_below} is the lower part produced by a Pull boundary:
it keeps exactly those sources whose current labels are below ‹beta›. The
first lemmas show that this split respects the finite bound, preserves the
tree-antichain property, and cannot increase the scaled cardinality used by
the FindPivots cap. These are small facts, but they are the side conditions
needed before the lower recursive call can be formed.
›
definition complete_tree_cover where
"complete_tree_cover d S B ⟷ (∀v∈bound_tree S B. through_complete d S v)"
definition range_tree where
"range_tree S a B =
{v ∈ tree_set S. a ≤ dist s v ∧ below_bound (dist s v) B}"
fun nondecreasing_from where
"nondecreasing_from a [] ⟷ True"
| "nondecreasing_from a (b # bs) ⟷ a ≤ b ∧ nondecreasing_from b bs"
fun bounds_le where
"bounds_le B [] ⟷ True"
| "bounds_le B (b # bs) ⟷ bound_le (Fin b) B ∧ bounds_le B bs"
fun range_tree_chain where
"range_tree_chain S a [] B = range_tree S a B"
| "range_tree_chain S a (b # bs) B =
range_tree S a (Fin b) ∪ range_tree_chain S b bs B"
fun range_tree_chain_list where
"range_tree_chain_list S a [] B = [range_tree S a B]"
| "range_tree_chain_list S a (b # bs) B =
range_tree S a (Fin b) # range_tree_chain_list S b bs B"
text ‹
The predicates @{const complete_tree_cover} and @{const range_tree} describe
the two main geometric facts used by the loop. A complete tree cover says
every vertex in a bounded tree is certified by a complete source. A range
tree is the part of a source tree whose true distances lie between a lower
boundary and an upper bound. The functions @{const range_tree_chain} and
@{const range_tree_chain_list} extend this to a monotone list of child
boundaries; the list form is convenient for relating one child postcondition
to one child range.
›
lemma below_bound_strict_trans:
assumes "a < b" "below_bound b B"
shows "below_bound a B"
using assms by (cases B) auto
lemma complete_verticesD:
assumes "u ∈ complete_vertices d"
shows "u ∈ V" "reachable s u" "d u = dist s u"
using assms unfolding complete_vertices_def by auto
lemma bound_tree_complete_vertices_eq:
assumes cover:
"⋀u. ⟦u ∈ S; reachable s u; below_bound (dist s u) B;
d u ≠ dist s u⟧ ⟹ through_complete d S u"
shows "bound_tree S B = bound_tree (S ∩ complete_vertices d) B"
proof
show "bound_tree (S ∩ complete_vertices d) B ⊆ bound_tree S B"
using bound_tree_mono[of "S ∩ complete_vertices d" S B] by blast
next
show "bound_tree S B ⊆ bound_tree (S ∩ complete_vertices d) B"
proof
fix v
assume v_bound: "v ∈ bound_tree S B"
then have vV: "v ∈ V" and reach_v: "reachable s v"
and through_S: "through S v" and below_v: "below_bound (dist s v) B"
unfolding bound_tree_def by auto
obtain u where uS: "u ∈ S" and uv: "tree_path u v"
using through_iff_tree_path[OF reach_v, of S] through_S by blast
have reach_u: "reachable s u"
using tree_path_root_reachable[OF uv] .
have u_below: "below_bound (dist s u) B"
using tree_path_dist_le[OF uv] below_v
by (cases B) auto
have "through (S ∩ complete_vertices d) v"
proof (cases "d u = dist s u")
case True
have u_complete: "u ∈ complete_vertices d"
using tree_path_root_in_V[OF uv] reach_u True
unfolding complete_vertices_def by blast
have u_path: "u ∈ set (shortest_path_to v)"
using uv by (auto dest: tree_pathD)
have sp_v: "shortest_walk s (shortest_path_to v) v"
using shortest_path_to_shortest[OF reach_v] .
show ?thesis
using uS u_complete sp_v u_path unfolding through_def by blast
next
case False
have "through_complete d S u"
using cover[OF uS reach_u u_below False] .
then have "through (S ∩ complete_vertices d) u"
unfolding through_complete_def .
then obtain q where qS: "q ∈ S ∩ complete_vertices d"
and qu: "tree_path q u"
using through_iff_tree_path[OF reach_u, of "S ∩ complete_vertices d"]
by blast
have qv: "tree_path q v"
using tree_path_trans[OF uv qu] .
have q_path: "q ∈ set (shortest_path_to v)"
using qv by (auto dest: tree_pathD)
have sp_v: "shortest_walk s (shortest_path_to v) v"
using shortest_path_to_shortest[OF reach_v] .
show ?thesis
using qS sp_v q_path unfolding through_def by blast
qed
then show "v ∈ bound_tree (S ∩ complete_vertices d) B"
using vV reach_v below_v unfolding bound_tree_def by blast
qed
qed
lemma bmssp_pre_full_bound_tree_complete_vertices_eq:
assumes pre: "bmssp_pre_full d S B"
shows "bound_tree S B = bound_tree (S ∩ complete_vertices d) B"
proof (rule bound_tree_complete_vertices_eq)
fix u
assume uS: "u ∈ S" and reach_u: "reachable s u"
and below_u: "below_bound (dist s u) B"
and incomplete_u: "d u ≠ dist s u"
have "u ∈ V"
using uS pre unfolding bmssp_pre_full_def by blast
then show "through_complete d S u"
using uS reach_u below_u incomplete_u pre unfolding bmssp_pre_full_def by blast
qed
lemma bound_tree_complete_vertices_eq_imp_cover:
assumes eq: "bound_tree S B = bound_tree (S ∩ complete_vertices d) B"
shows "complete_tree_cover d S B"
proof (unfold complete_tree_cover_def, intro ballI)
fix v
assume "v ∈ bound_tree S B"
then have "v ∈ bound_tree (S ∩ complete_vertices d) B"
using eq by simp
then have "through (S ∩ complete_vertices d) v"
unfolding bound_tree_def by blast
then show "through_complete d S v"
unfolding through_complete_def by simp
qed
lemma bmssp_pre_full_complete_tree_cover:
assumes pre: "bmssp_pre_full d S B"
shows "complete_tree_cover d S B"
using bound_tree_complete_vertices_eq_imp_cover
[OF bmssp_pre_full_bound_tree_complete_vertices_eq[OF pre]] .
lemma bmssp_pre_full_bound_mono:
assumes pre: "bmssp_pre_full d S B"
and le: "bound_le B' B"
shows "bmssp_pre_full d S B'"
proof -
have S_subset: "S ⊆ V"
using pre unfolding bmssp_pre_full_def by blast
have cover:
"⋀v. ⟦v ∈ V; reachable s v; below_bound (dist s v) B';
d v ≠ dist s v⟧ ⟹ through_complete d S v"
proof -
fix v
assume v: "v ∈ V" "reachable s v" "below_bound (dist s v) B'"
"d v ≠ dist s v"
have "below_bound (dist s v) B"
using le v(3) by (cases B'; cases B) auto
then show "through_complete d S v"
using pre v unfolding bmssp_pre_full_def by blast
qed
show ?thesis
using S_subset cover unfolding bmssp_pre_full_def by blast
qed
theorem concrete_find_pivots_complete_pivot_tree:
assumes sound: "sound_label d"
and pre: "bmssp_pre_full d S B"
and S_reaches: "⋀x. x ∈ S ⟹ reachable s x"
shows "bound_tree (find_pivots_pivots k d S B) B =
bound_tree
(find_pivots_pivots k d S B ∩
complete_vertices (find_pivots_label k d S B)) B"
using bmssp_pre_full_bound_tree_complete_vertices_eq
[OF find_pivots_establishes_pivot_pre_concrete[OF sound pre S_reaches]] .
theorem concrete_find_pivots_pivot_tree_cover:
assumes sound: "sound_label d"
and pre: "bmssp_pre_full d S B"
and S_reaches: "⋀x. x ∈ S ⟹ reachable s x"
shows "complete_tree_cover
(find_pivots_label k d S B)
(find_pivots_pivots k d S B) B"
using bmssp_pre_full_complete_tree_cover
[OF find_pivots_establishes_pivot_pre_concrete[OF sound pre S_reaches]] .
theorem concrete_capped_find_pivots_complete_pivot_tree:
assumes sound: "sound_label d"
and pre: "bmssp_pre_full d S B"
and S_reaches: "⋀x. x ∈ S ⟹ reachable s x"
shows "bound_tree (find_pivots_pivots_capped k cap d S B) B =
bound_tree
(find_pivots_pivots_capped k cap d S B ∩
complete_vertices (find_pivots_label_capped k cap d S B)) B"
using bmssp_pre_full_bound_tree_complete_vertices_eq
[OF find_pivots_capped_establishes_pivot_pre_concrete[OF sound pre S_reaches]] .
theorem concrete_capped_find_pivots_pivot_tree_cover:
assumes sound: "sound_label d"
and pre: "bmssp_pre_full d S B"
and S_reaches: "⋀x. x ∈ S ⟹ reachable s x"
shows "complete_tree_cover
(find_pivots_label_capped k cap d S B)
(find_pivots_pivots_capped k cap d S B) B"
using bmssp_pre_full_complete_tree_cover
[OF find_pivots_capped_establishes_pivot_pre_concrete[OF sound pre S_reaches]] .
lemma through_complete_obtain:
assumes "through_complete d S v"
obtains u p where
"u ∈ S"
"u ∈ complete_vertices d"
"shortest_walk s p v"
"u ∈ set p"
"d u = dist s u"
"dist s u ≤ dist s v"
proof -
obtain u p where u: "u ∈ S" "u ∈ complete_vertices d" "shortest_walk s p v" "u ∈ set p"
using assms unfolding through_complete_def through_def by blast
have "d u = dist s u"
using u(2) unfolding complete_vertices_def by blast
moreover have "dist s u ≤ dist s v"
using shortest_walk_prefix_dist_le u by blast
ultimately show thesis
using that u by blast
qed
lemma pull_minimum_incomplete_covered:
assumes pre: "bmssp_pre_full d S B"
and beta: "below_bound beta B"
and vV: "v ∈ V"
and reach: "reachable s v"
and lt: "dist s v < beta"
and incomplete: "d v ≠ dist s v"
shows "through_complete d (split_below d S beta) v"
proof -
have below_v_B: "below_bound (dist s v) B"
using below_bound_strict_trans[OF lt beta] .
have cover: "through_complete d S v"
using pre vV reach below_v_B incomplete unfolding bmssp_pre_full_def by blast
then obtain u p where uS: "u ∈ S" and ucomp: "u ∈ complete_vertices d"
and p: "shortest_walk s p v" and up: "u ∈ set p"
and du: "d u = dist s u" and dist_le: "dist s u ≤ dist s v"
by (rule through_complete_obtain)
have "d u < beta"
using du dist_le lt by linarith
then have "u ∈ split_below d S beta"
using uS unfolding split_below_def by blast
then have "through (split_below d S beta ∩ complete_vertices d) v"
using ucomp p up unfolding through_def by blast
then show ?thesis
unfolding through_complete_def .
qed
lemma pull_minimum_pre_for_lower_split:
assumes pre: "bmssp_pre_full d S B"
and beta: "below_bound beta B"
shows "bmssp_pre_full d (split_below d S beta) (Fin beta)"
proof -
have S_subset: "split_below d S beta ⊆ V"
using pre unfolding bmssp_pre_full_def split_below_def by blast
have cover:
"⋀v. ⟦v ∈ V; reachable s v; below_bound (dist s v) (Fin beta); d v ≠ dist s v⟧
⟹ through_complete d (split_below d S beta) v"
using pull_minimum_incomplete_covered[OF pre beta] by auto
show ?thesis
using S_subset cover unfolding bmssp_pre_full_def by blast
qed
lemma split_below_subset:
"split_below d S beta ⊆ S"
unfolding split_below_def by blast
lemma range_tree_eq_bound_diff:
"range_tree S a B = bound_tree S B - bound_tree S (Fin a)"
unfolding range_tree_def bound_tree_eq_tree_set by auto
lemma range_tree_subset_bound_tree:
"range_tree S a B ⊆ bound_tree S B"
unfolding range_tree_eq_bound_diff by blast
lemma finite_bound_tree [simp]:
"finite (bound_tree S B)"
proof -
have "bound_tree S B ⊆ V"
unfolding bound_tree_def by blast
then show ?thesis
using finite_subset[OF _ finite_V] by blast
qed
lemma finite_range_tree [simp]:
"finite (range_tree S a B)"
proof -
have "range_tree S a B ⊆ V"
unfolding range_tree_def tree_set_def by blast
then show ?thesis
using finite_subset[OF _ finite_V] by blast
qed
lemma finite_range_tree_chain [simp]:
"finite (range_tree_chain S a bs B)"
by (induction bs arbitrary: a) simp_all
lemma finite_range_tree_chain_list_sets [simp]:
assumes "X ∈ set (range_tree_chain_list S a bs B)"
shows "finite X"
using assms by (induction bs arbitrary: a) auto
lemma Union_range_tree_chain_list:
"⋃(set (range_tree_chain_list S a bs B)) = range_tree_chain S a bs B"
by (induction bs arbitrary: a) auto
lemma range_tree_chain_lower_bound:
assumes mono: "nondecreasing_from a bs"
and x: "x ∈ range_tree_chain S a bs B"
shows "a ≤ dist s x"
using assms
proof (induction bs arbitrary: a)
case Nil
then show ?case
by (simp add: range_tree_def)
next
case (Cons b bs)
then consider "x ∈ range_tree S a (Fin b)" |
"x ∈ range_tree_chain S b bs B"
by auto
then show ?case
proof cases
case 1
then show ?thesis
unfolding range_tree_def by blast
next
case 2
have "b ≤ dist s x"
using Cons.IH[of b] Cons.prems 2 by simp
moreover have "a ≤ b"
using Cons.prems by simp
ultimately show ?thesis
by linarith
qed
qed
lemma range_tree_disjoint_lower:
"bound_tree S (Fin a) ∩ range_tree S a B = {}"
unfolding range_tree_eq_bound_diff by blast
lemma bound_tree_disjoint_range_tree_chain:
assumes mono: "nondecreasing_from a bs"
shows "bound_tree S (Fin a) ∩ range_tree_chain S a bs B = {}"
proof
show "bound_tree S (Fin a) ∩ range_tree_chain S a bs B ⊆ {}"
proof
fix x
assume x: "x ∈ bound_tree S (Fin a) ∩ range_tree_chain S a bs B"
then have "dist s x < a"
unfolding bound_tree_def by auto
moreover have "a ≤ dist s x"
using range_tree_chain_lower_bound[OF mono] x by blast
ultimately show "x ∈ {}"
by simp
qed
qed simp
lemma range_tree_disjoint_range_tree_chain_tail:
assumes a_le_b: "a ≤ b"
and mono_tail: "nondecreasing_from b bs"
shows "range_tree S a (Fin b) ∩ range_tree_chain S b bs B = {}"
proof
show "range_tree S a (Fin b) ∩ range_tree_chain S b bs B ⊆ {}"
proof
fix x
assume x: "x ∈ range_tree S a (Fin b) ∩ range_tree_chain S b bs B"
then have "dist s x < b"
unfolding range_tree_def by auto
moreover have "b ≤ dist s x"
using range_tree_chain_lower_bound[OF mono_tail] x by blast
ultimately show "x ∈ {}"
by simp
qed
qed simp
lemma card_range_tree_chain_eq_sum_list:
assumes mono: "nondecreasing_from a bs"
shows "card (range_tree_chain S a bs B) =
sum_list (map card (range_tree_chain_list S a bs B))"
using mono
proof (induction bs arbitrary: a)
case Nil
then show ?case
by simp
next
case (Cons b bs)
have a_le_b: "a ≤ b"
using Cons.prems by simp
have mono_tail: "nondecreasing_from b bs"
using Cons.prems by simp
have disjoint:
"range_tree S a (Fin b) ∩ range_tree_chain S b bs B = {}"
using range_tree_disjoint_range_tree_chain_tail[OF a_le_b mono_tail] .
have card_union:
"card (range_tree S a (Fin b) ∪ range_tree_chain S b bs B) =
card (range_tree S a (Fin b)) + card (range_tree_chain S b bs B)"
by (rule card_Un_disjoint) (simp_all add: disjoint)
show ?case
using card_union Cons.IH[OF mono_tail] by simp
qed
lemma sum_list_map_mult_left:
fixes c :: nat
and f :: "'a ⇒ nat"
shows "sum_list (map (λx. c * f x) xs) = c * sum_list (map f xs)"
by (induction xs) (simp_all add: algebra_simps)
lemma sum_list_map_card_mult_left:
fixes C :: nat
and Xs :: "'v set list"
shows "sum_list (map (λX. C * card X) Xs) = C * sum_list (map card Xs)"
by (induction Xs) (simp_all add: algebra_simps)
lemma sum_list_le_if_list_all2:
assumes "list_all2 (λc X. c ≤ C * card X) costs Xs"
shows "sum_list costs ≤ sum_list (map (λX. C * card X) Xs)"
using assms
proof (induction rule: list_all2_induct)
case Nil
then show ?case by simp
next
case (Cons c X costs Xs)
then show ?case by simp
qed
lemma child_costs_le_range_tree_chain_card:
assumes mono: "nondecreasing_from a bs"
and costs: "list_all2 (λc X. c ≤ C * card X) costs
(range_tree_chain_list S a bs B)"
shows "sum_list costs ≤ C * card (range_tree_chain S a bs B)"
proof -
have "sum_list costs ≤
sum_list (map (λX. C * card X) (range_tree_chain_list S a bs B))"
using sum_list_le_if_list_all2[OF costs] .
also have "… =
C * sum_list (map card (range_tree_chain_list S a bs B))"
by (rule sum_list_map_card_mult_left)
also have "… = C * card (range_tree_chain S a bs B)"
using card_range_tree_chain_eq_sum_list[OF mono, of S B] by simp
finally show ?thesis .
qed
lemma range_tree_adjacent_disjoint:
"range_tree S a (Fin b) ∩ range_tree S b B = {}"
unfolding range_tree_def by auto
lemma range_tree_adjacent_union:
assumes "a ≤ b"
and "bound_le (Fin b) B"
shows "range_tree S a (Fin b) ∪ range_tree S b B = range_tree S a B"
using assms unfolding range_tree_def by (cases B) auto
lemma bound_tree_split_at:
assumes "bound_le (Fin a) B"
shows "bound_tree S B = bound_tree S (Fin a) ∪ range_tree S a B"
using assms unfolding range_tree_def bound_tree_eq_tree_set
by (cases B) auto
lemma bound_tree_adjacent_union:
assumes "a ≤ b"
and "bound_le (Fin b) B"
shows "bound_tree S (Fin a) ∪ range_tree S a (Fin b) ∪ range_tree S b B =
bound_tree S B"
proof -
have union: "range_tree S a (Fin b) ∪ range_tree S b B = range_tree S a B"
using range_tree_adjacent_union[OF assms] .
have le_a_B: "bound_le (Fin a) B"
using assms by (cases B) auto
show ?thesis
using union bound_tree_split_at[OF le_a_B, of S]
by (cases B) auto
qed
lemma complete_on_Un:
assumes "complete_on d A" "complete_on d B"
shows "complete_on d (A ∪ B)"
using assms unfolding complete_on_def by blast
lemma complete_on_Union_list:
assumes "⋀X. X ∈ set Xs ⟹ complete_on d X"
shows "complete_on d (⋃(set Xs))"
using assms unfolding complete_on_def by blast
lemma complete_on_bound_tree_split:
assumes "bound_le (Fin a) B"
and lower: "complete_on d (bound_tree S (Fin a))"
and upper: "complete_on d (range_tree S a B)"
shows "complete_on d (bound_tree S B)"
proof -
have "complete_on d (bound_tree S (Fin a) ∪ range_tree S a B)"
using complete_on_Un[OF lower upper] .
then show ?thesis
using bound_tree_split_at[OF assms(1), of S] by simp
qed
lemma bound_tree_range_chain_union:
assumes mono: "nondecreasing_from a bs"
and bounds: "bounds_le B (a # bs)"
shows "bound_tree S (Fin a) ∪ range_tree_chain S a bs B = bound_tree S B"
using assms
proof (induction bs arbitrary: a)
case Nil
then show ?case
using bound_tree_split_at[of a B S] by simp
next
case (Cons b bs)
have a_le_b: "a ≤ b"
using Cons.prems(1) by simp
have mono_tail: "nondecreasing_from b bs"
using Cons.prems(1) by simp
have b_le_B: "bound_le (Fin b) B"
using Cons.prems(2) by simp
have bounds_tail: "bounds_le B (b # bs)"
using Cons.prems(2) by simp
have split_ab:
"bound_tree S (Fin b) = bound_tree S (Fin a) ∪ range_tree S a (Fin b)"
using bound_tree_split_at[of a "Fin b" S] a_le_b by simp
have tail:
"bound_tree S (Fin b) ∪ range_tree_chain S b bs B = bound_tree S B"
using Cons.IH[OF mono_tail bounds_tail] .
show ?case
using split_ab tail by auto
qed
lemma card_bound_tree_range_chain_union:
assumes mono: "nondecreasing_from a bs"
and bounds: "bounds_le B (a # bs)"
shows "card (bound_tree S B) =
card (bound_tree S (Fin a)) + card (range_tree_chain S a bs B)"
proof -
have union: "bound_tree S (Fin a) ∪ range_tree_chain S a bs B = bound_tree S B"
using bound_tree_range_chain_union[OF mono bounds, of S] .
have disjoint: "bound_tree S (Fin a) ∩ range_tree_chain S a bs B = {}"
using bound_tree_disjoint_range_tree_chain[OF mono, of S] .
have "card (bound_tree S (Fin a) ∪ range_tree_chain S a bs B) =
card (bound_tree S (Fin a)) + card (range_tree_chain S a bs B)"
by (rule card_Un_disjoint) (simp_all add: disjoint)
then show ?thesis
using union by simp
qed
lemma complete_on_range_chain_union:
assumes mono: "nondecreasing_from a bs"
and bounds: "bounds_le B (a # bs)"
and lower: "complete_on d (bound_tree S (Fin a))"
and chain: "complete_on d (range_tree_chain S a bs B)"
shows "complete_on d (bound_tree S B)"
proof -
have "complete_on d (bound_tree S (Fin a) ∪ range_tree_chain S a bs B)"
using complete_on_Un[OF lower chain] .
then show ?thesis
using bound_tree_range_chain_union[OF mono bounds, of S] by simp
qed
lemma complete_on_range_tree_chain_list:
assumes "⋀X. X ∈ set (range_tree_chain_list S a bs B) ⟹ complete_on d X"
shows "complete_on d (range_tree_chain S a bs B)"
proof -
have "complete_on d (⋃(set (range_tree_chain_list S a bs B)))"
using complete_on_Union_list[OF assms] .
then show ?thesis
using Union_range_tree_chain_list[of S a bs B] by simp
qed
theorem partition_loop_trace_assembly_post:
assumes le: "bound_le B' B"
and mono: "nondecreasing_from a bs"
and bounds: "bounds_le B' (a # bs)"
and lower: "complete_on d' (bound_tree S (Fin a))"
and children: "list_all2 (λU X. U = X ∧ complete_on d' U) Us
(range_tree_chain_list S a bs B')"
and U_def: "U = bound_tree S (Fin a) ∪ ⋃(set Us)"
shows "bmssp_post_full d S B d' B' U"
proof -
have Union_eq:
"⋃(set Us) = ⋃(set (range_tree_chain_list S a bs B'))"
using children by (induction rule: list_all2_induct) auto
have children_complete: "⋀X. X ∈ set Us ⟹ complete_on d' X"
using children by (induction rule: list_all2_induct) auto
have chain_complete: "complete_on d' (range_tree_chain S a bs B')"
proof -
have "complete_on d' (⋃(set Us))"
by (rule complete_on_Union_list[OF children_complete])
then show ?thesis
using Union_eq Union_range_tree_chain_list[of S a bs B'] by simp
qed
have U_tree: "U = bound_tree S B'"
using U_def Union_eq Union_range_tree_chain_list[of S a bs B']
bound_tree_range_chain_union[OF mono bounds, of S]
by simp
have "complete_on d' U"
unfolding U_def
using complete_on_Un[OF lower]
complete_on_Union_list[OF children_complete] by blast
then show ?thesis
using le U_tree unfolding bmssp_post_full_def by blast
qed
text ‹
The range-chain lemmas culminate in
@{thm partition_loop_trace_assembly_post}. The hypotheses are exactly the
certificate carried by the concrete partition trace: a returned bound below
the input bound, nondecreasing child boundaries, child bounds below the
returned bound, completeness of the lower prefix, and one completed set for
each range in @{const range_tree_chain_list}. The theorem proves that their
union is precisely @{const bound_tree} for the returned bound and that the
final labels are complete there.
›
lemma pull_minimum_bound_tree_lower_split:
assumes cover: "complete_tree_cover d S (Fin beta)"
and beta'_le: "beta' ≤ beta"
shows "bound_tree S (Fin beta') = bound_tree (split_below d S beta) (Fin beta')"
proof
show "bound_tree S (Fin beta') ⊆ bound_tree (split_below d S beta) (Fin beta')"
proof
fix v
assume v: "v ∈ bound_tree S (Fin beta')"
then have vV: "v ∈ V" and reach_v: "reachable s v"
and through_S: "through S v" and lt_beta': "dist s v < beta'"
unfolding bound_tree_def by auto
have v_beta: "v ∈ bound_tree S (Fin beta)"
using v beta'_le unfolding bound_tree_def by auto
then have "through_complete d S v"
using cover unfolding complete_tree_cover_def by blast
then obtain u p where uS: "u ∈ S" and ucomp: "u ∈ complete_vertices d"
and p: "shortest_walk s p v" and up: "u ∈ set p"
and du: "d u = dist s u" and dist_le: "dist s u ≤ dist s v"
by (rule through_complete_obtain)
have "d u < beta"
using du dist_le lt_beta' beta'_le by linarith
then have "u ∈ split_below d S beta"
using uS unfolding split_below_def by blast
then have "through (split_below d S beta) v"
using p up unfolding through_def by blast
then show "v ∈ bound_tree (split_below d S beta) (Fin beta')"
using vV reach_v lt_beta' unfolding bound_tree_def by auto
qed
next
show "bound_tree (split_below d S beta) (Fin beta') ⊆ bound_tree S (Fin beta')"
using bound_tree_mono[OF split_below_subset[of d S beta], of "Fin beta'"] by blast
qed
lemma pull_recursive_post_lifts_bound_tree:
assumes cover: "complete_tree_cover d S (Fin beta)"
and post: "bmssp_post_full d (split_below d S beta) (Fin beta) d' B' U"
shows "U = bound_tree S B'"
proof -
have le: "bound_le B' (Fin beta)"
and U: "U = bound_tree (split_below d S beta) B'"
using post unfolding bmssp_post_full_def by auto
show ?thesis
proof (cases B')
case Infinity
then have False
using le by simp
then show ?thesis
by blast
next
case (Fin beta')
then have beta'_le: "beta' ≤ beta"
using le by simp
have "bound_tree S (Fin beta') =
bound_tree (split_below d S beta) (Fin beta')"
using pull_minimum_bound_tree_lower_split[OF cover beta'_le] .
then show ?thesis
using U Fin by simp
qed
qed
theorem concrete_find_pivots_pull_pre:
assumes sound: "sound_label d"
and pre: "bmssp_pre_full d S B"
and S_reaches: "⋀x. x ∈ S ⟹ reachable s x"
and beta: "below_bound beta B"
shows "bmssp_pre_full
(find_pivots_label k d S B)
(split_below (find_pivots_label k d S B)
(find_pivots_pivots k d S B) beta)
(Fin beta)"
proof -
have pivot_pre:
"bmssp_pre_full
(find_pivots_label k d S B)
(find_pivots_pivots k d S B) B"
using find_pivots_establishes_pivot_pre_concrete[OF sound pre S_reaches] .
show ?thesis
using pull_minimum_pre_for_lower_split[OF pivot_pre beta] .
qed
theorem concrete_capped_find_pivots_pull_pre:
assumes sound: "sound_label d"
and pre: "bmssp_pre_full d S B"
and S_reaches: "⋀x. x ∈ S ⟹ reachable s x"
and beta: "below_bound beta B"
shows "bmssp_pre_full
(find_pivots_label_capped k cap d S B)
(split_below (find_pivots_label_capped k cap d S B)
(find_pivots_pivots_capped k cap d S B) beta)
(Fin beta)"
proof -
have pivot_pre:
"bmssp_pre_full
(find_pivots_label_capped k cap d S B)
(find_pivots_pivots_capped k cap d S B) B"
using find_pivots_capped_establishes_pivot_pre_concrete[OF sound pre S_reaches] .
show ?thesis
using pull_minimum_pre_for_lower_split[OF pivot_pre beta] .
qed
theorem concrete_find_pivots_pull_bound_tree_lower:
assumes sound: "sound_label d"
and pre: "bmssp_pre_full d S B"
and S_reaches: "⋀x. x ∈ S ⟹ reachable s x"
and beta: "below_bound beta B"
and beta'_le: "beta' ≤ beta"
shows "bound_tree (find_pivots_pivots k d S B) (Fin beta') =
bound_tree
(split_below (find_pivots_label k d S B)
(find_pivots_pivots k d S B) beta)
(Fin beta')"
proof -
let ?d' = "find_pivots_label k d S B"
let ?P = "find_pivots_pivots k d S B"
have pivot_pre_B: "bmssp_pre_full ?d' ?P B"
using find_pivots_establishes_pivot_pre_concrete[OF sound pre S_reaches] .
have pivot_pre_beta: "bmssp_pre_full ?d' ?P (Fin beta)"
using bmssp_pre_full_bound_mono[OF pivot_pre_B] beta
by (cases B) auto
have cover_beta: "complete_tree_cover ?d' ?P (Fin beta)"
using bmssp_pre_full_complete_tree_cover[OF pivot_pre_beta] .
show ?thesis
using pull_minimum_bound_tree_lower_split[OF cover_beta beta'_le] .
qed
theorem concrete_capped_find_pivots_pull_bound_tree_lower:
assumes sound: "sound_label d"
and pre: "bmssp_pre_full d S B"
and S_reaches: "⋀x. x ∈ S ⟹ reachable s x"
and beta: "below_bound beta B"
and beta'_le: "beta' ≤ beta"
shows "bound_tree (find_pivots_pivots_capped k cap d S B) (Fin beta') =
bound_tree
(split_below (find_pivots_label_capped k cap d S B)
(find_pivots_pivots_capped k cap d S B) beta)
(Fin beta')"
proof -
let ?d' = "find_pivots_label_capped k cap d S B"
let ?P = "find_pivots_pivots_capped k cap d S B"
have pivot_pre_B: "bmssp_pre_full ?d' ?P B"
using find_pivots_capped_establishes_pivot_pre_concrete[OF sound pre S_reaches] .
have pivot_pre_beta: "bmssp_pre_full ?d' ?P (Fin beta)"
using bmssp_pre_full_bound_mono[OF pivot_pre_B] beta
by (cases B) auto
have cover_beta: "complete_tree_cover ?d' ?P (Fin beta)"
using bmssp_pre_full_complete_tree_cover[OF pivot_pre_beta] .
show ?thesis
using pull_minimum_bound_tree_lower_split[OF cover_beta beta'_le] .
qed
theorem concrete_find_pivots_pull_recursive_post_lifts:
assumes sound: "sound_label d"
and pre: "bmssp_pre_full d S B"
and S_reaches: "⋀x. x ∈ S ⟹ reachable s x"
and beta: "below_bound beta B"
and post: "bmssp_post_full
(find_pivots_label k d S B)
(split_below (find_pivots_label k d S B)
(find_pivots_pivots k d S B) beta)
(Fin beta) d'' B' U"
shows "U = bound_tree (find_pivots_pivots k d S B) B'"
proof -
let ?d' = "find_pivots_label k d S B"
let ?P = "find_pivots_pivots k d S B"
have pivot_pre_B: "bmssp_pre_full ?d' ?P B"
using find_pivots_establishes_pivot_pre_concrete[OF sound pre S_reaches] .
have pivot_pre_beta: "bmssp_pre_full ?d' ?P (Fin beta)"
using bmssp_pre_full_bound_mono[OF pivot_pre_B] beta
by (cases B) auto
have cover_beta: "complete_tree_cover ?d' ?P (Fin beta)"
using bmssp_pre_full_complete_tree_cover[OF pivot_pre_beta] .
show ?thesis
using pull_recursive_post_lifts_bound_tree[OF cover_beta post] .
qed
theorem concrete_capped_find_pivots_pull_recursive_post_lifts:
assumes sound: "sound_label d"
and pre: "bmssp_pre_full d S B"
and S_reaches: "⋀x. x ∈ S ⟹ reachable s x"
and beta: "below_bound beta B"
and post: "bmssp_post_full
(find_pivots_label_capped k cap d S B)
(split_below (find_pivots_label_capped k cap d S B)
(find_pivots_pivots_capped k cap d S B) beta)
(Fin beta) d'' B' U"
shows "U = bound_tree (find_pivots_pivots_capped k cap d S B) B'"
proof -
let ?d' = "find_pivots_label_capped k cap d S B"
let ?P = "find_pivots_pivots_capped k cap d S B"
have pivot_pre_B: "bmssp_pre_full ?d' ?P B"
using find_pivots_capped_establishes_pivot_pre_concrete[OF sound pre S_reaches] .
have pivot_pre_beta: "bmssp_pre_full ?d' ?P (Fin beta)"
using bmssp_pre_full_bound_mono[OF pivot_pre_B] beta
by (cases B) auto
have cover_beta: "complete_tree_cover ?d' ?P (Fin beta)"
using bmssp_pre_full_complete_tree_cover[OF pivot_pre_beta] .
show ?thesis
using pull_recursive_post_lifts_bound_tree[OF cover_beta post] .
qed
text ‹
The Pull-minimum lemmas connect the range algebra to FindPivots. Once
FindPivots establishes a pivot precondition, @{const split_below} can be used
as the source set for a recursive call below a Pull boundary. If that
recursive call returns a BMSSP postcondition for the split set, the lifting
lemmas identify its output tree with the corresponding pivot tree. Both
capped and uncapped FindPivots variants have parallel theorems because later
operational relations use the capped executable search.
›
theorem concrete_find_pivots_final_tree_assembly:
assumes sound: "sound_label d"
and pre: "bmssp_pre_full d S B"
and S_reaches: "⋀x. x ∈ S ⟹ reachable s x"
and loop: "bmssp_post_full
(find_pivots_label k d S B)
(find_pivots_pivots k d S B) B d_loop B' U_loop"
shows "U_loop ∪
{v ∈ bound_tree S B'. find_pivots_label k d S B v = dist s v} =
bound_tree S B'"
proof -
let ?d' = "find_pivots_label k d S B"
let ?P = "find_pivots_pivots k d S B"
let ?W = "{v ∈ bound_tree S B'. ?d' v = dist s v}"
have loop_le: "bound_le B' B" and U_loop: "U_loop = bound_tree ?P B'"
using loop unfolding bmssp_post_full_def by auto
have P_subset_S: "?P ⊆ S"
unfolding find_pivots_pivots_def by blast
have pivot_pre: "bmssp_pre_full ?d' ?P B"
using find_pivots_establishes_pivot_pre_concrete[OF sound pre S_reaches] .
show ?thesis
proof
show "U_loop ∪ ?W ⊆ bound_tree S B'"
proof
fix v
assume "v ∈ U_loop ∪ ?W"
then show "v ∈ bound_tree S B'"
proof
assume "v ∈ U_loop"
then have "v ∈ bound_tree ?P B'"
using U_loop by simp
then show ?thesis
using bound_tree_mono[OF P_subset_S, of B'] by blast
next
assume "v ∈ ?W"
then show ?thesis
by blast
qed
qed
next
show "bound_tree S B' ⊆ U_loop ∪ ?W"
proof
fix v
assume v_bound: "v ∈ bound_tree S B'"
then have vV: "v ∈ V" and reach_v: "reachable s v"
and below_B': "below_bound (dist s v) B'"
unfolding bound_tree_def by auto
show "v ∈ U_loop ∪ ?W"
proof (cases "?d' v = dist s v")
case True
then show ?thesis
using v_bound by blast
next
case False
have below_B: "below_bound (dist s v) B"
using loop_le below_B' by (cases B'; cases B) auto
have "through_complete ?d' ?P v"
using pivot_pre vV reach_v below_B False
unfolding bmssp_pre_full_def by blast
then have "through ?P v"
by (rule through_complete_imp_through)
then have "v ∈ bound_tree ?P B'"
using vV reach_v below_B' unfolding bound_tree_def by blast
then show ?thesis
using U_loop by blast
qed
qed
qed
qed
theorem concrete_capped_find_pivots_final_tree_assembly:
assumes sound: "sound_label d"
and pre: "bmssp_pre_full d S B"
and S_reaches: "⋀x. x ∈ S ⟹ reachable s x"
and loop: "bmssp_post_full
(find_pivots_label_capped k cap d S B)
(find_pivots_pivots_capped k cap d S B) B d_loop B' U_loop"
shows "U_loop ∪
{v ∈ bound_tree S B'. find_pivots_label_capped k cap d S B v = dist s v} =
bound_tree S B'"
proof -
let ?d' = "find_pivots_label_capped k cap d S B"
let ?P = "find_pivots_pivots_capped k cap d S B"
let ?W = "{v ∈ bound_tree S B'. ?d' v = dist s v}"
have loop_le: "bound_le B' B" and U_loop: "U_loop = bound_tree ?P B'"
using loop unfolding bmssp_post_full_def by auto
have pivot_pre: "bmssp_pre_full ?d' ?P B"
using find_pivots_capped_establishes_pivot_pre_concrete[OF sound pre S_reaches] .
have P_subset_V: "?P ⊆ V"
using pivot_pre unfolding bmssp_pre_full_def by blast
have P_through_S:
"⋀v. v ∈ bound_tree ?P B' ⟹ v ∈ bound_tree S B'"
proof -
fix v
assume vP: "v ∈ bound_tree ?P B'"
then have vV: "v ∈ V" and reach_v: "reachable s v"
and through_P: "through ?P v" and below_v: "below_bound (dist s v) B'"
unfolding bound_tree_def by auto
have "through S v"
proof -
obtain u p where uP: "u ∈ ?P" and sp: "shortest_walk s p v" and up: "u ∈ set p"
using through_P unfolding through_def by blast
have "u ∈ S"
proof (cases "card (find_pivots_seen_capped k cap d S B) > cap")
case True
then show ?thesis
using uP unfolding find_pivots_pivots_capped_def by simp
next
case False
then show ?thesis
using uP unfolding find_pivots_pivots_capped_def by auto
qed
then show ?thesis
using sp up unfolding through_def by blast
qed
then show "v ∈ bound_tree S B'"
using vV reach_v below_v unfolding bound_tree_def by blast
qed
show ?thesis
proof
show "U_loop ∪ ?W ⊆ bound_tree S B'"
using U_loop P_through_S by blast
next
show "bound_tree S B' ⊆ U_loop ∪ ?W"
proof
fix v
assume v_bound: "v ∈ bound_tree S B'"
then have vV: "v ∈ V" and reach_v: "reachable s v"
and below_B': "below_bound (dist s v) B'"
unfolding bound_tree_def by auto
show "v ∈ U_loop ∪ ?W"
proof (cases "?d' v = dist s v")
case True
then show ?thesis
using v_bound by blast
next
case False
have below_B: "below_bound (dist s v) B"
using loop_le below_B' by (cases B'; cases B) auto
have "through_complete ?d' ?P v"
using pivot_pre vV reach_v below_B False
unfolding bmssp_pre_full_def by blast
then have "through ?P v"
by (rule through_complete_imp_through)
then have "v ∈ bound_tree ?P B'"
using vV reach_v below_B' unfolding bound_tree_def by blast
then show ?thesis
using U_loop by blast
qed
qed
qed
qed
theorem concrete_find_pivots_final_assembly_post:
assumes sound: "sound_label d"
and pre: "bmssp_pre_full d S B"
and S_reaches: "⋀x. x ∈ S ⟹ reachable s x"
and loop: "bmssp_post_full
(find_pivots_label k d S B)
(find_pivots_pivots k d S B) B d_final B' U_loop"
and compW: "complete_on d_final
{v ∈ bound_tree S B'. find_pivots_label k d S B v = dist s v}"
defines "U ≡ U_loop ∪
{v ∈ bound_tree S B'. find_pivots_label k d S B v = dist s v}"
shows "bmssp_post_full d S B d_final B' U"
proof -
let ?W = "{v ∈ bound_tree S B'. find_pivots_label k d S B v = dist s v}"
have le: "bound_le B' B"
using loop unfolding bmssp_post_full_def by blast
have U_eq: "U = bound_tree S B'"
using concrete_find_pivots_final_tree_assembly[OF sound pre S_reaches loop]
unfolding U_def by simp
have loop_complete: "complete_on d_final U_loop"
using loop unfolding bmssp_post_full_def by blast
have "complete_on d_final U"
unfolding U_def using complete_on_Un[OF loop_complete compW] .
then show ?thesis
using le U_eq unfolding bmssp_post_full_def by blast
qed
theorem concrete_capped_find_pivots_final_assembly_post:
assumes sound: "sound_label d"
and pre: "bmssp_pre_full d S B"
and S_reaches: "⋀x. x ∈ S ⟹ reachable s x"
and loop: "bmssp_post_full
(find_pivots_label_capped k cap d S B)
(find_pivots_pivots_capped k cap d S B) B d_final B' U_loop"
and compW: "complete_on d_final
{v ∈ bound_tree S B'. find_pivots_label_capped k cap d S B v = dist s v}"
defines "U ≡ U_loop ∪
{v ∈ bound_tree S B'. find_pivots_label_capped k cap d S B v = dist s v}"
shows "bmssp_post_full d S B d_final B' U"
proof -
let ?W = "{v ∈ bound_tree S B'. find_pivots_label_capped k cap d S B v = dist s v}"
have le: "bound_le B' B"
using loop unfolding bmssp_post_full_def by blast
have U_eq: "U = bound_tree S B'"
using concrete_capped_find_pivots_final_tree_assembly[OF sound pre S_reaches loop]
unfolding U_def by simp
have loop_complete: "complete_on d_final U_loop"
using loop unfolding bmssp_post_full_def by blast
have "complete_on d_final U"
unfolding U_def using complete_on_Un[OF loop_complete compW] .
then show ?thesis
using le U_eq unfolding bmssp_post_full_def by blast
qed
text ‹
The final assembly theorems are the facts used by
‹concrete_capped_bmssp_step›. The loop solves the pivot tree, while
FindPivots may have completed additional vertices in the caller's original
tree. The assembly theorem proves that the union of those two regions is
the caller's returned bounded tree. The postcondition theorems then add
completeness of the explicitly completed FindPivots region and conclude
@{const bmssp_post_full} for the whole non-base step.
›
end
end