CLP(FD)的相互排他性

时间:2017-11-21 13:16:28

标签: prolog clpfd

我正在使用EXPOSE 3000 编写Prolog程序,并且难以实现我期望的约束之一。

输出是一个整数列表(长度取决于程序另一部分的输入),其中有一对互斥的预定义数字对,每对中的一个数字必须< / strong>在输出中。

一个例子:

输出是一个整数列表,每个整数在1到10之间。输出必须包含3或4,但不能同时包含两者。

到目前为止,我有以下内容,它限制了它,以便3和4不能同时在输出中,但是它不能确保输出中的其中一个

clp(fd)

编辑:
所以跑步:

mutual2([A], ME1):-
    (A in 3 #==> ME1) #/\ (#\ A in 4 #<== ME1).
mutual2([A, B| Tail], ME1):-
    (A in 3 #==> ME1) #/\ (#\ A in 4 #<== ME1),
    (B in 3 #==> ME1) #/\ (#\ B in 4 #<== ME1),
    mutual2([B|Tail], ME1).

给出:

[A,B] ins 2..6, A #< B, mutual2([1,2,B,A,5],M), label([A,B]).

但我不希望A = 2, B = 3, M = 1 ; A = 2, B = 4, M = 0 ; A = 2, B = 5, M in 0..1 ; A = 3, B = 5, M = 1 ; A = 4, B = 5, M = 0 ; 成为有效输出,因为A=2, B=5, M in 0..1A都不是3或4。

1 个答案:

答案 0 :(得分:3)

我可能会使用CLP(FD)和DCG的组合,因为我们正在处理序列。

这是一种识别包含正好一个3或一个4的序列的实现:

:- use_module(library(clpfd)).

one_of_3_4 --> no_3_4, [3], no_3_4.
one_of_3_4 --> no_3_4, [4], no_3_4.

no_3_4 --> [].
no_3_4 --> [X], { X in 1..2 \/ 5..9 }.

这产生了这样的结果:

2 ?- phrase(one_of_3_4, L), label(L).
L = [3] ;
L = [3, 1] ;
L = [3, 2] ;
L = [3, 5] ;
L = [3, 6] ;
L = [3, 7] ;
L = [3, 8] ;
L = [3, 9] ;
L = [1, 3] ;
L = [2, 3] ;
L = [5, 3] ;
L = [6, 3] ;
L = [7, 3] ;
L = [8, 3] ;
L = [9, 3] ;
...

这不是原始问题的完整解决方案,但应该提供如何以透明方式处理它的想法。

<小时/> 如果您不想使用DCG,这里有另一种方法,首先指定3或4以外的单个数字列表,然后在列表中的任意位置插入3或4(SWI Prolog):

:- use_module(library(clpfd)).

one_of_3_4(L) :-
    length(L1, _),
    L1 ins 1..2 \/ 5..9,
    ( select(3, L, L1)
    ; select(4, L, L1)
    ).

然后可以按如下方式调用:

2 ?- one_of_34(L), label(L).
L = [3] ;
L = [4] ;
L = [3, 1] ;
L = [3, 2] ;
L = [3, 5] ;
L = [3, 6] ;
L = [3, 7] ;
L = [3, 8] ;
L = [3, 9] ;
L = [1, 3] ;
L = [2, 3] ;
L = [5, 3] ;
L = [6, 3] ;
L = [7, 3] ;
L = [8, 3] ;
L = [9, 3] ;
L = [4, 1] ;
L = [4, 2] ;
L = [4, 5] ;
L = [4, 6] ;
L = [4, 7] ;
L = [4, 8] ;
L = [4, 9] ;
L = [1, 4] ;
L = [2, 4] ;
L = [5, 4] ;
L = [6, 4] ;
L = [7, 4] ;
L = [8, 4] ;
L = [9, 4] ;
...

<小时/> 在回答对此答案的评论时,您可以创建一个专门应用于CLP(FD)场景的非成员谓词:

not_member(_, []).
not_member(X, [Y|T]) :- X #\= Y, not_member(X, T).

或者简而言之,您可以使用not_member/2maplist/2缩写为:

not_member(X, L) :- maplist(#\=(X), L).

使用not_member/2,这可以按预期工作:

mutual(Output, A, B):-
    member(A, Output), not_member(B, Output).
mutual(Output, A, B) :-
    member(B, Output), not_member(A, Output).

查询会产生所有结果:

?- [A,B] ins 2..5, A #< B, mutual([A,B,5],3,4), label([A,B]).
A = 3,
B = 5 ;
A = 2,
B = 3 ;
A = 4,
B = 5 ;
A = 2,
B = 4 ;
false.