Alternate stops
You will learn how to use the Alternates option with a practical example.
In vehicle routing problems (VRPs) you may want your drivers to have a break at specific locations that are especially suitable for this. The router engine provides the Alternates option to configure such stops for each vehicle. The router will then add exactly one of those stops optimally to the vehicle's route.
The Alternates option is often combined with the Windows and the Services option to enforce a driver's break during the given time window for the specified "service time".

Example

The aim of this example is to define alternate stops (or breaks) for a vehicle. The introductory router example is used as a base, where routes are created to visit seven landmarks in Kyoto using two vehicles. Note, this example also uses the Capacity option for illustrative purposes.
alternates-input
Save the following information in an input.json file (see input and output for more information on working with input files).
JSON
1
{
2
"stops": [
3
{
4
"id": "Fushimi Inari Taisha",
5
"position": { "lon": 135.772695, "lat": 34.967146 }
6
},
7
{
8
"id": "Kiyomizu-dera",
9
"position": { "lon": 135.78506, "lat": 34.994857 }
10
},
11
{
12
"id": "Nijō Castle",
13
"position": { "lon": 135.748134, "lat": 35.014239 }
14
},
15
{
16
"id": "Kyoto Imperial Palace",
17
"position": { "lon": 135.762057, "lat": 35.025431 }
18
},
19
{
20
"id": "Gionmachi",
21
"position": { "lon": 135.775682, "lat": 35.002457 }
22
},
23
{
24
"id": "Kinkaku-ji",
25
"position": { "lon": 135.728898, "lat": 35.039705 }
26
},
27
{
28
"id": "Arashiyama Bamboo Forest",
29
"position": { "lon": 135.672009, "lat": 35.017209 }
30
}
31
],
32
"vehicles": ["v1", "v2"],
33
"alternate_stops": [
34
{
35
"id": "v1",
36
"stops": ["Nijō Castle", "Kiyomizu-dera"]
37
},
38
{
39
"id": "v2",
40
"stops": ["Nijō Castle", "Kiyomizu-dera"]
41
}
42
],
43
"quantities": [-1, -1, -1, -1, -1, 0, 0],
44
"capacities": [3, 3]
45
}
Copied!

Code

The following program uses the CLI Runner to obtain a solution and requires access to the Nextmv code repository on GitHub. To request access, please contact [email protected].
To proceed with running the example, create a main.go file and use the code snippet below.
Go
1
package main
2
3
import (
4
"github.com/nextmv-io/code/engines/route"
5
"github.com/nextmv-io/code/hop/run/cli"
6
"github.com/nextmv-io/code/hop/solve"
7
)
8
9
// Struct to read from JSON in.
10
type input struct {
11
Stops []route.Stop `json:"stops,omitempty"`
12
Vehicles []string `json:"vehicles,omitempty"`
13
Alternates []route.Alternate `json:"alternate_stops,omitempty"`
14
Quantities []int `json:"quantities,omitempty"`
15
Capacities []int `json:"capacities,omitempty"`
16
}
17
18
// Use the CLI runner to solve a Vehicle Routing Problem.
19
func main() {
20
f := func(i input, opt solve.Options) (solve.Solver, error) {
21
router, err := route.NewRouter(
22
i.Stops,
23
i.Vehicles,
24
route.Alternates(i.Alternates),
25
route.Capacity(i.Quantities, i.Capacities),
26
)
27
if err != nil {
28
return nil, err
29
}
30
31
return router.Solver(opt)
32
}
33
34
cli.Run(f)
35
}
Copied!
To execute the example, specify the path to the input.json file using command-line flags and use jq to extract the solution state (see runners for more information on building and running programs).
Bash
1
go run main.go -hop.runner.input.path input.json | jq .state
Copied!

Solution

The solution should look similar to this one:
JSON
1
{
2
"unassigned": [],
3
"vehicles": [
4
{
5
"id": "v1",
6
"route": [
7
{
8
"id": "Kyoto Imperial Palace",
9
"position": {
10
"lon": 135.762057,
11
"lat": 35.025431
12
}
13
},
14
{
15
"id": "Nijō Castle",
16
"position": {
17
"lon": 135.748134,
18
"lat": 35.014239
19
}
20
},
21
{
22
"id": "Kinkaku-ji",
23
"position": {
24
"lon": 135.728898,
25
"lat": 35.039705
26
}
27
},
28
{
29
"id": "Arashiyama Bamboo Forest",
30
"position": {
31
"lon": 135.672009,
32
"lat": 35.017209
33
}
34
}
35
],
36
"route_duration": 1085
37
},
38
{
39
"id": "v2",
40
"route": [
41
{
42
"id": "Gionmachi",
43
"position": {
44
"lon": 135.775682,
45
"lat": 35.002457
46
}
47
},
48
{
49
"id": "Kiyomizu-dera",
50
"position": {
51
"lon": 135.78506,
52
"lat": 34.994857
53
}
54
},
55
{
56
"id": "Fushimi Inari Taisha",
57
"position": {
58
"lon": 135.772695,
59
"lat": 34.967146
60
}
61
}
62
],
63
"route_duration": 448
64
}
65
]
66
}
Copied!
You can see that only one alternate stop was assigned to each vehicle. In this example, Nijō Castle was assigned to v1 and Kiyomizu-dera was assigned to v2.
alternates-with-capacity-output
Export as PDF
Copy link