Prolog Rules (Predicates) - prolog

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

Related

forall/2 predicate query doesn’t return results

I have the following facts.
loves(ami, paul).
loves(lucy, paul).
female(ami).
artist(ami).
female(lucy).
artist(lucy).
canadian(paul).
lovesCanadianArtists(Person) :- forall(canadian(X), loves(Person, X)).
When I execute the query in SWI-Prolog:
?- lovesCanadianArtists(X).
The answer is true, and I don't get results.
Someone told me that the issue is the predicate isLovedByArtists(Person) is not inversible or invertible. So, I should add a condition on Person variable because it is not bound by the forall\2 predicate. Like:
lovesCanadianArtists(Person) :- female(Person), forall(canadian(X), loves(Person, X)).
So, my questions are:
Is this predicate invertibility documented anywhere ? I can't find it.
For me, the explanation given is wrong, and but I am not sure whether I should get results with my first rule. What's the underlying issue here ?
What's the underlying issue here ?
"forall/2 does not change any variable bindings. [...] If your intent is to create variable bindings, the forall/2 control structure is inadequate." - https://www.swi-prolog.org/pldoc/man?section=forall2
Perhaps one of foreach, findall, bagof or setof will do what you want, although it's not clear from the plural 'artists' and singular 'Person' exactly what that is; e.g. for a list of all People who love at least one Canadian artist, which may have duplicates if you add more Canadian artists:
lovesCanadianArtists(People) :-
findall(Person, (canadian(X), loves(Person, X)), People).

Sorting a knowledge database in 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
]

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

Basic Prolog Family Relation

I am new to prolog and was hoping someone could clear this up for me. I want to query if someone is a father. So I wrote the following statements and rules:
man(Joe).
man(Josh).
man(John).
parent(Joe,Josh).
parent(Josh,John).
father(D,K) :- man(D), parent(D,K).
I am confused because when I run the query:
father(Joe,John).
true.
It returns true. Why is this? It seems to be searching though the relations but I have no idea why!
In prolog, strings that start with a capital are variables. When you write parent(Joe,Josh)., you're not defining a relationship between two people Joe and Josh, but you're saying that the parent relationship is true for any values of the variables 'Joe' and 'Josh'.
For the relations to work as expected, you have to either use lower-case atoms (e.g. father(joe,josh).), or use quoted atoms (father('Joe', 'Josh').).

Using And clause in HEAD of a prolog statement

Every member of this club is either educated or rich or both.
I wanted to write a statement very similar to above in my PROLOG code. I wrote everything else.
edu(X);rich(X) :- member(X).
This is what I had written. But then PROLOG doesn't allow any operators in the clause head. I have spent 5 hours till now trying to do various things with this statement but unable to reach a solution that works. :(
See http://en.wikipedia.org/wiki/Horn_clause for am explanation of the form of logic Prolog is based on.
Given your statement, ("Every member of this club is either educated or rich or both."), the only things you can declare to be true are:
A person is educated if they are a member and not rich.
A person is rich if they are a member and not educated.
The following, for example, are not necessarily true:
A person who is rich and educated is a member.
A member who is rich is educated.
A member who is rich is not educated.
You can't combine multiple heads. If you want edu(X) and rich(X) to be true when member(X) is true, you have to define them separately ("every member of this club is educationed" and "every member of this club is rich"):
edu(X) :-
member(X).
rich(X) :-
member(X).
The tricky part is that your original statement is not well-formed. It says that some members may be rich but not educated or vice versa. This is problematic. For example, let's take the naive case that if a member isn't rich, he's educated, and the reverse:
edu(X) :-
member(X), \+ rich(X).
rich(X) :-
member(X), \+ edu(X).
Now, according to these rules, nobody is automatically rich and educated. So long as we define every member as at least one of the two, this is fine. However, consider these facts:
member(alice).
member(bob).
member(charlie).
member(dave).
rich(alice).
edu(bob).
rich(charlie).
edu(charlie).
In this case, rich(alice) works fine, because it's a fact. edu(alice) will result in no. The reverse is true for bob. With charlie, we've defined both as facts, so both are true. But what about dave? Both edu(dave) and rich(dave) refer back to the other, creating an infinite recursion. Without any further knowledge of what you're doing, the best we can do to resolve this is to default either edu(X) or rich(X) to true:
edu(X) :-
member(X).
rich(X) :-
member(X), \+ edu(X).
Now everyone is assumed to be educated unless we explicitly declare otherwise. You could do the same thing defaulting to rich if you preferred. Short of additional information, this is the best you can do.
As a side note: the idea of using disjunctions in heads of clauses has lead to disjunctive logic programming, see, e.g., "Foundations of Disjunctive Logic Programming" by Jorge Lobo, Jack Minker, Arcot Rajaseka. edu(X);rich(X) :- member(X). would be a valid disjunctive clause. A related topic, disjunctive Datalog, has been explored by Nicola Leone, Gerald Pfeifer and Wolfgang Faber in the DLV project: http://www.dbai.tuwien.ac.at/proj/dlv/
Maybe you want to write:
member(X) :- edu(X) ; rich(X)
If someone is educated, rich or both, is a member of the club.

Resources