Theory Kruskal

(* Title:      Kruskal's Minimum Spanning Tree Algorithm
   Author:     Walter Guttmann
   Maintainer: Walter Guttmann <walter.guttmann at canterbury.ac.nz>
*)

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 "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 = hT  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  wT)"

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 = gT"
    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 * fT))  (f  top * minarc h * fT)T  minarc h) g (h  -minarc h  -minarc hT)
                                                card { x . regular x  x  --h  x  -minarc h  x  -minarc hT } < card { x . regular x  x  --h }) 
           (¬ minarc h  -forest_components f  kruskal_spanning_invariant f g (h  -minarc h  -minarc hT)
                                                  card { x . regular x  x  --h  x  -minarc h  x  -minarc hT } < card { x . regular x  x  --h })"
proof -
  let ?e = "minarc h"
  let ?f = "(f  -(top * ?e * fT))  (f  top * ?e * fT)T  ?e"
  let ?h = "h  -?e  -?eT"
  let ?F = "forest_components f"
  let ?n1 = "card { x . regular x  x  --h }"
  let ?n2 = "card { x . regular x  x  --h  x  -?e  x  -?eT }"
  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 (?eT)"
    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 "?eT * top * ?eT = ?eT"
        using assms(2) by (simp add: arc_top_arc minarc_arc)
      hence "?eT * top * ?eT  -?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 = ?hT"
          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 (opaque_lifting) 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 = ?hT"
          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 (opaque_lifting) 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 * fT))  (f  top * e * fT)T  e
        ELSE
          SKIP
        FI;
        h := h  -e  -eT
     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 * fT))  (f  top * e * fT)T  e
        ELSE
          SKIP
        FI;
        h := h  -e  -eT
     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 * fT))  (f  top * ?e * fT)T  ?e"
  let ?h = "h  -?e  -?eT"
  let ?F = "forest_components f"
  let ?n1 = "card { x . regular x  x  --h }"
  let ?n2 = "card { x . regular x  x  --h  x  -?e  x  -?eT }"
  assume 1: "kruskal_invariant f g h  h  bot"
  from 1 obtain w where 2: "minimum_spanning_forest w g  f  w  wT"
    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 "?eT * top * ?eT = ?eT"
        using 1 by (simp add: arc_top_arc minarc_arc)
      hence "?eT * top * ?eT  -?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  wT"
        proof
          let ?p = "w  top * ?e * wT"
          let ?v = "(w  -(top * ?e * wT))  ?pT"
          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 * wT)  g) + sum (?pT  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 * wT)  g) + sum (?p  g)"
              using 1 kruskal_invariant_def kruskal_spanning_invariant_def sum_symmetric by simp
            also have "... = sum (((w  -(top * ?e * wT))  ?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  ?vT = w  wT"
          proof -
            have "?v  ?vT = (w  -?p)  ?pT  (wT  -?pT)  ?p"
              using conv_complement conv_dist_inf conv_dist_sup inf_import_p sup_assoc by simp
            also have "... = w  wT"
              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 * ?eT = 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)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 * ?eT * ?vT  ?F * ?eT * 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  fT  (?v  -?d  -?dT)  (?vT  -?d  -?dT)"
            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  ?wT"
          proof (intro conjI)
            have 18: "?eT  ?v"
              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) * ?eT  ?v * ?eT"
                using inf_le1 mult_left_isotone by simp
              hence "(?v  -?d) * ?eT = bot"
                using 13 le_bot by simp
              hence 20: "?e * (?v  -?d)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)T * ?eT * 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)"
                using star.circ_increasing by simp
              also have "...  (--(g  -h))"
                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  fT  ?e"
              using conv_dist_inf inf_le1 sup_left_isotone sup_mono by presburger
            also have "...  (?v  -?d  -?dT)  (?vT  -?d  -?dT)  ?e"
              using 17 sup_left_isotone by simp
            also have "...  (?v  -?d)  (?vT  -?d  -?dT)  ?e"
              using inf.cobounded1 sup_inf_distrib2 by presburger
            also have "... = ?w  (?vT  -?d  -?dT)"
              by (simp add: sup_assoc sup_commute)
            also have "...  ?w  (?vT  -?dT)"
              using inf.sup_right_isotone inf_assoc sup_right_isotone by simp
            also have "...  ?w  ?wT"
              using conv_complement conv_dist_inf conv_dist_sup sup_right_isotone by simp
            finally show "?f  ?w  ?wT"
              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  wT"
    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  fT * f"
    using 29 spanning_forest_def inf.sup_right_isotone by simp
  also have "...  f  fT"
    apply (rule cancel_separate_6[where z=w and y="wT"])
    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  fT"
    by simp
  have "sum (f  g) = sum ((w  wT)  (f  g))"
    using 30 by (metis inf_absorb2 inf.assoc)
  also have "... = sum (w  (f  g)) + sum (wT  (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  (fT  gT))"
    by (metis conv_dist_inf conv_involutive sum_conv)
  also have "... = sum (f  (w  g)) + sum (fT  (w  g))"
    using 28 inf.commute inf.assoc kruskal_invariant_def kruskal_spanning_invariant_def by simp
  also have "... = sum ((f  fT)  (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