Prolog simple rules - prolog

Started learning Prolog 2 days ago and came across this problem, I'm trying to program both rules at the end but they don't seem to work correctly. What am I doing wrong?
% gender/2: identifies the gender of a person
gender(beto,male).
gender(willy,male).
gender(caonabo,male).
gender(haley,female).
gender(mary,female).
gender(yoli,female).
%friend/2 specifies the friendship between two persons
friend(beto,willy).
friend(willy,caonabo).
friend(willy,haley).
friend(haley,mary).
friend(haley,yoli).
% Rule to know if a person has any female friends
has_fFriend(person):- friend(person,friend),genero(friend,female).
% Rule to know if the person has any friends of it's same gender
homofriend(person):- friend(person,friend), gender(person,X) == gender(friend,X).

Related

Prolog: is valid distribution Rule

I am new to Prolog, how should I think to find the right solution without pre-defined/built-in predicates?
Writing a rule is required is_valid_distribution rule
Test the distribution of students and teachers over classes
students([s1,s2,s3,s4]).
teachers([t1,t2, t3]).
Constraints:
A student is not allowed to be in two classes at the same time, nor twice in one class!
Sum of students in two classes = the total number of students (i.e All students are present).
Teachers could be more than two in the same class, but every class must has at least one teacher.
Class not allowed to be empty or has just teachers, i.e. class must have at least one student and one teacher.
Develop a general solution, i.e. your rules must solve the problem with different facts like:
students([s1,s2,s3,s4, ahmad, ali, maya]).
teachers([t1,t2, omar]).
Don't define any other facts.
You are invited to define any necessary rules which maight help you solve the problem!
succeeded tests:
is_valid_distribution([t1,s1,s2], [t2,s3,s4]). % idial case
is_valid_distribution([t1,s1,s2], [t2,t3,s3,s4]). % more than one teacher in one class is allowed.
faild tests:
is_valid_distribution([t1,s1,s2], [t2,s1,s3,s4]). % student appears in two classes at same time.
is_valid_distribution([t1,s1,s1], [t2,s3,s4]). % student appears twice in one class.
is_valid_distribution([t1,s1,s2], [t1,s3,s4]). % teacher appears in two classes at same time.
is_valid_distribution([t1,t1, s1,s2], [t2,s3,s4]). % teacher appears twice in one class
is_valid_distribution([t1,s1,s2], [t2,s3]). % sum of students != all students.
is_valid_distribution([t1,s1,s2], [s3,s4]). % no teachers in class2.
is_valid_distribution([], [t1,t2,s1,s2,s3,s4]). % empty class not allowed
is_valid_distribution([t1], [t1,t2,s1,s2,s3,s4]). % class with one teacher is not allowed.
Your solution can have the following general structure:
is_valid_distribution(Class1, Class2) :-
students(Students),
teachers(Teachers),
no_student_twice(Students, Class1, Class2), % constraint 1
all_students_in_some_class(Students, Class1, Class2), % constraint 2
at_least_one_teacher_per_class(Teachers, Class1, Class2), % constraint 3
at_least_one_student_per_class(Students, Class1, Class2). % constraint 4
Now you "only" need to implement rules capturing the different constraints. I won't show you all of them, but here for example is the implementation of constraint 4:
at_least_one_student_per_class(Students, Class1, Class2) :-
% there is some student in class 1
member(Student1, Students),
member(Student1, Class1),
% there is some student in class 2
member(Student2, Students),
member(Student2, Class2).
I hope this gives you a starting point.

Prolog: can we pass a fact as argument to another fact?

I have a rule where I have to check whether a person who works for a department also works for its college and the university. The sample knowledge base is the following:
university(xxx). /*the university*/
col(scienceAndMath,xxx). /*the college of the university*/
dept_col(biology,scienceAndMath). /*the department of the college*/
dept_faculty(michael,biology). /*the faculty member of the department*/
I have to make a rule, namely works_for(X,Y) to check that an individual who works for a department, also works for its college and the university. I am trying to do this in the following manner, but to no avail.
works_for(X,Y):-dept_faculty(X,Y).
works_for(X,Y):-dept_col(works_for(X,Y),Y).
/*also tried works_for(X,Y):-dept_col(dept_faculty(X,Y),Y)./*
For example, for the query works_for(michael,X)., the result should be following:
X = biology
X = scienceAndMath
How do I pass a fact as argument to another fact? At present, the answer of the query is the following:
X = biology
false.

Prolog knowledge query

% A quiz team structure takes the form:
% team(Captain, Vice_captain, Regular_team_members).
% Captain and Vice_captain are player structures;
% Regular_team_members is a list of player structures.
% player structures take the form:
% player(First_name, Surname, details(Speciality,Recent_score)).
team(player(niall,elliott,details(history,11)),
player(michelle,cartwright,details(fashion,19)),
[player(peter,lawlor,details(science,12)),
player(louise,boyle,details(current_affairs,17))]).
I've been given the database above (I haven't copied over all the entries of people as it would be too long).
I've been asked to get the surname of any vice-captain whose team includes a captain or a regular team member whose speciality is science.
I can get the surname of the vice-captains using the code below but I can't return only those teams that include a captain or regular team members whose speciality is science. What would I need to add to do this?
part_two(Surname):-
team(_,player(_,Surname,_),_).
I've also been asked to also get the first name and the surname of any captain whose regular team members number more than one and who all have the same surnames.
This is my attempt so far:
part_three(First_name,Surname):-
team(Captain,_,Regular_team_members),
first_name(Captain,First_name),
surname(Captain,Surname),
Regular_team_members=[_,_|_].
I just need to exclude the details of those captains whose regular team members don't all have the same surname.
part_two(Surname):-
team(Captain, Vice_captain, Regular_team_members),
surname(Vice_captain, Surname),
member(Player, [Captain|Regular_team_members]),
specialty(Player, science).
% 'abstract data structures' accessors
surname(player(_First_name, Surname, _Details), Surname).
specialty(player(_First_name, _Surname, details(Speciality, _Recent_score)), Speciality).
Since you're going anyway to scan the Regular_team_members list, looking for appropriate constraint, you can get a simpler 'program' first 'joining' the Captain to other players.
You could change a little what you have already written as follows:
part_two(Surname):-
team(P,player(_,Surname,_),L),
( P=player(_,_,details(science,_)) -> true ; member(player(_,_,details(science,_)),L) ).
Example:
Database:
team(player(niall,elliott,details(history,11)),
player(michelle,cartwright,details(fashion,19)),
[player(peter,lawlor,details(history,12)),
player(louise,boyle,details(current_affairs,17))]).
team(player(niall1,elliott1,details(science,11)),
player(michelle1,cartwright1,details(fashion,19)),
[player(peter,lawlor,details(history,12)),
player(louise,boyle,details(current_affairs,17))]).
team(player(niall2,elliott2,details(history,11)),
player(michelle2,cartwright2,details(fashion,19)),
[player(peter,lawlor,details(science,12)),
player(louise,boyle,details(current_affairs,17))]).
team(player(niall3,elliott3,details(science,11)),
player(michelle3,cartwright3,details(fashion,19)),
[player(peter,lawlor,details(science,12)),
player(louise,boyle,details(current_affairs,17))]).
Now querying:
?- part_two(X).
X = cartwright1 ;
X = cartwright2 ;
X = cartwright3.

setof/3 and NAF

so I have a set of facts:
course(cs61, "intro to cs")
...
course(cs62b, "data structure")
...
grade(adam, cs61, spring11, "A")
...
grade(chrisitian, cs61, fall2010, "A-")
I need to define a predicate good_standing(Student) to determine whether the Student got A in every class he took. I must use 2 different approaches:
use setof/3
use NAF
on the 1st. I have tried to figure out get Result_list: the set of students that got A from every class he took. and then call member(Student, Result_list). But I don't know what to get the Result_list since the syntax is a bit strange to me.
1) For the NAF solution you should keep in mind that the good-standing student is the one with no grades lower than A, i.e., the one such that there is no course he/she took and the grade is lower than A. We also require this person to take at least one course.
good_standing(Student) :- grade(Student, _,_,_),
\+ (grade(Student, Course, _, Grade),
lower(Grade,"A")).
with lower/2 defining relation between the grades:
lower("A-","A").
lower("B","A").
...
The solution above works if students get only one grade per course.
2) For the setof solution you can find all grades per student and check that they are A.
grade(Student, Grade) :- grade(Student, _,_,Grade).
good_standing(Student) :- setof(Grade, grade(Student,Grade), ["A"]).
Alternatively, as suggested by false we can make the existential quantification explicit within setof:
good_standing(Student) :- setof(Grade,
Course^Period^grade(Student,Course,Period,Grade),
["A"]).

Unique elements in list (Prolog)

I'm implementing a variation on Einstein's Riddle and i'm having some trouble.
When trying to calculate the solution i try this:
solve(Street) :- Street = [_House1,_House2,_House3,_House4,_House5],
%hint one goes here
%hint two goes here
%etc.
I can then ask the solution by typing: solve(Street)
However this comes up as solution:
house(flower, food, pet, sport)
house(flower, food, pet, sport)
house(x , food, pet, sport)
house(flower, food, pet, sport)
house(x, flower, pet, sport)
As you can see there's 2 times x, the rest are all types of foods, flowers, pets and sports.
But every type is unique: if one person likes flower X, noone else can like X.
Now, the reason why my solution gives 2 x's is easy to see: we are given an amount of hints but in all the hints there are only mentioned 4 flowers. So Prolog doesn't know there is another flower, and just uses x twice, just because it's possible and fulfills all the other hints.
What i want to say is that all the types of foods and flowers etc. in Street are unique so he should leave some blank when he used all types already. 3 would look like: house(x , food, pet ,sport) and 5 would look like: house(_, flower, pet, sport).
I also tried adding this to the hints: (let's say "cactus" is one of the flowers not mentioned in the hints)
member(house(cactus,_,_,_), Street)
However then my program doesn't end...
A hint may look like this:
is_neighbour(house(_,_,_,football),house(_,_,fish,_), Street),
with : is_neighbour(A,B,List) giving true when A and B are next to each other in List.
The hint can be translated to: the person who loves football lives next to the person who has fish.
If any more info need to be provided i'm willing to elaborate. :)
To express that no flower is reported twice, and also to make sure that all flowers are bound, you can use the permutation/2 predicate: the list of all flowers should be a permutation of the list of specified flowers. This would read like [untested]
flowers([], []).
flowers([house(Flower,_,_,_)|Street], [Flower|Rest]) :- flowers(Street, Rest).
-- ...
flowers(Street, Flowers),
permutation(Flowers, [kaktus, tulpe, nelke, rose, fingerhut]),
Edit: for 10 flowers, using permutations is probably too slow. An alternative approach is
flower(kaktus).
flower(tulpe).
flower(nelke).
--...
flowers(Street,[F1,F2,F3,F4,F5,F6,F7,F8,F9,F10]),
flower(F1), flower(F2), F1\=F2,
flower(F3), F3\=F1, F3\=F2,
flower(F4), F4\=F1, F4\=F2, F4\=F3,
--...

Resources