listprologgraph-theoryswi-prologadjacency-list

Graph representations in Prolog


Consider the following graph

enter image description here

and that it is described by the below Prolog term :

graph([connected(a,[b,c]), connected(b,[a,c]), connected(c,[a,b,d]), connected(d,[c]) ]).

I would like to define a predicate which transforms the above connections into a list of the corresponding pairs. In other words, a predicate which yields [[a,b],[a,c],[b,c],[c,d]] for the above term-graph.

Could you please advise how to do it ?

My attempt so far is the following :

map 2-neighbor vertex to pairs :

map2ne(adjacent(H,[K|T]),Pair) :-
    append([H],[K],L),
    append([H],T,M),
    append([L],[M],Pair).

This runs ok.

map 3-neighbor vertex to pairs :

map3n(adjacent(H,[K,L|T]),Pair) :-
    append([H],[K],A1),
    append([H],[L],A2),
    append([A1],[A2],Z),
    append([H],T,M),
    append(Z,[M],Pair).

This also runs ok.

But when I try to extend it to n-neighbor vertex, then it fails :

mapmany(adjacent(H, [K|_]),Pair) :-
    append([H],[K],L),
    append(L,[],Pair),
    mapmany(adjacent(H,[K|_]),M),
    append(M,Pair,Pair).

And also the below fails, which was intented to map many n-neighbor vertices to pairs :

mapping(Map,Pairs) :-
    select(X,Map,Y),
    mapmany(X,PairX),
    append([PairX],Pairs),
    mapping(Y,Pairs).

Solution

  • There are too many flaws in your code:

    To to create an edge, you can do the following:

    edge(V, W, Edge) :-
        (   V @< W
        ->  Edge = V-W
        ;   Edge = W-V ).
    

    Examples:

    ?- edge(a, b, Edge).
    Edge = a-b.
    
    ?- edge(b, a, Edge).
    Edge = a-b.
    

    To create all edges connecting a vertex V to its neighbors Ns, without duplicates, just ask:

    ?- V=a, Ns=[b,c,d], setof(E, W^Ns^(member(W,Ns), edge(V,W,E)), Edges).
    V = a,
    Ns = [b, c, d],
    Edges = [a-b, a-c, a-d].
    

    Notice that the construct Var^Goal tells setof/3 not to bind variable Var in Goal (in other words, indicates that Var is existentially quantified).

    Generalizing this idea, we have:

    graph_edges(Graph, Edges) :-
        setof( Edge,
               V^Ns^W^( member(connected(V, Ns), Graph),
                        member(W, Ns),
                        edge(V, W, Edge)),
               Edges ).
    
    graph([connected(a, [b, c]),
           connected(b, [a, c]),
           connected(c, [a, b, d]),
           connected(d, [c])]).
    

    Example:

    ?- graph(G), graph_edges(G, E).
    G = [connected(a, [b, c]), connected(b, [a, c]), connected(c, [a, b, d]), connected(d, [c])],
    E = [a-b, a-c, b-c, c-d].
    

    LIBRARY UGRAPHS

    In SWI-Prolog, a trivial solution would be to use the predicate edges/2 from library(ugraphs). Be careful though, because the representation of undirected graphs on which the predicate edge/2 is based is different from the one you are considering (an undirected graph in the library(ugraphs) is represented by a list of vertex pairs where the order of the vertices in these pairs matters). For example:

    ?- edges([a-[b,c], b-[a,c], c-[a,b,d], d-[c]], E).
    E = [a-b, a-c, b-a, b-c, c-a, c-b, c-d, d-c].