testing in the console - prolog

The consult ?- go(c, g). returns false, but states true for ?- go(a, d).. I do not actually understand it, as I have added the proper rules, and for most of them it works.
Here are the statements I'm using:
door(a, b).
door(b, c).
door(c, d).
door(b, e).
door(e, f).
door(e, g).
go(FromRoom, ToRoom):-
door(FromRoom,ToRoom).
go(FromRoom, ToRoom):-
door(ToRoom, FromRoom).
go(FromRoom, ToRoom) :-
door(FromRoom, NextRoom),
go(NextRoom, ToRoom), !.
go(FromRoom, ToRoom):-
door(ToRoom,NextRoom),
go(NextRoom, FromRoom), !.

You need to add accumulator to your predicate to avoid got stuck in inf loop.
door(a, b).
door(b, c).
door(c, d).
door(b, e).
door(e, f).
door(e, g).
go(From, To, T) :-
T=[From|T1],
go(From, To, [To], T1).
go(From, To,T, T) :-
door(From, To),!.
go(From,To,T,T) :-
door(To,From),!.
go(From, To, Acc,T) :-
door(X, Do),!,
\+ member(X, Acc),
go(From, X, [X|Acc],T).
go(From,To,Acc,T) :-
door(X,Z),!,
\+member(Z,Acc),
go(X,To,[X|Acc],T).

You fourth rule should read
go(FromRoom, ToRoom):-
door(ToRoom,NextRoom),
go(FromRoom,NextRoom),!.
because you already swapped the search order in calling door/2, but this leads to looping, as rightly remarked by #whd. Here a version that 'returns' the path
go(Room, Room, Path, Path).
go(FromRoom, ToRoom, SoFar, Path) :-
( door(FromRoom, NextRoom) ; door(NextRoom, FromRoom) ),
\+ member(NextRoom, SoFar),
go(NextRoom, ToRoom, [NextRoom|SoFar], Path).
test:
?- go(c,g,[],P).
P = [g, e, b, c, d] ;
P = [g, e, b] ;
false.
Due to Prolog search order, it 'takes a tour' in d before going back. It's easy to avoid acting on the SoFar parameter at top level call...

Related

Prolog: find and put into the list duplicates

Good day, guys. Can't figure out, why prolog predicate is putting all duplicates into my new list. F.e. I have to pick all duplicates:
?- duplicates([a, b, a, a, d, d], R).
R = [a, d]
I have wrote this prolog program:
duplicates([], []).
duplicates([First|Rest], NewRest) :-
not(member(First, Rest)),
duplicates(Rest, NewRest).
duplicates([First|Rest], [First|NewRest]) :-
member(First, Rest),
duplicates(Rest, NewRest).
But it returns:
R = [a, a] .
I think I need to put a (!) sign somewhere, but cannot understand, where. Any suggestions?
library(aggregate) allows a compact solution for your problem.
duplicates(L,D) :- findall(K,(aggregate(count,member(K,L),C),C>1),D).
?- duplicates([a, b, a, a, d, d], R).
R = [a, d].
Clearly, it's less immediate to grasp than #Raubsauger' good answer, and not available in every Prolog out there.
Try this:
duplicates([], []).
duplicates([First|Rest], NewRest) :-
\+ member(First, Rest),
duplicates(Rest, NewRest).
duplicates([First|Rest], NewRest) :-
duplicates(Rest, NewRest),
member(First, NewRest).
duplicates([First|Rest], [First|NewRest]) :-
member(First, Rest),
duplicates(Rest, NewRest),
\+ member(First, NewRest).
?- duplicates([a, b, a, a, d, d], R).
R = [a, d] ;
false.
I have choosen a version where you don't need cuts (the !). Also I added another rule: elements in NewRest can appear only once. Note: membership in NewRest can be testet only after unification of all of its entries.

How can i calculate a non-weighted graph length for a path that is given

This is the code so far.
next_to(a, b).
next_to(a, c).
next_to(a, f).
next_to(b, c).
next_to(b, d).
next_to(b, e).
next_to(e, f).
next_to(g, h).
joint_with(X,Y):- next_to(X,Y) ;
next_to(Y,X).
show_path(Node, FinishNode, [Node,FinishNode]) :-
joint_with(Node, FinishNode).
show_path(Node, FinishNode, [Node | Restroute]) :-
joint_with(Node, ANode),
show_path(ANode, FinishNode, Restroute).
How can i change show_path to calculate the length aswell (Give explanation how it work's if possible thanks in advance)
According to Willem's advice, I constructed a solution for your problem which is the following:
next_to(a, b).
next_to(a, c).
next_to(a, f).
next_to(b, c).
next_to(b, d).
next_to(b, e).
next_to(e, f).
next_to(g, h).
joint_with(X, Y) :-
( next_to(X, Y)
; next_to(Y, X)
).
show_path(Node, FinishNode, [Node, FinishNode], _) :-
joint_with(Node, FinishNode).
show_path(Node, FinishNode, [Node|Restroute], Counter) :-
joint_with(Node, ANode),
show_path(ANode, FinishNode, Restroute, _),
length([Node|Restroute], Counter),
!.
But if backtracking doesn't finish Counter does not take its value.

prolog finding first cousins in family

Trying to do a prolog question to find first cousins!
/* first person is parent of second person */
parent(a, b).
parent(b, f).
parent(a, d).
parent(f, g).
parent(a, k).
parent(f, h).
parent(k, l).
parent(f, i).
parent(k, m).
parent(l, t).
parent(b, e).
sibling(X,Y) :- parent(Z,X), parent(Z,Y), not(X=Y).
grandparent(X, Z) :-
parent(X, Y),
parent(Y, Z).
cousin1(Child1,Child2) :-
grandparent(Y1,Child1),
grandparent(Y2,Child2),
not(sibling(Child1,Child2)),
Y1=Y2 .
Seems to be working, but is there a way to stop it from returning true if the same child is input?
EDIT: final answer
cousin1(Child1,Child2) :-
parent(Y1,Child1),
parent(Y2,Child2),
sibling(Y1,Y2).
Final answer!
cousin1(Child1,Child2) :-
parent(Y1,Child1),
parent(Y2,Child2),
sibling(Y1,Y2).
Write a .not-self predicate, which returns false if the children are equal. Add that to your cousin predicate.

Prolog finding and removing predicate

I my have code:
locdiff([A|T], [A|_], T).
locdiff([H|T], L2, [H|T2]) :-
locdiff(T, L2, T2).
and when i test it with locdiff([(a,1), (b,2), (b,3), (c,3), (c,4)], [(b,_)], L3), it only finds and removes one of the [(b,_)] which is (b,2). I need it to find and remove both (b,2) and (b,3) or what ever the [(b,_)] contains. can anyone help me with what i have missed?
there is a technical complication that's worth to note if you follow larsman' hint, that I would implement straight in this way
locdiff([], _, []).
locdiff([A|T], [A|_], R) :-
!, locdiff(T, [A|_], R).
locdiff([H|T], L2, [H|T2]) :-
locdiff(T, L2, T2).
with this
?- locdiff([(a,1), (b,2), (b,3), (c,3), (c,4)], [(b,_)], L3).
L3 = [ (a, 1), (b, 3), (c, 3), (c, 4)].
you can see that the first instance is removed, and the last. That's because the first match binds the anonymous variable, and then forbids following matchings, except the last (b,_)
Then a completed procedure would read
locdiff([], _, []).
locdiff([H|T], [A|_], R) :-
\+ \+ H = A, % double negation allows matching without binding
!, locdiff(T, [A|_], R).
locdiff([H|T], L2, [H|T2]) :-
locdiff(T, L2, T2).
now the outcome is what you are requiring.
Alternatively, you need to be more precise in pattern matching, avoiding undue binding
locdiff([], _, []).
locdiff([(A,_)|T], [(A,_)|_], R) :-
!, locdiff(T, [(A,_)|_], R).
locdiff([H|T], L2, [H|T2]) :-
locdiff(T, L2, T2).
?- locdiff([(a,1), (b,2), (b,3), (c,3), (c,4)], [(b,_)], L3).
L3 = [ (a, 1), (c, 3), (c, 4)].
Please note that some library has specific functionality, like exclude/3 in SWI-Prolog, but still you need attention to avoid bindings:
eq([(E,_)|_], (E,_)).
locdiff(L, E, R) :-
exclude(eq(E), L, R).
May be you need something loke that :
locdiff([], _, []).
locdiff([(b,_)|T], [(b,_)], T1) :-
!, locdiff(T, [(b,_)], T1).
locdiff([H|T], L2, [H|T2]) :-
locdiff(T, L2, T2).
But why do you write [A| _] if there is only one element in the list ?
[EDIT] I forgot the ! in the second rule

how to print the whole route

Such as for go(a, d). i want it to print the route as well such as route a, route b, route, c and route d
door(a, b).
door(b, c).
door(c, d).
door(b, e).
door(e, f).
door(e, g).
go(FromRoom, ToRoom):-
door(FromRoom,ToRoom).
go(FromRoom, ToRoom) :-
door(FromRoom, NextRoom),
go(NextRoom, ToRoom).
A good way is to simply turn go/2 into a relation that also takes the route into account. As is often the case when describing lists, DCGs are a good fit:
go(From, To) --> [From, To], { door(From, To) }.
go(From, To) --> [From],
{ door(From, Next) },
go(Next, To).
Example:
?- phrase(go(a, d), Rooms).
Rooms = [a, b, c, d] ;
false.
And regarding write/1: This is rarely necessary because we can often let the toplevel take care of printing answers. format/2 is often a better fit than write/1 for formatting output if needed, for example, instead of:
write('['), write(From), write(':'), write(To), write(']')
you can write:
format("[~w: ~w]", [From, To])
Please try not to mix IO and logic in your predicates. It will make your code hard to test, debug, reason about and will produce very confusing output on backtraking.
Here you can keep the road in a list during the recursion.
An example would be, with a third argument:
go(FromRoom, ToRoom, [FromRoom, ToRoom]) :-
door(FromRoom, ToRoom).
go(FromRoom, ToRoom, [FromRoom|Path]) :-
door(FromRoom, NextRoom),
go(NextRoom, ToRoom, Path).
A query correctly returns the path:
?- go(a, g, Path).
Path = [a, b, e, g] ;
false.
If necessary, you can then format the output list Path when you output it. But it's now a really simpler problem: format a list instead of output things during recursion.
You need to use the write predicate for this as follows
go(FromRoom, ToRoom):-
door(FromRoom,ToRoom),
write('['), write(FromRoom), write(':'), write(ToRoom), write(']').
go(FromRoom, ToRoom) :-
door(FromRoom, NextRoom),
write('['), write(FromRoom), write(':'), write(NextRoom), write(']'),
go(NextRoom, ToRoom).
Alternatively, the route in the format you wanted is
go(FromRoom, ToRoom):-
door(FromRoom,ToRoom),
write(FromRoom), write(' route '), write(ToRoom).
go(FromRoom, ToRoom) :-
door(FromRoom, NextRoom),
write(FromRoom), write(' route '),
go(NextRoom, ToRoom).

Resources