Stop group service times
You will learn how to use the Service Groups option with a practical example.
In vehicle routing problems (VRPs), you sometimes need to account for the amount of extra time required to enter a building or a fenced area. This allows for a more realistic VRP model that includes more than just loading and unloading times. This information can be added to the model using the ServiceGroups option.
The ServiceGroups option is often combined with the Services, Shifts and Windows options.

Example

The router example is used as a base, where routes are created to visit seven landmarks in Kyoto using two vehicles. This time, we define a service group of a few stops. In addition, we also use the Shifts option to have ETA and ETD in the output.
service-groups-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
"service_groups": [
34
{
35
"group": ["Fushimi Inari Taisha", "Kiyomizu-dera", "Nijō Castle"],
36
"duration": 900
37
}
38
],
39
"shifts": [
40
{
41
"start": "2020-10-17T10:00:00-06:00"
42
},
43
{
44
"start": "2020-10-17T12:00:00-06:00"
45
}
46
]
47
}
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
ServiceGroups []route.ServiceGroup `json:"service_groups,omitempty"`
14
Shifts []route.TimeWindow `json:"shifts,omitempty"`
15
}
16
17
// Use the CLI runner to solve a Vehicle Routing Problem.
18
func main() {
19
f := func(i input, opt solve.Options) (solve.Solver, error) {
20
router, err := route.NewRouter(
21
i.Stops,
22
i.Vehicles,
23
route.ServiceGroups(i.ServiceGroups),
24
route.Shifts(i.Shifts),
25
)
26
if err != nil {
27
return nil, err
28
}
29
30
return router.Solver(opt)
31
}
32
33
cli.Run(f)
34
}
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": "Fushimi Inari Taisha",
9
"position": {
10
"lon": 135.772695,
11
"lat": 34.967146
12
},
13
"estimated_arrival": "2020-10-17T10:00:00-06:00",
14
"estimated_departure": "2020-10-17T10:15:00-06:00"
15
},
16
{
17
"id": "Kiyomizu-dera",
18
"position": {
19
"lon": 135.78506,
20
"lat": 34.994857
21
},
22
"estimated_arrival": "2020-10-17T10:20:28-06:00",
23
"estimated_departure": "2020-10-17T10:20:28-06:00"
24
},
25
{
26
"id": "Gionmachi",
27
"position": {
28
"lon": 135.775682,
29
"lat": 35.002457
30
},
31
"estimated_arrival": "2020-10-17T10:22:28-06:00",
32
"estimated_departure": "2020-10-17T10:22:28-06:00"
33
},
34
{
35
"id": "Kyoto Imperial Palace",
36
"position": {
37
"lon": 135.762057,
38
"lat": 35.025431
39
},
40
"estimated_arrival": "2020-10-17T10:27:12-06:00",
41
"estimated_departure": "2020-10-17T10:27:12-06:00"
42
},
43
{
44
"id": "Nijō Castle",
45
"position": {
46
"lon": 135.748134,
47
"lat": 35.014239
48
},
49
"estimated_arrival": "2020-10-17T10:30:10-06:00",
50
"estimated_departure": "2020-10-17T10:45:10-06:00"
51
},
52
{
53
"id": "Kinkaku-ji",
54
"position": {
55
"lon": 135.728898,
56
"lat": 35.039705
57
},
58
"estimated_arrival": "2020-10-17T10:50:43-06:00",
59
"estimated_departure": "2020-10-17T10:50:43-06:00"
60
}
61
],
62
"route_duration": 3042
63
},
64
{
65
"id": "v2",
66
"route": [
67
{
68
"id": "Arashiyama Bamboo Forest",
69
"position": {
70
"lon": 135.672009,
71
"lat": 35.017209
72
},
73
"estimated_arrival": "2020-10-17T12:00:00-06:00",
74
"estimated_departure": "2020-10-17T12:00:00-06:00"
75
}
76
],
77
"route_duration": 0
78
}
79
]
80
}
Copied!
The estimated arrival and departure of the stops show that for the stops Fushimi Inari Taisha and Kiyomizu-dera the service time has been applied only once for both stops, because they were approached as one group. Also, the service time was applied to Nijō Castle again, since it was approached as an isolated stop.
service-groups-output
Export as PDF
Copy link