"github.com/nextmv-io/code/engines/measure"
"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.
Stops []route.Stop `json:"stops,omitempty"`
Vehicles []string `json:"vehicles,omitempty"`
IgnoreTriangularity bool `json:"ignore_triangularity,omitempty"`
Penalties []int `json:"penalties,omitempty"`
// Use the CLI runner to solve a Vehicle Routing Problem.
f := func(i input, opt solve.Options) (solve.Solver, error) {
limits := make([]route.Limit, len(i.Vehicles))
for i, m := range measures {
router, err := route.NewRouter(
route.Limits(limits, i.IgnoreTriangularity),
route.Unassigned(i.Penalties),
return router.Solver(opt)
// measures returns an array of Haversine measures based on stops.
func measures(i input) []measure.ByIndex {
points := make([]measure.Point, count+2*len(i.Vehicles))
for s, stop := range i.Stops {
points[s] = measure.Point{stop.Position.Lon, stop.Position.Lat}
measures := make([]measure.ByIndex, len(i.Vehicles))
m := measure.Indexed(measure.HaversineByPoint(), points)
for v := range i.Vehicles {