You are viewing Nextmv legacy docs. ⚡️ Go to latest docs ⚡️

Router

Limit Distances

You will learn how to use the LimitDistances option with a practical example.

In vehicle routing problems (VRPs) it is sometimes required to limit routes. To limit the route length or duration the router engine offers the LimitDistances and LimitDurations options. For all other use cases it provides the Limits option to configure custom limits for vehicles.

Note that LimitDistances is working with haversine distances internally. If you want to calculate limit distances based on another measure, please use the Limits option.

To limit the route's length, a slice of values representing the maximum length must be provided. The values must be given in meters as the underlying measure uses this unit. In addition, a flag must be specified to ignore or adhere to the triangle inequality.

Example

The aim of this example is to define distance limits for vehicles and an unassigned penalty to be able to receive a solution. The introductory router example is used as a base, where routes are created to visit seven landmarks in Kyoto using two vehicles.

limit-distances-input

Save the following information in an input.json file (see input and output for more information on working with input files).

{
  "stops": [
    {
      "id": "Fushimi Inari Taisha",
      "position": { "lon": 135.772695, "lat": 34.967146 }
    },
    {
      "id": "Kiyomizu-dera",
      "position": { "lon": 135.78506, "lat": 34.994857 }
    },
    {
      "id": "Nijō Castle",
      "position": { "lon": 135.748134, "lat": 35.014239 }
    },
    {
      "id": "Kyoto Imperial Palace",
      "position": { "lon": 135.762057, "lat": 35.025431 }
    },
    {
      "id": "Gionmachi",
      "position": { "lon": 135.775682, "lat": 35.002457 }
    },
    {
      "id": "Kinkaku-ji",
      "position": { "lon": 135.728898, "lat": 35.039705 }
    },
    {
      "id": "Arashiyama Bamboo Forest",
      "position": { "lon": 135.672009, "lat": 35.017209 }
    }
  ],
  "vehicles": ["v1", "v2"],
  "limits": [9000, 9000],
  "ignore_triangularity": true,
  "penalties": [2000000, 2000000, 2000000, 2000000, 2000000, 2000000, 2000000]
}
Copy

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 support@nextmv.io.

To proceed with running the example, create a main.go file and use the code snippet below.

package main

import (
    "github.com/nextmv-io/code/engines/route"
    "github.com/nextmv-io/code/hop/run/cli"
    "github.com/nextmv-io/code/hop/solve"
)

// Struct to read from JSON in.
type input struct {
    Stops               []route.Stop `json:"stops,omitempty"`
    Vehicles            []string     `json:"vehicles,omitempty"`
    IgnoreTriangularity bool         `json:"ignore_triangularity,omitempty"`
    Penalties           []int        `json:"penalties,omitempty"`
    Limits              []float64    `json:"limits,omitempty"`
}

// Use the CLI runner to solve a Vehicle Routing Problem.
func main() {
    f := func(i input, opt solve.Options) (solve.Solver, error) {
        router, err := route.NewRouter(
            i.Stops,
            i.Vehicles,
            route.LimitDistances(i.Limits, i.IgnoreTriangularity),
            route.Unassigned(i.Penalties),
        )
        if err != nil {
            return nil, err
        }

        return router.Solver(opt)
    }
    cli.Run(f)
}
Copy

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).

go run main.go -hop.runner.input.path input.json | jq .state
Copy

Solution

The solution should look similar to this one:

{
  "unassigned": [
    {
      "id": "Arashiyama Bamboo Forest",
      "position": {
        "lon": 135.672009,
        "lat": 35.017209
      }
    }
  ],
  "vehicles": [
    {
      "id": "v1",
      "route": [
        {
          "id": "Kinkaku-ji",
          "position": {
            "lon": 135.728898,
            "lat": 35.039705
          }
        },
        {
          "id": "Nijō Castle",
          "position": {
            "lon": 135.748134,
            "lat": 35.014239
          }
        },
        {
          "id": "Kyoto Imperial Palace",
          "position": {
            "lon": 135.762057,
            "lat": 35.025431
          }
        }
      ],
      "route_duration": 510
    },
    {
      "id": "v2",
      "route": [
        {
          "id": "Fushimi Inari Taisha",
          "position": {
            "lon": 135.772695,
            "lat": 34.967146
          }
        },
        {
          "id": "Kiyomizu-dera",
          "position": {
            "lon": 135.78506,
            "lat": 34.994857
          }
        },
        {
          "id": "Gionmachi",
          "position": {
            "lon": 135.775682,
            "lat": 35.002457
          }
        }
      ],
      "route_duration": 448
    }
  ]
}
Copy

You can see that one stop is unassigned in the solution. Because of the route's limitation, it was not possible to add it to either of the two routes anymore.

limit-distances-output

Page last updated

Go to on-page nav menu