Simple Prolog program - Unsure about results - prolog

Completely new to Prolog (SWI-Prolog in this case) so apologies for this very basic question. I have a simple program below.
loves(vincent,mia).
loves(marsellus,mia).
loves(pumpkin,honey_bunny).
loves(honey_bunny,pumpkin).
jealous(X, Y):- loves(X,Z), loves(Y,Z).
I'm a little confused as to the results of the following query:
?- jealous(vincent, X).
X = vincent ;
X = marsellus.
Perhaps I'm just not accustomed to the unification process of Prolog, but shouldn't the answer just be marsellus? Why is vincent included here as a valid result?
Also, as a followup question: Am I correct in that in order to get a result of all the 'jealous' people, I would write a query such as jealous(X, Y). ?
If so, can someone explain the following result of said query?
?- jealous(X, Y).
X = Y, Y = vincent ;
X = vincent,
Y = marsellus ;
X = marsellus,
Y = vincent ;
X = Y, Y = marsellus ;
X = Y, Y = pumpkin ;
X = Y, Y = honey_bunny.
Any help would be greatly appreciated. Thanks!

For your first question, I can see how the output makes sense.
You're asking for a list of people that love the same person that Vincent loves.
Since both Vincent and Marsellus love Mia, the list is {Vincent, Marsellus}, as you are getting.
I'm not sure of the syntax for Prolog but you'd want something like:
jealous(X, Y):- loves(X,Z), loves(Y,Z), X \== Y.
to remove those cases where X and Y refer to the same person, using whatever symbol in Prolog meaning "not equal to" if it's not \==.
It's a little hard to be jealous of yourself unless you're suffering from some sort of split-personality disorder and, if you are, you could argue it's not yourself you're actually jealous of, self becoming a rather fluid concept in those circumstances.
The second question output also makes sense, after a bit of thought, and is related to the same problem as described above. Looking at the output slightly reformatted:
X = Y, Y = vincent ;
X = vincent, Y = marsellus ;
X = marsellus, Y = vincent ;
X = Y, Y = marsellus ;
X = Y, Y = pumpkin ;
X = Y, Y = honey_bunny.
These are the jealousy ouputs, with the X = Y meaning exactly that, X and Y are the same, with Y being specified as the second item on each line. It can be rewritten as:
X = vincent, Y = vincent ;
X = vincent, Y = marsellus ;
X = marsellus, Y = vincent ;
X = marsellus, Y = marsellus ;
X = pumpkin, Y = pumpkin ;
X = honey_bunny, Y = honey_bunny.
In other words, similar to the first question, everyone is jealous of themselves, as well as any other people who may love a given target.
I suspect that, if you modify the jealousy detector as suggested, all that self-loathing may just disappear, and the world will be a happier place.
Well, other than for Vincent and Marsellus, who obviously still dislike each other, and who are both suffering from unrequited love. The world can sometimes be such a harsh place :-)

Related

How to make a rule return all details of a fact using Prolog

Using Prolog, I first created two facts called grade and food: The first fact is grade(X,Y) where X is the student (rob or matt) and Y is the grade level (freshman or sophomore). The second fact is food(X,Y) where X is the student (rob or matt) and Y is the food (pizza, burger, pasta, wrap).
I created a rule called preference(X,Y), where X is the student (rob or matt) and Y is the students' preference.
I want to enter preference(rob,X). in the GNU Prolog and have it return:
sophomore, pizza, burger.
However, it keeps returning: sophomore, pizza, pizza.
How do I fix this problem? I've spent hours looking into this. Thanks
This is the code I have:
grade(rob, sophomore).
grade(matt, freshman).
food(rob, pizza).
food(rob, burger).
food(matt, pasta).
food(matt, wrap).
preference(X,Y):-
grade(X,A),
food(X,B),
food(X,C),
Y = (A, B, C).
The way you have defined your facts is nice. The way you query it is not conventional. Here is how I would do it. The "preference" rule is simpler:
grade(rob, sophomore).
grade(matt, freshman).
food(rob, pizza).
food(rob, burger).
food(matt, pasta).
food(matt, wrap).
preference(X, A, Y):-
grade(X, A),
food(X, Y).
You conventionally query the database and get all solutions with backtracking:
?- preference(rob, Grade, Food).
Grade = sophomore,
Food = pizza ;
Grade = sophomore,
Food = burger.
If you want to collect the foods, you can use bagof/setof, like this:
?- bagof(Food, preference(rob, Grade, Food), Foods).
Grade = sophomore,
Foods = [pizza, burger].
What if you want to query all freshmen?
?- bagof(Food, preference(Person, freshman, Food), Foods).
Person = matt,
Foods = [pasta, wrap].
You need to state that the value of B and C are different; there are multiple ways to do that, for the simplicity I go with \==/2 (documentation):
preference(X,Y):-
grade(X,A),
food(X,B),
food(X,C),
B\==C,
Y = (A, B, C).
Gives the output
| ?- preference(X,Y).
X = rob
Y = (sophomore,pizza,burger) ? ;
X = rob
Y = (sophomore,burger,pizza) ? ;
X = matt
Y = (freshman,pasta,wrap) ? ;
X = matt
Y = (freshman,wrap,pasta) ? ;
no
If you don't want to have the basically doubled entries you can go with the (in this case lexical) "less than" #</2:
preference(X,Y):-
grade(X,A),
food(X,B),
food(X,C),
B #< C,
Y = (A, B, C).
| ?- preference(X,Y).
X = rob
Y = (sophomore,burger,pizza) ? ;
X = matt
Y = (freshman,pasta,wrap) ? ;
no
I may be wrong, but I suspect this may be a misunderstanding of prolog in general in addition to a non-intuitive REPL. Prolog doesn't really "return" a value, it just tries to match the variables to values that make your predicates true, and I would be willing to bet you're hitting enter after you see the first result.
The way preference is currently written B and C will match any two foods that rob is associated with. This could be pizza, pizza or pizza, burger or burger, pizza, or so on. It does not check whether B and C are equal. When I run preference(rob,X). prolog does not only give me the first result UNLESS I hit enter.
| ?- preference(rob,X).
X = (sophomore,pizza,pizza) ? ?
Action (; for next solution, a for all solutions, RET to stop) ?
If you hit a (or spam ; a few times) prolog will give you the rest of the results.
| ?- preference(rob,X).
X = (sophomore,pizza,pizza) ? a
X = (sophomore,pizza,burger)
X = (sophomore,burger,pizza)
X = (sophomore,burger,burger)
yes
| ?-
I think that all you really need to get all of a person's preferences is just food unless you specifically need them in a tuple or list which will take some slightly more complicated logic (let me know in a comment if that's what you're looking for)
| ?- food(rob, X).
X = pizza ? a
X = burger
yes
| ?-

How not to show if there is same result occurs more than once- Prolog

Scenario
I have the code as below. My question is how to don't show appearing same result more than once.
male(charles).
male(andrew).
male(edward).
female(ann).
age(charles, 70).
age(ann, 65).
age(andrew, 60).
age(edward, 55).
nextking(X) :- age(X,P), age(Y,Q),
P>=Q, X\==Y; age(X,55).
Current Output
What I need
I need the output to be charles, ann, andrew, edward. No repetition of names.
With a fairly recent version, you can use library(solution_sequences):
?- distinct(nextking(X)).
X = charles ;
X = ann ;
X = andrew ;
X = edward.
or use the classic 'all solutions' builtin:
?- setof(K,K^nextking(K),Ks),member(X,Ks).
Ks = [andrew, ann, charles, edward],
X = andrew ;
Ks = [andrew, ann, charles, edward],
X = ann ;
...
but in this case, we loose the answer order defined by the KB.
Your nextking/1 predicate is rather inefficient, and furthermore does not guarantee the persons to be sorted by age.
If we would for example put charles last in the list of facts, we get:
?- nextking(X).
X = ann ;
X = ann ;
X = andrew ;
X = charles ;
X = charles ;
X = charles ;
X = edward.
basically te predicate you wrote has two clauses:
nextking(X) :-
age(X,P),
age(Y,Q),
P >= Q,
X\==Y.
nextking(X) :-
age(X, 55).
The first simply will yield any X for which there exists a person Y that is younger. But that thus gives no guarantees that these elements are sorted. Finally the last predicate will unify with all persons X that are 55 years old. For this specific case this works, but it would mean if we state another fact age(louise, 14), then this will fail. Not only is the approach incorrect, but even if it was correct it will be very "unstable".
We can make use of the setof/3 [swi-doc] predicate that does not only perform a uniqness filter, but also sorts the elements.
Since we want to sort the members of the royal family by descending age, we thus should construct 2-tuples (or an other structure that encapsulates the two parameters) where the first parameter contains the negative age, and the second parameter the corresponding person.
We can then use member/2 [swi-doc] to "unwind" the list in individual unifications:
nextking(X) :-
setof((NA, X), A^(age(X, A), NA is -A), Royals),
member((_, X), Royals).
This will produce the list of elements like:
?- nextking(X).
X = charles ;
X = ann ;
X = andrew ;
X = edward.
regardless how the facts are ordered in the source file.

Does SWI-Prolog have a way to read scientific notation?

Does SWI-Prolog have a way to read scientific notation? I couldn't find anything here or in the document. For example, is there a way to read 7.33E-05 besides hard-parsing it?
Thank you!
One option to read numbers like 7.33E-05 is by using "read_term" predicate family, e.g.:
read_term_from_atom('7.33E-05', N, [])
should parse and save 7.33E-05 into variable N.
Here's an example use of the scientific notation:
?- X = 7.33E-05, Y = 6.4E-03, Z = X+Y, Y > X.
X = 7.33e-5,
Y = 0.0064,
Z = 7.33e-5+0.0064.
To actually do simple math use:
?- use_module(library(clpr)).
?- X = 7.33E-05, Y = 6.4E-03, {Z=X+Y}.
X = 7.33e-5,
Y = 0.0064,
Z = 0.0064733

Understanding recursivity in Prolog

I have this example:
descend(X,Y) :- child(X,Y).
descend(X,Y) :- child(X,Z), descend(Z,Y).
child(anne,bridget).
child(bridget,caroline).
child(caroline,donna).
It works great and I understand it. This is a solution of a little exercise. My solution was the same but changing:
descend(X,Y) :- descend(X,Z), descend(Z,Y).
That is, changing child for descend in the second descend rule.
If I query descend(X, Y). in the first solution, I obtain:
?- descend(X, Y).
X = anne,
Y = bridget ;
X = bridget,
Y = caroline ;
X = caroline,
Y = donna ;
X = anne,
Y = caroline ;
X = anne,
Y = donna ;
X = bridget,
Y = donna ;
false.
Which is correct. But if I query with my solution the same, I get:
?- descend(X, Y).
X = anne,
Y = bridget ;
X = bridget,
Y = caroline ;
X = caroline,
Y = donna ;
X = anne,
Y = caroline ;
X = anne,
Y = donna ;
ERROR: Out of local stack
It doesn't say X = bridget,Y = donna ; and it also overflows. I understand why it overflows. What I don't understand is why it doesn't find this last relationship. Is it because of the overflow? If so, why? (Why is the stack so big with such small knowledge base?).
If I query descend(bridget, donna) it answers yes.
I'm having problems imagining the exploration tree...
Apart from that question, I guess that the original solution is more efficient (ignoring the fact that mine enters in a infinite loop at the end), isn't it?
Thanks!
I'm having problems imagining the exploration tree...
Yes, that's quite difficult in Prolog. And it would be worse if you had a bigger database! But most of the time it is not necessary to envision the very precise search tree. Instead, you can use several quite robust notions.
Remember how you formulated your query. You looked at one solution after the other. But what you really were interested in was the question whether or not the query terminates. You can go for it without looking at the solutions by adding false.
?- descend(X, Y), false.
ERROR: Out of local stack
This query can never be true. It can either fail, overflow, or loop, or produce another error. What remains is a very useful notion: Universal termination or as in this case non-termination.
This can be extended to your actual program:
descend(X,Y) :- false, child(X,Y).
descend(X,Y) :- descend(X,Z), false, descend(Z,Y).
If this fragment called a failure-slice does not terminate, then also your original program does not terminate. Look at this miserable remainder of your program! Not even child/2 is present any longer. And thus we can conclude that child/2 does not influence non-termination! The Y occurs only once. And X will never cause a failure. Thus descend/2 terminates never!
So this conclusion is much more general than just a statement about a specific search tree. It's a statement about all of them.
If you still want to reason about the very precise order of solutions, you will have to go into the very gore of actual execution. But why bother? It's extremely complex, in particular if your child/2 relation contains cycles. Chances are that you will confuse things and build inaccurate theories (at least I did). No need for another cargo cult. I, for one, have given up to "step through" such myriads of detail. And I do not miss it.

Order of goals(statements) in Prolog rules

I began to study Prolog recently and faced one strange problem.
Here you can see a code example (I use SWI-Prolog 7.2.3) which gives a tree of relationships and my solution of 2 tasks.
/* File: ancestors.pl
Author: Dave Robertson
Purpose: Relationships in a family tree
Suppose we have a family tree like this :
alan andrea bruce betty eddie elsie fred freda
| | | | | | | |
|_____| |_____| |_____| |_____|
| | | |
clive clarissa greg greta
| |__________|___| | |
|__________|__| |_____________|
| | |
dave doris henry
which is defined in Prolog by the following 3 sets of predicates:
*/
% parent(Parent, Child).
% Parent is the parent of Child.
parent(alan, clive).
parent(andrea, clive).
parent(bruce, clarissa).
parent(betty, clarissa).
parent(clive, dave).
parent(clarissa, dave).
parent(clive, doris).
parent(clarissa, doris).
parent(eddie, greg).
parent(elsie, greg).
parent(fred, greta).
parent(freda, greta).
parent(greg, henry).
parent(greta, henry).
%% PROBLEM 1
%% How do you find out if someone is the ancestor of someone else ?
ancestor(X,Y) :- parent(X,Y).
ancestor(X,Y) :- parent(X,Z), ancestor(Z,Y).
%% PROBLEM 3
%% How do you know if someone is related to someone else ?
relative(X,Y) :- ancestor(X,Y).
relative(X,Y) :- ancestor(Y,X).
relative(X,Y) :- ancestor(Z,X), ancestor(Z,Y), X\==Y.
When I want to get the relatives of dave I do:
relative(dave,X).
X = clive ;
X = clarissa ;
X = alan ;
X = andrea ;
X = bruce ;
X = betty ;
X = doris ;
X = doris ;
X = clive ;
X = doris ;
X = clive ;
X = doris ;
X = clarissa ;
X = doris ;
X = clarissa ;
X = doris ;
false.
And then I change my definition of relative next way:
relative(X,Y) :- ancestor(X,Y).
relative(X,Y) :- ancestor(Y,X).
relative(X,Y) :- X\==Y, ancestor(Z,X), ancestor(Z,Y).
I simply change the order of goals in the last statement.
And now I have the following output:
relative(dave,X).
X = clive ;
X = clarissa ;
X = alan ;
X = andrea ;
X = bruce ;
X = betty ;
X = dave ;
X = doris ;
X = dave ;
X = doris ;
X = clive ;
X = dave ;
X = doris ;
X = clive ;
X = dave ;
X = doris ;
X = clarissa ;
X = dave ;
X = doris ;
X = clarissa ;
X = dave ;
X = doris ;
false.
I see dave in the output! How did this happen? I wrote that X \== Y... Can anybody give me a good explanation of this?
And one more question. How do I make my program not to write the same answers?
Thank you!
(\==)/2 is not a pure relation and can only be understood operationally. If you use it, exchanging the order of goals may yield declaratively wrong results:
?- X \== Y, X = Y.
X = Y.
Please use dif/2 instead for a pure and completely declarative way to state disequality of terms.
?- dif(X, Y), X = Y.
false.
See prolog-dif for more information.
Especially as a novice, try to abstain from using impure constructs and perserve logical-purity!
How? Use prolog-dif!
Instead of X \== Y simply write dif(X, Y).
Prolog is a programming language based on a specific resolution method, and the problem you describe is just that: a problem (well, I would call it a bug) in your program. The order of clauses and goals is how you control your algorithm: a sequence of steps with defined effects on your representation. Then a knowledge about such effects is IMHO unavoidable, and - I think - replacing (\==)/2 by dif/2 isn't going to make your life easier, when you'll try to code something more complex. At least, in my experience, I faced additional difficulties when I had to model and debug my code.
(\==)/2 is meant to ease metaprogramming, when you need to compare variables for identity. As such, it's effectively a rather advanced feature, not needed for your program. But (maybe because it's so similar to C/C++/Java operators), it's easy to undervalue its purpose.
For your usage, (\=)/2 would serve better, but again, it requires, for a simple use, that both arguments are instantiated. This being true, depends on the whole 'inference graph' resulting from the actual calling of goals - the operational semantic. Generally, it's not simple (or even feasible, I think) to determine if a predicate is safe to call with a specific pattern. Consider this counterexample I got as a comment about a my naive assertion - append/3, a pure Prolog library predicate, being safe for all instatiation patterns:
?- append(Xs,[a],Xs).
To avoid duplicates, and listing the outcome, I would use setof/3
?- setof(R, relative(dave, R), Relatives), maplist(writeln, Relatives).

Resources