Imports
import Mathlib

CLRS Section 8.2 - Counting sort

This file starts Chapter 8 with the stable bucket view of counting sort. CLRS implements the algorithm with a count array and prefix sums; the mathematical content is that keys are emitted in increasing order and that each equal-key subsequence is copied in its original order.

We model that proof spine directly. Given a key function into natural numbers and a maximum key, countingSortBy scans the key values in order and emits the corresponding input bucket. The main theorem packages the three facts used by the textbook proof:

  • the output is ordered by key;

  • every key bucket is exactly the corresponding input bucket, hence stable;

  • membership is preserved when all input keys are at most the declared maximum.

The count-array implementation and linear-time cost model are future refinements of this stable bucket specification.

namespace CLRSnamespace Chapter08

Ordered lists by key

A compact sortedness predicate for lists ordered by a natural-number key.

def OrderedBy (key : α Nat) : List α Prop | [] => True | [_] => True | x :: y :: ys => key x key y OrderedBy key (y :: ys)

Every element in a list has key at most upper.

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

Every element in a list has key at least lower.

def AllKeysGe (key : α Nat) (lower : Nat) (xs : List α) : Prop := x xs, lower key x
theorem orderedBy_tail {key : α Nat} {x : α} {xs : List α} (h : OrderedBy key (x :: xs)) : OrderedBy key xs := cases xs with theorem orderedBy_allKeysGe_tail {key : α Nat} {x : α} {xs : List α} (h : OrderedBy key (x :: xs)) : AllKeysGe key (key x) xs := induction xs generalizing x with theorem orderedBy_cons_of_allKeysGe {key : α Nat} {x : α} {xs : List α} (hxs : OrderedBy key xs) (hall : AllKeysGe key (key x) xs) : OrderedBy key (x :: xs) := cases xs with exact hall y ( ), hxs

Stable buckets

The input bucket whose elements have key k, preserving input order.

def bucket (key : α Nat) (xs : List α) (k : Nat) : List α := xs.filter fun x => key x == k
theorem bucket_append (key : α Nat) (xs ys : List α) (k : Nat) : bucket key (xs ++ ys) k = bucket key xs k ++ bucket key ys k := theorem mem_bucket_iff {key : α Nat} {xs : List α} {k : Nat} {x : α} : x bucket key xs k x xs key x = k := theorem bucket_all_keys_eq (key : α Nat) (xs : List α) (k : Nat) : x bucket key xs k, key x = k := theorem bucket_orderedBy (key : α Nat) (xs : List α) (k : Nat) : OrderedBy key (bucket key xs k) := orderedBy_of_all_keys_eq (bucket_all_keys_eq key xs k)theorem count_bucket_self [DecidableEq α] (key : α Nat) (xs : List α) (x : α) : List.count x (bucket key xs (key x)) = List.count x xs :=

Filtering a bucket by a second key keeps it only when the keys agree.

theorem bucket_bucket_eq (key : α Nat) (xs : List α) (j k : Nat) : bucket key (bucket key xs j) k = if j = k then bucket key xs k else [] :=
theorem bucket_eq_nil_of_allKeysLe_lt {key : α Nat} {xs : List α} {upper k : Nat} (hxs : AllKeysLe key xs upper) (hgt : upper < k) : bucket key xs k = [] :=

Counting sort by stable buckets

Stable counting sort by natural-number keys bounded by maxKey.

The function emits the bucket for key 0, then key 1, and so on through maxKey.

def countingSortBy (maxKey : Nat) (key : α Nat) (xs : List α) : List α := (List.range (maxKey + 1)).flatMap (bucket key xs)
theorem countingSortBy_succ (maxKey : Nat) (key : α Nat) (xs : List α) : countingSortBy (maxKey + 1) key xs = countingSortBy maxKey key xs ++ bucket key xs (maxKey + 1) :=

If k ≤ maxKey, the k-bucket of the output is exactly the k-bucket of the input. This is the stable-copy theorem for in-range keys.

theorem countingSortBy_bucket_eq_of_gt (maxKey : Nat) (key : α Nat) (xs : List α) {k : Nat} (hk : maxKey < k) : bucket key (countingSortBy maxKey key xs) k = [] :=

Counting sort preserves every equal-key subsequence when the input keys are bounded by maxKey. This is the stability statement.

exact Nat.le_trans hale ( )

Reader-facing correctness theorem for stable counting sort.

theorem countingSortBy_correct [DecidableEq α] (maxKey : Nat) (key : α Nat) (xs : List α) (hxs : AllKeysLe key xs maxKey) : OrderedBy key (countingSortBy maxKey key xs) ( k, bucket key (countingSortBy maxKey key xs) k = bucket key xs k) ( x, x countingSortBy maxKey key xs x xs) (countingSortBy maxKey key xs).Perm xs := countingSortBy_ordered maxKey key xs, countingSortBy_bucket_eq maxKey key xs hxs, countingSortBy_mem_iff maxKey key xs hxs, countingSortBy_perm maxKey key xs hxs
end Chapter08end CLRS