Pickups & deliveries
You will learn how to use the Precedence option with a practical example.
Pickups & deliveries are widely used in vehicle routing problems (VRPs) because often one or more items need to be picked up along the route before they are delivered to a customer. This is known as the vehicle routing problem with pickups & deliveries (VRPPD).
The router engine provides the Precedence option to configure a precedence relation between stops. This is done by adding a list of precedence jobs. For each job, it is specified that a stop (pick up) must precede another stop (drop off) in the same route. A stop may appear in several jobs, meaning that the option allows you to specify many pickups before a drop off and vice versa.

Example

The router example is used as a base, where routes are created to visit seven landmarks in Kyoto using two vehicles. This time, two precedence instructions are defined.
precedence-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
"precedences": [
34
{ "pick_up": "Fushimi Inari Taisha", "drop_off": "Kiyomizu-dera" },
35
{ "pick_up": "Gionmachi", "drop_off": "Kiyomizu-dera" }
36
]
37
}
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
Precedences []route.Job `json:"precedences,omitempty"`
14
}
15
16
// Use the CLI runner to solve a Vehicle Routing Problem.
17
func main() {
18
f := func(i input, opt solve.Options) (solve.Solver, error) {
19
router, err := route.NewRouter(
20
i.Stops,
21
i.Vehicles,
22
route.Precedence(i.Precedences),
23
)
24
if err != nil {
25
return nil, err
26
}
27
28
return router.Solver(opt)
29
}
30
31
cli.Run(f)
32
}
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
},
14
{
15
"id": "Gionmachi",
16
"position": {
17
"lon": 135.775682,
18
"lat": 35.002457
19
}
20
},
21
{
22
"id": "Kiyomizu-dera",
23
"position": {
24
"lon": 135.78506,
25
"lat": 34.994857
26
}
27
},
28
{
29
"id": "Kyoto Imperial Palace",
30
"position": {
31
"lon": 135.762057,
32
"lat": 35.025431
33
}
34
},
35
{
36
"id": "Nijō Castle",
37
"position": {
38
"lon": 135.748134,
39
"lat": 35.014239
40
}
41
},
42
{
43
"id": "Kinkaku-ji",
44
"position": {
45
"lon": 135.728898,
46
"lat": 35.039705
47
}
48
}
49
],
50
"route_duration": 1423
51
},
52
{
53
"id": "v2",
54
"route": [
55
{
56
"id": "Arashiyama Bamboo Forest",
57
"position": {
58
"lon": 135.672009,
59
"lat": 35.017209
60
}
61
}
62
],
63
"route_duration": 0
64
}
65
]
66
}
Copied!
You can see that one vehicle serves the stop Arashiyama Bamboo Forest whereas the other services the rest of the stops. Note that in the extended route the precedence constraints are fulfilled and Fushimi Inari Taisha and Gionmachi are visited before Kiyomizu-dera.
precedence-output
Export as PDF
Copy link