Compatible Doclog docs for library(ugraphs)

This commit is contained in:
Adrián Arroyo Calle
2022-12-05 00:09:32 +01:00
parent 3bdcc3aba9
commit d429b263eb

View File

@@ -53,7 +53,7 @@
connect_ugraph/3 % +Graph1, -Start, -Graph connect_ugraph/3 % +Graph1, -Start, -Graph
]). ]).
/** <module> Graph manipulation library /** Graph manipulation library
The S-representation of a graph is a list of (vertex-neighbours) pairs, The S-representation of a graph is a list of (vertex-neighbours) pairs,
where the pairs are in standard order (as produced by keysort) and the where the pairs are in standard order (as produced by keysort) and the
@@ -61,55 +61,50 @@ neighbours of each vertex are also in standard order (as produced by
sort). This form is convenient for many calculations. sort). This form is convenient for many calculations.
A new UGraph from raw data can be created using A new UGraph from raw data can be created using
vertices_edges_to_ugraph/3. vertices\_edges\_to\_ugraph/3.
Adapted to support some of the functionality of the SICStus ugraphs Adapted to support some of the functionality of the SICStus ugraphs
library by Vitor Santos Costa. library by Vitor Santos Costa.
Ported from YAP 5.0.1 to SWI-Prolog by Jan Wielemaker. Ported from YAP 5.0.1 to SWI-Prolog by Jan Wielemaker.
@author R.A.O'Keefe Ported from SWI-Prolog to Scryer by Adrián Arroyo Calle
@author Vitor Santos Costa
@author Jan Wielemaker License: BSD-2 or Artistic 2.0
@license BSD-2 or Artistic 2.0
*/ */
:- use_module(library(lists)). :- use_module(library(lists)).
:- use_module(library(pairs)). :- use_module(library(pairs)).
:- use_module(library(ordsets)). :- use_module(library(ordsets)).
%! vertices(+Graph, -Vertices) %% vertices(+Graph, -Vertices)
% %
% Unify Vertices with all vertices appearing in Graph. Example: % Unify Vertices with all vertices appearing in Graph. Example:
% %
% ?- vertices([1-[3,5],2-[4],3-[],4-[5],5-[]], L). % ?- vertices([1-[3,5],2-[4],3-[],4-[5],5-[]], L).
% L = [1, 2, 3, 4, 5] % L = [1, 2, 3, 4, 5]
vertices([], []) :- !. vertices([], []) :- !.
vertices([Vertex-_|Graph], [Vertex|Vertices]) :- vertices([Vertex-_|Graph], [Vertex|Vertices]) :-
vertices(Graph, Vertices). vertices(Graph, Vertices).
%! vertices_edges_to_ugraph(+Vertices, +Edges, -UGraph) is det. %% vertices_edges_to_ugraph(+Vertices, +Edges, -UGraph) is det.
% %
% Create a UGraph from Vertices and edges. Given a graph with a % Create a UGraph from Vertices and edges. Given a graph with a
% set of Vertices and a set of Edges, Graph must unify with the % set of Vertices and a set of Edges, Graph must unify with the
% corresponding S-representation. Note that the vertices without % corresponding S-representation. Note that the vertices without
% edges will appear in Vertices but not in Edges. Moreover, it is % edges will appear in Vertices but not in Edges. Moreover, it is
% sufficient for a vertice to appear in Edges. % sufficient for a vertice to appear in Edges.
% %
% == % ?- vertices_edges_to_ugraph([],[1-3,2-4,4-5,1-5], L).
% ?- vertices_edges_to_ugraph([],[1-3,2-4,4-5,1-5], L). % L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[]]
% L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[]]
% ==
% %
% In this case all vertices are defined implicitly. The next % In this case all vertices are defined implicitly. The next
% example shows three unconnected vertices: % example shows three unconnected vertices:
% %
% == % ?- vertices_edges_to_ugraph([6,7,8],[1-3,2-4,4-5,1-5], L).
% ?- vertices_edges_to_ugraph([6,7,8],[1-3,2-4,4-5,1-5], L). % L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[], 6-[], 7-[], 8-[]]
% L = [1-[3,5], 2-[4], 3-[], 4-[5], 5-[], 6-[], 7-[], 8-[]]
% ==
vertices_edges_to_ugraph(Vertices, Edges, Graph) :- vertices_edges_to_ugraph(Vertices, Edges, Graph) :-
sort(Edges, EdgeSet), sort(Edges, EdgeSet),
@@ -119,15 +114,13 @@ vertices_edges_to_ugraph(Vertices, Edges, Graph) :-
p_to_s_group(VertexSet, EdgeSet, Graph). p_to_s_group(VertexSet, EdgeSet, Graph).
%! add_vertices(+Graph, +Vertices, -NewGraph) %% add_vertices(+Graph, +Vertices, -NewGraph)
% %
% Unify NewGraph with a new graph obtained by adding the list of % Unify NewGraph with a new graph obtained by adding the list of
% Vertices to Graph. Example: % Vertices to Graph. Example:
% %
% ``` % ?- add_vertices([1-[3,5],2-[]], [0,1,2,9], NG).
% ?- add_vertices([1-[3,5],2-[]], [0,1,2,9], NG). % NG = [0-[], 1-[3,5], 2-[], 9-[]]
% NG = [0-[], 1-[3,5], 2-[], 9-[]]
% ```
% replace with real msort/2 when available % replace with real msort/2 when available
msort_(List, Sorted) :- msort_(List, Sorted) :-
@@ -159,23 +152,16 @@ add_empty_vertices([], []).
add_empty_vertices([V|G], [V-[]|NG]) :- add_empty_vertices([V|G], [V-[]|NG]) :-
add_empty_vertices(G, NG). add_empty_vertices(G, NG).
%! del_vertices(+Graph, +Vertices, -NewGraph) is det. %% del_vertices(+Graph, +Vertices, -NewGraph) is det.
% %
% Unify NewGraph with a new graph obtained by deleting the list of % Unify NewGraph with a new graph obtained by deleting the list of
% Vertices and all the edges that start from or go to a vertex in % Vertices and all the edges that start from or go to a vertex in
% Vertices to the Graph. Example: % Vertices to the Graph. Example:
% %
% == % ?- del_vertices([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[2,6],8-[]],
% ?- del_vertices([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[2,6],8-[]],
% [2,1], % [2,1],
% NL). % NL).
% NL = [3-[],4-[5],5-[],6-[],7-[6],8-[]] % NL = [3-[],4-[5],5-[],6-[],7-[6],8-[]]
% ==
%
% @compat Upto 5.6.48 the argument order was (+Vertices, +Graph,
% -NewGraph). Both YAP and SWI-Prolog have changed the argument
% order for compatibility with recent SICStus as well as
% consistency with del_edges/3.
del_vertices(Graph, Vertices, NewGraph) :- del_vertices(Graph, Vertices, NewGraph) :-
sort(Vertices, V1), % JW: was msort sort(Vertices, V1), % JW: was msort
@@ -204,32 +190,28 @@ split_on_del_vertices(>, V, Edges, [_|Vs], Vs, V1, [V-NEdges|NG], NG) :-
ord_subtract(Edges, V1, NEdges). ord_subtract(Edges, V1, NEdges).
split_on_del_vertices(=, _, _, [_|Vs], Vs, _, NG, NG). split_on_del_vertices(=, _, _, [_|Vs], Vs, _, NG, NG).
%! add_edges(+Graph, +Edges, -NewGraph) %% add_edges(+Graph, +Edges, -NewGraph)
% %
% Unify NewGraph with a new graph obtained by adding the list of Edges % Unify NewGraph with a new graph obtained by adding the list of Edges
% to Graph. Example: % to Graph. Example:
% %
% ``` % ?- add_edges([1-[3,5],2-[4],3-[],4-[5],
% ?- add_edges([1-[3,5],2-[4],3-[],4-[5],
% 5-[],6-[],7-[],8-[]], % 5-[],6-[],7-[],8-[]],
% [1-6,2-3,3-2,5-7,3-2,4-5], % [1-6,2-3,3-2,5-7,3-2,4-5],
% NL). % NL).
% NL = [1-[3,5,6], 2-[3,4], 3-[2], 4-[5], % NL = [1-[3,5,6], 2-[3,4], 3-[2], 4-[5],
% 5-[7], 6-[], 7-[], 8-[]] % 5-[7], 6-[], 7-[], 8-[]]
% ```
add_edges(Graph, Edges, NewGraph) :- add_edges(Graph, Edges, NewGraph) :-
p_to_s_graph(Edges, G1), p_to_s_graph(Edges, G1),
ugraph_union(Graph, G1, NewGraph). ugraph_union(Graph, G1, NewGraph).
%! ugraph_union(+Graph1, +Graph2, -NewGraph) %% ugraph_union(+Graph1, +Graph2, -NewGraph)
% %
% NewGraph is the union of Graph1 and Graph2. Example: % NewGraph is the union of Graph1 and Graph2. Example:
% %
% ``` % ?- ugraph_union([1-[2],2-[3]],[2-[4],3-[1,2,4]],L).
% ?- ugraph_union([1-[2],2-[3]],[2-[4],3-[1,2,4]],L). % L = [1-[2], 2-[3,4], 3-[1,2,4]]
% L = [1-[2], 2-[3,4], 3-[1,2,4]]
% ```
ugraph_union(Set1, [], Set1) :- !. ugraph_union(Set1, [], Set1) :- !.
ugraph_union([], Set2, Set2) :- !. ugraph_union([], Set2, Set2) :- !.
@@ -245,25 +227,23 @@ ugraph_union(<, Head1, Tail1, Head2, Tail2, [Head1|Union]) :-
ugraph_union(>, Head1, Tail1, Head2, Tail2, [Head2|Union]) :- ugraph_union(>, Head1, Tail1, Head2, Tail2, [Head2|Union]) :-
ugraph_union([Head1|Tail1], Tail2, Union). ugraph_union([Head1|Tail1], Tail2, Union).
%! del_edges(+Graph, +Edges, -NewGraph) %% del_edges(+Graph, +Edges, -NewGraph)
% %
% Unify NewGraph with a new graph obtained by removing the list of % Unify NewGraph with a new graph obtained by removing the list of
% Edges from Graph. Notice that no vertices are deleted. Example: % Edges from Graph. Notice that no vertices are deleted. Example:
% %
% ``` % ?- del_edges([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[],8-[]],
% ?- del_edges([1-[3,5],2-[4],3-[],4-[5],5-[],6-[],7-[],8-[]],
% [1-6,2-3,3-2,5-7,3-2,4-5,1-3], % [1-6,2-3,3-2,5-7,3-2,4-5,1-3],
% NL). % NL).
% NL = [1-[5],2-[4],3-[],4-[],5-[],6-[],7-[],8-[]] % NL = [1-[5],2-[4],3-[],4-[],5-[],6-[],7-[],8-[]]
% ```
del_edges(Graph, Edges, NewGraph) :- del_edges(Graph, Edges, NewGraph) :-
p_to_s_graph(Edges, G1), p_to_s_graph(Edges, G1),
graph_subtract(Graph, G1, NewGraph). graph_subtract(Graph, G1, NewGraph).
%! graph_subtract(+Set1, +Set2, ?Difference) %% graph_subtract(+Set1, +Set2, ?Difference)
% %
% Is based on ord_subtract % Is based on ord_subtract
graph_subtract(Set1, [], Set1) :- !. graph_subtract(Set1, [], Set1) :- !.
graph_subtract([], _, []). graph_subtract([], _, []).
@@ -279,12 +259,12 @@ graph_subtract(<, Head1, Tail1, Head2, Tail2, [Head1|Difference]) :-
graph_subtract(>, Head1, Tail1, _, Tail2, Difference) :- graph_subtract(>, Head1, Tail1, _, Tail2, Difference) :-
graph_subtract([Head1|Tail1], Tail2, Difference). graph_subtract([Head1|Tail1], Tail2, Difference).
%! edges(+Graph, -Edges) %% edges(+Graph, -Edges)
% %
% Unify Edges with all edges appearing in Graph. Example: % Unify Edges with all edges appearing in Graph. Example:
% %
% ?- edges([1-[3,5],2-[4],3-[],4-[5],5-[]], L). % ?- edges([1-[3,5],2-[4],3-[],4-[5],5-[]], L).
% L = [1-3, 1-5, 2-4, 4-5] % L = [1-3, 1-5, 2-4, 4-5]
edges(Graph, Edges) :- edges(Graph, Edges) :-
s_to_p_graph(Graph, Edges). s_to_p_graph(Graph, Edges).
@@ -324,15 +304,13 @@ s_to_p_graph([], _, P_Graph, P_Graph) :- !.
s_to_p_graph([Neib|Neibs], Vertex, [Vertex-Neib|P], Rest_P) :- s_to_p_graph([Neib|Neibs], Vertex, [Vertex-Neib|P], Rest_P) :-
s_to_p_graph(Neibs, Vertex, P, Rest_P). s_to_p_graph(Neibs, Vertex, P, Rest_P).
%! transitive_closure(+Graph, -Closure) %% transitive_closure(+Graph, -Closure)
% %
% Generate the graph Closure as the transitive closure of Graph. % Generate the graph Closure as the transitive closure of Graph.
% Example: % Example:
% %
% ``` % ?- transitive_closure([1-[2,3],2-[4,5],4-[6]],L).
% ?- transitive_closure([1-[2,3],2-[4,5],4-[6]],L). % L = [1-[2,3,4,5,6], 2-[4,5,6], 4-[6]]
% L = [1-[2,3,4,5,6], 2-[4,5,6], 4-[6]]
% ```
transitive_closure(Graph, Closure) :- transitive_closure(Graph, Closure) :-
warshall(Graph, Graph, Closure). warshall(Graph, Graph, Closure).
@@ -354,23 +332,16 @@ warshall([X-Neibs|G], V, Y, [X-Neibs|NewG]) :-
warshall(G, V, Y, NewG). warshall(G, V, Y, NewG).
warshall([], _, _, []). warshall([], _, _, []).
%! transpose_ugraph(Graph, NewGraph) is det. %% transpose_ugraph(Graph, NewGraph) is det.
% %
% Unify NewGraph with a new graph obtained from Graph by replacing % Unify NewGraph with a new graph obtained from Graph by replacing
% all edges of the form V1-V2 by edges of the form V2-V1. The cost % all edges of the form V1-V2 by edges of the form V2-V1. The cost
% is O(|V|*log(|V|)). Notice that an undirected graph is its own % is O(|V|*log(|V|)). Notice that an undirected graph is its own
% transpose. Example: % transpose. Example:
% %
% ==
% ?- transpose([1-[3,5],2-[4],3-[],4-[5], % ?- transpose([1-[3,5],2-[4],3-[],4-[5],
% 5-[],6-[],7-[],8-[]], NL). % 5-[],6-[],7-[],8-[]], NL).
% NL = [1-[],2-[],3-[1],4-[2],5-[1,4],6-[],7-[],8-[]] % NL = [1-[],2-[],3-[1],4-[2],5-[1,4],6-[],7-[],8-[]]
% ==
%
% @compat This predicate used to be known as transpose/2.
% Following SICStus 4, we reserve transpose/2 for matrix
% transposition and renamed ugraph transposition to
% transpose_ugraph/2.
transpose_ugraph(Graph, NewGraph) :- transpose_ugraph(Graph, NewGraph) :-
edges(Graph, Edges), edges(Graph, Edges),
@@ -382,13 +353,13 @@ flip_edges([], []).
flip_edges([Key-Val|Pairs], [Val-Key|Flipped]) :- flip_edges([Key-Val|Pairs], [Val-Key|Flipped]) :-
flip_edges(Pairs, Flipped). flip_edges(Pairs, Flipped).
%! compose(+LeftGraph, +RightGraph, -NewGraph) %% compose(+LeftGraph, +RightGraph, -NewGraph)
% %
% Compose NewGraph by connecting the _drains_ of LeftGraph to the % Compose NewGraph by connecting the _drains_ of LeftGraph to the
% _sources_ of RightGraph. Example: % _sources_ of RightGraph. Example:
% %
% ?- compose([1-[2],2-[3]],[2-[4],3-[1,2,4]],L). % ?- compose([1-[2],2-[3]],[2-[4],3-[1,2,4]],L).
% L = [1-[4], 2-[1,2,4], 3-[]] % L = [1-[4], 2-[1,2,4], 3-[]]
compose(G1, G2, Composition) :- compose(G1, G2, Composition) :-
vertices(G1, V1), vertices(G1, V1),
@@ -423,21 +394,15 @@ compose1(=, V1, Vs1, V1, N2, G2, SoFar, Comp) :-
ord_union(N2, SoFar, Next), ord_union(N2, SoFar, Next),
compose1(Vs1, G2, Next, Comp). compose1(Vs1, G2, Next, Comp).
%! top_sort(+Graph, -Sorted) is semidet. %% top_sort(+Graph, -Sorted) is semidet.
%! top_sort(+Graph, -Sorted, ?Tail) is semidet.
% %
% Sorted is a topological sorted list of nodes in Graph. A % Sorted is a topological sorted list of nodes in Graph. A
% toplogical sort is possible if the graph is connected and % toplogical sort is possible if the graph is connected and
% acyclic. In the example we show how topological sorting works % acyclic. In the example we show how topological sorting works
% for a linear graph: % for a linear graph:
% %
% == % ?- top_sort([1-[2], 2-[3], 3-[]], L).
% ?- top_sort([1-[2], 2-[3], 3-[]], L). % L = [1, 2, 3]
% L = [1, 2, 3]
% ==
%
% The predicate top_sort/3 is a difference list version of
% top_sort/2.
top_sort(Graph, Sorted) :- top_sort(Graph, Sorted) :-
vertices_and_zeros(Graph, Vertices, Counts0), vertices_and_zeros(Graph, Vertices, Counts0),
@@ -445,6 +410,11 @@ top_sort(Graph, Sorted) :-
select_zeros(Counts1, Vertices, Zeros), select_zeros(Counts1, Vertices, Zeros),
top_sort(Zeros, Sorted, Graph, Vertices, Counts1). top_sort(Zeros, Sorted, Graph, Vertices, Counts1).
%% top_sort(+Graph, -Sorted, ?Tail) is semidet.
%
% The predicate top\_sort/3 is a difference list version of
% top\_sort/2.
top_sort(Graph, Sorted0, Sorted) :- top_sort(Graph, Sorted0, Sorted) :-
vertices_and_zeros(Graph, Vertices, Counts0), vertices_and_zeros(Graph, Vertices, Counts0),
count_edges(Graph, Vertices, Counts0, Counts1), count_edges(Graph, Vertices, Counts0, Counts1),
@@ -520,17 +490,19 @@ decr_list(Neibs, [_|Vertices], [N|Counts1], [N|Counts2], Zi, Zo) :-
decr_list(Neibs, Vertices, Counts1, Counts2, Zi, Zo). decr_list(Neibs, Vertices, Counts1, Counts2, Zi, Zo).
%! neighbors(+Vertex, +Graph, -Neigbours) is det.
%! neighbours(+Vertex, +Graph, -Neigbours) is det. %% neighbours(+Vertex, +Graph, -Neigbours) is det.
% %
% Neigbours is a sorted list of the neighbours of Vertex in Graph. % Neigbours is a sorted list of the neighbours of Vertex in Graph.
% Example: % Example:
% %
% ``` % ?- neighbours(4,[1-[3,5],2-[4],3-[],
% ?- neighbours(4,[1-[3,5],2-[4],3-[],
% 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL). % 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL).
% NL = [1,2,7,5] % NL = [1,2,7,5]
% ```
%% neighbors(+Vertex, +Graph, -Neigbours) is det.
%
% Same as neighbours/3
neighbors(Vertex, Graph, Neig) :- neighbors(Vertex, Graph, Neig) :-
neighbours(Vertex, Graph, Neig). neighbours(Vertex, Graph, Neig).
@@ -542,24 +514,22 @@ neighbours(V,[_|G],Neig) :-
neighbours(V,G,Neig). neighbours(V,G,Neig).
%! connect_ugraph(+UGraphIn, -Start, -UGraphOut) is det. %% connect_ugraph(+UGraphIn, -Start, -UGraphOut) is det.
% %
% Adds Start as an additional vertex that is connected to all vertices % Adds Start as an additional vertex that is connected to all vertices
% in UGraphIn. This can be used to create an topological sort for a % in UGraphIn. This can be used to create an topological sort for a
% not connected graph. Start is before any vertex in UGraphIn in the % not connected graph. Start is before any vertex in UGraphIn in the
% standard order of terms. No vertex in UGraphIn can be a variable. % standard order of terms. No vertex in UGraphIn can be a variable.
% %
% Can be used to order a not-connected graph as follows: % Can be used to order a not-connected graph as follows:
% %
% ``` % top_sort_unconnected(Graph, Vertices) :-
% top_sort_unconnected(Graph, Vertices) :-
% ( top_sort(Graph, Vertices) % ( top_sort(Graph, Vertices)
% -> true % -> true
% ; connect_ugraph(Graph, Start, Connected), % ; connect_ugraph(Graph, Start, Connected),
% top_sort(Connected, Ordered0), % top_sort(Connected, Ordered0),
% Ordered0 = [Start|Vertices] % Ordered0 = [Start|Vertices]
% ). % ).
% ```
connect_ugraph([], 0, []) :- !. connect_ugraph([], 0, []) :- !.
connect_ugraph(Graph, Start, [Start-Vertices|Graph]) :- connect_ugraph(Graph, Start, [Start-Vertices|Graph]) :-
@@ -567,12 +537,12 @@ connect_ugraph(Graph, Start, [Start-Vertices|Graph]) :-
Vertices = [First|_], Vertices = [First|_],
before(First, Start). before(First, Start).
%! before(+Term, -Before) is det. %% before(+Term, -Before) is det.
% %
% Unify Before to a term that comes before Term in the standard % Unify Before to a term that comes before Term in the standard
% order of terms. % order of terms.
% %
% @error instantiation_error if Term is unbound. % Throws instantiation_error if Term is unbound.
before(X, _) :- before(X, _) :-
var(X), var(X),
@@ -585,21 +555,21 @@ before(Number, Start) :-
before(_, 0). before(_, 0).
%! complement(+UGraphIn, -UGraphOut) %% complement(+UGraphIn, -UGraphOut)
% %
% UGraphOut is a ugraph with an edge between all vertices that are % UGraphOut is a ugraph with an edge between all vertices that are
% _not_ connected in UGraphIn and all edges from UGraphIn removed. % _not_ connected in UGraphIn and all edges from UGraphIn removed.
% Example: % Example:
% %
% ``` % ?- complement([1-[3,5],2-[4],3-[],
% ?- complement([1-[3,5],2-[4],3-[],
% 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL). % 4-[1,2,7,5],5-[],6-[],7-[],8-[]], NL).
% NL = [1-[2,4,6,7,8],2-[1,3,5,6,7,8],3-[1,2,4,5,6,7,8], % NL = [1-[2,4,6,7,8],2-[1,3,5,6,7,8],3-[1,2,4,5,6,7,8],
% 4-[3,5,6,8],5-[1,2,3,4,6,7,8],6-[1,2,3,4,5,7,8], % 4-[3,5,6,8],5-[1,2,3,4,6,7,8],6-[1,2,3,4,5,7,8],
% 7-[1,2,3,4,5,6,8],8-[1,2,3,4,5,6,7]] % 7-[1,2,3,4,5,6,8],8-[1,2,3,4,5,6,7]]
% ```
% %
% @tbd Simple two-step algorithm. You could be smarter, I suppose.
% TODO: Simple two-step algorithm. You could be smarter, I suppose.
complement(G, NG) :- complement(G, NG) :-
vertices(G,Vs), vertices(G,Vs),
@@ -611,13 +581,13 @@ complement([V-Ns|G], Vs, [V-INs|NG]) :-
ord_subtract(Vs,Ns1,INs), ord_subtract(Vs,Ns1,INs),
complement(G, Vs, NG). complement(G, Vs, NG).
%! reachable(+Vertex, +UGraph, -Vertices) %% reachable(+Vertex, +UGraph, -Vertices)
% %
% True when Vertices is an ordered set of vertices reachable in % True when Vertices is an ordered set of vertices reachable in
% UGraph, including Vertex. Example: % UGraph, including Vertex. Example:
% %
% ?- reachable(1,[1-[3,5],2-[4],3-[],4-[5],5-[]],V). % ?- reachable(1,[1-[3,5],2-[4],3-[],4-[5],5-[]],V).
% V = [1, 3, 5] % V = [1, 3, 5]
reachable(N, G, Rs) :- reachable(N, G, Rs) :-
reachable([N], G, [N], Rs). reachable([N], G, [N], Rs).