Unbroken loops loops - prolog

Hi I have this problem that I can not solve.
I am a Prolog rookie and I've seen a ton of these family tree examples but none seem to address my problem.
Say I have
son(X, Y) :-
\+daughter(X, Y),
father(Y, X).
father(Y, X) :-
male(X),
son(X, Y).
and I call one of them, it will go back and forth between the conditions because each one would satisfy the one before, therefore resulting in a local stack error.
Most seem to recommend removing one of the definitions, but I need to answer father and son queries. Please, help, this seems so simple, but I just can not figure it out. How can I break after looping once?
TIA

You could:
1) you could use a wrapper predicate:
father(Y,X):-
male(X),
son_data(X,Y).
son(X,Y):-
son_data(X,Y).
son(X,Y):-
\+daughter(X, Y),
father(Y, X).
your database should look like
son_data(mike,steph).
....
father(nick,john).
....
(no son/2 entries)
2) use a prolog version that supports tabling (such as XSB) (or implement it; not such a good idea ofc)

Related

Use a rule if a fact doesn't exist in prolog?

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).

PROLOG: Trying to get around predsort deleting duplicate objects

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...

Prolog negation with more solutions

I've got a little problem and don't know where to find a solution. You probably heard of problem of flying birds:
bird(eagle).
bird(penguin).
can_fly(penguin):-!,fail.
can_fly(X):-bird(X).
I tried to modify and use this knowledge for some "love story". Imagine this
maried(a, b).
maried(c, d).
lovers(a, d).
likes(X, Y):-maried(X, Y).
Now I want to say something like "If X is maried with Y, but X is Z's lover, then X doesn't like Y, but likes Z".
I tried this:
likes(X, Y) :- lovers(X, Y).
likes(X, Y) :- maried(X, Y), lovers(X, _),!,fail.
likes(X, Y) :- maried(X, Y).
It works unless I want to evaluate a goal
likes(A, B).
If there is more facts in the database and Prolog finds first cheater, it will stop backtracking and I can't find any other solution. Maybe it will be obvious after, but now I have nothing on my mind..
Thanks in advance (and maybe sorry for my English :))
Already your first example is not too useful. You can ask:
is the eagle a bird?
is the penguin a bird?
can the eagle fly?
can the penguin fly?
but you can't even ask, "which birds can fly?":
?- can_fly(Bird).
false.
If you would want to be able to ask more general question, like, "which birds can fly?", or "which birds cannot fly?", you would need to either explicitly list the flying or non-flying birds. As most birds can fly, let's list explicitly the non-flying birds:
bird(eagle).
bird(penguin).
bird(ostrich).
bird(dodo).
bird(sparrow).
bird(pigeon).
flightless_bird(penguin).
flightless_bird(ostrich).
flightless_bird(dodo).
bird_of_pray(eagle).
extinct(dodo).
extinct(wooly_mammoth).
can_fly(Bird) :-
bird(Bird),
\+ flightless_bird(Bird).
extinct_bird(Bird) :-
bird(Bird),
extinct(Bird).
Note the use of the ISO predicate for negation, \+/1. It is true if the goal cannot be proven. It is much cleaner than the fail-cut combination you are using.
How you organize your knowledge is a totally different question. The example I have given is incomplete and not necessarily the best way to do it. As a general rule, you should try to keep your data in a normalized form, with facts and clauses of facts playing the role of tables and table rows.
Hopefully this answer points in the right direction.
The cut-fail thing is an antipattern that's misleading you. It would be much better to say something in the original like this:
bird(eagle).
bird(penguin).
flightless(penguin).
can_fly(X) :- bird(X), \+ flightless(X).
See #boris's answer for an excellent and much more detailed discussion of this problem.
So, you have this database. I'm going to put names in so that I can comprehend it a little better.
married(bill, hillary).
married(barack, michelle).
lovers(bill, michelle).
Now what you want to say is that married people like each other, unless they're cheating. Well, it would be better to define these terms in Prolog so we can reason with them. Create the language we need to use to define our domain. That's going to look like this:
cheating(Cheater, SpitedSpouse, Lover) :-
married(Cheater, SpitedSpouse),
lovers(Cheater, Lover),
SpitedSpouse \= Lover.
Now it's much easier to define likes/2!
likes(Husband, Wife) :- married(Husband, Wife), \+ cheating(Husband, Wife, _).
likes(Husband, Lover) :- cheating(Husband, _, Lover).
We can even define dislikes properly:
dislikes(SpitedSpouse, Lover) :- cheating(_, SpitedSpouse, Lover).
dislikes(Cheater, Spouse) :- cheating(Cheater, Spouse, _).
Look at what we've learned: what you really have is a marriage relationship between two people, or a cheating relationship between three people, and of your other predicates are just projections of these two fundamental relationships. That's pretty neat, yeah? :) cheating/3 is basically the classic "love triangle." That suggests ways we could evolve the program to be more potent: handling love quadrilaterals, of course! And so forth.
Notice something interesting? This code can't "catch" michelle—isn't she just as culpable as bill? This underscores a bigger problem: the gender/orientation limitation of the predicates. I think it helps to have concrete nouns like these to see the logical relationships, but it's a dangerous shortcut that should be resolved. An easy way to handle the logic would be to create a predicate like this:
spouse(X, Y) :- married(X, Y)
spouse(X, Y) :- married(Y, X).
Of course you then have to do more checks to make sure you don't have the same people repeated, but it's not hard, and then change your variables to be less gender-specific.

Transforming a sentence creates an infinite loop - but how?

I can't figure out where this is going wrong. Please note that I am very new to Prolog and I'm sure I'm missing something - just no idea what that might be. Could anyone help me out please?
Thanks, here is my code:
printSentence([]).
printSentence([W|[]]) :-
write(W),
write('.'),
nl.
printSentence([W|R]) :-
write(W),
write(' '),
printSentence(R).
transform([], Result).
transform([Word|Rest], Result) :-
replace(Word, Replacement),
append(Result, Replacement, NewResult),
transform(Rest, NewResult).
replace(my, your).
replace(i, you).
replace(you, me).
replace(am, are).
replace(Word, Word).
test :-
X = [you, are, my, only, hope],
transform(X, Result),
printSentence(Result).
#Junuxx' answer is one step to the solution ; there is also another problem in your program. But first step back: #Junuxx spotted the problem and fixed it. Nice. But how can you spot such a problem? Actually, you asked »infinite loop – but how?«
What is cool in Prolog is that you can often localize the looping program up to a very tiny fragment of the program. Such a fragment is called a failure-slice. That is: No more eye-sores reading lengthy programs!
Let's get back to your program. If you load it, you will get a message like:
Warning: /usager/SO/paranoid.pl:13:
Singleton variables: [Result]
Which gives you already a hint on something most probably wrong. Alas, this is not your biggest concern for the moment. Your biggest problem is that the goal test loops!
Localizing non-termination
So how can you with low effort realize what is actually looping?
One way would be to fire up a tracer, which will show you step-by-step how Prolog executes this program. However, the tracer will show you a lot of irrelevant detail. Detail, that you do not need to understand when programming in Prolog. Detail, that fills up your mind such that chances are that you will miss the actual problem completely. So unless you want to spend time on screens full with flickering lines, stay away from tracers.
The other way is to add goals false into your program. Remember, your program loops already, so such extra goals will not hurt you much. Why vandalize your program with these false goals that you never wanted to write in the first place? It's because these false goals will help you detect the culprit of non-termination in your program by hiding "irrelevant" parts. This is so, thanks to the following observation:
If a failure-slice (= your vandalized program) does not terminate then the original program does not terminate either.
In a sense, the failure-slice is a reason why your program does not terminate. Or to put it more strongly: As long as you do not change the visible part in a failure-slice ; that is, as long as you are only trying your luck by modifying parts that are not visible in the failure slice, the problem will persist! Guaranteed! That is not the nicest kind of guarantee but it is better than being blind.
Here is what I get as a failure slice. I removed printSentence/1 because it is no longer used in the fragment. And I added the definition of append/3. Some Prologs offer append/3 as a built-in predicate that you cannot modify. In that case use another name, like local_append/3 – just don't forget to replace all occurrences!
append([], Zs, Zs) :- false.
append([X|Xs], Ys, [X|Zs]) :-
append(Xs, Ys, Zs), false.
transform([], Result) :- false.
transform([Word|Rest], Result) :-
replace(Word, Replacement),
append(Result, Replacement, NewResult), false,
transform(Rest, NewResult).
replace(my, your) :- false.
replace(i, you) :- false.
replace(you, me).
replace(am, are) :- false.
replace(Word, Word) :- false.
test :-
X = [you, are, my, only, hope],
transform(X, Result), false,
printSentence(Result).
When I load this failure-slice, I get:
?- test.
ERROR: Out of local stack
Which is a good indication that the program does not terminate. On my finite hardware it exhausts all resources instead. ((To be pedantic, this program might still terminate, it might only need too much resources. But remember: We have this if failure-slice loops, then the entire program loops. In any case, proving non-termination of the failure-slice will often be easier, since the fragment is shorter)).
Some observations: Originally, transform/2 used to be recursive. Now, it no longer is. The only recursion left is within append/3. So I first look at the goal append(Result, Replacement, NewResult) and I try to figure out what the variables might be. The easiest is the 3rd argument: NewResult is the only occurrence in our fragment, we can thus replace it by _. The second argument's variable Replacement will always be me. And the first argument (here I have now to look at test/0) will be an uninstantiated variable. So we have to consider the goal append(_, me, _).
Simply run append(_, me, _), false to see that this goal does not terminate! You can see this also by inspecting the failure-slice. Here is it, again:
append([], Zs, Zs) :- false.
append([X|Xs], Ys, [X|Zs]) :-
append(Xs, Ys, Zs), false.
Look at Ys: Nobody cares about it, it is just "handed over". Only the first and the third argument might guarantee termination!
For more see the tag failure-slice.
Fine print
Certain restrictions apply! Void where prohibited! You can do above reasoning only with a pure, monotonic Prolog program. Actually, some benign side-effects as the ones you have in your program are OK too. As long as they do not affect the control-flow.
The other problem
There is another problem with your program. Run printSentence([you]), false to see it! Backtracking and side-effects do not flock together easily. For a beginner, the best is to avoid side-effects all together. See this question and that answer for an example, how to remove useless side-effects in programming problems.
Why not call transform([you, are, my, only hope], Xs) or maplist(replace,[you, are, my only, hope], Xs) directly? It lets you again concentrate on the relevant parts!
This should work. Notice you had a singleton in transform([],Result). Also, append doesn't work in the way you tried to use it, but you were on the right track generally.
transform([], []).
transform([Word|Rest], [Replacement|RestOfResult]) :-
replace(Word, Replacement),
transform(Rest, RestOfResult).

Prolog — symmetrical predicates

I have to simulate family tree in prolog.
And i have problem of symetrical predicates.
Facts:
parent(x,y).
male(x).
female(y).
age(x, number).
Rules:
blood_relation is giving me headache. this is what i have done:
blood_relation(X,Y) :- ancestor(X,Y).
blood_relation(X,Y) :- uncle(X,Y)
; brother(X,Y)
; sister(X,Y)
; (mother(Z,Y),sister(X,Z))
; (father(Z,Y),sister(X,Z))
; (father(Z,Y),brother(X,Z)).
blood_relation(X,Y) :- uncle(X,Z)
, blood_relation(Z,Y).
and I am getting i think satisfactory results(i have double prints - can i fix this), problem is that i want that this relation be symmetrical. It is not now.
blood_relation(johns_father, john):yes
blood_relation(john,johns_father): no
so..is there a way to fix this.
And i need query: All pairs that are not in blood_relation..
Update:
What kinds of relationships is the first statement supposed to satisfy?
blood_relation(X,Y):-blood_relation(X,Y).
sorry..it is a bad copy/paste..it
blood_relation(X,Y):-ancestor(X,Y).
Now fixed above.
here are other rules:
father(X,Y) :-
parent(X,Y),male(X).
mother(X,Y) :-
parent(X,Y),female(X).
brother(X,Y) :-
parent(Z,X),parent(Z,Y),
male(X).
sister(X,Y) :-
parent(Z,X),parent(Z,Y),
female(X).
grandFather(X,Y) :-
parent(Z,Y),parent(X,Z),
male(X).
grandMother(X,Y) :-
parent(Z,Y),
parent(X,Z),female(X).
uncle(X,Y) :-
mother(Z,Y),brother(X,Z).
ancestor(X,Y) :-
ancestor(X,Y).
ancestor(X,Y) :-
parent(X,Z),ancestor(Z,Y).
Mother's brother is in uncle definition. It's kind of strange. I've got rules that I need to implement, and I don't know how I can implement rules besides that. I'm just confused.
Any idea how to make blood_relation symmetric? And not_blood_relation is a new rule. And I need query. This one is really giving me headache. Maybe because relation is written like crap.
And there are no more facts. That's all. All rules, and all facts.
query.. not(blood_relation(X,Y)) doesn't work, and I really don't know why.
For example query:
age(X,Y), Y>18,
not(parent(X,Z)),write(X),nl,fail.
works just fine
The naive solution to making a particular predicate symmetric isn't that far from a decent one. For the sake of generality, let's look at a friendship relation so people don't get tripped up on uncles and the like.
Here are some facts detailing a friendship relation (where, say, the numbers are user ids and the particular ordering of the arguments came from who initiated the friendship).
friends(1,2).
friends(5,2).
friends(7,4).
You'd initially think a rule like "friends(A,B) :- friends(B,A)." would fix things right up, but this leads you to infinite recursion because it tells prolog that if it just swaps the argument one more time it might just work. There is a predicate called "#</2" that tells you whether one term (even a variable) comes before another in the "standard order of terms". The technical meaning isn't all that important here, but what we care about is that for two different terms it is only true for one ordering of them. We can use this to break the infinite recursion!
This single rule will take care of making "friend/2" symmetric.
friends(A,B) :- A #< B, friends(B,A).
As neat as this is, there is an approach way you should take for large projects. Recall that the ordering of the args in my list of facts had some actual meaning (who initiated the friendship). Adding the final rule destroyed future access to this information and, for other people reading the code, hides the symmetric property in a single line of code which is easy to ignore in the face of a block of hard-coded data.
Condsider the industrial-strength solution:
friended(1,2).
friended(5,2).
friended(7,4).
friends(A,B) :- friended(A,B).
friends(A,B) :- friended(B,A).
It is bulkier, but it reads cleanly without using obscure predicates and retains the original information (which you might want again someday in a real application).
--
As for finding pairs that don't have a specific property, make sure you always include some predicate to provide context in your rule when you use negation to look for actual individuals.
potential_enemies(A,B) :- user(A), user(B), \+ friends(A,B).
A bit looks like a homework, isn't it...
One trick which most of beginners of prolog don't think of is list pattern matching. Think of a tree like [a1,[[a2],[b2,[[e3],[f3]]],[c2]]] as in <tree>=[root,[<tree1>,<tree2>,...]]:
%Y is immediate child of X?
child(X,Y,[X|S]) :- member([Y|_],S).
%pick one tree in S and check
child(X,Y,[X|S]) :- member([Z|SS],S),child(Z,Y,[Z|SS]).
%X and Y end up with same root?
sib(X,Y,[R|T]) :- child(R,X,[R|T]), child(R,Y,[R|T]).
I think you can improve upon this like, using pairs as roots, adding genders, giving names to specific relations of members of the tree...
What kinds of relationships is the first statement supposed to satisfy?
blood_relation(X,Y):-blood_relation(X,Y).
That isn't telling you anything that you don't already "know" and is going to cause you recursion headaches. As for the 'no' answer, is looks like you've already gotten all of the answers from the query that you are going to get, and the interpreter is just telling you that there aren't any more.
You really should post more facts, and the definition of uncle/2, and is there a reason why you're not matching a mother's brother, just her sister? You have lots of other issues to work on :-).
For everything that is not a blood relation, try this:
not_blood_relation(X, Y) :- blood_relation(X, Y), !, fail.
not_blood_relation(X, Y).
And ask yourself why it works!

Resources