Finding complement of a set in prolog - prolog

suppose i've defined three clubs in Prolog:
club(football, [john, mary, peter, jane]).
club(basketball, [peter, jane, tom, kim]).
club(dance, [emily, andrew, john, jacob]).
now i wish to find the complement of football club from the combined three clubs (i.e answer should display [tom, kim,emily, andrew, jacob])
please write a code in prolog to perform the above task.
i tried to append the three lists and then subtract the football list from the combined list but i was getting multiple errors

Let's imagine that I somehow had a relation club_member/2 like this:
?- club_member(C, M).
C = football, M = john ;
C = football, M = mary ;
C = football, M = peter ;
C = football, M = jane ;
C = basketball, M = peter ; % etc
You can redefine your rules or maybe figure out how to define a new rule that translates it at run time. Once you have it, union(A, B) is A ; B and complement as in A \ B is the set difference or A, \+ B. So:
?- setof(M,
( ( club_member(basketball, M)
; club_member(dance, M)
),
\+ club_member(football, M)
),
Members).
Members = [andrew, emily, jacob, kim, tom].
The parentheses look excessive :-( but cannot be avoided in that case.
In this particular case, if you assume that the union of all three is the universe, then the complement A' could be defined also as:
?- setof(M,
C^( club_member(C, M),
\+ club_member(football, M)
),
Members).
Members = [andrew, emily, jacob, kim, tom].

Related

How to translate "one of the ends" of a list in Prolog?

It is said that Eno is in a cinema where there are 4 seats. Eno is seated at one of the ends.
What I would like to know is how I can translate the "one of the ends" into a code.
Here, the 4 seats is a List P with a length of 4.
What I tried is using nth1:
one_of_the_end(ListP, Eno):- nth1(1, ListP, Eno);nth1(4, ListP, Eno).
However it doesn't work.
Could you help me ?
Thank you in advance
Since Eno is the name of a specific person and not a variable, you should represent it in Prolog as eno (or if you prefer, 'Eno'). So a simple solution is as follows:
eno_at_one_end([eno, _, _, _]).
eno_at_one_end([_, _, _, eno]).
Examples:
?- eno_at_one_end([ann, bob, coy, eno]).
true.
?- eno_at_one_end([ann, bob, eno, coy]).
false.
?- eno_at_one_end([ann, eno, bob, coy]).
false.
?- eno_at_one_end([eno, ann, bob, coy]).
true .
?- eno_at_one_end([ann, bob, coy, dan]).
false.
Can express in swi-prolog as e.g.:
?- length(Seats, 4), (Seats = [Eno|_] ; last(Seats, Eno)).
Seats = [Eno,_,_,_] ;
Seats = [_,_,_,Eno].
or
?- length(Seats, 4), member(Pos, [1, 4]), nth1(Pos, Seats, Eno).
Seats = [Eno,_,_,_],
Pos = 1 ;
Seats = [_,_,_,Eno],
Pos = 4.

; (or) operator in Prolog not returning true unless the left side is true, even if the right side of the operator returns true by itself

I'm trying to return true if either of the two rules on opposite sides of an or operator succeed in Prolog. It only works if what's on the left side of the or operator is found to be true.
It seems like my code should work according to http://www.cse.unsw.edu.au/~billw/dictionaries/prolog/or.html.
Case2 works when case1 is commented out, so it should be returning true, but because it is on the right side of the operator, it isn't. (?)
For clarity, the parameters mean Person1, Person2, TypeOfCousinsTheyAre, DegreesRemovedTheyAre. I am trying to write rules that determine whether two people are first-cousins-once-removed.
Here is the line that uses the or operator which won't return true if the right side is true:
cousins(A, B, 1, 1) :- ( cousinsCase1(A, B, 1, 1) ; cousinsCase2(A, B, 1, 1) ).
Other things I have tried:
(1) Omitting the or operator and writing two identical functions, but whenever they are called and the top one fails, my program crashes.
cousins(A, B, 1, 1) :- var(FirstCousin),
cousin(A, FirstCousin, 1, 0),
parent(FirstCousin, B),
A \= B.
cousins(A, B, 1, 1) :- var(P1),
parent(P1, A),
cousin(P1, B, 1, 0),
A \= B,
A \= P1,
B \= P1.
(2) I have also tried an if-statement to call the other function if the first one fails, but it crashes if the first case fails again.
cousins(A, B, 1, 1) :- cousinsCase1(A, B, 1, 1) -> true ; cousinsCase2(A, B, 1, 1)).
Is there a different way to call the other rule if the first one fails?
EDIT
To take the advice given, here is more of the code:
Facts:
parent(gggm, ggm).
parent(ggm, gm).
parent(gm, m).
parent(m, self).
parent(self, d).
parent(d, gd).
parent(gggm, gga).
parent(gga, c12a).
parent(c12a, c21a).
parent(c21a, c3).
parent(ggm, ga)
parent(ga, c11a).
parent(c11a, c2).
parent(gm, a).
parent(a, c1).
parent(m, s).
parent(s, n).
parent(n, gn).
parent(c1, c11b).
parent(c11b, c12b).
parent(c2, c21b).
parent(c21b, c22).
parent(c3, c31).
parent(c31, c32).
Other rules I have written in order to get the above ones to work:
% Sibling Rule
sibling(A, B) :- parent(P, A), parent(P, B), A \= B.
% First-cousin Rule:
cousin(A, B, 1, 0) :- sibling(P1, P2), parent(P1, A), parent(P2, B).
% Second-cousin Rule:
cousin(A, B, 2, 0) :- parent(P1, A),
parent(P2, B),
parent(PP1, P1), % your grandparent
parent(PP2, P2), % your grand-aunt/uncle
sibling(PP1, PP2). % they're siblings
% 3rd-cousin and more Rule
cousin(A, B, M, 0) :- ReducedM = M - 1,
cousin(A, B, ReducedM, 0).
Calls to the above rules: Sidenote: Both calls do work but the problem is getting them both to work without commenting out the other rule:
cousins(self, c11b, 1, 1).
This call corresponds to the first "1st-cousin, once-removed" case and the case returns the correct answer of true if the other case is commented out.
cousins(self, c11a, 1, 1).
This call corresponds to the second "1st-cousin, once-removed" case and the case returns the correct answer of true if the other case is commented out.
This is a comment in an answer because it will not format correctly in a comment.
What most beginners to Prolog don't realize early enough is that Prolog is based on logic (that they realize) and the three basics operators of logic and, or and not are operators in Prolog, namely (, ; \+). It is not realizing those operators for what they really are.
Starting with not which in Prolog use to be not/1 but is now commonly (\+)/1.
?- \+ false.
true.
?- \+ true.
false.
or using the older not/1 which you can use but is like speaking in a Shakespearean play because it is no longer done this way. I am including this here because many older examples still have it in the examples this way.
?- not(true).
false.
?- not(false).
true.
Next is and which in Prolog is ,/2.
The reason many new Prolog users don't see this as logical and is that a , in many other programming languages is seen as a statement separator (Ref) and acting much like a , in an English sentence. The entire problem with understating , in programming is that it is really an operator and is used for so many things that programmers don't even realize that it should almost always be thought of as an operator but with many different meanings, (operator overloading). Also because , is used as a statement separator, the statements are typically put on separate lines and some programmers even think that a comma (,) is just a statement end like a period (.) is a line end in a sentence; that is not the way to think of these single character operators. They are operators and need to be seen and comprehended as such.
So now that you know where and how your ideas that cause you problems are coming from, the next time you see a comma , or a period . in a programming language really take time to think about what it means.
?- true,true.
true.
?- true,false.
false.
?- false,true.
false.
?- false,false.
false.
Finally logical or which in Prolog is ;/2 or in DCGs will appear as |/2. The use of |/2 in DCGs is the same as | in BNF.
?- true;true.
true ;
true.
?- true;false.
true ;
false.
?- false;true.
true.
?- false;false.
false.
The interesting thing to note about the results of using or (;) in Prolog is that it will they will return when true as many times as one of the propositions is true and false only when all of the propositions are false. (Not sure if proposition is the correct word to use here). e.g.
?- false;false;false.
false.
?- false;false;true.
true.
?- true;false;true.
true ;
true.
?- true;true;true.
true ;
true ;
true.
In case you didn't heed my warning about thinking about the operators when you see them, how many of you looked at
?- true,true.
true.
and did not think that would commonly be written in source code as
true,
true.
with the , looking like a statement end. , is not a statement end, it is the logical and operator. So do yourself a favor and be very critical of even a single , as it has a specific meaning in programming.
A reverse way to get this idea across is to use the addition operator (+) like a statement end operator which it is not but to someone new to math could be mistakenly taken to be that as seen in this reformatting of a simple math expression.
A =
1 +
2 +
3
That is not how one is use to seeing a simple math expression, but in the same way how some programmers are looking at the use of the , operator.
Over the years one thing I have seen that divides programmers who easily get this from the programmers who struggle with this all their careers are those that do well in a parsing class easily get this because they have to parse the syntax down to the tokens such as ,, then convert that into the semantics of the language.
For more details see section 1.2. Control on page 23 of this paper.
EDIT
You really need to use test cases. Here are two to get you started.
This is done using SWI-Prolog
:- begin_tests(family_relationship).
sibling_test_case_generator(ggm ,gga ).
sibling_test_case_generator(gga ,ggm ).
sibling_test_case_generator(gm ,ga ).
sibling_test_case_generator(ga ,gm ).
sibling_test_case_generator(m ,a ).
sibling_test_case_generator(a ,m ).
sibling_test_case_generator(self,s ).
sibling_test_case_generator(s ,self).
test(01,[forall(sibling_test_case_generator(Person,Sibling))]) :-
sibling(Person,Sibling).
cousin_1_0_test_case_generator(gm ,c12a).
cousin_1_0_test_case_generator(ga ,c12a).
cousin_1_0_test_case_generator(m ,c11a).
cousin_1_0_test_case_generator(a ,c11a).
cousin_1_0_test_case_generator(self,c1 ).
cousin_1_0_test_case_generator(s ,c1 ).
cousin_1_0_test_case_generator(d ,n ).
cousin_1_0_test_case_generator(c12a,gm ).
cousin_1_0_test_case_generator(c12a,ga ).
cousin_1_0_test_case_generator(c11a,m ).
cousin_1_0_test_case_generator(c11a,a ).
cousin_1_0_test_case_generator(c1 ,self).
cousin_1_0_test_case_generator(c1 ,s ).
cousin_1_0_test_case_generator(n ,d ).
test(02,[nondet,forall(cousin_1_0_test_case_generator(Person,Cousin))]) :-
cousin(Person, Cousin, 1, 0).
:- end_tests(family_relationship).
EDIT
By !Original:J DiVector: Matt Leidholm (LinkTiger) - Own work based on: Cousin tree.png, Public Domain, Link
This is an answer.
Using this code based on what you gave in the question and a few changes as noted below this code works. Since you did not give test cases I am not sure if the answers are what you expect or need.
parent(gggm, ggm).
parent(ggm, gm).
parent(gm, m).
parent(m, self).
parent(self, d).
parent(d, gd).
parent(gggm, gga).
parent(gga, c12a).
parent(c12a, c21a).
parent(c21a, c3).
parent(ggm, ga).
parent(ga, c11a).
parent(c11a, c2).
parent(gm, a).
parent(a, c1).
parent(m, s).
parent(s, n).
parent(n, gn).
parent(c1, c11b).
parent(c11b, c12b).
parent(c2, c21b).
parent(c21b, c22).
parent(c3, c31).
parent(c31, c32).
% Sibling Rule
sibling(A, B) :-
parent(P, A),
parent(P, B),
A \= B.
% First-cousin Rule:
cousin(A, B, 1, 0) :-
sibling(P1, P2),
parent(P1, A),
parent(P2, B).
% Second-cousin Rule:
cousin(A, B, 2, 0) :-
parent(P1, A),
parent(P2, B),
parent(PP1, P1), % your grandparent
parent(PP2, P2), % your grand-aunt/uncle
sibling(PP1, PP2). % they're siblings
% 3rd-cousin and more Rule
cousin(A, B, M, 0) :-
% ReducedM = M - 1,
ReducedM is M - 1,
ReducedM > 0,
cousin(A, B, ReducedM, 0).
cousinsCase1(A, B, 1, 1) :-
% var(FirstCousin),
cousin(A, FirstCousin, 1, 0),
parent(FirstCousin, B),
A \= B.
cousinsCase2(A, B, 1, 1) :-
% var(P1),
parent(P1, A),
cousin(P1, B, 1, 0),
A \= B,
A \= P1,
B \= P1.
cousins(A, B, 1, 1) :-
(
cousinsCase1(A, B, 1, 1)
;
cousinsCase2(A, B, 1, 1)
).
The first change was as Paulo noted and the checks for var/2 were commented out.
The next change was to change = to is.
The third change to stop infinite looping was to add ReducedM > 0,.
This query now runs.
?- cousins(Person,Cousin,1,1).
Person = gm,
Cousin = c21a ;
Person = ga,
Cousin = c21a ;
Person = m,
Cousin = c2 ;
Person = a,
Cousin = c2 ;
Person = self,
Cousin = c11b ;
Person = s,
Cousin = c11b ;
Person = d,
Cousin = gn ;
Person = c12a,
Cousin = m ;
Person = c12a,
Cousin = a ;
Person = c12a,
Cousin = c11a ;
Person = c11a,
Cousin = self ;
Person = c11a,
Cousin = s ;
Person = c11a,
Cousin = c1 ;
Person = c1,
Cousin = d ;
Person = c1,
Cousin = n ;
Person = n,
Cousin = gd ;
Person = m,
Cousin = c12a ;
Person = self,
Cousin = c11a ;
Person = d,
Cousin = c1 ;
Person = gd,
Cousin = n ;
Person = c21a,
Cousin = gm ;
Person = c21a,
Cousin = ga ;
Person = c11a,
Cousin = c12a ;
Person = c2,
Cousin = m ;
Person = c2,
Cousin = a ;
Person = a,
Cousin = c12a ;
Person = c1,
Cousin = c11a ;
Person = s,
Cousin = c11a ;
Person = n,
Cousin = c1 ;
Person = gn,
Cousin = d ;
Person = c11b,
Cousin = self ;
Person = c11b,
Cousin = s ;
false.

Why does a distinct query return duplicate values?

Here is the program:
sibling(joe, mary).
sibling(joe, bob).
person(P) :- distinct(sibling(P, _); sibling(_, P)).
Here is the query:
person(P).
I would expect to get 3 names, instead I get 4.
In short: Prolog keeps track of all variables that come out of the goal, including don't cares (_).
The problem is that you introduce free variables here, that are not distinct. Indeed, as is specified in the documentation of distinct/1 [swi-doc]. The above is functionally equivalent to:
distinct(Goal) :-
findall(Goal, Goal, List),
list_to_set(List, Set),
member(Goal, Set).
Now if we make a simple call with sibling(P, _), we get:
?- Goal = sibling(P, _), distinct(Goal).
Goal = sibling(joe, mary),
P = joe ;
Goal = sibling(joe, bob),
P = joe.
or with a goal with a logical "or":
?- Goal = (sibling(P, _); sibling(_, P)), distinct(Goal).
Goal = (sibling(joe, mary);sibling(_4908, joe)),
P = joe ;
Goal = (sibling(joe, bob);sibling(_4908, joe)),
P = joe ;
Goal = (sibling(mary, _4904);sibling(joe, mary)),
P = mary ;
Goal = (sibling(bob, _4904);sibling(joe, bob)),
P = bob.
So as you can see, Goal is unified twice: once with sibling(joe, mary), and once with sibling(joe, bob). The uniqness filter will not have any effect, since mary is not the same as bob.
We can however define a helper predicate here, to get rid of these variables, like:
person(P) :-
sibling(P, _).
person(P) :-
sibling(_, P).
and then we can query with:
?- Goal = person(P), distinct(Goal).
Goal = person(joe),
P = joe ;
Goal = person(mary),
P = mary ;
Goal = person(bob),
P = bob.
or without using a Goal variable:
?- distinct(person(P)).
P = joe ;
P = mary ;
P = bob.

Rule for amount of facts

For a school project I want to make a planning maker in Prolog. I want Prolog to make a planning for every day. On each day a certain amount of employees are needed and employees can only work on certain days. I want Prolog to make a planning that plans the right amount of people on each day. For that I wrote the following code:
workingday_employeesneeded(monday, 2).
workingday_employeesneeded(tuesday, 1).
workingday_employeesneeded(wednesday, 2).
employee_availability(tom, monday).
employee_availability(thomas, monday).
employee_availability(timme, monday).
employee_availability(timo, monday).
employee_availability(tom, tuesday).
planning(Employee, Day) :-
workingday_employeesneeded(Day, Amount),
employee_availability(Employee, Day).
planning(Employee, Day) :-
aggregate_all(count, planning(Employee, Day), Count),
workingday_employeesneeded(Day, Amount),
Count <= Amount.
However, I can't get Prolog to give me the right result, as I query the following Prolog gives me all the options, not regarding the amount of employees needed.
?- planning(X, Y).
X = tom,
Y = monday ;
X = thomas,
Y = monday ;
X = timme,
Y = monday ;
X = timo,
Y = monday ;
X = tom,
Y = tuesday ;
false.
Can you guy's see what I'm doing wrong? Thanks in advance!
EDIT:
I thought it might be handy to make a list of employees for each day in the planning. So I edited the code to the following (also fixing some syntax errors pointed out in the comments);
planning_on_day(Day, Employees) :-
workingday_employeesneeded(Day, Amount),
findall(E, employee_availability(E, Day), Employees),
length(Employees, Amount).
The following problem still exists; if there are more employees available than needed the program does not print the planning for that day instead of only picking the first N employees.
Do you guys have suggestions to fix that problem?
Simply your predicate fails because first you use findall/3 then you constraint the length of the list. For instance, for monday there are 4 employees available, you find all of them with findall/3 and store into Employees. Then you check the lenght of the list and it fails. To solve it you need find all the available employees and then find a subset of the list with desired length. So your code will be:
subset([], []).
subset([E|Tail], [E|NTail]):-
subset(Tail, NTail).
subset([_|Tail], NTail):-
subset(Tail, NTail).
planning_on_day(Day, Employees) :-
workingday_employeesneeded(Day, Amount),
findall(E, employee_availability(E, Day), E),
length(Employees,Amount),
subset(E,Employees).
?- planning_on_day(monday,P).
P = [tom, thomas]
P = [tom, timme]
P = [tom, timo]
P = [thomas, timme]
P = [thomas, timo]
P = [timme, timo]
false
?- planning_on_day(tuesday,P).
P = [tom]
false
?- planning_on_day(wednesday,P).
false
Then, if you want find the plan of the week you can add:
isDifferent(_, []).
isDifferent(X, [H | T]) :-
X \= H,
isDifferent(X, T).
allDifferent([]).
allDifferent([H | T]) :-
isDifferent(H, T),
allDifferent(T).
solve([],Plan,Plan):-
flatten(Plan,P),
allDifferent(P).
solve([Day|T],LT,Plan):-
workingday_employeesneeded(Day, Amount),
planning_on_day(Day,PlanD),
length(A,Amount),
subset(PlanD,A),
append(LT,[PlanD],LT1),
solve(T,LT1,Plan).
?- solve([monday,tuesday],[],L).
L = [[thomas, timme], [tom]]
L = [[thomas, timo], [tom]]
L = [[timme, timo], [tom]]

Knowledge Based System of a family tree in SWI-Prolog

I have these family facts:
male(jerry).
male(stuart).
male(warren).
male(peter).
female(kather).
female(maryalice).
female(ann).
brother(jerry,stuart).
brother(jerry,kather).
brother(peter, warren).
sister(ann, maryalice).
sister(kather,jerry).
parent_of(warren,jerry).
parent_of(maryalice,jerry).
And using the base predicates male, female and parent_of I want to define father, mother, son, daughter, sibling, spouse and parent_of.
This is what I have done:
father(P,C) :- male(P), parent_of(P,C).
mother(P,C) :- female(P), parent_of(P,C).
son(C,P) :- male(C), parent_of(P,C).
daughter(C,P) :- female(C), parent_of(P,C).
sibling(C,OC) :- parent_of(P,C), parent_of(P,OC).
spouse(H,W) :- parent_of(H,C), parent_of(W,C).
parent_of(P,C) :-
( ( sister(C,OC) ; sister(OC,C))
; ( brother(C,OC) ; brother(OC,C))).
By querying parent_of(P,C) it should return that warren is a parent of jerry,stuart and kather and that maryalice is a parent of jerry, stuart and kather also. But this is what I get:
?- parent_of(X,Y).
X = warren,
Y = jerry ;
X = maryalice,
Y = jerry ;
Y = ann ;
Y = kather ;
Y = maryalice ;
Y = jerry ;
Y = jerry ;
Y = jerry ;
Y = peter ;
Y = stuart ;
Y = kather ;
Y = warren.
It does not make any sense! Any help is much appreciated!
Kind regards,
Richard
I fully agree with the answer by danielp, but I hope to attract your attention on another problem, that maybe has gone unnoticed: why X appears only on the first two results ? That's because your last predicate is effectively
parent_of(P,C) :- sister(C,OC).
parent_of(P,C) :- sister(OC,C).
parent_of(P,C) :- brother(C,OC).
parent_of(P,C) :- brother(OC,C).
and P is never bound by such rules. So, you're right
It does not make any sense!
You mixed up facts and predicates which is basically possible but not a recommended approach (at least in this case).
You wrote that you want to define male, female and parent_of as basic facts but in your first source code above you define also sister and brother. That you can easily define by a rule like "S is a sister of X when S is female and has a parent C and X has the same parent C and is not equal to S".
There is no need for re-defining parent_of by sister and brother.
Now let's have a look at the result of your query:
The first two results are the facts you defined (warren and jerry, marryalice and jerry).
The next results are produced by your predicate. Since you did not specify anything about the variable P it remains unbound and is not printed in the result (thus only Y = ... is shown).
And the variable C in the predicate fulfills one of the four conditions you specified (C is a sister of somebody (ann, kather), somebody is a sister of C (maryalice,jerry), C is a brother of somebody (two times jerry, peter) or somebody is a brother of C (stuart, kather, warren).
Summary: Replace the definitions of brother and sister by rules and drop the parent_of predicate.

Resources