Question

I have the following knowledge base representing a directed graph:

edge(1, 2).
edge(2, 3).
edge(2, 4).
edge(3, 3).
edge(3, 4).
edge(3, 5).
edge(4, 3).

I want to print difference between number of incoming and outgoing edges for each node. Here is what I have so far:

outgoing(E) :- edge(E, _).
ingoing(E) :- edge(_, E).

count_outgoing(E, Count) :- findall(E, outgoing(E), Bag), length(Bag, Count).
count_ingoing(E, Count) :- findall(E, ingoing(E), Bag), length(Bag, Count).

count(E, D) :- count_outgoing(E, OC), count_ingoing(E, IC), D is IC - OC.

count :- edge(E, _), count(E, D), write(E), write(' '), write(D), nl, fail; true.

However, this solution repeats nodes that have more than one outgoing edge. How can I fix it? (Let's skip the fact that if a node doesn't have any outgoing edges, it won't get printed for now).

Was it helpful?

Solution

The problem is that count_outgoing/2 and count_incoming/2 are implicitly finding your nodes. If you did it explicitly, you'd have the control you need. The simplest thing to do is get a set of nodes and iterate that. Like this:

node(N) :- edge(N, _) ; edge(_, N).
all_nodes(Nodes) :- setof(N, node(N), Nodes).

Your main could then use member/2 to generate the nodes:

count :- 
  all_nodes(Nodes), 
  forall(member(N, Nodes), 
    (count(N, D), 
     format('node ~a has a difference of ~a~n', [N, D]))).
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top