Choosing all possible options from List in Prolog - list

So I have to write different procedures that will help me solve the farmer-wolf-goat-cabbage-fertilizer puzzle. For those of you that don't know it, it involves a farmer having to cross from the North bank of a river to the South bank with all the other objects. A bank is rendered safe in 3 situations: the farmer is present OR, the wolf is not left with the goat OR, the goat is not left behind with the cabbage. For the purpose of the exercise, the variables will be [f,b,g,w,c].
The procedure (choose(Bank, Items)) I am stuck at involves finding a list of 1 or 2 elements (always including the farmer - f), that could be part of a transport from a Bank without leaving it unsafe.
If one does choose([g,f,b], Items), the possible returned values for Items can be [f], [f,g], [f,b]. However, if we do choose([g,f,c], Items), the only possible values returned are [f,c] or [f,g], since the goat and cabbage cannot be left behind together.
Thus, could anyone please give me a hint how to get all possible options for Items but in lists no longer than 2 items?

I can't test right now but I guess that you could write something like :
choose(Bank, [f, Other]) :-
select(f, Bank, Rest),
select(Other, Rest, LeftBehind),
safe(LeftBehind).
choose(Bank, [f]) :-
select(f, Bank, LeftBehind),
safe(LeftBehind).

Related

Riddle puzzle in clingo

So in the tag prolog someone wanted to solve the "the giant cat army riddle" by Dan Finkel (see video / Link for description of the puzzle).
Since I want to improve in answer set programming I hereby challenge you to solve the puzzle more efficient than me. You will find my solution as answer. I'll accept the fastest running answer (except if it's using dirty hacks).
Rules:
hardcoding the length of the list (or something similar) counts as dirty hack.
The output has to be in the predicate r/2, where it's first argument is the index of the list and the second its entry.
Time measured is for the first valid answer.
num(0..59).
%valid operation pairs
op(N*N,N):- N=2..7.
% no need to add operations that start with 14
op(Ori,New):- num(Ori), New = Ori+7, num(New), Ori!=14.
op(Ori,New):- num(Ori), New = Ori+5, num(New), Ori!=14.
%iteratively create new numbers from old numbers
l(0,0).
{l(T+1,New) : op(Old,New)} = 1 :- l(T,Old), num(T+1), op(Old,_).
%no number twice
:- 2 #sum {1,T : l(T,Value)}, num(Value).
%2 before 10 before 14
%linear encoding
reached(T,10) :- l(T,10).
reached(T+1,10) :- reached(T,10), num(T+1).
:- reached(T,10), l(T,2).
:- l(T,14), l(T+1,_).
%looks nicer, but quadratic
%:- l(T2,2), l(T10,10), T10<T2.
%:- l(T14,14), l(T10,10), T14<T10.
%we must have these three numbers in the list somewhere
:- not l(_,2).
:- not l(_,10).
:- not l(_,14).
#show r(T,V) : l(T,V).
#show.
Having a slightly more ugly encoding improves grounding a lot (which was your main problem).
I restricted op/2 to not start with 14, as this should be the last element in the list
I do create the list iteratively, this may not be as nice, but at least for the start of the list it already removed impossible to reach values via grounding. So you will never have l(1,33) or l(2,45) etc...
Also list generation stops when reaching the value 14, as no more operation is possible/needed.
I also added a linear scaling version of the "before" section, although it is not really necessary for this short list (but a cool trick in general if you have long lists!) This is called "chaining".
Also note that your show statement is non-trivial and does create some constraints/variables.
I hope this helps, otherwise feel free to ask such questions also on our potassco mailing list ;)
My first attempt is to generate a permutation of numbers and force successor elements to be connected by one of the 3 operations (+5, +7 or sqrt). I predefine the operations to avoid choosing/counting problems. Testing for <60 is not necessary since the output of an operation has to be a number between 0 and 59. The generated List l/2 is forwarded to the output r/2 until the number 14 appears. I guess there is plenty of room to outrun my solution.
num(0..59).
%valid operation pairs
op(N*N,N):- N=2..7.
op(Ori,New):- num(Ori), New = Ori+7, num(New).
op(Ori,New):- num(Ori), New = Ori+5, num(New).
%for each position one number
l(0,0).
{l(T,N):num(N)}==1:-num(T).
{l(T,N):num(T)}==1:-num(N).
% following numbers are connected with an operation until 14
:- l(T,Ori), not op(Ori,New), l(T+1,New), l(End,14), T+1<=End.
% 2 before 10 before 14
:- l(T2,2), l(T10,10), T10<T2.
:- l(T14,14), l(T10,10), T14<T10.
% output
r(T,E):- l(T,E), l(End,14), T<=End.
#show r/2.
first Answer:
r(0,0) r(1,5) r(2,12) r(3,19) r(4,26) r(5,31) r(6,36) r(7,6)
r(8,11) r(9,16) r(10,4) r(11,2) r(12,9) r(13,3) r(14,10) r(15,15)
r(16,20) r(17,25) r(18,30) r(19,37) r(20,42) r(21,49) r(22,7) r(23,14)
There are multiple possible lists with different length.

Prolog: How to adjust the maximum length of lists shown in a trace?

Feel free to cut immediately past the first two paragraphs, they are mostly waffle explaining the situation.
I'm working on a task for my University course, while I don't want any help solving the actual problem (I feel like that's "cheating" as it were) I would like help finding a way to extend the lengths of lists shown in prolog when tracing. For example, in the task you have to make a path finder through a maze with coloured "edges" between nodes which are each assigned a unique letter from the alphabet. The edges are "two way" and there is a "start" node that connects via a red edge to the "m" node also. The goal is to reach the "g" node in the middle while going along edges from the start in a repeating order of [red,brown,yellow].
Anyway, I think my algorithm finds a correct route at the bottom of the recursion, but going through the tracer is possible thousands of steps (I was holding return for about 2 minutes before it finished). Currently it doesn't "return" the generated list of steps (and while I'm sure some of you would be able to tell me how to do so, I'd rather you didn't because it's important I learn the actual prolog myself I feel) so the only time I see what's in the list of route steps is in the trace. SO here is the problem:
path(k, [red, brown, yellow], [[start, red], [m, brown], [e, yellow], [h, red], [r, brown], [p, yellow], [n|...], [...|...]|...], [start, m, e, h, r, p, n, j|...], g)
The final list holds the route I want to know if it's valid, however:
[start, m, e, h, r, p, n, j|...]
Cuts off at j, I want the trace to show FULL lists, otherwise I will have to go back through 100s of lines of trace trying to find the broken up and "correct" nodes in the path, with lots of backtracking mixed in i.e. really hard, and really easy to make a mistake. Also the I'm using program only keeps 30 or so lines prior (no idea if this is normal but I am using a SWI-Prolog(Multi-threaded, version 7.2.3) from the official site). Which means I'd have to go through everything past the first time it reaches the j node which would take a huge amount of time.
So as I say, this could be solved by having the list be unified (or whatever it is called) as a "return" (or whatever it is called) but I don't want an answer like that spoon fed to me and would rather figure it out on my own. So if you know how to do so, please refrain from telling me and just still with the way to increase the maximum displayed list with trace thank you.
I appreciate the help, sorry for the hoops I'm asking people to jump through.
to prevent these kinds of outputs [_|...] adding the code below ;
:- set_prolog_flag(toplevel_print_options,
[quoted(true), portrayed(true), max_depth(0)]).

Prolog CLPFD trying to define domain for lists of list

I am working on a constraints programming problem in Prolog and I am having problems trying to define a domain for lists of list. The initial challenge of the problem is as follows:
trains([[1,2,0,1], %from station, to station, departs at, arrives at
[2,3,4,5],
[2,3,0,1],
[3,4,5,6],
[3,4,2,3],
[3,4,8,9]]).
threepath(A,D,Ps):-
Ps = [[A,B, _T0, T1], [B,C, T2, T3], [C,D, T4, _T5]],
T2 #> T1,
T4 #> T3,
trains(Ts),
tuples_in(Ps, Ts).
After that, I am expected to expand on this to accommodate for any number of trains instead of only 3. Here is my attempt at doing that:
anypath(A,D,Ps,N):-
length(Ps,N),
Ps ins Xs,
Xs = [A,B,C,D],
Xs ins 1..9. %How to define the domain for a list of length 4 inside a list of variable length.
However, I am not very sure how to define a domain for lists of list. So far, I have defined length(Ps, N) so that Ps can have any length. Then, I tried to define the variables inside of Ps so that they will be list of length 4 but failed horribly.
Additionally, I am also not sure how to define the constraints for a variable length of Ps like the 3 scenario case where T2 #> T1 and T3 #> T4. The pattern that I am seeing is the last element of the next list should be greater than the third element of the list before it but I am stuck on the syntax to represent this constraint as well.
Right now, I am trying to use recursion to somehow set the Head of Ps to a list of length 4 and to recurse through to do the same with the tails since I won't be able to know how long the list Ps will be.
I would be grateful if someone can shed some light on this.
Update on Progress 25/3/2015
I read on an example of another problem that a maplist was used to produce inner lists. An excerpt of the code is:
length_(Length, List) :- length(List, Length).
child_row(X) :- X ins 1..16 .
ww(X) :-
write(X),
write('/').
print_row(Row) :-
maplist(ww, Row),
nl.
children(Class) :-
length(Class, 4),
maplist(length_(4), Class),
maplist(child_row , Class),
From what I understand, maplist(length_(4), Class) applies the length_(4) to every element inside Class and creates inner lists of length 4 as a result. So, I tried to apply this to my problem and here is my attempt:
length_(Length, List) :- length(List, Length).
anypath(A,D,Ps,N):-
length(Ps,N),
maplist(length_(4), Ps),
%constraint(Ps),
trains(Ts),
tuples_in(Ps, Ts).
However, I get an error message saying "length/2: Type error: list' expected, found4'" regardless of whether N is set to 3 or 4 and I don't quite understand this as well since it should work the same way as the example above and gtrace is a bit messy to detect what's wrong for me.
I am currently stuck at the moment and I will update if I figure anything out.
So, I have another question that I hope can be answered is "What is the normal practice of creating inner lists and how do you normally do it yourself?".
Thanks!
You can flatten the list with
append(Trains, FlatTrains)
and then constrain the domain of FlatTrains
FlatTrains ins 1..9

Prolog - Recursive List

Here is my question:
A small club decided to set up a telephone network for urgent messages
amongst its members. The following arrangement was agreed:
Anne can phone both Bill and Mary. Bill can phone both Tom
and Sue. Tom can phone both Liz and Frank. Liz can also phone
Frank if necessary.
Express this information as seven Prolog facts of the form
can_phone(anne,bill). Now write recursive Prolog rules for a predicate message_route such
that message_route(A,B,R) is true if A can pass a message to B routed
via the people in list R, using the club’s telephone arrangements. For
example, message_route(anne,frank,[anne,bill,tom,liz,frank])
would be true (because anne can phone bill, who can phone tom,
who can phone liz, who can phone frank).
I have this so far:
can_phone(anne,bill).
can_phone(anne,mary).
can_phone(bill,tom).
can_phone(bill,sue).
can_phone(tom,liz).
can_phone(tom,frank).
can_phone(liz,frank).
For my message_route, I have experimented and have this working which allows me to complete the second part of the question without the requirement of restricting the list to a specified list of persons (R).
message_route(A,B) :- can_phone(A,B).
message_route(A,B) :- can_phone(A,X), message_route(X,B).
I don't understand how to implement this list in my answer.
Accumulating a list is relatively straightforward: first, observe that if A can call B directly, the list is simply [A, B]. Hence, we can rewrite your first rule as
message_route(A,B,[A,B]) :- can_phone(A,B).
The second rule is a bit trickier: you need to unify to a list produced by message_route, and insert A at its head. Note that you do not need to insert X or B, because they would be provided by the returned list:
message_route(A,B,[A|Tail]) :- can_phone(A,X), message_route(X,B,Tail).
Here is a small demo that uses your data.
Note that this code would be chasing its own tail if the data that you present represents a graph with loops, rather than a tree. To avoid this, you could avoid picking X if it is already part of the Tail list.

Prolog Program for a recordings database

I have three types of facts:
album(code, artist, title, date).
songs(code, songlist).
musicians(code, list).
Example:
album(123, 'Rolling Stones', 'Beggars Banquet', 1968).
songs(123, ['Sympathy for the Devil', 'Street Fighting Man']).
musicians(123, [[vocals, 'Mick Jagger'], [guitar, 'Keith Richards', 'Brian Jones']].
I need to create these 4 rules:
together(X,Y) This succeeds if X and Y have played on the same album.
artistchain(X,Y) This succeeds if a chain of albums exists from X to Y;
two musicians are linked in the chain by 'together'.
role(X,Y) This succeeds if X had role Y (e.g. guitar) ever.
song(X,Y) This succeeds if artist X recorded song Y.
Any help?
I haven't been able to come up with much but for role(X,Y) I came up with:
role(X,Y) :- prole(X,Y,musicians(_,W)).
prole(X,Y,[[Y|[X|T]]|Z]).
prole(X,Y,[[Y|[H|T]]|Z]) :- prole(X,Y,[[Y|T]|Z]).
prole(X,Y,[A|Z]) :- prole(X,Y,Z).
But that doesn't work. It does work if I manually put in a list instead of musicians(_,W) like [[1,2,3],[4,5,6]].
Is there another way for me to insert the list as a variable?
As for the other rules I'm at a complete loss. Any help would really be appreciated.
You have a misconception about Prolog: Answering a goal in Prolog is not the same as calling a function!
E.g.: You expect that when "role(X,Y) :- prole(X,Y,musicians(_,W))." is executed, "musicians(_,W)" will be evaluated, because it is an argument to "prole". This is not how Prolog works. At each step, it attempts to unify the goal with a stored predicate, and all arguments are treaded either as variables or grounded terms.
The correct way to do it is:
role(X,Y) :- musicians(_, L), prole(X,Y,L).
The first goal unifies L with a list of musicians, and the second goal finds the role (assuming that the rest of your code is correct).
Little Bobby Tables is right, you need to understand the declarative style of Prolog. Your aim is to provide a set of rules that will match against the set of facts in the database.
Very simply, imagine that I have the following database
guitarist(keith).
guitarist(jim).
in_band('Rolling Stones', keith).
in_band('Rolling Stones', mick).
Supposed I want to find out who is both a guitarist and in the Rolling Stones. I could use a rule like this
stones_guitarist(X):-
guitarist(X),
in_band('Rolling Stones', X).
When a variable name is given within a rule (in this case X) it holds its value during the rule, so what we're saying is that the X which is a guitarist must also be the same X that is in a band called 'Rolling Stones'.
There are lots of possible ways for you to arrange the database. For example it might be easier if the names of the musicians were themselves a list (e.g. [guitar,[keith,brian]]).
I hope the following example for song(X,Y) is of some help. I'm using Sicstus Prolog so import the lists library to get 'member', but if you don't have that it's fairly easy to make it yourself.
:- use_module(library(lists)).
song(ARTIST,SONG):-
album(CODE,ARTIST,_,_),
songs(CODE,TRACKS),
member(SONG,TRACKS).