TL; DR: Ответы @ CAFEBABE , @ CapelliC , @ mat и @ sharky все не хватает!
Итак ... что же точно являются недостатками ответов, предложенных ранее?
@ CAFEBABE заявлено:
Приятно, что в этом решении время выполнения линейно по длине обоих списков.
Давайте проверим это утверждение!
?- numlist(1,1000,Zs), time(posAt__CAFEBABE1(Zs,1000,Zs)).
% <b>999,001</b> inferences, 0.090 CPU in 0.091 seconds (100% CPU, 11066910 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 4 inferences, 0.000 CPU in 0.000 seconds (97% CPU, 66738 Lips)
false.
Облом! Остальные прекрасно справляются:
<sub>?- numlist(1,1000,Zs), time(posAt__CapelliC1(Zs,1000,Zs)).
% <b>671</b> inferences, 0.000 CPU in 0.000 seconds (98% CPU, 3492100 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...].
?- numlist(1,1000,Zs), time(posAt__mat1(Zs,1000,Zs)).
% <b>3,996</b> inferences, 0.001 CPU in 0.001 seconds (99% CPU, 3619841 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 5 inferences, 0.000 CPU in 0.000 seconds (89% CPU, 154703 Lips)
false.
?- numlist(1,1000,Zs), time(posAt__sharky1(Zs,1000,Zs)).
% <b>1,000</b> inferences, 0.000 CPU in 0.000 seconds (100% CPU, 2627562 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 4 inferences, 0.000 CPU in 0.000 seconds (82% CPU, 97109 Lips)
false.
</sub>
@ CapelliC использовал nth1/3
, что может (и может) вызвать проблемы с универсальным завершением:
?- time((posAt__CapelliC1(_,N,[a,b,c]), false)).
<b>**LOOPS**</b>
D'Oh! Все остальные прекрасно справляются:
<sub>?- time((posAt__CAFEBABE1(_,_,[a,b,c]), false)).
% 14 inferences, 0.000 CPU in 0.000 seconds (88% CPU, 1098470 Lips)
<b>false</b>.
?- time((posAt__mat1(_,_,[a,b,c]), false)).
% 2,364 inferences, 0.001 CPU in 0.001 seconds (100% CPU, 2764075 Lips)
<b>false</b>.
?- time((posAt__sharky1(_,_,[a,b,c]), false)).
% 6 inferences, 0.000 CPU in 0.000 seconds (89% CPU, 207247 Lips)
<b>false</b>.
</sub>
Код @ mat имеет проблемы со сложностью.
@CAFEBABE и @CapelliC делают «немного лучше» - их коды работают быстрее, потому что они используют примитивы более низкого уровня (is)/2
и nth1/3
.
?- numlist(1,1000,Zs), time((posAt__mat1(Zs,_,_), false)).
% <b>33,365,972</b> inferences, 1.643 CPU in 1.643 seconds (100% CPU, 20304661 Lips)
false.
?- numlist(1,1000,Zs), time((posAt__CAFEBABE1(Zs,_,_), false)).
% <b>1,001,002</b> inferences, 0.083 CPU in 0.083 seconds (100% CPU, 12006557 Lips)
false.
?- numlist(1,1000,Zs), time((posAt__CapelliC1(Zs,_,_), false)).
% <b>171,673</b> inferences, 0.030 CPU in 0.030 seconds (100% CPU, 5810159 Lips)
false.
Код @sharky явно лучший в этом отношении:
<sub>?- numlist(1,1000,Zs), time((posAt__sharky1(Zs,_,_), false)).
% <b>1,003</b> inferences, 0.001 CPU in 0.001 seconds (100% CPU, 1605658 Lips)
false.
</sub>
В коде @ sharky используется встроенный мета-логический предикат (==)/2
, что приводит к потере логической устойчивости при использовании с недостаточно конкретизированными терминами. Этот запрос должен быть выполнен успешно:
?- posAt__sharky1([a], 1, Xs).
<b>false</b>.
Все остальные коды дают логически обоснованный ответ:
<sub>?- posAt__CAFEBABE1([a], 1, Xs).
<b>Xs = [a|_G235]</b> ;
false.
?- posAt__CapelliC1([a], 1, Xs).
<b>Xs = [a|_G235]</b>.
?- posAt__mat1([a], 1, Xs).
<b>Xs = [a|_G235]</b> ;
false.
</sub>
Проходя мимо первого ответа, код @ CAFEBABE получает больше, чем немного неэффективно:
?- numlist(1,1000,Zs), time(posAt__CAFEBABE1(Zs,1,Zs)).
% 0 inferences, 0.000 CPU in 0.000 seconds (93% CPU, 0 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% <b>999,004</b> inferences, 0.076 CPU in 0.076 seconds (100% CPU, 13121058 Lips)
false.
Аналогично & mdash; но на порядок меньше & mdash; проблемы с кодом @ sharky:
<sub>?- numlist(1,1000,Zs), time(posAt__sharky1(Zs,1,Zs)).
% 1 inferences, 0.000 CPU in 0.000 seconds (75% CPU, 31492 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% <b>1,003</b> inferences, 0.001 CPU in 0.001 seconds (100% CPU, 1078556 Lips)
false.</sub>
С кодами @CapelliC и @mat все в порядке:
<sub>?- numlist(1,1000,Zs), time(posAt__CapelliC1(Zs,1,Zs)).
% <b>7</b> inferences, 0.000 CPU in 0.000 seconds (85% CPU, 306802 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...].
?- numlist(1,1000,Zs), time(posAt__mat1(Zs,1,Zs)).
% 0 inferences, 0.000 CPU in 0.000 seconds (80% CPU, 0 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% <b>5</b> inferences, 0.000 CPU in 0.000 seconds (84% CPU, 345662 Lips)
false.
</sub>
Итак ... что нам делать?
Почему бы не следовать этому подходу и объединить код @ mat и @ sharky?
:- use_module(<a href="http://eu.swi-prolog.org/man/clpfd.html" rel="nofollow noreferrer">library(clpfd)</a>).
posAt__NEW(L0, Pos, L1) :-
posAt__NEW_(L0, 1, Pos, L1).
posAt__NEW_([<b>X</b>|_], Pos, Pos, [<b>X</b>|_]).
posAt__NEW_([_|X0s], CurrPos, Pos, [_|X1s]) :-
<b>CurrPos<a href="http://www.swi-prolog.org/pldoc/doc_for?object=%23%3C%20/%202" rel="nofollow noreferrer"> #< </a>Pos,</b>
NextPos<b><a href="http://www.swi-prolog.org/pldoc/doc_for?object=%23%3D%20/%202" rel="nofollow noreferrer"> #= </a></b>CurrPos + 1,
posAt__NEW_(X0s, NextPos, Pos, X1s).
Давайте снова запустим приведенные выше примеры запросов с помощью posAt__NEW/3
:
<sub>?- numlist(1,1000,Zs), time(posAt__NEW(Zs,1000,Zs)).
% <b>4,997</b> inferences, 0.000 CPU in 0.000 seconds (100% CPU, 18141619 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 9 inferences, 0.000 CPU in 0.000 seconds (71% CPU, 122877 Lips)
false.
?- time((posAt__NEW(_,_,[a,b,c]), false)).
% 440 inferences, 0.001 CPU in 0.001 seconds (98% CPU, 803836 Lips)
<b>false</b>.
?- numlist(1,1000,Zs), time((posAt__NEW(Zs,_,_), false)).
% <b>154,955</b> inferences, 0.014 CPU in 0.014 seconds (100% CPU, 11067900 Lips)
false.
?- posAt__NEW([a], 1, Xs).
<b>Xs = [a|_G229]</b> ;
false.
?- numlist(1,1000,Zs), time(posAt__NEW(Zs,1,Zs)).
% 1 inferences, 0.000 CPU in 0.000 seconds (93% CPU, 121818 Lips)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% <b>7</b> inferences, 0.000 CPU in 0.000 seconds (86% CPU, 266748 Lips)
false.
</sub>
Хорошо! Наконец, мы убедились, что цель, использованная в приведенном выше запросе 3 rd , имеет linear сложность:
<sub>?- numlist(1,100,Zs), time((posAt__NEW(Zs,_,_), false)).
% <b>15,455</b> inferences, 0.004 CPU in 0.004 seconds (100% CPU, 3545396 Lips)
false.
?- numlist(1,1000,Zs), time((posAt__NEW(Zs,_,_), false)).
% <b>154,955</b> inferences, 0.016 CPU in 0.017 seconds (98% CPU, 9456629 Lips)
false.
?- numlist(1,10000,Zs), time((posAt__NEW(Zs,_,_), false)).
% <b>1,549,955</b> inferences, 0.098 CPU in 0.099 seconds (99% CPU, 15790369 Lips)
false.
?- numlist(1,100000,Zs), time((posAt__NEW(Zs,_,_), false)).
% <b>15,499,955</b> inferences, 1.003 CPU in 1.007 seconds (100% CPU, 15446075 Lips)
false.
</sub>