TL;DR: @CAFEBABE、@CapelliC、@mat、および@sharky による回答はすべて不十分です!
それで...以前に提案された答えの欠点は正確には何ですか?
@CAFEBABE は次のように述べています。
このソリューションの優れた点は、ランタイムが両方のリストの長さに対して線形であることです。
その声明をテストしてみましょう!
?- numlist(1,1000,Zs), time(posAt__CAFEBABE1(Zs,1000,Zs))。
% 999,001推論、0.091 秒で 0.090 CPU (100% CPU、11066910 リップ)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 4 つの推論、0.000 秒で 0.000 CPU (97% CPU、66738 リップ)
間違い。
残念!他のものはうまくいきます:
?- numlist(1,1000,Zs), time(posAt__CapelliC1(Zs,1000,Zs))。
% 671推論、0.000 秒で 0.000 CPU (98% CPU、3492100 リップ)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...].
?- numlist(1,1000,Zs), time(posAt__mat1(Zs,1000,Zs))。
% 3,996推論、0.001 秒で 0.001 CPU (99% CPU、3619841 リップ)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 5 つの推論、0.000 秒で 0.000 CPU (89% CPU、154703 リップ)
間違い。
?- numlist(1,1000,Zs), time(posAt__sharky1(Zs,1000,Zs))。
% 1,000推論、0.000 秒で 0.000 CPU (100% CPU、2627562 リップ)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 4 つの推論、0.000 秒で 0.000 CPU (82% CPU、97109 リップ)
間違い。
@CapelliC used nth1/3
、これはユニバーサルターミネーションで問題を引き起こす可能性があります(実際に発生します):
?- time((posAt__CapelliC1(_,N,[a,b,c]), false))。
**ループ**
ああ!他のすべてはうまくいきます:
?- time((posAt__CAFEBABE1(_,_,[a,b,c]), false))。
% 14 の推論、0.000 秒で 0.000 CPU (88% CPU、1098470 リップ)
偽。
?- time((posAt__mat1(_,_,[a,b,c]), false))。
% 2,364 推論、0.001 秒で 0.001 CPU (100% CPU、2764075 リップ)
偽。
?- time((posAt__sharky1(_,_,[a,b,c]), false))。
% 6 推論、0.000 秒で 0.000 CPU (89% CPU、207247 リップ)
偽。
@mat のコードには複雑な問題があります。@CAFEBABE と @CapelliC は「少し優れています」 — 低レベルのプリミティブ(is)/2
とnth1/3
.
?- numlist(1,1000,Zs), time((posAt__mat1(Zs,_,_), false))。
% 33,365,972推論、1.643 秒で 1.643 CPU (100% CPU、20304661 リップ)
間違い。
?- numlist(1,1000,Zs), time((posAt__CAFEBABE1(Zs,_,_), false))。
% 1,001,002推論、0.083 秒で 0.083 CPU (100% CPU、12006557 リップ)
間違い。
?- numlist(1,1000,Zs), time((posAt__CapelliC1(Zs,_,_), false))。
% 171,673推論、0.030 秒で 0.030 CPU (100% CPU、5810159 リップ)
間違い。
@sharky によるコードは、この点で明らかに最適です。
?- numlist(1,1000,Zs), time((posAt__sharky1(Zs,_,_), false))。
% 1,003推論、0.001 秒で 0.001 CPU (100% CPU、1605658 リップ)
間違い。
@sharky のコードはメタ論理組み込み述語(==)/2
を使用しているため、インスタンス化が不十分な用語で使用すると論理的な健全性が失われます。このクエリは成功するはずです:
?- posAt__sharky1([a], 1, Xs).
偽。
他のコードはすべて論理的に正しい答えを与えます:
?- posAt__CAFEBABE1([a], 1, Xs).
Xs = [a|_G235] ;
間違い。
?- posAt__CapelliC1([a], 1, Xs).
Xs = [a|_G235] .
?- posAt__mat1([a], 1, Xs).
Xs = [a|_G235] ;
間違い。
最初の答えを過ぎると、@ CAFEBABEのコードは少し効率が悪くなります。
?- numlist(1,1000,Zs), time(posAt__CAFEBABE1(Zs,1,Zs))。
% 0 推論、0.000 秒で 0.000 CPU (93% CPU、0 リップ)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 999,004推論、0.076 秒で 0.076 CPU (100% CPU、13121058 リップ)
間違い。
@sharky のコードでは、同様の (ただし、1 桁小さい) 問題が発生しています。
?- numlist(1,1000,Zs), time(posAt__sharky1(Zs,1,Zs))。
% 1 推論、0.000 秒で 0.000 CPU (75% CPU、31492 リップ)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 1,003推論、0.001 秒で 0.001 CPU (100% CPU、1078556 リップ)
間違い。
@CapelliC と @mat によるコードはどちらも問題なく動作しています。
?- numlist(1,1000,Zs), time(posAt__CapelliC1(Zs,1,Zs))。
% 7推論、0.000 秒で 0.000 CPU (85% CPU、306802 リップ)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...].
?- numlist(1,1000,Zs), time(posAt__mat1(Zs,1,Zs))。
% 0 推論、0.000 秒で 0.000 CPU (80% CPU、0 リップ)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 5 つの推論、0.000 秒で 0.000 CPU (84% CPU、345662 リップ)
間違い。
どうしようか?このアプローチに従って、@mat と @sharky のコードを組み合わせてみませんか?
:- use_module(ライブラリ(clpfd) )。
posAt__NEW(L0, 位置, L1) :-
posAt__NEW_(L0, 1, 位置, L1).
posAt__NEW_([ X |_], 位置, 位置, [ X |_])。
posAt__NEW_([_|X0s], CurrPos, Pos, [_|X1s]) :-
CurrPos #< Pos,
NextPos #= CurrPos + 1,
posAt__NEW_(X0s、NextPos、Pos、X1s)。
posAt__NEW/3
上記のサンプル クエリを次のように再実行してみましょう。
?- numlist(1,1000,Zs), time(posAt__NEW(Zs,1000,Zs))。
% 4,997推論、0.000 秒で 0.000 CPU (100% CPU、18141619 リップ)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 9 つの推論、0.000 秒で 0.000 CPU (71% CPU、122877 リップ)
間違い。
?- time((posAt__NEW(_,_,[a,b,c]), false))。
% 440 推論、0.001 秒で 0.001 CPU (98% CPU、803836 リップ)
偽。
?- numlist(1,1000,Zs), time((posAt__NEW(Zs,_,_), false))。
% 154,955推論、0.014 秒で 0.014 CPU (100% CPU、11067900 リップ)
間違い。
?- posAt__NEW([a], 1, Xs).
Xs = [a|_G229] ;
間違い。
?- numlist(1,1000,Zs), time(posAt__NEW(Zs,1,Zs))。
% 1 推論、0.000 秒で 0.000 CPU (93% CPU、121818 リップ)
Zs = [1, 2, 3, 4, 5, 6, 7, 8, 9|...] ;
% 7推論、0.000 秒で 0.000 CPU (86% CPU、266748 リップ)
間違い。
大丈夫!最後に、上記の 3番目のクエリで使用されるゴールが線形複雑性を持つことを確認します。
?- numlist(1,100,Zs), time((posAt__NEW(Zs,_,_), false))。
% 15,455の推論、0.004 秒で 0.004 CPU (100% CPU、3545396 リップ)
間違い。
?- numlist(1,1000,Zs), time((posAt__NEW(Zs,_,_), false))。
% 154,955推論、0.017 秒で 0.016 CPU (98% CPU、9456629 リップ)
間違い。
?- numlist(1,10000,Zs), time((posAt__NEW(Zs,_,_), false))。
% 1,549,955推論、0.099 秒で 0.098 CPU (99% CPU、15790369 リップ)
間違い。
?- numlist(1,100000,Zs), time((posAt__NEW(Zs,_,_), false))。
% 15,499,955推論、1.007 秒で 1.003 CPU (100% CPU、15446075 リップ)
間違い。