我在Prolog中有几个动态的事实,我想对它们进行洗牌(以随机顺序重新排序)。 Prolog中有什么方法可以做到这一点吗?
:- dynamic max/3.
max(1,2,3).
max(1,5,6).
max(3,4,5).
max(2,2,5).
可能的随机顺序:
max(2,2,5).
max(1,2,3).
max(3,4,5).
max(1,5,6).
答案 0 :(得分:1)
正如您提到的那样,您正在使用SWI-Prolog,一种可能的解决方案是使用其nth_clause/3
和clause/3
内置谓词。这个想法是使用代理谓词ramdom_max/3
访问谓词。我还假设您只有事实。
:- use_module(library(lists)).
:- use_module(library(random)).
ramdom_max(A, B, C) :-
predicate_property(max(_,_,_), number_of_clauses(N)),
numlist(1, N, List),
random_permutation(List, Permutation),
member(Index, Permutation),
nth_clause(max(_,_,_), Index, Ref),
clause(max(A,B,C), _, Ref).
通话示例:
?- ramdom_max(A, B, C).
A = 1,
B = 2,
C = 3 ;
A = 3,
B = 4,
C = 5 ;
A = 1,
B = 5,
C = 6 ;
A = B, B = 2,
C = 5.
每次调用ramdom_max/3
谓词都会为您提供不同的子句随机顺序,但仍会枚举回溯中的所有子句。
但是,这是一个计算上相对昂贵的解决方案。但是由于max/3
是一个动态谓词,ramdom_max /3
子句主体中的第一个目标无法优化为仅运行一次。让我们检查一下推理次数:
% autoload the time/1 library predicate:
?- time(true).
% 3 inferences, 0.000 CPU in 0.000 seconds (60% CPU, 333333 Lips)
true.
?- time(ramdom_max(A, B, C)).
% 42 inferences, 0.000 CPU in 0.000 seconds (85% CPU, 913043 Lips)
A = 3,
B = 4,
C = 5 ;
% 6 inferences, 0.000 CPU in 0.000 seconds (69% CPU, 272727 Lips)
A = 1,
B = 2,
C = 3 ;
% 4 inferences, 0.000 CPU in 0.000 seconds (69% CPU, 222222 Lips)
A = 1,
B = 5,
C = 6 ;
% 6 inferences, 0.000 CPU in 0.000 seconds (70% CPU, 250000 Lips)
A = B, B = 2,
C = 5.
在使用findall/3
进行评论重新注释时,有必要与luker的建议进行比较。可能的实现方式是:
ramdom_max(A, B, C) :-
findall(max(A,B,C), max(A,B,C), Clauses),
random_permutation(Clauses, Permutation),
member(max(A,B,C), Permutation).
定时通话:
?- time(ramdom_max(A, B, C)).
% 40 inferences, 0.000 CPU in 0.000 seconds (78% CPU, 930233 Lips)
A = 1,
B = 5,
C = 6 ;
% 2 inferences, 0.000 CPU in 0.000 seconds (50% CPU, 200000 Lips)
A = 1,
B = 2,
C = 3 ;
% 2 inferences, 0.000 CPU in 0.000 seconds (45% CPU, 250000 Lips)
A = B, B = 2,
C = 5 ;
% 4 inferences, 0.000 CPU in 0.000 seconds (62% CPU, 250000 Lips)
A = 3,
B = 4,
C = 5.
在此非常有限测试中,性能大致相同。但这也是一个更简单,更可移植的解决方案。但是,对要解决的问题有更多了解可能会找到更好的解决方案。