Compatibility attributes
You will learn how to use the Attribute option with a practical example.
In vehicle routing problems (VRPs) stops can sometimes only be served by specific vehicles. E.g., some delivery items may need a cooling system to keep fresh or maybe larger items must be delivered on a truck and do not fit in a smaller vehicle.
The router engine provides the Attribute option to configure compatibility attributes for stops and vehicles separately. This is done by specifying a list of attributes for stops and vehicles, respectively. Stops that have configured attributes are only compatible with vehicles that match at least one of them. Stops that do not have any specified attributes are compatible with any vehicle. Vehicles that do not have any specified attributes are only compatible with stops without attributes.

Example

The aim of this example is to define compatibility attributes for stops and vehicles. The introductory router example is used as a base, where routes are created to visit seven landmarks in Kyoto using two vehicles.
attributes-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
"vehicle_attributes": [
34
{
35
"id": "v1",
36
"attributes": ["A"]
37
},
38
{
39
"id": "v2",
40
"attributes": ["B"]
41
}
42
],
43
"stop_attributes": [
44
{
45
"id": "Fushimi Inari Taisha",
46
"attributes": ["A", "C"]
47
},
48
{
49
"id": "Arashiyama Bamboo Forest",
50
"attributes": ["B"]
51
},
52
{
53
"id": "Kinkaku-ji",
54
"attributes": ["B"]
55
}
56
]
57
}
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
VehicleAttributes []route.Attributes `json:"vehicle_attributes"`
14
StopAttributes []route.Attributes `json:"stop_attributes"`
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.Attribute(i.VehicleAttributes, i.StopAttributes),
24
)
25
if err != nil {
26
return nil, err
27
}
28
return router.Solver(opt)
29
}
30
cli.Run(f)
31
}
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": "Kiyomizu-dera",
16
"position": {
17
"lon": 135.78506,
18
"lat": 34.994857
19
}
20
},
21
{
22
"id": "Gionmachi",
23
"position": {
24
"lon": 135.775682,
25
"lat": 35.002457
26
}
27
},
28
{
29
"id": "Nijō Castle",
30
"position": {
31
"lon": 135.748134,
32
"lat": 35.014239
33
}
34
},
35
{
36
"id": "Kyoto Imperial Palace",
37
"position": {
38
"lon": 135.762057,
39
"lat": 35.025431
40
}
41
}
42
],
43
"route_duration": 908
44
},
45
{
46
"id": "v2",
47
"route": [
48
{
49
"id": "Kinkaku-ji",
50
"position": {
51
"lon": 135.728898,
52
"lat": 35.039705
53
}
54
},
55
{
56
"id": "Arashiyama Bamboo Forest",
57
"position": {
58
"lon": 135.672009,
59
"lat": 35.017209
60
}
61
}
62
],
63
"route_duration": 575
64
}
65
]
66
}
Copied!
You can see that the stop Fushimi Inari Taisha has been assigned to v1 and the stops Arashiyama Bamboo Forest and Kinkaku-ji have been assigned to v2 due to the compatibility attributes. All other stops are cost-optimally assigned to the vehicles.
attributes-output
Export as PDF
Copy link