Imports
import Mathlib.Tactic

26.2–26.3. Parallel Recurrences

This module defines the Chapter 26 main-text work/span recurrence models for P-MATMUL, P-MERGE, and P-MERGE-SORT, together with their exact power-of-two solutions.

namespace CLRSnamespace Chapter27 private theorem pow_two_succ_eq (k : ) : 2 ^ (k + 1) / 2 = 2 ^ k := by rw [pow_succ] omega private theorem pow_two_succ_sub (k : ) : 2 ^ (k + 1) - 2 ^ (k + 1) / 2 = 2 ^ k := by rw [pow_succ] omegaprivate theorem log_two_pow (k : ) : Nat.log 2 (2 ^ k) = k := Nat.log_pow (by norm_num) k private theorem two_le_two_pow_succ (k : ) : 2 2 ^ (k + 1) := by rw [pow_succ] have := Nat.one_le_pow k 2 (by norm_num) omega private theorem two_pow_succ_mul (k : ) : 2 ^ (k + 1) * 2 ^ (k + 1) = 4 ^ (k + 1) := by have h42 : (4 : ) = 2 ^ 2 := by norm_num rw [h42, pow_mul, pow_add] congr 1 omega

§26.2: Parallel matrix multiplication (P-MATMUL)

Work recurrence for P-MATMUL: T₁(n) = 8 T₁(n/2) + n².

def pMatMulWork (n : ) : := if n 1 then n else 8 * pMatMulWork (n / 2) + n * n termination_by n decreasing_by exact Nat.div_lt_self (by omega) (by norm_num)
theorem pMatMulWork_unfold {n : } (hn : 2 n) : pMatMulWork n = 8 * pMatMulWork (n / 2) + n * n := by rw [pMatMulWork] simp [show ¬n 1 by omega]

Exact work on powers of two: T₁(2ᵏ) + 4ᵏ = 2·8ᵏ (work Θ(n³)).

theorem pMatMulWork_pow_two (k : ) : pMatMulWork (2 ^ k) + 4 ^ k = 2 * 8 ^ k := by induction k with | zero => native_decide | succ k ih => rw [pMatMulWork_unfold (two_le_two_pow_succ k), pow_two_succ_eq, two_pow_succ_mul] nlinarith [ih, pow_succ (4 : ) k, pow_succ (8 : ) k]

Span recurrence for P-MATMUL: T∞(n) = T∞(n/2) + 1.

def pMatMulSpan (n : ) : := if n 1 then n else pMatMulSpan (n / 2) + 1 termination_by n decreasing_by exact Nat.div_lt_self (by omega) (by norm_num)
theorem pMatMulSpan_unfold {n : } (hn : 2 n) : pMatMulSpan n = pMatMulSpan (n / 2) + 1 := by rw [pMatMulSpan] simp [show ¬n 1 by omega]

Exact span on powers of two: T∞(2ᵏ) = k + 1 (span Θ(log n)).

theorem pMatMulSpan_pow_two (k : ) : pMatMulSpan (2 ^ k) = k + 1 := by induction k with | zero => native_decide | succ k ih => rw [pMatMulSpan_unfold (two_le_two_pow_succ k), pow_two_succ_eq, ih]

§26.3: Parallel merge (P-MERGE)

Work recurrence for P-MERGE: two parallel recursive merges on the two halves plus a Θ(log n) binary-search combine, T₁(n) = T₁(⌊n/2⌋) + T₁(⌈n/2⌉) + (⌊log₂ n⌋ + 1).

def pMergeWork (n : ) : := if n 1 then n else pMergeWork (n / 2) + pMergeWork (n - n / 2) + (Nat.log 2 n + 1) termination_by n decreasing_by · exact Nat.div_lt_self (by omega) (by norm_num) · exact Nat.sub_lt (by omega) (Nat.div_pos (by omega) (by norm_num))
theorem pMergeWork_unfold {n : } (hn : 2 n) : pMergeWork n = pMergeWork (n / 2) + pMergeWork (n - n / 2) + (Nat.log 2 n + 1) := by rw [pMergeWork] simp [show ¬n 1 by omega]

Exact work on powers of two: T₁(2ᵏ) + (k + 3) = 4·2ᵏ (work Θ(n)).

theorem pMergeWork_pow_two (k : ) : pMergeWork (2 ^ k) + (k + 3) = 4 * 2 ^ k := by induction k with | zero => rw [pMergeWork] norm_num | succ k ih => rw [pMergeWork_unfold (two_le_two_pow_succ k), pow_two_succ_sub, pow_two_succ_eq, log_two_pow] nlinarith [ih, pow_succ (2 : ) k]

Span recurrence for P-MERGE: the critical path follows the larger half, T∞(n) = T∞(⌈n/2⌉) + (⌊log₂ n⌋ + 1).

def pMergeSpan (n : ) : := if n 1 then n else pMergeSpan (n - n / 2) + (Nat.log 2 n + 1) termination_by n decreasing_by exact Nat.sub_lt (by omega) (Nat.div_pos (by omega) (by norm_num))
theorem pMergeSpan_unfold {n : } (hn : 2 n) : pMergeSpan n = pMergeSpan (n - n / 2) + (Nat.log 2 n + 1) := by rw [pMergeSpan] simp [show ¬n 1 by omega]

Exact span on powers of two: 2·T∞(2ᵏ) = (k+1)(k+2) (span Θ(log² n)).

theorem pMergeSpan_pow_two (k : ) : 2 * pMergeSpan (2 ^ k) = (k + 1) * (k + 2) := by induction k with | zero => rw [pMergeSpan] norm_num | succ k ih => rw [pMergeSpan_unfold (two_le_two_pow_succ k), pow_two_succ_sub, log_two_pow] nlinarith [ih]

§26.3: Parallel merge sort (P-MERGE-SORT)

Work recurrence for P-MERGE-SORT: T₁(n) = T₁(⌊n/2⌋) + T₁(⌈n/2⌉) + n.

def pMergeSortWork (n : ) : := if n 1 then n else pMergeSortWork (n / 2) + pMergeSortWork (n - n / 2) + n termination_by n decreasing_by · exact Nat.div_lt_self (by omega) (by norm_num) · exact Nat.sub_lt (by omega) (Nat.div_pos (by omega) (by norm_num))
theorem pMergeSortWork_unfold {n : } (hn : 2 n) : pMergeSortWork n = pMergeSortWork (n / 2) + pMergeSortWork (n - n / 2) + n := by rw [pMergeSortWork] simp [show ¬n 1 by omega]

Exact work on powers of two: T₁(2ᵏ) = 2ᵏ·(k+1) (work Θ(n log n)).

theorem pMergeSortWork_pow_two (k : ) : pMergeSortWork (2 ^ k) = 2 ^ k * (k + 1) := by induction k with | zero => rw [pMergeSortWork] norm_num | succ k ih => rw [pMergeSortWork_unfold (two_le_two_pow_succ k), pow_two_succ_sub, pow_two_succ_eq] nlinarith [ih, pow_succ (2 : ) k]

Span recurrence for P-MERGE-SORT: T∞(n) = T∞(⌈n/2⌉) + (P-MERGE span on n elements).

def pMergeSortSpan (n : ) : := if n 1 then n else pMergeSortSpan (n - n / 2) + pMergeSpan n termination_by n decreasing_by exact Nat.sub_lt (by omega) (Nat.div_pos (by omega) (by norm_num))
theorem pMergeSortSpan_unfold {n : } (hn : 2 n) : pMergeSortSpan n = pMergeSortSpan (n - n / 2) + pMergeSpan n := by rw [pMergeSortSpan] simp [show ¬n 1 by omega]

Exact span on powers of two: 6·T∞(2ᵏ) = 6 + k·(k² + 6k + 11) (span Θ(log³ n)).

theorem pMergeSortSpan_pow_two (k : ) : 6 * pMergeSortSpan (2 ^ k) = 6 + k * (k * k + 6 * k + 11) := by induction k with | zero => rw [pMergeSortSpan] norm_num | succ k ih => rw [pMergeSortSpan_unfold (two_le_two_pow_succ k), pow_two_succ_sub] have hS := pMergeSpan_pow_two (k + 1) nlinarith [ih, hS]
end Chapter27end CLRS