I have several Prolog facts indicating that something or someone is either a person, location or object. I have a clause go(person,location) that indicated that a person moves from where they are to the location given in the clause. However, when I ask the relevant query to find out if someone is at a certain location, Prolog responds with every person that was ever there according to the clauses. How do I go about writing a rule that says that if you are in one location you are by definition not in any of the others?
It appears that you left one important aspect out when modeling the situation as Prolog facts: When did the person go to the location?
Assume you had instead facts of the form:
person_went_to_at(Person, Location, Time).
then it would be pretty easy to determine, for any point in time, where everyone was, and where they moved to last (and, therefore, are now).
You probably need to add timing information to your facts. Imagine the following situtation:
go(dad, kitchen, bathroom).
go(dad, bathroom, garage).
go(dad, garage, kitchen).
Since Prolog is (more or less) declarative, in this case, the actual order of the facts in the file does not matter. So, you cannot conclude that dad is in the kitchen, he might have started from and returned to the garage. Even if you add some kind of starting predicate, say startLoc(dad, kitchen), this does not help with loops (e.g. when you add go(dad, kitchen, outside) to the above rules).
If you add timing information (and leave out the previous room, as this is clear from the timing information), this becomes:
go(dad, bathroom,1).
go(dad, garage,2).
go(dad, kitchen,3).
The actual numbers are not relevant, just their order. You can now get the latest location by ensuring that there is no later "go" command with dad:
location(X, Y) :- go(X, Y, T), \+ ( go(X, _, T2), T2 > T ).
Related
I am learning Prolog via http://www.learnprolognow.org and I am having some trouble understanding how to recursively build up a variable with results from another recursive call, as per Practical Session 3.4, question 3. The initial problem is a straight-forward recursive call to determine if a route is feasible. But the follow-on problem asks you to show the actual path to get to the end of the route.
We are given the following knowledge base of travel information:
byCar(auckland,hamilton).
byCar(hamilton,raglan).
byCar(valmont,saarbruecken).
byCar(valmont,metz).
byTrain(metz,frankfurt).
byTrain(saarbruecken,frankfurt).
byTrain(metz,paris).
byTrain(saarbruecken,paris).
byPlane(frankfurt,bangkok).
byPlane(frankfurt,singapore).
byPlane(paris,losAngeles).
byPlane(bangkok,auckland).
byPlane(singapore,auckland).
byPlane(losAngeles,auckland).
Write a predicate travel/2 which determines whether it is possible to
travel from one place to another by chaining together car, train, and
plane journeys. For example, your program should answer yes to the
query travel(valmont,raglan).
I solved this problem with the following code:
travel(From,To) :-
byCar(From,To).
travel(From,To) :-
byTrain(From,To).
travel(From,To) :-
byPlane(From,To).
travel(From,To) :-
byCar(From,NewTo),
travel(NewTo,To).
travel(From,To) :-
byTrain(From,NewTo),
travel(NewTo,To).
travel(From,To) :-
byPlane(From,NewTo),
travel(NewTo,To).
The follow-on problem is:
So, by using travel/2 to query the above database, you can find out
that it is possible to go from Valmont to Raglan. If you are planning
such a voyage, that’s already something useful to know, but you would
probably prefer to have the precise route from Valmont to Raglan.
Write a predicate travel/3 which tells you which route to take when
travelling from one place to another. For example, the program should
respond
X = go(valmont,metz,go(metz,paris,go(paris,losAngeles)))
to the query travel(valmont,losAngeles,X)
I have been struggling to populate X with a series of go(From,To) that show the successive steps of the journey. It looks like a recursive problem but I do not know how one should go about tackling it. This technique seems fundamental to Prolog programming, and I am quite interested in the thinking process to solve this problem and I look forward to any insight you can provide.
I had a go at this. I made one change to your first solution, just to remove some redundancy. I used the predicate connected/2 to generalize the relationship common to all connections appearing in the by_car/2, by_train/2, and by_plane/2 facts:
connected(From, To) :- by_car(From, To).
connected(From, To) :- by_train(From, To).
connected(From, To) :- by_plane(From, To).
Then I defined travel/2 as a recursive relationship over connected/2:
travel(From, To) :-
connected(From, To).
travel(From, To) :-
connected(From, Through),
travel(Through, To).
Turning to travel/3, notice that the final connection in the nested go... terms is a structure go/2, but the rest are go/3s. So we need to populate X with a series of nested go/3 structures that terminate in a go/2. This last is our base condition. Then it is simply a matter of repeating the second clause of travel/2, but including a go/3 in the third argument that will capture the values instantiated to From and Through on each iteration:
travel(From, To, go(From, To)) :-
connected(From, To).
travel(From, To, go(From, Through, Route)) :-
connected(From, Through),
travel(Through, To, Route).
I'm a beginner at prolog and I'm trying to make pacman move by itself using netlogo and prolog. So this is part of my code:
walkfront(_,_,_,_,_,_,Pacman,DirP,Lab,Ghost,_,Pellet,_,_,Decision) :-
findall(Dir,
( member(Dir,[0,90,180,270]),
\+ ( member((G,false),Ghost), dangerous(Pacman,G,2,Dir,_) ) ),
L),
findall(Dir,(member(Dir,[0,90,180,270]),(member(P,Pellet))),T),
chooseNotDangerous(L,Pacman,DirP,Lab,Dir,T)
walkfront(_,_,_,_,_,_,Pacman,DirP,Lab,Ghost,_,Pellet,_,_,Decision) this line has all the lists of information I'm getting from netlogo, Pacman has the position of pacman (x,y), DirP is the direction pacman is facing, Lab is the free spaces in the maze, Ghost is the position of the ghosts (x,y,eaten?), Pellet is a list of all the positions of the pellets (x,y), Decision is the output choosen by pacman.
The first findall is supposed to give me all the directions (Dir) that don't have ghosts and that aren't dangerous and save them in a list called L.
The second findall, I wanted it to give me all the directions that have pellets and save them in a list called T.
My question is if this findall's are correct because my code isn't working for some reason and I think it might be beacause of the second findall.
Thank you for helping me :).
Technically, findall/3 never fails, as it will complete with an empty result list if none of the calls succeed (well, exceptions apart, if your Prolog implements them).
Of course, it's impossible to answer your question, without all the code. And probably, even with all the code available, you will get little - if any - help, because the structure of your program seems more complex than what could be advisable.
Prolog is a language with a relational data model, and such data model is better employed when it's possible to keep the relations clean, best if normalized. Now you have a predicate with 16 arguments. How are you going to ensure all of them play correctly together ?
I would say - not change now the structure of your program, if you succeed debugging it ok. But the next program - if any - use another style, and the facilities that your Prolog offers to implement data hiding.
Plain old Prolog 'only' had compound terms: you code should likely be
packman(CurrPackManState, CurrGhostsState, NextPackManState, NextGhostsState) :-
...
where CurrGhostsState should be a list of CurrGhostState, and each element of this list should unify with an appropriate structure, hiding information about position, color, shape, etc...
SWI-Prolog now has dicts, and any Prolog will let you use DCGs to reduce the complexity of the code. See this page from Markus Triska, look for 'Implicitly passing states around'.
Also, you can always choice to put some less frequently updated info - like for instance the maze structure - in global database, with assert/retract.
Clue
Four guests (Colonel Mustard, Professor Plum, Miss Scarlett, Ms. Green) attend a dinner party at the home of Mr. Boddy. Suddenly, the lights go out! When they come back, Mr Boddy lies dead in the middle of the table. Everyone is a suspect. Upon further examination, the following facts come to light:
Mr Boddy was having an affair with Ms. Green.
Professor Plum is married to Ms. Green.
Mr. Boddy was very rich.
Colonel Mustard is very greedy.
Miss Scarlett was also having an affair with Mr. Boddy.
There are two possible motives for the murder:
Hatred: Someone hates someone else if that other person is having an affair with his/her spouse.
Greed: Someone is willing to commit murder if they are greedy and not rich, and the victim is rich.
Part A: Write the above facts and rules in your Prolog program. Use the following names for the people: colMustard, profPlum, missScarlet, msGreen, mrBoddy. Be careful about how you encode (or don’t encode) symmetric relationships like marriage - you don’t want infinite loops! married(X,Y) :- married(Y,X) % INFINITE LOOP
?-suspect(Killer,mrBoddy)
Killer = suspect_name_1
Killer = suspect_name_2
etc.
Part B: Write a predicate, suspect/2, that determines who the suspects may be, i.e. who had a motive.
?-suspect(Killer,mrBoddy)
Killer = unique_suspect.
Part C: Add a single factto your database that will result in there being a unique suspect.
Clearly indicate this line in your source comments so that it can be removed/added for
grading.
?-suspect(Killer,mrBoddy)
Killer = unique_suspect.
Whenever I type in
suspect(Killer,mrBoddy).
I get
suspect(Killer,mrBoddy).
Killer = profPlum
I'm missing
Killer = colMustard.
Here's my source.
%8) Clue
%facts
affair(mrBoddy,msGreen).
affair(missScarlett, mrBoddy).
affair(X,Y) :- affair(X,Y), affair(Y,X).
married(profPlum, msGreen).
married(X,Y) :- married(X,Y), married(Y,X).
rich(mrBoddy).
greedy(colMustard).
%rules
hate(X,Y) :- married(X,Spouse), affair(Y,Spouse).
greed(X,Y) :- greedy(X), not(rich(X)), rich(Y).
%suspect
suspect(X,Y):- hate(X,Y).
suspect(X,Y):- greed(X,Y).
There are two kinds of problems with your program. One is on the procedural level: you observed that Prolog loops; the other is on the logical level — Prolog people call this rather the declarative level. Since the first annoying thing is this endless loop, let's first narrow that down. Actually we get:
?- suspect(Killer,mrBoddy).
Killer = profPlum ;
ERROR: Out of local stack
You have now several options to narrow down this problem. Either, go with the other answer and call up a tracer. While the tracer might show you the actual culprit it might very well intersperse it with many irrelevant steps. So many that your mind will overflow.
The other option is to manually modify your program by adding goals false into your program. I will add as many false goals as I can while still getting a loop. The big advantage is that this way you will see in your source the actual culprit (or to be more precise one of potentially many such culprits).1 After trying a bit, this is what I got as failure-slice:
?- suspect(Killer,mrBoddy), false.
married(profPlum, msGreen) :- false.
married(X,Y) :- married(X,Y), false, married(Y,X).
hate(X,Y) :- married(X,Spouse), false, affair(Y,Spouse).
suspect(X,Y):- hate(X,Y), false.
suspect(X,Y):- false, greed(X,Y).
All remaining parts of your program were irrelevant, that is, they are no longer used. So essentially the rule
married(X,Y) :- married(X,Y), married(Y,X).
is the culprit.
Now, for the declarative part of it. What does this rule mean anyway? To understand it, I will interpret :- as an implication. So provided what is written on the right-hand side is true, we conclude what is written on the left-hand side. In this case:
Provided X is married to Y and Y is married to X
we can conclude that
X is married to Y.
This conclusion concluded what we have assumed to be true anyway. So it does not define anything new, logically. You can just remove the rule to get same results — declaratively. So married(profPlum, msGreen) holds but married(msGreen, profPlum) does not. In other words, your rules are not correct, as you claim.
To resolve this problem, remove the rule, rename all facts to husband_wife/2 and add the definition
married(M,F) :- husband_wife(M,F).
married(F,M) :- husband_wife(M,F).
So the actual deeper problem here was a logical error. In addition to that Prolog's proof mechanism is very simplistic, turning this into a loop. But that is not much more than a welcome excuse to the original logical problem.2
Footnotes:1 This method only works for pure, monotonic fragments. Non-monotonic constructs like not/1 or (\+)/1 must not appear in the fragment.
2 This example is of interest to #larsmans.
The problem is the recursive rules of the predicates affair/2 and married/2. Attempting to use them easily leads to an endless loop (i.e. until the stack memory is exhausted). You must use a different predicate in each case to represent that if X is having an affair with Y, then Y is having an affair with X. You also need to change your definition of the suspect/2 predicate to call those new predicates.
To better understand why you get an endless loop, use the trace facilities of your Prolog system. Try:
?- trace, suspect(Killer, mrBoddy).
and go step by step.
I am learning about Prolog recently and I came up with a question.
How do I say:
Any Employee drives, walks, rides or flies to work in Prolog clauses?
"Any" is where I am having problem with.
Here is my thought process.
Employee(tom). %tom is an employee (fact)
drives(X) :- Employee(X).
walks(X) :- Employee(X).
rides(X) :- Employee(X).
flies(X) :- Employee(X).
Is this a correct approach?
I think it's the other way around:
employee(X):- drives(X).
employee(X):- walks(X).
employee(X):- rides(X).
employee(X):- flies(X).
Plus facts for drives, walks, etc.
Whichever employee it is, one of these must hold. If it doesn't, then employee(X) fails.
This is, then, what it means under this Prolog database, that "any employee either flies, rides, etc.".
What you've written means, that given an X such that employee(X) holds, each of drives(X), walks(X), etc., will hold as well. I.e. "any employee walks, and drives, and rides, and flies" to work. (and of course, predicates must start with a lower case letter, always).
I'm running my first few programs in Prolog and have hit a snag in the kind of experiment I'm trying to run. Initially I was doing it on a mini-map of a few US states but I simplified it to an alphabet:
adj(a,b).
adj(b,a).
adj(b,c).
adj(c,b).
adj(c,d).
na(X, Z) :- \+adj(X, Z).
When I query for na(a, What). I don't get any responses (just a no) but if I individually check na(a,d) it, of course, naturally returns yes.
What's the explanation behind why this would happen? I've been able to get other queries to work in different programs so I'm wondering what key information I'm missing. Thanks!
Think of (\+)/1 not as logical negation, but as "not provable". \+ na(a, What) succeeds if and only if na(a, What) is not provable. Since na(a, What) yields at least one solution and is thus provable, its negation (in this sense) fails. (\+)/1 is thus logically incomplete: It fails in this case although, as you observed, there are ground values that would make it succeed. However, (\+/1) works like you expect from logical negation if its argument is ground. You can therefore solve it for example with
na(X, Y) :- country(X), country(Y), \+ adj(X, Y).
where country/1 yields ground instances of countries. Another way to solve it is to explicitly enumerate countries that are not adjacent, which is possible since the domain is finite. An advantage of this approach is that your queries are then monotonic: Adding new facts will never make a query that previously succeeded fail (this does not hold when using (\+)/1 as above). This is a nice property for declarative debugging.