Nurse Scheduling with Competence Constraints - job-scheduling

I am struggling to figure out how I can leverage Google OR Tools CP-SAT solver to find a feasible solution to the nurse scheduling problem with a slight modification: each shift is restricted to a subset of nurses who have certain competences (i.e. novice, intermediate, advanced). Competences expire after a time, meaning a nurse cannot be scheduled for a shift requiring an expired competence. However, a nurse can regain competence by working on a shift with someone who currently has that competence.
In my program, I am hoping to schedule multiple days at a time. How can I define a constraint that says a nurse with expired competence can only be scheduled for a shift on day n provided that the nurse is scheduled to regain competence on some day less than n?

First look at the shift_scheduling_sat.py example. Adapting to skills restrictions should be easy.
Now, about expiration.
The first step is to mark shifts where the nurse learns the skill.
For each shifts, for each nurse, create a bool var if the nurse is paired with somebody who has the competence. Add the implication nurse is schedule on that shift & skilled person on the same shift -> nurse is qualified for that competence on that shift.
Now for all other shifts requiring that competence,
you know the times of each shift. For a given shift, collect all potential preceding shifts close enough (no expiration), and add nurse works on this shift implies Or(nurse acquired that shift on one compatible preceding shift -- including this one).

Related

Maximise subset selection under constraints

I am working on a scheduling problem for a team of volunteers. I have boiled my problem down to the following algorithmic problem:
I have a matrix with ~60 rows representing volunteers and ~14 columns representing days. Each entry is an integer in the range 0 to 3 inclusive representing how free the volunteer is on that day. I want to choose exactly 4 entries from each column (4 volunteers a day) such that (in order of importance)
A 0-entry is never chosen.
The workload is as spread out as possible (first give everyone one shift, then start giving out second shifts, etc. We can expect that most volunteers will only have one shift per 2-week period, and some may even have none.)
The sum over selected entries is maximised (volunteers get days that they prefer).
I want to output a decision matrix that has a 1 whenever a volunteer is chosen for a day, and 0 otherwise. I believe this is an instance of the nurse-rostering problem, so I'm not expecting a fast solution, but I just want to make a brute force algorithm that will work in a reasonable time for my ~60 person team. I'm just really not sure how to start tackling this problem. Is it suited for backtracking, or is there some way to calculate the best placement of each volunteer based on the distribution of his/her day-scores?

How to optimize events scheduling with unknown future events?

Scenario:
I need to give users opportunity to book different times for the service.
Caveat is that i dont have bookings in advance but i need to fill them as they come in.
Bookings can be represented as keyvalue pairs:
[startTime, duration]
So, for example, [9,3] would mean event starts at 9 o’clock and has duration of 3 hours.
Rules:
users come in one by one, there is never a batch of users requests
no bookings can overlap
service is available 24/7 so no need to worry about “working time”
users choose duration on their own
obviously, once user chooses&confirms his booking we cannot shuffle it anymore
we dont want gaps to be lesser than some amount of time. this one is based on probability that future users will fill in the gap. for example, if distribution of durations over users bookings is such that probability for future users filling the gap shorter than x hours is less than p then we want a rule that gap cannot be shorter than x. (for purpose of this question, we can assume x being hardcoded, here i just explain reasons)
the goal is to have service-busy-duration maximized
My thinking so far...
I keep the list of bookings made so far
I also keep track of gaps (as they are potential slots for new users booking)
When new user comes with his booking [startTime, duration] i first check for ideal case where gapLength = duration. if there is no such gaps, i find all slots (gaps) that satisfy condition gapLength - duration > minimumGapDuration and order them in descending order by that gapLength - duration value
I assign user to the first gap with maximum value of gapLength - duration since that gives me highest probability that gap remaining after this booking will also get filled in future
Questions:
Are there some problems with my approach that i am missing?
Are there some algorithms solving this particular problem?
Is there some usual approach (good starting point) which i could start with and optimize later? (i am actually trying to get enough infos to start but not making some critical mistake; optimizations can/should come later)
PS.
From research so far it sounds this might be the case for constraint programming. I would like to avoid it if possible as i have no clue about it (maybe its simple, i just dont know) but if it makes a real difference, i will go for its benefits and implement it.
I went through stackoverflow for similar problems but didnt find one with unknown future events. If there is such and this is direct duplicate, please refer to it.

How to Schedule Tasks

There is a carwash that can only service 1 customer at a time. The goal of the car wash is to have as many happy customers as possible by making them wait the least amount of time in the queue. If the customers can be serviced under 15 minutes they are joyful, under an hour they are happy, between 1 hour to 3 hours neutral and 3 hours to 8 hours angry. (The goal is to minimize angry people and maximize happy people). The only caveat to this problem is that each car takes a different amount of time to wash and service so we cannot always serve on first come first serve basis given the goal we have to maximize customer utility. So it may look like this:
Customer Line :
Customer1) Task:6 Minutes (1st arrival)
Customer2) Task:3 Minutes (2nd arrival)
Customer3) Task:9 Minutes (3rd)
Customer4) Task:4 Minutes (4th)
Service Line:
Serve Customer 2, Serve Customer 1, Serve Customer 4, Serve Customer 3.
In this way, no one waited in line for more than 15 minutes before being served. I know I should use some form of priority queue to implement this but I honestly know how should I give priority to different customers. I cannot give priority to customers with the least amount of work needed since they may be the last customer to have arrived for example (others would be very angry) and I cannot just compare based on time since the first guy might have a task that takes the whole day.So how would I compare these customers to each other with the goal of maximizing happiness?
Cheers
This is similar to ordering calls to a call center. It becomes more interesting when you have gold and silver customers. Anyway:
Every car has readyTime (the earliest time it can be washed, so it's arrival time - which might be different for each car) and a dueTime (the moment the customer becomes angry, so 3 hours after readyTime).
Then use a constraint solver (like OptaPlanner) to determine the order of the cars (*). The order of the cars (which is a genuine planning variable) implies the startWashingTime of each car (which is a shadow variable), because in your example, if customer 1 is ordered after customer 2 and if we start at 08:00, we can deduce that customer 1's startWashingTime is 08:03.
Then the endWashingTime is startWashingTime + washingDuration.
Then it's just a matter of adding 2 constraints and let the solver solve() it:
endWashingTime must be lower than dueTime, this is a hard constraint. This is to have no angry customers.
endWashingTime must be lower than startTime plus 15 minutes, this is a soft constraint. This is to maximize happy customers.
(*) This problem is NP-complete or NP-hard because you can relax it to a knapsack problem. In practice this means: you can't write an algorithm for it that scales out and finds the optimal solution in reasonable time. But a constraint solver can get you close.

Class Scheduling to Boolean satisfiability [Polynomial-time reduction] part 2

I asked few days ago, a question about how to transform a University Class Scheduling Problem into a Boolean Satisfiability Problem.
(Class Scheduling to Boolean satisfiability [Polynomial-time reduction])
I got an answer by #Amit who was very elegant and easy to code.
Basically, his answer was like this : instead of considering courses, he considered time-intervals.
So for the i-th course, he just indicted all the possible intervals for this course. And we obtain a solution when there is at least 1 true-interval for every course and when no interval overlap an other.
This methods works very well when we consider only courses and nothing else. I generalize it by encoding the room inside the interval.
for example, instead of [8-10] to say that a course can happen between 8am and 10am.
I used [0.00801 - 0.01001] to say that a course can happen between 8am and 10am in the room 1.
I'm sure that you are currently wandering "why use double ?" well, because here come my problem :
To continue to generalize this method, I encode also the n° of the teacher in this interval.
I used [1.00801 - 1.01001] to say that a course can happen between 8am and 10am in the room 1 and be taught by the teacher n°1.
Here is what I got for now :
like this [1.008XX - 1.010XX] can happen in the same time as [2.008YY - 2.010YY], which is true, if the teacher 1 is teaching in the room X between 8am and 10am, the teacher 2 can teach also in Y between 8am and 10am, if and only if the room is available.
The problem is : with this method I cannot assure that XX and YY will be different and that YY will be available, because [1.008XX - 1.010XX] don't overlap [2.008XX - 2.010XX], so for now, the solver consider this possible.
And I still don't have any clue on how to assure this, by using this interval-method...
I need a way to encode {Interval, room and teacher-id} in order that :
a teacher cannot be in 2 places in the same interval.
there cannot be 2 teachers in the same room for the same interval.
there is a least 1 interval true by course.
Thanks in advance for your help,
Best regards !
Follow up question: Class Scheduling to Boolean satisfiability [Polynomial-time reduction] Final Part
This answer is extension of Part 1's answer, and uses the same notations when possible.
Ok, assume each interval is assigned to one teacher (if more than one teacher can take the interval, just have multiple instances of it, with different teachers per instance), so to indicate teacher t teaches in a classroom p at time x to y, we can use the old variable that this class is given - V_{i,j} - for the class and interval.
For each teacher t , and for each pair of intervals c=(x1,y1), d=(x2,y2) in classes (a,b) the teacher might participate in, add the clause:
Q_{t,i,j} = Not(V_ac) OR Not(V_bd) OR Smaller(y1,x2) OR Smaller(y2,x1)
Intuitively, the above clause guarantees a teacher cannot be in the same time in two places - no intervals overlap that the same teacher is assigned to them.
By chaining each pair (i,j) for each teacher t with AND to the original formula, it satisfies your first constraint - a teacher cannot be in 2 places in the same interval. - since each teacher cannot be in two places at the same time.
Your second constraint there cannot be 2 teachers in the same room for the same interval. is also satisfied by the fact that there cannot be two classes that overlap the time and class.
The 3rd constraint there is a least 1 interval true by course. is satisfied by the F1 clause, since you have to choose at least one interval (with one teacher assigned) for each course.

On-call night scheduling algorithm

I work in a residence hall at my college as an RA, and each night we need two RAs to be on call (able to respond to incidents and emergencies). Each month, RAs submit the nights they cannot be on call (due to a conflict of some sort). There are both male and female RAs. I am trying to come up with an effective algorithm to find the best arrangement of on-call nights for any particular month that satisfies the following requirements:
No RA is scheduled for a night he or she has listed as unavailable.
No RA is on-call more than a specified number of nights per month.
No RA is on-call twice within any given three-night span.
Each night has exactly two RAs on call.
Each night has, if possible, one male and one female RA on call.
Doing some research, I've found that this is a resource-constrained scheduling problem, and it is considered NP-complete. Therefore, I don't need to find the optimal solution, just any solution that works.
So far, I've considered the following approaches:
A simple 2d array of RAs x nights where each cell holds a boolean value answering whether or not that RA is on call for that night. I could hold the RAs in two priority queues (one male and one female) sorted by how many nights they've had so far, how long it has been since their last on call night, and simply iterate through the nights, selecting one RA from each queue, and then backtracking if I hit a dead end where nobody can work a particular night.
A tripartite graph with male RAs on one side, female RAs on another, and nights on the last side. In the solution, each night would have an edge to one male and one female RA. I would start with all edges connected and then remove edges until a solution is found.
Some sort of genetic approach using the above structures.
What sort of approach do you suggest I use? Is there something I haven't thought of that might work better? This is not a homework question; I am trying to develop a website that would make it easy for my staff and possibly other staffs on campus to submit date preferences and then generate a schedule that works for everybody.
I recommend the 2d array, but instead of iterating through the nights in order from first to last you iterate through the nights in order from most to least constrained - in other words, start with the night that has the fewest RAs available due to conflicts. This heuristic could also apply to the tripartite graph if you go with that approach - it's basically a question of domain representation, the algorithm itself isn't affected at this point.
The question is what you do when you reach the last few nights and find that no RAs are available. At this point you would do a local search to attempt to reach a viable solution, for example you've selected RA1 for NightA but RA2 and RA3 were also available on that night, so you select RA2 or RA3 to see if that frees up RA1 for the night on which you did not have an available RA.
Using the binary variables mentioned, your problem can be formulated as an Integer Linear Program (ILP). If there are not more than a few thousand variables, this can probably be solved optimally by a solver such as GLPK. All constraints but the last one are already linear. For "Each night has, if possible, one male and one female RA on call", you can introduce another Boolean variable "x" for each night, have a constraint "sum of female RAs on call <= 1 + x", and then minimize the sum of x's, thereby allowing the constraint to be violated at a cost. If you provide the data to the solver in text format, this should also be not too hard to implement.

Resources