Sorting a knowledge database in Prolog - prolog

It's my first day with Prolog, and i need some help.
I have a Konwledge database of students student(Id,fName,lName,grade), I would like to display the list of students in order of merit, I have some ideas but I can not realise theme since I'm not familiar at all with prolog programming paradigm and syntax.
please recommend me a code that do this.

student(1, sleve, mcdichael,4).
student(2, darryl, archideld,2).
student(3, mario, mcrlwain, 1).
student(4, bobson, dugnutt, 3).
student(5, dean, wesrey, 6).
student(6, mike, truk, 5).
student(7, dwigt, rortugal, 7).
sortedStudents(SortedStudents) :-
findall(Grade-First-Last,
student(_, First, Last, Grade),
StudentData),
sort(1, #=<, StudentData, SortedStudents).
Uses findall/3 to get all the student records and turn them into a compound term of grade-firstname-lastname and sort/4 (might be SWI Prolog specific) to sort by term entry 1 (grade):
e.g.
?- sortedStudents(S).
S = [
1-mario-mcrlwain,
2-darryl-archideld,
3-bobson-dugnutt,
4-sleve-mcdichael,
5-mike-truk,
6-dean-wesrey,
7-dwigt-rortugal
]

Related

Prolog Rules (Predicates)

I'm new in Prolog SWI can you help me to solve this.
Suppose have a database with predicates likes (person1, person2) and hobbies (person1, hobby). Now, how can I design a rule such that the system answers that two people have the same kind of liking or not depending on their hobbies.
likes (john, jake).
true
finally, I did it
hobby(harry,music).
hobby(harry,running).
hobby(jocker,swimming).
hobby(jocker,movies).
hobby(jocker,art).
hobby(curl,running).
hobby(curl,art).
hobby(curl,movies).
same_hobby(P1,P2) :-
dif(P1,P2),
hobby(P1,H),
hobby(P2,H).

setof with compound predicate

I am struggling with a question in an assignment with prolog.
So, I have the following fact database in prolog:
student(name(doe, [john]), 33332, ['CSI1120'] ).
student(name(doe, [jane]), 33336, ['CSI1120'] ).
evaluation('CSI1120', homework(1), ['Prolog', database ], 5).
mark('CSI1120', 33332, homework(1), 3.5 ).
mark('CSI1120', 33336, homework(1), 4.0 ).
My goal here is to create a predicate listAllMarks/3 such as
?- returnAllMarks('CSI1120',homework(1),L).
Returns:
L= [(33332, 3.5), (33336, 4.0)].
In order to resolve this problem, I was thinking of making use of the prolog setof/3, so I came with the following predicate.
returnAllMarks(C,H,L):- setof(L,mark(C,_,H,X),[L|X]).
This doesn't seems to work, the predicate always return false. I"m suspecting that this may be due to the fact I am using setof against a compound predicate, but I could be wrong (I'm still in the early stages of learning prolog).
Do you guys have an idea? I look at this problem from all angles, and I am stuck here.
Thank you.
You could write something like:
returnAllMarks(C,H,L):- setof( (X,Y), mark(C,X,H,Y), L).
Example:
?- returnAllMarks('CSI1120',homework(1),L).
L = [ (33332, 3.5), (33336, 4.0)].

Learning Prolog (cuts, lists, negation) push me in the right direction

I have the following base knowledge:
“NBA players over 30 years old that have won at least 3 NBA championships are superstars. NBA players below 30 are superstars only if they appear on the front cover of a videogame or if they have at least 5 million followers in Twitter.”
Define a unary predicate superstar that gives only one answer (true/false) to each query, when applied to a concrete person, e.g. superstar(pauGasol). The rules should only check a fact once (for instance, they should not check the age of the queried person twice). You can’t use the “;” operator.
You can use these data in your tests (4 of these 8 players are superstars, according to the previous definition):
age(kobeBryant,37).
championships(kobeBryant,5).
millionsFollowers(kobeBryant,9).
age(pauGasol,35).
championships(pauGasol,2).
videogameCover(pauGasol).
millionsFollowers(pauGasol,3).
age(marcGasol,31).
videogameCover(marcGasol).
millionsFollowers(marcGasol,1).
age(stephenCurry,28).
championships(stephenCurry,1).
videogameCover(stephenCurry).
millionsFollowers(stephenCurry,5).
age(klayThompson,26).
championships(klayThompson,1).
age(kevinDurant,27).
millionsFollowers(kevinDurant,13).
age(russellWestbrook,27).
videogameCover(russellWestbrook).
millionsFollowers(russellWestbrook,3).
age(dwayneWade,29).
championships(dwayneWade,3).
millionsFollowers(dwayneWade,4).
So what i did was this:
superstar(X):- age(X,Y), Y>=30, championships(X,Z), Z>=3,!.
superstar(X):- age(X,Y), Y=<30, videogameCover(X),!.
superstar(X):- millionsFollowers(X,Z), Z>=5.
We learned lists, cuts and negation last lesson.
Could someone push me in the right direction as to what should i use, so the age is only checked once, and if it's greater then 30 goes one way less then 30 goes other way, im new to prolog and programming in general.
I am not asking for a solution, I am asking for a push, hint.
When i will figure it out, I will post the solution my self hopefully.
The request to access only once a DB table normalizes the AND/OR search tree. You could introduce a service predicate to discriminate a pre-condition.
superstar(X) :- age(X,Y), age_check(X,Y).
now, using the cut, you can actually commit to a branch
age_check(X,Y) :- Y>=30, !, championships(X,Z), Z>=3.
% other 2 rules for age_check, actually not using Y
or, avoid the cut, but use a correct domain disjunction:
age_check(X,Y) :- Y>=30, championships(X,Z), Z>=3.
age_check(X,Y) :- Y<30, etc etc
...
in the end i did it like this:
superstar(A) :- age(A,B), B>=30, !, championships(A,C), C>=3.
superstar(A) :- videogameCover(A),!.
superstar(A) :- millionsFollowers(A,B), B>=5.
This is how the teacher wanted it to be, seems like that is way to complicated for something that can be done simpler:
trichampion(X) :- championships(X,Z), Z>=3.
socialmediastar(X) :- millionsFollowers(X,Z), Z>=5.
superstar(X) :- age(X,Y), Y>=30,!,trichampion(X).
superstar(X) :- videogameCover(X),!.
superstar(X) :- socialmediastar(X).

How can I go through a list of facts in Answer Set Prolog?

I have a list of facts like
student(mary).
student(john).
etc, and also
course(math).
course(a).
course(b).
etc, and
took(john,math).
...
I have to say if a student can or can not graduate.
To graduate a student have to have all the courses taken. But how can I say this without write all term in the rule?
what I think was
can_graduate(X) :- took_all_courses(X).
but I dont know how to explain the rule took all courses without writing all courses. Can someone help me?
thanks.
took_all_courses(Student) :-
student(Student),
forall( course(C), took(Student,C) ).
Since this is Answer-Set Prolog and not Prolog, higher-order predicates such as forall are not available. What you want to do is count firstly the number of courses and secondly the number of courses the student has taken. How about using aggregates for this?
took_all_courses(Student) :-
student(S),
TotalCourses = #max{C:course(C)}, CoursesTaken = #max{C:took(S,C)},
TotalCourses == CoursesTaken.
I've not tested, but that should work, you might have to play around a bit with the syntax of the aggregates depending on the version of the grounder you are using, (e.g. see Clingo 3 vs 4).

Prolog: find a supplier who supply all parts

I'm new to Prolog. These are my facts.
part_cost(Part, Supplier)
part_cost(top_tube ,cinelli).
part_cost(top_tube ,columbus).
part_cost(down_tube ,columbus).
part_cost(head_tube ,cinelli).
part_cost(head_tube ,columbus).
part_cost(seat_mast ,cinelli).
part_cost(seat_mast ,columbus).
I want to find a supplier who supplies all kinds of parts, which is actually columbus.
I don't know how to say "all" in Prolog language.
Any help is appreciated.
Update
Thank you, #Ankur and #Sergey Dymchenko. Your list approach inspired me! I can write rules:
supplyAllParts(Supplier, []):-true.
supplyAllParts(Supplier, [Part|PartRest]) :-
part_cost(Part, Supplier, _, _),
supplyAllParts(Supplier, PartRest).
and call it by
?- supplyAllParts(S,[top_tube, down_tube, head_tube, seat_mast]).
S = columbus.
Now can Prolog dynamically find the part list ([top_tube, down_tube, head_tube, seat_mast]) from the facts rather than I manually provide it?
supplies([],_).
supplies([H|T],S) :- part_cost(H,S), supplies(T,S).
| ?- setof(P,S^part_cost(P,S),R), supplies(R,Supplier).
R = [down_tube,head_tube,seat_mast,top_tube]
Supplier = columbus
First, you probably need to define a notion of "all parts" manually, because maybe there is some kind of "bottom_super_gravitsapa", that no one has:
% store in sorted order, to compare with setof results later
sort([top_tube, down_tube, head_tube, seat_mast], AllParts)
To get a list of all parts for every supplier we can use setof/3:
?- setof(Part, part_cost(Part, Supplier), Parts).
setof(Part, part_cost(Part, Supplier), Parts).
Supplier = cinelli
Parts = [head_tube,seat_mast,top_tube] ?;
Supplier = columbus
Parts = [down_tube,head_tube,seat_mast,top_tube]
yes
And now just add a condition that list of parts for a specific supplier and AllParts are the same:
Parts == AllParts
If you don't want to define AllParts manually and assume that there is a supplier for every possible part, you can use another setof to get AllParts from the facts before the main setof.
all is a big word, in any language, and what it means varies so much... Down to the earth , in Prolog we have findall/3 family, that outputs a list with all patterns we instruct to extract from succeeded queries. The output list then is further processed ... But for your case, library(aggregate) is more handy:
supplies_all(Supplier) :-
aggregate(max(N,S), count_part_cost(S,N), max(_, Supplier)).
count_part_cost(S,N) :-
aggregate(count, P^part_cost(P,S), N).
I used a service predicate count_part_cost/2, just to keep the main one clear...
If you try to 'inline' them, beware to variables usage. Study variables quantification until you are comfortable with it.
edit As noted by Sergey, my code is not correct. Here is my bet for a more appropriate definition:
supplies_all(Supplier) :-
setof(P, S^part_cost(P,S), Ps),
setof(P, part_cost(P,Supplier), Ps).
I think it highlights well what I intended above recommending about studying variable quantification...
edit another possible definition, less costly but with redundant multiple solution (well, we have setof for that...)
supplies_all(Supplier) :-
% peek any Supplier from catalog
part_cost(_,Supplier),
% check it has all parts available
forall(part_cost(P,_), part_cost(P,Supplier)).

Resources