skip to Main Content

I have the

map of Romania
from the Russell and Norvig book about artificial intelligence. I created links between the cities like this:

link(oradea, zerind, 71).
link(oradea, sibiu, 151).
link(zerind, arad, 75).
link(arad, sibiu, 140).
link(arad, timisoara, 118).
link(timisoara, lugoj, 111).
link(lugoj, mehadia, 70).
link(mehadia, drobeta, 75).
link(drobeta, craiova, 120).

I want to find the cities that connect with Oradea or Arad but when I ask this:

(link(X, arad, _); link(arad, X, _));(link(X, oradea, _); link(oradea, X, _)).

It returns:

X = zerind ;
X = sibiu ;
X = timisoara ;
X = zerind ;
X = sibiu.

How can I make it return a solution only once?

3

Answers


  1. One easy way to achieve this is using setof/3 which eliminates the duplicates from the list of solutions:

    ?- setof(X, Dist^((link(X, arad, Dist) ; link(arad, X, Dist)) ; 
                      (link(X, oradea, Dist) ; link(orade, X, Dist))), All).
    

    There is a difference between this and your query, as in this one all solutions are being put in a list, not given one at a time. But you can use member/2 to get the same behaviour:

    ?- setof(X, Dist^((link(X, arad, Dist) ; link(arad, X, Dist)) ;
                      (link(X, oradea, Dist) ; link(oradea, X, Dist))), All),
       member(X, All).
    X = sibiu,
    All = [sibiu, timisoara, zerind] ;
    X = timisoara,
    All = [sibiu, timisoara, zerind] ;
    X = zerind,
    All = [sibiu, timisoara, zerind].
    

    Edit : false’s answer is a better solution as it doesn’t build the unnecessary list All.

    Login or Signup to reply.
  2. ?- setof(t, Dist^((link(X, arad, Dist) ; link(arad, X, Dist)) ;
                      (link(X, oradea, Dist) ; link(oradea, X, Dist))), _).
       X = sibiu
    ;  X = timisoara
    ;  X = zerind.
    
    Login or Signup to reply.
  3. Another way to get your solutions only once is to dynamically use the database to store the solutions when you find them:

    ?- retractall(sol(_)),
       (link(X,arad,_) ; link(arad,X,_) ; link(X,oradea,_) ; link(oradea,X,_)),
       + sol(X),
       assertz(sol(X)).
    

    Observations:

    1. The solution with setof/3 is better and it should be preferred.

    2. In order to avoid leaving the database with garbage facts (undesired side effects), you can clean them all in the end:

      ?- ( 
           retractall(sol(_)),
           (link(X,arad,_);link(arad, X, _) ; link(X,oradea,_);link(oradea,X,_)),
           + sol(X), assertz(sol(X))
         ;
           retractall(sol(_)), fail
         ).
      
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search