Imports

CLRS Section 8.4 - Bucket sort

This file adds a deterministic correctness layer for bucket sort and a first finite-uniform probability interface for the expected-time argument.

The full probabilistic expected-time analysis in CLRS depends on a distributional assumption about the input. Here we isolate the pure correctness spine:

  • distribute values into buckets by a bucket-index function;

  • sort each bucket by the final key;

  • concatenate buckets in increasing bucket-index order;

  • prove the result is ordered and is a permutation of the input.

The theorem is intentionally parametric in the bucket-index function. A separate cross-bucket assumption states that every value in an earlier bucket is at most every value in a later bucket according to the final sort key.

The finite-uniform layer proves the collision fact behind the textbook expected time argument: two independently chosen uniform buckets collide with probability 1/m; therefore the expected quadratic bucket-occupancy cost for n independent samples into n buckets is at most linear in n. The final wrapper adds the linear scan/distribution term used by the CLRS expected-time proof and obtains a concrete ≤ 3n bound for this abstract cost expression.

namespace CLRSnamespace Chapter08universe u vvariable {α : Type u}

Bucket-sort model

Every element in a list has bucket index strictly below upper.

def AllKeysLt (key : α Nat) (xs : List α) (upper : Nat) : Prop := x xs, key x < upper

Bucket sort with an abstract per-bucket sorter.

The buckets are scanned in increasing order 0, 1, ..., bucketCount - 1.

def bucketSortBy (bucketCount : Nat) (bucketOf : α Nat) (sortBucket : List α List α) (xs : List α) : List α := (List.range bucketCount).flatMap fun k => sortBucket (bucket bucketOf xs k)
theorem bucketSortBy_succ (bucketCount : Nat) (bucketOf : α Nat) (sortBucket : List α List α) (xs : List α) : bucketSortBy (bucketCount + 1) bucketOf sortBucket xs = bucketSortBy bucketCount bucketOf sortBucket xs ++ sortBucket (bucket bucketOf xs bucketCount) := theorem orderedBy_of_pairwise {key : α Nat} : {xs : List α}, xs.Pairwise (fun x y => key x key y) OrderedBy key xs cases h with exact hhead y ( ), orderedBy_of_pairwise htailtheorem flatMap_perm_of_forall {β : Type v} (ks : List β) (f g : β List α) (h : k ks, (f k).Perm (g k)) : (ks.flatMap f).Perm (ks.flatMap g) := induction ks with theorem bucketSortBy_perm_bucket_scan (bucketCount : Nat) (bucketOf : α Nat) (sortBucket : List α List α) (xs : List α) (hsort_perm : ys, (sortBucket ys).Perm ys) : (bucketSortBy bucketCount bucketOf sortBucket xs).Perm ((List.range bucketCount).flatMap fun k => bucket bucketOf xs k) := exact hcross ( ) theorem bucketSortBy_mem_iff [DecidableEq α] (bucketCount : Nat) (bucketOf : α Nat) (sortBucket : List α List α) (xs : List α) (hxs : AllKeysLt bucketOf xs bucketCount) (hsort_perm : ys, (sortBucket ys).Perm ys) (x : α) : x bucketSortBy bucketCount bucketOf sortBucket xs x xs := (bucketSortBy_perm bucketCount bucketOf sortBucket xs hxs hsort_perm).mem_iff

Reader-facing correctness theorem for abstract deterministic bucket sort.

theorem bucketSortBy_correct [DecidableEq α] (bucketCount : Nat) (bucketOf rank : α Nat) (sortBucket : List α List α) (xs : List α) (hxs : AllKeysLt bucketOf xs bucketCount) (hsort_ordered : k, OrderedBy rank (sortBucket (bucket bucketOf xs k))) (hsort_perm : ys, (sortBucket ys).Perm ys) (hcross : {x y : α}, bucketOf x < bucketOf y rank x rank y) : OrderedBy rank (bucketSortBy bucketCount bucketOf sortBucket xs) ( x, x bucketSortBy bucketCount bucketOf sortBucket xs x xs) (bucketSortBy bucketCount bucketOf sortBucket xs).Perm xs := bucketSortBy_ordered bucketCount bucketOf rank sortBucket xs hsort_ordered hsort_perm hcross, bucketSortBy_mem_iff bucketCount bucketOf sortBucket xs hxs hsort_perm, bucketSortBy_perm bucketCount bucketOf sortBucket xs hxs hsort_perm

Executable bucket sorter using merge sort inside each bucket

Sort one bucket by the final natural-number rank.

def sortBucketByRank (rank : α Nat) (xs : List α) : List α := xs.mergeSort (fun x y => decide (rank x rank y))
theorem sortBucketByRank_perm (rank : α Nat) (xs : List α) : (sortBucketByRank rank xs).Perm xs := theorem sortBucketByRank_ordered (rank : α Nat) (xs : List α) : OrderedBy rank (sortBucketByRank rank xs) :=

Bucket sort whose per-bucket sorter is Lean's verified merge sort.

def bucketSortByRank (bucketCount : Nat) (bucketOf rank : α Nat) (xs : List α) : List α := bucketSortBy bucketCount bucketOf (sortBucketByRank rank) xs

Reader-facing correctness theorem for the executable bucket-sort model.

The cross-bucket hypothesis is the deterministic analogue of the CLRS bucket interval fact: every item in an earlier bucket is no larger than every item in a later bucket.

theorem bucketSortByRank_correct [DecidableEq α] (bucketCount : Nat) (bucketOf rank : α Nat) (xs : List α) (hxs : AllKeysLt bucketOf xs bucketCount) (hcross : {x y : α}, bucketOf x < bucketOf y rank x rank y) : OrderedBy rank (bucketSortByRank bucketCount bucketOf rank xs) ( x, x bucketSortByRank bucketCount bucketOf rank xs x xs) (bucketSortByRank bucketCount bucketOf rank xs).Perm xs :=

Finite-uniform expected-cost interface

A real-valued 0/1 indicator for finite bucket probabilities.

def probabilityIndicator (P : Prop) [Decidable P] : := if P then 1 else 0

Uniform average over the finite bucket set Fin m.

noncomputable def uniformAverageFin {m : Nat} (X : Fin m ) : := ( i : Fin m, X i) / (m : )

Uniform average over two independent finite bucket choices.

noncomputable def uniformAverageFin2 {m : Nat} (X : Fin m Fin m ) : := uniformAverageFin fun i => uniformAverageFin fun j => X i j

A fixed bucket has probability 1/m under the finite-uniform bucket model.

Two independently chosen uniform buckets collide with probability 1/m. This is the probability fact used in the CLRS bucket-sort second-moment calculation.

calc uniformAverageFin2 (fun i j : Fin m => probabilityIndicator (i = j)) = uniformAverageFin (fun _i : Fin m => 1 / (m : )) := _ = 1 / (m : ) :=

The textbook second-moment bucket-occupancy expression for n independent samples into m uniform buckets: E[Σ_i n_i^2] = n + n(n-1)/m.

noncomputable def expectedBucketQuadraticCost (m n : Nat) : := (n : ) + (n : ) * ((n : ) - 1) / (m : )

With as many buckets as input elements, the quadratic bucket-occupancy expectation is 2n - 1.

With n buckets for n elements, the expected quadratic bucket-occupancy cost is at most 2n.

Abstract CLRS bucket-sort expected cost: a linear scan/distribution term plus the expected quadratic bucket-occupancy cost for sorting the buckets.

noncomputable def expectedBucketSortCost (n : Nat) : := (n : ) + expectedBucketQuadraticCost n n

With n buckets for n elements, the abstract expected bucket-sort cost is 3n - 1.

CLRS-facing linear expected-cost bound for the finite-uniform bucket-sort cost interface.

end Chapter08end CLRS