Sorting algorithms/Patience sort: Difference between revisions

Content added Content deleted
Line 1,122: Line 1,122:
.include "../affichage.inc"
.include "../affichage.inc"
</lang>
</lang>

=={{header|ATS}}==

===A patience sort for non-linear lists of integers, guaranteeing a sorted result===

<lang ats>//--------------------------------------------------------------------
//
// 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_length
{n : int}
(lst : sorted_entier_list n)
:<> [0 <= n] int n
*)

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_length {n} lst =
(* This implementation is tail-recursive. *)
let
fun
count {m : nat | m <= n} .<n - m>.
(lst : sorted_entier_list (n - m),
m : int m)
:<> [0 <= n] int n =
case+ lst of
| SNIL => m
| _ ::: tail => count {m + 1} (tail, succ m)

prval () = lemma_sorted_entier_list_param lst
in
count (lst, 0)
end
*)

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

(*------------------------------------------------------------------*)</lang>

{{out}}
<pre>$ patscc -O3 -DATS_MEMALLOC_GCBDW patience_sort_task_verified.dats -lgc && ./a.out
unsorted 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
sorted 2 4 8 15 22 22 37 38 46 48 49 53 54 54 58 70 72 76 80 82 84 86 90 93 98</pre>


=={{header|AutoHotkey}}==
=={{header|AutoHotkey}}==