在 Prolog 中,可以按随机顺序选择解决方案吗?

5 prolog

如果我有以下几点:

a(X) :- X = 1; X = 2; X = 3; X = 4.
Run Code Online (Sandbox Code Playgroud)

我可以按确定性顺序生成解决方案:

?- a(X).
X = 1 ;
X = 2 ;
X = 3 ;
X = 4.
Run Code Online (Sandbox Code Playgroud)

是否有任何方法可以要求系统以非确定性随机顺序生成解决方案?例如:

?- a(X).
X = 4 ;
X = 1 ;
X = 3 ;
X = 2.
Run Code Online (Sandbox Code Playgroud)

我知道我可以找到所有解决方案,然后随机选择一个 ( 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)
Run Code Online (Sandbox Code Playgroud)

当确定,生成该解决方案X = d, Y = c, Z = d采用?- p(X,Y,Z).总会经过47级以前的解决方案(4 * 3 * 4 = 48)。但是,如果以非确定性顺序选择析取,系统可能会X = d在 D1、Y = cD2、Z = dD3处选择,将其生成为第一个解决方案。

这被用于受约束的 AI 生成的内容,因此在现实世界的用例中有更多的变量。

mat*_*mat 1

从您在评论中所说的来看,我的印象是您的用例的一个更重要的问题是:

可以按随机顺序创建解决方案吗?

(这是因为你说你不能全部创建,然后随机选择一个。)

为了以不同的顺序创建它们,鲍里斯暗示了一个好方法:只需重新排序析取即可!

例如,在您显示的情况下:

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) :-
    成员(X,[a,b,c,d]),
    成员(Y,[a,b,c]),
    成员(Z,[a,b,c,d])。

这样,可以更轻松地打乱列表并使用随机列表来生成解决方案。

例如,您可以将其更改为:

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) :-
    随机排列(Ls0,Ls),
    成员(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。

请注意,这种将随机性合并到代码中的方法是不纯粹的:您的程序中现在存在隐式全局状态,并且您无法再轻松地重现在描述此类程序的测试用例等时所需的结果。解决方案必须使该状态明确,例如通过携带随机 种子作为参数之一,以便每次运行都是完全可重现的。

请注意,像这样的重新排序连词和/或目标仅适用于Prolog 的单调子集,因此请确保使用声明性功能(如 约束)来安全地交换目标,并增加代码的通用性!

  • random_permutation/2 和 member/2 的结合确实是解决我的问题的方法。我了解如何使我的程序适应这种风格。谢谢你! (2认同)