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.