ROUTES OpenBI
Delivery rounds that leave a depot, visit the places in view and come back, each vehicle within its capacity, planned with Google OR-Tools.
Group: Operations research. OpenBI’s own: DAX has no function of this name.
Syntax
ROUTES ( <places>, <name>, <latitude>, <longitude>, <vehicles> [, <demand> [, <capacity> [, <depot>
[, <seconds> [, <distances>, <fromPlace>, <toPlace>, <distance>]]]]] )
| Parameter | Type | Description |
|---|---|---|
places | Table | The places to visit, the depot among them: such as the Places table, as the filters leave it. |
name | Expression evaluated for each row | The row's place, by name. A row without one is left out; a name seen before is skipped. |
latitude | Expression evaluated for each row | The row's latitude in degrees. |
longitude | Expression evaluated for each row | The row's longitude in degrees. |
vehicles | Whole number | How many vehicles there are, from 1 to 200. Not all of them need be used. |
demand | Expression optional, evaluated for each row | What the row's place takes, such as crates: a number, 0 or more, rounded to a whole one. Left out, nothing is carried. |
capacity | Number optional | The most a vehicle carries. Left out or blank, there is no limit. |
depot | Text optional | The place the vehicles leave from and come back to. Left out, the first place by name whose demand is 0. |
seconds | Number optional | How long the search may improve the routes: 2 when left out, at most 60. |
distances | Table optional | A table of distances between places, such as driving meters. Given, it comes with the three that follow. |
fromPlace | Expression optional, evaluated for each row | The distance row's first place, by name. |
toPlace | Expression optional, evaluated for each row | The distance row's second place, by name. |
distance | Expression optional, evaluated for each row | The distance from the one to the other, 0 or more, rounded to a whole number. |
Returns
Table. A row for each stop of each vehicle used: Vehicle (numbered from 1), Order (0 at the depot, and the depot again last), Place with its Lat and Lon, Load (the demand served up to and including that stop), Distance (driven by then), and the vehicle's whole round in Route distance and Route load.
Remarks
- It plans a capacitated vehicle routing problem: every place but the depot is visited once, by one vehicle, no vehicle carries more than its capacity, and the total distance is as short as the search finds. Start from the cheapest arcs, then a guided local search for the seconds given.
- Without a table of distances the distance between two places is the great circle between their coordinates, in meters. With one, its pairs are used in the direction given (from the first place to the second), and a pair it lacks falls back on the great circle; Distance and Route distance are then in the table's units, such as minutes.
- The places are the rows of the table as the filters leave them, so a slicer on districts plans the routes for those districts only. Keep the depot in view: a named depot that the filters remove makes the call an error.
- Name the depot. Left out, it is the first place in alphabetical order whose demand is 0, which may not be the one meant: without a demand, every place has 0.
- When the vehicles cannot carry all the demand, there are no routes and the call is an error: add vehicles or capacity. Fewer than two places, a negative distance, or a place with neither coordinates nor distances to the others is an error too.
- A search limited in time may find other routes of the same length, or close to it, in another session; the same question asked again while the engine runs gets the same routes at once.
- A table of distances must come with all four of its arguments; at most 1,000 places.
Compared with DAX
An OpenBI function: DAX has none like it, so a measure or query that uses it works in OpenBI only, not in Power BI or Analysis Services.
Examples
Three vans of 70 crates
The depot at Alnabru and fifteen shops, each van carrying at most 70 of the 178 crates, distances along the great circle.
EVALUATE
SELECTCOLUMNS (
ROUTES ( Places, Places[Place], Places[Lat], Places[Lon], 3, [Deliveries], 70 ),
"Van", [Vehicle],
"Stop", [Order],
"Place", [Place],
"Crates so far", [Load],
"Meters so far", [Distance]
)
| Van | Stop | Place | Crates so far | Meters so far |
|---|---|---|---|---|
| 1 | 0 | Depot Alnabru | 0 | 0 |
| 1 | 1 | Shop Grünerløkka | 18 | 5097 |
| 1 | 2 | Shop Frogner | 30 | 7967 |
| 1 | 3 | Shop Skøyen | 38 | 9637 |
| 1 | 4 | Shop Majorstuen | 52 | 11739 |
| 1 | 5 | Shop St. Hanshaugen | 67 | 13177 |
| 1 | 6 | Depot Alnabru | 67 | 19091 |
| 2 | 0 | Depot Alnabru | 0 | 0 |
| 2 | 1 | Shop Storo | 9 | 4323 |
| 2 | 2 | Shop Nydalen | 19 | 5150 |
| 2 | 3 | Shop Ullevål | 26 | 7196 |
| 2 | 4 | Shop Sagene | 39 | 8548 |
| 2 | 5 | Shop Torshov | 53 | 8988 |
| 2 | 6 | Depot Alnabru | 53 | 13704 |
| 3 | 0 | Depot Alnabru | 0 | 0 |
| 3 | 1 | Shop Kampen | 9 | 4188 |
| 3 | 2 | Shop Tøyen | 20 | 4973 |
| 3 | 3 | Shop Grønland | 32 | 5482 |
| 3 | 4 | Shop Bjørvika | 48 | 6296 |
| 3 | 5 | Shop Vålerenga | 58 | 8005 |
| 3 | 6 | Depot Alnabru | 58 | 12089 |
On the road: driving meters
The same vans with the Distances table's meters by road: each van's round, and the kilometers in all.
EVALUATE
VAR Rounds =
ROUTES (
Places, Places[Place], Places[Lat], Places[Lon], 3, [Deliveries], 70, "Depot Alnabru", 2,
Distances, Distances[From], Distances[To], Distances[Meters]
)
RETURN
ROW (
"Vans used", COUNTROWS ( FILTER ( Rounds, [Order] = 0 ) ),
"Crates", SUMX ( FILTER ( Rounds, [Order] = 0 ), [Route load] ),
"Kilometers", SUMX ( FILTER ( Rounds, [Order] = 0 ), [Route distance] ) / 1000
)
| Vans used | Crates | Kilometers |
|---|---|---|
| 3 | 178 | 65.7 |
One van for the eastern shops
The filter keeps the depot and three shops; one van without a capacity takes them in turn.
EVALUATE
SELECTCOLUMNS (
CALCULATETABLE (
ROUTES ( Places, Places[Place], Places[Lat], Places[Lon], 1, [Deliveries], , "Depot Alnabru" ),
Places[District] IN { "Alnabru", "Tøyen", "Kampen", "Vålerenga" }
),
"Stop", [Order],
"Place", [Place],
"Crates so far", [Load],
"Meters so far", [Distance],
"Round", [Route distance]
)
| Stop | Place | Crates so far | Meters so far | Round |
|---|---|---|---|---|
| 0 | Depot Alnabru | 0 | 0 | 10461 |
| 1 | Shop Vålerenga | 10 | 4084 | 10461 |
| 2 | Shop Kampen | 19 | 4882 | 10461 |
| 3 | Shop Tøyen | 30 | 5667 | 10461 |
| 4 | Depot Alnabru | 30 | 10461 | 10461 |