2

If I have a map with nodes 1,2,...,n, I want to know if I can go from n1 to n2, I can use the following code:

path(1,2).
path(3,5).
.....

get_to(A,B) :- path(A,B).
get_to(A,B) :- path(A,C),get_to(C,B).

But how can record the path from A to B and show it ?

false
  • 10,264
  • 13
  • 101
  • 209
祝堅志
  • 21
  • 3

2 Answers2

1

First, let us get terminology right: The direct connections between nodes (often called vertices) are called edges. And the whole way is called a path. Here is a first attempt:

path(A,B,[A,B]) :- edge(A,B).
path(A,C,[A,B|Vs]) :- edge(A,B), path(B,C,[B|Vs]).

Note that the list can now be used to determine all paths of a fixed length.

?-length(P, 10), path(A,B, P).

Or even all paths, sorted by length:

?- length(P, N), path(A,B, P).

The price for this generality is that this last query does not terminate. There are ways to fix this, but they are not straight-forward.

false
  • 10,264
  • 13
  • 101
  • 209
0

Well you could use an accumulator:

get_to(A,B,L) :-
    get_to(A,B,[A],L).

get_to(A,B,L,L2) :-
    path(A,B),
    append(L,[B],L2).
get_to(A,B,L,L3) :-
    path(A,C),
    append(L,[C],L2),
    get_to(C,B,L2,L3).

Where L is an array storing the nodes in the path.

In case the graph looks like:

path(1,2).
path(1,3).
path(3,4).
path(4,6).
path(6,5).
path(5,7).

This will result in:

?- get_to(1,7,L).
L = [1, 3, 4, 6, 5, 7]

A problem with this approach is however that the append operation takes linear time resulting in a significant overhead. You can however try to construct the path in reverse...

get_to(A,B,L) :-
    get_to(A,B,[B],L).

get_to(A,B,L,[A|L]) :-
    path(A,B).
get_to(A,B,L,L2) :-
    path(C,B),
    get_to(A,C,[C|L],L2).

resulting - evidently - in the same path, but much faster...

?- get_to(1,7,L).
L = [1, 3, 4, 6, 5, 7] .
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • May I ask a simple question ? get_to(1,3,[1],[2,3]). get_to(1,3,L) :- get_to(1,3,[1],[2,3]). ? get_to(1,3,L). Why can't this print L ? – 祝堅志 Jul 27 '14 at 08:35
  • Well you only declare `get_to/4` (with four arguments). Then you call `get_to/3` with three arguments. If `L` remains uninstantiated it isn't printed... – Willem Van Onsem Jul 27 '14 at 18:00
  • Sory,My silly question is your first clause get_to(A,B,L) :- get_to(A,B,[A],L). Is L = [A] + L ? Otherwise, Where to add [1] to L – 祝堅志 Jul 29 '14 at 14:33
  • Well you don't really "add" something to a variable, since a variable in prolog can only be assigned a value once. The code uses two predicates: `get_to/3` (with 3 arguments) and `get_to/4` (four arguments). The first clause only "binds" `get_to/3` with `get_to/4`. And this is done by starting the "construction" of the path with `[A]`. The last argument of `get_to/4` is the final path. And this is binded with `L`... – Willem Van Onsem Jul 29 '14 at 21:22