Imports
BFS-selected unit-capacity augmentation
This module defines the flow iteration used by the executable §25.1 algorithm. Unlike the abstract existence-level loop, an active step augments along the shortest path reconstructed by the executable residual BFS.
namespace CLRSnamespace Matchingsopen Finset Classicalopen Chapter26variable {V : Type*} [Fintype V] [DecidableEq V]One BFS-selected augmentation step in the bipartite flow network.
noncomputable def bfsFlowStep (G : BipartiteGraph V)
(φ : Flow (V ⊕ Bool) (toFlowNetwork V G)) :
Flow (V ⊕ Bool) (toFlowNetwork V G) :=
if h : φ.hasAugmentingPath then
φ.augment (bfs_shortestAugmenting φ h).path
else φtheorem bfsFlowStep_of_hasAugmentingPath (G : BipartiteGraph V)
(φ : Flow (V ⊕ Bool) (toFlowNetwork V G)) (h : φ.hasAugmentingPath) :
bfsFlowStep G φ = φ.augment (bfs_shortestAugmenting φ h).path := by
simp [bfsFlowStep, h]theorem bfsFlowStep_of_noAugmentingPath (G : BipartiteGraph V)
(φ : Flow (V ⊕ Bool) (toFlowNetwork V G)) (h : ¬ φ.hasAugmentingPath) :
bfsFlowStep G φ = φ := by
simp [bfsFlowStep, h]The BFS step preserves integrality on the unit-capacity network.
theorem bfsFlowStep_integral (G : BipartiteGraph V)
(φ : Flow (V ⊕ Bool) (toFlowNetwork V G)) (hint : φ.IsIntegral) :
(bfsFlowStep G φ).IsIntegral := by
by_cases h : φ.hasAugmentingPath
· rw [bfsFlowStep_of_hasAugmentingPath G φ h]
exact IsIntegral_augment φ hint toFlowNetwork_integral_capacity _
· rw [bfsFlowStep_of_noAugmentingPath G φ h]
exact hintAn active BFS step increases the integral flow value by at least one.
theorem bfsFlowStep_value_ge_one (G : BipartiteGraph V)
(φ : Flow (V ⊕ Bool) (toFlowNetwork V G)) (hint : φ.IsIntegral)
(h : φ.hasAugmentingPath) :
φ.value + 1 ≤ (bfsFlowStep G φ).value := by
rw [bfsFlowStep_of_hasAugmentingPath G φ h]
exact augment_value_ge_one φ hint toFlowNetwork_integral_capacity _Iterate the BFS step from an arbitrary starting flow.
noncomputable def bfsFlowIterFrom (G : BipartiteGraph V)
(φ : Flow (V ⊕ Bool) (toFlowNetwork V G)) : ℕ →
Flow (V ⊕ Bool) (toFlowNetwork V G)
| 0 => φ
| n + 1 => bfsFlowStep G (bfsFlowIterFrom G φ n)The §25.1 flow iteration starts from the zero flow.
noncomputable def bfsFlowIter (G : BipartiteGraph V) (n : ℕ) :
Flow (V ⊕ Bool) (toFlowNetwork V G) :=
bfsFlowIterFrom G (zeroFlow (toFlowNetwork V G)) n@[simp]
theorem bfsFlowIterFrom_zero (G : BipartiteGraph V)
(φ : Flow (V ⊕ Bool) (toFlowNetwork V G)) :
bfsFlowIterFrom G φ 0 = φ := rfl@[simp]
theorem bfsFlowIterFrom_succ (G : BipartiteGraph V)
(φ : Flow (V ⊕ Bool) (toFlowNetwork V G)) (n : ℕ) :
bfsFlowIterFrom G φ (n + 1) = bfsFlowStep G (bfsFlowIterFrom G φ n) := rflIteration composes over addition of step counts.
theorem bfsFlowIterFrom_add (G : BipartiteGraph V)
(φ : Flow (V ⊕ Bool) (toFlowNetwork V G)) (m n : ℕ) :
bfsFlowIterFrom G φ (m + n) =
bfsFlowIterFrom G (bfsFlowIterFrom G φ m) n := by
induction n with
| zero => simp
| succ n ih =>
rw [Nat.add_succ, bfsFlowIterFrom_succ, bfsFlowIterFrom_succ, ih]Once no augmenting path exists, every later iterate is the same flow.
theorem bfsFlowIterFrom_eq_of_noAugmentingPath (G : BipartiteGraph V)
(φ : Flow (V ⊕ Bool) (toFlowNetwork V G))
(h : ¬ φ.hasAugmentingPath) :
∀ n, bfsFlowIterFrom G φ n = φ := by
intro n
induction n with
| zero => rfl
| succ n ih =>
rw [bfsFlowIterFrom_succ, ih, bfsFlowStep_of_noAugmentingPath G φ h]A later augmenting path implies that all earlier iterates also had one.
theorem bfsFlowIter_hasAugmentingPath_of_le (G : BipartiteGraph V)
{i j : ℕ} (hij : i ≤ j)
(hj : (bfsFlowIter G j).hasAugmentingPath) :
(bfsFlowIter G i).hasAugmentingPath := by
by_contra hi
have hji : j = i + (j - i) := by omega
have hstable := bfsFlowIterFrom_eq_of_noAugmentingPath G (bfsFlowIter G i) hi (j - i)
have heq : bfsFlowIter G j = bfsFlowIter G i := by
unfold bfsFlowIter
rw [hji, bfsFlowIterFrom_add]
change bfsFlowIterFrom G (bfsFlowIter G i) (j - i) = bfsFlowIter G i
exact hstable
rw [heq] at hj
exact hi hjEvery iterate from the zero flow is integral.
theorem bfsFlowIter_integral (G : BipartiteGraph V) :
∀ n, (bfsFlowIter G n).IsIntegral := by
intro n
induction n with
| zero =>
exact IsIntegral_zero
| succ n ih =>
simpa [bfsFlowIter, bfsFlowIterFrom] using bfsFlowStep_integral G _ ih
The source cut of the constructed network has capacity exactly |L|.
theorem matchingNetwork_sourceCut (G : BipartiteGraph V) :
∑ v : V ⊕ Bool,
(toFlowNetwork V G).c (toFlowNetwork V G).s v = (G.L.card : ℝ) := by
simp [toFlowNetwork, capFunc]Every iterate is bounded by the source cut.
theorem bfsFlowIter_value_le_left_card (G : BipartiteGraph V) (n : ℕ) :
(bfsFlowIter G n).value ≤ (G.L.card : ℝ) := by
rw [← matchingNetwork_sourceCut G]
exact value_le_source_cut (bfsFlowIter G n)
If the first n iterates all admit augmentation, the nth flow has
value at least n.
theorem bfsFlowIter_value_ge_of_prefix (G : BipartiteGraph V) (n : ℕ)
(hsteps : ∀ i < n, (bfsFlowIter G i).hasAugmentingPath) :
(n : ℝ) ≤ (bfsFlowIter G n).value := by
induction n with
| zero => simp [bfsFlowIter, bfsFlowIterFrom, zeroFlow, Flow.value]
| succ n ih =>
have hn : (bfsFlowIter G n).hasAugmentingPath := hsteps n (by omega)
have hprefix : ∀ i < n, (bfsFlowIter G i).hasAugmentingPath :=
fun i hi => hsteps i (by omega)
have hge := ih hprefix
have hinc := bfsFlowStep_value_ge_one G (bfsFlowIter G n)
(bfsFlowIter_integral G n) hn
have hnext : bfsFlowIter G (n + 1) = bfsFlowStep G (bfsFlowIter G n) := rfl
rw [hnext]
push_cast
linarithend Matchingsend CLRS