Initial data commit
This commit is contained in:
parent
72d218235f
commit
f23f22d71c
199087 changed files with 3378941 additions and 0 deletions
|
|
@ -0,0 +1,680 @@
|
|||
(*------------------------------------------------------------------*)
|
||||
|
||||
#include "share/atspre_staload.hats"
|
||||
|
||||
vtypedef array_tup_vt (a : vt@ype+, p : addr, n : int) =
|
||||
(* An array, without size information attached. *)
|
||||
@(array_v (a, p, n),
|
||||
mfree_gc_v p |
|
||||
ptr p)
|
||||
|
||||
extern fn {a : t@ype}
|
||||
patience_sort
|
||||
{ifirst, len : int | 0 <= ifirst}
|
||||
{n : int | ifirst + len <= n}
|
||||
(arr : &RD(array (a, n)),
|
||||
ifirst : size_t ifirst,
|
||||
len : size_t len)
|
||||
:<!wrt> (* Return an array of indices into arr. *)
|
||||
[p : addr]
|
||||
array_tup_vt
|
||||
([i : int | len == 0 ||
|
||||
(ifirst <= i && i < ifirst + len)] size_t i,
|
||||
p, len)
|
||||
|
||||
(* patience_sort$lt : the order predicate. *)
|
||||
extern fn {a : t@ype}
|
||||
patience_sort$lt (x : a, y : a) :<> bool
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
(*
|
||||
|
||||
In the following implementation of next_power_of_two:
|
||||
|
||||
* I implement it as a template for all types of kind g1uint. This
|
||||
includes dependent forms of uint, usint, ulint, ullint, size_t,
|
||||
and yet more types in the prelude; also whatever others one may
|
||||
create.
|
||||
|
||||
* I prove the result is not less than the input.
|
||||
|
||||
* I prove the result is less than twice the input.
|
||||
|
||||
* I prove the result is a power of two. This last proof is
|
||||
provided in the form of an EXP2 prop.
|
||||
|
||||
* I do NOT return what number two is raised to (though I easily
|
||||
could have). I leave that number "existentially defined". In
|
||||
other words, I prove only that some such non-negative number
|
||||
exists.
|
||||
|
||||
*)
|
||||
|
||||
fn {tk : tkind}
|
||||
next_power_of_two
|
||||
{i : pos}
|
||||
(i : g1uint (tk, i))
|
||||
:<> [k : int | i <= k; k < 2 * i]
|
||||
[n : nat]
|
||||
@(EXP2 (n, k) | g1uint (tk, k)) =
|
||||
let
|
||||
(* This need not be a fast implementation. *)
|
||||
|
||||
val one : g1uint (tk, 1) = g1u2u 1u
|
||||
|
||||
fun
|
||||
loop {j : pos | j < i} .<i + i - j>.
|
||||
(pf : [n : nat] EXP2 (n, j) |
|
||||
j : g1uint (tk, j))
|
||||
:<> [k : int | i <= k; k < 2 * i]
|
||||
[n : nat]
|
||||
@(EXP2 (n, k) | g1uint (tk, k)) =
|
||||
let
|
||||
val j2 = j + j
|
||||
in
|
||||
if i <= j2 then
|
||||
@(EXP2ind pf | j2)
|
||||
else
|
||||
loop (EXP2ind pf | j2)
|
||||
end
|
||||
in
|
||||
if i = one then
|
||||
@(EXP2bas () | one)
|
||||
else
|
||||
loop (EXP2bas () | one)
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
stadef link (ifirst : int, ilast : int, i : int) : bool =
|
||||
0 <= i && i <= ilast - ifirst + 1
|
||||
|
||||
typedef link_t (ifirst : int, ilast : int, i : int) =
|
||||
(* A size_t within legal range for a normalized link, including the
|
||||
"nil" link 0. *)
|
||||
[link (ifirst, ilast, i)]
|
||||
size_t i
|
||||
typedef link_t (ifirst : int, ilast : int) =
|
||||
[i : int]
|
||||
link_t (ifirst, ilast, i)
|
||||
|
||||
fn {a : t@ype}
|
||||
find_pile {ifirst, ilast : int | ifirst <= ilast}
|
||||
{n : int | ilast < n}
|
||||
{num_piles : nat | num_piles <= ilast - ifirst + 1}
|
||||
{n_piles : int | ilast - ifirst + 1 <= n_piles}
|
||||
{q : pos | q <= ilast - ifirst + 1}
|
||||
(ifirst : size_t ifirst,
|
||||
arr : &RD(array (a, n)),
|
||||
num_piles : size_t num_piles,
|
||||
piles : &RD(array (link_t (ifirst, ilast),
|
||||
n_piles)),
|
||||
q : size_t q)
|
||||
:<> [i : pos | i <= num_piles + 1]
|
||||
size_t i =
|
||||
(*
|
||||
Bottenbruch search for the leftmost pile whose top is greater than
|
||||
or equal to the next value dealt by "deal".
|
||||
|
||||
References:
|
||||
|
||||
* H. Bottenbruch, "Structure and use of ALGOL 60", Journal of
|
||||
the ACM, Volume 9, Issue 2, April 1962, pp.161-221.
|
||||
https://doi.org/10.1145/321119.321120
|
||||
|
||||
The general algorithm is described on pages 214 and 215.
|
||||
|
||||
* https://en.wikipedia.org/w/index.php?title=Binary_search_algorithm&oldid=1062988272#Alternative_procedure
|
||||
*)
|
||||
if num_piles = i2sz 0 then
|
||||
i2sz 1
|
||||
else
|
||||
let
|
||||
macdef lt = patience_sort$lt<a>
|
||||
|
||||
prval () = lemma_g1uint_param ifirst
|
||||
prval () = prop_verify {0 <= ifirst} ()
|
||||
|
||||
fun
|
||||
loop {j, k : nat | j <= k; k < num_piles}
|
||||
.<k - j>.
|
||||
(arr : &RD(array (a, n)),
|
||||
piles : &array (link_t (ifirst, ilast), n_piles),
|
||||
j : size_t j,
|
||||
k : size_t k)
|
||||
:<> [i : pos | i <= num_piles + 1]
|
||||
size_t i =
|
||||
if j = k then
|
||||
begin
|
||||
if succ j <> num_piles then
|
||||
succ j
|
||||
else
|
||||
let
|
||||
val piles_j = piles[j]
|
||||
val () = $effmask_exn assertloc (piles_j <> g1u2u 0u)
|
||||
|
||||
val x1 = arr[pred q + ifirst]
|
||||
and x2 = arr[pred piles_j + ifirst]
|
||||
in
|
||||
if x2 \lt x1 then
|
||||
succ (succ j)
|
||||
else
|
||||
succ j
|
||||
end
|
||||
end
|
||||
else
|
||||
let
|
||||
typedef index (i : int) = [0 <= i; i < n] size_t i
|
||||
typedef index = [i : int] index i
|
||||
|
||||
stadef i = j + ((k - j) / 2)
|
||||
val i : size_t i = j + ((k - j) / g1u2u 2u)
|
||||
|
||||
val piles_j = piles[j]
|
||||
val () = $effmask_exn assertloc (piles_j <> g1u2u 0u)
|
||||
|
||||
val x1 = arr[pred q + ifirst]
|
||||
and x2 = arr[pred piles_j + ifirst]
|
||||
in
|
||||
if x2 \lt x1 then
|
||||
loop (arr, piles, i + 1, k)
|
||||
else
|
||||
loop (arr, piles, j, i)
|
||||
end
|
||||
in
|
||||
loop (arr, piles, g1u2u 0u, pred num_piles)
|
||||
end
|
||||
|
||||
fn {a : t@ype}
|
||||
deal {ifirst, ilast : int | ifirst <= ilast}
|
||||
{n : int | ilast < n}
|
||||
(ifirst : size_t ifirst,
|
||||
ilast : size_t ilast,
|
||||
arr : &RD(array (a, n)))
|
||||
:<!wrt> [num_piles : int | num_piles <= ilast - ifirst + 1]
|
||||
[n_piles : int | ilast - ifirst + 1 <= n_piles]
|
||||
[n_links : int | ilast - ifirst + 1 <= n_links]
|
||||
[p_piles : addr]
|
||||
[p_links : addr]
|
||||
@(size_t num_piles,
|
||||
array_tup_vt (link_t (ifirst, ilast),
|
||||
p_piles, n_piles),
|
||||
array_tup_vt (link_t (ifirst, ilast),
|
||||
p_links, n_links)) =
|
||||
let
|
||||
prval () = prop_verify {0 < ilast - ifirst + 1} ()
|
||||
|
||||
stadef num_elems = ilast - ifirst + 1
|
||||
val num_elems : size_t num_elems = succ (ilast - ifirst)
|
||||
|
||||
typedef link_t (i : int) = link_t (ifirst, ilast, i)
|
||||
typedef link_t = link_t (ifirst, ilast)
|
||||
|
||||
val zero : size_t 0 = g1u2u 0u
|
||||
val one : size_t 1 = g1u2u 1u
|
||||
val link_nil : link_t 0 = g1u2u 0u
|
||||
|
||||
fun
|
||||
loop {q : pos | q <= num_elems + 1}
|
||||
{m : nat | m <= num_elems}
|
||||
.<num_elems + 1 - q>.
|
||||
(arr : &RD(array (a, n)),
|
||||
q : size_t q,
|
||||
piles : &array (link_t, num_elems),
|
||||
links : &array (link_t, num_elems),
|
||||
m : size_t m)
|
||||
:<!wrt> [num_piles : nat | num_piles <= num_elems]
|
||||
size_t num_piles =
|
||||
if q = succ (num_elems) then
|
||||
m
|
||||
else
|
||||
let
|
||||
val i = find_pile {ifirst, ilast} (ifirst, arr, m, piles, q)
|
||||
|
||||
(* We have no proof the number of elements will not exceed
|
||||
storage. However, we know it will not, because the number
|
||||
of piles cannot exceed the size of the input. Let us get
|
||||
a "proof" by runtime check. *)
|
||||
val () = $effmask_exn assertloc (i <= num_elems)
|
||||
in
|
||||
links[pred q] := piles[pred i];
|
||||
piles[pred i] := q;
|
||||
if i = succ m then
|
||||
loop {q + 1} (arr, succ q, piles, links, succ m)
|
||||
else
|
||||
loop {q + 1} (arr, succ q, piles, links, m)
|
||||
end
|
||||
|
||||
val piles_tup = array_ptr_alloc<link_t> num_elems
|
||||
macdef piles = !(piles_tup.2)
|
||||
val () = array_initize_elt<link_t> (piles, num_elems, link_nil)
|
||||
|
||||
val links_tup = array_ptr_alloc<link_t> num_elems
|
||||
macdef links = !(links_tup.2)
|
||||
val () = array_initize_elt<link_t> (links, num_elems, link_nil)
|
||||
|
||||
val num_piles = loop (arr, one, piles, links, zero)
|
||||
in
|
||||
@(num_piles, piles_tup, links_tup)
|
||||
end
|
||||
|
||||
fn {a : t@ype}
|
||||
k_way_merge {ifirst, ilast : int | ifirst <= ilast}
|
||||
{n : int | ilast < n}
|
||||
{n_piles : int | ilast - ifirst + 1 <= n_piles}
|
||||
{num_piles : pos | num_piles <= ilast - ifirst + 1}
|
||||
{n_links : int | ilast - ifirst + 1 <= n_links}
|
||||
(ifirst : size_t ifirst,
|
||||
ilast : size_t ilast,
|
||||
arr : &RD(array (a, n)),
|
||||
num_piles : size_t num_piles,
|
||||
piles : &array (link_t (ifirst, ilast), n_piles),
|
||||
links : &array (link_t (ifirst, ilast), n_links))
|
||||
:<!wrt> (* Return an array of indices into arr. *)
|
||||
[p : addr]
|
||||
array_tup_vt
|
||||
([i : int | ifirst <= i; i <= ilast] size_t i,
|
||||
p, ilast - ifirst + 1) =
|
||||
(*
|
||||
k-way merge by tournament tree.
|
||||
|
||||
See Knuth, volume 3, and also
|
||||
https://en.wikipedia.org/w/index.php?title=K-way_merge_algorithm&oldid=1047851465#Tournament_Tree
|
||||
|
||||
However, I store a winners tree instead of the recommended losers
|
||||
tree. If the tree were stored as linked nodes, it would probably
|
||||
be more efficient to store a losers tree. However, I am storing
|
||||
the tree as an array, and one can find an opponent quickly by
|
||||
simply toggling the least significant bit of a competitor's array
|
||||
index.
|
||||
*)
|
||||
let
|
||||
typedef link_t (i : int) = link_t (ifirst, ilast, i)
|
||||
typedef link_t = [i : int] link_t i
|
||||
|
||||
val link_nil : link_t 0 = g1u2u 0u
|
||||
|
||||
typedef index_t (i : int) = [ifirst <= i; i <= ilast] size_t i
|
||||
typedef index_t = [i : int] index_t i
|
||||
|
||||
val [total_external_nodes : int]
|
||||
@(_ | total_external_nodes) = next_power_of_two num_piles
|
||||
prval () = prop_verify {num_piles <= total_external_nodes} ()
|
||||
|
||||
stadef total_nodes = (2 * total_external_nodes) - 1
|
||||
val total_nodes : size_t total_nodes =
|
||||
pred (g1u2u 2u * total_external_nodes)
|
||||
|
||||
(* We will ignore index 0 of the winners tree arrays. *)
|
||||
stadef winners_size = total_nodes + 1
|
||||
val winners_size : size_t winners_size = succ total_nodes
|
||||
|
||||
val winners_values_tup = array_ptr_alloc<link_t> winners_size
|
||||
macdef winners_values = !(winners_values_tup.2)
|
||||
val () = array_initize_elt<link_t> (winners_values, winners_size,
|
||||
link_nil)
|
||||
|
||||
val winners_links_tup = array_ptr_alloc<link_t> winners_size
|
||||
macdef winners_links = !(winners_links_tup.2)
|
||||
val () = array_initize_elt<link_t> (winners_links, winners_size,
|
||||
link_nil)
|
||||
|
||||
(* - - - - - - - - - - - - - - - - - - - - - - - - - - *)
|
||||
(* Record which pile a winner will have come from. *)
|
||||
|
||||
fun
|
||||
init_pile_links
|
||||
{i : nat | i <= num_piles}
|
||||
.<num_piles - i>.
|
||||
(winners_links : &array (link_t, winners_size),
|
||||
i : size_t i)
|
||||
:<!wrt> void =
|
||||
if i <> num_piles then
|
||||
begin
|
||||
winners_links[total_external_nodes + i] := succ i;
|
||||
init_pile_links (winners_links, succ i)
|
||||
end
|
||||
|
||||
val () = init_pile_links (winners_links, g1u2u 0u)
|
||||
|
||||
(* - - - - - - - - - - - - - - - - - - - - - - - - - - *)
|
||||
(* The top of each pile becomes a starting competitor. *)
|
||||
|
||||
fun
|
||||
init_competitors
|
||||
{i : nat | i <= num_piles}
|
||||
.<num_piles - i>.
|
||||
(winners_values : &array (link_t, winners_size),
|
||||
piles : &array (link_t, n_piles),
|
||||
i : size_t i)
|
||||
:<!wrt> void =
|
||||
if i <> num_piles then
|
||||
begin
|
||||
winners_values[total_external_nodes + i] := piles[i];
|
||||
init_competitors (winners_values, piles, succ i)
|
||||
end
|
||||
|
||||
val () = init_competitors (winners_values, piles, g1u2u 0u)
|
||||
|
||||
(* - - - - - - - - - - - - - - - - - - - - - - - - - - *)
|
||||
(* Discard the top of each pile. *)
|
||||
|
||||
fun
|
||||
discard_tops {i : nat | i <= num_piles}
|
||||
.<num_piles - i>.
|
||||
(piles : &array (link_t, n_piles),
|
||||
links : &array (link_t, n_links),
|
||||
i : size_t i)
|
||||
:<!wrt> void =
|
||||
if i <> num_piles then
|
||||
let
|
||||
val link = piles[i]
|
||||
|
||||
(* None of the piles should have been empty. *)
|
||||
val () = $effmask_exn assertloc (link <> g1u2u 0u)
|
||||
in
|
||||
piles[i] := links[pred link];
|
||||
discard_tops (piles, links, succ i)
|
||||
end
|
||||
|
||||
val () = discard_tops (piles, links, g1u2u 0u)
|
||||
|
||||
(* - - - - - - - - - - - - - - - - - - - - - - - - - - *)
|
||||
(* How to play a game. *)
|
||||
|
||||
fn
|
||||
play_game {i : int | 2 <= i; i <= total_nodes}
|
||||
(arr : &RD(array (a, n)),
|
||||
winners_values : &array (link_t, winners_size),
|
||||
i : size_t i)
|
||||
:<> [iwinner : pos | iwinner <= total_nodes]
|
||||
size_t iwinner =
|
||||
let
|
||||
macdef lt = patience_sort$lt<a>
|
||||
|
||||
fn
|
||||
find_opponent {i : int | 2 <= i; i <= total_nodes}
|
||||
(i : size_t i)
|
||||
:<> [j : int | 2 <= j; j <= total_nodes]
|
||||
size_t j =
|
||||
let
|
||||
(* The prelude contains bitwise operations only for
|
||||
non-dependent unsigned integer. We will not bother to
|
||||
add them ourselves, but instead go back and forth
|
||||
between dependent and non-dependent. *)
|
||||
val i0 = g0ofg1 i
|
||||
val j0 = g0uint_lxor<size_kind> (i0, g0u2u 1u)
|
||||
val j = g1ofg0 j0
|
||||
|
||||
(* We have no proof the opponent is in the proper
|
||||
range. Create a "proof" by runtime checks. *)
|
||||
val () = $effmask_exn assertloc (g1u2u 2u <= j)
|
||||
val () = $effmask_exn assertloc (j <= total_nodes)
|
||||
in
|
||||
j
|
||||
end
|
||||
|
||||
val j = find_opponent i
|
||||
val winner_i = winners_values[i]
|
||||
and winner_j = winners_values[j]
|
||||
in
|
||||
if winner_i = link_nil then
|
||||
j
|
||||
else if winner_j = link_nil then
|
||||
i
|
||||
else
|
||||
let
|
||||
val i1 = pred winner_i + ifirst
|
||||
and i2 = pred winner_j + ifirst
|
||||
prval () = lemma_g1uint_param i1
|
||||
prval () = lemma_g1uint_param i2
|
||||
in
|
||||
if arr[i2] \lt arr[i1] then j else i
|
||||
end
|
||||
end
|
||||
|
||||
(* - - - - - - - - - - - - - - - - - - - - - - - - - - *)
|
||||
|
||||
fun
|
||||
build_tree {istart : pos | istart <= total_external_nodes}
|
||||
.<istart>.
|
||||
(arr : &RD(array (a, n)),
|
||||
winners_values : &array (link_t, winners_size),
|
||||
winners_links : &array (link_t, winners_size),
|
||||
istart : size_t istart)
|
||||
:<!wrt> void =
|
||||
if istart <> 1 then
|
||||
let
|
||||
fun
|
||||
play_initial_games
|
||||
{i : int | istart <= i; i <= (2 * istart) + 1}
|
||||
.<(2 * istart) + 1 - i>.
|
||||
(arr : &RD(array (a, n)),
|
||||
winners_values : &array (link_t, winners_size),
|
||||
winners_links : &array (link_t, winners_size),
|
||||
i : size_t i)
|
||||
:<!wrt> void =
|
||||
if i <= pred (istart + istart) then
|
||||
let
|
||||
val iwinner = play_game (arr, winners_values, i)
|
||||
and i2 = i / g1u2u 2u
|
||||
in
|
||||
winners_values[i2] := winners_values[iwinner];
|
||||
winners_links[i2] := winners_links[iwinner];
|
||||
play_initial_games (arr, winners_values,
|
||||
winners_links, succ (succ i))
|
||||
end
|
||||
in
|
||||
play_initial_games (arr, winners_values, winners_links,
|
||||
istart);
|
||||
build_tree (arr, winners_values, winners_links,
|
||||
istart / g1u2u 2u)
|
||||
end
|
||||
|
||||
val () = build_tree (arr, winners_values, winners_links,
|
||||
total_external_nodes)
|
||||
|
||||
(* - - - - - - - - - - - - - - - - - - - - - - - - - - *)
|
||||
|
||||
fun
|
||||
replay_games {i : pos | i <= total_nodes}
|
||||
.<i>.
|
||||
(arr : &RD(array (a, n)),
|
||||
winners_values : &array (link_t, winners_size),
|
||||
winners_links : &array (link_t, winners_size),
|
||||
i : size_t i)
|
||||
:<!wrt> void =
|
||||
if i <> g1u2u 1u then
|
||||
let
|
||||
val iwinner = play_game (arr, winners_values, i)
|
||||
and i2 = i / g1u2u 2u
|
||||
in
|
||||
winners_values[i2] := winners_values[iwinner];
|
||||
winners_links[i2] := winners_links[iwinner];
|
||||
replay_games (arr, winners_values, winners_links, i2)
|
||||
end
|
||||
|
||||
stadef num_elems = ilast - ifirst + 1
|
||||
val num_elems : size_t num_elems = succ (ilast - ifirst)
|
||||
|
||||
val sorted_tup = array_ptr_alloc<index_t> num_elems
|
||||
|
||||
fun
|
||||
merge {isorted : nat | isorted <= num_elems}
|
||||
{p_sorted : addr}
|
||||
.<num_elems - isorted>.
|
||||
(pf_sorted : !array_v (index_t?, p_sorted,
|
||||
num_elems - isorted)
|
||||
>> array_v (index_t, p_sorted,
|
||||
num_elems - isorted) |
|
||||
arr : &RD(array (a, n)),
|
||||
piles : &array (link_t, n_piles),
|
||||
links : &array (link_t, n_links),
|
||||
winners_values : &array (link_t, winners_size),
|
||||
winners_links : &array (link_t, winners_size),
|
||||
p_sorted : ptr p_sorted,
|
||||
isorted : size_t isorted)
|
||||
:<!wrt> void =
|
||||
(* This function not only fills in the "sorted_tup" array, but
|
||||
transforms it from "uninitialized" to "initialized". *)
|
||||
if isorted <> num_elems then
|
||||
let
|
||||
prval @(pf_elem, pf_rest) = array_v_uncons pf_sorted
|
||||
val winner = winners_values[1]
|
||||
val () = $effmask_exn assertloc (winner <> link_nil)
|
||||
val () = !p_sorted := pred winner + ifirst
|
||||
|
||||
(* Move to the next element in the winner's pile. *)
|
||||
val ilink = winners_links[1]
|
||||
val () = $effmask_exn assertloc (ilink <> link_nil)
|
||||
val inext = piles[pred ilink]
|
||||
val () = (if inext <> link_nil then
|
||||
piles[pred ilink] := links[pred inext])
|
||||
|
||||
(* Replay games, with the new element as a competitor. *)
|
||||
val i = (total_nodes / g1u2u 2u) + ilink
|
||||
val () = $effmask_exn assertloc (i <= total_nodes)
|
||||
val () = winners_values[i] := inext
|
||||
val () =
|
||||
replay_games (arr, winners_values, winners_links, i)
|
||||
|
||||
val () = merge (pf_rest | arr, piles, links,
|
||||
winners_values, winners_links,
|
||||
ptr_succ<index_t> p_sorted,
|
||||
succ isorted)
|
||||
prval () = pf_sorted := array_v_cons (pf_elem, pf_rest)
|
||||
in
|
||||
end
|
||||
else
|
||||
let
|
||||
prval () = pf_sorted :=
|
||||
array_v_unnil_nil{index_t?, index_t} pf_sorted
|
||||
in
|
||||
end
|
||||
|
||||
val () = merge (sorted_tup.0 | arr, piles, links,
|
||||
winners_values, winners_links,
|
||||
sorted_tup.2, i2sz 0)
|
||||
|
||||
val () = array_ptr_free (winners_values_tup.0,
|
||||
winners_values_tup.1 |
|
||||
winners_values_tup.2)
|
||||
val () = array_ptr_free (winners_links_tup.0,
|
||||
winners_links_tup.1 |
|
||||
winners_links_tup.2)
|
||||
in
|
||||
sorted_tup
|
||||
end
|
||||
|
||||
implement {a}
|
||||
patience_sort (arr, ifirst, len) =
|
||||
let
|
||||
prval () = lemma_g1uint_param ifirst
|
||||
prval () = lemma_g1uint_param len
|
||||
in
|
||||
if len = i2sz 0 then
|
||||
let
|
||||
val sorted_tup = array_ptr_alloc<size_t 0> len
|
||||
prval () = sorted_tup.0 :=
|
||||
array_v_unnil_nil{Size_t?, Size_t} sorted_tup.0
|
||||
in
|
||||
sorted_tup
|
||||
end
|
||||
else
|
||||
let
|
||||
val ilast = ifirst + pred len
|
||||
val @(num_piles, piles_tup, links_tup) =
|
||||
deal<a> (ifirst, ilast, arr)
|
||||
macdef piles = !(piles_tup.2)
|
||||
macdef links = !(links_tup.2)
|
||||
prval () = lemma_g1uint_param num_piles
|
||||
val () = $effmask_exn assertloc (num_piles <> i2sz 0)
|
||||
val sorted_tup = k_way_merge<a> (ifirst, ilast, arr,
|
||||
num_piles, piles, links)
|
||||
in
|
||||
array_ptr_free (piles_tup.0, piles_tup.1 | piles_tup.2);
|
||||
array_ptr_free (links_tup.0, links_tup.1 | links_tup.2);
|
||||
sorted_tup
|
||||
end
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
fn
|
||||
int_patience_sort_ascending
|
||||
{ifirst, len : int | 0 <= ifirst}
|
||||
{n : int | ifirst + len <= n}
|
||||
(arr : &RD(array (int, n)),
|
||||
ifirst : size_t ifirst,
|
||||
len : size_t len)
|
||||
:<!wrt> [p : addr]
|
||||
array_tup_vt
|
||||
([i : int | len == 0 ||
|
||||
(ifirst <= i && i < ifirst + len)] size_t i,
|
||||
p, len) =
|
||||
let
|
||||
implement
|
||||
patience_sort$lt<int> (x, y) =
|
||||
x < y
|
||||
in
|
||||
patience_sort<int> (arr, ifirst, len)
|
||||
end
|
||||
|
||||
fn {a : t@ype}
|
||||
find_length {n : int}
|
||||
(lst : list (a, n))
|
||||
:<> [m : int | m == n] size_t m =
|
||||
let
|
||||
prval () = lemma_list_param lst
|
||||
in
|
||||
g1i2u (length lst)
|
||||
end
|
||||
|
||||
implement
|
||||
main0 () =
|
||||
let
|
||||
val example_list =
|
||||
$list (22, 15, 98, 82, 22, 4, 58, 70, 80, 38, 49, 48, 46, 54,
|
||||
93, 8, 54, 2, 72, 84, 86, 76, 53, 37, 90)
|
||||
|
||||
val ifirst = i2sz 10
|
||||
val [len : int] len = find_length example_list
|
||||
|
||||
#define ARRSZ 100
|
||||
val () = assertloc (i2sz 10 + len <= ARRSZ)
|
||||
|
||||
var arr : array (int, ARRSZ)
|
||||
val () = array_initize_elt<int> (arr, i2sz ARRSZ, 0)
|
||||
|
||||
prval @(pf_left, pf_right) =
|
||||
array_v_split {int} {..} {ARRSZ} {10} (view@ arr)
|
||||
prval @(pf_middle, pf_right) =
|
||||
array_v_split {int} {..} {90} {len} pf_right
|
||||
|
||||
val p = ptr_add<int> (addr@ arr, 10)
|
||||
val () = array_copy_from_list<int> (!p, example_list)
|
||||
|
||||
prval pf_right = array_v_unsplit (pf_middle, pf_right)
|
||||
prval () = view@ arr := array_v_unsplit (pf_left, pf_right)
|
||||
|
||||
val @(pf_sorted, pfgc_sorted | p_sorted) =
|
||||
int_patience_sort_ascending (arr, i2sz 10, len)
|
||||
|
||||
macdef sorted = !p_sorted
|
||||
|
||||
var i : [i : nat | i <= len] size_t i
|
||||
in
|
||||
print! ("unsorted ");
|
||||
for (i := i2sz 0; i <> len; i := succ i)
|
||||
print! (" ", arr[i2sz 10 + i]);
|
||||
println! ();
|
||||
|
||||
print! ("sorted ");
|
||||
for (i := i2sz 0; i <> len; i := succ i)
|
||||
print! (" ", arr[sorted[i]]);
|
||||
println! ();
|
||||
|
||||
array_ptr_free (pf_sorted, pfgc_sorted | p_sorted)
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
|
@ -0,0 +1,876 @@
|
|||
(* A version of the patience sort that uses arrays passed to it as its
|
||||
workspace, and returns the results in an array passed to it.
|
||||
|
||||
This way, the arrays could be reused between calls, or easily put
|
||||
on the stack if they are not too large, yet still allocated if they
|
||||
are larger than that.
|
||||
|
||||
Notice that the work arrays both start *and finish* as
|
||||
uninitialized storage. *)
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
#include "share/atspre_staload.hats"
|
||||
|
||||
(* ================================================================ *)
|
||||
(* Interface declarations that really should be moved to a .sats *)
|
||||
(* file. *)
|
||||
|
||||
stadef patience_sort_index (ifirst : int, len : int, i : int) =
|
||||
len == 0 || (ifirst <= i && i < ifirst + len)
|
||||
typedef patience_sort_index (ifirst : int, len : int, i : int) =
|
||||
[patience_sort_index (ifirst, len, i)] size_t i
|
||||
typedef patience_sort_index (ifirst : int, len : int) =
|
||||
[i : int] patience_sort_index (ifirst, len, i)
|
||||
|
||||
stadef patience_sort_link (ifirst : int, len : int, i : int) =
|
||||
0 <= i && i <= len
|
||||
typedef patience_sort_link (ifirst : int, len : int, i : int) =
|
||||
[patience_sort_link (ifirst, len, i)] size_t i
|
||||
typedef patience_sort_link (ifirst : int, len : int) =
|
||||
[i : int] patience_sort_link (ifirst, len, i)
|
||||
|
||||
(* patience_sort$lt : the order predicate for patience sort. *)
|
||||
extern fn {a : t@ype}
|
||||
patience_sort$lt (x : a, y : a) :<> bool
|
||||
|
||||
local
|
||||
|
||||
typedef index_t (ifirst : int, len : int) =
|
||||
patience_sort_index (ifirst, len)
|
||||
typedef link_t (ifirst : int, len : int) =
|
||||
patience_sort_link (ifirst, len)
|
||||
|
||||
in
|
||||
|
||||
extern fn {a : t@ype}
|
||||
patience_sort_given_workspaces
|
||||
{ifirst, len : int | 0 <= ifirst}
|
||||
{n : int | ifirst + len <= n}
|
||||
{power : int | len <= power}
|
||||
{n_piles : int | len <= n_piles}
|
||||
{n_links : int | len <= n_links}
|
||||
{n_winv : int | 2 * power <= n_winv}
|
||||
{n_winl : int | 2 * power <= n_winl}
|
||||
(pf_exp2 : [exponent : nat] EXP2 (exponent, power) |
|
||||
arr : &RD(array (a, n)),
|
||||
ifirst : size_t ifirst,
|
||||
len : size_t len,
|
||||
power : size_t power,
|
||||
piles : &array (link_t (ifirst, len)?, n_piles) >> _,
|
||||
links : &array (link_t (ifirst, len)?, n_links) >> _,
|
||||
winvals : &array (link_t (ifirst, len)?, n_winv) >> _,
|
||||
winlinks : &array (link_t (ifirst, len)?, n_winl) >> _,
|
||||
sorted : &array (index_t (ifirst, len)?, len)
|
||||
>> array (index_t (ifirst, len), len))
|
||||
:<!wrt> void
|
||||
|
||||
extern fn {a : t@ype}
|
||||
patience_sort_with_its_own_workspaces
|
||||
{ifirst, len : int | 0 <= ifirst}
|
||||
{n : int | ifirst + len <= n}
|
||||
(arr : &RD(array (a, n)),
|
||||
ifirst : size_t ifirst,
|
||||
len : size_t len,
|
||||
sorted : &array (index_t (ifirst, len)?, len)
|
||||
>> array (index_t (ifirst, len), len))
|
||||
:<!wrt> void
|
||||
|
||||
end
|
||||
|
||||
overload patience_sort with patience_sort_given_workspaces
|
||||
overload patience_sort with patience_sort_with_its_own_workspaces
|
||||
|
||||
extern fn {tk : tkind}
|
||||
next_power_of_two
|
||||
{i : pos}
|
||||
(i : g1uint (tk, i))
|
||||
:<> [k : int | i <= k; k < 2 * i]
|
||||
[n : nat]
|
||||
@(EXP2 (n, k) | g1uint (tk, k))
|
||||
|
||||
(* ================================================================ *)
|
||||
(* What follows is implementation and belongs in .dats files. *)
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
(*
|
||||
|
||||
In the following implementation of next_power_of_two:
|
||||
|
||||
* I implement it as a template for all types of kind g1uint. This
|
||||
includes dependent forms of uint, usint, ulint, ullint, size_t,
|
||||
and yet more types in the prelude; also whatever others one may
|
||||
create.
|
||||
|
||||
* I prove the result is not less than the input.
|
||||
|
||||
* I prove the result is less than twice the input.
|
||||
|
||||
* I prove the result is a power of two. This last proof is
|
||||
provided in the form of an EXP2 prop.
|
||||
|
||||
* I do NOT return what number two is raised to (though I easily
|
||||
could have). I leave that number "existentially defined". In
|
||||
other words, I prove only that some such non-negative number
|
||||
exists.
|
||||
|
||||
*)
|
||||
|
||||
implement {tk}
|
||||
next_power_of_two {i} (i) =
|
||||
let
|
||||
(* This is not the fastest implementation, although it does verify
|
||||
its own correctness. *)
|
||||
|
||||
val one : g1uint (tk, 1) = g1u2u 1u
|
||||
|
||||
fun
|
||||
loop {j : pos | j < i} .<i + i - j>.
|
||||
(pf : [n : nat] EXP2 (n, j) |
|
||||
j : g1uint (tk, j))
|
||||
:<> [k : int | i <= k; k < 2 * i]
|
||||
[n : nat]
|
||||
@(EXP2 (n, k) | g1uint (tk, k)) =
|
||||
let
|
||||
val j2 = j + j
|
||||
in
|
||||
if i <= j2 then
|
||||
@(EXP2ind pf | j2)
|
||||
else
|
||||
loop (EXP2ind pf | j2)
|
||||
end
|
||||
in
|
||||
if i = one then
|
||||
@(EXP2bas () | one)
|
||||
else
|
||||
loop (EXP2bas () | one)
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
extern praxi {a : vt@ype}
|
||||
array_uninitize_without_doing_anything
|
||||
{n : int}
|
||||
(arr : &array (INV(a), n) >> array (a?, n),
|
||||
asz : size_t n)
|
||||
:<prf> void
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
stadef index_t (ifirst : int, len : int, i : int) =
|
||||
patience_sort_index (ifirst, len, i)
|
||||
typedef index_t (ifirst : int, len : int, i : int) =
|
||||
patience_sort_index (ifirst, len, i)
|
||||
typedef index_t (ifirst : int, len : int) =
|
||||
patience_sort_index (ifirst, len)
|
||||
|
||||
stadef link_t (ifirst : int, len : int, i : int) =
|
||||
patience_sort_link (ifirst, len, i)
|
||||
typedef link_t (ifirst : int, len : int, i : int) =
|
||||
patience_sort_link (ifirst, len, i)
|
||||
typedef link_t (ifirst : int, len : int) =
|
||||
patience_sort_link (ifirst, len)
|
||||
|
||||
fn {a : t@ype}
|
||||
find_pile {ifirst, len : int}
|
||||
{n : int | ifirst + len <= n}
|
||||
{num_piles : nat | num_piles <= len}
|
||||
{n_piles : int | len <= n_piles}
|
||||
{q : pos | q <= len}
|
||||
(ifirst : size_t ifirst,
|
||||
arr : &RD(array (a, n)),
|
||||
num_piles : size_t num_piles,
|
||||
piles : &RD(array (link_t (ifirst, len), n_piles)),
|
||||
q : size_t q)
|
||||
:<> [i : pos | i <= num_piles + 1]
|
||||
size_t i =
|
||||
(*
|
||||
Bottenbruch search for the leftmost pile whose top is greater than
|
||||
or equal to the next value dealt by "deal".
|
||||
|
||||
References:
|
||||
|
||||
* H. Bottenbruch, "Structure and use of ALGOL 60", Journal of
|
||||
the ACM, Volume 9, Issue 2, April 1962, pp.161-221.
|
||||
https://doi.org/10.1145/321119.321120
|
||||
|
||||
The general algorithm is described on pages 214 and 215.
|
||||
|
||||
* https://en.wikipedia.org/w/index.php?title=Binary_search_algorithm&oldid=1062988272#Alternative_procedure
|
||||
*)
|
||||
if num_piles = i2sz 0 then
|
||||
i2sz 1
|
||||
else
|
||||
let
|
||||
macdef lt = patience_sort$lt<a>
|
||||
|
||||
prval () = lemma_g1uint_param ifirst
|
||||
prval () = prop_verify {0 <= ifirst} ()
|
||||
|
||||
fun
|
||||
loop {j, k : nat | j <= k; k < num_piles}
|
||||
.<k - j>.
|
||||
(arr : &RD(array (a, n)),
|
||||
piles : &array (link_t (ifirst, len), n_piles),
|
||||
j : size_t j,
|
||||
k : size_t k)
|
||||
:<> [i : pos | i <= num_piles + 1]
|
||||
size_t i =
|
||||
if j = k then
|
||||
begin
|
||||
if succ j <> num_piles then
|
||||
succ j
|
||||
else
|
||||
let
|
||||
val piles_j = piles[j]
|
||||
val () = $effmask_exn assertloc (piles_j <> g1u2u 0u)
|
||||
|
||||
val x1 = arr[pred q + ifirst]
|
||||
and x2 = arr[pred piles_j + ifirst]
|
||||
in
|
||||
if x2 \lt x1 then
|
||||
succ (succ j)
|
||||
else
|
||||
succ j
|
||||
end
|
||||
end
|
||||
else
|
||||
let
|
||||
typedef index (i : int) = [0 <= i; i < n] size_t i
|
||||
typedef index = [i : int] index i
|
||||
|
||||
stadef i = j + ((k - j) / 2)
|
||||
val i : size_t i = j + ((k - j) / g1u2u 2u)
|
||||
|
||||
val piles_j = piles[j]
|
||||
val () = $effmask_exn assertloc (piles_j <> g1u2u 0u)
|
||||
|
||||
val x1 = arr[pred q + ifirst]
|
||||
and x2 = arr[pred piles_j + ifirst]
|
||||
in
|
||||
if x2 \lt x1 then
|
||||
loop (arr, piles, i + 1, k)
|
||||
else
|
||||
loop (arr, piles, j, i)
|
||||
end
|
||||
in
|
||||
loop (arr, piles, g1u2u 0u, pred num_piles)
|
||||
end
|
||||
|
||||
fn {a : t@ype}
|
||||
deal {ifirst, len : int}
|
||||
{n : int | ifirst + len <= n}
|
||||
(ifirst : size_t ifirst,
|
||||
len : size_t len,
|
||||
arr : &RD(array (a, n)),
|
||||
piles : &array (link_t (ifirst, len)?, len)
|
||||
>> array (link_t (ifirst, len), len),
|
||||
links : &array (link_t (ifirst, len)?, len)
|
||||
>> array (link_t (ifirst, len), len))
|
||||
:<!wrt> [num_piles : int | num_piles <= len]
|
||||
size_t num_piles =
|
||||
let
|
||||
prval () = lemma_g1uint_param ifirst
|
||||
prval () = lemma_g1uint_param len
|
||||
|
||||
typedef link_t (i : int) = link_t (ifirst, len, i)
|
||||
typedef link_t = link_t (ifirst, len)
|
||||
|
||||
val zero : size_t 0 = g1u2u 0u
|
||||
val one : size_t 1 = g1u2u 1u
|
||||
val link_nil : link_t 0 = g1u2u 0u
|
||||
|
||||
fun
|
||||
loop {q : pos | q <= len + 1}
|
||||
{m : nat | m <= len}
|
||||
.<len + 1 - q>.
|
||||
(arr : &RD(array (a, n)),
|
||||
q : size_t q,
|
||||
piles : &array (link_t, len) >> _,
|
||||
links : &array (link_t, len) >> _,
|
||||
m : size_t m)
|
||||
:<!wrt> [num_piles : nat | num_piles <= len]
|
||||
size_t num_piles =
|
||||
if q = succ (len) then
|
||||
m
|
||||
else
|
||||
let
|
||||
val i = find_pile {ifirst, len} (ifirst, arr, m, piles, q)
|
||||
|
||||
(* We have no proof the number of elements will not exceed
|
||||
storage. However, we know it will not, because the number
|
||||
of piles cannot exceed the size of the input. Let us get
|
||||
a "proof" by runtime check. *)
|
||||
val () = $effmask_exn assertloc (i <= len)
|
||||
in
|
||||
links[pred q] := piles[pred i];
|
||||
piles[pred i] := q;
|
||||
if i = succ m then
|
||||
loop {q + 1} (arr, succ q, piles, links, succ m)
|
||||
else
|
||||
loop {q + 1} (arr, succ q, piles, links, m)
|
||||
end
|
||||
in
|
||||
array_initize_elt<link_t> (piles, len, link_nil);
|
||||
array_initize_elt<link_t> (links, len, link_nil);
|
||||
loop (arr, one, piles, links, zero)
|
||||
end
|
||||
|
||||
fn {a : t@ype}
|
||||
k_way_merge {ifirst, len : int}
|
||||
{n : int | ifirst + len <= n}
|
||||
{num_piles : pos | num_piles <= len}
|
||||
{power : int | len <= power}
|
||||
(pf_exp2 : [exponent : nat] EXP2 (exponent, power) |
|
||||
arr : &RD(array (a, n)),
|
||||
ifirst : size_t ifirst,
|
||||
len : size_t len,
|
||||
num_piles : size_t num_piles,
|
||||
power : size_t power,
|
||||
piles : &array (link_t (ifirst, len), len) >> _,
|
||||
links : &RD(array (link_t (ifirst, len), len)),
|
||||
winvals : &array (link_t (ifirst, len)?, 2 * power)
|
||||
>> _,
|
||||
winlinks : &array (link_t (ifirst, len)?, 2 * power)
|
||||
>> _,
|
||||
sorted : &array (index_t (ifirst, len)?, len)
|
||||
>> array (index_t (ifirst, len), len))
|
||||
:<!wrt> void =
|
||||
(*
|
||||
k-way merge by tournament tree.
|
||||
|
||||
See Knuth, volume 3, and also
|
||||
https://en.wikipedia.org/w/index.php?title=K-way_merge_algorithm&oldid=1047851465#Tournament_Tree
|
||||
|
||||
However, I store a winners tree instead of the recommended losers
|
||||
tree. If the tree were stored as linked nodes, it would probably
|
||||
be more efficient to store a losers tree. However, I am storing
|
||||
the tree as an array, and one can find an opponent quickly by
|
||||
simply toggling the least significant bit of a competitor's array
|
||||
index.
|
||||
*)
|
||||
let
|
||||
prval () = lemma_g1uint_param ifirst
|
||||
prval () = lemma_g1uint_param len
|
||||
|
||||
typedef link_t (i : int) = link_t (ifirst, len, i)
|
||||
typedef link_t = link_t (ifirst, len)
|
||||
|
||||
val link_nil : link_t 0 = g1u2u 0u
|
||||
|
||||
typedef index_t (i : int) = index_t (ifirst, len, i)
|
||||
typedef index_t = index_t (ifirst, len)
|
||||
|
||||
val [total_external_nodes : int]
|
||||
@(_ | total_external_nodes) = next_power_of_two num_piles
|
||||
prval () = prop_verify {num_piles <= total_external_nodes} ()
|
||||
|
||||
stadef total_nodes = (2 * total_external_nodes) - 1
|
||||
val total_nodes : size_t total_nodes =
|
||||
pred (g1u2u 2u * total_external_nodes)
|
||||
|
||||
(* We will ignore index 0 of the winners tree arrays. *)
|
||||
stadef winners_size = total_nodes + 1
|
||||
val winners_size : size_t winners_size = succ total_nodes
|
||||
|
||||
(* An exercise for the reader is to write a proof that
|
||||
winners_size <= 2 * power, so one can get rid of the
|
||||
runtime assertion here: *)
|
||||
val () = $effmask_exn assertloc (winners_size <= 2 * power)
|
||||
|
||||
prval @(winvals_left, winvals_right) =
|
||||
array_v_split {link_t?} {..} {2 * power} {winners_size}
|
||||
(view@ winvals)
|
||||
prval () = view@ winvals := winvals_left
|
||||
|
||||
prval @(winlinks_left, winlinks_right) =
|
||||
array_v_split {link_t?} {..} {2 * power} {winners_size}
|
||||
(view@ winlinks)
|
||||
prval () = view@ winlinks := winlinks_left
|
||||
|
||||
val () = array_initize_elt<link_t> (winvals, winners_size,
|
||||
link_nil)
|
||||
val () = array_initize_elt<link_t> (winlinks, winners_size,
|
||||
link_nil)
|
||||
|
||||
|
||||
(* - - - - - - - - - - - - - - - - - - - - - - - - - - *)
|
||||
(* Record which pile a winner will have come from. *)
|
||||
|
||||
fun
|
||||
init_pile_links
|
||||
{i : nat | i <= num_piles}
|
||||
.<num_piles - i>.
|
||||
(winlinks : &array (link_t, winners_size),
|
||||
i : size_t i)
|
||||
:<!wrt> void =
|
||||
if i <> num_piles then
|
||||
begin
|
||||
winlinks[total_external_nodes + i] := succ i;
|
||||
init_pile_links (winlinks, succ i)
|
||||
end
|
||||
|
||||
val () = init_pile_links (winlinks, g1u2u 0u)
|
||||
|
||||
(* - - - - - - - - - - - - - - - - - - - - - - - - - - *)
|
||||
(* The top of each pile becomes a starting competitor. *)
|
||||
|
||||
fun
|
||||
init_competitors
|
||||
{i : nat | i <= num_piles}
|
||||
.<num_piles - i>.
|
||||
(winvals : &array (link_t, winners_size),
|
||||
piles : &array (link_t, len),
|
||||
i : size_t i)
|
||||
:<!wrt> void =
|
||||
if i <> num_piles then
|
||||
begin
|
||||
winvals[total_external_nodes + i] := piles[i];
|
||||
init_competitors (winvals, piles, succ i)
|
||||
end
|
||||
|
||||
val () = init_competitors (winvals, piles, g1u2u 0u)
|
||||
|
||||
(* - - - - - - - - - - - - - - - - - - - - - - - - - - *)
|
||||
(* Discard the top of each pile. *)
|
||||
|
||||
fun
|
||||
discard_tops {i : nat | i <= num_piles}
|
||||
.<num_piles - i>.
|
||||
(piles : &array (link_t, len),
|
||||
links : &array (link_t, len),
|
||||
i : size_t i)
|
||||
:<!wrt> void =
|
||||
if i <> num_piles then
|
||||
let
|
||||
val link = piles[i]
|
||||
|
||||
(* None of the piles should have been empty. *)
|
||||
val () = $effmask_exn assertloc (link <> g1u2u 0u)
|
||||
in
|
||||
piles[i] := links[pred link];
|
||||
discard_tops (piles, links, succ i)
|
||||
end
|
||||
|
||||
val () = discard_tops (piles, links, g1u2u 0u)
|
||||
|
||||
(* - - - - - - - - - - - - - - - - - - - - - - - - - - *)
|
||||
(* How to play a game. *)
|
||||
|
||||
fn
|
||||
play_game {i : int | 2 <= i; i <= total_nodes}
|
||||
(arr : &RD(array (a, n)),
|
||||
winvals : &array (link_t, winners_size),
|
||||
i : size_t i)
|
||||
:<> [iwinner : pos | iwinner <= total_nodes]
|
||||
size_t iwinner =
|
||||
let
|
||||
macdef lt = patience_sort$lt<a>
|
||||
|
||||
fn
|
||||
find_opponent {i : int | 2 <= i; i <= total_nodes}
|
||||
(i : size_t i)
|
||||
:<> [j : int | 2 <= j; j <= total_nodes]
|
||||
size_t j =
|
||||
let
|
||||
(* The prelude contains bitwise operations only for
|
||||
non-dependent unsigned integer. We will not bother to
|
||||
add them ourselves, but instead go back and forth
|
||||
between dependent and non-dependent. *)
|
||||
val i0 = g0ofg1 i
|
||||
val j0 = g0uint_lxor<size_kind> (i0, g0u2u 1u)
|
||||
val j = g1ofg0 j0
|
||||
|
||||
(* We have no proof the opponent is in the proper
|
||||
range. Create a "proof" by runtime checks. *)
|
||||
val () = $effmask_exn assertloc (g1u2u 2u <= j)
|
||||
val () = $effmask_exn assertloc (j <= total_nodes)
|
||||
in
|
||||
j
|
||||
end
|
||||
|
||||
val j = find_opponent i
|
||||
val winner_i = winvals[i]
|
||||
and winner_j = winvals[j]
|
||||
in
|
||||
if winner_i = link_nil then
|
||||
j
|
||||
else if winner_j = link_nil then
|
||||
i
|
||||
else
|
||||
let
|
||||
val i1 = pred winner_i + ifirst
|
||||
and i2 = pred winner_j + ifirst
|
||||
prval () = lemma_g1uint_param i1
|
||||
prval () = lemma_g1uint_param i2
|
||||
in
|
||||
if arr[i2] \lt arr[i1] then j else i
|
||||
end
|
||||
end
|
||||
|
||||
(* - - - - - - - - - - - - - - - - - - - - - - - - - - *)
|
||||
|
||||
fun
|
||||
build_tree {istart : pos | istart <= total_external_nodes}
|
||||
.<istart>.
|
||||
(arr : &RD(array (a, n)),
|
||||
winvals : &array (link_t, winners_size),
|
||||
winlinks : &array (link_t, winners_size),
|
||||
istart : size_t istart)
|
||||
:<!wrt> void =
|
||||
if istart <> 1 then
|
||||
let
|
||||
fun
|
||||
play_initial_games
|
||||
{i : int | istart <= i; i <= (2 * istart) + 1}
|
||||
.<(2 * istart) + 1 - i>.
|
||||
(arr : &RD(array (a, n)),
|
||||
winvals : &array (link_t, winners_size),
|
||||
winlinks : &array (link_t, winners_size),
|
||||
i : size_t i)
|
||||
:<!wrt> void =
|
||||
if i <= pred (istart + istart) then
|
||||
let
|
||||
val iwinner = play_game (arr, winvals, i)
|
||||
and i2 = i / g1u2u 2u
|
||||
in
|
||||
winvals[i2] := winvals[iwinner];
|
||||
winlinks[i2] := winlinks[iwinner];
|
||||
play_initial_games (arr, winvals, winlinks,
|
||||
succ (succ i))
|
||||
end
|
||||
in
|
||||
play_initial_games (arr, winvals, winlinks, istart);
|
||||
build_tree (arr, winvals, winlinks, istart / g1u2u 2u)
|
||||
end
|
||||
|
||||
val () = build_tree (arr, winvals, winlinks, total_external_nodes)
|
||||
|
||||
(* - - - - - - - - - - - - - - - - - - - - - - - - - - *)
|
||||
|
||||
fun
|
||||
replay_games {i : pos | i <= total_nodes}
|
||||
.<i>.
|
||||
(arr : &RD(array (a, n)),
|
||||
winvals : &array (link_t, winners_size),
|
||||
winlinks : &array (link_t, winners_size),
|
||||
i : size_t i)
|
||||
:<!wrt> void =
|
||||
if i <> g1u2u 1u then
|
||||
let
|
||||
val iwinner = play_game (arr, winvals, i)
|
||||
and i2 = i / g1u2u 2u
|
||||
in
|
||||
winvals[i2] := winvals[iwinner];
|
||||
winlinks[i2] := winlinks[iwinner];
|
||||
replay_games (arr, winvals, winlinks, i2)
|
||||
end
|
||||
|
||||
fun
|
||||
merge {isorted : nat | isorted <= len}
|
||||
{p_sorted : addr}
|
||||
.<len - isorted>.
|
||||
(pf_sorted : !array_v (index_t?, p_sorted,
|
||||
len - isorted)
|
||||
>> array_v (index_t, p_sorted,
|
||||
len - isorted) |
|
||||
arr : &RD(array (a, n)),
|
||||
piles : &array (link_t, len),
|
||||
links : &array (link_t, len),
|
||||
winvals : &array (link_t, winners_size),
|
||||
winlinks : &array (link_t, winners_size),
|
||||
p_sorted : ptr p_sorted,
|
||||
isorted : size_t isorted)
|
||||
:<!wrt> void =
|
||||
(* This function not only fills in the "sorted" array, but
|
||||
transforms it from "uninitialized" to "initialized". *)
|
||||
if isorted <> len then
|
||||
let
|
||||
prval @(pf_elem, pf_rest) = array_v_uncons pf_sorted
|
||||
val winner = winvals[1]
|
||||
val () = $effmask_exn assertloc (winner <> link_nil)
|
||||
val () = !p_sorted := pred winner + ifirst
|
||||
|
||||
(* Move to the next element in the winner's pile. *)
|
||||
val ilink = winlinks[1]
|
||||
val () = $effmask_exn assertloc (ilink <> link_nil)
|
||||
val inext = piles[pred ilink]
|
||||
val () = (if inext <> link_nil then
|
||||
piles[pred ilink] := links[pred inext])
|
||||
|
||||
(* Replay games, with the new element as a competitor. *)
|
||||
val i = (total_nodes / g1u2u 2u) + ilink
|
||||
val () = $effmask_exn assertloc (i <= total_nodes)
|
||||
val () = winvals[i] := inext
|
||||
val () = replay_games (arr, winvals, winlinks, i)
|
||||
|
||||
val () = merge (pf_rest |
|
||||
arr, piles, links, winvals, winlinks,
|
||||
ptr_succ<index_t> p_sorted, succ isorted)
|
||||
prval () = pf_sorted := array_v_cons (pf_elem, pf_rest)
|
||||
in
|
||||
end
|
||||
else
|
||||
let
|
||||
prval () = pf_sorted :=
|
||||
array_v_unnil_nil{index_t?, index_t} pf_sorted
|
||||
in
|
||||
end
|
||||
|
||||
val () = merge (view@ sorted |
|
||||
arr, piles, links, winvals, winlinks,
|
||||
addr@ sorted, i2sz 0)
|
||||
|
||||
prval () =
|
||||
array_uninitize_without_doing_anything<link_t>
|
||||
(winvals, winners_size)
|
||||
prval () =
|
||||
array_uninitize_without_doing_anything<link_t>
|
||||
(winlinks, winners_size)
|
||||
prval () = view@ winvals :=
|
||||
array_v_unsplit (view@ winvals, winvals_right)
|
||||
prval () = view@ winlinks :=
|
||||
array_v_unsplit (view@ winlinks, winlinks_right)
|
||||
in
|
||||
end
|
||||
|
||||
implement {a}
|
||||
patience_sort_given_workspaces
|
||||
{ifirst, len} {n} {power}
|
||||
{n_piles} {n_links} {n_winv} {n_winl}
|
||||
(pf_exp2 | arr, ifirst, len, power,
|
||||
piles, links, winvals, winlinks,
|
||||
sorted) =
|
||||
let
|
||||
prval () = lemma_g1uint_param ifirst
|
||||
prval () = lemma_g1uint_param len
|
||||
|
||||
typedef index_t = index_t (ifirst, len)
|
||||
typedef link_t = link_t (ifirst, len)
|
||||
in
|
||||
if len = i2sz 0 then
|
||||
let
|
||||
prval () = view@ sorted :=
|
||||
array_v_unnil_nil{index_t?, index_t} (view@ sorted)
|
||||
in
|
||||
end
|
||||
else
|
||||
let
|
||||
prval @(piles_left, piles_right) =
|
||||
array_v_split {link_t?} {..} {n_piles} {len} (view@ piles)
|
||||
prval () = view@ piles := piles_left
|
||||
|
||||
prval @(links_left, links_right) =
|
||||
array_v_split {link_t?} {..} {n_links} {len} (view@ links)
|
||||
prval () = view@ links := links_left
|
||||
|
||||
prval @(winvals_left, winvals_right) =
|
||||
array_v_split {link_t?} {..} {n_winv} {2 * power}
|
||||
(view@ winvals)
|
||||
prval () = view@ winvals := winvals_left
|
||||
|
||||
prval @(winlinks_left, winlinks_right) =
|
||||
array_v_split {link_t?} {..} {n_winl} {2 * power}
|
||||
(view@ winlinks)
|
||||
prval () = view@ winlinks := winlinks_left
|
||||
|
||||
val num_piles =
|
||||
deal {ifirst, len} {n} (ifirst, len, arr, piles, links)
|
||||
prval () = lemma_g1uint_param num_piles
|
||||
val () = $effmask_exn assertloc (num_piles <> i2sz 0)
|
||||
|
||||
val () =
|
||||
k_way_merge {ifirst, len} {n} {..} {power}
|
||||
(pf_exp2 | arr, ifirst, len, num_piles, power,
|
||||
piles, links, winvals, winlinks,
|
||||
sorted)
|
||||
|
||||
prval () =
|
||||
array_uninitize_without_doing_anything<link_t>
|
||||
(piles, len)
|
||||
prval () =
|
||||
array_uninitize_without_doing_anything<link_t>
|
||||
(links, len)
|
||||
|
||||
prval () = view@ piles :=
|
||||
array_v_unsplit (view@ piles, piles_right)
|
||||
prval () = view@ links :=
|
||||
array_v_unsplit (view@ links, links_right)
|
||||
prval () = view@ winvals :=
|
||||
array_v_unsplit (view@ winvals, winvals_right)
|
||||
prval () = view@ winlinks :=
|
||||
array_v_unsplit (view@ winlinks, winlinks_right)
|
||||
in
|
||||
end
|
||||
end
|
||||
|
||||
(* ================================================================ *)
|
||||
(* An interface that provides the workspaces. If the subarray to *)
|
||||
(* be sorted is small enough, stack storage will be used. *)
|
||||
|
||||
#define LEN_THRESHOLD 128
|
||||
#define WINNERS_SIZE 256
|
||||
|
||||
prval () = prop_verify {WINNERS_SIZE == 2 * LEN_THRESHOLD} ()
|
||||
|
||||
local
|
||||
prval pf_exp2 = EXP2bas () (* 1*)
|
||||
prval pf_exp2 = EXP2ind pf_exp2 (* 2 *)
|
||||
prval pf_exp2 = EXP2ind pf_exp2 (* 4 *)
|
||||
prval pf_exp2 = EXP2ind pf_exp2 (* 8 *)
|
||||
prval pf_exp2 = EXP2ind pf_exp2 (* 16 *)
|
||||
prval pf_exp2 = EXP2ind pf_exp2 (* 32 *)
|
||||
prval pf_exp2 = EXP2ind pf_exp2 (* 64 *)
|
||||
prval pf_exp2 = EXP2ind pf_exp2 (* 128 *)
|
||||
in
|
||||
prval pf_exp2_for_stack_storage = pf_exp2
|
||||
end
|
||||
|
||||
implement {a}
|
||||
patience_sort_with_its_own_workspaces
|
||||
{ifirst, len} {n} (arr, ifirst, len, sorted) =
|
||||
let
|
||||
prval () = lemma_g1uint_param ifirst
|
||||
prval () = lemma_g1uint_param len
|
||||
|
||||
typedef link_t = link_t (ifirst, len)
|
||||
|
||||
fn
|
||||
sort {ifirst, len : int | 0 <= ifirst}
|
||||
{n : int | ifirst + len <= n}
|
||||
{power : int | len <= power}
|
||||
{n_piles : int | len <= n_piles}
|
||||
{n_links : int | len <= n_links}
|
||||
{n_winv : int | 2 * power <= n_winv}
|
||||
{n_winl : int | 2 * power <= n_winl}
|
||||
(pf_exp2 : [exponent : nat] EXP2 (exponent, power) |
|
||||
arr : &RD(array (a, n)),
|
||||
ifirst : size_t ifirst,
|
||||
len : size_t len,
|
||||
power : size_t power,
|
||||
piles : &array (link_t (ifirst, len)?, n_piles) >> _,
|
||||
links : &array (link_t (ifirst, len)?, n_links) >> _,
|
||||
winvals : &array (link_t (ifirst, len)?, n_winv) >> _,
|
||||
winlinks : &array (link_t (ifirst, len)?, n_winl) >> _,
|
||||
sorted : &array (index_t (ifirst, len)?, len)
|
||||
>> array (index_t (ifirst, len), len))
|
||||
:<!wrt> void =
|
||||
patience_sort_given_workspaces<a>
|
||||
{ifirst, len} {n} {power}
|
||||
{n_piles} {n_links} {n_winv} {n_winl}
|
||||
(pf_exp2 | arr, ifirst, len, power, piles, links,
|
||||
winvals, winlinks, sorted)
|
||||
in
|
||||
if len <= i2sz LEN_THRESHOLD then
|
||||
let
|
||||
var piles : array (link_t?, LEN_THRESHOLD)
|
||||
var links : array (link_t?, LEN_THRESHOLD)
|
||||
var winvals : array (link_t?, WINNERS_SIZE)
|
||||
var winlinks : array (link_t?, WINNERS_SIZE)
|
||||
in
|
||||
sort (pf_exp2_for_stack_storage |
|
||||
arr, ifirst, len, i2sz LEN_THRESHOLD,
|
||||
piles, links, winvals, winlinks, sorted)
|
||||
end
|
||||
else
|
||||
let
|
||||
val @(pf_piles, pfgc_piles | p_piles) =
|
||||
array_ptr_alloc<link_t> len
|
||||
val @(pf_links, pfgc_links | p_links) =
|
||||
array_ptr_alloc<link_t> len
|
||||
|
||||
val @(pf_exp2 | power) = next_power_of_two<size_kind> len
|
||||
|
||||
val @(pf_winvals, pfgc_winvals | p_winvals) =
|
||||
array_ptr_alloc<link_t> (power + power)
|
||||
val @(pf_winlinks, pfgc_winlinks | p_winlinks) =
|
||||
array_ptr_alloc<link_t> (power + power)
|
||||
|
||||
macdef piles = !p_piles
|
||||
macdef links = !p_links
|
||||
macdef winvals = !p_winvals
|
||||
macdef winlinks = !p_winlinks
|
||||
in
|
||||
sort (pf_exp2 |
|
||||
arr, ifirst, len, power, piles, links,
|
||||
winvals, winlinks, sorted);
|
||||
array_ptr_free (pf_piles, pfgc_piles | p_piles);
|
||||
array_ptr_free (pf_links, pfgc_links | p_links);
|
||||
array_ptr_free (pf_winvals, pfgc_winvals | p_winvals);
|
||||
array_ptr_free (pf_winlinks, pfgc_winlinks | p_winlinks)
|
||||
end
|
||||
end
|
||||
|
||||
(* ================================================================ *)
|
||||
(* A demonstration program. *)
|
||||
|
||||
fn {a : t@ype}
|
||||
find_length {n : int}
|
||||
(lst : list (a, n))
|
||||
:<> [m : int | m == n] size_t m =
|
||||
let
|
||||
prval () = lemma_list_param lst
|
||||
in
|
||||
g1i2u (length lst)
|
||||
end
|
||||
|
||||
implement
|
||||
main0 () =
|
||||
let
|
||||
implement
|
||||
patience_sort$lt<int> (x, y) =
|
||||
x < y
|
||||
|
||||
val example_list =
|
||||
$list (22, 15, 98, 82, 22, 4, 58, 70, 80, 38, 49, 48, 46, 54,
|
||||
93, 8, 54, 2, 72, 84, 86, 76, 53, 37, 90)
|
||||
|
||||
val ifirst = i2sz 10
|
||||
val [len : int] len = find_length example_list
|
||||
|
||||
#define ARRSZ 100
|
||||
val () = assertloc (i2sz 10 + len <= ARRSZ)
|
||||
|
||||
var arr : array (int, ARRSZ)
|
||||
val () = array_initize_elt<int> (arr, i2sz ARRSZ, 0)
|
||||
|
||||
prval @(pf_left, pf_right) =
|
||||
array_v_split {int} {..} {ARRSZ} {10} (view@ arr)
|
||||
prval @(pf_middle, pf_right) =
|
||||
array_v_split {int} {..} {90} {len} pf_right
|
||||
|
||||
val p = ptr_add<int> (addr@ arr, 10)
|
||||
val () = array_copy_from_list<int> (!p, example_list)
|
||||
|
||||
prval pf_right = array_v_unsplit (pf_middle, pf_right)
|
||||
prval () = view@ arr := array_v_unsplit (pf_left, pf_right)
|
||||
|
||||
typedef index_t = patience_sort_index (10, len)
|
||||
|
||||
var sorted : array (index_t, ARRSZ)
|
||||
val () = array_initize_elt<index_t> (sorted, i2sz ARRSZ,
|
||||
g1u2u 10u)
|
||||
|
||||
prval @(sorted_left, sorted_right) =
|
||||
array_v_split {index_t} {..} {ARRSZ} {len} (view@ sorted)
|
||||
prval () = view@ sorted := sorted_left
|
||||
|
||||
val () = patience_sort<int> (arr, i2sz 10, len, sorted)
|
||||
|
||||
prval () = view@ sorted :=
|
||||
array_v_unsplit (view@ sorted, sorted_right)
|
||||
|
||||
var i : [i : nat | i <= len] size_t i
|
||||
in
|
||||
print! ("unsorted ");
|
||||
for (i := i2sz 0; i <> len; i := succ i)
|
||||
print! (" ", arr[i2sz 10 + i]);
|
||||
println! ();
|
||||
|
||||
print! ("sorted ");
|
||||
for (i := i2sz 0; i <> len; i := succ i)
|
||||
print! (" ", arr[sorted[i]]);
|
||||
println! ()
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
|
@ -0,0 +1,372 @@
|
|||
//--------------------------------------------------------------------
|
||||
//
|
||||
// A patience sort for 32-bit signed integers.
|
||||
//
|
||||
// This implementation proves that result is sorted, though it
|
||||
// does not prove that the result is of the same length as the
|
||||
// original.
|
||||
//
|
||||
//--------------------------------------------------------------------
|
||||
|
||||
#include "share/atspre_staload.hats"
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
#define ENTIER_MAX 2147483647
|
||||
|
||||
(* We do not include the most negative two's-complement number. *)
|
||||
stadef entier (i : int) = ~ENTIER_MAX <= i && i <= ENTIER_MAX
|
||||
sortdef entier = {i : int | entier i}
|
||||
|
||||
typedef entier (i : int) = [entier i] int i
|
||||
typedef entier = [i : entier] entier i
|
||||
|
||||
datatype sorted_entier_list (int, int) =
|
||||
| sorted_entier_list_nil (0, ENTIER_MAX)
|
||||
| {n : nat}
|
||||
{i, j : entier | ~(j < i)}
|
||||
sorted_entier_list_cons (n + 1, i) of
|
||||
(entier i, sorted_entier_list (n, j))
|
||||
typedef sorted_entier_list (n : int) =
|
||||
[i : entier] sorted_entier_list (n, i)
|
||||
typedef sorted_entier_list =
|
||||
[n : int] sorted_entier_list n
|
||||
|
||||
infixr ( :: ) :::
|
||||
#define NIL list_nil ()
|
||||
#define :: list_cons
|
||||
#define SNIL sorted_entier_list_nil ()
|
||||
#define ::: sorted_entier_list_cons
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
extern prfn
|
||||
lemma_sorted_entier_list_param
|
||||
{n : int}
|
||||
(lst : sorted_entier_list n)
|
||||
:<prf> [0 <= n] void
|
||||
|
||||
extern fn
|
||||
sorted_entier_list_merge
|
||||
{m, n : int}
|
||||
{i, j : entier}
|
||||
(lst1 : sorted_entier_list (m, i),
|
||||
lst2 : sorted_entier_list (n, j))
|
||||
:<> sorted_entier_list (m + n, min (i, j))
|
||||
|
||||
extern fn
|
||||
entier_list_patience_sort
|
||||
{n : int}
|
||||
(lst : list (entier, n)) (* An ordinary list. *)
|
||||
:<!wrt> sorted_entier_list (* No proof of the length. *)
|
||||
|
||||
extern fn
|
||||
sorted_entier_list2list
|
||||
{n : int}
|
||||
(lst : sorted_entier_list n)
|
||||
:<> list (entier, n)
|
||||
|
||||
overload merge with sorted_entier_list_merge
|
||||
overload patience_sort with entier_list_patience_sort
|
||||
overload to_list with sorted_entier_list2list
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
primplement
|
||||
lemma_sorted_entier_list_param {n} lst =
|
||||
case+ lst of
|
||||
| SNIL => ()
|
||||
| _ ::: _ => ()
|
||||
|
||||
implement
|
||||
sorted_entier_list_merge (lst1, lst2) =
|
||||
(* This implementation is *NOT* tail recursive. It will use O(m+n)
|
||||
stack space. *)
|
||||
let
|
||||
fun
|
||||
recurs {m, n : nat}
|
||||
{i, j : entier} .<m + n>.
|
||||
(lst1 : sorted_entier_list (m, i),
|
||||
lst2 : sorted_entier_list (n, j))
|
||||
:<> sorted_entier_list (m + n, min (i, j)) =
|
||||
case+ lst1 of
|
||||
| SNIL => lst2
|
||||
| i ::: tail1 =>
|
||||
begin
|
||||
case+ lst2 of
|
||||
| SNIL => lst1
|
||||
| j ::: tail2 =>
|
||||
if ~(j < i) then
|
||||
i ::: recurs (tail1, lst2)
|
||||
else
|
||||
j ::: recurs (lst1, tail2)
|
||||
end
|
||||
|
||||
prval () = lemma_sorted_entier_list_param lst1
|
||||
prval () = lemma_sorted_entier_list_param lst2
|
||||
in
|
||||
recurs (lst1, lst2)
|
||||
end
|
||||
|
||||
implement
|
||||
entier_list_patience_sort {n} lst =
|
||||
let
|
||||
prval () = lemma_list_param lst
|
||||
val n : int n = length lst
|
||||
in
|
||||
if n = 0 then
|
||||
SNIL
|
||||
else if n = 1 then
|
||||
let
|
||||
val+ head :: NIL = lst
|
||||
in
|
||||
head ::: SNIL
|
||||
end
|
||||
else
|
||||
let
|
||||
val @(pf, pfgc | p) =
|
||||
array_ptr_alloc<sorted_entier_list> (i2sz n)
|
||||
macdef piles = !p
|
||||
val () = array_initize_elt (piles, i2sz n, SNIL)
|
||||
|
||||
fn
|
||||
find_pile {m : nat | m <= n}
|
||||
{x : entier}
|
||||
(num_piles : int m,
|
||||
piles : &array (sorted_entier_list, n),
|
||||
x : entier x)
|
||||
:<> [i : nat | i < n]
|
||||
[len : int]
|
||||
[y : entier | ~(y < x)]
|
||||
@(int i, sorted_entier_list (len, y)) =
|
||||
//
|
||||
// Bottenbruch search for the leftmost pile whose top is
|
||||
// greater than or equal to some element x.
|
||||
//
|
||||
// References:
|
||||
//
|
||||
// * H. Bottenbruch, "Structure and use of ALGOL 60",
|
||||
// Journal of the ACM, Volume 9, Issue 2, April 1962,
|
||||
// pp.161-221. https://doi.org/10.1145/321119.321120
|
||||
//
|
||||
// The general algorithm is described on pages 214
|
||||
// and 215.
|
||||
//
|
||||
// * https://en.wikipedia.org/w/index.php?title=Binary_search_algorithm&oldid=1062988272#Alternative_procedure
|
||||
//
|
||||
let
|
||||
fun
|
||||
loop {j, k : nat | j < k; k < m}
|
||||
{x : entier} .<k - j>.
|
||||
(piles : &array (sorted_entier_list, n),
|
||||
j : int j,
|
||||
k : int k,
|
||||
x : entier x)
|
||||
:<> [i : nat | i < n]
|
||||
[len : int]
|
||||
[y : entier | ~(y < x)]
|
||||
@(int i, sorted_entier_list (len, y)) =
|
||||
let
|
||||
val i = j + g1int_ndiv (k - j, 2)
|
||||
val pile = piles[i]
|
||||
val- head ::: _ = pile
|
||||
in
|
||||
if head < x then
|
||||
begin
|
||||
if succ i <> k then
|
||||
loop (piles, succ i, k, x)
|
||||
else
|
||||
let
|
||||
val pile1 = piles[k]
|
||||
in
|
||||
case- pile1 of
|
||||
| head1 ::: _ =>
|
||||
if head1 < x then
|
||||
let
|
||||
(* Runtime check for buffer overrun. *)
|
||||
val () =
|
||||
$effmask_exn assertloc (k + 1 < n)
|
||||
in
|
||||
(* No pile satisfies the binary search.
|
||||
Start a new pile. *)
|
||||
@(k + 1, SNIL)
|
||||
end
|
||||
else
|
||||
@(k, pile1)
|
||||
end
|
||||
end
|
||||
else
|
||||
begin
|
||||
if j <> i then
|
||||
loop (piles, j, i, x)
|
||||
else
|
||||
@(j, pile)
|
||||
end
|
||||
end
|
||||
in
|
||||
if 1 < num_piles then
|
||||
let
|
||||
prval () = prop_verify {m >= 1} ()
|
||||
in
|
||||
loop (piles, 0, pred num_piles, x)
|
||||
end
|
||||
else if num_piles = 1 then
|
||||
let
|
||||
prval () = prop_verify {m == 1} ()
|
||||
val pile = piles[0]
|
||||
in
|
||||
case- pile of
|
||||
| head ::: _ =>
|
||||
if head < x then
|
||||
@(1, SNIL)
|
||||
else
|
||||
@(0, pile)
|
||||
end
|
||||
else
|
||||
let
|
||||
prval () = prop_verify {m == 0} ()
|
||||
in
|
||||
@(0, SNIL)
|
||||
end
|
||||
end
|
||||
|
||||
fun
|
||||
deal {m : nat | m <= n}
|
||||
{j : nat | j <= n} .<m>.
|
||||
(num_piles : &int j >> int k,
|
||||
piles : &array (sorted_entier_list, n) >> _,
|
||||
lst : list (entier, m))
|
||||
:<!wrt> #[k : nat | j <= k; k <= n] void =
|
||||
(* This implementation verifies at compile time that the
|
||||
piles are sorted. *)
|
||||
case+ lst of
|
||||
| NIL => ()
|
||||
| head :: tail =>
|
||||
let
|
||||
val @(i, pile) = find_pile (num_piles, piles, head)
|
||||
prval () = lemma_sorted_entier_list_param pile
|
||||
in
|
||||
piles[i] := head ::: pile;
|
||||
num_piles := max (num_piles, succ i);
|
||||
deal (num_piles, piles, tail);
|
||||
end
|
||||
|
||||
fun
|
||||
make_list_of_piles
|
||||
{num_piles, i : nat | num_piles <= n;
|
||||
i <= num_piles}
|
||||
.<num_piles - i>.
|
||||
(num_piles : int num_piles,
|
||||
piles : &array (sorted_entier_list, n),
|
||||
i : int i)
|
||||
:<> [m : nat] @(list (sorted_entier_list, m), int m) =
|
||||
(* I do NOT bother to make this implementation tail
|
||||
recursive. *)
|
||||
if i = num_piles then
|
||||
@(NIL, 0)
|
||||
else
|
||||
let
|
||||
val @(lst, m) =
|
||||
make_list_of_piles (num_piles, piles, succ i)
|
||||
in
|
||||
@(piles[i] :: lst, succ m)
|
||||
end
|
||||
|
||||
var num_piles : Int = 0
|
||||
val () = deal (num_piles, piles, lst)
|
||||
val @(list_of_piles, m) =
|
||||
make_list_of_piles (num_piles, piles, 0)
|
||||
|
||||
val () = array_ptr_free (pf, pfgc | p)
|
||||
|
||||
fun
|
||||
merge_piles {m : nat} .<m>.
|
||||
(list_of_piles : list (sorted_entier_list, m),
|
||||
m : int m)
|
||||
:<!wrt> sorted_entier_list =
|
||||
(* This is essentially the same algorithm as a
|
||||
NON-tail-recursive mergesort. *)
|
||||
if m = 1 then
|
||||
let
|
||||
val+ sorted_lst :: NIL = list_of_piles
|
||||
in
|
||||
sorted_lst
|
||||
end
|
||||
else if m = 0 then
|
||||
SNIL
|
||||
else
|
||||
let
|
||||
val m_left = m \g1int_ndiv 2
|
||||
val m_right = m - m_left
|
||||
val @(left, right) =
|
||||
list_split_at (list_of_piles, m_left)
|
||||
val left = merge_piles (list_vt2t left, m_left)
|
||||
and right = merge_piles (right, m_right)
|
||||
in
|
||||
left \merge right
|
||||
end
|
||||
in
|
||||
merge_piles (list_of_piles, m)
|
||||
end
|
||||
end
|
||||
|
||||
implement
|
||||
sorted_entier_list2list lst =
|
||||
(* This implementation is *NOT* tail recursive. It will use O(n)
|
||||
stack space. *)
|
||||
let
|
||||
fun
|
||||
recurs {n : nat} .<n>.
|
||||
(lst : sorted_entier_list n)
|
||||
:<> list (entier, n) =
|
||||
case+ lst of
|
||||
| SNIL => NIL
|
||||
| head ::: tail => head :: recurs tail
|
||||
|
||||
prval () = lemma_sorted_entier_list_param lst
|
||||
in
|
||||
recurs lst
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
|
||||
fn
|
||||
print_Int_list
|
||||
{n : int}
|
||||
(lst : list (Int, n))
|
||||
: void =
|
||||
let
|
||||
fun
|
||||
loop {n : nat} .<n>.
|
||||
(lst : list (Int, n))
|
||||
: void =
|
||||
case+ lst of
|
||||
| NIL => ()
|
||||
| head :: tail =>
|
||||
begin
|
||||
print! (" ");
|
||||
print! (head);
|
||||
loop tail
|
||||
end
|
||||
prval () = lemma_list_param lst
|
||||
in
|
||||
loop lst
|
||||
end
|
||||
|
||||
implement
|
||||
main0 () =
|
||||
let
|
||||
val example_list =
|
||||
$list (22, 15, 98, 82, 22, 4, 58, 70, 80, 38, 49, 48, 46, 54,
|
||||
93, 8, 54, 2, 72, 84, 86, 76, 53, 37, 90)
|
||||
val sorted_list = patience_sort example_list
|
||||
in
|
||||
print! ("unsorted ");
|
||||
print_Int_list example_list;
|
||||
println! ();
|
||||
print! ("sorted ");
|
||||
print_Int_list (to_list sorted_list);
|
||||
println! ()
|
||||
end
|
||||
|
||||
(*------------------------------------------------------------------*)
|
||||
Loading…
Add table
Add a link
Reference in a new issue