2021-03-09 v0.7.0 released
Introducing v0.7.0.
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.
Bash
1
go get github.com/nextmv-io/code/hop
2
go get github.com/nextmv-io/code/hopm
Copied!
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:
Go
1
// Next places a queen in each available column of the most constrained row.
2
func (b board) Next() []model.State {
3
next := []model.State{}
4
if row, ok := model.IntDomains(b).Smallest(); ok {
5
for it := b[row].Iterator(); it.Next(); {
6
next = append(next, b.place(row, it.Value()))
7
}
8
}
9
return next
10
}
Copied!
For v0.7.0 with Expanders:
Go
1
// Next places a queen in each available column of the most constrained row.
2
func (b board) Next() model.Expander {
3
next := []model.State{}
4
if row, ok := model.IntDomains(b).Smallest(); ok {
5
for it := b[row].Iterator(); it.Next(); {
6
next = append(next, b.place(row, it.Value()))
7
}
8
}
9
return expand.Eager(next...)
10
}
Copied!
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:
Go
1
func (s state) Next() []model.State {
2
next := []model.State{}
3
for _, n := range s.fleetState.Next() {
4
next = append(next, state{
5
fleetState: n.(fleet.State),
6
outputTransformer: s.outputTransformer,
7
})
8
}
9
return next
10
}
Copied!
For v0.7.0 with Expanders:
Go
1
func (s state) Next() model.Expander {
2
expander := s.fleetState.Next()
3
if expander == nil {
4
return nil
5
}
6
return expand.Lazy(func() model.State {
7
if next := expander.Expand(); next != nil {
8
return state{
9
fleetState: next.(fleet.State),
10
outputTransformer: s.outputTransformer,
11
}
12
}
13
return nil
14
})
15
}
Copied!
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.