如何访问prolog中的列表排列?

时间:2012-02-03 19:29:09

标签: list prolog permutation prolog-dif

我想访问列表排列并将其作为参数传递给其他函数。

这是排列代码:

takeout(X,[X|R],R).  
takeout(X,[F|R],[F|S]) :-
   takeout(X,R,S),
   write(S).

perm([X|Y],Z) :-
   perm(Y,W),
   takeout(X,Z,W).  
perm([],[]).

3 个答案:

答案 0 :(得分:9)

首先,让我们重新定义你的谓词,这样他们就不会做任何不必要的I / O:

takeout(X,[X|R],R).  
takeout(X,[F |R],[F|S]) :- takeout(X,R,S).

perm([X|Y],Z) :- perm(Y,W), takeout(X,Z,W).  
perm([],[]).

现在你可以被认为是一种“纯粹的”排列函数:

?- perm([1,2,3], X).
X = [1, 2, 3] ;
X = [2, 1, 3] ;
X = [2, 3, 1] ;
X = [1, 3, 2] ;
X = [3, 1, 2] ;
X = [3, 2, 1] ;
false.

因此,假设您有一个max_heap函数,它接受一个值列表并生成一个树。我会让你担心,所以让我们假设它存在并被称为max_heap/2,让我们进一步假设你有办法展示这个有吸引力的display_heap/1。为了“取”排列并将其作为参数“发送”给这些函数,你实际上在数学中说:假设P是X的排列,让我们用它做一个max_heap并显示它。或者,假设P是X的排列,H是由X组成的最大堆,让我们显示H:

show_heaps(List) :- perm(List, P), max_heap(P, H), display_heap(H).

这与我的英语句子相同:假设P是列表的排列,那么H是它的堆表示,然后显示它。从技术上讲,display_heap/1仍然是一个谓词,对于给定的堆可能是真或假。在实践中,它始终是真的,如果你运行它,你仍然必须反复点击;说,给我另一个解决方案,除非你使用故障驱动的循环或类似{{的语外谓词1}}使所有解决方案都找到。

编辑:让我们讨论故障驱动的循环和findall/3。首先让我添加一些新的谓词,因为我不确切知道你在做什么,但这对我们的目的无关紧要。

findall/3

所以现在我有一个谓词double([X|Xs], [Y|Ys]) :- Y is X*2, double(Xs, Ys). double([],[]). showlist(Xs) :- print(Xs). ,它使列表中的值加倍,谓词double/2在标准输出上打印列表。我们可以这样试试:

showlist/1

当您输入?- perm([1,2,3], X), double(X, Y), showlist(Y). [2,4,6] X = [1, 2, 3], Y = [2, 4, 6] ; [4,2,6] X = [2, 1, 3], Y = [4, 2, 6] ; [4,6,2] X = [2, 3, 1], Y = [4, 6, 2] ; [2,6,4] X = [1, 3, 2], Y = [2, 6, 4] ; [6,2,4] X = [3, 1, 2], Y = [6, 2, 4] ; [6,4,2] X = [3, 2, 1], Y = [6, 4, 2] ; false. 时,您说“或”?到Prolog。换句话说,你说“还有什么?”你告诉Prolog,实际上,这不是我想要的答案,试着找到另一个我更喜欢的答案。您可以使用故障驱动的循环来形式化此过程:

;

所以现在你看到每个排列的输出都经过?- perm([1,2,3], X), double(X, Y), showlist(Y), fail. [2,4,6][4,2,6][4,6,2][2,6,4][6,2,4][6,4,2] false. ,然后Prolog报告错误。这就是这样的意思:

double/2

看看它是如何工作的:

show_all_heaps(List) :- perm(List, X), double(X, Y), showlist(Y), nl, fail.
show_all_heaps(_).

另一种选择是使用?- show_all_heaps([1,2,3]). [2,4,6] [4,2,6] [4,6,2] [2,6,4] [6,2,4] [6,4,2] true. ,看起来更像是这样:

findall/3

使用它来解决你的问题可能超出了你正在做的任何家庭作业的范围。

答案 1 :(得分:2)

我们可以根据same_length/2select/3定义list_permutation/2,如下所示:

:- use_module(library(lists),[same_length/2,select/3]).

list_permutation(As,Bs) :-
   same_length(As,Bs),          % redundant goal helps termination
   list_permutation_(As,Bs).

list_permutation_([],[]).
list_permutation_([A|As],Bs0) :-
    select(A,Bs0,Bs),
    list_permutation_(As,Bs).

感谢same_length/2,以下两个查询 1,2 普遍终止:

?- list_permutation([1,2,3],Ys).
  Ys = [1,2,3]
; Ys = [1,3,2]
; Ys = [2,1,3]
; Ys = [3,1,2]
; Ys = [2,3,1]
; Ys = [3,2,1]
; false.

?- list_permutation(Xs,[1,2,3]).
  Xs = [1,2,3]
; Xs = [1,3,2]
; Xs = [2,1,3]
; Xs = [2,3,1]
; Xs = [3,1,2]
; Xs = [3,2,1]
; false.

到目前为止,这么好。但是,如果有重复的列表项,答案序列会是什么样的?

?- list_permutation([1,1,1],Ys).
  Ys = [1,1,1]
; Ys = [1,1,1]
; Ys = [1,1,1]
; Ys = [1,1,1]
; Ys = [1,1,1]
; Ys = [1,1,1]
; false.

5/6的答案是多余的!我们能做什么?我们只是使用selectd/3 而不是select/3

list_permuted(As,Bs) :-
   same_length(As,Bs),
   list_permuted_(As,Bs).

list_permuted_([],[]).
list_permuted_([A|As],Bs0) :-
   selectd(A,Bs0,Bs),           % use selectd/3, not select/3
   list_permuted_(As,Bs).

让我们重新运行以上为我们提供5个冗余解决方案的查询!

?- list_permuted([1,1,1],Ys).
  Ys = [1,1,1]
; false.

?- list_permuted(Xs,[1,1,1]).
  Xs = [1,1,1]
; false.

更好!所有多余的答案都消失了。

让我们比较一些示例案例的解决方案集:

?- _Xs = [1,2,1,1,2,1,1,2,1],
   setof(Ys,list_permutation(_Xs,Ys),Yss),
   setof(Ys,list_permuted(_Xs,Ys),Yss),
   length(Yss,N).
N = 84, Yss = [[1,1,1,1,1,1,2,2,2],[1,1,1,1,1,2,1,2,2],[...|...]|...].

OK!经验运行时测量与尺寸略大的问题怎么样?
我们使用call_time/2来测量运行时间,单位为毫秒T_ms

?- call_time(\+ (list_permutation([1,2,1,1,1,2,1,1,1,2,1],_),false),T_ms).
T_ms = 8110.

?- call_time(\+ (list_permuted(   [1,2,1,1,1,2,1,1,1,2,1],_),false),T_ms).
T_ms = 140.

OK!通过适当汇编if_/3(=)/3list_permuted/2甚至更快!

脚注1:使用SICStus Prolog版本4.3.2(x86_64-linux-glibc2.12)。
脚注2:为了便于阅读,Prolog toplevel给出的答案已经过后处理。 功能

答案 2 :(得分:1)

如果你只想探索最后没有“假”的排列,这段代码可能会有所帮助

takeout(X,[F |R],[F|S]) :- F\=X, takeout(X,R,S).
takeout(X,[X|R],R).
perm([X|Y],Z) :- perm(Y,W), takeout(X,Z,W).  
perm([],[]).

因此,烫发的输出([a,b],B)将是

B=[a,b]
B=[b,a]