I'm new to prolog.
The idea of my project is to say "The room X is free if none is a guest of X, while X is taken if a family lives in X".
I use a predicate
guest(FamilySurname,RoomTaken)
So this mean that a family has taken that room.
taken(X) :- guest(_,X).
So if a family lives in room X, then X is taken.
My problem is how could i say that the room X is free? I should use a kind of NOT, like:
free(X) :- "NOT EXIST" guest(_,X).
How could i translate that "NOT EXIST" in prolog?
I have tried with ! but it doesn't work properly... maybe I'm placing it in the wrong way.
Sorry for my english.
Check the following code:
taken(X, Y) :- guest(Y,X).
free(X) :- \+ guest(_,X).
I made the a little change to taken, now it shows you who is on that room.
guest(albert, 123).
?- taken(123, R).
R = albert.
And the free() predicate it's pretty straightforward, I used the negation operator, you can check How to negate in Prolog
The code in the first answer does not seem to be a solution, i.e. the query ?- free(X) will not give an answer, where as the query ?- free(foo) will be successful. One needs to consider query floundering in Prolog into account, i.e. all variables
Consider the following code in which two alternatives for presenting the free predicate.
room(123).
room(124).
guest(albert, 123).
taken(Room) :- guest(_, Room).
free2(Room) :- room(Room),
\+ taken(Room).
free(Room) :- room(Room),
forall(guest(_, RoomTaken),
RoomTaken \= Room).
Firstly, I'm not a prolog programmer. I'm doing an assignment for school where we build a small expert system. I've chosen to use prolog for the assignment and I'm following this book: http://www.amzi.com/distribution/files/xsip_book.pdf. Specifically I'm looking at chapter 2.
There is a procedure in this book that I would like to use called "ask." It can be found on page 14. Ask, uses another procedure called "known" to remember the answers to questions. I have basically copied this procedure for use in my code, but I am getting an existence error related to the "known" procedure. Not being a prolog programmer, I don't know how to debug it. Hopefully someone can help.
Here is a sample run of my code:
| ?- species(X).
uncaught exception: error(existence_error(procedure,known/3),ask/2)
Here is the code:
species(limba) :- %There are a bunch of these
distribution(west_africa),
color(tan_with_black_streaks),
figure(plain),
janka_hardness(670),
workability(easy).
distribution(X) :- ask(distribution, X).
color(X) :- ask(color, X).
figure(X) :- ask(figure, X).
janka_hardness(X) :- ask(janka_hardness, X).
workability(X) :- ask(workability, X).
ask(A, V) :-
known(yes, A, V),
!.
ask(A, V) :-
known(_, A, V),
!,
fail.
ask(A, V) :-
write(A:V),
write('? : '),
read(Y),
asserta(known(Y, A, V)),
Y == yes.
This program expects known/3 to be dynamic (and the book you pointed to says this). That is, it's created and managed at run time. The Prolog documentation tells you how to declare a dynamic predicate. You might want to read through it. – lurker
I'm trying to make it so predsort wont delete any duplicate objects that I have, and I think I know the logic in it but I can't seem to get it to work. I've been trying to call previous predicates that sort by another item when a duplicate is found but im getting errors when I try this.
process(3, X) :-
nl,
sort(X, Q),
show_records(Q),
nl, nl, menu(Q).
process(4, X) :-
nl,
predsort(sortName,X,Q),
show_records(Q),
nl, nl, menu(Q).
sortName(T, [_,E,_], [_,R,_]) :-
(compare(T, E, R)
->process(3, X)
).
process(5, X) :-
nl,
predsort(sortGrade,X,Q),
show_records(Q),
nl, nl, menu(Q).
sortGrade(T, [_,_,E], [_,_,R]) :-
(compare(T, E, R)
->process(4,X)
).
Process 3 sorts by the first value in the sublist, 4 the second one, and 5 the last. I'm trying to make it where when 5 finds a duplicate it'll go to 4, and from 4 to three if need be.
I will answer anyway, even if you spotted you're own solution, since it's not clear to me if ditto solution matches with mine.
What I mean: time ago I wrote my own predmsort/3 (predating in obvious mode the terminoloy of sort/msort) for exactly the same reason you have reported.
Time passed before I realized that there was a much better solution to my problem:
just never return =.
That is, so simple...
Learning some basic prolog and am having difficulty wrapping my head around the logic.
Scenario: An individual contracts viral meningitis and happens to interact with various other individuals. This is my prolog logic so far.
%-- Set a sickness condition.
%-- -------------------------------------------------------- --%
setILL(X) :- write(X), write(' is ill'), nl.
%-- Link some interactions between individuals.
%-- -------------------------------------------------------- --%
interact(ella, james).
interact(ella, tyrone).
interact(james, ben).
interact(james, frank).
interact(james, carl).
interact(carl, james).
interact(carl, evan).
interact(evan, mike).
interact(evan, kelly).
interact(mike, frank).
interact(kelly, carl).
interact(kelly, frank).
interact(kelly, ben).
interact(sven, mike).
%-- Create an interaction condition.
%-- -------------------------------------------------------- --%
came_in_contact(X, Y) :- setILL(X), write(X), write(' has had contact with '), write(Y), X\=Y, !, nl.
%-- Create a rule for sickness
%-- -------------------------------------------------------- --%
sick(X) :- interact(X, Y), contact(X, Y), Y\=X.
whosick(R) :- findall([X], sick(X), R).
Now the interactions are what they are supposed to be and there should be two paths each start with ella (whom is originally sick) and ends with sven (the supposed last individual to be sick). I simply wish to print out the two possible paths without including useless interactions. E.g. tyrone will talk to no one else and neither will ben. I also wish to remove repeasts (see below).
When I execute
whosick(X).
I get
ella is ill
ella has had contact with james
ella is ill
ella has had contact with tyrone
james is ill
james has had contact with ben
james is ill
james has had contact with frank
james is ill
james has had contact with carl
carl is ill
carl has had contact with james
carl is ill
carl has had contact with evan
evan is ill
evan has had contact with mike
evan is ill
evan has had contact with kelly
mike is ill
mike has had contact with frank
kelly is ill
kelly has had contact with carl
kelly is ill
kelly has had contact with frank
kelly is ill
kelly has had contact with ben
sven is ill
sven has had contact with mike
X = [[ella], [ella], [james], [james], [james], [carl], [carl], [evan], [...]|...].
First of all, there's a typo in the code you provided: came_in_contact should be contact or it won't run. Minor issue.
Second issue: I'm not sure what you mean by this: findall([X], sick(X), R). There's no especial reason to use [X] here instead of just X, and the results look a little nicer with this change:
X = [ella, ella, james, james, james, carl, carl|...].
An issue with more significance is that, stylistically, setill is 100% side-effects despite the stateful-sounding name. setill doesn't "set" anyone "ill," it just prints to standard output that someone is ill. It is, you might say, part of the "view" if this were MVC. And so part of the problem you're having is that you're calling this "view" code from deep within the "model," in sick/2.
You mention parenthetically that Ella is the origin of the outbreak, but there's no fact in your Prolog database, so Prolog is certainly not aware of it. Additionally, you seem to be interested in the "path" that infection took, but your Prolog doesn't know anything about a path—in fact, it's really just dumping out your fact database. To prove it, let's add a new fact at the top:
interact(gail, hank).
Sure enough, it's now the first "solution" even though Gail and Hank are isolated from the rest of the graph:
gail is ill
gail has had contact with hank
… (old output repeated)
...
So, you're kind of off in the weeds here. You have an incomplete fact database, your rules don't really capture the logic of the problem and they intersperse logic with printing. By the time we're done here the code is going to look pretty different. I'm not sure whether this is homework or not, it sounds like you're self-studying, but it has kind of a homeworky vibe so I'm going to try and sketch out how I would proceed without putting it all together.
First, you need to make Prolog aware of all the facts it needs to compute the solution. To wit, you have to add a fact about the originator:
infected(ella) :- !.
This is going to become the base case. Now we need to employ inductive reasoning and say, a person is infected if that person has been in contact with an infected person:
infected(X) :- interact(X, Y), X \= Y, infected(Y), !.
Note: these cuts are fairly important. There's no need to compute another solution because a person either is or is not infected. If we succeed on either branch proving they are infected, there's nothing else to say.
Now we can get reasonable solutions for some people:
?- infected(ella).
true.
?- infected(gail).
false.
Other people seem to get no solution:
?- infected(james).
(I typed Ctrl+C)
^CAction (h for help) ? abort
% Execution Aborted
The reason James doesn't arrive at a solution is because Prolog is using a depth-first search. Handily, the next thing you have to do is discover the infection path, so if you can prevent Prolog from trying people who are already in the path, you can solve the problem by getting the path you also need. You're going to have to do employ a similar base case/inductive case structure, but pass along an additional argument for the path of the infection. You can find examples of this kind of thing all over so I won't bore you with the details here.
Do take note of this: we are not going to intermix the logic of the problem with the displaying of results. This is just good policy with Prolog because of backtracking. If you print something out because a binding succeeded here, and in the next term it fails, the whole failure could go back past the printout, leaving a confused user. We can easily trick Prolog into printing out lies from solutions that failed later on. So you always want to write your Prolog so that it finds the solutions and then displays them separately. Think model-view-controller.
So let's assume you have found a predicate, path/3 (presumably path(Source, Last, Path)). When you run it, you're going to get solutions like this:
?- path(ella, X, Path).
X = sven
Path = [ella, james, ...] ;
X = sven
Path = [ella, tyrone, ...] ;
false.
This is the predicate you'll want to wrap with your findall/3, and then you'll want to walk through the results and print out the parts you need path-by-path.
Edit: In response to your comment, let's take a look at your new predicate:
path(_, X, P) :- findall(X, interact(_, X), P).
I'm afraid this isn't any closer than before. Let's see what happens when I ask for the path from myself:
?- path('Daniel Lyons', X, Path).
Path = [james, tyrone, ben, frank, carl, james, evan, mike|...].
In fact you can put absolutely anything in there and you'll get exactly the same result:
?- path('Jack Donaghy', X, Path).
Path = [james, tyrone, ben, frank, carl, james, evan, mike|...].
?- path(3.1415926, X, Path).
Path = [james, tyrone, ben, frank, carl, james, evan, mike|...].
?- path([a,b,c,d,e], X, Path).
Path = [james, tyrone, ben, frank, carl, james, evan, mike|...].
This is because your rule is true for anything in the first position. If you had more clauses this could be meaningful because one of the other clauses could say something about this argument, but lacking that it really does mean anything. So your predicate could just as well be written:
path(X, P) :- findall(X, interact(_, X), P).
Every _ is a completely unique binding; they do not influence each other at all, so if you were hoping for an effect there you'd want something more like this:
path(F, X, P) :- findall(X, interact(F, X), P).
And you see right away that this doesn't help you much:
?- path(ella, X, P).
P = [james, tyrone].
So let's solve the problem already.
person(X) :- interact(X, _) ; interact(_, X).
This is just a helper that returns everybody whether they're on the left or right of the interaction.
path(Originator, Path) :-
setof(X, person(X), People),
path(Originator, Path, People).
This helper gets you a path from a particular person. We are relying on a helper function I'll show in just a second. We prune the possibilities to something reasonable by starting off with the list of all people. That way we can just choose the next person from the list of people we haven't examined yet, and we don't have to worry about cycles or too much recursion.
path(Originator, [], _).
path(Originator, [NextPerson|Rest], Considering) :-
select(NextPerson, Considering, RemainingToConsider),
interact(Originator, NextPerson),
path(NextPerson, Rest, RemainingToConsider).
The first clause says, we can always be done. The path from the originator to nobody is the empty path. This is a base case for our induction.
The second clause says, choose someone from the list of people we have left to consider. That someone interacted with the originator. Now find a path from that person through the people remaining to be considered. (select/3 unifies the third argument with the second argument without the first argument).
Let's look at a run:
?- path(ella, X).
X = [] ;
X = [james] ;
X = [james, ben] ;
X = [james, carl] ;
X = [james, carl, evan] ;
X = [james, carl, evan, kelly] ;
X = [james, carl, evan, kelly, ben] ;
X = [james, carl, evan, kelly, frank] ;
X = [james, carl, evan, mike] ;
X = [james, carl, evan, mike, frank] ;
X = [james, frank] ;
X = [tyrone] ;
false.
Now, in your original question you said something about Ben and Frank and not being interested in the other paths. I still don't see a logical reading that will distinguish between those cases, but you can at least find all the longest paths, like this:
longest_paths(Originator, Path) :-
path(Originator, Path),
\+ (path(Originator, Path2),
length(Path, MaxLen),
length(Path2, NextLen),
NextLen > MaxLen).
This isn't terribly efficient, but what it says is, find me a path Path from Originator, such that there is no other path with a longer length. This finds us three solutions:
?- longest_paths(ella, X).
X = [james, carl, evan, kelly, ben] ;
X = [james, carl, evan, kelly, frank] ;
X = [james, carl, evan, mike, frank] ;
false.
And this is as close as I think I can get you to the solution you want. I hope it helps!
likes(tom,jerry).
likes(mary,john).
likes(mary,mary).
likes(tom,mouse).
likes(jerry,jerry).
likes(jerry,cheese).
likes(mary,fruit).
likes(john,book).
likes(mary,book).
likes(tom,john).
likes(john,X):-likes(X,john), X\=john.
Hi there, above is a very simple prolog file, with some facts and only one rule: John likes anyone who likes him.
But after loading this file and ask Prolog the following query:
likes(john,X).
The program crashes. The reason is somehow prolog gets stuck at likes(john,john) even though the rule states that X\=john.
Any advice?
Ironically, given the site we're on, you're getting a stack overflow.
It does this because of the order of execution that prolog uses, it's going to go into an infinite recursion at likes(X,john) in your rule, it activates the rule again - not a fact - never getting to the X\=john bit.
One way to fix this is to have your rule named differently from your fact like this:
kindoflikes(tom,jerry).
kindoflikes(mary,john).
kindoflikes(mary,mary).
kindoflikes(tom,mouse).
kindoflikes(jerry,jerry).
kindoflikes(jerry,cheese).
kindoflikes(mary,fruit).
kindoflikes(john,book).
kindoflikes(mary,book).
kindoflikes(tom,john).
likes(Y,X):- kindoflikes(X,Y), X\=Y.
likex(Y,X):- kindoflikes(Y,X), X\=Y.
Note the reversal of X and Y in the kindoflikes in the two rule definitions.
So you get:
?- likes(john,X).
X = mary ;
X = tom ;
X = book.
But you're not locked into finding what john likes, and you can do:
?- likes(jerry,X).
X = tom ;
X = cheese.
Your first question was why your program crashes. I am not sure what kind of Prolog system you are using, but many systems produce a clean "resource error" which can be handled from within Prolog.
Your actual problem is that your program does not terminate for the query likes(john, X). It gives you the expected answers and only then it loops.
?- likes(john,X).
X = book
; X = mary
; X = tom
; resource_error(local_stack). % ERROR: Out of local stack
You have been pretty lucky that you detected that problem so rapidly. Imagine more answers, and it would have not been that evident that you have the patience to go through all answers. But there is a shortcut for that. Ask instead:
?- likes(john, X), false.
This false goal is never true. So it readily prevents any answer. At best, a query with false at the end terminates. Currently this is not the case. The reason for this non-termination is best seen when considering the following failure-slice (look up other answers for more details):
?- likes(john,X), false.
loops.
likes(tom,jerry) :- false.
likes(mary,john) :- false.
likes(mary,mary) :- false.
likes(tom,mouse) :- false.
likes(jerry,jerry) :- false.
likes(jerry,cheese) :- false.
likes(mary,fruit) :- false.
likes(john,book) :- false.
likes(mary,book) :- false.
likes(tom,john) :- false.
likes(john,X) :-
likes(X,john), false,
X\=john.
So it is this tiny little part of your program that is responsible for the stack overflow. To fix the problem we have to do something in that tiny little part. Here is one: add a goal dif(X, john) such that the rule now reads:
likes(john,X) :-
dif(X, john),
likes(X,john).
dif/2 is available in many Prolog systems like: SICStus, SWI, YAP, B, IF.