我认为@CapelliC [已删除] 的比较具有误导性。 OP 要求一个谓词比较两个列表 并检查它们是否相同,除了可能出现交换的最后两个元素(这与 只是 交换单个列表的最后两个元素)。因此,更公平的比较应该调用要与两个实例化列表作为输入进行比较的谓词。
我的建议是修改perf_belt/3如下:
/* File: last2swap_perf.pl
Author: Carlo
Created: Dec 12 2021
Purpose: compare answers to https://stackoverflow.com/q/70281408/874024
*/
:- module(last2swap_perf, [cmp/2]).
:- meta_predicate perf_belt(+,+,3).
% CapelliC's solutions
% append/2 based
last2swap_app2(A,B,[U,V]):-
append([C,[U,V]],A),
append([C,[V,U]],B).
% append/3 based
last2swap_app3(A,B,[U,V]):-
append(C,[U,V],A),
append(C,[V,U],B).
% slago' solution
lastTwoReversed(L1, L2, [X1,X2]) :-
reverse(L1, [X1,X2|Rest]),
reverse(L2, [X2,X1|Rest]).
% brebs' answer
swap_last_2([Elem1, Elem2|Tail], SwappedLst, Last2) :-
swap_last_2_(Tail, Elem1, Elem2, [], RevSwappedLst, Last2),
reverse(RevSwappedLst, SwappedLst).
% This swaps the last 2 elements
swap_last_2_([], Elem1, Elem2, SoFar, [Elem1, Elem2|SoFar], [Elem2, Elem1]).
swap_last_2_([Head|Tail], Elem1, Elem2, SoFar, SwappedLst, Last2) :-
% Move the elements along
swap_last_2_(Tail, Elem2, Head, [Elem1|SoFar], SwappedLst, Last2).
%! %%% minimal perf utility
perf_belt(NRep, LList, Pred) :- % <== NEW VERSION PROPOSED
make_lists(LList, List1, List2),
time( forall(between(1, NRep, _), % <== TWO INSTANTIATED LISTS AS INPUT
call(Pred, List1, List2, _)) ).
make_lists(N, List1, List2) :-
N1 is N - 1,
N2 is N - 2,
numlist(1, N2, Prefix),
append(Prefix, [N1, N], List1),
append(Prefix, [N, N1], List2).
cmp(NRep,LList) :-
perf_belt(NRep,LList,last2swap_app2),
perf_belt(NRep,LList,last2swap_app3),
perf_belt(NRep,LList,lastTwoReversed),
perf_belt(NRep,LList,swap_last_2).
结果更公平在 SWI-Prolog 8.4.1 版本上运行,我们可以看到双反转还不错。
?- cmp(100, 100).
% 71,101 inferences, 0.000 CPU in 0.000 seconds (?% CPU, Infinite Lips)
% 20,101 inferences, 0.000 CPU in 0.000 seconds (?% CPU, Infinite Lips)
% 20,701 inferences, 0.000 CPU in 0.000 seconds (?% CPU, Infinite Lips)
% 20,401 inferences, 0.000 CPU in 0.000 seconds (?% CPU, Infinite Lips)
true.
?- cmp(100, 1000).
% 701,101 inferences, 0.047 CPU in 0.047 seconds (100% CPU, 14956821 Lips)
% 200,101 inferences, 0.031 CPU in 0.031 seconds (100% CPU, 6403232 Lips)
% 200,701 inferences, 0.016 CPU in 0.016 seconds (100% CPU, 12844864 Lips)
% 200,401 inferences, 0.016 CPU in 0.016 seconds (100% CPU, 12825664 Lips)
true.
?- cmp(1000, 1000).
% 7,011,001 inferences, 0.438 CPU in 0.437 seconds (100% CPU, 16025145 Lips)
% 2,001,001 inferences, 0.219 CPU in 0.219 seconds (100% CPU, 9147433 Lips)
% 2,007,001 inferences, 0.141 CPU in 0.141 seconds (100% CPU, 14272007 Lips)
% 2,004,001 inferences, 0.141 CPU in 0.141 seconds (100% CPU, 14250674 Lips)
true.