Prolog get list from different relations - prolog

i´d like to get a list from a graph. The variables with two letters are the points and the one letter is a line. Each line can contain multiple points.
conn(bs, oc, c).
conn(oc, tc, c).
conn(bs, gp, j).
conn(gp, cc, j).
conn(gp, pc, p).
conn(pc, ls, p).
conn(gp, oc, v).
conn(oc, pc, b).
conn(pc, cc, b).
conn(tc, ls, n).
conn(ls, cc, n).
link(X, Y, Z) :- conn(X, Y, Z), !.
link(X, Y, Z) :- conn(Y, X, Z).
Now i want to get a list with all points belonging to a line. By typing:
getpoints(c, X).
i would expect
X = [bs, oc, tc]
This is how i tried to get my result:
getpoints(Line, [First|[]]) :- not(link(First, _Second, Line)).
getpoints(Line, [First|Rest]) :- link(First, _Second, Line), getpoints(Line, Rest).
Does anybody has an idea?

If you aren't interested in a particular order of points, you could use setof/3
By example
getpoints(Line, Points) :-
setof(X, Y^(conn(X, Y, Line) ; conn(Y, X, Line)), Points).
--- EDIT ---
Is it very complicadet to get the order of the points?
If you're point are really a line (not a more general graph), you can write something like
nextLine(Line, EndLine, []) :-
\+ conn(EndLine, _, Line).
nextLine(Line, Start, [NextPoint | NextLine]) :-
conn(Start, NextPoint, Line),
nextLine(Line, NextPoint, NextLine).
getpoints(Line, [Start, NextPoint | NextLine]) :-
conn(Start, NextPoint, Line),
\+ conn(_, Start, Line),
nextLine(Line, NextPoint, NextLine).
The idea is find, in getpoints/2, the Start point of the line, that is the point that is on the left of a conn/3 (conn(Start, NextPoint, Line)) but isn't on the right of a conn/3 (\+ conn(_, Start, Line)).
In this way you have the first two point of the line and, calling nextLine/3 recursively, you detect the following points in the correct order.

Related

Prevent cycle in Depth first search using prolog

Is there any way to prevent cycle in this code.
move(a,b).
move(b,a).
move(a,c).
move(b,d).
move(b,e).
move(d,h).
move(d,i).
move(e,j).
move(e,k).
move(c,f).
move(c,g).
move(f,l).
move(f,m).
move(g,n).
move(g,o).
goal(n).
goSolveTheMaze(Start,Way) :-
dfs(Start, Way),!.
dfs(Goal, [Goal]) :-
goal(Goal),!.
dfs(Start, [Start|Way]) :-
move(Start, N),
dfs(N, Way).
so when move(a,b) move to (b,c) dont go back to (b,a),
when run goSolveTheMaze(a,path).
The output should be path=[a,c,g,n].
What if you add a third argument to dfs which is a list of where you've already visited? You could then use \+/1 and member/2 to avoid returning to places you've already been.
For example, if you use the following:
move(a,b).
move(b,a).
move(a,c).
move(b,d).
move(b,e).
move(d,h).
move(d,i).
move(e,j).
move(e,k).
move(c,f).
move(c,g).
move(f,l).
move(f,m).
move(g,n).
move(g,o).
goal(n).
goSolveTheMaze(Start,Way) :-
dfs(Start, Way, [Start]),!.
dfs(Goal, [Goal], _) :-
goal(Goal),!.
dfs(Start, [Start|Way], Visited) :-
move(Start, N),
\+ member(N, Visited),
dfs(N, Way, [N|Visited]).
Then the query:
?- goSolveTheMaze(a, X).
Will produce the result:
X = [a, c, g, n]
Update in response to comment "can you tell me what \+ do?":
The \+ predicate is true when its argument cannot be proven. Therefore in the above example the line \+ member(N, Visited) means "when N is not a member of the list Visited".
See: https://www.swi-prolog.org/pldoc/man?predicate=%5C%2B/1

Finding the path length of an Acyclic Graph in Prolog

Okay, so I have the graph:
and I want to be able to create a rule to find all the paths from X to Y and their lengths (number of edges). For
example, another path from a to e exists via d, f, and g. Its length is 4.
So far my code looks like this:
edge(a,b).
edge(b,e).
edge(a,c).
edge(c,d).
edge(e,d).
edge(d,f).
edge(d,g).
path(X, Y):-
edge(X, Y).
path(X, Y):-
edge(X, Z),
path(Z, Y).
I am a bit unsure how I should approach this. I've entered a lot of rules in that don't work and I am now confused. So, I thought I would bring it back to the basics and see what you guys could come up with. I would like to know why you done what you done also if that's possible. Thank you in advance.
This situation has been asked several times already. Firstly, your edge/2 predicates are incomplete, missing edges like edge(c,d), edge(f,g), or edge(g,e).
Secondly, you need to store the list of already visited nodes to avoid creating loops.
Then, when visiting a new node, you must check that this new node is not yet visited, in the Path variable. However, Path is not yet instanciated. So you need a delayed predicate to check looping (all_dif/1). Here is a simplified version using the lazy implementation by https://stackoverflow.com/users/4609915/repeat.
go(X, Y) :-
path(X, Y, Path),
length(Path, N),
write(Path), write(' '), write(N), nl.
path(X, Y, [X, Y]):-
edge(X, Y).
path(X, Y, [X | Path]):-
all_dif(Path),
edge(X, Z),
path(Z, Y, Path).
%https://stackoverflow.com/questions/30328433/definition-of-a-path-trail-walk
%which uses a dynamic predicate for defining path
%Here is the lazy implementation of loop-checking
all_dif(Xs) :- % enforce pairwise term inequality
freeze(Xs, all_dif_aux(Xs,[])). % (may be delayed)
all_dif_aux([], _).
all_dif_aux([E|Es], Vs) :-
maplist(dif(E), Vs), % is never delayed
freeze(Es, all_dif_aux(Es,[E|Vs])). % (may be delayed)
Here are some executions with comments
?- go(a,e).
[a,b,e] 3 %%% three nodes: length=2
true ;
[a,c,d,f,g,e] 6
true ;
[a,c,f,g,e] 5
true ;
[a,d,f,g,e] 5
true ;
false. %%% no more solutions
Is this a reply to your question ?

Prolog: script doesn't halt

I'm currently trying to learn prolog. I hope you can help..
I have three rules:
reverse - retrieves the reverse of a list
startswith - checks if the second list is a prefix of the first list
suffix - checks if the first list is a suffix of the second list
reverse([H|T], Y) :- append(Z, [H], Y), reverse(T, Z).
reverse([], Y) :- Y = [].
startswith(_, []).
startswith([Xh|Xt], [Yh|Yt]) :- Xh=Yh, startswith(Xt, Yt).
suffix(X, Y) :- reverse(X, XR), reverse(Y, YR), startswith(YR,XR).
reverse and startswith seem to work as they should.
But suffix doesn't stop calculating. I cannot understand why?
In general, it's a bad idea to pass variables that have yet to be unified to predicates that you will unify later. Essentially, append(Z,[H],Y) is spiraling off into prolog never-never land because it's unifying Z over and over based on your version of Prolog's append.
Change
reverse([H|T], Y) :- append(Z, [H], Y), reverse(T, Z).
To
reverse([H|T], Y) :- reverse(T, Z), append(Z, [H], Y).
So that you unify Z before you pass it to append

Regarding two implementations of min_of_list in prolog

Can someone explain clearly why this implementation (from SO 3965054) of min_of_list works in prolog:
% via: http://stackoverflow.com/questions/3965054/prolog-find-minimum-in-a-list
min_of_list_1( [H], H).
min_of_list_1([H,K|T],M) :- H =< K, min_of_list_1([H|T],M).
min_of_list_1([H,K|T],M) :- H > K, min_of_list_1([K|T],M).
while this implementation generates an incorrect output:
min_of_list_2( [H], H).
min_of_list_2( [H| T], X) :- compare(<, X, H), min_of_list_2(T, X).
min_of_list_2( [H| T], H) :- compare(>, X, H), min_of_list_2(T, X).
min_of_list_2( [H| T], H) :- compare(=, X, H), min_of_list_2(T, H).
Epilogue. This works.
min_of_list_3( [H], H).
min_of_list_3( [H| T], X) :- min_of_list_3(T, X), compare(<, X, H).
min_of_list_3( [H| T], H) :- min_of_list_3(T, X), compare(>, X, H).
min_of_list_3( [H| T], H) :- min_of_list_3(T, X), compare(=, X, H).
?
The behavior I get is that min_of_list_2 returns the last element in the list.
Thanks.
The first clause of min_of_list_2/2 is OK, it says the minimum of a list with a single element is that element. The second clause is not quite so OK: The intention seems to state that if X is the minimum of the list T, and X is smaller than H, then X is also the minimum of the list [H|T], and this would work as intended if compare/3 behaved like a true relation, but unfortunately it doesn't:
?- compare(<, a, b).
true.
Yet the more general query fails as if there were no solution (although we know there is at least one!):
?- compare(<, a, X).
false.
Since one typical usage of min_of_list_2/2 (including for example its use in the third clause) leaves the second argument uninstantiated, you will run into this problem. Your code will work as expected if you place all calls of compare/3 after the respective recursive calls of min_of_list_2/2. As a consequence, your predicate is then no longer tail recursive, in contrast to the other program you posted. The compare/3 call in the last clause should be removed (what is the X in that case?), as it will always fail!
the first one compares the first two elements of the list and then puts the min again in the list till there is only one element.
the second one... takes the head of the list and compares with X. X is non-instantiated in the first call so compare(<,X,_any_number) will be true. X wont be instantiated so the same will repeat till there is only one element in the list which will be returned* (the last one).
'* where returned = unified with the second argument.

not member rule in prolog doesn't work as expected

I'm trying to write a simple maze search program in prolog, before I add a room to visited list I'm checking whether it is already a member of the visited list. However, I can't get this to work, even if I use the code from the book:
d(a,b).
d(b,e).
d(b,c).
d(d,e).
d(c,d).
d(e,f).
d(g,e).
go(X, X, T).
go(X, Y, T) :-
(d(X,Z) ; d(Z, X)),
\+ member(Z,T),
go(Z, Y, [Z|T]).
What do I do wrong?
Your program seems to be ok.
I guess the problem is that you are calling go/3 with the third argument uninstantiated.
In that case it will member(X, T) will always succeed, thus failing the clause.
You might call your predicate with the empty list as the third parameter:
e.g.
?- go(a, g, []).
true
If you want to return the path consider adding another parameter to go, like this:
go(From, To, Path):-
go(From, To, [], Path).
go(X, X, T, T).
go(X, Y, T, NT) :-
(d(X,Z) ; d(Z, X)),
\+ member(Z,T),
go(Z, Y, [Z|T], NT).

Resources