Prolog, strange answer of setof - prolog

I'm using the online compiler https://swish.swi-prolog.org/
Given the next facts:
frontier(spain,france).
frontier(spain,portugal).
frontier(portugal,spain).
frontier(france,spain).
frontier(france,italy).
frontier(france,germany).
frontier(france,belgium).
frontier(france,swiztland).
frontier(belgium,netherlands).
frontier(belgium,france).
frontier(belgium,germany).
frontier(netherlands,germany).
frontier(netherlands,belgium).
frontier(germany,netherlands).
frontier(germany,belgium).
frontier(germany,france).
frontier(germany,austria).
frontier(germany,swiztland).
frontier(austria,germany).
frontier(austria,swiztland).
frontier(austria,italy).
frontier(swiztland,austria).
frontier(swiztland,france).
frontier(swiztland,germany).
frontier(swiztland,italy).
frontier(italy,france).
frontier(italy,swiztland).
frontier(italy,austria).
I would like to obtain all of the countries but without obtain repeated ones.
Thus, I use a setof predicate, which avoids the repeated, like this:
setof(Country, (frontier(Country,_)), Countries).
The problem is that, when I executed the query, I obtained some iterations:
[germany, italy, swiztland]
[france, germany, netherlands]
[belgium, germany, italy, spain, swiztland],
[austria, belgium, france, netherlands, swiztland]
[austria, france, swiztland]
[belgium, germany]
[spain]
[france, portugal]
[austria, france, germany, italy]
I don't understand why, I was expected that the list Countries return me the list of all the countries without repeated ones and sorted, that's why I use the anonymus variable in the second argument of the predicate frontier, because I don't care about the second argument, only I want the first argument without repeated ones.
Any help?

Related

Prolog, print employees with same names

This is my first time using Prolog.
I have employees:
employee(eID,firstname,lastname,month,year).
I have units:
unit(uID,type,eId).
I want to make a predicate
double_name(X).
that prints the last names of the employees with the same first name in the unit X.
I am doing something like this :
double_name(X) :-
unit(X,_,_eID),
employee(_eID,_firstname,_,_,_),
_name = _firstname,
employee(_,_name,_lastname,_,_),
write(_lastname).
But it prints all the employees in the unit.
How can i print only the employees with the same name ?
unit(unit_01,type,1).
unit(unit_01,type,2).
unit(unit_01,type,3).
employee(1,mary,smith,6,1992).
employee(2,fred,jones,1,1990).
employee(3,mary,cobbler,2,1995).
double_name(Unit) :-
unit(Unit,_,Eid_1),
employee(Eid_1,Firstname,Lastname_1,_,_),
unit(Unit,_,Eid_2),
Eid_1 \= Eid_2,
employee(Eid_2,Firstname,Lastname_2,_,_),
write(Firstname),write(","),write(Lastname_1),nl,
write(Firstname),write(","),write(Lastname_2).
Variables in Prolog typically start with an upper case letter, but starting them with and underscore is allowed, but not typical.
In double_name/2 the predicates like
unit(Unit,_,Eid_1)
employee(Eid_1,Firstname,Lastname_1,_,_)
are used to load the values from the facts into variables while pattern matching (via unification) that the bound variables match with the fact.
To ensure that a person is not compared with themselves.
Eid_1 \= Eid_2
and to make sure that two people have the same first name the same variable is used: Firstname.
The write/1 and nl/0 predicates just write the result to the screen.
Example:
?- double_name(unit_01).
mary,smith
mary,cobbler
true ;
mary,cobbler
mary,smith
true ;
false.
Notice that the correct answer is duplicated. This can be resolved.
See: Prolog check if first element in lists are not equal and second item in list is equal
and look at the use of normalize/4 and setof/3 in my answer
which I leave as an exercise for you.

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]

Sort a parameter value in ascending orders in Prolog

I have a list of facts that have those parameters: Name, Longitude, Latitude. I want to write a predicate that sorts the Latitude only.
Here's part of my facts.
pool(roy, -75.702744, 45.4089761).
pool(marth, -75.731638, 45.3803301).
pool(jiggy, -75.7449645, 45.40431589).
pool(yamaha, -75.7114829, 45.3993461).
I tried to do something of the following but didn't get lucky:
furthest(Lat-Long):- setof(Lat-Long, pool(_, Long, Lat), [Lat-Long|_]).
Any ideas of how I should tackle this?
does this work?
pool(roy, -75.702744, 45.4089761).
pool(marth, -75.731638, 45.3803301).
pool(jiggy, -75.7449645, 45.40431589).
pool(yamaha, -75.7114829, 45.3993461).
my_sort:-
findall(forsort(Lat,Name),pool(Name,Long,Lat),List),
msort(List,Sorted),
write(Sorted).
?- my_sort.
[forsort(45.3803301,marth),forsort(45.3993461,yamaha),forsort(45.40431589,jiggy),forsort(45.4089761,roy)]
true.
Excerpt of manual below(SWI):
msort sorts List to the standard order of terms
Standard Order of Terms:
Compound terms are first checked on their arity, then on their functor name (alphabetically) and
finally recursively on their arguments, leftmost argument first.

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

Unique elements in list (Prolog)

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

Resources