Prolog - 从邻接矩阵中提取边
Prolog - extract edges from an adjacency matrix
我有一个表示图形邻接矩阵的列表列表。
我正在寻找一种从中提取图形边缘的方法:
?- getEdges([[0,1,0,0],[1,0,1,1],[0,1,0,0],[0,1,0,0]],Edges).
Edges = [[1,2],[2,4],[2,3]]
感谢
解决方案(假设有向图)类似于以下内容:
假设您正在检查邻接矩阵并且您位于特定行。您需要一个谓词来检查该行的邻接列表并过滤掉所有 0
元素,从而生成一个包含以下形式的元素的列表:
(From, To)
其中 From
对应行索引,To
对应非零列。
执行此操作的一个简单谓词称为 like
?- rowEdges(Row, AdjList, Result).
所以你可以尝试这样做:
rowEdges(Row, AdjList, Result) :- edges(AdjList, 1, Row, [], Result).
edges([H|T], Column, Row, Acc, Res) :-
NewColumn is Column + 1,
( H =:= 1 -> edges(T, NewColumn, Row, [(Row, Column)|Acc], Res);
edges(T, NewColumn, Row, Acc, Res)).
edges([], _, _, Res, Res).
谓词edges/5
检查行邻接表的每个元素,同时跟踪元素的列索引。如果应该添加一条边,它将采用 (Row, Column)
的形式,这就是我们必须提供 Row
作为参数的原因。
rowEdges/3
只是提供正确的初始化,对于累加器(Acc
)应该是一个空列表,对于列索引应该是 1
。
现在您可以将 rowEdges/3
应用于每一行,您必须通过类似的过程找到所有边。
示例:
?- rowEdges(2, [1,0,1,1,0,1], Result).
Result = [(2, 6), (2, 4), (2, 3), (2, 1)].
如果您希望边缘按列升序生成,您只需修改 rowEdges/3
以生成反向输出,因为 edges/5
使用累加器。
rowEdges(Row, AdjList, Result) :- edges(AdjList, 1, Row, Acc, Res), reverse(Res, Result).
另一种方法是,首先创建一个标识有效边的谓词。对于无向图,这是一个简单的谓词:
edge(M, [R,C]) :-
nth1(R, M, Row),
nth1(C, Row, 1),
R =< C. % Remove this for directed graphs
这是一个示例查询:
| ?- edge([[0,1,0,0],[1,0,1,1],[0,1,0,0],[0,1,0,0]],Edge).
Edge = [1,2] ? a
Edge = [2,3]
Edge = [2,4]
(1 ms) no
| ?-
它用每条回溯标识每条边。它使用 nth1/3
谓词,即关系 nth1(N, List, Element)
表示 Element
位于 N
in List
,其中第一个元素是元素编号 1
.
对于有向图,只需去掉R =< C
条件,即可得到:
| ?- edge([[0,1,0,0],[1,0,1,1],[0,1,0,0],[0,1,0,0]],Edge).
Edge = [1,2] ? a
Edge = [2,1]
Edge = [2,3]
Edge = [2,4]
Edge = [3,2]
Edge = [4,2]
(1 ms) no
| ?-
如果您想用另一种方式来表示边而不是 2 元素列表 [R,C]
,您只需将子句的头部从 edge(M, [R,C])
更改为例如 [=24] =]:
| ?- edge([[0,1,0,0],[1,0,1,1],[0,1,0,0],[0,1,0,0]],Edge).
Edge = 1-2 ? a
Edge = 2-3
Edge = 2-4
(1 ms) no
| ?-
如果你想将所有边收集到一个列表中,你可以使用setof/3
:
all_edges(M, Edges) :-
setof(E, edge(M, E), Edges).
| ?- all_edges([[0,1,0,0],[1,0,1,1],[0,1,0,0],[0,1,0,0]],E), Edges).
Edges = [1-2,2-3,2-4]
yes
| ?-
我有一个表示图形邻接矩阵的列表列表。
我正在寻找一种从中提取图形边缘的方法:
?- getEdges([[0,1,0,0],[1,0,1,1],[0,1,0,0],[0,1,0,0]],Edges).
Edges = [[1,2],[2,4],[2,3]]
感谢
解决方案(假设有向图)类似于以下内容:
假设您正在检查邻接矩阵并且您位于特定行。您需要一个谓词来检查该行的邻接列表并过滤掉所有 0
元素,从而生成一个包含以下形式的元素的列表:
(From, To)
其中 From
对应行索引,To
对应非零列。
执行此操作的一个简单谓词称为 like
?- rowEdges(Row, AdjList, Result).
所以你可以尝试这样做:
rowEdges(Row, AdjList, Result) :- edges(AdjList, 1, Row, [], Result).
edges([H|T], Column, Row, Acc, Res) :-
NewColumn is Column + 1,
( H =:= 1 -> edges(T, NewColumn, Row, [(Row, Column)|Acc], Res);
edges(T, NewColumn, Row, Acc, Res)).
edges([], _, _, Res, Res).
谓词edges/5
检查行邻接表的每个元素,同时跟踪元素的列索引。如果应该添加一条边,它将采用 (Row, Column)
的形式,这就是我们必须提供 Row
作为参数的原因。
rowEdges/3
只是提供正确的初始化,对于累加器(Acc
)应该是一个空列表,对于列索引应该是 1
。
现在您可以将 rowEdges/3
应用于每一行,您必须通过类似的过程找到所有边。
示例:
?- rowEdges(2, [1,0,1,1,0,1], Result).
Result = [(2, 6), (2, 4), (2, 3), (2, 1)].
如果您希望边缘按列升序生成,您只需修改 rowEdges/3
以生成反向输出,因为 edges/5
使用累加器。
rowEdges(Row, AdjList, Result) :- edges(AdjList, 1, Row, Acc, Res), reverse(Res, Result).
另一种方法是,首先创建一个标识有效边的谓词。对于无向图,这是一个简单的谓词:
edge(M, [R,C]) :-
nth1(R, M, Row),
nth1(C, Row, 1),
R =< C. % Remove this for directed graphs
这是一个示例查询:
| ?- edge([[0,1,0,0],[1,0,1,1],[0,1,0,0],[0,1,0,0]],Edge).
Edge = [1,2] ? a
Edge = [2,3]
Edge = [2,4]
(1 ms) no
| ?-
它用每条回溯标识每条边。它使用 nth1/3
谓词,即关系 nth1(N, List, Element)
表示 Element
位于 N
in List
,其中第一个元素是元素编号 1
.
对于有向图,只需去掉R =< C
条件,即可得到:
| ?- edge([[0,1,0,0],[1,0,1,1],[0,1,0,0],[0,1,0,0]],Edge).
Edge = [1,2] ? a
Edge = [2,1]
Edge = [2,3]
Edge = [2,4]
Edge = [3,2]
Edge = [4,2]
(1 ms) no
| ?-
如果您想用另一种方式来表示边而不是 2 元素列表 [R,C]
,您只需将子句的头部从 edge(M, [R,C])
更改为例如 [=24] =]:
| ?- edge([[0,1,0,0],[1,0,1,1],[0,1,0,0],[0,1,0,0]],Edge).
Edge = 1-2 ? a
Edge = 2-3
Edge = 2-4
(1 ms) no
| ?-
如果你想将所有边收集到一个列表中,你可以使用setof/3
:
all_edges(M, Edges) :-
setof(E, edge(M, E), Edges).
| ?- all_edges([[0,1,0,0],[1,0,1,1],[0,1,0,0],[0,1,0,0]],E), Edges).
Edges = [1-2,2-3,2-4]
yes
| ?-