Theory Kleene_Relation_Algebras

(* Title:      Kleene Relation Algebras
   Author:     Walter Guttmann
   Maintainer: Walter Guttmann <walter.guttmann at canterbury.ac.nz>
*)

section ‹Kleene Relation Algebras›

text ‹
This theory combines Kleene algebras with Stone relation algebras.
Relation algebras with transitive closure have been studied by cite"Ng1984".
The weakening to Stone relation algebras allows us to talk about reachability in weighted graphs, for example.

Many results in this theory are used in the correctness proof of Prim's minimum spanning tree algorithm.
In particular, they are concerned with the exchange property, preservation of parts of the invariant and with establishing parts of the postcondition.
›

theory Kleene_Relation_Algebras

imports Stone_Relation_Algebras.Relation_Algebras Kleene_Algebras

begin

text ‹
We first note that bounded distributive lattices can be expanded to Kleene algebras by reusing some of the operations.
›

sublocale bounded_distrib_lattice < comp_inf: bounded_kleene_algebra where star = "λx . top" and one = top and times = inf
  apply unfold_locales
  apply (simp add: inf.assoc)
  apply simp
  apply simp
  apply (simp add: le_infI2)
  apply (simp add: inf_sup_distrib2)
  apply simp
  apply simp
  apply simp
  apply simp
  apply simp
  apply (simp add: inf_sup_distrib1)
  apply simp
  apply simp
  by (simp add: inf_assoc)

text ‹
We add the Kleene star operation to each of bounded distributive allegories, pseudocomplemented distributive allegories and Stone relation algebras.
We start with single-object bounded distributive allegories.
›

class bounded_distrib_kleene_allegory = bounded_distrib_allegory + kleene_algebra
begin

subclass bounded_kleene_algebra ..

lemma conv_star_conv:
  "x  xTT"
proof -
  have "xT * xT  xT"
    by (simp add: star.right_plus_below_circ)
  hence 1: "x * xTT  xTT"
    using conv_dist_comp conv_isotone by fastforce
  have "1  xTT"
    by (simp add: reflexive_conv_closed star.circ_reflexive)
  hence "1  x * xTT  xTT"
    using 1 by simp
  thus ?thesis
    using star_left_induct by fastforce
qed

text ‹
It follows that star and converse commute.
›

lemma conv_star_commute:
  "xT = xT"
proof (rule order.antisym)
  show "xT  xT"
    using conv_star_conv conv_isotone by fastforce
next
  show "xT  xT"
    by (metis conv_star_conv conv_involutive)
qed

lemma conv_plus_commute:
  "x+T = xT+"
  by (simp add: conv_dist_comp conv_star_commute star_plus)

text ‹Lemma reflexive_inf_star› was contributed by Nicolas Robinson-O'Brien.›

lemma reflexive_inf_star:
  assumes "reflexive y"
    shows "y  x = 1  (y  x+)"
  by (simp add: assms star_left_unfold_equal sup.absorb2 sup_inf_distrib1)

text ‹
The following results are variants of a separation lemma of Kleene algebras.
›

lemma cancel_separate_2:
  assumes "x * y  1"
    shows "((w  x)  (z  y)) = (z  y) * (w  x)"
proof -
  have "(w  x) * (z  y)  1"
    by (meson assms comp_isotone order.trans inf.cobounded2)
  thus ?thesis
    using cancel_separate_1 sup_commute by simp
qed

lemma cancel_separate_3:
  assumes "x * y  1"
    shows "(w  x) * (z  y) = (w  x)  (z  y)"
proof -
  have "(w  x) * (z  y)  1"
    by (meson assms comp_isotone order.trans inf.cobounded2)
  thus ?thesis
    by (simp add: cancel_separate_eq)
qed

lemma cancel_separate_4:
  assumes "z * y  1"
      and "w  y  z"
      and "x  y  z"
    shows "w * x = (w  y) * ((w  z)  (x  y)) * (x  z)"
proof -
  have "w * x = ((w  y)  (w  z)) * ((x  y)  (x  z))"
    by (metis assms(2,3) inf.orderE inf_sup_distrib1)
  also have "... = (w  y) * ((w  z) * (x  y)) * (x  z)"
    by (metis assms(1) cancel_separate_2 sup_commute mult_assoc)
  finally show ?thesis
    by (simp add: assms(1) cancel_separate_3)
qed

lemma cancel_separate_5:
  assumes "w * zT  1"
    shows "w  x * (y  z)  y"
proof -
  have "w  x * (y  z)  (x  w * (y  z)T) * (y  z)"
    by (metis dedekind_2 inf_commute)
  also have "...  w * zT * (y  z)"
    by (simp add: conv_dist_inf inf.coboundedI2 mult_left_isotone mult_right_isotone)
  also have "...  y  z"
    by (metis assms mult_1_left mult_left_isotone)
  finally show ?thesis
    by simp
qed

lemma cancel_separate_6:
  assumes "z * y  1"
      and "w  y  z"
      and "x  y  z"
      and "v * zT  1"
      and "v  y = bot"
    shows "v  w * x  x  w"
proof -
  have "v  (w  y) * (x  y)  v  y * (x  y)"
    using comp_inf.mult_right_isotone mult_left_isotone star_isotone by simp
  also have "...  v  y"
    by (simp add: inf.coboundedI2 star.circ_increasing star.circ_mult_upper_bound star_right_induct_mult)
  finally have 1: "v  (w  y) * (x  y) = bot"
    using assms(5) le_bot by simp
  have "v  w * x = v  (w  y) * ((w  z)  (x  y)) * (x  z)"
    using assms(1-3) cancel_separate_4 by simp
  also have "... = (v  (w  y) * ((w  z)  (x  y)) * (x  z) * (x  z))  (v  (w  y) * ((w  z)  (x  y)))"
    by (metis inf_sup_distrib1 star.circ_back_loop_fixpoint)
  also have "...  x  (v  (w  y) * ((w  z)  (x  y)))"
    using assms(4) cancel_separate_5 semiring.add_right_mono by simp
  also have "... = x  (v  (w  y) * (w  z))"
    using 1 by (simp add: inf_sup_distrib1 mult_left_dist_sup sup_monoid.add_assoc)
  also have "... = x  (v  (w  y) * (w  z) * (w  z))  (v  (w  y))"
    by (metis comp_inf.semiring.distrib_left star.circ_back_loop_fixpoint sup_assoc)
  also have "...  x  w  (v  (w  y))"
    using assms(4) cancel_separate_5 sup_left_isotone sup_right_isotone by simp
  also have "...  x  w  (v  y)"
    using comp_inf.mult_right_isotone star_isotone sup_right_isotone by simp
  finally show ?thesis
    using assms(5) le_bot by simp
qed

text ‹
We show several results about the interaction of vectors and the Kleene star.
›

lemma vector_star_1:
  assumes "vector x"
    shows "xT * (x * xT)  xT"
proof -
  have "xT * (x * xT) = (xT * x) * xT"
    by (simp add: star_slide)
  also have "...  top * xT"
    by (simp add: mult_left_isotone)
  also have "... = xT"
    using assms vector_conv_covector by auto
  finally show ?thesis
    .
qed

lemma vector_star_2:
  "vector x  xT * (x * xT)  xT * bot"
  by (simp add: star_absorb vector_star_1)

lemma vector_vector_star:
  "vector v  (v * vT) = 1  v * vT"
  by (simp add: transitive_star vv_transitive)

lemma equivalence_star_closed:
  "equivalence x  equivalence (x)"
  by (simp add: conv_star_commute star.circ_reflexive star.circ_transitive_equal)

lemma equivalence_plus_closed:
  "equivalence x  equivalence (x+)"
  by (simp add: conv_star_commute star.circ_reflexive star.circ_sup_one_left_unfold star.circ_transitive_equal)

text ‹
The following equivalence relation characterises the component trees of a forest.
This is a special case of undirected reachability in a directed graph.
›

abbreviation "forest_components f  fT * f"

lemma forest_components_equivalence:
  "injective x  equivalence (forest_components x)"
  apply (intro conjI)
  apply (simp add: reflexive_mult_closed star.circ_reflexive)
  apply (metis cancel_separate_1 order.eq_iff star.circ_transitive_equal)
  by (simp add: conv_dist_comp conv_star_commute)

lemma forest_components_increasing:
  "x  forest_components x"
  by (metis order.trans mult_left_isotone mult_left_one star.circ_increasing star.circ_reflexive)

lemma forest_components_isotone:
  "x  y  forest_components x  forest_components y"
  by (simp add: comp_isotone conv_isotone star_isotone)

lemma forest_components_idempotent:
  "injective x  forest_components (forest_components x) = forest_components x"
  by (metis forest_components_equivalence cancel_separate_1 star.circ_transitive_equal star_involutive)

lemma forest_components_star:
  "injective x  (forest_components x) = forest_components x"
  using forest_components_equivalence forest_components_idempotent star.circ_transitive_equal by simp

text ‹
The following lemma shows that the nodes reachable in the graph can be reached by only using edges between reachable nodes.
›

lemma reachable_restrict:
  assumes "vector r"
    shows "rT * g = rT * ((rT * g)T * (rT * g)  g)"
proof -
  have 1: "rT  rT * ((rT * g)T * (rT * g)  g)"
    using mult_right_isotone mult_1_right star.circ_reflexive by fastforce
  have 2: "covector (rT * g)"
    using assms covector_mult_closed vector_conv_covector by auto
  have "rT * ((rT * g)T * (rT * g)  g) * g  rT * g * g"
    by (simp add: mult_left_isotone mult_right_isotone star_isotone)
  also have "...  rT * g"
    by (simp add: mult_assoc mult_right_isotone star.left_plus_below_circ star_plus)
  finally have "rT * ((rT * g)T * (rT * g)  g) * g = rT * ((rT * g)T * (rT * g)  g) * g  rT * g"
    by (simp add: le_iff_inf)
  also have "... = rT * ((rT * g)T * (rT * g)  g) * (g  rT * g)"
    using assms covector_comp_inf covector_mult_closed vector_conv_covector by auto
  also have "... = (rT * ((rT * g)T * (rT * g)  g)  rT * g) * (g  rT * g)"
    by (simp add: inf.absorb2 inf_commute mult_right_isotone star_isotone)
  also have "... = rT * ((rT * g)T * (rT * g)  g) * (g  rT * g  (rT * g)T)"
    using 2 by (metis comp_inf_vector_1)
  also have "... = rT * ((rT * g)T * (rT * g)  g) * ((rT * g)T  rT * g  g)"
    using inf_commute inf_assoc by simp
  also have "... = rT * ((rT * g)T * (rT * g)  g) * ((rT * g)T * (rT * g)  g)"
    using 2 by (metis covector_conv_vector inf_top.right_neutral vector_inf_comp)
  also have "...  rT * ((rT * g)T * (rT * g)  g)"
    by (simp add: mult_assoc mult_right_isotone star.left_plus_below_circ star_plus)
  finally have "rT * g  rT * ((rT * g)T * (rT * g)  g)"
    using 1 star_right_induct by auto
  thus ?thesis
    by (simp add: order.eq_iff mult_right_isotone star_isotone)
qed

lemma kruskal_acyclic_inv_1:
  assumes "injective f"
      and "e * forest_components f * e = bot"
    shows "(f  top * e * fT)T * f * e = bot"
proof -
  let ?q = "top * e * fT"
  let ?F = "forest_components f"
  have "(f  ?q)T * f * e = ?qT  fT * f * e"
    by (metis (mono_tags) comp_associative conv_dist_inf covector_conv_vector inf_vector_comp vector_top_closed)
  also have "...  ?qT  ?F * e"
    using comp_inf.mult_right_isotone mult_left_isotone star.circ_increasing by simp
  also have "... = f * eT * top  ?F * e"
    by (simp add: conv_dist_comp conv_star_commute mult_assoc)
  also have "...  ?F * eT * top  ?F * e"
    by (metis conv_dist_comp conv_star_commute conv_top inf.sup_left_isotone star.circ_right_top star_outer_increasing mult_assoc)
  also have "... = ?F * (eT * top  ?F * e)"
    by (metis assms(1) forest_components_equivalence equivalence_comp_dist_inf mult_assoc)
  also have "... = (?F  top * e) * ?F * e"
    by (simp add: comp_associative comp_inf_vector_1 conv_dist_comp inf_vector_comp)
  also have "...  top * e * ?F * e"
    by (simp add: mult_left_isotone)
  also have "... = bot"
    using assms(2) mult_assoc by simp
  finally show ?thesis
    by (simp add: bot_unique)
qed

lemma kruskal_forest_components_inf_1:
  assumes "f  w  wT"
      and "injective w"
      and "f  forest_components g"
    shows "f * forest_components (forest_components g  w)  forest_components (forest_components g  w)"
proof -
  let ?f = "forest_components g"
  let ?w = "forest_components (?f  w)"
  have "f * ?w = (f  (w  wT)) * ?w"
    by (simp add: assms(1) inf.absorb1)
  also have "... = (f  w) * ?w  (f  wT) * ?w"
    by (simp add: inf_sup_distrib1 semiring.distrib_right)
  also have "...  (?f  w) * ?w  (f  wT) * ?w"
    using assms(3) inf.sup_left_isotone mult_left_isotone sup_left_isotone by simp
  also have "...  (?f  w) * ?w  (?f  wT) * ?w"
    using assms(3) inf.sup_left_isotone mult_left_isotone sup_right_isotone by simp
  also have "... = (?f  w) * ?w  (?f  w)T * ?w"
    by (simp add: conv_dist_comp conv_dist_inf conv_star_commute)
  also have "...  (?f  w) * ?w  ?w"
    by (metis star.circ_loop_fixpoint sup_ge1 sup_right_isotone)
  also have "... = ?w  (?f  w) * (?f  w)  (?f  w) * (?f  w)T+ * (?f  w)"
    by (metis comp_associative mult_left_dist_sup star.circ_loop_fixpoint sup_commute sup_assoc)
  also have "...  ?w  (?f  w)  (?f  w) * (?f  w)T+ * (?f  w)"
    using star.left_plus_below_circ sup_left_isotone sup_right_isotone by auto
  also have "... = ?w  (?f  w) * (?f  w)T+ * (?f  w)"
    by (metis star.circ_loop_fixpoint sup.right_idem)
  also have "...  ?w  w * wT * ?w"
    using comp_associative conv_dist_inf mult_isotone sup_right_isotone by simp
  also have "... = ?w"
    by (metis assms(2) coreflexive_comp_top_inf inf.cobounded2 sup.orderE)
  finally show ?thesis
    by simp
qed

lemma kruskal_forest_components_inf:
  assumes "f  w  wT"
      and "injective w"
    shows "forest_components f  forest_components (forest_components f  w)"
proof -
  let ?f = "forest_components f"
  let ?w = "forest_components (?f  w)"
  have 1: "1  ?w"
    by (simp add: reflexive_mult_closed star.circ_reflexive)
  have "f * ?w  ?w"
    using assms forest_components_increasing kruskal_forest_components_inf_1 by simp
  hence 2: "f  ?w"
    using 1 star_left_induct by fastforce
  have "fT * ?w  ?w"
    apply (rule kruskal_forest_components_inf_1)
    apply (metis assms(1) conv_dist_sup conv_involutive conv_isotone sup_commute)
    apply (simp add: assms(2))
    by (metis le_supI2 star.circ_back_loop_fixpoint star.circ_increasing)
  thus "?f  ?w"
    using 2 star_left_induct by simp
qed

end

text ‹
We next add the Kleene star to single-object pseudocomplemented distributive allegories.
›

class pd_kleene_allegory = pd_allegory + bounded_distrib_kleene_allegory
begin

text ‹
The following definitions and results concern acyclic graphs and forests.
›

abbreviation acyclic :: "'a  bool" where "acyclic x  x+  -1"

abbreviation forest :: "'a  bool" where "forest x  injective x  acyclic x"

lemma forest_bot:
  "forest bot"
  by simp

lemma acyclic_down_closed:
  "x  y  acyclic y  acyclic x"
  using comp_isotone star_isotone by fastforce

lemma forest_down_closed:
  "x  y  forest y  forest x"
  using conv_isotone mult_isotone star_isotone by fastforce

lemma acyclic_star_below_complement:
  "acyclic w  wT  -w"
  by (simp add: conv_star_commute schroeder_4_p)

lemma acyclic_star_below_complement_1:
  "acyclic w  w  wT = bot"
  using pseudo_complement schroeder_5_p by force

lemma acyclic_star_inf_conv:
  assumes "acyclic w"
  shows "w  wT = 1"
proof -
  have "w+  wT  (w  wT) * w"
    by (metis conv_star_commute dedekind_2 star.circ_transitive_equal)
  also have "... = bot"
    by (metis assms conv_star_commute p_antitone_iff pseudo_complement schroeder_4_p semiring.mult_not_zero star.circ_circ_mult star_involutive star_one)
  finally have "w  wT  1"
    by (metis order.eq_iff le_bot mult_left_zero star.circ_plus_one star.circ_zero star_left_unfold_equal sup_inf_distrib1)
  thus ?thesis
    by (simp add: order.antisym star.circ_reflexive)
qed

lemma acyclic_asymmetric:
  "acyclic w  asymmetric w"
  by (simp add: dual_order.trans pseudo_complement schroeder_5_p star.circ_increasing)

lemma forest_separate:
  assumes "forest x"
    shows "x * xT  xT * x  1"
proof -
  have "x * 1  -xT"
    using assms schroeder_5_p by force
  hence 1: "x  xT = bot"
    by (simp add: pseudo_complement)
  have "x  xT * x = (1  x * x)  xT * x"
    using star.circ_right_unfold_1 by simp
  also have "... = (1  xT * x)  (x * x  xT * x)"
    by (simp add: inf_sup_distrib2)
  also have "...  1  (x * x  xT * x)"
    using sup_left_isotone by simp
  also have "... = 1  (x  xT) * x"
    by (simp add: assms injective_comp_right_dist_inf)
  also have "... = 1"
    using 1 by simp
  finally have 2: "x  xT * x  1"
    .
  hence 3: "xT  xT * x  1"
    by (metis (mono_tags, lifting) conv_star_commute conv_dist_comp conv_dist_inf conv_involutive coreflexive_symmetric)
  have "x * xT  xT * x  (x  xT)  xT * x"
    using assms cancel_separate inf.sup_left_isotone by simp
  also have "...  1"
    using 2 3 by (simp add: inf_sup_distrib2)
  finally show ?thesis
    .
qed

text ‹
The following definition captures the components of undirected weighted graphs.
›

abbreviation "components g  (--g)"

lemma components_equivalence:
  "symmetric x  equivalence (components x)"
  by (simp add: conv_star_commute conv_complement star.circ_reflexive star.circ_transitive_equal)

lemma components_increasing:
  "x  components x"
  using order_trans pp_increasing star.circ_increasing by blast

lemma components_isotone:
  "x  y  components x  components y"
  by (simp add: pp_isotone star_isotone)

lemma cut_reachable:
  assumes "vT = rT * t"
      and "t  g"
    shows "v * -vT  g  (rT * g)T * (rT * g)"
proof -
  have "v * -vT  g  v * top  g"
    using inf.sup_left_isotone mult_right_isotone top_greatest by blast
  also have "... = (rT * t)T * top  g"
    by (metis assms(1) conv_involutive)
  also have "...  (rT * g)T * top  g"
    using assms(2) conv_isotone inf.sup_left_isotone mult_left_isotone mult_right_isotone star_isotone by auto
  also have "...  (rT * g)T * ((rT * g) * g)"
    by (metis conv_involutive dedekind_1 inf_top.left_neutral)
  also have "...  (rT * g)T * (rT * g)"
    by (simp add: mult_assoc mult_right_isotone star.left_plus_below_circ star_plus)
  finally show ?thesis
    .
qed

text ‹
The following lemma shows that the predecessors of visited nodes in the minimum spanning tree extending the current tree have all been visited.
›

lemma predecessors_reachable:
  assumes "vector r"
      and "injective r"
      and "vT = rT * t"
      and "forest w"
      and "t  w"
      and "w  (rT * g)T * (rT * g)  g"
      and "rT * g  rT * w"
    shows "w * v  v"
proof -
  have "w * r  (rT * g)T * (rT * g) * r"
    using assms(6) mult_left_isotone by auto
  also have "...  (rT * g)T * top"
    by (simp add: mult_assoc mult_right_isotone)
  also have "... = (rT * g)T"
    by (simp add: assms(1) comp_associative conv_dist_comp)
  also have "...  (rT * w)T"
    by (simp add: assms(7) conv_isotone)
  also have "... = wT * r"
    by (simp add: conv_dist_comp conv_star_commute)
  also have "...  -w * r"
    using assms(4) by (simp add: mult_left_isotone acyclic_star_below_complement)
  also have "...  -(w * r)"
    by (simp add: assms(2) comp_injective_below_complement)
  finally have 1: "w * r = bot"
    by (simp add: le_iff_inf)
  have "v = tT * r"
    by (metis assms(3) conv_dist_comp conv_involutive conv_star_commute)
  also have "... = tT * v  r"
    by (simp add: calculation star.circ_loop_fixpoint)
  also have "...  wT * v  r"
    using assms(5) comp_isotone conv_isotone semiring.add_right_mono by auto
  finally have "w * v  w * wT * v  w * r"
    by (simp add: comp_left_dist_sup mult_assoc mult_right_isotone)
  also have "... = w * wT * v"
    using 1 by simp
  also have "...  v"
    using assms(4) by (simp add: star_left_induct_mult_iff star_sub_one)
  finally show ?thesis
    .
qed

subsection ‹Prim's Algorithm›

text ‹
The following results are used for proving the correctness of Prim's minimum spanning tree algorithm.
›

subsubsection ‹Preservation of Invariant›

text ‹
We first treat the preservation of the invariant.
The following lemma shows that the while-loop preserves that v› represents the nodes of the constructed tree.
The remaining lemmas in this section show that t› is a spanning tree.
The exchange property is treated in the following two sections.
›

lemma reachable_inv:
  assumes "vector v"
      and "e  v * -vT"
      and "e * t = bot"
      and "vT = rT * t"
    shows "(v  eT * top)T = rT * (t  e)"
proof -
  have 1: "vT  rT * (t  e)"
    by (simp add: assms(4) mult_right_isotone star.circ_sub_dist)
  have 2: "(eT * top)T = top * e"
    by (simp add: conv_dist_comp)
  also have "... = top * (v * -vT  e)"
    by (simp add: assms(2) inf_absorb2)
  also have "...  top * (v * top  e)"
    using inf.sup_left_isotone mult_right_isotone top_greatest by blast
  also have "... = top * vT * e"
    by (simp add: comp_inf_vector inf.sup_monoid.add_commute)
  also have "... = vT * e"
    using assms(1) vector_conv_covector by auto
  also have "...  rT * (t  e) * e"
    using 1 by (simp add: mult_left_isotone)
  also have "...  rT * (t  e) * (t  e)"
    by (simp add: mult_right_isotone)
  also have "...  rT * (t  e)"
    by (simp add: comp_associative mult_right_isotone star.right_plus_below_circ)
  finally have 3: "(v  eT * top)T  rT * (t  e)"
    using 1 by (simp add: conv_dist_sup)
  have "rT  rT * t"
    using sup.bounded_iff star.circ_back_loop_prefixpoint by blast
  also have "...  (v  eT * top)T"
    by (metis assms(4) conv_isotone sup_ge1)
  finally have 4: "rT  (v  eT * top)T"
    .
  have "(v  eT * top)T * (t  e) = (v  eT * top)T * t  (v  eT * top)T * e"
    by (simp add: mult_left_dist_sup)
  also have "...  (v  eT * top)T * t  top * e"
    using comp_isotone semiring.add_left_mono by auto
  also have "... = vT * t  top * e * t  top * e"
    using 2 by (simp add: conv_dist_sup mult_right_dist_sup)
  also have "... = vT * t  top * e"
    by (simp add: assms(3) comp_associative)
  also have "...  rT * t  top * e"
    by (metis assms(4) star.circ_back_loop_fixpoint sup_ge1 sup_left_isotone)
  also have "... = vT  top * e"
    by (simp add: assms(4))
  finally have 5: "(v  eT * top)T * (t  e)  (v  eT * top)T"
    using 2 by (simp add: conv_dist_sup)
  have "rT * (t  e)  (v  eT * top)T * (t  e)"
    using 4 by (simp add: mult_left_isotone)
  also have "...  (v  eT * top)T"
    using 5 by (simp add: star_right_induct_mult)
  finally show ?thesis
    using 3 by (simp add: order.eq_iff)
qed

text ‹
The next result is used to show that the while-loop preserves acyclicity of the constructed tree.
›

lemma acyclic_inv:
  assumes "acyclic t"
      and "vector v"
      and "e  v * -vT"
      and "t  v * vT"
    shows "acyclic (t  e)"
proof -
  have "t+ * e  t+ * v * -vT"
    by (simp add: assms(3) comp_associative mult_right_isotone)
  also have "...  v * vT * t * v * -vT"
    by (simp add: assms(4) mult_left_isotone)
  also have "...  v * top * -vT"
    by (metis mult_assoc mult_left_isotone mult_right_isotone top_greatest)
  also have "... = v * -vT"
    by (simp add: assms(2))
  also have "...  -1"
    by (simp add: pp_increasing schroeder_3_p)
  finally have 1: "t+ * e  -1"
    .
  have 2: "e * t = e"
    using assms(2-4) et(1) star_absorb by blast
  have "e = 1  e  e * e * e"
    by (metis star.circ_loop_fixpoint star_square_2 sup_commute)
  also have "... = 1  e"
    using assms(2,3) ee comp_left_zero bot_least sup_absorb1 by simp
  finally have 3: "e = 1  e"
    .
  have "e  v * -vT"
    by (simp add: assms(3))
  also have "...  -1"
    by (simp add: pp_increasing schroeder_3_p)
  finally have 4: "t+ * e  e  -1"
    using 1 by simp
  have "(t  e)+ = (t  e) * t * (e * t)"
    using star_sup_1 mult_assoc by simp
  also have "... = (t  e) * t * (1  e)"
    using 2 3 by simp
  also have "... = t+ * (1  e)  e * t * (1  e)"
    by (simp add: comp_right_dist_sup)
  also have "... = t+ * (1  e)  e * (1  e)"
    using 2 by simp
  also have "... = t+ * (1  e)  e"
    using 3 by (metis star_absorb assms(2,3) ee)
  also have "... = t+  t+ * e  e"
    by (simp add: mult_left_dist_sup)
  also have "...  -1"
    using 4 by (metis assms(1) sup.absorb1 sup.orderI sup_assoc)
  finally show ?thesis
    .
qed

text ‹
The following lemma shows that the extended tree is in the component reachable from the root.
›

lemma mst_subgraph_inv_2:
  assumes "regular (v * vT)"
      and "t  v * vT  --g"
      and "vT = rT * t"
      and "e  v * -vT  --g"
      and "vector v"
      and "regular ((v  eT * top) * (v  eT * top)T)"
    shows "t  e  (rT * (--((v  eT * top) * (v  eT * top)T  g)))T * (rT * (--((v  eT * top) * (v  eT * top)T  g)))"
proof -
  let ?v = "v  eT * top"
  let ?G = "?v * ?vT  g"
  let ?c = "rT * (--?G)"
  have "vT  rT * (--(v * vT  g))"
    using assms(1-3) inf_pp_commute mult_right_isotone star_isotone by auto
  also have "...  ?c"
    using comp_inf.mult_right_isotone comp_isotone conv_isotone inf.commute mult_right_isotone pp_isotone star_isotone sup.cobounded1 by presburger
  finally have 2: "vT  ?c  v  ?cT"
    by (metis conv_isotone conv_involutive)
  have "t  v * vT"
    using assms(2) by auto
  hence 3: "t  ?cT * ?c"
    using 2 order_trans mult_isotone by blast
  have "e  v * top  --g"
    by (metis assms(4,5) inf.bounded_iff inf.sup_left_divisibility mult_right_isotone top.extremum)
  hence "e  v * top  top * e  --g"
    by (simp add: top_left_mult_increasing inf.boundedI)
  hence "e  v * top * e  --g"
    by (metis comp_inf_covector inf.absorb2 mult_assoc top.extremum)
  hence "t  e  (v * vT  --g)  (v * top * e  --g)"
    using assms(2) sup_mono by blast
  also have "... = v * ?vT  --g"
    by (simp add: inf_sup_distrib2 mult_assoc mult_left_dist_sup conv_dist_comp conv_dist_sup)
  also have "...  --?G"
    using assms(6) comp_left_increasing_sup inf.sup_left_isotone pp_dist_inf by auto
  finally have 4: "t  e  --?G"
    .
  have "e  e * eT * e"
    by (simp add: ex231c)
  also have "...  v * -vT * -v * vT * e"
    by (metis assms(4) mult_left_isotone conv_isotone conv_dist_comp mult_assoc mult_isotone conv_involutive conv_complement inf.boundedE)
  also have "...  v * top * vT * e"
    by (metis mult_assoc mult_left_isotone mult_right_isotone top.extremum)
  also have "... = v * rT * t * e"
    using assms(3,5) by (simp add: mult_assoc)
  also have "...  v * rT * (t  e)"
    by (simp add: comp_associative mult_right_isotone star.circ_mult_upper_bound star.circ_sub_dist_1 star_isotone sup_commute)
  also have "...  v * ?c"
    using 4 by (simp add: mult_assoc mult_right_isotone star_isotone)
  also have "...  ?cT * ?c"
    using 2 by (simp add: mult_left_isotone)
  finally show ?thesis
    using 3 by simp
qed

lemma span_inv:
  assumes "e  v * -vT"
      and "vector v"
      and "arc e"
      and "t  (v * vT)  g"
      and "gT = g"
      and "vT = rT * t"
      and "injective r"
      and "rT  vT"
      and "rT * ((v * vT)  g)  rT * t"
    shows "rT * (((v  eT * top) * (v  eT * top)T)  g)  rT * (t  e)"
proof -
  let ?d = "(v * vT)  g"
  have 1: "(v  eT * top) * (v  eT * top)T = v * vT  v * vT * e  eT * v * vT  eT * e"
    using assms(1-3) ve_dist by simp
  have "tT  ?dT"
    using assms(4) conv_isotone by simp
  also have "... = (v * vT)  gT"
    by (simp add: conv_dist_comp conv_dist_inf)
  also have "... = ?d"
    by (simp add: assms(5))
  finally have 2: "tT  ?d"
    .
  have "v * vT = (rT * t)T * (rT * t)"
    by (metis assms(6) conv_involutive)
  also have "... = tT * (r * rT) * t"
    by (simp add: comp_associative conv_dist_comp conv_star_commute)
  also have "...  tT * 1 * t"
    by (simp add: assms(7) mult_left_isotone star_right_induct_mult_iff star_sub_one)
  also have "... = tT * t"
    by simp
  also have "...  ?d * t"
    using 2 by (simp add: comp_left_isotone star.circ_isotone)
  also have "...  ?d * ?d"
    using assms(4) mult_right_isotone star_isotone by simp
  also have 3: "... = ?d"
    by (simp add: star.circ_transitive_equal)
  finally have 4: "v * vT  ?d"
    .
  have 5: "rT * ?d * (v * vT  g)  rT * ?d"
    by (simp add: comp_associative mult_right_isotone star.circ_plus_same star.left_plus_below_circ)
  have "rT * ?d * (v * vT * e  g)  rT * ?d * v * vT * e"
    by (simp add: comp_associative comp_right_isotone)
  also have "...  rT * ?d * e"
    using 3 4 by (metis comp_associative comp_isotone eq_refl)
  finally have 6: "rT * ?d * (v * vT * e  g)  rT * ?d * e"
    .
  have 7: "x . rT * (1  v * vT) * eT * x = bot"
  proof
    fix x
    have "rT * (1  v * vT) * eT * x  rT * (1  v * vT) * eT * top"
      by (simp add: mult_right_isotone)
    also have "... = rT * eT * top  rT * v * vT * eT * top"
      by (simp add: comp_associative mult_left_dist_sup mult_right_dist_sup)
    also have "... = rT * eT * top"
      by (metis assms(1,2) mult_assoc mult_right_dist_sup mult_right_zero sup_bot_right vTeT)
    also have "...  vT * eT * top"
      by (simp add: assms(8) comp_isotone)
    also have "... = bot"
      using vTeT assms(1,2) by simp
    finally show "rT * (1  v * vT) * eT * x = bot"
      by (simp add: le_bot)
  qed
  have "rT * ?d * (eT * v * vT  g)  rT * ?d * eT * v * vT"
    by (simp add: comp_associative comp_right_isotone)
  also have "...  rT * (1  v * vT) * eT * v * vT"
    by (metis assms(2) star.circ_isotone vector_vector_star inf_le1 comp_associative comp_right_isotone comp_left_isotone)
  also have "... = bot"
    using 7 by simp
  finally have 8: "rT * ?d * (eT * v * vT  g) = bot"
    by (simp add: le_bot)
  have "rT * ?d * (eT * e  g)  rT * ?d * eT * e"
    by (simp add: comp_associative comp_right_isotone)
  also have "...  rT * (1  v * vT) * eT * e"
    by (metis assms(2) star.circ_isotone vector_vector_star inf_le1 comp_associative comp_right_isotone comp_left_isotone)
  also have "... = bot"
    using 7 by simp
  finally have 9: "rT * ?d * (eT * e  g) = bot"
    by (simp add: le_bot)
  have "rT * ?d * ((v  eT * top) * (v  eT * top)T  g) = rT * ?d * ((v * vT  v * vT * e  eT * v * vT  eT * e)  g)"
    using 1 by simp
  also have "... = rT * ?d * ((v * vT  g)  (v * vT * e  g)  (eT * v * vT  g)  (eT * e  g))"
    by (simp add: inf_sup_distrib2)
  also have "... = rT * ?d * (v * vT  g)  rT * ?d * (v * vT * e  g)  rT * ?d * (eT * v * vT  g)  rT * ?d * (eT * e  g)"
    by (simp add: comp_left_dist_sup)
  also have "... = rT * ?d * (v * vT  g)  rT * ?d * (v * vT * e  g)"
    using 8 9 by simp
  also have "...  rT * ?d  rT * ?d * e"
    using 5 6 sup.mono by simp
  also have "... = rT * ?d * (1  e)"
    by (simp add: mult_left_dist_sup)
  finally have 10: "rT * ?d * ((v  eT * top) * (v  eT * top)T  g)  rT * ?d * (1  e)"
    by simp
  have "rT * ?d * e * (v * vT  g)  rT * ?d * e * v * vT"
    by (simp add: comp_associative comp_right_isotone)
  also have "... = bot"
    by (metis assms(1,2) comp_associative comp_right_zero ev comp_left_zero)
  finally have 11: "rT * ?d * e * (v * vT  g) = bot"
    by (simp add: le_bot)
  have "rT * ?d * e * (v * vT * e  g)  rT * ?d * e * v * vT * e"
    by (simp add: comp_associative comp_right_isotone)
  also have "... = bot"
    by (metis assms(1,2) comp_associative comp_right_zero ev comp_left_zero)
  finally have 12: "rT * ?d * e * (v * vT * e  g) = bot"
    by (simp add: le_bot)
  have "rT * ?d * e * (eT * v * vT  g)  rT * ?d * e * eT * v * vT"
    by (simp add: comp_associative comp_right_isotone)
  also have "...  rT * ?d * 1 * v * vT"
    by (metis assms(3) arc_injective comp_associative comp_left_isotone comp_right_isotone)
  also have "... = rT * ?d * v * vT"
    by simp
  also have "...  rT * ?d * ?d"
    using 4 by (simp add: mult_right_isotone mult_assoc)
  also have "... = rT * ?d"
    by (simp add: star.circ_transitive_equal comp_associative)
  finally have 13: "rT * ?d * e * (eT * v * vT  g)  rT * ?d"
    .
  have "rT * ?d * e * (eT * e  g)  rT * ?d * e * eT * e"
    by (simp add: comp_associative comp_right_isotone)
  also have "...  rT * ?d * 1 * e"
    by (metis assms(3) arc_injective comp_associative comp_left_isotone comp_right_isotone)
  also have "... = rT * ?d * e"
    by simp
  finally have 14: "rT * ?d * e * (eT * e  g)  rT * ?d * e"
    .
  have "rT * ?d * e * ((v  eT * top) * (v  eT * top)T  g) = rT * ?d * e * ((v * vT  v * vT * e  eT * v * vT  eT * e)  g)"
    using 1 by simp
  also have "... = rT * ?d * e * ((v * vT  g)  (v * vT * e  g)  (eT * v * vT  g)  (eT * e  g))"
    by (simp add: inf_sup_distrib2)
  also have "... = rT * ?d * e * (v * vT  g)  rT * ?d * e * (v * vT * e  g)  rT * ?d * e * (eT * v * vT  g)  rT * ?d * e * (eT * e  g)"
    by (simp add: comp_left_dist_sup)
  also have "... = rT * ?d * e * (eT * v * vT  g)  rT * ?d * e * (eT * e  g)"
    using 11 12 by simp
  also have "...  rT * ?d  rT * ?d * e"
    using 13 14 sup_mono by simp
  also have "... = rT * ?d * (1  e)"
    by (simp add: mult_left_dist_sup)
  finally have 15: "rT * ?d * e * ((v  eT * top) * (v  eT * top)T  g)  rT * ?d * (1  e)"
    by simp
  have "rT  rT * ?d"
    using mult_right_isotone star.circ_reflexive by fastforce
  also have "...  rT * ?d * (1  e)"
    by (simp add: semiring.distrib_left)
  finally have 16: "rT  rT * ?d * (1  e)"
    .
  have "rT * ?d * (1  e) * ((v  eT * top) * (v  eT * top)T  g) = rT * ?d * ((v  eT * top) * (v  eT * top)T  g)  rT * ?d * e * ((v  eT * top) * (v  eT * top)T  g)"
    by (simp add: semiring.distrib_left semiring.distrib_right)
  also have "...  rT * ?d * (1  e)"
    using 10 15 le_supI by simp
  finally have "rT * ?d * (1  e) * ((v  eT * top) * (v  eT * top)T  g)  rT * ?d * (1  e)"
    .
  hence "rT  rT * ?d * (1  e) * ((v  eT * top) * (v  eT * top)T  g)  rT * ?d * (1  e)"
    using 16 sup_least by simp
  hence "rT * ((v  eT * top) * (v  eT * top)T  g)  rT * ?d * (1  e)"
    by (simp add: star_right_induct)
  also have "...  rT * t * (1  e)"
    by (simp add: assms(9) mult_left_isotone)
  also have "...  rT * (t  e)"
    by (simp add: star_one_sup_below)
  finally show ?thesis
    .
qed

subsubsection ‹Exchange gives Spanning Trees›

text ‹
The following abbreviations are used in the spanning tree application using Prim's algorithm to construct the new tree for the exchange property.
It is obtained by replacing an edge with one that has minimal weight and reversing the path connecting these edges.
Here, w represents a weighted graph, v represents a set of nodes and e represents an edge.
›

abbreviation prim_E :: "'a  'a  'a  'a" where "prim_E w v e  w  --v * -vT  top * e * wT"
abbreviation prim_P :: "'a  'a  'a  'a" where "prim_P w v e  w  -v * -vT  top * e * wT"
abbreviation prim_EP :: "'a  'a  'a  'a" where "prim_EP w v e  w  -vT  top * e * wT"
abbreviation prim_W :: "'a  'a  'a  'a" where "prim_W w v e  (w  -(prim_EP w v e))  (prim_P w v e)T  e"

text ‹
The lemmas in this section are used to show that the relation after exchange represents a spanning tree.
The results in the next section are used to show that it is a minimum spanning tree.
›

lemma exchange_injective_3:
  assumes "e  v * -vT"
      and "vector v"
    shows "(w  -(prim_EP w v e)) * eT = bot"
proof -
  have 1: "top * e  -vT"
    by (simp add: assms schroeder_4_p vTeT)
  have "top * e  top * e * wT"
    using sup_right_divisibility star.circ_back_loop_fixpoint by blast
  hence "top * e  -vT  top * e * wT"
    using 1 by simp
  hence "top * e  -(w  -prim_EP w v e)"
    by (metis inf.assoc inf_import_p le_infI2 p_antitone p_antitone_iff)
  hence "(w  -(prim_EP w v e)) * eT  bot"
    using p_top schroeder_4_p by blast
  thus ?thesis
    using le_bot by simp
qed

lemma exchange_injective_6:
  assumes "arc e"
      and "forest w"
    shows "(prim_P w v e)T * eT = bot"
proof -
  have "e