diff --git a/thys/Relational_Disjoint_Set_Forests/Disjoint_Set_Forests.thy b/thys/Relational_Disjoint_Set_Forests/Disjoint_Set_Forests.thy --- a/thys/Relational_Disjoint_Set_Forests/Disjoint_Set_Forests.thy +++ b/thys/Relational_Disjoint_Set_Forests/Disjoint_Set_Forests.thy @@ -1,2426 +1,2426 @@ (* Title: Disjoint-Set Forests Author: Walter Guttmann Maintainer: Walter Guttmann *) theory Disjoint_Set_Forests imports - Aggregation_Algebras.Hoare_Logic + "HOL-Hoare.Hoare_Logic" Stone_Kleene_Relation_Algebras.Kleene_Relation_Algebras begin no_notation trancl ("(_\<^sup>+)" [1000] 999) context kleene_algebra begin lemma star_sup_2: assumes "x * x \ x" and "x * y \ x" shows "(x \ y)\<^sup>\ = y\<^sup>\ * (x \ 1)" proof - have "(x \ y)\<^sup>\ = y\<^sup>\ * (x * y\<^sup>\)\<^sup>\" by (simp add: star.circ_decompose_6 star_sup_1) also have "... = y\<^sup>\ * x\<^sup>\" using assms(2) dual_order.antisym star.circ_back_loop_prefixpoint star_right_induct_mult by fastforce also have "... = y\<^sup>\ * (x \ 1)" by (simp add: assms(1) sup_commute transitive_star) finally show ?thesis . qed end context stone_relation_algebra begin text \ We start with a few basic properties of arcs, points and rectangles. An arc in a Stone relation algebra corresponds to an atom in a relation algebra and represents a single edge in a graph. A point represents a set of nodes. A rectangle represents the Cartesian product of two sets of nodes \cite{BerghammerStruth2010}. \ lemma points_arc: "point x \ point y \ arc (x * y\<^sup>T)" by (metis comp_associative conv_dist_comp conv_involutive equivalence_top_closed) lemma point_arc: "point x \ arc (x * x\<^sup>T)" by (simp add: points_arc) lemma injective_codomain: assumes "injective x" shows "x * (x \ 1) = x \ 1" proof (rule antisym) show "x * (x \ 1) \ x \ 1" by (metis assms comp_right_one dual_order.trans inf.boundedI inf.cobounded1 inf.sup_monoid.add_commute mult_right_isotone one_inf_conv) next show "x \ 1 \ x * (x \ 1)" by (metis coreflexive_idempotent inf.cobounded1 inf.cobounded2 mult_left_isotone) qed abbreviation rectangle :: "'a \ bool" where "rectangle x \ x * top * x = x" lemma arc_rectangle: "arc x \ rectangle x" using arc_top_arc by blast section \Relation-Algebraic Semantics of Associative Array Access\ text \ The following two operations model updating array $x$ at index $y$ to value $z$, and reading the content of array $x$ at index $y$, respectively. The read operation uses double brackets to avoid ambiguity with list syntax. The remainder of this section shows basic properties of these operations. \ abbreviation rel_update :: "'a \ 'a \ 'a \ 'a" ("(_[_\_])" [70, 65, 65] 61) where "x[y\z] \ (y \ z\<^sup>T) \ (-y \ x)" abbreviation rel_access :: "'a \ 'a \ 'a" ("(2_[[_]])" [70, 65] 65) where "x[[y]] \ x\<^sup>T * y" text \Theorem 1.1\ lemma update_univalent: assumes "univalent x" and "vector y" and "injective z" shows "univalent (x[y\z])" proof - have 1: "univalent (y \ z\<^sup>T)" using assms(3) inf_commute univalent_inf_closed by force have "(y \ z\<^sup>T)\<^sup>T * (-y \ x) = (y\<^sup>T \ z) * (-y \ x)" by (simp add: conv_dist_inf) also have "... = z * (y \ -y \ x)" by (metis assms(2) covector_inf_comp_3 inf.sup_monoid.add_assoc inf.sup_monoid.add_commute) finally have 2: "(y \ z\<^sup>T)\<^sup>T * (-y \ x) = bot" by simp have 3: "vector (-y)" using assms(2) vector_complement_closed by simp have "(-y \ x)\<^sup>T * (y \ z\<^sup>T) = (-y\<^sup>T \ x\<^sup>T) * (y \ z\<^sup>T)" by (simp add: conv_complement conv_dist_inf) also have "... = x\<^sup>T * (-y \ y \ z\<^sup>T)" using 3 by (metis (mono_tags, hide_lams) conv_complement covector_inf_comp_3 inf.sup_monoid.add_assoc inf.sup_monoid.add_commute) finally have 4: "(-y \ x)\<^sup>T * (y \ z\<^sup>T) = bot" by simp have 5: "univalent (-y \ x)" using assms(1) inf_commute univalent_inf_closed by fastforce have "(x[y\z])\<^sup>T * (x[y\z]) = (y \ z\<^sup>T)\<^sup>T * (x[y\z]) \ (-y \ x)\<^sup>T * (x[y\z])" by (simp add: conv_dist_sup mult_right_dist_sup) also have "... = (y \ z\<^sup>T)\<^sup>T * (y \ z\<^sup>T) \ (y \ z\<^sup>T)\<^sup>T * (-y \ x) \ (-y \ x)\<^sup>T * (y \ z\<^sup>T) \ (-y \ x)\<^sup>T * (-y \ x)" by (simp add: mult_left_dist_sup sup_assoc) finally show ?thesis using 1 2 4 5 by simp qed text \Theorem 1.2\ lemma update_total: assumes "total x" and "vector y" and "regular y" and "surjective z" shows "total (x[y\z])" proof - have "(x[y\z]) * top = x*top[y\top*z]" by (simp add: assms(2) semiring.distrib_right vector_complement_closed vector_inf_comp conv_dist_comp) also have "... = top[y\top]" using assms(1) assms(4) by simp also have "... = top" using assms(3) regular_complement_top by auto finally show ?thesis by simp qed text \Theorem 1.3\ lemma update_mapping: assumes "mapping x" and "vector y" and "regular y" and "bijective z" shows "mapping (x[y\z])" using assms update_univalent update_total by simp text \Theorem 1.4\ lemma read_injective: assumes "injective y" and "univalent x" shows "injective (x[[y]])" using assms injective_mult_closed univalent_conv_injective by blast text \Theorem 1.5\ lemma read_surjective: assumes "surjective y" and "total x" shows "surjective (x[[y]])" using assms surjective_mult_closed total_conv_surjective by blast text \Theorem 1.6\ lemma read_bijective: assumes "bijective y" and "mapping x" shows "bijective (x[[y]])" by (simp add: assms read_injective read_surjective) text \Theorem 1.7\ lemma read_point: assumes "point p" and "mapping x" shows "point (x[[p]])" using assms comp_associative read_injective read_surjective by auto text \Theorem 1.8\ lemma update_postcondition: assumes "point x" "point y" shows "x \ p = x * y\<^sup>T \ p[[x]] = y" apply (rule iffI) subgoal by (metis assms comp_associative conv_dist_comp conv_involutive covector_inf_comp_3 equivalence_top_closed vector_covector) subgoal apply (rule antisym) subgoal by (metis assms conv_dist_comp conv_involutive inf.boundedI inf.cobounded1 vector_covector vector_restrict_comp_conv) subgoal by (smt assms comp_associative conv_dist_comp conv_involutive covector_restrict_comp_conv dense_conv_closed equivalence_top_closed inf.boundedI shunt_mapping vector_covector preorder_idempotent) done done text \Back and von Wright's array independence requirements \cite{BackWright1998}, later also lens laws \cite{FosterGreenwaldMoorePierceSchmitt2007}\ lemma put_get: assumes "vector y" "surjective y" "vector z" shows "(x[y\z])[[y]] = z" proof - have "(x[y\z])[[y]] = (y\<^sup>T \ z) * y \ (-y\<^sup>T \ x\<^sup>T) * y" by (simp add: conv_complement conv_dist_inf conv_dist_sup mult_right_dist_sup) also have "... = z * y" proof - have "(-y\<^sup>T \ x\<^sup>T) * y = bot" by (metis assms(1) covector_inf_comp_3 inf_commute conv_complement mult_right_zero p_inf vector_complement_closed) thus ?thesis by (simp add: assms covector_inf_comp_3 inf_commute) qed also have "... = z" by (metis assms(2,3) mult_assoc) finally show ?thesis . qed lemma put_put: "(x[y\z])[y\w] = x[y\w]" by (metis inf_absorb2 inf_commute inf_le1 inf_sup_distrib1 maddux_3_13 sup_inf_absorb) lemma get_put: assumes "point y" shows "x[y\x[[y]]] = x" proof - have "x[y\x[[y]]] = (y \ y\<^sup>T * x) \ (-y \ x)" by (simp add: conv_dist_comp) also have "... = (y \ x) \ (-y \ x)" proof - have "y \ y\<^sup>T * x = y \ x" proof (rule antisym) have "y \ y\<^sup>T * x = (y \ y\<^sup>T) * x" by (simp add: assms vector_inf_comp) also have "(y \ y\<^sup>T) * x = y * y\<^sup>T * x" by (simp add: assms vector_covector) also have "... \ x" using assms comp_isotone by fastforce finally show "y \ y\<^sup>T * x \ y \ x" by simp have "y \ x \ y\<^sup>T * x" by (simp add: assms vector_restrict_comp_conv) thus "y \ x \ y \ y\<^sup>T * x" by simp qed thus ?thesis by simp qed also have "... = x" proof - have "regular y" using assms bijective_regular by blast thus ?thesis by (metis inf.sup_monoid.add_commute maddux_3_11_pp) qed finally show ?thesis . qed lemma update_inf: "u \ y \ (x[y\z]) \ u = z\<^sup>T \ u" by (smt comp_inf.mult_right_dist_sup comp_inf.semiring.mult_zero_right inf.left_commute inf.sup_monoid.add_assoc inf_absorb2 p_inf sup_bot_right inf.sup_monoid.add_commute) lemma update_inf_same: "(x[y\z]) \ y = z\<^sup>T \ y" by (simp add: update_inf) lemma update_inf_different: "u \ -y \ (x[y\z]) \ u = x \ u" by (smt inf.right_idem inf.sup_monoid.add_commute inf.sup_relative_same_increasing inf_import_p maddux_3_13 sup.cobounded2 update_inf_same) end section \Relation-Algebraic Semantics of Disjoint-Set Forests\ text \ A disjoint-set forest represents a partition of a set into equivalence classes. We take the represented equivalence relation as the semantics of a forest. It is obtained by operation \fc\ below. Additionally, operation \wcc\ giving the weakly connected components of a graph will be used for the semantics of the union of two disjoint sets. Finally, operation \root\ yields the root of a component tree, that is, the representative of a set containing a given element. This section defines these operations and derives their properties. \ context stone_kleene_relation_algebra begin lemma equivalence_star_closed: "equivalence x \ equivalence (x\<^sup>\)" by (simp add: conv_star_commute star.circ_reflexive star.circ_transitive_equal) lemma equivalence_plus_closed: "equivalence x \ equivalence (x\<^sup>+)" by (simp add: conv_star_commute star.circ_reflexive star.circ_sup_one_left_unfold star.circ_transitive_equal) lemma reachable_without_loops: "x\<^sup>\ = (x \ -1)\<^sup>\" proof (rule antisym) have "x * (x \ -1)\<^sup>\ = (x \ 1) * (x \ -1)\<^sup>\ \ (x \ -1) * (x \ -1)\<^sup>\" by (metis maddux_3_11_pp mult_right_dist_sup regular_one_closed) also have "... \ (x \ -1)\<^sup>\" by (metis inf.cobounded2 le_supI mult_left_isotone star.circ_circ_mult star.left_plus_below_circ star_involutive star_one) finally show "x\<^sup>\ \ (x \ -1)\<^sup>\" by (metis inf.cobounded2 maddux_3_11_pp regular_one_closed star.circ_circ_mult star.circ_sup_2 star_involutive star_sub_one) next show "(x \ -1)\<^sup>\ \ x\<^sup>\" by (simp add: star_isotone) qed lemma plus_reachable_without_loops: "x\<^sup>+ = (x \ -1)\<^sup>+ \ (x \ 1)" by (metis comp_associative maddux_3_11_pp regular_one_closed star.circ_back_loop_fixpoint star.circ_loop_fixpoint sup_assoc reachable_without_loops) lemma star_plus_loops: "x\<^sup>\ \ 1 = x\<^sup>+ \ 1" using star.circ_plus_one star_left_unfold_equal sup_commute by auto lemma star_plus_without_loops: "x\<^sup>\ \ -1 = x\<^sup>+ \ -1" by (metis maddux_3_13 star_left_unfold_equal) text \Theorem 4.2\ lemma omit_redundant_points: assumes "point p" shows "p \ x\<^sup>\ = (p \ 1) \ (p \ x) * (-p \ x)\<^sup>\" proof (rule antisym) let ?p = "p \ 1" have "?p * x * (-p \ x)\<^sup>\ * ?p \ ?p * top * ?p" by (metis comp_associative mult_left_isotone mult_right_isotone top.extremum) also have "... \ ?p" by (simp add: assms injective_codomain vector_inf_one_comp) finally have "?p * x * (-p \ x)\<^sup>\ * ?p * x \ ?p * x" using mult_left_isotone by blast hence "?p * x * (-p \ x)\<^sup>\ * (p \ x) \ ?p * x" by (simp add: assms comp_associative vector_inf_one_comp) also have 1: "... \ ?p * x * (-p \ x)\<^sup>\" using mult_right_isotone star.circ_reflexive by fastforce finally have "?p * x * (-p \ x)\<^sup>\ * (p \ x) \ ?p * x * (-p \ x)\<^sup>\ * (-p \ x) \ ?p * x * (-p \ x)\<^sup>\" by (simp add: mult_right_isotone star.circ_plus_same star.left_plus_below_circ mult_assoc) hence "?p * x * (-p \ x)\<^sup>\ * ((p \ -p) \ x) \ ?p * x * (-p \ x)\<^sup>\" by (simp add: comp_inf.mult_right_dist_sup mult_left_dist_sup) hence "?p * x * (-p \ x)\<^sup>\ * x \ ?p * x * (-p \ x)\<^sup>\" by (metis assms bijective_regular inf.absorb2 inf.cobounded1 inf.sup_monoid.add_commute shunting_p) hence "?p * x * (-p \ x)\<^sup>\ * x \ ?p * x \ ?p * x * (-p \ x)\<^sup>\" using 1 by simp hence "?p * (1 \ x * (-p \ x)\<^sup>\) * x \ ?p * x * (-p \ x)\<^sup>\" by (simp add: comp_associative mult_left_dist_sup mult_right_dist_sup) also have "... \ ?p * (1 \ x * (-p \ x)\<^sup>\)" by (simp add: comp_associative mult_right_isotone) finally have "?p * x\<^sup>\ \ ?p * (1 \ x * (-p \ x)\<^sup>\)" using star_right_induct by (meson dual_order.trans le_supI mult_left_sub_dist_sup_left mult_sub_right_one) also have "... = ?p \ ?p * x * (-p \ x)\<^sup>\" by (simp add: comp_associative semiring.distrib_left) finally show "p \ x\<^sup>\ \ ?p \ (p \ x) * (-p \ x)\<^sup>\" by (simp add: assms vector_inf_one_comp) show "?p \ (p \ x) * (-p \ x)\<^sup>\ \ p \ x\<^sup>\" by (metis assms comp_isotone inf.boundedI inf.cobounded1 inf.coboundedI2 inf.sup_monoid.add_commute le_supI star.circ_increasing star.circ_transitive_equal star_isotone star_left_unfold_equal sup.cobounded1 vector_export_comp) qed text \Weakly connected components\ abbreviation "wcc x \ (x \ x\<^sup>T)\<^sup>\" text \Theorem 5.1\ lemma wcc_equivalence: "equivalence (wcc x)" apply (intro conjI) subgoal by (simp add: star.circ_reflexive) subgoal by (simp add: star.circ_transitive_equal) subgoal by (simp add: conv_dist_sup conv_star_commute sup_commute) done text \Theorem 5.2\ lemma wcc_increasing: "x \ wcc x" by (simp add: star.circ_sub_dist_1) lemma wcc_isotone: "x \ y \ wcc x \ wcc y" using conv_isotone star_isotone sup_mono by blast lemma wcc_idempotent: "wcc (wcc x) = wcc x" using star_involutive wcc_equivalence by auto text \Theorem 5.3\ lemma wcc_below_wcc: "x \ wcc y \ wcc x \ wcc y" using wcc_idempotent wcc_isotone by fastforce text \Theorem 5.4\ lemma wcc_bot: "wcc bot = 1" by (simp add: star.circ_zero) lemma wcc_one: "wcc 1 = 1" by (simp add: star_one) text \Theorem 5.5\ lemma wcc_top: "wcc top = top" by (simp add: star.circ_top) text \Theorem 5.6\ lemma wcc_with_loops: "wcc x = wcc (x \ 1)" by (metis conv_dist_sup star_decompose_1 star_sup_one sup_commute symmetric_one_closed) lemma wcc_without_loops: "wcc x = wcc (x \ -1)" by (metis conv_star_commute star_sum reachable_without_loops) lemma forest_components_wcc: "injective x \ wcc x = forest_components x" by (simp add: cancel_separate_1) text \Components of a forest, which is represented using edges directed towards the roots\ abbreviation "fc x \ x\<^sup>\ * x\<^sup>T\<^sup>\" text \Theorem 2.1\ lemma fc_equivalence: "univalent x \ equivalence (fc x)" apply (intro conjI) subgoal by (simp add: reflexive_mult_closed star.circ_reflexive) subgoal by (metis cancel_separate_1 eq_iff star.circ_transitive_equal) subgoal by (simp add: conv_dist_comp conv_star_commute) done text \Theorem 2.2\ lemma fc_increasing: "x \ fc x" by (metis le_supE mult_left_isotone star.circ_back_loop_fixpoint star.circ_increasing) text \Theorem 2.3\ lemma fc_isotone: "x \ y \ fc x \ fc y" by (simp add: comp_isotone conv_isotone star_isotone) text \Theorem 2.4\ lemma fc_idempotent: "univalent x \ fc (fc x) = fc x" by (metis fc_equivalence cancel_separate_1 star.circ_transitive_equal star_involutive) text \Theorem 2.5\ lemma fc_star: "univalent x \ (fc x)\<^sup>\ = fc x" using fc_equivalence fc_idempotent star.circ_transitive_equal by simp lemma fc_plus: "univalent x \ (fc x)\<^sup>+ = fc x" by (metis fc_star star.circ_decompose_9) text \Theorem 2.6\ lemma fc_bot: "fc bot = 1" by (simp add: star.circ_zero) lemma fc_one: "fc 1 = 1" by (simp add: star_one) text \Theorem 2.7\ lemma fc_top: "fc top = top" by (simp add: star.circ_top) text \Theorem 5.7\ lemma fc_wcc: "univalent x \ wcc x = fc x" by (simp add: fc_star star_decompose_1) lemma fc_via_root: assumes "total (p\<^sup>\ * (p \ 1))" shows "fc p = p\<^sup>\ * (p \ 1) * p\<^sup>T\<^sup>\" proof (rule antisym) have "1 \ p\<^sup>\ * (p \ 1) * p\<^sup>T\<^sup>\" by (smt assms comp_associative conv_dist_comp conv_star_commute coreflexive_idempotent coreflexive_symmetric inf.cobounded2 total_var) hence "fc p \ p\<^sup>\ * p\<^sup>\ * (p \ 1) * p\<^sup>T\<^sup>\ * p\<^sup>T\<^sup>\" by (metis comp_right_one mult_left_isotone mult_right_isotone mult_assoc) thus "fc p \ p\<^sup>\ * (p \ 1) * p\<^sup>T\<^sup>\" by (simp add: star.circ_transitive_equal mult_assoc) show "p\<^sup>\ * (p \ 1) * p\<^sup>T\<^sup>\ \ fc p" by (metis comp_isotone inf.cobounded2 mult_1_right order.refl) qed text \Theorem 4.1\ lemma update_acyclic_1: assumes "acyclic (p \ -1)" and "point y" and "vector w" and "w \ p\<^sup>\ * y" shows "acyclic ((p[w\y]) \ -1)" proof - let ?p = "p[w\y]" have "w * y\<^sup>T \ p\<^sup>\" using assms(2,4) shunt_bijective by blast hence "w * y\<^sup>T \ (p \ -1)\<^sup>\" using reachable_without_loops by auto hence "w * y\<^sup>T \ -1 \ (p \ -1)\<^sup>\ \ -1" by (simp add: inf.coboundedI2 inf.sup_monoid.add_commute) also have "... \ (p \ -1)\<^sup>+" by (simp add: star_plus_without_loops) finally have 1: "w \ y\<^sup>T \ -1 \ (p \ -1)\<^sup>+" using assms(2,3) vector_covector by auto have "?p \ -1 = (w \ y\<^sup>T \ -1) \ (-w \ p \ -1)" by (simp add: inf_sup_distrib2) also have "... \ (p \ -1)\<^sup>+ \ (-w \ p \ -1)" using 1 sup_left_isotone by blast also have "... \ (p \ -1)\<^sup>+ \ (p \ -1)" using comp_inf.mult_semi_associative sup_right_isotone by auto also have "... = (p \ -1)\<^sup>+" by (metis star.circ_back_loop_fixpoint sup.right_idem) finally have "(?p \ -1)\<^sup>+ \ (p \ -1)\<^sup>+" by (metis comp_associative comp_isotone star.circ_transitive_equal star.left_plus_circ star_isotone) also have "... \ -1" using assms(1) by blast finally show ?thesis by simp qed lemma update_acyclic_2: assumes "acyclic (p \ -1)" and "point y" and "point x" and "y \ p\<^sup>T\<^sup>\ * x" and "univalent p" and "p\<^sup>T * y \ y" shows "acyclic ((p[p\<^sup>T\<^sup>\*x\y]) \ -1)" proof - have "p\<^sup>T * p\<^sup>\ * y = p\<^sup>T * p * p\<^sup>\ * y \ p\<^sup>T * y" by (metis comp_associative mult_left_dist_sup star.circ_loop_fixpoint) also have "... \ p\<^sup>\ * y" by (metis assms(5,6) comp_right_one le_supI le_supI2 mult_left_isotone star.circ_loop_fixpoint star.circ_transitive_equal) finally have "p\<^sup>T\<^sup>\ * x \ p\<^sup>\ * y" by (simp add: assms(2-4) bijective_reverse conv_star_commute comp_associative star_left_induct) thus ?thesis by (simp add: assms(1-3) vector_mult_closed update_acyclic_1) qed lemma update_acyclic_3: assumes "acyclic (p \ -1)" and "point y" and "point w" and "y \ p\<^sup>T\<^sup>\ * w" shows "acyclic ((p[w\y]) \ -1)" by (simp add: assms bijective_reverse conv_star_commute update_acyclic_1) lemma rectangle_star_rectangle: "rectangle a \ a * x\<^sup>\ * a \ a" by (metis mult_left_isotone mult_right_isotone top.extremum) lemma arc_star_arc: "arc a \ a * x\<^sup>\ * a \ a" using arc_top_arc rectangle_star_rectangle by blast lemma star_rectangle_decompose: assumes "rectangle a" shows "(a \ x)\<^sup>\ = x\<^sup>\ \ x\<^sup>\ * a * x\<^sup>\" proof (rule antisym) have 1: "1 \ x\<^sup>\ \ x\<^sup>\ * a * x\<^sup>\" by (simp add: star.circ_reflexive sup.coboundedI1) have "(a \ x) * (x\<^sup>\ \ x\<^sup>\ * a * x\<^sup>\) = a * x\<^sup>\ \ a * x\<^sup>\ * a * x\<^sup>\ \ x\<^sup>+ \ x\<^sup>+ * a * x\<^sup>\" by (metis comp_associative semiring.combine_common_factor semiring.distrib_left sup_commute) also have "... = a * x\<^sup>\ \ x\<^sup>+ \ x\<^sup>+ * a * x\<^sup>\" using assms rectangle_star_rectangle by (simp add: mult_left_isotone sup_absorb1) also have "... = x\<^sup>+ \ x\<^sup>\ * a * x\<^sup>\" by (metis comp_associative star.circ_loop_fixpoint sup_assoc sup_commute) also have "... \ x\<^sup>\ \ x\<^sup>\ * a * x\<^sup>\" using star.left_plus_below_circ sup_left_isotone by auto finally show "(a \ x)\<^sup>\ \ x\<^sup>\ \ x\<^sup>\ * a * x\<^sup>\" using 1 by (metis comp_right_one le_supI star_left_induct) next show "x\<^sup>\ \ x\<^sup>\ * a * x\<^sup>\ \ (a \ x)\<^sup>\" by (metis comp_isotone le_supE le_supI star.circ_increasing star.circ_transitive_equal star_isotone sup_ge2) qed lemma star_arc_decompose: "arc a \ (a \ x)\<^sup>\ = x\<^sup>\ \ x\<^sup>\ * a * x\<^sup>\" using arc_top_arc star_rectangle_decompose by blast lemma plus_rectangle_decompose: assumes "rectangle a" shows "(a \ x)\<^sup>+ = x\<^sup>+ \ x\<^sup>\ * a * x\<^sup>\" proof - have "(a \ x)\<^sup>+ = (a \ x) * (x\<^sup>\ \ x\<^sup>\ * a * x\<^sup>\)" by (simp add: assms star_rectangle_decompose) also have "... = a * x\<^sup>\ \ a * x\<^sup>\ * a * x\<^sup>\ \ x\<^sup>+ \ x\<^sup>+ * a * x\<^sup>\" by (metis comp_associative semiring.combine_common_factor semiring.distrib_left sup_commute) also have "... = a * x\<^sup>\ \ x\<^sup>+ \ x\<^sup>+ * a * x\<^sup>\" using assms rectangle_star_rectangle by (simp add: mult_left_isotone sup_absorb1) also have "... = x\<^sup>+ \ x\<^sup>\ * a * x\<^sup>\" by (metis comp_associative star.circ_loop_fixpoint sup_assoc sup_commute) finally show ?thesis by simp qed text \Theorem 6.1\ lemma plus_arc_decompose: "arc a \ (a \ x)\<^sup>+ = x\<^sup>+ \ x\<^sup>\ * a * x\<^sup>\" using arc_top_arc plus_rectangle_decompose by blast text \Theorem 6.2\ lemma update_acyclic_4: assumes "acyclic (p \ -1)" and "point y" and "point w" and "y \ p\<^sup>\ * w = bot" shows "acyclic ((p[w\y]) \ -1)" proof - let ?p = "p[w\y]" have "y\<^sup>T * p\<^sup>\ * w \ -1" using assms(4) comp_associative pseudo_complement schroeder_3_p by auto hence 1: "p\<^sup>\ * w * y\<^sup>T * p\<^sup>\ \ -1" by (metis comp_associative comp_commute_below_diversity star.circ_transitive_equal) have "?p \ -1 \ (w \ y\<^sup>T) \ (p \ -1)" by (metis comp_inf.mult_right_dist_sup dual_order.trans inf.cobounded1 inf.coboundedI2 inf.sup_monoid.add_assoc le_supI sup.cobounded1 sup_ge2) also have "... = w * y\<^sup>T \ (p \ -1)" using assms(2,3) by (simp add: vector_covector) finally have "(?p \ -1)\<^sup>+ \ (w * y\<^sup>T \ (p \ -1))\<^sup>+" by (simp add: comp_isotone star_isotone) also have "... = (p \ -1)\<^sup>+ \ (p \ -1)\<^sup>\ * w * y\<^sup>T * (p \ -1)\<^sup>\" using assms(2,3) plus_arc_decompose points_arc by (simp add: comp_associative) also have "... \ (p \ -1)\<^sup>+ \ p\<^sup>\ * w * y\<^sup>T * p\<^sup>\" using reachable_without_loops by auto also have "... \ -1" using 1 assms(1) by simp finally show ?thesis by simp qed lemma acyclic_down_closed: "x \ y \ acyclic y \ acyclic x" using comp_isotone star_isotone by fastforce text \Theorem 6.3\ lemma update_acyclic_5: assumes "acyclic (p \ -1)" and "point w" shows "acyclic ((p[w\w]) \ -1)" proof - let ?p = "p[w\w]" have "?p \ -1 \ (w \ w\<^sup>T \ -1) \ (p \ -1)" by (metis comp_inf.mult_right_dist_sup inf.cobounded2 inf.sup_monoid.add_assoc sup_right_isotone) also have "... = p \ -1" using assms(2) by (metis comp_inf.covector_complement_closed equivalence_top_closed inf_top.right_neutral maddux_3_13 pseudo_complement regular_closed_top regular_one_closed vector_covector vector_top_closed) finally show ?thesis using assms(1) acyclic_down_closed by blast qed text \Root of the tree containing point $x$ in the disjoint-set forest $p$\ abbreviation "root p x \ p\<^sup>T\<^sup>\ * x \ (p \ 1) * top" text \Theorem 3.1\ lemma root_var: "root p x = (p \ 1) * p\<^sup>T\<^sup>\ * x" by (simp add: coreflexive_comp_top_inf inf_commute mult_assoc) text \Theorem 3.2\ lemma root_successor_loop: "univalent p \ root p x = p[[root p x]]" by (metis root_var injective_codomain comp_associative conv_dist_inf coreflexive_symmetric equivalence_one_closed inf.cobounded2 univalent_conv_injective) lemma root_transitive_successor_loop: "univalent p \ root p x = p\<^sup>T\<^sup>\ * (root p x)" by (metis mult_1_right star_one star_simulation_right_equal root_successor_loop) text \The root of a tree of a node belongs to the same component as the node.\ lemma root_same_component: "injective x \ root p x * x\<^sup>T \ fc p" by (metis comp_associative coreflexive_comp_top_inf eq_refl inf.sup_left_divisibility inf.sup_monoid.add_commute mult_isotone star.circ_circ_mult star.circ_right_top star.circ_transitive_equal star_one star_outer_increasing test_preserves_equation top_greatest) lemma root_vector: "vector x \ vector (root p x)" by (simp add: vector_mult_closed root_var) lemma root_vector_inf: "vector x \ root p x * x\<^sup>T = root p x \ x\<^sup>T" by (simp add: vector_covector root_vector) lemma root_same_component_vector: "injective x \ vector x \ root p x \ x\<^sup>T \ fc p" using root_same_component root_vector_inf by fastforce lemma univalent_root_successors: assumes "univalent p" shows "(p \ 1) * p\<^sup>\ = p \ 1" proof (rule antisym) have "(p \ 1) * p \ p \ 1" by (smt assms(1) comp_inf.mult_semi_associative conv_dist_comp conv_dist_inf conv_order equivalence_one_closed inf.absorb1 inf.sup_monoid.add_assoc injective_codomain) thus "(p \ 1) * p\<^sup>\ \ p \ 1" using star_right_induct_mult by blast show "p \ 1 \ (p \ 1) * p\<^sup>\" by (metis coreflexive_idempotent inf_le1 inf_le2 mult_right_isotone order_trans star.circ_increasing) qed lemma same_component_same_root_sub: assumes "univalent p" and "bijective y" and "x * y\<^sup>T \ fc p" shows "root p x \ root p y" proof - have "root p x * y\<^sup>T \ (p \ 1) * p\<^sup>T\<^sup>\" by (smt assms(1,3) mult_isotone mult_assoc root_var fc_plus fc_star eq_iff univalent_root_successors) thus ?thesis by (simp add: assms(2) shunt_bijective root_var) qed lemma same_component_same_root: assumes "univalent p" and "bijective x" and "bijective y" and "x * y\<^sup>T \ fc p" shows "root p x = root p y" proof (rule antisym) show "root p x \ root p y" using assms(1,3,4) same_component_same_root_sub by blast have "y * x\<^sup>T \ fc p" using assms(1,4) fc_equivalence conv_dist_comp conv_isotone by fastforce thus "root p y \ root p x" using assms(1,2) same_component_same_root_sub by blast qed lemma same_roots_sub: assumes "univalent q" and "p \ 1 \ q \ 1" and "fc p \ fc q" shows "p\<^sup>\ * (p \ 1) \ q\<^sup>\ * (q \ 1)" proof - have "p\<^sup>\ * (p \ 1) \ p\<^sup>\ * (q \ 1)" using assms(2) mult_right_isotone by auto also have "... \ fc p * (q \ 1)" using mult_left_isotone mult_right_isotone star.circ_reflexive by fastforce also have "... \ fc q * (q \ 1)" by (simp add: assms(3) mult_left_isotone) also have "... = q\<^sup>\ * (q \ 1)" by (metis assms(1) conv_dist_comp conv_dist_inf conv_star_commute inf_commute one_inf_conv symmetric_one_closed mult_assoc univalent_root_successors) finally show ?thesis . qed lemma same_roots: assumes "univalent p" and "univalent q" and "p \ 1 = q \ 1" and "fc p = fc q" shows "p\<^sup>\ * (p \ 1) = q\<^sup>\ * (q \ 1)" by (smt assms conv_dist_comp conv_dist_inf conv_involutive conv_star_commute inf_commute one_inf_conv symmetric_one_closed root_var univalent_root_successors) lemma same_root: assumes "univalent p" and "univalent q" and "p \ 1 = q \ 1" and "fc p = fc q" shows "root p x = root q x" by (metis assms mult_assoc root_var univalent_root_successors) lemma loop_root: assumes "injective x" and "x = p[[x]]" shows "x = root p x" proof (rule antisym) have "x \ p * x" by (metis assms comp_associative comp_right_one conv_order equivalence_one_closed ex231c inf.orderE inf.sup_monoid.add_commute mult_left_isotone mult_right_isotone one_inf_conv) hence "x = (p \ 1) * x" by (simp add: assms(1) inf_absorb2 injective_comp_right_dist_inf) thus "x \ root p x" by (metis assms(2) coreflexive_comp_top_inf inf.boundedI inf.cobounded1 inf.cobounded2 mult_isotone star.circ_increasing) next show "root p x \ x" using assms(2) le_infI1 star_left_induct_mult by auto qed lemma test_comp_test_inf: "(x \ 1) * y * (z \ 1) = (x \ 1) * y \ y * (z \ 1)" by (smt comp_right_one comp_right_subdist_inf coreflexive_comp_top_inf inf.left_commute inf.orderE inf_le2 mult_assoc) lemma test_comp_test_top: "y \ (x \ 1) * top * (z \ 1) = (x \ 1) * y * (z \ 1)" proof - have "\u v . (v \ u\<^sup>T)\<^sup>T = v\<^sup>T \ u" using conv_dist_inf by auto thus ?thesis by (smt conv_dist_comp conv_involutive coreflexive_comp_top_inf inf.cobounded2 inf.left_commute inf.sup_monoid.add_commute symmetric_one_closed mult_assoc symmetric_top_closed) qed lemma one_loop: assumes "acyclic (p \ -1)" and "univalent p" shows "(p \ 1) * (p\<^sup>T \ -1)\<^sup>+ * (p \ 1) = bot" proof - have "p\<^sup>T\<^sup>+ \ (p \ 1) * top * (p \ 1) = (p \ 1) * p\<^sup>T\<^sup>+ * (p \ 1)" by (simp add: test_comp_test_top) also have "... \ p\<^sup>T\<^sup>\ * (p \ 1)" by (simp add: inf.coboundedI2 mult_left_isotone star.circ_mult_upper_bound star.circ_reflexive star.left_plus_below_circ) also have "... = p \ 1" by (metis assms(2) conv_dist_comp conv_dist_inf conv_star_commute inf_commute one_inf_conv symmetric_one_closed univalent_root_successors) also have "... \ 1" by simp finally have "(p \ 1) * top * (p \ 1) \ -(p\<^sup>T\<^sup>+ \ -1)" using p_antitone p_antitone_iff p_shunting_swap by blast hence "(p \ 1)\<^sup>T * (p\<^sup>T\<^sup>+ \ -1) * (p \ 1)\<^sup>T \ bot" using triple_schroeder_p p_top by blast hence "(p \ 1) * (p\<^sup>T\<^sup>+ \ -1) * (p \ 1) = bot" by (simp add: coreflexive_symmetric le_bot) thus ?thesis by (smt assms(1) conv_complement conv_dist_comp conv_dist_inf conv_star_commute inf_absorb1 star.circ_plus_same symmetric_one_closed reachable_without_loops star_plus_without_loops) qed lemma root_root: "root p x = root p (root p x)" by (smt comp_associative comp_inf.mult_right_sub_dist_sup_right dual_order.eq_iff inf.cobounded1 inf.cobounded2 inf.orderE mult_right_isotone star.circ_loop_fixpoint star.circ_transitive_equal root_var) lemma loop_root_2: assumes "acyclic (p \ -1)" and "univalent p" and "injective x" and "x \ p\<^sup>T\<^sup>+ * x" shows "x = root p x" proof (rule antisym) have 1: "x = x \ -(-1 * x)" by (metis assms(3) comp_injective_below_complement inf.orderE mult_1_left regular_one_closed) have "x \ (p\<^sup>T \ -1)\<^sup>+ * x \ (p \ 1) * x" by (metis assms(4) inf_commute mult_right_dist_sup one_inf_conv plus_reachable_without_loops) also have "... \ -1 * x \ (p \ 1) * x" by (metis assms(1) conv_complement conv_dist_inf conv_isotone conv_plus_commute mult_left_isotone semiring.add_right_mono symmetric_one_closed) also have "... \ -1 * x \ root p x" using comp_isotone inf.coboundedI2 star.circ_reflexive sup_right_isotone by auto finally have "x \ (-1 * x \ root p x) \ -(-1 * x)" using 1 inf.boundedI inf.order_iff by blast also have "... \ root p x" using inf.sup_left_divisibility by auto finally show 2: "x \ root p x" . have "root p x = (p \ 1) * x \ (p \ 1) * (p\<^sup>T \ -1)\<^sup>+ * x" by (metis comp_associative mult_left_dist_sup star.circ_loop_fixpoint sup_commute reachable_without_loops root_var) also have "... \ x \ (p \ 1) * (p\<^sup>T \ -1)\<^sup>+ * root p x" using 2 by (metis coreflexive_comp_top_inf inf.cobounded2 mult_right_isotone semiring.add_mono) also have "... = x" by (metis assms(1,2) one_loop root_var mult_assoc semiring.mult_not_zero sup_bot_right) finally show "root p x \ x" . qed end context stone_relation_algebra_tarski begin text \Two basic results about points using the Tarski rule of relation algebras\ lemma point_in_vector_partition: assumes "point x" and "vector y" shows "x \ -y \ x \ --y" proof (cases "x * x\<^sup>T \ -y") case True have "x \ x * x\<^sup>T * x" by (simp add: ex231c) also have "... \ -y * x" by (simp add: True mult_left_isotone) also have "... \ -y" by (metis assms(2) mult_right_isotone top.extremum vector_complement_closed) finally show ?thesis by simp next case False have "x \ x * x\<^sup>T * x" by (simp add: ex231c) also have "... \ --y * x" using False assms(1) arc_in_partition mult_left_isotone point_arc by blast also have "... \ --y" by (metis assms(2) mult_right_isotone top.extremum vector_complement_closed) finally show ?thesis by simp qed lemma point_atomic_vector: assumes "point x" and "vector y" and "regular y" and "y \ x" shows "y = x \ y = bot" proof (cases "x \ -y") case True thus ?thesis using assms(4) inf.absorb2 pseudo_complement by force next case False thus ?thesis using assms point_in_vector_partition by fastforce qed lemma point_in_vector_partition_2: assumes "point x" and "vector y" and "regular y" and "\ y \ -x" shows "x \ y" using assms point_in_vector_partition p_antitone_iff by fastforce text \Theorem 4.3\ lemma distinct_points: assumes "point x" and "point y" and "x \ y" shows "x \ y = bot" by (metis assms antisym comp_bijective_complement inf.sup_monoid.add_commute mult_left_one pseudo_complement regular_one_closed point_in_vector_partition) text \Back and von Wright's array independence requirements \cite{BackWright1998}\ lemma put_get_different_vector: assumes "vector y" "vector w" "w \ -y" shows "(x[y\z])[[w]] = x[[w]]" proof - have "(x[y\z])[[w]] = (y\<^sup>T \ z) * w \ (-y\<^sup>T \ x\<^sup>T) * w" by (simp add: conv_complement conv_dist_inf conv_dist_sup mult_right_dist_sup) also have "... = z * (w \ y) \ x\<^sup>T * (w \ -y)" by (metis assms(1) conv_complement covector_inf_comp_3 inf_commute vector_complement_closed) also have "... = z * (w \ y) \ x\<^sup>T * w" by (simp add: assms(3) inf.absorb1) also have "... = z * bot \ x\<^sup>T * w" by (metis assms(3) comp_inf.semiring.mult_zero_right inf.absorb1 inf.sup_monoid.add_assoc p_inf) also have "... = x\<^sup>T * w" by simp finally show ?thesis . qed lemma put_get_different: assumes "point y" "point w" "w \ y" shows "(x[y\z])[[w]] = x[[w]]" proof - have "w \ y = bot" using assms distinct_points by simp hence "w \ -y" using pseudo_complement by simp thus ?thesis by (simp add: assms(1) assms(2) put_get_different_vector) qed lemma put_put_different_vector: assumes "vector y" "vector v" "v \ y = bot" shows "(x[y\z])[v\w] = (x[v\w])[y\z]" proof - have "(x[y\z])[v\w] = (v \ w\<^sup>T) \ (-v \ y \ z\<^sup>T) \ (-v \ -y \ x)" by (simp add: comp_inf.semiring.distrib_left inf_assoc sup_assoc) also have "... = (v \ w\<^sup>T) \ (y \ z\<^sup>T) \ (-v \ -y \ x)" by (metis assms(3) inf_commute inf_import_p p_inf selection_closed_id) also have "... = (y \ z\<^sup>T) \ (v \ w\<^sup>T) \ (-y \ -v \ x)" by (simp add: inf_commute sup_commute) also have "... = (y \ z\<^sup>T) \ (-y \ v \ w\<^sup>T) \ (-y \ -v \ x)" using assms distinct_points pseudo_complement inf.absorb2 by simp also have "... = (x[v\w])[y\z]" by (simp add: comp_inf.semiring.distrib_left inf_assoc sup_assoc) finally show ?thesis . qed lemma put_put_different: assumes "point y" "point v" "v \ y" shows "(x[y\z])[v\w] = (x[v\w])[y\z]" using assms distinct_points put_put_different_vector by blast end section \Verifying Operations on Disjoint-Set Forests\ text \ In this section we verify the make-set, find-set and union-sets operations of disjoint-set forests. We start by introducing syntax for updating arrays in programs. Updating the value at a given array index means updating the whole array. \ syntax "_rel_update" :: "idt \ 'a \ 'a \ 'b com" ("(2_[_] :=/ _)" [70, 65, 65] 61) translations "x[y] := z" => "(x := (y \ z\<^sup>T) \ (CONST uminus y \ x))" text \ The finiteness requirement in the following class is used for proving that the operations terminate. \ class finite_regular_p_algebra = p_algebra + assumes finite_regular: "finite { x . regular x }" class stone_kleene_relation_algebra_tarski = stone_kleene_relation_algebra + stone_relation_algebra_tarski class stone_kleene_relation_algebra_tarski_finite_regular = stone_kleene_relation_algebra_tarski + finite_regular_p_algebra begin subsection \Make-Set\ text \ We prove two correctness results about make-set. The first shows that the forest changes only to the extent of making one node the root of a tree. The second result adds that only singleton sets are created. \ definition "make_set_postcondition p x p0 \ x \ p = x * x\<^sup>T \ -x \ p = -x \ p0" theorem make_set: "VARS p [ point x \ p0 = p ] p[x] := x [ make_set_postcondition p x p0 ]" apply vcg_tc_simp by (simp add: make_set_postcondition_def inf_sup_distrib1 inf_assoc[THEN sym] vector_covector[THEN sym]) theorem make_set_2: "VARS p [ point x \ p0 = p \ p \ 1 ] p[x] := x [ make_set_postcondition p x p0 \ p \ 1 ]" proof vcg_tc fix p assume 1: "point x \ p0 = p \ p \ 1" show "make_set_postcondition (p[x\x]) x p0 \ p[x\x] \ 1" proof (rule conjI) show "make_set_postcondition (p[x\x]) x p0" using 1 by (simp add: make_set_postcondition_def inf_sup_distrib1 inf_assoc[THEN sym] vector_covector[THEN sym]) show "p[x\x] \ 1" using 1 by (metis coreflexive_sup_closed dual_order.trans inf.cobounded2 vector_covector) qed qed text \ The above total-correctness proof allows us to extract a function, which can be used in other implementations below. This is a technique of \cite{Guttmann2018c}. \ lemma make_set_exists: "point x \ \p' . make_set_postcondition p' x p" using tc_extract_function make_set by blast definition "make_set p x \ (SOME p' . make_set_postcondition p' x p)" lemma make_set_function: assumes "point x" and "p' = make_set p x" shows "make_set_postcondition p' x p" proof - let ?P = "\p' . make_set_postcondition p' x p" have "?P (SOME z . ?P z)" using assms(1) make_set_exists by (meson someI) thus ?thesis using assms(2) make_set_def by auto qed subsection \Find-Set\ text \ Disjoint-set forests are represented by their parent mapping. It is a forest except each root of a component tree points to itself. We prove that find-set returns the root of the component tree of the given node. \ abbreviation "disjoint_set_forest p \ mapping p \ acyclic (p \ -1)" definition "find_set_precondition p x \ disjoint_set_forest p \ point x" definition "find_set_invariant p x y \ find_set_precondition p x \ point y \ y \ p\<^sup>T\<^sup>\ * x" definition "find_set_postcondition p x y \ point y \ y = root p x" lemma find_set_1: "find_set_precondition p x \ find_set_invariant p x x" apply (unfold find_set_invariant_def) using mult_left_isotone star.circ_reflexive find_set_precondition_def by fastforce lemma find_set_2: "find_set_invariant p x y \ y \ p[[y]] \ find_set_invariant p x (p[[y]]) \ card { z . regular z \ z \ p\<^sup>T\<^sup>\ * (p[[y]]) } < card { z . regular z \ z \ p\<^sup>T\<^sup>\ * y }" proof - let ?s = "{ z . regular z \ z \ p\<^sup>T\<^sup>\ * y }" let ?t = "{ z . regular z \ z \ p\<^sup>T\<^sup>\ * (p[[y]]) }" assume 1: "find_set_invariant p x y \ y \ p[[y]]" have 2: "point (p[[y]])" using 1 read_point find_set_invariant_def find_set_precondition_def by simp show "find_set_invariant p x (p[[y]]) \ card ?t < card ?s" proof (unfold find_set_invariant_def, intro conjI) show "find_set_precondition p x" using 1 find_set_invariant_def by simp show "vector (p[[y]])" using 2 by simp show "injective (p[[y]])" using 2 by simp show "surjective (p[[y]])" using 2 by simp show "p[[y]] \ p\<^sup>T\<^sup>\ * x" using 1 by (metis (hide_lams) find_set_invariant_def comp_associative comp_isotone star.circ_increasing star.circ_transitive_equal) show "card ?t < card ?s" proof - have 3: "(p\<^sup>T \ -1) * (p\<^sup>T \ -1)\<^sup>+ * y \ (p\<^sup>T \ -1)\<^sup>+ * y" by (simp add: mult_left_isotone mult_right_isotone star.left_plus_below_circ) have "p[[y]] = (p\<^sup>T \ 1) * y \ (p\<^sup>T \ -1) * y" by (metis maddux_3_11_pp mult_right_dist_sup regular_one_closed) also have "... \ ((p[[y]]) \ y) \ (p\<^sup>T \ -1) * y" by (metis comp_left_subdist_inf mult_1_left semiring.add_right_mono) also have "... = (p\<^sup>T \ -1) * y" using 1 2 find_set_invariant_def distinct_points by auto finally have 4: "(p\<^sup>T \ -1)\<^sup>\ * (p[[y]]) \ (p\<^sup>T \ -1)\<^sup>+ * y" using 3 by (metis inf.antisym_conv inf.eq_refl inf_le1 mult_left_isotone star_plus mult_assoc) hence "p\<^sup>T\<^sup>\ * (p[[y]]) \ p\<^sup>T\<^sup>\ * y" by (metis mult_isotone order_refl star.left_plus_below_circ star_plus mult_assoc) hence 5: "?t \ ?s" using order_trans by auto have 6: "y \ ?s" using 1 find_set_invariant_def bijective_regular mult_left_isotone star.circ_reflexive by fastforce have 7: "\ y \ ?t" proof assume "y \ ?t" hence "y \ (p\<^sup>T \ -1)\<^sup>+ * y" using 4 by (metis reachable_without_loops mem_Collect_eq order_trans) hence "y * y\<^sup>T \ (p\<^sup>T \ -1)\<^sup>+" using 1 find_set_invariant_def shunt_bijective by simp also have "... \ -1" using 1 by (metis (mono_tags, lifting) find_set_invariant_def find_set_precondition_def conv_dist_comp conv_dist_inf conv_isotone conv_star_commute equivalence_one_closed star.circ_plus_same symmetric_complement_closed) finally have "y \ -y" using schroeder_4_p by auto thus False using 1 by (metis find_set_invariant_def comp_inf.coreflexive_idempotent conv_complement covector_vector_comp inf.absorb1 inf.sup_monoid.add_commute pseudo_complement surjective_conv_total top.extremum vector_top_closed regular_closed_top) qed show "card ?t < card ?s" apply (rule psubset_card_mono) subgoal using finite_regular by simp subgoal using 5 6 7 by auto done qed qed qed lemma find_set_3: "find_set_invariant p x y \ y = p[[y]] \ find_set_postcondition p x y" proof - assume 1: "find_set_invariant p x y \ y = p[[y]]" show "find_set_postcondition p x y" proof (unfold find_set_postcondition_def, rule conjI) show "point y" using 1 find_set_invariant_def by simp show "y = root p x" proof (rule antisym) have "y * y\<^sup>T \ p" using 1 by (metis find_set_invariant_def find_set_precondition_def shunt_bijective shunt_mapping top_right_mult_increasing) hence "y * y\<^sup>T \ p \ 1" using 1 find_set_invariant_def le_infI by blast hence "y \ (p \ 1) * top" using 1 by (metis find_set_invariant_def order_lesseq_imp shunt_bijective top_right_mult_increasing mult_assoc) thus "y \ root p x" using 1 find_set_invariant_def by simp next have 2: "x \ p\<^sup>\ * y" using 1 find_set_invariant_def find_set_precondition_def bijective_reverse conv_star_commute by auto have "p\<^sup>T * p\<^sup>\ * y = p\<^sup>T * p * p\<^sup>\ * y \ (p[[y]])" by (metis comp_associative mult_left_dist_sup star.circ_loop_fixpoint) also have "... \ p\<^sup>\ * y \ y" using 1 by (metis find_set_invariant_def find_set_precondition_def comp_isotone mult_left_sub_dist_sup semiring.add_right_mono star.circ_back_loop_fixpoint star.circ_circ_mult star.circ_top star.circ_transitive_equal star_involutive star_one) also have "... = p\<^sup>\ * y" by (metis star.circ_loop_fixpoint sup.left_idem sup_commute) finally have 3: "p\<^sup>T\<^sup>\ * x \ p\<^sup>\ * y" using 2 by (simp add: comp_associative star_left_induct) have "p * y \ (p \ 1) * top = (p \ 1) * p * y" using comp_associative coreflexive_comp_top_inf inf_commute by auto also have "... \ p\<^sup>T * p * y" by (metis inf.cobounded2 inf.sup_monoid.add_commute mult_left_isotone one_inf_conv) also have "... \ y" using 1 find_set_invariant_def find_set_precondition_def mult_left_isotone by fastforce finally have 4: "p * y \ y \ -((p \ 1) * top)" using 1 by (metis find_set_invariant_def shunting_p bijective_regular) have "p\<^sup>T * (p \ 1) \ p\<^sup>T \ 1" using 1 by (metis find_set_invariant_def find_set_precondition_def N_top comp_isotone coreflexive_idempotent inf.cobounded2 inf.sup_monoid.add_commute inf_assoc one_inf_conv shunt_mapping) hence "p\<^sup>T * (p \ 1) * top \ (p \ 1) * top" using inf_commute mult_isotone one_inf_conv by auto hence "p * -((p \ 1) * top) \ -((p \ 1) * top)" by (metis comp_associative inf.sup_monoid.add_commute p_antitone p_antitone_iff schroeder_3_p) hence "p * y \ p * -((p \ 1) * top) \ y \ -((p \ 1) * top)" using 4 dual_order.trans le_supI sup_ge2 by blast hence "p * (y \ -((p \ 1) * top)) \ y \ -((p \ 1) * top)" by (simp add: mult_left_dist_sup) hence "p\<^sup>\ * y \ y \ -((p \ 1) * top)" by (simp add: star_left_induct) hence "p\<^sup>T\<^sup>\ * x \ y \ -((p \ 1) * top)" using 3 dual_order.trans by blast thus "root p x \ y" using 1 by (metis find_set_invariant_def shunting_p bijective_regular) qed qed qed theorem find_set: "VARS y [ find_set_precondition p x ] y := x; WHILE y \ p[[y]] INV { find_set_invariant p x y } VAR { card { z . regular z \ z \ p\<^sup>T\<^sup>\ * y } } DO y := p[[y]] OD [ find_set_postcondition p x y ]" apply vcg_tc_simp apply (fact find_set_1) apply (fact find_set_2) by (fact find_set_3) lemma find_set_exists: "find_set_precondition p x \ \y . find_set_postcondition p x y" using tc_extract_function find_set by blast text \ The root of a component tree is a point, that is, represents a singleton set of nodes. This could be proved from the definitions using Kleene-relation algebraic calculations. But they can be avoided because the property directly follows from the postcondition of the previous correctness proof. The corresponding algorithm shows how to obtain the root. We therefore have an essentially constructive proof of the following result. \ text \Theorem 3.3\ lemma root_point: "disjoint_set_forest p \ point x \ point (root p x)" using find_set_exists find_set_precondition_def find_set_postcondition_def by simp definition "find_set p x \ (SOME y . find_set_postcondition p x y)" lemma find_set_function: assumes "find_set_precondition p x" and "y = find_set p x" shows "find_set_postcondition p x y" by (metis assms find_set_def find_set_exists someI) subsection \Path Compression\ text \ The path-compression technique is frequently implemented in recursive implementations of find-set modifying the tree on the way out from recursive calls. Here we implement it using a second while-loop, which iterates over the same path to the root and changes edges to point to the root of the component, which is known after the while-loop in find-set completes. We prove that path compression preserves the equivalence-relational semantics of the disjoint-set forest and also preserves the roots of the component trees. Additionally we prove the exact effect of path compression. \ definition "path_compression_precondition p x y \ disjoint_set_forest p \ point x \ point y \ y = root p x" definition "path_compression_invariant p x y p0 w \ path_compression_precondition p x y \ point w \ y \ p\<^sup>T\<^sup>\ * w \ (w \ x \ p[[x]] = y \ y \ x \ p\<^sup>T\<^sup>+ * w \ -x) \ p \ 1 = p0 \ 1 \ fc p = fc p0 \ root p w = y \ (w \ y \ p[[w]] \ w \ p\<^sup>T\<^sup>+ * w \ -w) \ p[[w]] = p0[[w]] \ p0[p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * w)\y] = p \ disjoint_set_forest p0 \ y = root p0 x \ w \ p0\<^sup>T\<^sup>\ * x" definition "path_compression_postcondition p x y p0 \ path_compression_precondition p x y \ p \ 1 = p0 \ 1 \ fc p = fc p0 \ p0[p0\<^sup>T\<^sup>\ * x\y] = p" text \ We first consider a variant that achieves the effect as a single update. The parents of all nodes reachable from x are simultaneously updated to the root of the component of x. \ lemma path_compression_exact: assumes "path_compression_precondition p0 x y" and "p0[p0\<^sup>T\<^sup>\ * x\y] = p" shows "p \ 1 = p0 \ 1" "fc p = fc p0" proof - have a1: "disjoint_set_forest p0" and a2: "point x" and a3: "point y" and a4: "y = root p0 x" using path_compression_precondition_def assms(1) by auto have 1: "regular (p0\<^sup>T\<^sup>\ * x)" using a1 a2 bijective_regular mapping_regular regular_closed_star regular_conv_closed regular_mult_closed by auto have "p \ 1 = (p0\<^sup>T\<^sup>\ * x \ y\<^sup>T \ 1) \ (-(p0\<^sup>T\<^sup>\ * x) \ p0 \ 1)" using assms(2) inf_sup_distrib2 by auto also have "... = (p0\<^sup>T\<^sup>\ * x \ p0 \ 1) \ (-(p0\<^sup>T\<^sup>\ * x) \ p0 \ 1)" proof - have "p0\<^sup>T\<^sup>\ * x \ y\<^sup>T \ 1 = p0\<^sup>T\<^sup>\ * x \ p0 \ 1" proof (rule antisym) have "(p0 \ 1) * p0\<^sup>T\<^sup>\ * x \ 1 \ p0" by (smt coreflexive_comp_top_inf_one inf.absorb_iff2 inf.cobounded2 inf.sup_monoid.add_assoc root_var) hence "p0\<^sup>T\<^sup>\ * x \ y\<^sup>T \ 1 \ p0" by (metis inf_le1 a4 conv_dist_inf coreflexive_symmetric inf.absorb2 inf.cobounded2 inf.sup_monoid.add_assoc root_var symmetric_one_closed) thus "p0\<^sup>T\<^sup>\ * x \ y\<^sup>T \ 1 \ p0\<^sup>T\<^sup>\ * x \ p0 \ 1" by (meson inf.le_sup_iff order.refl) have "p0\<^sup>T\<^sup>\ * x \ p0 \ 1 \ y" by (metis a4 coreflexive_comp_top_inf_one inf.cobounded1 inf_assoc inf_le2) thus "p0\<^sup>T\<^sup>\ * x \ p0 \ 1 \ p0\<^sup>T\<^sup>\ * x \ y\<^sup>T \ 1" by (smt conv_dist_inf coreflexive_symmetric inf.absorb_iff2 inf.cobounded2 inf.sup_monoid.add_assoc) qed thus ?thesis by simp qed also have "... = p0 \ 1" using 1 by (metis inf.sup_monoid.add_commute inf_sup_distrib1 maddux_3_11_pp) finally show "p \ 1 = p0 \ 1" . show "fc p = fc p0" proof (rule antisym) have 2: "univalent (p0[p0\<^sup>T\<^sup>\ * x\y])" by (simp add: a1 a2 a3 update_univalent mult_assoc) have 3: "-(p0\<^sup>T\<^sup>\ * x) \ p0 \ (p0[p0\<^sup>T\<^sup>\ * x\y])\<^sup>\ * (p0[p0\<^sup>T\<^sup>\ * x\y])\<^sup>T\<^sup>\" using fc_increasing inf.order_trans sup.cobounded2 by blast have "p0\<^sup>T\<^sup>\ * x \ p0 \ (p0\<^sup>T\<^sup>\ \ p0 * x\<^sup>T) * (x \ p0\<^sup>\ * p0)" by (metis conv_involutive conv_star_commute dedekind) also have "... \ p0\<^sup>T\<^sup>\ * x \ p0 * x\<^sup>T * p0\<^sup>\ * p0" by (metis comp_associative inf.boundedI inf.cobounded2 inf_le1 mult_isotone) also have "... \ p0\<^sup>T\<^sup>\ * x \ top * x\<^sup>T * p0\<^sup>\" using comp_associative comp_inf.mult_right_isotone mult_isotone star.right_plus_below_circ by auto also have "... = p0\<^sup>T\<^sup>\ * x * x\<^sup>T * p0\<^sup>\" by (metis a2 symmetric_top_closed vector_covector vector_inf_comp vector_mult_closed) also have "... \ (p0\<^sup>T\<^sup>\ * x * y\<^sup>T) * (y * x\<^sup>T * p0\<^sup>\)" by (metis a3 antisym comp_inf.top_right_mult_increasing conv_involutive dedekind_1 inf.sup_left_divisibility inf.sup_monoid.add_commute mult_right_isotone surjective_conv_total mult_assoc) also have "... = (p0\<^sup>T\<^sup>\ * x \ y\<^sup>T) * (y \ x\<^sup>T * p0\<^sup>\)" by (metis a2 a3 vector_covector vector_inf_comp vector_mult_closed) also have "... = (p0\<^sup>T\<^sup>\ * x \ y\<^sup>T) * (p0\<^sup>T\<^sup>\ * x \ y\<^sup>T)\<^sup>T" by (simp add: conv_dist_comp conv_dist_inf conv_star_commute inf_commute) also have "... \ (p0[p0\<^sup>T\<^sup>\ * x\y])\<^sup>\ * (p0[p0\<^sup>T\<^sup>\ * x\y])\<^sup>T\<^sup>\" by (meson conv_isotone dual_order.trans mult_isotone star.circ_increasing sup.cobounded1) finally have "p0\<^sup>T\<^sup>\ * x \ p0 \ (p0[p0\<^sup>T\<^sup>\ * x\y])\<^sup>\ * (p0[p0\<^sup>T\<^sup>\ * x\y])\<^sup>T\<^sup>\" . hence "(p0\<^sup>T\<^sup>\ * x \ p0) \ (-(p0\<^sup>T\<^sup>\ * x) \ p0) \ (p0[p0\<^sup>T\<^sup>\ * x\y])\<^sup>\ * (p0[p0\<^sup>T\<^sup>\ * x\y])\<^sup>T\<^sup>\" using 3 le_supI by blast hence "p0 \ (p0[p0\<^sup>T\<^sup>\ * x\y])\<^sup>\ * (p0[p0\<^sup>T\<^sup>\ * x\y])\<^sup>T\<^sup>\" using 1 by (metis inf_commute maddux_3_11_pp) hence "fc p0 \ (p0[p0\<^sup>T\<^sup>\ * x\y])\<^sup>\ * (p0[p0\<^sup>T\<^sup>\ * x\y])\<^sup>T\<^sup>\" using 2 fc_idempotent fc_isotone by fastforce thus "fc p0 \ fc p" by (simp add: assms(2)) have "((p0\<^sup>T\<^sup>\ * x \ y\<^sup>T) \ (-(p0\<^sup>T\<^sup>\ * x) \ p0))\<^sup>\ = (-(p0\<^sup>T\<^sup>\ * x) \ p0)\<^sup>\ * ((p0\<^sup>T\<^sup>\ * x \ y\<^sup>T) \ 1)" proof (rule star_sup_2) have 4: "transitive (p0\<^sup>T\<^sup>\ * x)" using a2 comp_associative mult_right_isotone rectangle_star_rectangle by auto have "transitive (y\<^sup>T)" by (metis a3 conv_dist_comp inf.eq_refl mult_assoc) thus "transitive (p0\<^sup>T\<^sup>\ * x \ y\<^sup>T)" using 4 transitive_inf_closed by auto have 5: "p0\<^sup>T\<^sup>\ * x * (-(p0\<^sup>T\<^sup>\ * x) \ p0) \ p0\<^sup>T\<^sup>\ * x" by (metis a2 mult_right_isotone top_greatest mult_assoc) have "(-(p0\<^sup>T\<^sup>\ * x) \ p0)\<^sup>T * y \ p0\<^sup>T * y" by (simp add: conv_dist_inf mult_left_isotone) also have "... \ y" using a1 a4 root_successor_loop by auto finally have "y\<^sup>T * (-(p0\<^sup>T\<^sup>\ * x) \ p0) \ y\<^sup>T" using conv_dist_comp conv_isotone by fastforce thus "(p0\<^sup>T\<^sup>\ * x \ y\<^sup>T) * (-(p0\<^sup>T\<^sup>\ * x) \ p0) \ p0\<^sup>T\<^sup>\ * x \ y\<^sup>T" using 5 comp_left_subdist_inf inf_mono order_trans by blast qed hence "p\<^sup>\ = (-(p0\<^sup>T\<^sup>\ * x) \ p0)\<^sup>\ * ((p0\<^sup>T\<^sup>\ * x \ y\<^sup>T) \ 1)" by (simp add: assms(2)) also have "... \ p0\<^sup>\ * ((p0\<^sup>T\<^sup>\ * x \ y\<^sup>T) \ 1)" by (simp add: mult_left_isotone star_isotone) also have "... = p0\<^sup>\ * (p0\<^sup>T\<^sup>\ * x * y\<^sup>T \ 1)" by (simp add: a2 a3 vector_covector vector_mult_closed) also have "... = p0\<^sup>\ * (p0\<^sup>T\<^sup>\ * (x * x\<^sup>T) * p0\<^sup>\ * (p0 \ 1) \ 1)" by (metis a4 coreflexive_symmetric inf.cobounded2 root_var comp_associative conv_dist_comp conv_involutive conv_star_commute) also have "... \ p0\<^sup>\ * (p0\<^sup>T\<^sup>\ * 1 * p0\<^sup>\ * (p0 \ 1) \ 1)" by (metis a2 mult_left_isotone mult_right_isotone semiring.add_left_mono sup_commute) also have "... = p0\<^sup>\ * (p0\<^sup>T\<^sup>\ * (p0 \ 1) \ p0\<^sup>\ * (p0 \ 1) \ 1)" by (simp add: a1 cancel_separate_eq mult_right_dist_sup) also have "... = p0\<^sup>\ * ((p0 \ 1) \ p0\<^sup>\ * (p0 \ 1) \ 1)" by (smt univalent_root_successors a1 conv_dist_comp conv_dist_inf coreflexive_idempotent coreflexive_symmetric inf.cobounded2 injective_codomain loop_root root_transitive_successor_loop symmetric_one_closed) also have "... = p0\<^sup>\ * (p0\<^sup>\ * (p0 \ 1) \ 1)" by (metis inf.sup_left_divisibility inf_commute sup.left_idem sup_commute sup_relative_same_increasing) also have "... \ p0\<^sup>\ * p0\<^sup>\" by (metis inf.cobounded2 inf_commute order.refl order_lesseq_imp star.circ_mult_upper_bound star.circ_reflexive star.circ_transitive_equal sup.boundedI sup_monoid.add_commute) also have "... = p0\<^sup>\" by (simp add: star.circ_transitive_equal) finally show "fc p \ fc p0" by (metis conv_order conv_star_commute mult_isotone) qed qed lemma update_acyclic_6: assumes "disjoint_set_forest p" and "point x" shows "acyclic ((p[p\<^sup>T\<^sup>\*x\root p x]) \ -1)" using assms root_point root_successor_loop update_acyclic_2 by auto theorem path_compression_assign: "VARS p t w [ path_compression_precondition p x y \ p0 = p ] p[p\<^sup>T\<^sup>\ * x] := y [ path_compression_postcondition p x y p0 ]" apply vcg_tc_simp apply (unfold path_compression_precondition_def path_compression_postcondition_def) apply (intro conjI) subgoal using update_univalent mult_assoc by auto subgoal using bijective_regular mapping_regular regular_closed_star regular_conv_closed regular_mult_closed update_mapping mult_assoc by auto subgoal using update_acyclic_6 by blast subgoal by blast subgoal by blast subgoal by blast subgoal by blast subgoal by blast subgoal by blast subgoal by (smt same_root path_compression_exact path_compression_precondition_def update_univalent vector_mult_closed) subgoal using path_compression_exact(1) path_compression_precondition_def by blast subgoal using path_compression_exact(2) path_compression_precondition_def by blast by blast text \ We next look at implementing these updates using a loop. \ lemma path_compression_1a: assumes "point x" and "disjoint_set_forest p" and "x \ root p x" shows "p\<^sup>T\<^sup>+ * x \ - x" by (meson assms bijective_regular mapping_regular regular_closed_star regular_conv_closed regular_mult_closed vector_mult_closed point_in_vector_partition_2 loop_root_2) lemma path_compression_1b: "x \ p\<^sup>T\<^sup>\ * x" using mult_left_isotone star.circ_reflexive by fastforce lemma path_compression_1: "path_compression_precondition p x y \ path_compression_invariant p x y p x" using path_compression_invariant_def path_compression_precondition_def loop_root path_compression_1a path_compression_1b by auto lemma path_compression_2: "path_compression_invariant p x y p0 w \ y \ p[[w]] \ path_compression_invariant (p[w\y]) x y p0 (p[[w]]) \ card { z . regular z \ z \ (p[w\y])\<^sup>T\<^sup>\ * (p[[w]]) } < card { z . regular z \ z \ p\<^sup>T\<^sup>\ * w }" proof - let ?p = "p[w\y]" let ?s = "{ z . regular z \ z \ p\<^sup>T\<^sup>\ * w }" let ?t = "{ z . regular z \ z \ ?p\<^sup>T\<^sup>\ * (p[[w]]) }" assume 1: "path_compression_invariant p x y p0 w \ y \ p[[w]]" have i1: "disjoint_set_forest p" and i2: "point x" and i3: "point y" and i4: "y = root p x" using 1 path_compression_invariant_def path_compression_precondition_def by meson+ have i5: "point w" and i6: "y \ p\<^sup>T\<^sup>\ * w" and i7: "w \ x \ p[[x]] = y \ y \ x \ p\<^sup>T\<^sup>+ * w \ -x" and i8: "p \ 1 = p0 \ 1" and i9: "fc p = fc p0" and i10: "root p w = y" and i11: "w \ y \ p[[w]] \ w" and i12: "p[[w]] = p0[[w]]" and i13: "p0[p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * w)\y] = p" using 1 path_compression_invariant_def by blast+ have i14: "disjoint_set_forest p0" and i15: "y = root p0 x" and i16: "w \ p0\<^sup>T\<^sup>\ * x" using 1 path_compression_invariant_def by auto have 2: "point (p[[w]])" using i1 i5 read_point by blast show "path_compression_invariant ?p x y p0 (p[[w]]) \ card ?t < card ?s" proof (unfold path_compression_invariant_def, intro conjI) have 3: "mapping ?p" by (simp add: i1 i3 i5 bijective_regular update_total update_univalent) have 4: "w \ y" using 1 i1 i4 root_successor_loop by blast hence 5: "w \ y = bot" by (simp add: i3 i5 distinct_points) hence "y * w\<^sup>T \ -1" using pseudo_complement schroeder_4_p by auto hence "y * w\<^sup>T \ p\<^sup>T\<^sup>\ \ -1" using i5 i6 shunt_bijective by auto also have "... \ p\<^sup>T\<^sup>+" by (simp add: star_plus_without_loops) finally have 6: "y \ p\<^sup>T\<^sup>+ * w" using i5 shunt_bijective by auto have 7: "w * w\<^sup>T \ -p\<^sup>T\<^sup>+" proof (rule ccontr) assume "\ w * w\<^sup>T \ -p\<^sup>T\<^sup>+" hence "w * w\<^sup>T \ --p\<^sup>T\<^sup>+" using i5 point_arc arc_in_partition by blast hence "w * w\<^sup>T \ p\<^sup>T\<^sup>+ \ 1" using i1 i5 mapping_regular regular_conv_closed regular_closed_star regular_mult_closed by simp also have "... = ((p\<^sup>T \ 1) * p\<^sup>T\<^sup>\ \ 1) \ ((p\<^sup>T \ -1) * p\<^sup>T\<^sup>\ \ 1)" by (metis comp_inf.mult_right_dist_sup maddux_3_11_pp mult_right_dist_sup regular_one_closed) also have "... = ((p\<^sup>T \ 1) * p\<^sup>T\<^sup>\ \ 1) \ ((p \ -1)\<^sup>+ \ 1)\<^sup>T" by (metis conv_complement conv_dist_inf conv_plus_commute equivalence_one_closed reachable_without_loops) also have "... \ ((p\<^sup>T \ 1) * p\<^sup>T\<^sup>\ \ 1) \ (-1 \ 1)\<^sup>T" by (metis (no_types, hide_lams) i1 sup_right_isotone inf.sup_left_isotone conv_isotone) also have "... = (p\<^sup>T \ 1) * p\<^sup>T\<^sup>\ \ 1" by simp also have "... \ (p\<^sup>T \ 1) * top \ 1" by (metis comp_inf.comp_isotone coreflexive_comp_top_inf equivalence_one_closed inf.cobounded1 inf.cobounded2) also have "... \ p\<^sup>T" by (simp add: coreflexive_comp_top_inf_one) finally have "w * w\<^sup>T \ p\<^sup>T" by simp hence "w \ p[[w]]" using i5 shunt_bijective by blast hence "w = p[[w]]" using 2 by (metis i5 epm_3 mult_semi_associative) thus False using 4 i11 by auto qed hence 8: "w \ p\<^sup>T\<^sup>+ * w = bot" using p_antitone_iff pseudo_complement schroeder_4_p by blast show "y \ ?p\<^sup>T\<^sup>\ * (p[[w]])" proof - have "(w \ y\<^sup>T)\<^sup>T * (-w \ p)\<^sup>T\<^sup>\ * p\<^sup>T * w \ w\<^sup>T * (-w \ p)\<^sup>T\<^sup>\ * p\<^sup>T * w" by (simp add: conv_isotone mult_left_isotone) also have "... \ w\<^sup>T * p\<^sup>T\<^sup>\ * p\<^sup>T * w" by (simp add: conv_isotone mult_left_isotone star_isotone mult_right_isotone) also have "... = w\<^sup>T * p\<^sup>T\<^sup>+ * w" by (simp add: star_plus mult_assoc) also have "... = bot" using 8 by (smt i5 covector_inf_comp_3 mult_assoc conv_dist_comp conv_star_commute covector_bot_closed equivalence_top_closed inf.le_iff_sup mult_left_isotone) finally have "((w \ y\<^sup>T)\<^sup>T \ (-w \ p)\<^sup>T) * (-w \ p)\<^sup>T\<^sup>\ * p\<^sup>T * w \ (-w \ p)\<^sup>T * (-w \ p)\<^sup>T\<^sup>\ * p\<^sup>T * w" by (simp add: bot_unique mult_right_dist_sup) also have "... \ (-w \ p)\<^sup>T\<^sup>\ * p\<^sup>T * w" by (simp add: mult_left_isotone star.left_plus_below_circ) finally have "?p\<^sup>T * (-w \ p)\<^sup>T\<^sup>\ * p\<^sup>T * w \ (-w \ p)\<^sup>T\<^sup>\ * p\<^sup>T * w" by (simp add: conv_dist_sup) hence "?p\<^sup>T\<^sup>\ * p\<^sup>T * w \ (-w \ p)\<^sup>T\<^sup>\ * p\<^sup>T * w" by (metis comp_associative star.circ_loop_fixpoint star_left_induct sup_commute sup_least sup_left_divisibility) hence "w \ ?p\<^sup>T\<^sup>\ * p\<^sup>T * w \ w \ (-w \ p)\<^sup>T\<^sup>\ * p\<^sup>T * w" using inf.sup_right_isotone by blast also have "... \ w \ p\<^sup>T\<^sup>\ * p\<^sup>T * w" using conv_isotone mult_left_isotone star_isotone inf.sup_right_isotone by simp also have "... = bot" using 8 by (simp add: star_plus) finally have 9: "w\<^sup>T * ?p\<^sup>T\<^sup>\ * p\<^sup>T * w = bot" by (smt i5 covector_inf_comp_3 mult_assoc conv_dist_comp covector_bot_closed equivalence_top_closed inf.le_iff_sup mult_left_isotone bot_least inf.absorb1) have "p\<^sup>T * ?p\<^sup>T\<^sup>\ * p\<^sup>T * w = ((w \ p)\<^sup>T \ (-w \ p)\<^sup>T) * ?p\<^sup>T\<^sup>\ * p\<^sup>T * w" by (metis i5 bijective_regular conv_dist_sup inf.sup_monoid.add_commute maddux_3_11_pp) also have "... = (w \ p)\<^sup>T * ?p\<^sup>T\<^sup>\ * p\<^sup>T * w \ (-w \ p)\<^sup>T * ?p\<^sup>T\<^sup>\ * p\<^sup>T * w" by (simp add: mult_right_dist_sup) also have "... \ w\<^sup>T * ?p\<^sup>T\<^sup>\ * p\<^sup>T * w \ (-w \ p)\<^sup>T * ?p\<^sup>T\<^sup>\ * p\<^sup>T * w" using semiring.add_right_mono comp_isotone conv_isotone by auto also have "... = (-w \ p)\<^sup>T * ?p\<^sup>T\<^sup>\ * p\<^sup>T * w" using 9 by simp also have "... \ ?p\<^sup>T\<^sup>+ * p\<^sup>T * w" by (simp add: conv_isotone mult_left_isotone) also have "... \ ?p\<^sup>T\<^sup>\ * p\<^sup>T * w" by (simp add: comp_isotone star.left_plus_below_circ) finally have "p\<^sup>T\<^sup>\ * p\<^sup>T * w \ ?p\<^sup>T\<^sup>\ * p\<^sup>T * w" by (metis comp_associative star.circ_loop_fixpoint star_left_induct sup_commute sup_least sup_left_divisibility) thus "y \ ?p\<^sup>T\<^sup>\ * (p[[w]])" using 6 by (simp add: star_simulation_right_equal mult_assoc) qed have 10: "acyclic (?p \ -1)" using i1 i10 i3 i5 inf_le1 update_acyclic_3 by blast have "?p[[p\<^sup>T\<^sup>+ * w]] \ p\<^sup>T\<^sup>+ * w" proof - have "(w\<^sup>T \ y) * p\<^sup>T\<^sup>+ * w = y \ w\<^sup>T * p\<^sup>T\<^sup>+ * w" by (metis i3 inf_vector_comp vector_inf_comp) hence "?p[[p\<^sup>T\<^sup>+ * w]] = (y \ w\<^sup>T * p\<^sup>T\<^sup>+ * w) \ (-w\<^sup>T \ p\<^sup>T) * p\<^sup>T\<^sup>+ * w" by (simp add: comp_associative conv_complement conv_dist_inf conv_dist_sup mult_right_dist_sup) also have "... \ y \ (-w\<^sup>T \ p\<^sup>T) * p\<^sup>T\<^sup>+ * w" using sup_left_isotone by auto also have "... \ y \ p\<^sup>T * p\<^sup>T\<^sup>+ * w" using mult_left_isotone sup_right_isotone by auto also have "... \ y \ p\<^sup>T\<^sup>+ * w" using semiring.add_left_mono mult_left_isotone mult_right_isotone star.left_plus_below_circ by auto also have "... = p\<^sup>T\<^sup>+ * w" using 6 by (simp add: sup_absorb2) finally show ?thesis by simp qed hence 11: "?p\<^sup>T\<^sup>\ * (p[[w]]) \ p\<^sup>T\<^sup>+ * w" using star_left_induct by (simp add: mult_left_isotone star.circ_mult_increasing) hence 12: "?p\<^sup>T\<^sup>+ * (p[[w]]) \ p\<^sup>T\<^sup>+ * w" using dual_order.trans mult_left_isotone star.left_plus_below_circ by blast have 13: "?p[[x]] = y \ y \ x \ ?p\<^sup>T\<^sup>+ * (p[[w]]) \ -x" proof (cases "w = x") case True hence "?p[[x]] = (w\<^sup>T \ y) * w \ (-w\<^sup>T \ p\<^sup>T) * w" by (simp add: conv_complement conv_dist_inf conv_dist_sup mult_right_dist_sup) also have "... = (w\<^sup>T \ y) * w \ p\<^sup>T * (-w \ w)" by (metis i5 conv_complement covector_inf_comp_3 inf.sup_monoid.add_commute vector_complement_closed) also have "... = (w\<^sup>T \ y) * w" by simp also have "... = y * w" by (simp add: i5 covector_inf_comp_3 inf.sup_monoid.add_commute) also have "... = y" by (metis i3 i5 comp_associative) finally show ?thesis using 4 8 12 True pseudo_complement inf.sup_monoid.add_commute order.trans by blast next case False have "?p[[x]] = (w\<^sup>T \ y) * x \ (-w\<^sup>T \ p\<^sup>T) * x" by (simp add: conv_complement conv_dist_inf conv_dist_sup mult_right_dist_sup) also have "... = y * (w \ x) \ p\<^sup>T * (-w \ x)" by (metis i5 conv_complement covector_inf_comp_3 inf_commute vector_complement_closed) also have "... = p\<^sup>T * (-w \ x)" using i2 i5 False distinct_points by auto also have "... = y" using i2 i5 i7 False distinct_points inf.absorb2 pseudo_complement by auto finally show ?thesis using 12 False i7 dual_order.trans by blast qed thus "p[[w]] \ x \ ?p[[x]] = y \ y \ x \ ?p\<^sup>T\<^sup>+ * (p[[w]]) \ -x" by simp have 14: "?p\<^sup>T\<^sup>\ * x = x \ y" proof (rule antisym) have "?p\<^sup>T * (x \ y) = y \ ?p\<^sup>T * y" using 13 by (simp add: mult_left_dist_sup) also have "... = y \ (w\<^sup>T \ y) * y \ (-w\<^sup>T \ p\<^sup>T) * y" by (simp add: conv_complement conv_dist_inf conv_dist_sup mult_right_dist_sup sup_assoc) also have "... \ y \ (w\<^sup>T \ y) * y \ p\<^sup>T * y" using mult_left_isotone sup_right_isotone by auto also have "... = y \ (w\<^sup>T \ y) * y" using i1 i10 root_successor_loop sup_commute by auto also have "... \ y \ y * y" using mult_left_isotone sup_right_isotone by auto also have "... = y" by (metis i3 comp_associative sup.idem) also have "... \ x \ y" by simp finally show "?p\<^sup>T\<^sup>\ * x \ x \ y" by (simp add: star_left_induct) next show "x \ y \ ?p\<^sup>T\<^sup>\ * x" using 13 by (metis mult_left_isotone star.circ_increasing star.circ_loop_fixpoint sup.boundedI sup_ge2) qed have 15: "y = root ?p x" proof - have "(p \ 1) * y = (p \ 1) * (p \ 1) * p\<^sup>T\<^sup>\ * x" by (simp add: i4 comp_associative root_var) also have "... = (p \ 1) * p\<^sup>T\<^sup>\ * x" using coreflexive_idempotent by auto finally have 16: "(p \ 1) * y = y" by (simp add: i4 root_var) have 17: "(p \ 1) * x \ y" by (metis (no_types, lifting) i4 comp_right_one mult_left_isotone mult_right_isotone star.circ_reflexive root_var) have "root ?p x = (?p \ 1) * (x \ y)" using 14 by (metis mult_assoc root_var) also have "... = (w \ y\<^sup>T \ 1) * (x \ y) \ (-w \ p \ 1) * (x \ y)" by (simp add: inf_sup_distrib2 semiring.distrib_right) also have "... = (w \ 1 \ y\<^sup>T) * (x \ y) \ (-w \ p \ 1) * (x \ y)" by (simp add: inf.left_commute inf.sup_monoid.add_commute) also have "... = (w \ 1) * (y \ (x \ y)) \ (-w \ p \ 1) * (x \ y)" by (simp add: i3 covector_inf_comp_3) also have "... = (w \ 1) * y \ (-w \ p \ 1) * (x \ y)" by (simp add: inf.absorb1) also have "... = (w \ 1 * y) \ (-w \ (p \ 1) * (x \ y))" by (simp add: i5 inf_assoc vector_complement_closed vector_inf_comp) also have "... = (w \ y) \ (-w \ ((p \ 1) * x \ y))" using 16 by (simp add: mult_left_dist_sup) also have "... = (w \ y) \ (-w \ y)" using 17 by (simp add: sup.absorb2) also have "... = y" using 5 inf.sup_monoid.add_commute le_iff_inf pseudo_complement sup_monoid.add_0_left by fastforce finally show ?thesis by simp qed show "path_compression_precondition ?p x y" using 3 10 15 i2 i3 path_compression_precondition_def by blast show "vector (p[[w]])" using 2 by simp show "injective (p[[w]])" using 2 by simp show "surjective (p[[w]])" using 2 by simp have "w \ p \ 1 \ w \ w\<^sup>T \ p" by (metis inf.boundedE inf.boundedI inf.cobounded1 inf.cobounded2 one_inf_conv) also have "... = w * w\<^sup>T \ p" by (simp add: i5 vector_covector) also have "... \ -p\<^sup>T\<^sup>+ \ p" using 7 by (simp add: inf.coboundedI2 inf.sup_monoid.add_commute) finally have "w \ p \ 1 = bot" by (metis (no_types, hide_lams) conv_dist_inf coreflexive_symmetric inf.absorb1 inf.boundedE inf.cobounded2 pseudo_complement star.circ_mult_increasing) also have "w \ y\<^sup>T \ 1 = bot" using 5 antisymmetric_bot_closed asymmetric_bot_closed comp_inf.schroeder_2 inf.absorb1 one_inf_conv by fastforce finally have "w \ p \ 1 = w \ y\<^sup>T \ 1" by simp thus 18: "?p \ 1 = p0 \ 1" by (metis i5 i8 bijective_regular inf.sup_monoid.add_commute inf_sup_distrib2 maddux_3_11_pp) show 19: "fc ?p = fc p0" proof - have "p[[w]] = p\<^sup>T * (w \ p\<^sup>\ * y)" by (metis i3 i5 i6 bijective_reverse conv_star_commute inf.absorb1) also have "... = p\<^sup>T * (w \ p\<^sup>\) * y" by (simp add: i5 vector_inf_comp mult_assoc) also have "... = p\<^sup>T * ((w \ 1) \ (w \ p) * (-w \ p)\<^sup>\) * y" by (simp add: i5 omit_redundant_points) also have "... = p\<^sup>T * (w \ 1) * y \ p\<^sup>T * (w \ p) * (-w \ p)\<^sup>\ * y" by (simp add: comp_associative mult_left_dist_sup mult_right_dist_sup) also have "... \ p\<^sup>T * y \ p\<^sup>T * (w \ p) * (-w \ p)\<^sup>\ * y" by (metis semiring.add_right_mono comp_isotone eq_iff inf.cobounded1 inf.sup_monoid.add_commute mult_1_right) also have "... = y \ p\<^sup>T * (w \ p) * (-w \ p)\<^sup>\ * y" using i1 i4 root_successor_loop by auto also have "... \ y \ p\<^sup>T * p * (-w \ p)\<^sup>\ * y" using comp_isotone sup_right_isotone by auto also have "... \ y \ (-w \ p)\<^sup>\ * y" by (metis i1 comp_associative eq_refl shunt_mapping sup_right_isotone) also have "... = (-w \ p)\<^sup>\ * y" by (metis star.circ_loop_fixpoint sup.left_idem sup_commute) finally have 20: "p[[w]] \ (-w \ p)\<^sup>\ * y" by simp have "p\<^sup>T * (-w \ p)\<^sup>\ * y = p\<^sup>T * y \ p\<^sup>T * (-w \ p) * (-w \ p)\<^sup>\ * y" by (metis comp_associative mult_left_dist_sup star.circ_loop_fixpoint sup_commute) also have "... = y \ p\<^sup>T * (-w \ p) * (-w \ p)\<^sup>\ * y" using i1 i4 root_successor_loop by auto also have "... \ y \ p\<^sup>T * p * (-w \ p)\<^sup>\ * y" using comp_isotone sup_right_isotone by auto also have "... \ y \ (-w \ p)\<^sup>\ * y" by (metis i1 comp_associative eq_refl shunt_mapping sup_right_isotone) also have "... = (-w \ p)\<^sup>\ * y" by (metis star.circ_loop_fixpoint sup.left_idem sup_commute) finally have 21: "p\<^sup>T\<^sup>\ * p\<^sup>T * w \ (-w \ p)\<^sup>\ * y" using 20 by (simp add: comp_associative star_left_induct) have "w\<^sup>T \ p\<^sup>T = p\<^sup>T * (w\<^sup>T \ 1)" by (metis i5 comp_right_one covector_inf_comp_3 inf.sup_monoid.add_commute one_inf_conv) also have "... \ p[[w]]" by (metis comp_right_subdist_inf inf.boundedE inf.sup_monoid.add_commute one_inf_conv) also have "... \ p\<^sup>T\<^sup>\ * p\<^sup>T * w" by (simp add: mult_left_isotone star.circ_mult_increasing_2) also have "... \ (-w \ p)\<^sup>\ * y" using 21 by simp finally have "w \ p \ y\<^sup>T * (-w \ p)\<^sup>T\<^sup>\" by (metis conv_dist_comp conv_dist_inf conv_involutive conv_isotone conv_star_commute) hence "w \ p \ (w \ y\<^sup>T) * (-w \ p)\<^sup>T\<^sup>\" by (simp add: i5 vector_inf_comp) also have "... \ (w \ y\<^sup>T) * ?p\<^sup>T\<^sup>\" by (simp add: conv_isotone mult_right_isotone star_isotone) also have "... \ ?p * ?p\<^sup>T\<^sup>\" by (simp add: mult_left_isotone) also have "... \ fc ?p" by (simp add: mult_left_isotone star.circ_increasing) finally have 22: "w \ p \ fc ?p" by simp have "-w \ p \ ?p" by simp also have "... \ fc ?p" by (simp add: fc_increasing) finally have "(w \ -w) \ p \ fc ?p" using 22 by (simp add: comp_inf.semiring.distrib_left inf.sup_monoid.add_commute) hence "p \ fc ?p" by (metis i5 bijective_regular inf.sup_monoid.add_commute inf_sup_distrib1 maddux_3_11_pp) hence 23: "fc p \ fc ?p" using 3 fc_idempotent fc_isotone by fastforce have "?p \ (w \ y\<^sup>T) \ p" using sup_right_isotone by auto also have "... = w * y\<^sup>T \ p" by (simp add: i3 i5 vector_covector) also have "... \ p\<^sup>\ \ p" by (smt i5 i6 conv_dist_comp conv_involutive conv_isotone conv_star_commute le_supI shunt_bijective star.circ_increasing sup_absorb1) also have "... \ fc p" using fc_increasing star.circ_back_loop_prefixpoint by auto finally have "fc ?p \ fc p" using i1 fc_idempotent fc_isotone by fastforce thus ?thesis using 23 i9 by auto qed show "?p[[p[[w]]]] = p0[[p[[w]]]]" proof - have "?p[[p[[w]]]] = p[[p[[w]]]]" using 2 4 i5 i11 by (simp add: put_get_different) also have "... = p[[p0[[w]]]]" by (simp add: i12) also have "... = (p0[p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * w)\y])[[p0[[w]]]]" using i13 by auto also have "... = p0[[p0[[w]]]]" proof - have "p0[[w]] \ -(p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * w))" by (meson inf.coboundedI2 mult_left_isotone p_antitone p_antitone_iff star.circ_increasing) thus ?thesis by (meson i2 i5 put_get_different_vector vector_complement_closed vector_inf_closed vector_mult_closed) qed also have "... = p0[[p[[w]]]]" by (simp add: i12) finally show ?thesis . qed have 24: "root ?p (p[[w]]) = root p0 (p[[w]])" using 3 18 19 i14 same_root by blast also have "... = root p0 (p0[[w]])" by (simp add: i12) also have 25: "... = root p0 w" by (metis i5 i14 conv_involutive forest_components_increasing mult_left_isotone shunt_bijective injective_mult_closed read_surjective same_component_same_root) finally show 26: "root ?p (p[[w]]) = y" by (metis i1 i10 i14 i8 i9 same_root) show "p[[w]] \ y \ ?p[[p[[w]]]] \ p[[w]] \ ?p\<^sup>T\<^sup>+ * (p[[w]]) \ -(p[[w]])" proof assume 27: "p[[w]] \ y" show "?p[[p[[w]]]] \ p[[w]] \ ?p\<^sup>T\<^sup>+ * (p[[w]]) \ -(p[[w]])" proof show "?p[[p[[w]]]] \ p[[w]]" using 2 26 27 loop_root by auto show "?p\<^sup>T\<^sup>+ * (p[[w]]) \ -(p[[w]])" using 2 3 10 26 27 by (simp add: path_compression_1a) qed qed show "univalent p0" "total p0" "acyclic (p0 \ -1)" by (simp_all add: i14) show "y = root p0 x" by (simp add: i15) show "p[[w]] \ p0\<^sup>T\<^sup>\ * x" by (metis i12 i16 mult_isotone star.circ_increasing star.circ_transitive_equal mult_assoc) let ?q = "p0[p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * (p[[w]]))\y]" show "?q = ?p" proof - have 28: "w \ p0\<^sup>T\<^sup>+ * w = p0\<^sup>T\<^sup>\ * w" using comp_associative star.circ_loop_fixpoint sup_commute by auto hence 29: "p0\<^sup>T\<^sup>+ * w = p0\<^sup>T\<^sup>\ * w \ -w" using 4 24 25 26 by (metis i12 i14 i5 inf.orderE maddux_3_13 path_compression_1a) hence "p0\<^sup>T\<^sup>\ * (p[[w]]) \ -w" by (metis i12 inf_le2 star_plus mult.assoc) hence "w \ -(p0\<^sup>T\<^sup>\ * (p[[w]]))" by (simp add: p_antitone_iff) hence "w \ p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * (p[[w]]))" by (simp add: i16) hence 30: "?q \ w = ?p \ w" by (metis update_inf update_inf_same) have 31: "?q \ p0\<^sup>T\<^sup>+ * w = ?p \ p0\<^sup>T\<^sup>+ * w" proof - have "?q \ p0\<^sup>T\<^sup>+ * w = p0 \ p0\<^sup>T\<^sup>+ * w" by (metis i12 comp_associative inf.cobounded2 p_antitone_iff star.circ_plus_same update_inf_different) also have "... = p \ p0\<^sup>T\<^sup>+ * w" using 29 by (metis i13 inf.cobounded2 inf.sup_monoid.add_assoc p_antitone_iff update_inf_different) also have "... = ?p \ p0\<^sup>T\<^sup>+ * w" using 29 by (simp add: update_inf_different) finally show ?thesis . qed have 32: "?q \ p0\<^sup>T\<^sup>\ * w = ?p \ p0\<^sup>T\<^sup>\ * w" using 28 30 31 by (metis inf_sup_distrib1) have 33: "?q \ (p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * w)) = ?p \ (p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * w))" proof - have "p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * w) \ p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * (p[[w]]))" using 29 by (metis i12 inf.sup_right_isotone mult.semigroup_axioms p_antitone_inf star_plus semigroup.assoc) hence "?q \ (p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * w)) = y\<^sup>T \ p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * w)" by (metis inf_assoc update_inf) also have "... = p \ (p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * w))" by (metis i13 inf_assoc update_inf_same) also have "... = ?p \ (p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * w))" by (simp add: inf.coboundedI2 p_antitone path_compression_1b inf_assoc update_inf_different) finally show ?thesis . qed have "p0\<^sup>T\<^sup>\ * w \ (p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * w)) = p0\<^sup>T\<^sup>\ * x" proof - have 34: "regular (p0\<^sup>T\<^sup>\ * w)" using i14 i5 bijective_regular mapping_regular regular_closed_star regular_conv_closed regular_mult_closed by auto have "p0\<^sup>T\<^sup>\ * w \ p0\<^sup>T\<^sup>\ * x" by (metis i16 comp_associative mult_right_isotone star.circ_transitive_equal) hence "p0\<^sup>T\<^sup>\ * w \ (p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * w)) = p0\<^sup>T\<^sup>\ * x \ (p0\<^sup>T\<^sup>\ * w \ -(p0\<^sup>T\<^sup>\ * w))" by (simp add: comp_inf.semiring.distrib_left inf.absorb2) also have "... = p0\<^sup>T\<^sup>\ * x" using 34 by (metis inf_sup_distrib1 maddux_3_11_pp) finally show ?thesis . qed hence 35: "?q \ p0\<^sup>T\<^sup>\ * x = ?p \ p0\<^sup>T\<^sup>\ * x" using 32 33 by (metis inf_sup_distrib1) have 36: "regular (p0\<^sup>T\<^sup>\ * x)" using i14 i2 bijective_regular mapping_regular regular_closed_star regular_conv_closed regular_mult_closed by auto have "-(p0\<^sup>T\<^sup>\ * x) \ -w" by (simp add: i16 p_antitone) hence "?q \ -(p0\<^sup>T\<^sup>\ * x) = ?p \ -(p0\<^sup>T\<^sup>\ * x)" by (metis i13 p_antitone_inf update_inf_different) thus ?thesis using 35 36 by (metis maddux_3_11_pp) qed show "card ?t < card ?s" proof - have "?p\<^sup>T * p\<^sup>T\<^sup>\ * w = (w\<^sup>T \ y) * p\<^sup>T\<^sup>\ * w \ (-w\<^sup>T \ p\<^sup>T) * p\<^sup>T\<^sup>\ * w" by (simp add: conv_complement conv_dist_inf conv_dist_sup mult_right_dist_sup) also have "... \ (w\<^sup>T \ y) * p\<^sup>T\<^sup>\ * w \ p\<^sup>T * p\<^sup>T\<^sup>\ * w" using mult_left_isotone sup_right_isotone by auto also have "... \ (w\<^sup>T \ y) * p\<^sup>T\<^sup>\ * w \ p\<^sup>T\<^sup>\ * w" using mult_left_isotone star.left_plus_below_circ sup_right_isotone by blast also have "... \ y * p\<^sup>T\<^sup>\ * w \ p\<^sup>T\<^sup>\ * w" using semiring.add_right_mono mult_left_isotone by auto also have "... \ y * top \ p\<^sup>T\<^sup>\ * w" by (simp add: comp_associative le_supI1 mult_right_isotone) also have "... = p\<^sup>T\<^sup>\ * w" by (simp add: i3 i6 sup_absorb2) finally have "?p\<^sup>T\<^sup>\ * p\<^sup>T * w \ p\<^sup>T\<^sup>\ * w" using 11 by (metis dual_order.trans star.circ_loop_fixpoint sup_commute sup_ge2 mult_assoc) hence 37: "?t \ ?s" using order_lesseq_imp mult_assoc by auto have 38: "w \ ?s" by (simp add: i5 bijective_regular path_compression_1b) have 39: "\ w \ ?t" proof assume "w \ ?t" hence 40: "w \ (?p\<^sup>T \ -1)\<^sup>\ * (p[[w]])" using reachable_without_loops by auto hence "p[[w]] \ (?p \ -1)\<^sup>\ * w" using 2 by (smt i5 bijective_reverse conv_star_commute reachable_without_loops) also have "... \ p\<^sup>\ * w" proof - have "p\<^sup>T\<^sup>\ * y = y" using i1 i4 root_transitive_successor_loop by auto hence "y\<^sup>T * p\<^sup>\ * w = y\<^sup>T * w" by (metis conv_dist_comp conv_involutive conv_star_commute) also have "... = bot" using 5 by (metis i5 inf.idem inf.sup_monoid.add_commute mult_left_zero schroeder_1 vector_inf_comp) finally have 41: "y\<^sup>T * p\<^sup>\ * w = bot" by simp have "(?p \ -1) * p\<^sup>\ * w = (w \ y\<^sup>T \ -1) * p\<^sup>\ * w \ (-w \ p \ -1) * p\<^sup>\ * w" by (simp add: comp_inf.mult_right_dist_sup mult_right_dist_sup) also have "... \ (w \ y\<^sup>T \ -1) * p\<^sup>\ * w \ p * p\<^sup>\ * w" by (meson inf_le1 inf_le2 mult_left_isotone order_trans sup_right_isotone) also have "... \ (w \ y\<^sup>T \ -1) * p\<^sup>\ * w \ p\<^sup>\ * w" using mult_left_isotone star.left_plus_below_circ sup_right_isotone by blast also have "... \ y\<^sup>T * p\<^sup>\ * w \ p\<^sup>\ * w" by (meson inf_le1 inf_le2 mult_left_isotone order_trans sup_left_isotone) also have "... = p\<^sup>\ * w" using 41 by simp finally show ?thesis by (metis comp_associative le_supI star.circ_loop_fixpoint sup_ge2 star_left_induct) qed finally have "w \ p\<^sup>T\<^sup>\ * p\<^sup>T * w" using 11 40 reachable_without_loops star_plus by auto thus False using 4 i1 i10 i5 loop_root_2 star.circ_plus_same by auto qed show "card ?t < card ?s" apply (rule psubset_card_mono) subgoal using finite_regular by simp subgoal using 37 38 39 by auto done qed qed qed lemma path_compression_3a: assumes "path_compression_invariant p x (p[[w]]) p0 w" shows "p0[p0\<^sup>T\<^sup>\ * x\p[[w]]] = p" proof - let ?y = "p[[w]]" let ?p = "p0[p0\<^sup>T\<^sup>\ * x\?y]" have i1: "disjoint_set_forest p" and i2: "point x" and i3: "point ?y" and i4: "?y = root p x" using assms path_compression_invariant_def path_compression_precondition_def by meson+ have i5: "point w" and i6: "?y \ p\<^sup>T\<^sup>\ * w" and i7: "w \ x \ p[[x]] = ?y \ ?y \ x \ p\<^sup>T\<^sup>+ * w \ -x" and i8: "p \ 1 = p0 \ 1" and i9: "fc p = fc p0" and i10: "root p w = ?y" and i11: "w \ ?y \ p[[w]] \ w" and i12: "p[[w]] = p0[[w]]" and i13: "p0[p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * w)\?y] = p" and i14: "disjoint_set_forest p0" and i15: "?y = root p0 x" and i16: "w \ p0\<^sup>T\<^sup>\ * x" using assms path_compression_invariant_def by blast+ have 1: "?p \ ?y = p \ ?y" by (metis i1 i15 i3 i4 get_put inf_le1 root_successor_loop update_inf update_inf_same) have 2: "?p \ w = p \ w" by (metis i5 i12 i16 get_put update_inf update_inf_same) have "?y = root p0 w" by (metis i1 i10 i14 i8 i9 same_root) hence "p0\<^sup>T\<^sup>\ * w = w \ ?y" by (metis i12 i14 root_transitive_successor_loop star.circ_loop_fixpoint star_plus sup_monoid.add_commute mult_assoc) hence 3: "?p \ p0\<^sup>T\<^sup>\ * w = p \ p0\<^sup>T\<^sup>\ * w" using 1 2 by (simp add: inf_sup_distrib1) have "p0\<^sup>T\<^sup>\ * w \ p0\<^sup>T\<^sup>\ * x" by (metis i16 comp_associative mult_right_isotone star.circ_transitive_equal) hence 4: "?p \ (p0\<^sup>T\<^sup>\ * x \ p0\<^sup>T\<^sup>\ * w) = p \ (p0\<^sup>T\<^sup>\ * x \ p0\<^sup>T\<^sup>\ * w)" using 3 by (simp add: inf.absorb2) have 5: "?p \ (p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * w)) = p \ (p0\<^sup>T\<^sup>\ * x \ -(p0\<^sup>T\<^sup>\ * w))" by (metis i13 inf_le1 update_inf update_inf_same) have "regular (p0\<^sup>T\<^sup>\ * w)" using i14 i5 bijective_regular mapping_regular regular_closed_star regular_conv_closed regular_mult_closed by auto hence 6: "?p \ p0\<^sup>T\<^sup>\ * x = p \ p0\<^sup>T\<^sup>\ * x" using 4 5 by (smt inf_sup_distrib1 maddux_3_11_pp) have 7: "?p \ -(p0\<^sup>T\<^sup>\ * x) = p \ -(p0\<^sup>T\<^sup>\ * x)" by (smt i13 inf.sup_monoid.add_commute inf_import_p inf_sup_absorb le_iff_inf p_dist_inf update_inf_different inf.idem p_antitone_inf) have "regular (p0\<^sup>T\<^sup>\ * x)" using i14 i2 bijective_regular mapping_regular regular_closed_star regular_conv_closed regular_mult_closed by auto thus "?p = p" using 6 7 by (smt inf_sup_distrib1 maddux_3_11_pp) qed lemma path_compression_3: "path_compression_invariant p x (p[[w]]) p0 w \ path_compression_postcondition p x (p[[w]]) p0" using path_compression_invariant_def path_compression_postcondition_def path_compression_precondition_def path_compression_3a by blast theorem path_compression: "VARS p t w [ path_compression_precondition p x y \ p0 = p ] w := x; WHILE y \ p[[w]] INV { path_compression_invariant p x y p0 w } VAR { card { z . regular z \ z \ p\<^sup>T\<^sup>\ * w } } DO t := w; w := p[[w]]; p[t] := y OD [ path_compression_postcondition p x y p0 ]" apply vcg_tc_simp apply (fact path_compression_1) apply (fact path_compression_2) using path_compression_3 by auto lemma path_compression_exists: "path_compression_precondition p x y \ \p' . path_compression_postcondition p' x y p" using tc_extract_function path_compression by blast definition "path_compression p x y \ (SOME p' . path_compression_postcondition p' x y p)" lemma path_compression_function: assumes "path_compression_precondition p x y" and "p' = path_compression p x y" shows "path_compression_postcondition p' x y p" by (metis assms path_compression_def path_compression_exists someI) subsection \Find-Set with Path Compression\ text \ We sequentially combine find-set and path compression. We consider implementations which use the previously derived functions and implementations which unfold their definitions. \ theorem find_set_path_compression: "VARS p y [ find_set_precondition p x \ p0 = p ] y := find_set p x; p := path_compression p x y [ path_compression_postcondition p x y p0 ]" apply vcg_tc_simp using find_set_function find_set_postcondition_def find_set_precondition_def path_compression_function path_compression_precondition_def by fastforce theorem find_set_path_compression_1: "VARS p t w y [ find_set_precondition p x \ p0 = p ] y := find_set p x; w := x; WHILE y \ p[[w]] INV { path_compression_invariant p x y p0 w } VAR { card { z . regular z \ z \ p\<^sup>T\<^sup>\ * w } } DO t := w; w := p[[w]]; p[t] := y OD [ path_compression_postcondition p x y p0 ]" apply vcg_tc_simp using find_set_function find_set_postcondition_def find_set_precondition_def path_compression_1 path_compression_precondition_def apply fastforce apply (fact path_compression_2) by (fact path_compression_3) theorem find_set_path_compression_2: "VARS p y [ find_set_precondition p x \ p0 = p ] y := x; WHILE y \ p[[y]] INV { find_set_invariant p x y \ p0 = p } VAR { card { z . regular z \ z \ p\<^sup>T\<^sup>\ * y } } DO y := p[[y]] OD; p := path_compression p x y [ path_compression_postcondition p x y p0 ]" apply vcg_tc_simp apply (fact find_set_1) apply (fact find_set_2) by (smt find_set_3 find_set_invariant_def find_set_postcondition_def find_set_precondition_def path_compression_function path_compression_precondition_def) theorem find_set_path_compression_3: "VARS p t w y [ find_set_precondition p x \ p0 = p ] y := x; WHILE y \ p[[y]] INV { find_set_invariant p x y \ p0 = p } VAR { card { z . regular z \ z \ p\<^sup>T\<^sup>\ * y } } DO y := p[[y]] OD; w := x; WHILE y \ p[[w]] INV { path_compression_invariant p x y p0 w } VAR { card { z . regular z \ z \ p\<^sup>T\<^sup>\ * w } } DO t := w; w := p[[w]]; p[t] := y OD [ path_compression_postcondition p x y p0 ]" apply vcg_tc_simp apply (simp add: find_set_1) apply (fact find_set_2) using find_set_3 find_set_invariant_def find_set_postcondition_def find_set_precondition_def path_compression_1 path_compression_precondition_def apply blast apply (fact path_compression_2) by (fact path_compression_3) text \ Find-set with path compression returns two results: the representative of the tree and the modified disjoint-set forest. \ lemma find_set_path_compression_exists: "find_set_precondition p x \ \p' y . path_compression_postcondition p' x y p" using tc_extract_function find_set_path_compression by blast definition "find_set_path_compression p x \ (SOME (p',y) . path_compression_postcondition p' x y p)" lemma find_set_path_compression_function: assumes "find_set_precondition p x" and "(p',y) = find_set_path_compression p x" shows "path_compression_postcondition p' x y p" proof - let ?P = "\(p',y) . path_compression_postcondition p' x y p" have "?P (SOME z . ?P z)" apply (unfold some_eq_ex) using assms(1) find_set_path_compression_exists by simp thus ?thesis using assms(2) find_set_path_compression_def by auto qed text \ We prove that \find_set_path_compression\ returns the same representative as \find_set\. \ lemma find_set_path_compression_find_set: assumes "find_set_precondition p x" shows "find_set p x = snd (find_set_path_compression p x)" proof - let ?r = "find_set p x" let ?p = "fst (find_set_path_compression p x)" let ?y = "snd (find_set_path_compression p x)" have 1: "find_set_postcondition p x ?r" by (simp add: assms find_set_function) have "path_compression_postcondition ?p x ?y p" using assms find_set_path_compression_function prod.collapse by blast thus "?r = ?y" using 1 by (smt assms same_root find_set_precondition_def find_set_postcondition_def path_compression_precondition_def path_compression_postcondition_def) qed text \ A weaker postcondition suffices to prove that the two forests have the same semantics; that is, they describe the same disjoint sets and have the same roots. \ lemma find_set_path_compression_path_compression_semantics: assumes "find_set_precondition p x" shows "fc (path_compression p x (find_set p x)) = fc (fst (find_set_path_compression p x))" and "path_compression p x (find_set p x) \ 1 = fst (find_set_path_compression p x) \ 1" proof - let ?r = "find_set p x" let ?q = "path_compression p x ?r" let ?p = "fst (find_set_path_compression p x)" let ?y = "snd (find_set_path_compression p x)" have 1: "path_compression_postcondition (path_compression p x ?r) x ?r p" using assms find_set_function find_set_postcondition_def find_set_precondition_def path_compression_function path_compression_precondition_def by auto have 2: "path_compression_postcondition ?p x ?y p" using assms find_set_path_compression_function prod.collapse by blast show "fc ?q = fc ?p" using 1 2 by (simp add: path_compression_postcondition_def) show "?q \ 1 = ?p \ 1" using 1 2 by (simp add: path_compression_postcondition_def) qed text \ With the current, stronger postcondition of path compression describing the precise effect of how links change, we can prove that the two forests are actually equal. \ lemma find_set_path_compression_find_set_pathcompression: assumes "find_set_precondition p x" shows "path_compression p x (find_set p x) = fst (find_set_path_compression p x)" proof - let ?r = "find_set p x" let ?q = "path_compression p x ?r" let ?p = "fst (find_set_path_compression p x)" let ?y = "snd (find_set_path_compression p x)" have 1: "path_compression_postcondition (path_compression p x ?r) x ?r p" using assms find_set_function find_set_postcondition_def find_set_precondition_def path_compression_function path_compression_precondition_def by auto have 2: "path_compression_postcondition ?p x ?y p" using assms find_set_path_compression_function prod.collapse by blast have "?r = ?y" by (simp add: assms find_set_path_compression_find_set) thus "?q = ?p" using 1 2 by (simp add: path_compression_postcondition_def) qed subsection \Union-Sets\ text \ We only consider a naive union-sets operation (without ranks). The semantics is the equivalence closure obtained after adding the link between the two given nodes, which requires those two elements to be in the same set. The implementation uses temporary variable \t\ to store the two results returned by find-set with path compression. The disjoint-set forest, which keeps being updated, is threaded through the sequence of operations. \ definition "union_sets_precondition p x y \ disjoint_set_forest p \ point x \ point y" definition "union_sets_postcondition p x y p0 \ union_sets_precondition p x y \ fc p = wcc (p0 \ x * y\<^sup>T)" lemma union_sets_1: assumes "union_sets_precondition p0 x y" and "path_compression_postcondition p1 x r p0" and "path_compression_postcondition p2 y s p1" shows "union_sets_postcondition (p2[r\s]) x y p0" proof (unfold union_sets_postcondition_def union_sets_precondition_def, intro conjI) let ?p = "p2[r\s]" have 1: "disjoint_set_forest p1 \ point r \ r = root p1 x \ p1 \ 1 = p0 \ 1 \ fc p1 = fc p0" using assms(2) path_compression_precondition_def path_compression_postcondition_def by auto have 2: "disjoint_set_forest p2 \ point s \ s = root p2 y \ p2 \ 1 = p1 \ 1 \ fc p2 = fc p1" using assms(3) path_compression_precondition_def path_compression_postcondition_def by auto hence 3: "fc p2 = fc p0" using 1 by simp show 4: "univalent ?p" using 1 2 update_univalent by blast show "total ?p" using 1 2 bijective_regular update_total by blast show "acyclic (?p \ -1)" proof (cases "r = s") case True thus ?thesis using 2 update_acyclic_5 by fastforce next case False hence "bot = r \ s" using 1 2 distinct_points by blast also have "... = r \ p2\<^sup>T\<^sup>\ * s" using 2 by (smt root_transitive_successor_loop) finally have "s \ p2\<^sup>\ * r = bot" using schroeder_1 conv_star_commute inf.sup_monoid.add_commute by fastforce thus ?thesis using 1 2 update_acyclic_4 by blast qed show "vector x" using assms(1) by (simp add: union_sets_precondition_def) show "injective x" using assms(1) by (simp add: union_sets_precondition_def) show "surjective x" using assms(1) by (simp add: union_sets_precondition_def) show "vector y" using assms(1) by (simp add: union_sets_precondition_def) show "injective y" using assms(1) by (simp add: union_sets_precondition_def) show "surjective y" using assms(1) by (simp add: union_sets_precondition_def) show "fc ?p = wcc (p0 \ x * y\<^sup>T)" proof (rule antisym) have "r = p1[[r]]" using 1 by (metis root_successor_loop) hence "r * r\<^sup>T \ p1\<^sup>T" using 1 eq_refl shunt_bijective by blast hence "r * r\<^sup>T \ p1" using 1 conv_order coreflexive_symmetric by fastforce hence "r * r\<^sup>T \ p1 \ 1" using 1 inf.boundedI by blast also have "... = p2 \ 1" using 2 by simp finally have "r * r\<^sup>T \ p2" by simp hence "r \ p2 * r" using 1 shunt_bijective by blast hence 5: "p2[[r]] \ r" using 2 shunt_mapping by blast have "r \ p2 \ r * (top \ r\<^sup>T * p2)" using 1 by (metis dedekind_1) also have "... = r * r\<^sup>T * p2" by (simp add: mult_assoc) also have "... \ r * r\<^sup>T" using 5 by (metis comp_associative conv_dist_comp conv_involutive conv_order mult_right_isotone) also have "... \ 1" using 1 by blast finally have 6: "r \ p2 \ 1" by simp have "p0 \ wcc p0" by (simp add: star.circ_sub_dist_1) also have "... = wcc p2" using 3 by (simp add: star_decompose_1) also have 7: "... \ wcc ?p" proof - have "wcc p2 = wcc ((-r \ p2) \ (r \ p2))" using 1 by (metis bijective_regular inf.sup_monoid.add_commute maddux_3_11_pp) also have "... \ wcc ((-r \ p2) \ 1)" using 6 wcc_isotone sup_right_isotone by simp also have "... = wcc (-r \ p2)" using wcc_with_loops by simp also have "... \ wcc ?p" using wcc_isotone sup_ge2 by blast finally show ?thesis by simp qed finally have 8: "p0 \ wcc ?p" by force have "r \ p1\<^sup>T\<^sup>\ * x" using 1 by (metis inf_le1) hence 9: "r * x\<^sup>T \ p1\<^sup>T\<^sup>\" using assms(1) shunt_bijective union_sets_precondition_def by blast hence "x * r\<^sup>T \ p1\<^sup>\" using conv_dist_comp conv_order conv_star_commute by force also have "... \ wcc p1" by (simp add: star.circ_sub_dist) also have "... = wcc p2" using 1 2 by (simp add: fc_wcc) also have "... \ wcc ?p" using 7 by simp finally have 10: "x * r\<^sup>T \ wcc ?p" by simp have 11: "r * s\<^sup>T \ wcc ?p" using 1 2 star.circ_sub_dist_1 sup_assoc vector_covector by auto have "s \ p2\<^sup>T\<^sup>\ * y" using 2 by (metis inf_le1) hence 12: "s * y\<^sup>T \ p2\<^sup>T\<^sup>\" using assms(1) shunt_bijective union_sets_precondition_def by blast also have "... \ wcc p2" using star_isotone sup_ge2 by blast also have "... \ wcc ?p" using 7 by simp finally have 13: "s * y\<^sup>T \ wcc ?p" by simp have "x \ x * r\<^sup>T * r \ y \ y * s\<^sup>T * s" using 1 2 shunt_bijective by blast hence "x * y\<^sup>T \ x * r\<^sup>T * r * (y * s\<^sup>T * s)\<^sup>T" using comp_isotone conv_isotone by blast also have "... = x * r\<^sup>T * r * s\<^sup>T * s * y\<^sup>T" by (simp add: comp_associative conv_dist_comp) also have "... \ wcc ?p * (r * s\<^sup>T) * (s * y\<^sup>T)" using 10 by (metis mult_left_isotone mult_assoc) also have "... \ wcc ?p * wcc ?p * (s * y\<^sup>T)" using 11 by (metis mult_left_isotone mult_right_isotone) also have "... \ wcc ?p * wcc ?p * wcc ?p" using 13 by (metis mult_right_isotone) also have "... = wcc ?p" by (simp add: star.circ_transitive_equal) finally have "p0 \ x * y\<^sup>T \ wcc ?p" using 8 by simp hence "wcc (p0 \ x * y\<^sup>T) \ wcc ?p" using wcc_below_wcc by simp thus "wcc (p0 \ x * y\<^sup>T) \ fc ?p" using 4 fc_wcc by simp have "-r \ p2 \ wcc p2" by (simp add: inf.coboundedI2 star.circ_sub_dist_1) also have "... = wcc p0" using 3 by (simp add: star_decompose_1) also have "... \ wcc (p0 \ x * y\<^sup>T)" by (simp add: wcc_isotone) finally have 14: "-r \ p2 \ wcc (p0 \ x * y\<^sup>T)" by simp have "r * x\<^sup>T \ wcc p1" using 9 inf.order_trans star.circ_sub_dist sup_commute by fastforce also have "... = wcc p0" using 1 by (simp add: star_decompose_1) also have "... \ wcc (p0 \ x * y\<^sup>T)" by (simp add: wcc_isotone) finally have 15: "r * x\<^sup>T \ wcc (p0 \ x * y\<^sup>T)" by simp have 16: "x * y\<^sup>T \ wcc (p0 \ x * y\<^sup>T)" using le_supE star.circ_sub_dist_1 by blast have "y * s\<^sup>T \ p2\<^sup>\" using 12 conv_dist_comp conv_order conv_star_commute by fastforce also have "... \ wcc p2" using star.circ_sub_dist sup_commute by fastforce also have "... = wcc p0" using 3 by (simp add: star_decompose_1) also have "... \ wcc (p0 \ x * y\<^sup>T)" by (simp add: wcc_isotone) finally have 17: "y * s\<^sup>T \ wcc (p0 \ x * y\<^sup>T)" by simp have "r \ r * x\<^sup>T * x \ s \ s * y\<^sup>T * y" using assms(1) shunt_bijective union_sets_precondition_def by blast hence "r * s\<^sup>T \ r * x\<^sup>T * x * (s * y\<^sup>T * y)\<^sup>T" using comp_isotone conv_isotone by blast also have "... = r * x\<^sup>T * x * y\<^sup>T * y * s\<^sup>T" by (simp add: comp_associative conv_dist_comp) also have "... \ wcc (p0 \ x * y\<^sup>T) * (x * y\<^sup>T) * (y * s\<^sup>T)" using 15 by (metis mult_left_isotone mult_assoc) also have "... \ wcc (p0 \ x * y\<^sup>T) * wcc (p0 \ x * y\<^sup>T) * (y * s\<^sup>T)" using 16 by (metis mult_left_isotone mult_right_isotone) also have "... \ wcc (p0 \ x * y\<^sup>T) * wcc (p0 \ x * y\<^sup>T) * wcc (p0 \ x * y\<^sup>T)" using 17 by (metis mult_right_isotone) also have "... = wcc (p0 \ x * y\<^sup>T)" by (simp add: star.circ_transitive_equal) finally have "?p \ wcc (p0 \ x * y\<^sup>T)" using 1 2 14 vector_covector by auto hence "wcc ?p \ wcc (p0 \ x * y\<^sup>T)" using wcc_below_wcc by blast thus "fc ?p \ wcc (p0 \ x * y\<^sup>T)" using 4 fc_wcc by simp qed qed theorem union_sets: "VARS p r s t [ union_sets_precondition p x y \ p0 = p ] t := find_set_path_compression p x; p := fst t; r := snd t; t := find_set_path_compression p y; p := fst t; s := snd t; p[r] := s [ union_sets_postcondition p x y p0 ]" proof vcg_tc_simp let ?t1 = "find_set_path_compression p0 x" let ?p1 = "fst ?t1" let ?r = "snd ?t1" let ?t2 = "find_set_path_compression ?p1 y" let ?p2 = "fst ?t2" let ?s = "snd ?t2" let ?p = "?p2[?r\?s]" assume 1: "union_sets_precondition p0 x y" hence 2: "path_compression_postcondition ?p1 x ?r p0" by (simp add: find_set_precondition_def union_sets_precondition_def find_set_path_compression_function) hence "path_compression_postcondition ?p2 y ?s ?p1" using 1 by (meson find_set_precondition_def union_sets_precondition_def find_set_path_compression_function path_compression_postcondition_def path_compression_precondition_def prod.collapse) thus "union_sets_postcondition (?p2[?r\?s]) x y p0" using 1 2 by (simp add: union_sets_1) qed lemma union_sets_exists: "union_sets_precondition p x y \ \p' . union_sets_postcondition p' x y p" using tc_extract_function union_sets by blast definition "union_sets p x y \ (SOME p' . union_sets_postcondition p' x y p)" lemma union_sets_function: assumes "union_sets_precondition p x y" and "p' = union_sets p x y" shows "union_sets_postcondition p' x y p" by (metis assms union_sets_def union_sets_exists someI) theorem union_sets_2: "VARS p r s t [ union_sets_precondition p x y \ p0 = p ] r := find_set p x; p := path_compression p x r; s := find_set p y; p := path_compression p y s; p[r] := s [ union_sets_postcondition p x y p0 ]" proof vcg_tc_simp let ?r = "find_set p0 x" let ?p1 = "path_compression p0 x ?r" let ?s = "find_set ?p1 y" let ?p2 = "path_compression ?p1 y ?s" assume 1: "union_sets_precondition p0 x y" hence 2: "path_compression_postcondition ?p1 x ?r p0" using find_set_function find_set_postcondition_def find_set_precondition_def path_compression_function path_compression_precondition_def union_sets_precondition_def by auto hence "path_compression_postcondition ?p2 y ?s ?p1" using 1 find_set_function find_set_postcondition_def find_set_precondition_def path_compression_function path_compression_precondition_def union_sets_precondition_def path_compression_postcondition_def by meson thus "union_sets_postcondition (?p2[?r\?s]) x y p0" using 1 2 by (simp add: union_sets_1) qed end end diff --git a/thys/Relational_Disjoint_Set_Forests/ROOT b/thys/Relational_Disjoint_Set_Forests/ROOT --- a/thys/Relational_Disjoint_Set_Forests/ROOT +++ b/thys/Relational_Disjoint_Set_Forests/ROOT @@ -1,16 +1,16 @@ chapter AFP session Relational_Disjoint_Set_Forests (AFP) = Stone_Kleene_Relation_Algebras + options [timeout = 600] sessions - Aggregation_Algebras + "HOL-Hoare" theories Disjoint_Set_Forests document_files "root.tex" "root.bib" diff --git a/thys/Relational_Minimum_Spanning_Trees/Kruskal.thy b/thys/Relational_Minimum_Spanning_Trees/Kruskal.thy --- a/thys/Relational_Minimum_Spanning_Trees/Kruskal.thy +++ b/thys/Relational_Minimum_Spanning_Trees/Kruskal.thy @@ -1,595 +1,595 @@ (* Title: Kruskal's Minimum Spanning Tree Algorithm Author: Walter Guttmann Maintainer: Walter Guttmann *) section \Kruskal's Minimum Spanning Tree Algorithm\ text \ In this theory we prove total correctness of Kruskal's minimum spanning tree algorithm. The proof uses the following steps \cite{Guttmann2018c}. We first establish that the algorithm terminates and constructs a spanning tree. This is a constructive proof of the existence of a spanning tree; any spanning tree algorithm could be used for this. We then conclude that a minimum spanning tree exists. This is necessary to establish the invariant for the actual correctness proof, which shows that Kruskal's algorithm produces a minimum spanning tree. \ theory Kruskal -imports Aggregation_Algebras.Hoare_Logic Aggregation_Algebras.Aggregation_Algebras +imports "HOL-Hoare.Hoare_Logic" Aggregation_Algebras.Aggregation_Algebras begin context m_kleene_algebra begin definition "spanning_forest f g \ forest f \ f \ --g \ components g \ forest_components f \ regular f" definition "minimum_spanning_forest f g \ spanning_forest f g \ (\u . spanning_forest u g \ sum (f \ g) \ sum (u \ g))" definition "kruskal_spanning_invariant f g h \ symmetric g \ h = h\<^sup>T \ g \ --h = h \ spanning_forest f (-h \ g)" definition "kruskal_invariant f g h \ kruskal_spanning_invariant f g h \ (\w . minimum_spanning_forest w g \ f \ w \ w\<^sup>T)" text \ We first show two verification conditions which are used in both correctness proofs. \ lemma kruskal_vc_1: assumes "symmetric g" shows "kruskal_spanning_invariant bot g g" proof (unfold kruskal_spanning_invariant_def, intro conjI) show "symmetric g" using assms by simp next show "g = g\<^sup>T" using assms by simp next show "g \ --g = g" using inf.sup_monoid.add_commute selection_closed_id by simp next show "spanning_forest bot (-g \ g)" using star.circ_transitive_equal spanning_forest_def by simp qed lemma kruskal_vc_2: assumes "kruskal_spanning_invariant f g h" and "h \ bot" shows "(minarc h \ -forest_components f \ kruskal_spanning_invariant ((f \ -(top * minarc h * f\<^sup>T\<^sup>\)) \ (f \ top * minarc h * f\<^sup>T\<^sup>\)\<^sup>T \ minarc h) g (h \ -minarc h \ -minarc h\<^sup>T) \ card { x . regular x \ x \ --h \ x \ -minarc h \ x \ -minarc h\<^sup>T } < card { x . regular x \ x \ --h }) \ (\ minarc h \ -forest_components f \ kruskal_spanning_invariant f g (h \ -minarc h \ -minarc h\<^sup>T) \ card { x . regular x \ x \ --h \ x \ -minarc h \ x \ -minarc h\<^sup>T } < card { x . regular x \ x \ --h })" proof - let ?e = "minarc h" let ?f = "(f \ -(top * ?e * f\<^sup>T\<^sup>\)) \ (f \ top * ?e * f\<^sup>T\<^sup>\)\<^sup>T \ ?e" let ?h = "h \ -?e \ -?e\<^sup>T" let ?F = "forest_components f" let ?n1 = "card { x . regular x \ x \ --h }" let ?n2 = "card { x . regular x \ x \ --h \ x \ -?e \ x \ -?e\<^sup>T }" have 1: "regular f \ regular ?e" by (metis assms(1) kruskal_spanning_invariant_def spanning_forest_def minarc_regular) hence 2: "regular ?f \ regular ?F \ regular (?e\<^sup>T)" using regular_closed_star regular_conv_closed regular_mult_closed by simp have 3: "\ ?e \ -?e" using assms(2) inf.orderE minarc_bot_iff by fastforce have 4: "?n2 < ?n1" apply (rule psubset_card_mono) using finite_regular apply simp using 1 3 kruskal_spanning_invariant_def minarc_below by auto show "(?e \ -?F \ kruskal_spanning_invariant ?f g ?h \ ?n2 < ?n1) \ (\ ?e \ -?F \ kruskal_spanning_invariant f g ?h \ ?n2 < ?n1)" proof (rule conjI) have 5: "injective ?f" apply (rule kruskal_injective_inv) using assms(1) kruskal_spanning_invariant_def spanning_forest_def apply simp apply (simp add: covector_mult_closed) apply (simp add: comp_associative comp_isotone star.right_plus_below_circ) apply (meson mult_left_isotone order_lesseq_imp star_outer_increasing top.extremum) using assms(1,2) kruskal_spanning_invariant_def kruskal_injective_inv_2 minarc_arc spanning_forest_def apply simp using assms(2) arc_injective minarc_arc apply blast using assms(1,2) kruskal_spanning_invariant_def kruskal_injective_inv_3 minarc_arc spanning_forest_def by simp show "?e \ -?F \ kruskal_spanning_invariant ?f g ?h \ ?n2 < ?n1" proof assume 6: "?e \ -?F" have 7: "equivalence ?F" using assms(1) kruskal_spanning_invariant_def forest_components_equivalence spanning_forest_def by simp have "?e\<^sup>T * top * ?e\<^sup>T = ?e\<^sup>T" using assms(2) by (simp add: arc_top_arc minarc_arc) hence "?e\<^sup>T * top * ?e\<^sup>T \ -?F" using 6 7 conv_complement conv_isotone by fastforce hence 8: "?e * ?F * ?e = bot" using le_bot triple_schroeder_p by simp show "kruskal_spanning_invariant ?f g ?h \ ?n2 < ?n1" proof (unfold kruskal_spanning_invariant_def, intro conjI) show "symmetric g" using assms(1) kruskal_spanning_invariant_def by simp next show "?h = ?h\<^sup>T" using assms(1) by (simp add: conv_complement conv_dist_inf inf_commute inf_left_commute kruskal_spanning_invariant_def) next show "g \ --?h = ?h" using 1 2 by (metis (hide_lams) assms(1) kruskal_spanning_invariant_def inf_assoc pp_dist_inf) next show "spanning_forest ?f (-?h \ g)" proof (unfold spanning_forest_def, intro conjI) show "injective ?f" using 5 by simp next show "acyclic ?f" apply (rule kruskal_acyclic_inv) using assms(1) kruskal_spanning_invariant_def spanning_forest_def apply simp apply (simp add: covector_mult_closed) using 8 assms(1) kruskal_spanning_invariant_def spanning_forest_def kruskal_acyclic_inv_1 apply simp using 8 apply (metis comp_associative mult_left_sub_dist_sup_left star.circ_loop_fixpoint sup_commute le_bot) using 6 by (simp add: p_antitone_iff) next show "?f \ --(-?h \ g)" apply (rule kruskal_subgraph_inv) using assms(1) kruskal_spanning_invariant_def spanning_forest_def apply simp using assms(1) apply (metis kruskal_spanning_invariant_def minarc_below order.trans pp_isotone_inf) using assms(1) kruskal_spanning_invariant_def apply simp using assms(1) kruskal_spanning_invariant_def by simp next show "components (-?h \ g) \ forest_components ?f" apply (rule kruskal_spanning_inv) using 5 apply simp using 1 regular_closed_star regular_conv_closed regular_mult_closed apply simp using 1 apply simp using assms(1) kruskal_spanning_invariant_def spanning_forest_def by simp next show "regular ?f" using 2 by simp qed next show "?n2 < ?n1" using 4 by simp qed qed next show "\ ?e \ -?F \ kruskal_spanning_invariant f g ?h \ ?n2 < ?n1" proof assume "\ ?e \ -?F" hence 9: "?e \ ?F" using 2 assms(2) arc_in_partition minarc_arc by fastforce show "kruskal_spanning_invariant f g ?h \ ?n2 < ?n1" proof (unfold kruskal_spanning_invariant_def, intro conjI) show "symmetric g" using assms(1) kruskal_spanning_invariant_def by simp next show "?h = ?h\<^sup>T" using assms(1) by (simp add: conv_complement conv_dist_inf inf_commute inf_left_commute kruskal_spanning_invariant_def) next show "g \ --?h = ?h" using 1 2 by (metis (hide_lams) assms(1) kruskal_spanning_invariant_def inf_assoc pp_dist_inf) next show "spanning_forest f (-?h \ g)" proof (unfold spanning_forest_def, intro conjI) show "injective f" using assms(1) kruskal_spanning_invariant_def spanning_forest_def by simp next show "acyclic f" using assms(1) kruskal_spanning_invariant_def spanning_forest_def by simp next have "f \ --(-h \ g)" using assms(1) kruskal_spanning_invariant_def spanning_forest_def by simp also have "... \ --(-?h \ g)" using comp_inf.mult_right_isotone inf.sup_monoid.add_commute inf_left_commute p_antitone_inf pp_isotone by presburger finally show "f \ --(-?h \ g)" by simp next show "components (-?h \ g) \ ?F" apply (rule kruskal_spanning_inv_1) using 9 apply simp using 1 apply simp using assms(1) kruskal_spanning_invariant_def spanning_forest_def apply simp using assms(1) kruskal_spanning_invariant_def forest_components_equivalence spanning_forest_def by simp next show "regular f" using 1 by simp qed next show "?n2 < ?n1" using 4 by simp qed qed qed qed text \ The following result shows that Kruskal's algorithm terminates and constructs a spanning tree. We cannot yet show that this is a minimum spanning tree. \ theorem kruskal_spanning: "VARS e f h [ symmetric g ] f := bot; h := g; WHILE h \ bot INV { kruskal_spanning_invariant f g h } VAR { card { x . regular x \ x \ --h } } DO e := minarc h; IF e \ -forest_components f THEN f := (f \ -(top * e * f\<^sup>T\<^sup>\)) \ (f \ top * e * f\<^sup>T\<^sup>\)\<^sup>T \ e ELSE SKIP FI; h := h \ -e \ -e\<^sup>T OD [ spanning_forest f g ]" apply vcg_tc_simp using kruskal_vc_1 apply simp using kruskal_vc_2 apply simp using kruskal_spanning_invariant_def by auto text \ Because we have shown total correctness, we conclude that a spanning tree exists. \ lemma kruskal_exists_spanning: "symmetric g \ \f . spanning_forest f g" using tc_extract_function kruskal_spanning by blast text \ This implies that a minimum spanning tree exists, which is used in the subsequent correctness proof. \ lemma kruskal_exists_minimal_spanning: assumes "symmetric g" shows "\f . minimum_spanning_forest f g" proof - let ?s = "{ f . spanning_forest f g }" have "\m\?s . \z\?s . sum (m \ g) \ sum (z \ g)" apply (rule finite_set_minimal) using finite_regular spanning_forest_def apply simp using assms kruskal_exists_spanning apply simp using sum_linear by simp thus ?thesis using minimum_spanning_forest_def by simp qed text \ Kruskal's minimum spanning tree algorithm terminates and is correct. This is the same algorithm that is used in the previous correctness proof, with the same precondition and variant, but with a different invariant and postcondition. \ theorem kruskal: "VARS e f h [ symmetric g ] f := bot; h := g; WHILE h \ bot INV { kruskal_invariant f g h } VAR { card { x . regular x \ x \ --h } } DO e := minarc h; IF e \ -forest_components f THEN f := (f \ -(top * e * f\<^sup>T\<^sup>\)) \ (f \ top * e * f\<^sup>T\<^sup>\)\<^sup>T \ e ELSE SKIP FI; h := h \ -e \ -e\<^sup>T OD [ minimum_spanning_forest f g ]" proof vcg_tc_simp assume "symmetric g" thus "kruskal_invariant bot g g" using kruskal_vc_1 kruskal_exists_minimal_spanning kruskal_invariant_def by simp next fix f h let ?e = "minarc h" let ?f = "(f \ -(top * ?e * f\<^sup>T\<^sup>\)) \ (f \ top * ?e * f\<^sup>T\<^sup>\)\<^sup>T \ ?e" let ?h = "h \ -?e \ -?e\<^sup>T" let ?F = "forest_components f" let ?n1 = "card { x . regular x \ x \ --h }" let ?n2 = "card { x . regular x \ x \ --h \ x \ -?e \ x \ -?e\<^sup>T }" assume 1: "kruskal_invariant f g h \ h \ bot" from 1 obtain w where 2: "minimum_spanning_forest w g \ f \ w \ w\<^sup>T" using kruskal_invariant_def by auto hence 3: "regular f \ regular w \ regular ?e" using 1 by (metis kruskal_invariant_def kruskal_spanning_invariant_def minimum_spanning_forest_def spanning_forest_def minarc_regular) show "(?e \ -?F \ kruskal_invariant ?f g ?h \ ?n2 < ?n1) \ (\ ?e \ -?F \ kruskal_invariant f g ?h \ ?n2 < ?n1)" proof (rule conjI) show "?e \ -?F \ kruskal_invariant ?f g ?h \ ?n2 < ?n1" proof assume 4: "?e \ -?F" have 5: "equivalence ?F" using 1 kruskal_invariant_def kruskal_spanning_invariant_def forest_components_equivalence spanning_forest_def by simp have "?e\<^sup>T * top * ?e\<^sup>T = ?e\<^sup>T" using 1 by (simp add: arc_top_arc minarc_arc) hence "?e\<^sup>T * top * ?e\<^sup>T \ -?F" using 4 5 conv_complement conv_isotone by fastforce hence 6: "?e * ?F * ?e = bot" using le_bot triple_schroeder_p by simp show "kruskal_invariant ?f g ?h \ ?n2 < ?n1" proof (unfold kruskal_invariant_def, intro conjI) show "kruskal_spanning_invariant ?f g ?h" using 1 4 kruskal_vc_2 kruskal_invariant_def by simp next show "\w . minimum_spanning_forest w g \ ?f \ w \ w\<^sup>T" proof let ?p = "w \ top * ?e * w\<^sup>T\<^sup>\" let ?v = "(w \ -(top * ?e * w\<^sup>T\<^sup>\)) \ ?p\<^sup>T" have 7: "regular ?p" using 3 regular_closed_star regular_conv_closed regular_mult_closed by simp have 8: "injective ?v" apply (rule kruskal_exchange_injective_inv_1) using 2 minimum_spanning_forest_def spanning_forest_def apply simp apply (simp add: covector_mult_closed) apply (simp add: comp_associative comp_isotone star.right_plus_below_circ) using 1 2 kruskal_injective_inv_3 minarc_arc minimum_spanning_forest_def spanning_forest_def by simp have 9: "components g \ forest_components ?v" apply (rule kruskal_exchange_spanning_inv_1) using 8 apply simp using 7 apply simp using 2 minimum_spanning_forest_def spanning_forest_def by simp have 10: "spanning_forest ?v g" proof (unfold spanning_forest_def, intro conjI) show "injective ?v" using 8 by simp next show "acyclic ?v" apply (rule kruskal_exchange_acyclic_inv_1) using 2 minimum_spanning_forest_def spanning_forest_def apply simp by (simp add: covector_mult_closed) next show "?v \ --g" apply (rule sup_least) using 2 inf.coboundedI1 minimum_spanning_forest_def spanning_forest_def apply simp using 1 2 by (metis kruskal_invariant_def kruskal_spanning_invariant_def conv_complement conv_dist_inf order.trans inf.absorb2 inf.cobounded1 minimum_spanning_forest_def spanning_forest_def) next show "components g \ forest_components ?v" using 9 by simp next show "regular ?v" using 3 regular_closed_star regular_conv_closed regular_mult_closed by simp qed have 11: "sum (?v \ g) = sum (w \ g)" proof - have "sum (?v \ g) = sum (w \ -(top * ?e * w\<^sup>T\<^sup>\) \ g) + sum (?p\<^sup>T \ g)" using 2 by (metis conv_complement conv_top epm_8 inf_import_p inf_top_right regular_closed_top vector_top_closed minimum_spanning_forest_def spanning_forest_def sum_disjoint) also have "... = sum (w \ -(top * ?e * w\<^sup>T\<^sup>\) \ g) + sum (?p \ g)" using 1 kruskal_invariant_def kruskal_spanning_invariant_def sum_symmetric by simp also have "... = sum (((w \ -(top * ?e * w\<^sup>T\<^sup>\)) \ ?p) \ g)" using inf_commute inf_left_commute sum_disjoint by simp also have "... = sum (w \ g)" using 3 7 maddux_3_11_pp by simp finally show ?thesis by simp qed have 12: "?v \ ?v\<^sup>T = w \ w\<^sup>T" proof - have "?v \ ?v\<^sup>T = (w \ -?p) \ ?p\<^sup>T \ (w\<^sup>T \ -?p\<^sup>T) \ ?p" using conv_complement conv_dist_inf conv_dist_sup inf_import_p sup_assoc by simp also have "... = w \ w\<^sup>T" using 3 7 conv_complement conv_dist_inf inf_import_p maddux_3_11_pp sup_monoid.add_assoc sup_monoid.add_commute by simp finally show ?thesis by simp qed have 13: "?v * ?e\<^sup>T = bot" apply (rule kruskal_reroot_edge) using 1 apply (simp add: minarc_arc) using 2 minimum_spanning_forest_def spanning_forest_def by simp have "?v \ ?e \ ?v \ top * ?e" using inf.sup_right_isotone top_left_mult_increasing by simp also have "... \ ?v * (top * ?e)\<^sup>T" using covector_restrict_comp_conv covector_mult_closed vector_top_closed by simp finally have 14: "?v \ ?e = bot" using 13 by (metis conv_dist_comp mult_assoc le_bot mult_left_zero) let ?d = "?v \ top * ?e\<^sup>T * ?v\<^sup>T\<^sup>\ \ ?F * ?e\<^sup>T * top \ top * ?e * -?F" let ?w = "(?v \ -?d) \ ?e" have 15: "regular ?d" using 3 regular_closed_star regular_conv_closed regular_mult_closed by simp have 16: "?F \ -?d" apply (rule kruskal_edge_between_components_1) using 5 apply simp using 1 conv_dist_comp minarc_arc mult_assoc by simp have 17: "f \ f\<^sup>T \ (?v \ -?d \ -?d\<^sup>T) \ (?v\<^sup>T \ -?d \ -?d\<^sup>T)" apply (rule kruskal_edge_between_components_2) using 16 apply simp using 1 kruskal_invariant_def kruskal_spanning_invariant_def spanning_forest_def apply simp using 2 12 by (metis conv_dist_sup conv_involutive conv_isotone le_supI sup_commute) show "minimum_spanning_forest ?w g \ ?f \ ?w \ ?w\<^sup>T" proof (intro conjI) have 18: "?e\<^sup>T \ ?v\<^sup>\" apply (rule kruskal_edge_arc_1[where g=g and h=h]) using minarc_below apply simp using 1 apply (metis kruskal_invariant_def kruskal_spanning_invariant_def inf_le1) using 1 kruskal_invariant_def kruskal_spanning_invariant_def apply simp using 9 apply simp using 13 by simp have 19: "arc ?d" apply (rule kruskal_edge_arc) using 5 apply simp using 10 spanning_forest_def apply blast using 1 apply (simp add: minarc_arc) using 3 apply (metis conv_complement pp_dist_star regular_mult_closed) using 2 8 12 apply (simp add: kruskal_forest_components_inf) using 10 spanning_forest_def apply simp using 13 apply simp using 6 apply simp using 18 by simp show "minimum_spanning_forest ?w g" proof (unfold minimum_spanning_forest_def, intro conjI) have "(?v \ -?d) * ?e\<^sup>T \ ?v * ?e\<^sup>T" using inf_le1 mult_left_isotone by simp hence "(?v \ -?d) * ?e\<^sup>T = bot" using 13 le_bot by simp hence 20: "?e * (?v \ -?d)\<^sup>T = bot" using conv_dist_comp conv_involutive conv_bot by force have 21: "injective ?w" apply (rule injective_sup) using 8 apply (simp add: injective_inf_closed) using 20 apply simp using 1 arc_injective minarc_arc by blast show "spanning_forest ?w g" proof (unfold spanning_forest_def, intro conjI) show "injective ?w" using 21 by simp next show "acyclic ?w" apply (rule kruskal_exchange_acyclic_inv_2) using 10 spanning_forest_def apply blast using 8 apply simp using inf.coboundedI1 apply simp using 19 apply simp using 1 apply (simp add: minarc_arc) using inf.cobounded2 inf.coboundedI1 apply simp using 13 by simp next have "?w \ ?v \ ?e" using inf_le1 sup_left_isotone by simp also have "... \ --g \ ?e" using 10 sup_left_isotone spanning_forest_def by blast also have "... \ --g \ --h" by (simp add: le_supI2 minarc_below) also have "... = --g" using 1 by (metis kruskal_invariant_def kruskal_spanning_invariant_def pp_isotone_inf sup.orderE) finally show "?w \ --g" by simp next have 22: "?d \ (?v \ -?d)\<^sup>T\<^sup>\ * ?e\<^sup>T * top" apply (rule kruskal_exchange_spanning_inv_2) using 8 apply simp using 13 apply (metis semiring.mult_not_zero star_absorb star_simulation_right_equal) using 17 apply simp by (simp add: inf.coboundedI1) have "components g \ forest_components ?v" using 10 spanning_forest_def by auto also have "... \ forest_components ?w" apply (rule kruskal_exchange_forest_components_inv) using 21 apply simp using 15 apply simp using 1 apply (simp add: arc_top_arc minarc_arc) apply (simp add: inf.coboundedI1) using 13 apply simp using 8 apply simp apply (simp add: le_infI1) using 22 by simp finally show "components g \ forest_components ?w" by simp next show "regular ?w" using 3 7 regular_conv_closed by simp qed next have 23: "?e \ g \ bot" using 1 by (metis kruskal_invariant_def kruskal_spanning_invariant_def comp_inf.semiring.mult_zero_right inf.sup_monoid.add_assoc inf.sup_monoid.add_commute minarc_bot_iff minarc_meet_bot) have "g \ -h \ (g \ -h)\<^sup>\" using star.circ_increasing by simp also have "... \ (--(g \ -h))\<^sup>\" using pp_increasing star_isotone by blast also have "... \ ?F" using 1 kruskal_invariant_def kruskal_spanning_invariant_def inf.sup_monoid.add_commute spanning_forest_def by simp finally have 24: "g \ -h \ ?F" by simp have "?d \ --g" using 10 inf.coboundedI1 spanning_forest_def by blast hence "?d \ --g \ -?F" using 16 inf.boundedI p_antitone_iff by simp also have "... = --(g \ -?F)" by simp also have "... \ --h" using 24 p_shunting_swap pp_isotone by fastforce finally have 25: "?d \ --h" by simp have "?d = bot \ top = bot" using 19 by (metis mult_left_zero mult_right_zero) hence "?d \ bot" using 1 le_bot by auto hence 26: "?d \ h \ bot" using 25 by (metis inf.absorb_iff2 inf_commute pseudo_complement) have "sum (?e \ g) = sum (?e \ --h \ g)" by (simp add: inf.absorb1 minarc_below) also have "... = sum (?e \ h)" using 1 by (metis kruskal_invariant_def kruskal_spanning_invariant_def inf.left_commute inf.sup_monoid.add_commute) also have "... \ sum (?d \ h)" using 19 26 minarc_min by simp also have "... = sum (?d \ (--h \ g))" using 1 kruskal_invariant_def kruskal_spanning_invariant_def inf_commute by simp also have "... = sum (?d \ g)" using 25 by (simp add: inf.absorb2 inf_assoc inf_commute) finally have 27: "sum (?e \ g) \ sum (?d \ g)" by simp have "?v \ ?e \ -?d = bot" using 14 by simp hence "sum (?w \ g) = sum (?v \ -?d \ g) + sum (?e \ g)" using sum_disjoint inf_commute inf_assoc by simp also have "... \ sum (?v \ -?d \ g) + sum (?d \ g)" using 23 27 sum_plus_right_isotone by simp also have "... = sum (((?v \ -?d) \ ?d) \ g)" using sum_disjoint inf_le2 pseudo_complement by simp also have "... = sum ((?v \ ?d) \ (-?d \ ?d) \ g)" by (simp add: sup_inf_distrib2) also have "... = sum ((?v \ ?d) \ g)" using 15 by (metis inf_top_right stone) also have "... = sum (?v \ g)" by (simp add: inf.sup_monoid.add_assoc) finally have "sum (?w \ g) \ sum (?v \ g)" by simp thus "\u . spanning_forest u g \ sum (?w \ g) \ sum (u \ g)" using 2 11 minimum_spanning_forest_def by auto qed next have "?f \ f \ f\<^sup>T \ ?e" using conv_dist_inf inf_le1 sup_left_isotone sup_mono by presburger also have "... \ (?v \ -?d \ -?d\<^sup>T) \ (?v\<^sup>T \ -?d \ -?d\<^sup>T) \ ?e" using 17 sup_left_isotone by simp also have "... \ (?v \ -?d) \ (?v\<^sup>T \ -?d \ -?d\<^sup>T) \ ?e" using inf.cobounded1 sup_inf_distrib2 by presburger also have "... = ?w \ (?v\<^sup>T \ -?d \ -?d\<^sup>T)" by (simp add: sup_assoc sup_commute) also have "... \ ?w \ (?v\<^sup>T \ -?d\<^sup>T)" using inf.sup_right_isotone inf_assoc sup_right_isotone by simp also have "... \ ?w \ ?w\<^sup>T" using conv_complement conv_dist_inf conv_dist_sup sup_right_isotone by simp finally show "?f \ ?w \ ?w\<^sup>T" by simp qed qed next show "?n2 < ?n1" using 1 kruskal_vc_2 kruskal_invariant_def by auto qed qed next show "\ ?e \ -?F \ kruskal_invariant f g ?h \ ?n2 < ?n1" using 1 kruskal_vc_2 kruskal_invariant_def by auto qed next fix f assume 28: "kruskal_invariant f g bot" hence 29: "spanning_forest f g" using kruskal_invariant_def kruskal_spanning_invariant_def by auto from 28 obtain w where 30: "minimum_spanning_forest w g \ f \ w \ w\<^sup>T" using kruskal_invariant_def by auto hence "w = w \ --g" by (simp add: inf.absorb1 minimum_spanning_forest_def spanning_forest_def) also have "... \ w \ components g" by (metis inf.sup_right_isotone star.circ_increasing) also have "... \ w \ f\<^sup>T\<^sup>\ * f\<^sup>\" using 29 spanning_forest_def inf.sup_right_isotone by simp also have "... \ f \ f\<^sup>T" apply (rule cancel_separate_6[where z=w and y="w\<^sup>T"]) using 30 minimum_spanning_forest_def spanning_forest_def apply simp using 30 apply (metis conv_dist_inf conv_dist_sup conv_involutive inf.cobounded2 inf.orderE) using 30 apply (simp add: sup_commute) using 30 minimum_spanning_forest_def spanning_forest_def apply simp using 30 by (metis acyclic_star_below_complement comp_inf.mult_right_isotone inf_p le_bot minimum_spanning_forest_def spanning_forest_def) finally have 31: "w \ f \ f\<^sup>T" by simp have "sum (f \ g) = sum ((w \ w\<^sup>T) \ (f \ g))" using 30 by (metis inf_absorb2 inf.assoc) also have "... = sum (w \ (f \ g)) + sum (w\<^sup>T \ (f \ g))" using 30 inf.commute acyclic_asymmetric sum_disjoint minimum_spanning_forest_def spanning_forest_def by simp also have "... = sum (w \ (f \ g)) + sum (w \ (f\<^sup>T \ g\<^sup>T))" by (metis conv_dist_inf conv_involutive sum_conv) also have "... = sum (f \ (w \ g)) + sum (f\<^sup>T \ (w \ g))" using 28 inf.commute inf.assoc kruskal_invariant_def kruskal_spanning_invariant_def by simp also have "... = sum ((f \ f\<^sup>T) \ (w \ g))" using 29 acyclic_asymmetric inf.sup_monoid.add_commute sum_disjoint spanning_forest_def by simp also have "... = sum (w \ g)" using 31 by (metis inf_absorb2 inf.assoc) finally show "minimum_spanning_forest f g" using 29 30 minimum_spanning_forest_def by simp qed end end diff --git a/thys/Relational_Minimum_Spanning_Trees/Prim.thy b/thys/Relational_Minimum_Spanning_Trees/Prim.thy --- a/thys/Relational_Minimum_Spanning_Trees/Prim.thy +++ b/thys/Relational_Minimum_Spanning_Trees/Prim.thy @@ -1,477 +1,477 @@ (* Title: Prim's Minimum Spanning Tree Algorithm Author: Walter Guttmann Maintainer: Walter Guttmann *) section \Prim's Minimum Spanning Tree Algorithm\ text \ In this theory we prove total correctness of Prim's minimum spanning tree algorithm. The proof has the same overall structure as the total-correctness proof of Kruskal's algorithm \cite{Guttmann2018c}. The partial-correctness proof of Prim's algorithm is discussed in \cite{Guttmann2016c,Guttmann2018b}. \ theory Prim -imports Aggregation_Algebras.Hoare_Logic Aggregation_Algebras.Aggregation_Algebras +imports "HOL-Hoare.Hoare_Logic" Aggregation_Algebras.Aggregation_Algebras begin context m_kleene_algebra begin abbreviation "component g r \ r\<^sup>T * (--g)\<^sup>\" definition "spanning_tree t g r \ forest t \ t \ (component g r)\<^sup>T * (component g r) \ --g \ component g r \ r\<^sup>T * t\<^sup>\ \ regular t" definition "minimum_spanning_tree t g r \ spanning_tree t g r \ (\u . spanning_tree u g r \ sum (t \ g) \ sum (u \ g))" definition "prim_precondition g r \ g = g\<^sup>T \ injective r \ vector r \ regular r" definition "prim_spanning_invariant t v g r \ prim_precondition g r \ v\<^sup>T = r\<^sup>T * t\<^sup>\ \ spanning_tree t (v * v\<^sup>T \ g) r" definition "prim_invariant t v g r \ prim_spanning_invariant t v g r \ (\w . minimum_spanning_tree w g r \ t \ w)" lemma span_tree_split: assumes "vector r" shows "t \ (component g r)\<^sup>T * (component g r) \ --g \ (t \ (component g r)\<^sup>T \ t \ component g r \ t \ --g)" proof - have "(component g r)\<^sup>T * (component g r) = (component g r)\<^sup>T \ component g r" by (metis assms conv_involutive covector_mult_closed vector_conv_covector vector_covector) thus ?thesis by simp qed lemma span_tree_component: assumes "spanning_tree t g r" shows "component g r = component t r" using assms by (simp add: antisym mult_right_isotone star_isotone spanning_tree_def) text \ We first show three verification conditions which are used in both correctness proofs. \ lemma prim_vc_1: assumes "prim_precondition g r" shows "prim_spanning_invariant bot r g r" proof (unfold prim_spanning_invariant_def, intro conjI) show "prim_precondition g r" using assms by simp next show "r\<^sup>T = r\<^sup>T * bot\<^sup>\" by (simp add: star_absorb) next let ?ss = "r * r\<^sup>T \ g" show "spanning_tree bot ?ss r" proof (unfold spanning_tree_def, intro conjI) show "injective bot" by simp next show "acyclic bot" by simp next show "bot \ (component ?ss r)\<^sup>T * (component ?ss r) \ --?ss" by simp next have "component ?ss r \ component (r * r\<^sup>T) r" by (simp add: mult_right_isotone star_isotone) also have "... \ r\<^sup>T * 1\<^sup>\" using assms by (metis inf.eq_iff p_antitone regular_one_closed star_sub_one prim_precondition_def) also have "... = r\<^sup>T * bot\<^sup>\" by (simp add: star.circ_zero star_one) finally show "component ?ss r \ r\<^sup>T * bot\<^sup>\" . next show "regular bot" by simp qed qed lemma prim_vc_2: assumes "prim_spanning_invariant t v g r" and "v * -v\<^sup>T \ g \ bot" shows "prim_spanning_invariant (t \ minarc (v * -v\<^sup>T \ g)) (v \ minarc (v * -v\<^sup>T \ g)\<^sup>T * top) g r \ card { x . regular x \ x \ component g r \ x \ -(v \ minarc (v * -v\<^sup>T \ g)\<^sup>T * top)\<^sup>T } < card { x . regular x \ x \ component g r \ x \ -v\<^sup>T }" proof - let ?vcv = "v * -v\<^sup>T \ g" let ?e = "minarc ?vcv" let ?t = "t \ ?e" let ?v = "v \ ?e\<^sup>T * top" let ?c = "component g r" let ?g = "--g" let ?n1 = "card { x . regular x \ x \ ?c \ x \ -v\<^sup>T }" let ?n2 = "card { x . regular x \ x \ ?c \ x \ -?v\<^sup>T }" have 1: "regular v \ regular (v * v\<^sup>T) \ regular (?v * ?v\<^sup>T) \ regular (top * ?e)" using assms(1) by (metis prim_spanning_invariant_def spanning_tree_def prim_precondition_def regular_conv_closed regular_closed_star regular_mult_closed conv_involutive regular_closed_top regular_closed_sup minarc_regular) hence 2: "t \ v * v\<^sup>T \ ?g" using assms(1) by (metis prim_spanning_invariant_def spanning_tree_def inf_pp_commute inf.boundedE) hence 3: "t \ v * v\<^sup>T" by simp have 4: "t \ ?g" using 2 by simp have 5: "?e \ v * -v\<^sup>T \ ?g" using 1 by (metis minarc_below pp_dist_inf regular_mult_closed regular_closed_p) hence 6: "?e \ v * -v\<^sup>T" by simp have 7: "vector v" using assms(1) prim_spanning_invariant_def prim_precondition_def by (simp add: covector_mult_closed vector_conv_covector) hence 8: "?e \ v" using 6 by (metis conv_complement inf.boundedE vector_complement_closed vector_covector) have 9: "?e * t = bot" using 3 6 7 et(1) by blast have 10: "?e * t\<^sup>T = bot" using 3 6 7 et(2) by simp have 11: "arc ?e" using assms(2) minarc_arc by simp have "r\<^sup>T \ r\<^sup>T * t\<^sup>\" by (metis mult_right_isotone order_refl semiring.mult_not_zero star.circ_separate_mult_1 star_absorb) hence 12: "r\<^sup>T \ v\<^sup>T" using assms(1) by (simp add: prim_spanning_invariant_def) have 13: "vector r \ injective r \ v\<^sup>T = r\<^sup>T * t\<^sup>\" using assms(1) prim_spanning_invariant_def prim_precondition_def minimum_spanning_tree_def spanning_tree_def reachable_restrict by simp have "g = g\<^sup>T" using assms(1) prim_invariant_def prim_spanning_invariant_def prim_precondition_def by simp hence 14: "?g\<^sup>T = ?g" using conv_complement by simp show "prim_spanning_invariant ?t ?v g r \ ?n2 < ?n1" proof (rule conjI) show "prim_spanning_invariant ?t ?v g r" proof (unfold prim_spanning_invariant_def, intro conjI) show "prim_precondition g r" using assms(1) prim_spanning_invariant_def by simp next show "?v\<^sup>T = r\<^sup>T * ?t\<^sup>\" using assms(1) 6 7 9 by (simp add: reachable_inv prim_spanning_invariant_def prim_precondition_def spanning_tree_def) next let ?G = "?v * ?v\<^sup>T \ g" show "spanning_tree ?t ?G r" proof (unfold spanning_tree_def, intro conjI) show "injective ?t" using assms(1) 10 11 by (simp add: injective_inv prim_spanning_invariant_def spanning_tree_def) next show "acyclic ?t" using assms(1) 3 6 7 acyclic_inv prim_spanning_invariant_def spanning_tree_def by simp next show "?t \ (component ?G r)\<^sup>T * (component ?G r) \ --?G" using 1 2 5 7 13 prim_subgraph_inv inf_pp_commute mst_subgraph_inv_2 by auto next show "component (?v * ?v\<^sup>T \ g) r \ r\<^sup>T * ?t\<^sup>\" proof - have 15: "r\<^sup>T * (v * v\<^sup>T \ ?g)\<^sup>\ \ r\<^sup>T * t\<^sup>\" using assms(1) 1 by (metis prim_spanning_invariant_def spanning_tree_def inf_pp_commute) have "component (?v * ?v\<^sup>T \ g) r = r\<^sup>T * (?v * ?v\<^sup>T \ ?g)\<^sup>\" using 1 by simp also have "... \ r\<^sup>T * ?t\<^sup>\" using 2 6 7 11 12 13 14 15 by (metis span_inv) finally show ?thesis . qed next show "regular ?t" using assms(1) by (metis prim_spanning_invariant_def spanning_tree_def regular_closed_sup minarc_regular) qed qed next have 16: "top * ?e \ ?c" proof - have "top * ?e = top * ?e\<^sup>T * ?e" using 11 by (metis arc_top_edge mult_assoc) also have "... \ v\<^sup>T * ?e" using 7 8 by (metis conv_dist_comp conv_isotone mult_left_isotone symmetric_top_closed) also have "... \ v\<^sup>T * ?g" using 5 mult_right_isotone by auto also have "... = r\<^sup>T * t\<^sup>\ * ?g" using 13 by simp also have "... \ r\<^sup>T * ?g\<^sup>\ * ?g" using 4 by (simp add: mult_left_isotone mult_right_isotone star_isotone) also have "... \ ?c" by (simp add: comp_associative mult_right_isotone star.right_plus_below_circ) finally show ?thesis by simp qed have 17: "top * ?e \ -v\<^sup>T" using 6 7 by (simp add: schroeder_4_p vTeT) have 18: "\ top * ?e \ -(top * ?e)" by (metis assms(2) inf.orderE minarc_bot_iff conv_complement_sub_inf inf_p inf_top.left_neutral p_bot symmetric_top_closed vector_top_closed) have 19: "-?v\<^sup>T = -v\<^sup>T \ -(top * ?e)" by (simp add: conv_dist_comp conv_dist_sup) hence 20: "\ top * ?e \ -?v\<^sup>T" using 18 by simp show "?n2 < ?n1" apply (rule psubset_card_mono) using finite_regular apply simp using 1 16 17 19 20 by auto qed qed lemma prim_vc_3: assumes "prim_spanning_invariant t v g r" and "v * -v\<^sup>T \ g = bot" shows "spanning_tree t g r" proof - let ?g = "--g" have 1: "regular v \ regular (v * v\<^sup>T)" using assms(1) by (metis prim_spanning_invariant_def spanning_tree_def prim_precondition_def regular_conv_closed regular_closed_star regular_mult_closed conv_involutive) have 2: "v * -v\<^sup>T \ ?g = bot" using assms(2) pp_inf_bot_iff pp_pp_inf_bot_iff by simp have 3: "v\<^sup>T = r\<^sup>T * t\<^sup>\ \ vector v" using assms(1) by (simp add: covector_mult_closed prim_invariant_def prim_spanning_invariant_def vector_conv_covector prim_precondition_def) have 4: "t \ v * v\<^sup>T \ ?g" using assms(1) 1 by (metis prim_spanning_invariant_def inf_pp_commute spanning_tree_def inf.boundedE) have "r\<^sup>T * (v * v\<^sup>T \ ?g)\<^sup>\ \ r\<^sup>T * t\<^sup>\" using assms(1) 1 by (metis prim_spanning_invariant_def inf_pp_commute spanning_tree_def) hence 5: "component g r = v\<^sup>T" using 1 2 3 4 by (metis span_post) have "regular (v * v\<^sup>T)" using assms(1) by (metis prim_spanning_invariant_def spanning_tree_def prim_precondition_def regular_conv_closed regular_closed_star regular_mult_closed conv_involutive) hence 6: "t \ v * v\<^sup>T \ ?g" by (metis assms(1) prim_spanning_invariant_def spanning_tree_def inf_pp_commute inf.boundedE) show "spanning_tree t g r" apply (unfold spanning_tree_def, intro conjI) using assms(1) prim_spanning_invariant_def spanning_tree_def apply simp using assms(1) prim_spanning_invariant_def spanning_tree_def apply simp using 5 6 apply simp using assms(1) 5 prim_spanning_invariant_def apply simp using assms(1) prim_spanning_invariant_def spanning_tree_def by simp qed text \ The following result shows that Prim's algorithm terminates and constructs a spanning tree. We cannot yet show that this is a minimum spanning tree. \ theorem prim_spanning: "VARS t v e [ prim_precondition g r ] t := bot; v := r; WHILE v * -v\<^sup>T \ g \ bot INV { prim_spanning_invariant t v g r } VAR { card { x . regular x \ x \ component g r \ -v\<^sup>T } } DO e := minarc (v * -v\<^sup>T \ g); t := t \ e; v := v \ e\<^sup>T * top OD [ spanning_tree t g r ]" apply vcg_tc_simp apply (simp add: prim_vc_1) using prim_vc_2 apply blast using prim_vc_3 by auto text \ Because we have shown total correctness, we conclude that a spanning tree exists. \ lemma prim_exists_spanning: "prim_precondition g r \ \t . spanning_tree t g r" using tc_extract_function prim_spanning by blast text \ This implies that a minimum spanning tree exists, which is used in the subsequent correctness proof. \ lemma prim_exists_minimal_spanning: assumes "prim_precondition g r" shows "\t . minimum_spanning_tree t g r" proof - let ?s = "{ t . spanning_tree t g r }" have "\m\?s . \z\?s . sum (m \ g) \ sum (z \ g)" apply (rule finite_set_minimal) using finite_regular spanning_tree_def apply simp using assms prim_exists_spanning apply simp using sum_linear by simp thus ?thesis using minimum_spanning_tree_def by simp qed text \ Prim's minimum spanning tree algorithm terminates and is correct. This is the same algorithm that is used in the previous correctness proof, with the same precondition and variant, but with a different invariant and postcondition. \ theorem prim: "VARS t v e [ prim_precondition g r \ (\w . minimum_spanning_tree w g r) ] t := bot; v := r; WHILE v * -v\<^sup>T \ g \ bot INV { prim_invariant t v g r } VAR { card { x . regular x \ x \ component g r \ -v\<^sup>T } } DO e := minarc (v * -v\<^sup>T \ g); t := t \ e; v := v \ e\<^sup>T * top OD [ minimum_spanning_tree t g r ]" proof vcg_tc_simp assume "prim_precondition g r \ (\w . minimum_spanning_tree w g r)" thus "prim_invariant bot r g r" using prim_invariant_def prim_vc_1 by simp next fix t v let ?vcv = "v * -v\<^sup>T \ g" let ?vv = "v * v\<^sup>T \ g" let ?e = "minarc ?vcv" let ?t = "t \ ?e" let ?v = "v \ ?e\<^sup>T * top" let ?c = "component g r" let ?g = "--g" let ?n1 = "card { x . regular x \ x \ ?c \ x \ -v\<^sup>T }" let ?n2 = "card { x . regular x \ x \ ?c \ x \ -?v\<^sup>T }" assume 1: "prim_invariant t v g r \ ?vcv \ bot" hence 2: "regular v \ regular (v * v\<^sup>T)" by (metis (no_types, hide_lams) prim_invariant_def prim_spanning_invariant_def spanning_tree_def prim_precondition_def regular_conv_closed regular_closed_star regular_mult_closed conv_involutive) have 3: "t \ v * v\<^sup>T \ ?g" using 1 2 by (metis (no_types, hide_lams) prim_invariant_def prim_spanning_invariant_def spanning_tree_def inf_pp_commute inf.boundedE) hence 4: "t \ v * v\<^sup>T" by simp have 5: "t \ ?g" using 3 by simp have 6: "?e \ v * -v\<^sup>T \ ?g" using 2 by (metis minarc_below pp_dist_inf regular_mult_closed regular_closed_p) hence 7: "?e \ v * -v\<^sup>T" by simp have 8: "vector v" using 1 prim_invariant_def prim_spanning_invariant_def prim_precondition_def by (simp add: covector_mult_closed vector_conv_covector) have 9: "arc ?e" using 1 minarc_arc by simp from 1 obtain w where 10: "minimum_spanning_tree w g r \ t \ w" by (metis prim_invariant_def) hence 11: "vector r \ injective r \ v\<^sup>T = r\<^sup>T * t\<^sup>\ \ forest w \ t \ w \ w \ ?c\<^sup>T * ?c \ ?g \ r\<^sup>T * (?c\<^sup>T * ?c \ ?g)\<^sup>\ \ r\<^sup>T * w\<^sup>\" using 1 2 prim_invariant_def prim_spanning_invariant_def prim_precondition_def minimum_spanning_tree_def spanning_tree_def reachable_restrict by simp hence 12: "w * v \ v" using predecessors_reachable reachable_restrict by auto have 13: "g = g\<^sup>T" using 1 prim_invariant_def prim_spanning_invariant_def prim_precondition_def by simp hence 14: "?g\<^sup>T = ?g" using conv_complement by simp show "prim_invariant ?t ?v g r \ ?n2 < ?n1" proof (unfold prim_invariant_def, intro conjI) show "prim_spanning_invariant ?t ?v g r" using 1 prim_invariant_def prim_vc_2 by blast next show "\w . minimum_spanning_tree w g r \ ?t \ w" proof let ?f = "w \ v * -v\<^sup>T \ top * ?e * w\<^sup>T\<^sup>\" let ?p = "w \ -v * -v\<^sup>T \ top * ?e * w\<^sup>T\<^sup>\" let ?fp = "w \ -v\<^sup>T \ top * ?e * w\<^sup>T\<^sup>\" let ?w = "(w \ -?fp) \ ?p\<^sup>T \ ?e" have 15: "regular ?f \ regular ?fp \ regular ?w" using 2 10 by (metis regular_conv_closed regular_closed_star regular_mult_closed regular_closed_top regular_closed_inf regular_closed_sup minarc_regular minimum_spanning_tree_def spanning_tree_def) show "minimum_spanning_tree ?w g r \ ?t \ ?w" proof (intro conjI) show "minimum_spanning_tree ?w g r" proof (unfold minimum_spanning_tree_def, intro conjI) show "spanning_tree ?w g r" proof (unfold spanning_tree_def, intro conjI) show "injective ?w" using 7 8 9 11 exchange_injective by blast next show "acyclic ?w" using 7 8 11 12 exchange_acyclic by blast next show "?w \ ?c\<^sup>T * ?c \ --g" proof - have 16: "w \ -?fp \ ?c\<^sup>T * ?c \ --g" using 10 by (simp add: le_infI1 minimum_spanning_tree_def spanning_tree_def) have "?p\<^sup>T \ w\<^sup>T" by (simp add: conv_isotone inf.sup_monoid.add_assoc) also have "... \ (?c\<^sup>T * ?c \ --g)\<^sup>T" using 11 conv_order by simp also have "... = ?c\<^sup>T * ?c \ --g" using 2 14 conv_dist_comp conv_dist_inf by simp finally have 17: "?p\<^sup>T \ ?c\<^sup>T * ?c \ --g" . have "?e \ ?c\<^sup>T * ?c \ ?g" using 5 6 11 mst_subgraph_inv by auto thus ?thesis using 16 17 by simp qed next show "?c \ r\<^sup>T * ?w\<^sup>\" proof - have "?c \ r\<^sup>T * w\<^sup>\" using 10 minimum_spanning_tree_def spanning_tree_def by simp also have "... \ r\<^sup>T * ?w\<^sup>\" using 4 7 8 10 11 12 15 by (metis mst_reachable_inv) finally show ?thesis . qed next show "regular ?w" using 15 by simp qed next have 18: "?f \ ?p = ?fp" using 2 8 epm_1 by fastforce have "arc (w \ --v * -v\<^sup>T \ top * ?e * w\<^sup>T\<^sup>\)" using 5 6 8 9 11 12 reachable_restrict arc_edge by auto hence 19: "arc ?f" using 2 by simp hence "?f = bot \ top = bot" by (metis mult_left_zero mult_right_zero) hence "?f \ bot" using 1 le_bot by auto hence "?f \ v * -v\<^sup>T \ ?g \ bot" using 2 11 by (simp add: inf.absorb1 le_infI1) hence "g \ (?f \ v * -v\<^sup>T) \ bot" using inf_commute pp_inf_bot_iff by simp hence 20: "?f \ ?vcv \ bot" by (simp add: inf_assoc inf_commute) hence 21: "?f \ g = ?f \ ?vcv" using 2 by (simp add: inf_assoc inf_commute inf_left_commute) have 22: "?e \ g = minarc ?vcv \ ?vcv" using 7 by (simp add: inf.absorb2 inf.assoc inf.commute) hence 23: "sum (?e \ g) \ sum (?f \ g)" using 15 19 20 21 by (simp add: minarc_min) have "?e \ bot" using 20 comp_inf.semiring.mult_not_zero semiring.mult_not_zero by blast hence 24: "?e \ g \ bot" using 22 minarc_meet_bot by auto have "sum (?w \ g) = sum (w \ -?fp \ g) + sum (?p\<^sup>T \ g) + sum (?e \ g)" using 7 8 10 by (metis sum_disjoint_3 epm_8 epm_9 epm_10 minimum_spanning_tree_def spanning_tree_def) also have "... = sum (((w \ -?fp) \ ?p\<^sup>T) \ g) + sum (?e \ g)" using 11 by (metis epm_8 sum_disjoint) also have "... \ sum (((w \ -?fp) \ ?p\<^sup>T) \ g) + sum (?f \ g)" using 23 24 by (simp add: sum_plus_right_isotone) also have "... = sum (w \ -?fp \ g) + sum (?p\<^sup>T \ g) + sum (?f \ g)" using 11 by (metis epm_8 sum_disjoint) also have "... = sum (w \ -?fp \ g) + sum (?p \ g) + sum (?f \ g)" using 13 sum_symmetric by auto also have "... = sum (((w \ -?fp) \ ?p \ ?f) \ g)" using 2 8 by (metis sum_disjoint_3 epm_11 epm_12 epm_13) also have "... = sum (w \ g)" using 2 8 15 18 epm_2 by force finally have "sum (?w \ g) \ sum (w \ g)" . thus "\u . spanning_tree u g r \ sum (?w \ g) \ sum (u \ g)" using 10 order_lesseq_imp minimum_spanning_tree_def by auto qed next show "?t \ ?w" using 4 8 10 mst_extends_new_tree by simp qed qed next show "?n2 < ?n1" using 1 prim_invariant_def prim_vc_2 by auto qed next fix t v let ?g = "--g" assume 25: "prim_invariant t v g r \ v * -v\<^sup>T \ g = bot" hence 26: "regular v" by (metis prim_invariant_def prim_spanning_invariant_def spanning_tree_def prim_precondition_def regular_conv_closed regular_closed_star regular_mult_closed conv_involutive) from 25 obtain w where 27: "minimum_spanning_tree w g r \ t \ w" by (metis prim_invariant_def) have "spanning_tree t g r" using 25 prim_invariant_def prim_vc_3 by blast hence "component g r = v\<^sup>T" by (metis 25 prim_invariant_def span_tree_component prim_spanning_invariant_def spanning_tree_def) hence 28: "w \ v * v\<^sup>T" using 26 27 by (simp add: minimum_spanning_tree_def spanning_tree_def inf_pp_commute) have "vector r \ injective r \ forest w" using 25 27 by (simp add: prim_invariant_def prim_spanning_invariant_def prim_precondition_def minimum_spanning_tree_def spanning_tree_def) hence "w = t" using 25 27 28 prim_invariant_def prim_spanning_invariant_def mst_post by blast thus "minimum_spanning_tree t g r" using 27 by simp qed end end diff --git a/thys/Relational_Minimum_Spanning_Trees/ROOT b/thys/Relational_Minimum_Spanning_Trees/ROOT --- a/thys/Relational_Minimum_Spanning_Trees/ROOT +++ b/thys/Relational_Minimum_Spanning_Trees/ROOT @@ -1,18 +1,19 @@ chapter AFP session Relational_Minimum_Spanning_Trees (AFP) = Aggregation_Algebras + options [timeout = 600] sessions + "HOL-Hoare" Relational_Disjoint_Set_Forests theories Kruskal Prim Boruvka document_files "root.tex" "root.bib"