Skip to content

Instantly share code, notes, and snippets.

@britannio
Created March 6, 2024 19:41
Show Gist options
  • Save britannio/e352a93ee3ee025818629b523f6ab51d to your computer and use it in GitHub Desktop.
Save britannio/e352a93ee3ee025818629b523f6ab51d to your computer and use it in GitHub Desktop.
module QuickSortPermutationSimple
#push-options "--fuel 1 --ifuel 1"
//Some auxiliary definitions to make this a standalone example
let rec length #a (l:list a)
: nat
= match l with
| [] -> 0
| _ :: tl -> 1 + length tl
let rec append #a (l1 l2:list a)
: list a
= match l1 with
| [] -> l2
| hd :: tl -> hd :: append tl l2
let rec sorted (l:list int)
: bool
= match l with
| [] -> true
| [x] -> true
| x :: y :: xs -> x <= y && sorted (y :: xs)
let rec count (#a:eqtype) (x:a) (l:list a)
: nat
= match l with
| hd::tl -> (if hd = x then 1 else 0) + count x tl
| [] -> 0
let mem (#a:eqtype) (i:a) (l:list a)
: bool
= count i l > 0
let is_permutation (#a:eqtype) (l m:list a) =
forall x. count x l = count x m
let rec append_count (#t:eqtype)
(l1 l2:list t)
: Lemma (ensures (forall a. count a (append l1 l2) = (count a l1 + count a l2)))
= match l1 with
| [] -> ()
| hd::tl -> append_count tl l2
let rec partition (#a:Type) (f:a -> bool) (l:list a)
: x:(list a & list a) { length (fst x) + length (snd x) = length l }
= match l with
| [] -> [], []
| hd::tl ->
let l1, l2 = partition f tl in
if f hd
then hd::l1, l2
else l1, hd::l2
let rec sort (l:list int)
: Tot (list int) (decreases (length l))
= match l with
| [] -> []
| pivot :: tl ->
let hi, lo = partition ((<=) pivot) tl in
append (sort lo) (pivot :: sort hi)
let rec partition_mem_permutation (#a:eqtype)
(f:(a -> bool))
(l:list a)
: Lemma (let l1, l2 = partition f l in
(forall x. mem x l1 ==> f x) /\
(forall x. mem x l2 ==> not (f x)) /\
(is_permutation l (append l1 l2)))
= match l with
| [] -> ()
| hd :: tl ->
partition_mem_permutation f tl;
let hi, lo = partition f tl in
append_count hi lo;
append_count hi (hd::lo);
append_count (hd :: hi) lo
let rec sorted_concat (l1:list int{sorted l1})
(l2:list int{sorted l2})
(pivot:int)
: Lemma (requires (forall y. mem y l1 ==> not (pivot <= y)) /\
(forall y. mem y l2 ==> pivot <= y))
(ensures sorted (append l1 (pivot :: l2)))
= match l1 with
| [] -> ()
| hd :: tl -> sorted_concat tl l2 pivot
let permutation_app_lemma (#a:eqtype) (hd:a) (tl:list a)
(l1:list a) (l2:list a)
: Lemma (requires (is_permutation tl (append l1 l2)))
(ensures (is_permutation (hd::tl) (append l1 (hd::l2))))
= append_count l1 l2;
append_count l1 (hd :: l2)
let rec sort_correct (l:list int)
: Lemma (ensures (
sorted (sort l) /\
is_permutation l (sort l)))
(decreases (length l))
= match l with
| [] -> ()
| pivot :: tl ->
let hi, lo = partition ((<=) pivot) tl in
partition_mem_permutation ((<=) pivot) tl;
append_count lo hi;
append_count hi lo;
assert (is_permutation tl (append lo hi));
sort_correct hi;
sort_correct lo;
sorted_concat (sort lo) (sort hi) pivot;
append_count (sort lo) (sort hi);
assert (is_permutation tl (sort lo `append` sort hi));
permutation_app_lemma pivot tl (sort lo) (sort hi)
let rec sort_intrinsic (l:list int)
: Tot (m:list int {
sorted m /\
is_permutation l m
})
(decreases (length l))
= match l with
| [] -> []
| pivot :: tl ->
let hi, lo = partition ((<=) pivot) tl in
partition_mem_permutation ((<=) pivot) tl;
append_count lo hi; append_count hi lo;
sorted_concat (sort_intrinsic lo) (sort_intrinsic hi) pivot;
append_count (sort_intrinsic lo) (sort_intrinsic hi);
permutation_app_lemma pivot tl (sort_intrinsic lo) (sort_intrinsic hi);
append (sort_intrinsic lo) (pivot :: sort_intrinsic hi)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment