Quicksort
DefinitionQuicksort#✓fully proved
Deterministic quicksort on lists over a linear order, using the first entry as pivot and counting comparisons. The empty list is returned unchanged at no cost. On a list with first entry \(p\) and tail \(t\), the algorithm stably splits \(t\) into the entries less than \(p\), equal to \(p\) and greater than \(p\), using one comparison per entry of \(t\); it then recursively sorts the lesser and greater parts and returns the sorted lesser part, followed by \(p\), the entries equal to \(p\) in their original order, and the sorted greater part. The cost is the total number of comparisons.
def quickSort (xs : List α) : TimeM Nat (List α) :=
let rec loop : Nat → List α → TimeM Nat (List α)
| 0, _ => pure []
| _ + 1, [] => pure []
| fuel + 1, pivot :: tail => do
let parts ← partition3 pivot tail
let below ← loop fuel parts.below
let above ← loop fuel parts.above
return below ++ (pivot :: (parts.equal ++ above))
loop xs.length xs
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 2 · Used by 4
TheoremCorrectness of quicksort#✓fully proved
For every list \(\ell\) over a linear order, the output of quicksort on \(\ell\) is sorted in nondecreasing order and is a permutation of \(\ell\); in particular every value occurs in the output exactly as often as in \(\ell\).
theorem quickSort_correct (xs : List α) :
List.Pairwise (fun x y => x ≤ y) (quickSort xs).ret ∧
List.Perm (quickSort xs).ret xs
def quickSort (xs : List α) : TimeM Nat (List α) :=
let rec loop : Nat → List α → TimeM Nat (List α)
| 0, _ => pure []
| _ + 1, [] => pure []
| fuel + 1, pivot :: tail => do
let parts ← partition3 pivot tail
let below ← loop fuel parts.below
let above ← loop fuel parts.above
return below ++ (pivot :: (parts.equal ++ above))
loop xs.length xs
CSLibExt/Algorithms/Lean/Sort/Quick.lean:36
Uses 5
TheoremWorst-case comparison bound for quicksort#✓fully proved
For every list of length \(n\) over a linear order, quicksort performs at most \(n(n-1)/2\) comparisons.
theorem quickSort_time (xs : List α) :
(quickSort xs).time ≤ xs.length * (xs.length - 1) / 2
def quickSort (xs : List α) : TimeM Nat (List α) :=
let rec loop : Nat → List α → TimeM Nat (List α)
| 0, _ => pure []
| _ + 1, [] => pure []
| fuel + 1, pivot :: tail => do
let parts ← partition3 pivot tail
let below ← loop fuel parts.below
let above ← loop fuel parts.above
return below ++ (pivot :: (parts.equal ++ above))
loop xs.length xs
CSLibExt/Algorithms/Lean/Sort/Quick.lean:36
Uses 5
DefinitionNumber of list entries strictly between two values#✓fully proved
For a list \(\ell\) over a linear order and elements \(a\) and \(b\), this is the number of entries \(x\) of \(\ell\), counted with multiplicity, such that \(a < x < b\).
public def betweenCount (xs : List α) (a b : α) : ℕ :=
(xs.filter (fun x => a < x ∧ x < b)).length
TheoremExpected comparisons of quicksort on a random permutation#✓fully proved
Let \(\ell\) be a list without repeated entries over a linear order. The expected number of comparisons made by quicksort on the list obtained by rearranging the entries of \(\ell\) by a uniformly random permutation of their positions, computed in the extended nonnegative reals \([0, \infty]\), equals
where the sum runs over pairs of entries \(a < b\) of \(\ell\) and \(d(a, b)\) is the number of entries of \(\ell\) strictly between \(a\) and \(b\) (CLRS Section 7.4).
public theorem quickSort_expectedTime_uniformPermutation
(xs : List α) (hxs : xs.Nodup) :
expectedTime quickSort (uniformPermutation xs) =
∑ p ∈ (xs.toFinset ×ˢ xs.toFinset).filter (fun p => p.1 < p.2),
(2 : ℝ≥0∞) * ((betweenCount xs p.1 p.2 + 2 : ℝ≥0∞))⁻¹
noncomputable def expectedTime (algo : γ → TimeM Nat β)
(dist : PMF γ) : ℝ≥0∞ :=
dist.expectENN (fun xs => ((algo xs).time : ℝ≥0∞))
CSLibExt/Algorithms/Lean/Random/ExpectedCost.lean:49
def quickSort (xs : List α) : TimeM Nat (List α) :=
let rec loop : Nat → List α → TimeM Nat (List α)
| 0, _ => pure []
| _ + 1, [] => pure []
| fuel + 1, pivot :: tail => do
let parts ← partition3 pivot tail
let below ← loop fuel parts.below
let above ← loop fuel parts.above
return below ++ (pivot :: (parts.equal ++ above))
loop xs.length xs
CSLibExt/Algorithms/Lean/Sort/Quick.lean:36
noncomputable def uniformPermutation (xs : List α) : PMF (List α) :=
(Cslib.Probability.PMF.uniformOfFintype (Equiv.Perm (Fin xs.length))).map
(fun σ => List.ofFn (fun p => xs.get (σ p)))
CSLibExt/Algorithms/Lean/Random/ExpectedCost.lean:55
public def betweenCount (xs : List α) (a b : α) : ℕ :=
(xs.filter (fun x => a < x ∧ x < b)).length
CSLibExt/Algorithms/Lean/Sort/QuickExpected.lean:49
Uses 12 · Used by 1
TheoremExpected comparisons of quicksort on a random permutation, as a real number#✓fully proved
Let \(\ell\) be a list without repeated entries over a linear order. Take the expected number of comparisons made by quicksort on the list obtained by rearranging the entries of \(\ell\) by a uniformly random permutation of their positions, which is an element of \([0, \infty]\), and convert it to a real number. The result equals the real sum
where the sum runs over pairs of entries \(a < b\) of \(\ell\) and \(d(a, b)\) is the number of entries of \(\ell\) strictly between \(a\) and \(b\).
public theorem quickSort_expectedTime_uniformPermutation_toReal
(xs : List α) (hxs : xs.Nodup) :
(expectedTime quickSort (uniformPermutation xs)).toReal =
∑ p ∈ (xs.toFinset ×ˢ xs.toFinset).filter (fun p => p.1 < p.2),
(2 : ℝ) / (betweenCount xs p.1 p.2 + 2)
noncomputable def expectedTime (algo : γ → TimeM Nat β)
(dist : PMF γ) : ℝ≥0∞ :=
dist.expectENN (fun xs => ((algo xs).time : ℝ≥0∞))
CSLibExt/Algorithms/Lean/Random/ExpectedCost.lean:49
def quickSort (xs : List α) : TimeM Nat (List α) :=
let rec loop : Nat → List α → TimeM Nat (List α)
| 0, _ => pure []
| _ + 1, [] => pure []
| fuel + 1, pivot :: tail => do
let parts ← partition3 pivot tail
let below ← loop fuel parts.below
let above ← loop fuel parts.above
return below ++ (pivot :: (parts.equal ++ above))
loop xs.length xs
CSLibExt/Algorithms/Lean/Sort/Quick.lean:36
noncomputable def uniformPermutation (xs : List α) : PMF (List α) :=
(Cslib.Probability.PMF.uniformOfFintype (Equiv.Perm (Fin xs.length))).map
(fun σ => List.ofFn (fun p => xs.get (σ p)))
CSLibExt/Algorithms/Lean/Random/ExpectedCost.lean:55
public def betweenCount (xs : List α) (a b : α) : ℕ :=
(xs.filter (fun x => a < x ∧ x < b)).length
CSLibExt/Algorithms/Lean/Sort/QuickExpected.lean:49
Loading dependency explorer…
The dependency explorer needs JavaScript and its graph data.