2
votes

given a set of assertions in prolog designed to be edges denoting the directed connections between nodes:

edge(n1, n2).
edge(n2, n3).
edge(n1, n4).

the following query gives an infinite concatenation of [n1, n2, n1, n2 ... ] ...

allnodes([]).
allnodes([X | [ Y | Xs]]) :-
    edge(X, Y),
    allnodes(Xs).

when asked as allnodes(Result)

What I'm looking for is the list [n1, n2, n3, n4] in some order.

2

2 Answers

3
votes

Let's try to understand the clauses you wrote. The first clause allnodes([]). basically reads "there are no nodes". This is obviously not true unless there are no edges defined at all.

The second clause can be interpreted along the lines of "all nodes consist of X and Y if there is an edge from X to Y, plus all nodes". See the recursion here? The list contains itself as tail! That's why you get the same nodes over and over again.

What you actually want is the set of all nodes which occur as either start or end node for an edge.

To make it easier for ourselves, let's first translate to prolog what it means for something to be a node:

node(N) :- edge(N, _).
node(N) :- edge(_, N).

Simple as that. Something is a node if some edge starts there, or some edge ends there.

Now all we have to do is find everything that satisfies above predicate.

allnodes(Nodes) :- setof(N, node(N), Nodes).

Note that I use setof/3 rather than findall/3 to remove duplicates, as above definition of node/2 will succeed once for each occurrence of a node in an edge, e.g. it will succeed twice for n1 and n2.

This gives the result you're looking for:

?- allnodes(N).
N = [n1, n2, n3, n4]
0
votes

Consider using an existing library, for example library(ugraphs). It is very well documented, but to get you started, here is how you can make a graph from the list of edges and then show all the vertices:

?- bagof(A-B, edge(A, B), Edges),
   vertices_edges_to_ugraph([], Edges, G),
   vertices(G, Vertices).
Edges = [n1-n2, n1-n4, n2-n3],
G = [n1-[n2, n4], n2-[n3], n3-[], n4-[]],
Vertices = [n1, n2, n3, n4].

This also uses bagof/3 to build a list of From-To pairs. The other two predicates are from the library. This example is with SWI-Prolog, but the library itself should work with any half-decent Prolog implementation, and the code is on Github.

Just getting the vertices is of course trivial but for anything more complicated a library is always better.