Relational Learning: What does this Prolog Output say? - prolog

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

Related

Prolog display the results in an array/list

So I've this problem that is bugging me a lot:
We've the fact student(sID,LR,[courses]).
In which sID is the student ID, LR to determine if he is a left or right-handed person, and [courses] is an array of courses.
Next, we've the predicate listStudents(C,L) which C represents one Course and L the List. The predicate wants to return a List of Students that are in C Course.
Example:
student(23,1,[math101,phy203]).
student(24,0,[math101,phy203,art]).
student(25,1,[phy203,art]).
?- listStudents(math101,L)
L=[23,24]
Now, I've tried for several things like:
listStudents(C,L):- student(C,_,Y), member(C,Y)
and I realized later it's wrong as it returns me
L=23
L=24
Afterwards I was reading about findall() and made this
listStudents(C,L):- findall(S, study(C,S), L).
study(C,S):- estudiante(S,_,Y), member(C,Y).
which makes a return that I did not expect
L=[23,23,24,24,24]

Comparing more than 2 lists' elements in prolog to find if exactly two elements are the same

Each list represents a customer and his car brand and colour:
customer([_Name,_Surname,_Car,_Color]).
I would like to know if I can check in more than 2 lists that no customers have the same car of the same color. Because each customer has different name and surname from the others, (meaning that only _Car and _Color can take the same values in lists), I think one way is to check that the lists have not exactly 2 same elements.
An example of lists is:
customer1([john,brown,vw,black]).
customer2([will,smith,audi,green]).
customer3([nick,cave,bmw,blue]).
customer4([jim,beam,bmw,black]).
In this example none has the same brand and the same color, so it's true.
What I imagine is something like:
result:-customer1(X1,Y1,Z1,W1),
customer2(X2,Y2,Z2,W2),
customer3(X3,Y3,Z3,W3),
customer4(X4,Y4,Z4,W4),
(check that no Z's AND W's are the same).
Is this possible?
this query would answer about different persons having the same Car of same Color:
?- customer([Name1,Surname1,Car,Color]), customer([Name2,Surname2,Car,Color]), ( Name1 \= Name2 ; Surname1 \= Surname2).
This will tell you if two lists share the same car & color:
sameCarAndColor( [_,_,Car,Color], [_,_,Car,Color] ).
To check more than 2, just use this on each possible pair of lists.

In prolog how do you represent state transitions and actions performed by objects?

I have a problem domain consisting of several city state nodes and paths indicating the cost association between places/cities, also the agent is a chopper which can fly from one city to the next. The scenario problem is for a chopper to take off from one city and land at another. I know how to implement city states and transitions ok without operations such as takeoff, land etc..., I am just not sure how you represent the agent operations in terms of states or data structures, in order to satisfy an outcome effect such as:- chopper_islanded(true), chopper_at(cityj).
% nodes
place(rescueship).
place(citya).
place(cityb).
place(cityc).
place(cityd).
place(citye).
place(cityf).
place(cityg).
place(cityh).
place(cityi).
place(cityj).
% objects
is_chopper(chopper1).
% connections
path(rescueship, citya, 100).
path(rescueship, cityc, 200).
path(rescueship, cityb, 150).
path(cityc, cityd, 110).
path(cityd, citye, 140).
path(cityd, cityf, 100).
path(citya, cityi, 70).
path(cityi, cityg, 130).
path(cityb, cityg, 90).
path(cityi, cityf, 50).
path(citye, cityf, 90).
path(citye, cityj, 50).
path(cityh, cityj, 90).
path(cityi, cityh, 70).
path(citya,cityc,120).
path(citya,cityb,60).
% chopper attributes
chopper_islanded(true).
chopper_islanded(false).
chopper_at(X):- chopper_islanded(true); chopper_islanded(false), place(X), is_chopper(chopper1).
% place states, G=on ground, A= in air, v[list of conditions],Ch = chopper
state(v([G,A],P,Ch)):- chopper_islanded(G), chopper_islanded(A), place(P), chopper_at(Ch).
% chopper operations
%takeOff(V1,V2):- place(V1), place(V2).
%takeOff(v([_,A,P),v([false,A],P)).
%land(chopper):- chopper_islanded(false).
%flyto(p1,p2) :- path(p1,p2,_), chopper_islanded(false).
% tried many attempts to implement operations but couldn't understand how to represent an action
connected(P1,P2,C):- path(P1,P2,C) ; path(P2,P1,C).
transition(S1,S2,C) :- connected(S1,S2,C).
initial(rescueship).
goal(cityj).
% breadth first search uses an initialised state and a goal state which has been omitted for clarity.
bfgs(P)
To solve the route I use a breadth first search algorithm which works ok without any chopper operations, it finds the quickest route approximately and returns the list of travelled nodes. My biggest issue is how does one represent actions that the chopper does in order to achieve a certain state, and what data structure is best to use for this? sorry if the code is a mess! I have been stumped trying to figure out the semantics, so I haven't omitted my mistakes to demonstrate to others that I have tried at least.
Think in terms of relations between actions and states.
First describe what an action in a specific state of the chopper leads to. For example:
action_state0_state(take_off, landed, flying).
action_state0_state(land, flying, landed).
action_state0_state(crash, flying, crashed).
action_state0_state(repair, crashed, landed).
Using just these simple definitions, you can already reason about a list of actions and the eventual state of the chopper that starts - for example - in landed position:
?- length(As, _), foldl(action_state0_state, As, landed, S).
As = [],
S = landed
As = [take_off],
S = flying
As = [take_off, land],
S = landed
As = [take_off, crash],
S = crashed
As = [take_off, land, take_off],
S = flying
As = [take_off, crash, repair],
S = landed .
A list of actions seems an appropriate data structure in this case, since the empty list makes sense, the number of elements is not known in advance etc.

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

What would you use for `n to n` relations in python?

after fiddling around with dictionaries, I came to the conclusion, that I would need a data structure that would allow me an n to n lookup. One example would be: A course can be visited by several students and each student can visit several courses.
What would be the most pythonic way to achieve this? It wont be more than 500 Students and 100 courses, to stay with the example. So I would like to avoid using a real database software.
Thanks!
Since your working set is small, I don't think it is a problem to just store the student IDs as lists in the Course class. Finding students in a class would be as simple as doing
course.studentIDs
To find courses a student is in, just iterate over the courses and find the ID:
studentIDToGet = "johnsmith001"
studentsCourses = list()
for course in courses:
if studentIDToGet in course.studentIDs:
studentsCourses.append(course.id)
There's other ways you could do it. You could have a dictionary of studentIDs mapped to courseIDs or two dictionaries that - one mapped studentIDs:courseIDs and another courseIDs:studentIDs - when updated, update each other.
The implementation I wrote out the code for would probably be the slowest, which is why I mentioned that your working set is small enough that it would not be a problem. The other implentations I mentioned but did not show the code for would require some more code to make them work that just aren't worth the effort.
It depends completely on what operations you want the structure to be able to carry out quickly.
If you want to be able to quickly look up properties related to both a course and a student, for example how many hours a student has spent on studies for a specific course, or what grade the student has in the course if he has finished it, and if he has finished it etc. a vector containing n*m elements is probably what you need, where n is the number of students and m is the number of courses.
If on the other hand the average number of courses a student has taken is much less than the total number of courses (which it probably is for a real case scenario), and you want to be able to quickly look up all the courses a student has taken, you probably want to use an array consisting of n lists, either linked lists, resizable vectors or similar – depending on if you want to be able to with the lists; maybe that is to quickly remove elements in the middle of the lists, or quickly access an element at a random location. If you both want to be able to quickly remove elements in the middle of the lists and have quick random access to list elements, then maybe some kind of tree structure would be the most suitable for you.
Most tree data structures carry out all basic operations in logarithmic time to the number of elements in the tree. Beware that some tree data structures have an amortized time on these operators that is linear to the number of elements in the tree, even though the average time for a randomly constructed tree would be logarithmic. A typical example of when this happens is if you use a binary search tree and build it up with increasingly large elements. Don't do that; scramble the elements before you use them to build up the tree in that case, or use a divide-and-conquer method and split the list in two parts and one pivot element and create the tree root with the pivot element, then recursively create trees from both the left part of the list and the right part of the list, these also using the divide-and-conquer method, and attach them to the root as the left child and the right child respectively.
I'm sorry, I don't know python so I don't know what data structures that are part of the language and which you have to create yourself.
I assume you want to index both the Students and Courses. Otherwise you can easily make a list of tuples to store all Student,Course combinations: [ (St1, Crs1), (St1, Crs2) .. (St2, Crs1) ... (Sti, Crsi) ... ] and then do a linear lookup everytime you need to. For upto 500 students this ain't bad either.
However if you'd like to have a quick lookup either way, there is no builtin data structure. You can simple use two dictionaries:
courses = { crs1: [ st1, st2, st3 ], crs2: [ st_i, st_j, st_k] ... }
students = { st1: [ crs1, crs2, crs3 ], st2: [ crs_i, crs_j, crs_k] ... }
For a given student s, looking up courses is now students[s]; and for a given course c, looking up students is courses[c].
For something simple like what you want to do, you could create a simple class with data members and methods to maintain them and keep them consistent with each other. For this problem two dictionaries would be needed. One keyed by student name (or id) that keeps track of the courses each is taking, and another that keeps track of which students are in each class.
defaultdicts from the 'collections' module could be used instead of plain dicts to make things more convenient. Here's what I mean:
from collections import defaultdict
class Enrollment(object):
def __init__(self):
self.students = defaultdict(set)
self.courses = defaultdict(set)
def clear(self):
self.students.clear()
self.courses.clear()
def enroll(self, student, course):
if student not in self.courses[course]:
self.students[student].add(course)
self.courses[course].add(student)
def drop(self, course, student):
if student in self.courses[course]:
self.students[student].remove(course)
self.courses[course].remove(student)
# remove student if they are not taking any other courses
if len(self.students[student]) == 0:
del self.students[student]
def display_course_enrollments(self):
print "Class Enrollments:"
for course in self.courses:
print ' course:', course,
print ' ', [student for student in self.courses[course]]
def display_student_enrollments(self):
print "Student Enrollments:"
for student in self.students:
print ' student', student,
print ' ', [course for course in self.students[student]]
if __name__=='__main__':
school = Enrollment()
school.enroll('john smith', 'biology 101')
school.enroll('mary brown', 'biology 101')
school.enroll('bob jones', 'calculus 202')
school.display_course_enrollments()
print
school.display_student_enrollments()
school.drop('biology 101', 'mary brown')
print
print 'After mary brown drops biology 101:'
print
school.display_course_enrollments()
print
school.display_student_enrollments()
Which when run produces the following output:
Class Enrollments:
course: calculus 202 ['bob jones']
course: biology 101 ['mary brown', 'john smith']
Student Enrollments:
student bob jones ['calculus 202']
student mary brown ['biology 101']
student john smith ['biology 101']
After mary brown drops biology 101:
Class Enrollments:
course: calculus 202 ['bob jones']
course: biology 101 ['john smith']
Student Enrollments:
student bob jones ['calculus 202']
student john smith ['biology 101']

Resources