Hello,
I note that the discussion about driver breaks fizzled out (https://github.com/jsprit/jsprit/issues/99) but I find it hard to believe that people are not encountering this all the time. As such, is there an established work-around that is best practice or do people know what has the most success? I'll list the problems I'm having and my proposed approach.
I define the break as a job that is equidistant to all other locations and is of a unique package type that each vehicle can only hold one of, with set delivery times. Note: Defining near-zero distance/time to this location causes drivers to actively use the break as a wormhole. From this point on it's fire fighting with multiple drivers.
If I define my whole fleet, I need to define an equal number of break objects. Thus, my entire fleet is deployed even if the optimal solution is not to use all vehicles. This causes some drivers to only work up to the point of their break, and stop, whilst other drivers sit around waiting for their break to happen and then start deliveries after their break. I tried making it extremely expensive to return to the warehouse from the break location to try prompt the necessary vehicles to stay deployed. However, since they're all already deployed, this penalty goes across the board, keeping them all deployed. I can't think how to put hard constraints in here because there may be times that similar behaviour to this is actually required as a solution. We have varying delivery time windows, so it's possible I need to deploy more vehicles in the afternoon.
I don't want to go down the route of adding hard constraints to create two working time windows either. Our drivers are given a window in which to take their break, so it makes sense to maintain this flexibility.
What I am thinking:
Iteratively make new break locations between 1 and total fleet size . Each new break location is further away from all locations (except the warehouse) than the previous one, making it drastically more expensive for each new driver to do anything other than return to the warehouse. Does this seem viable? I imagine that to secure success, these distances need to scale rapidly for each new object and be on a different magnitude than real delivery distances. Might this have implications on the algorithm's ability to solve the problem? Might it just stop assigning break objects? Any implications I might not have thought about?
The next problem is different vehicle types with different running costs (the fleet is homogeneous atm thankfully). I either make a single break object type that can be juggled around the whole fleet (requiring lots of iterations to find a global optimum) or new break object types for each type of vehicle. Undecided, but I think it would need to be different types.
I have problems of different shifts etc. to deal with on top, plus getting real route statistics back from this mess, so I'd just like some assurance that what I am doing is viable and logical before I get stuck in J
Thanks.
---- On Wed, 22 Jul 2015 18:18:30 +0100 j.pi...@gmail.com wrote ----
--
You received this message because you are subscribed to the Google Groups "jsprit-mailing-list" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jsprit-mailing-...@googlegroups.com.
To post to this group, send email to jsprit-ma...@googlegroups.com.
Visit this group at http://groups.google.com/group/jsprit-mailing-list.
For more options, visit https://groups.google.com/d/optout.
---- On Wed, 22 Jul 2015 18:18:30 +0100 j.pi...@gmail.com wrote ----
--
--
Hi Philip,
Thank you so much for your detailed explanation, I love this idea even if it's bending my mind a bit! There's a lot of basic supporting code involved (kicking break stops out of the unassigned job list etc.) so it will take time for me to give proper feedback on this.
I think the implementation would have to be slightly different than you suggested. In much the same way as my initial idea, the whole fleet is now mobilised to deliver breaks. The "optimal" solution could then be very bizarre because if I had as many vehicles as total deliveries, each vehicle would carry one break and the corresponding actual delivery for which there is a zero distance/time penalty between them (disregarding time window constraints for the thought experiment). I've set it an impossible task to deliver all the breaks, but it seeks to deliver as many as possible. Crunching it down to more "actual" deliveries than vehicles, I imagine this could be a very undesirable type of clustering.
I think I could get away with just creating one set of break locations to mirror all real locations, but create one break location at the warehouse for each vehicle. Perhaps what I would need to do is *massively* inflate the distance from the warehouse (plus warehouse break) to every other location by a constant factor but keep the travel time the same. Otherwise, every vehicle is fair game to be assigned deliveries, which would result in lower man-hour costs. I have to mitigate this somehow, I've lost fixed costs as a limiter to the number of drivers.
I need to think more on this and then actually start testing bits out. Many thanks again with the base suggestion, I have a feeling it's a lot more solid than what I was planning. If you have any further thoughts going forward, I'd love to hear them. I'll be sure to report back once I have something more concrete.
Regards,
Josh
---- On Sun, 26 Jul 2015 17:32:59 +0100 j.pi...@gmail.com wrote ----
Hi Phil and Josh,
I really like your discussion about driver breaks, and love to see that you seem to find a solution for it. That is really great!
When it comes to waiting times, currently it is somewhat difficult to take them into account reasonably. However, this is what I am currently working at. In a few days you will be able to add waiting times to the optimization easily. Just by setting a vehicle type cost param much like .setCostPerDistance(..), e.g. .setCostPerWaitingTime(..). Additionally, you will be able to specify that vehicle departure times are variable. If so, the algorithm searches for a departure time that minimizes total waiting time of a route.
This way, you will probably solve the problem that drivers wait an hour for their breaks. Instead, they will server other customers, since minimizing total costs will be a trade-off between distance and waiting, e.g. one waiting time unit might be worth two distance units.
What keeps me working at it and is not yet solved is how I can locally estimate the total amount of waiting time a new customer adds to an existing route ...
Best,
Stefan
Am 26/07/15 um 20:49 schrieb j.pi...@gmail.com:
6b-8ed9-4746-a7...@googlegroups.com" type="cite">
The problem he will have is that to do this is that waiting time is completely dynamic. When you seek to insert jobs into a route (solving only for fuel cost and driver hours), you simply reference the distance/time matrix and everything is predictable.
Hopefully my last messages make more sense now.
Regards,
Josh
Hi Phil,
Apologies, I see now what you said here makes perfect sense, I went off topic. Why have a lunch break if you're waiting longer than the lunch break to take it (in an extreme case)? Yes, then I must caveat my work-around in that it's only stable when the driver is otherwise completely packed with work. The work-around guarantees a break, but that in itself opens a new set of problems. With the current tools, I guess we dead-end here.
Something makes me a little uneasy about trying to actually estimate a cost penalty value on waiting time, in such a dynamic problem space, without skewing the solution in an unpredictable way. We'll have to wait and see, but I will be very active in testing it. I think for the sake of my sanity - previously having drivers opening wormholes or making them take their break in an alternate dimension - I'll put this issue to bed until then!
Best of luck on this one, Stefan. Thanks Both for this discussion.
Josh
You are correct. In this regards, I have created a branch called 'min-waiting-start-times'. Take a look at this example. If you run the example with .setWaitingTimeCosts(0.0) you will get the following solutions:
[ alpha * ( waitingCosts(k,arrivalTime_k) + waitingCosts(j,arrivalTime_j)) ] + epsilon
cost. Equally, the service time of k increases epsilon. Could this be introducing a bias that a job with a long service time but, additionally, a waiting time before it could be seen as an attractive choice?
It projects forward a powerful estimation about how this insertion could affect subsequent waiting times, but I wonder if this is too powerful as it can overpower the analysis of the present activity insertion.
Hi Stefan,
I have got the new branch fully set up and integrated with my own data. Initial observation – it's working exactly as intended right out-of-the-box. Fantastic! I'll be starting proper benchmarks soon (on everything but computation time... I'm running this experimental branch on a virtual machine to avoid me accidentally damaging my existing setup). Even on the VM it's fast enough to not really see any difference. I'll then move on to trying to break it or pull out anomalies with fringe cases.
I'll probably be quiet for a while now while I collate all my tests and give feedback. But, at the very least you know one person has this running and testing it (and liking it a lot) :)
Great work on this one, Stefan.
Josh
Hi Stefan,
--