(* Title: Correctness of Path Algorithms Author: Walter Guttmann, Peter Hoefner Maintainer: Walter Guttmann <walter.guttmann at canterbury.ac.nz> Peter Hoefner <peter at hoefner-online.de> *) section ‹Correctness of Path Algorithms› text ‹ To show that our theory of paths integrates with verification tasks, we verify the correctness of three basic path algorithms. Algorithms at the presented level are executable and can serve prototyping purposes. Data refinement can be carried out to move from such algorithms to more efficient programs. The total-correctness proofs use a library developed in \<^cite>‹"Guttmann2018c"›. › theory Path_Algorithms imports "HOL-Hoare.Hoare_Logic" Rooted_Paths begin no_notation trancl ("(_⇧^{+})" [1000] 999) class choose_singleton_point_signature = fixes choose_singleton :: "'a ⇒ 'a" fixes choose_point :: "'a ⇒ 'a" class relation_algebra_rtc_tarski_choose_point = relation_algebra_rtc_tarski + choose_singleton_point_signature + assumes choose_singleton_singleton: "x ≠ 0 ⟹ singleton (choose_singleton x)" assumes choose_singleton_decreasing: "choose_singleton x ≤ x" assumes choose_point_point: "is_vector x ⟹ x ≠ 0 ⟹ point (choose_point x)" assumes choose_point_decreasing: "choose_point x ≤ x" begin no_notation composition (infixl ";" 75) and times (infixl "*" 70) notation composition (infixl "*" 75) subsection ‹Construction of a path› text ‹ Our first example is a basic greedy algorithm that constructs a path from a vertex $x$ to a different vertex $y$ of a directed acyclic graph $D$. › abbreviation "construct_path_inv q x y D W ≡ is_acyclic D ∧ point x ∧ point y ∧ point q ∧ D⇧^{⋆}* q ≤ D⇧^{T}⇧^{⋆}* x ∧ W ≤ D ∧ terminating_path W ∧ (W = 0 ⟷ q=y) ∧ (W ≠ 0 ⟷ q = start_points W ∧ y = end_points W)" abbreviation "construct_path_inv_simp q x y D W ≡ is_acyclic D ∧ point x ∧ point y ∧ point q ∧ D⇧^{⋆}* q ≤ D⇧^{T}⇧^{⋆}* x ∧ W ≤ D ∧ terminating_path W ∧ q = start_points W ∧ y = end_points W" lemma construct_path_pre: assumes "is_acyclic D" and "point y" and "point x" and "D⇧^{⋆}* y ≤ D⇧^{T}⇧^{⋆}* x" shows "construct_path_inv y x y D 0" apply (intro conjI, simp_all add: assms is_inj_def is_p_fun_def path_def) using assms(2) cycle_iff by fastforce text ‹ The following three lemmas are auxiliary lemmas for ‹construct_path_inv›. They are pulled out of the main proof to have more structure. › lemma path_inv_points: assumes "construct_path_inv q x y D W ∧ q ≠ x" shows "point q" and "point (choose_point (D*q))" using assms apply blast by (metis assms choose_point_point comp_assoc is_vector_def point_def reachable_implies_predecessor) lemma path_inv_choose_point_decrease: assumes "construct_path_inv q x y D W ∧ q ≠ x" shows "W≠0 ⟹ choose_point (D*q) ≤ -((W + choose_point (D*q) * q⇧^{T})⇧^{T}*1)" proof - let ?q = "choose_point (D*q)" let ?W = "W + ?q * q⇧^{T}" assume as: "W≠0" hence "q*W ≤ W⇧^{+}" (* "connected_root q W" *) by (metis assms conv_contrav conv_invol conv_iso conv_terminating_path forward_terminating_path_end_points_1 plus_conv point_def ss423bij terminating_path_iff) hence "?q ⋅ W⇧^{T}*1 ≤ D*q ⋅ W⇧^{T}⇧^{+}*q" using choose_point_decreasing meet_iso meet_isor inf_mono assms connected_root_iff2 by simp also have "... ≤ (D ⋅ D⇧^{T}⇧^{+})*q" by (metis assms inj_distr point_def conv_contrav conv_invol conv_iso meet_isor mult_isol_var mult_isor star_conv star_slide_var star_subdist sup.commute sup.orderE) also have "... ≤ 0" by (metis acyclic_trans assms conv_zero step_has_target order.eq_iff galois_aux ss_p18) finally have a: "?q ≤ -(W⇧^{T}*1)" using galois_aux le_bot by blast have "point ?q" using assms by(rule path_inv_points(2)) hence "?q ≤ -(q*?q⇧^{T}*1)" by (metis assms acyclic_imp_one_step_different_points(2) point_is_point choose_point_decreasing edge_end end_point_char end_point_no_successor) with a show ?thesis by (simp add: inf.boundedI) qed lemma end_points: assumes "construct_path_inv q x y D W ∧ q ≠ x" shows "choose_point (D*q) = start_points (W + choose_point (D*q) * q⇧^{T})" and "y = end_points (W + choose_point (D*q) * q⇧^{T})" proof - let ?q = "choose_point (D*q)" let ?W = "W + ?q * q⇧^{T}" show 1: "?q = start_points ?W" proof (rule order.antisym) show" start_points ?W ≤ ?q" by (metis assms(1) path_inv_points(2) acyclic_imp_one_step_different_points(2) choose_point_decreasing edge_end edge_start sup.commute path_concatenation_start_points_approx point_is_point order.eq_iff sup_bot_left) show "?q ≤ start_points ?W" proof - have a: "?q = ?q*q⇧^{T}*1" by (metis assms(1) comp_assoc point_equations(1) point_is_point aux4 conv_zero choose_point_decreasing choose_point_point conv_contrav conv_one point_def inf.orderE inf_compl_bot inf_compl_bot_right is_vector_def maddux_142 sup_bot_left sur_def_var1) hence "?q =(q ⋅ -q) + (?q ⋅ -q ⋅ -(?W⇧^{T}*1))" by (metis assms path_inv_points(2) path_inv_choose_point_decrease acyclic_imp_one_step_different_points(1) choose_point_decreasing inf.orderE inf_compl_bot sup_inf_absorb edge_start point_is_point sup_bot_left) also have "... ≤ (W*1 ⋅ -(?W⇧^{T}*1) ⋅ -q) + (?q ⋅ -q ⋅ -(?W⇧^{T}*1))" by simp also have "... = (W*1 + ?q) ⋅ -(q + ?W⇧^{T}*1)" by (metis compl_sup inf_sup_distrib2 meet_assoc sup.commute) also have "... ≤ ?W*1 ⋅ -(?W⇧^{T}*1)" using a by (metis inf.left_commute distrib_right' compl_sup inf.cobounded2) finally show "?q ≤ start_points ?W" . qed qed show "y = end_points ?W" proof - have point_nq: "point ?q" using assms by(rule path_inv_points(2)) hence yp: "y ≤ -?q" using 1 assms by (metis acyclic_imp_one_step_different_points(2) choose_point_decreasing cycle_no_points(1) finite_iff finite_iff_msc forward_finite_iff_msc path_aux1a path_edge_equals_cycle point_is_point point_not_equal(1) terminating_iff1) have "y = y + (W*1 ⋅ -(W⇧^{T}*1) ⋅ -(W*1))" by (simp add: inf.commute) also have "... = y + (q ⋅ -(W*1))" using assms by fastforce also have "... = y + (q ⋅ -(W*1) ⋅ -?q)" by (metis calculation sup_assoc sup_inf_absorb) also have "... = (y ⋅ -?q) + (q ⋅ -(W*1) ⋅ -?q)" using yp by (simp add: inf.absorb1) also have "... = (W⇧^{T}*1 ⋅ -(W*1) ⋅ -?q) + (q ⋅ -(W*1) ⋅ -?q)" using assms by fastforce also have "... = (W⇧^{T}*1 + q) ⋅ -(W*1) ⋅ -?q" by (simp add: inf_sup_distrib2) also have "... = (W⇧^{T}*1 + q) ⋅ -(W*1 + ?q)" by (simp add: inf.assoc) also have "... = (W⇧^{T}*1 + q*?q⇧^{T}*1) ⋅ -(W*1 + ?q*q⇧^{T}*1)" using point_nq by(metis assms(1) comp_assoc conv_contrav conv_one is_vector_def point_def sur_def_var1) also have "... = (?W⇧^{T})*1 ⋅ -(?W*1)" by simp finally show ?thesis . qed qed lemma construct_path_inv: assumes "construct_path_inv q x y D W ∧ q ≠ x" shows "construct_path_inv (choose_point (D*q)) x y D (W + choose_point (D*q)*q⇧^{T})" proof (intro conjI) let ?q = "choose_point (D*q)" let ?W = "W + ?q * q⇧^{T}" show "is_acyclic D" using assms by blast show point_y: "point y" using assms by blast show "point x" using assms by blast show "?W ≤ D" using assms choose_point_decreasing le_sup_iff point_def ss423bij inf.boundedE by blast show "D⇧^{⋆}*?q ≤ D⇧^{T}⇧^{⋆}*x" proof - have "D⇧^{+}*q ≤ D⇧^{T}⇧^{⋆}*x" using assms conv_galois_2 order_trans star_1l by blast thus ?thesis by (metis choose_point_decreasing comp_assoc dual_order.trans mult_isol star_slide_var) qed show point_nq: "point ?q" using assms by(rule path_inv_points(2)) show pathW: "path ?W" proof(cases "W=0") assume "W=0" thus ?thesis using assms edge_is_path point_is_point point_nq by simp next assume a: "W≠0" have b: "?q*q⇧^{T}≤ 1*?q*q⇧^{T}*-(?q*q⇧^{T}*1)" proof - have "?q*q⇧^{T}≤1" by simp thus ?thesis using assms point_nq by(metis different_points_consequences(1) point_def sur_def_var1 acyclic_imp_one_step_different_points(2) choose_point_decreasing comp_assoc is_vector_def point_def point_equations(3,4) point_is_point) qed have c: "W ≤ -(1*W)*W*1" using assms terminating_path_iff by blast have d: "(?q*q⇧^{T})⇧^{T}*1 ⋅ -((?q*q⇧^{T})*1) = W*1 ⋅ -(W⇧^{T}*1)" using a by (metis assms path_inv_points(2) acyclic_reachable_points choose_point_decreasing edge_end point_is_point comp_assoc point_def sur_total total_one) have e: "?q*q⇧^{T}*1 ⋅ W⇧^{T}*1 = 0" proof - have "?q*q⇧^{T}*1 ⋅ W⇧^{T}*1 = ?q ⋅ W⇧^{T}*1" using assms point_nq by (metis comp_assoc conv_contrav conv_one is_vector_def point_def sur_def_var1) also have "... ≤ -(?W⇧^{T}*1) ⋅ ?W⇧^{T}*1" using assms path_inv_choose_point_decrease by (smt a conv_contrav conv_iso conv_one inf_mono less_eq_def subdistl_eq) also have "... ≤ 0" using compl_inf_bot eq_refl by blast finally show ?thesis using bot_unique by blast qed show ?thesis using b c d e by (metis assms comp_assoc edge_is_path path_concatenation_cycle_free point_is_point sup.commute point_nq) qed show "?W = 0 ⟷ ?q = y" apply (rule iffI) apply (metis assms conv_zero dist_alt edge_start inf_compl_bot_right modular_1_aux' modular_2_aux' point_is_point sup.left_idem sup_bot_left point_nq) by (smt assms end_points(1) conv_contrav conv_invol cycle_no_points(1) end_point_iff2 has_start_end_points_iff path_aux1b path_edge_equals_cycle point_is_point start_point_iff2 sup_bot_left top_greatest pathW) show "?W≠0 ⟷ ?q = start_points ?W ∧ y = end_points ?W" apply (rule iffI) using assms end_points apply blast using assms by force show "terminating ?W" by (smt assms end_points end_point_iff2 has_start_end_points_iff point_is_point start_point_iff2 terminating_iff1 pathW point_nq) qed theorem construct_path_partial: "VARS p q W { is_acyclic D ∧ point y ∧ point x ∧ D⇧^{⋆}*y ≤ D⇧^{T}⇧^{⋆}*x } W := 0; q := y; WHILE q ≠ x INV { construct_path_inv q x y D W } DO p := choose_point (D*q); W := W + p*q⇧^{T}; q := p OD { W ≤ D ∧ terminating_path W ∧ (W=0 ⟷ x=y) ∧ (W≠0 ⟷ x = start_points W ∧ y = end_points W) }" apply vcg using construct_path_pre apply blast using construct_path_inv apply blast by fastforce end (* relation_algebra_rtc_tarski_choose_point *) text ‹For termination, we additionally need finiteness.› context finite begin lemma decrease_set: assumes "∀x::'a . Q x ⟶ P x" and "P w" and "¬ Q w" shows "card { x . Q x } < card { x . P x }" by (metis Collect_mono assms card_seteq finite mem_Collect_eq not_le) end class relation_algebra_rtc_tarski_choose_point_finite = relation_algebra_rtc_tarski_choose_point + relation_algebra_rtc_tarski_point_finite begin lemma decrease_variant: assumes "y ≤ z" and "w ≤ z" and "¬ w ≤ y" shows "card { x . x ≤ y } < card { x . x ≤ z }" by (metis Collect_mono assms card_seteq linorder_not_le dual_order.trans finite_code mem_Collect_eq) lemma construct_path_inv_termination: assumes "construct_path_inv q x y D W ∧ q ≠ x" shows "card { z . z ≤ -(W + choose_point (D*q)*q⇧^{T}) } < card { z . z ≤ -W }" proof - let ?q = "choose_point (D*q)" let ?W = "W + ?q * q⇧^{T}" show ?thesis proof (rule decrease_variant) show "-?W ≤ -W" by simp show "?q * q⇧^{T}≤ -W" by (metis assms galois_aux inf_compl_bot_right maddux_142 mult_isor order_trans top_greatest) show "¬ (?q * q⇧^{T}≤ -?W)" using assms end_points(1) by (smt acyclic_imp_one_step_different_points(2) choose_point_decreasing compl_sup inf.absorb1 inf_compl_bot_right sup.commute sup_bot.left_neutral conv_zero end_points(2)) qed qed theorem construct_path_total: "VARS p q W [ is_acyclic D ∧ point y ∧ point x ∧ D⇧^{⋆}*y ≤ D⇧^{T}⇧^{⋆}*x ] W := 0; q := y; WHILE q ≠ x INV { construct_path_inv q x y D W } VAR { card { z . z ≤ -W } } DO p := choose_point (D*q); W := W + p*q⇧^{T}; q := p OD [ W ≤ D ∧ terminating_path W ∧ (W=0 ⟷ x=y) ∧ (W≠0 ⟷ x = start_points W ∧ y = end_points W) ]" apply vcg_tc using construct_path_pre apply blast apply (rule CollectI, rule conjI) using construct_path_inv apply blast using construct_path_inv_termination apply clarsimp by fastforce end (* relation_algebra_rtc_tarski_choose_point_finite *) subsection ‹Topological sorting› text ‹ In our second example we look at topological sorting. Given a directed acyclic graph, the problem is to construct a linear order of its vertices that contains $x$ before $y$ for each edge $(x,y)$ of the graph. If the input graph models dependencies between tasks, the output is a linear schedule of the tasks that respects all dependencies. › context relation_algebra_rtc_tarski_choose_point begin abbreviation topological_sort_inv where "topological_sort_inv q v R W ≡ regressively_finite R ∧ R ⋅ v*v⇧^{T}≤ W⇧^{+}∧ terminating_path W ∧ W*1 = v⋅-q ∧ (W = 0 ∨ q = end_points W) ∧ point q ∧ R*v ≤ v ∧ q ≤ v ∧ is_vector v" lemma topological_sort_pre: assumes "regressively_finite R" shows "topological_sort_inv (choose_point (minimum R 1)) (choose_point (minimum R 1)) R 0" proof (intro conjI,simp_all add:assms) let ?q = "choose_point (- (R⇧^{T}* 1))" show point_q: "point ?q" using assms by (metis (full_types) annir choose_point_point galois_aux2 is_inj_def is_sur_def is_vector_def one_idem_mult point_def ss_p18 inf_top_left one_compl) show "R ⋅ ?q * ?q⇧^{T}≤ 0" by (metis choose_point_decreasing conv_invol end_point_char order.eq_iff inf_bot_left schroeder_2) show "path 0" by (simp add: is_inj_def is_p_fun_def path_def) show "R*?q ≤ ?q" by (metis choose_point_decreasing compl_bot_eq conv_galois_1 inf_compl_bot_left2 le_inf_iff) show "is_vector ?q" using point_q point_def by blast qed lemma topological_sort_inv: assumes "v ≠ 1" and "topological_sort_inv q v R W" shows "topological_sort_inv (choose_point (minimum R (- v))) (v + choose_point (minimum R (- v))) R (W + q * choose_point (minimum R (- v))⇧^{T})" proof (intro conjI) let ?p = "choose_point (minimum R (-v))" let ?W = "W + q*?p⇧^{T}" let ?v = "v + ?p" show point_p: "point ?p" using assms by (metis choose_point_point compl_bot_eq double_compl galois_aux2 comp_assoc is_vector_def vector_compl vector_mult) hence ep_np: "end_points (q*?p⇧^{T}) = ?p" using assms(2) by (metis aux4 choose_point_decreasing edge_end le_supI1 point_in_vector_or_complement_iff point_is_point) hence sp_q: "start_points (q*?p⇧^{T}) = q" using assms(2) point_p by (metis (no_types, lifting) conv_contrav conv_invol edge_start point_is_point) hence ep_sp: "W ≠ 0 ⟹ end_points W = start_points (q*?p⇧^{T})" using assms(2) by force have "W*1 ⋅ (q*?p⇧^{T})⇧^{T}*1 = v⋅-q⋅?p" using assms(2) point_p is_vector_def mult_assoc point_def point_equations(3) point_is_point by auto hence 1: "W*1 ⋅ (q*?p⇧^{T})⇧^{T}*1 = 0" by (metis choose_point_decreasing dual_order.trans galois_aux inf.cobounded2 inf.commute) show "regressively_finite R" using assms(2) by blast show "R ⋅ ?v*?v⇧^{T}≤ ?W⇧^{+}" proof - have a: "R ⋅ v*v⇧^{T}≤ ?W⇧^{+}" using assms(2) by (meson mult_isol_var order.trans order_prop star_subdist) have b: "R ⋅ v*?p⇧^{T}≤ ?W⇧^{+}" proof - have "R ⋅ v*?p⇧^{T}≤ W*1*?p⇧^{T}+ q*?p⇧^{T}" by (metis inf_le2 assms(2) aux4 double_compl inf_absorb2 distrib_right) also have "... = W*?p⇧^{T}+ q*?p⇧^{T}" using point_p by (metis conv_contrav conv_one is_vector_def mult_assoc point_def) also have "... ≤ W⇧^{+}*end_points W*?p⇧^{T}+ q*?p⇧^{T}" using assms(2) by (meson forward_terminating_path_end_points_1 join_iso mult_isor terminating_path_iff) also have "... ≤ W⇧^{+}*q*?p⇧^{T}+ q*?p⇧^{T}" using assms(2) by (metis annil eq_refl) also have "... = W⇧^{⋆}*q*?p⇧^{T}" using conway.dagger_unfoldl_distr mult_assoc sup_commute by fastforce also have "... ≤ ?W⇧^{+}" by (metis mult_assoc mult_isol_var star_slide_var star_subdist sup_ge2) finally show ?thesis . qed have c: "R ⋅ ?p*v⇧^{T}≤ ?W⇧^{+}" proof - have "v ≤ -?p" using choose_point_decreasing compl_le_swap1 inf_le1 order_trans by blast hence "R*v ≤ -?p" using assms(2) order.trans by blast thus ?thesis by (metis galois_aux inf_le2 schroeder_2) qed have d: "R ⋅ ?p*?p⇧^{T}≤ ?W⇧^{+}" proof - have "R ⋅ ?p*?p⇧^{T}≤ R ⋅ 1'" using point_p is_inj_def meet_isor point_def by blast also have "... = 0" using assms(2) regressively_finite_irreflexive galois_aux by blast finally show ?thesis using bot_least inf.absorb_iff2 by simp qed have "R ⋅ ?v*?v⇧^{T}= (R ⋅ v*v⇧^{T}) + (R ⋅ v*?p⇧^{T}) + (R ⋅ ?p*v⇧^{T}) + (R ⋅ ?p*?p⇧^{T})" by (metis conv_add distrib_left distrib_right inf_sup_distrib1 sup.commute sup.left_commute) also have "... ≤ ?W⇧^{+}" using a b c d by (simp add: le_sup_iff) finally show ?thesis . qed show pathW: "path ?W" proof (cases "W = 0") assume "W = 0" thus ?thesis using assms(2) point_p edge_is_path point_is_point sup_bot_left by auto next assume a1: "W ≠ 0" have fw_path: "forward_terminating_path W" using assms(2) terminating_iff by blast have bw_path: "backward_terminating_path (q*?p⇧^{T})" using assms point_p sp_q by (metis conv_backward_terminating conv_has_start_points conv_path edge_is_path forward_terminating_iff1 point_is_point start_point_iff2) show ?thesis using fw_path bw_path ep_sp 1 a1 path_concatenation_cycle_free by blast qed show "terminating ?W" proof (rule start_end_implies_terminating) show "has_start_points ?W" apply (cases "W = 0") using assms(2) sp_q pathW apply (metis (no_types, lifting) point_is_point start_point_iff2 sup_bot.left_neutral) using assms(2) ep_sp 1 pathW by (metis has_start_end_points_iff path_concatenation_start_points start_point_iff2 terminating_iff1) show "has_end_points ?W" apply (cases "W = 0") using point_p ep_np ep_sp pathW end_point_iff2 point_is_point apply force using point_p ep_np ep_sp 1 pathW by (metis end_point_iff2 path_concatenation_end_points point_is_point) qed show "?W*1 = ?v⋅-?p" proof - have "?W*1 = v" by (metis assms(2) point_p is_vector_def mult_assoc point_def point_equations(3) point_is_point aux4 distrib_right' inf_absorb2 sup.commute) also have "... = v⋅-?p" by (metis choose_point_decreasing compl_le_swap1 inf.cobounded1 inf.orderE order_trans) finally show ?thesis by (simp add: inf_sup_distrib2) qed show "?W = 0 ∨ ?p = end_points ?W" using ep_np ep_sp 1 by (metis path_concatenation_end_points sup_bot_left) show "R*?v ≤ ?v" using assms(2) by (meson choose_point_decreasing conv_galois_1 inf.cobounded2 order.trans sup.coboundedI1 sup_least) show "?p ≤ ?v" by simp show "is_vector ?v" using assms(2) point_p point_def vector_add by blast qed lemma topological_sort_post: assumes "¬ v ≠ 1" and "topological_sort_inv q v R W" shows "R ≤ W⇧^{+}∧ terminating_path W ∧ (W + W⇧^{T})*1 = -1'*1" proof (intro conjI,simp_all add:assms) show "R ≤ W⇧^{+}" using assms by force show " backward_terminating W ∧ W ≤ 1 * W * (- v + q)" using assms by force show "v ⋅ - q + W⇧^{T}* 1 = - 1' * 1" proof (cases "W = 0") assume "W = 0" thus ?thesis using assms by (metis compl_bot_eq conv_one conv_zero double_compl inf_top.left_neutral is_inj_def le_bot mult_1_right one_idem_mult point_def ss_p18 star_zero sup.absorb2 top_le) next assume a1: "W ≠ 0" hence "-1' ≠ 0" using assms backward_terminating_path_irreflexive le_bot by fastforce hence "1 = 1*-1'*1" by (simp add: tarski) also have "... = -1'*1" by (metis comp_assoc distrib_left mult_1_left sup_top_left distrib_right sup_compl_top) finally have a: "1 = -1'*1" . have "W*1 + W⇧^{T}*1 = 1" using assms a1 by (metis double_compl galois_aux4 inf.absorb_iff2 inf_top.left_neutral) thus ?thesis using a by (simp add: assms(2)) qed qed theorem topological_sort_partial: "VARS p q v W { regressively_finite R } W := 0; q := choose_point (minimum R 1); v := q; WHILE v ≠ 1 INV { topological_sort_inv q v R W } DO p := choose_point (minimum R (-v)); W := W + q*p⇧^{T}; q := p; v := v + p OD { R ≤ W⇧^{+}∧ terminating_path W ∧ (W + W⇧^{T})*1 = -1'*1 }" apply vcg using topological_sort_pre apply blast using topological_sort_inv apply blast using topological_sort_post by blast end (* relation_algebra_rtc_tarski_choose_point *) context relation_algebra_rtc_tarski_choose_point_finite begin lemma topological_sort_inv_termination: assumes "v ≠ 1" and "topological_sort_inv q v R W" shows "card {z . z ≤ -(v + choose_point (minimum R (-v)))} < card { z . z ≤ -v }" proof (rule decrease_variant) let ?p = "choose_point (minimum R (-v))" let ?v = "v + ?p" show "-?v ≤ -v" by simp show "?p ≤ -v" using choose_point_decreasing inf.boundedE by blast have "point ?p" using assms by (metis choose_point_point compl_bot_eq double_compl galois_aux2 comp_assoc is_vector_def vector_compl vector_mult) thus "¬ (?p ≤ -?v)" by (metis annir compl_sup inf.absorb1 inf_compl_bot_right maddux_20 no_end_point_char) qed text ‹ Use precondition ‹is_acyclic› instead of ‹regressively_finite›. They are equivalent for finite graphs. › theorem topological_sort_total: "VARS p q v W [ is_acyclic R ] W := 0; q := choose_point (minimum R 1); v := q; WHILE v ≠ 1 INV { topological_sort_inv q v R W } VAR { card { z . z ≤ -v } } DO p := choose_point (minimum R (-v)); W := W + q*p⇧^{T}; q := p; v := v + p OD [ R ≤ W⇧^{+}∧ terminating_path W ∧ (W + W⇧^{T})*1 = -1'*1 ]" apply vcg_tc apply (drule acyclic_regressively_finite) using topological_sort_pre apply blast apply (rule CollectI, rule conjI) using topological_sort_inv apply blast using topological_sort_inv_termination apply auto[1] using topological_sort_post by blast end (* relation_algebra_rtc_tarski_choose_point_finite *) subsection ‹Construction of a tree› text ‹ Our last application is a correctness proof of an algorithm that constructs a non-empty cycle for a given directed graph. This works in two steps. The first step is to construct a directed tree from a given root along the edges of the graph. › context relation_algebra_rtc_tarski_choose_point begin abbreviation construct_tree_pre where "construct_tree_pre x y R ≡ y ≤ R⇧^{T}⇧^{⋆}*x ∧ point x" abbreviation construct_tree_inv where "construct_tree_inv v x y D R ≡ construct_tree_pre x y R ∧ is_acyclic D ∧ is_inj D ∧ D ≤ R ∧ D*x = 0 ∧ v = x + D⇧^{T}*1 ∧ x*v⇧^{T}≤ D⇧^{⋆}∧ D ≤ v*v⇧^{T}∧ is_vector v" abbreviation construct_tree_post where "construct_tree_post x y D R ≡ is_acyclic D ∧ is_inj D ∧ D ≤ R ∧ D*x = 0 ∧ D⇧^{T}*1 ≤ D⇧^{T}⇧^{⋆}*x ∧ D⇧^{⋆}*y ≤ D⇧^{T}⇧^{⋆}*x" lemma construct_tree_pre: assumes "construct_tree_pre x y R" shows "construct_tree_inv x x y 0 R" using assms by (simp add: is_inj_def point_def) lemma construct_tree_inv_aux: assumes "¬ y ≤ v" and "construct_tree_inv v x y D R" shows "singleton (choose_singleton (v*-v⇧^{T}⋅ R))" proof (rule choose_singleton_singleton, rule notI) assume "v*-v⇧^{T}⋅ R = 0" hence "R⇧^{T}⇧^{⋆}*v ≤ v" by (metis galois_aux conv_compl conv_galois_1 conv_galois_2 conv_invol double_compl star_inductl_var) hence "y = 0" using assms by (meson mult_isol order_trans sup.cobounded1) thus False using assms point_is_point by auto qed lemma construct_tree_inv: assumes "¬ y ≤ v" and "construct_tree_inv v x y D R" shows "construct_tree_inv (v + choose_singleton (v*-v⇧^{T}⋅ R)⇧^{T}*1) x y (D + choose_singleton (v*-v⇧^{T}⋅ R)) R" proof (intro conjI) let ?e = "choose_singleton (v*-v⇧^{T}⋅ R)" let ?D = "D + ?e" let ?v = "v + ?e⇧^{T}*1" have 1: "?e ≤ v*-v⇧^{T}" using choose_singleton_decreasing inf.boundedE by blast show "point x" by (simp add: assms) show "y ≤ R⇧^{T}⇧^{⋆}*x" by (simp add: assms) show "is_acyclic ?D" using 1 assms acyclic_inv by fastforce show "is_inj ?D" using 1 construct_tree_inv_aux assms injective_inv by blast show "?D ≤ R" apply (rule sup.boundedI) using assms apply blast using choose_singleton_decreasing inf.boundedE by blast show "?D*x = 0" proof - have "?D*x = ?e*x" by (simp add: assms) also have "... ≤ ?e*v" by (simp add: assms mult_isol) also have "... ≤ v*-v⇧^{T}*v" using 1 mult_isor by blast also have "... = 0" by (metis assms(2) annir comp_assoc vector_prop1) finally show ?thesis using le_bot by blast qed show "?v = x + ?D⇧^{T}*1" by (simp add: assms sup_assoc) show "x*?v⇧^{T}≤ ?D⇧^{⋆}" proof - have "x*?v⇧^{T}= x*v⇧^{T}+ x*1*?e" by (simp add: distrib_left mult_assoc) also have "... ≤ D⇧^{⋆}+ x*1*(?e ⋅ v*-v⇧^{T})" using 1 by (metis assms(2) inf.absorb1 join_iso) also have "... = D⇧^{⋆}+ x*1*(?e ⋅ v ⋅ -v⇧^{T})" by (metis assms(2) comp_assoc conv_compl inf.assoc vector_compl vector_meet_comp) also have "... ≤ D⇧^{⋆}+ x*1*(?e ⋅ v)" using join_isol mult_subdistl by fastforce also have "... = D⇧^{⋆}+ x*(1 ⋅ v⇧^{T})*?e" by (metis assms(2) inf.commute mult_assoc vector_2) also have "... = D⇧^{⋆}+ x*v⇧^{T}*?e" by simp also have "... ≤ D⇧^{⋆}+ D⇧^{⋆}*?e" using assms join_isol mult_isor by blast also have "... ≤ ?D⇧^{⋆}" by (meson le_sup_iff prod_star_closure star_ext star_subdist) finally show ?thesis . qed show "?D ≤ ?v*?v⇧^{T}" proof (rule sup.boundedI) show "D ≤ ?v*?v⇧^{T}" using assms by (meson conv_add distrib_left le_supI1 conv_iso dual_order.trans mult_isol_var order_prop) have "?e ≤ v*(-v⇧^{T}⋅ v⇧^{T}*?e)" using 1 inf.absorb_iff2 modular_1' by fastforce also have "... ≤ v*1*?e" by (simp add: comp_assoc le_infI2 mult_isol_var) also have "... ≤ ?v*?v⇧^{T}" by (metis conv_contrav conv_invol conv_iso conv_one mult_assoc mult_isol_var sup.cobounded1 sup_ge2) finally show "?e ≤ ?v*?v⇧^{T}" by simp qed show "is_vector ?v" using assms comp_assoc is_vector_def by fastforce qed lemma construct_tree_post: assumes "y ≤ v" and "construct_tree_inv v x y D R" shows "construct_tree_post x y D R" proof - have "v*x⇧^{T}≤ D⇧^{T}⇧^{⋆}" by (metis (no_types, lifting) assms(2) conv_contrav conv_invol conv_iso star_conv) hence 1: "v ≤ D⇧^{T}⇧^{⋆}*x" using assms point_def ss423bij by blast hence 2: "D⇧^{T}*1 ≤ D⇧^{T}⇧^{⋆}*x" using assms le_supE by blast have "D⇧^{⋆}*y ≤ D⇧^{T}⇧^{⋆}*x" proof (rule star_inductl, rule sup.boundedI) show "y ≤ D⇧^{T}⇧^{⋆}*x" using 1 assms order.trans by blast next have "D*(D⇧^{T}⇧^{⋆}*x) = D*x + D*D⇧^{T}⇧^{+}*x" by (metis conway.dagger_unfoldl_distr distrib_left mult_assoc) also have "... = D*D⇧^{T}⇧^{+}*x" using assms by simp also have "... ≤ 1'*D⇧^{T}⇧^{⋆}*x" by (metis assms(2) is_inj_def mult_assoc mult_isor) finally show "D*(D⇧^{T}⇧^{⋆}*x) ≤ D⇧^{T}⇧^{⋆}*x" by simp qed thus "construct_tree_post x y D R" using 2 assms by simp qed theorem construct_tree_partial: "VARS e v D { construct_tree_pre x y R } D := 0; v := x; WHILE ¬ y ≤ v INV { construct_tree_inv v x y D R } DO e := choose_singleton (v*-v⇧^{T}⋅ R); D := D + e; v := v + e⇧^{T}*1 OD { construct_tree_post x y D R }" apply vcg using construct_tree_pre apply blast using construct_tree_inv apply blast using construct_tree_post by blast end (* relation_algebra_rtc_tarski_choose_point *) context relation_algebra_rtc_tarski_choose_point_finite begin lemma construct_tree_inv_termination: assumes " ¬ y ≤ v" and "construct_tree_inv v x y D R" shows "card { z . z ≤ -(v + choose_singleton (v*-v⇧^{T}⋅ R)⇧^{T}*1) } < card { z . z ≤ -v }" proof (rule decrease_variant) let ?e = "choose_singleton (v*-v⇧^{T}⋅ R)" let ?v = "v + ?e⇧^{T}*1" have 1: "?e ≤ v*-v⇧^{T}" using choose_singleton_decreasing inf.boundedE by blast have 2: "singleton ?e" using construct_tree_inv_aux assms by auto show "-?v ≤ -v" by simp have "?e⇧^{T}≤ -v*v⇧^{T}" using 1 conv_compl conv_iso by force also have "... ≤ -v*1" by (simp add: mult_isol) finally show "?e⇧^{T}*1 ≤ -v" using assms by (metis is_vector_def mult_isor one_compl) thus "¬ (?e⇧^{T}*1 ≤ -?v)" using 2 by (metis annir compl_sup inf.absorb1 inf_compl_bot_right surj_one tarski) qed theorem construct_tree_total: "VARS e v D [ construct_tree_pre x y R ] D := 0; v := x; WHILE ¬ y ≤ v INV { construct_tree_inv v x y D R } VAR { card { z . z ≤ -v } } DO e := choose_singleton (v*-v⇧^{T}⋅ R); D := D + e; v := v + e⇧^{T}*1 OD [ construct_tree_post x y D R ]" apply vcg_tc using construct_tree_pre apply blast apply (rule CollectI, rule conjI) using construct_tree_inv apply blast using construct_tree_inv_termination apply force using construct_tree_post by blast end (* relation_algebra_rtc_tarski_choose_point_finite *) subsection ‹Construction of a non-empty cycle› text ‹ The second step is to construct a path from the root to a given vertex in the tree. Adding an edge back to the root gives the cycle. › context relation_algebra_rtc_tarski_choose_point begin abbreviation comment where "comment _ ≡ SKIP" (* instead of inner comments *) abbreviation construct_cycle_inv where "construct_cycle_inv v x y D R ≡ construct_tree_inv v x y D R ∧ point y ∧ y*x⇧^{T}≤ R" lemma construct_cycle_pre: assumes " ¬ is_acyclic R" and "y = choose_point ((R⇧^{+}⋅ 1')*1)" and "x = choose_point (R⇧^{⋆}*y ⋅ R⇧^{T}*y)" shows "construct_cycle_inv x x y 0 R" proof(rule conjI, rule_tac [2] conjI) show point_y: "point y" using assms by (simp add: choose_point_point is_vector_def mult_assoc galois_aux ss_p18) have "R⇧^{⋆}*y ⋅ R⇧^{T}*y ≠ 0" proof have "R⇧^{+}⋅ 1' = (R⇧^{+})⇧^{T}⋅ 1'" by (metis (mono_tags, opaque_lifting) conv_e conv_times inf.cobounded1 inf.commute many_strongly_connected_iff_6_eq mult_oner star_subid) also have "... = R⇧^{T}⇧^{+}⋅ 1'" using plus_conv by fastforce also have "... ≤ (R⇧^{T}⇧^{⋆}⋅ R)*R⇧^{T}" by (metis conv_contrav conv_e conv_invol modular_2_var mult_oner star_slide_var) also have "... ≤ (R⇧^{T}⇧^{⋆}⋅ R)*1" by (simp add: mult_isol) finally have a: "(R⇧^{+}⋅ 1')*1 ≤ (R⇧^{T}⇧^{⋆}⋅ R)*1" by (metis mult_assoc mult_isor one_idem_mult) assume "R⇧^{⋆}*y ⋅ R⇧^{T}*y = 0" hence "(R⇧^{⋆}⋅ R⇧^{T})*y = 0" using point_y inj_distr point_def by blast hence "(R⇧^{⋆}⋅ R⇧^{T})⇧^{T}*1 ≤ -y" by (simp add: conv_galois_1) hence "y ≤ -((R⇧^{⋆}⋅ R⇧^{T})⇧^{T}*1)" using compl_le_swap1 by blast also have "... = -((R⇧^{T}⇧^{⋆}⋅ R)*1)" by (simp add: star_conv) also have "... ≤ -((R⇧^{+}⋅ 1')*1)" using a comp_anti by blast also have "... ≤ -y" by (simp add: assms galois_aux ss_p18 choose_point_decreasing) finally have "y = 0" using inf.absorb2 by fastforce thus False using point_y annir point_equations(2) point_is_point tarski by force qed hence point_x: "point x" by (metis point_y assms(3) inj_distr is_vector_def mult_assoc point_def choose_point_point) hence "y ≤ R⇧^{T}⇧^{⋆}* x" by (metis assms(3) point_y choose_point_decreasing inf_le1 order.trans point_swap star_conv) thus tree_inv: "construct_tree_inv x x y 0 R" using point_x construct_tree_pre by blast show "y * x⇧^{T}≤ R" proof - have "x ≤ R⇧^{⋆}*y ⋅ R⇧^{T}*y" using assms(3) choose_point_decreasing by blast also have "... = (R⇧^{⋆}⋅ R⇧^{T})*y" using point_y inj_distr point_def by fastforce finally have "x*y⇧^{T}≤ R⇧^{⋆}⋅ R⇧^{T}" using point_y point_def ss423bij by blast also have "... ≤ R⇧^{T}" by simp finally show ?thesis using conv_iso by force qed qed lemma construct_cycle_pre2: assumes "y ≤ v" and "construct_cycle_inv v x y D R" shows "construct_path_inv y x y D 0 ∧ D ≤ R ∧ D * x = 0 ∧ y * x⇧^{T}≤ R" proof(intro conjI, simp_all add: assms) show "D⇧^{⋆}* y ≤ D⇧^{T}⇧^{⋆}* x" using assms construct_tree_post by blast show "path 0" by (simp add: is_inj_def is_p_fun_def path_def) show "y ≠ 0" using assms(2) is_point_def point_is_point by blast qed lemma construct_cycle_post: assumes "¬ q ≠ x" and "(construct_path_inv q x y D W ∧ D ≤ R ∧ D * x = 0 ∧ y * x⇧^{T}≤ R)" shows "W + y * x⇧^{T}≠ 0 ∧ W + y * x⇧^{T}≤ R ∧ cycle (W + y * x⇧^{T})" proof(intro conjI) let ?C = "W + y*x⇧^{T}" show "?C ≠ 0" by (metis assms acyclic_imp_one_step_different_points(2) no_trivial_inverse point_def ss423bij sup_bot.monoid_axioms monoid.left_neutral) show "?C ≤ R" using assms(2) order_trans sup.boundedI by blast show "path (W + y * x⇧^{T})" by (metis assms construct_tree_pre edge_is_path less_eq_def path_edge_equals_cycle point_is_point terminating_iff1) show "many_strongly_connected (W + y * x⇧^{T})" by (metis assms construct_tree_pre bot_least conv_zero less_eq_def path_edge_equals_cycle star_conv star_subid terminating_iff1) qed theorem construct_cycle_partial: "VARS e p q v x y C D W { ¬ is_acyclic R } y := choose_point ((R⇧^{+}⋅ 1')*1); x := choose_point (R⇧^{⋆}*y ⋅ R⇧^{T}*y); D := 0; v := x; WHILE ¬ y ≤ v INV { construct_cycle_inv v x y D R } DO e := choose_singleton (v*-v⇧^{T}⋅ R); D := D + e; v := v + e⇧^{T}*1 OD; comment { is_acyclic D ∧ point y ∧ point x ∧ D⇧^{⋆}*y ≤ D⇧^{T}⇧^{⋆}*x }; W := 0; q := y; WHILE q ≠ x INV { construct_path_inv q x y D W ∧ D ≤ R ∧ D*x = 0 ∧ y*x⇧^{T}≤ R } DO p := choose_point (D*q); W := W + p*q⇧^{T}; q := p OD; comment { W ≤ D ∧ terminating_path W ∧ (W = 0 ⟷ q=y) ∧ (W ≠ 0 ⟷ q = start_points W ∧ y = end_points W) }; C := W + y*x⇧^{T}{ C ≠ 0 ∧ C ≤ R ∧ cycle C }" apply vcg using construct_cycle_pre apply blast using construct_tree_inv apply blast using construct_cycle_pre2 apply blast using construct_path_inv apply blast using construct_cycle_post by blast end (* relation_algebra_rtc_tarski_choose_point *) context relation_algebra_rtc_tarski_choose_point_finite begin theorem construct_cycle_total: "VARS e p q v x y C D W [ ¬ is_acyclic R ] y := choose_point ((R⇧^{+}⋅ 1')*1); x := choose_point (R⇧^{⋆}*y ⋅ R⇧^{T}*y); D := 0; v := x; WHILE ¬ y ≤ v INV { construct_cycle_inv v x y D R } VAR { card { z . z ≤ -v } } DO e := choose_singleton (v*-v⇧^{T}⋅ R); D := D + e; v := v + e⇧^{T}*1 OD; comment { is_acyclic D ∧ point y ∧ point x ∧ D⇧^{⋆}*y ≤ D⇧^{T}⇧^{⋆}*x }; W := 0; q := y; WHILE q ≠ x INV { construct_path_inv q x y D W ∧ D ≤ R ∧ D*x = 0 ∧ y*x⇧^{T}≤ R } VAR { card { z . z ≤ -W } } DO p := choose_point (D*q); W := W + p*q⇧^{T}; q := p OD; comment { W ≤ D ∧ terminating_path W ∧ (W = 0 ⟷ q=y) ∧ (W ≠ 0 ⟷ q = start_points W ∧ y = end_points W)}; C := W + y*x⇧^{T}[ C ≠ 0 ∧ C ≤ R ∧ cycle C ]" apply vcg_tc using construct_cycle_pre apply blast apply (rule CollectI, rule conjI) using construct_tree_inv apply blast using construct_tree_inv_termination apply force using construct_cycle_pre2 apply blast apply (rule CollectI, rule conjI) using construct_path_inv apply blast using construct_path_inv_termination apply clarsimp using construct_cycle_post by blast end (* relation_algebra_rtc_tarski_choose_point_finite *) end