Version 0.7.0 released
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
the overview of solvers 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
the overview of solvers 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.