Related
I'm currently learning Prolog and I want to create a specific rule which will check if a person can watch a film. The condition for true should be age of person equal of higher than required age for film.
So I have something like that:
person("John",19).
person("Kate",14).
person("Carl",8).
film("Shining",18,"Horror").
film("Little Agents",13,"Family").
film("Frozen",7,"Animation").
can_borrow(film(_,Age1,_),person(_,Age2)):-Age2>=Age1.
And if I ask i.e.
?- can_borrow(film("Shining",18,"Horror"),person("John",19)).
It works and returns true.
But when I ask to show me all possible combinations (all films which every person can watch)
?- can_borrow(X,Y).
I have an error:
ERROR: Arguments are not sufficiently instantiated
How to write the rule properly, so it would work as I've written above?
Thanks in advance.
The film(_, Age1, _) and person(_, Age2) in can_borrow(film(_, Age1, _), person(_, Age2)) are just terms with a functor that happens to be the same as a predicate. But Prolog does not attach special meanings to it. You should here call predicates to unify the terms. For example:
can_borrow(film(Title, Age1, Genre), person(Name, Age2)) :-
film(Title, Age1, Genre),
person(Name, Age2),
Age1 =< Age2.
I am new to Prolog as a whole and i am learning prolog query.
I am looking at this tutorial.
http://www.cs.trincoll.edu/~ram/cpsc352/notes/prolog/factsrules.html
and trying to play around with my own database.
Person("Mike", "123456"). //Person(Name,ID)
Info("CA", "123456", "17"). //Info(State, ID, Age)
What I am trying to do:
I am trying to return someone's age by their name and State.
by doing the following query, this should return 17.
Age_Of(Name, State, N) :- Info(State, Person(Name, X), N).
i tried the above code and it returns "No". I believe that it is still evaluate as boolean. However, I want the function to return the actual age.
First of all, let's point some facts:
You should write your database of facts without using a capital letter as first letter. So Person("Mike", "123456"). should be person("Mike", "123456"). and Info("CA", "123456", "17"). should be info("CA", "123456", "17").
In prolog there are not functions but only predicates and should be defined aswell using non capital letter, so Age_Of(Name, State, N) should be age_of(Name, State, N).
Even if you remove all first capital letter, you get Singleton variables: [X] while you execute the code. This mean that you dhave defined a variable, in this case X, but not used anywhere. In this case, you should replace every singleton variable with _ or add _ before the variable (_X in this case).
To solve your problem, this is the solution:
person("Mike", "123456"). % person(Name,ID)
info("CA", "123456", "17"). % info(State, ID, Age)
age_of(Name, State, Age):-
person(Name,ID),
info(State, ID, Age).
So first you have to find the ID of a person with a given name and then find the corresponding age. Query:
?- age_of(Name,State,Age).
Age = "17",
Name = "Mike",
State = "CA"
This query is quite generic, you can be more specific (for instance, specifing a name). Hope it helps.
% 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.
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.
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,
--...