我正在尝试在Prolog中实现一些图算法。我想到了使用统一来从图结构构建树的想法:
图可以定义如下:
一个
Vertex-Variable
对列表,其中Vertex
是表示顶点的常量,Variable
是相应的变量,将用作对该顶点的“引用”。 例如:[a-A, b-B, c-C, d-D]
一个
VertexVar-NeighboursList
对列表,其中VertexVar
和NeighboursList
中的各个邻居都是“引用变量”。 例如:[A-[B,C,D],B-[A,C],C-[A,B],D-[A]]
表示b
,c
,d
是a
的邻居等。
然后,在执行某些图算法(例如搜索组件或简单DFS / BFS等)之前,可以使用诸如unify_neighbours
之类的谓词将VertexVar-NeighbourList
对统一为VertexVar = NeighboursList
。完成后,可以将顶点变量解释为其邻居的列表,每个邻居再次是其邻居的列表。
因此,当遍历图时,这将导致良好的性能,因为不需要在图中的每个顶点上进行线性搜索以查找某个顶点及其邻居。
但我的问题是:如何比较这些顶点变量? (检查它们是否相同。)我尝试使用A == B
,但存在一些冲突。 对于上面的示例(具有unify_neighbours
谓词),Prolog 在内部将图解释为:
[a-[S_1, S_2, S_3], b-S_1, c-S_2, d-S_3]
其中:
S_1 = [[S_1, S_2, S_3], S_2]
S_2 = [[S_1, S_2, S_3], S_1]
S_3 = [[S_1, S_2, S_3]]
这个问题与
S_1
和S_2
(也称为b
和cX = [something, Y],Y = [something,X],X == Y
为true
。相同的问题也会出现在共享相同邻居的顶点上。例如:U-[A,B]
和V-[A,B]
。
我的问题是:是否有其他比较变量的方法,可以帮助我解决这个问题?类似于比较面向过程编程语言中的地址,而不是内容本身。或者这样做太过程化了,会破坏Prolog声明式的思想吗?
例子
graph_component(Vertices, Neighbours, C) :-
% Vertices and Neighbours as explained above.
% C is some component found in the graph.
vertices_refs(Vertices, Refs),
% Refs are only the variables from the pairs.
unify_neighbours(Neighbours), % As explained above.
rec_(Vertices, Refs, [], C).
rec_(Vertices, Refs, Found, RFound) :-
% Vertices as before.
% Refs is a stack of the vertex variables to search.
% Found are the vertices found so far.
% RFound is the resulting component found.
[Ref|RRest] = Refs,
vertices_pair(Vertices, Vertex-Ref),
% Vertex is the corresponding Vertex for the Ref variable
not(member(Vertex, Found)),
% Go deep:
rec_(Vertices, Ref, [Vertex|Found], DFound),
list_revpush_result([Vertex|Found], DFound, Found1),
% Go wide:
rec_(Vertices, RRest, Found1, RFound).
rec_(Vertices, Refs, Found, []) :-
% End of reccursion.
[Ref|_] = Refs,
vertices_pair(Vertices, Vertex-Ref),
member(Vertex, Found).
这个例子并不能真正地工作,但是它提供了一个思路。(同时,检查顶点是否被发现是线性完成的,因此性能仍然不好,但只是用于演示。)现在为变量寻找相应顶点的谓词被实现为:
vertices_pair([Vertex-Ref|_], Vertex-Ref).
vertices_pair([_-OtherRef|Rest], Vertex-Ref) :-
Ref \== OtherRef,
vertices_pair(Rest, Vertex-Ref).
在这里,\==
操作符并不是我想要的,它会创建一些冲突。