2

I know the title of the topic exists here: A prolog program that reflects people sitting at a round table

But I need a different solution, more simple.

So I have this problem where 4 people sit around a square table.

We know their names. And that someone is the orthopedist, someone the dentist, someone the surgeon and someone the pediatrician.

We have a knowledge base that you will see in the code.

And we have to find what is the name of the pediatrician.

My program finds it, but doesn't print all four possible combinations for the list that represents the seats on the table.

table(List):-
    length(List,4),
    member(convive(argiro,_,female),List),
    member(convive(georgia,_,female),List),
    member(convive(basilis,_,male),List),
    member(convive(dimitris,_,male),List),
    left(convive(_,dentist,_),convive(argiro,_,female),List),
    oppo(convive(_,surgeon,_),convive(basilis,_,male),List),
    next(convive(georgia,_,female),convive(dimitris,_,male),List),
    left(convive(_,_,female),convive(_,orthopedist,_),List),
    member(convive(_,pediatrecian,_),List).

left(X,Y,ConLs):-append(_,[X,Y|_],ConLs).

left(X,Y,ConLs):-prefix(X,ConLs),last(ConLs,Y).

next(X,Y,ConLs):-left(X,Y,ConLs).

next(X,Y,ConLs):-append(_,[Y,X|_],ConLs).

next(X,Y,ConLs):-prefix(Y,ConLs),last(ConLs,X).

oppo(X,Y,ConLs):-next(X,Z,ConLs),next(Z,Y,ConLs),X\==Y.

On the terminal I get:

?- table(List),member(convive(Name,pediatrecian,_),List).

List = [convive(basilis, dentist, male), convive(argiro, pediatrecian, female), convive(georgia, surgeon, female), convive(dimitris, orthopedist, male)], Name = argiro ;

List = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male), convive(basilis, dentist, male), convive(argiro, pediatrecian, female)], Name = argiro ;

false.

So as you can see, I get the name, but only the 2 possible lists representing where each person is seated. There should also be:

List = [convive(dimitris, orthopedist, male), convive(basilis, dentist, male), convive(argiro, pediatrecian, female), convive(georgia, surgeon, female)]

List = [convive(argiro, pediatrecian, female), convive(georgia, surgeon, female), convive(dimitris, orthopedist, male), convive(basilis, dentist, male)]

I have used the lines

left(X,Y,ConLs):-prefix(X,ConLs),last(ConLs,Y).

next(X,Y,ConLs):-prefix(Y,ConLs),last(ConLs,X).

But, they are not doing anything, if I erase them, I get the same result.

UPDATE

table(List):-
length(List,4),
member(convive(argiro,_,female),List),
member(convive(georgia,_,female),List),
member(convive(basilis,_,male),List),
member(convive(dimitris,_,male),List),
left(convive(_,dentist,_),convive(argiro,_,female),List),
oppo(convive(_,surgeon,_),convive(basilis,_,male),List),
next(convive(georgia,_,female),convive(dimitris,_,male),List),
left(convive(_,_,female),convive(_,orthopedist,_),List),
member(convive(_,pediatrecian,_),List).

left(X,Y,ConLs):-append(_,[X,Y|_],ConLs).

left(X,Y,ConLs):-prefix(X,ConLs),last(ConLs,Y).

next(X,Y,ConLs):-left(X,Y,ConLs);left(Y,X,ConLs).

%next(X,Y,ConLs):-append(_,[Y,X|_],ConLs).

next(X,Y,ConLs):-prefix(Y,ConLs),last(ConLs,X).

%oppo(X,Y,ConLs):-next(X,Z,ConLs),next(Z,Y,ConLs),X\==Y.

oppo(X,Y,[X,_,Y,_]).

oppo(X,Y,[Y,_,X,_]).

oppo(X,Y,[_,X,_,Y]).

oppo(X,Y,[_,Y,_,X]).

So, oppo/3 seems to be working fine on the given lists

?- table(List), oppo(convive(argiro,pediatrecian,female),Name,List).

List = [convive(basilis, dentist, male), convive(argiro, pediatrecian, female), convive(georgia, surgeon, female), convive(dimitris, orthopedist, male)],

Name = convive(dimitris, orthopedist, male) ;

List = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male), convive(basilis, dentist, male), convive(argiro, pediatrecian, female)],

Name = convive(dimitris, orthopedist, male) ;

false.


left/3 seems to be doing the same thing that I'm trying to solve in the first place, it works in the list where argiro is number 2 and georgia is 3 which is a simple case, but in the second list that you can see above in oppo/3 results, where argiro is number 4 and georgia is number 1, it should see that georgia is again on the left of argiro but doesn't.

?- table(List), left(convive(argiro,pediatrecian,female),Name,List).

List = [convive(basilis, dentist, male), convive(argiro, pediatrecian, female), convive(georgia, surgeon, female), convive(dimitris, orthopedist, male)],

Name = convive(georgia, surgeon, female) ;

false.


Now next/3 returns some pretty disturbing results. I don't know what to make of this, I'm a newbie in Prolog. Some are okay, but some seem to be taking whole arrays as results, some say List = Name.

The first three results are ok, and the fourth is doing the same as left/3, it can't see that the first one in the list is next to the last one so it returns an empty array.

What is happening here?

?- table(List), next(convive(argiro,pediatrecian,female),Name,List).

List = [convive(basilis, dentist, male), convive(argiro, pediatrecian, female), convive(georgia, surgeon, female), convive(dimitris, orthopedist, male)],

Name = convive(georgia, surgeon, female) ;

List = [convive(basilis, dentist, male), convive(argiro, pediatrecian, female), convive(georgia, surgeon, female), convive(dimitris, orthopedist, male)],

Name = convive(basilis, dentist, male) ;

List = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male), convive(basilis, dentist, male), convive(argiro, pediatrecian, female)],

Name = convive(basilis, dentist, male) ;

List = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male), convive(basilis, dentist, male), convive(argiro, pediatrecian, female)],

Name = [] ;

List = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male), convive(basilis, dentist, male), convive(argiro, pediatrecian, female)],

Name = [convive(georgia, surgeon, female)] ;

List = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male), convive(basilis, dentist, male), convive(argiro, pediatrecian, female)],

Name = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male)] ;

List = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male), convive(basilis, dentist, male), convive(argiro, pediatrecian, female)],

Name = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male), convive(basilis, dentist, male)] ;

List = Name,

Name = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male), convive(basilis, dentist, male), convive(argiro, pediatrecian, female)] ;

List = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male), convive(basilis, dentist, male), convive(argiro, pediatrecian, female)],

Name = [] ;

List = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male), convive(basilis, dentist, male), convive(argiro, pediatrecian, female)],

Name = [convive(georgia, surgeon, female)] ;

List = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male), convive(basilis, dentist, male), convive(argiro, pediatrecian, female)],

Name = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male)] ;

List = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male), convive(basilis, dentist, male), convive(argiro, pediatrecian, female)],

Name = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male), convive(basilis, dentist, male)] ;

List = Name,

Name = [convive(georgia, surgeon, female), convive(dimitris, orthopedist, male), convive(basilis, dentist, male), convive(argiro, pediatrecian, female)] ;

false.

UPDATE

So I learned that prefix/2 works with strings, for example, prefix(x,[x,y,z]). returns false. That's why it's not working, and that explains the results in next/3, but still my problem isn't solved.

Any other way to make left and next work with the first and last part of the list?

  • *I get the name, but the lists should be four*. I'm not sure what that means. Can you describe more precisely what you think the answer should be? Four what? `table(List)` yields a list of 4 elements. Are they the correct ones? Then your `member` call only picks out one of them because of the conditions of the first argument of that call. – lurker May 29 '17 at 10:25
  • I edited it. I think I made it more clear, if you still have questions, please ask. – Giannis Pappas May 29 '17 at 10:43
  • Although the problem is similar to that linked, I think the rules for your problem are pertinent to the solution and are different than the ones in the link. For example, your code assumes that there are 4 (not 5) people around the table, and that there are exactly 2 male and 2 female. You didn't state that as a rule, so it's not clear to me that your code enforcing such a rule is correct. You might want to run separate tests on your aux predicates, `left/3`, `next/3`, and `oppo/3` to make sure they're working properly. You can call then directly at the Prolog prompt. – lurker May 29 '17 at 11:29
  • Where are `prefix/3` and `last/3` defined? – lurker May 29 '17 at 11:29
  • About the genders, it is like I have done it because these are greek names for which one can know the gender. So these lines in the Knowledge Base are ok. I will check the aux predicates. The prefix/3 and last/3 are built-in http://www.swi-prolog.org/pldoc/doc/swi/library/lists.pl – Giannis Pappas May 29 '17 at 15:14
  • 1
    Ah ok, thanks. I don't know all the SWI built-ins. – lurker May 29 '17 at 16:37

1 Answers1

0

I bet the culprit is \== in oppo, because these predicates are used here in generative fashion. Try to get rid of it. Just hand-coding the four possibilities is enough - your lists are of fixed length and very short, after all:

oppo(X,Y,[X,_,Y,_]).
.....

next/3 is easier / clearer if coded as a disjunction of two calls to left/3.

For left/3 itself, you could also form a circle from your ConLs by

circle_up(Ls,Circle):- head(A,Ls), append(Ls,[A],Circle).

and use Circle in one simple call to append to complete the definition of left/3. This assumes the definition

head(A,L):- L=[A|_].
Will Ness
  • 70,110
  • 9
  • 98
  • 181