I am going to attempt solving a scheduling problem with Prolog. I have a set of requests from people in the format
req_id, user_id, start_date, end_date, state
each of these people are in one or more groups
group_id, user_id
and each group are defined by
group_id, loose, strict
where the loose and strict are integers >= 0
The initial state of each request is unknown, and can be changed to either rejected or approved.
To explain loose and strict on the groups consider the following example
Group A - Loose 1 - Strict 1
Group B - Loose 1 - Strict 0
Group C - Loose 0 - Strict 1
Given these data at any given time we need 3 people at work as 1 person can solve both A and B loose (given he is in both of those groups) and 1 person is needed for A strict and 1 person for C strict.
The date span will be limited to 5-6 weeks - never open ended searches.
Problem 1: how to I represent the available personnel at any given time so no group rules can be broken
Problem 2: how do I "force" that prolog searches for the maximum possible accept actions instead of just rejecting all requests
Edit
Sorry for the late followup, I hurt my leg and haven't had the time to do this.
My current code is:
updateGroupStrict(
[ group(Group,N,Loose) | GroupsRest ],
[ usergroup(User,Group) | _ ],
User,
[ group(Group,M,Loose) | GroupsRest ]
) :- N > 0,
M is N - 1.
% Reduce strict helper, try next group
updateGroupStrict( [ GroupHead | GroupsRest ], UserGroups, User, [ GroupHead | UpdatedGroups ] ) :- updateGroupStrict(GroupsRest,UserGroups,User,UpdatedGroups).
% Reduce strict helper, try next usergroup
updateGroupStrict(Groups,[ _ | UserGroupTail ],User,UpdatedGroups) :- updateGroupStrict(Groups,UserGroupTail,User,UpdatedGroups).
handle(Groups, _, userrequest( _, [ request(_, accept) | _ ]), Groups).
% to reject a request, the groups should be updated in the following way
% - A strict accept should only update 1 strict group
handle(
Groups,
UserGroups,
userrequest( User, [ request(_, reject) | _ ]),
UpdatedGroups
) :- updateGroupStrict(Groups, UserGroups, User, UpdatedGroups).
% Success when all requests have been processed - meaning the list is empty, and all groups are 0,0.
planned([],_,[]).
% If a group do not have more unsatisfied then just reduce it
planned( [ group(_,0,0) | GroupsTail ], UserGroups, Requests ) :- planned( GroupsTail, UserGroups, Requests ).
% To reduce the list of requests, handle the head, and continue on the rest
planned( Groups, UserGroups, [ RequestHead | RequestTail] ) :-
handle( Groups, UserGroups, RequestHead, UpdatedGroups ),
planned( UpdatedGroups, UserGroups, RequestTail ).
The assumptions made in this code is that there is only strict rules, all requests are same length (completely overlapping), and all users have made an request.
planned([group(group1,1,0)],[usergroup(user1,group1)],[userrequest(user1,[request(request1,RequestAction1)]),userrequest(user2,[request(request2,RequestAction2)])]).
So I finally managed to find a solution. Instead of all these intermediate representations I now have two
This way I am able to remove the user from a group's users when a request is approved. And just leave him if rejected. And finally just check if there is enough users in a group accordingly to the limit.