Files
mercury/tests/general/array_binsearch.m
Zoltan Somogyi 33eb3028f5 Clean up the tests in half the test directories.
tests/accumulator/*.m:
tests/analysis_*/*.m:
tests/benchmarks*/*.m:
tests/debugger*/*.{m,exp,inp}:
tests/declarative_debugger*/*.{m,exp,inp}:
tests/dppd*/*.m:
tests/exceptions*/*.m:
tests/general*/*.m:
tests/grade_subdirs*/*.m:
tests/hard_coded*/*.m:
    Make these tests use four-space indentation, and ensure that
    each module is imported on its own line. (I intend to use the latter
    to figure out which subdirectories' tests can be executed in parallel.)

    These changes usually move code to different lines. For the debugger tests,
    specify the new line numbers in .inp files and expect them in .exp files.
2015-02-14 20:14:03 +11:00

325 lines
11 KiB
Mathematica

%---------------------------------------------------------------------------%
% vim: ts=4 sw=4 et ft=mercury
%
% Test the array.[approx_]binary_search predicates.
%
%---------------------------------------------------------------------------%
:- module array_binsearch.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
%---------------------------------------------------------------------------%
%---------------------------------------------------------------------------%
:- implementation.
:- import_module array.
:- import_module int.
:- import_module list.
:- import_module string.
%---------------------------------------------------------------------------%
main(!IO) :-
SortedList = [1, 1, 1, 3, 3, 3, 5, 5, 7, 7, 8, 8, 10, 10, 11, 11,
13, 13, 13, 16, 16, 19, 20, 20, 21, 21, 23, 27, 28, 28, 28, 29, 31],
DistractedSortedList = [401, 1, 301, 403, 103, 303, 5, 5, 207, 307,
408, 108, 210, 10, 411, 311,
113, 213, 213, 316, 216, 319, 420, 220, 321, 121,
323, 227, 28, 228, 28, 29, 231],
Max = 32,
run_undistracted_tests(SortedList, Max, !IO),
run_distracted_tests(DistractedSortedList, Max, !IO).
:- func distraction_ordering(int, int) = comparison_result.
distraction_ordering(A, B) = R :-
UndistractedA = A rem 100,
UndistractedB = B rem 100,
R = ordering(UndistractedA, UndistractedB).
%---------------------------------------------------------------------------%
:- pred run_undistracted_tests(list(int)::in, int::in, io::di, io::uo) is det.
run_undistracted_tests(SortedList, Max, !IO) :-
array.from_list(SortedList, Array),
io.write_string("Undistracted tests\n", !IO),
io.write(SortedList, !IO),
io.nl(!IO),
io.nl(!IO),
undistracted_exact_test_loop(Array, 0, Max, !IO),
undistracted_approx_test_loop(Array, 0, Max, !IO).
:- pred undistracted_exact_test_loop(array(int)::in, int::in, int::in,
io::di, io::uo) is det.
undistracted_exact_test_loop(Array, Cur, Max, !IO) :-
( if Cur > Max then
io.nl(!IO)
else
io.format("exact search for %3d ", [i(Cur)], !IO),
( if array.binary_search(ordering, Array, Cur, Index) then
( if
exact_verify_success(ordering, Array, Max, Cur, Index,
First, Last)
then
io.format("succeeds correctly at %3d", [i(Index)], !IO),
io.format(", first %3d, last %3d\n", [i(First), i(Last)], !IO)
else
io.format("succeeds INCORRECTLY at %3d\n", [i(Index)], !IO)
)
else
( if exact_verify_failure(ordering, Array, Max, Cur) then
io.format("fails correctly\n", [], !IO)
else
io.format("fails INCORRECTLY\n", [], !IO)
)
),
undistracted_exact_test_loop(Array, Cur + 1, Max, !IO)
).
:- pred undistracted_approx_test_loop(array(int)::in, int::in, int::in,
io::di, io::uo) is det.
undistracted_approx_test_loop(Array, Cur, Max, !IO) :-
( if Cur > Max then
io.nl(!IO)
else
io.format("approx search for %3d ", [i(Cur)], !IO),
( if
array.approx_binary_search(ordering, Array, Cur, Index)
then
( if
approx_verify_success(distraction_ordering, Array, Max, Cur,
Index, First, Last)
then
io.format("succeeds correctly at %3d", [i(Index)], !IO),
io.format(", first %3d, last %3d\n", [i(First), i(Last)], !IO)
else
io.format("succeeds INCORRECTLY at %3d\n", [i(Index)], !IO)
)
else
( if
approx_verify_failure(distraction_ordering, Array, Max, Cur)
then
io.format("fails correctly\n", [], !IO)
else
io.format("fails INCORRECTLY\n", [], !IO)
)
),
undistracted_approx_test_loop(Array, Cur + 1, Max, !IO)
).
%---------------------------------------------------------------------------%
:- pred run_distracted_tests(list(int)::in, int::in, io::di, io::uo) is det.
run_distracted_tests(SortedList, Max, !IO) :-
array.from_list(SortedList, Array),
io.write_string("Distracted tests\n", !IO),
io.write(SortedList, !IO),
io.nl(!IO),
io.nl(!IO),
distracted_exact_test_loop(Array, 0, 0, Max, !IO),
distracted_exact_test_loop(Array, 1, 0, Max, !IO),
distracted_exact_test_loop(Array, 2, 0, Max, !IO),
distracted_exact_test_loop(Array, 3, 0, Max, !IO),
distracted_exact_test_loop(Array, 4, 0, Max, !IO),
distracted_approx_test_loop(Array, 0, 0, Max, !IO),
distracted_approx_test_loop(Array, 1, 0, Max, !IO),
distracted_approx_test_loop(Array, 2, 0, Max, !IO),
distracted_approx_test_loop(Array, 3, 0, Max, !IO),
distracted_approx_test_loop(Array, 4, 0, Max, !IO).
:- pred distracted_exact_test_loop(array(int)::in, int::in, int::in, int::in,
io::di, io::uo) is det.
distracted_exact_test_loop(Array, Distraction, Cur, Max, !IO) :-
( if Cur > Max then
io.nl(!IO)
else
DCur = Distraction * 100 + Cur,
io.format("exact search for %3d ", [i(DCur)], !IO),
( if
array.binary_search(distraction_ordering, Array, DCur, Index)
then
( if
exact_verify_success(distraction_ordering, Array, Max, DCur,
Index, First, Last)
then
io.format("succeeds correctly at %3d", [i(Index)], !IO),
io.format(", first %3d, last %3d\n", [i(First), i(Last)], !IO)
else
io.format("succeeds INCORRECTLY at %3d\n", [i(Index)], !IO)
)
else
( if
exact_verify_failure(distraction_ordering, Array, Max, DCur)
then
io.format("fails correctly\n", [], !IO)
else
io.format("fails INCORRECTLY\n", [], !IO)
)
),
distracted_exact_test_loop(Array, Distraction, Cur + 1, Max, !IO)
).
:- pred distracted_approx_test_loop(array(int)::in, int::in, int::in, int::in,
io::di, io::uo) is det.
distracted_approx_test_loop(Array, Distraction, Cur, Max, !IO) :-
( if Cur > Max then
io.nl(!IO)
else
DCur = Distraction * 100 + Cur,
io.format("approx search for %3d ", [i(DCur)], !IO),
( if
array.approx_binary_search(distraction_ordering, Array,
DCur, Index)
then
( if
approx_verify_success(distraction_ordering, Array, Max, DCur,
Index, First, Last)
then
io.format("succeeds correctly at %3d", [i(Index)], !IO),
io.format(", first %3d, last %3d\n", [i(First), i(Last)], !IO)
else
io.format("succeeds INCORRECTLY at %3d\n", [i(Index)], !IO)
)
else
( if
approx_verify_failure(distraction_ordering, Array, Max, DCur)
then
io.format("fails correctly\n", [], !IO)
else
io.format("fails INCORRECTLY\n", [], !IO)
)
),
distracted_approx_test_loop(Array, Distraction, Cur + 1, Max, !IO)
).
%---------------------------------------------------------------------------%
:- pred exact_verify_success(comparison_func(int)::in, array(int)::in,
int::in, int::in, int::in, int::out, int::out) is semidet.
exact_verify_success(Cmp, Array, Max, Value, FoundIndex,
FirstIndex, LastIndex) :-
array.lookup(Array, FoundIndex, ValueAtFoundIndex),
Cmp(ValueAtFoundIndex, Value) = Res,
Res = (=),
require_det (
exact_search_back(Cmp, Array, Value, FoundIndex, FirstIndex),
exact_search_forward(Cmp, Array, Max, Value, FoundIndex, LastIndex)
).
:- pred exact_search_back(comparison_func(int)::in, array(int)::in,
int::in, int::in, int::out) is det.
exact_search_back(Cmp, Array, Value, CurIndex, FirstIndex) :-
% invariant: Array[CurIndex] = Value
NextIndex = CurIndex - 1,
( if NextIndex >= 0 then
array.lookup(Array, NextIndex, ValueAtNextIndex),
( if Cmp(ValueAtNextIndex, Value) = (=) then
exact_search_back(Cmp, Array, Value, NextIndex, FirstIndex)
else
FirstIndex = CurIndex
)
else
FirstIndex = CurIndex
).
:- pred exact_search_forward(comparison_func(int)::in, array(int)::in,
int::in, int::in, int::in, int::out) is det.
exact_search_forward(Cmp, Array, Max, Value, CurIndex, LastIndex) :-
% invariant: Array[CurIndex] = Value
NextIndex = CurIndex + 1,
( if NextIndex < Max then
array.lookup(Array, NextIndex, ValueAtNextIndex),
( if Cmp(ValueAtNextIndex, Value) = (=) then
exact_search_forward(Cmp, Array, Max, Value, NextIndex, LastIndex)
else
LastIndex = CurIndex
)
else
LastIndex = CurIndex
).
:- pred exact_verify_failure(comparison_func(int)::in, array(int)::in,
int::in, int::in) is semidet.
exact_verify_failure(Cmp, Array, Max, Value) :-
exact_verify_failure_loop(Cmp, Array, 0, Max, Value).
:- pred exact_verify_failure_loop(comparison_func(int)::in, array(int)::in,
int::in, int::in, int::in) is semidet.
exact_verify_failure_loop(Cmp, Array, Cur, Max, Value) :-
( if Cur = Max then
true
else
array.lookup(Array, Cur, CurValue),
Cmp(CurValue, Value) \= (=),
exact_verify_failure_loop(Cmp, Array, Cur + 1, Max, Value)
).
%---------------------------------------------------------------------------%
:- pred approx_verify_success(comparison_func(int)::in, array(int)::in,
int::in, int::in, int::in, int::out, int::out) is semidet.
approx_verify_success(Cmp, Array, Max, Value, FoundIndex,
FirstIndex, LastIndex) :-
array.lookup(Array, FoundIndex, ValueAtFoundIndex),
Cmp(ValueAtFoundIndex, Value) = Res,
(
Res = (=),
require_det (
exact_search_back(Cmp, Array, Value, FoundIndex, FirstIndex),
exact_search_forward(Cmp, Array, Max, Value, FoundIndex, LastIndex)
)
;
Res = (<),
require_det (
exact_search_back(Cmp, Array, ValueAtFoundIndex,
FoundIndex, FirstIndex),
exact_search_forward(Cmp, Array, Max, ValueAtFoundIndex,
FoundIndex, LastIndex)
),
FollowIndex = LastIndex + 1,
( if FollowIndex < Max then
array.lookup(Array, FollowIndex, ValueAtFollowIndex),
Cmp(Value, ValueAtFollowIndex) = (<)
else
true
)
).
:- pred approx_verify_failure(comparison_func(int)::in, array(int)::in,
int::in, int::in) is semidet.
approx_verify_failure(Cmp, Array, Max, Value) :-
approx_verify_failure_loop(Cmp, Array, 0, Max, Value).
:- pred approx_verify_failure_loop(comparison_func(int)::in, array(int)::in,
int::in, int::in, int::in) is semidet.
approx_verify_failure_loop(Cmp, Array, Cur, Max, Value) :-
( if Cur = Max then
true
else
array.lookup(Array, Cur, CurValue),
Cmp(CurValue, Value) = (>),
approx_verify_failure_loop(Cmp, Array, Cur + 1, Max, Value)
).
%---------------------------------------------------------------------------%