Retrieve elements from facts in Prolog - prolog

I am currently learning Prolog for a class right now. I am using GNU Prolog to define a rule for example class_info(X,Y) and a similar rule, where X is the name of the professor and Y will be the output of the info. For example:
?- class_info(steve, Y).
Y = math ;
false.
But I only know how to return algebraic expressions in rules, but not the one above.
Suppose I have the following facts.
/*facts */
job(steve, professor).
job(john, professor).
teaches(steve, math).
teaches(john, chemistry).
class(math, calculus).
class(chemistry, organic).
class(math, algebra).
class(chemistry, basic).
%rule
class_info(X, Y) :-
%absolutely have no idea what do here, 'is' does not work, since it's only for algebraic expressions
.
exact_class(X, Y) :-
%exact_class(steve, Y). returns Y = calculus? and Y = algebra upon pressing ';'
.
Any help would be appreciated. I am not looking for code, but something to point me in the right direction. The Prolog GNU manual is kind of hard to follow.

class_info(X, Y) :-
teaches(X, Y).
?- class_info(steve,Y).
Y = math ;
false.
Ok, sorry for putting one solution right on top but Prolog is hard to grasp without examples. So I just put the first solution, the second you have to figure out with a bit of explanation.
So you are asking which lecturer X holds which class Y. You already have this info within teaches/2, so you just forward the values from this predicate. So it says something like if a teacher X teaches the lecture Y, the classinfo from X is Y. You can add addional information, for example the teacher has to be a professor. You do this "and" (conjunction) by putting a , between the predicates:
class_info(X, Y) :-
teaches(X, Y),
job(X, professor).
?- class_info(steve,Y).
Y = math ;
false.
Please note that variables start with a capital letter. Questions are asked by starting with ?-, the answers are separeted by a semicolon ; until there are no solutions left (false.).
You can even be more specific about this by using a predicate which also forwards the lecturers job:
class_info_job(X, Y, Z) :-
teaches(X, Y),
job(X, Z).
?- class_info_job (steve, Y, Z).
Y = math,
Z = professor ;
false.
?- class_info_job (steve, Y, professor).
Y = math;
false.
?- class_info_job(X, math, Z).
X = steve,
Z = professor ;
false.
?- class_info_job(X, Y, Z).
X = steve,
Y = math,
Z = professor ;
X = john,
Y = chemistry,
Z = professor ;
false.
Ok, so these were some examples how to play around. I hope this enough to help you with the second rule.

Related

Prolog encoded integers, less/2(X, Y) predicate

A question states the following:
In Prolog, non-negative integers can be encoded as numerals given by 0 and its successors (with, for example, the numeral s(s(s(0))) encoding 3).
numeral(0).
numeral(s(X)) :- numeral(X).
Define the predicate less/2(X, Y) that holds when X and Y are numerals encoding non-negative integers x and y such that x < y. For example,
?- less(0, s(0)).
yes.
?- less(s(s(0)), s(s(0))).
no.
I have been able to come up with a solution for this question, however, it suffers from a limitation. Here is my solution:
less(X, s(X)) :- numeral(X).
less(X, Z) :- less(X, Y), less(Y, Z).
This solution correctly outputs a yes for inputs that satisfy this predicate. However, for inputs that expect a no, this solution seems to enter an endless recursion of some sort, and the program just keeps running, rather than outputting a no.
Please help.
I would do it like this:
less(0, s(Y)) :- numeral(Y).
less(s(X), s(Y)) :- less(X, Y).
?- less(0, s(0)).
true.
?- less(s(s(0)), s(s(0))).
false.
The idea is that 0 is less than any s(Y), where Y is a numeral. If X is not 0, then X is s(X'), and X = s(X') is less than Y = s(Y') iff X' is less than Y'.
This does only work if both X and Y are numerals. If X is not a numeral then it will get stuck somewhere in the recursion and "returns" false. Same for Y, except that there need to be a test at the end if the rest of Y is a numeral.
Try this:
less2(X, s(X)) :- numeral(X).
less2(X, s(Y)) :- less2(X,Y).
Seems to work for me; your solution could recurse endlessly though, because if there exists no value of Y between X and Z it will simply try everything under the sun.

Why does my predicate not work, when a similar predicate does?

I have the following facts:
loves(andy, julia).
loves(andrew, maria).
loves(bob, sofia).
loved(juila).
loved(maria).
loved(sofia).
and I want to have two predicates:
do_love(X, Y) :- ...
is_loved(X, Y) :- ...
which returns Y as the name of the person, and X as the fact itself. For the loved fact, I wrote:
is_loved(X, Y) :- X = loved(Y), X.
which as expected, returns:
is_loved(X,Y).
X = loved(juila),
Y = juila ;
X = loved(maria),
Y = maria ;
X = loved(sofia),
Y = sofia.
However, when I write the predicate for the loves fact in a similar way:
do_love(X, Y) :- X = loves(X, Y), X.
it returns false for the query:
do_love(X,Y).
false.
I'm new to prolog, and can't really see why this is the case. Why does the query for is_loved work, while the one for do_love doesn't?
The problem is you're trying to unify X with two different values:
X = loves(...) and
loves(X, ...)
(I truncate using ... because those parts are irrelevant to what I'm saying).
In other words, your do_love predicate is saying "X must unify with a loves predicate" and also "X must unify with the first argument in a loves predicate". With the data set you've set up, no single value fulfills both requirements.
Depending on what you're trying to do, this might be what you want:
do_love(X, Y) :- loves(X, Y).
Sidenote 1: Predicates don't "return" values like they do in other languages with functions. You don't need the , X in your predicates for them to work.
Sidenote 2: The = is a "unify" operator, rather than an "assignment" like other languages. See this page for more info.

Can't show the second answer in Prolog

sisters(mary,catherine).
sisters(catherine,mary).
brothers(john,simone).
brothers(simone,john).
marriage(john,mary,2010).
marriage(mary,john,2010).
marriage(kate,simone,2009).
marriage(simone,kate,2009).
marriage(catherine,josh,2011).
marriage(josh,catherine,2011).
birth(mary,johnny).
birth(mary,peter).
birth(catherine,william).
birth(kate,betty).
givebirthyear(mary,peter,2015).
givebirthyear(mary,johnny,2012).
givebirthyear(catherine,william,2012).
givebirthyear(kate,betty,2011).
siblings(X,Y) :-
birth(Parent,X),
birth(Parent,Y).
cousins(X,Y) :-
birth(Xparent,X),
birth(Yparent,Y),
sisters(Xparent,Yparent).
cousins(X,Y) :-
X \= Y,
birth(Xmom,X),
birth(Ymom,Y),
marriage(Xmom,Xdad,_),
marriage(Ymom,Ydad,_),
brothers(Xdad,Ydad).
I don' know what's happening in my code. When I input
cousins(betty,johnny).
and
cousins(william,johnny).
The prolog says true. But when I entered
cousins(S,johnny).
THe prolog says S = william but didn't show me that S = betty. I don't really know what's happening. Need help.
Here is the prolog result I got.
?- cousins(S,johnny).
S = william ;
false.
?- cousins(betty,johnny).
true.
?- cousins(william,johnny).
true .
The problem
The reason this happens is because
X \= Y,
actually means:
\+(X = Y).
now \+ or not in Prolog has some weird behaviour compared to the logical not. \+ means negation as finite failure. This means that \+(G) is considered to be true in case Prolog queries G, and can not find a way to satisfy G, and that G is finite (eventually the quest to satisfy G ends).
Now if we query \+(X = Y), Prolog will thus aim to unify X and Y. In case X and Y are (ungrounded) variables, then X can be equal to Y. As a result X \= Y fails in case X and Y are free variables.
So basically we can either use another predicate that for instance puts a constraint on the two variables that is triggered when the variables are grounded, or we can reorder the body of the clause, such that X and Y are already grounded before we call X \= Y.
If we can make for instance the assumption that X and Y will be grounded after calling birth/2, we can reorder the clause to:
cousins(X,Y) :-
birth(Xmom,X),
birth(Ymom,Y),
X \= Y,
marriage(Xmom,Xdad,_),
marriage(Ymom,Ydad,_),
brothers(Xdad,Ydad).
Prolog has however a predicate dif/2 that puts a constraint on the two variables, and from the moment the two are grounded, it will fail if the two are equal. So we can use it like:
cousins(X,Y) :-
dif(X,Y),
birth(Xmom,X),
birth(Ymom,Y),
marriage(Xmom,Xdad,_),
marriage(Ymom,Ydad,_),
brothers(Xdad,Ydad).
Making things simpler
That being said, I think you make the program too complex. We can start with a few definitions:
two people are slibings/2 if they are brothers/2 or sisters/2.
slibings(X,Y) :-
brothers(X,Y).
slibings(X,Y) :-
sisters(X,Y).
It is however possible that brothers/2 and sisters/2 do not provide all information. Two people are also slibings if they have the same mother (we will assume that people do not divorce here, or at least not give birth to other children after they remarry).
slibings(X,Y) :-
dif(X,Y),
birth(Mother,X),
birth(Mother,Y).
a parent/2 of a person is the mother of the person or the father (the person that married the mother).
So we can write:
parent(Mother,X) :-
birth(Mother,X).
parent(Father,X) :-
birth(Mother,X),
marriage(Father,Mother,_).
based on your example, the marriage/3 predicate is bidirectional: in case marriage(X,Y,Z)., then there is also a fact marriage(Y,X,Z)..
And now we can define:
two people are cousins if there parents are slibings:
cousins(X,Y) :-
parent(MF1,X),
parent(MF2,Y),
slibings(MF1,MF2).
and that's it.

Prolog - Make two Instantiations Equal

I'm very new to Prolog so please bear with me.
Lets say I have the following:
foo(bar(a,b)).
foo(bar(b,a)).
Then I enter foo(X) as a query:
?- foo(X).
X = bar(a, b) ;
X = bar(b, a).
Prolog returns two instantiations of X to satisfy the query: bar(a, b) and bar(b,a).
Is there away I can make these two instantiations equivalent? Once Prolog instantiates X to bar(a,b), it won't instantiate it to bar(b,a).
So when I enter foo(X) as a query:
?- foo(X).
X = bar(a, b).
X was no instantiated as bar(b,a), because it's equivalent to bar(a,b). Is this possible to do with Prolog, or does it go against the fundamental principals of Prolog?
The first clause of symmetry/2 deals with cases in which both foo(bar(a,b)) and foo(bar(b,a)) occur. I use the standard order of terms in order to return only the former. Notice that the use of #< would have falsely excluded results like foo(bar(e,e)).
The second clause treats cases in which either foo(bar(c,d)) or foo(bar(d,c)) occur.
foo(bar(a, b)).
foo(bar(b, a)).
foo(bar(c, d)).
foo(bar(e, e)).
symmetry(X, Y):-
foo(bar(X, Y)),
foo(bar(Y, X)),
X #=< Y.
symmetry(X, Y):-
foo(bar(X, Y)),
\+ foo(bar(Y, X)).
Example of usage:
?- symmetry(X, Y).
X = a,
Y = b ;
X = Y, Y = e ;
X = c,
Y = d ;
false
Hope this helps!
Identity of literals it's the core of unification - the fundamental operation of Prolog algorithm - and then the answer to your question it's no, it's not possible to handle bar(a,b) as bar(b,a).

Prolog Beginner: How to unify with arithmetic comparison operators or how to get a set var to range of values

I am new to Prolog. I need to write an integer adder that will add numbers between 0-9 to other numbers 0-9 and produce a solution 0-18. This is what I want to do:
% pseudo code
add(in1, in2, out) :-
in1 < 10,
in2 < 10,
out < 18.
I would like to be able to call it like this:
To check if it is a valid addition:
?- add(1,2,3).
true.
?- add(1,2,4).
false.
With one missing variable:
?- add(X,2,3).
X = 1.
?- add(1,4,X).
X = 5.
With multiple missing variables:
?- add(X,Y,Z).
% Some output that would make sense. Some examples could be:
X=1, Y=1, Z=2 ;
X=2, Y=1, Z=3 ......
I realize that this is probably a pretty simplistic question and it is probably very straightforward. However, according to the Prolog tutorial I am using:
"Unlike unification Arithmetic Comparison Operators operators cannot be used to give values to a variable. The can only be evaluated when every term on each side have been instantiated."
All modern Prolog systems provide finite domain constraints, which are true relations that can (in contrast to more low-level arithmetic predicates like is/2 and >/2) be used in all directions. In SWI-Prolog:
:- use_module(library(clpfd)).
plus(X, Y, Z) :-
[X,Y] ins 0..9,
X + Y #= Z.
Results for your examples:
?- plus(1,2,3).
true.
?- plus(1,2,4).
false.
?- plus(X,2,3).
X = 1.
?- plus(1,4,X).
X = 5.
?- plus(X,Y,Z).
X in 0..9,
X+Y#=Z,
Y in 0..9,
Z in 0..18.
Since the predicate can be used in all directions, it does no longer make sense to call it "add/3", as that would imply a direction, but the predicate truly describes when the relation holds and is thus more general.
What about this?:
add(X,Y,Z) :-
Z is X + Y,
X < 10,
Y < 10,
Z < 19.
Problem: this works nicely for queries of the form add(1,1,X) because Z's instantiated before the < calls, but fails when you ask add(X,1,2). You could use var/1 to distinguish the kind of query (var/1 tells you whether a variable's uninstantiated or not), but that sounds like a lot of pain.
Solution:
lessThanTen(9).
lessThanTen(8).
lessThanTen(7).
lessThanTen(6).
lessThanTen(5).
lessThanTen(4).
lessThanTen(3).
lessThanTen(2).
lessThanTen(1).
lessThanTen(0).
addSimple(Add1,Add2,Sol) :-
lessThanTen(Add1),
lessThanTen(Add2),
Sol is Add1+Add2.

Resources