The pandemic has highlighted how supply chains are coming under pressure to solve last mile delivery problems as more and more consumers demand door-to-door delivery (for free).
Solving the last mile problem is notoriously hard. In fact,
The last mile can consume up to 30% of the entire supply chain cost.
That's huge.
Delivery and logistics companies have to find ways to become more efficient. And they are. Drones are being used, self driving vehicles are right around the corner (literally; looking left and right before crossing the street is arguably more important than ever), and companies are investing heavily in route optimization.
Here's a quick example of just how much money is being left out there on the tarmac.
Consider a small to mid-sized U.S. based logistics and delivery company with 50 vehicles in their fleet. Let's be conservative and assume the driver is paid $20 per hour and it costs 12 cents per mile in fuel costs. We can ignore wear and tear (you can't in the real world) to make things simple.
First we calculate the average per-hour fuel costs. Since our hypothetical delivery company is working in an urban environment, they only move about 10 miles per hour. This yields a fuel cost of $1.20 per hour.
Add that to the $20 per hour for labor and you have a total hourly cost to company, per vehicle per hour, of $21.20.
Now, assume the vehicles are operating 8 hours per day, Monday to Friday, four weeks per month. That gives us the following:
50 vehicles x $21.20 per hour x 8 hours per day x 20 days per month =
$169 600 per month
To put it another way, our company is spending (at the very least) a touch over $2 million per year on transport costs. Without taking into account wear and tear, insurance, and, and, and...
Streamlining costs by as little as 5% would lead to savings of around $100 000 per year. So why isn't every company implementing their own route optimization systems?
The truth of the matter is that building software that can optimize routes, taking into account a host of real-world costs, constraints and conditions is extremely difficult.
Here's why...
Pretend our small to mid-sized delivery company has 250 deliveries to make on Monday morning, split up between their 50 vehicles. We want to find the optimal way to route each vehicle so that every delivery is made within the given time-frame (i.e. the company's operating hours).
To do this we try to check each and every possibility. After all, we have access to some pretty fast computers these days.
We can pick a vehicle to visit a location. Then, repeat the process for the next location, and so on until all 250 deliveries have been made.
To work out the total number of permutations we need to check, we can use the following formula:
50 x 250 + 50 x 249 + ... + 50 x 2 + 50 x 1
= 50²⁵⁰ x 250!
= 5.5⁴²⁴ x 3.2 x 10⁴⁹²
= 1.78 x 10⁹¹⁷
That's a big number. To put it into perspective,
A simple route optimization problem with a single vehicle and 50 stops has 30 million times more permutations than atoms of Hydrogen in the Sun (10⁵⁷).
In fact, there are only about 10⁸⁰ atoms in the entire known universe. That's such a small fraction of the number of possible permutations in our seemingly everyday problem that it is essentially 0 by comparison.
To try and check each possibility would take more time than there is left in this Universe and many trillions more (Universe lifespans) thereafter, using all the processors we have ever built.
Clearly that's not on the cards for a Monday morning. No matter how serious our delivery company is about saving money.
So straightforward route optimization software is not really something delivery and logistics companies want to tackle in their spare time. Although companies like UPS are spending millions trying.
The good news is that APIs (Application Programming Interface) are becoming widely available to do this for surprisingly little cost.
From as little as $10 per vehicle per month it is possible for our delivery company to plug into a vehicle routing API and turn their unordered list of deliveries into a series of optimal routes for their entire fleet in a way that honors their specific business requirements and objectives.
At $10 per vehicle per month, the cost to company for 50 vehicles is $500 per month (or $6000 per year), offset by potential savings of $100 000.
With only the minimum of API development skills required, it is possible to drastically lower delivery costs overnight. Bear in mind that some companies have reported savings of around 30% after integrating route optimization software.
Here's a sample JSON API request for a simple schedule with a single vehicle and five locations - courtesy of Optergon's route optimization API:
{
"job":{
"Reference":"XXXXXX",
"JobOptimizationType":"Cost",
"JobMode":"MinimizeVehicles",
"MultiTrip":true,
"CreatedDate":"\/Date(1610015158000+0000)\/",
"Vehicles":[
{
"Reference":"ODC-P1",
"Name":"Our Delivery Company Pickup I",
"TimeWindows":[
{
"Identifier":"35a77f76-5f1f-4a4a-82bd-xxxxxxxxxxx",
"Range":450000,
"FixedCost":0,
"TimeCost":10,
"DistanceCost":1,
"StartLocationReference":"Depot",
"EndLocationReference":"Depot",
"TimeDilation":0,
"WorkingTime":{
"StartTime":"\/Date(1606294800000+0000)\/",
"EndTime":"\/Date(1606323600000+0000)\/"
},
"Attributes":null,
"Capacities":null,
"VehicleBreaks":null
}
]
}
],
"Locations":[
{
"Reference":"Depot",
"Name":"Our Depot, Our City",
"ServiceDuration":0,
"IsDepot":true,
"IsRefuel":false,
"IsRequired":true,
"TurnAroundTime":1800,
"TurnAroundCost":0,
"Constraints":null,
"PickupDropOffs":null,
"TimeWindows":[
{
"StartTime":"\/Date(1606294800000+0000)\/",
"EndTime":"\/Date(1609002000000+0000)\/"
}
],
"Position":{
"Latitude":xx.xxxxx,
"Longitude":-x.xxxxx
},
"ScheduleDateTimeCheckString":""
},{
"Reference":"Delivery I",
"Name":"32 Delivery Rd",
"ServiceDuration":500,
"IsDepot":false,
"IsRefuel":false,
"IsRequired":true,
"TurnAroundTime":0,
"TurnAroundCost":0,
"Constraints":null,
"PickupDropOffs":null,
"TimeWindows":[
{
"StartTime":"\/Date(1606294800000+0000)\/",
"EndTime":"\/Date(1609002000000+0000)\/"
}
],
"Position":{
"Latitude":xx.xxxxx,
"Longitude":-x.xxxxx
},
"ScheduleDateTimeCheckString":""
},{
"Reference":"Delivery II",
"Name":"2 Drop-Off Ave",
"ServiceDuration":500,
"IsDepot":false,
"IsRefuel":false,
"IsRequired":true,
"TurnAroundTime":0,
"TurnAroundCost":0,
"Constraints":null,
"PickupDropOffs":null,
"TimeWindows":[
{
"StartTime":"\/Date(1606294800000+0000)\/",
"EndTime":"\/Date(1609002000000+0000)\/"
}
],
"Position":{
"Latitude":xx.xxxxx,
"Longitude":-x.xxxxx
},
"ScheduleDateTimeCheckString":""
},{
"Reference":"Delivery III",
"Name":"51 Package Place",
"ServiceDuration":500,
"IsDepot":false,
"IsRefuel":false,
"IsRequired":true,
"TurnAroundTime":0,
"TurnAroundCost":0,
"Constraints":null,
"PickupDropOffs":null,
"TimeWindows":[
{
"StartTime":"\/Date(1606294800000+0000)\/",
"EndTime":"\/Date(1609002000000+0000)\/"
}
],
"Position":{
"Latitude":xx.xxxxx,
"Longitude":-x.xxxxx
},
"ScheduleDateTimeCheckString":""
},{
"Reference":"Delivery IV",
"Name":"123 Parcel St",
"ServiceDuration":500,
"IsDepot":false,
"IsRefuel":false,
"IsRequired":true,
"TurnAroundTime":0,
"TurnAroundCost":0,
"Constraints":null,
"PickupDropOffs":null,
"TimeWindows":[
{
"StartTime":"\/Date(1606294800000+0000)\/",
"EndTime":"\/Date(1609002000000+0000)\/"
}
],
"Position":{
"Latitude":xx.xxxxx,
"Longitude":-x.xxxxx
},
"ScheduleDateTimeCheckString":""
}
]
},
"token":{
"UserGuid":"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXX",
"Signature":"XXXXXXXXXXXXXXXXXXXXXXXXXX="
}
}
JSON skills aside, all this API request does is:The API JSON response is very similar (and effectively hides the complexity associated with tackling massive vehicle routing problems):
{
"ErrorCode":"0",
"Message":"ok",
"Result":{
"Comment":"",
"Confidence":0,
"Cost":34.18,
"CreatedDate":"\/Date(1610015166203+0000)\/",
"Distance":20640,
"Error":"",
"Execution":0,
"JobReference":"XXXXXX",
"ResultCode":1,
"SolutionId":XXXXXX,
"Time":4875,
"Units":1,
"UnreachedLocations":null,
"UnusedDepots":null,
"UnusedVehicles":null,
"Vehicles":[
{
"Comment":"",
"Cost":34.18,
"Distance":20640,
"DrivingTime":4875,
"DurationTime":2000,
"Error":"",
"Name":"Our Delivery Company Pickup I",
"SolutionUnitStatusId":1,
"Stops":[
{
"ArrivalTime":"\/Date(1606294800000+0000)\/",
"Comment":"",
"DepartureTime":"\/Date(1606294800000+0000)\/",
"DrivingDistance":0,
"DrivingDistanceSum":0,
"DrivingTime":0,
"DrivingTimeSum":0,
"Duration":0,
"DurationSum":0,
"Error":"",
"Index":0,
"IsDepot":true,
"LocationReference":"Depot",
"Name":"Our Depot, Our City",
"Position":{
"Latitude":xx.xxxxx,
"Longitude":-x.xxxxx
},
"ScheduledEnd":"\/Date(1606294800000+0000)\/",
"ScheduledStart":"\/Date(1606294800000+0000)\/",
"WaitTime":0,
"WaitTimeSum":0
},{
"ArrivalTime":"\/Date(1606294970000+0000)\/",
"Comment":"",
"DepartureTime":"\/Date(1606295470000+0000)\/",
"DrivingDistance":757,
"DrivingDistanceSum":757,
"DrivingTime":170,
"DrivingTimeSum":170,
"Duration":500,
"DurationSum":500,
"Error":"",
"Index":1,
"IsDepot":false,
"LocationReference":"Delivery III",
"Name":"51 Package Place",
"Position":{
"Latitude":xx.xxxxx,
"Longitude":-x.xxxxx
},
"ScheduledEnd":"\/Date(1606295470000+0000)\/",
"ScheduledStart":"\/Date(1606294970000+0000)\/",
"WaitTime":0,
"WaitTimeSum":0
},{
"ArrivalTime":"\/Date(1606295566000+0000)\/",
"Comment":"",
"DepartureTime":"\/Date(1606296066000+0000)\/",
"DrivingDistance":337,
"DrivingDistanceSum":1094,
"DrivingTime":96,
"DrivingTimeSum":266,
"Duration":500,
"DurationSum":1000,
"Error":"",
"Index":2,
"IsDepot":false,
"LocationReference":"Delivery IV",
"Name":"123 Parcel St",
"Position":{
"Latitude":xx.xxxxxx,
"Longitude":-x.xxxxx
},
"ScheduledEnd":"\/Date(1606296066000+0000)\/",
"ScheduledStart":"\/Date(1606295566000+0000)\/",
"WaitTime":0,
"WaitTimeSum":0
},{
"ArrivalTime":"\/Date(1606296776000+0000)\/",
"Comment":"",
"DepartureTime":"\/Date(1606297276000+0000)\/",
"DrivingDistance":5460,
"DrivingDistanceSum":6554,
"DrivingTime":710,
"DrivingTimeSum":976,
"Duration":500,
"DurationSum":1500,
"Error":"",
"Index":3,
"IsDepot":false,
"LocationReference":"Delivery I",
"Name":"32 Delivery Rd",
"Position":{
"Latitude":xx.xxxxx,
"Longitude":-x.xxxxx
},
"ScheduledEnd":"\/Date(1606297276000+0000)\/",
"ScheduledStart":"\/Date(1606296776000+0000)\/",
"WaitTime":0,
"WaitTimeSum":0
},{
"ArrivalTime":"\/Date(1606298471000+0000)\/",
"Comment":"",
"DepartureTime":"\/Date(1606298971000+0000)\/",
"DrivingDistance":9396,
"DrivingDistanceSum":15950,
"DrivingTime":1195,
"DrivingTimeSum":2171,
"Duration":500,
"DurationSum":2000,
"Error":"",
"Index":4,
"IsDepot":false,
"LocationReference":"Delivery II",
"Name":"2 Drop-Off Ave",
"Position":{
"Latitude":xx.xxxxxx,
"Longitude":-x.xxxxx
},
"ScheduledEnd":"\/Date(1606298971000+0000)\/",
"ScheduledStart":"\/Date(1606298471000+0000)\/",
"WaitTime":0,
"WaitTimeSum":0
},{
"ArrivalTime":"\/Date(1606299675000+0000)\/",
"Comment":"",
"DepartureTime":"\/Date(1606299675000+0000)\/",
"DrivingDistance":4690,
"DrivingDistanceSum":20640,
"DrivingTime":704,
"DrivingTimeSum":2875,
"Duration":0,
"DurationSum":2000,
"Error":"",
"Index":5,
"IsDepot":true,
"LocationReference":"Depot",
"Name":"Our Depot, Our City",
"Position":{
"Latitude":xx.xxxxx,
"Longitude":-x.xxxxx
},
"ScheduledEnd":"\/Date(1606299675000+0000)\/",
"ScheduledStart":"\/Date(1606299675000+0000)\/",
"WaitTime":0,
"WaitTimeSum":0
}
],
"TimeWindow":{
"EndTime":"\/Date(1606323600000+0000)\/",
"Identifier":"56cf7e2f-2dc1-418e-9c6a-180d849a75fa",
"StartTime":"\/Date(1606294800000+0000)\/"
},
"VehicleReference":"ODC-P1",
"WaitTime":0
}
]
},
"Status":"ok"
}
This solution has taken an unordered list of locations and converted them into an array of vehicles, each with an optimized delivery route that obeys the constraints of the business rules specified in the request.
Specifically, it:
In other words, each vehicle is routed in order to lower the overall cost-to-company. At the same time, no vehicle carries more than its stated capacity, works overtime (unless it is impossible to avoid), or carries something it cannot (i.e. only cold chain vehicles will carry frozen goods, if so specified).
Essentially, the API converts a problem like this (shown with 50 locations and 3 vehicles):
3 vehicle, 50 location route optimization problem courtesy of Optergon.
Into a solution (that obeys all specified, real-world business constraints), like this:
Optimal vehicle routing solution for 3 vehicles courtesy of Optergon.
Any business that incurs some form of transport cost essentially has three choices in front of it:
Until recently, option 1 sufficed because the consumer essentially covered the cost of transport. Delivery costs were simply accepted as an additional expense, or built into the cost of goods directly.
The pandemic has accelerated the demand for low cost, last-mile deliveries. This leaves options 2 and 3 open to logistics companies that need to remain competitive.
Building a custom route optimization system requires a rare combination of math and programming skills. Designers and developers implement meta-heuristic algorithms that are tricky to build and debug.
If non-deterministic code is tricky to build, it's even trickier to debug. To boot, it also requires a massively multi-threaded environment that, in turn, requires expensive, highly specialized hardware. A big ask for small to mid-sized logistics companies.
This leaves option 3 (i.e. integration with a route optimization API) as the only real option available. Fortunately,
It only requires savings in the order of a fraction of a percent to make route optimization API integration instantly financially viable.
From a financial perspective, integrating with a 3rd party API essentially has an immediate positive return. Literally, the minute your company starts following optimal delivery routes, the time and distance spent on the road drops.
While there are obvious reductions in labor, fuel, wear and tear, insurance, and a host of other costs plummet, there are a host of hidden benefits for the entire supply chain. Knowing optimal delivery routes ahead of time means:
With manifold upstream and downstream benefits for any logistics company, plus an immediate positive return on investment, almost everyone in the supply chain should be looking at route optimization integration for the last mile.
I personally savor the idea that millions of tons of Carbon and other pollutants will no longer be pumped into our atmosphere by less than efficiently routed delivery vehicles. I'll go so far as saying that even Mother Nature will thank you for using a route optimization API.
Previously published at https://optergon.com/blog/costbenefits-route-optimization-api-integration