Median of medians
DefinitionGroup medians for median-of-medians selection#✓fully proved
Given a list \(xs\) over a linear order, split \(xs\) into consecutive blocks of five elements, the last of which may be shorter. Sort each block \(g\) by insertion sort and return, in block order, the entry at position \(\lfloor (|g| - 1)/2 \rfloor\) (counting from \(0\)) of each sorted block, that is, its lower median. The cost is the total number of comparisons made by these insertion sorts.
def medianOfMediansGroups {α : Type u} [LinearOrder α] (xs : List α) :
TimeM Nat (List α) :=
let rec loop : List (List α) → TimeM Nat (List α)
| [] => pure []
| group :: groups => do
let sorted ← insertionSort group
let tail ← loop groups
match sorted[(group.length - 1) / 2]? with
| none => pure tail
| some x => pure (x :: tail)
loop (xs.toChunks 5)
def insertionSort : List α → TimeM Nat (List α)
| [] => pure []
| a :: xs => TimeM.bind (insertionSort xs) (insertionSortInsert a)
CSLibExt/Algorithms/Lean/Sort/InsertionCost.lean:48
Uses 1 · Used by 10
TheoremComparison cost of the group medians#✓fully proved
For every list \(xs\) of length \(n\) over a linear order, computing the group medians of \(xs\) takes at most \(2n\) comparisons.
theorem medianOfMediansGroups_time {α : Type u} [LinearOrder α] (xs : List α) :
(medianOfMediansGroups xs).time ≤ 2 * xs.length
def medianOfMediansGroups {α : Type u} [LinearOrder α] (xs : List α) :
TimeM Nat (List α) :=
let rec loop : List (List α) → TimeM Nat (List α)
| [] => pure []
| group :: groups => do
let sorted ← insertionSort group
let tail ← loop groups
match sorted[(group.length - 1) / 2]? with
| none => pure tail
| some x => pure (x :: tail)
loop (xs.toChunks 5)
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians/Groups.lean:33
Uses 4 · Used by 1
TheoremGroup medians come from the input#✓fully proved
For every list \(xs\) over a linear order, every entry of the list of group medians of \(xs\) is an element of \(xs\).
theorem medianOfMediansGroups_mem {α : Type u} [LinearOrder α] {xs : List α} {x : α}
(hx : x ∈ (medianOfMediansGroups xs).ret) : x ∈ xs
def medianOfMediansGroups {α : Type u} [LinearOrder α] (xs : List α) :
TimeM Nat (List α) :=
let rec loop : List (List α) → TimeM Nat (List α)
| [] => pure []
| group :: groups => do
let sorted ← insertionSort group
let tail ← loop groups
match sorted[(group.length - 1) / 2]? with
| none => pure tail
| some x => pure (x :: tail)
loop (xs.toChunks 5)
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians/Groups.lean:33
Uses 3 · Used by 3
TheoremGroup medians are lower medians of their blocks#✓fully proved
Let \(xs\) be a list over a linear order, and let \(g_1, \dots, g_m\) be its consecutive blocks of five elements, the last of which may be shorter. Then the list of group medians of \(xs\) has the same length \(m\), say \(x_1, \dots, x_m\), and for each \(i\), writing \(k_i = \lfloor (|g_i| - 1)/2 \rfloor\) and counting elements of \(g_i\) with multiplicity: \(x_i\) belongs to \(g_i\), at most \(k_i\) elements of \(g_i\) are less than \(x_i\), and more than \(k_i\) elements of \(g_i\) are less than or equal to \(x_i\).
theorem medianOfMediansGroups_correct {α : Type u} [LinearOrder α] (xs : List α) :
List.Forall₂ (fun group x => x ∈ group ∧
group.countP (fun y => decide (y < x)) ≤ (group.length - 1) / 2 ∧
(group.length - 1) / 2 < group.countP (fun y => decide (y ≤ x)))
(xs.toChunks 5) (medianOfMediansGroups xs).ret
def medianOfMediansGroups {α : Type u} [LinearOrder α] (xs : List α) :
TimeM Nat (List α) :=
let rec loop : List (List α) → TimeM Nat (List α)
| [] => pure []
| group :: groups => do
let sorted ← insertionSort group
let tail ← loop groups
match sorted[(group.length - 1) / 2]? with
| none => pure tail
| some x => pure (x :: tail)
loop (xs.toChunks 5)
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians/Groups.lean:33
Uses 7 · Used by 2
TheoremNumber of group medians#✓fully proved
For every list \(xs\) of length \(n\) over a linear order, the list of group medians of \(xs\) has exactly \(\lfloor (n + 4)/5 \rfloor = \lceil n/5 \rceil\) entries.
theorem medianOfMediansGroups_length {α : Type u} [LinearOrder α] (xs : List α) :
(medianOfMediansGroups xs).ret.length = (xs.length + 4) / 5
def medianOfMediansGroups {α : Type u} [LinearOrder α] (xs : List α) :
TimeM Nat (List α) :=
let rec loop : List (List α) → TimeM Nat (List α)
| [] => pure []
| group :: groups => do
let sorted ← insertionSort group
let tail ← loop groups
match sorted[(group.length - 1) / 2]? with
| none => pure tail
| some x => pure (x :: tail)
loop (xs.toChunks 5)
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians/Groups.lean:33
Uses 2 · Used by 2
DefinitionMedian-of-medians selection#✓fully proved
Given a list \(L\) over a linear order and a zero-based rank \(k\), median-of-medians selection returns either an element of \(L\) or nothing, charging one unit of cost per order comparison. If \(k \ge |L|\), where \(|L|\) is the length of \(L\), it returns nothing at no cost. Otherwise it runs the following recursive procedure on \((L, k)\) with a budget of \(|L|\) nested calls, returning nothing if the budget runs out. A list of length at most \(140\) is handled by deterministic quickselect at the current rank. A longer list is cut into consecutive groups of five entries, the last possibly shorter; each group is sorted by insertion sort and its lower median is kept, giving a list \(M\) of \(m\) medians. The procedure recursively selects the entry of \(M\) at rank \(\lfloor m/2 \rfloor\) as the pivot \(x\) (returning nothing if that call does), and splits the list by a three-way partition into the entries below \(x\), equal to \(x\) and above \(x\), with \(b\) entries below and \(e\) equal. If the current rank \(r\) satisfies \(r < b\) it recurses on the lower part with rank \(r\); if \(b \le r < b + e\) it returns \(x\); otherwise it recurses on the upper part with rank \(r - b - e\).
Cslib.Algorithms.Lean.TimeM.medianOfMedians · 19 lines
def medianOfMedians {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| fuel + 1, ys, rank =>
if ys.length ≤ 140 then quickselect ys rank else do
let medians ← medianOfMediansGroups ys
let pivot ← loop fuel medians (medians.length / 2)
match pivot with
| none => pure none
| some x => do
let parts ← partition3 x ys
if rank < parts.below.length then
loop fuel parts.below rank
else if rank < parts.below.length + parts.equal.length then
pure (some x)
else
loop fuel parts.above (rank - (parts.below.length + parts.equal.length))
if k < xs.length then loop xs.length xs k else pure none
def quickselect (xs : List α) (k : Nat) : TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| _ + 1, [], _ => pure none
| fuel + 1, pivot :: tail, rank => do
let parts ← partition3 pivot tail
if rank < parts.below.length then
loop fuel parts.below rank
else if rank < parts.below.length + parts.equal.length + 1 then
return some pivot
else
loop fuel parts.above
⋯
CSLibExt/Algorithms/Lean/Selection/Quickselect.lean:37
def medianOfMediansGroups {α : Type u} [LinearOrder α] (xs : List α) :
TimeM Nat (List α) :=
let rec loop : List (List α) → TimeM Nat (List α)
| [] => pure []
| group :: groups => do
let sorted ← insertionSort group
let tail ← loop groups
match sorted[(group.length - 1) / 2]? with
| none => pure tail
| some x => pure (x :: tail)
loop (xs.toChunks 5)
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians/Groups.lean:33
def partition3 (pivot : α) : List α → TimeM Nat (ThreeWayPartition α)
| [] => pure { below := [], equal := [], above := [] }
| x :: xs => do
✓
let parts ← partition3 pivot xs
match cmp x pivot with
| .lt => return { parts with below := x :: parts.below }
| .eq => return { parts with equal := x :: parts.equal }
| .gt => return { parts with above := x :: parts.above }
CSLibExt/Algorithms/Lean/Sort/Partition.lean:47
Uses 4 · Used by 14
TheoremMedian-of-medians selection is quickselect on short lists#✓fully proved
For every list \(L\) of length at most \(140\) over a linearly ordered type and every natural number \(k\), median-of-medians selection of rank \(k\) in \(L\) coincides with timed quickselect of rank \(k\) in \(L\): both return the same result and are charged the same number of comparisons.
theorem medianOfMedians_eq_quickselect_of_length_le {α : Type u} [LinearOrder α]
(xs : List α) (k : Nat) (hlen : xs.length ≤ 140) :
medianOfMedians xs k = quickselect xs k
def medianOfMedians {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| fuel + 1, ys, rank =>
if ys.length ≤ 140 then quickselect ys rank else do
let medians ← medianOfMediansGroups ys
let pivot ← loop fuel medians (medians.length / 2)
match pivot with
| none => pure none
| some x => do
let parts ← partition3 x ys
⋯
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians.lean:40
def quickselect (xs : List α) (k : Nat) : TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| _ + 1, [], _ => pure none
| fuel + 1, pivot :: tail, rank => do
let parts ← partition3 pivot tail
if rank < parts.below.length then
loop fuel parts.below rank
else if rank < parts.below.length + parts.equal.length + 1 then
return some pivot
else
loop fuel parts.above
⋯
CSLibExt/Algorithms/Lean/Selection/Quickselect.lean:37
Uses 5 · Used by 3
TheoremOut-of-range ranks cost no comparisons#✓fully proved
For every list \(L\) over a linearly ordered type and every natural number \(k\) at least the length of \(L\), median-of-medians selection of rank \(k\) in \(L\) returns nothing and is charged zero comparisons.
theorem medianOfMedians_eq_pure_none_of_length_le_rank {α : Type u} [LinearOrder α]
(xs : List α) (k : Nat) (hk : xs.length ≤ k) :
medianOfMedians xs k = pure none
def medianOfMedians {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| fuel + 1, ys, rank =>
if ys.length ≤ 140 then quickselect ys rank else do
let medians ← medianOfMediansGroups ys
let pivot ← loop fuel medians (medians.length / 2)
match pivot with
| none => pure none
| some x => do
let parts ← partition3 x ys
⋯
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians.lean:40
Uses 5 · Used by 1
TheoremComparison bound for median-of-medians selection on short lists#✓fully proved
For every list \(L\) of length \(n \le 140\) over a linearly ordered type and every natural number \(k\), median-of-medians selection of rank \(k\) in \(L\) is charged at most \(80n\) comparisons.
theorem medianOfMedians_base_time {α : Type u} [LinearOrder α]
(xs : List α) (k : Nat) (hlen : xs.length ≤ 140) :
(medianOfMedians xs k).time ≤ 80 * xs.length
def medianOfMedians {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| fuel + 1, ys, rank =>
if ys.length ≤ 140 then quickselect ys rank else do
let medians ← medianOfMediansGroups ys
let pivot ← loop fuel medians (medians.length / 2)
match pivot with
| none => pure none
| some x => do
let parts ← partition3 x ys
⋯
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians.lean:40
Uses 4 · Used by 1
TheoremCorrectness of median-of-medians selection on short lists#✓fully proved
Let \(L\) be a list of length at most \(140\) over a linearly ordered type and let \(k\) be a natural number. If median-of-medians selection of rank \(k\) in \(L\) returns an element \(x\), then \(x\) occurs in \(L\), the number of entries of \(L\) less than \(x\), counted with multiplicity, is at most \(k\), and \(k\) is less than the number of entries of \(L\) that are at most \(x\).
theorem medianOfMedians_base_correct {α : Type u} [LinearOrder α]
{xs : List α} {k : Nat} {x : α} (hlen : xs.length ≤ 140)
(hresult : (medianOfMedians xs k).ret = some x) :
x ∈ xs ∧ xs.countP (fun y => decide (y < x)) ≤ k ∧
k < xs.countP (fun y => decide (y ≤ x))
def medianOfMedians {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| fuel + 1, ys, rank =>
if ys.length ≤ 140 then quickselect ys rank else do
let medians ← medianOfMediansGroups ys
let pivot ← loop fuel medians (medians.length / 2)
match pivot with
| none => pure none
| some x => do
let parts ← partition3 x ys
⋯
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians.lean:40
Uses 4
TheoremCorrectness of median-of-medians selection#✓fully proved
Let \(L\) be a list over a linearly ordered type and let \(k\) be a natural number. If median-of-medians selection of rank \(k\) in \(L\) returns an element \(x\), then \(x\) occurs in \(L\), the number of entries of \(L\) less than \(x\), counted with multiplicity, is at most \(k\), and \(k\) is less than the number of entries of \(L\) that are at most \(x\).
theorem medianOfMedians_correct {α : Type u} [LinearOrder α]
{xs : List α} {k : Nat} {x : α} (hresult : (medianOfMedians xs k).ret = some x) :
x ∈ xs ∧ xs.countP (fun y => decide (y < x)) ≤ k ∧
k < xs.countP (fun y => decide (y ≤ x))
def medianOfMedians {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| fuel + 1, ys, rank =>
if ys.length ≤ 140 then quickselect ys rank else do
let medians ← medianOfMediansGroups ys
let pivot ← loop fuel medians (medians.length / 2)
match pivot with
| none => pure none
| some x => do
let parts ← partition3 x ys
⋯
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians.lean:40
Uses 12 · Used by 5
TheoremMedian-of-medians selection succeeds on valid ranks#✓fully proved
For every list \(L\) over a linearly ordered type and every natural number \(k\) less than the length of \(L\), median-of-medians selection of rank \(k\) in \(L\) returns some element.
theorem medianOfMedians_exists {α : Type u} [LinearOrder α]
(xs : List α) (k : Nat) (hk : k < xs.length) :
∃ x, (medianOfMedians xs k).ret = some x
def medianOfMedians {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| fuel + 1, ys, rank =>
if ys.length ≤ 140 then quickselect ys rank else do
let medians ← medianOfMediansGroups ys
let pivot ← loop fuel medians (medians.length / 2)
match pivot with
| none => pure none
| some x => do
let parts ← partition3 x ys
⋯
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians.lean:40
Uses 16 · Used by 4
TheoremMedian-of-medians selection fails exactly on out-of-range ranks#✓fully proved
For every list \(L\) over a linearly ordered type and every natural number \(k\), median-of-medians selection of rank \(k\) in \(L\) returns nothing if and only if \(k\) is at least the length of \(L\).
theorem medianOfMedians_eq_none_iff {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
(medianOfMedians xs k).ret = none ↔ xs.length ≤ k
def medianOfMedians {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| fuel + 1, ys, rank =>
if ys.length ≤ 140 then quickselect ys rank else do
let medians ← medianOfMediansGroups ys
let pivot ← loop fuel medians (medians.length / 2)
match pivot with
| none => pure none
| some x => do
let parts ← partition3 x ys
⋯
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians.lean:40
Uses 3 · Used by 1
TheoremMedian-of-medians selection agrees with sorting#✓fully proved
For every list \(L\) over a linearly ordered type and every natural number \(k\), median-of-medians selection of rank \(k\) in \(L\) returns the entry at zero-based position \(k\) of the insertion sort of \(L\) by \(\le\) when \(k\) is less than the length of \(L\), and returns nothing otherwise.
theorem medianOfMedians_eq_getElem?_insertionSort {α : Type u} [LinearOrder α]
(xs : List α) (k : Nat) :
(medianOfMedians xs k).ret = (xs.insertionSort (· ≤ ·))[k]?
def medianOfMedians {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| fuel + 1, ys, rank =>
if ys.length ≤ 140 then quickselect ys rank else do
let medians ← medianOfMediansGroups ys
let pivot ← loop fuel medians (medians.length / 2)
match pivot with
| none => pure none
| some x => do
let parts ← partition3 x ys
⋯
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians.lean:40
TheoremSet rank of a median-of-medians result#✓fully proved
Let \(L\) be a list without repeated entries over a linear order and let \(k \in \mathbb{N}\). If median-of-medians selection on \(L\) at zero-based rank \(k\) returns an element \(x\), then the set \(\{y \in L : y \le x\}\) has exactly \(k + 1\) elements.
theorem medianOfMedians_set_rank {α : Type u} [LinearOrder α]
{xs : List α} {k : Nat} {x : α} (hnodup : xs.Nodup)
(hresult : (medianOfMedians xs k).ret = some x) :
(xs.toFinset.filter (fun y => y ≤ x)).card = k + 1
def medianOfMedians {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| fuel + 1, ys, rank =>
if ys.length ≤ 140 then quickselect ys rank else do
let medians ← medianOfMediansGroups ys
let pivot ← loop fuel medians (medians.length / 2)
match pivot with
| none => pure none
| some x => do
let parts ← partition3 x ys
⋯
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians.lean:40
Uses 7 · Used by 1
TheoremOne-based rank of a median-of-medians result#✓fully proved
Let \(L\) be a list without repeated entries over a linear order and let \(i \ge 1\). If median-of-medians selection on \(L\) at zero-based rank \(i - 1\) returns an element \(x\), then the set \(\{y \in L : y \le x\}\) has exactly \(i\) elements.
theorem medianOfMedians_source_rank {α : Type u} [LinearOrder α]
{xs : List α} (i : Nat) (hi : 0 < i) (hnodup : xs.Nodup) {x : α}
(hresult : (medianOfMedians xs (i - 1)).ret = some x) :
(xs.toFinset.filter (fun y => y ≤ x)).card = i
def medianOfMedians {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| fuel + 1, ys, rank =>
if ys.length ≤ 140 then quickselect ys rank else do
let medians ← medianOfMediansGroups ys
let pivot ← loop fuel medians (medians.length / 2)
match pivot with
| none => pure none
| some x => do
let parts ← partition3 x ys
⋯
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians.lean:40
Uses 2 · Used by 1
TheoremMedian of medians selects every one-based rank#✓fully proved
Let \(L\) be a list without repeated entries over a linear order, of length \(n\), and let \(1 \le i \le n\). Then median-of-medians selection on \(L\) at zero-based rank \(i - 1\) returns an element \(x\) of \(L\), and the set \(\{y \in L : y \le x\}\) has exactly \(i\) elements.
theorem medianOfMedians_source_exists {α : Type u} [LinearOrder α]
(xs : List α) (i : Nat) (hi : 0 < i) (hlen : i ≤ xs.length) (hnodup : xs.Nodup) :
∃ x, (medianOfMedians xs (i - 1)).ret = some x ∧ x ∈ xs ∧
(xs.toFinset.filter (fun y => y ≤ x)).card = i
def medianOfMedians {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| fuel + 1, ys, rank =>
if ys.length ≤ 140 then quickselect ys rank else do
let medians ← medianOfMediansGroups ys
let pivot ← loop fuel medians (medians.length / 2)
match pivot with
| none => pure none
| some x => do
let parts ← partition3 x ys
⋯
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians.lean:40
TheoremMedian of medians finds the lower median#✓fully proved
Let \(L\) be a nonempty list of length \(n\) over a linear order, and let \(k = \lfloor (n - 1)/2 \rfloor\). Then median-of-medians selection on \(L\) at zero-based rank \(k\) returns an element \(x\) of \(L\) such that at most \(k\) entries of \(L\) are less than \(x\) and more than \(k\) entries of \(L\) are at most \(x\), where entries are counted with repetition.
theorem medianOfMedians_lower_median {α : Type u} [LinearOrder α]
(xs : List α) (hnonempty : 0 < xs.length) :
∃ x, (medianOfMedians xs ((xs.length - 1) / 2)).ret = some x ∧
x ∈ xs ∧ xs.countP (fun y => decide (y < x)) ≤ (xs.length - 1) / 2 ∧
(xs.length - 1) / 2 < xs.countP (fun y => decide (y ≤ x))
def medianOfMedians {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| fuel + 1, ys, rank =>
if ys.length ≤ 140 then quickselect ys rank else do
let medians ← medianOfMediansGroups ys
let pivot ← loop fuel medians (medians.length / 2)
match pivot with
| none => pure none
| some x => do
let parts ← partition3 x ys
⋯
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians.lean:40
Uses 3
TheoremMedian of medians finds the upper median#✓fully proved
Let \(L\) be a nonempty list of length \(n\) over a linear order, and let \(k = \lfloor n/2 \rfloor\). Then median-of-medians selection on \(L\) at zero-based rank \(k\) returns an element \(x\) of \(L\) such that at most \(k\) entries of \(L\) are less than \(x\) and more than \(k\) entries of \(L\) are at most \(x\), where entries are counted with repetition.
theorem medianOfMedians_upper_median {α : Type u} [LinearOrder α]
(xs : List α) (hnonempty : 0 < xs.length) :
∃ x, (medianOfMedians xs (xs.length / 2)).ret = some x ∧
x ∈ xs ∧ xs.countP (fun y => decide (y < x)) ≤ xs.length / 2 ∧
xs.length / 2 < xs.countP (fun y => decide (y ≤ x))
def medianOfMedians {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| fuel + 1, ys, rank =>
if ys.length ≤ 140 then quickselect ys rank else do
let medians ← medianOfMediansGroups ys
let pivot ← loop fuel medians (medians.length / 2)
match pivot with
| none => pure none
| some x => do
let parts ← partition3 x ys
⋯
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians.lean:40
Uses 3
TheoremSize budget for the two median-of-medians recursive calls#✓fully proved
Let \(n\), \(m\) and \(p\) be natural numbers with \(n \ge 140\), \(m \le \lfloor (n + 4)/5 \rfloor\) and \(p \le \lfloor 7n/10 \rfloor + 6\). Then \(20m + 20p + n \le 20n\).
theorem medianOfMedians_child_size_budget (n m p : Nat) (hn : 140 ≤ n)
(hm : m ≤ (n + 4) / 5) (hp : p ≤ 7 * n / 10 + 6) :
20 * m + 20 * p + n ≤ 20 * n
Used by 1
TheoremCost budget for one median-of-medians step#✓fully proved
Let \(n\), \(m\), \(p\), \(a\), \(c_1\) and \(c_2\) be natural numbers with \(n \ge 140\), \(m \le \lfloor (n + 4)/5 \rfloor\), \(p \le \lfloor 7n/10 \rfloor + 6\), \(c_1 \le 20am\) and \(c_2 \le 20ap\). Then \(c_1 + c_2 + an \le 20an\).
theorem medianOfMedians_combine_time (n m p a leftCost rightCost : Nat)
(hn : 140 ≤ n) (hm : m ≤ (n + 4) / 5) (hp : p ≤ 7 * n / 10 + 6)
(hleft : leftCost ≤ 20 * a * m) (hright : rightCost ≤ 20 * a * p) :
leftCost + rightCost + a * n ≤ 20 * a * n
Uses 1 · Used by 2
TheoremMedian of medians makes linearly many comparisons#✓fully proved
For every list \(L\) of length \(n\) over a linear order and every \(k \in \mathbb{N}\), median-of-medians selection on \(L\) at rank \(k\) charges at most \(80n\) comparisons, where \(n\) counts repeated entries.
Only order comparisons are charged; list construction, rank checks and recursion are free.
theorem medianOfMedians_time {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
(medianOfMedians xs k).time ≤ 80 * xs.length
def medianOfMedians {α : Type u} [LinearOrder α] (xs : List α) (k : Nat) :
TimeM Nat (Option α) :=
let rec loop : Nat → List α → Nat → TimeM Nat (Option α)
| 0, _, _ => pure none
| fuel + 1, ys, rank =>
if ys.length ≤ 140 then quickselect ys rank else do
let medians ← medianOfMediansGroups ys
let pivot ← loop fuel medians (medians.length / 2)
match pivot with
| none => pure none
| some x => do
let parts ← partition3 x ys
⋯
CSLibExt/Algorithms/Lean/Selection/MedianOfMedians.lean:40
Uses 20
TheoremLinear solution of the median-of-medians recurrence#✓fully proved
Let \(T : \mathbb{N} \to \mathbb{N}\) and \(a \in \mathbb{N}\). Suppose that \(T(n) \le 20an\) for every \(n \le 140\), and that for every \(n > 140\) there are \(m, p \in \mathbb{N}\) with \(m \le \lfloor (n + 4)/5 \rfloor\), \(p \le \lfloor 7n/10 \rfloor + 6\) and \(T(n) \le T(m) + T(p) + an\). Then \(T(n) \le 20an\) for every \(n \in \mathbb{N}\).
theorem medianOfMedians_linear_recurrence (T : Nat → Nat) (a : Nat)
(hbase : ∀ n, n ≤ 140 → T n ≤ 20 * a * n)
(hstep : ∀ n, 140 < n → ∃ m p,
m ≤ (n + 4) / 5 ∧ p ≤ 7 * n / 10 + 6 ∧ T n ≤ T m + T p + a * n) :
∀ n, T n ≤ 20 * a * n
Uses 1
Loading dependency explorer…
The dependency explorer needs JavaScript and its graph data.