Files
mercury/tests/hard_coded/stable_sort.m
2019-12-30 05:25:40 +11:00

90 lines
2.6 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%---------------------------------------------------------------------------%
%
% Test whether list.sort is stable.
%
%---------------------------------------------------------------------------%
:- module stable_sort.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- import_module bool.
:- import_module int.
:- import_module list.
:- import_module random.
:- import_module random.sfc16.
main(!IO) :-
generate_random_list(List),
% io.write(List),
% io.nl,
% io.write(sort(List) `with_type` list({int, int})),
% io.nl,
is_sort_stable(List, Stable),
(
Stable = yes,
io.write_string("list.sort/3 appears stable\n", !IO)
;
Stable = no,
io.write_string("list.sort/3 is not stable\n", !IO)
).
:- pred generate_random_list(list({int, int})::out) is det.
generate_random_list(List) :-
RandomState0 = random.sfc16.init,
% We generate random integers from 0 to 9. The list length must be
% large enough to ensure that there are plenty of duplications,
% otherwise the test is trivial.
Count = 100,
generate_random_list_2(Count, [], List, RandomState0, _).
:- pred generate_random_list_2(int::in,
list({int, int})::in, list({int, int})::out,
RandomState::in, RandomState::out) is det <= random(RandomState).
generate_random_list_2(Count, List0, List, !RandomState) :-
( if Count > 0 then
uniform_int_in_range(0, 9, R1, !RandomState),
uniform_int_in_range(0, 9, R2, !RandomState),
generate_random_list_2(Count - 1, [{R1, R2} | List0], List,
!RandomState)
else
List = List0
).
:- pred is_sort_stable(list({int, int})::in, bool::out) is det.
is_sort_stable(Unsorted, Stable) :-
% If the sort is stable, then sorting on the second component
% followed by sorting on the first component *should* give a
% fully sorted result.
list.sort(compare_second, Unsorted, SortedOnSecond),
list.sort(compare_first, SortedOnSecond, SortedOnSecondThenFirst),
% Check whether the result is fully sorted.
list.sort(Unsorted, Sorted),
( if SortedOnSecondThenFirst = Sorted then
Stable = yes
else
Stable = no
).
:- pred compare_first({int, int}::in, {int, int}::in, comparison_result::out)
is det.
compare_first({A, _}, {B, _}, Res) :-
compare(Res, A, B).
:- pred compare_second({int, int}::in, {int, int}::in, comparison_result::out)
is det.
compare_second({_, A}, {_, B}, Res) :-
compare(Res, A, B).