Prolog 似乎无法返回查询的某些特定答案。我在 SWI-Prolog 中编写了一段简短的代码,其中我尝试检查给定的二进制向量 C 是否可以由 生成矩阵 G 生成。所有计算均以模 2 进行。当我为二元向量
codeword/2
调用主谓词 [0,1,1]
时,它返回 true
,这是查询的正确答案:
codeword([0,1,1],[[1,1,1],[1,0,0]]).
true.
但是,当我在查询中调用谓词时
codeword([X,Y,Z],[[1,1,1],[1,0,0]]),X+Y+Z =:= 2.
它返回
false
,这显然是一个错误的答案,因为我们确实知道[0,1,1]
实际上是一个代码字。换句话说,通过第一个查询,我们可以看到[0,1,1]
确实是一个码字;但第二个查询表明该代码不包含权重为2的码字,这是不正确的。
这是 Prolog 中的正常行为吗?我们可以认为它是一个错误吗?
这是我写的:
addbinvecs([A],[B],[C]) :-
(A = B -> C = 0; C = 1).
addbinvecs([H1|T1],[H2|T2],[H3|T3]) :-
(H1 = H2 -> H3 = 0; H3 = 1),
addbinvecs(T1,T2,T3).
%%%
allzero([0]).
allzero([H|T]):-
H = 0,
allzero(T).
%%%
codeword(X,[_|_]) :- allzero(X).
codeword(C,[C|_]).
codeword(C,[_|Gt]):-
codeword(C,Gt).
codeword(C,[Gh|Gt]):-
addbinvecs(C,Gh,C1),
codeword(C1,Gt).
在您的评论中加注星号:
我没有采用削减。
哦,是的,你做到了!您使用的 if-then-else 构造隐式地使用了剪切,从而对搜索空间进行了过多的修剪。但你自己怎么能看到呢?
首先,接受您的查询并删除额外的条件:
?- codeword([A,B,C],[[1,1,1],[1,0,0]]).
A = 0, B = 0, C = 0
; A = 1, B = 1, C = 1
; A = 0, B = 0, C = 0
; A = 1, B = 0, C = 0
; A = 1, B = 1, C = 1
; false, unexpected, incomplete.
因此,虽然这些答案都很好,但缺少进一步的答案。解决这个问题的一个简单方法是用它的纯版本替换这个 if-then-else 结构,称为
if_/3
:
:- use_module(library(reif)).
addbinvecs([A],[B],[C]) :-
if_(A = B, C = 0, C = 1).
% (A = B -> C = 0; C = 1).
addbinvecs([H1|T1],[H2|T2],[H3|T3]) :-
if_(H1 = H2, H3 = 0, H3 = 1),
% (H1 = H2 -> H3 = 0; H3 = 1),
addbinvecs(T1,T2,T3).
?- codeword([A,B,C],[[1,1,1],[1,0,0]]).
A = 0, B = 0, C = 0
; A = 1, B = 1, C = 1
; A = 0, B = 0, C = 0
; A = 1, B = 0, C = 0
; A = 1, B = 1, C = 1
; B = 1, C = 1, dif:dif(A,1) % new
; false.
(在SWI中,您需要安装库(reif),在Scryer或Trealla中它是预先安装的。)
现在包含您期望的解决方案,除了......它有点太笼统了。它不仅承认
A = 0, B = 1, C = 1
,而且还承认无数其他解决方案,例如
true
; false.
但是,这就是你一开始所描述的!要缩小范围,您必须声明所有变量都是二进制的。这对你来说应该不会太难。