具体的な例を見ると、すぐに関係のない詳細に埋もれてしまいます。プログラムの重要な特性を見失うほどです。代わりに、障害スライスと呼ばれる次のプログラム フラグメントを見てみましょう。プログラムに目標を追加すると、失敗スライスが得false
られます。失敗スライスは、多くの興味深い特性を元のプログラムと共有しています。たとえばGoal, false
、障害スライスで実行された目標は、元のプログラムよりも多くの推論を使用することはありません。または逆に、元のプログラムはより多くの (またはせいぜい同じ数の) 推論を使用します。そこで、そのようなスライスの 1 つを指摘させてください。
list_to_set([],[]) :- false .
list_to_set([A|X],[A|Y]):-
list_to_set(X,Y), false ,
\+member(A,Y) .
list_to_set([A|X],Y):-
list_to_set(X,Y), false ,
member(A,Y) .
そして、このフラグメントはもはや具体的な要素には関心がないので (A
も も使用されなくなりました)、最も一般的なリストにmember/2
使用できます。length/2
このようにして、すべての長さに必要な推論の最小数を次のように観察できます。
?- length(L, N), call_inferences((list_to_set(L,_),false;true),Inf)。
N = 0、Inf = 3;
N = 1、Inf = 6;
N = 2、Inf = 12;
N = 3、Inf = 24;
N = 4、Inf = 48;
N = 5、Inf = 96;
N = 6、Inf = 192;
N = 7、Inf = 384;
N = 8、Inf = 768;
N = 9、Inf = 1536;
N = 10、Inf = 3072 ...
使用する
:- meta_predicate user:call_inferences(0,-).
call_inferences( Goal, Inferences) :-
statistics(inferences, Inferences0),
Goal,
statistics(inferences, Inferences1),
Inferences is Inferences1 - Inferences0.
推論の数は、要素が増えるごとに 2 倍になります。つまり、指数関数的に成長します。したがって、実装には少なくとも指数関数的に多くの推論が必要です...具体的な例を見る必要はありません。
あなたのプログラムにはさらに問題があります:
?- L=[A,B],list_to_set(L,S), L = [a,b].
失敗しますが、
?- L=[A,B], L = [a,b], list_to_set(L,S).
成功します。つまり、プログラムはもはや純粋な関係ではありません。maplist(dif(A),Y)
の代わりに使用し\+ member(A,Y)
ます。