Prolog riddle solving - prolog

The statement :
Four couples in all
Attended a costume ball.
2
The lady dressed as a cat
Arrived with her husband Matt.
3
Two couples were already there,
One man dressed like a bear.
4
First to arrive wasn't Vince,
But he got there before the Prince.
5
The witch (not Sue) is married to Chuck,
Who was dressed as Donald Duck.
6
Mary came in after Lou,
Both were there before Sue.
7
The Gipsy arrived before Ann,
Neither is wed to Batman.
8
If Snow White arrived after Tess,
Then how was each couple dressed?
My code is here , but it returns false :
sol(S):-
S=[[1,L1,M1,LD1,MD1],
[2,L2,M2,LD2,MD2],
[3,L3,M3,LD3,MD3],
[4,L4,M4,LD4,MD4]],
member([_,_,matt,cat,_],S),
member([ALR,_,_,_,bear],S),
(ALR =:= 1 ; ALR =:= 2),
not(member([1,_,vince,_,_],S)),
member([VN,_,vince,_,_],S),
member([PS,_,_,_,prince],S),
VN < PS ,
member([_,_,chuck,witch,donald],S),
not(member([_,sue,_,witch,_],S)),
member([MRY,mary,_,_,_],S),
member([LOU,_,lou,_,_],S),
member([SUE,sue,_,_,_],S),
MRY > LOU,
MRY < SUE,
member([GPS,_,_,gipsy,_],S),
member([ANN,ann,_,_,_],S),
GPS < ANN ,
not(member([_,_,_,gipsy,batman],S)),
not(member([_,ann,_,_,batman],S)),
member([SW,_,_,snowwhite,_],S),
member([TS,tess,_,_,_],S),
SW > TS ,
perm([sue,mary,ann,tess],[L1,L2,L3,L4]),
perm([matt,lou,vince,chuck],[M1,M2,M3,M4]),
perm([cat,witch,gipsy,snowwhite],[LD1,LD2,LD3,LD4]),
perm([donald,prince,batman,bear],[MD1,MD2,MD3,MD4]).
takeout(X,[X|R],R).
takeout(X,[F|R],[F|S]) :- takeout(X,R,S).
perm([],[]).
perm([X|Y],Z) :- perm(Y,W), takeout(X,Z,W).
Any solution ?

You should move all your not(...) goals to the very end of the predicate.
not(G) means, "G is impossible to satisfy right now". When tried too early, with many still non-instantiated variables in the lists, it is in fact very often possible to satisfy a goal, and the whole not(...) call will fail right away.
Alternatively, delay the checking of the inequality on a variable until it is instantiated, e.g. in SWI Prolog with freeze/2 (as seen e.g. in this answer).

Related

knowledgment unification in prolog

What I have to do is to unify the possible options and solve the problem with these sentences
The Spaniard lives next to the red house.
The Norwegian lives in the blue house.
An Italian lives in the second house.
This is my attempt but I am getting an error, could someone please help me.
neighborhood(N):-
length(V,3),
next(house(_,spaniard), house(red,_), V),
member(house(blue,norway), V),
V = [_|house(_,italian)].
You may write a procedure that enforces each of your rules, and then let prolog find the possible ordering of houses that fulfill all those rules:
neiborhood(Houses):-
Houses=[House1, Italy, House3], % these are the houses, after rule 3
Italy=house(_ItalyColor, italy),
Spain=house(_SpainColor, spain),
% rule 2:
Norway=house(blue, norway),
member(House1-House3, [Spain-Norway, Norway-Spain]),
% rule 1:
append(_, [HouseA, HouseB|_], Houses),
(HouseA-HouseB=Spain-house(red, _) ; HouseB-HouseA=Spain-house(red, _)).
In this code I assumed when you said that the Spaniard lives next to the red house that it may live "to the left" or "to the right" of that house.
Also note that you only mention 2 house colors, so the third one gets unassigned color. Maybe you are missing another rule, possible which is the missing color.
Sample run:
?- neiborhood(Houses).
Houses = [house(_163550, spain), house(red, italy), house(blue, norway)] ;
Houses = [house(blue, norway), house(red, italy), house(_163550, spain)] ;
false.
In both solutions, the Spain house does not have any color assigned.

Number of legs and heads from Horse and Men in Prolog - RIDDLE

I am currently trying to solve a riddle:
"How many men and horses have 8 heads and 20 feet?"
As I am trying to solve this question with Prolog, my attempt was:
puzzle(M,H,M+H,M*2 + H*4).
And then running:
puzzle(M, H,8,20).
Unfortunately, swipl just returns false.
Can anybody say, why prolog is not working as I was expecting?
To anyone that is interested in a working solution:
horsemen(Man, Horse, Heads, Legs) :-
between(0, Legs, Man),
between(0, Legs, Horse),
Legs is 2*Man + 4*Horse, Heads is Man + Horse.
Anyway, I can't really understand, why the easier solution is not working.
If you write your expression like this:
puzzleSimple(M,M+2).
Prolog will return true for a statement like this :
puzzleSimple(3,3+2). or puzzleSimple(M,M+2).
But it will return false for puzzleSimple(3,5). What you see here is that, prolog will not execute the M+2as an arithmetic operation but rather use it in pattern matching. For arithmetic operations, you need to use the is keyword. For example:
puzzleSimple(M,V):-
V is M + 2.
This code will return true for puzzleSimple(3,5). So, when you try to directly use
puzzle(M,H,M+H,M*2 + H*4). and call puzzle(M, H,8,20).
It returns false, because the pattern is not matching.
You can also modify the code to this:
puzzle(M,H,X,Y):-
X is M+H,
Y is M*2 + H*4.
Now it will be correct in the sense of pattern matching and arithmetic operations. However, when you again call puzzle(M, H,8,20). You will see an Arguments are not sufficiently instantiated error. Why? Because you tried to do an arithmetic operation with a variable which is not instantiated. That is why the working solution uses the predicate between/3. Between assigns a value to a variable and enables the use of backtracking for finding multiple solutions.
Note : Using the gtrace command in swipl can help you in debugging your code!
You can solve it using the library "CLP(FD) Constraint Logic Programming over Finite Domains".
:-use_module(library(clpfd)).
%% "How many men and horses have 8 heads and 20 feet?"
men_and_horses(Men, Horses):-
Men in 0..10,
Horses in 0..10,
Men + Horses #= 8, %% heads must be 8
Men * 2 + Horses * 4 #= 20. %% feet mus be 20
The solution is
?- men_and_horses(X,Y).
X = 6,
Y = 2.

Solving a puzzle in Prolog

I am new to prolog and I am trying to solve this puzzle problem. I did a couple tutorials on youtube on the basics of prolog, but I need some help solving the puzzle below.
Two weeks ago, four enthusiasts made sightings of objects in the sky in their neighborhood. Each of the four reported his or her sightings on a different day. The FBI came and was able to give each person a different explanation of what he or she had "really" seen. Can you determine the day ( Tuesday through Friday ) each person sighted the object, as well as the object that it turned out to be?
Mr. K made his sighting at some point earlier in the week than the one who saw the balloon, but at some point later in the week, than the one who spotted the Kite ( who isn't Ms. G ).
Friday's sighting was made by either Ms. Barn or the one who saw a plane ( or both ).
Mr. Nik did not make his sighting on Tuesday.
Mr. K isn't the one whose object turned out to be a telephone pole.
I have my set my rules up correctly, but I can't seem to get the logic down pack. I am looking for guidance not direct answers. On the far right, I have listed the number to each question i am attempting to answer
enthu(mr_k).
enthu(ms_barn).
enthu(ms_g).
enthu(mr_nik).
object(ballon).
object(kite).
object(plane).
object(tele_pole).
day(tuesday).
day(wednesday).
day(thursday).
day(friday).
sight(X,ballon).
sighting(mr_k):- 1
day(X),
sight(X,Y),
didntc_kite(ms_g).
friday_sight:- enthu(ms_barn); 2
saw(X,plane);
both(ms_barn,X).
nosight_tuesday(mr_nik,X). 3
no_telepole(mr_k,Y). 4
I know you didn't ask for a solution, but I find it hard to describe what to do without a working solution. I apologise for that.
Here's what I would do:
/*
1. Mr. K made his sighting at some point earlier in the week than the one who saw the balloon, but at some point later in the week, than the one who spotted the Kite ( who isn't Ms. G ).
2. Friday's sighting was made by either Ms. Barn or the one who saw a plane ( or both ).
3. Mr. Nik did not make his sighting on Tuesday.
4. Mr. K isn't the one whose object turned out to be a telephone pole.
*/
?-
% Set up a list of lists to be the final solution
Days = [[tuesday,_,_],[wednesday,_,_],[thursday,_,_],[friday,_,_]],
/* 1 */ before([_,mr_k,_],[_,_,balloon],Days),
/* 1 */ before([_,_,kite],[_,mr_k,_],Days),
/* 2 */ (member([friday,ms_barn,_],Days);
member([friday,_,plane],Days);
member([friday,ms_barn,plane],Days)),
% Fill in the rest of the people
members([[_,mr_k,_],[_,ms_barn,_],[_,ms_g,_],[_,mr_nik,_]],Days),
% Fill in the rest of the objects
members([[_,_,balloon],[_,_,kite],[_,_,plane],[_,_,tele_pole]],Days),
% Negations should be done after the solution is populated
/* 1 */ member([_,NOT_ms_g,kite],Days), NOT_ms_g \= ms_g,
/* 3 */ member([tuesday,NOT_mr_nik,_],Days), NOT_mr_nik \= mr_nik,
/* 4 */ member([_,NOT_mr_k,tele_pole],Days), NOT_mr_k \= mr_k,
write(Days),
nl,
fail.
% Checks that `X` comes before `Y`
% in the list `Ds`
before(X,Y,Ds) :-
remainder(X,Ds,Rs),
member(Y,Rs).
% Finds a member of a list and
% unifies the third parameter such
% that it is the remaining elements in
% the list after the found member
remainder(X,[X|Ds],Ds).
remainder(X,[_|Ds],Rs) :- remainder(X,Ds,Rs).
% An extended version of `member` that
% checks if the members of the first list
% are all members of the second
members([],_).
members([X|Xs],Ds) :-
member(X,Ds),
members(Xs,Ds).
That gives me:
[[tuesday, ms_g, tele_pole],
[wednesday, mr_nik, kite],
[thursday, mr_k, plane],
[friday, ms_barn, balloon]]

Prolog: simulate disjunctive facts

I've got a logic problem that I'd like to solve, so I thought, "I know, I'll try Prolog!"
Unfortunately, I'm running into a brick wall almost immediately. One of the assumptions involved is a disjunctive fact; either A, B or C is true (or more than one), but I do not know which. I've since learned that this is something Prolog does not support.
There's a lot of documentation out there that seems to address the subject, but most of it seems to immediately involve more intricate concepts and solves more advanced problems. What I'm looking for is an isolated way to simulate defining the above fact (as defining it straight away is, by limitations of Prolog, not possible).
How could I address this? Can I wrap it in a rule somehow?
EDIT: I realise I have not been very clear. Given my lack of familiarity with Prolog, I did not want to get caught up in a syntax error when trying to convey the problem, and instead went with natural language. I guess that did not work out, so I'll give it a shot in pseudo-Prolog anyway.
Intuitively, what I would want to do would be something like this, to declare that either foo(a), foo(b) or foo(c) holds, but I do not know which:
foo(a); foo(b); foo(c).
Then I would expect the following result:
?- foo(a); foo(b); foo(c).
true
Unfortunately, the fact I'm trying to declare (namely foo(x) holds for at least one x \in {a, b, c}) cannot be defined as such. Specifically, it results in No permission to modify static procedure '(;)/2'.
Side-note: after declaring the disjunctive fact, the result of ?- foo(a). would be a bit unclear to me from a logical perspective; it is clearly not true, but false does not cover it either -- Prolog simply does not have sufficient information to answer that query in this case.
EDIT 2: Here's more context to make it more of a real-world scenario, as I might have over-simplified and lost details in translation.
Say there are three people involved. Alice, Bob and Charlie. Bob holds two cards out of the set {1, 2, 3, 4}. Alice asks him questions, in response to which he shows her one card that Charlie does not see, or shows no cards. In case more cards are applicable, Bob shows just one of them. Charlie's task is to learn what cards Bob is holding. As one might expect, Charlie is an automated system.
Alice asks Bob "Do you have a 1 or a 2?", in response to which Bob shows Alice a card. Charlie now learns that Bob owns a 1 or a 2.
Alice then asks "Do you have a 2 or a 3", to which Bob has no cards to show. Clearly, Bob had a 1, which he showed Alice previously. Charlie should now be able to derive this, based on these two facts.
What I'm trying to model is the knowledge that Bob owns a 1 or a 2 (own(Bob, 1) \/ own(Bob, 2)), and that Bob does not own a 2 or a 3 (not (own(Bob, 2) \/ own(Bob, 3))). Querying if Bob owns a 1 should now be true; Charlie can derive this.
The straight-forward answer to your question:
if you can model your problem with constraint logic programming over finite domains, then, an "exclusive or" can be implemented using #\ as follows:
Of the three variables X, Y, Z, exactly one can be in the domain 1..3.
D = 1..3, X in D #\ Y in D #\ Z in D
To generalize this, you can write:
disj(D, V, V in D #\ Rest, Rest).
vars_domain_disj([V|Vs], D, Disj) :-
foldl(disj(D), Vs, Disj, V in D #\ Disj).
and use it as:
?- vars_domain_disj([X,Y,Z], 2 \/ 4 \/ 42, D).
D = (Y in 2\/4\/42#\ (Z in 2\/4\/42#\ (X in 2\/4\/42#\D))).
If you don't use CLP(FD), for example you can't find a nice mapping between your problem and integers, you can do something else. Say your variables are in a list List, and any of them, but exactly one, can be foo, and the rest cannot be foo, you can say:
?- select(foo, [A,B,C], Rest), maplist(dif(foo), Rest).
A = foo,
Rest = [B, C],
dif(B, foo),
dif(C, foo) ;
B = foo,
Rest = [A, C],
dif(A, foo),
dif(C, foo) ;
C = foo,
Rest = [A, B],
dif(A, foo),
dif(B, foo) ;
false.
The query reads: in the list [A,B,C], one of the variables can be foo, then the rest must be different from foo. You can see the three possible solutions to that query.
Original answer
It is, sadly, often claimed that Prolog does not support one thing or another; usually, this is not true.
Your question is not exactly clear at the moment, but say you mean that, with this program:
foo(a).
foo(b).
foo(c).
You get the following answer to the query:
?- foo(X).
X = a ;
X = b ;
X = c.
Which you probably interpreted as:
foo(a) is true, and foo(b) is true, and foo(c) is true.
But, if I understand your question, you want a rule which says, for example:
exactly one of foo(a), foo(b), and foo(c) can be true.
However, depending on the context, that it, the rest of your program and your query, the original solution can mean exactly that!
But you really need to be more specific in your question, because the solution will depend on it.
Edit after edited question
Here is a solution to that particular problem using constraint programming over finite domains with the great library(clpfd) by Markus Triska, available in SWI-Prolog.
Here is the full code:
:- use_module(library(clpfd)).
cards(Domain, Holds, QAs) :-
all_distinct(Holds),
Holds ins Domain,
maplist(qa_constraint(Holds), QAs).
qa_constraint(Vs, D-no) :-
maplist(not_in(D), Vs).
qa_constraint([V|Vs], D-yes) :-
foldl(disj(D), Vs, Disj, V in D #\ Disj).
not_in(D, V) :- #\ V in D.
disj(D, V, V in D #\ Rest, Rest).
And two example queries:
?- cards(1..4, [X,Y], [1 \/ 2 - yes, 2 \/ 3 - no]), X #= 1.
X = 1,
Y = 4 ;
false.
If the set of cards is {1,2,3,4}, and Bob is holding two cards, and when Alice asked "do you have 1 or 2" he said "yes", and when she asked "do you have 2 or 3" he said no, then: can Charlie know if Bob is holding a 1?
To which the answer is:
Yes, and if Bob is holding a 1, the other card is 4; there are no further possible solutions.
Or:
?- cards(1..4, [X,Y], [1 \/ 2 - yes, 2 \/ 3 - no]), X #= 3.
false.
Same as above, can Charlie know if Bob is holding a 3?
Charlie knows for sure that Bob is not holding a three!
What does it all mean?
:- use_module(library(clpfd)).
Makes the library available.
cards(Domain, Holds, QAs) :-
all_distinct(Holds),
Holds ins Domain,
maplist(qa_constraint(Holds), QAs).
This defines the rule we can query from the top level. The first argument must be a valid domain: in your case, it will be 1..4 that states that cards are in the set {1,2,3,4}. The second argument is a list of variables, each representing one of the cards that Bob is holding. The last is a list of "questions" and "answers", each in the format Domain-Answer, so that 1\/2-yes means "To the question, do you hold 1 or 2, the answer is 'yes'".
Then, we say that all cards that Bob holds are distinct, and each of them is one of the set, and then we map each of the question-answer pairs to the cards.
qa_constraint(Vs, D-no) :-
maplist(not_in(D), Vs).
qa_constraint([V|Vs], D-yes) :-
foldl(disj(D), Vs, Disj, V in D #\ Disj).
The "no" answer is easy: just say that for each of the cards Bob is holding, it is not in the provided domain: #\ V in D.
not_in(D, V) :- #\ V in D.
The "yes" answer means that we need an exclusive or for all cards Bob is holding; 2\/3-yes should result in "Either the first card is 2 or 3, or the second card is 2 or 3, but not both!"
disj(D, V, V in D #\ Rest, Rest).
To understand the last one, try:
?- foldl(disj(2\/3), [A,B], Rest, C in 2\/3 #\ Rest).
Rest = (A in 2\/3#\ (B in 2\/3#\ (C in 2\/3#\Rest))).
A generate-and-test solution in vanilla Prolog:
card(1). card(2). card(3). card(4).
owns(bob, oneof, [1,2]). % i.e., at least one of
owns(bob, not, 2).
owns(bob, not, 3).
hand(bob, Hand) :-
% bob has two distinct cards:
card(X), card(Y), X < Y, Hand = [X, Y],
% if there is a "oneof" constraint, check it:
(owns(bob, oneof, S) -> (member(A,S), member(A, Hand)) ; true),
% check all the "not" constraints:
((owns(bob, not, Card), member(Card,Hand)) -> false; true).
Transcript using the above:
$ swipl
['disjunctions.pl'].
% disjunctions.pl compiled 0.00 sec, 9 clauses
true.
?- hand(bob,Hand).
Hand = [1, 4] ;
;
false.
Note that Prolog is Turing complete, so generally speaking, when someone says "it can't be done in Prolog" they usually mean something like "it involves some extra work".
Just for the sake of it, here is a small program:
card(1). card(2). card(3). card(4). % and so on
holds_some_of([1,2]). % and so on
holds_none_of([2,3]). % and so on
holds_card(C) :-
card(C),
holds_none_of(Ns),
\+ member(C, Ns).
I have omitted who owns what and such. I have not normalized holds_some_of/1 and holds_none_of/1 on purpose.
This is actually enough for the following queries:
?- holds_card(X).
X = 1 ;
X = 4.
?- holds_card(1).
true.
?- holds_card(2).
false.
?- holds_card(3).
false.
?- holds_card(4).
true.
which comes to show that you don't even need the knowledge that Bob is holding 1 or 2. By the way, while trying to code this, I noticed the following ambiguity, from the original problem statement:
Alice asks Bob "Do you have a 1 or a 2?", in response to which Bob shows Alice a card. Charlie now learns that Bob owns a 1 or a 2.
Does that now mean that Bob has exactly one of 1 and 2, or that he could be holding either one or both of the cards?
PS
The small program above can actually be reduced to the following query:
?- member(C, [1,2,3,4]), \+ member(C, [2,3]).
C = 1 ;
C = 4.
(Eep, I just realized this is 6 years old, but maybe it's interesting to introduce logic-programming languages with probabilistic choices for the next stumbler )
I would say the accepted answer is the most correct, but if one is interested in probabilities, a PLP language such as problog might be interesting:
This example assumes we don't know how many cards bob holds. It can be modified for a fixed number of cards without much difficulty.
card(C):- between(1,5,C). % wlog: A world with 5 cards
% Assumption: We don't know how many cards bob owns. Adapting to a fixed number of cards isn't hard either
0.5::own(bob, C):-
card(C).
pos :- (own(bob,1); own(bob,2)).
neg :- (own(bob,2); own(bob,3)).
evidence(pos). % tells problog pos is true.
evidence(\+neg). % tells problog neg is not true.
query(own(bob,Z)).
Try it online: https://dtai.cs.kuleuven.be/problog/editor.html#task=prob&hash=5f28ffe6d59cae0421bb58bc892a5eb1
Although the semantics of problog are a bit harder to pick-up than prolog, I find this approach an interesting way of expressing the problem. The computation is also harder, but that's not necessarily something the user has to worry about.

Prolog Loops until True

I'm pretty new to Prolog but I'm trying to get this program to give me the first set of twin primes that appears either at or above N.
twins(M) :-
M2 is M + 2,
twin_prime(M, M2),
write(M),
write(' '),
write(M2).
M3 is M + 1,
twins(M3).
However, I'm not completely sure how to go about getting it to loop and repeat until it's true. I've tried using the repeat/0 predicate but I just get stuck in an infinite loop. Does anyone have any tips I could try? I'm pretty new to Prolog.
You're on the right track using tail recursion and #Jake Mitchell's solution works swell. But here are some tips that might help clarify a few basic concepts in Prolog:
First, it seems like your predicate twins/1 is actually defining a relationship between 2 numbers, namely, the two twin primes. Since Prolog is great for writing very clear, declarative, relational programs, you might make the predicate more precise and explicit by making it twin_primes/2. (That this should be a binary predicate is also pretty clear from your name for the predicate, since one thing cannot be twins...)
One nice bonus of explicitly working with a binary predicate when describing binary relations is that we no longer have to fuss with IO operations to display our results. We'll simply be able to query twin_primes(X,Y) and have the results returned as Prolog reports back on viable values of X and Y.
Second, and more importantly, your current definition of twins/1 wants to describe a disjunction: "twins(M) is true if M and M + 2 are both prime or if M3 is M + 3 and twins(M3) is true". The basic way of expressing disjunctions like this is by writing multiple clauses. A single clause of the form <Head> :- <Body> declares that the Head is true if all the statements composing the Body are true. Several clauses with the same head, like <Head> :- <Body1>. <Head> :- <Body2>. ..., declare that Head is true if Body1 is true or if Body2 is true. (Note that a series of clauses defining rules for a predicate are evaluated sequentially, from top to bottom. This is pretty important, since it introduces non-declarative elements into the foundations of our programs, and it can be exploited to achieve certain results.)
In fact, you are only a small step from declaring a second rule for twins/1. You just tried putting both clause-bodies under the same head instance. Prolog requires the redundant measure of declaring two different rules in cases like this. Your code should be fine (assuming your definition of twin_prime/2 works), if you just change it like so:
twins(M) :-
M2 is M + 2,
twin_prime(M, M2),
write(M),
write(' '),
write(M2).
twins(M) :-
\+twin_prime(M, M2), %% `\+` means "not"
M3 is M + 1,
twins(M3).
Note that if you take advantage of Prolog's back-tracking, you often don't actually need to effect loops through tail recursion. For example, here's an alternative approach, taking into account some of what I advised previously and using a quick (but not as in "efficient" or "fast") and dirty predicate for generating primes:
prime(2).
prime(P) :-
between(2,inf,P),
N is (P // 2 + 1),
forall(between(2,N,Divisor), \+(0 is P mod Divisor)).
twin_primes(P1, P2) :-
prime(P1),
P2 is P1 + 2,
prime(P2).
twin_primes/2 gets a prime number from prime/1, then calculates P2 and checks if it is prime. Since prime/1 will generate an infinite number of primes on backtracking, twin_primes/2 will just keep asking it for numbers until it finds a satisfactory solution. Note that, if called with two free variables, this twin_primes/2 will generate twin primes:
?- twin_primes(P1, P2).
P1 = 3,
P2 = 5 ;
P1 = 5,
P2 = 7 ;
P1 = 11,
P2 = 13 ;
P1 = 17,
P2 = 19 ;
P1 = 29,
P2 = 31 ;
But it will also verify if two numbers are twin primes if queried with specific values, or give you the twin of a prime, if it exists, if you give a value for P1 but leave P2 free:
?- twin_primes(3,Y). Y = 5.
There's a handy if-then-else operator that works well for this.
twin_prime(3,5).
twin_prime(5,7).
twin_prime(11,13).
next_twin(N) :-
A is N+1,
B is N+2,
(twin_prime(N,B) ->
write(N),
write(' '),
write(B)
;
next_twin(A)).
And a quick test:
?- next_twin(5).
5 7
true.
?- next_twin(6).
11 13
true.

Resources