I’m looking for a fast way to sort a list in reverse order in Prolog. Algorithmically it should perform as quickly as standard sort, but the options that I’ve come up with are much slower, for obvious reasons.
Predicate rsort1/2 sorts and then reverses.
rsort1(L1, L2) :-
sort(L1, Tmp),
reverse(Tmp, L2).
Predicate rsort2/2 uses predsort/3 with a custom comparator.
rsort2(L1, L2) :-
predsort(reverse_compare, L1, L2).
reverse_compare(Delta, E1, E2) :-
compare(Delta, E2, E1).
To test their performance I’ve generated a huge random list like this:
?- Size = 1234567,
findall(N, (between(1, Size, _), N is random(Size)), Ns),
assert(test_list(Ns)).
Size = 1234567,
Ns = [183677, 351963, 737135, 246842, 22754, 1176800, 1036258|...].
These are the runtimes for the standard sort:
?- test_list(Ns), time(sort(Ns, NsS)).
% 2 inferences, 7.550 CPU in 8.534 seconds (88% CPU, 0 Lips)
Ns = [183677, 351963, 737135, 246842, 22754, 1176800, 1036258, 625628|...],
NsS = [0, 1, 3, 5, 8, 10, 12, 14, 16|...].
… for rsort1:
?- test_list(Ns), time(rsort1(Ns, NsS)).
% 779,895 inferences, 8.310 CPU in 9.011 seconds (92% CPU, 93850 Lips)
Ns = [183677, 351963, 737135, 246842, 22754, 1176800, 1036258, 625628|...],
NsS = [1234564, 1234563, 1234562, 1234558, 1234557, 1234556, 1234555|...].
… and for rsort2:
?- test_list(Ns), time(rsort2(Ns, NsS)).
% 92,768,484 inferences, 67.990 CPU in 97.666 seconds (70% CPU, 1364443 Lips)
Ns = [183677, 351963, 737135, 246842, 22754, 1176800, 1036258, 625628|...],
NsS = [1234564, 1234563, 1234562, 1234558, 1234557, 1234556, 1234555|...].
Can I do better than rsort1 and rsort2 speedwise?
If you’re after a sorting routine that is portable (i.e., defined using PROLOG), then you probably won’t be able to implement anything faster (or as fast, with a need to reverse the sort order) than those predicates that execute sorting routines natively in C/C++, such as
sort/2ormsort/2.If speed is of overriding concern here, you could of course write your own non-portable predicate with an external definition to do the reverse sorting. For example, the SWI-PL C++ interface could be used (see the examples there) to write a C++ definition of
rsort/2, perhaps using the comparison predicates also implemented in C++.Similarly, you could also write
rsort/2in C using the SWI-PL C interface.src/pl-list.cin the SWI-PROLOG source contains implementations of the sorting methods (namelynat_sort()) which is used forsort/2,msort/2andkeysort/2. To implementrsort/2, you might only need to follow their implementation and tweak/reverse the interpretation of calls tocompare()which describes the standard order of terms.