Theory MFMC_Countable.MFMC_Finite
theory MFMC_Finite imports
  EdmondsKarp_Maxflow.EdmondsKarp_Termination_Abstract
  "HOL-Library.While_Combinator"
begin
section ‹Existence of maximum flows and minimal cuts in finite graphs›
text ‹This theory derives the existencs of a maximal flow or a minimal cut for finite graphs
from the termination proof of the Edmonds-Karp algorithm.›
context Graph begin
lemma outgoing_outside: "x ∉ V ⟹ outgoing x = {}"
  by(auto simp add: outgoing_def V_def)
lemma incoming_outside: "x ∉ V ⟹ incoming x = {}"
  by(auto simp add: incoming_def V_def)
end
context NFlow begin
lemma conservation: "⟦ x ≠ s; x ≠ t ⟧ ⟹ sum f (incoming x) = sum f (outgoing x)"
  by(cases "x ∈ V")(auto simp add: conservation_const outgoing_outside incoming_outside)
lemma augmenting_path_imp_shortest: 
  "isAugmentingPath p ⟹ ∃p. Graph.isShortestPath cf s p t"
  using Graph.obtain_shortest_path unfolding isAugmentingPath_def
  by (fastforce simp: Graph.isSimplePath_def Graph.connected_def)
lemma shortest_is_augmenting: 
  "Graph.isShortestPath cf s p t ⟹ isAugmentingPath p"
  unfolding isAugmentingPath_def using Graph.shortestPath_is_simple
  by (fastforce)
definition "augment_with_path p ≡ augment (augmentingFlow p)"
end
context Network begin
definition "shortest_augmenting_path f = (SOME p. Graph.isShortestPath (residualGraph c f) s p t)"
lemma shortest_augmenting_path:
  assumes "NFlow c s t f" 
  and "∃p. NPreflow.isAugmentingPath c s t f p"
  shows "Graph.isShortestPath (residualGraph c f) s (shortest_augmenting_path f) t"
  using assms unfolding shortest_augmenting_path_def
  by clarify(rule someI_ex, rule NFlow.augmenting_path_imp_shortest)
definition max_flow where
  "max_flow = while
     (λf. ∃p. NPreflow.isAugmentingPath c s t f p)
     (λf. NFlow.augment_with_path c f (shortest_augmenting_path f)) (λ_. 0)"
lemma max_flow:
  "NFlow c s t max_flow" (is ?thesis1)
  "¬ (∃p. NPreflow.isAugmentingPath c s t max_flow p)" (is ?thesis2)
proof -
  have "NFlow c s t (λ_. 0)"
    by unfold_locales(simp_all add: cap_non_negative)
  moreover have "NFlow c s t (NFlow.augment_with_path c f (shortest_augmenting_path f))"
    if "NFlow c s t f" and "∃p. NPreflow.isAugmentingPath c s t f p" for f
  proof -
    interpret NFlow c s t f using that(1) .
    interpret F: Flow c s t "NFlow.augment c f (NPreflow.augmentingFlow c f (shortest_augmenting_path f))"
      by(intro augment_flow_presv augFlow_resFlow shortest_is_augmenting shortest_augmenting_path[OF that])
    show ?thesis using that
      by(simp add: NFlow.augment_with_path_def)(unfold_locales)
  qed
  ultimately have "NFlow c s t max_flow ∧ ¬ (∃p. NPreflow.isAugmentingPath c s t max_flow p)"
    unfolding max_flow_def
    by(rule while_rule[where P="NFlow c s t" and r="measure (λf. ek_analysis_defs.ekMeasure (residualGraph c f) s t)"])
      (auto intro: shortest_augmenting_path NFlow.shortest_path_decr_ek_measure simp add: NFlow.augment_with_path_def)
  thus ?thesis1 ?thesis2 by simp_all
qed
end
end