Imports
Stored matrix-chain costs and splits
The endpoint N denotes matrices indexed 0 through N, hence N+1 matrices.
Layer l stores intervals [i,i+l]; only shorter layers are read. Every split
candidate is evaluated once, and its minimizing index is stored with its cost.
The old recursive optimum is used only in proofs.
namespace CLRS.Chapter15.MatrixChainExecutionopen DPExecutionstructure Cell where
cost : Nat
split : Nat
deriving Inhabited, Repr, DecidableEqdef candidate (dims : Nat → Nat) (rows : Array (Array Cell))
(i l k : Nat) : Nat :=
(get rows (k-i) i).cost + (get rows (i+l-(k+1)) (k+1)).cost +
dims i * dims (k+1) * dims (i+l+1)def step (dims : Nat → Nat) : Nat → Array (Array Cell) → Nat → Cell × Nat
| 0, _, i => (⟨0, i⟩, 0)
| l+1, rows, i =>
let best := minimum (candidate dims rows i (l+1)) i l
(⟨best.value, best.index⟩, best.visits)Compute and retain all intervals 0≤i≤j≤N.
def execute (dims : Nat → Nat) (N : Nat) : Table Cell :=
buildLayers (fun l => N+1-l) (step dims) (N+1)The stored split is in range and attains the independently defined optimum.
def CorrectCell (dims : Nat → Nat) (l i : Nat) (cell : Cell) : Prop :=
cell.cost = matrixChainOpt dims i (i+l) ∧
(0 < l → i ≤ cell.split ∧ cell.split < i+l ∧
cell.cost = matrixSplitCost dims (matrixChainOpt dims) i (i+l) cell.split)
private theorem candidate_correct (dims : Nat → Nat) (N l i : Nat)
(rows : Array (Array Cell))
(hprev : ∀ k, k < l → ∀ i, i < N+1-k → CorrectCell dims k i (get rows k i))
(hi : i < N+1-l) (k : Nat) (hk : i ≤ k) (hk' : k < i+l) :
candidate dims rows i l k = matrixSplitCost dims (matrixChainOpt dims) i (i+l) k := by
have hleft := (hprev (k-i) (by omega) i (by omega)).1
have hright := (hprev (i+l-(k+1)) (by omega) (k+1) (by omega)).1
have he : i + (k-i) = k := by omega
have he' : k+1+(i+l-(k+1)) = i+l := by omega
rw [he] at hleft
rw [he'] at hright
simp only [candidate, matrixSplitCost, hleft, hright]
private theorem step_correct (dims : Nat → Nat) (N l : Nat)
(rows : Array (Array Cell))
(hprev : ∀ k, k < l → ∀ i, i < N+1-k → CorrectCell dims k i (get rows k i))
(i : Nat) (hi : i < N+1-l) : CorrectCell dims l i (step dims l rows i).1 := by
cases l with
| zero =>
simp [CorrectCell, step, matrixChainOpt]
| succ l =>
have hc := candidate_correct dims N (l+1) i rows hprev hi
let f := candidate dims rows i (l+1)
have hbest : (minimum f i l).value = matrixChainOpt dims i (i+(l+1)) := by
apply minimum_value_eq
· intro k hk hk'
dsimp only [f]
rw [hc k hk (by omega)]
exact (matrixChainOpt_lowerBound dims).2 (by simp [Finset.mem_Icc]; omega)
· obtain ⟨hk, heq⟩ := matrixChainSplit_optimal dims i (i+(l+1)) (by omega)
have hb := Finset.mem_Icc.mp hk
refine ⟨matrixChainSplit dims i (i+(l+1)), hb.1, by omega, ?_⟩
exact (hc _ hb.1 (by omega)).trans heq.symm
obtain ⟨hlo, hhi, heq, _⟩ := minimum_spec f i l
change (minimum f i l).value = _ ∧
(0 < l+1 → i ≤ (minimum f i l).index ∧ (minimum f i l).index < i+(l+1) ∧
(minimum f i l).value = _)
refine ⟨hbest, fun _ => ⟨hlo, by omega, ?_⟩⟩
exact heq.trans (hc _ hlo (by omega))Every stored entry is the optimum, with a valid tight stored split.
theorem execute_get_correct (dims : Nat → Nat) (N l i : Nat)
(hl : l ≤ N) (hi : i+l ≤ N) :
CorrectCell dims l i (get (execute dims N).rows l i) := by
apply buildLayers_property (fun l => N+1-l) (step dims) (CorrectCell dims)
(fun l rows _ hp i hi => step_correct dims N l rows hp i hi) (N+1) l (by omega) i
(by omega)
A direct cost-table refinement for interval [i,j].
theorem execute_cost (dims : Nat → Nat) (N i j : Nat) (hij : i ≤ j) (hj : j ≤ N) :
(get (execute dims N).rows (j-i) i).cost = matrixChainOpt dims i j := by
have h := (execute_get_correct dims N (j-i) i (by omega) (by omega)).1
simpa [Nat.add_sub_of_le hij] using h@[simp] theorem step_visits (dims : Nat → Nat) (l : Nat) (rows : Array (Array Cell)) (i : Nat) :
(step dims l rows i).2 = l := by cases l <;> simp [step]Each interval cell is written once by the actual layered execution.
theorem execute_cells (dims : Nat → Nat) (N : Nat) :
(execute dims N).cellWrites = ∑ l ∈ Finset.range (N+1), (N+1-l) :=
buildLayers_cellWrites _ _ _Candidate visits come from the returned minimum-scan counters.
theorem execute_candidateVisits (dims : Nat → Nat) (N : Nat) :
(execute dims N).candidateVisits = ∑ l ∈ Finset.range (N+1), (N+1-l)*l :=
buildLayers_candidateVisits _ id _ (step_visits dims) _A finite stored table has the certified cost/split contract on its domain.
def CorrectTable (dims : Nat → Nat) (N : Nat) (rows : Array (Array Cell)) : Prop :=
∀ l i, l ≤ N → i+l ≤ N → CorrectCell dims l i (get rows l i)
private theorem stored_split {dims : Nat → Nat} {N : Nat} {rows : Array (Array Cell)}
(h : CorrectTable dims N rows) (i j : Nat) (hij : i < j) (hj : j ≤ N) :
i ≤ (get rows (j-i) i).split ∧ (get rows (j-i) i).split < j ∧
matrixChainOpt dims i j =
matrixSplitCost dims (matrixChainOpt dims) i j (get rows (j-i) i).split := by
have hc := h (j-i) i (by omega) (by omega)
have hs := hc.2 (by omega)
have he : i+(j-i) = j := by omega
dsimp only [CorrectCell] at hc
rw [he] at hc hs
exact ⟨hs.1, hs.2.1, hc.1.symm.trans hs.2.2⟩Reconstruct using stored indices only. The finite-domain proof is erased; no recursive optimum or legacy split selector is evaluated here.
def reconstruct (dims : Nat → Nat) (N : Nat) (rows : Array (Array Cell))
(h : CorrectTable dims N rows) (i j : Nat) (hij : i ≤ j) (hj : j ≤ N) : ChainPlan i j :=
if ht : i < j then
let k := (get rows (j-i) i).split
have hs := stored_split h i j ht hj
ChainPlan.split i k j
(reconstruct dims N rows h i k hs.1 (by omega))
(reconstruct dims N rows h (k+1) j (by omega) hj)
else
have he : i = j := by omega
he ▸ ChainPlan.single i
termination_by j-i
decreasing_by
all_goals
have _hs := stored_split h i j ht hj
try dsimp only [k] at *
omegaThe plan follows the stored split in every subinterval.
theorem reconstruct_reconstructed (dims : Nat → Nat) (N : Nat) (rows : Array (Array Cell))
(h : CorrectTable dims N rows) (i j : Nat) (hij : i ≤ j) (hj : j ≤ N) :
ChainPlan.ReconstructedBy (fun i j => (get rows (j-i) i).split)
(reconstruct dims N rows h i j hij hj) := by
rw [reconstruct]
split
next ht =>
have hs := stored_split h i j ht hj
exact ChainPlan.ReconstructedBy.split i _ j rfl
(reconstruct_reconstructed dims N rows h i _ hs.1 (by omega))
(reconstruct_reconstructed dims N rows h _ j (by omega) hj)
next ht =>
have he : i = j := by omega
subst j
exact ChainPlan.ReconstructedBy.single i
termination_by j-i
decreasing_by
all_goals
omegaStored-table reconstruction attains the independent optimum.
theorem reconstruct_cost (dims : Nat → Nat) (N : Nat) (rows : Array (Array Cell))
(h : CorrectTable dims N rows) (i j : Nat) (hij : i ≤ j) (hj : j ≤ N) :
ChainPlan.cost dims (reconstruct dims N rows h i j hij hj) = matrixChainOpt dims i j := by
rw [reconstruct]
split
next ht =>
have hs := stored_split h i j ht hj
rw [ChainPlan.cost, reconstruct_cost dims N rows h i _ hs.1 (by omega),
reconstruct_cost dims N rows h _ j (by omega) hj]
exact hs.2.2.symm
next ht =>
have he : i = j := by omega
subst j
simp [ChainPlan.cost, matrixChainOpt]
termination_by j-i
decreasing_by
all_goals
omegaBuild a table once and reconstruct the complete chain from that same table.
def executePlan (dims : Nat → Nat) (N : Nat) : ChainPlan 0 N × Table Cell :=
let table := execute dims N
(reconstruct dims N table.rows (fun l i hl hi => execute_get_correct dims N l i hl hi)
0 N (Nat.zero_le _) le_rfl, table)
theorem executePlan_correct (dims : Nat → Nat) (N : Nat) :
MatrixChainOptimalPlan dims (executePlan dims N).1 := by
intro other
have he := reconstruct_cost dims N (execute dims N).rows
(fun l i hl hi => execute_get_correct dims N l i hl hi) 0 N (Nat.zero_le _) le_rfl
change ChainPlan.cost dims (reconstruct dims N (execute dims N).rows _ 0 N _ _) ≤ _
rw [he]
exact matrixChain_opt_le_planCost (matrixChainOpt_lowerBound dims) otherEvery actual interval-evaluation event is unique.
theorem execute_once (dims : Nat → Nat) (N : Nat) :
(execute dims N).evaluatedStates.Nodup :=
buildLayers_evaluatedStates_nodup _ _ _The actual evaluation trace covers exactly the valid interval states.
theorem execute_state_iff (dims : Nat → Nat) (N l i : Nat) :
(l,i) ∈ (execute dims N).evaluatedStates ↔ i+l ≤ N := by
rw [execute, buildLayers_evaluatedStates_mem]
omegaQuadratic storage from actual interval writes.
theorem execute_cells_le (dims : Nat → Nat) (N : Nat) :
(execute dims N).cellWrites ≤ (N+1)^2 := by
rw [execute_cells]
exact interval_cells_le_square NCubic bound on the actual candidate-scan counter.
theorem execute_candidateVisits_le (dims : Nat → Nat) (N : Nat) :
(execute dims N).candidateVisits ≤ (N+1)^3 := by
rw [execute_candidateVisits]
exact interval_visits_le_cube NThe reconstructed plan's cost equals the optimum in the same returned table.
theorem executePlan_cost (dims : Nat → Nat) (N : Nat) :
ChainPlan.cost dims (executePlan dims N).1 =
(get (executePlan dims N).2.rows N 0).cost := by
dsimp only [executePlan]
rw [reconstruct_cost]
simpa using (execute_cost dims N 0 N (Nat.zero_le _) le_rfl).symmExact quadratic count of stored interval cells.
theorem execute_cells_closed (dims : Nat → Nat) (N : Nat) :
2 * (execute dims N).cellWrites = (N+1)*(N+2) := by
rw [execute_cells]
exact interval_cells_closed NExact cubic count of executed candidates.
theorem execute_candidateVisits_closed (dims : Nat → Nat) (N : Nat) :
6 * (execute dims N).candidateVisits = N*(N+1)*(N+2) := by
rw [execute_candidateVisits]
exact interval_visits_closed NTwo-sided quadratic storage bounds, including the diagonal boundary.
theorem execute_cells_bounds (dims : Nat → Nat) (N : Nat) :
(N+1)^2 ≤ 2 * (execute dims N).cellWrites ∧
(execute dims N).cellWrites ≤ (N+1)^2 := by
refine ⟨?_, execute_cells_le dims N⟩
rw [execute_cells_closed]
nlinarithTwo-sided cubic candidate bounds.
theorem execute_candidateVisits_bounds (dims : Nat → Nat) (N : Nat) :
N^3 ≤ 6 * (execute dims N).candidateVisits ∧
(execute dims N).candidateVisits ≤ (N+1)^3 := by
refine ⟨?_, execute_candidateVisits_le dims N⟩
rw [execute_candidateVisits_closed]
nlinarith [sq_nonneg (N : ℤ)]end CLRS.Chapter15.MatrixChainExecution