Search code examples
prologprolog-dif

Use Prolog to definition the departments and employees relationship


I'm working my way through an old exam and trying to check my work. I've attached images but the text is as quoted below:

We want to extend a program for handling the staff of a company.

For each department there is a fact department(Id, Manager, Groups) that defines the name of the department, Id, the name of its manager, Manager, and a list of working groups or other departments which constitute the department, Groups.

For each working group there is a fact, group(Id, Leader, Participant), that defines Id, a unique name for the group, Leader, a manager or leader of the group, and a list, Participant, containing the names of the members of the group.

Individuals can be members of one or more working groups, or "just" managers. The same person can be leader or manager for multiple groups/departments. Leaders are considered to be part of the working group they lead, while managers higher up in the hierarchy are not automatically members in any working group.

E.g. the database of the program can look like this:

   department( management, knut_billkvist, [administration, factory] ).
   department( administration, lisa_larsson, [economy, staff] ).
   department( economy, ahmed_hassan, [billing, budget, project_office] ).
   department( staff, jenny_bengtsson, [recruitment, health, salaries] ).
   department( factory, rune_viking, [assembly, testing] ).

   group( billing, lotta_persson, [anna_nilsson,arne_johnsson] ).
   group( budget, lena_levin, [kurt_allgen, mona_malm] ).
   group( project_office, ahmed_hassan, [kurt_allgen, anna_nilsson] ).
   group( recruitment, lill_nilsson, [annie_cedrell, jonna_spjuth] ).
   group( salaries, bengt_karlsson, [gullbritt_svensson, siri_hallin] ).
   group( assembly, rune_runesson, [johnny_kraft] ).
   group( testing, allan_snygg, [edvin_karlsson, mohammed_tayed] ).

Define these predicates!

  • A predicate coworker(Name, Department, Group) which is true if a person, Name, belongs to a certain department, Department, and a certain working group, Group, (use none if the person doesn't belong to any working group).

  • A predicate leader(Name, GroupId) that is true if a person, Name, is a leader of a certain working group GroupId.

  • A predicate manager(Name, Id) that is true if a person is a manager for a certain department, Id or ledaer of a working group with the name Id.

Please consider that individuals can often be members of working groups directly, and they can also be implicit members of departments on several levels!

My code is as follows:

coworker(Name,Department,Group):-
    begot(Name,department(ID,Name,group),Group).

leader(Name,GroupID):-
    bagof(Name,Group(ID,Name,Participants),GroupId).

manager(Name,ID):-
    setof (Name,Department(ID,Name,Groups),ID)setof (Name,Group(Id,names,participants),GroupId).

I have modified my code following the suggestions below into this:

cowoker(Name,Department,Group) :-
   group(Group,Name,Manager).

leader(Name,GroupID) :-
   Group(_,Name,GroupID).

manager(Name,ID) :-
   department(_,Name,ID),
   Group(_,Name,GroupId).

Solution

  • Your first problem is that you have some confusion about what you can use for variables or identifiers in Prolog. Every variable must begin with an uppercase letter, and every identifier must not begin with one. So the code Group(Id,Name,Participants) is wrong, because Group begins with an uppercase letter, and department(Id,Name,group) is wrong, because group should be capitalized. On top of that, this line is just zany: setof (Name,Department(ID,Name,Groups),ID)setof ...

    I don't think you actually need setof/3 or bagof/3 or findall/3 to answer any of these questions. I'll give you one of them, because I can tell this is homework, but it should be sufficient for you to see how to approach the problem.

    leader(Name, GroupId) :- 
        group(GroupId, Name, _).
    

    You're programming with relations here. The relationship between leader(Name, Group) is that there is some group Group and Name is the leader. This is what I have specified in my definition of leader/2. Notice that I didn't do anything with the list of people in the group. I don't need them for this task. This is just rearranging the data you already have! It doesn't have to be taxing.

    The other two questions are almost as easy. Now try, and do not let yourself be confused by second-order predicates! I don't think you'll need them.

    Edit: since this is not homework, let's look at how I would do the other two.

    coworker/3 is sort of misnamed; it doesn't tell you anything about a pair of workers, just what group and department each person is in. So the implementation will use member/2 to enumerate people, like so:

    coworker(Name, Department, Group) :-
        department(Department, _, Groups),
        member(Group, Groups),
        group(Group, _, People),
        member(Name, People).
    

    This is actually only 1/3rd of the story. This case covers people at the bottom rung, but it won't get people who manage groups or who manage departments and thus exist above the whole group hierarchy, so we need two more rules:

     coworker(Name, Department, none) :-
          department(Department, Name, _).
     coworker(Name, Department, Group) :-
          department(Department, _, Groups),
          member(Group, Groups),
          group(Group, Name, _).
    

    It feels like we could implement this with manager/2 but manager/2 discards the information about whether they manage a department or a group, so we can't use it to recover that information without redoing some work. So it's probably better to define it separately, although it will look like the second and third clauses of coworker/3 repeated:

     manager(Name, Department) :-
          department(Department, Name, _).
     manager(Name, Group) :-
          department(Department, _, Groups),
          member(Group, Groups),
          group(Group, Name, _).
    

    There you have it.