1

我正在尝试创建一个谓词,它将生成对带有数字的复合术语的所有可能的评估,例如assign_distinct_values([A-B], E).应该产生 99 个结果。

但是,我在当前的工作中找不到不确定性:

assign_distinct_values(E, A) :-
       term_variables(E, V),
       assign_distinct_values(E, V, [0,1,2,3,4,5,6,7,8,9], A).

assign_distinct_values(E, [], [], E).
assign_distinct_values(E, [], _, E).
assign_distinct_values(E, V, N, A) :-
       select(Num, N, N2),
       select(Var, V, V2),
       Var is Num,
       assign_distinct_values(E, V2, N2, A).

这会生成一个对称的结果,其中包含以下重复项:

  • 1-0
  • 0-1
  • 0-1
  • 1-0
4

2 回答 2

2

L 是值列表,E、A 是输出变量

assign_distinct_values(E, A, L) :-
    member(E,L),
    delete(L,E,L1),
    member(A,L1).

使用 prolog 谓词相当快。member(X,L)检查 X 是否在 L 中,如果是,我们创建一个不包含 X 的新列表 L1delete(L,X,L1)并以相同的方式再次检查第二个成员。

另一个版本:

assign_distinct_values(E, A) :-
    L = [0,1,2,3,4,5,6,7,8,9],
    member(E,L),
    delete(L,E,L1),
    member(A,L1).

行得通吗?我的机器上没有安装 prolog。

问候

于 2013-06-13T17:13:55.080 回答
2

首先考虑使用更有意义的命名约定:我建议在表示列表的变量名称后附加一个“s”,并更系统地对它们进行编号(从 0 开始),并使用更具声明性和意义的谓词名称:

with_distinct_integers(E0, E) :-
       term_variables(E0, Vs),
       with_distinct_integers(E0, Vs, [0,1,2,3,4,5,6,7,8,9], E).

with_distinct_integers(E, [], [], E).
with_distinct_integers(E, [], _, E).
with_distinct_integers(E0, Vs0, Ns0, E) :-
       select(Num, Ns0, Ns),
       select(Var, Vs0, Vs),
       Var is Num,
       with_distinct_integers(E0, Vs, Ns, E).

专注于with_distinct_integers/4现在。您会看到第一个子句被第二个包含,因此您可以省略第一个子句而不会丢失解决方案。该变量Var仅用于将其与 统一Num,因此您可以立即使用单个变量:

with_distinct_integers(E, [], _, E).
with_distinct_integers(E0, Vs0, Ns0, E) :-
       select(Num, Ns0, Ns),
       select(Num, Vs0, Vs),
       with_distinct_integers(E0, Vs, Ns, E).

您仍然会发现使用此简化版本的意外重复解决方案,我将其作为一个简单的练习来找出导致此问题的原因:

?- with_distinct_integers(X-Y, [X,Y], [0,1], A).
..., A = 0-1 ;
..., A = 1-0 ;
..., A = 1-0 ;
..., A = 0-1 ;
false.

提示:只需对简化定义进行声明式推理即可。继续简化:当您已经拥有所需的一切(即它的变量)可用时,为什么还要绕过原始术语?考虑:

with_distinct_integers(E) :-
       term_variables(E, Vs),
       numlist(0, 9, Ns),
       with_distinct_integers(Vs, Ns).

with_distinct_integers([], _).
with_distinct_integers([V|Vs], Ns0) :-
       select(V, Ns0, Ns),
       with_distinct_integers(Vs, Ns).

示例查询,计算所有解决方案:

?- findall(., with_distinct_integers([X-Y]), Ls), length(Ls, L).
Ls = ['.', '.', '.', '.', '.', '.', '.', '.', '.'|...],
L = 90.

旁边的惊喜:只有 90 个解决方案,而不是 99 个。

还可以考虑使用有限域约束,它们是整数上的关系,可以让您轻松制定此类任务:

:- use_module(library(clpfd)).

with_distinct_integers(E) :-
        term_variables(E, Vs),
        Vs ins 0..9,
        all_different(Vs),
        label(Vs).

示例查询:

?- with_distinct_integers(X-Y).
X = 0,
Y = 1 ;
X = 0,
Y = 2 ;
X = 0,
Y = 3 .
于 2013-06-13T17:44:45.737 回答