Prolog: is valid distribution Rule - prolog

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.

Related

Prolog simple rules

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).

Relational Learning: What does this Prolog Output say?

I need to find relations in a prolog dataset. I have different kinds of trains with different features, for example Train1:
has_car(rel_east1,car_11).
has_car(rel_east1,car_12).
has_car(rel_east1,car_13).
infront(car_11,car_12).
infront(car_12,car_13).
size(car_11,long).
size(car_12,long).
size(car_13,short).
shape(car_11,hexagon).
shape(car_12,rectangle).
shape(car_13,hexagon).
load(car_11,rectangle).
load(car_12,circle).
load(car_13,triangle).
I have ten different trains. Now I used the Metagol algorithm which shall learn the different relations within the different trains. As a result I get a list with different clauses. And here is my problem: I don't understand the inductive steps in between the clauses. For example:
relational(A):-has_car(A,B),relational_1(B).
relational_1(A):-relational_2(A,rectangle).
relational_2(A,B):-relational_3(A),shape(A,B).
relational_3(A):-infront(A,B),relational_4(B).
relational_4(A):-load(A,triangle).
The only thing I know is, that the whole clause says: "There is a Train which contains a car which is in the shape rectangle. This car is in front of another car which contains a triangle."
But can anybody explain the code to me? Line for line?
For example, I don't understand how to read the 2nd line: "If there is a relation 1 with A, then there is also a relation 2 between A and rectangle"?
I am not 100% sure, but I think the relational_x predicates, are relations (predicates) that are 'invented' by metagol for your learning task.
As naming invented predicates is a hard task (for which there is not a good solution for ) you get these type of names.
For instance if you used the example `kinship1' here : https://github.com/metagol/metagol
?- [kinship1].
Warning: /media/sam/9bb6ab40-5f17-481e-aba8-7bd9e4e05d66/home/sam/Documents/Prolog_practise/metagol/metagol.pl:250:
Local definition of metagol:list_to_set/2 overrides weak import from lists
true.
?- a.
% learning grandparent/2
% clauses: 1
% clauses: 2
% clauses: 3
grandparent_1(A,B):-father(A,B).
grandparent_1(A,B):-mother(A,B).
grandparent(A,B):-grandparent_1(A,C),grandparent_1(C,B).
true .
It learns the grandparent/2 relation by also learning grandparent_1/2. Which we as humans would call parent/2.
So relational_4(A):-load(A,triangle). you might call 'car carrying a load which is triangle shaped' . and relational_3(A):-infront(A,B),relational_4(B). would then be 'car in front of a car carrying a load which is triangle shaped' etc
relational_4(A):-load(A,triangle).
If an object A is loaded with a triangle then A is relational_4
or
There is a car which has a load which is a triangle.
relational_3(A):-infront(A,B),relational_4(B).
If an object A is infront of object B and B is relational_4 then A is relational_3
or
Car A is infront of a car B which has a load which is a triangle
relational_2(A,B):-relational_3(A),shape(A,B).
If A is relational_3 and has shape B then A relational_2 B.
or
Car A is a car infront of another car which is loaded with a triangle, car A has an unspecified shape.
relational_1(A):-relational_2(A,rectangle).
If an object A is relational_2 rectangle then A is relational_1
or
There is a car which has a rectangle shape, it is infront of a car which caries a triangle load.
relational(A):-has_car(A,B),relational_1(B).
If an object A has a car B and B is relational_1 then relational A.
There is a train which has a car, that car is a rectangle in shape and it is infront of a car that has a triangle load

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.

Checking List in Prolog

I'm trying to do a schedule that has constraints in Prolog. Scheduling will be based on two constraints. The courses of the same semester and the courses taught by the same instructor cannot be scheduled to the same time slot.
course(ceng123,1).
Course code and semester of course.
slot(monday,1).
Day and hour on day.
teaches(jack,ceng123).
Teacher and course code.
course(cse111,1).
course(cse112,1).
course(cse113,1).
course(cse114,1).
course(cse115,2).
course(cse116,2).
course(cse117,2).
course(cse118,2).
slot(monday,1).
slot(monday,2).
slot(tuesday,1).
slot(tuesday,2).
teaches(erkan,cse111).
teaches(erkan,cse112).
teaches(erkan,cse113).
teaches(erkan,cse114).
teaches(merkan,cse115).
teaches(merkan,cse116).
teaches(kan,cse117).
teaches(kan,cse118).
The answer that I expect is:
?- schedule([cse111,cse112,cse113,cse114,cse115,cse116,cse117,cse118],X).
X = [cse111, monday, 1, cse112, monday, 2, cse113, tuesday, 1, cse114, tuesday, 2, cse115, monday, 1, cse116, monday, 2, cse117, tuesday, 1, cse118, tuesday, 2]
I wrote a code that has no constraints:
course(cse111,1).
course(cse112,1).
course(cse113,1).
course(cse114,1).
course(cse115,2).
course(cse116,2).
course(cse117,2).
course(cse118,2).
slot(monday,1).
slot(monday,2).
slot(tuesday,1).
slot(tuesday,2).
teaches(erkan,cse111).
teaches(erkan,cse112).
teaches(erkan,cse113).
teaches(erkan,cse114).
teaches(merkan,cse115).
teaches(merkan,cse116).
teaches(kan,cse117).
teaches(kan,cse118).
schedule([],[]).
schedule([Course|CourseTail],[Course,Day,Slot|ScheduleTail]):-
slot(Day,Slot),schedule(CourseTail,ScheduleTail).
There is no problem, but when i try this;
course(cse111,1).
course(cse112,1).
course(cse113,1).
course(cse114,1).
course(cse115,2).
course(cse116,2).
course(cse117,2).
course(cse118,2).
slot(monday,1).
slot(monday,2).
slot(tuesday,1).
slot(tuesday,2).
teaches(erkan,cse111).
teaches(erkan,cse112).
teaches(erkan,cse113).
teaches(erkan,cse114).
teaches(merkan,cse115).
teaches(merkan,cse116).
teaches(kan,cse117).
teaches(kan,cse118).
schedule([],[]).
schedule([Course|CourseTail],[Course,Day,Slot|ScheduleTail]):-
schedule(CourseTail,ScheduleTail), check(Course,Day,Slot,ScheduleTail).
check(_, _, _,[]).
check(Course,Day,Slot,[Course2,Day2,Slot2|Tail]):- check(Course,Day,Slot,Tail),
course(Course,Semester1),course(Course2,Semester2),Semester1=\=Semester2,
slot(Day,Slot),slot(Day2,Slot2).
I tried to write constraint but I took an error.
uncaught exception: error(syntax_error('user_input:1 (char:4) . or operator expected after expression'),read_term/3)
Can you see the mistake?
Singleton variable is a variable which is mentioned only once in the program: See wiki. You get that for line 27 which I presume is this one: check(Course,Day,Slot,[]). You can replace it with check(_, _, _,[]). ('_' means any variable. This means you can universally quantify the variables.)
You do not get an error. Prolog saying no just means that your constraints cannot be satisfied.
You should start by clearly defining your constraints.
From your comments, I read:
Two courses in an hour cannot have same semester number and same teacher's courses will not be in same hour.
Therefore you can assign a schedule to a course when it fulfills those requirements, hinting that you have to know which assignments have been already issued. So you can create a procedure that keeps the current schedule and only add a new assignment when your requirements are met.
So, start by defining your schedule/2 procedure that calls a new procedure schedule/3 with an empty list:
schedule(Courses,Schedule):-
schedule(Courses, [], Schedule).
Now, this procedure has on the first argument the list of courses to assign a schedule, keeps the current assignments con the second argument and unifies the third argument with the final Schedule (with the data you require, that is Course, Day and Slot).
I'll use a structure to represent each assignment schedule(Course, Day, Slot) because just mixing those datum in a list is not a good idea.
schedule([], _, []).
schedule([Course|CourseTail], Courses, [schedule(Course,Day,Slot)|ScheduleTail]):-
% Two courses in an hour cannot have same semester number and same teacher's courses will not be in same hour.
course(Course, Semester),
teaches(Teacher, Course),
slot(Day, Slot),
\+ member(s(Day, Slot, Semester, _), Courses),
\+ member(s(Day, Slot, _, Teacher), Courses),
schedule(CourseTail, [s(Day, Slot, Semester, Teacher)|Courses], ScheduleTail).
First clause is the base case. It states that when there are no more courses in the input list, then the schedule will be empty.
Second clause takes the first Course from the input list and computes a possible Semester, Theacher and Day/Slot for that course, and then just checks if the constraints are met. It tests whether there is already a schedule for that Day/Slot/Semester and whether there is already an assignment for the Teacher at that Day/Slot. If the requirements are met then we add this assignment to the list of current assignments and continue recursion.
Upon return, we add the Course/Day/Slot to the list of the final Schedule.

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"]).

Resources