Release Notes
This page details relevant updates for each release. As always, you can find release specific implementation details in the package docs as well for that version.
Nextmv Cloud release July 21, 2021 - New charts and updated console UI
This release introduces multiple solutions for runs along with an easy way for customers to evaluate the returned solutions to help configure their Dispatch app. It also includes a UI overhaul for the Nextmv Cloud Console.
New solution evaluation charts
Three new charts are now available for visualizing existing output data: Solution Value Over Time, Solution Value Composition, and Vehicle Value Composition. These visualizations were added to provide additional understanding around returned solutions and can help with app configuration.
More user-friendly interface
We improved the overall design and layout of the Nextmv Cloud Welcome and Demo pages to create a better user experience as customers get started with Nextmv, navigate and configure their Dispatch app, and explore returned solutions.
Improvements and fixes
- Updated JSON input file overview and explanation on Welcome page with more details for getting started
- Added vehicle and stop counter subtext for input files to quickly size up a particular routing problem
- Added tooltips and graphics to facilitate understanding of various aspects in the Dispatch app such as JSON input field definitions and value function composition
- Updated color scheme in map results to be higher contrast and improved highlighting to facilitate better visual parsing of routes
- Added text-based route description for each vehicle in Results tab
- Introduced a new dropdown under Results tab for visualizing each returned solution on the map
Nextmv v0.8.0 Release June 15, 2021 - ALNS introduced
Nextmv version 0.8.0 introduces some performance improvements, the addition of
Dash to the code monorepo on GitHub (alongside Hop and HopM, now Engines), the
rebranding of HopM to Engines, the introduction of the Extend folder to isolate
those modules which require external dependencies and the addition,
modification, and deprecation of some API features in HopM (now Engines).
Dash
Moved to Code Monorepo
Before downloading v0.8.0, it is important to note that we’ve added Dash to the
code monorepo on GitHub. This means import paths have changed
(github.com/nextmv-io/dash is now github.com/nextmv-io/code/dash) and this
must be reflected when using the go get command.
go get github.com/nextmv-io/code/dash
| Version 0.7.3 and before | Version 0.8.0 and above |
|---|---|
| github.com/nextmv-io/dash | github.com/nextmv-io/code/dash |
Hop
Heuristic Modeling with ALNS (Adaptive Large Neighborhood Search)
This version includes the addition of support for adaptive large neighborhood search (ALNS), a heuristic solver for finding more improving solutions faster. The addition of ALNS brings significant performance improvements. This can be particularly beneficial when grouping many vehicles together in a fleet and solving large-scale routing problems.
ALNS is now supported in the vehicle and fleet engines by default. No additional
upgrade steps are required to use ALNS for users employing
vehicle.DefaultSolver(state, opt) or fleet.DefaultSolver(state, opt).
However, for users employing solve.Minimizer(outputState, opt),
solve.Minimizer(outputState,opt) will need to be replaced with
vehicle.Solver(root, opt) or fleet.Solver(root, opt) to use ALNS in the
vehicle or fleet engine, respectively.
Default operators and parameters are provided for use with ALNS. Custom inputs are supported if required. See the package docs for additional details. Further support will be provided for ALNS in vehicle and fleet engines in future releases.
Hop API Changes
A context.Context argument has been added to the following method
declarations:
model.State.Next()solve.Solver.All()solve.Solver.Last()
While this argument is now required when calling implementations of these methods, it is not required that a user do anything with it. Its purpose is to empower a user to end a run sooner in the process of diagram construction, so as to better respect a prescribed time limit.
Aditionally, diagram node generation stops after n nodes. Previously, n
nodes were explored, but many more may have been generated. Upgrading and not
adjusting n may result in fewer good solutions, so higher n values may be
required to achieve the same results.
Hop API Additions
To support hybrid optimization with ALNS, two new interfaces have been added:
solve.Hybridsolve.Inferrer
The first enables the combination of different solvers and the parallelization of multiple solvers. The second can be used to share results between solvers.
Engines (Formerly HopM)
We have renamed HopM to engines. This means import paths have changed
(github.com/nextmv-io/code/engines) and this must be reflected in your
go get command.
go get github.com/nextmv-io/code/engines
| Version 0.6.6 and before | Version 0.7.0 - 0.7.3 | Version 0.8.0 and above |
|---|---|---|
| github.com/nextmv-io/hopm | github.com/nextmv-io/code/hopm | github.com/nextmv-io/code/engines |
Engines API Changes
As above, a context.Context argument has been added to the following method
declarations:
fleet.Router.Feasiblefleet.Router.Optimalfleet.Router.WarmFeasible
This argument is required when calling implementations of these methods. See above in Hop's "API Changes" section for some additional notes on this change.
Also, service times durations []int and maximum waiting times before each
window waitMax []int now need to be provided when constructing a window
measure. Previously, service and waiting times were part of a measure. Now,
times are provided to a measure. This enables the specification of maximum wait
time, for example.
Engines API Additions
When using a CustomRouter, a function must now be passed in for each phase.
Two new default functions are available for use (these are used for the
DefaultRouter):
fleet.SolverFuncGeneratorfleet.AlnsSolverFuncGenerator
New methods have been added to the fleet Engine to enable the following:
- Set a vehicle's state (
fleet.State.SetVehicle) - Set list of locations for a vehicle (
vehicle.State.SetLocations) - Set and validate routes for a vehicle (
vehicle.State.SetRoute) - Specify a custom compatibility constraint for a vehicle and a location
(
fleet.CustomVehicleFilter())
Enforcment of Assignment
Default UnassignedPenalties behavior has changed:
- If no unassigned penalties are provided, assignment will be enforced (note, this could result in no feasible solutions being returned).
- If unassigned penalties are provided, assignment will not be enforced. Unassignment will be discouraged (more or less, based on the penalty value).
If using a penalty to prevent unassigned locations, it is advised to remove it
in order to benefit from the new default behavior for the fleet engine: if no
UnassignedPenalties are provided, all locations are assigned a vehicle. Note,
the enforcement of assignment could result in no feasible solutions being
returned. To discourage (but still allow for some) unassigned locations, we
suggest to add unassigned penalties (see
modeling-best-practices for more on unassignment
penalties).
Measures
Measures API Changes
Index interfaces, such as haversineByIndex and euclideanByIndex, will be
soon deprecated. ByIndex measures should now be generated with the Indexed
function.
Extend
There is a new suite of modules, called extend, which use third-party
dependencies such as AWS Lambda or OSRM. This may be a breaking change as these
same features used to be part of dash, hop and hopm (now engines). This
means import paths have changed (github.com/nextmv-io/code/hopm/measure/osrm
is now github.com/nextmv-io/code/extend/measure/osrm) and this must be
reflected when using the go get command.
Nextmv v0.7.1 April 8, 2021
Nextmv version 0.7.1 introduces a few changes that extend existing functionality and improve efficiency. The changes introduced with this release are not breaking and optional for Nextmv customers to upgrade. A summary of added functionality is included below.
Hop fleet extensions
Exposed new information in Hop fleet
Assigned vehicles and locations
The new Assigned() (int, model.IntDomain) function gives access to the set of
locations and the vehicle those locations were assigned to in the previous call
to Next(). The function can be called on a fleet state and will return an
index and an IntDomain. Note, if no locations were assigned, then an empty
domain will be returned by the function. Previously, accessing this information
required ranging and recomputing over all vehicles. We recommend using the new
Assigned function for a more efficient approach.
Vehicle state
The new Vehicle(index int) vehicle.State function gives fast access to the
state of a particular vehicle. The function takes an index of a vehicle (this
can be passed from Assigned) and returns the vehicle state.
Added flexible assigner framework
This version introduces a flexible assigner framework to Hop to facilitate the addition of commonly used filters or constraints. To use the new assigner framework, you will need to specify three things:
- Location selector: Takes in state and returns an
IntDomainrepresenting the next locations to be assigned to vehicles. Ifnil, the minimum from the domain of remaining location indices will be taken by default. - Location grouper: Specifies for a given index location, all locations (including the index location itself) that must be assigned with the same vehicle (e.g., if a pickup is assigned to a vehicle, then the drop off must also be assigned to that vehicle). A default location grouper function is provided for convenience.
- Vehicle filter: Takes in a list of vehicles, locations, and routes for those
vehicles and returns an
IntDomainrepresenting valid combinations of vehicles and locations to be assigned next. New vehicle filters are detailed below.
Added new vehicle filters
Three vehicle filters are now supported in Hop fleet and made available through the assigner framework. The following vehicle filters are available:
- Max route length filter: Prevents the assignment of locations to vehicles that will exceed a max route length (measured in time or distance between two locations).
- Capacity filter: Prevents the assignment of locations to vehicles that will exceed vehicle capacity constraints (e.g., a car with only one seat for a passenger will not be assigned to a pickup location with >1 passenger).
- Attributes filter: Prevents the assignment of locations to vehicles that are not eligible due to compatibility of vehicle and location attributes (e.g., a location with a pick up that requires refrigeration will not be assigned to a vehicle without refrigeration)
Note, because vehicle filters serve as a pre-filter they also help to improve search efficiency. We recommend customers use the built-in vehicle filters (when appropriate) for this reason.
Extended value function
Penalty cost for unassigned locations can now be included in the value function. The penalty cost will help to direct the search algorithm away from unassigned locations in solutions. Unassignment is still allowed, but can be penalized.
To add penalties for unassigned locations, specify an integer slice of
UnassignedPenalities on the fleet struct. Locations can have different
penalties (e.g., if there is a high priority locations that must be served,
they can have higher penalties).
If no penalty is provided, the solver defaults to previous behavior (tries to assign everything, but some locations may still be unassigned).
Added access to the underlying vehicle model
A new function transform func(vehicle.State) vehicle.State has been added to
CustomRouter to provide access to the underlying vehicle model. This enables
constraints such as earliness and lateness to be considered as part of the
vehicle model search to find improving results faster. ETAs and time windows can
now be tracked when planning a vehicle route as well.
Hop vehicle model extensions
Exposed new information in Hop vehicle
Accumulated cost
The accumulated cost for each stop in a route can be accessed using
vehicle.State.Cost(index int) float64. This simplifies the calculation of an
ETA as part of the value function.
Vehicle state constraints
The constraints of a vehicle state can be accessed using
vehicle.State.Constraints(). This new method returns the constraints of
vehicle at the state it was called on.
Cost on a window constraint
Window constraints specify hard time windows that need to be met. If a vehicle
arrives early, a wait time will be enforced. The new vehicle.Coster interface
specifies a Cost(index int) int method implemented by the Window constraint
that captures both the accumulated measure and enforced wait time.
Added max route length constraint
The vehicle max route length constraint requires a measure, max route length,
and a boolean to ignore the triangular inequality as input. Most customers using
their own costs (e.g., a matrix measure) will want to set ignoreTriangular to
TRUE. See the package docs for additional details.
Simplified measure specifications
Previously, separate point and index interfaces were implemented for each form
of measurement (e.g., HaversineByPoint, HaversineByIndex,
EuclideanByPoint, EuclideanByIndex, etc.). As we add new measures, we are
moving to a more scalable system where only ByPoint is specified, and
ByIndex is dynamically generated.
Use the new Indexed function to generate a ByIndex measure: Indexed(m
ByPoint, points []Point) ByIndex. The function takes a ByPoint measure and a
slice of points as input and returns a ByIndex measure.
While switching to the new implementation of indexed measures is not required to upgrade, we strongly recommend customers do so. The change will be required in future releases.
Support for Alternate locations
This release adds support for alternate location handling. The Vehicle input
schema has a new field AlternateLocations of type IntDomain. This domain
specifies a set of locations one of which has to be visited by the vehicle. One
usage scenario is when the vehicle should go on a break, and there are multiple
break locations. The model will choose the closest (as determined by the given
measure) one.
Additionally we added Alternate() (index, location int), which gives access to
the index in the route at which the alternate location can be found as well as
the actual location that is used from the set of alternate locations.
Introducing Nextmv apps
Apps provide a faster way to get started with Nextmv and can be used off-the-
shelf or customized to your needs. The first Nextmv App is now available in the
apps repo on GitHub. The first application
is Dispatch, a base multi-vehicle fleet routing app with no pre-specified
constraints. This base app is ready to use with Hop v0.7.1 and can be easily
extended to include the new functionality detailed above. Stay tuned as we
continue to add new apps.
Nextmv v0.7.0 March 9, 2021
Nextmv version 0.7.0 introduces a few important changes that improve time to first feasible solution, help with memory use management, and align product releases.
This release introduces breaking changes. All Nextmv customers migrating to Hop v0.7.0 will need to make a few changes to their models to ensure smooth operations.
Updating Import Paths
Before downloading v0.7.0, it is important to note that we’ve combined Hop and
HopM into a single GitHub repository called code. This means import paths have
changed (github.com/nextmv-io/hop is now github.com/nextmv-io/code/hop) and
this must be reflected in your go get command.
go get github.com/nextmv-io/code/hop
go get github.com/nextmv-io/code/hopm
You’ll need to replace the old import paths manually inside your models. Under
Files, you’ll need to find, edit, and replace the old import paths with the new
ones. It’s also good practice to do a go mod tidy once you’ve made the import
updates.
| Version 0.6.6 and before | Version 0.7.0 and above |
|---|---|
| github.com/nextmv-io/hop | github.com/nextmv-io/code/hop |
| github.com/nextmv-io/hopm | github.com/nextmv-io/code/hopm |
Updating Next Method for Expansion Limits
We’ve introduced expansion limits in version 0.7.0 to improve time to first
feasible solution and better manage memory use. This enhancement has a direct
impact on the Next method. If you try go build, you will see a build error
that shows the Next method is expecting a model.Expander but is instead
returning []model.State.
Models without HopM Components
Any user with a custom model that does not embed a HopM component should update
their Next method to return an Eager expander.
We'll look at our n-queens model as an example.
For v0.6.6 and before:
// Next places a queen in each available column of the most constrained row.
func (b board) Next() []model.State {
next := []model.State{}
if row, ok := model.IntDomains(b).Smallest(); ok {
for it := b[row].Iterator(); it.Next(); {
next = append(next, b.place(row, it.Value()))
}
}
return next
}
For v0.7.0 with Expanders:
// Next places a queen in each available column of the most constrained row.
func (b board) Next() model.Expander {
next := []model.State{}
if row, ok := model.IntDomains(b).Smallest(); ok {
for it := b[row].Iterator(); it.Next(); {
next = append(next, b.place(row, it.Value()))
}
}
return expand.Eager(next...)
}
We use an Eager expander to maintain the same state space we had before this
release. We could also use Lazy to return less child states. See
How Hop Hops for more details on Expanders.
Models with HopM Components
Any user with an embedded Hop component should update their Next method to
return a Lazy expander.
We'll look at our dispatch model as an example. When we embed a HopM component
like Fleet and need to access HopM's state for value function changes, our
Next method is a wrapped HopM state.
For v0.6.6 and before:
func (s state) Next() []model.State {
next := []model.State{}
for _, n := range s.fleetState.Next() {
next = append(next, state{
fleetState: n.(fleet.State),
outputTransformer: s.outputTransformer,
})
}
return next
}
For v0.7.0 with Expanders:
func (s state) Next() model.Expander {
expander := s.fleetState.Next()
if expander == nil {
return nil
}
return expand.Lazy(func() model.State {
if next := expander.Expand(); next != nil {
return state{
fleetState: next.(fleet.State),
outputTransformer: s.outputTransformer,
}
}
return nil
})
}
We use an Lazy expander to limit the number of states returned by default. See
How Hop Hops for more details on Expanders.
Updating CLI and ENV Options
Beginning with version 0.7.0, the hop.runner.output.solutions environment
variable will now default to last instead of all. This default setting tells
Hop to only output the final improving solution in a Hop model. If this is the
desired behavior of your model, all you need to do is remove this line of code
from your command line or env. If you desire to have it return all, you will
need to set the runner options accordingly.