Prolog - 检测有向图中连接节点的谓词

Prolog - Predicate To Detect Connected Nodes In a Directed Graph

我正在查看 this 问题,其中我们在 Prolog 中创建一个谓词,它在有向图中找到两个节点 ("metro stations") 之间的路径。原代码建议如下

path(Start, Dest, [[Start,Dest]]) :- connected(Start, Dest).
path(Start, Dest, [[Start, Waypoint]|Path]) :- dif(Dest, Waypoint), 
    connected(Start, Waypoint), path(Waypoint, Dest, Path).

但是,为了处理循环并消除包含它们的列表,我尝试沿着递归存储我已经停止的站点,并检查我没有重复它们中的任何一个。这是我想出的代码(请注意,我没有列出列表,而是列出了电台本身)

alldifferent(_,[]).
alldifferent(X,[L|Ls]) :- dif(X,L), alldifferent(X,Ls).

pathaux(Start, Dest, [Start,Dest],Q) :- connected(Start, Dest), alldifferent(Start,Q).
pathaux(Start, Dest, [Start, Waypoint|Path],Q) :- dif(Dest, Waypoint),
    connected(Start, Waypoint), 
    pathaux(Waypoint, Dest, Path, [Start|Q]), alldifferent(Start,Q).

path(X,Y,Z) :- pathaux(X,Y,Z,[]).

但是,当我添加创建循环的规则时

connected(ataba,naguib).
connected(naguib,sadat).
connected(sadat,opera).
connected(opera,dokki).
connected(opera,ataba). //Note this one

我得到了一个无限递归!怎么会?以及如何解决这个问题?

how come?

首先考虑一下你原程序non-termination的原因:


<s>path(Start, Dest, [[Start,Dest]]) :- <b>false</b>, connected(Start, Dest)</s>.
path(Start, Dest, [[Start, Waypoint]|Path]) :-
   dif(Dest, Waypoint), 
   connected(Start, Waypoint),
   path(Waypoint, Dest, Path), <b>false</b>.

仅此片段就负责 non-termination。如果这没有终止,您的原始程序也会终止。

现在,转到您的其他程序。顺便说一句,您对 alldifferent/2 的定义通常写为 maplist(dif(X), Xs).


<s>pathaux(Start, Dest, [Start,Dest],Q) :- <b>false</b>, connected(Start, Dest), alldifferent(Start,Q)</s>.
pathaux(Start, Dest, [Start, Waypoint|Path],Q) :-
   dif(Dest, Waypoint),
   connected(Start, Waypoint), 
   pathaux(Waypoint, Dest, Path, [Start|Q]), <b>false</b>,
   <s>alldifferent(Start,Q)</s>.

path(X,Y,Z) :- pathaux(X,Y,Z,[]).

你发现不同了吗?列表有点不同,还有一个辅助参数,但是片段中,没有人使用这个参数。所以大致相同。因此:

这个新定义与您原来的程序一样糟糕(或更糟)!

最通用的解决方案是 here. See 有关此技术的更多信息,以定位 non-termination 的实际原因。