Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/blackberry/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Prolog 图中的圈检测_Prolog_Directed Graph - Fatal编程技术网

Prolog 图中的圈检测

Prolog 图中的圈检测,prolog,directed-graph,Prolog,Directed Graph,我们得到了一个包含以下事实的图表: edge(a,b) edge(a,c) edge(b,a) edge(c,d) edge(d,d) edge(d,e) edge(e,f) edge(f,g) edge(g,e) 我们需要定义一个规则,cycle(X),它确定是否有一个从节点X开始的循环 我真的不知道该怎么做,我试着遍历节点并检查下一个节点是否会再次启动,但我似乎无法让它工作我已经有一段时间没有使用Prolog了,但这种方法可能会起作用:路径是一系列边,其中每条边从上一条边结束的节点开始(例

我们得到了一个包含以下事实的图表:

edge(a,b)
edge(a,c)
edge(b,a)
edge(c,d)
edge(d,d)
edge(d,e)
edge(e,f)
edge(f,g)
edge(g,e)
我们需要定义一个规则,
cycle(X)
,它确定是否有一个从节点
X
开始的循环


我真的不知道该怎么做,我试着遍历节点并检查下一个节点是否会再次启动,但我似乎无法让它工作

我已经有一段时间没有使用Prolog了,但这种方法可能会起作用:路径是一系列边,其中每条边从上一条边结束的节点开始(例如A->b,b->c,c->d)。普通路径是一条边,通过获取现有路径并向其添加边,可以形成更复杂的路径。循环是在同一节点上开始和结束的路径。您可以使用这些定义来构建Prolog规则吗?

我已经有一段时间没有使用Prolog了,但下面是我解决这个问题的方法

您可以创建规则
path(X,Y)
,检查是否存在从节点
X
Y
的路径。路径是单条边或通向路径的边。有了这个,很容易找到从节点
X
开始的循环——它将是路径(X,X)。以下是我的实现(摘自我的头顶,不一定正确,但给出了想法):


阿尔奇的想法是一个很好的起点,但如果它在搜索路径时发现另一个循环,它将创建一个无限循环


我也已经多年没有使用prolog了,但是您需要类似于
路径(X,Y,visted)
的东西,在这里您可以跟踪访问的节点,防止无休止的循环。

我使用深度优先搜索访问的节点列表,如果我们在遍历过程中遇到任何访问的节点,它将返回true。我用小输入进行了测试,它看起来工作正常

cycle(X):- cycleh(X,[X]).
cycleh(X,Visited) :- edge(X,Y), (member(Y,Visited) -> !,true; cycleh(Y,[Y|Visited])).

这应该可以做到:

cycle( X ) :-
  cycle( X , [] ).

cycle( Curr , Visited ) :-
  member( Curr, Visited ) ,
  !. 
cycle( Curr , Visited ) :-
  edge( Curr , Next ) ,
  cycle( Next , [Curr|Visited] ) .
虽然这似乎是一个类似于@Gökhan Uras的解决方案——但伟大的思想都是一样的!或者什么的(B)

基本逻辑是,如果当前节点已经被访问过,就有一个循环(在
cycle/2
helper谓词中的第一个子句)。在这一点上,我们切割(!)并声明成功切割(!)的原因是,如果没有它,回溯将导致重新访问已经访问过的节点,从而产生无限的循环集


如果当前节点未被访问,我们将获取锚定在当前节点上的一条边并访问该边。回溯到
cycle/2
的第2个子句将访问下一条边,因此,一旦某个特定路径耗尽,
cycle/2
将回溯并尝试另一条路径。

如果您的Prolog系统具有前向链接器,您可以使用它但要注意,它可能会消耗大量内存,因为它将生成并保留
路径/2
事实

以下是如何在转发链器中制定规则,该转发链器不会自动消除重复项。
\+
用于明确消除重复项:

:- forward edge/2.
:- forward path/2.

path(X,Y) :- edge(X,Y), \+ path(X,Y).
path(X,Y) :- edge(X,Z), path(Z,Y), \+ path(X,Y).
cycle(X) :- path(X,X).
为了让这个例子更有趣一点,我删除了
边(d,d)

?- postulate(edge(a,b)), postulate(edge(a,c)), postulate(edge(b,a)),    
postulate(edge(c,d)), postulate(edge(d,e)), postulate(edge(e,f)), 
postulate(edge(f,g)), postulate(edge(g,e)), cycle(X).
X = a ;
X = b ;
X = e ;
X = f ;
X = g
此处的
postate/1
谓词发布一个事件,并保持转发链接器的传播程序运行。如何编写转发规则取决于您使用的Prolog系统各自的库

附言:还有一些研究正在进行:

获取edge(a,b)、edge(b,c)、edge(c,b)和查询?-cycle(X)。深度优先Prolog将运行到一个无限循环中,并且找不到该循环。
?- postulate(edge(a,b)), postulate(edge(a,c)), postulate(edge(b,a)),    
postulate(edge(c,d)), postulate(edge(d,e)), postulate(edge(e,f)), 
postulate(edge(f,g)), postulate(edge(g,e)), cycle(X).
X = a ;
X = b ;
X = e ;
X = f ;
X = g