Imports

CLRS Section 7.3 - Randomized quicksort

This section defines the expected-comparison recurrence for randomized quicksort (CLRS equation (7.4)) and proves its closed-form solution, giving the O(n log n) average-case bound for the first time in CLRS-Lean.

The expected number of comparisons expectedComparisons n = E[T(n)] satisfies:

  • T(0) = 0, T(1) = 0

  • For n >= 1: T(n) = n-1 + (2/n) * sum_{k=0}^{n-1} T(k)

The closed form is T(n) = 2(n+1)H_n - 4n where H_n is the n-th harmonic number. This yields T(n) <= 2n H_n and T(n) <= n^2 (quadratic fallback).

Main results:

  • Lemma harmonic_succ: recurrence for harmonic numbers

  • Lemma harmonic_le_n: H_n <= n

  • Lemma sum_mul_harmonic_eq: sum_{k=1}^{n} k H_k = n(n+1)/2 H_n - n(n-1)/4

  • Lemma sum_expectedComparisons_eq: closed form of sum_{k=0}^{n-1} T(k)

  • Theorem expectedComparisons_closed_form: named CLRS closed-form formula

  • Theorem expectedComparisons_recurrence: closed form satisfies CLRS (7.4)

  • Theorem expectedComparisons_telescope: (n+1)T(n+1) = (n+2)T(n) + 2n

  • Theorem expectedComparisons_clrs_harmonic_bound: T(n) <= 2(n+1)H_n

  • Theorem expectedComparisons_harmonic_bound: T(n) <= 2n H_n

  • Theorem expectedComparisons_quadratic: T(n) <= n^2

  • Theorem expectedComparisons_monotone: T(n) <= T(n+1)

Implementation details

The detailed probability proof remains available outside the main sidebar:

Notation conventions:

  • harmonic n : H_n, the n-th harmonic number in Q

  • expectedComparisons n : T(n), expected number of comparisons for randomized quicksort on n distinct elements

namespace CLRSnamespace Chapter07open Chapter07

Harmonic numbers

The n-th harmonic number as a rational. H_0 = 0, H_{n+1} = H_n + 1/(n+1).

def harmonic : Nat Rat | 0 => 0 | n+1 => harmonic n + 1 / ((n+1 : Nat) : Rat)
@[simp] theorem harmonic_zero : harmonic 0 = 0 := rfl@[simp] theorem harmonic_one : harmonic 1 = 1 := by simp [harmonic]

Recurrence for harmonic numbers: H_{n+1} = H_n + 1/(n+1).

theorem harmonic_succ (n : Nat) : harmonic (n+1) = harmonic n + (1 : Rat) / ((n+1 : Nat) : Rat) := rfl

Harmonic numbers are nonnegative.

theorem harmonic_nonneg (n : Nat) : 0 harmonic n := by induction n with | zero => simp | succ n ih => rw [harmonic_succ] have hpos : 0 (1 : Rat) / ((n+1 : Nat) : Rat) := by positivity nlinarith

The harmonic number is bounded by its index: H_n <= n for all n.

This trivial bound is enough for many estimates.

theorem harmonic_le_n (n : Nat) : harmonic n (n : Rat) := by induction n with | zero => simp | succ n ih => rw [harmonic_succ] push_cast have hdiv : (1 : Rat) / ((n : Rat) + 1) 1 := (div_le_one (by positivity)).mpr (by nlinarith) nlinarith

Expected comparisons: closed form

Expected number of comparisons in randomized quicksort on n distinct elements, given by the closed-form solution of CLRS recurrence (7.4):

T(n) = 2(n+1)H_n - 4n

where H_n is the n-th harmonic number. This is a computable deterministic rational function; the expectation is folded into the recurrence coefficients, not into a probability space.

def expectedComparisons (n : Nat) : Rat := 2 * ((n : Rat) + 1) * harmonic n - 4 * (n : Rat)

Named CLRS closed form for randomized-quicksort expected comparisons.

theorem expectedComparisons_closed_form (n : Nat) : expectedComparisons n = 2 * ((n : Rat) + 1) * harmonic n - 4 * (n : Rat) := rfl
@[simp] theorem expectedComparisons_zero : expectedComparisons 0 = 0 := by simp [expectedComparisons, harmonic]@[simp] theorem expectedComparisons_one : expectedComparisons 1 = 0 := by simp [expectedComparisons, harmonic] ring

Explicit formula for expectedComparisons (n+1) in terms of harmonic (n+1).

theorem expectedComparisons_succ (n : Nat) : expectedComparisons (n+1) = 2 * ((n+1 : Rat) + 1) * harmonic (n+1) - 4 * ((n+1 : Rat)) := by simp [expectedComparisons]

Key combinatorial identity - sum of k times harmonic k

Central combinatorial identity for the expected-quicksort closed form:

sum_{k=1}^{n} k * H_k = (n(n+1)/2) * H_n - n(n-1)/4

This is proved by induction on n using the harmonic recurrence to express H_n in terms of H_{n+1} in the inductive step.

theorem sum_mul_harmonic_eq (n : Nat) : ( k Finset.Icc 1 n, ((k : Rat) * harmonic k)) = (((n : Rat) * ((n : Rat) + 1)) / 2) * harmonic n - ((n : Rat) * ((n : Rat) - 1) / 4) := by induction n with | zero => simp [harmonic] | succ n ih => rw [Finset.sum_Icc_succ_top (by omega) (fun k => (k : Rat) * harmonic k)] rw [ih] -- Now: (n(n+1)/2)*H_n - n(n-1)/4 + (n+1)*H_{n+1} = ((n+1)(n+2)/2)*H_{n+1} - (n+1)n/4 -- Use H_n = H_{n+1} - 1/(n+1) have hH_n : harmonic n = harmonic (n+1) - (1 : Rat) / ((n+1 : Nat) : Rat) := by rw [harmonic_succ] ring rw [hH_n] push_cast ring_nf have hpos : ((n : Nat) : Rat) + 1 0 := by intro hzero have hsum : ((n+1 : Nat) : Rat) = 0 := by push_cast; simpa using hzero exact Nat.succ_ne_zero n (by exact_mod_cast hsum) field_simp [hpos] ring

Sum of expected comparisons

Closed form for the sum of expected comparisons up to n-1:

sum_{k=0}^{n-1} T(k) = n(n+1)*H_n - (5 n^2 - n)/2

theorem sum_expectedComparisons_eq (n : Nat) : ( k Finset.range n, expectedComparisons k) = ((n : Rat) * ((n : Rat) + 1)) * harmonic n - ((5 : Rat) * (n : Rat) * (n : Rat) - (n : Rat)) / 2 := by induction n with | zero => simp | succ n ih => rw [Finset.sum_range_succ, expectedComparisons, ih] have hH_succ : harmonic (n+1) = harmonic n + (1 : Rat) / ((n+1 : Nat) : Rat) := harmonic_succ n rw [hH_succ] push_cast ring_nf have hpos : ((n : Nat) : Rat) + 1 0 := by intro hzero have hsum : ((n+1 : Nat) : Rat) = 0 := by push_cast; simpa using hzero exact Nat.succ_ne_zero n (by exact_mod_cast hsum) field_simp [hpos] ring

Recurrence verification

The closed-form expectedComparisons satisfies the CLRS expected-comparison recurrence (7.4): for n >= 1,

T(n) = n-1 + (2/n) * sum_{k=0}^{n-1} T(k).

The proof multiplies through by n and uses the closed form of the sum.

theorem expectedComparisons_recurrence (n : Nat) (hn : n 1) : expectedComparisons n = ((n : Rat) - 1) + (2 / (n : Rat)) * ( k Finset.range n, expectedComparisons k) := by have hnpos : (n : Rat) 0 := by intro hzero have : n = 0 := by exact_mod_cast hzero omega -- Clear denominator by multiplying both sides by n field_simp [hnpos] -- Goal: n * T(n) = n * (n-1) + 2 * S(n) rw [sum_expectedComparisons_eq n] rw [expectedComparisons] ring

Alternative form of the recurrence, clearing denominators:

(n+1) * T(n+1) = (n+2) * T(n) + 2n for all n >= 0.

This telescoping identity is the key to the closed form and is used in the inductive proofs below.

theorem expectedComparisons_telescope (n : Nat) : ((n+1 : Nat) : Rat) * expectedComparisons (n+1) = (((n : Rat) + 2)) * expectedComparisons n + 2 * (n : Rat) := by rw [expectedComparisons, expectedComparisons] have hH_succ : harmonic (n+1) = harmonic n + (1 : Rat) / ((n+1 : Nat) : Rat) := harmonic_succ n rw [hH_succ] push_cast ring_nf have hpos : ((n : Nat) : Rat) + 1 0 := by intro hzero have hsum : ((n+1 : Nat) : Rat) = 0 := by push_cast; simpa using hzero exact Nat.succ_ne_zero n (by exact_mod_cast hsum) field_simp [hpos] ring

Expected comparisons: nonnegativity

Expected comparisons are nonnegative.

theorem expectedComparisons_nonneg (n : Nat) : 0 expectedComparisons n := by induction n with | zero => simp | succ n ih => have ht := expectedComparisons_telescope n -- ht: (n+1)*T(n+1) = (n+2)*T(n) + 2n -- RHS >= 0 since T(n) >= 0 and n >= 0, and (n+1) > 0 so T(n+1) >= 0 have hpos_denom : ((n+1 : Nat) : Rat) 0 := Nat.cast_ne_zero.mpr (Nat.succ_ne_zero n) have hnum_nonneg : 0 (((n : Rat) + 2)) * expectedComparisons n + 2 * (n : Rat) := by nlinarith -- From ht: T(n+1) = numerator / (n+1) have hT_expr : expectedComparisons (n+1) = ((((n : Rat) + 2)) * expectedComparisons n + 2 * (n : Rat)) / ((n+1 : Nat) : Rat) := (eq_div_iff_mul_eq hpos_denom).mpr (by -- Need: T(n+1) * (n+1) = numerator -- ht gives: (n+1) * T(n+1) = numerator simpa [mul_comm] using ht) rw [hT_expr] refine div_nonneg hnum_nonneg (by positivity)

Bounds

Harmonic upper bound. The expected number of comparisons in randomized quicksort is at most 2 n * H_n.

Since H_n = Theta(log n), this gives T(n) = O(n log n).

theorem expectedComparisons_harmonic_bound (n : Nat) : expectedComparisons n 2 * (n : Rat) * harmonic n := by have hle : harmonic n (n : Rat) := harmonic_le_n n rw [expectedComparisons] nlinarith

CLRS-facing harmonic upper bound using the closed-form scale 2(n+1)H_n.

theorem expectedComparisons_clrs_harmonic_bound (n : Nat) : expectedComparisons n 2 * ((n : Rat) + 1) * harmonic n := by rw [expectedComparisons_closed_form] have hn : 0 (4 : Rat) * (n : Rat) := by positivity nlinarith

Quadratic upper bound. On any input of length n, the expected number of comparisons is at most n^2.

The proof uses induction with the telescope identity: T(n+1) = ((n+2)T(n) + 2n)/(n+1). The inductive hypothesis T(n) <= n^2 and a simple polynomial inequality n^2 + n + 1 >= 0 close the step.

theorem expectedComparisons_quadratic (n : Nat) : expectedComparisons n (n : Rat) * (n : Rat) := by induction n with | zero => simp | succ n ih => have ht := expectedComparisons_telescope n -- ht: (n+1)*T(n+1) = (n+2)*T(n) + 2n have hpos : ((n+1 : Nat) : Rat) 0 := Nat.cast_ne_zero.mpr (Nat.succ_ne_zero n) -- From ht: T(n+1) = ((n+2)*T(n) + 2n) / (n+1) have hT_succ : expectedComparisons (n+1) = ((((n : Rat) + 2)) * expectedComparisons n + 2 * (n : Rat)) / ((n+1 : Nat) : Rat) := (eq_div_iff_mul_eq hpos).mpr (by simpa [mul_comm] using ht) rw [hT_succ] -- Need: ((n+2)*T(n) + 2n) / (n+1) <= (n+1)^2 -- First, bound the numerator using ih: T(n) <= n^2 have hnum_bound : (((n : Rat) + 2)) * expectedComparisons n + 2 * (n : Rat) ((n : Rat) + 1) * ((n : Rat) + 1) * ((n : Rat) + 1) := by -- (n+2)*T(n) + 2n <= (n+2)*n^2 + 2n = n^3 + 2n^2 + 2n -- <= n^3 + 3n^2 + 3n + 1 = (n+1)^3 (since n^2 + n + 1 >= 0) nlinarith -- Apply the division lemma: if a <= b and c > 0, then a/c <= b/c refine le_trans (div_le_div_of_nonneg_right hnum_bound (by positivity)) ?_ -- Now need: (n+1)^3 / (n+1) <= (n+1)^2 -- Since (n+1)^3 / (n+1) = (n+1)^2 exactly, this is equality push_cast have h_eq : ((n : Rat) + 1) * ((n : Rat) + 1) * ((n : Rat) + 1) / ((n : Rat) + 1) = ((n : Rat) + 1) * ((n : Rat) + 1) := by field_simp [show ((n : Rat) + 1) 0 from by positivity] exact h_eq.le

Monotonicity. The expected comparison count is non-decreasing: T(n) <= T(n+1).

From the telescope identity, T(n+1) - T(n) = (T(n) + 2n)/(n+1) >= 0.

theorem expectedComparisons_monotone (n : Nat) : expectedComparisons n expectedComparisons (n+1) := by have ht := expectedComparisons_telescope n -- ht: (n+1)*T(n+1) = (n+2)*T(n) + 2n -- Rearranged: (n+1)*(T(n+1) - T(n)) = T(n) + 2n -- Since T(n) >= 0, RHS >= 0, so T(n+1) - T(n) >= 0 have hpos : ((n+1 : Nat) : Rat) 0 := Nat.cast_ne_zero.mpr (Nat.succ_ne_zero n) have hnonneg : 0 expectedComparisons n := expectedComparisons_nonneg n have hdiff : expectedComparisons (n+1) - expectedComparisons n = (expectedComparisons n + 2 * (n : Rat)) / ((n+1 : Nat) : Rat) := (eq_div_iff_mul_eq hpos).mpr (by -- Need: (T(n+1) - T(n)) * (n+1) = T(n) + 2n -- Start from ht: (n+1)*T(n+1) = (n+2)*T(n) + 2n calc (expectedComparisons (n+1) - expectedComparisons n) * ((n+1 : Nat) : Rat) = ((n+1 : Nat) : Rat) * expectedComparisons (n+1) - ((n+1 : Nat) : Rat) * expectedComparisons n := by ring _ = (((n : Rat) + 2) * expectedComparisons n + 2 * (n : Rat)) - ((n+1 : Nat) : Rat) * expectedComparisons n := by rw [ht] _ = expectedComparisons n + 2 * (n : Rat) := by push_cast; ring ) have hdiff_nonneg : 0 expectedComparisons (n+1) - expectedComparisons n := by rw [hdiff] refine div_nonneg ?_ (by positivity) nlinarith linarith

Asymptotic Θ(n log n) bound

We now lift the harmonic upper bound to the textbook asymptotic statement T(n) = Θ(n log n) using the standard harmonic bounds log(n+1) ≤ H_n ≤ 1 + log n from Mathlib.

open Chapter03

The rational harmonic number defined in this section equals Mathlib's global harmonic number after casting to .

theorem harmonic_eq_mathlib_harmonic (n : ) : (harmonic n : ) = (_root_.harmonic n : ) := by induction n with | zero => simp [harmonic, _root_.harmonic] | succ n ih => rw [harmonic_succ, _root_.harmonic_succ] push_cast rw [ih] simp

Expected comparisons cast to , for use with the Chapter 3 asymptotic wrappers.

noncomputable def expectedComparisonsReal (n : ) : := (expectedComparisons n : )

Cast of the harmonic upper bound to .

theorem expectedComparisons_harmonic_bound_real (n : ) : expectedComparisonsReal n 2 * (n : ) * (harmonic n : ) := by have h := expectedComparisons_harmonic_bound n dsimp [expectedComparisonsReal] exact_mod_cast h

Lower bound. For n ≥ 1, the expected number of comparisons is at least n * H_n - 4n.

theorem expectedComparisons_lower_bound_real (n : ) (_hn : 1 n) : (n : ) * (harmonic n : ) - 4 * (n : ) expectedComparisonsReal n := by dsimp [expectedComparisonsReal, expectedComparisons] push_cast have h_nonneg : 0 (harmonic n : ) := by exact mod_cast harmonic_nonneg n nlinarith

The local harmonic after casting is bounded by 1 + log n.

theorem harmonic_le_one_add_log' (n : ) : (harmonic n : ) 1 + Real.log (n : ) := by rw [harmonic_eq_mathlib_harmonic n] exact harmonic_le_one_add_log n

The local harmonic after casting is bounded below by log (n+1).

theorem log_add_one_le_harmonic' (n : ) : Real.log ((n : ) + 1) (harmonic n : ) := by rw [harmonic_eq_mathlib_harmonic n] simpa [Nat.cast_add, Nat.cast_one] using log_add_one_le_harmonic n

Randomized quicksort is O(n log n). The expected number of comparisons satisfies T(n) = O(n log n).

theorem expectedComparisons_isBigO_nlogn : isBigO expectedComparisonsReal (fun n : => (n : ) * Real.log (n : )) := by rw [isBigO_iff] have h_harm_le : n : , (harmonic n : ) 1 + Real.log (n : ) := harmonic_le_one_add_log' -- Real.log → ∞, so eventually log n ≥ 1 have h_log_eventually : ∀ᶠ (n : ) in Filter.atTop, (1 : ) Real.log (n : ) := (Real.tendsto_log_atTop.comp tendsto_natCast_atTop_atTop) (Filter.eventually_ge_atTop (1 : )) rcases Filter.eventually_atTop.mp h_log_eventually with n₁, hn₁ refine 4, by norm_num, max 2 n₁, fun n hn => ?_ have hn2 : 2 n := le_trans (le_max_left _ _) hn have hn_log_ge_one : (1 : ) Real.log (n : ) := hn₁ n (le_trans (le_max_right _ _) hn) have hn_pos : 1 n := by omega have hn_real_pos : 1 (n : ) := by exact_mod_cast hn_pos have hlog_nonneg : 0 Real.log (n : ) := Real.log_nonneg hn_real_pos have hT_nonneg : 0 expectedComparisonsReal n := by dsimp [expectedComparisonsReal]; exact mod_cast expectedComparisons_nonneg n have hmul_nonneg : 0 (n : ) * Real.log (n : ) := by positivity rw [abs_of_nonneg hT_nonneg, abs_of_nonneg hmul_nonneg] calc expectedComparisonsReal n 2 * (n : ) * (harmonic n : ) := expectedComparisons_harmonic_bound_real n _ 2 * (n : ) * (1 + Real.log (n : )) := by have h_nonneg : 0 2 * (n : ) := by positivity gcongr exact h_harm_le n _ = 2 * (n : ) + 2 * ((n : ) * Real.log (n : )) := by ring _ 4 * ((n : ) * Real.log (n : )) := by -- 2n ≤ 2n*log n when log n ≥ 1, so 2n + 2n*log n ≤ 4n*log n have h : 2 * (n : ) 2 * ((n : ) * Real.log (n : )) := by have hn_nonneg : 0 (n : ) := Nat.cast_nonneg _ calc 2 * (n : ) = 2 * (n : ) * (1 : ) := by ring _ 2 * (n : ) * Real.log (n : ) := by gcongr _ = 2 * ((n : ) * Real.log (n : )) := by ring nlinarith

Randomized quicksort is Ω(n log n). The expected number of comparisons satisfies T(n) = Ω(n log n).

theorem expectedComparisons_isBigOmega_nlogn : isBigOmega expectedComparisonsReal (fun n : => (n : ) * Real.log (n : )) := by rw [isBigOmega_iff] -- Use log(n+1) ≤ H_n and T(n) ≥ n*H_n - 4n have h_harm_lower : n : , Real.log ((n : ) + 1) (harmonic n : ) := log_add_one_le_harmonic' -- Real.log → ∞, so eventually log n ≥ 8 have h_log_eventually : ∀ᶠ (n : ) in Filter.atTop, (8 : ) Real.log (n : ) := (Real.tendsto_log_atTop.comp tendsto_natCast_atTop_atTop) (Filter.eventually_ge_atTop (8 : )) rcases Filter.eventually_atTop.mp h_log_eventually with n₀₁, hn₀₁ -- Also need log(n+1) ≥ (1/2)*log n for large n -- Since log(n+1)/log n → 1, for log n ≥ 8 we have log(n+1) ≥ (3/4)*log n -- Actually log(n+1) ≥ log n ≥ (1/2)*log n trivially let n₀ := max n₀₁ 8 refine 1/8, by norm_num, n₀, fun n hn => ?_ have hn₁ : n₀₁ n := le_trans (le_max_left _ _) hn have hn_pos : 8 n := le_trans (le_max_right _ _) hn have hn_real_pos : 0 < (n : ) := by have : 0 < n := by omega exact_mod_cast this have hT_nonneg : 0 expectedComparisonsReal n := by dsimp [expectedComparisonsReal]; exact mod_cast expectedComparisons_nonneg n have hn1pos : 1 n := by omega have hn1real : 1 (n : ) := by exact_mod_cast hn1pos have hlog_nonneg : 0 Real.log (n : ) := Real.log_nonneg hn1real have hmul_nonneg : 0 (n : ) * Real.log (n : ) := by positivity rw [abs_of_nonneg hT_nonneg, abs_of_nonneg hmul_nonneg] have h_log_ge_eight : (8 : ) Real.log (n : ) := hn₀₁ n hn₁ -- log(n+1) ≥ log n ≥ 8 for n ≥ n₀ have h_log_succ_ge : Real.log (n : ) Real.log ((n : ) + 1) := Real.log_le_log (by positivity) (by nlinarith) -- T(n) ≥ n*H_n - 4n ≥ n*log(n+1) - 4n ≥ n*log n - 4n -- Since log n ≥ 8, we have log n/8 ≥ 1, so 4n ≤ (log n/2)*n = n*log n/2 -- Thus n*log n - 4n ≥ n*log n/2 ≥ n*log n/8 calc (1/8 : ) * ((n : ) * Real.log (n : )) = ((n : ) * Real.log (n : )) / 8 := by ring _ ((n : ) * Real.log (n : )) - 4 * (n : ) := by -- Need: (n*log n)/8 ≤ n*log n - 4n ⇔ 4n ≤ (7/8)*n*log n ⇔ 32/7 ≤ log n ≈ 4.57 -- Since log n ≥ 8, this holds. have h : 4 * (n : ) (7/8 : ) * ((n : ) * Real.log (n : )) := by calc 4 * (n : ) = (n : ) * 4 := by ring _ (n : ) * ((7/8 : ) * Real.log (n : )) := by nlinarith [h_log_ge_eight] _ = (7/8 : ) * ((n : ) * Real.log (n : )) := by ring nlinarith _ (n : ) * Real.log ((n : ) + 1) - 4 * (n : ) := by nlinarith _ (n : ) * (harmonic n : ) - 4 * (n : ) := by nlinarith [h_harm_lower n] _ expectedComparisonsReal n := expectedComparisons_lower_bound_real n hn1pos

Randomized quicksort is Θ(n log n). The expected number of comparisons satisfies T(n) = Θ(n log n).

theorem expectedComparisons_isBigTheta_nlogn : isBigTheta expectedComparisonsReal (fun n : => (n : ) * Real.log (n : )) := expectedComparisons_isBigO_nlogn, expectedComparisons_isBigOmega_nlogn

Bridge: probability model to closed form

We connect the random-permutation pairwise comparison probability (compared_prob, CLRS Theorem 7.3) to the deterministic closed form expectedComparisons n and the Θ(n log n) asymptotic.

open CLRS.Probability

Additive recurrence: T(n+1) = T(n) + 2*(H_{n+1} - 1).

theorem expectedComparisons_succ_add_two (n : ) : expectedComparisons (n+1) = expectedComparisons n + 2 * (harmonic (n+1) - 1) := by have ht := expectedComparisons_telescope n have hpos : ((n+1 : ) : ) 0 := Nat.cast_ne_zero.mpr (Nat.succ_ne_zero n) have hT_succ : expectedComparisons (n+1) = (((n : ) + 2) * expectedComparisons n + 2 * (n : )) / ((n+1 : ) : ) := (eq_div_iff_mul_eq hpos).mpr (by simpa [mul_comm] using ht) rw [hT_succ] rw [show expectedComparisons n = 2 * ((n : ) + 1) * harmonic n - 4 * (n : ) from rfl] have hH_succ : harmonic (n+1) = harmonic n + (1 : ) / ((n+1 : ) : ) := harmonic_succ n rw [hH_succ] push_cast field_simp [show ((n : ) + 1) 0 from by positivity] ring

The double sum of pairwise comparison probabilities 2/(j-i+1) over all 0 ≤ i < j < n equals the expected-comparison closed form.

theorem sum_compared_prob_eq_expectedComparisons (n : ) : ( i Finset.range n, j Finset.range n, if i < j then (2 : ) / ((j - i + 1 : ) : ) else 0) = (expectedComparisons n : ) := by induction n with | zero => simp [expectedComparisons] | succ n ih => -- S(n+1) = S(n) + A(n), where A(n) = Σ_{i<n} 2/(n-i+1) -- Split the outer sum: i=n contributes nothing (n < j never holds in range (n+1)) rw [Finset.sum_range_succ] have h_last_row_zero : ( j Finset.range (n+1), if (n : ) < j then (2 : ) / ((j - n + 1 : ) : ) else 0) = 0 := by apply Finset.sum_eq_zero; intro j hj rw [Finset.mem_range] at hj simp [show ¬ (n : ) < j from by omega] rw [h_last_row_zero, add_zero] -- For i < n, split inner sum at j = n (the new column) have h_inner_split : ( i Finset.range n, j Finset.range (n+1), if i < j then (2 : ) / ((j - i + 1 : ) : ) else 0) = ( i Finset.range n, j Finset.range n, if i < j then (2 : ) / ((j - i + 1 : ) : ) else 0) + ( i Finset.range n, (2 : ) / (((n : ) - i + 1 : ) : )) := by calc ( i Finset.range n, j Finset.range (n+1), if i < j then (2 : ) / ((j - i + 1 : ) : ) else 0) = ( i Finset.range n, (( j Finset.range n, if i < j then (2 : ) / ((j - i + 1 : ) : ) else 0) + (if i < n then (2 : ) / (((n : ) - i + 1 : ) : ) else 0))) := by refine Finset.sum_congr rfl (fun i hi => ?_) rw [Finset.sum_range_succ] _ = ( i Finset.range n, j Finset.range n, if i < j then (2 : ) / ((j - i + 1 : ) : ) else 0) + ( i Finset.range n, (if i < n then (2 : ) / (((n : ) - i + 1 : ) : ) else 0)) := by rw [Finset.sum_add_distrib] _ = ( i Finset.range n, j Finset.range n, if i < j then (2 : ) / ((j - i + 1 : ) : ) else 0) + ( i Finset.range n, (2 : ) / (((n : ) - i + 1 : ) : )) := by congr 1 apply Finset.sum_congr rfl; intro i hi have hi_lt_n : i < n := Finset.mem_range.1 hi simp [hi_lt_n] rw [h_inner_split, ih] rw [expectedComparisons_succ_add_two n] congr 1 -- Prove A(n) = 2*(H_{n+1} - 1) using the same recurrence -- A(0) = 0, A(n+1) = A(n) + 2/(n+2) -- Both sides satisfy this recurrence have hA_recurrence : m, ( i Finset.range m, (2 : ) / (((m : ) - i + 1 : ) : )) = 2 * (harmonic (m+1) - 1) := by intro m induction m with | zero => simp [harmonic] | succ m ih => -- A(m+1) = Σ_{i∈range(m+1)} 2/((m+1)-i+1) -- Decompose: i=0 term = 2/(m+2), remaining shifted by i↦i+1 have h_decomp : (Finset.range (m+1) : Finset ) = ({0} : Finset ) ((Finset.range m).map (· + 1), Nat.succ_injective) := by ext i; constructor · intro hi have hi_val : i < m+1 := Finset.mem_range.1 hi rcases Nat.eq_zero_or_pos i with (rfl | hpos) · apply Finset.mem_union_left; simp · apply Finset.mem_union_right apply Finset.mem_map.mpr have h_bound : i - 1 < m := by omega refine i-1, Finset.mem_range.2 h_bound, ?_ have h_one_le : 1 i := Nat.one_le_of_lt hpos dsimp rw [Nat.sub_add_cancel h_one_le] · intro hi rcases Finset.mem_union.1 hi with (h | h) · rcases Finset.mem_singleton.1 h with rfl exact Finset.mem_range.2 (by have : 0 < m+1 := Nat.zero_lt_succ m exact this) · rcases Finset.mem_map.1 h with j, hj, rfl have hj_val : j < m := Finset.mem_range.1 hj have : j+1 < m+1 := Nat.add_lt_add_right hj_val 1 exact Finset.mem_range.2 this have h_disjoint : Disjoint ({0} : Finset ) ((Finset.range m).map (· + 1), Nat.succ_injective) := by refine Finset.disjoint_singleton_left.mpr (fun h => ?_) rcases Finset.mem_map.1 h with j, hj, h have : j + 1 = 0 := h omega rw [h_decomp, Finset.sum_union h_disjoint, Finset.sum_singleton, Finset.sum_map] -- Now: 2/((m+1)-0+1) + Σ_{j∈range m} 2/((m+1)-(j+1)+1) -- = 2/(m+2) + Σ_{j∈range m} 2/(m-j+1) -- = 2/(m+2) + A(m) simp only [Function.Embedding.coeFn_mk] have h0 : ((m+1 : ) - 0 + 1 : ) = (m+2 : ) := by omega have h_shift : j, ((m+1 : ) - (j+1) + 1 : ) = ((m : ) - j + 1 : ) := by intro j; omega simp_rw [h0, h_shift] rw [ih] rw [harmonic_succ (m+1)] push_cast; ring exact hA_recurrence n
end Chapter07end CLRS