如果我有以下内容:
a(X) :- X = 1; X = 2; X = 3; X = 4.
我可以按确定的顺序生成解决方案:
?- a(X).
X = 1 ;
X = 2 ;
X = 3 ;
X = 4.
是否有任何方法要求系统以非确定性,随机顺序生成解决方案?例如:
?- a(X).
X = 4 ;
X = 1 ;
X = 3 ;
X = 2.
我知道我可以找到所有解决方案然后随机选择一个(findall(X, a(X), Y), random_member(Z, Y).
),但在我的情况下这太贵了。
可能更清楚的例子:
p(X,Y,Z) :-
(X = a; X = b; X = c; X = d), % (D1)
(Y = a; Y = b; Y = c), % (D2)
(Z = a; Z = b; Z = c; Z = d). % (D3)
确定性时,使用X = d, Y = c, Z = d
生成解决方案?- p(X,Y,Z).
将始终通过之前的47个解决方案(4 * 3 * 4 = 48
)。但是,如果以非确定性顺序选择析取,系统可能会选择D1处的X = d
,D2处的Y = c
,D3处的Z = d
,将其生成为第一个解决方案。
这用于受约束的AI生成的内容,因此在现实世界的用例中还有更多的变量。
答案 0 :(得分:0)
根据您在评论中的说法,我的印象是,对您的用例更重要的问题是:
可以随机顺序创建解决方案吗?
(这是因为你说你不能全部创建它们,然后选择一个随机的。)
要以不同的顺序创建它们,Boris已经暗示了一个好方法:只需重新排序析取!
例如,在您显示的情况下:
p(X, Y, Z) :- (X = a; X = b; X = c; X = d), % (D1) (Y = a; Y = b; Y = c), % (D2) (Z = a; Z = b; Z = c; Z = d). % (D3)
如果分离(例如:(X = c ; X = b ; etc.)
和每个片段可能以不同的顺序产生解决方案),您可以(自动)通过交换订单来创建此片段的声明等效版本。
但是,首次将其重写为等效版本可能更容易:
p(X, Y, Z) :- member(X, [a,b,c,d]), member(Y, [a,b,c]), member(Z, [a,b,c,d]).
通过这种方式, shuffle 列表更容易,并使用随机列表生成解决方案。
例如,您可以将其更改为:
p(X, Y, Z) :- random_member(X, [a,b,c,d]), random_member(Y, [a,b,c]), random_member(Z, [a,b,c,d]). random_member(X, Ls0) :- random_permutation(Ls0, Ls), member(X, Ls).
现在,您将得到如下答案:
?- p(X, Y, Z). X = d, Y = Z, Z = b ; X = Z, Z = d, Y = b ; X = d, Y = b, Z = c ; etc.
请注意,这种将随机性合并到代码中的方法是不纯:程序中现在存在隐式全局状态,并且在描述测试用例等时无法再轻松地再现所需的结果。对于这样的程序。保留 logical-purity 的解决方案必须使此状态显式,例如将随机种子作为参数之一,每次运行都是完全可重现的。
请注意,重新排序此类连词和/或目标仅适用于Prolog的纯和单调子集,因此请确保使用等声明性功能约束以安全地交换目标,并增加代码的通用性!