the presentation of the problem should eliminate the ambiguity of the node names, so we can express the links accordingly

now we can write
can_connect(a,b,_). can_connect(a,c,1). can_connect(c,d,_). link(1,2). link(1,3). link(1,4). link(4,5). link(4,6). link(7,4). link(7,8). type(1,a). type(2,b). type(3,_). type(4,c). type(5,d). type(6,_). type(7,a). type(8,_).
The underlined (anonymous variable) in Prolog plays a role similar to NULL in SQL, it can take any value.
So, the first fragment
node_type(N, NT) :- type(N, NT), nonvar(NT), !. % assume a node has only one type
can be used to express what we know about a problem.
Can_connect / 3 facts can then be read as
a can connect to any number of b a can connect to just 1 c etc
Where we do not know the type of node, a complex rule is required that indicates the type of the source of the node to the type of the target node and takes into account the counting restriction, something like
node_type(N, NT) :- link(M, N), type(M, MT), can_connect(MT, NT, C), aggregate(count, Y^(link(M, Y), type(Y, NT)), C). ?- forall(between(1,8,N), (node_type(N,T),writeln(N:T))). 1:a 2:b 3:b 4:c 5:d 6:d 7:a 8:b true.
edit, if your Prolog does not have a library ( aggregate ) where the / 3 aggregate is loaded from, you can try
node_type(N, NT) :- link(M, N), type(M, MT), can_connect(MT, NT, C), findall(t, (link(M, Y), type(Y, NT)), Ts), length(Ts, C).
edit, first of all, the updated chart marked with known types:

my previous code only worked under very limited assumptions. Here's something more general that checks for limitations on the full schedule (as suggested by the @false comment), with the โgenerate and testโ approach.
node_type(N, NT) :- assoc_types(Typed), maplist(check_connections(Typed), Typed), memberchk(N:NT, Typed). assoc_types(Typed) :- findall(N, type(N, _), L), maplist(typed, L, Typed). typed(N, N:T) :- type(N, T), member(T, [a,b,c,d]). check_connections(Graph, N:NT) :- forall(link(N, M), ( memberchk(M:MT, Graph), can_connect(NT, MT, C), aggregate(count, X^(link(N, X), memberchk(X:MT, Graph)), C) )).
now ?- node_type(4,X). out of order ...