Imports
import Mathlib

CLRS Section 14.1 - Order-statistic trees

This section gives the first augmentation proof for CLRS-Lean. An order-statistic tree stores, at every node, a size field intended to equal the number of nodes in that subtree. The operation osSelect? uses the stored size of the left child to implement rank selection.

The file separates the executable augmented operation from its ideal mathematical specification:

  • storedSize reads the cached field;

  • realSize recomputes the mathematical subtree size;

  • WellSized says every cached field is correct;

  • rankSelect? is the ideal selector using recomputed sizes;

  • osSelect? is the augmented selector using cached sizes.

Main results:

  • Theorem storedSize_eq_realSize_of_wellSized: a well-sized tree has a correct root size field.

  • Theorem realSize_recomputeSizes: recomputing cached size fields preserves the mathematical subtree size.

  • Theorem recomputeSizes_wellSized: recomputing size fields establishes the augmentation invariant.

  • Theorem keys_recomputeSizes: recomputing size fields preserves the inorder key sequence.

  • Theorem rankSelect?_recomputeSizes: recomputing size fields preserves the ideal rank-selection result.

  • Theorems keys_rotateLeft and keys_rotateRight: rotations preserve the inorder key sequence.

  • Theorems rotateLeft_wellSized and rotateRight_wellSized: rotations with local size recomputation preserve the size augmentation invariant.

  • Theorems storedSize_rotateLeft_of_wellSized and storedSize_rotateRight_of_wellSized: rotations preserve the cached root size of a well-sized tree.

  • Theorems rankSelect?_rotateLeft and rankSelect?_rotateRight: rotations preserve the ideal rank-selection result.

  • Theorem osSelect?_eq_rankSelect?_of_wellSized: on a well-sized tree, the augmented selector agrees with the ideal rank selector.

  • Theorems osSelect?_rotateLeft_eq_rankSelect?_of_wellSized and osSelect?_rotateRight_eq_rankSelect?_of_wellSized: after a size-preserving rotation, the augmented selector still implements the original ideal rank selector.

  • Theorems rotateLeft_recomputeSizes_wellSized and rotateRight_recomputeSizes_wellSized: recompute-then-rotate produces a well-sized tree from any input tree.

  • Theorems osSelect?_rotateLeft_recomputeSizes_eq_rankSelect? and osSelect?_rotateRight_recomputeSizes_eq_rankSelect?: recompute-then- rotate preserves the augmented selector's agreement with the original ideal rank selector.

Current gaps:

  • The size-preserving and rank-preserving rotation layer is functional; it is not yet connected to the Chapter 13 red-black insertion/deletion fixup procedures.

  • Interval trees and the general augmentation theorem remain future targets.

namespace CLRSnamespace Chapter14

Augmented tree model

A binary tree whose internal nodes cache their subtree size.

inductive OSTree where | empty : OSTree | node : OSTree Nat Nat OSTree OSTree deriving Repr, DecidableEq
namespace OSTree

Mathematical inorder traversal of the keys, ignoring cached sizes.

def keys : OSTree List Nat | empty => [] | node left key _size right => keys left ++ [key] ++ keys right

The cached size stored at the root. Empty trees have cached size zero.

def storedSize : OSTree Nat | empty => 0 | node _left _key size _right => size

The mathematical size obtained by recursively counting nodes.

def realSize : OSTree Nat | empty => 0 | node left _key _size right => realSize left + realSize right + 1

Every cached size field agrees with the mathematical subtree size.

def WellSized : OSTree Prop | empty => True | node left _key size right => WellSized left WellSized right size = realSize left + realSize right + 1

Recompute every cached size field from the children upward.

def recomputeSizes : OSTree OSTree | empty => empty | node left key _size right => let left' := recomputeSizes left let right' := recomputeSizes right node left' key (realSize left' + realSize right' + 1) right'

Local rotations

Left rotation with local size recomputation. If the right child is empty, the tree is left unchanged.

def rotateLeft : OSTree OSTree | node a x _ (node b y _ c) => let left' := node a x (realSize a + realSize b + 1) b node left' y (realSize left' + realSize c + 1) c | t => t

Right rotation with local size recomputation. If the left child is empty, the tree is left unchanged.

def rotateRight : OSTree OSTree | node (node a x _ b) y _ c => let right' := node b y (realSize b + realSize c + 1) c node a x (realSize a + realSize right' + 1) right' | t => t

Selectors

The ideal rank selector, using mathematically recomputed subtree sizes. Ranks are zero-based: rank zero returns the first inorder key.

def rankSelect? : OSTree Nat Option Nat | empty, _ => none | node left key _size right, i => if i < realSize left then rankSelect? left i else if i = realSize left then some key else rankSelect? right (i - realSize left - 1)

The augmented order-statistic selector, using cached subtree sizes rather than recomputing them. The main theorem states that this agrees with rankSelect? whenever the cached fields are well-sized.

def osSelect? : OSTree Nat Option Nat | empty, _ => none | node left key _size right, i => if i < storedSize left then osSelect? left i else if i = storedSize left then some key else osSelect? right (i - storedSize left - 1)

Augmentation correctness

A well-sized tree has a correct root size field.

theorem storedSize_eq_realSize_of_wellSized {t : OSTree} (h : WellSized t) : storedSize t = realSize t := cases t with

Recomputing cached size fields preserves the inorder key sequence.

theorem keys_recomputeSizes (t : OSTree) : keys (recomputeSizes t) = keys t := induction t with

Recomputing cached size fields preserves the mathematical subtree size.

theorem realSize_recomputeSizes (t : OSTree) : realSize (recomputeSizes t) = realSize t := induction t with

Recomputing cached size fields establishes the size augmentation invariant.

theorem recomputeSizes_wellSized (t : OSTree) : WellSized (recomputeSizes t) := induction t with

Rotation correctness for the size augmentation

Left rotation preserves the inorder key sequence.

theorem keys_rotateLeft (t : OSTree) : keys (rotateLeft t) = keys t := cases t with cases right with

Right rotation preserves the inorder key sequence.

theorem keys_rotateRight (t : OSTree) : keys (rotateRight t) = keys t := cases t with cases left with

Left rotation preserves the mathematical subtree size.

theorem realSize_rotateLeft (t : OSTree) : realSize (rotateLeft t) = realSize t := cases t with cases right with

Right rotation preserves the mathematical subtree size.

theorem realSize_rotateRight (t : OSTree) : realSize (rotateRight t) = realSize t := cases t with cases left with

Left rotation preserves the cached root size of a well-sized tree.

theorem storedSize_rotateLeft_of_wellSized {t : OSTree} (h : WellSized t) : storedSize (rotateLeft t) = storedSize t := cases t with cases right with

Right rotation preserves the cached root size of a well-sized tree.

theorem storedSize_rotateRight_of_wellSized {t : OSTree} (h : WellSized t) : storedSize (rotateRight t) = storedSize t := cases t with cases left with

Left rotation preserves ideal rank selection.

Right rotation preserves ideal rank selection.

Left rotation with local size recomputation preserves WellSized.

theorem rotateLeft_wellSized {t : OSTree} (h : WellSized t) : WellSized (rotateLeft t) := cases t with cases right with

Right rotation with local size recomputation preserves WellSized.

theorem rotateRight_wellSized {t : OSTree} (h : WellSized t) : WellSized (rotateRight t) := cases t with cases left with

The augmented selector agrees with the ideal selector on well-sized trees.

theorem osSelect?_eq_rankSelect?_of_wellSized {t : OSTree} {i : Nat} (h : WellSized t) : osSelect? t i = rankSelect? t i := induction t generalizing i with

Recomputing size fields preserves the ideal rank selector.

theorem rankSelect?_recomputeSizes (t : OSTree) (i : Nat) : rankSelect? (recomputeSizes t) i = rankSelect? t i := induction t generalizing i with

After a size-preserving left rotation, the augmented selector still implements the original ideal rank selector.

theorem osSelect?_rotateLeft_eq_rankSelect?_of_wellSized {t : OSTree} {i : Nat} (h : WellSized t) : osSelect? (rotateLeft t) i = rankSelect? t i := calc osSelect? (rotateLeft t) i = rankSelect? (rotateLeft t) i := osSelect?_eq_rankSelect?_of_wellSized (rotateLeft_wellSized h) _ = rankSelect? t i := rankSelect?_rotateLeft t i

After a size-preserving right rotation, the augmented selector still implements the original ideal rank selector.

theorem osSelect?_rotateRight_eq_rankSelect?_of_wellSized {t : OSTree} {i : Nat} (h : WellSized t) : osSelect? (rotateRight t) i = rankSelect? t i := calc osSelect? (rotateRight t) i = rankSelect? (rotateRight t) i := osSelect?_eq_rankSelect?_of_wellSized (rotateRight_wellSized h) _ = rankSelect? t i := rankSelect?_rotateRight t i

Recomputing size fields makes the augmented selector agree with the ideal selector without requiring an external invariant proof.

theorem osSelect?_recomputeSizes_eq_rankSelect? (t : OSTree) (i : Nat) : osSelect? (recomputeSizes t) i = rankSelect? (recomputeSizes t) i :=

Recomputing size fields and then rotating left produces a well-sized tree.

theorem rotateLeft_recomputeSizes_wellSized (t : OSTree) : WellSized (rotateLeft (recomputeSizes t)) :=

Recomputing size fields and then rotating right produces a well-sized tree.

theorem rotateRight_recomputeSizes_wellSized (t : OSTree) : WellSized (rotateRight (recomputeSizes t)) :=

After recomputing size fields and rotating left, the augmented selector still implements the original ideal rank selector.

theorem osSelect?_rotateLeft_recomputeSizes_eq_rankSelect? (t : OSTree) (i : Nat) : osSelect? (rotateLeft (recomputeSizes t)) i = rankSelect? t i := calc osSelect? (rotateLeft (recomputeSizes t)) i = rankSelect? (recomputeSizes t) i := osSelect?_rotateLeft_eq_rankSelect?_of_wellSized (recomputeSizes_wellSized t) _ = rankSelect? t i := rankSelect?_recomputeSizes t i

After recomputing size fields and rotating right, the augmented selector still implements the original ideal rank selector.

theorem osSelect?_rotateRight_recomputeSizes_eq_rankSelect? (t : OSTree) (i : Nat) : osSelect? (rotateRight (recomputeSizes t)) i = rankSelect? t i := calc osSelect? (rotateRight (recomputeSizes t)) i = rankSelect? (recomputeSizes t) i := osSelect?_rotateRight_eq_rankSelect?_of_wellSized (recomputeSizes_wellSized t) _ = rankSelect? t i := rankSelect?_recomputeSizes t i
end OSTreeend Chapter14end CLRS