Traditional modeling and optimization tools require translating decision data (i.e. inputs) and business logic to some other form before calling some optimization algorithm. In contrast, Nextmv's tools are designed to operate directly on business data and produce decisions that are actionable by software systems. This makes decisions more interpretable and easier to test. It also makes integration with data warehouses and business intelligence platforms significantly easier.
Nextmv SDK allows you to write a custom input schema to use Nextmv with any input data. See below for more information on writing custom input and output data.
Define input structure
To read input data into a model on Nextmv, you will need to define a Go struct
, detailing the structure of your input data.
For example, take the following JSON sample data below for a routing problem. It has a driver's name, their capacity and location, and a vector of pickup and delivery requests to route for them.
The input data structure can be defined with the following Go struct
.
Customize JSON formatting
You can change the way the names that Go structures use by default are read in and written out using json
annotations on your structs.
With these additions, a model can now read data that looks like this:
If you need finer-grained control over how data are read in and decisions are written, you can provide UnmarshalJSON
and MarshalJSON
methods for the types as shown in the Go docs.
As an example, we can change the way our state
type is written when solutions are found. Say we implement a duration
method for state
that estimates the time to complete a path and returns a time.Duration
. We add that to our model output with a MarshalJSON
method. We also add the request list from the input.
Define decision state
Next, define a decision (or system) state for your model. In the example above, we keep the current path as a slice of integers to refer to the locations by index.
Other data can be stored in your state, such as the final location of the driver or the cost of the route, depending on your requirements.
Standard output
Since Path
is exported, Nextmv's solver will automatically serialize it as the model output. All that is needed is to hook up the input type to a runner, construct a state, and return a solver operating on that state through different methods, including the Feasible
, Next
and any other methods required. See the solver overview for more information on the Feasible
and Next
methods.
Once you go build
your model into a binary, it will read input
structures from standard input and write state
structures to standard output. An alternative to using standard input and output is to use the -hop.runner.input.path
and -hop.runner.output.path
command-line flags. See build and run your app for more on next steps and the dispatch app for a full example.
Output statistics
Output statistics are provided about the results of the solver for a specific problem.
Below is an example of output statistics for a solver result.
The first field under the statistics
is bounds
, which contains the upper
and lower
bounds. In cases where the solver is maximizing or minimizing an objective, the upper
and lower
bounds are continuously updated after generating a new state.
If the bounds are the same in value that means that the solver has mathematically proven optimality of its best solution. When those are not the same value, the solver terminated early while searching the state space proving optimality. In that case, the solver will return the best found to date, but hasn't explored enough states to prove that it is the mathematical optimal. You can read more about the Bounds
method here.
In the search
object, you'll notice that there are values for generated
, expanded
, deferred
, reduced
, explored
, and filtered
.
The solver's search mechanism is a state exploration. It projects states forward from the root state to determine what decisions you should make. Every transition in that search produces a new state which the solver then explores.
Generated
states are all the states the solver has created.
Filtered
states are those that have been removed from the search because they have been bounded out. The solver has determined that it cannot, from a particular set of decisions, produce a solution that will be better than the best one it has found so far.
Expanded
states are all the states that are not Filtered
.
Reduced
states are states that have been removed from the search because a Reducer
was able to determine that there are states that strictly dominate them.
Deferred
states are states saved for later exploration if there's time. This is how the solver manages explosion of the state space. The solver won't explore every state sequentially. It will try to explore the most fruitful ones first and defer the others for later exploration if there's time.
Restricted
states are the states that have not been deferred, but instead will be investigated immediately.
Explored
states are all states Hop has fully explored. Those states are not able to produce more child states.
Each of these categories contain both feasible and infeasible states.