So, how do we build Rosters anyway?
Well….let me tell you a story.
We start off with a template. It doesn’t matter where we get it from, whether it’s a DRS template that we import or a spreadsheet, or whatever but we represent that template in our systems as a Rota.
A Rota is really just a grid of days vs. a number of weeks and a shift (ie. a time range that someone will work).
Looks like a Rota to me. We represent this in our database as
- Rota - The object that has a Location (e.g. Danger Hospital #7) and it owns a collection of
- RotaWeek(s) - which has a order (1 - 20) and owns a collection of
- RotaShift(s) - which each have a time range (e.g. 09:00 - 17:00) and a day (Monday - Sunday) . Here one week only has one shift per day. It could have more but that would be confusing.
What do we do with this?
Well, we take this pattern and we apply it to a number of users we’ve decided are lucky enough to be selected to work at this Location.
A Rota can have a number of RotaBuild(s), a RotaBuild is really just a configuration for the Roster that I want to generate based on the Rota e.g. as above. And a Rota might have multiple builds if it is used multiple times, e.g. once per rotation August, then again in February, etc.
RotaBuild - has a time range (5th August - 2nd February), links to the original Rota, and assigns a number of User(s) associated with that build.
Press a button and… gadzooks a Roster is spat out the other side! It’s magic and this black box is basically The Lament Configuration, hooks and chains aplenty.
But how? What magic is this?
Well….funny you should ask. The whole purpose of this blog is this section because it’s pretty confusing.
We know who is supposed to be working those shifts right….say the 20 doctors we just added to our RotaBuild.
Yes, this picture again. Unsupervised we could build a Roster by saying…Doctor 1 is going to work Week 1, then the week after Week 2, then 3 then 4, and so on. The Doctor’s shift pattern is made up of placing the Doctor in a starting position (say 1) and they rotate through the pattern (20 times) until they reach the beginning again and continue or until the time range of the build runs out. We would save those Shifts with Doctor 1 asssigned to them and Doctor 1 knows exactly what they are working in the next 6 months.
Now Doctor 2 would start in Week 2, and do the same thing. The week after they would work Week 3, etc.
That’s not solving that’s just giving a Doctor a position, rotating through a pattern and creating RosterShift(s) as we go. We could assign each Doctor a starting week (and we do initially) and be done with it. But what if when it’s Doctor 5’s turn to work Week 13 and they can’t because their cat needs a haircut?
Well, then we need the maths to kick in.
We need to find a way to say ‘Don’t allocate Doctor’s in positions that would mean they have to work on a given day’, or in the world of the NHS that can mean ‘don’t allocate a Doctor where they would have to work any shift other than a 9 - 5’ (because 9 - 5 is easier to cover, or accept a smaller team on occasion). Basically the solver should try to work around any kind of mandatory shifts, such as long days, night shifts or individual’s holidays, weddings and pet grooming emergencies.
So, we take our Rota our RotaBuild and we say, what would these shifts look like if no one was assigned to them so in memory we generate a large collection of RosterShift(s) ranging from the start and end date we gave our RotaBuild and for all 20 weeks. It’s a massive matrix of shifts. Then we say if Doctor 1 was given Week 1 and we run through all the shifts that Doctor 1 would have been given, are there any clashes? If his cat is having a haircut give it a score of 99 and then we run it again, if Doctor 1 was given Week 2 are there any clashes?, etc for all 20 weeks of the Rota. Then we move onto the next user. Eventually you’ll end up with another grid.
This time, it’s Weeks horizontally and User(s) vertically. And we can see that some Weeks have a score of 1000, some 0 and some -1.
If you give Doctor 1 a starting week of 1, they’ll have no clashes and a total score of 0. If you give Doctor 1 a starting week of 3 or 4, they’ll have clashes and a total score of 1000.
1000 means ‘Don’t assign this user to this week’, -1000 means ‘definitely assign this user to this shift’. So we can create an elaborate scoring system to determine to what degree a User should, or should not be assigned a particular week.
Yeah, like so what?!
Well, then you fire this dataset at something else and that magic box spits out a result. It says:
I know you thought the most optimum assignment order for each week (or the order you first gave me) was 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,…but actually 1, 9, 7, 2, 5, 4, 6, 5, 8, 3 is much better for avoiding all those naughty clashes.
Thanks MATHS. You da bomb.
Then we say, well the black box told us to assign users like that, so we do. And then we save all of the RosterShift(s) we had in memory. Then the Roster is dropped out the other side and hey presto, happy customers, and saving 3 months of messing around trying to work this out manually.
Time is precious, and getting a system to do all the heavy lifting and optimisation leaves far more time for Administrators to deal with day to day issues and lets Staff feel confident that their life plans are not reliant on swapping all of their shifts around with their colleagues.