Recursive reference in prolog - prolog

I meet some problem when I try to implement
friends(mia, ellen).
friends(mia, lucy).
friends(X,Y) :-
friends(X,Z),
friends(Y,Z).
and when i ask ?- friends(mia, X)., it run out of local stack.
Then I add
friends(ellen, mia) friends(lucy, mia)
I ask ?- friends(mia, X). ,it keeps replying X = mia.
I can't understand, why it is recursive?

First, two assumptions:
the actual code you wanted to write is the following one, with appropriate dots:
friends(mia,ellen).
friends(mia,lucy).
friends(X,Y) :-
friends(X,Z),
friends(Z,Y).
transivity holds: friends of friends are my friends too (I would rather model friendship as a distance: "A is near B" and "B is near C" does not necessarly imply "A is near C"). repeat's answer is right about figuring out first what you want to model.
Now, let's see why we go into infinite recursion.
Step-by-step
So, what happens when we ask: friends(mia,X) ?
First clause gives Y=ellen (you ask for more solutions)
Second clause gives Y=lucy (you ask again for more solutions)
Stack overflow !
Let's detail the third clause:
I want to know if friends(mia,Y) holds for some variable Y.
Is there a variable Z such that friends(mia,Z) holds ?
Notice that apart from a renaming from Y to Z, we are asking the same question as step 1 above? This smells like infinite recursion, but let's see...
We try the first two clauses of friends, but then we fail because there is no friends(ellen,Y) nor friends(lucy,Y), so...
We call the third clause in order to find if there is a transitive friendship, and we are back to step 1 without having progressed any further => infinite recursion.
This problem is analogous to infinite Left recursion in context-free grammars.
A fix
Have two predicates:
known_friends/2, which gives direct relationships.
friends/2, which also encodes transitivity
known_friends(mia,ellen).
known_friends(mia,lucy).
friends(X,Y) :- known_friends(X,Y).
friends(X,Y) :- known_friends(X,Z), friends(Z,Y).
Now, when we ask friends(mia,X), friends/2 gives the same answer as the two clauses of known_friends/2, but does not find any answer for the transitive clause: the difference here is that known_friends will make a little progress, namely find a known friend of mia (without recursion), and try to find (recursively) if that friend is a friend of some other people.
Friends' friends
If we add known_friends(ellen, bishop) :-) then friends will also find Y=bishop, because:
known_friends(mia,ellen) holds, and
friends(ellen,bishop) is found recursively.
Circularity
If you add cyclic dependencies in the friendship graph (in known_friends), then you will have an infinite traversal of this graph with friends. Before you can fix that, you have to consider the following questions:
Does friends(X,Y) <=> friends(Y,X) hold for all (X,Y) ?
What about friends(X,X), for all X ?
Then, you should keep a set of all seen people when evaluating friends in order to detect when you are looping through known_friends, while taking into account the above properties. This should not be too difficult too implement, if you want to try.

This clause of friends/2 is flawed:
friends(X,Y) :- friends(X,Z),friends(Y,Z).
Translate that into English: "If X and Y have a mutual friend Z, then X and Y are friends."
Or, let's specialize, let X be "me", let Y be my neighbour "FooBert", and let Z be "you": So if I am your friend and FooBert is your friend... does that make me and FooBert friends? I don't think so, I hate that guy---he always slams the door when he gets home. :)
I suggest you consider the algebraic properties that the relation friends/2 should have, the ones it may have, and ones it should not have. What about reflexivity, symmetry, anti-symmetry, transitivity?

Related

misconception about how prolog works

So I am currently learning prolog and I can't get my head around how this language works.
"It tries all the possible solutions until it finds one, if it doesn't it returns false" is what I've read that this language does. You just Describe the solution and it finds it for you
With that in mind, I am trying to solve the 8 queens problem ( how to place 8 queens on a chess board without anyone threatening the others).
I have this predicate, 'safe' that gets a list of pairs, the positions of all the queens and succeeds when they are not threatening each other.
When I enter in the terminal
?- safe([(1,2),(3,5)]).
true ?
| ?- safe([(1,3),(1,7)]).
no
| ?- safe([(2,2),(3,3)]).
no
| ?- safe([(2,2),(3,4),(8,7)]).
true ?
it recognizes the correct from the wrong answers, so it knows if something is a possible solution
BUT
when I enter
| ?- safe(L).
L = [] ? ;
L = [_] ? ;
it gives me the default answers, even though it recognizes a solution for 2 queens when I enter them.
here is my code
threatens((_,Row),(_,Row)).
threatens((Column,_),(Column,_)).
threatens((Column1,Row1),(Column2,Row2)) :-
Diff1 is Column1 - Row1,
Diff2 is Column2 - Row2,
abs(Diff1) =:= abs(Diff2).
safe([]).
safe([_]).
safe([A,B|T]) :-
\+ threatens(A,B),
safe([A|T]),
safe(T).
One solution I found to the problem is to create predicates 'position' and modify the 'safe' one
possition((0,0)).
possition((1,0)).
...
...
possition((6,7)).
possition((7,7)).
safe([A,B|T]) :-
possition(A),
possition(B),
\+ threatens(A,B),
safe([A|T]),
safe(T).
safe(L,X):-
length(L,X),
safe(L).
but this is just stupid, as you have to type everything explicitly and really really slow,
even for 6 queens.
My real problem here, is not with the code itself but with prolog, I am trying to think in prolog, But all I read is
Describe how the solution would look like and let it work out what is would be
Well that's what I have been doing but it does not seem to work,
Could somebody point me to some resources that don't teach you the semantics but how to think in prolog
Thank you
but this is just stupid, as you have to type everything explicitly and really really slow, even for 6 queens.
Regarding listing the positions, the two coordinates are independent, so you could write something like:
position((X, Y)) :-
coordinate(X),
coordinate(Y).
coordinate(1).
coordinate(2).
...
coordinate(8).
This is already much less typing. It's even simpler if your Prolog has a between/3 predicate:
coordinate(X) :-
between(1, 8, X).
Regarding the predicate being very slow, this is because you are asking it to do too much duplicate work:
safe([A,B|T]) :-
...
safe([A|T]),
safe(T).
Once you know that [A|T] is safe, T must be safe as well. You can remove the last goal and will get an exponential speedup.
Describe how the solution would look like and let it work out what is
would be
demands that the AI be very strong in general. We are not there yet.
You are on the right track though. Prolog essentially works by enumerating possible solutions and testing them, rejecting those that don't fit the conditions encoded in the program. The skill resides in performing a "good enumeration" (traversing the domain in certain ways, exploiting domain symmetries and overlaps etc) and subsequent "fast rejection" (quickly throwing away whole sectors of the search space as not promising). The basic pattern:
findstuff(X) :- generate(X),test(X).
And evidently the program must first generate X before it can test X, which may not be always evident to beginners.
Logic-wise,
findstuff(X) :- x_fulfills_test_conditions(X),x_fullfills_domain_conditions(X).
which is really another way of writing
findstuff(X) :- test(X),generate(X).
would be the same, but for Prolog, as a concrete implementation, there would be nothing to work with.
That X in the program always stands for a particular value (which may be uninstantiated at a given moment, but becomes more and more instantiated going "to the right"). Unlike in logic, where the X really stands for an unknown object onto which we pile constraints until -ideally- we can resolve X to a set of concrete values by applying a lot of thinking to reformulate constraints.
Which brings us the the approach of "Constraint Logic Programming (over finite domains)", aka CLP(FD) which is far more elegant and nearer what's going on when thinking mathematically or actually doing theorem proving, see here:
https://en.wikipedia.org/wiki/Constraint_logic_programming
and the ECLiPSe logic programming system
http://eclipseclp.org/
and
https://www.metalevel.at/prolog/clpz
https://github.com/triska/clpfd/blob/master/n_queens.pl
N-Queens in Prolog on YouTube. as a must-watch
This is still technically Prolog (in fact, implemented on top of Prolog) but allows you to work on a more abstract level than raw generate-and-test.
Prolog is radically different in its approach to computing.
Arithmetic often is not required at all. But the complexity inherent in a solution to a problem show up in some place, where we control how relevant information are related.
place_queen(I,[I|_],[I|_],[I|_]).
place_queen(I,[_|Cs],[_|Us],[_|Ds]):-place_queen(I,Cs,Us,Ds).
place_queens([],_,_,_).
place_queens([I|Is],Cs,Us,[_|Ds]):-
place_queens(Is,Cs,[_|Us],Ds),
place_queen(I,Cs,Us,Ds).
gen_places([],[]).
gen_places([_|Qs],[_|Ps]):-gen_places(Qs,Ps).
qs(Qs,Ps):-gen_places(Qs,Ps),place_queens(Qs,Ps,_,_).
goal(Ps):-qs([0,1,2,3,4,5,6,7,8,9,10,11],Ps).
No arithmetic at all, columns/rows are encoded in a clever choice of symbols (the numbers indeed are just that, identifiers), diagonals in two additional arguments.
The whole program just requires a (very) small subset of Prolog, namely a pure 2-clauses interpreter.
If you take the time to understand what place_queens/4 does (operationally, maybe, if you have above average attention capabilities), you'll gain a deeper understanding of what (pure) Prolog actually computes.

Binary logic in prolog

I want to solve following problem using inference making power of prolog.
One day, 3 persons, a, b, c were caught by police at the crime spot. When police settled interrogating them:
i) a says I am innocent
ii) b says a is criminal
iii) c says I am innocent.
Its known that
i) Exactly one person speaks true.
ii) Exactly one criminal is there.
Who is criminal?
To model above problem in First Order logic:
Consider c/1 is a predicate returns true when argument is Criminal
we can write:
(not(c(a)),c(c)) ; (c(c),c(a)).
c(a); c(b); c(c).
(not(c(a)),not(c(b))) ; (not(c(a)),not(c(c))) ; (not(c(b)),not(c(c))).
After modelling above statements in prolog, I will query:
?-c(X).
it should return:
X=c.
But error I got:
"No permission to modify static procedure `(;)/2'"
Since PROLOG does indeed work with Horn clauses, you'll need things of form head :- tail, reading :- as "if."
solve(Solution) :- ...
%With a Solution looking something like:
% solve(a(truth,innocent),b(false,criminal),c(false,innocent)).
To use the generate and test method, which is a common and reasonable way to solve this, you'd do something like this:
solve(Solution) :-
Solution = [a(_,_),b(_,_),c(_,_)],
generate(Solution),
validate(Solution).
generate should give you a well-formed Solution, that is, one having all the variables filled in with values that make some kind of sense (that is, false, true, criminal, innocent).
validate should ensure that the Solution matches the constraints you gave.
solve only completes when one of generate's solutions makes it past validate's constraints.
For an introduction to the generate and test method, see this tutorial.
But if you're writing code that isn't Horn clauses, you might need a tutorial on writing PROLOG functions (OK, relations), like this one.

In Prolog how can I cut redundant answers

I am working on a dictionary-like program with prolog, and my code goes like this:
define(car,vehicle).
define(car,that).
define(car,has).
define(car,four).
define(car,wheels).
define(wheels,round).
define(wheels,object).
define(wheels,used).
define(wheels,in).
define(wheels,transportation).
defined(X):-define(X,_).
anotherdefined(X):- \+ undefined(X).
undefined(X):- \+define(X,_).
I am trying to write a defined/1 predicate which will give me:
?-defined(X).
X = car ;
X = wheels ;
false.
Yet, my defined/1 gives me X=car. five times (naturally) for everytime it counters define(car,_).
and my anotherdefined/1 gives me only true. What is the method to stop prolog backtracking to the other instances of define(car,_).,and skip to define(wheels,_).?
Edit: I have written the following lines to get the result I want with givedefinedword/1,
listdefined(X):-findall(Y,defined(Y),Z),sort(Z,X).
givedefinedword(X):-listdefined(List),member(X,List).
However since I wanted an efficient predicate (which I will use in many others) it beats the purpose. This predicate does too much process.
Or, Would it be better to use a predicate that modifies the code? say prepares a list of defined words, and modifies it when new definitions are added.
Thanks.
If you change define to relate items and lists, like
definelist(car, [vehicle, that, has, four, wheels]).
% etc.
defined(X) :- definelist(X, _).
then defined will no longer produce duplicates, nor require linear space.
Of course, a query define(X, Y) must now be performed as definelist(X, L), member(Y, L). If you want this to be efficient as well, you may need to duplicate all definitions.
What are you trying to achieve with your program? It seems that you want to have facts in the form:
"A car is a vehicle that has four wheels"
"Wheels are round objects used in transportation" (a bit vague)
How are you going to use these facts? #larsmans suggestion if perfectly fine, if you want to just have your statement as a "sentence". It really depends what you will do with the information though.
Consider structuring the information in your database:
is(car, vehicle).
is(bicycle, vehicle).
is(boat, vehicle).
has(car, wheel(four)).
has(car, motor).
has(bicycle, wheel(two)).
Given this database, you can at least ask a question like, "what vehicles are there?", "does a bicycle have a motor?", or maybe, "how many wheels does a car have?", or "which vehicles have no wheels?"
?- is(X, vehicle).
?- has(bicycle, motor).
?- has(car, wheel(N)).
?- is(X, vehicle), \+ has(X, wheel(_)).
and so on.
Once you have defined your problem better, you can define your data structures better, which will make writing a program to solve your problem easier.

How to represent uniqueness?

I am trying to write an agent for determining what card a player has, and I am struggling to represent that each card can only have been dealt to a single player.
So have I have something^ like this:
player(p1).
player(p2).
card(ace).
card(king).
card(queen).
card(jack).
but I am struggling on writing the rule for uniqueness. Borrowing something from logic class, I though about defining uniqueness as "if X has Y, then if something has Y, that something must be X".
has_card(P, C) :-
player(P),
card(C),
not(player(P2),
P2 =\= P,
has_card(P2, C)
).
but this fails because not/3 is not defined.
I tried rewriting it as:
has_card(P, C) :-
player(P),
card(C),
player(P2),
P2 =\= P,
not(has_card(P2,C)).
but then the query (which I expect to return false)
has_card(P, ace).
errors out with
ERROR: =\=/2: Arithmetic: `player1/0' is not a function
So, how can I represent uniqueness?
^ complicating --likely-- unnecessary details omitted
EDIT: in first attempt at has_card I have P2==P which should have been P2=\=P, fixed now
First off, as the error is telling you, you are using =\=, which is arithmetic inequality. For comparing on standard order of terms, you should use \==.
Then, the "not" as in "true when negated goal not true", you should probably use \+, like this:
\+ a == b
which is the same as
a \== b
The not/1 predicate is still available in most Prolog implementations but not recommended.
Fixing these two things will sort out the problem you are having at the moment.
But, as it is at the moment, your has_card/2 at no point maps a card to a player, really (it uses circular logic as far as I can see). Since you are not showing how exactly you know which cards belong to which player at any given moment, it is difficult to comment on that. Either way, some sort of term that you pass around would be probably better than changing the database with assert and retract.

Prolog - Rules are correct, but not outputting the way it's supposed to?

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.

Resources