Optimizing Routes
The RouteCloud API optimizes routes by POSTing optimize requests in JSON format to /v1/optimize. The "optimize routes" call attempts to improve on the solution provided in the request. It does this by rearranging jobs on the given routes in a way that minimizes the cost of the routes and respects any constraints that have been applied on the routes and jobs. If a job cannot be placed on a route, it is placed in the unrouted_jobs list instead.
This process differs from the Building Routes process in that by reducing the types of optimizations that can be applied it runs significantly more quickly. It is recommended that you use the optimize process only to quickly check for improvements once the majority of your jobs have been assigned by a build request.
Note
To run the examples in this tutorial, you will need:
- A RouteCloud API login. Use your Verizon Connect Enterprise username and password to authenticate with the RouteCloud API. To obtain a username and password, contact Verizon Connect sales.
- cURL to run the requests. You can download a cURL binary from here.
You can download a copy of the optimizing_routes.json
example optimize request from here.
Run the request in the command line using cURL:
curl -u "telogisuser%3Amain:password" "https://routecloud.telogis.com/v1/optimize?wait=1" -H "Content-Type: application/json" --data-binary "@optimizing_routes.json" -L
Substitute youraccount%3Amain
for your username (replacing the colon with %3A
), and password
with your password. See the Authentication topic for more information and alternative authentication methods.
The wait=1
parameter instructs RouteCloud to return the results synchronously. This means that results are returned directly to the command window.
See Retrieving API Results for more information about synchronous and asynchronous tasks.
RouteCloud will optimize the jobs and should return a response within a few seconds.
Request
{
"id": "optimizing_routes",
"routes": [
{
"id": "route0",
"location": "39.718005, -104.969531",
"start_time": "09:00",
"max_working_time": "08:00",
"date": "2016-1-18",
"breaks": [
{ "id": "route0_lunch_break", "start": "12:00", "length": "00:30" }
],
"jobs": [
{ "id": "job7", "time_on_site": "00:10", "location": "39.727919, -105.103126", "required_route_attributes": [ "heavy_truck" ] },
{ "id": "job2", "time_on_site": "00:15", "location": "39.708990, -105.026954", "date": "2016-1-19" },
{ "id": "job5", "time_on_site": "00:10", "location": "39.638635, -105.128906", "required_route_attributes": [ "hazmat" ] },
{ "id": "job8", "time_on_site": "00:10", "location": "39.615167, -104.887500", "time_window": { "start": "13:00", "end": "15:00" } }
]
},
{
"id": "route1",
"location": "39.718005, -104.969531",
"start_time": "09:00",
"max_working_time": "08:00",
"route_attributes": [ "hazmat" ],
"date": "2016-1-19",
"breaks": [
{ "id": "route1_lunch_break", "start": "12:00", "length": "00:30" }
],
"jobs": [
{ "id": "job4", "time_on_site": "00:15", "location": "39.590789, -105.084376", "allowed_dates": [ "2016-1-20" ] },
{ "id": "job6", "time_on_site": "00:10", "location": "39.597111, -105.041015", "disallowed_route_attributes": [ "hazmat" ] },
{ "id": "job10", "time_on_site": "00:10", "location": "39.749546, -105.069141" }
]
},
{
"id": "route2",
"location": "39.718005, -104.969531",
"start_time": "09:00",
"max_working_time": "04:00",
"date": "2016-1-20",
"breaks": [
{ "id": "route2_lunch_break", "start": "12:00", "length": "00:30" }
],
"jobs": [
{ "id": "job0", "time_on_site": "00:10", "location": "39.635928, -105.049219" },
{ "id": "job1", "time_on_site": "00:10", "location": "39.725375, -104.791080", "date": "2016-1-18" },
{ "id": "job3", "time_on_site": "00:10", "location": "39.653975, -105.093750", "allowed_dates": [ "2016-1-18", "2016-1-19" ] },
{ "id": "job9", "time_on_site": "00:10", "location": "39.820688, -105.133594" }
]
}
],
"jobs": [
{ "id": "job11", "time_on_site": "00:10", "location": "39.556465, -104.976563" }
]
}
*The optimizing_routes.json request. Click here to open in the UI. *
The request JSON consists of an array of routes and an array of jobs. The jobs in the request are assigned in a sub-optimal way:
job5
,job6
, andjob7
have attribute mismatches.job1
,job2
,job3
, andjob4
are delivered on incorrect days.job11
is not assigned to a route.- Many stops can be rearranged to make the routes more efficient.
The jobs will be rearranged by the RouteCloud optimizer in a way that minimizes the cost and respects the constraints set out in the request. The resulting routes will be returned in a response object.
Response
{
"routes": [
{
"id": "route0",
"cost": 25.94,
"internal_cost": 134.2,
"distance_meters": 49226,
"working_time": "01:04:22",
"driving_time": "00:54:22",
"stops": [
{ "type": "depot", ... },
{ "job": "job1", "type": "job", ... },
{ "type": "depot", ... }
]
},
{
"id": "route1",
"cost": 91.62,
"internal_cost": 232.76,
"distance_meters": 122724,
"working_time": "04:28:18",
"driving_time": "02:31:32",
"stops": [
{ "type": "depot", ... },
{ "job": "job2", "type": "job", ... },
{ "job": "job10", "type": "job", ... },
{ "job": "job9", "type": "job", ... },
{ "job": "job3", "type": "job", ... },
{ "job": "job5", "type": "job", ... },
{ "job": "job0", "type": "job", ... },
{ "break": "route1_lunch_break", "type": "break", ... },
{ "job": "job11", "type": "job", ... },
{ "job": "job8", "type": "job", ... },
{ "type": "depot", ... }
]
},
{
"id": "route2",
"cost": 31.14,
"internal_cost": 142.51,
"distance_meters": 45230,
"working_time": "01:28:22",
"driving_time": "01:03:22",
"stops": [
{ "type": "depot", ... },
{ "job": "job6", "type": "job", ... },
{ "job": "job4", "type": "job", ... },
{ "type": "depot", ... }
]
}
],
"unrouted_jobs": [ { "id": "job7", "job": "job7" } ]
}
A snipped version of the optimizing_routes.json response. The full response is available here. Click here to open in the UI.
The response object consists of an array of route objects, and an array of unrouted jobs.
- Each route contains an ordered list of stops as well as information about the route, such as its total time, and distance in meters.
- Each stop in the route.stops array can be either a job, break, or depot. The arrival time and the time/distance are calculated from the previous stop.
The optimizing_routes.json request produces a response with the following assignments and sequences:
route0
:depot
,job1
,depot
route1
:depot
,job2
,job10
,job9
,job3
,job5
,job0
,break
,job11
,job8
,depot
route2
:depot
,job6
,job4
,depot
unrouted_jobs
:job7
These route assignments minimize cost while obeying all of the job constraints specified in the optimizing_routes.json request.
Explanation:
- Accurate arrival times, driving times, and driving distances have been calculated for every stop.
job1
,job2
,job3
, andjob4
were moved to routes that would respect their date constraints. See Routing with Dates for more information on dates.job5
,job6
, andjob7
were moved to respect their attribute requirements. See Routing with Attributes for more information on attributes.job5
was placed onroute1
because it required thehazmat
attribute.job6
was placed onroute2
. It was not placed onroute1
because it disallowed thehazmat
attribute.job7
was unrouted as its requiredheavy_truck
attribute could not be satisfied.
job8
was moved to the end ofroute8
to minimize the amount of idle time taken before it, since its time window opens at 1:00 PM.- See Routing with Time Windows for more information on time windows.
- Depots and breaks have been inserted as necessary, in the same way as described in Building Routes.
What Next?
- Continue to Sequencing Routes.
- View the /v1/optimize reference.
- Back to Building Routes.