Reputation: 4730
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).
Upvotes: 1
Views: 150
Reputation: 22803
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]))).
Upvotes: 1