Question

If I have a list of edges for a problem like "Show me the routes from a city that is considered dangerous to one that is considered safe" as so...

dangerous(oakland).
safe(portland).

move(rome,plane,portland).
move(portland,plane,rome).
move(halifax,train,gatwick).
move(gatwick,car,rome).
move(portland,plane,newyork).
move(oakland,plane,rome).
move(oakland,plane,gatwick).
move(halifax,train,gatwick).
move(gatwick,plane,rome).
move(oakland,train,newyork).

I can get a list of Paths that lead to a safe city by using the following depth first search(found on SO)...

dfs_start(Start, Goal, Path) :- phrase(dfs(Start, [], Goal), Path).

dfs(Node, _, Goal)   --> [Node], { call(Goal, Node) }.
dfs(Node0, Es, Goal) --> [Node0],
        { move(Node0,_,Node1), \+ member(Node1, Es) },
        dfs(Node1, [Node0|Es], Goal).

The problem I'm trying to solve however is to find all of the Paths from dangerous cities that do NOT lead to a safe city (which in this case would only be one oakland -> newyork.) If I call the above function with...

dfs_start(oakland,safe,Path).

...I get

Path = [oakland, rome, portland] ;
Path = [oakland, gatwick, rome, portland] ;
Path = [oakland, gatwick, rome, portland] ;

...but what I'm looking to do is call something like...

dfs_start(oakland,unsafe,Path).

...and get...

Path = [oakland, newyork] ;

Any advice would be greatly appreciated!

Was it helpful?

Solution

The problem description is ambiguous, maybe that's the cause of your doubt. As I understand it, unsafe(X). is plainly wrong, because eliminates each filtering condition. You could try to simplify the rule in this way (I've commented out the inefficient rule, you can delete it):

% unsafe(X) :- findall(Y,safe(Y),SafeList), member(X,SafeList), !, fail.
unsafe(X) :- \+ safe(X).

Edit the comment you exchanged with Will Ness clarified a bit the task: the stop condition must be true when the path cannot be extended more, and any safe city is banned from path. I simplified a bit the code, removing unnecessary features, so you can concentrate on the logic: graph is acyclic, so the visited path is not required, and instead of passing down a Goal, just use the required statement:

unsafe_path([Start|Path]) :-
    dangerous(Start),
    phrase(dfs(Start), Path).

dfs(Node) --> [Node1],
   {  move(Node, _, Node1),
      \+ lead_to_safe(Node1)
    } -> dfs(Node1) ; {true}.

lead_to_safe(Node) :- safe(Node).
lead_to_safe(Node) :-
    move(Node, _, Node1),
    lead_to_safe(Node1).

test:

?- unsafe_path(P).
P = [oakland, newyork].

if we add a fictious city the path is extended:

?- assertz(move(newyork,train,turin)).

?- unsafe_path(P).
P = [oakland, newyork, turin].

if we make turin a gateway to a safe city:

?- assertz(move(turin,train,portland)).

?- unsafe_path(P).
P = [oakland].
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top