Im am developing a logistics application and at the moment, I try to solve the following problem:
- In the system, there are multiple machines.
- Each machine has one or more skills. For example, machine 1 can have skill A and B and machine 2 can have skill B and C.
- Users can make reservations like: At some unknown time in the future, I need to use a machine with skill A. The application may accept or reject this reservation request.
- Later, users can redeem their reservation: I have reserved a machine with skill A, please make it available to me now.
- When a user is finished using a machine, they release the machine and return it to the system, so that the machine becomes available again.
Context: A "user" is a worker in a factory that needs to use a machine "soon", for example, in 5 minutes, or in 30 minutes, or in 2 hours. I guess we can assume that it is on the same work day. The worker does not know beforehand for how long they need to use the machine. It may be only for 5 minutes, but usually it is for about 30 minutes up to a few hours. In the past, workers were able to reserve concrete machines. However, they would always reserve those machines with most skills and block those for other workers. If they would have chosen a machine with a smaller subset of skills, specific for their problem, more workers would be able to work on the machines at once.
I thought about using some kind of ticket system: When the user makes a reservation and the application knows the it can be fulfilled, the app returns a reservation token, for example, a guid. When redeeming the reservation, the user sends the reservation token to the app.
I am now struggling with step 3. If the user made a reservation in step 3, then redeeming the reservation in step 4 must always succeed. (That's kind of the point of making a reservation.) This means that in step 3, the application needs to check that there are always enough machines available to fulfill all granted reservations. How can I do this in an optimal way? The application should be able to accept as many reservations as possible.
For me, the fact that each machine can have multiple skills makes it hard to solve the problem.
Example:
Say there are three machines:
- Machine 1: Skill A and B.
- Machine 2: Skill B and C.
- Machine 3: Skill C and D.
Say there are currently two active reservations, one for skill B and one for skill C. If another user now wants to make a reservation for skill A, this is okay, because all three reservations can be mapped to the machines simultaneously.
However, if there are currently three active reservations, one for skill B, one for skill C, and one for skill D, then an incoming reservation for skill A must be rejected.
What I tried:
I know that I can use a greedy algorithm that ensures that all granted reservations can be fulfilled: In step 3, the application looks for a machine that is not reserved and not in use and then reserves it. For example, in above setting, if a user reserves a machine with skill B, the application internally marks machine 1 as reserved and blocks it until the reservation is redeemed and the user releases the machine.
However, this algorithm is not optimal. Take above example. If the first user reserves a machine with skill B, the application may choose machine 1. If then another user tries to make a reservation for skill A, the application must reject the request, because the only machine with skill A is already reserved. If however the application had chosen to use machine 2 for skill B, it would be able to accept the reservation for skill A.
Is there some optimal algorithm that maximizes the number of accepted reservations?
(available_machines, reservations) → assignment | null
. To add a reservation, add it to the floating reservations set, try to compute an assignment, and commit the reservation if an assignment could be found. This strategy works regardless of how optimal your assignment algorithm is, and avoids having to bind reservations to fixed machines that you'd have to move around. Your problem is small enough to do all of this in-memory.